Skip to content
Closed
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
bcea35f
feat: implement skills management system with UI and backend integration
Jan 8, 2026
586c50b
feat: implement skills management system with UI and backend integration
Jan 8, 2026
c50217c
feat: add file selection functionality and enhance skill presenter tests
Jan 9, 2026
d9bef6e
feat: document additional issues and recommendations from skills syst…
Jan 9, 2026
bf7f2e7
chore: Merge branch 'dev' into feat/skills
zerob13 Jan 9, 2026
dad5418
feat(skills): Refactor skill metadata prompt building and enhance ski…
Jan 9, 2026
9bcc1ce
fix(skills): Merge branch 'feat/skills' of github.os:ThinkInAIXYZ/dee…
Jan 9, 2026
e03fd04
feat(skills): Add unit tests for security and tool scanning modules
Jan 9, 2026
ee4e72e
feat(agent): gate filesystem writes
zerob13 Jan 9, 2026
0c2cc34
chore(i18n): add skill sync strings
zerob13 Jan 9, 2026
f01a8b0
chore: update i18n
zerob13 Jan 9, 2026
ae603e3
feat(skills): add format adapters for Codex, Copilot User, Goose, Kil…
Jan 10, 2026
5683b52
fix(claudeCodeAdapter): specify types for id and name properties
Jan 10, 2026
bb7f2f1
feat(skills): Update localization files to replace "مهارت‌ها", "Compé…
Jan 11, 2026
425ecdd
feat: add skills panel component and related functionality
Jan 11, 2026
be05e51
feat: enhance mention handling to support slash mentions and improve …
Jan 11, 2026
96e0c94
chore: add i18n translate
zerob13 Jan 12, 2026
31fc271
feat(skills): finish
Jan 13, 2026
cfa3eac
feat: add i18n translate
zerob13 Jan 13, 2026
899dc57
feat: init acp enhance
Jan 13, 2026
eecba09
feat(acp): add model support
Jan 13, 2026
76faecc
feat(acp): merge with dev
Jan 13, 2026
15ea81c
feat(acp): add agent icon
Jan 13, 2026
2c8dab5
feat(acp): enhance warmup process and add workdir change confirmation
Jan 15, 2026
dde9980
chore: Merge branch 'dev' into feat/acp_model_enhance
zerob13 Jan 15, 2026
55732a2
chore: i18n update
zerob13 Jan 15, 2026
961d762
feat(acp): add OpenCode as builtin agent with icon support
Jan 15, 2026
689e48b
feat(acp): add gemini-cli as builtin agent
Jan 15, 2026
eb86fa9
feat(acp): add gemini cli
Jan 16, 2026
2e35285
feat(acp): add qwen code acp
Jan 16, 2026
dc82455
feat: update webcontents refactor specs
Jan 16, 2026
0dad490
feat(chatwindow): refactor
Jan 17, 2026
dbee385
feat(render): refactor save
Jan 19, 2026
cb06a07
refactor(renderer): extract chat composables and add adapters
Jan 19, 2026
b6f2e60
refactor(renderer): finalize domain refactors
Jan 20, 2026
139f6ff
feat(acp): merge with dev
Jan 20, 2026
d2cddb4
refactor: improve title generation flow and add i18n support for sett…
zerob13 Jan 20, 2026
ab9a7c0
refactor(model): simplify model selection with provider initializatio…
zerob13 Jan 20, 2026
fba8907
chore: Merge branch 'dev' into feat/acp_model_enhance
zerob13 Jan 21, 2026
c10d559
refactor(renderer): align stores with adapters
Jan 21, 2026
4f01be6
fix: use chatStore config for new thread model selection
zerob13 Jan 21, 2026
94b6e80
fix: format
zerob13 Jan 21, 2026
752ed86
refactor: replace deprecated openOrFocusSettingsTab with openOrFocusS…
zerob13 Jan 21, 2026
c615827
fix: correct translations in multiple language files
zerob13 Jan 21, 2026
ba2d71e
feat(renderer): composable summary
Jan 22, 2026
05275c9
fix(renderer): merge
Jan 22, 2026
58c0265
refactor(main): remove local search stack
zerob13 Jan 22, 2026
4ec4d2a
feat(splash): redesign splash window with compact progress UI
zerob13 Jan 23, 2026
3e561ae
docs: add spec for model config
zerob13 Jan 23, 2026
bcca898
feat: add chat config
zerob13 Jan 23, 2026
27bafca
fix(chat-input): restore prompts and tools in @ mention trigger
zerob13 Jan 23, 2026
7cd9a0b
feat(ui): hide model settings panel by default
zerob13 Jan 23, 2026
5963c68
feat(ui): rename more settings button
zerob13 Jan 23, 2026
55955f6
style(ui): reduce right panel bottom padding
zerob13 Jan 23, 2026
8fb821c
fix(chat-input): update model selector
zerob13 Jan 23, 2026
1a6a367
feat(acp): enhance model suppor
zerob13 Jan 23, 2026
27f8429
refactor(render): clean up unused code
Jan 25, 2026
f7798c9
feat(acp): clean up acp from agent
Jan 25, 2026
f8edd0b
feat(acp): clean up chatmode
Jan 25, 2026
6025b2a
feat(agent): add agentic presenter
Jan 25, 2026
2b863d1
feat(agentic): complete main presenter refactor
Jan 25, 2026
d66a383
feat(agentic): done research
Jan 25, 2026
0c753db
feat(agentic): render integration
Jan 26, 2026
04f3798
feat(agentic): keep skills
Jan 26, 2026
283ab21
fix(chat-input): restore model selection
zerob13 Jan 28, 2026
976be52
chore: Merge branch 'dev' into feat/acp_model_enhance
zerob13 Jan 28, 2026
527ac7c
docs: add question tool spec
zerob13 Jan 28, 2026
fc0143c
chore(merge): merge upstream
zerob13 Feb 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions docs/specs/acp-mode-defaults/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# ACP Mode Defaults and Session Settings - Plan

