mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-10-07 12:58:49 +08:00
* feat: integrate LLM profiles into settings route (PR C) - Add LlmSettingsLocalView component for integrated profile management - Extend SdkSectionSaveControl to expose form values for custom save flows - Update LLM settings route to render profile list with create/edit views - Add i18n keys for profile create/edit UI (CREATE_PROFILE, EDIT_PROFILE, PROFILE_CREATED, PROFILE_UPDATED, MODEL_REQUIRED, STATUS, BUTTON) - Add test coverage for LlmSettingsLocalView The integrated view shows: - Profile list with active badge and action menu - Add Profile button that opens create form - Edit button that loads profile config and opens edit form - Back/Cancel buttons to return to list view Co-authored-by: openhands <openhands@all-hands.dev> * chore: address PR review feedback (#393) - Improve mock typing with properly typed helper functions that provide all required React Query fields, eliminating incomplete 'as unknown as' casts - Add integration test that verifies the save flow (fills in profile name, clicks save, verifies UI state transitions) - Add component documentation noting future refactoring opportunity (extract useProfileForm, useProfileSave hooks for better testability) - Document API key preservation behavior: currently preserves existing encrypted key in edit mode with no new key; note about potential 'Clear API Key' UX enhancement for future - Document auto-derive name race condition: client-side uniqueness check uses render-time state, so concurrent profile creation by another client would result in server conflict error (handled gracefully) - Document default export change in route file: LlmSettingsLocalView is now the default export; named export LlmSettingsScreen remains for embedded use Co-authored-by: openhands <openhands@all-hands.dev> * fix: update llm-settings test to use named export The default export of llm-settings.tsx changed to render LlmSettingsLocalView (the profiles manager). The test needs to import the named export LlmSettingsScreen to test the form component directly. Co-authored-by: openhands <openhands@all-hands.dev> * Fix LLM profile button/badge sizing and update typescript-client to v0.6.0 - BrandButton: Change padding from p-2 to px-3 py-2 for better text display - ProfileRow: Increase active badge vertical padding from py-0.5 to py-1 - Update @openhands/typescript-client from commit SHA to v0.6.0 tag Co-authored-by: openhands <openhands@all-hands.dev> * Fix LLM settings to show regular form in cloud mode and empty form in create mode - LlmSettingsRoute: Render LlmSettingsScreen (standard form) for cloud backends and LlmSettingsLocalView (profile manager) for local backends only - LlmSettingsLocalView: Pass empty initial values in create mode to ensure fresh form fields, add key prop to force form remount between profiles - Add unit tests for cloud vs local backend rendering - Add unit tests for create mode empty form initialization Co-authored-by: openhands <openhands@all-hands.dev> * Fix edit mode form initialization to display profile values - Fix initialValueOverrides logic to properly check for edit mode AND existing initialValues before using them - Add prefix to edit mode key for clearer remount semantics - Add unit tests verifying edit mode populates profile name correctly - Add unit tests verifying getProfile is called with encrypted mode Co-authored-by: openhands <openhands@all-hands.dev> * Add debug logging to trace edit profile data flow Co-authored-by: openhands <openhands@all-hands.dev> * Fix edit profile config parsing - read from config directly not config.llm The API returns profile config with llm settings at the top level (config.model, config.api_key, config.base_url), not nested under config.llm. Fixed the parsing to read directly from detail.config. Co-authored-by: openhands <openhands@all-hands.dev> * Handle profile rename during edit and update active profile When editing a profile and changing its name: 1. Rename the profile first using ProfilesService.renameProfile 2. Then save the profile config to the new name 3. If the renamed profile was the active profile, re-activate it after the rename (since rename doesn't update active_profile) This prevents creating duplicate profiles when just changing the name. Co-authored-by: openhands <openhands@all-hands.dev> * Fix package-lock.json to use https protocol for typescript-client The lock file was using git+ssh:// protocol which causes Vercel build failures since Vercel doesn't have SSH keys configured. Changed to git+https:// and removed the integrity hash (git deps don't have one). Co-authored-by: openhands <openhands@all-hands.dev> * chore(profiles): UI polish, shared validation, onboarding integration (#417) * fix(profiles): Available Profiles heading translation * fix(profiles): use brand badge for active profile indicator * feat(profiles): replace form heading with "Back to LLM profiles list" * fix(profiles): unify profile-name validation and reject any whitespace * fix(onboarding): persist onboarding LLM choice as an active profile * refactor(profiles): drop redundant trim/wrapper after validator change * Fix LLM profile route mocks and warnings * chore: update baseline snapshots [skip ci] --------- Co-authored-by: openhands <openhands@all-hands.dev> Co-authored-by: Vasco Schiavo <115561717+VascoSch92@users.noreply.github.com> Co-authored-by: Graham Neubig <neubig@gmail.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
227 lines
7.8 KiB
JSON
227 lines
7.8 KiB
JSON
{
|
|
"name": "@openhands/agent-canvas",
|
|
"version": "1.0.0-alpha.3",
|
|
"description": "Agent Canvas UI for OpenHands - run AI coding agents with a visual interface",
|
|
"license": "MIT",
|
|
"private": false,
|
|
"type": "module",
|
|
"repository": {
|
|
"type": "git",
|
|
"url": "https://github.com/OpenHands/agent-canvas"
|
|
},
|
|
"homepage": "https://github.com/OpenHands/agent-canvas#readme",
|
|
"bugs": {
|
|
"url": "https://github.com/OpenHands/agent-canvas/issues"
|
|
},
|
|
"bin": {
|
|
"agent-canvas": "bin/agent-canvas.mjs"
|
|
},
|
|
"engines": {
|
|
"node": ">=22.12.0"
|
|
},
|
|
"dependencies": {
|
|
"@heroui/react": "2.8.10",
|
|
"@microlink/react-json-view": "1.31.20",
|
|
"@monaco-editor/react": "4.7.0",
|
|
"@openhands/typescript-client": "git+https://github.com/OpenHands/typescript-client.git#v0.6.0",
|
|
"@react-router/node": "7.14.2",
|
|
"@react-router/serve": "7.14.2",
|
|
"@tailwindcss/vite": "4.2.4",
|
|
"@tanstack/react-query": "5.100.9",
|
|
"@uidotdev/usehooks": "2.4.1",
|
|
"@xterm/addon-fit": "0.11.0",
|
|
"@xterm/xterm": "6.0.0",
|
|
"axios": "1.16.0",
|
|
"class-variance-authority": "0.7.1",
|
|
"clsx": "2.1.1",
|
|
"downshift": "9.3.2",
|
|
"framer-motion": "12.38.0",
|
|
"i18next": "26.0.8",
|
|
"i18next-browser-languagedetector": "8.2.1",
|
|
"i18next-http-backend": "4.0.0",
|
|
"isbot": "5.1.39",
|
|
"lucide-react": "1.14.0",
|
|
"monaco-editor": "0.55.1",
|
|
"posthog-js": "1.372.6",
|
|
"react": "19.2.5",
|
|
"react-dom": "19.2.5",
|
|
"react-hot-toast": "2.6.0",
|
|
"react-i18next": "17.0.6",
|
|
"react-icons": "5.6.0",
|
|
"react-markdown": "10.1.0",
|
|
"react-router": "7.14.2",
|
|
"react-syntax-highlighter": "16.1.1",
|
|
"rehype-raw": "7.0.0",
|
|
"rehype-sanitize": "6.0.0",
|
|
"remark-breaks": "4.0.0",
|
|
"remark-gfm": "4.0.1",
|
|
"sirv-cli": "3.0.1",
|
|
"socket.io-client": "4.8.3",
|
|
"tailwind-merge": "3.5.0",
|
|
"tailwind-scrollbar": "4.0.2",
|
|
"unist-util-visit": "5.1.0",
|
|
"uuid": "14.0.0",
|
|
"vite": "8.0.10",
|
|
"zustand": "5.0.12"
|
|
},
|
|
"scripts": {
|
|
"dev": "npm run dev:docker",
|
|
"dev:dangerously-dockerless": "node --env-file-if-exists=.env scripts/dev-static.mjs",
|
|
"dev:dangerously-dockerless:dynamic": "node --env-file-if-exists=.env scripts/dev-with-automation.mjs",
|
|
"dev:safe": "node --env-file-if-exists=.env scripts/dev-safe.mjs",
|
|
"dev:extra-backend": "node --env-file-if-exists=.env scripts/dev-extra-backend.mjs",
|
|
"dev:automation": "node --env-file-if-exists=.env scripts/dev-with-automation.mjs",
|
|
"dev:docker": "node --env-file-if-exists=.env scripts/dev-docker.mjs",
|
|
"dev:docker:dynamic": "node --env-file-if-exists=.env scripts/dev-docker.mjs --dynamic",
|
|
"dev:minimal": "node --env-file-if-exists=.env scripts/dev-safe.mjs",
|
|
"dev:frontend": "npm run make-i18n && cross-env VITE_MOCK_API=false react-router dev",
|
|
"dev:mock": "npm run make-i18n && cross-env VITE_MOCK_API=true react-router dev",
|
|
"build": "npm run build:app",
|
|
"build:mock": "npm run make-i18n && cross-env VITE_MOCK_API=true react-router build",
|
|
"start": "npx sirv-cli build/ --single",
|
|
"test": "npm run make-i18n && vitest run",
|
|
"test:e2e": "playwright test --pass-with-no-tests",
|
|
"test:e2e:live": "node --env-file-if-exists=.env tests/e2e/live/scripts/run-live-e2e.mjs",
|
|
"test:e2e:snapshots": "playwright test tests/e2e/snapshots --project=chromium",
|
|
"test:e2e:snapshots:update": "playwright test tests/e2e/snapshots --project=chromium --update-snapshots",
|
|
"test:coverage": "npm run make-i18n && vitest run --coverage",
|
|
"dev_wsl": "VITE_WATCH_USE_POLLING=true vite",
|
|
"preview": "vite preview",
|
|
"make-i18n": "node scripts/make-i18n-translations.cjs",
|
|
"prelint": "npm run make-i18n",
|
|
"lint": "npm run typecheck && eslint src && prettier --check src/**/*.{ts,tsx}",
|
|
"lint:fix": "eslint src --fix && prettier --write src/**/*.{ts,tsx}",
|
|
"prepare": "husky",
|
|
"typecheck": "react-router typegen && tsc",
|
|
"typecheck:staged": "react-router typegen && npx tsc --noEmit --skipLibCheck",
|
|
"check-translation-completeness": "node scripts/check-translation-completeness.cjs",
|
|
"build:app": "npm run make-i18n && react-router build",
|
|
"build:lib": "npm run make-i18n && react-router typegen && cross-env BUILD_LIB=true vite build && tsc -p tsconfig.lib.json"
|
|
},
|
|
"lint-staged": {
|
|
"src/**/*.{ts,tsx,js}": [
|
|
"eslint --fix",
|
|
"prettier --write"
|
|
],
|
|
"src/**/*.{ts,tsx}": [
|
|
"bash -c 'npm run typecheck:staged'"
|
|
],
|
|
"src/**/*": [
|
|
"npm run check-translation-completeness"
|
|
]
|
|
},
|
|
"devDependencies": {
|
|
"@eslint/eslintrc": "3.3.1",
|
|
"@eslint/js": "9.39.4",
|
|
"@mswjs/socket.io-binding": "0.2.0",
|
|
"@playwright/test": "1.59.1",
|
|
"@react-router/dev": "7.14.2",
|
|
"@tailwindcss/typography": "0.5.19",
|
|
"@tanstack/eslint-plugin-query": "5.100.9",
|
|
"@testing-library/dom": "10.4.1",
|
|
"@testing-library/jest-dom": "6.9.1",
|
|
"@testing-library/react": "16.3.2",
|
|
"@testing-library/user-event": "14.6.1",
|
|
"@types/mdast": "4.0.4",
|
|
"@types/node": "25.6.0",
|
|
"@types/react": "19.2.14",
|
|
"@types/react-dom": "19.2.3",
|
|
"@types/react-syntax-highlighter": "15.5.13",
|
|
"@typescript-eslint/eslint-plugin": "8.59.2",
|
|
"@typescript-eslint/parser": "8.59.2",
|
|
"@vercel/react-router": "1.3.0",
|
|
"@vitest/coverage-v8": "4.1.5",
|
|
"cross-env": "10.1.0",
|
|
"eslint": "9.39.4",
|
|
"eslint-config-prettier": "10.1.8",
|
|
"eslint-import-resolver-typescript": "4.4.4",
|
|
"eslint-plugin-i18next": "6.1.4",
|
|
"eslint-plugin-import-x": "4.16.2",
|
|
"eslint-plugin-jsx-a11y": "6.10.2",
|
|
"eslint-plugin-prettier": "5.5.5",
|
|
"eslint-plugin-react": "7.37.5",
|
|
"eslint-plugin-react-hooks": "7.1.1",
|
|
"eslint-plugin-unused-imports": "4.4.1",
|
|
"globals": "16.5.0",
|
|
"husky": "9.1.7",
|
|
"jsdom": "29.1.1",
|
|
"lint-staged": "16.4.0",
|
|
"msw": "2.14.2",
|
|
"postcss-prefix-selector": "2.1.1",
|
|
"prettier": "3.8.3",
|
|
"tailwindcss": "4.2.4",
|
|
"typescript": "6.0.3",
|
|
"vite-plugin-svgr": "5.2.0",
|
|
"vitest": "4.1.5"
|
|
},
|
|
"packageManager": "npm@10.5.0",
|
|
"volta": {
|
|
"node": "22.12.0"
|
|
},
|
|
"msw": {
|
|
"workerDirectory": [
|
|
"public"
|
|
]
|
|
},
|
|
"overrides": {
|
|
"dompurify": "3.3.2"
|
|
},
|
|
"main": "./dist/index.cjs",
|
|
"module": "./dist/index.js",
|
|
"types": "./dist/index.d.ts",
|
|
"files": [
|
|
"dist",
|
|
"bin",
|
|
"build",
|
|
"scripts"
|
|
],
|
|
"exports": {
|
|
".": {
|
|
"types": "./dist/index.d.ts",
|
|
"import": "./dist/index.js",
|
|
"require": "./dist/index.cjs"
|
|
},
|
|
"./browser": {
|
|
"types": "./dist/components/browser/index.d.ts",
|
|
"import": "./dist/components/browser/index.js",
|
|
"require": "./dist/components/browser/index.cjs"
|
|
},
|
|
"./conversation": {
|
|
"types": "./dist/components/conversation/index.d.ts",
|
|
"import": "./dist/components/conversation/index.js",
|
|
"require": "./dist/components/conversation/index.cjs"
|
|
},
|
|
"./files": {
|
|
"types": "./dist/components/files/index.d.ts",
|
|
"import": "./dist/components/files/index.js",
|
|
"require": "./dist/components/files/index.cjs"
|
|
},
|
|
"./settings": {
|
|
"types": "./dist/components/settings/index.d.ts",
|
|
"import": "./dist/components/settings/index.js",
|
|
"require": "./dist/components/settings/index.cjs"
|
|
},
|
|
"./sidebar": {
|
|
"types": "./dist/components/sidebar/index.d.ts",
|
|
"import": "./dist/components/sidebar/index.js",
|
|
"require": "./dist/components/sidebar/index.cjs"
|
|
},
|
|
"./terminal": {
|
|
"types": "./dist/components/terminal/index.d.ts",
|
|
"import": "./dist/components/terminal/index.js",
|
|
"require": "./dist/components/terminal/index.cjs"
|
|
},
|
|
"./i18n": {
|
|
"types": "./dist/i18n/index.d.ts",
|
|
"import": "./dist/i18n/index.js",
|
|
"require": "./dist/i18n/index.cjs"
|
|
},
|
|
"./package.json": "./package.json"
|
|
},
|
|
"peerDependencies": {
|
|
"react": "19.2.5",
|
|
"react-dom": "19.2.5",
|
|
"react-router": "7.14.2"
|
|
}
|
|
}
|