Skip to content

Commit fe206d3

Browse files
zerob13zhangmo8wangle201210KirinJin2046
authored
release: 0.5.7 (#1300)
* chore: typecheck with tsgo (#1278) * feat: image left align * feat: app settings skills (#1283) * docs: add spec for app-settings * feat: implement chat-driven settings control with skill gating Add a safe, validated API for modifying DeepChat application settings via natural language. Settings changes are controlled by a dedicated 'deepchat-settings' skill to ensure tools are only available when contextually relevant. Key features: - Skill-gated tool injection: settings tools only appear when deepchat-settings skill is active - Safe settings apply API with Zod validation and strict allowlist - Support for toggles (sound, copy COT, chat mode) and enums (language, theme, font size) - Defense-in-depth: runtime skill verification before applying changes - Deep-linked settings navigation for unsupported/complex settings - Comprehensive test coverage for validation, mapping, and skill gating Changes: - Add ChatSettingsToolHandler with validated apply/open methods - Integrate with AgentToolManager for tool definition gating - Create deepchat-settings built-in skill with clear activation rules - Add shared types for requests/responses (chatSettings.ts) - Implement settings window navigation with SECTION_ALIASES - Add unit tests for handler and integration tests for tool gating - Translate spec documents (plan.md, spec.md, tasks.md) to Chinese - Fix type errors in getCurrentValue and OPEN_SECTION_VALUES * refactor: remove chatMode from settings control and add permission service Remove chatMode setting from the allowlist as it requires conversation-scoped updates that are better handled separately. Add permission checking for settings window opening to provide user control over settings navigation. Key changes: - Remove setChatMode tool and related schemas from ChatSettingsToolHandler - Add SettingsPermissionService for managing tool approvals (one-time and session) - Add permission check for deepchat_settings_open tool - Update PermissionHandler to handle settings permission grants - Add rememberable flag to permission request structure - Update AgentToolManager to consume approvals before opening settings - Add settingsPermissionService to main presenter index - Clear settings approvals when conversation ends - Update spec documents to reflect removed chatMode feature - Remove chatMode-related tests and types This ensures settings window opening requires explicit user approval and provides a cleaner separation of concerns for chat mode management. * docs: translate to en * chore: yo browser less context (#1284) * docs: add specs for yo browesr context manager * feat(yo-browser): improve skill description and add yo_browser_cdp_send to offload whitelist * refactor(yobrowser): remove skill gating and make CDP tools always available in agent mode * refactor(yobrowser): add CDP method schema validation with strict enums - Add enum-based validation for cdp_send method (11 common CDP methods) - Add detailed union schemas for each method's parameters with examples - Add normalizeCdpParams method to handle both object and JSON string inputs - Prevent method typos and provide better type safety for CDP interactions * fix(yobrowser): add strict tab ID validation in CDP send handler * chore: update deps * refactor: agent provider simplification (#1286) * docs: add spec for agent provider * refactor(agent): remove BaseAgentProvider layer and simplify provider hierarchy * feat(mcp): implement real Apple Maps search using URL scheme (#1289) * feat: support voice.ai (#1291) * feat: remove custome tiptap (#1295) * feat: settings auto scroll toggle (#1293) * feat: settings auto scroll toggle * feat: i18n support * fix(renderer): remove specific event listeners instead of all * feat: add tooltip for filling default API URL in settings (#1296) * fix: fix model list refresh failed (#1297) * feat: add question tools (#1298) * feat(agent): add question tool flow * feat(mcp): implement real Apple Maps search using URL scheme (#1289) * feat: support voice.ai (#1291) * feat: remove custome tiptap (#1295) * feat: settings auto scroll toggle (#1293) * feat: settings auto scroll toggle * feat: i18n support * fix(renderer): remove specific event listeners instead of all * feat: add tooltip for filling default API URL in settings (#1296) * refactor(question): simplify question request UI to single-choice interface * fix(chat): restore pending question state * fix: review issues --------- Co-authored-by: Qi Jin <jin.qi1@northeastern.edu> Co-authored-by: xiaomo <wegi866@gmail.com> * chore: integrated vue-tsgo (#1299) * chore: integrated vue-tsgo * chore: update recommendation exteion * chore: update * feat: add prompt for ask tool * chore: version to 0.5.7 --------- Co-authored-by: xiaomo <wegi866@gmail.com> Co-authored-by: wanna <wanna.w@binarywalk.com> Co-authored-by: Qi Jin <jin.qi1@northeastern.edu>
2 parents 48e068c + 85665d7 commit fe206d3

160 files changed

Lines changed: 5583 additions & 1737 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.vscode/extensions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"recommendations": ["dbaeumer.vscode-eslint", "lokalise.i18n-ally", "esbenp.prettier-vscode"]
2+
"recommendations": ["dbaeumer.vscode-eslint", "lokalise.i18n-ally", "esbenp.prettier-vscode", "TypeScriptTeam.native-preview"]
33
}

.vscode/settings.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@
55
"i18n-ally.keystyle": "nested",
66
"i18n-ally.sourceLanguage": "zh-CN",
77
"i18n-ally.namespace": true,
8-
"i18n-ally.pathMatcher": "{locale}/{namespaces}.json"
8+
"i18n-ally.pathMatcher": "{locale}/{namespaces}.json",
9+
"unocss.disable": true,
10+
"typescript.experimental.useTsgo": true
911
}