## Architecture Changes

- Main process
- Track ACP session models in `AcpProcessHandle` and `AcpSessionRecord`.
- Extend ACP provider + session manager to read/write session model and expose session models over IPC.
- Emit a new renderer event when ACP session models are ready.
- Renderer
- Update mode selector to show Agent + ACP agents only.
- Add ACP session settings UI (model + permission mode) for Claude Code and Codex.
- Add composable to load ACP session models and apply selections.
- Shared types
- Extend presenter interfaces to include ACP session model APIs.
- Add types for ACP session model descriptors.

## Event Flow

1. ACP session created (or warmup session probed).
2. Main process extracts `models.availableModels` + `models.currentModelId`.
3. Main process sends `ACP_WORKSPACE_EVENTS.SESSION_MODELS_READY` with:
- conversationId (if bound), agentId, workdir, current, available.
4. Renderer composable updates the ACP session model selector.

## Data Model Updates

- `AcpProcessHandle`
- `availableModels?: Array<{ id; name; description? }>`
- `currentModelId?: string`
- `AcpSessionRecord`
- `availableModels?: Array<{ id; name; description? }>`
- `currentModelId?: string`

## UI/UX Plan

- Mode switcher:
- Show Agent row.
- Show ACP Agent list (each ACP agent entry is selectable).
- Selecting an ACP agent sets mode to `acp agent` and model to that agent.
- Chat settings popover (ChatConfig):
- When providerId is `acp` and modelId is `claude-code-acp` or `codex-acp`,
render ACP session settings section.
- Session Model: select from ACP session models.
- Permission Mode: select from ACP session modes.

## Compatibility & Migration

- Default MCP enabled for new installs only; existing stored setting is respected.
- Stored chatMode `chat` is migrated to `agent` during mode load.

## Test Strategy

