@myagentroam/agent 0.9.134 → 0.9.136
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/main.js +10 -1
- package/dist/host/local-agent-host.d.ts +9 -7
- package/dist/host/local-agent-host.js +77 -5
- package/dist/host/local-process-executor.d.ts +2 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -0
- package/dist/model/catalog-file.d.ts +4 -0
- package/dist/model/configuration.d.ts +13 -0
- package/dist/model/configuration.js +11 -0
- package/dist/model/contracts.d.ts +7 -0
- package/dist/model/openai-responses.d.ts +1 -1
- package/dist/model/openai-responses.js +90 -21
- package/dist/prompts/workflow.js +2 -0
- package/dist/runtime/context-gc-runtime.d.ts +1 -0
- package/dist/runtime/context-gc-runtime.js +3 -0
- package/dist/runtime/context-gc-tokens.d.ts +1 -0
- package/dist/runtime/context-gc-tokens.js +1 -1
- package/dist/runtime/context-gc.d.ts +1 -0
- package/dist/runtime/context-gc.js +85 -8
- package/dist/runtime/context-projection.js +19 -2
- package/dist/sandbox/linux/bubblewrap-sandbox-executor.js +29 -2
- package/dist/sdk/agent.js +212 -25
- package/dist/sdk/mcp-catalog.d.ts +13 -0
- package/dist/sdk/mcp-catalog.js +219 -0
- package/dist/sdk/types.d.ts +50 -1
- package/dist/session/context-gc-checkpoint.d.ts +7 -1
- package/dist/session/context-gc-checkpoint.js +28 -2
- package/dist/session/context-gc-replacements.d.ts +7 -0
- package/dist/session/context-gc-replacements.js +26 -0
- package/dist/session/jsonl-store.d.ts +6 -0
- package/dist/session/jsonl-store.js +92 -54
- package/dist/subagent/scheduler.d.ts +3 -3
- package/dist/subagent/session-controller.d.ts +1 -1
- package/dist/tools/agent-cancel.js +1 -0
- package/dist/tools/agent-message.js +1 -0
- package/dist/tools/agent-start.js +1 -0
- package/dist/tools/agent-wait.js +1 -0
- package/dist/tools/apply-patch.js +2 -1
- package/dist/tools/callers.d.ts +4 -0
- package/dist/tools/callers.js +18 -0
- package/dist/tools/code-mode/engine.d.ts +43 -0
- package/dist/tools/code-mode/engine.js +1 -0
- package/dist/tools/code-mode/quickjs-engine.d.ts +2 -0
- package/dist/tools/code-mode/quickjs-engine.js +454 -0
- package/dist/tools/code-mode/state.d.ts +20 -0
- package/dist/tools/code-mode/state.js +82 -0
- package/dist/tools/code-mode/worker.d.ts +1 -0
- package/dist/tools/code-mode/worker.js +65 -0
- package/dist/tools/code-mode.d.ts +5 -3
- package/dist/tools/code-mode.js +129 -120
- package/dist/tools/exec.js +1 -0
- package/dist/tools/execution-limits.d.ts +8 -0
- package/dist/tools/execution-limits.js +8 -0
- package/dist/tools/local-registry.d.ts +2 -0
- package/dist/tools/local-registry.js +1 -1
- package/dist/tools/question.js +1 -0
- package/dist/tools/read.js +1 -0
- package/dist/tools/registry.js +3 -0
- package/dist/tools/runtime-context.d.ts +2 -0
- package/dist/tools/runtime.js +3 -1
- package/dist/tools/skill.js +1 -0
- package/dist/tools/todo-read.js +1 -0
- package/dist/tools/todo-write.js +1 -0
- package/dist/tools/tool-search.d.ts +43 -0
- package/dist/tools/tool-search.js +278 -0
- package/dist/tools/view-image.js +1 -0
- package/dist/tools/web-fetch.js +1 -0
- package/dist/tools/web-search.js +1 -0
- package/package.json +3 -1
package/dist/sdk/agent.js
CHANGED
|
@@ -3,7 +3,7 @@ import { isDeepStrictEqual } from 'node:util';
|
|
|
3
3
|
import { describeMarAgentError, MarAgentError } from '../error.js';
|
|
4
4
|
import { negotiateHost } from '../host/contracts.js';
|
|
5
5
|
import { AnthropicMessagesAdapter, isAnthropicRecoverableStreamError } from '../model/anthropic-messages.js';
|
|
6
|
-
import { marAgentReasoningEffortSchema, resolveModelDefaultReasoningEffort } from '../model/configuration.js';
|
|
6
|
+
import { marAgentReasoningEffortSchema, resolveModelDefaultReasoningEffort, usesResponsesConfigurationUpdates } from '../model/configuration.js';
|
|
7
7
|
import { modelRetryMaxAttempts, isRetryableModelRequestError, waitForModelRetry } from '../model/http.js';
|
|
8
8
|
import { OpenAiResponsesAdapter, isOpenAiResponsesRecoverableStreamError } from '../model/openai-responses.js';
|
|
9
9
|
import { AsyncQueue } from '../runtime/async-queue.js';
|
|
@@ -11,9 +11,11 @@ import { PlanOutputPrefix, splitPlanOutput } from '../runtime/plan-output.js';
|
|
|
11
11
|
import { AGENT_EXECUTION_POLICY } from '../runtime/execution-policy.js';
|
|
12
12
|
import { RolloutBudget, resolveRolloutBudgetOptions } from '../runtime/rollout-budget.js';
|
|
13
13
|
import { ContextGcRuntime } from '../runtime/context-gc-runtime.js';
|
|
14
|
-
import { buildContextProjection } from '../runtime/context-projection.js';
|
|
14
|
+
import { buildContextProjection, providerToolCallId, providerToolName } from '../runtime/context-projection.js';
|
|
15
15
|
import { countModelTokens, countTextLines, truncateModelText } from '../runtime/token-budget.js';
|
|
16
16
|
import { TOOL_EXECUTION_LIMITS } from '../tools/execution-limits.js';
|
|
17
|
+
import { DeferredMcpRegistry } from '../tools/tool-search.js';
|
|
18
|
+
import { assertMcpToolCatalog } from './mcp-catalog.js';
|
|
17
19
|
import { DEFAULT_COMPACTION_FOCUS, CompactionOperation, buildCompactionInput, buildCompactionMessages, buildNativeCompactionMessages, buildCompactedHistory, compactedHistoryMessages, continuationMessage } from '../runtime/compact.js';
|
|
18
20
|
import { buildSystemPrompt, MAR_AGENT_PROMPT_VERSION } from '../prompts/index.js';
|
|
19
21
|
import { buildEnvironmentContext } from '../prompts/core.js';
|
|
@@ -31,7 +33,8 @@ import { BUILTIN_TOOL_DEFINITIONS } from '../tools/registry.js';
|
|
|
31
33
|
import { agentStartToolDefinitionWithModels } from '../tools/agent-start.js';
|
|
32
34
|
import { executeRegisteredTool } from '../tools/runtime.js';
|
|
33
35
|
import { scheduleToolCallBatch } from '../tools/scheduler.js';
|
|
34
|
-
import {
|
|
36
|
+
import { projectCodeModeTools } from '../tools/code-mode.js';
|
|
37
|
+
import { allowsToolCaller, toolCallers } from '../tools/callers.js';
|
|
35
38
|
import { SubagentSessionController } from '../subagent/session-controller.js';
|
|
36
39
|
/** Retry only classified recoverable failures within the attempt budget; never retry cancellation. */
|
|
37
40
|
async function recoverModelStream(error, retryState, signal) {
|
|
@@ -261,6 +264,7 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
261
264
|
releaseSession = await store.acquireSessionLease(sessionId);
|
|
262
265
|
await refreshSessionAdapters(executionModelGeneration);
|
|
263
266
|
const sessionState = await store.readExecutionState(sessionId);
|
|
267
|
+
let codeModeState = await store.readCodeModeState(sessionId);
|
|
264
268
|
const todo = TodoStore.restore(sessionState.todo);
|
|
265
269
|
const contextRecords = sessionState.contextRecords;
|
|
266
270
|
const contextualWorldStateGeneration = latestContextualWorldStateGeneration(contextRecords);
|
|
@@ -410,9 +414,7 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
410
414
|
let lastServerUsage = latestModelUsage(contextRecords, selectedModel.id);
|
|
411
415
|
const compactUserTokenLimit = Math.min(20_000, Math.floor(selectedModel.contextWindowTokens / 8));
|
|
412
416
|
const reasoningEffort = input.reasoningEffort ?? selectedModel.defaultReasoningEffort;
|
|
413
|
-
const useEffortUpdates = selectedModel
|
|
414
|
-
selectedModel.responsesEncoding !== 'LITE' &&
|
|
415
|
-
selectedModel.codexCredential === true;
|
|
417
|
+
const useEffortUpdates = usesResponsesConfigurationUpdates(selectedModel);
|
|
416
418
|
const previousReasoningEffort = useEffortUpdates
|
|
417
419
|
? reasoningEffortBaseline(contextRecords, selectedModel.id)
|
|
418
420
|
: undefined;
|
|
@@ -496,7 +498,32 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
496
498
|
: { executionScopeId: internal.mcpExecutionScopeId }
|
|
497
499
|
: { claimExecutionScope: true })
|
|
498
500
|
};
|
|
499
|
-
const
|
|
501
|
+
const readMcpCatalog = async () => {
|
|
502
|
+
if (options.host.listMcpToolCatalog) {
|
|
503
|
+
const catalog = await options.host.listMcpToolCatalog(catalogContext);
|
|
504
|
+
assertMcpToolCatalog(catalog);
|
|
505
|
+
return catalog;
|
|
506
|
+
}
|
|
507
|
+
const definitions = (await options.host.listMcpTools?.(catalogContext)) ?? [];
|
|
508
|
+
return {
|
|
509
|
+
revision: createHash('sha256').update(JSON.stringify(definitions)).digest('hex'),
|
|
510
|
+
servers: [{ id: 'legacy', name: 'External MCP' }],
|
|
511
|
+
tools: definitions.map((definition) => ({
|
|
512
|
+
definition,
|
|
513
|
+
serverId: 'legacy',
|
|
514
|
+
rawName: definition.name,
|
|
515
|
+
sourceIdentity: `legacy:${executionId}`,
|
|
516
|
+
definitionRevision: createHash('sha256')
|
|
517
|
+
.update(JSON.stringify(definition))
|
|
518
|
+
.digest('hex'),
|
|
519
|
+
lifetime: 'execution',
|
|
520
|
+
exposure: 'deferred'
|
|
521
|
+
}))
|
|
522
|
+
};
|
|
523
|
+
};
|
|
524
|
+
const mcpCatalog = await readMcpCatalog();
|
|
525
|
+
const mcpRegistry = new DeferredMcpRegistry(discoveredMcpToolNames(messages));
|
|
526
|
+
const mcpTools = mcpCatalog.tools.map((tool) => tool.definition);
|
|
500
527
|
const extensions = (await options.host.listExecutionExtensions?.(catalogContext)) ?? {};
|
|
501
528
|
if (extensions.tools?.some((tool) => tool.name.startsWith('mcp__')))
|
|
502
529
|
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Host tools cannot use the MCP namespace.');
|
|
@@ -511,12 +538,15 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
511
538
|
const combinedTools = [...builtinTools, ...(extensions.tools ?? []), ...mcpTools];
|
|
512
539
|
if (new Set(combinedTools.map((tool) => tool.name)).size !== combinedTools.length)
|
|
513
540
|
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Tool names conflict.');
|
|
514
|
-
const
|
|
541
|
+
const toolEligible = (tool) => {
|
|
542
|
+
toolCallers(tool);
|
|
515
543
|
if (sessionSource.type === 'subagent' && tool.agentScope === 'ROOT_ONLY')
|
|
516
544
|
return false;
|
|
517
545
|
if (sessionSource.type === 'subagent' &&
|
|
518
546
|
(tool.name.startsWith('agent_') || tool.name === 'question'))
|
|
519
547
|
return false;
|
|
548
|
+
if (tool.name === 'tool_search')
|
|
549
|
+
return mcpRegistry.hasDeferred;
|
|
520
550
|
return tool.name === 'code_mode'
|
|
521
551
|
? selectedModelForTools.codeMode && description.capabilities.includes('code.execute')
|
|
522
552
|
: tool.name === 'question'
|
|
@@ -527,7 +557,10 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
527
557
|
: tool.name === 'view_image'
|
|
528
558
|
? selectedModelForTools.inputCapabilities.includes('IMAGE')
|
|
529
559
|
: tool.name !== 'web_fetch' || description.capabilities.includes('web.fetch');
|
|
530
|
-
}
|
|
560
|
+
};
|
|
561
|
+
mcpRegistry.update(mcpCatalog, (tool) => toolEligible(tool.definition));
|
|
562
|
+
rebindMcpToolSearchOutputs(messages, mcpRegistry);
|
|
563
|
+
const availableTools = combinedTools.filter(toolEligible);
|
|
531
564
|
const instructionContext = await loadAgentInstructions({
|
|
532
565
|
home: description.homeDirectory,
|
|
533
566
|
workspace: instructionWorkspace,
|
|
@@ -546,8 +579,14 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
546
579
|
agentInstructionInsertIndex &&
|
|
547
580
|
messages[agentInstructionInsertIndex - 1]?.contextKind === 'environment')
|
|
548
581
|
agentInstructionInsertIndex--;
|
|
549
|
-
const
|
|
550
|
-
|
|
582
|
+
const baseTools = () => [...builtinTools, ...(extensions.tools ?? [])].filter((tool) => toolEligible(tool) &&
|
|
583
|
+
(tool.name !== 'skill' || (instructionContext?.skills.size ?? 0) > 0));
|
|
584
|
+
let executionTools = mcpRegistry.project(baseTools());
|
|
585
|
+
const restoreMcpDiscovery = () => {
|
|
586
|
+
mcpRegistry.restore(discoveredMcpToolNames(messages));
|
|
587
|
+
rebindMcpToolSearchOutputs(messages, mcpRegistry);
|
|
588
|
+
executionTools = mcpRegistry.project(baseTools());
|
|
589
|
+
};
|
|
551
590
|
const loadRetainedSessionResources = async () => {
|
|
552
591
|
const hostResources = (await options.host.listSessionResources?.(sessionId)) ?? {
|
|
553
592
|
processes: []
|
|
@@ -581,7 +620,9 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
581
620
|
? { guaranteedCommands: description.guaranteedCommands }
|
|
582
621
|
: {}),
|
|
583
622
|
workspace: logicalWorkspace,
|
|
584
|
-
tools: availableTools
|
|
623
|
+
tools: availableTools
|
|
624
|
+
.filter((tool) => !tool.name.startsWith('mcp__'))
|
|
625
|
+
.map((tool) => tool.name),
|
|
585
626
|
highDensityCompaction: selectedModel.highDensityCompaction,
|
|
586
627
|
extension: [
|
|
587
628
|
options.systemInstruction,
|
|
@@ -591,6 +632,27 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
591
632
|
.filter(Boolean)
|
|
592
633
|
.join('\n\n')
|
|
593
634
|
});
|
|
635
|
+
const syncMcpWorldState = async (index) => {
|
|
636
|
+
const snapshot = mcpRegistry.navigation();
|
|
637
|
+
if (contextualWorldState.mcpSnapshot === snapshot)
|
|
638
|
+
return;
|
|
639
|
+
contextualWorldState = {
|
|
640
|
+
...contextualWorldState,
|
|
641
|
+
mcpSnapshot: snapshot,
|
|
642
|
+
entries: [
|
|
643
|
+
...contextualWorldState.entries,
|
|
644
|
+
{
|
|
645
|
+
index,
|
|
646
|
+
kind: 'mcp',
|
|
647
|
+
content: snapshot ?? '<mcp_catalog>No deferred MCP tools remain.</mcp_catalog>'
|
|
648
|
+
}
|
|
649
|
+
]
|
|
650
|
+
};
|
|
651
|
+
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
652
|
+
await persistContextualWorldState(store, sessionId, contextualWorldState);
|
|
653
|
+
};
|
|
654
|
+
if (mode !== 'compact')
|
|
655
|
+
await syncMcpWorldState(agentInstructionInsertIndex);
|
|
594
656
|
const initialSystemPrompt = mode === 'compact'
|
|
595
657
|
? buildExecutionSystemPrompt(executionTools, 'run')
|
|
596
658
|
: buildExecutionSystemPrompt();
|
|
@@ -740,6 +802,7 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
740
802
|
});
|
|
741
803
|
contextGc.reset();
|
|
742
804
|
messages.splice(0, messages.length, environmentContextUpdate(executionEnvironment), ...compactedHistoryMessages(replacementHistory));
|
|
805
|
+
restoreMcpDiscovery();
|
|
743
806
|
projectedExecutionBudgetStage = undefined;
|
|
744
807
|
recordedEnvironment = executionEnvironment;
|
|
745
808
|
compactionUserMessages = replacementHistory
|
|
@@ -785,7 +848,12 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
785
848
|
let roundServerUsage;
|
|
786
849
|
const pendingTools = [];
|
|
787
850
|
let incompleteToolCall = false;
|
|
851
|
+
executionTools = mcpRegistry.project(baseTools());
|
|
852
|
+
if (mode !== 'compact')
|
|
853
|
+
await syncMcpWorldState(messages.length);
|
|
788
854
|
await ensureContextBudget();
|
|
855
|
+
if (mode !== 'compact')
|
|
856
|
+
await syncMcpWorldState(messages.length);
|
|
789
857
|
appendExecutionBudgetEnvironment();
|
|
790
858
|
if (mode !== 'compact') {
|
|
791
859
|
executionEnvironment = { ...currentEnvironment, ...currentLocalTimeContext() };
|
|
@@ -793,6 +861,14 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
793
861
|
}
|
|
794
862
|
const toolsAllowed = mode !== 'compact' && (!rolloutBudget?.active || rolloutBudget.stage !== 'exhausted');
|
|
795
863
|
const roundTools = mode === 'compact' ? executionTools : toolsAllowed ? executionTools : [];
|
|
864
|
+
const requestTools = (() => {
|
|
865
|
+
if (selectedModel.protocol !== 'OPENAI_RESPONSES' ||
|
|
866
|
+
selectedModel.responsesEncoding === 'LITE')
|
|
867
|
+
return projectCodeModeTools(roundTools);
|
|
868
|
+
const directNames = new Set(mcpRegistry.projectDirect(baseTools()).map((tool) => tool.name));
|
|
869
|
+
// Discovery and caller policy are independent: keep nested declarations for active tools.
|
|
870
|
+
return projectCodeModeTools(roundTools).filter((tool) => directNames.has(tool.name));
|
|
871
|
+
})();
|
|
796
872
|
const systemPrompt = mode === 'compact'
|
|
797
873
|
? buildExecutionSystemPrompt(roundTools, 'run')
|
|
798
874
|
: buildExecutionSystemPrompt(roundTools);
|
|
@@ -804,7 +880,14 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
804
880
|
: normalizeMessagesForModel(insertContextualWorldState(requestContextMessages, contextualWorldState.entries), {
|
|
805
881
|
supportsImages: selectedModel.inputCapabilities.includes('IMAGE')
|
|
806
882
|
});
|
|
883
|
+
const roundMcpExpectations = new Map(roundTools
|
|
884
|
+
.filter((tool) => tool.name.startsWith('mcp__'))
|
|
885
|
+
.map((tool) => [tool.name, mcpRegistry.expectedTool(tool.name)]));
|
|
807
886
|
let sawModelSemanticEvent = false;
|
|
887
|
+
let requestStartedAt;
|
|
888
|
+
let firstVisibleOutputAt;
|
|
889
|
+
let requestCompletedAt;
|
|
890
|
+
let requestOutputTokens;
|
|
808
891
|
const roundMessageCount = messages.length;
|
|
809
892
|
const persistToolCalls = async (calls) => {
|
|
810
893
|
for (const call of calls) {
|
|
@@ -834,11 +917,17 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
834
917
|
const startModel = manualCompaction
|
|
835
918
|
? (request) => manualCompaction.start(selected, request)
|
|
836
919
|
: (request) => selected.start(request, controller.signal);
|
|
920
|
+
requestStartedAt = performance.now();
|
|
837
921
|
for await (const event of startModel({
|
|
838
922
|
retryState: modelRetryState,
|
|
839
923
|
system: systemPrompt,
|
|
840
|
-
messages: modelMessages
|
|
841
|
-
|
|
924
|
+
messages: modelMessages.map((message) => message.toolSearchTools
|
|
925
|
+
? {
|
|
926
|
+
...message,
|
|
927
|
+
toolSearchTools: message.toolSearchTools.filter((tool) => allowsToolCaller(tool, 'direct'))
|
|
928
|
+
}
|
|
929
|
+
: message),
|
|
930
|
+
tools: requestTools,
|
|
842
931
|
...(mode === 'compact'
|
|
843
932
|
? { toolChoice: 'none' }
|
|
844
933
|
: toolsAllowed
|
|
@@ -884,13 +973,15 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
884
973
|
}
|
|
885
974
|
delta = prefix.push(delta);
|
|
886
975
|
}
|
|
887
|
-
if (mode !== 'compact' && delta)
|
|
976
|
+
if (mode !== 'compact' && delta) {
|
|
977
|
+
firstVisibleOutputAt ??= performance.now();
|
|
888
978
|
await emit({
|
|
889
979
|
type: 'message.delta',
|
|
890
980
|
itemId: event.itemId,
|
|
891
981
|
phase: event.phase,
|
|
892
982
|
delta
|
|
893
983
|
});
|
|
984
|
+
}
|
|
894
985
|
}
|
|
895
986
|
else if (event.type === 'text.completed') {
|
|
896
987
|
const phase = event.phase ?? 'final_answer';
|
|
@@ -898,13 +989,15 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
898
989
|
finalAnswer = event.text;
|
|
899
990
|
planOutputPrefixes.delete(event.itemId);
|
|
900
991
|
if (mode !== 'compact') {
|
|
992
|
+
if (event.text.length > 0)
|
|
993
|
+
firstVisibleOutputAt ??= performance.now();
|
|
901
994
|
if (mode === 'plan' && sessionSource.type !== 'subagent') {
|
|
902
995
|
const parts = splitPlanOutput(event.text);
|
|
903
996
|
for (const [index, part] of parts.entries()) {
|
|
904
997
|
const itemId = index === 0 ? event.itemId : `${event.itemId}:plan-part:${index}`;
|
|
905
998
|
if (part.kind === 'plan')
|
|
906
999
|
await emit({ type: 'plan.completed', itemId, text: part.text });
|
|
907
|
-
else
|
|
1000
|
+
else {
|
|
908
1001
|
await emit({
|
|
909
1002
|
type: 'message.completed',
|
|
910
1003
|
itemId,
|
|
@@ -913,9 +1006,10 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
913
1006
|
modelId: selectedModel.id,
|
|
914
1007
|
modelName: selectedModel.name
|
|
915
1008
|
});
|
|
1009
|
+
}
|
|
916
1010
|
}
|
|
917
1011
|
}
|
|
918
|
-
else
|
|
1012
|
+
else {
|
|
919
1013
|
await emit({
|
|
920
1014
|
type: 'message.completed',
|
|
921
1015
|
itemId: event.itemId,
|
|
@@ -924,11 +1018,18 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
924
1018
|
modelId: selectedModel.id,
|
|
925
1019
|
modelName: selectedModel.name
|
|
926
1020
|
});
|
|
1021
|
+
}
|
|
927
1022
|
}
|
|
928
1023
|
messages.push({ role: 'assistant', content: event.text });
|
|
929
1024
|
}
|
|
930
1025
|
else if (event.type === 'usage') {
|
|
931
1026
|
latestUsage = event.usage;
|
|
1027
|
+
requestOutputTokens =
|
|
1028
|
+
typeof event.usage.outputTokens === 'number' &&
|
|
1029
|
+
Number.isSafeInteger(event.usage.outputTokens) &&
|
|
1030
|
+
event.usage.outputTokens >= 0
|
|
1031
|
+
? event.usage.outputTokens
|
|
1032
|
+
: undefined;
|
|
932
1033
|
const reportedContext = event.usage.contextInputTokens ?? event.usage.inputTokens;
|
|
933
1034
|
if (reportedContext !== undefined &&
|
|
934
1035
|
Number.isSafeInteger(reportedContext) &&
|
|
@@ -974,8 +1075,26 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
974
1075
|
sawTool = true;
|
|
975
1076
|
pendingTools.push(event);
|
|
976
1077
|
}
|
|
977
|
-
else if (event.type === 'completed')
|
|
1078
|
+
else if (event.type === 'completed') {
|
|
978
1079
|
stop = event.reason;
|
|
1080
|
+
requestCompletedAt = performance.now();
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
if (mode !== 'compact' && firstVisibleOutputAt !== undefined) {
|
|
1084
|
+
const completedAt = requestCompletedAt ?? performance.now();
|
|
1085
|
+
const ttftMs = Math.max(0, Math.round(firstVisibleOutputAt - requestStartedAt));
|
|
1086
|
+
const outputDurationMs = Math.max(0, Math.round(completedAt - firstVisibleOutputAt));
|
|
1087
|
+
const outputTokens = requestOutputTokens;
|
|
1088
|
+
const tokensPerSecond = outputTokens !== undefined && outputDurationMs > 0
|
|
1089
|
+
? Number(((outputTokens * 1000) / outputDurationMs).toFixed(2))
|
|
1090
|
+
: undefined;
|
|
1091
|
+
await emit({
|
|
1092
|
+
type: 'model.performance',
|
|
1093
|
+
ttftMs,
|
|
1094
|
+
...(outputTokens === undefined ? {} : { outputTokens }),
|
|
1095
|
+
outputDurationMs,
|
|
1096
|
+
...(tokensPerSecond === undefined ? {} : { tokensPerSecond })
|
|
1097
|
+
});
|
|
979
1098
|
}
|
|
980
1099
|
pendingOutputContinuation = undefined;
|
|
981
1100
|
incompleteToolCall = pendingTools.some((call) => call.argumentError !== undefined);
|
|
@@ -1031,7 +1150,7 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
1031
1150
|
finalAnswer = '';
|
|
1032
1151
|
continue;
|
|
1033
1152
|
}
|
|
1034
|
-
const executeCall = async (call, signal = controller.signal) => {
|
|
1153
|
+
const executeCall = async (call, signal = controller.signal, caller = 'direct') => {
|
|
1035
1154
|
await emit({
|
|
1036
1155
|
type: 'tool.started',
|
|
1037
1156
|
toolName: call.name,
|
|
@@ -1041,11 +1160,20 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
1041
1160
|
try {
|
|
1042
1161
|
if (call.argumentError)
|
|
1043
1162
|
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', call.argumentError);
|
|
1044
|
-
if (!
|
|
1163
|
+
if (!roundTools.some((tool) => tool.name === call.name && allowsToolCaller(tool, caller)))
|
|
1045
1164
|
throw new MarAgentError('MAR_AGENT_TOOL_NOT_AVAILABLE', 'Tool is unavailable in this execution.');
|
|
1046
1165
|
const output = await executeRegisteredTool(call.name, call.arguments, call.callId, {
|
|
1047
1166
|
host: options.host,
|
|
1048
1167
|
todo,
|
|
1168
|
+
...(roundMcpExpectations.get(call.name)
|
|
1169
|
+
? { expectedMcpTool: roundMcpExpectations.get(call.name) }
|
|
1170
|
+
: {}),
|
|
1171
|
+
searchMcpTools: (arguments_, searchSignal) => mcpRegistry.expose(arguments_, {
|
|
1172
|
+
signal: searchSignal,
|
|
1173
|
+
base: baseTools(),
|
|
1174
|
+
window: selectedModel.contextWindowTokens,
|
|
1175
|
+
system: systemPrompt
|
|
1176
|
+
}),
|
|
1049
1177
|
...(subagents === undefined ? {} : { subagents }),
|
|
1050
1178
|
mode,
|
|
1051
1179
|
sessionId,
|
|
@@ -1053,14 +1181,22 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
1053
1181
|
signal,
|
|
1054
1182
|
codeMode: {
|
|
1055
1183
|
supportsImages: selectedModel.inputCapabilities.includes('IMAGE'),
|
|
1056
|
-
tools: roundTools,
|
|
1184
|
+
tools: roundTools.filter((tool) => allowsToolCaller(tool, 'programmatic')),
|
|
1185
|
+
state: codeModeState,
|
|
1186
|
+
commitState: async (mutations) => {
|
|
1187
|
+
codeModeState = await store.commitCodeModeState(sessionId, mutations, {
|
|
1188
|
+
executionId,
|
|
1189
|
+
turnId
|
|
1190
|
+
});
|
|
1191
|
+
return codeModeState;
|
|
1192
|
+
},
|
|
1057
1193
|
invoke: async (nested, nestedSignal) => {
|
|
1058
1194
|
const result = await executeCall({
|
|
1059
1195
|
type: 'client_tool.call',
|
|
1060
1196
|
name: nested.name,
|
|
1061
1197
|
arguments: nested.arguments,
|
|
1062
1198
|
callId: nested.callId ?? randomUUID()
|
|
1063
|
-
}, nestedSignal);
|
|
1199
|
+
}, nestedSignal, 'programmatic');
|
|
1064
1200
|
if (result.failed)
|
|
1065
1201
|
throw result.error;
|
|
1066
1202
|
return { ...result.output, content: result.content };
|
|
@@ -1127,10 +1263,14 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
1127
1263
|
mimeType: image.mimeType,
|
|
1128
1264
|
data: Buffer.from(image.dataBase64, 'base64')
|
|
1129
1265
|
})));
|
|
1266
|
+
const toolSearchTools = result.call.name === 'tool_search' && !result.failed
|
|
1267
|
+
? result.output.toolSearchTools
|
|
1268
|
+
: undefined;
|
|
1130
1269
|
const message = {
|
|
1131
1270
|
role: 'tool',
|
|
1132
1271
|
callId: result.call.callId,
|
|
1133
1272
|
content: result.content,
|
|
1273
|
+
...(toolSearchTools === undefined ? {} : { toolSearchTools }),
|
|
1134
1274
|
...('images' in result && result.images?.length ? { images: result.images } : {})
|
|
1135
1275
|
};
|
|
1136
1276
|
messages.push(message);
|
|
@@ -1139,7 +1279,10 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
1139
1279
|
payload: {
|
|
1140
1280
|
role: message.role,
|
|
1141
1281
|
callId: message.callId,
|
|
1142
|
-
content: message.content
|
|
1282
|
+
content: message.content,
|
|
1283
|
+
...(message.toolSearchTools === undefined
|
|
1284
|
+
? {}
|
|
1285
|
+
: { toolSearchTools: message.toolSearchTools })
|
|
1143
1286
|
},
|
|
1144
1287
|
executionId,
|
|
1145
1288
|
turnId
|
|
@@ -1182,6 +1325,7 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
1182
1325
|
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
1183
1326
|
usage: latestUsage,
|
|
1184
1327
|
modelProtocol: selectedModel.protocol,
|
|
1328
|
+
responsesConfigurationUpdates: usesResponsesConfigurationUpdates(selectedModel),
|
|
1185
1329
|
workspace: logicalWorkspace,
|
|
1186
1330
|
platform: description.platform,
|
|
1187
1331
|
getActiveProcessIds: async () => {
|
|
@@ -1201,6 +1345,7 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
1201
1345
|
projection: committed.projection
|
|
1202
1346
|
});
|
|
1203
1347
|
messages.splice(0, messages.length, ...refreshed.messages);
|
|
1348
|
+
restoreMcpDiscovery();
|
|
1204
1349
|
projectedExecutionBudgetStage = undefined;
|
|
1205
1350
|
recordedEnvironment = refreshed.environmentState;
|
|
1206
1351
|
compactionUserMessages = [...refreshed.userMessages];
|
|
@@ -1551,6 +1696,10 @@ function resolveAgentModels(configurations, requestedDefaultModelId) {
|
|
|
1551
1696
|
throw new MarAgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Responses encoding is invalid.');
|
|
1552
1697
|
if (model.fastMode === true && model.protocol !== 'OPENAI_RESPONSES')
|
|
1553
1698
|
throw new MarAgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Fast mode requires Responses.');
|
|
1699
|
+
if (model.serviceTier !== undefined &&
|
|
1700
|
+
(model.protocol !== 'OPENAI_RESPONSES' ||
|
|
1701
|
+
!['auto', 'default', 'flex', 'priority', 'fast', 'ultrafast'].includes(model.serviceTier)))
|
|
1702
|
+
throw new MarAgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Responses service tier is invalid.');
|
|
1554
1703
|
if (model.credentialProvider !== undefined)
|
|
1555
1704
|
credentialProviders.add(model.credentialProvider);
|
|
1556
1705
|
}
|
|
@@ -1982,7 +2131,7 @@ function parsePersistedContextualWorldState(payload) {
|
|
|
1982
2131
|
const entry = value;
|
|
1983
2132
|
if (!Number.isSafeInteger(entry.index) ||
|
|
1984
2133
|
entry.index < 0 ||
|
|
1985
|
-
(entry.kind !== 'instructions' && entry.kind !== 'resources') ||
|
|
2134
|
+
(entry.kind !== 'instructions' && entry.kind !== 'resources' && entry.kind !== 'mcp') ||
|
|
1986
2135
|
typeof entry.content !== 'string' ||
|
|
1987
2136
|
entry.content.length === 0)
|
|
1988
2137
|
return undefined;
|
|
@@ -2000,6 +2149,7 @@ function parsePersistedContextualWorldState(payload) {
|
|
|
2000
2149
|
initialized: true,
|
|
2001
2150
|
instructionSnapshot,
|
|
2002
2151
|
resourceSnapshot,
|
|
2152
|
+
mcpSnapshot: typeof record.mcpSnapshot === 'string' ? record.mcpSnapshot : undefined,
|
|
2003
2153
|
entries
|
|
2004
2154
|
};
|
|
2005
2155
|
}
|
|
@@ -2017,6 +2167,7 @@ async function persistContextualWorldState(store, sessionId, state) {
|
|
|
2017
2167
|
generation: state.generation ?? null,
|
|
2018
2168
|
instructionSnapshot: state.instructionSnapshot ?? null,
|
|
2019
2169
|
resourceSnapshot: state.resourceSnapshot ?? null,
|
|
2170
|
+
mcpSnapshot: state.mcpSnapshot ?? null,
|
|
2020
2171
|
entries: state.entries
|
|
2021
2172
|
});
|
|
2022
2173
|
}
|
|
@@ -2034,6 +2185,7 @@ function updateContextualWorldState(state, index, current) {
|
|
|
2034
2185
|
entries.push({ index, kind: 'resources', content: resourceContent });
|
|
2035
2186
|
return {
|
|
2036
2187
|
generation: state.generation,
|
|
2188
|
+
mcpSnapshot: state.mcpSnapshot,
|
|
2037
2189
|
initialized: true,
|
|
2038
2190
|
instructionSnapshot: current.instructionSnapshot,
|
|
2039
2191
|
resourceSnapshot: current.resourceSnapshot,
|
|
@@ -2096,6 +2248,38 @@ function stableJson(value) {
|
|
|
2096
2248
|
.join(',')}}`;
|
|
2097
2249
|
return JSON.stringify(value) ?? 'undefined';
|
|
2098
2250
|
}
|
|
2251
|
+
function discoveredMcpToolNames(messages) {
|
|
2252
|
+
const calls = toolSearchCallIds(messages);
|
|
2253
|
+
const names = new Set();
|
|
2254
|
+
for (const message of messages)
|
|
2255
|
+
for (const tool of calls.has(message.callId ?? '') ? (message.toolSearchTools ?? []) : [])
|
|
2256
|
+
if (tool.name.startsWith('mcp__'))
|
|
2257
|
+
names.add(tool.name);
|
|
2258
|
+
return [...names];
|
|
2259
|
+
}
|
|
2260
|
+
function rebindMcpToolSearchOutputs(messages, registry) {
|
|
2261
|
+
const calls = toolSearchCallIds(messages);
|
|
2262
|
+
for (const message of messages) {
|
|
2263
|
+
if (!message.toolSearchTools)
|
|
2264
|
+
continue;
|
|
2265
|
+
if (!calls.has(message.callId ?? '')) {
|
|
2266
|
+
delete message.toolSearchTools;
|
|
2267
|
+
continue;
|
|
2268
|
+
}
|
|
2269
|
+
const definitions = registry.restoredDefinitions(message.toolSearchTools.map((tool) => tool.name));
|
|
2270
|
+
message.toolSearchTools = definitions;
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
function toolSearchCallIds(messages) {
|
|
2274
|
+
return new Set(messages
|
|
2275
|
+
.filter((message) => (message.role === 'tool_call' &&
|
|
2276
|
+
message.name === 'tool_search' &&
|
|
2277
|
+
typeof message.callId === 'string') ||
|
|
2278
|
+
(message.role === 'provider' &&
|
|
2279
|
+
providerToolName(message) === 'tool_search' &&
|
|
2280
|
+
providerToolCallId(message) !== undefined))
|
|
2281
|
+
.map((message) => message.role === 'provider' ? providerToolCallId(message) : message.callId));
|
|
2282
|
+
}
|
|
2099
2283
|
/** Project only known, validated tool result shapes into public structured events. */
|
|
2100
2284
|
function structuredToolEventData(toolName, value) {
|
|
2101
2285
|
if (!isRecord(value))
|
|
@@ -2192,7 +2376,10 @@ function structuredToolArtifacts(value) {
|
|
|
2192
2376
|
}
|
|
2193
2377
|
/** Keep streaming deltas live-only; exec output has one durable copy in model context records. */
|
|
2194
2378
|
function eventForPersistence(event) {
|
|
2195
|
-
if (event.type === 'message.delta' ||
|
|
2379
|
+
if (event.type === 'message.delta' ||
|
|
2380
|
+
event.type === 'context.compacting' ||
|
|
2381
|
+
event.type === 'model.performance' ||
|
|
2382
|
+
event.type === 'message.performance')
|
|
2196
2383
|
return undefined;
|
|
2197
2384
|
if (event.type !== 'tool.completed' || event.toolName !== 'exec' || !event.data)
|
|
2198
2385
|
return event;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ClientToolDefinition } from '../model/contracts.js';
|
|
2
|
+
import type { McpToolCatalog } from './types.js';
|
|
3
|
+
export declare const MCP_DEFINITION_LIMITS: Readonly<{
|
|
4
|
+
depth: 64;
|
|
5
|
+
nodes: 32768;
|
|
6
|
+
definitionBytes: number;
|
|
7
|
+
catalogBytes: number;
|
|
8
|
+
tools: 10000;
|
|
9
|
+
servers: 256;
|
|
10
|
+
}>;
|
|
11
|
+
/** Shared Host and Node publication boundary, not a provider-specific conversion. */
|
|
12
|
+
export declare function assertMcpToolDefinition(value: unknown): asserts value is ClientToolDefinition;
|
|
13
|
+
export declare function assertMcpToolCatalog(value: unknown): asserts value is McpToolCatalog;
|