docs/architecture/tool-system.md

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ graph TB
2929
3030
AgentToolMgr[AgentToolManager]
3131
FsHandler[AgentFileSystemHandler]
32-
Browser[Yo Browser Tools]
32+
YoBrowser[Yo Browser CDP]
3333
end
3434
3535
subgraph "外部服务"
@@ -48,10 +48,10 @@ graph TB
4848
McpClient --> MCPServers
4949
5050
AgentToolMgr --> FsHandler
51-
AgentToolMgr --> Browser
51+
AgentToolMgr --> YoBrowser
5252
5353
FsHandler --> Files
54-
Browser --> Web
54+
YoBrowser --> Web
5555
5656
classDef router fill:#e3f2fd
5757
classDef mcp fill:#fff3e0
@@ -60,7 +60,7 @@ graph TB
6060
6161
class ToolP,Mapper router
6262
class McpP,ServerMgr,ToolMgr,McpClient mcp
63-
class AgentToolMgr,FsHandler,Browser agent
63+
class AgentToolMgr,FsHandler,YoBrowser agent
6464
class MCPServers,Files,Web external
6565
```
6666

@@ -622,23 +622,20 @@ class AgentFileSystemHandler {
622622
3. **边界检查**:防止 `../` 越界访问
623623
4. **正则验证**`grep_search``text_replace` 使用 `validateRegexPattern` 防 ReDoS
624624

625-
### Browser 工具
625+
### YoBrowser CDP 工具
626626

627-
```typescript
628-
// 通过 Yo Browser Presenter 调用
629-
async callBrowserTool(toolName: string, args: any): Promise<string> {
630-
switch (toolName) {
631-
case 'browser_navigate':
632-
return await this.yoBrowserPresenter.navigate(args.url)
633-
case 'browser_scrape':
634-
return await this.yoBrowserPresenter.scrape(args.url)
635-
case 'browser_screenshot':
636-
return await this.yoBrowserPresenter.screenshot(args.url)
637-
default:
638-
throw new Error(`未知的 Browser 工具: ${toolName}`)
639-
}
640-
}
641-
```
627+
YoBrowser 提供基于 Chrome DevTools Protocol (CDP) 的最小工具集,在 agent 模式下直接可用。
628+
629+
**可用工具**
630+
- `yo_browser_tab_list` - 列出所有浏览器 tabs
631+
- `yo_browser_tab_new` - 创建新 tab
632+
- `yo_browser_tab_activate` - 激活指定 tab
633+
- `yo_browser_tab_close` - 关闭 tab
634+
- `yo_browser_cdp_send` - 发送 CDP 命令
635+
636+
**安全约束**
637+
- `local://` URL 禁止 CDP attach(在 `BrowserTab.ensureSession()` 中检查)
638+
- 所有 CDP 命令通过 `webContents.debugger.sendCommand()` 执行
642639

643640
## 🔐 权限系统
644641

docs/archives/workspace-agent-refactoring-summary.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ graph TB
196196

197197
- MCP 工具:保持原始命名
198198
- Agent FileSystem 工具:不加前缀(`read_file` 等)
199-
- Yo Browser:保留 `browser_` 前缀
199+
- Yo Browser:使用 `yo_browser_` 前缀
200200

