feat(coding): add renderer conversation store
This commit is contained in:
82
shared/coding-conversation-subagent-protocol.ts
Normal file
82
shared/coding-conversation-subagent-protocol.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import type { PublicUsage, SubagentDetailsV1 } from './coding-conversation-contracts';
|
||||
|
||||
const STATUSES = new Set(['queued', 'running', 'complete', 'error', 'aborted', 'skipped']);
|
||||
|
||||
function recordValue(value: unknown): Record<string, unknown> | null {
|
||||
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
||||
? value as Record<string, unknown>
|
||||
: null;
|
||||
}
|
||||
|
||||
function publicUsage(value: unknown): PublicUsage | undefined {
|
||||
const usage = recordValue(value);
|
||||
if (!usage
|
||||
|| typeof usage.inputTokens !== 'number'
|
||||
|| typeof usage.outputTokens !== 'number'
|
||||
|| !Number.isFinite(usage.inputTokens)
|
||||
|| !Number.isFinite(usage.outputTokens)
|
||||
|| usage.inputTokens < 0
|
||||
|| usage.outputTokens < 0
|
||||
|| (usage.cacheReadTokens !== undefined
|
||||
&& (typeof usage.cacheReadTokens !== 'number'
|
||||
|| !Number.isFinite(usage.cacheReadTokens)
|
||||
|| usage.cacheReadTokens < 0))
|
||||
|| (usage.cacheWriteTokens !== undefined
|
||||
&& (typeof usage.cacheWriteTokens !== 'number'
|
||||
|| !Number.isFinite(usage.cacheWriteTokens)
|
||||
|| usage.cacheWriteTokens < 0))) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
inputTokens: usage.inputTokens,
|
||||
outputTokens: usage.outputTokens,
|
||||
...(typeof usage.cacheReadTokens === 'number' ? { cacheReadTokens: usage.cacheReadTokens } : {}),
|
||||
...(typeof usage.cacheWriteTokens === 'number' ? { cacheWriteTokens: usage.cacheWriteTokens } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
export function projectSubagentDetailsV1(value: unknown): SubagentDetailsV1 | undefined {
|
||||
const record = recordValue(value);
|
||||
if (!record
|
||||
|| record.schema !== 'subagent.v1'
|
||||
|| typeof record.dispatchId !== 'string'
|
||||
|| !record.dispatchId.trim()
|
||||
|| !['single', 'parallel', 'chain'].includes(String(record.mode))
|
||||
|| !Array.isArray(record.tasks)
|
||||
|| record.tasks.length === 0
|
||||
|| record.tasks.length > 8) return undefined;
|
||||
const tasks: SubagentDetailsV1['tasks'] = [];
|
||||
for (const value of record.tasks) {
|
||||
const task = recordValue(value);
|
||||
if (!task
|
||||
|| typeof task.taskId !== 'string'
|
||||
|| !task.taskId.trim()
|
||||
|| typeof task.agentId !== 'string'
|
||||
|| !task.agentId.trim()
|
||||
|| (task.toolProfile !== 'read-only' && task.toolProfile !== 'coding')
|
||||
|| !STATUSES.has(String(task.status))
|
||||
|| (task.summary !== undefined && typeof task.summary !== 'string')
|
||||
|| (task.errorCode !== undefined && typeof task.errorCode !== 'string')) return undefined;
|
||||
const usage = task.usage === undefined ? undefined : publicUsage(task.usage);
|
||||
if (task.usage !== undefined && !usage) return undefined;
|
||||
tasks.push({
|
||||
taskId: task.taskId,
|
||||
agentId: task.agentId,
|
||||
toolProfile: task.toolProfile,
|
||||
status: task.status as SubagentDetailsV1['tasks'][number]['status'],
|
||||
...(typeof task.summary === 'string' ? { summary: task.summary.slice(0, 4_000) } : {}),
|
||||
...(typeof task.errorCode === 'string' ? { errorCode: task.errorCode.slice(0, 64) } : {}),
|
||||
...(usage ? { usage } : {}),
|
||||
});
|
||||
}
|
||||
return {
|
||||
schema: 'subagent.v1',
|
||||
dispatchId: record.dispatchId,
|
||||
mode: record.mode as SubagentDetailsV1['mode'],
|
||||
tasks,
|
||||
};
|
||||
}
|
||||
|
||||
export function subagentDetailsOfResult(value: unknown): SubagentDetailsV1 | undefined {
|
||||
return projectSubagentDetailsV1(recordValue(value)?.details);
|
||||
}
|
||||
Reference in New Issue
Block a user