subagent thinking accordion; indicator fixes; script details & edit

This commit is contained in:
2026-04-20 15:09:37 -04:00
parent a188268906
commit b1d4459809
25 changed files with 2041 additions and 174 deletions

View File

@@ -381,9 +381,75 @@ export class WebSocketHandler {
// Workspace sync: patch message
logger.debug({ store: payload.store, seq: payload.seq }, 'Handling workspace patch');
await workspace!.handlePatch(payload.store, payload.seq, payload.patch || []);
} else if (payload.type === 'client_log') {
const level: string = payload.level ?? 'log';
const msg = `[client:${authContext.sessionId}] ${payload.message ?? ''}`;
const logMeta = { source: 'client', sessionId: authContext.sessionId };
if (level === 'error') logger.error(logMeta, msg);
else if (level === 'warn') logger.warn(logMeta, msg);
else if (level === 'debug') logger.debug(logMeta, msg);
else logger.info(logMeta, msg);
} else if (payload.type === 'agent_stop') {
logger.info('Agent stop requested');
harness?.interrupt();
} else if (payload.type === 'read_details') {
// Read the details field for a category item
const { category, name } = payload;
if (!harness) {
socket.send(JSON.stringify({ type: 'details_error', category, name, error: 'Session not ready' }));
} else {
try {
const details = await harness.readDetails(category, name);
if (details === null) {
socket.send(JSON.stringify({ type: 'details_error', category, name, error: 'Item not found or has no details' }));
} else {
socket.send(JSON.stringify({ type: 'details_data', category, name, details }));
}
} catch (error) {
logger.error({ error, category, name }, 'Error reading details');
socket.send(JSON.stringify({ type: 'details_error', category, name, error: 'Failed to read details' }));
}
}
} else if (payload.type === 'update_details') {
// User submitted a revised details string — diff and invoke the appropriate subagent
const { category, name, details: newDetails } = payload;
if (!harness) {
socket.send(JSON.stringify({ type: 'details_updated', category, name, success: false, error: 'Session not ready' }));
} else {
try {
let hadError = false;
for await (const event of harness.streamDetailsUpdate(category, name, newDetails)) {
const e = event as HarnessEvent;
switch (e.type) {
case 'chunk':
socket.send(JSON.stringify({ type: 'subagent_chunk', agentName: category, content: e.content }));
break;
case 'subagent_chunk':
socket.send(JSON.stringify({ type: 'subagent_chunk', agentName: e.agentName, content: e.content }));
break;
case 'subagent_tool_call':
socket.send(JSON.stringify({ type: 'subagent_tool_call', agentName: e.agentName, toolName: e.toolName, label: e.label }));
break;
case 'tool_call':
socket.send(JSON.stringify({ type: 'agent_tool_call', toolName: e.toolName, label: e.label }));
break;
case 'image':
socket.send(JSON.stringify({ type: 'image', data: e.data, mimeType: e.mimeType, caption: e.caption }));
break;
case 'error':
hadError = true;
socket.send(JSON.stringify({ type: 'subagent_chunk', agentName: category, content: `Error in ${e.source}` }));
break;
case 'done':
break;
}
}
socket.send(JSON.stringify({ type: 'details_updated', category, name, success: !hadError }));
} catch (error) {
logger.error({ error, category, name }, 'Error updating details');
socket.send(JSON.stringify({ type: 'details_updated', category, name, success: false, error: 'Failed to update details' }));
}
}
} else if (this.isDatafeedMessage(payload)) {
// Historical data request - send to OHLC service
logger.info({ type: payload.type }, 'Routing to datafeed handler');