201201
### 工具路由机制
202202

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Plan: Agent Provider Simplification (ACP-only)
2+
3+
## Summary
4+
5+
Replace the “agent provider” abstraction and detection logic with a single explicit rule: **ACP is the only agent provider and is identified by `providerId === 'acp'`.**
6+
7+
## Current Call Flow (relevant parts)
8+
9+
- Main:
10+
- `ProviderInstanceManager.createProviderInstance()` already special-cases `provider.id === 'acp'`.
11+
- `ProviderInstanceManager.isAgentProvider()` uses `instanceof BaseAgentProvider` and (if instance not created) a constructor prototype check (`isAgentConstructor`).
12+
- `LLMProviderPresenter.isAgentProvider()` exposes this to the renderer via `ILlmProviderPresenter`.
13+
- Renderer:
14+
- `src/renderer/src/stores/modelStore.ts` calls `llmproviderPresenter.isAgentProvider(providerId)` over IPC to choose between:
15+
- `agentModelStore.refreshAgentModels(providerId)` (ACP path)
16+
- `refreshStandardModels + refreshCustomModels` (standard path)
17+
- Other renderer logic already treats ACP as special via `provider.id === 'acp'`.
18+
19+
## Proposed Changes
20+
21+
### 1) Remove agent-provider classification API
22+
23+
- Remove `isAgentProvider(providerId: string)` from:
24+
- `src/shared/types/presenters/llmprovider.presenter.d.ts`
25+
- `src/shared/types/presenters/legacy.presenters.d.ts`
26+
- `src/main/presenter/llmProviderPresenter/index.ts`
27+
- `src/main/presenter/llmProviderPresenter/managers/providerInstanceManager.ts`
28+
29+
Rationale: It is only used by the renderer for ACP gating, and ACP can be identified locally by ID.
30+
31+
### 2) Replace renderer gating with an explicit ACP check
32+
33+
- In `src/renderer/src/stores/modelStore.ts`:
34+
- Remove the async IPC call `llmP.isAgentProvider(providerId)`.
35+
- Replace with a local predicate: `providerId === 'acp'`.
36+
- Keep the existing ACP refresh path using `agentModelStore.refreshAgentModels('acp')` (no behavioral change).
37+
38+
### 3) Remove `BaseAgentProvider` (optional but preferred)
39+
40+
Because `BaseAgentProvider` is only used by `AcpProvider`, delete the base class and:
41+
42+
- Make `AcpProvider` extend `BaseLLMProvider` directly.
43+
- Move `cleanup()` logic into `AcpProvider` (or delegate to `AcpSessionManager` / `AcpProcessManager`).
44+
- Ensure `cleanup()` is safe to call multiple times and during shutdown.
45+
46+
Notes:
47+
- `acpCleanupHook` currently awaits `cleanup()` even though `BaseAgentProvider.cleanup()` is `void`. Consider standardizing ACP cleanup to `Promise<void>` to match usage.
48+
49+
## Compatibility / Migration
50+
51+
- No user data migration.
52+
- Provider ID `acp` remains unchanged and is treated as a stable internal contract.
53+
- Any internal IPC typing generation must be updated to reflect removal of `isAgentProvider`.
54+
55+
## Test Strategy
56+
57+
Add minimal tests focusing on the only behavioral dependency (renderer model refresh selection):
58+
59+
- Renderer unit test for `modelStore.refreshProviderModels()`:
60+
- When `providerId === 'acp'`, it uses `agentModelStore.refreshAgentModels`.
61+
- When `providerId !== 'acp'`, it uses standard refresh path.
62+
63+
Main-process unit tests are optional; the change is mostly removal and ACP-id checks.
64+
65+
## Rollout
66+
67+
Single PR is acceptable if changes stay localized (types + modelStore + ACP provider base class cleanup).
68+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Agent Provider Simplification (ACP-only)
2+
3+
## Background
4+
5+
DeepChat currently distinguishes between:
6+
7+
- **LLM providers**: network-backed providers that implement `BaseLLMProvider` (OpenAI/Anthropic/etc).
8+
- **Agent providers**: providers that manage local agent sessions/processes (currently only `acp` via `AcpProvider`).
9+
10+
The codebase implements this distinction via a dedicated base class (`BaseAgentProvider`) and a runtime/type-detection API (`isAgentProvider`), which is then consumed from the renderer via IPC.
11+
12+
## Problem
13+
14+
- `BaseAgentProvider` is only used by `AcpProvider`, so the abstraction adds indirection without real reuse.
15+
- Provider type detection is over-engineered (`isAgentConstructor` + prototype checks) and duplicates existing ACP-specific branching.
16+
- The renderer calls `llmproviderPresenter.isAgentProvider(providerId)` over IPC, but the only “agent provider” is `providerId === 'acp'`. This creates unnecessary main↔renderer coupling and call complexity.
17+
18+
## Goals
19+
20+
- Treat **ACP as the only agent provider** and identify it **only by `providerId === 'acp'`**.
21+
- Remove the generic “agent provider type detection” path and the renderer IPC dependency for this decision.
22+
- Keep user-visible behavior unchanged:
23+
- ACP agents still appear as selectable models when ACP is enabled.
24+
- Non-ACP providers keep the standard model/custom-model refresh behavior.
25+
- Shutdown and provider disable still clean up ACP resources.
26+
27+
## Non-goals
28+
29+
- Supporting multiple agent providers beyond ACP.
30+
- Redesigning ACP model derivation (agents-as-models) or session/workspace semantics.
31+
- Changing persisted provider IDs or stored settings schemas.
32+
33+
## Acceptance Criteria
34+
35+
- Renderer no longer calls `llmproviderPresenter.isAgentProvider(...)`; ACP decision is local (`providerId === 'acp'`).
36+
- Main process no longer needs `isAgentConstructor` / prototype-based provider classification.
37+
- No remaining runtime dependency on `BaseAgentProvider` for correctness (ACP cleanup remains correct).
38+
- `pnpm run typecheck`, `pnpm test`, `pnpm run lint` pass.
39+
40+
## Open Questions
41+
42+
- None.
43+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Tasks: Agent Provider Simplification (ACP-only)
2+
3+
1. Update renderer to stop using IPC for agent-provider detection
4+
- Remove `llmproviderPresenter.isAgentProvider` usage from `src/renderer/src/stores/modelStore.ts`.
5+
- Gate ACP behavior by `providerId === 'acp'`.
6+
7+
2. Remove `isAgentProvider` from the presenter contract
8+
- Remove from `src/shared/types/presenters/llmprovider.presenter.d.ts`.
9+
- Remove from `src/shared/types/presenters/legacy.presenters.d.ts`.
10+
- Remove implementation from `src/main/presenter/llmProviderPresenter/index.ts`.
11+
12+
3. Remove main-side agent-provider classification implementation
13+
- Delete `ProviderInstanceManager.isAgentProvider()` and `isAgentConstructor()` in `src/main/presenter/llmProviderPresenter/managers/providerInstanceManager.ts`.
14+
- Ensure no other code path depends on `BaseAgentProvider` type checks.
15+
16+
4. Remove `BaseAgentProvider` abstraction (preferred)
17+
- Delete `src/main/presenter/llmProviderPresenter/baseAgentProvider.ts`.
18+
- Update `src/main/presenter/llmProviderPresenter/providers/acpProvider.ts` to extend `BaseLLMProvider` directly.
19+
- Keep/adjust ACP cleanup semantics (safe shutdown, provider disable, app quit).
20+
21+
5. Add/adjust tests
22+
- Add a Vitest suite under `test/renderer/**` validating model refresh selection for ACP vs non-ACP.
23+
24+
6. Quality gates
25+
- Run `pnpm run format`, `pnpm run lint`, `pnpm run typecheck`, and `pnpm test`.
26+
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Plan: Control Settings via Chat
2+
3+
## Key Decision: Skill-Based Context Control
4+
5+
This feature MUST be described and delivered as a DeepChat skill so that additional instructions/context are only injected when the user actually requests to change DeepChat settings.
6+
7+
- Skill Name (suggested): `deepchat-settings`
8+
- Activation: Activated via `skill_control` **ONLY** when the user request involves DeepChat settings/preferences.
9+
- Deactivation: Call `skill_control` after completing the setting change to keep context lean.
10+
11+
## Tool Injection Control (No Skill, No Tools)
12+
13+
Configuration-related tools MUST NOT appear in the LLM tool list (and MUST NOT be mentioned in the system prompt) unless the `deepchat-settings` skill is active.
14+
15+
Implementation intent:
16+
17+
- Define dedicated tools (MCP-format function definitions):
18+
- `deepchat_settings_toggle`
19+
- `deepchat_settings_set_language`
20+
- `deepchat_settings_set_theme`
21+
- `deepchat_settings_set_font_size`
22+
- `deepchat_settings_open`
23+
- **DO NOT** expose them through MCP server/tool list UI (avoid being auto-enabled into `enabledMcpTools`).
24+
- Only inject these tool definitions when:
25+
- `deepchat-settings` is enabled for the current conversation, AND
26+
- The skill's pre-metadata `allowedTools` includes the tool name.
27+
28+
This requires conversation-scoped tool definition construction:
29+
30+
- Extend tool definition construction context to include `conversationId`.
31+
- Retrieve `skillsAllowedTools` for that conversation (via `SkillPresenter.getActiveSkillsAllowedTools`).
32+
- Only conditionally append `deepchat_settings_*` tool definitions when allowed.
33+
34+
## Step 1: Safe Settings Application API (Main Process)
35+
36+
### Entry Point
37+
38+
Implement a narrow, validated application surface in the main process (presenter method or agent tool handler) for:
39+
40+
- Accepting `unknown` input and validating it (Zod-style, similar to `AgentFileSystemHandler`).
41+
- Using an allowlist of setting IDs.
42+
- Applying changes by calling existing `ConfigPresenter` methods so existing event broadcasts remain correct.
43+
- Returning structured results to render confirmation/error messages.
44+
45+
### Allowlisted Settings and Mapping
46+
47+
Toggle settings:
48+
49+
- `soundEnabled` -> `ConfigPresenter.setSoundEnabled(boolean)` (broadcasts: `CONFIG_EVENTS.SOUND_ENABLED_CHANGED`)
50+
- `copyWithCotEnabled` -> `ConfigPresenter.setCopyWithCotEnabled(boolean)` (broadcasts: `CONFIG_EVENTS.COPY_WITH_COT_CHANGED`)
51+
52+
Enum settings:
53+
54+
- `language` -> `ConfigPresenter.setLanguage(locale)` (broadcasts: `CONFIG_EVENTS.LANGUAGE_CHANGED`)
55+
- `theme` -> `ConfigPresenter.setTheme('dark' | 'light' | 'system')` (broadcasts: `CONFIG_EVENTS.THEME_CHANGED`)
56+
- `fontSizeLevel` -> `ConfigPresenter.setSetting('fontSizeLevel', level)` (broadcasts `CONFIG_EVENTS.FONT_SIZE_CHANGED` via special case)
57+
58+
### Validation Rules
59+
60+
- Strict allowlist; reject unknown IDs.
61+
- No implicit type conversion in Step 1.
62+
- Validation per setting:
63+
- Booleans: must be boolean type
64+
- Enum values: must match allowed set
65+
- `fontSizeLevel`: must be integer within supported range (source of truth TBD; may align with `uiSettingsStore` constants)
66+
- `language`: must be one of supported locales (reuse support list from config)
67+
68+
### Defense in Depth: Require Skill Activity
69+
70+
Even with controlled tool injection, maintain runtime checks:
71+
72+
- If `deepchat-settings` is **NOT** enabled for the conversation, reject application and return error telling the model/user to activate it.
73+
- This ensures settings don't accidentally change due to unrelated agent behavior.
74+
75+
## Step 2: Skill Definition (Natural Language Behavior)
76+
77+
### Built-in Skill Artifact
78+
79+
Add `resources/skills/deepchat-settings/SKILL.md`:
80+
81+
- Pre-metadata `description` MUST explicitly state:
82+
- This is ONLY for changing DeepChat application settings.
83+
- Activate ONLY when user requests setting changes (settings/preferences/theme/language/font/sound/copy COT).
84+
- Do NOT activate for OS settings or programming/code settings.
85+
- Body MUST define:
86+
- Supported settings (allowlist) and canonical values.
87+
- How to ask clarifying questions when ambiguous.
88+
- When to refuse and instead open settings.
89+
- Always deactivate after completing setting tasks.
90+
91+
### Disallowed Settings -> Open Settings
92+
93+
For requests involving MCP configuration, prompts, providers, API keys, etc.:
94+
95+
- Do NOT apply via tools.
96+
- Provide precise instructions telling user where to change them.
97+
- Open settings window and navigate to relevant section if possible.
98+
99+
Implementation options for opening/navigating settings:
100+
101+
- Use `presenter.windowPresenter.createSettingsWindow()`.
102+
- Optionally `executeJavaScript` to set localStorage navigation hint that UI can read.
103+
- Or add dedicated IPC channel from main process -> settings renderer to navigate to tab/section.
104+
105+
## Data Model
106+
107+
Introduce shared request/response types (for Step 1 entry point + tools):
108+
109+
- `ChatSettingId` (union of allowlisted IDs)
110+
- `ApplyChatSettingRequest` (discriminated union `{ id, value }`)
111+
- `ApplyChatSettingResult`
112+
- `{ ok: true; id; value; previousValue?; appliedAt }`
113+
- `{ ok: false; errorCode; message; details? }`
114+
115+
## Testing Strategy
116+
117+
- Main process (Vitest):
118+
- Allowlist + validation (reject invalid values, no writes)
119+
- Each supported setting maps to correct `ConfigPresenter` method
120+
- Skill requirement enforcement works (tool rejects when skill inactive)
121+
- Renderer/UI (if any navigation hints added):
122+
- Settings page navigation handler tests (optional)

0 commit comments

Comments
 (0)