Conversation
- Remove mirrored DB Helpers (AgentRow, ProviderRow, MCPServerRow, getAgent, getProvider, getAgentMcpServers, getAgentSkillNames) - Import getAgentRow, getProvider, getAgentMcpServers, getAgentSkillNames, createBuiltInTools, loadRegistryTools, loadMcpTools from shared-infra - Replace inline builtInTools construction with createBuiltInTools(workingDir) - Add loadRegistryTools() to load search tools (tavily/anysearch/arxiv), matching Chat path capability - Remove decryptApiKey import (handled internally by shared-infra) - Remove '// ---- DB Helpers (mirrored from runtime.ts) ----' comment - All 12 tests pass
- Remove duplicate normalizeProviderId, getProvider, getAgentMcpServers, getAgentSkillNames functions - Remove DEFAULT_INTERRUPT_ON constant definition (imported from shared-infra) - Remove inline TOOL_REGISTRY array and loadToolConfig function - Import getProvider, getAgentMcpServers, getAgentSkillNames, normalizeProviderId, DEFAULT_INTERRUPT_ON, createBuiltInTools, loadRegistryTools, loadMcpTools from ./shared-infra - Replace inline builtInTools construction with createBuiltInTools(project.path) - Replace TOOL_REGISTRY loop with loadRegistryTools() call - Remove decryptApiKey, createDeleteFileTool, createTavilyTool, createAnysearchTool, createArxivTool, createBashTool, createFetchTool imports (handled by shared-infra) - All 13 runtime tests pass
# Conflicts: # src/main/deepagent/runtime.ts # src/main/workflow/node-executor.ts
- Add spanId/parentSpanId fields to ExecutionStep in types.ts - Add spanId? to node_start WorkflowStreamEvent type - Implement createSpanId/createChildSpan helpers in node-executor.ts - Generate nodeSpanId at executor entry for each node invocation - Create agentSpan (child of node) for each invokeAgent call - Create toolSpan (child of agentSpan) for each tool_call/tool_result step - Create iterationSpan (child of node) for loop iterations - Create itemSpan (child of node) for foreach items - Inject spanId into node_start events in workflow-runtime.ts
- Add SpanBadge component showing first 4 chars of spanId - Steps with parentSpanId get pl-4 indentation and border-l-2 indicator - SpanBadge appears in thinking, tool_call, tool_result, and system steps - System/task steps with parentSpanId get ml-4 margin for visual nesting - Uses var(--color-border) and var(--color-text-muted) design tokens
Merge worktree-agent-a9006904fe6dff070 (Plan 16-03: span trace + UI hierarchy). Resolved conflicts in types.ts and ExecutionPanel.tsx — kept t() i18n from HEAD, added SpanBadge/indent from worktree, preserved var(--color-bg-sunken) tokens. Fixed deviation: replaced inline createSpanId/createChildSpan in node-executor.ts and workflow-runtime.ts with imports from shared-infra.ts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tion - Restore createRuntimeModel export (P0: llm.ts build break) - Restore createAgentTools for Master Agent CRUD (P1: agent management regression) - Restore parallel node dispatcher/worker logic with span trace (P1: fan-out regression) - Parallel worker prompt includes full taskContext (upstream outputs, routing hints) - Parallel dispatcher prefers worker results over raw items for chained parallel nodes - Fan-out treats concurrencyLimit=0 as MAX_PARALLEL_ITEMS (50), not unlimited - Worker routing not propagated to global state (avoids non-deterministic overwrites) - Worker outputs persisted under original nodeId (aligned with node_start/trace keys) - Ordinary node output shape preserved (result object, not wrapper map) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ExecutionStep 加 goal?/summary? 字段(T1) - parallel-task-tool: task_start 移至 createParallelTaskTool,goal 用 task.description(T2) - ParallelWorker 加 agentName?/goal?,handler 专用 task_start 分支创建 worker(T3) - TaskPanel 并行 worker 卡片:显示 agentName、token 估算替换步骤数(T4) - SubagentView: goal 和 agentName 对两种 worker 类型统一生效(T5) - 修复 ParallelBatchSection 缺少 useTranslation 导致任务面板崩溃 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- runtime.ts: 注册 createParallelTaskTool 到 builtInTools - stream-accumulator.ts: 加 onChunk 回调,支持 thinking/<think> 流式透传 - preload/index.ts: 暴露 onParallelTaskStep IPC 订阅接口 - ChatArea.tsx: viewingParallelWorker 时渲染 SubagentView,隐藏输入栏 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
移除 GSD 占位注释块,加入 gstack 安装说明 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- fetchAgentActivity 新增 parallel_tasks 工具调用重建逻辑 从 call.input(tasks)和 call.output(results)还原 ParallelBatch[] textBuffer = result.output,goal = task.description,status 按 call.status 推断 - parallel-task-tool: 结果对象加 agentName 字段,restore 后显示名不降级为 slug - set() 加 parallelBatches: restoredBatches Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…mary Issue 1 — agentSlug 碰撞: - ParallelTaskStepEvent 加 workerId 字段(per-task UUID) - parallel-task-tool 每个 task 生成独立 workerId,所有 push 携带 - onParallelTaskStep 改用 workerId 做精确查找(findWorker helper) - viewingParallelWorker 类型加 workerId?,ChatArea/TaskPanel 优先用 workerId 匹配 Issue 2 — task_end 结果摘要: - ExecutionStep 加 summary? 字段 - task_end 步骤携带 output.slice(0,300) 作为 summary - task_end handler 将 summary 存入 ParallelWorker - TaskPanel worker 卡片完成后展示 summary/textBuffer 预览(line-clamp-2) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
LangChain streams tool-call arguments via handleLLMNewToken alongside
text tokens. Buffer tokens per-LLM-call and discard on tool-call
responses (detected via additional_kwargs.tool_calls for OpenAI-style
and tool_use content blocks for Anthropic-style), so raw JSON args like
{"file_path":"..."} no longer leak into textBuffer and appear below the
tool cards in the agent detail view.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SubagentView.tsx & ToolMessageCard.tsx — Phase 4 design language upgrades: back button group-hover/active/focus, separator div, ping animation status dot, token chip, goal accent line, expand button hover, failure alert ring, StepTimeline separator, toast backdrop-blur + focus ring; ToolMessageCard icon upgrades and button hover/active/focus states. runtime.ts, llm.ts, sessionStore.ts, types.ts — parallel worker infrastructure: wires parallel task steps into session state, restores parallelBatches on reload, and aligns event routing so the detail view receives tool_call/tool_result/text_chunk steps correctly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ChatArea: switch textIndent → paddingLeft for token overlay so all lines (not just the first) are indented past the prefix tokens - Remove now-unnecessary onScroll translateY handlers (paddingLeft handles multi-line without needing scroll sync) - Expand LeadingToken.source union type to include 'skill:project' and 'skill:global' (matching actual runtime values from command registry) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add imageBase64 field to Message type and ChatPayload. SQLite migration adds image_data column. IPC handlers serialize/deserialize image data. Runtime builds ContentBlock array for multimodal LLM messages.
Add clipboard paste handler with 5-image/5MB limits and toast warnings. Dual thumbnail strip in welcome and composer views. Lightbox via createPortal with Esc/overlay/button dismiss using design tokens. Fix Toaster theme to follow system light/dark preference.
…guard - Restrict handlePaste to safe bitmap types (png/jpeg/webp/gif), blocking SVG data URLs that could execute scripts in Electron renderer - Add window.matchMedia mock for jsdom test environment (Toaster theme) - Guard ParallelBatchSection against undefined batches Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
CDF/src/main/deepagent/runtime.ts
Line 585 in d464170
当用户在 TaskPanel 里选择 “Auto (Bypass)” 时,该值只写入 store,但聊天运行时仍无条件传入 DEFAULT_INTERRUPT_ON,所以 write/edit/delete_agent 等工具仍会触发审批,和界面提示“所有工具调用无需确认”不一致;这里应按存储的 approvalMode 解析 interruptOn。
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -295,32 +251,22 @@ async function buildInputMessages(sessionId: string, currentMessage: RuntimeInpu | |||
| role: message.role, | |||
| content: message.content, | |||
| })), | |||
| ...(hasCurrent ? [] : [{ role: 'user' as const, content: currentMessage.content }]), | |||
| ...(hasCurrent ? [] : [{ role: 'user' as const, content: currentContent }]), | |||
| const effectiveLimit = concurrencyLimit > 0 ? concurrencyLimit : MAX_PARALLEL_ITEMS; | ||
| const limit = Math.min(items.length, effectiveLimit); | ||
| const sends: Send[] = []; | ||
| for (let i = 0; i < limit; i++) { |
Relocate the permission mode control (strict/agent_decides/bypass) from TaskPanel header into both welcome and session composer toolbars. Rearrange toolbar layout: left side has + attachment and approval mode, right side has model selector and send button. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2cae7af902
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const agent = createDeepAgent({ | ||
| model, | ||
| backend, | ||
| systemPrompt: agentRow.system_prompt || undefined, | ||
| skills: skillsSources.length > 0 ? skillsSources : undefined, | ||
| permissions, | ||
| tools: [...mcpRuntime.tools, ...builtInTools], |
There was a problem hiding this comment.
Preserve approval gates for parallel workers
当聊天里的 parallel_tasks worker 被要求执行 write_file/edit_file/delete_file 这类文件操作时,这里创建的是一个新的 DeepAgent,但没有像主聊天 runtime 一样传入 DEFAULT_INTERRUPT_ON。由于 worker 仍然通过 createBuiltInTools(projectPath) 获得高权限工具,strict 审批模式下这些操作会在 worker 内直接执行而不触发用户审批,相当于绕过了已有安全边界。
Useful? React with 👍 / 👎.
| return resolution; | ||
| }; | ||
|
|
||
| const executeNode = createAgentNodeExecutor(node, upstreamNodeIds, approvalMode, onApprovalNeeded); |
There was a problem hiding this comment.
| // parallel 节点的 out-edges:source 替换为 worker node | ||
| if (parallelNodeIds.has(sourceId)) { | ||
| const workerNodeId = `${sourceId}__worker`; | ||
| builder.addEdge(workerNodeId as any, toGraphNode(targetId, 'target') as any); |
There was a problem hiding this comment.
Pass parallel worker outputs to downstream nodes
当 parallel 节点后面接普通 task/review 节点时,这里把图上的出边改接到 parallelId__worker,但目标节点的 upstreamNodeIds 早已按原始 workflow edge 记录为 parallelId。createNodeStateExtractor 只读取 nodeOutputs[parallelId],也就是 dispatcher 的 {items,count},不会收集 parallelId__worker:0 等 worker 结果,所以下游节点会拿原始条目继续执行而不是并行处理后的输出。
Useful? React with 👍 / 👎.
| type="button" | ||
| onClick={() => handleSend()} | ||
| disabled={!inputVal.trim() || isStreaming} | ||
| className="p-2 rounded-lg bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] disabled:bg-[var(--color-bg-hover)] disabled:text-[var(--color-text-muted)] text-white transition-all shadow-md flex items-center justify-center cursor-pointer" | ||
| className="dialog-btn send" |
- TaskPanel 从侧边栏改为 absolute 定位的悬浮弹出面板,移除 resize 逻辑 - 触发图标从 Info 换为 SlidersHorizontal - ApprovalModeSelector 按钮背景改为透明,修复与对话框背景色不一致 - Sidebar resize handle 宽度从 4px 减为 2px,拖拽颜色降低至 40% 透明度 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 005b839895
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -1078,12 +1296,14 @@ export const useSessionStore = create<SessionState>((set, get) => ({ | |||
| message: { | |||
| id: userMsgId, | |||
| content, | |||
| ...(options?.imageBase64?.length ? { imageBase64: options.imageBase64 } : {}), | |||
There was a problem hiding this comment.
Preserve images when retrying failed sends
当本次消息包含 options.imageBase64 且 llm.chat 返回 runtime_error 或抛错时,下面的重试 action 仍只重新调用 sendMessage(projectId, content, overrides, targetSessionId),不会把这里加入 payload 的图片重新传入;image-only 消息重试后只会发送“请描述这张图片”文本,模型仍看不到图片。请把 options(或至少 imageBase64)也闭包进两个 retry action。
Useful? React with 👍 / 👎.
| @@ -485,7 +473,6 @@ export async function createDeepAgentRuntime( | |||
| defaultModel: provider.default_model, | |||
| providerType: provider.provider_type, | |||
| model: modelName, | |||
There was a problem hiding this comment.
Pass provider context limits into chat models
MiniMax model creation uses config.contextLimit to cap maxTokens; after this call stopped forwarding provider.context_limit, any MiniMax chat whose configured limit is below the 65,536 default will request an over-limit response and can be rejected by the provider. Keep passing the provider context limit here (and in the subagent/workflow model paths) as before.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 37a1390a82
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ipcMain.handle('fs:readFile', (_, rootPath: string, filePath: string) => { | ||
| try { | ||
| return { ok: true, data: readFile(rootPath, filePath) }; |
There was a problem hiding this comment.
Resolve file roots on the main side
这里把 renderer 传来的 rootPath 当作安全边界;resolveProjectFile 只校验 filePath 位于这个同样由 renderer 提供的 root 下。任意渲染端代码都可以调用 window.electronAPI.fs.readFile('/', '/etc/hosts')(同理 readDirectory/getFileInfo)读取或监听项目外文件,绕过项目隔离和 Electron 的最小权限边界。请改为传 projectId,在主进程从 DB 取 project.path 后再做路径校验。
Useful? React with 👍 / 👎.
| }); | ||
| return JSON.stringify({ executionId, status: 'started' }); | ||
|
|
||
| const completionPromise = waitForWorkflowCompletion(executionId); |
There was a problem hiding this comment.
Avoid missing fast workflow completions
在 chat 工具调用 run_workflow 且未传 timeout_ms 时,runWorkflow 会启动后台 IIFE 后返回 executionId,但非常快的工作流(例如空图或只含立即结束节点)可能在这行注册 waiter 之前已经调用 notifyCompletion。notifyCompletion 只唤醒当时存在的 waiter、不缓存结果,因此这里得到的 completionPromise 会永远 pending,导致 Agent 工具调用卡住。请让 waiter 能检查已完成的 DB 状态,或调整为不会在注册前完成。
Useful? React with 👍 / 👎.
| useEffect(() => { | ||
| if (!rootPath) return; | ||
| const unsub = window.electronAPI.fs.onDirectoryChange((_event, data) => { | ||
| const dirPath = data.path.substring(0, data.path.lastIndexOf('/')); |
实现文件面板的完整文件管理功能: - 异步化 readDirectory/readFile/getFileInfo(fs.promises) - 新增 writeFile/createFile/createDirectory/renameEntry/trashEntry 写操作 - 右键上下文菜单(新建/重命名/删除/复制路径/Finder 打开) - 文件编辑 + Cmd+S 保存 + dirty 标记 + 可选自动保存 - Markdown 预览/编辑切换 - Watcher 重构为 per-directory depth:0 按需监听 - 路径安全校验(resolveProjectFile + isProtectedPath)全覆盖 - 中英文 i18n 文案同步 - 35 个单元测试全部通过 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. SystemSettings 新增文件自动保存开关(读写 electron-store autoSave) 2. fileStore 从单一 previewFile 改为 openTabs 数组 + activeTabIndex, 点击文件新增 tab 而非替换,支持单独关闭 3. MarkdownRenderer 添加 ``` 代码块 fence 处理,避免三反引号被 renderInlineMarkdown 的 `.*?` regex 误匹配为行内代码 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Domain docs, ADRs, research, and spikes stay on disk for local agent work but are no longer versioned or pushed.
…t/subagent messages
Summary
Large dev branch merge containing the full CDF Agent Workstation feature set built since initial release:
Image Upload Spike (latest)
image_datacolumn for spike storage (full impl uses attachments table)Workflow Engine (Phases 13-16)
responseFormat, parallel fan-out/fan-in workersParallel Task Execution
UI Polish & Design System
Test Coverage
Image upload spike has 0% test coverage (27 untested paths). This is expected for a spike — full test coverage will be added with the production implementation (attachments table + file-on-disk).
Pre-Landing Review
Review scoped to image upload spike (post-9503c45). No P0/P1 findings.
Adversarial Review
6 findings from Claude adversarial subagent:
image/svg+xmlpaste — restricted to safe bitmap types (png/jpeg/webp/gif)Plan Completion
Plan:
~/.gstack/projects/suntc-pi-gsd/suntc-dev-design-20260623-021150.mdScope: Spike assignment (per plan's "The Assignment" section)
Test plan
🤖 Generated with Claude Code