@myagentroam/agent 0.10.11 → 0.10.13
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/model/openai-responses.js +2 -1
- package/dist/agent-core/prompts/index.d.ts +1 -1
- package/dist/agent-core/prompts/index.js +1 -1
- package/dist/agent-core/prompts/modes.js +3 -3
- package/dist/agent-core/runtime/contracts.d.ts +1 -0
- package/dist/agent-core/runtime/execution-policy.d.ts +0 -5
- package/dist/agent-core/runtime/execution-policy.js +0 -5
- package/dist/agent-core/runtime/execution.d.ts +0 -2
- package/dist/agent-core/runtime/execution.js +0 -5
- package/dist/agent-core/sdk/agent.js +0 -3
- package/dist/agent-core/sdk/session.d.ts +0 -2
- package/dist/agent-core/sdk/session.js +1 -33
- package/dist/agent-core/sdk/types.d.ts +1 -0
- package/dist/agent-core/session/jsonl-store.js +22 -15
- package/package.json +1 -1
- package/dist/agent-core/prompts/execution-budget.d.ts +0 -3
- package/dist/agent-core/prompts/execution-budget.js +0 -9
- package/dist/agent-core/runtime/rollout-budget.d.ts +0 -25
- package/dist/agent-core/runtime/rollout-budget.js +0 -96
|
@@ -949,7 +949,8 @@ function responsesRequestBody(configuration, request, messages) {
|
|
|
949
949
|
...(tools.length > 0 ? { tool_choice: toolChoice, parallel_tool_calls: true } : {}),
|
|
950
950
|
input,
|
|
951
951
|
stream: true,
|
|
952
|
-
store: configuration.
|
|
952
|
+
store: configuration.responsesPreviousResponseId === true &&
|
|
953
|
+
configuration.responsesTransport?.transport !== 'WEBSOCKET',
|
|
953
954
|
...(configuration.responsesOptionalParameters?.textVerbosity === false
|
|
954
955
|
? {}
|
|
955
956
|
: { text: { verbosity: 'low' } }),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExecutionMode } from '../runtime/contracts.js';
|
|
2
2
|
import { type CorePromptPart } from '../extensions/prompt-composition.js';
|
|
3
|
-
export declare const MAR_AGENT_PROMPT_VERSION = "1.
|
|
3
|
+
export declare const MAR_AGENT_PROMPT_VERSION = "1.64";
|
|
4
4
|
interface SystemPromptInput {
|
|
5
5
|
mode: ExecutionMode;
|
|
6
6
|
platform: string;
|
|
@@ -5,7 +5,7 @@ import { modePrompt } from './modes.js';
|
|
|
5
5
|
import { outputStylePrompt } from './output.js';
|
|
6
6
|
import { subagentPrompt } from './subagent.js';
|
|
7
7
|
import { interactionPrompt, longRunningPrompt, safetyPrompt, toolUsagePrompt, workflowPrompt } from './workflow.js';
|
|
8
|
-
export const MAR_AGENT_PROMPT_VERSION = '1.
|
|
8
|
+
export const MAR_AGENT_PROMPT_VERSION = '1.64';
|
|
9
9
|
export function buildSystemPrompt(input) {
|
|
10
10
|
return renderPromptSections(buildSystemPromptSections(input));
|
|
11
11
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export function modePrompt(mode, input) {
|
|
2
2
|
if (mode !== 'plan')
|
|
3
3
|
return '';
|
|
4
|
-
const investigationGuidance = 'Resolve discoverable facts through targeted read-only investigation. Ask about user-owned preferences and tradeoffs early when they cannot be inferred from the request, conversation, or workspace evidence.
|
|
4
|
+
const investigationGuidance = 'Resolve discoverable facts through targeted read-only investigation. Ask about user-owned preferences and tradeoffs early when they cannot be inferred from the request, conversation, or workspace evidence.';
|
|
5
5
|
const decisionGuidance = input.questionAvailable
|
|
6
6
|
? 'Use question for unresolved choices that materially change the result; do not finalize the plan while such choices remain. Do not invent support for multiple outcomes or silently choose a default to avoid asking.'
|
|
7
|
-
: 'Ask a concise plain-text question for unresolved user-owned choices that materially change the result instead of finalizing an ambiguous plan.
|
|
8
|
-
const finalGuidance = 'Once the plan is decision-complete, return only a concise, actionable plan. Break the work into meaningful, logically ordered deliverables that are easy to verify. Do not pad the plan with filler or obvious steps. Include the implementation and verification detail needed to execute it, without drafting the implementation itself.
|
|
7
|
+
: 'Ask a concise plain-text question for unresolved user-owned choices that materially change the result instead of finalizing an ambiguous plan. If user input is unavailable, state the unresolved decision and its impact instead of guessing. Do not invent support for multiple outcomes or silently choose a default.';
|
|
8
|
+
const finalGuidance = 'Once the plan is decision-complete, return only a concise, actionable plan. Break the work into meaningful, logically ordered deliverables that are easy to verify. Do not pad the plan with filler or obvious steps. Include the implementation and verification detail needed to execute it, without drafting the implementation itself. Do not ask whether to proceed or claim unresolved work is complete.';
|
|
9
9
|
return `# Plan mode
|
|
10
10
|
Use tools only for read-only investigation that reduces uncertainty and improves the plan. Do not create, modify, delete, rename, or move files, and do not run commands intended to mutate repository-tracked state or implement the requested work. This is behavioral guidance, not a security boundary; the normal tools and Host policies remain available.
|
|
11
11
|
|
|
@@ -30,6 +30,7 @@ export interface ExecutionResult {
|
|
|
30
30
|
errorCode?: string;
|
|
31
31
|
errorMessage?: string;
|
|
32
32
|
}
|
|
33
|
+
/** @deprecated Execution token budgets are no longer enforced. */
|
|
33
34
|
export interface RolloutBudgetOptions {
|
|
34
35
|
limitTokens?: number;
|
|
35
36
|
conserveAtRemainingTokens?: number;
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
export declare const AGENT_EXECUTION_POLICY: Readonly<{
|
|
2
2
|
subagentModelRounds: 32;
|
|
3
|
-
rolloutBudgetTokens: 1250000;
|
|
4
|
-
rolloutBudgetConserveRemainingTokens: 350000;
|
|
5
|
-
rolloutBudgetFinalizeRemainingTokens: 200000;
|
|
6
|
-
rolloutBudgetSamplingTokenWeight: 1;
|
|
7
|
-
rolloutBudgetPrefillTokenWeight: 1;
|
|
8
3
|
toolEventSummaryCharacters: 2000;
|
|
9
4
|
modelToolOutputTokens: 10000;
|
|
10
5
|
automaticCompactionPercent: 90;
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
export const AGENT_EXECUTION_POLICY = Object.freeze({
|
|
2
2
|
subagentModelRounds: 32,
|
|
3
|
-
rolloutBudgetTokens: 1_250_000,
|
|
4
|
-
rolloutBudgetConserveRemainingTokens: 350_000,
|
|
5
|
-
rolloutBudgetFinalizeRemainingTokens: 200_000,
|
|
6
|
-
rolloutBudgetSamplingTokenWeight: 1,
|
|
7
|
-
rolloutBudgetPrefillTokenWeight: 1,
|
|
8
3
|
toolEventSummaryCharacters: 2_000,
|
|
9
4
|
modelToolOutputTokens: 10_000,
|
|
10
5
|
automaticCompactionPercent: 90,
|
|
@@ -5,7 +5,6 @@ import type { ToolRuntimeImage } from '../tools/runtime-context.js';
|
|
|
5
5
|
import type { AuthoritativeModelUsage } from './context/usage.js';
|
|
6
6
|
import type { ExecutionMode } from './contracts.js';
|
|
7
7
|
import type { EventPayload } from './events.js';
|
|
8
|
-
import type { RolloutBudget } from './rollout-budget.js';
|
|
9
8
|
export interface PreparedExecutionRound {
|
|
10
9
|
readonly request: ModelRequest;
|
|
11
10
|
readonly toolScope: RoundToolScope;
|
|
@@ -18,7 +17,6 @@ export interface ExecutionLoopInput {
|
|
|
18
17
|
readonly model: Pick<MarAgentModelConfiguration, 'id' | 'name'>;
|
|
19
18
|
readonly messages: ModelMessage[];
|
|
20
19
|
readonly toolImages: ToolRuntimeImage[];
|
|
21
|
-
readonly rolloutBudget: RolloutBudget | undefined;
|
|
22
20
|
readonly publish: (event: EventPayload) => Promise<void>;
|
|
23
21
|
readonly appendContext: (message: ModelMessage) => Promise<void>;
|
|
24
22
|
readonly prepareRound: (continuation: ModelMessage | undefined) => Promise<PreparedExecutionRound>;
|
|
@@ -35,7 +35,6 @@ export class ExecutionLoop {
|
|
|
35
35
|
const pendingTools = [];
|
|
36
36
|
let incompleteToolCall = false;
|
|
37
37
|
const round = await input.prepareRound(pendingOutputContinuation);
|
|
38
|
-
input.rolloutBudget?.assertAvailable();
|
|
39
38
|
let sawModelSemanticEvent = false;
|
|
40
39
|
let requestStartedAt;
|
|
41
40
|
let firstModelResponseAt;
|
|
@@ -340,9 +339,6 @@ export class ExecutionLoop {
|
|
|
340
339
|
if (input.sourceType === 'subagent')
|
|
341
340
|
this.finalAnswer = '';
|
|
342
341
|
}
|
|
343
|
-
input.rolloutBudget?.recordUsage(latestUsage);
|
|
344
|
-
if (!input.signal.aborted)
|
|
345
|
-
input.rolloutBudget?.assertAvailable();
|
|
346
342
|
if (mode !== 'compact' && stop === 'max_output') {
|
|
347
343
|
const needsContinuation = !sawTool || incompleteToolCall;
|
|
348
344
|
if (needsContinuation) {
|
|
@@ -365,7 +361,6 @@ export class ExecutionLoop {
|
|
|
365
361
|
const aborted = toolResults.find((result) => result.failed)?.error;
|
|
366
362
|
throw aborted ?? new MarAgentError('MAR_AGENT_EXECUTION_CANCELLED', 'Execution cancelled.');
|
|
367
363
|
}
|
|
368
|
-
input.rolloutBudget?.assertAvailable();
|
|
369
364
|
if (input.mailbox.hasPending() && (await input.mailbox.append())) {
|
|
370
365
|
this.finalAnswer = '';
|
|
371
366
|
continue;
|
|
@@ -7,7 +7,6 @@ import { negotiateHost } from '../host/contracts.js';
|
|
|
7
7
|
import { toolCallers } from '../tools/callers.js';
|
|
8
8
|
import { AnthropicMessagesAdapter } from '../model/anthropic-messages.js';
|
|
9
9
|
import { OpenAiResponsesAdapter } from '../model/openai-responses.js';
|
|
10
|
-
import { resolveRolloutBudgetOptions } from '../runtime/rollout-budget.js';
|
|
11
10
|
import { JsonlSessionStore } from '../session/jsonl-store.js';
|
|
12
11
|
/** Validate models before Host negotiation and expose only built-in protocol adapters. */
|
|
13
12
|
export async function createMarAgent(options) {
|
|
@@ -17,7 +16,6 @@ export async function createMarAgent(options) {
|
|
|
17
16
|
}
|
|
18
17
|
/** Package-internal seam for deterministic adapter tests; not a package export. */
|
|
19
18
|
export async function createMarAgentWithAdapter(options) {
|
|
20
|
-
const rolloutBudgetOptions = resolveRolloutBudgetOptions(options.rolloutBudget);
|
|
21
19
|
const resolvedModels = resolveAgentModels(options.models);
|
|
22
20
|
let { models, defaultModelId } = resolvedModels;
|
|
23
21
|
let modelGeneration = 0;
|
|
@@ -169,7 +167,6 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
169
167
|
sessionRuntimes,
|
|
170
168
|
sessionWriterOwner
|
|
171
169
|
},
|
|
172
|
-
rolloutBudgetOptions,
|
|
173
170
|
hasCustomAdapters: options.adapterFactory !== undefined,
|
|
174
171
|
modelState: () => ({ models, defaultModelId, generation: modelGeneration }),
|
|
175
172
|
createAdapter,
|
|
@@ -9,7 +9,6 @@ import type { CoreAgentsBackend } from '../extensions/agents.js';
|
|
|
9
9
|
import type { HostDescription, MarAgentHost } from '../host/contracts.js';
|
|
10
10
|
import { type MarAgentReasoningEffort } from '../model/configuration.js';
|
|
11
11
|
import type { ModelAdapter, ModelMessage } from '../model/contracts.js';
|
|
12
|
-
import { resolveRolloutBudgetOptions } from '../runtime/rollout-budget.js';
|
|
13
12
|
import { JsonlSessionStore } from '../session/jsonl-store.js';
|
|
14
13
|
import { SubagentSessionController, type SubagentMailboxMessage, type SubagentMessageDelivery, type SubagentTurnHandle } from '../subagent/session-controller.js';
|
|
15
14
|
import { createSessionToolScheduler } from '../tools/scheduler.js';
|
|
@@ -69,7 +68,6 @@ interface SessionServices {
|
|
|
69
68
|
readonly store: JsonlSessionStore;
|
|
70
69
|
readonly extensions: ExtensionManager;
|
|
71
70
|
readonly registry: AgentSessionRegistry;
|
|
72
|
-
readonly rolloutBudgetOptions: ReturnType<typeof resolveRolloutBudgetOptions>;
|
|
73
71
|
readonly hasCustomAdapters: boolean;
|
|
74
72
|
readonly modelState: () => {
|
|
75
73
|
readonly models: ReadonlyMap<string, ResolvedModelConfiguration>;
|
|
@@ -24,7 +24,6 @@ import { coreMcpCatalog } from '../extensions/mcp.js';
|
|
|
24
24
|
import { isDeepStrictEqual } from 'node:util';
|
|
25
25
|
import { MarAgentError, describeMarAgentError } from '../error.js';
|
|
26
26
|
import { usesResponsesConfigurationUpdates } from '../model/configuration.js';
|
|
27
|
-
import { executionBudgetEnvironmentEntry } from '../prompts/execution-budget.js';
|
|
28
27
|
import { MAR_AGENT_PROMPT_VERSION, buildSystemPromptSections } from '../prompts/index.js';
|
|
29
28
|
import { renderPromptSections } from '../extensions/prompt-composition.js';
|
|
30
29
|
import { retainedSessionResourcesSnapshot } from '../prompts/resources.js';
|
|
@@ -37,7 +36,6 @@ import { ContextGcRuntime } from '../runtime/context/gc-runtime.js';
|
|
|
37
36
|
import { AGENT_EXECUTION_POLICY } from '../runtime/execution-policy.js';
|
|
38
37
|
import { loadAgentInstructions, renderAgentInstructions } from '../runtime/context/instructions.js';
|
|
39
38
|
import { normalizeMessagesForModel } from '../runtime/context/normalize.js';
|
|
40
|
-
import { RolloutBudget } from '../runtime/rollout-budget.js';
|
|
41
39
|
import { compactSummaryFromCheckpoint, inputMetadataFromRecord } from '../session/jsonl-store.js';
|
|
42
40
|
import { SubagentSessionController } from '../subagent/session-controller.js';
|
|
43
41
|
import { agentStartToolDefinitionWithModels } from '../tools/agent/agent-start.js';
|
|
@@ -50,7 +48,7 @@ import { TodoStore } from '../tools/agent/todo.js';
|
|
|
50
48
|
import { DeferredMcpRegistry } from '../tools/mcp/tool-search.js';
|
|
51
49
|
/** SDK Session orchestration owns warm resources; Runtime owns only the model/tool loop. */
|
|
52
50
|
export function createSessionOpener(services) {
|
|
53
|
-
const { host, description, settings, store,
|
|
51
|
+
const { host, description, settings, store, createAdapter, activeAdaptersExcept } = services;
|
|
54
52
|
const { active, activeExecutionAdapters, executionResults, sessionRuntimes, sessionWriterOwner } = services.registry;
|
|
55
53
|
const openSession = async (sessionId, workspace) => {
|
|
56
54
|
const storedSession = await store.getSession(sessionId);
|
|
@@ -327,9 +325,6 @@ export function createSessionOpener(services) {
|
|
|
327
325
|
let finalAnswer = '';
|
|
328
326
|
let executionLoop;
|
|
329
327
|
let manualCompaction;
|
|
330
|
-
const rolloutBudget = sessionSource.type === 'user' && rolloutBudgetOptions
|
|
331
|
-
? new RolloutBudget(rolloutBudgetOptions)
|
|
332
|
-
: undefined;
|
|
333
328
|
let releaseSession;
|
|
334
329
|
let executionToolSources;
|
|
335
330
|
let selectedTurn;
|
|
@@ -395,23 +390,6 @@ export function createSessionOpener(services) {
|
|
|
395
390
|
pendingAppends.length = 0;
|
|
396
391
|
immediateTarget = messages;
|
|
397
392
|
let recordedEnvironment = restored.environmentState;
|
|
398
|
-
let projectedExecutionBudgetStage;
|
|
399
|
-
const appendExecutionBudgetEnvironment = () => {
|
|
400
|
-
rolloutBudget?.assertAvailable();
|
|
401
|
-
const currentStage = rolloutBudget?.active ? rolloutBudget.stage : 'inactive';
|
|
402
|
-
if (currentStage === 'exhausted')
|
|
403
|
-
return;
|
|
404
|
-
if (currentStage === projectedExecutionBudgetStage)
|
|
405
|
-
return;
|
|
406
|
-
const previousStage = projectedExecutionBudgetStage;
|
|
407
|
-
projectedExecutionBudgetStage = currentStage;
|
|
408
|
-
if ((previousStage === undefined &&
|
|
409
|
-
(currentStage === 'normal' || currentStage === 'inactive')) ||
|
|
410
|
-
(currentStage === 'inactive' && previousStage === 'normal'))
|
|
411
|
-
return;
|
|
412
|
-
const entry = executionBudgetEnvironmentEntry(currentStage === 'normal' ? 'inactive' : currentStage);
|
|
413
|
-
messages.push(environmentContextUpdate(executionEnvironment, executionEnvironment, [entry]));
|
|
414
|
-
};
|
|
415
393
|
let compactContext;
|
|
416
394
|
const writeInputRecord = async (content, type, metadata, call, committed) => {
|
|
417
395
|
call.signal.throwIfAborted();
|
|
@@ -1107,7 +1085,6 @@ export function createSessionOpener(services) {
|
|
|
1107
1085
|
manualCompactionStarted = true;
|
|
1108
1086
|
manualCompaction = createCompactionOperation(manualCompactionId, compactSignal);
|
|
1109
1087
|
await emit({ type: 'context.compacting', compactionId: manualCompactionId });
|
|
1110
|
-
rolloutBudget?.assertAvailable();
|
|
1111
1088
|
manualExtension = await generateCompactExtension(messages, 'manual', compactFocus, manualCompaction);
|
|
1112
1089
|
}
|
|
1113
1090
|
if (mode === 'compact' && manualExtension === undefined) {
|
|
@@ -1259,7 +1236,6 @@ export function createSessionOpener(services) {
|
|
|
1259
1236
|
}
|
|
1260
1237
|
if (!compactSummary)
|
|
1261
1238
|
throw new MarAgentError('MAR_AGENT_COMPACT_FAILED', 'Automatic compact failed.');
|
|
1262
|
-
rolloutBudget?.recordUsage(latestUsage);
|
|
1263
1239
|
let replacementHistory = buildCompactedHistory(compactSummary, retainCurrent ? compactionUserMessages.slice(0, -1) : compactionUserMessages, compactUserTokenLimit, retainCurrent
|
|
1264
1240
|
? {
|
|
1265
1241
|
content: current.content,
|
|
@@ -1297,7 +1273,6 @@ export function createSessionOpener(services) {
|
|
|
1297
1273
|
});
|
|
1298
1274
|
contextGc.reset();
|
|
1299
1275
|
restoreMcpDiscovery();
|
|
1300
|
-
projectedExecutionBudgetStage = undefined;
|
|
1301
1276
|
recordedEnvironment = executionEnvironment;
|
|
1302
1277
|
compactionUserMessages = replacementHistory
|
|
1303
1278
|
.filter((message) => message.kind !== 'summary')
|
|
@@ -1337,7 +1312,6 @@ export function createSessionOpener(services) {
|
|
|
1337
1312
|
model: selectedModel,
|
|
1338
1313
|
messages,
|
|
1339
1314
|
toolImages: currentExecutionToolImages,
|
|
1340
|
-
rolloutBudget,
|
|
1341
1315
|
publish: emit,
|
|
1342
1316
|
appendContext: (message) => withRecordProjection(async () => {
|
|
1343
1317
|
await store.append(sessionId, {
|
|
@@ -1350,7 +1324,6 @@ export function createSessionOpener(services) {
|
|
|
1350
1324
|
prepareRound: async (pendingOutputContinuation) => {
|
|
1351
1325
|
if (mode !== 'compact')
|
|
1352
1326
|
await appendMailboxMessages();
|
|
1353
|
-
appendExecutionBudgetEnvironment();
|
|
1354
1327
|
updateMcpRegistry();
|
|
1355
1328
|
executionTools = mcpRegistry.project(baseTools());
|
|
1356
1329
|
if (mode !== 'compact')
|
|
@@ -1358,7 +1331,6 @@ export function createSessionOpener(services) {
|
|
|
1358
1331
|
await ensureContextBudget();
|
|
1359
1332
|
if (mode !== 'compact')
|
|
1360
1333
|
await syncMcpWorldState(messages.length);
|
|
1361
|
-
appendExecutionBudgetEnvironment();
|
|
1362
1334
|
if (mode !== 'compact') {
|
|
1363
1335
|
executionEnvironment = { ...currentEnvironment, ...currentLocalTimeContext() };
|
|
1364
1336
|
await recordEnvironment();
|
|
@@ -1491,7 +1463,6 @@ export function createSessionOpener(services) {
|
|
|
1491
1463
|
.map((entry) => entry.message);
|
|
1492
1464
|
messages.splice(0, messages.length, ...refreshed.messages, ...lateMessages);
|
|
1493
1465
|
restoreMcpDiscovery();
|
|
1494
|
-
projectedExecutionBudgetStage = undefined;
|
|
1495
1466
|
recordedEnvironment = refreshed.environmentState;
|
|
1496
1467
|
compactionUserMessages = [...refreshed.userMessages];
|
|
1497
1468
|
agentInstructionInsertIndex = contextualInstructionInsertIndex(messages);
|
|
@@ -1512,8 +1483,6 @@ export function createSessionOpener(services) {
|
|
|
1512
1483
|
}
|
|
1513
1484
|
});
|
|
1514
1485
|
if (manualExtension) {
|
|
1515
|
-
rolloutBudget?.recordUsage(manualExtension.usage);
|
|
1516
|
-
rolloutBudget?.assertAvailable();
|
|
1517
1486
|
if (manualExtension.usage)
|
|
1518
1487
|
await emit({ type: 'usage.updated', ...publicModelUsage(manualExtension.usage) });
|
|
1519
1488
|
}
|
|
@@ -1602,7 +1571,6 @@ export function createSessionOpener(services) {
|
|
|
1602
1571
|
if (sessionRuntime.toolSources === executionToolSources)
|
|
1603
1572
|
delete sessionRuntime.toolSources;
|
|
1604
1573
|
internal.signal?.removeEventListener('abort', abortSource);
|
|
1605
|
-
rolloutBudget?.discard();
|
|
1606
1574
|
await manualCompaction?.dispose();
|
|
1607
1575
|
await selectedTurn?.close().catch(() => undefined);
|
|
1608
1576
|
try {
|
|
@@ -60,6 +60,7 @@ export interface CreateMarAgentOptions {
|
|
|
60
60
|
readonly logicalPath: string;
|
|
61
61
|
readonly physicalPath: string;
|
|
62
62
|
};
|
|
63
|
+
/** @deprecated Accepted for source compatibility and otherwise ignored. */
|
|
63
64
|
rolloutBudget?: false | RolloutBudgetOptions;
|
|
64
65
|
runtimeExtensions?: readonly CoreRuntimeExtension[] | CoreExtensionSource;
|
|
65
66
|
}
|
|
@@ -1002,15 +1002,15 @@ export class JsonlSessionStore {
|
|
|
1002
1002
|
}
|
|
1003
1003
|
async #appendRecord(sessionId, input) {
|
|
1004
1004
|
this.#assertOpen();
|
|
1005
|
-
const
|
|
1005
|
+
const before = this.#shared.index.sessions.find((item) => item.id === sessionId) ??
|
|
1006
1006
|
this.#shared.pendingSessions.get(sessionId);
|
|
1007
|
-
if (!
|
|
1007
|
+
if (!before)
|
|
1008
1008
|
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
1009
1009
|
const published = !this.#shared.pendingSessions.has(sessionId);
|
|
1010
1010
|
const record = {
|
|
1011
1011
|
schemaVersion: 1,
|
|
1012
1012
|
recordId: randomUUID(),
|
|
1013
|
-
sequence:
|
|
1013
|
+
sequence: before.nextSequence,
|
|
1014
1014
|
timestamp: input.timestamp ?? new Date().toISOString(),
|
|
1015
1015
|
sessionId,
|
|
1016
1016
|
...(input.executionId ? { executionId: input.executionId } : {}),
|
|
@@ -1019,7 +1019,7 @@ export class JsonlSessionStore {
|
|
|
1019
1019
|
payload: input.payload
|
|
1020
1020
|
};
|
|
1021
1021
|
JSON.stringify(record); // Reject malformed payloads before binding resources.
|
|
1022
|
-
await bindToolResultResources(this.sessionDirectory(sessionId), record, (sequence) => this.#readRecordAtSequence(
|
|
1022
|
+
await bindToolResultResources(this.sessionDirectory(sessionId), record, (sequence) => this.#readRecordAtSequence(before, sequence), true);
|
|
1023
1023
|
const serialized = `${JSON.stringify(record)}\n`;
|
|
1024
1024
|
let segment = await this.#currentSegment(sessionId);
|
|
1025
1025
|
let path = this.#segmentPath(sessionId, segment);
|
|
@@ -1049,16 +1049,13 @@ export class JsonlSessionStore {
|
|
|
1049
1049
|
finally {
|
|
1050
1050
|
await handle.close();
|
|
1051
1051
|
}
|
|
1052
|
-
|
|
1053
|
-
await
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
typeof image.fileName === 'string' &&
|
|
1060
|
-
validInputImageFileName(image.fileName))
|
|
1061
|
-
await rm(join(this.sessionDirectory(sessionId), 'input_images', `.${image.fileName}.pending`), { force: true }).catch(() => undefined);
|
|
1052
|
+
// Index refreshes and commits can replace metadata during file I/O. Publish all
|
|
1053
|
+
// durable-record metadata onto the current entry without another await boundary.
|
|
1054
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId) ??
|
|
1055
|
+
this.#shared.pendingSessions.get(sessionId);
|
|
1056
|
+
if (!meta)
|
|
1057
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
1058
|
+
meta.nextSequence = record.sequence + 1;
|
|
1062
1059
|
const segmentMetadata = meta.segments ?? (meta.segments = []);
|
|
1063
1060
|
const known = segmentMetadata.find((item) => item.number === segment);
|
|
1064
1061
|
if (known) {
|
|
@@ -1078,6 +1075,15 @@ export class JsonlSessionStore {
|
|
|
1078
1075
|
this.#shared.index.revision++;
|
|
1079
1076
|
this.#markIndexDirty(sessionId);
|
|
1080
1077
|
}
|
|
1078
|
+
await completeToolResultResources(this.sessionDirectory(sessionId), record);
|
|
1079
|
+
if (record.type === 'turn.user' &&
|
|
1080
|
+
isObject(record.payload) &&
|
|
1081
|
+
Array.isArray(record.payload.images))
|
|
1082
|
+
for (const image of record.payload.images)
|
|
1083
|
+
if (isObject(image) &&
|
|
1084
|
+
typeof image.fileName === 'string' &&
|
|
1085
|
+
validInputImageFileName(image.fileName))
|
|
1086
|
+
await rm(join(this.sessionDirectory(sessionId), 'input_images', `.${image.fileName}.pending`), { force: true }).catch(() => undefined);
|
|
1081
1087
|
return record;
|
|
1082
1088
|
}
|
|
1083
1089
|
async read(sessionId) {
|
|
@@ -1815,7 +1821,6 @@ export class JsonlSessionStore {
|
|
|
1815
1821
|
}
|
|
1816
1822
|
/** Repair the last segment and pending images under the lease, then sync sequence metadata. */
|
|
1817
1823
|
async #reconcileTail(sessionId) {
|
|
1818
|
-
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
1819
1824
|
const paths = await this.#segmentPaths(sessionId);
|
|
1820
1825
|
const latestPath = paths.at(-1);
|
|
1821
1826
|
await repairSegmentTail(latestPath);
|
|
@@ -1830,6 +1835,8 @@ export class JsonlSessionStore {
|
|
|
1830
1835
|
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Session history is corrupt.');
|
|
1831
1836
|
const bytes = (await stat(latestPath)).size;
|
|
1832
1837
|
const firstSequence = records[0].sequence;
|
|
1838
|
+
// Tail recovery must publish onto metadata that is current after all file I/O.
|
|
1839
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
1833
1840
|
const known = meta.segments?.find((item) => item.number === segment);
|
|
1834
1841
|
const titleRecord = records.findLast((record) => record.type === 'session.title.updated' &&
|
|
1835
1842
|
typeof record.payload.title === 'string');
|
package/package.json
CHANGED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import type { RolloutBudgetStage } from '../runtime/rollout-budget.js';
|
|
2
|
-
export type ExecutionBudgetEnvironmentStage = Exclude<RolloutBudgetStage, 'normal' | 'exhausted'> | 'inactive';
|
|
3
|
-
export declare function executionBudgetEnvironmentEntry(stage: ExecutionBudgetEnvironmentStage): string;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export function executionBudgetEnvironmentEntry(stage) {
|
|
2
|
-
if (stage === 'inactive')
|
|
3
|
-
return '<execution_guidance status="inactive" />';
|
|
4
|
-
const privateInstruction = 'This is internal runtime guidance. Never mention the budget, thresholds, remaining amount, or budget stage in user-visible progress or the final answer.';
|
|
5
|
-
const guidance = stage === 'finalize'
|
|
6
|
-
? 'Enter finalization now. Do not start new investigation or new subagents. Complete only the current atomic change, the minimum necessary verification, and the final answer as soon as possible.'
|
|
7
|
-
: 'Stop expanding scope and stop optional work. Prefer completing the current objective with the evidence already gathered, and avoid new investigation unless it is strictly required for correctness.';
|
|
8
|
-
return `<execution_guidance stage="${stage}">\n${privateInstruction}\n\n${guidance}\n</execution_guidance>`;
|
|
9
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { ModelUsage } from '../model/contracts.js';
|
|
2
|
-
import type { RolloutBudgetOptions } from './contracts.js';
|
|
3
|
-
export type RolloutBudgetStage = 'normal' | 'conserve' | 'finalize' | 'exhausted';
|
|
4
|
-
export interface ResolvedRolloutBudgetOptions {
|
|
5
|
-
limitTokens: number;
|
|
6
|
-
conserveAtRemainingTokens: number;
|
|
7
|
-
finalizeAtRemainingTokens: number;
|
|
8
|
-
samplingTokenWeight: number;
|
|
9
|
-
prefillTokenWeight: number;
|
|
10
|
-
}
|
|
11
|
-
export declare class RolloutBudget {
|
|
12
|
-
#private;
|
|
13
|
-
readonly options: ResolvedRolloutBudgetOptions;
|
|
14
|
-
constructor(options: ResolvedRolloutBudgetOptions);
|
|
15
|
-
get active(): boolean;
|
|
16
|
-
get limitTokens(): number;
|
|
17
|
-
get spentTokens(): number;
|
|
18
|
-
get remainingTokens(): number;
|
|
19
|
-
get stage(): RolloutBudgetStage;
|
|
20
|
-
recordUsage(usage: ModelUsage | undefined): number;
|
|
21
|
-
discard(): void;
|
|
22
|
-
assertAvailable(): void;
|
|
23
|
-
}
|
|
24
|
-
export declare function resolveRolloutBudgetOptions(options: false | RolloutBudgetOptions | undefined): ResolvedRolloutBudgetOptions | undefined;
|
|
25
|
-
export declare function createRolloutBudget(options: false | RolloutBudgetOptions | undefined): RolloutBudget | undefined;
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { MarAgentError } from '../error.js';
|
|
2
|
-
import { AGENT_EXECUTION_POLICY } from './execution-policy.js';
|
|
3
|
-
export class RolloutBudget {
|
|
4
|
-
options;
|
|
5
|
-
#spentTokens = 0;
|
|
6
|
-
#active = true;
|
|
7
|
-
constructor(options) {
|
|
8
|
-
this.options = options;
|
|
9
|
-
}
|
|
10
|
-
get active() {
|
|
11
|
-
return this.#active;
|
|
12
|
-
}
|
|
13
|
-
get limitTokens() {
|
|
14
|
-
return this.options.limitTokens;
|
|
15
|
-
}
|
|
16
|
-
get spentTokens() {
|
|
17
|
-
return this.#spentTokens;
|
|
18
|
-
}
|
|
19
|
-
get remainingTokens() {
|
|
20
|
-
return Math.max(0, this.limitTokens - this.#spentTokens);
|
|
21
|
-
}
|
|
22
|
-
get stage() {
|
|
23
|
-
if (!this.#active)
|
|
24
|
-
return 'normal';
|
|
25
|
-
const remaining = this.remainingTokens;
|
|
26
|
-
if (remaining <= 0)
|
|
27
|
-
return 'exhausted';
|
|
28
|
-
if (remaining <= this.options.finalizeAtRemainingTokens)
|
|
29
|
-
return 'finalize';
|
|
30
|
-
if (remaining <= this.options.conserveAtRemainingTokens)
|
|
31
|
-
return 'conserve';
|
|
32
|
-
return 'normal';
|
|
33
|
-
}
|
|
34
|
-
recordUsage(usage) {
|
|
35
|
-
if (!this.#active || !usage)
|
|
36
|
-
return 0;
|
|
37
|
-
const providerUnits = usage.rolloutBudgetUnits;
|
|
38
|
-
if (providerUnits !== undefined && (!Number.isFinite(providerUnits) || providerUnits < 0))
|
|
39
|
-
throw new MarAgentError('MAR_AGENT_MODEL_PROTOCOL_ERROR', 'Provider rollout budget units are invalid.');
|
|
40
|
-
const charged = providerUnits ??
|
|
41
|
-
nonnegative(usage.outputTokens) * this.options.samplingTokenWeight +
|
|
42
|
-
Math.max(nonnegative(usage.contextInputTokens ?? usage.inputTokens) -
|
|
43
|
-
nonnegative(usage.cacheReadTokens), 0) *
|
|
44
|
-
this.options.prefillTokenWeight;
|
|
45
|
-
this.#spentTokens += charged;
|
|
46
|
-
return charged;
|
|
47
|
-
}
|
|
48
|
-
discard() {
|
|
49
|
-
this.#active = false;
|
|
50
|
-
}
|
|
51
|
-
assertAvailable() {
|
|
52
|
-
if (this.stage === 'exhausted')
|
|
53
|
-
throw new MarAgentError('MAR_AGENT_ROLLOUT_BUDGET_EXCEEDED', 'The execution token budget has been exhausted.');
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
export function resolveRolloutBudgetOptions(options) {
|
|
57
|
-
if (options === false)
|
|
58
|
-
return undefined;
|
|
59
|
-
const limitTokens = options?.limitTokens ?? AGENT_EXECUTION_POLICY.rolloutBudgetTokens;
|
|
60
|
-
if (!Number.isSafeInteger(limitTokens) || limitTokens < 2)
|
|
61
|
-
return invalid();
|
|
62
|
-
const conserveAtRemainingTokens = options?.conserveAtRemainingTokens ??
|
|
63
|
-
Math.min(AGENT_EXECUTION_POLICY.rolloutBudgetConserveRemainingTokens, Math.max(1, Math.floor(limitTokens * 0.28)));
|
|
64
|
-
const finalizeAtRemainingTokens = options?.finalizeAtRemainingTokens ??
|
|
65
|
-
Math.min(AGENT_EXECUTION_POLICY.rolloutBudgetFinalizeRemainingTokens, Math.max(0, Math.min(conserveAtRemainingTokens - 1, Math.floor(limitTokens * 0.16))));
|
|
66
|
-
const samplingTokenWeight = options?.samplingTokenWeight ?? AGENT_EXECUTION_POLICY.rolloutBudgetSamplingTokenWeight;
|
|
67
|
-
const prefillTokenWeight = options?.prefillTokenWeight ?? AGENT_EXECUTION_POLICY.rolloutBudgetPrefillTokenWeight;
|
|
68
|
-
if (!Number.isSafeInteger(conserveAtRemainingTokens) ||
|
|
69
|
-
conserveAtRemainingTokens < 0 ||
|
|
70
|
-
conserveAtRemainingTokens >= limitTokens ||
|
|
71
|
-
!Number.isSafeInteger(finalizeAtRemainingTokens) ||
|
|
72
|
-
finalizeAtRemainingTokens < 0 ||
|
|
73
|
-
finalizeAtRemainingTokens >= conserveAtRemainingTokens ||
|
|
74
|
-
!Number.isFinite(samplingTokenWeight) ||
|
|
75
|
-
samplingTokenWeight < 0 ||
|
|
76
|
-
!Number.isFinite(prefillTokenWeight) ||
|
|
77
|
-
prefillTokenWeight < 0)
|
|
78
|
-
return invalid();
|
|
79
|
-
return {
|
|
80
|
-
limitTokens,
|
|
81
|
-
conserveAtRemainingTokens,
|
|
82
|
-
finalizeAtRemainingTokens,
|
|
83
|
-
samplingTokenWeight,
|
|
84
|
-
prefillTokenWeight
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
export function createRolloutBudget(options) {
|
|
88
|
-
const resolved = resolveRolloutBudgetOptions(options);
|
|
89
|
-
return resolved ? new RolloutBudget(resolved) : undefined;
|
|
90
|
-
}
|
|
91
|
-
function nonnegative(value) {
|
|
92
|
-
return value !== undefined && Number.isFinite(value) && value >= 0 ? value : 0;
|
|
93
|
-
}
|
|
94
|
-
function invalid() {
|
|
95
|
-
throw new MarAgentError('MAR_AGENT_ROLLOUT_BUDGET_INVALID', 'Rollout budget configuration is invalid.');
|
|
96
|
-
}
|