feat: add conversation runtime contracts
This commit is contained in:
362
electron/coding-runtime/contracts.ts
Normal file
362
electron/coding-runtime/contracts.ts
Normal file
@@ -0,0 +1,362 @@
|
||||
export type ConversationThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high';
|
||||
|
||||
export interface ProductModelRef {
|
||||
accountId: string;
|
||||
modelId: string;
|
||||
thinkingLevel: ConversationThinkingLevel;
|
||||
}
|
||||
|
||||
export interface ConversationModelState {
|
||||
model: ProductModelRef | null;
|
||||
modelResolution: 'resolved' | 'required';
|
||||
}
|
||||
|
||||
export interface PublicUsage {
|
||||
inputTokens: number;
|
||||
outputTokens: number;
|
||||
cacheReadTokens?: number;
|
||||
cacheWriteTokens?: number;
|
||||
}
|
||||
|
||||
export type CodingRuntimeErrorCode =
|
||||
| 'CODING_RUNTIME_START_FAILED'
|
||||
| 'CODING_RUNTIME_READY_TIMEOUT'
|
||||
| 'CODING_RUNTIME_PROTOCOL_ERROR'
|
||||
| 'CODING_PROVIDER_AUTH_REQUIRED'
|
||||
| 'CODING_MODEL_UNAVAILABLE'
|
||||
| 'CODING_SESSION_UNREADABLE'
|
||||
| 'CODING_STORAGE_WRITE_FAILED'
|
||||
| 'CODING_REQUEST_UNCERTAIN'
|
||||
| 'CODING_MIGRATION_MODEL_REQUIRED'
|
||||
| 'CODING_CONVERSATION_NOT_FOUND';
|
||||
|
||||
export interface CodingRuntimePublicError {
|
||||
code: CodingRuntimeErrorCode;
|
||||
message: string;
|
||||
recoverable: boolean;
|
||||
}
|
||||
|
||||
export type ConversationRunStatus =
|
||||
| 'idle'
|
||||
| 'preparing'
|
||||
| 'queued'
|
||||
| 'running'
|
||||
| 'retrying'
|
||||
| 'compacting'
|
||||
| 'aborting'
|
||||
| 'error';
|
||||
|
||||
export type PromptMode = 'prompt' | 'steer' | 'follow-up';
|
||||
|
||||
export interface ConversationRunState {
|
||||
status: ConversationRunStatus;
|
||||
runId?: string;
|
||||
mode?: PromptMode;
|
||||
startedAt?: number;
|
||||
settledAt?: number;
|
||||
terminalReason?: 'completed' | 'aborted' | 'failed';
|
||||
retry?: {
|
||||
attempt: number;
|
||||
delayMs: number;
|
||||
};
|
||||
error?: CodingRuntimePublicError;
|
||||
}
|
||||
|
||||
export interface ConversationQueueItem {
|
||||
id: string;
|
||||
clientRequestId: string;
|
||||
mode: 'steer' | 'follow-up';
|
||||
text: string;
|
||||
attachmentIds: string[];
|
||||
}
|
||||
|
||||
export interface ConversationQueueState {
|
||||
items: ConversationQueueItem[];
|
||||
}
|
||||
|
||||
export interface ConversationContextState {
|
||||
usedTokens: number;
|
||||
contextWindow: number;
|
||||
outputLimit?: number;
|
||||
compaction: 'idle' | 'running';
|
||||
lastCompactionId?: string;
|
||||
}
|
||||
|
||||
export interface ConversationInteractionOption {
|
||||
id: string;
|
||||
label: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface ConversationInteraction {
|
||||
id: string;
|
||||
conversationId: string;
|
||||
runId: string;
|
||||
kind: 'select' | 'confirm' | 'input' | 'editor';
|
||||
title: string;
|
||||
message?: string;
|
||||
options?: ConversationInteractionOption[];
|
||||
status: 'pending' | 'answered' | 'rejected' | 'cancelled';
|
||||
}
|
||||
|
||||
export interface PublicWorkerState {
|
||||
status: 'stopped' | 'starting' | 'ready' | 'recovering' | 'error';
|
||||
generation: number;
|
||||
error?: CodingRuntimePublicError;
|
||||
}
|
||||
|
||||
export type ConversationContentBlock =
|
||||
| {
|
||||
kind: 'text';
|
||||
id: string;
|
||||
text: string;
|
||||
status: 'streaming' | 'complete';
|
||||
}
|
||||
| {
|
||||
kind: 'thinking';
|
||||
id: string;
|
||||
text: string;
|
||||
status: 'streaming' | 'complete';
|
||||
}
|
||||
| {
|
||||
kind: 'image';
|
||||
id: string;
|
||||
attachmentId: string;
|
||||
mime: string;
|
||||
};
|
||||
|
||||
export interface ConversationMessageNode {
|
||||
kind: 'message';
|
||||
id: string;
|
||||
sourceEntryId?: string;
|
||||
clientRequestId?: string;
|
||||
role: 'user' | 'assistant';
|
||||
status: 'optimistic' | 'streaming' | 'complete' | 'error' | 'aborted';
|
||||
blocks: ConversationContentBlock[];
|
||||
usage?: PublicUsage;
|
||||
stopReason?: 'stop' | 'length' | 'tool-use' | 'error' | 'aborted';
|
||||
}
|
||||
|
||||
export interface ChangedFileDetailsV1 {
|
||||
schema: 'changed-file.v1';
|
||||
paths: string[];
|
||||
}
|
||||
|
||||
export interface TaskStateDetailsV1 {
|
||||
schema: 'task-state.v1';
|
||||
tasks: Array<{
|
||||
id: string;
|
||||
title: string;
|
||||
status: 'pending' | 'running' | 'complete' | 'error';
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface WriteLeaseDetailsV1 {
|
||||
schema: 'write-lease.v1';
|
||||
status: 'waiting' | 'held' | 'released';
|
||||
}
|
||||
|
||||
export interface SubagentDetailsV1 {
|
||||
schema: 'subagent.v1';
|
||||
dispatchId: string;
|
||||
mode: 'single' | 'parallel' | 'chain';
|
||||
tasks: Array<{
|
||||
taskId: string;
|
||||
agentId: string;
|
||||
toolProfile: 'read-only' | 'coding';
|
||||
status: 'queued' | 'running' | 'complete' | 'error' | 'aborted' | 'skipped';
|
||||
summary?: string;
|
||||
errorCode?: string;
|
||||
usage?: PublicUsage;
|
||||
}>;
|
||||
}
|
||||
|
||||
export type KnownToolDetails =
|
||||
| ChangedFileDetailsV1
|
||||
| TaskStateDetailsV1
|
||||
| WriteLeaseDetailsV1
|
||||
| SubagentDetailsV1;
|
||||
|
||||
export interface ConversationToolNode {
|
||||
kind: 'tool';
|
||||
id: string;
|
||||
toolCallId: string;
|
||||
toolName: string;
|
||||
title: string;
|
||||
inputText: string;
|
||||
status: 'declared' | 'waiting' | 'running' | 'complete' | 'error' | 'aborted';
|
||||
output: ConversationContentBlock[];
|
||||
details?: KnownToolDetails;
|
||||
}
|
||||
|
||||
export interface ConversationCompactionNode {
|
||||
kind: 'compaction';
|
||||
id: string;
|
||||
runId: string;
|
||||
source: 'manual' | 'automatic';
|
||||
status: 'running' | 'complete' | 'error';
|
||||
willRetry: boolean;
|
||||
summary?: string;
|
||||
}
|
||||
|
||||
export interface ConversationBoundaryNode {
|
||||
kind: 'boundary';
|
||||
id: string;
|
||||
runId: string;
|
||||
boundary: 'turn-start' | 'turn-end' | 'retry';
|
||||
attempt?: number;
|
||||
delayMs?: number;
|
||||
}
|
||||
|
||||
export interface ConversationSubagentNode {
|
||||
kind: 'subagent';
|
||||
id: string;
|
||||
runId: string;
|
||||
details: SubagentDetailsV1;
|
||||
}
|
||||
|
||||
export interface ConversationNoticeNode {
|
||||
kind: 'notice';
|
||||
id: string;
|
||||
code: string;
|
||||
level: 'info' | 'warning' | 'error';
|
||||
message: string;
|
||||
}
|
||||
|
||||
export type ConversationNode =
|
||||
| ConversationMessageNode
|
||||
| ConversationToolNode
|
||||
| ConversationCompactionNode
|
||||
| ConversationBoundaryNode
|
||||
| ConversationSubagentNode
|
||||
| ConversationNoticeNode;
|
||||
|
||||
export interface ConversationSnapshot {
|
||||
schemaVersion: 1;
|
||||
conversation: {
|
||||
id: string;
|
||||
projectId: string;
|
||||
agentId: string;
|
||||
title: string;
|
||||
model: ConversationModelState;
|
||||
};
|
||||
nodes: ConversationNode[];
|
||||
run: ConversationRunState;
|
||||
queue: ConversationQueueState;
|
||||
context: ConversationContextState;
|
||||
pendingInteractions: ConversationInteraction[];
|
||||
worker: PublicWorkerState;
|
||||
cursor: {
|
||||
workerGeneration: number;
|
||||
seq: number;
|
||||
leafEntryId?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type ConversationPatch =
|
||||
| { op: 'worker.state'; state: PublicWorkerState }
|
||||
| { op: 'run.state'; run: ConversationRunState }
|
||||
| { op: 'message.upsert'; node: ConversationMessageNode }
|
||||
| { op: 'message.block-delta'; messageId: string; blockId: string; delta: string }
|
||||
| { op: 'tool.upsert'; node: ConversationToolNode }
|
||||
| { op: 'compaction.upsert'; node: ConversationCompactionNode }
|
||||
| { op: 'subagent.upsert'; node: ConversationSubagentNode }
|
||||
| { op: 'queue.replace'; queue: ConversationQueueState }
|
||||
| { op: 'interaction.upsert'; interaction: ConversationInteraction }
|
||||
| { op: 'interaction.remove'; interactionId: string }
|
||||
| { op: 'context.replace'; context: ConversationContextState }
|
||||
| { op: 'snapshot.invalidated'; reason: string };
|
||||
|
||||
export interface ConversationPatchEnvelope {
|
||||
conversationId: string;
|
||||
workerGeneration: number;
|
||||
runId?: string;
|
||||
seq: number;
|
||||
at: number;
|
||||
patch: ConversationPatch;
|
||||
}
|
||||
|
||||
export interface PrepareConversationInput {
|
||||
conversationId: string;
|
||||
projectId: string;
|
||||
agentId: string;
|
||||
title: string;
|
||||
model: ConversationModelState;
|
||||
}
|
||||
|
||||
export interface ConversationRuntimeState {
|
||||
conversationId: string;
|
||||
status: PublicWorkerState['status'];
|
||||
workerGeneration: number;
|
||||
error?: CodingRuntimePublicError;
|
||||
}
|
||||
|
||||
export interface PromptConversationInput {
|
||||
clientRequestId: string;
|
||||
conversationId: string;
|
||||
mode: PromptMode;
|
||||
text: string;
|
||||
attachments: Array<{ attachmentId: string }>;
|
||||
}
|
||||
|
||||
export interface QueueMessageInput {
|
||||
clientRequestId: string;
|
||||
conversationId: string;
|
||||
text: string;
|
||||
attachments: Array<{ attachmentId: string }>;
|
||||
}
|
||||
|
||||
export interface PromptAcceptance {
|
||||
accepted: true;
|
||||
conversationId: string;
|
||||
clientRequestId: string;
|
||||
runId: string;
|
||||
mode: PromptMode;
|
||||
queuePosition?: number;
|
||||
}
|
||||
|
||||
export interface QueueAcceptance {
|
||||
accepted: true;
|
||||
conversationId: string;
|
||||
clientRequestId: string;
|
||||
mode: 'steer' | 'follow-up';
|
||||
queuePosition: number;
|
||||
}
|
||||
|
||||
export interface SetConversationModelInput {
|
||||
conversationId: string;
|
||||
accountId: string;
|
||||
modelId: string;
|
||||
}
|
||||
|
||||
export interface SetThinkingLevelInput {
|
||||
conversationId: string;
|
||||
thinkingLevel: ConversationThinkingLevel;
|
||||
}
|
||||
|
||||
export interface ForkConversationInput {
|
||||
sourceConversationId: string;
|
||||
sourceEntryId?: string;
|
||||
conversation: PrepareConversationInput;
|
||||
}
|
||||
|
||||
export interface ForkResult {
|
||||
conversationId: string;
|
||||
snapshot: ConversationSnapshot;
|
||||
}
|
||||
|
||||
export interface CodingConversationRuntime {
|
||||
prepare(input: PrepareConversationInput): Promise<ConversationRuntimeState>;
|
||||
getSnapshot(conversationId: string): Promise<ConversationSnapshot>;
|
||||
prompt(input: PromptConversationInput): Promise<PromptAcceptance>;
|
||||
steer(input: QueueMessageInput): Promise<QueueAcceptance>;
|
||||
followUp(input: QueueMessageInput): Promise<QueueAcceptance>;
|
||||
abort(conversationId: string): Promise<void>;
|
||||
setModel(input: SetConversationModelInput): Promise<ConversationModelState>;
|
||||
setThinking(input: SetThinkingLevelInput): Promise<ConversationModelState>;
|
||||
compact(conversationId: string): Promise<void>;
|
||||
fork(input: ForkConversationInput): Promise<ForkResult>;
|
||||
recover(conversationId: string): Promise<ConversationRuntimeState>;
|
||||
dispose(conversationId: string): Promise<void>;
|
||||
subscribe(listener: (patch: ConversationPatchEnvelope) => void): () => void;
|
||||
}
|
||||
Reference in New Issue
Block a user