@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.
@@ -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.responsesTransport?.transport !== 'WEBSOCKET',
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.63";
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.63';
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. If current environment guidance requires finalization, stop further exploration and use only evidence already gathered.';
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. When current environment guidance requires finalization and 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. When current environment guidance requires finalization, return the concise verified staged plan and distinguish incomplete work or unresolved decisions. Do not ask whether to proceed or claim unresolved work is complete.';
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, rolloutBudgetOptions, createAdapter, activeAdaptersExcept } = services;
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 meta = this.#shared.index.sessions.find((item) => item.id === sessionId) ??
1005
+ const before = this.#shared.index.sessions.find((item) => item.id === sessionId) ??
1006
1006
  this.#shared.pendingSessions.get(sessionId);
1007
- if (!meta)
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: meta.nextSequence,
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(meta, sequence), true);
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
- meta.nextSequence++;
1053
- await completeToolResultResources(this.sessionDirectory(sessionId), record);
1054
- if (record.type === 'turn.user' &&
1055
- isObject(record.payload) &&
1056
- Array.isArray(record.payload.images))
1057
- for (const image of record.payload.images)
1058
- if (isObject(image) &&
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/agent",
3
- "version": "0.10.11",
3
+ "version": "0.10.13",
4
4
  "description": "Embeddable MAR coding agent SDK and CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -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
- }