eidolon-ai-runtime-host-contract 0.0.0-stage → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +20 -4
- package/src/ActorManagement.ts +22 -0
- package/src/AgentAdapters.ts +171 -0
- package/src/AgentAdaptersWire.ts +61 -0
- package/src/Attachment.ts +15 -0
- package/src/Command.ts +110 -0
- package/src/ContentRead.ts +20 -0
- package/src/Conversation.ts +18 -0
- package/src/Daemon.ts +63 -0
- package/src/Effects.ts +61 -0
- package/src/ExecutionEnvironment.ts +28 -0
- package/src/GlobalTaskSpace.ts +116 -0
- package/src/Goal.ts +29 -0
- package/src/HostInteractions.ts +190 -0
- package/src/HostPort.ts +144 -0
- package/src/Observation.ts +128 -0
- package/src/Organization.ts +14 -0
- package/src/Participant.ts +93 -0
- package/src/Schedule.ts +79 -0
- package/src/Schema.ts +598 -0
- package/src/SessionImport.ts +38 -0
- package/src/SessionManagement.ts +23 -0
- package/src/SessionProject.ts +9 -0
- package/src/Statistics.ts +24 -0
- package/src/Workflow.ts +207 -0
- package/src/WorkflowAuthoring.ts +76 -0
- package/src/WorkflowConversationOwner.ts +164 -0
- package/src/WorkflowExecutionCatalog.ts +48 -0
- package/src/WorkflowHumanReview.ts +26 -0
- package/src/WorkflowHumanReviewSchema.ts +90 -0
- package/src/WorkflowLaunch.ts +47 -0
- package/src/WorkflowLaunchMaterials.ts +43 -0
- package/src/WorkflowLaunchMaterialsSchema.ts +166 -0
- package/src/WorkflowLaunchParameters.ts +63 -0
- package/src/WorkflowLaunchReview.ts +90 -0
- package/src/WorkflowLaunchSchema.ts +181 -0
- package/src/WorkflowPresentation.ts +67 -0
- package/src/WorkflowSchema.ts +199 -0
- package/src/WorkflowSessionCall.ts +47 -0
- package/src/WorkflowTaskTree.ts +46 -0
- package/src/index.ts +89 -0
- package/README.md +0 -3
package/package.json
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eidolon-ai-runtime-host-contract",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"types": "./src/index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"description": "Serializable runtime host protocol and injected effects shared by local and remote shells.",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"holarchy-eidolon-adapter": "0.2.2"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public",
|
|
19
|
+
"registry": "https://registry.npmjs.com/"
|
|
20
|
+
},
|
|
21
|
+
"private": false
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Original Actor lifecycle, distinct from closing a browser pane or deleting files. */
|
|
2
|
+
export type ActorLifecycle = Readonly<{
|
|
3
|
+
state: 'active' | 'archived' | 'tombstoned';
|
|
4
|
+
revision: number;
|
|
5
|
+
changedAt?: number;
|
|
6
|
+
}>;
|
|
7
|
+
export type ActorManagementCommand = Readonly<{
|
|
8
|
+
commandId: string;
|
|
9
|
+
kind: 'archive_actor' | 'delete_actor';
|
|
10
|
+
expectedServerInstanceId: string;
|
|
11
|
+
expectedEpoch: string;
|
|
12
|
+
expectedLifecycleRevision: number;
|
|
13
|
+
}>;
|
|
14
|
+
/** Principal-scoped durable proof; a historical receipt does not overwrite the current lifecycle. */
|
|
15
|
+
export type ActorManagementResult = Readonly<{
|
|
16
|
+
sessionId: string;
|
|
17
|
+
actorId: string;
|
|
18
|
+
commandId: string;
|
|
19
|
+
kind: ActorManagementCommand['kind'];
|
|
20
|
+
submittedEpoch: string;
|
|
21
|
+
lifecycle: Readonly<{state: 'archived' | 'tombstoned'; revision: number; changedAt: number}>;
|
|
22
|
+
}>;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { ExecutionEnvironmentRef, ExecutionEnvironmentContext } from './ExecutionEnvironment';
|
|
2
|
+
import type { HostRequest } from './HostPort';
|
|
3
|
+
import type { ParticipantContextCut } from './Participant';
|
|
4
|
+
/** Original external runtimes keep their own handles; these are never Native TaskSpace IDs. */
|
|
5
|
+
export type AgentAdapterKind = 'codex' | 'claude' | 'grok';
|
|
6
|
+
export type AgentAdapterSourceRef = Readonly<{
|
|
7
|
+
kind: 'agent-adapter';
|
|
8
|
+
daemonId: string;
|
|
9
|
+
adapterId: string;
|
|
10
|
+
revision: number;
|
|
11
|
+
}>;
|
|
12
|
+
export type AgentAdapterConfiguration = Readonly<{
|
|
13
|
+
provider: AgentAdapterKind;
|
|
14
|
+
name: string;
|
|
15
|
+
model: string;
|
|
16
|
+
environment: ExecutionEnvironmentRef;
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
}>;
|
|
19
|
+
export type AgentAdapterRegistration = Readonly<{
|
|
20
|
+
source: AgentAdapterSourceRef;
|
|
21
|
+
configuration: AgentAdapterConfiguration;
|
|
22
|
+
}>;
|
|
23
|
+
export type AgentAdapterCapabilities = Readonly<{
|
|
24
|
+
submit: boolean;
|
|
25
|
+
interrupt: boolean;
|
|
26
|
+
observeOriginal: boolean;
|
|
27
|
+
nativeTaskSpace: false;
|
|
28
|
+
nativeActorHistory: false;
|
|
29
|
+
attachments: false;
|
|
30
|
+
artifacts: false;
|
|
31
|
+
tools: 'chat-only' | 'read-only';
|
|
32
|
+
context: 'retained' | 'explicit-cut';
|
|
33
|
+
}>;
|
|
34
|
+
export type AgentAdapterView = AgentAdapterRegistration & Readonly<{
|
|
35
|
+
canSubmit: boolean;
|
|
36
|
+
unavailableReason?: string;
|
|
37
|
+
installedVersion?: string;
|
|
38
|
+
access: 'unverified' | 'observed';
|
|
39
|
+
capabilities: AgentAdapterCapabilities;
|
|
40
|
+
}>;
|
|
41
|
+
export type AgentAdapterDirectory = Readonly<{
|
|
42
|
+
daemonId: string;
|
|
43
|
+
adapters: readonly AgentAdapterView[];
|
|
44
|
+
}>;
|
|
45
|
+
export type AgentExecutionHandle = Readonly<{
|
|
46
|
+
kind: 'agent-execution';
|
|
47
|
+
source: AgentAdapterSourceRef;
|
|
48
|
+
provider: AgentAdapterKind;
|
|
49
|
+
sessionId: string;
|
|
50
|
+
turnId?: string;
|
|
51
|
+
}>;
|
|
52
|
+
export type AgentExecutionState = 'queued' | 'sending' | 'running' | 'completed' | 'failed' | 'cancelled' | 'unknown';
|
|
53
|
+
export type AgentAdapterSendCommand = Readonly<{
|
|
54
|
+
source: AgentAdapterSourceRef;
|
|
55
|
+
bindingKey: string;
|
|
56
|
+
commandId: string;
|
|
57
|
+
text: string;
|
|
58
|
+
contextCut: ParticipantContextCut;
|
|
59
|
+
}>;
|
|
60
|
+
export type AgentExecutionSnapshot = Readonly<{
|
|
61
|
+
source: AgentAdapterSourceRef;
|
|
62
|
+
bindingKey: string;
|
|
63
|
+
commandId: string;
|
|
64
|
+
fingerprint: string;
|
|
65
|
+
revision: number;
|
|
66
|
+
state: AgentExecutionState;
|
|
67
|
+
handle?: AgentExecutionHandle;
|
|
68
|
+
result?: string;
|
|
69
|
+
errorCode?: string;
|
|
70
|
+
canInterrupt: boolean;
|
|
71
|
+
}>;
|
|
72
|
+
export type AgentAdapterConfigureCommand = Readonly<{
|
|
73
|
+
commandId: string;
|
|
74
|
+
adapterId: string;
|
|
75
|
+
expectedRevision: number;
|
|
76
|
+
configuration: AgentAdapterConfiguration;
|
|
77
|
+
}>;
|
|
78
|
+
export type AgentAdapterConfigureReceipt = Readonly<{
|
|
79
|
+
commandId: string;
|
|
80
|
+
adapterId: string;
|
|
81
|
+
revision: number;
|
|
82
|
+
fingerprint: string;
|
|
83
|
+
}>;
|
|
84
|
+
export type AgentAdapterSelector = Readonly<{
|
|
85
|
+
source: AgentAdapterSourceRef;
|
|
86
|
+
bindingKey: string;
|
|
87
|
+
commandId: string;
|
|
88
|
+
}>;
|
|
89
|
+
export type AgentAdapterInterruptCommand = AgentAdapterSelector & Readonly<{
|
|
90
|
+
controlId: string;
|
|
91
|
+
expectedRevision: number;
|
|
92
|
+
}>;
|
|
93
|
+
export type AgentDriverEvent = Readonly<{
|
|
94
|
+
kind: 'session';
|
|
95
|
+
sessionId: string;
|
|
96
|
+
}> | Readonly<{
|
|
97
|
+
kind: 'handle';
|
|
98
|
+
handle: AgentExecutionHandle;
|
|
99
|
+
}> | Readonly<{
|
|
100
|
+
kind: 'sending';
|
|
101
|
+
}> | Readonly<{
|
|
102
|
+
kind: 'running';
|
|
103
|
+
}>;
|
|
104
|
+
export type AgentDriverResult = Readonly<{
|
|
105
|
+
state: 'completed';
|
|
106
|
+
handle: AgentExecutionHandle;
|
|
107
|
+
text: string;
|
|
108
|
+
}> | Readonly<{
|
|
109
|
+
state: 'failed' | 'cancelled' | 'unknown';
|
|
110
|
+
handle?: AgentExecutionHandle;
|
|
111
|
+
errorCode: string;
|
|
112
|
+
}>;
|
|
113
|
+
export type AgentDriverInput = Readonly<{
|
|
114
|
+
command: AgentAdapterSendCommand;
|
|
115
|
+
configuration: AgentAdapterConfiguration;
|
|
116
|
+
environment: ExecutionEnvironmentContext;
|
|
117
|
+
sessionId?: string;
|
|
118
|
+
}>;
|
|
119
|
+
export type AgentDriver = Readonly<{
|
|
120
|
+
probe(provider: AgentAdapterKind): Promise<Readonly<{
|
|
121
|
+
installed: boolean;
|
|
122
|
+
version?: string;
|
|
123
|
+
capabilities: AgentAdapterCapabilities;
|
|
124
|
+
}>>;
|
|
125
|
+
start(input: AgentDriverInput, onEvent: (event: AgentDriverEvent) => Promise<void>): Readonly<{
|
|
126
|
+
result: Promise<AgentDriverResult>;
|
|
127
|
+
interrupt(): Promise<void>;
|
|
128
|
+
close(): Promise<void>;
|
|
129
|
+
}>;
|
|
130
|
+
}>;
|
|
131
|
+
export type AgentAdapterHost = Readonly<{
|
|
132
|
+
directory(request: HostRequest): Promise<AgentAdapterDirectory>;
|
|
133
|
+
configure(request: HostRequest, command: AgentAdapterConfigureCommand): Promise<AgentAdapterConfigureReceipt>;
|
|
134
|
+
configurationResult(request: HostRequest, commandId: string): Promise<AgentAdapterConfigureReceipt>;
|
|
135
|
+
send(request: HostRequest, command: AgentAdapterSendCommand): Promise<AgentExecutionSnapshot>;
|
|
136
|
+
observe(request: HostRequest, selector: AgentAdapterSelector): Promise<AgentExecutionSnapshot>;
|
|
137
|
+
interrupt(request: HostRequest, command: AgentAdapterInterruptCommand): Promise<AgentExecutionSnapshot>;
|
|
138
|
+
busy(workspaceKey: string): boolean;
|
|
139
|
+
close(): Promise<void>;
|
|
140
|
+
}>;
|
|
141
|
+
export type AgentAdapterBinding = Readonly<{
|
|
142
|
+
source: AgentAdapterSourceRef;
|
|
143
|
+
bindingKey: string;
|
|
144
|
+
sessionId?: string;
|
|
145
|
+
}>;
|
|
146
|
+
export type AgentAdapterExecutionRecord = Readonly<{
|
|
147
|
+
command: AgentAdapterSendCommand;
|
|
148
|
+
configuration: AgentAdapterConfiguration;
|
|
149
|
+
snapshot: AgentExecutionSnapshot;
|
|
150
|
+
}>;
|
|
151
|
+
export type AgentAdapterState = Readonly<{
|
|
152
|
+
version: 1;
|
|
153
|
+
revision: number;
|
|
154
|
+
registrations: readonly AgentAdapterRegistration[];
|
|
155
|
+
receipts: readonly AgentAdapterConfigureReceipt[];
|
|
156
|
+
bindings: readonly AgentAdapterBinding[];
|
|
157
|
+
executions: readonly AgentAdapterExecutionRecord[];
|
|
158
|
+
controls: readonly Readonly<{
|
|
159
|
+
controlId: string;
|
|
160
|
+
fingerprint: string;
|
|
161
|
+
source: AgentAdapterSourceRef;
|
|
162
|
+
bindingKey: string;
|
|
163
|
+
commandId: string;
|
|
164
|
+
state: 'sending' | 'accepted' | 'unknown';
|
|
165
|
+
}>[];
|
|
166
|
+
}>;
|
|
167
|
+
export type AgentAdapterStore = Readonly<{
|
|
168
|
+
read(): AgentAdapterState;
|
|
169
|
+
commit(expectedRevision: number, state: AgentAdapterState): void;
|
|
170
|
+
close(): void;
|
|
171
|
+
}>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { AgentAdapterConfigureCommand, AgentAdapterConfigureReceipt, AgentAdapterDirectory, AgentAdapterSourceRef, AgentAdapterSendCommand, AgentAdapterSelector, AgentAdapterInterruptCommand, AgentExecutionHandle, AgentExecutionSnapshot, AgentAdapterConfiguration } from './AgentAdapters';
|
|
2
|
+
import { parseExecutionEnvironmentRef, parseHostParticipantSendCommand, WireSchemaError } from './Schema';
|
|
3
|
+
function object(value: unknown, keys: readonly string[]): Record<string, any> { if (!value || typeof value !== 'object' || Array.isArray(value) || Object.keys(value).some(k => !keys.includes(k)))
|
|
4
|
+
throw new WireSchemaError('agent_adapter'); return value as Record<string, any>; }
|
|
5
|
+
function text(value: unknown, max = 256): asserts value is string { if (typeof value !== 'string' || !value || value.length > max)
|
|
6
|
+
throw new WireSchemaError('agent_adapter_text'); }
|
|
7
|
+
function id(value: unknown): asserts value is string { text(value, 128); if (!/^[A-Za-z0-9_-]+$/.test(value))
|
|
8
|
+
throw new WireSchemaError('agent_adapter_id'); }
|
|
9
|
+
function integer(value: unknown, min = 0): asserts value is number { if (!Number.isSafeInteger(value) || (value as number) < min)
|
|
10
|
+
throw new WireSchemaError('agent_adapter_revision'); }
|
|
11
|
+
function flag(value: unknown): asserts value is boolean { if (typeof value !== 'boolean')
|
|
12
|
+
throw new WireSchemaError('agent_adapter_flag'); }
|
|
13
|
+
function provider(value: unknown) { if (!['codex', 'claude', 'grok'].includes(String(value)))
|
|
14
|
+
throw new WireSchemaError('agent_adapter_provider'); }
|
|
15
|
+
export function parseAgentAdapterSourceRef(value: unknown): AgentAdapterSourceRef { const v = object(value, ['kind', 'daemonId', 'adapterId', 'revision']); if (v.kind !== 'agent-adapter')
|
|
16
|
+
throw new WireSchemaError('agent_adapter_source'); id(v.daemonId); id(v.adapterId); integer(v.revision, 1); return value as AgentAdapterSourceRef; }
|
|
17
|
+
export function parseAgentAdapterConfiguration(value: unknown): AgentAdapterConfiguration { const v = object(value, ['provider', 'name', 'model', 'environment', 'enabled']); provider(v.provider); text(v.name, 120); text(v.model); if (!/^[A-Za-z0-9][A-Za-z0-9_.:/-]*$/.test(v.model))
|
|
18
|
+
throw new WireSchemaError('agent_adapter_model'); parseExecutionEnvironmentRef(v.environment); flag(v.enabled); return value as AgentAdapterConfiguration; }
|
|
19
|
+
export function parseAgentAdapterConfigureCommand(value: unknown): AgentAdapterConfigureCommand { const v = object(value, ['commandId', 'adapterId', 'expectedRevision', 'configuration']); id(v.commandId); id(v.adapterId); integer(v.expectedRevision); parseAgentAdapterConfiguration(v.configuration); return value as AgentAdapterConfigureCommand; }
|
|
20
|
+
export function parseAgentAdapterConfigureReceipt(value: unknown): AgentAdapterConfigureReceipt { const v = object(value, ['commandId', 'adapterId', 'revision', 'fingerprint']); id(v.commandId); id(v.adapterId); integer(v.revision, 1); text(v.fingerprint); return value as AgentAdapterConfigureReceipt; }
|
|
21
|
+
export function parseAgentAdapterSelector(value: unknown): AgentAdapterSelector { const v = object(value, ['source', 'bindingKey', 'commandId']); parseAgentAdapterSourceRef(v.source); text(v.bindingKey); id(v.commandId); return value as AgentAdapterSelector; }
|
|
22
|
+
export function parseAgentAdapterInterruptCommand(value: unknown): AgentAdapterInterruptCommand { const v = object(value, ['source', 'bindingKey', 'commandId', 'controlId', 'expectedRevision']); parseAgentAdapterSelector({ source: v.source, bindingKey: v.bindingKey, commandId: v.commandId }); id(v.controlId); integer(v.expectedRevision, 1); return value as AgentAdapterInterruptCommand; }
|
|
23
|
+
export function parseAgentAdapterSendCommand(value: unknown): AgentAdapterSendCommand { const v = object(value, ['source', 'bindingKey', 'commandId', 'text', 'contextCut']); parseAgentAdapterSourceRef(v.source); text(v.bindingKey); id(v.commandId); text(v.text, 65536); parseHostParticipantSendCommand({ bindingKey: v.bindingKey, commandId: v.commandId, text: v.text, contextCut: v.contextCut, recipient: { kind: 'member', ref: 'adapter-wire-validation', ownerScopeRef: 'adapter-wire-validation', bindingRef: 'validation', bindingDigest: 'validation', admissionRef: 'validation' } }); return value as AgentAdapterSendCommand; }
|
|
24
|
+
export function parseAgentExecutionHandle(value: unknown): AgentExecutionHandle { const v = object(value, ['kind', 'source', 'provider', 'sessionId', 'turnId']); if (v.kind !== 'agent-execution')
|
|
25
|
+
throw new WireSchemaError('agent_execution_handle'); parseAgentAdapterSourceRef(v.source); provider(v.provider); text(v.sessionId); if (v.turnId !== undefined)
|
|
26
|
+
text(v.turnId); if (v.provider === 'codex' && !v.turnId)
|
|
27
|
+
throw new WireSchemaError('agent_execution_turn'); return value as AgentExecutionHandle; }
|
|
28
|
+
export function parseAgentExecutionSnapshot(value: unknown): AgentExecutionSnapshot { const v = object(value, ['source', 'bindingKey', 'commandId', 'fingerprint', 'revision', 'state', 'handle', 'result', 'errorCode', 'canInterrupt']); parseAgentAdapterSelector({ source: v.source, bindingKey: v.bindingKey, commandId: v.commandId }); text(v.fingerprint); integer(v.revision, 1); flag(v.canInterrupt); if (!['queued', 'sending', 'running', 'completed', 'failed', 'cancelled', 'unknown'].includes(v.state))
|
|
29
|
+
throw new WireSchemaError('agent_execution_state'); if (v.handle !== undefined) {
|
|
30
|
+
const handle = parseAgentExecutionHandle(v.handle);
|
|
31
|
+
if (['kind', 'daemonId', 'adapterId', 'revision'].some(k => (handle.source as any)[k] !== v.source[k]))
|
|
32
|
+
throw new WireSchemaError('agent_execution_source');
|
|
33
|
+
} if (v.state === 'completed' && (!v.handle || typeof v.result !== 'string'))
|
|
34
|
+
throw new WireSchemaError('agent_execution_result'); if (v.result !== undefined && (v.state !== 'completed' || typeof v.result !== 'string' || new TextEncoder().encode(v.result).byteLength > 8 * 1024 * 1024))
|
|
35
|
+
throw new WireSchemaError('agent_execution_result'); if (v.errorCode !== undefined)
|
|
36
|
+
text(v.errorCode); return value as AgentExecutionSnapshot; }
|
|
37
|
+
export function parseAgentAdapterDirectory(value: unknown): AgentAdapterDirectory { const v = object(value, ['daemonId', 'adapters']); id(v.daemonId); if (!Array.isArray(v.adapters) || v.adapters.length > 128)
|
|
38
|
+
throw new WireSchemaError('agent_adapter_directory'); for (const row of v.adapters) {
|
|
39
|
+
const a = object(row, ['source', 'configuration', 'canSubmit', 'unavailableReason', 'installedVersion', 'access', 'capabilities']);
|
|
40
|
+
const ref = parseAgentAdapterSourceRef(a.source);
|
|
41
|
+
if (ref.daemonId !== v.daemonId)
|
|
42
|
+
throw new WireSchemaError('agent_adapter_source');
|
|
43
|
+
parseAgentAdapterConfiguration(a.configuration);
|
|
44
|
+
flag(a.canSubmit);
|
|
45
|
+
if (a.unavailableReason !== undefined)
|
|
46
|
+
text(a.unavailableReason);
|
|
47
|
+
if (a.installedVersion !== undefined)
|
|
48
|
+
text(a.installedVersion, 512);
|
|
49
|
+
if (!['unverified', 'observed'].includes(a.access))
|
|
50
|
+
throw new WireSchemaError('agent_adapter_access');
|
|
51
|
+
const c = object(a.capabilities, ['submit', 'interrupt', 'observeOriginal', 'nativeTaskSpace', 'nativeActorHistory', 'attachments', 'artifacts', 'tools', 'context']);
|
|
52
|
+
for (const key of ['submit', 'interrupt', 'observeOriginal'])
|
|
53
|
+
flag(c[key]);
|
|
54
|
+
for (const key of ['nativeTaskSpace', 'nativeActorHistory', 'attachments', 'artifacts'])
|
|
55
|
+
if (c[key] !== false)
|
|
56
|
+
throw new WireSchemaError('agent_adapter_capability');
|
|
57
|
+
if (!['retained', 'explicit-cut'].includes(c.context))
|
|
58
|
+
throw new WireSchemaError('agent_adapter_context');
|
|
59
|
+
if (!['chat-only', 'read-only'].includes(c.tools))
|
|
60
|
+
throw new WireSchemaError('agent_adapter_tools');
|
|
61
|
+
} return value as AgentAdapterDirectory; }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type AttachmentMime = "text/plain" | "image/png" | "image/jpeg" | "image/webp"
|
|
2
|
+
export type HostInputPart = Readonly<
|
|
3
|
+
| { type: "text"; text: string; filename?: string }
|
|
4
|
+
| { type: "image"; mime: Exclude<AttachmentMime, "text/plain">; dataUrl: string; filename?: string }
|
|
5
|
+
| { type: "attachment"; attachmentId: string }
|
|
6
|
+
>
|
|
7
|
+
export type AttachmentOperation = Readonly<
|
|
8
|
+
| { kind: "begin"; expectedEpoch: string; uploadId: string; filename: string; mime: AttachmentMime; totalBytes: number; digest: string }
|
|
9
|
+
| { kind: "append"; expectedEpoch: string; attachmentId: string; offsetBytes: number; data: string }
|
|
10
|
+
| { kind: "release"; expectedEpoch: string; attachmentId: string }
|
|
11
|
+
>
|
|
12
|
+
export type AttachmentSummary = Readonly<{
|
|
13
|
+
attachmentId: string; epoch: string; state: "uploading" | "ready" | "released" | "expired" | "failed"
|
|
14
|
+
filename: string; mime: AttachmentMime; uploadedBytes: number; totalBytes: number; expiresAt: number; digest?: string
|
|
15
|
+
}>
|
package/src/Command.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { HostInputPart } from "./Attachment"
|
|
2
|
+
import type { ConversationOperation } from "./Conversation"
|
|
3
|
+
import type { GoalControl, GoalControlReceipt, SessionGoalView } from "./Goal"
|
|
4
|
+
export type ActorAction = "host_interaction" | "observe" | "read_history" | "send_text" | "cancel_turn" | "answer_question" | "set_model" | "compact" | "send_input" | "upload_attachment" | "set_work_mode" | "fork_conversation" | "rewind_conversation" | "set_goal" | "continue_goal" | "archive_actor" | "delete_actor"
|
|
5
|
+
export type ActorExecutionKind = "primary" | "interactive" | "delegate" | "detached"
|
|
6
|
+
export type TurnState = "queued" | "running" | "waiting_input" | "succeeded" | "failed" | "cancelled" | "interrupted"
|
|
7
|
+
|
|
8
|
+
export type ProtocolError = Readonly<{
|
|
9
|
+
code: string
|
|
10
|
+
requestId: string
|
|
11
|
+
retryable: boolean
|
|
12
|
+
message?: string
|
|
13
|
+
currentEpoch?: string
|
|
14
|
+
state?: "unknown"
|
|
15
|
+
}>
|
|
16
|
+
|
|
17
|
+
export type CommandPayloads = {
|
|
18
|
+
host_interaction: { actorId: string; operationJson: string }
|
|
19
|
+
send_text: { actorId: string; text: string }
|
|
20
|
+
send_input: { actorId: string; parts: readonly HostInputPart[] }
|
|
21
|
+
cancel_turn: { actorId: string; turnId: string }
|
|
22
|
+
answer_question: { actorId: string; turnId: string; questionnaireId: string; responseText: string }
|
|
23
|
+
create_actor: { profileId: string; displayName?: string; modelRef?: string }
|
|
24
|
+
set_model: { actorId: string; modelRef: string }
|
|
25
|
+
compact: { actorId: string; expectedHistoryRevision: string }
|
|
26
|
+
set_work_mode: { actorId: string; workMode: "build" | "plan" }
|
|
27
|
+
set_goal: GoalControl
|
|
28
|
+
continue_goal: { actorId: string; goalId: string }
|
|
29
|
+
fork_conversation: { actorId: string; expectedHistoryRevision: string; selector: { kind: "current_head" } | { kind: "through_committed_message"; messageId: string } }
|
|
30
|
+
rewind_conversation: { actorId: string; expectedHistoryRevision: string; selector: { kind: "through_committed_message"; messageId: string } }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type CommandEnvelope = {
|
|
34
|
+
[K in keyof CommandPayloads]: Readonly<{
|
|
35
|
+
commandId: string
|
|
36
|
+
surfaceId: string
|
|
37
|
+
expectedEpoch: string
|
|
38
|
+
kind: K
|
|
39
|
+
payload: Readonly<CommandPayloads[K]>
|
|
40
|
+
}>
|
|
41
|
+
}[keyof CommandPayloads]
|
|
42
|
+
|
|
43
|
+
export type AssociatedTurn = Readonly<{
|
|
44
|
+
actorId: string
|
|
45
|
+
turnId: string
|
|
46
|
+
state: TurnState
|
|
47
|
+
canCancel: boolean
|
|
48
|
+
pendingQuestionIds: readonly string[]
|
|
49
|
+
source?: "goal"
|
|
50
|
+
goalId?: string
|
|
51
|
+
}>
|
|
52
|
+
|
|
53
|
+
export type CommandReceipt = Readonly<{
|
|
54
|
+
commandId: string
|
|
55
|
+
epoch: string
|
|
56
|
+
status: "accepted"
|
|
57
|
+
turnId?: string
|
|
58
|
+
acceptedAt: string
|
|
59
|
+
}>
|
|
60
|
+
|
|
61
|
+
export type CommandStatus = Readonly<{
|
|
62
|
+
commandId: string
|
|
63
|
+
epoch: string
|
|
64
|
+
turnId?: string
|
|
65
|
+
state: "accepted" | "applied" | "rejected" | "unknown"
|
|
66
|
+
associatedTurn?: AssociatedTurn
|
|
67
|
+
result?: { actorId?: string; compact?: Readonly<{ compacted: boolean; tokensBefore: number; messagesAfter: number; historyRevision: string }>; workMode?: "build" | "plan"; conversation?: ConversationOperation; goal?: GoalControlReceipt }
|
|
68
|
+
error?: ProtocolError
|
|
69
|
+
}>
|
|
70
|
+
|
|
71
|
+
export type ExistingControl = Readonly<{
|
|
72
|
+
status: "existing_control"
|
|
73
|
+
epoch: string
|
|
74
|
+
requestedCommandId: string
|
|
75
|
+
existingControlId: string
|
|
76
|
+
actorId: string
|
|
77
|
+
turnId: string
|
|
78
|
+
questionnaireId?: string
|
|
79
|
+
}>
|
|
80
|
+
|
|
81
|
+
export type AlreadyTerminal = Readonly<{
|
|
82
|
+
status: "already_terminal"
|
|
83
|
+
epoch: string
|
|
84
|
+
requestedCommandId: string
|
|
85
|
+
associatedTurn: AssociatedTurn
|
|
86
|
+
}>
|
|
87
|
+
|
|
88
|
+
export type CommandAdmission = CommandReceipt | ExistingControl | AlreadyTerminal
|
|
89
|
+
|
|
90
|
+
export type ActorSummary = Readonly<{
|
|
91
|
+
actorId: string
|
|
92
|
+
lifecycle?: import('./ActorManagement').ActorLifecycle
|
|
93
|
+
/** Stable identity within this session, only for fixed foreground actors. */
|
|
94
|
+
memberId?: string
|
|
95
|
+
displayName: string
|
|
96
|
+
executionKind: ActorExecutionKind
|
|
97
|
+
runtimeState: "idle" | "running" | "waiting_input" | "stopped" | "failed"
|
|
98
|
+
allowedActions: readonly ActorAction[]
|
|
99
|
+
capabilities: Readonly<{ textInput: boolean; cancelTurn: boolean; questionnaireAnswer: boolean }>
|
|
100
|
+
disabledReasons?: Readonly<Record<string, string>>
|
|
101
|
+
modelRef?: string
|
|
102
|
+
workContext?: Readonly<{ workMode: "build" | "plan"; taskPhase: "normal" | "answer"; workModeUpdatedAt: string; taskPhaseUpdatedAt: string }>
|
|
103
|
+
threadGoal?: SessionGoalView
|
|
104
|
+
}>
|
|
105
|
+
|
|
106
|
+
export type CreateSessionCommand = Readonly<{
|
|
107
|
+
commandId: string
|
|
108
|
+
profileId: string
|
|
109
|
+
expectedServerInstanceId: string
|
|
110
|
+
}>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { MessagePreview } from "./Observation"
|
|
2
|
+
|
|
3
|
+
export type HistoryPage = Readonly<{
|
|
4
|
+
actorId: string
|
|
5
|
+
epoch: string
|
|
6
|
+
historyRevision: string
|
|
7
|
+
messages: readonly MessagePreview[]
|
|
8
|
+
nextCursor?: string
|
|
9
|
+
}>
|
|
10
|
+
|
|
11
|
+
export type MessageContentChunk = Readonly<{
|
|
12
|
+
codec: "public-message-json-v1"
|
|
13
|
+
encoding: "base64"
|
|
14
|
+
messageId: string
|
|
15
|
+
historyRevision: string
|
|
16
|
+
offsetBytes: number
|
|
17
|
+
totalBytes: number
|
|
18
|
+
data: string
|
|
19
|
+
nextCursor?: string
|
|
20
|
+
}>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Public publication facts, separate from execution replay and private proof. */
|
|
2
|
+
export type ConversationOperationResult =
|
|
3
|
+
| Readonly<{ kind: "fork"; targetSessionId: string; targetActorId: string; cutoffMessageId?: string; transactionId: string }>
|
|
4
|
+
| Readonly<{ kind: "rewind"; retainedMessageCount: number; removedMessageCount: number; cutoffMessageId: string; historyRevision: string; transactionId: string }>
|
|
5
|
+
|
|
6
|
+
export type ConversationOperation = Readonly<{
|
|
7
|
+
operationId: string
|
|
8
|
+
sessionId: string
|
|
9
|
+
actorId: string
|
|
10
|
+
commandId: string
|
|
11
|
+
epoch: string
|
|
12
|
+
submittedEpoch: string
|
|
13
|
+
kind: "fork" | "rewind"
|
|
14
|
+
state: "pending" | "unknown" | "applied" | "rejected"
|
|
15
|
+
result?: ConversationOperationResult
|
|
16
|
+
errorCode?: string
|
|
17
|
+
}>
|
|
18
|
+
export type ConversationOperationList = Readonly<{ epoch: string; operations: readonly ConversationOperation[] }>
|
package/src/Daemon.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { HostCapabilities, RuntimeHostPort } from './HostPort'
|
|
2
|
+
import type { ResourceEffectKind } from './Effects'
|
|
3
|
+
import type {HostRequest} from './HostPort'
|
|
4
|
+
import type {WorkflowTaskTreeRelayIntent,WorkflowTaskTreeTrustedContext,WorkflowTaskTreeOwnerCall} from './WorkflowTaskTree'
|
|
5
|
+
|
|
6
|
+
export type WorkspaceRegistration = Readonly<{
|
|
7
|
+
workspaceKey: string; workspaceId: string; workDir: string; revision: number; placement: 'workspace' | 'independent'
|
|
8
|
+
}>
|
|
9
|
+
export type DaemonCapabilities = Readonly<{
|
|
10
|
+
protocolVersion: '1'; mode: 'daemon'; daemonId: string; daemonInstanceId: string
|
|
11
|
+
globalWorkspaceKey: string; limits: { workspaces: number; workers: number; requests: number; subscriptions: number; sessionsPerWorkspace: number }
|
|
12
|
+
}>
|
|
13
|
+
export type WorkspaceView = WorkspaceRegistration & Readonly<{
|
|
14
|
+
state: 'registered' | 'opening' | 'ready' | 'closing' | 'failed'; serverInstanceId?: string; error?: string
|
|
15
|
+
}>
|
|
16
|
+
export const hostOperations = ['organizationWorkbench','organizationDirectory','previewOrganization','commandOrganization','organizationResult','hostInteractions','executionEnvironmentBusy','workflowDefinitions','workflowRuns','workflowRun','workflowEvents','commandWorkflow','workflowCommandResult','workflowMaterial','globalTaskCreateResult','globalTaskRootPlan','globalTaskDetail','globalTaskArtifact','globalTaskSpaces','globalTaskSpace','commandGlobalTaskSpace','globalTaskSpaceResult','participantDirectory', 'openParticipant', 'submitExecution', 'executionOutputPage', 'participantWork','controlParticipant','executionArtifact','participantAttachment', 'sessions', 'createSession', 'sessionMetadata', 'manageSession', 'sessionManagementResult',
|
|
17
|
+
'workflowMaterialFiles', 'workflowLaunchMaterials', 'workflowLaunch','workflowLaunchParameters','workflowAuthoring','workflowHumanReview','workflowSessionCall','workflowExecutionCatalog','workflowConversationOwner',
|
|
18
|
+
'actors', 'statistics', 'conversationOperations', 'conversationOperation', 'command', 'attachment',
|
|
19
|
+
'commandStatus', 'history', 'content', 'subscribe', 'isBusy'] as const
|
|
20
|
+
export type HostOperation = typeof hostOperations[number]
|
|
21
|
+
export type WorkerConfig = Readonly<{
|
|
22
|
+
workspace: WorkspaceRegistration; globalRoot: string; principalId: string; grantsVersion: string
|
|
23
|
+
globalAuthority?: Readonly<{daemonId:string;globalWorkspaceKey:string}>;
|
|
24
|
+
daemonAuthority?: Readonly<{daemonId:string;globalWorkspaceKey:string}>;
|
|
25
|
+
taskTreeEnabled?:boolean;
|
|
26
|
+
executionEnvironmentsEnabled?:boolean;
|
|
27
|
+
sessionLimit?: number
|
|
28
|
+
runtimeConfig?: { adapter?: string; model?: string; mcp?: boolean; metadata?: Record<string,unknown>; captureProviderRequests?: boolean; approvalMode?: 'default' | 'full-auto' | 'dangerous' }
|
|
29
|
+
}>
|
|
30
|
+
export type WorkerRequest =
|
|
31
|
+
| { kind: 'init'; config: WorkerConfig }
|
|
32
|
+
| { kind: 'call'; id: string; operation: HostOperation; args: unknown[] }
|
|
33
|
+
| { kind: 'pull' | 'unsubscribe'; id: string; subscriptionId: string }
|
|
34
|
+
| { kind: 'close'; id: string }
|
|
35
|
+
| { kind: 'prepare-close'; id: string }
|
|
36
|
+
| { kind: 'lease-result'; id: string; leaseId?: string; error?: string }
|
|
37
|
+
| { kind:'tasktree-owner-call';id:string;request:HostRequest;context:WorkflowTaskTreeTrustedContext;intent:WorkflowTaskTreeRelayIntent }
|
|
38
|
+
| { kind:'tasktree-relay-result';id:string;value?:unknown;error?:{status:number;code:string;state?:string} }
|
|
39
|
+
| {kind:'execution-environment-result';id:string;value?:import('./ExecutionEnvironment').ExecutionEnvironmentContext;error?:{status:number;code:string}}
|
|
40
|
+
export type WorkerReply =
|
|
41
|
+
| { kind: 'ready'; capabilities: HostCapabilities }
|
|
42
|
+
| { kind: 'result'; id: string; value?: unknown; error?: { status: number; code: string; currentEpoch?: string; state?: string } }
|
|
43
|
+
| { kind: 'lease'; id: string; effect: ResourceEffectKind; targets?: readonly string[];workflowTaskTree?:import('./WorkflowTaskTree').WorkflowTaskTreeOrigin;executionEnvironment?:import('./ExecutionEnvironment').ExecutionEnvironmentRef;workflowMaterialRead?:import('./Effects').WorkflowMaterialReadOrigin;authorizationRead?:import('./Effects').HostAuthorizationReadOrigin }
|
|
44
|
+
| { kind: 'lease-cancel'; id: string }
|
|
45
|
+
| { kind: 'release' | 'invalidate'; leaseId: string }
|
|
46
|
+
| { kind:'tasktree-relay';id:string;request:HostRequest;intent:WorkflowTaskTreeRelayIntent }
|
|
47
|
+
| {kind:'execution-environment-resolve';id:string;request:HostRequest;ref:import('./ExecutionEnvironment').ExecutionEnvironmentRef;action:'read'|'execute'}
|
|
48
|
+
export type WorkspaceWorker = Readonly<{
|
|
49
|
+
port: RuntimeHostPort; capabilities: HostCapabilities; exited: Promise<unknown>; close(force?: boolean): Promise<void>
|
|
50
|
+
taskTreeCall?:WorkflowTaskTreeOwnerCall;
|
|
51
|
+
}>
|
|
52
|
+
export type WorkspaceRegistryStore = Readonly<{
|
|
53
|
+
daemonId: string; list(): readonly WorkspaceRegistration[]
|
|
54
|
+
register(workDir: string, placement?: 'workspace' | 'independent'): Promise<WorkspaceRegistration>
|
|
55
|
+
remove(key: string): void; close(): void
|
|
56
|
+
resources: Readonly<{ uncertain(): readonly string[]; acquire(id: string, key: string): void; release(id: string): void; invalidate(key: string): void }>
|
|
57
|
+
}>
|
|
58
|
+
export type DaemonEffects = Readonly<{
|
|
59
|
+
registry: WorkspaceRegistryStore
|
|
60
|
+
canonicalDirectory(path: string): Promise<string>
|
|
61
|
+
createWorker(config: WorkerConfig): Promise<WorkspaceWorker>
|
|
62
|
+
newId(): string
|
|
63
|
+
}>
|
package/src/Effects.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ActorAction } from "./Command"
|
|
2
|
+
import type { ObservationFrame } from "./Observation"
|
|
3
|
+
|
|
4
|
+
export type Principal = Readonly<{ principalId: string; grantsVersion: string }>
|
|
5
|
+
export type AuthorizationTarget =
|
|
6
|
+
| Readonly<{kind:'workflow-materials';action:'read';path:string}>
|
|
7
|
+
| Readonly<{kind:'agent-adapters';action:'discover'|'configure'}>
|
|
8
|
+
| Readonly<{kind:'agent-adapter';adapterId:string;action:'observe'|'execute'|'interrupt'}>
|
|
9
|
+
| Readonly<{kind:'execution-environments';action:'discover'}>
|
|
10
|
+
| Readonly<{kind:'execution-environment';workspaceKey:string;action:'read'|'execute'}>
|
|
11
|
+
| Readonly<{kind:'daemon-schedules';action:'read'|'manage'|'execute';scheduleId?:string}>
|
|
12
|
+
| Readonly<{kind:'workflows';action:'discover'|'read'|'start'|'resume';runId?:string}>
|
|
13
|
+
| Readonly<{kind:'global-taskspaces';action:'list'|'create'}>
|
|
14
|
+
| Readonly<{kind:'global-taskspace';taskSpaceId:string;action:'read'|'edit'|'execute'|'control'}>
|
|
15
|
+
| Readonly<{ kind: "server"; action: "list_sessions" | "create_session" | "discover_sessions" | "manage_workspaces" | "stop_daemon" | "register_workflow_conversation_owner" }>
|
|
16
|
+
| Readonly<{ kind: "session"; sessionId: string; action: "open" | "import_session" | "create_actor" | "read_statistics" | "rename" | "archive" }>
|
|
17
|
+
| Readonly<{ kind: "actor"; sessionId: string; actorId: string; action: ActorAction }>
|
|
18
|
+
|
|
19
|
+
export type HostAuthorizationEffects = Readonly<{
|
|
20
|
+
permits: (principal: Principal, target: AuthorizationTarget) => boolean
|
|
21
|
+
currentGrantsVersion: (principalId: string) => string | undefined
|
|
22
|
+
}>
|
|
23
|
+
|
|
24
|
+
export type HostIdentityEffects = Readonly<{
|
|
25
|
+
newId: () => string
|
|
26
|
+
now: () => number
|
|
27
|
+
}>
|
|
28
|
+
|
|
29
|
+
export type ResourceEffectKind = "read_only" | "workspace_mutation" | "unclassified"
|
|
30
|
+
export type ResourceLease = Readonly<{ release: () => void; invalidate?: () => void }>
|
|
31
|
+
export type WorkflowMaterialReadOrigin = Readonly<{ request: import('./HostPort').HostRequest; path: string }>
|
|
32
|
+
export type HostAuthorizationReadOrigin = Readonly<{request:import('./HostPort').HostRequest;target:AuthorizationTarget}>
|
|
33
|
+
export type HostResourceEffects = Readonly<{
|
|
34
|
+
acquire: (input: Readonly<{ workDir: string; kind: ResourceEffectKind; targets?: readonly string[]; signal?: AbortSignal;workflowTaskTree?:import('./WorkflowTaskTree').WorkflowTaskTreeOrigin;executionEnvironment?:import('./ExecutionEnvironment').ExecutionEnvironmentRef;workflowMaterialRead?:WorkflowMaterialReadOrigin;authorizationRead?:HostAuthorizationReadOrigin }>) => Promise<ResourceLease>
|
|
35
|
+
}>
|
|
36
|
+
|
|
37
|
+
export type SessionWriterLeaseEffects = Readonly<{
|
|
38
|
+
acquire: (sessionStorageKey: string) => Promise<ResourceLease>
|
|
39
|
+
}>
|
|
40
|
+
|
|
41
|
+
export type ObservationCursorBinding = Readonly<{
|
|
42
|
+
epoch: string
|
|
43
|
+
principalId: string
|
|
44
|
+
grantsVersion: string
|
|
45
|
+
actors: readonly string[]
|
|
46
|
+
}>
|
|
47
|
+
export type ObservationCursorEffects = Readonly<{
|
|
48
|
+
issue: (binding: ObservationCursorBinding, seq: number) => string
|
|
49
|
+
read: (binding: ObservationCursorBinding, cursor: string) => number | undefined
|
|
50
|
+
}>
|
|
51
|
+
|
|
52
|
+
export type ObservationQueue = Readonly<{
|
|
53
|
+
frames: AsyncIterable<ObservationFrame>
|
|
54
|
+
push: (frame: ObservationFrame, lane: "bootstrap" | "live") => boolean
|
|
55
|
+
close: () => void
|
|
56
|
+
isClosed: () => boolean
|
|
57
|
+
}>
|
|
58
|
+
export type ObservationQueueEffects = Readonly<{
|
|
59
|
+
create: (onClose: () => void) => ObservationQueue
|
|
60
|
+
frameBytes: (frame: ObservationFrame) => number
|
|
61
|
+
}>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { WorkspaceRegistration } from './Daemon';
|
|
2
|
+
/** A reference to parent-owned registration, never a caller-provided filesystem path. */
|
|
3
|
+
export type ExecutionEnvironmentRef = Readonly<{
|
|
4
|
+
kind: 'daemon-workspace';
|
|
5
|
+
daemonId: string;
|
|
6
|
+
workspaceKey: string;
|
|
7
|
+
revision: number;
|
|
8
|
+
}>;
|
|
9
|
+
export type ExecutionEnvironmentView = Readonly<{
|
|
10
|
+
ref: ExecutionEnvironmentRef;
|
|
11
|
+
name: string;
|
|
12
|
+
workDir: string;
|
|
13
|
+
state: 'registered' | 'opening' | 'ready' | 'closing' | 'failed';
|
|
14
|
+
canExecute: boolean;
|
|
15
|
+
unavailableReason?: string;
|
|
16
|
+
}>;
|
|
17
|
+
export type ExecutionEnvironmentDirectory = Readonly<{
|
|
18
|
+
daemonId: string;
|
|
19
|
+
environments: readonly ExecutionEnvironmentView[];
|
|
20
|
+
}>;
|
|
21
|
+
/** Trusted composition result: public input cannot create this context or replace its path. */
|
|
22
|
+
export type ExecutionEnvironmentContext = Readonly<{
|
|
23
|
+
ref: ExecutionEnvironmentRef;
|
|
24
|
+
workspace: WorkspaceRegistration;
|
|
25
|
+
}>;
|
|
26
|
+
export type ExecutionEnvironmentEffects = Readonly<{
|
|
27
|
+
resolve(request: import('./HostPort').HostRequest, ref: ExecutionEnvironmentRef, action: 'read' | 'execute'): Promise<ExecutionEnvironmentContext>;
|
|
28
|
+
}>;
|