- Manual:
- Fresh install: MCP enabled, default mode Agent.
- Mode switcher shows Agent + ACP agents only.
- Selecting ACP agent switches model without using model selector.
- Claude Code/Codex: session model + permission mode selectors populate after session starts.
- Selecting session model/mode updates ACP session.

46 changes: 46 additions & 0 deletions docs/specs/acp-mode-defaults/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# ACP Mode Defaults and Session Settings - Specification

> Version: 1.0
> Date: 2025-03-01
> Status: Draft

## Overview

Improve the default chat experience by enabling MCP by default, simplifying mode selection to Agent and ACP Agent, and adding ACP session settings for Claude Code and Codex.

## Goals

- Enable MCP by default for new installs.
- Default chat mode to Agent and only expose Agent + ACP Agent in the UI.
- When switching to ACP Agent, let users pick an ACP agent directly (no extra model selector step).
- In ACP Agent mode for Claude Code and Codex, expose session-level settings (model and permission mode).

## User Stories

- As a user, MCP should be on by default so I can use tools immediately.
- As a user, I should only see Agent and ACP Agent modes and default to Agent.
- As a user, switching to ACP Agent should immediately select an ACP agent without opening the model selector.
- As a user, when using Claude Code or Codex in ACP Agent mode, I can choose the session model and permission mode.

## Acceptance Criteria

- MCP is enabled by default for new installs.
- The mode switcher lists only Agent and ACP Agent entries; chat mode is not selectable.
- ACP Agent mode selection provides a direct list of available ACP agents; selecting one sets both mode and model.
- If a saved chat mode is `chat`, it is migrated to `agent` on load.
- For ACP Agent sessions using `claude-code-acp` or `codex-acp`, the settings panel shows:
- Session model selector (from ACP session models).
- Permission mode selector (from ACP session modes).
- Session model/mode selections apply to the active ACP session and update when the agent reports new options.

## Non-Goals

- Adding new ACP agent types or changing ACP agent definitions.
- Persisting ACP session model selections across app restarts.
- Redesigning the model selector beyond ACP Agent selection flow.

## Assumptions

- ACP agents expose session modes and session models through ACP `newSession`.
- Claude Code and Codex provide meaningful session modes for permission presets.

11 changes: 11 additions & 0 deletions docs/specs/acp-mode-defaults/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# ACP Mode Defaults and Session Settings - Tasks

1. Enable MCP by default in main + renderer default config.
2. Update chat mode defaults and fallbacks to Agent; remove Chat from mode selector.
3. Update mode selector to list ACP agents and auto-select model on ACP Agent selection.
4. Extend ACP process/session tracking to include session models; add model-ready event.
5. Expose ACP session model APIs via presenters and shared types.
6. Add renderer composable for ACP session models and extend ACP mode selection to direct set.
7. Add ACP session settings UI in ChatConfig for Claude Code/Codex.
8. Update i18n entries for new ACP session settings labels.

