feat: phase 3-5 — workflow engine, background subagents, multi-modal, cache shape, inline diff
Phase 3: Dynamic Workflow Engine - VM sandbox (node:vm) with agent/parallel/pipeline API, Claude Code compatible - Workflow file discovery (.boocode/workflows/*.js + ~/.boocode/workflows/*.js) - Workflow manager with session/chat creation and inference dispatch - Built-in catalog: deep-research, review-code, find-issues - Resumability cache: SHA-256 hash of agent spec, in-memory Map Phase 4: Background Subagents - background-task.ts service: spawn/poll/cancel lifecycle - spawn_subagent, subagent_status, subagent_result tools in ALL_TOOLS Phase 5: Multi-modal + Cache Shape - Multi-modal stub with type defs and hook point in payload.ts - CacheShapeBadge component in trace viewer (colored bar + %)
This commit is contained in:
@@ -79,6 +79,7 @@ function channelDeltaToLegacyFrame(delta: ChannelDeltaWsFrame): WsFrame | null {
|
||||
output: delta.output,
|
||||
truncated: delta.truncated!,
|
||||
...(delta.error ? { error: delta.error } : {}),
|
||||
...(delta.diff ? { diff: delta.diff } : {}),
|
||||
};
|
||||
case 'error':
|
||||
return {
|
||||
@@ -172,6 +173,7 @@ function applyFrame(state: State, frame: WsFrame): State {
|
||||
finished_at: null,
|
||||
created_at: new Date().toISOString(),
|
||||
metadata: null,
|
||||
...(frame.compare_group_id ? { compare_group_id: frame.compare_group_id } : {}),
|
||||
};
|
||||
return { ...state, messages: [...state.messages, newMsg] };
|
||||
}
|
||||
@@ -195,21 +197,18 @@ function applyFrame(state: State, frame: WsFrame): State {
|
||||
return { ...state, messages: next };
|
||||
}
|
||||
case 'tool_result': {
|
||||
const toolResultsBase = {
|
||||
tool_call_id: frame.tool_call_id,
|
||||
output: frame.output,
|
||||
truncated: frame.truncated,
|
||||
...(frame.error ? { error: frame.error } : {}),
|
||||
...(frame.diff ? { diff: frame.diff } : {}),
|
||||
};
|
||||
const exists = state.messages.some((m) => m.id === frame.tool_message_id);
|
||||
if (exists) {
|
||||
const next = state.messages.map((m) =>
|
||||
m.id === frame.tool_message_id
|
||||
? {
|
||||
...m,
|
||||
role: 'tool' as const,
|
||||
tool_results: {
|
||||
tool_call_id: frame.tool_call_id,
|
||||
output: frame.output,
|
||||
truncated: frame.truncated,
|
||||
...(frame.error ? { error: frame.error } : {}),
|
||||
},
|
||||
status: 'complete' as const,
|
||||
}
|
||||
? { ...m, role: 'tool' as const, tool_results: toolResultsBase, status: 'complete' as const }
|
||||
: m,
|
||||
);
|
||||
return { ...state, messages: next };
|
||||
@@ -222,12 +221,7 @@ function applyFrame(state: State, frame: WsFrame): State {
|
||||
content: '',
|
||||
kind: 'message',
|
||||
tool_calls: null,
|
||||
tool_results: {
|
||||
tool_call_id: frame.tool_call_id,
|
||||
output: frame.output,
|
||||
truncated: frame.truncated,
|
||||
...(frame.error ? { error: frame.error } : {}),
|
||||
},
|
||||
tool_results: toolResultsBase,
|
||||
status: 'complete',
|
||||
last_seq: 0,
|
||||
tokens_used: null,
|
||||
@@ -258,6 +252,7 @@ function applyFrame(state: State, frame: WsFrame): State {
|
||||
...(frame.finished_at !== undefined ? { finished_at: frame.finished_at } : {}),
|
||||
...(frame.model !== undefined ? { model: frame.model } : {}),
|
||||
...(frame.metadata !== undefined ? { metadata: frame.metadata } : {}),
|
||||
...(frame.compare_group_id !== undefined ? { compare_group_id: frame.compare_group_id } : {}),
|
||||
}
|
||||
: m,
|
||||
);
|
||||
@@ -301,6 +296,7 @@ function applyFrame(state: State, frame: WsFrame): State {
|
||||
...m,
|
||||
status: 'failed' as const,
|
||||
...(errorMeta ? { metadata: errorMeta } : {}),
|
||||
...(frame.compare_group_id !== undefined ? { compare_group_id: frame.compare_group_id } : {}),
|
||||
}
|
||||
: m,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user