@myagentroam/agent 0.9.159 → 0.9.160
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/agent-core/extensions/agents.d.ts +69 -0
- package/dist/agent-core/extensions/agents.js +160 -0
- package/dist/agent-core/extensions/contracts.d.ts +260 -0
- package/dist/agent-core/extensions/contracts.js +1 -0
- package/dist/agent-core/extensions/data.d.ts +84 -0
- package/dist/agent-core/extensions/data.js +83 -0
- package/dist/agent-core/extensions/environment.d.ts +27 -0
- package/dist/agent-core/extensions/environment.js +52 -0
- package/dist/agent-core/extensions/files.d.ts +64 -0
- package/dist/agent-core/extensions/files.js +26 -0
- package/dist/agent-core/extensions/hooks.d.ts +32 -0
- package/dist/agent-core/extensions/hooks.js +135 -0
- package/dist/agent-core/extensions/manager.d.ts +39 -0
- package/dist/agent-core/extensions/manager.js +458 -0
- package/dist/agent-core/extensions/mcp.d.ts +99 -0
- package/dist/agent-core/extensions/mcp.js +433 -0
- package/dist/agent-core/extensions/model-request.d.ts +60 -0
- package/dist/agent-core/extensions/model-request.js +167 -0
- package/dist/agent-core/extensions/model-stream.d.ts +9 -0
- package/dist/agent-core/extensions/model-stream.js +101 -0
- package/dist/agent-core/extensions/models.d.ts +43 -0
- package/dist/agent-core/extensions/models.js +1 -0
- package/dist/agent-core/extensions/network.d.ts +32 -0
- package/dist/agent-core/extensions/network.js +97 -0
- package/dist/agent-core/extensions/operation.d.ts +29 -0
- package/dist/agent-core/extensions/operation.js +98 -0
- package/dist/agent-core/extensions/processes.d.ts +52 -0
- package/dist/agent-core/extensions/processes.js +283 -0
- package/dist/agent-core/extensions/prompt-composition.d.ts +24 -0
- package/dist/agent-core/extensions/prompt-composition.js +106 -0
- package/dist/agent-core/extensions/prompt-input.d.ts +23 -0
- package/dist/agent-core/extensions/prompt-input.js +46 -0
- package/dist/agent-core/extensions/resources.d.ts +27 -0
- package/dist/agent-core/extensions/resources.js +221 -0
- package/dist/agent-core/extensions/services.d.ts +31 -0
- package/dist/agent-core/extensions/services.js +61 -0
- package/dist/agent-core/extensions/session-input.d.ts +151 -0
- package/dist/agent-core/extensions/session-input.js +351 -0
- package/dist/agent-core/extensions/session-messages.d.ts +41 -0
- package/dist/agent-core/extensions/session-messages.js +76 -0
- package/dist/agent-core/extensions/session.d.ts +68 -0
- package/dist/agent-core/extensions/session.js +593 -0
- package/dist/agent-core/extensions/settings.d.ts +59 -0
- package/dist/agent-core/extensions/settings.js +115 -0
- package/dist/agent-core/extensions/store.d.ts +10 -0
- package/dist/agent-core/extensions/store.js +131 -0
- package/dist/agent-core/extensions/tools.d.ts +61 -0
- package/dist/agent-core/extensions/tools.js +266 -0
- package/dist/agent-core/host/contracts.d.ts +25 -0
- package/dist/agent-core/host/local-agent-host.d.ts +10 -1
- package/dist/agent-core/host/local-agent-host.js +132 -20
- package/dist/agent-core/host/local-file-access.d.ts +30 -0
- package/dist/agent-core/host/local-file-access.js +107 -0
- package/dist/agent-core/host/local-network-access.d.ts +6 -0
- package/dist/agent-core/host/local-network-access.js +97 -0
- package/dist/agent-core/host/local-process-executor.d.ts +5 -1
- package/dist/agent-core/host/local-session-environment.d.ts +18 -0
- package/dist/agent-core/host/local-session-environment.js +102 -0
- package/dist/agent-core/model/anthropic-messages.js +73 -23
- package/dist/agent-core/model/contracts.d.ts +12 -0
- package/dist/agent-core/model/openai-responses.js +73 -12
- package/dist/agent-core/model/text-blocks.d.ts +7 -0
- package/dist/agent-core/model/text-blocks.js +40 -0
- package/dist/agent-core/prompts/index.d.ts +6 -2
- package/dist/agent-core/prompts/index.js +38 -24
- package/dist/agent-core/runtime/context/gc-tokens.js +6 -1
- package/dist/agent-core/runtime/context/normalize.js +21 -1
- package/dist/agent-core/runtime/context/projection.js +35 -1
- package/dist/agent-core/runtime/context/request-budget.js +5 -2
- package/dist/agent-core/runtime/context/restore.d.ts +5 -0
- package/dist/agent-core/runtime/context/restore.js +47 -4
- package/dist/agent-core/runtime/context/usage.js +2 -3
- package/dist/agent-core/runtime/contracts.d.ts +2 -0
- package/dist/agent-core/runtime/execution.js +5 -2
- package/dist/agent-core/sdk/agent.js +177 -40
- package/dist/agent-core/sdk/extension-agents.d.ts +9 -0
- package/dist/agent-core/sdk/extension-agents.js +51 -0
- package/dist/agent-core/sdk/extension-models.d.ts +13 -0
- package/dist/agent-core/sdk/extension-models.js +128 -0
- package/dist/agent-core/sdk/extension-session.d.ts +30 -0
- package/dist/agent-core/sdk/extension-session.js +103 -0
- package/dist/agent-core/sdk/extension-tools.d.ts +16 -0
- package/dist/agent-core/sdk/extension-tools.js +126 -0
- package/dist/agent-core/sdk/session.d.ts +26 -2
- package/dist/agent-core/sdk/session.js +1215 -506
- package/dist/agent-core/sdk/types.d.ts +3 -0
- package/dist/agent-core/session/context-gc-checkpoint.js +1 -1
- package/dist/agent-core/session/jsonl-store.d.ts +28 -8
- package/dist/agent-core/session/jsonl-store.js +124 -84
- package/dist/agent-core/session/types.d.ts +4 -1
- package/dist/agent-core/storage/file-lock.d.ts +4 -0
- package/dist/agent-core/storage/file-lock.js +83 -0
- package/dist/agent-core/subagent/contracts.d.ts +11 -1
- package/dist/agent-core/subagent/scheduler.d.ts +8 -0
- package/dist/agent-core/subagent/session-controller.d.ts +22 -1
- package/dist/agent-core/subagent/session-controller.js +355 -98
- package/dist/agent-core/tools/agent/agent-start.d.ts +1 -1
- package/dist/agent-core/tools/code-mode/cells.js +5 -15
- package/dist/agent-core/tools/code-mode/dispatch.d.ts +1 -0
- package/dist/agent-core/tools/code-mode/dispatch.js +13 -1
- package/dist/agent-core/tools/code-mode/index.js +1 -2
- package/dist/agent-core/tools/code-mode/observations.d.ts +5 -0
- package/dist/agent-core/tools/code-mode/observations.js +16 -5
- package/dist/agent-core/tools/code-mode/quickjs-engine.js +10 -5
- package/dist/agent-core/tools/execution.d.ts +11 -2
- package/dist/agent-core/tools/execution.js +58 -21
- package/dist/agent-core/tools/input.d.ts +2 -0
- package/dist/agent-core/tools/input.js +36 -0
- package/dist/agent-core/tools/local/apply-patch.js +21 -17
- package/dist/agent-core/tools/local/exec.d.ts +4 -4
- package/dist/agent-core/tools/local/exec.js +234 -62
- package/dist/agent-core/tools/local/registry.d.ts +6 -0
- package/dist/agent-core/tools/local/registry.js +60 -9
- package/dist/agent-core/tools/mcp/catalog.d.ts +6 -2
- package/dist/agent-core/tools/mcp/catalog.js +4 -4
- package/dist/agent-core/tools/mcp/history.js +2 -2
- package/dist/agent-core/tools/mcp/tool-search.d.ts +3 -1
- package/dist/agent-core/tools/mcp/tool-search.js +2 -2
- package/dist/agent-core/tools/output-projection.d.ts +3 -1
- package/dist/agent-core/tools/output-projection.js +11 -2
- package/dist/agent-core/tools/runtime-context.d.ts +1 -0
- package/dist/agent-core/tools/runtime.d.ts +3 -1
- package/dist/agent-core/tools/runtime.js +22 -7
- package/dist/agent-core/tools/scheduler.d.ts +2 -0
- package/dist/agent-core/tools/scheduler.js +43 -6
- package/dist/index.d.ts +21 -0
- package/dist/sandbox/linux/bubblewrap-sandbox-executor.js +5 -2
- package/package.json +1 -1
|
@@ -4,9 +4,14 @@ import type { EnvironmentContextState } from './contracts.js';
|
|
|
4
4
|
import { type ContextProjection } from './projection.js';
|
|
5
5
|
export declare function restoreMessages(store: JsonlSessionStore, sessionId: string, records: readonly import('../../session/jsonl-store.js').SessionRecord[], options: {
|
|
6
6
|
includeImages: boolean;
|
|
7
|
+
strictImages?: boolean;
|
|
7
8
|
currentTurnId?: string;
|
|
8
9
|
projection?: ContextProjection;
|
|
9
10
|
}): Promise<{
|
|
11
|
+
toolOutcomes: WeakMap<ModelMessage, {
|
|
12
|
+
isError: boolean;
|
|
13
|
+
result?: unknown;
|
|
14
|
+
}>;
|
|
10
15
|
environmentState: EnvironmentContextState | undefined;
|
|
11
16
|
userMessages: string[];
|
|
12
17
|
messages: ModelMessage[];
|
|
@@ -2,9 +2,11 @@ import { MarAgentError } from '../../error.js';
|
|
|
2
2
|
import { compactSummaryFromCheckpoint, replacementHistoryFromCheckpoint } from '../../session/jsonl-store.js';
|
|
3
3
|
import { compactedHistoryMessages, continuationMessage } from '../compaction/history.js';
|
|
4
4
|
import { environmentContextUpdate, restoreEnvironmentState } from './environment.js';
|
|
5
|
-
import { buildContextProjection } from './projection.js';
|
|
5
|
+
import { buildContextProjection, restoreModelContext } from './projection.js';
|
|
6
6
|
export async function restoreMessages(store, sessionId, records, options) {
|
|
7
7
|
const messages = [];
|
|
8
|
+
const outcomes = new Map();
|
|
9
|
+
const toolOutcomes = new WeakMap();
|
|
8
10
|
const modelProjection = new Map((options.projection ??
|
|
9
11
|
buildContextProjection(records, (await store.getSession(sessionId)).workspace)).entries.map((entry) => [entry.record.recordId, entry.message]));
|
|
10
12
|
let userMessages = [];
|
|
@@ -13,15 +15,30 @@ export async function restoreMessages(store, sessionId, records, options) {
|
|
|
13
15
|
let environmentState;
|
|
14
16
|
for (const record of records) {
|
|
15
17
|
const payload = record.payload;
|
|
18
|
+
if ((record.type === 'tool.completed' || record.type === 'tool.failed') &&
|
|
19
|
+
typeof payload.callId === 'string') {
|
|
20
|
+
const result = record.type === 'tool.failed' ? payload.message : payload.data;
|
|
21
|
+
outcomes.set(JSON.stringify([record.executionId, payload.callId]), {
|
|
22
|
+
isError: record.type === 'tool.failed',
|
|
23
|
+
...(result === undefined ? {} : { result: structuredClone(result) })
|
|
24
|
+
});
|
|
25
|
+
}
|
|
16
26
|
const compactSummary = compactSummaryFromCheckpoint(record);
|
|
17
|
-
if (record.type === 'turn.user'
|
|
27
|
+
if ((record.type === 'turn.user' || record.type === 'extension.input') &&
|
|
28
|
+
typeof payload.prompt === 'string') {
|
|
18
29
|
userMessages.push(payload.prompt);
|
|
19
30
|
let images = [];
|
|
20
31
|
if (options.includeImages)
|
|
21
32
|
try {
|
|
22
33
|
images = await store.readInputImages(sessionId, payload.images);
|
|
34
|
+
if (options.strictImages &&
|
|
35
|
+
payload.images !== undefined &&
|
|
36
|
+
(!Array.isArray(payload.images) || images.length !== payload.images.length))
|
|
37
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Session input images cannot be fully restored.');
|
|
23
38
|
}
|
|
24
39
|
catch (error) {
|
|
40
|
+
if (options.strictImages)
|
|
41
|
+
throw error;
|
|
25
42
|
if (!(error instanceof MarAgentError) || error.code !== 'MAR_AGENT_SESSION_CORRUPT')
|
|
26
43
|
throw error;
|
|
27
44
|
ignoredImages += Array.isArray(payload.images) ? payload.images.length : 1;
|
|
@@ -30,9 +47,20 @@ export async function restoreMessages(store, sessionId, records, options) {
|
|
|
30
47
|
currentTurnUserIndex = messages.length;
|
|
31
48
|
messages.push({
|
|
32
49
|
role: 'user',
|
|
33
|
-
content: payload.prompt,
|
|
50
|
+
content: typeof payload.modelText === 'string' ? payload.modelText : payload.prompt,
|
|
34
51
|
...(images.length ? { images } : {})
|
|
35
52
|
});
|
|
53
|
+
const context = payload.modelContext ?? payload.context;
|
|
54
|
+
if (payload.contextRecords !== true && Array.isArray(context))
|
|
55
|
+
for (const text of context)
|
|
56
|
+
if (typeof text === 'string')
|
|
57
|
+
messages.push({ role: 'user', content: text });
|
|
58
|
+
}
|
|
59
|
+
else if (record.type === 'input.context') {
|
|
60
|
+
if (Array.isArray(payload.modelContext))
|
|
61
|
+
for (const text of payload.modelContext)
|
|
62
|
+
if (typeof text === 'string')
|
|
63
|
+
messages.push({ role: 'user', content: text });
|
|
36
64
|
}
|
|
37
65
|
else if ((record.type === 'message.completed' || record.type === 'plan.completed') &&
|
|
38
66
|
typeof payload.text === 'string')
|
|
@@ -49,6 +77,14 @@ export async function restoreMessages(store, sessionId, records, options) {
|
|
|
49
77
|
messages.push(...(history
|
|
50
78
|
? compactedHistoryMessages(history)
|
|
51
79
|
: [{ role: 'user', content: continuationMessage(compactSummary) }]));
|
|
80
|
+
if (Array.isArray(payload.retainedModelContext))
|
|
81
|
+
for (const item of payload.retainedModelContext) {
|
|
82
|
+
if (!item || typeof item !== 'object' || item.role !== 'user')
|
|
83
|
+
continue;
|
|
84
|
+
const message = restoreModelContext(item);
|
|
85
|
+
if (message)
|
|
86
|
+
messages.push(message);
|
|
87
|
+
}
|
|
52
88
|
}
|
|
53
89
|
else if (record.type === 'context.environment') {
|
|
54
90
|
const current = restoreEnvironmentState(payload);
|
|
@@ -61,12 +97,19 @@ export async function restoreMessages(store, sessionId, records, options) {
|
|
|
61
97
|
}
|
|
62
98
|
else if (record.type === 'model.context') {
|
|
63
99
|
const message = modelProjection.get(record.recordId);
|
|
64
|
-
if (message)
|
|
100
|
+
if (message) {
|
|
65
101
|
messages.push(message);
|
|
102
|
+
if (message.role === 'tool' && message.callId !== undefined) {
|
|
103
|
+
const outcome = outcomes.get(JSON.stringify([record.executionId, message.callId]));
|
|
104
|
+
if (outcome)
|
|
105
|
+
toolOutcomes.set(message, outcome);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
66
108
|
}
|
|
67
109
|
}
|
|
68
110
|
const completedToolCalls = new Set(messages.filter((message) => message.role === 'tool').map((message) => message.callId));
|
|
69
111
|
return {
|
|
112
|
+
toolOutcomes,
|
|
70
113
|
environmentState,
|
|
71
114
|
userMessages,
|
|
72
115
|
messages: messages.filter((message) => {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { isDeepStrictEqual } from 'node:util';
|
|
2
2
|
import { marAgentReasoningEffortSchema } from '../../model/configuration.js';
|
|
3
3
|
import { compactSummaryFromCheckpoint } from '../../session/jsonl-store.js';
|
|
4
|
-
import {
|
|
5
|
-
import { stableJson } from './request-budget.js';
|
|
4
|
+
import { estimatedRequestTokens } from './request-budget.js';
|
|
6
5
|
export function latestModelUsage(records, selectedModelId) {
|
|
7
6
|
let usage;
|
|
8
7
|
const toolCallIds = new Set();
|
|
@@ -104,7 +103,7 @@ export function shouldUseNativeCompaction(input) {
|
|
|
104
103
|
const historyDelta = appendOnlyUsageDelta(input.latestUsage, input.historyMessages);
|
|
105
104
|
if (historyDelta === undefined)
|
|
106
105
|
return false;
|
|
107
|
-
const appendedTokens =
|
|
106
|
+
const appendedTokens = estimatedRequestTokens('', [...historyDelta, ...input.appendedMessages], []);
|
|
108
107
|
return (input.latestUsage.contextInputTokens + input.latestUsage.outputTokens + appendedTokens <=
|
|
109
108
|
input.contextWindowTokens);
|
|
110
109
|
}
|
|
@@ -25,6 +25,8 @@ export interface ExecutionResult {
|
|
|
25
25
|
executionId: string;
|
|
26
26
|
status: 'completed' | 'failed' | 'cancelled';
|
|
27
27
|
finalAnswer: string;
|
|
28
|
+
/** The input hook answered without admitting input; no model Turn was requested. */
|
|
29
|
+
inputHandled?: boolean;
|
|
28
30
|
errorCode?: string;
|
|
29
31
|
errorMessage?: string;
|
|
30
32
|
}
|
|
@@ -302,6 +302,8 @@ export class ExecutionLoop {
|
|
|
302
302
|
const message = {
|
|
303
303
|
role: 'tool',
|
|
304
304
|
callId: result.call.callId,
|
|
305
|
+
name: result.call.name,
|
|
306
|
+
isError: result.failed,
|
|
305
307
|
content: result.content,
|
|
306
308
|
...(result.calls ? { calls: result.calls } : {}),
|
|
307
309
|
...(result.observations ? { observations: result.observations } : {}),
|
|
@@ -312,6 +314,8 @@ export class ExecutionLoop {
|
|
|
312
314
|
await input.appendContext({
|
|
313
315
|
role: message.role,
|
|
314
316
|
callId: result.call.callId,
|
|
317
|
+
name: result.call.name,
|
|
318
|
+
isError: result.failed,
|
|
315
319
|
content: message.content,
|
|
316
320
|
...(message.calls ? { calls: message.calls } : {}),
|
|
317
321
|
...(message.observations ? { observations: message.observations } : {}),
|
|
@@ -351,8 +355,7 @@ export class ExecutionLoop {
|
|
|
351
355
|
throw aborted ?? new MarAgentError('MAR_AGENT_EXECUTION_CANCELLED', 'Execution cancelled.');
|
|
352
356
|
}
|
|
353
357
|
input.rolloutBudget?.assertAvailable();
|
|
354
|
-
if (input.mailbox.hasPending()) {
|
|
355
|
-
await input.mailbox.append();
|
|
358
|
+
if (input.mailbox.hasPending() && (await input.mailbox.append())) {
|
|
356
359
|
this.finalAnswer = '';
|
|
357
360
|
continue;
|
|
358
361
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { addModelCredentialProviders, closeModelAdapters, resolveAgentModels } from './model-runtime.js';
|
|
2
2
|
import { createSessionOpener } from './session.js';
|
|
3
3
|
import { MarAgentError } from '../error.js';
|
|
4
|
+
import { ExtensionManager } from '../extensions/manager.js';
|
|
5
|
+
import { createExtensionModels } from './extension-models.js';
|
|
4
6
|
import { negotiateHost } from '../host/contracts.js';
|
|
7
|
+
import { toolCallers } from '../tools/callers.js';
|
|
5
8
|
import { AnthropicMessagesAdapter } from '../model/anthropic-messages.js';
|
|
6
9
|
import { OpenAiResponsesAdapter } from '../model/openai-responses.js';
|
|
7
10
|
import { resolveRolloutBudgetOptions } from '../runtime/rollout-budget.js';
|
|
@@ -29,6 +32,16 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
29
32
|
const sessionRuntimes = new Map();
|
|
30
33
|
const sessionWriterOwner = {};
|
|
31
34
|
let disposed = false;
|
|
35
|
+
let disposal;
|
|
36
|
+
const sessionLifecycles = new Set();
|
|
37
|
+
const trackSessionLifecycle = (operation) => {
|
|
38
|
+
if (disposed)
|
|
39
|
+
return Promise.reject(new MarAgentError('MAR_AGENT_DISPOSED', 'Agent is disposed.'));
|
|
40
|
+
const pending = operation();
|
|
41
|
+
sessionLifecycles.add(pending);
|
|
42
|
+
void pending.finally(() => sessionLifecycles.delete(pending)).catch(() => undefined);
|
|
43
|
+
return pending;
|
|
44
|
+
};
|
|
32
45
|
let reconfiguring = false;
|
|
33
46
|
const createAdapter = (modelId, configuredModels = models) => {
|
|
34
47
|
const configuration = configuredModels.get(modelId);
|
|
@@ -40,6 +53,85 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
40
53
|
: new AnthropicMessagesAdapter(configuration)));
|
|
41
54
|
};
|
|
42
55
|
const activeSessionIds = () => new Set([...active.keys()].map((key) => key.slice(0, key.indexOf(':'))));
|
|
56
|
+
const extensions = new ExtensionManager({
|
|
57
|
+
...(options.host.extensionPorts === undefined
|
|
58
|
+
? {}
|
|
59
|
+
: { hostPorts: options.host.extensionPorts }),
|
|
60
|
+
extensions: options.runtimeExtensions ?? [],
|
|
61
|
+
capabilities: [
|
|
62
|
+
'tools',
|
|
63
|
+
'prompts',
|
|
64
|
+
'commands',
|
|
65
|
+
'clock',
|
|
66
|
+
'services',
|
|
67
|
+
'hooks',
|
|
68
|
+
'observability',
|
|
69
|
+
'models',
|
|
70
|
+
'data.state',
|
|
71
|
+
'data.checkpoint',
|
|
72
|
+
'data.store',
|
|
73
|
+
'session',
|
|
74
|
+
'agents',
|
|
75
|
+
'settings',
|
|
76
|
+
...(options.host.extensionPorts?.environment ? ['environment'] : []),
|
|
77
|
+
...(options.host.extensionPorts?.files ? ['files'] : []),
|
|
78
|
+
...(options.host.extensionPorts?.network ? ['network'] : []),
|
|
79
|
+
...(options.host.extensionPorts?.mcp ? ['mcp'] : []),
|
|
80
|
+
...(options.host.extensionPorts?.processes ? ['processes'] : [])
|
|
81
|
+
],
|
|
82
|
+
models: createExtensionModels(() => ({ models, defaultModelId }), createAdapter, (snapshot, call) => {
|
|
83
|
+
const snapshots = sessionRuntimes.get(call.sessionId)?.requestSnapshots;
|
|
84
|
+
if (!snapshots)
|
|
85
|
+
throw new MarAgentError('MAR_AGENT_MODEL_SNAPSHOT_INVALID', 'Request snapshot is unavailable.');
|
|
86
|
+
return snapshots.resolve(snapshot);
|
|
87
|
+
}),
|
|
88
|
+
sessionBackend: (id) => sessionRuntimes.get(id)?.sessionBackend,
|
|
89
|
+
agentsBackend: (id) => sessionRuntimes.get(id)?.agentsBackend,
|
|
90
|
+
scheduleTool: (id) => (definition, run) => {
|
|
91
|
+
const schedule = sessionRuntimes.get(id)?.scheduleTool;
|
|
92
|
+
if (!schedule)
|
|
93
|
+
throw new MarAgentError('MAR_AGENT_TOOL_NOT_AVAILABLE', 'Session tool scheduler is unavailable.');
|
|
94
|
+
return schedule(definition, run);
|
|
95
|
+
},
|
|
96
|
+
baseTools: (id, context) => {
|
|
97
|
+
const execution = sessionRuntimes.get(id)?.toolSources;
|
|
98
|
+
if (context?.executionId && execution?.executionId === context.executionId)
|
|
99
|
+
return execution.bindings;
|
|
100
|
+
return (options.host.extensionPorts?.tools?.catalog(id, context?.executionId) ?? []).map((source) => ({
|
|
101
|
+
definition: {
|
|
102
|
+
...source.definition,
|
|
103
|
+
allowedCallers: [
|
|
104
|
+
...toolCallers({
|
|
105
|
+
...source.definition,
|
|
106
|
+
allowedCallers: source.definition.allowedCallers ??
|
|
107
|
+
(source.mcp ? ['direct', 'programmatic'] : ['direct'])
|
|
108
|
+
})
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
source: source.source,
|
|
112
|
+
...(source.mcp === undefined ? {} : { mcp: source.mcp }),
|
|
113
|
+
...(source.available === undefined ? {} : { available: source.available.bind(source) }),
|
|
114
|
+
invoke: source.execute.bind(source)
|
|
115
|
+
}));
|
|
116
|
+
},
|
|
117
|
+
allowTool: (id, name, definition) => {
|
|
118
|
+
const runtime = sessionRuntimes.get(id);
|
|
119
|
+
return !(runtime?.sourceType === 'subagent' && definition?.agentScope === 'ROOT_ONLY');
|
|
120
|
+
},
|
|
121
|
+
checkpoint: {
|
|
122
|
+
read: async (extensionId, key, call) => {
|
|
123
|
+
call.signal.throwIfAborted();
|
|
124
|
+
return store.readExtensionCheckpoint(call.sessionId, extensionId, key);
|
|
125
|
+
},
|
|
126
|
+
write: (extensionId, key, value, expectedRevision, call) => store.writeExtensionCheckpoint(call.sessionId, extensionId, key, value, expectedRevision, {
|
|
127
|
+
owner: sessionWriterOwner,
|
|
128
|
+
signal: call.signal,
|
|
129
|
+
...(call.executionId ? { executionId: call.executionId } : {}),
|
|
130
|
+
...(call.turnId ? { turnId: call.turnId } : {})
|
|
131
|
+
})
|
|
132
|
+
},
|
|
133
|
+
busyExcept: (sessionId) => [...activeSessionIds()].some((id) => id !== sessionId)
|
|
134
|
+
});
|
|
43
135
|
const activeAdaptersExcept = (sessionId) => {
|
|
44
136
|
const activeAdapters = new Set();
|
|
45
137
|
for (const [candidateSessionId, runtime] of sessionRuntimes)
|
|
@@ -61,6 +153,7 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
61
153
|
description,
|
|
62
154
|
settings,
|
|
63
155
|
store,
|
|
156
|
+
extensions,
|
|
64
157
|
registry: {
|
|
65
158
|
active,
|
|
66
159
|
activeExecutionAdapters,
|
|
@@ -81,21 +174,40 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
81
174
|
}
|
|
82
175
|
});
|
|
83
176
|
return {
|
|
177
|
+
extensionDiagnostics: () => extensions.diagnostics(),
|
|
84
178
|
createSession: async (input) => openSession((await store.createSession(input)).id, input.workspace),
|
|
85
179
|
openSession: (id) => openSession(id),
|
|
86
180
|
listSessions: (input) => store.list(input),
|
|
87
181
|
getSession: (id) => store.getSession(id),
|
|
88
182
|
setSessionTitle: (id, title, input) => store.updateTitle(id, title, { ...input, automatic: input?.automatic ?? false }, sessionWriterOwner),
|
|
89
|
-
clearSession: async (
|
|
183
|
+
clearSession: (id) => trackSessionLifecycle(async () => {
|
|
90
184
|
const runtime = sessionRuntimes.get(id);
|
|
91
185
|
if ([...active.keys()].some((key) => key.startsWith(`${id}:`)))
|
|
92
186
|
throw new MarAgentError('MAR_AGENT_EXECUTION_ACTIVE', 'A session cannot be cleared while an execution is active.');
|
|
93
|
-
await
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
187
|
+
await extensions.endSession(id, 'clear');
|
|
188
|
+
extensions.retireSession(id);
|
|
189
|
+
await completeAgentCleanup([
|
|
190
|
+
() => extensions.clearSession(id),
|
|
191
|
+
() => runtime?.inputs?.retire(),
|
|
192
|
+
() => runtime?.subagents?.dispose(),
|
|
193
|
+
() => closeModelAdapters(runtime === undefined ? [] : [...runtime.adapters.values()]),
|
|
194
|
+
() => {
|
|
195
|
+
// Existing SDK Session handles share this runtime and remain usable after clear.
|
|
196
|
+
if (runtime) {
|
|
197
|
+
runtime.adapters.clear();
|
|
198
|
+
runtime.adapterGeneration = modelGeneration;
|
|
199
|
+
delete runtime.todo;
|
|
200
|
+
delete runtime.subagents;
|
|
201
|
+
delete runtime.subagentsOpening;
|
|
202
|
+
delete runtime.contextualWorldState;
|
|
203
|
+
delete runtime.inputs;
|
|
204
|
+
delete runtime.requestSnapshots;
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
() => options.host.disposeSessionResources?.(id),
|
|
208
|
+
() => store.clearSession(id)
|
|
209
|
+
]);
|
|
210
|
+
}),
|
|
99
211
|
setSystemInstruction: (systemInstruction) => {
|
|
100
212
|
if (disposed)
|
|
101
213
|
throw new MarAgentError('MAR_AGENT_DISPOSED', 'Agent is disposed.');
|
|
@@ -169,52 +281,77 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
169
281
|
reconfiguring = false;
|
|
170
282
|
}
|
|
171
283
|
},
|
|
172
|
-
deleteSession: async (
|
|
284
|
+
deleteSession: (id) => trackSessionLifecycle(async () => {
|
|
173
285
|
const sessionIds = await store.sessionTree(id);
|
|
174
286
|
const sessionIdSet = new Set(sessionIds);
|
|
175
287
|
const executionKeys = [...active.keys()].filter((key) => sessionIdSet.has(key.slice(0, key.indexOf(':'))));
|
|
176
288
|
for (const key of executionKeys)
|
|
177
289
|
active.get(key)?.abort();
|
|
290
|
+
await Promise.all(sessionIds.map((sessionId) => extensions.endSession(sessionId, 'other', false)));
|
|
291
|
+
for (const sessionId of sessionIds)
|
|
292
|
+
extensions.retireSession(sessionId);
|
|
178
293
|
const runtimes = sessionIds.flatMap((sessionId) => {
|
|
179
294
|
const runtime = sessionRuntimes.get(sessionId);
|
|
180
295
|
sessionRuntimes.delete(sessionId);
|
|
181
296
|
return runtime === undefined ? [] : [runtime];
|
|
182
297
|
});
|
|
183
|
-
await
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
298
|
+
await completeAgentCleanup([
|
|
299
|
+
...sessionIds.map((sessionId) => () => extensions.clearSession(sessionId)),
|
|
300
|
+
...runtimes.map((runtime) => () => runtime.inputs?.retire()),
|
|
301
|
+
...runtimes.map((runtime) => () => runtime.subagents?.dispose()),
|
|
302
|
+
() => Promise.allSettled(executionKeys.flatMap((key) => {
|
|
303
|
+
const result = executionResults.get(key);
|
|
304
|
+
return result === undefined ? [] : [result];
|
|
305
|
+
})),
|
|
306
|
+
() => closeModelAdapters(runtimes.flatMap((runtime) => [...runtime.adapters.values()])),
|
|
307
|
+
...sessionIds.map((sessionId) => () => options.host.disposeSessionResources?.(sessionId)),
|
|
308
|
+
() => store.delete(id)
|
|
309
|
+
]);
|
|
310
|
+
}),
|
|
311
|
+
dispose: () => {
|
|
312
|
+
if (disposal)
|
|
313
|
+
return disposal;
|
|
195
314
|
disposed = true;
|
|
196
315
|
for (const controller of active.values())
|
|
197
316
|
controller.abort();
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
317
|
+
// Explicit end observers finish in a separate lifecycle frame before Session retirement.
|
|
318
|
+
const extensionDisposal = extensions.dispose();
|
|
319
|
+
void extensionDisposal.catch(() => undefined);
|
|
320
|
+
const runtimes = [...sessionRuntimes.values()];
|
|
321
|
+
disposal = completeAgentCleanup([
|
|
322
|
+
async () => {
|
|
323
|
+
const results = await Promise.allSettled([...sessionLifecycles]);
|
|
324
|
+
const failure = results.find((result) => result.status === 'rejected');
|
|
325
|
+
if (failure?.status === 'rejected')
|
|
326
|
+
throw failure.reason;
|
|
327
|
+
},
|
|
328
|
+
() => extensionDisposal,
|
|
329
|
+
...runtimes.map((runtime) => () => runtime.inputs?.retire()),
|
|
330
|
+
...runtimes.map((runtime) => () => runtime.subagents?.dispose()),
|
|
331
|
+
() => Promise.allSettled([...executionResults.values()]),
|
|
332
|
+
() => closeModelAdapters(runtimes.flatMap((runtime) => [...runtime.adapters.values()])),
|
|
333
|
+
...[...credentialProviders].map((provider) => () => provider.close()),
|
|
334
|
+
() => options.host.dispose(),
|
|
335
|
+
() => store.close()
|
|
336
|
+
]);
|
|
337
|
+
return disposal;
|
|
218
338
|
}
|
|
219
339
|
};
|
|
220
340
|
}
|
|
341
|
+
/** Finish independent cleanup steps and preserve the first authoritative failure. */
|
|
342
|
+
async function completeAgentCleanup(steps) {
|
|
343
|
+
let failed = false;
|
|
344
|
+
let failure;
|
|
345
|
+
for (const step of steps) {
|
|
346
|
+
try {
|
|
347
|
+
await step();
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
if (!failed)
|
|
351
|
+
failure = error;
|
|
352
|
+
failed = true;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (failed)
|
|
356
|
+
throw failure;
|
|
357
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CoreAgentsBackend } from '../extensions/agents.js';
|
|
2
|
+
import type { CoreOperationContext } from '../extensions/operation.js';
|
|
3
|
+
import type { SubagentParentOperation, SubagentSessionController } from '../subagent/session-controller.js';
|
|
4
|
+
/** Uses the Session's sole task controller, including its durable children and queue. */
|
|
5
|
+
export declare function createExtensionAgentsBackend(input: {
|
|
6
|
+
readonly controller: () => Promise<SubagentSessionController>;
|
|
7
|
+
readonly existingController: () => SubagentSessionController | undefined;
|
|
8
|
+
readonly parent: (controller: SubagentSessionController, call: CoreOperationContext) => SubagentParentOperation;
|
|
9
|
+
}): CoreAgentsBackend;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { MarAgentError } from '../error.js';
|
|
2
|
+
/** Uses the Session's sole task controller, including its durable children and queue. */
|
|
3
|
+
export function createExtensionAgentsBackend(input) {
|
|
4
|
+
const withController = async (call, run) => {
|
|
5
|
+
call.signal.throwIfAborted();
|
|
6
|
+
const controller = await input.controller();
|
|
7
|
+
call.signal.throwIfAborted();
|
|
8
|
+
return controller.withOperation(input.parent(controller, call), () => run(controller));
|
|
9
|
+
};
|
|
10
|
+
return {
|
|
11
|
+
own: (owner) => async () => {
|
|
12
|
+
await input.existingController()?.cancelOwned(owner);
|
|
13
|
+
},
|
|
14
|
+
spawn: (task, call) => withController(call, (controller) => controller.run({
|
|
15
|
+
description: task.description ?? 'Extension agent',
|
|
16
|
+
prompt: task.prompt,
|
|
17
|
+
role: task.role ?? 'general-purpose',
|
|
18
|
+
background: task.background ?? true,
|
|
19
|
+
...(task.modelId === undefined ? {} : { modelId: task.modelId }),
|
|
20
|
+
...(task.reasoningEffort === undefined ? {} : { reasoningEffort: task.reasoningEffort })
|
|
21
|
+
}, {
|
|
22
|
+
signal: call.signal,
|
|
23
|
+
...(task.turnSignal === undefined ? {} : { turnSignal: task.turnSignal }),
|
|
24
|
+
...(task.waitFor === undefined ? {} : { waitFor: task.waitFor }),
|
|
25
|
+
onCreated: (created) => {
|
|
26
|
+
if (created.status === 'failed')
|
|
27
|
+
throw new MarAgentError(created.errorCode ?? 'MAR_AGENT_SUBAGENT_FAILED', created.errorMessage ?? 'Agent could not start.');
|
|
28
|
+
}
|
|
29
|
+
})),
|
|
30
|
+
list: (call) => withController(call, async (controller) => controller.inspectAll()),
|
|
31
|
+
inspect: (target, call) => withController(call, (controller) => controller.inspect(target.agentId)),
|
|
32
|
+
wait: (target, call) => withController(call, (controller) => {
|
|
33
|
+
const options = {
|
|
34
|
+
waitMs: target.waitMs ?? 30_000,
|
|
35
|
+
...(target.untilSettled === undefined ? {} : { untilSettled: target.untilSettled }),
|
|
36
|
+
...(target.waitFor === undefined ? {} : { waitFor: target.waitFor }),
|
|
37
|
+
signal: call.signal
|
|
38
|
+
};
|
|
39
|
+
if (target.untilSettled && target.agentId === undefined)
|
|
40
|
+
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'An unbounded wait requires an agent id.');
|
|
41
|
+
return target.agentId === undefined
|
|
42
|
+
? controller.outputAny(options)
|
|
43
|
+
: controller.output(target.agentId, options);
|
|
44
|
+
}),
|
|
45
|
+
message: (target, call) => withController(call, (controller) => controller.message(target.agentId, target.message, {
|
|
46
|
+
...(target.delivery === undefined ? {} : { delivery: target.delivery }),
|
|
47
|
+
signal: call.signal
|
|
48
|
+
})),
|
|
49
|
+
cancel: (target, call) => withController(call, (controller) => controller.cancel(target.agentId))
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CoreModelsBackend } from '../extensions/models.js';
|
|
2
|
+
import type { CoreOperationContext } from '../extensions/operation.js';
|
|
3
|
+
import type { CoreModelRequest, CoreRequestSnapshot } from '../extensions/model-request.js';
|
|
4
|
+
import type { ModelAdapter, ModelRequest } from '../model/contracts.js';
|
|
5
|
+
import type { ResolvedModelConfiguration } from './model-runtime.js';
|
|
6
|
+
export declare function createExtensionModels(state: () => {
|
|
7
|
+
models: ReadonlyMap<string, ResolvedModelConfiguration>;
|
|
8
|
+
defaultModelId: string;
|
|
9
|
+
}, createAdapter: (modelId: string, models: ReadonlyMap<string, ResolvedModelConfiguration>) => ModelAdapter, resolveSnapshot?: (snapshot: CoreRequestSnapshot, call: CoreOperationContext) => {
|
|
10
|
+
modelId: string;
|
|
11
|
+
request: ModelRequest;
|
|
12
|
+
view: CoreModelRequest;
|
|
13
|
+
}): CoreModelsBackend;
|