@myagentroam/agent 0.11.39 → 0.11.40
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/dist/cli/catalog-file.d.ts +2 -0
- package/dist/cli/main.js +11 -4
- package/dist/cli/subagent/control.d.ts +56 -0
- package/dist/cli/subagent/control.js +219 -0
- package/dist/cli/subagent/history.d.ts +17 -0
- package/dist/cli/subagent/history.js +85 -0
- package/dist/cli/subagent/index.d.ts +10 -0
- package/dist/cli/subagent/index.js +94 -0
- package/dist/cli/subagent/native.d.ts +91 -0
- package/dist/cli/subagent/native.js +359 -0
- package/dist/cli/subagent/observations.d.ts +57 -0
- package/dist/cli/subagent/observations.js +351 -0
- package/dist/cli/subagent/query.d.ts +4 -0
- package/dist/cli/subagent/query.js +114 -0
- package/dist/cli/subagent/resources.d.ts +3 -0
- package/dist/cli/subagent/resources.js +112 -0
- package/dist/cli/subagent/snapshot.d.ts +77 -0
- package/dist/cli/subagent/snapshot.js +127 -0
- package/dist/cli/subagent/start.d.ts +24 -0
- package/dist/cli/subagent/start.js +201 -0
- package/dist/cli/subagent/wait-output.d.ts +19 -0
- package/dist/cli/subagent/wait-output.js +56 -0
- package/dist/cli/subagent/wait.d.ts +175 -0
- package/dist/cli/subagent/wait.js +453 -0
- package/dist/extensions/contracts.d.ts +2 -5
- package/dist/extensions/manager.d.ts +0 -2
- package/dist/extensions/manager.js +1 -2
- package/dist/extensions/models.d.ts +3 -0
- package/dist/extensions/operation.d.ts +8 -0
- package/dist/extensions/operation.js +3 -0
- package/dist/extensions/services.d.ts +9 -1
- package/dist/extensions/services.js +26 -3
- package/dist/extensions/session-context.d.ts +18 -0
- package/dist/extensions/session-context.js +4 -0
- package/dist/extensions/session-input.d.ts +2 -2
- package/dist/extensions/session-input.js +3 -4
- package/dist/extensions/session-messages.d.ts +1 -1
- package/dist/extensions/session-tools.js +20 -3
- package/dist/extensions/session.d.ts +1 -4
- package/dist/extensions/session.js +2 -16
- package/dist/extensions/tools.js +21 -3
- package/dist/extensions.d.ts +5 -2
- package/dist/extensions.js +2 -1
- package/dist/host/local-agent-host.d.ts +2 -2
- package/dist/host/local-exec-tool.d.ts +1 -1
- package/dist/host/local-exec-tool.js +28 -3
- package/dist/host/local-tool-registry.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/model/configuration.d.ts +3 -1
- package/dist/model/configuration.js +1 -0
- package/dist/model/openai-responses.js +5 -0
- package/dist/model/responses-request.js +9 -0
- package/dist/prompts/index.js +1 -3
- package/dist/prompts/resources.d.ts +1 -5
- package/dist/prompts/resources.js +3 -12
- package/dist/prompts/subagent.d.ts +1 -1
- package/dist/prompts/subagent.js +1 -1
- package/dist/runtime/context/gc-candidates-web.d.ts +6 -0
- package/dist/runtime/context/gc-candidates-web.js +53 -1
- package/dist/runtime/context/gc-candidates.js +1 -9
- package/dist/runtime/context/gc.js +19 -11
- package/dist/runtime/context/projection.js +1 -0
- package/dist/runtime/events.d.ts +4 -3
- package/dist/runtime/execution-handle.d.ts +2 -0
- package/dist/runtime/wait.js +12 -2
- package/dist/sdk/agent.js +94 -5
- package/dist/sdk/execution-context-coordinator.d.ts +2 -3
- package/dist/sdk/execution-context-coordinator.js +3 -3
- package/dist/sdk/execution-input.d.ts +3 -4
- package/dist/sdk/execution-input.js +31 -25
- package/dist/sdk/execution-round-preparation.d.ts +1 -1
- package/dist/sdk/execution-round-preparation.js +4 -4
- package/dist/sdk/execution-tool-catalog.js +2 -10
- package/dist/sdk/execution-tool-scope.d.ts +1 -3
- package/dist/sdk/execution-tool-scope.js +10 -12
- package/dist/sdk/extension-models.js +3 -0
- package/dist/sdk/extension-session-launch.d.ts +3 -2
- package/dist/sdk/extension-session-launch.js +2 -3
- package/dist/sdk/extension-tools.js +0 -2
- package/dist/sdk/native-steer.d.ts +2 -2
- package/dist/sdk/native-steer.js +2 -2
- package/dist/sdk/session-composition.d.ts +2 -17
- package/dist/sdk/session-execution-factory.d.ts +2 -3
- package/dist/sdk/session-execution-factory.js +20 -114
- package/dist/sdk/session-execution.d.ts +13 -7
- package/dist/sdk/session-execution.js +11 -3
- package/dist/sdk/session-extension-messages.d.ts +1 -3
- package/dist/sdk/session-extension-messages.js +14 -9
- package/dist/sdk/session-extension-prompt.js +1 -3
- package/dist/sdk/session-maintenance.d.ts +1 -0
- package/dist/sdk/session-maintenance.js +16 -7
- package/dist/sdk/session-open.d.ts +2 -3
- package/dist/sdk/session-open.js +5 -24
- package/dist/sdk/session-runtime.d.ts +19 -8
- package/dist/sdk/session-runtime.js +36 -30
- package/dist/sdk/session.d.ts +3 -2
- package/dist/sdk/session.js +22 -89
- package/dist/sdk/types.d.ts +36 -0
- package/dist/session/catalog.d.ts +22 -1
- package/dist/session/catalog.js +102 -0
- package/dist/session/context-gc-checkpoint.js +30 -1
- package/dist/session/context-gc-contract.d.ts +7 -0
- package/dist/session/context-gc-replacements.d.ts +3 -0
- package/dist/session/context-gc-replacements.js +26 -0
- package/dist/session/store/contracts.d.ts +2 -2
- package/dist/session/store/jsonl/directory-index.d.ts +1 -1
- package/dist/session/store/jsonl/directory-index.js +18 -17
- package/dist/session/store/jsonl/history.js +1 -1
- package/dist/session/store/jsonl/index-transaction.js +2 -8
- package/dist/session/store/jsonl/jsonl-store.d.ts +1 -1
- package/dist/session/store/jsonl/jsonl-store.js +24 -9
- package/dist/session/types.d.ts +1 -0
- package/dist/tools/agent/sleep.js +1 -1
- package/dist/tools/callers.js +1 -12
- package/dist/tools/code-mode/dispatch.js +5 -2
- package/dist/tools/code-mode/index.d.ts +1 -1
- package/dist/tools/code-mode/index.js +2 -0
- package/dist/tools/contracts.d.ts +20 -0
- package/dist/tools/execution-limits.d.ts +5 -20
- package/dist/tools/execution-limits.js +0 -2
- package/dist/tools/execution.js +16 -4
- package/dist/tools/local/exec.js +8 -2
- package/dist/tools/output-projection.d.ts +5 -2
- package/dist/tools/output-projection.js +133 -92
- package/dist/tools/registry.js +1 -13
- package/dist/tools/runtime-context.d.ts +1 -21
- package/package.json +2 -2
- package/dist/extensions/agents.d.ts +0 -100
- package/dist/extensions/agents.js +0 -121
- package/dist/runtime/context/gc-candidates-subagent.d.ts +0 -6
- package/dist/runtime/context/gc-candidates-subagent.js +0 -100
- package/dist/sdk/extension-agent-controller.d.ts +0 -3
- package/dist/sdk/extension-agent-controller.js +0 -69
- package/dist/sdk/extension-agents.d.ts +0 -9
- package/dist/sdk/extension-agents.js +0 -58
- package/dist/sdk/subagent-backend.d.ts +0 -3
- package/dist/sdk/subagent-backend.js +0 -49
- package/dist/subagent/contracts.d.ts +0 -107
- package/dist/subagent/contracts.js +0 -1
- package/dist/subagent/limits.d.ts +0 -17
- package/dist/subagent/limits.js +0 -17
- package/dist/subagent/model-update.d.ts +0 -2
- package/dist/subagent/model-update.js +0 -81
- package/dist/subagent/session-controller.d.ts +0 -87
- package/dist/subagent/session-controller.js +0 -1343
- package/dist/subagent/task.d.ts +0 -134
- package/dist/subagent/task.js +0 -436
- package/dist/subagent/turn-contracts.d.ts +0 -64
- package/dist/subagent/turn-contracts.js +0 -1
- package/dist/subagent/wait-targets.d.ts +0 -10
- package/dist/subagent/wait-targets.js +0 -26
- package/dist/subagent/wait.d.ts +0 -26
- package/dist/subagent/wait.js +0 -73
- package/dist/tools/agent/agent-cancel.d.ts +0 -7
- package/dist/tools/agent/agent-cancel.js +0 -29
- package/dist/tools/agent/agent-message.d.ts +0 -7
- package/dist/tools/agent/agent-message.js +0 -57
- package/dist/tools/agent/agent-start.d.ts +0 -12
- package/dist/tools/agent/agent-start.js +0 -106
- package/dist/tools/agent/agent-wait.d.ts +0 -7
- package/dist/tools/agent/agent-wait.js +0 -91
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
import { AgentError } from '@myagentroam/agent';
|
|
2
|
+
import { waitForToolCondition } from '@myagentroam/agent/extensions';
|
|
3
|
+
import { target } from './control.js';
|
|
4
|
+
import { boundedUtf8, nativeChildSnapshot, projectChildEvent, publicChildSnapshot } from './snapshot.js';
|
|
5
|
+
import { modelWaitAgent } from './wait-output.js';
|
|
6
|
+
function terminalStatus(type) {
|
|
7
|
+
if (type === 'execution.completed')
|
|
8
|
+
return 'completed';
|
|
9
|
+
if (type === 'execution.failed')
|
|
10
|
+
return 'failed';
|
|
11
|
+
if (type === 'execution.cancelled')
|
|
12
|
+
return 'cancelled';
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
function terminalFact(event, full = false) {
|
|
16
|
+
const status = terminalStatus(event?.type);
|
|
17
|
+
if (!status || !event)
|
|
18
|
+
return undefined;
|
|
19
|
+
return {
|
|
20
|
+
status,
|
|
21
|
+
...(event.type === 'execution.failed'
|
|
22
|
+
? {
|
|
23
|
+
errorCode: event.code,
|
|
24
|
+
...(event.message === undefined
|
|
25
|
+
? {}
|
|
26
|
+
: { errorMessage: full ? event.message : boundedUtf8(event.message, 1000).value })
|
|
27
|
+
}
|
|
28
|
+
: {}),
|
|
29
|
+
...(event.type === 'execution.completed' && event.permissionStop !== undefined
|
|
30
|
+
? {
|
|
31
|
+
permissionStop: full
|
|
32
|
+
? event.permissionStop
|
|
33
|
+
: {
|
|
34
|
+
...event.permissionStop,
|
|
35
|
+
reason: boundedUtf8(event.permissionStop.reason, 1000).value
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
: {})
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async function captureTarget(agent, session, observations, signal, history) {
|
|
42
|
+
observations.observe(session);
|
|
43
|
+
let executionId;
|
|
44
|
+
let terminal;
|
|
45
|
+
let projection = { changedFiles: [] };
|
|
46
|
+
const listeners = new Set();
|
|
47
|
+
const snapshot = session.subscribe((event) => {
|
|
48
|
+
if (event.executionId !== executionId)
|
|
49
|
+
return;
|
|
50
|
+
projectChildEvent(projection, event, observations.full);
|
|
51
|
+
const fact = terminalFact(event, observations.full);
|
|
52
|
+
if (!fact)
|
|
53
|
+
return;
|
|
54
|
+
terminal = fact;
|
|
55
|
+
for (const listener of listeners)
|
|
56
|
+
listener();
|
|
57
|
+
});
|
|
58
|
+
executionId = snapshot.activeExecutionId;
|
|
59
|
+
if (executionId)
|
|
60
|
+
projection = observations.snapshot(session.id, executionId);
|
|
61
|
+
terminal = terminalFact(snapshot.terminalEvent, observations.full);
|
|
62
|
+
if (executionId)
|
|
63
|
+
return {
|
|
64
|
+
session,
|
|
65
|
+
executionId,
|
|
66
|
+
startedBeforeTerminal: !terminal,
|
|
67
|
+
terminal: () => terminal,
|
|
68
|
+
snapshot: () => projection,
|
|
69
|
+
subscribe: (listener) => {
|
|
70
|
+
listeners.add(listener);
|
|
71
|
+
return () => {
|
|
72
|
+
listeners.delete(listener);
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
close: () => {
|
|
76
|
+
listeners.clear();
|
|
77
|
+
snapshot.unsubscribe();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
snapshot.unsubscribe();
|
|
81
|
+
let cursor;
|
|
82
|
+
let last;
|
|
83
|
+
const pages = [];
|
|
84
|
+
do {
|
|
85
|
+
signal.throwIfAborted();
|
|
86
|
+
const page = await history.sessionHistory(session.id, {
|
|
87
|
+
limit: 100,
|
|
88
|
+
...(cursor === undefined ? {} : { cursor })
|
|
89
|
+
});
|
|
90
|
+
signal.throwIfAborted();
|
|
91
|
+
if (!last)
|
|
92
|
+
last = page.entries
|
|
93
|
+
.flatMap((entry) => (entry.kind === 'event' ? [entry.event] : []))
|
|
94
|
+
.findLast((event) => event.type === 'execution.started' || terminalStatus(event.type));
|
|
95
|
+
const events = page.entries.flatMap((entry) => entry.kind === 'event' && entry.event.executionId === last?.executionId ? [entry.event] : []);
|
|
96
|
+
pages.push(events);
|
|
97
|
+
cursor = events.some((event) => event.type === 'execution.started')
|
|
98
|
+
? undefined
|
|
99
|
+
: page.nextCursor;
|
|
100
|
+
} while (cursor);
|
|
101
|
+
const observed = observations.terminal(session.id);
|
|
102
|
+
if (observed &&
|
|
103
|
+
(observed.executionId !== last?.executionId || last.type === 'execution.started')) {
|
|
104
|
+
const fact = terminalFact(observed, observations.full);
|
|
105
|
+
return {
|
|
106
|
+
session,
|
|
107
|
+
executionId: observed.executionId,
|
|
108
|
+
terminal: () => fact,
|
|
109
|
+
snapshot: () => observations.snapshot(session.id, observed.executionId),
|
|
110
|
+
subscribe: () => () => { },
|
|
111
|
+
close: () => { }
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (last &&
|
|
115
|
+
(terminalStatus(last.type) ||
|
|
116
|
+
(last.type === 'execution.started' &&
|
|
117
|
+
(await agent.sessionExecutionWasInterrupted(session.id, last.executionId, { signal }))))) {
|
|
118
|
+
for (const events of pages.reverse())
|
|
119
|
+
for (const event of events)
|
|
120
|
+
projectChildEvent(projection, event, observations.full);
|
|
121
|
+
const finalEvent = last;
|
|
122
|
+
const fact = finalEvent.type === 'execution.started'
|
|
123
|
+
? { status: 'interrupted' }
|
|
124
|
+
: terminalFact(finalEvent, observations.full);
|
|
125
|
+
return {
|
|
126
|
+
session,
|
|
127
|
+
executionId: finalEvent.executionId,
|
|
128
|
+
terminal: () => fact,
|
|
129
|
+
snapshot: () => projection,
|
|
130
|
+
subscribe: () => () => { },
|
|
131
|
+
close: () => { }
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
throw new AgentError('MAR_AGENT_SUBAGENT_EXECUTION_NOT_FOUND', 'Session has no Execution to wait for.');
|
|
135
|
+
}
|
|
136
|
+
/** A foreground wait observes fixed Execution identities, never owning or cancelling them. */
|
|
137
|
+
export function registerWait(context, agent, observations, history = agent) {
|
|
138
|
+
context.tools.register({
|
|
139
|
+
name: 'agent_wait',
|
|
140
|
+
description: 'Wait for direct child completion or a message; defaults to completion for 30 seconds.',
|
|
141
|
+
allowedCallers: ['direct', 'programmatic'],
|
|
142
|
+
inputSchema: {
|
|
143
|
+
type: 'object',
|
|
144
|
+
properties: {
|
|
145
|
+
agentId: { type: ['string', 'null'], minLength: 1 },
|
|
146
|
+
agentIds: {
|
|
147
|
+
type: ['array', 'null'],
|
|
148
|
+
minItems: 1,
|
|
149
|
+
maxItems: 8,
|
|
150
|
+
uniqueItems: true,
|
|
151
|
+
items: { type: 'string', minLength: 1 }
|
|
152
|
+
},
|
|
153
|
+
mode: { type: ['string', 'null'], enum: ['any', 'all', null] },
|
|
154
|
+
waitFor: { type: ['string', 'null'], enum: ['message', 'completion', null] },
|
|
155
|
+
waitMs: { type: ['integer', 'null'], minimum: 0, maximum: 300000 }
|
|
156
|
+
},
|
|
157
|
+
additionalProperties: false
|
|
158
|
+
},
|
|
159
|
+
async execute(raw, call) {
|
|
160
|
+
const value = raw;
|
|
161
|
+
const input = {
|
|
162
|
+
agentId: value.agentId ?? undefined,
|
|
163
|
+
agentIds: value.agentIds ?? undefined,
|
|
164
|
+
mode: value.mode ?? undefined,
|
|
165
|
+
waitFor: value.waitFor ?? undefined,
|
|
166
|
+
waitMs: value.waitMs ?? undefined
|
|
167
|
+
};
|
|
168
|
+
return waitForChild(context, agent, observations, input, call, 'model', observations, history);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
/** Model and native callers share target capture and acknowledgement, not their limits or cursors. */
|
|
173
|
+
export async function waitForChild(context, agent, observations, input, call, mode, receipts = observations, history = agent) {
|
|
174
|
+
call.signal.throwIfAborted();
|
|
175
|
+
if ((input.agentId !== undefined && input.agentIds !== undefined) ||
|
|
176
|
+
(input.mode !== undefined && input.agentIds === undefined) ||
|
|
177
|
+
(input.agentIds &&
|
|
178
|
+
(!input.agentIds.length ||
|
|
179
|
+
(mode === 'model' && input.agentIds.length > 8) ||
|
|
180
|
+
new Set(input.agentIds).size !== input.agentIds.length)))
|
|
181
|
+
throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Invalid wait targets.');
|
|
182
|
+
if (input.untilSettled && (mode !== 'native' || !input.agentId || input.waitFor === 'message'))
|
|
183
|
+
throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'An unbounded wait requires one completion target.');
|
|
184
|
+
if (input.waitMs !== undefined &&
|
|
185
|
+
(!Number.isSafeInteger(input.waitMs) ||
|
|
186
|
+
input.waitMs < 0 ||
|
|
187
|
+
(mode === 'model' && input.waitMs > 300000)))
|
|
188
|
+
throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Invalid wait duration.');
|
|
189
|
+
const single = input.agentIds === undefined;
|
|
190
|
+
let ids = input.agentIds ?? (input.agentId ? [input.agentId] : undefined);
|
|
191
|
+
if (!ids) {
|
|
192
|
+
const parent = await agent.getSession(context.sessionId);
|
|
193
|
+
call.signal.throwIfAborted();
|
|
194
|
+
const registration = agent.observeSessionExecutions(() => { });
|
|
195
|
+
ids = registration.sessions
|
|
196
|
+
.filter((session) => session.source.parentSessionId === context.sessionId &&
|
|
197
|
+
session.workspace === parent.workspace)
|
|
198
|
+
.map((session) => session.id);
|
|
199
|
+
registration.unsubscribe();
|
|
200
|
+
if (!ids.length) {
|
|
201
|
+
const candidates = [];
|
|
202
|
+
let cursor;
|
|
203
|
+
do {
|
|
204
|
+
call.signal.throwIfAborted();
|
|
205
|
+
const page = await agent.listSessions({
|
|
206
|
+
parentSessionId: context.sessionId,
|
|
207
|
+
limit: 100,
|
|
208
|
+
...(cursor === undefined ? {} : { cursor })
|
|
209
|
+
});
|
|
210
|
+
call.signal.throwIfAborted();
|
|
211
|
+
candidates.push(...page.sessions
|
|
212
|
+
.filter((session) => session.workspace === parent.workspace)
|
|
213
|
+
.map(({ id, createdAt }) => ({ id, createdAt })));
|
|
214
|
+
cursor = page.nextCursor;
|
|
215
|
+
} while (cursor);
|
|
216
|
+
candidates.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
217
|
+
for (const candidate of candidates) {
|
|
218
|
+
call.signal.throwIfAborted();
|
|
219
|
+
try {
|
|
220
|
+
const child = await agent.getSession(candidate.id);
|
|
221
|
+
if (child.source.parentSessionId === context.sessionId &&
|
|
222
|
+
child.workspace === parent.workspace) {
|
|
223
|
+
ids = [candidate.id];
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
if (!(error instanceof AgentError) || error.code !== 'MAR_AGENT_SESSION_NOT_FOUND')
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (!ids.length)
|
|
235
|
+
throw new AgentError('MAR_AGENT_SUBAGENT_NOT_FOUND', 'No direct child Session is available.');
|
|
236
|
+
const sessions = await Promise.all(ids.map(async (id) => {
|
|
237
|
+
const result = await target(agent, context.sessionId, id);
|
|
238
|
+
if (!result.child)
|
|
239
|
+
throw new AgentError('MAR_AGENT_SUBAGENT_NOT_FOUND', 'Session is not available.');
|
|
240
|
+
const source = result.summary.source;
|
|
241
|
+
return {
|
|
242
|
+
session: result.session,
|
|
243
|
+
metadata: {
|
|
244
|
+
description: source.type === 'subagent' ? source.description : result.summary.title,
|
|
245
|
+
...(source.type === 'subagent'
|
|
246
|
+
? {
|
|
247
|
+
role: source.role,
|
|
248
|
+
...(source.extensionId === undefined ? {} : { extensionId: source.extensionId })
|
|
249
|
+
}
|
|
250
|
+
: {}),
|
|
251
|
+
...(result.summary.modelId === undefined ? {} : { modelId: result.summary.modelId }),
|
|
252
|
+
...(result.summary.modelName === undefined
|
|
253
|
+
? {}
|
|
254
|
+
: { modelName: result.summary.modelName }),
|
|
255
|
+
...(result.summary.reasoningEffort === undefined
|
|
256
|
+
? {}
|
|
257
|
+
: { reasoningEffort: result.summary.reasoningEffort })
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
}));
|
|
261
|
+
const targets = [];
|
|
262
|
+
const receiptIdentities = [];
|
|
263
|
+
try {
|
|
264
|
+
for (const { session, metadata } of sessions) {
|
|
265
|
+
const captured = await captureTarget(agent, session, observations, call.signal, history);
|
|
266
|
+
targets.push({ ...captured, metadata });
|
|
267
|
+
const identity = receipts.receipt(session.id);
|
|
268
|
+
const historical = mode === 'model' && !identity && captured.executionId
|
|
269
|
+
? await agent.sessionInputReceipt(session.id, {
|
|
270
|
+
executionId: captured.executionId,
|
|
271
|
+
source: {
|
|
272
|
+
sessionId: context.sessionId,
|
|
273
|
+
extensionId: 'subagent',
|
|
274
|
+
actors: ['model', 'code-mode']
|
|
275
|
+
},
|
|
276
|
+
signal: call.signal
|
|
277
|
+
})
|
|
278
|
+
: undefined;
|
|
279
|
+
receiptIdentities.push(identity ??
|
|
280
|
+
(historical && {
|
|
281
|
+
clientMessageId: historical.clientMessageId,
|
|
282
|
+
executionId: historical.executionId
|
|
283
|
+
}));
|
|
284
|
+
}
|
|
285
|
+
call.signal.throwIfAborted();
|
|
286
|
+
const waitFor = input.waitFor ?? 'completion';
|
|
287
|
+
const read = (item) => {
|
|
288
|
+
const observation = item.executionId
|
|
289
|
+
? observations.capture(item.session.id, item.executionId)
|
|
290
|
+
: undefined;
|
|
291
|
+
const snapshot = item.session.subscribe(() => { });
|
|
292
|
+
snapshot.unsubscribe();
|
|
293
|
+
const observed = observation?.updates.find((update) => update.kind === 'terminal');
|
|
294
|
+
const observedStatus = terminalStatus(observed?.value);
|
|
295
|
+
const terminal = item.terminal() ??
|
|
296
|
+
(snapshot.activeExecutionId === item.executionId
|
|
297
|
+
? terminalFact(snapshot.terminalEvent)
|
|
298
|
+
: undefined) ??
|
|
299
|
+
(observedStatus === undefined
|
|
300
|
+
? undefined
|
|
301
|
+
: {
|
|
302
|
+
status: observedStatus,
|
|
303
|
+
...(observed?.errorCode === undefined ? {} : { errorCode: observed.errorCode }),
|
|
304
|
+
...(observed?.errorMessage === undefined
|
|
305
|
+
? {}
|
|
306
|
+
: { errorMessage: observed.errorMessage }),
|
|
307
|
+
...(observed?.permissionStop === undefined
|
|
308
|
+
? {}
|
|
309
|
+
: { permissionStop: observed.permissionStop })
|
|
310
|
+
});
|
|
311
|
+
const message = observation?.updates.some((update) => update.kind === 'message') === true;
|
|
312
|
+
return { observation, terminal, ready: !!terminal || (waitFor === 'message' && message) };
|
|
313
|
+
};
|
|
314
|
+
const ready = () => {
|
|
315
|
+
const items = targets.map(read);
|
|
316
|
+
return input.mode === 'all'
|
|
317
|
+
? items.every((item) => item.ready)
|
|
318
|
+
: items.some((item) => item.ready);
|
|
319
|
+
};
|
|
320
|
+
const duration = input.untilSettled
|
|
321
|
+
? Number.MAX_SAFE_INTEGER
|
|
322
|
+
: (input.waitMs ?? (mode === 'model' ? 30000 : 0));
|
|
323
|
+
let outcome = 'snapshot';
|
|
324
|
+
if (duration !== 0)
|
|
325
|
+
outcome = await waitForToolCondition({
|
|
326
|
+
ready,
|
|
327
|
+
subscribe: (listener) => {
|
|
328
|
+
const releases = [
|
|
329
|
+
observations.wake.subscribe(listener),
|
|
330
|
+
...targets.map((target) => target.subscribe(listener))
|
|
331
|
+
];
|
|
332
|
+
return () => {
|
|
333
|
+
for (const release of releases)
|
|
334
|
+
release();
|
|
335
|
+
};
|
|
336
|
+
},
|
|
337
|
+
waitMs: mode === 'model' ? Math.max(10000, duration) : duration,
|
|
338
|
+
signal: call.signal,
|
|
339
|
+
...(mode === 'model' ? { interrupt: call.waitInterrupt } : {})
|
|
340
|
+
});
|
|
341
|
+
call.signal.throwIfAborted();
|
|
342
|
+
const values = targets.map((item) => ({ item, ...read(item) }));
|
|
343
|
+
const selected = single
|
|
344
|
+
? [
|
|
345
|
+
values.find((value) => value.ready) ??
|
|
346
|
+
values.find((value) => value.observation) ??
|
|
347
|
+
values[0]
|
|
348
|
+
]
|
|
349
|
+
: values;
|
|
350
|
+
const receiptFacts = await Promise.all(selected.map(async ({ item }) => {
|
|
351
|
+
const identity = receiptIdentities[targets.indexOf(item)];
|
|
352
|
+
if (!identity)
|
|
353
|
+
return undefined;
|
|
354
|
+
const fact = await agent.sessionInputReceipt(item.session.id, identity);
|
|
355
|
+
return fact &&
|
|
356
|
+
(fact.executionId === item.executionId || fact.appliedExecutionId === item.executionId)
|
|
357
|
+
? fact
|
|
358
|
+
: undefined;
|
|
359
|
+
}));
|
|
360
|
+
call.signal.throwIfAborted();
|
|
361
|
+
const agents = selected.map(({ item, observation, terminal, ready: isReady }, index) => {
|
|
362
|
+
const waitOutcome = outcome === 'snapshot'
|
|
363
|
+
? 'snapshot'
|
|
364
|
+
: terminal
|
|
365
|
+
? 'completion'
|
|
366
|
+
: isReady
|
|
367
|
+
? 'message'
|
|
368
|
+
: outcome === 'interrupted'
|
|
369
|
+
? 'interrupted'
|
|
370
|
+
: outcome === 'timeout'
|
|
371
|
+
? 'timeout'
|
|
372
|
+
: 'snapshot';
|
|
373
|
+
const include = outcome !== 'snapshot' && (isReady || outcome === 'timeout' || outcome === 'interrupted');
|
|
374
|
+
const freshTerminal = include &&
|
|
375
|
+
terminal &&
|
|
376
|
+
item.executionId &&
|
|
377
|
+
(observations.claimTerminal(item.session.id, item.executionId) ||
|
|
378
|
+
item.startedBeforeTerminal);
|
|
379
|
+
const progress = mode === 'native' && include && !terminal && observation
|
|
380
|
+
? nativeChildSnapshot(item.snapshot())
|
|
381
|
+
: undefined;
|
|
382
|
+
const projection = freshTerminal
|
|
383
|
+
? mode === 'native'
|
|
384
|
+
? nativeChildSnapshot(item.snapshot())
|
|
385
|
+
: publicChildSnapshot(item.snapshot())
|
|
386
|
+
: progress
|
|
387
|
+
? {
|
|
388
|
+
...(progress.latestMessage ? { latestMessage: progress.latestMessage } : {}),
|
|
389
|
+
...(progress.latestActivity ? { latestActivity: progress.latestActivity } : {})
|
|
390
|
+
}
|
|
391
|
+
: {};
|
|
392
|
+
const updates = mode === 'model' &&
|
|
393
|
+
'summary' in projection &&
|
|
394
|
+
projection.summary &&
|
|
395
|
+
!projection.summaryTruncated
|
|
396
|
+
? observation?.updates.filter((update) => !('final' in update && update.final))
|
|
397
|
+
: observation?.updates;
|
|
398
|
+
if (include)
|
|
399
|
+
observation?.acknowledge();
|
|
400
|
+
return {
|
|
401
|
+
agentId: item.session.id,
|
|
402
|
+
...(item.executionId ? { executionId: item.executionId } : {}),
|
|
403
|
+
...(mode === 'native' ? item.metadata : {}),
|
|
404
|
+
status: terminal?.status ?? 'running',
|
|
405
|
+
waitOutcome,
|
|
406
|
+
...(terminal?.errorCode === undefined ? {} : { errorCode: terminal.errorCode }),
|
|
407
|
+
...(terminal?.errorMessage === undefined ? {} : { errorMessage: terminal.errorMessage }),
|
|
408
|
+
...(terminal?.permissionStop === undefined
|
|
409
|
+
? {}
|
|
410
|
+
: { permissionStop: terminal.permissionStop }),
|
|
411
|
+
...projection,
|
|
412
|
+
...(receiptFacts[index] ? { receipt: receiptFacts[index] } : {}),
|
|
413
|
+
...(include && updates?.length ? { updates } : {})
|
|
414
|
+
};
|
|
415
|
+
});
|
|
416
|
+
const groupOutcome = outcome === 'ready'
|
|
417
|
+
? values.filter((value) => value.ready).every((value) => value.terminal)
|
|
418
|
+
? 'completion'
|
|
419
|
+
: 'message'
|
|
420
|
+
: outcome;
|
|
421
|
+
const data = single
|
|
422
|
+
? {
|
|
423
|
+
...agents[0],
|
|
424
|
+
waitFor,
|
|
425
|
+
...(groupOutcome === 'interrupted' ? { waitOutcome: 'interrupted', reason: 'steer' } : {})
|
|
426
|
+
}
|
|
427
|
+
: {
|
|
428
|
+
mode: input.mode ?? 'any',
|
|
429
|
+
waitFor,
|
|
430
|
+
waitOutcome: groupOutcome,
|
|
431
|
+
...(groupOutcome === 'interrupted' ? { reason: 'steer' } : {}),
|
|
432
|
+
agents,
|
|
433
|
+
pendingAgentIds: values
|
|
434
|
+
.filter((value) => !value.ready)
|
|
435
|
+
.map((value) => value.item.session.id)
|
|
436
|
+
};
|
|
437
|
+
if (mode === 'native')
|
|
438
|
+
return { data, content: JSON.stringify(data) };
|
|
439
|
+
const modelAgents = agents.map((item) => modelWaitAgent(item, Math.floor(34000 / agents.length)));
|
|
440
|
+
const modelData = single
|
|
441
|
+
? {
|
|
442
|
+
...modelAgents[0],
|
|
443
|
+
waitFor,
|
|
444
|
+
...(groupOutcome === 'interrupted' ? { waitOutcome: 'interrupted', reason: 'steer' } : {})
|
|
445
|
+
}
|
|
446
|
+
: { ...data, agents: modelAgents };
|
|
447
|
+
return { data, content: JSON.stringify(modelData) };
|
|
448
|
+
}
|
|
449
|
+
finally {
|
|
450
|
+
for (const item of targets)
|
|
451
|
+
item.close();
|
|
452
|
+
}
|
|
453
|
+
}
|
|
@@ -3,7 +3,6 @@ import type { ExtensionPromptSection } from './prompt-composition.js';
|
|
|
3
3
|
import type { ExtensionCapabilitySnapshot } from './capabilities.js';
|
|
4
4
|
import type { ExtensionPromptComposition } from './prompt-composition.js';
|
|
5
5
|
import type { ExtensionModelsApi } from './models.js';
|
|
6
|
-
import type { ExtensionAgentsApi } from './agents.js';
|
|
7
6
|
import type { ExtensionDataApi } from './data.js';
|
|
8
7
|
import type { ExtensionMcpApi } from './mcp.js';
|
|
9
8
|
import type { ExtensionFilesApi } from './files.js';
|
|
@@ -18,7 +17,6 @@ import type { ExtensionOperationContext } from './operation.js';
|
|
|
18
17
|
import type { ExtensionDisposer, ExtensionResourceRegistration, ExtensionResourceScope } from './resources.js';
|
|
19
18
|
import type { ExtensionServiceRegistry } from './services.js';
|
|
20
19
|
import type { ExtensionToolRef, ExtensionToolInvocation, ExtensionToolCheck, ExtensionToolSpec } from './tools.js';
|
|
21
|
-
import type { DomainAgentOperations, DomainAgentFacts } from './agents.js';
|
|
22
20
|
import type { DomainCompactOperations, DomainCompactFacts } from './compaction.js';
|
|
23
21
|
import type { DomainEnvironmentOperations, DomainEnvironmentFacts } from './environment.js';
|
|
24
22
|
import type { DomainFileOperations, DomainFileFacts } from './files.js';
|
|
@@ -32,9 +30,9 @@ import type { DomainPromptInputOperations, DomainPromptInputFacts } from './prom
|
|
|
32
30
|
import type { DomainSessionOperations, DomainSessionFacts } from './session-input.js';
|
|
33
31
|
import type { DomainSettingsOperations, DomainSettingsFacts } from './settings.js';
|
|
34
32
|
import type { DomainToolOperations, DomainToolFacts } from './tools.js';
|
|
35
|
-
export interface ExtensionDomainOperations extends
|
|
33
|
+
export interface ExtensionDomainOperations extends DomainCompactOperations, DomainEnvironmentOperations, DomainFileOperations, DomainMcpOperations, DomainModelRequestOperations, DomainModelStreamOperations, DomainNetworkOperations, DomainProcessOperations, DomainPromptCompositionOperations, DomainPromptInputOperations, DomainSessionOperations, DomainSettingsOperations, DomainToolOperations {
|
|
36
34
|
}
|
|
37
|
-
export interface ExtensionDomainFacts extends
|
|
35
|
+
export interface ExtensionDomainFacts extends DomainCompactFacts, DomainEnvironmentFacts, DomainFileFacts, DomainMcpFacts, DomainModelRequestFacts, DomainModelStreamFacts, DomainNetworkFacts, DomainProcessFacts, DomainPromptCompositionFacts, DomainPromptInputFacts, DomainSessionFacts, DomainSettingsFacts, DomainToolFacts {
|
|
38
36
|
}
|
|
39
37
|
export interface ExtensionHookRegistrar {
|
|
40
38
|
intercept<Key extends keyof ExtensionDomainOperations>(key: Key, handler: ExtensionInterceptor<ExtensionDomainOperations[Key]['input'], ExtensionDomainOperations[Key]['output']>, options?: ExtensionHookOptions): ExtensionResourceRegistration;
|
|
@@ -55,7 +53,6 @@ export interface AgentExtensionContext {
|
|
|
55
53
|
}
|
|
56
54
|
export interface SessionExtensionContext extends AgentExtensionContext {
|
|
57
55
|
readonly mcp?: ExtensionMcpApi;
|
|
58
|
-
readonly agents?: ExtensionAgentsApi;
|
|
59
56
|
readonly environment?: ExtensionEnvironmentApi;
|
|
60
57
|
readonly settings?: ExtensionSettingsApi;
|
|
61
58
|
readonly processes?: ExtensionProcessesApi;
|
|
@@ -7,7 +7,6 @@ import type { ExtensionModelsBackend } from './models.js';
|
|
|
7
7
|
import type { ExtensionCheckpointBackend, ExtensionStoreBackend } from './data.js';
|
|
8
8
|
import type { ExtensionSessionBackend } from './session-input.js';
|
|
9
9
|
import type { AgentHostExtensionPorts } from './host-ports.js';
|
|
10
|
-
import { type ExtensionAgentsBackend } from './agents.js';
|
|
11
10
|
export interface ExtensionManagerOptions {
|
|
12
11
|
readonly toolRuntime: ExtensionToolRuntime;
|
|
13
12
|
readonly hostPorts?: AgentHostExtensionPorts;
|
|
@@ -19,7 +18,6 @@ export interface ExtensionManagerOptions {
|
|
|
19
18
|
readonly checkpoint?: ExtensionCheckpointBackend;
|
|
20
19
|
readonly store?: ExtensionStoreBackend;
|
|
21
20
|
readonly sessionBackend?: (sessionId: string) => ExtensionSessionBackend | undefined;
|
|
22
|
-
readonly agentsBackend?: (sessionId: string) => ExtensionAgentsBackend | undefined;
|
|
23
21
|
readonly allowTool?: (sessionId: string, name: string, definition?: ExtensionToolBinding['definition']) => boolean;
|
|
24
22
|
readonly scheduleTool?: (sessionId: string) => ExtensionSession['scheduleTool'];
|
|
25
23
|
}
|
|
@@ -4,7 +4,6 @@ import { ExtensionResourceScope } from './resources.js';
|
|
|
4
4
|
import { ExtensionServices } from './services.js';
|
|
5
5
|
import { ExtensionSession } from './session.js';
|
|
6
6
|
import { coreSettingsBinding, settingsCapabilities } from './settings.js';
|
|
7
|
-
import { agentCapabilities } from './agents.js';
|
|
8
7
|
/** Agent admission coordinates a single composition generation, never parallel replacement loops. */
|
|
9
8
|
export class ExtensionManager {
|
|
10
9
|
options;
|
|
@@ -109,7 +108,7 @@ export class ExtensionManager {
|
|
|
109
108
|
throw new AgentError('MAR_AGENT_EXTENSION_COMPOSITION_FAILED', 'Required extension initialization failed.');
|
|
110
109
|
let session = this.#sessions.get(sessionId);
|
|
111
110
|
if (!session) {
|
|
112
|
-
session = new ExtensionSession(this.options.toolRuntime, sessionId, this.#epochs.get(sessionId) ?? 0, this.#agentServices, this.operations,
|
|
111
|
+
session = new ExtensionSession(this.options.toolRuntime, sessionId, this.#epochs.get(sessionId) ?? 0, this.#agentServices, this.operations, this.capabilities, (diagnostic) => this.#diagnose(diagnostic), (context) => this.options.baseTools?.(sessionId, context) ?? [], this.options.models, this.options.checkpoint, this.options.sessionBackend?.(sessionId), this.options.hostPorts, (name, definition) => this.options.allowTool?.(sessionId, name, definition) ?? true, this.options.scheduleTool?.(sessionId), this.options.store);
|
|
113
112
|
this.#sessions.set(sessionId, session);
|
|
114
113
|
try {
|
|
115
114
|
await this.#attach(session, loadingSignal, baseTools);
|
|
@@ -13,6 +13,9 @@ export interface ExtensionModelDescription {
|
|
|
13
13
|
readonly maxOutputTokens: number;
|
|
14
14
|
readonly inputCapabilities: readonly string[];
|
|
15
15
|
readonly reasoningEfforts: readonly AgentReasoningEffort[];
|
|
16
|
+
readonly defaultReasoningEffort: AgentReasoningEffort;
|
|
17
|
+
readonly conversationModel: boolean;
|
|
18
|
+
readonly subagentModel: boolean;
|
|
16
19
|
readonly isDefault: boolean;
|
|
17
20
|
}
|
|
18
21
|
export type ExtensionModelTextBlock = ModelTextBlock;
|
|
@@ -10,6 +10,14 @@ export interface ExtensionOperationContext {
|
|
|
10
10
|
/** Correlation with the actual enclosing tool call; not an authority token. */
|
|
11
11
|
readonly toolCallId?: string;
|
|
12
12
|
readonly parentToolCallId?: string;
|
|
13
|
+
/** Wakes a foreground tool wait when its Execution receives a steering input. */
|
|
14
|
+
readonly waitInterrupt?: import('../runtime/wait.js').ToolWaitInterrupt;
|
|
15
|
+
/** Present only for the exact tool invocation explicitly approved by the Host. */
|
|
16
|
+
readonly permission?: Readonly<{
|
|
17
|
+
readonly decision: 'approved';
|
|
18
|
+
}>;
|
|
19
|
+
/** Effective execution permission mode, when the invocation has an execution owner. */
|
|
20
|
+
readonly permissionMode?: import('../tools/permission-contract.js').PermissionMode;
|
|
13
21
|
readonly actor: 'model' | 'sdk' | 'extension' | 'code-mode';
|
|
14
22
|
readonly entry: 'direct' | 'programmatic' | 'native-api';
|
|
15
23
|
readonly signal: AbortSignal;
|
|
@@ -59,6 +59,9 @@ export class ExtensionOperations {
|
|
|
59
59
|
...((identity.parentToolCallId ?? parent.parentToolCallId) === undefined
|
|
60
60
|
? {}
|
|
61
61
|
: { parentToolCallId: identity.parentToolCallId ?? parent.parentToolCallId }),
|
|
62
|
+
...((identity.waitInterrupt ?? parent.waitInterrupt) === undefined
|
|
63
|
+
? {}
|
|
64
|
+
: { waitInterrupt: identity.waitInterrupt ?? parent.waitInterrupt }),
|
|
62
65
|
entry: parent.entry,
|
|
63
66
|
signal: AbortSignal.any([identity.signal, parent.signal])
|
|
64
67
|
}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type { ExtensionResourceScope } from './resources.js';
|
|
2
|
+
import type { ExtensionOperationRunner } from './operation.js';
|
|
3
|
+
export interface ExtensionServiceConsumer {
|
|
4
|
+
readonly run: ExtensionOperationRunner;
|
|
5
|
+
readonly onDispose: (dispose: () => void | Promise<void>) => void;
|
|
6
|
+
}
|
|
2
7
|
export interface ExtensionServiceKey<T> {
|
|
3
8
|
readonly id: string;
|
|
4
9
|
readonly scope: 'agent' | 'session';
|
|
5
10
|
/** Compile-time service contract; never examined at runtime. */
|
|
6
11
|
readonly contract?: (implementation: T) => T;
|
|
12
|
+
/** Bind a service to the framework-owned consuming Session scope. */
|
|
13
|
+
readonly bindConsumer?: (implementation: T, consumer: ExtensionServiceConsumer) => T;
|
|
7
14
|
}
|
|
8
15
|
export interface ExtensionServiceRegistry {
|
|
9
16
|
provide<T>(key: ExtensionServiceKey<T>, implementation: T): void;
|
|
@@ -23,9 +30,10 @@ export declare class ExtensionServices {
|
|
|
23
30
|
readonly id: string;
|
|
24
31
|
readonly scope: 'agent' | 'session';
|
|
25
32
|
}): boolean;
|
|
33
|
+
resolve<T>(key: ExtensionServiceKey<T>): T | undefined;
|
|
26
34
|
hasOwned(key: {
|
|
27
35
|
readonly id: string;
|
|
28
36
|
readonly scope: 'agent' | 'session';
|
|
29
37
|
}, owner: ExtensionResourceScope): boolean;
|
|
30
|
-
bind(owner: ExtensionResourceScope): ExtensionServiceRegistry;
|
|
38
|
+
bind(owner: ExtensionResourceScope, run?: ExtensionOperationRunner): ExtensionServiceRegistry;
|
|
31
39
|
}
|
|
@@ -11,16 +11,30 @@ export class ExtensionServices {
|
|
|
11
11
|
has(key) {
|
|
12
12
|
return this.#find(key) !== undefined;
|
|
13
13
|
}
|
|
14
|
+
resolve(key) {
|
|
15
|
+
return this.#find(key)?.value;
|
|
16
|
+
}
|
|
14
17
|
hasOwned(key, owner) {
|
|
15
18
|
return (key.scope === this.scope &&
|
|
16
19
|
(this.#entries.get(key.id)?.some((entry) => entry.owner === owner) ?? false));
|
|
17
20
|
}
|
|
18
|
-
bind(owner) {
|
|
21
|
+
bind(owner, run) {
|
|
19
22
|
const consume = (key, options) => {
|
|
20
23
|
const entry = this.#find(key);
|
|
21
24
|
if (!entry && !options?.optional)
|
|
22
25
|
throw new AgentError('MAR_AGENT_EXTENSION_DEPENDENCY_MISSING', 'Required service is unavailable.');
|
|
23
|
-
|
|
26
|
+
if (!entry)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (!entry.bindConsumer)
|
|
29
|
+
return entry.value;
|
|
30
|
+
if (!run)
|
|
31
|
+
throw new AgentError('MAR_AGENT_EXTENSION_SERVICE_SCOPE', 'Service requires a Session consumer.');
|
|
32
|
+
return entry.bindConsumer(entry.value, {
|
|
33
|
+
run,
|
|
34
|
+
onDispose: (dispose) => {
|
|
35
|
+
owner.effect(() => dispose);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
24
38
|
};
|
|
25
39
|
const publish = (key, value, replace) => {
|
|
26
40
|
if (key.scope !== this.scope)
|
|
@@ -32,7 +46,16 @@ export class ExtensionServices {
|
|
|
32
46
|
throw new AgentError('MAR_AGENT_EXTENSION_SERVICE_CONFLICT', 'Service is already provided.');
|
|
33
47
|
if (!entries.length && replace)
|
|
34
48
|
throw new AgentError('MAR_AGENT_EXTENSION_DEPENDENCY_MISSING', 'Service replacement has no lower provider.');
|
|
35
|
-
const
|
|
49
|
+
const binder = key.bindConsumer;
|
|
50
|
+
const entry = {
|
|
51
|
+
value,
|
|
52
|
+
owner,
|
|
53
|
+
...(binder
|
|
54
|
+
? {
|
|
55
|
+
bindConsumer: (implementation, consumer) => binder(implementation, consumer)
|
|
56
|
+
}
|
|
57
|
+
: {})
|
|
58
|
+
};
|
|
36
59
|
owner.effect(() => () => {
|
|
37
60
|
const index = entries.indexOf(entry);
|
|
38
61
|
if (index !== -1)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ExtensionServiceKey } from './services.js';
|
|
2
|
+
/** Context proposed by a Session-scoped extension, confirmed only after durable submission. */
|
|
3
|
+
export interface ExtensionSessionContextItem {
|
|
4
|
+
readonly content: string;
|
|
5
|
+
/** Synchronously confirm only the version captured by collect, not later observations. */
|
|
6
|
+
acknowledge(): void;
|
|
7
|
+
}
|
|
8
|
+
export interface ExtensionSessionContextProvider {
|
|
9
|
+
collect(signal: AbortSignal): readonly ExtensionSessionContextItem[] | Promise<readonly ExtensionSessionContextItem[]>;
|
|
10
|
+
/** Bounded resource summary for normal and compact context reconstruction; consumes no updates. */
|
|
11
|
+
resources?(signal: AbortSignal): readonly string[] | Promise<readonly string[]>;
|
|
12
|
+
/** Wakes an active wait when unread model-visible context becomes available. */
|
|
13
|
+
readonly wake?: {
|
|
14
|
+
pending(): boolean;
|
|
15
|
+
subscribe(listener: () => void): () => void;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export declare const SESSION_CONTEXT_PROVIDER: ExtensionServiceKey<ExtensionSessionContextProvider>;
|