3 changes: 2 additions & 1 deletion src/main/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ export const WORKSPACE_EVENTS = {

// ACP-specific workspace events
export const ACP_WORKSPACE_EVENTS = {
SESSION_MODES_READY: 'acp-workspace:session-modes-ready' // Session modes available
SESSION_MODES_READY: 'acp-workspace:session-modes-ready', // Session modes available
SESSION_MODELS_READY: 'acp-workspace:session-models-ready' // Session models available
}

export const ACP_DEBUG_EVENTS = {
Expand Down
103 changes: 102 additions & 1 deletion src/main/presenter/agentPresenter/acp/acpProcessManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export interface AcpProcessHandle extends AgentProcessHandle {
boundConversationId?: string
/** The working directory this process was spawned with */
workdir: string
availableModels?: Array<{ id: string; name: string; description?: string }>
currentModelId?: string
availableModes?: Array<{ id: string; name: string; description: string }>
currentModeId?: string
mcpCapabilities?: schema.McpCapabilities
Expand Down Expand Up @@ -83,6 +85,7 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
private readonly fsHandlers = new Map<string, AcpFsHandler>()
private readonly agentLocks = new Map<string, Promise<void>>()
private readonly preferredModes = new Map<string, string>()
private readonly preferredModels = new Map<string, string>()
private shuttingDown = false

constructor(options: AcpProcessManagerOptions) {
Expand Down Expand Up @@ -183,6 +186,7 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
const resolvedWorkdir = this.resolveWorkdir(workdir)
const warmupKey = this.getWarmupKey(agent.id, resolvedWorkdir)
const preferredModeId = this.preferredModes.get(warmupKey)
const preferredModelId = this.preferredModels.get(warmupKey)
const releaseLock = await this.acquireAgentLock(agent.id)

try {
Expand All @@ -198,6 +202,7 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
`[ACP] Reusing warmup process for agent ${agent.id} (pid=${reusable.pid}, workdir=${resolvedWorkdir})`
)
this.applyPreferredMode(reusable, preferredModeId)
this.applyPreferredModel(reusable, preferredModelId)
return reusable
}

Expand All @@ -213,6 +218,7 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
`[ACP] Awaiting inflight warmup for agent ${agent.id} (pid=${inflightHandle.pid}, workdir=${resolvedWorkdir})`
)
this.applyPreferredMode(inflightHandle, preferredModeId)
this.applyPreferredModel(inflightHandle, preferredModelId)
return inflightHandle
}
if (inflightHandle.state === 'warmup') {
Expand Down Expand Up @@ -240,6 +246,7 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
console.warn(`[ACP] Failed to fetch modes during warmup for agent ${agent.id}:`, error)
})
this.applyPreferredMode(handle, preferredModeId)
this.applyPreferredModel(handle, preferredModelId)
console.info(
`[ACP] Warmup process ready for agent ${agent.id} (pid=${handle.pid}, workdir=${resolvedWorkdir})`
)
Expand Down Expand Up @@ -269,6 +276,23 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
}
}

/**
* Update preferred model for future warmup processes and sessions.
* The model will be applied when a warmup process is created or when a session is created.
*/
async setPreferredModel(agent: AcpAgentConfig, workdir: string, modelId: string): Promise<void> {
const resolvedWorkdir = this.resolveWorkdir(workdir)
const warmupKey = this.getWarmupKey(agent.id, resolvedWorkdir)
this.preferredModels.set(warmupKey, modelId)

// Apply to existing warmup handle if available
const existingWarmup = this.findReusableHandle(agent.id, resolvedWorkdir)
if (existingWarmup && this.isHandleAlive(existingWarmup)) {
existingWarmup.currentModelId = modelId
this.notifyModelsReady(existingWarmup)
}
}

getProcess(agentId: string): AcpProcessHandle | null {
const warmupHandle = Array.from(this.handles.values()).find(
(handle) => handle.agentId === agentId
Expand Down Expand Up @@ -382,6 +406,7 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,

// Immediately notify renderer if modes are already known
this.notifyModesReady(handle, conversationId)
this.notifyModelsReady(handle, conversationId)
console.info(
`[ACP] Bound process for agent ${agentId} to conversation ${conversationId} (pid=${handle.pid}, workdir=${handle.workdir})`
)
Expand Down Expand Up @@ -421,6 +446,28 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
}
}

getProcessModels(
agentId: string,
workdir?: string
):
| {
availableModels?: Array<{ id: string; name: string; description?: string }>
currentModelId?: string
}
| undefined {
const resolvedWorkdir = this.resolveWorkdir(workdir)
const candidates = this.getHandlesByAgent(agentId).filter(
(handle) => handle.workdir === resolvedWorkdir && this.isHandleAlive(handle)
)
const handle = candidates[0]
if (!handle) return undefined

return {
availableModels: handle.availableModels,
currentModelId: handle.currentModelId
}
}

