feat: add conversation runtime contracts
This commit is contained in:
344
tests/fixtures/coding-conversation-product-fixtures.ts
vendored
Normal file
344
tests/fixtures/coding-conversation-product-fixtures.ts
vendored
Normal file
@@ -0,0 +1,344 @@
|
||||
import type {
|
||||
ConversationPatch,
|
||||
ConversationPatchEnvelope,
|
||||
ConversationSnapshot,
|
||||
} from '../../electron/coding-runtime/contracts';
|
||||
|
||||
export const PI_PRODUCT_FIXTURE_SOURCE = Object.freeze({
|
||||
package: '@earendil-works/pi-coding-agent',
|
||||
version: '0.84.2',
|
||||
rule: 'Wire labels are fixture provenance only; projected values use Makelore product types.',
|
||||
});
|
||||
|
||||
export function createProductSnapshot(
|
||||
conversationId = 'conversation-a',
|
||||
workerGeneration = 1,
|
||||
): ConversationSnapshot {
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
conversation: {
|
||||
id: conversationId,
|
||||
projectId: 'project-a',
|
||||
agentId: 'agent-a',
|
||||
title: 'Fixture Conversation',
|
||||
model: {
|
||||
model: {
|
||||
accountId: 'account-a',
|
||||
modelId: 'model-a',
|
||||
thinkingLevel: 'medium',
|
||||
},
|
||||
modelResolution: 'resolved',
|
||||
},
|
||||
},
|
||||
nodes: [],
|
||||
run: { status: 'idle' },
|
||||
queue: { items: [] },
|
||||
context: {
|
||||
usedTokens: 0,
|
||||
contextWindow: 128_000,
|
||||
outputLimit: 8_192,
|
||||
compaction: 'idle',
|
||||
},
|
||||
pendingInteractions: [],
|
||||
worker: { status: 'ready', generation: workerGeneration },
|
||||
cursor: { workerGeneration, seq: 0 },
|
||||
};
|
||||
}
|
||||
|
||||
function envelope(seq: number, patch: ConversationPatch): ConversationPatchEnvelope {
|
||||
return {
|
||||
conversationId: 'conversation-a',
|
||||
workerGeneration: 1,
|
||||
runId: 'run-a',
|
||||
seq,
|
||||
at: 1_000 + seq,
|
||||
patch,
|
||||
};
|
||||
}
|
||||
|
||||
export const MIXED_PRODUCT_PATCHES: ConversationPatchEnvelope[] = [
|
||||
envelope(1, {
|
||||
op: 'run.state',
|
||||
run: { status: 'running', runId: 'run-a', mode: 'prompt', startedAt: 1_001 },
|
||||
}),
|
||||
envelope(2, {
|
||||
op: 'message.upsert',
|
||||
node: {
|
||||
kind: 'message',
|
||||
id: 'ui-user-a',
|
||||
clientRequestId: 'request-a',
|
||||
role: 'user',
|
||||
status: 'optimistic',
|
||||
blocks: [{ kind: 'text', id: 'user-text-a', text: 'Build it', status: 'complete' }],
|
||||
},
|
||||
}),
|
||||
envelope(3, {
|
||||
op: 'message.upsert',
|
||||
node: {
|
||||
kind: 'message',
|
||||
id: 'durable-user-a',
|
||||
sourceEntryId: 'entry-user-a',
|
||||
clientRequestId: 'request-a',
|
||||
role: 'user',
|
||||
status: 'complete',
|
||||
blocks: [{ kind: 'text', id: 'user-text-a', text: 'Build it', status: 'complete' }],
|
||||
},
|
||||
}),
|
||||
envelope(4, {
|
||||
op: 'message.upsert',
|
||||
node: {
|
||||
kind: 'message',
|
||||
id: 'ui-assistant-a',
|
||||
sourceEntryId: 'entry-assistant-a',
|
||||
role: 'assistant',
|
||||
status: 'streaming',
|
||||
blocks: [
|
||||
{ kind: 'thinking', id: 'thinking-a', text: 'Plan', status: 'streaming' },
|
||||
{ kind: 'text', id: 'assistant-text-a', text: 'Working', status: 'streaming' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
envelope(5, {
|
||||
op: 'message.block-delta',
|
||||
messageId: 'ui-assistant-a',
|
||||
blockId: 'assistant-text-a',
|
||||
delta: ' now',
|
||||
}),
|
||||
envelope(6, {
|
||||
op: 'tool.upsert',
|
||||
node: {
|
||||
kind: 'tool',
|
||||
id: 'tool-ui-a',
|
||||
toolCallId: 'tool-call-a',
|
||||
toolName: 'write',
|
||||
title: 'Write file',
|
||||
inputText: '{"path":"src/a.ts"}',
|
||||
status: 'running',
|
||||
output: [],
|
||||
details: { schema: 'write-lease.v1', status: 'held' },
|
||||
},
|
||||
}),
|
||||
envelope(7, {
|
||||
op: 'tool.upsert',
|
||||
node: {
|
||||
kind: 'tool',
|
||||
id: 'tool-ui-b',
|
||||
toolCallId: 'tool-call-b',
|
||||
toolName: 'read',
|
||||
title: 'Read file',
|
||||
inputText: '{"path":"src/b.ts"}',
|
||||
status: 'running',
|
||||
output: [],
|
||||
},
|
||||
}),
|
||||
envelope(8, {
|
||||
op: 'tool.upsert',
|
||||
node: {
|
||||
kind: 'tool',
|
||||
id: 'tool-wire-a',
|
||||
toolCallId: 'tool-call-a',
|
||||
toolName: 'write',
|
||||
title: 'Write file',
|
||||
inputText: '{"path":"src/a.ts"}',
|
||||
status: 'running',
|
||||
output: [{ kind: 'text', id: 'tool-output-a', text: 'first', status: 'streaming' }],
|
||||
details: { schema: 'changed-file.v1', paths: ['src/a.ts'] },
|
||||
},
|
||||
}),
|
||||
envelope(9, {
|
||||
op: 'tool.upsert',
|
||||
node: {
|
||||
kind: 'tool',
|
||||
id: 'tool-wire-a',
|
||||
toolCallId: 'tool-call-a',
|
||||
toolName: 'write',
|
||||
title: 'Write file',
|
||||
inputText: '{"path":"src/a.ts"}',
|
||||
status: 'complete',
|
||||
output: [{ kind: 'text', id: 'tool-output-a', text: 'first final', status: 'complete' }],
|
||||
details: { schema: 'changed-file.v1', paths: ['src/a.ts'] },
|
||||
},
|
||||
}),
|
||||
envelope(10, {
|
||||
op: 'tool.upsert',
|
||||
node: {
|
||||
kind: 'tool',
|
||||
id: 'tool-wire-b',
|
||||
toolCallId: 'tool-call-b',
|
||||
toolName: 'read',
|
||||
title: 'Read file',
|
||||
inputText: '{"path":"src/b.ts"}',
|
||||
status: 'error',
|
||||
output: [{ kind: 'text', id: 'tool-output-b', text: 'not found', status: 'complete' }],
|
||||
},
|
||||
}),
|
||||
envelope(11, {
|
||||
op: 'queue.replace',
|
||||
queue: {
|
||||
items: [{
|
||||
id: 'queue-a',
|
||||
clientRequestId: 'request-follow-up',
|
||||
mode: 'follow-up',
|
||||
text: 'Add tests',
|
||||
attachmentIds: [],
|
||||
}],
|
||||
},
|
||||
}),
|
||||
envelope(12, {
|
||||
op: 'interaction.upsert',
|
||||
interaction: {
|
||||
id: 'interaction-a',
|
||||
conversationId: 'conversation-a',
|
||||
runId: 'run-a',
|
||||
kind: 'select',
|
||||
title: 'Choose target',
|
||||
options: [{ id: 'web', label: 'Web' }, { id: 'desktop', label: 'Desktop' }],
|
||||
status: 'pending',
|
||||
},
|
||||
}),
|
||||
envelope(13, {
|
||||
op: 'compaction.upsert',
|
||||
node: {
|
||||
kind: 'compaction',
|
||||
id: 'compaction-a',
|
||||
runId: 'run-a',
|
||||
source: 'automatic',
|
||||
status: 'running',
|
||||
willRetry: true,
|
||||
},
|
||||
}),
|
||||
envelope(14, {
|
||||
op: 'context.replace',
|
||||
context: {
|
||||
usedTokens: 96_000,
|
||||
contextWindow: 128_000,
|
||||
outputLimit: 8_192,
|
||||
compaction: 'running',
|
||||
lastCompactionId: 'compaction-a',
|
||||
},
|
||||
}),
|
||||
envelope(15, {
|
||||
op: 'subagent.upsert',
|
||||
node: {
|
||||
kind: 'subagent',
|
||||
id: 'subagent-a',
|
||||
runId: 'run-a',
|
||||
details: {
|
||||
schema: 'subagent.v1',
|
||||
dispatchId: 'dispatch-a',
|
||||
mode: 'parallel',
|
||||
tasks: [
|
||||
{
|
||||
taskId: 'child-a',
|
||||
agentId: 'reviewer',
|
||||
toolProfile: 'read-only',
|
||||
status: 'complete',
|
||||
summary: 'Reviewed',
|
||||
},
|
||||
{
|
||||
taskId: 'child-b',
|
||||
agentId: 'tester',
|
||||
toolProfile: 'coding',
|
||||
status: 'running',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
envelope(16, {
|
||||
op: 'compaction.upsert',
|
||||
node: {
|
||||
kind: 'compaction',
|
||||
id: 'compaction-a',
|
||||
runId: 'run-a',
|
||||
source: 'automatic',
|
||||
status: 'complete',
|
||||
willRetry: true,
|
||||
},
|
||||
}),
|
||||
envelope(17, {
|
||||
op: 'context.replace',
|
||||
context: {
|
||||
usedTokens: 24_000,
|
||||
contextWindow: 128_000,
|
||||
outputLimit: 8_192,
|
||||
compaction: 'idle',
|
||||
lastCompactionId: 'compaction-a',
|
||||
},
|
||||
}),
|
||||
envelope(18, { op: 'interaction.remove', interactionId: 'interaction-a' }),
|
||||
envelope(19, {
|
||||
op: 'message.upsert',
|
||||
node: {
|
||||
kind: 'message',
|
||||
id: 'durable-assistant-a',
|
||||
sourceEntryId: 'entry-assistant-a',
|
||||
role: 'assistant',
|
||||
status: 'complete',
|
||||
blocks: [
|
||||
{ kind: 'thinking', id: 'thinking-a', text: 'Plan complete', status: 'complete' },
|
||||
{ kind: 'text', id: 'assistant-text-a', text: 'Done', status: 'complete' },
|
||||
],
|
||||
usage: { inputTokens: 120, outputTokens: 40 },
|
||||
stopReason: 'stop',
|
||||
},
|
||||
}),
|
||||
envelope(20, {
|
||||
op: 'run.state',
|
||||
run: {
|
||||
status: 'idle',
|
||||
runId: 'run-a',
|
||||
settledAt: 1_020,
|
||||
terminalReason: 'completed',
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
export const PI_WIRE_TO_PRODUCT_BOUNDARY = Object.freeze([
|
||||
{
|
||||
wireEvent: 'agent_end',
|
||||
projectedPatches: [] as ConversationPatch[],
|
||||
},
|
||||
{
|
||||
wireEvent: 'agent_settled',
|
||||
projectedPatches: [{
|
||||
op: 'run.state',
|
||||
run: {
|
||||
status: 'idle',
|
||||
runId: 'run-a',
|
||||
terminalReason: 'completed',
|
||||
},
|
||||
}] satisfies ConversationPatch[],
|
||||
},
|
||||
{
|
||||
wireEvent: 'retry',
|
||||
projectedPatches: [{
|
||||
op: 'run.state',
|
||||
run: {
|
||||
status: 'retrying',
|
||||
runId: 'run-a',
|
||||
retry: { attempt: 2, delayMs: 750 },
|
||||
},
|
||||
}] satisfies ConversationPatch[],
|
||||
},
|
||||
{
|
||||
wireEvent: 'toolResult.message_end',
|
||||
projectedPatches: [{
|
||||
op: 'tool.upsert',
|
||||
node: {
|
||||
kind: 'tool',
|
||||
id: 'tool-ui-a',
|
||||
toolCallId: 'tool-call-a',
|
||||
toolName: 'write',
|
||||
title: 'Write file',
|
||||
inputText: '{}',
|
||||
status: 'complete',
|
||||
output: [{ kind: 'text', id: 'tool-output-a', text: 'done', status: 'complete' }],
|
||||
},
|
||||
}] satisfies ConversationPatch[],
|
||||
},
|
||||
{
|
||||
wireEvent: 'custom.display-false',
|
||||
projectedPatches: [] as ConversationPatch[],
|
||||
},
|
||||
]);
|
||||
Reference in New Issue
Block a user