registerSessionListener(
agentId: string,
sessionId: string,
Expand Down Expand Up @@ -518,7 +565,7 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
const resultData = initResult as unknown as {
sessionId?: string
models?: {
availableModels?: Array<{ modelId: string }>
availableModels?: Array<{ modelId: string; name?: string; description?: string }>
currentModelId?: string
}
modes?: {
Expand All @@ -542,6 +589,18 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
console.info(`[ACP] Available models: ${resultData.models.availableModels?.length ?? 0}`)
console.info(`[ACP] Current model: ${resultData.models.currentModelId}`)
}
const initAvailableModels = resultData.models?.availableModels?.map(
(m: { modelId: string; name?: string; description?: string }) => ({
id: m.modelId,
name: m.name ?? m.modelId,
description: m.description ?? ''
})
)
if (initAvailableModels) {
console.info(
`[ACP] Available models: ${JSON.stringify(initAvailableModels.map((m) => m.id) ?? [])}`
)
}
const initAvailableModes = resultData.modes?.availableModes?.map(
(m: { id: string; name?: string; description?: string }) => ({
id: m.id,
Expand All @@ -555,6 +614,8 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
)
console.info(`[ACP] Current mode: ${resultData.modes?.currentModeId}`)
}
handleSeed.availableModels = initAvailableModels
handleSeed.currentModelId = resultData.models?.currentModelId
handleSeed.availableModes = initAvailableModes
handleSeed.currentModeId = resultData.modes?.currentModeId
} catch (error) {
Expand Down Expand Up @@ -588,6 +649,8 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
state: 'warmup',
boundConversationId: undefined,
workdir,
availableModels: handleSeed.availableModels,
currentModelId: handleSeed.currentModelId,
availableModes: handleSeed.availableModes,
currentModeId: handleSeed.currentModeId,
mcpCapabilities: handleSeed.mcpCapabilities
Expand Down Expand Up @@ -940,6 +1003,26 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
this.registerSessionWorkdir(response.sessionId, handle.workdir)
}

const models = response.models
if (models?.availableModels?.length) {
handle.availableModels = models.availableModels.map((model) => ({
id: model.modelId,
name: model.name ?? model.modelId,
description: model.description ?? ''
}))
if (
handle.currentModelId &&
handle.availableModels.some((m) => m.id === handle.currentModelId)
) {
// keep preferred
} else if (models.currentModelId) {
handle.currentModelId = models.currentModelId
} else {
handle.currentModelId = handle.availableModels[0]?.id ?? handle.currentModelId
}
this.notifyModelsReady(handle)
}

const modes = response.modes
if (modes?.availableModes?.length) {
handle.availableModes = modes.availableModes.map((mode) => ({
Expand Down Expand Up @@ -989,6 +1072,18 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
})
}

private notifyModelsReady(handle: AcpProcessHandle, conversationId?: string): void {
if (!handle.availableModels || handle.availableModels.length === 0) return

eventBus.sendToRenderer(ACP_WORKSPACE_EVENTS.SESSION_MODELS_READY, SendTarget.ALL_WINDOWS, {
conversationId: conversationId ?? handle.boundConversationId,
agentId: handle.agentId,
workdir: handle.workdir,
current: handle.currentModelId ?? '',
available: handle.availableModels
})
}

private getHandlesByAgent(agentId: string): AcpProcessHandle[] {
const handles: AcpProcessHandle[] = []
for (const handle of this.handles.values()) {
Expand Down Expand Up @@ -1044,6 +1139,12 @@ export class AcpProcessManager implements AgentProcessManager<AcpProcessHandle,
this.notifyModesReady(handle)
}

private applyPreferredModel(handle: AcpProcessHandle, preferredModelId?: string): void {
if (!preferredModelId) return
handle.currentModelId = preferredModelId
this.notifyModelsReady(handle)
}

private clearSessionsForAgent(agentId: string): void {
for (const [sessionId, entry] of this.sessionListeners.entries()) {
if (entry.agentId === agentId) {
Expand Down
Loading
Loading