@myagentroam/agent 0.9.173 → 0.9.175

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.
Files changed (29) hide show
  1. package/dist/agent-core/extensions/compaction.d.ts +1 -1
  2. package/dist/agent-core/extensions/model-request.js +7 -1
  3. package/dist/agent-core/extensions/model-stream.js +5 -1
  4. package/dist/agent-core/model/anthropic-messages.js +35 -25
  5. package/dist/agent-core/model/catalog-file.d.ts +0 -2
  6. package/dist/agent-core/model/catalog-file.js +7 -0
  7. package/dist/agent-core/model/configuration.d.ts +0 -1
  8. package/dist/agent-core/model/configuration.js +0 -1
  9. package/dist/agent-core/model/contracts.d.ts +13 -0
  10. package/dist/agent-core/model/openai-responses.js +57 -48
  11. package/dist/agent-core/model/sse.js +59 -9
  12. package/dist/agent-core/prompts/compact.d.ts +0 -1
  13. package/dist/agent-core/prompts/compact.js +0 -56
  14. package/dist/agent-core/prompts/index.d.ts +0 -1
  15. package/dist/agent-core/prompts/index.js +2 -9
  16. package/dist/agent-core/runtime/compaction/history.d.ts +1 -2
  17. package/dist/agent-core/runtime/compaction/history.js +4 -4
  18. package/dist/agent-core/runtime/events.d.ts +1 -1
  19. package/dist/agent-core/runtime/execution.js +35 -24
  20. package/dist/agent-core/runtime/model-generation-timing.d.ts +12 -0
  21. package/dist/agent-core/runtime/model-generation-timing.js +39 -0
  22. package/dist/agent-core/sdk/session.js +7 -11
  23. package/dist/agent-core/tools/agent/agent-start.js +3 -1
  24. package/dist/agent-core/tools/code-mode/index.js +10 -5
  25. package/dist/agent-core/tools/definition-projection.d.ts +7 -0
  26. package/dist/agent-core/tools/definition-projection.js +26 -0
  27. package/dist/agent-core/tools/mcp/tool-search.js +12 -4
  28. package/dist/cli/main.js +6 -4
  29. package/package.json +1 -1
@@ -1,4 +1,5 @@
1
1
  import { observationModelParts } from '../tools/code-mode/observations.js';
2
+ import { stableToolSchema } from '../tools/definition-projection.js';
2
3
  import { isDeepStrictEqual } from 'node:util';
3
4
  import { createHash, randomUUID } from 'node:crypto';
4
5
  import { describeMarAgentError, MarAgentError } from '../error.js';
@@ -89,6 +90,15 @@ export class OpenAiResponsesAdapter {
89
90
  const attemptContinuation = useContinuation;
90
91
  const attemptCredentialReason = credentialReason;
91
92
  const attemptTransport = this.configuration.responsesTransport?.transport === 'WEBSOCKET' ? 'WEBSOCKET' : 'HTTP';
93
+ const requestPrefixDiagnostic = request.onAttemptDiagnostic
94
+ ? {
95
+ requestInstructionsHash: hashResponsesValue(prepared.fullBody.instructions),
96
+ requestToolsHash: hashResponsesValue(prepared.fullBody.tools),
97
+ requestPropertiesHash: hashResponsesValue({ ...prepared.fullBody, input: undefined }),
98
+ requestInputHash: hashResponsesValue(prepared.fullBody.input),
99
+ requestInputItems: prepared.fullBody.input.length
100
+ }
101
+ : {};
92
102
  const prelude = [];
93
103
  let sawSemanticEvent = false;
94
104
  let firstSemanticEventType;
@@ -100,11 +110,12 @@ export class OpenAiResponsesAdapter {
100
110
  attempt: attemptNumber,
101
111
  maxAttempts,
102
112
  continuation: attemptContinuation,
103
- credentialReason: attemptCredentialReason
113
+ credentialReason: attemptCredentialReason,
114
+ ...requestPrefixDiagnostic
104
115
  });
105
116
  try {
106
117
  for await (const event of this.startAttempt(request, signal, requestBody, useContinuation, credentialReason, turn)) {
107
- if (event.type === 'output.delta') {
118
+ if (event.type.startsWith('output.')) {
108
119
  resetOutputTiming = true;
109
120
  yield event;
110
121
  continue;
@@ -130,6 +141,7 @@ export class OpenAiResponsesAdapter {
130
141
  maxAttempts,
131
142
  continuation: attemptContinuation,
132
143
  credentialReason: attemptCredentialReason,
144
+ ...requestPrefixDiagnostic,
133
145
  semanticEventObserved: sawSemanticEvent,
134
146
  ...(firstSemanticEventType === undefined ? {} : { firstSemanticEventType }),
135
147
  ...turn.connectionDiagnostic(),
@@ -146,6 +158,7 @@ export class OpenAiResponsesAdapter {
146
158
  maxAttempts,
147
159
  continuation: attemptContinuation,
148
160
  credentialReason: attemptCredentialReason,
161
+ ...requestPrefixDiagnostic,
149
162
  semanticEventObserved: sawSemanticEvent,
150
163
  ...(firstSemanticEventType === undefined ? {} : { firstSemanticEventType }),
151
164
  ...turn.connectionDiagnostic(),
@@ -297,10 +310,15 @@ export class OpenAiResponsesAdapter {
297
310
  for await (const raw of rawEvents) {
298
311
  const event = record(raw);
299
312
  const type = text(event.type) ?? 'unknown';
313
+ if (type === 'response.output_item.added' &&
314
+ ['reasoning', 'message', 'function_call', 'custom_tool_call'].includes(text(record(event.item).type) ?? ''))
315
+ yield observeModelStreamEvent({ type: 'output.started' }, modelStreamEventObservedAt(raw));
316
+ if (type === 'response.web_search_call.searching')
317
+ yield observeModelStreamEvent({ type: 'output.paused' }, modelStreamEventObservedAt(raw));
300
318
  if (type === 'response.output_item.done') {
301
319
  const item = responseItem(event.item);
302
320
  if (item)
303
- yield { type: 'response.item', provider: 'OPENAI_RESPONSES', item };
321
+ yield observeModelStreamEvent({ type: 'response.item', provider: 'OPENAI_RESPONSES', item }, modelStreamEventObservedAt(raw));
304
322
  }
305
323
  if (type === 'response.output_item.added' && text(record(event.item).type) === 'message') {
306
324
  const item = record(event.item);
@@ -319,7 +337,7 @@ export class OpenAiResponsesAdapter {
319
337
  if (completedText !== undefined && !emittedCompletedText.has(itemId)) {
320
338
  emittedCompletedText.add(itemId);
321
339
  pendingCompletedText.delete(itemId);
322
- yield { type: 'text.completed', itemId, phase, text: completedText };
340
+ yield observeModelStreamEvent({ type: 'text.completed', itemId, phase, text: completedText }, modelStreamEventObservedAt(raw));
323
341
  }
324
342
  }
325
343
  else if (type === 'response.output_item.added' &&
@@ -363,10 +381,10 @@ export class OpenAiResponsesAdapter {
363
381
  yield observeModelStreamEvent({ type: 'output.delta' }, modelStreamEventObservedAt(raw));
364
382
  }
365
383
  else if (type === 'response.created')
366
- yield {
384
+ yield observeModelStreamEvent({
367
385
  type: 'response.started',
368
386
  responseId: responseEventId(event) ?? 'unknown'
369
- };
387
+ }, modelStreamEventObservedAt(raw));
370
388
  else if (type === 'response.output_text.delta')
371
389
  yield observeModelStreamEvent({
372
390
  type: 'text.delta',
@@ -384,17 +402,17 @@ export class OpenAiResponsesAdapter {
384
402
  continue;
385
403
  if (phase) {
386
404
  emittedCompletedText.add(itemId);
387
- yield { type: 'text.completed', itemId, phase, text: completedText };
405
+ yield observeModelStreamEvent({ type: 'text.completed', itemId, phase, text: completedText }, modelStreamEventObservedAt(raw));
388
406
  }
389
407
  else
390
408
  pendingCompletedText.set(itemId, completedText);
391
409
  }
392
410
  else if (type === 'response.reasoning_summary_text.done')
393
- yield {
411
+ yield observeModelStreamEvent({
394
412
  type: 'reasoning.summary',
395
413
  itemId: text(event.item_id) ?? 'reasoning',
396
414
  text: text(event.text) ?? ''
397
- };
415
+ }, modelStreamEventObservedAt(raw));
398
416
  else if (type === 'response.output_item.done' &&
399
417
  text(record(event.item).type) === 'tool_search_call') {
400
418
  const item = record(event.item);
@@ -410,13 +428,13 @@ export class OpenAiResponsesAdapter {
410
428
  }
411
429
  if (!emittedFunctionCalls.has(callId)) {
412
430
  emittedFunctionCalls.add(callId);
413
- yield {
431
+ yield observeModelStreamEvent({
414
432
  type: 'client_tool.call',
415
433
  callId,
416
434
  name: 'tool_search',
417
435
  arguments: arguments_,
418
436
  ...(argumentError ? { argumentError } : {})
419
- };
437
+ }, modelStreamEventObservedAt(raw));
420
438
  }
421
439
  }
422
440
  else if (type === 'response.function_call_arguments.done' ||
@@ -440,13 +458,13 @@ export class OpenAiResponsesAdapter {
440
458
  'unknown';
441
459
  if (!emittedFunctionCalls.has(callId)) {
442
460
  emittedFunctionCalls.add(callId);
443
- yield {
461
+ yield observeModelStreamEvent({
444
462
  type: 'client_tool.call',
445
463
  callId,
446
464
  name: text(event.name) ?? text(item.name) ?? known?.name ?? 'unknown',
447
465
  arguments: args,
448
466
  ...(argumentError ? { argumentError } : {})
449
- };
467
+ }, modelStreamEventObservedAt(raw));
450
468
  }
451
469
  }
452
470
  else if (type === 'response.custom_tool_call_input.done' ||
@@ -458,13 +476,13 @@ export class OpenAiResponsesAdapter {
458
476
  const callId = text(event.call_id) ?? text(item.call_id) ?? known?.callId ?? itemId;
459
477
  if (!emittedFunctionCalls.has(callId)) {
460
478
  emittedFunctionCalls.add(callId);
461
- yield {
479
+ yield observeModelStreamEvent({
462
480
  type: 'client_tool.call',
463
481
  callId,
464
482
  name: text(event.name) ?? text(item.name) ?? known?.name ?? 'unknown',
465
483
  arguments: text(event.input) ?? text(item.input) ?? known?.input ?? '',
466
484
  inputMode: 'freeform'
467
- };
485
+ }, modelStreamEventObservedAt(raw));
468
486
  }
469
487
  }
470
488
  else if (type.includes('web_search_call') ||
@@ -489,7 +507,7 @@ export class OpenAiResponsesAdapter {
489
507
  ? {}
490
508
  : { sourcesTruncated: summary.sourcesTruncated })
491
509
  };
492
- yield {
510
+ yield observeModelStreamEvent({
493
511
  type: 'hosted_tool',
494
512
  itemId,
495
513
  kind,
@@ -503,13 +521,13 @@ export class OpenAiResponsesAdapter {
503
521
  ? 'COMPLETED'
504
522
  : 'RUNNING',
505
523
  summary
506
- };
524
+ }, modelStreamEventObservedAt(raw));
507
525
  }
508
526
  else if (type === 'response.output_text.annotation.added') {
509
527
  const annotation = record(event.annotation);
510
528
  const url = text(annotation.url);
511
529
  if (url)
512
- yield {
530
+ yield observeModelStreamEvent({
513
531
  type: 'citation',
514
532
  citation: {
515
533
  id: text(annotation.id) ??
@@ -517,9 +535,10 @@ export class OpenAiResponsesAdapter {
517
535
  url,
518
536
  ...(text(annotation.title) ? { title: text(annotation.title) } : {})
519
537
  }
520
- };
538
+ }, modelStreamEventObservedAt(raw));
521
539
  }
522
540
  else if (type === 'response.completed' || type === 'response.incomplete') {
541
+ yield observeModelStreamEvent({ type: 'output.completed' }, modelStreamEventObservedAt(raw));
523
542
  const responseData = record(event.response);
524
543
  if (type === 'response.completed')
525
544
  turn.captureCompletedResponseId(responseEventId(event));
@@ -527,21 +546,22 @@ export class OpenAiResponsesAdapter {
527
546
  if (emittedCompletedText.has(itemId))
528
547
  continue;
529
548
  emittedCompletedText.add(itemId);
530
- yield {
549
+ yield observeModelStreamEvent({
531
550
  type: 'text.completed',
532
551
  itemId,
533
552
  phase: textPhases.get(itemId) ?? 'final_answer',
534
553
  text: completedText
535
- };
554
+ }, modelStreamEventObservedAt(raw));
536
555
  }
537
556
  pendingCompletedText.clear();
538
557
  for (const citation of responseCitations(responseData))
539
- yield { type: 'citation', citation };
558
+ yield observeModelStreamEvent({ type: 'citation', citation }, modelStreamEventObservedAt(raw));
540
559
  const usage = record(responseData.usage);
541
560
  const inputDetails = record(usage.input_tokens_details);
542
561
  const rolloutBudgetUnits = optionalRolloutBudgetUnits(usage.codex_rollout_budget_units);
543
- yield {
562
+ yield observeModelStreamEvent({
544
563
  type: 'usage',
564
+ final: true,
545
565
  usage: {
546
566
  inputTokens: number(usage.input_tokens),
547
567
  contextInputTokens: number(usage.input_tokens),
@@ -550,7 +570,7 @@ export class OpenAiResponsesAdapter {
550
570
  cacheWriteTokens: number(inputDetails.cache_write_tokens),
551
571
  ...(rolloutBudgetUnits === undefined ? {} : { rolloutBudgetUnits })
552
572
  }
553
- };
573
+ }, modelStreamEventObservedAt(raw));
554
574
  yield observeModelStreamEvent({
555
575
  type: 'completed',
556
576
  reason: type === 'response.incomplete' ? 'max_output' : 'completed'
@@ -586,7 +606,7 @@ export class OpenAiResponsesAdapter {
586
606
  });
587
607
  }
588
608
  else if (!isNonSemanticOpenAiResponsesEvent(type))
589
- yield { type: 'unknown', nativeType: type };
609
+ yield observeModelStreamEvent({ type: 'unknown', nativeType: type }, modelStreamEventObservedAt(raw));
590
610
  }
591
611
  }
592
612
  catch (error) {
@@ -651,7 +671,7 @@ class OpenAiResponsesTurnSession {
651
671
  if (event.type === 'response.started' && event.responseId !== 'unknown')
652
672
  responseId = event.responseId;
653
673
  else if (event.type === 'response.item')
654
- outputItems.push(event.item);
674
+ outputItems.push(JSON.parse(JSON.stringify(event.item)));
655
675
  else if (event.type === 'text.delta' ||
656
676
  event.type === 'output.delta' ||
657
677
  event.type === 'text.completed' ||
@@ -706,7 +726,8 @@ class OpenAiResponsesTurnSession {
706
726
  invalidateResponsesWebSocket(this.state, false);
707
727
  clearResponsesContinuation(this.state);
708
728
  }
709
- const fullBody = responsesRequestBody(this.adapter.configuration, request, request.messages);
729
+ // The continuation baseline must not share mutable schemas or items with callers.
730
+ const fullBody = JSON.parse(JSON.stringify(responsesRequestBody(this.adapter.configuration, request, request.messages)));
710
731
  if (responsesContinuationEnabled(this.adapter.configuration)) {
711
732
  const incremental = incrementalResponsesInput(this.state, fullBody);
712
733
  if (incremental !== undefined) {
@@ -875,7 +896,7 @@ function responsesRequestBody(configuration, request, messages) {
875
896
  type: 'tool_search',
876
897
  execution: 'client',
877
898
  description: tool.description,
878
- parameters: strictFunctionSchema(tool.inputSchema)
899
+ parameters: stableToolSchema(strictFunctionSchema(stableToolSchema(tool.inputSchema)))
879
900
  }
880
901
  : responsesFunctionTool(tool));
881
902
  if (configuration.responsesToolNamespace && tools.length > 0) {
@@ -948,27 +969,13 @@ function incrementalResponsesInput(state, current) {
948
969
  if (current.input.length < baseline.length)
949
970
  return undefined;
950
971
  for (let index = 0; index < baseline.length; index++)
951
- if (!isDeepStrictEqual(baseline[index], current.input[index]))
972
+ if (JSON.stringify(baseline[index]) !== JSON.stringify(current.input[index]))
952
973
  return undefined;
953
974
  return current.input.slice(baseline.length);
954
975
  }
955
976
  function responsesContinuationPropertiesMatch(previous, current) {
956
- const properties = [
957
- 'model',
958
- 'service_tier',
959
- 'instructions',
960
- 'tools',
961
- 'tool_choice',
962
- 'max_output_tokens',
963
- 'parallel_tool_calls',
964
- 'reasoning',
965
- 'store',
966
- 'stream',
967
- 'include',
968
- 'prompt_cache_key',
969
- 'text'
970
- ];
971
- return properties.every((property) => isDeepStrictEqual(previous[property], current[property]));
977
+ return (JSON.stringify({ ...previous, input: undefined }) ===
978
+ JSON.stringify({ ...current, input: undefined }));
972
979
  }
973
980
  function clearResponsesContinuation(state) {
974
981
  delete state.lastRequest;
@@ -1387,6 +1394,8 @@ function webSocketReceiveError(cause) {
1387
1394
  });
1388
1395
  }
1389
1396
  function isSemanticEvent(event) {
1397
+ if (event.type.startsWith('output.'))
1398
+ return false;
1390
1399
  if (event.type === 'response.started' || event.type === 'usage' || event.type === 'response.item')
1391
1400
  return false;
1392
1401
  if (event.type === 'text.delta')
@@ -1508,11 +1517,11 @@ function responsesHeaders(credential, promptCacheKey, turnState) {
1508
1517
  authorization: `Bearer ${credential.bearer.reveal()}`,
1509
1518
  'content-type': 'application/json',
1510
1519
  accept: 'text/event-stream',
1520
+ 'x-client-request-id': randomUUID(),
1511
1521
  ...(promptCacheKey
1512
1522
  ? {
1513
1523
  'session-id': promptCacheKey,
1514
- 'thread-id': promptCacheKey,
1515
- 'x-client-request-id': promptCacheKey
1524
+ 'thread-id': promptCacheKey
1516
1525
  }
1517
1526
  : {})
1518
1527
  });
@@ -1927,7 +1936,7 @@ function responsesFunctionTool(tool) {
1927
1936
  type: 'function',
1928
1937
  name: tool.name,
1929
1938
  description: tool.description,
1930
- parameters: strict ? strictFunctionSchema(tool.inputSchema) : tool.inputSchema,
1939
+ parameters: stableToolSchema(strict ? strictFunctionSchema(stableToolSchema(tool.inputSchema)) : tool.inputSchema),
1931
1940
  strict
1932
1941
  };
1933
1942
  }
@@ -38,18 +38,66 @@ export async function* parseSse(response, signal, maxBytes = 16 * 1024 * 1024, i
38
38
  let buffer = '';
39
39
  let total = 0;
40
40
  let streamCompleted = false;
41
+ const receiverAbort = new AbortController();
42
+ const receiverSignal = AbortSignal.any([signal, receiverAbort.signal]);
43
+ const chunks = [];
44
+ let nextChunk = 0;
45
+ let receivedAll = false;
46
+ let receiverFailure;
47
+ let wake;
48
+ const notify = () => {
49
+ wake?.();
50
+ wake = undefined;
51
+ };
52
+ // Keep transport receipt independent of async SDK publication and persistence.
53
+ // The cumulative response byte limit also bounds the pending raw chunk queue.
54
+ const receive = (async () => {
55
+ try {
56
+ while (true) {
57
+ const { value, done } = await readStreamChunk(reader, receiverSignal, idleTimeoutMs);
58
+ const observedAt = performance.now();
59
+ if (done) {
60
+ streamCompleted = true;
61
+ break;
62
+ }
63
+ total += value.byteLength;
64
+ enforceResponseSize(total, maxBytes);
65
+ if (value.byteLength === 0)
66
+ continue;
67
+ chunks.push({ value, observedAt });
68
+ notify();
69
+ }
70
+ }
71
+ catch (error) {
72
+ receiverFailure = { error };
73
+ await reader.cancel(error).catch(() => undefined);
74
+ }
75
+ finally {
76
+ receivedAll = true;
77
+ notify();
78
+ }
79
+ })();
41
80
  try {
42
81
  while (true) {
43
- if (signal.aborted)
44
- throw signal.reason;
45
- const { value, done } = await readStreamChunk(reader, signal, idleTimeoutMs);
46
- const observedAt = performance.now();
47
- if (done) {
48
- streamCompleted = true;
49
- break;
82
+ signal.throwIfAborted();
83
+ const chunk = chunks[nextChunk];
84
+ if (chunk === undefined) {
85
+ if (receivedAll) {
86
+ if (receiverFailure !== undefined)
87
+ throw receiverFailure.error;
88
+ break;
89
+ }
90
+ await new Promise((resolve) => {
91
+ wake = resolve;
92
+ });
93
+ continue;
50
94
  }
51
- total += value.byteLength;
52
- enforceResponseSize(total, maxBytes);
95
+ chunks[nextChunk++] = undefined;
96
+ if (nextChunk >= 1_024 && nextChunk * 2 >= chunks.length) {
97
+ chunks.splice(0, nextChunk);
98
+ nextChunk = 0;
99
+ }
100
+ const { value, observedAt } = chunk;
53
101
  buffer += decoder.decode(value, { stream: true }).replaceAll('\r\n', '\n');
54
102
  let boundary;
55
103
  while ((boundary = buffer.indexOf('\n\n')) >= 0) {
@@ -75,6 +123,8 @@ export async function* parseSse(response, signal, maxBytes = 16 * 1024 * 1024, i
75
123
  throw new MarAgentError('MAR_AGENT_MODEL_PROTOCOL_ERROR', 'Model SSE ended with an incomplete frame.');
76
124
  }
77
125
  finally {
126
+ receiverAbort.abort();
127
+ await receive;
78
128
  await closeReader(reader, streamCompleted);
79
129
  }
80
130
  }
@@ -1,2 +1 @@
1
1
  export declare function compactionPrompt(): string;
2
- export declare function highDensityCompactionPrompt(): string;
@@ -24,59 +24,3 @@ Remove aggressively:
24
24
 
25
25
  Use compact Markdown with these headings when applicable: Objective, Instructions and constraints, Decisions and facts, Completed work, Verification and evidence, Active state, Open issues and risks, Next action. Omit empty headings. Prefer precise paths, IDs, error codes, and short evidence over narrative. Output only the handoff.`;
26
26
  }
27
- export function highDensityCompactionPrompt() {
28
- return `Compile the visible conversation into Textual Continuation IR that lets the next agent continue correctly after the transcript is discarded. Transfer state; do not recap, address the user, call tools, advance the task, or invent facts.
29
-
30
- Optimize for continuation fidelity first and density second. Prefer sufficient continuation state over brevity; never omit information required to resume correctly.
31
-
32
- ## Output contract
33
- Use these English section names when applicable; omit empty sections:
34
- 1. Goal contract
35
- 2. Current state
36
- 3. Settled matters
37
- 4. Necessary evidence
38
- 5. Open loops
39
-
40
- IR grammar and vocabulary are English: headings, keys, enums, state atoms, and control terms. Natural-language values may follow the task's dominant language. Preserve exact user-designated text and established domain terms; do not translate identifiers or invent localized IR terminology.
41
-
42
- Prefer records over prose:
43
- <object> | <key>=<value> | <key>=<value>
44
- <event/condition> -> <object>.<key>=<value> | <effect>
45
-
46
- Use | for parallel facts, = for current state, and -> only for causality, invalidation, or transition. Keep enums lowercase and semantic: required, forbidden, pending; never YES/NO. Omit empty or irrelevant unknown fields. Keep pending, not run, unverified, and failed distinct. Use a sentence only when records cannot express a multi-object cause, conflict, authorization, or safety boundary unambiguously.
47
-
48
- Examples:
49
- src/discount.js | cause=verified | edit=pending | tests=not run
50
- patch(src/discount.js) -> prior_read=stale | next=re-evidence
51
- authorization | action=<exact> | scope=<exact> | lifetime=<exact> | status=active
52
-
53
- ## Compiler
54
- 1. Resolve intent. The latest user correction overrides older intent. Extract the primary objective, current deliverable, completion criteria, non-goals, and boundaries.
55
- 2. Reduce time. Convert before -> event -> after into the latest evidenced state. Source mutation or base/branch change makes only affected evidence stale. History replacement invalidates Responses continuation, not factual evidence. Without an invalidating event, a verified claim remains current.
56
- 3. Build objects. Emit one current record per file, symbol, feature, migration, test, worktree axis, selected Skill, Todo/plan item, external decision, or external side effect. Deduplicate equivalent facts.
57
- 4. Separate status axes when needed:
58
- - completion=pending|in_progress|completed|blocked
59
- - epistemic=observed|verified|inferred|proposed|disproved
60
- - freshness=current|stale|superseded
61
- - scope=turn|worktree|base|branch|external
62
- 5. Bind evidence to the claim it proves. Prefer a verified conclusion over raw snapshots or intermediate hypotheses.
63
- 6. Select under budget. Protect, in order: objective, progress, boundaries and authorization, non-repeatable side effects, open loops, then necessary evidence. Remove provenance and recoverable detail only after those remain sufficient.
64
-
65
- ## Retention rules
66
- - Preserve active caller/user instructions outside filesystem-loaded AGENTS.md, exact authorization boundaries, confirmed decisions and exclusions, completed edits and side effects, verification actually run, reproducible failures, failed approaches that constrain the next step, unresolved risks, and the smallest established next action.
67
- - Authorization is valid only for its exact action, scope, and lifetime in the active request. Completed or superseded scopes cannot revive it. Object state, completion, tool availability, and convenience never imply permission.
68
- - Preserve decisive values, or an exact artifact path/command that deterministically recovers them, when a result controls later work. Counts or schemas alone are insufficient.
69
- - Preserve paths, symbols, APIs, tools, models, providers, JSON keys, protocol fields, commands, arguments, error codes, commit hashes, call IDs, sequences, versions, numbers, and user-designated text verbatim.
70
- - Preserve selected Skill names with only continuation-critical constraints. Preserve Todo/plan revision, item/status, and current minimum step.
71
- - Keep observed HEAD, validated base, target commit, and current worktree as separate axes. Evidence updates only what it directly proves; cross-axis, cross-base, and cross-branch inference remains unverified.
72
- - If evidence conflicts, use state=conflict | candidates=<short values> | next=re-evidence. Never choose a side without evidence.
73
-
74
- ## Exclusions
75
- Remove greetings, progress chatter, chronology that does not affect current state, duplicate facts, superseded hypotheses without remaining constraints, long logs, source bodies, verbose payloads, cheap-to-recover content, local-only integrity hashes, hidden reasoning, secrets, credentials, and unrelated content.
76
-
77
- Remove user/project/directory AGENTS.md text and constraints derived only from those files; the next Execution reloads them. Remove retained process/Subagent inventory, IDs, status, commands, cwd, and reuse instructions; Runtime reloads them.
78
-
79
- Before emitting, verify that objective, current progress, authorization/boundaries, completed versus unverified work, decisive evidence, open loops, and next action are explicit and non-contradictory.
80
-
81
- Output only compact Markdown IR.`;
82
- }
@@ -13,7 +13,6 @@ interface SystemPromptInput {
13
13
  workspace: string;
14
14
  tools: readonly string[];
15
15
  directTools?: readonly string[];
16
- highDensityCompaction?: boolean;
17
16
  extension?: string | undefined;
18
17
  }
19
18
  export declare function buildSystemPrompt(input: SystemPromptInput): string;
@@ -1,5 +1,5 @@
1
1
  import { renderPromptSections } from '../extensions/prompt-composition.js';
2
- import { compactionPrompt, highDensityCompactionPrompt } from './compact.js';
2
+ import { compactionPrompt } from './compact.js';
3
3
  import { environmentPrompt, identityPrompt, instructionPriorityPrompt, workspaceDisciplinePrompt } from './core.js';
4
4
  import { modePrompt } from './modes.js';
5
5
  import { outputStylePrompt } from './output.js';
@@ -36,14 +36,7 @@ export function buildSystemPromptSections(input) {
36
36
  questionAvailable: toolNames.has('question')
37
37
  })
38
38
  ],
39
- [
40
- 'compaction',
41
- input.mode === 'compact'
42
- ? input.highDensityCompaction
43
- ? highDensityCompactionPrompt()
44
- : compactionPrompt()
45
- : ''
46
- ],
39
+ ['compaction', input.mode === 'compact' ? compactionPrompt() : ''],
47
40
  ['subagent', toolNames.has('agent_start') ? subagentPrompt : ''],
48
41
  [
49
42
  'caller-instructions',
@@ -3,9 +3,8 @@ import type { CompactHistoryMessage, CompactUserInput } from '../../session/json
3
3
  export declare const DEFAULT_COMPACTION_FOCUS = "Create a durable continuation state for the next model invocation.";
4
4
  export declare function buildNativeCompactionMessages(messages: readonly ModelMessage[], input?: {
5
5
  focus?: string;
6
- highDensityCompaction?: boolean;
7
6
  }): ModelMessage[];
8
- export declare function buildCompactionMessages(evidence: string, highDensityCompaction?: boolean): ModelMessage[];
7
+ export declare function buildCompactionMessages(evidence: string): ModelMessage[];
9
8
  export declare function buildCompactionInput(messages: readonly ModelMessage[], input: {
10
9
  focus?: string;
11
10
  maxTokens: number;
@@ -1,9 +1,9 @@
1
1
  import { countModelTokens, truncateModelText } from '../token-budget.js';
2
- import { compactionPrompt, highDensityCompactionPrompt } from '../../prompts/compact.js';
2
+ import { compactionPrompt } from '../../prompts/compact.js';
3
3
  export const DEFAULT_COMPACTION_FOCUS = 'Create a durable continuation state for the next model invocation.';
4
4
  export function buildNativeCompactionMessages(messages, input = {}) {
5
5
  const focus = input.focus?.trim();
6
- const contract = input.highDensityCompaction ? highDensityCompactionPrompt() : compactionPrompt();
6
+ const contract = compactionPrompt();
7
7
  return [
8
8
  ...messages
9
9
  .filter((message) => message.contextKind !== 'private')
@@ -21,13 +21,13 @@ export function buildNativeCompactionMessages(messages, input = {}) {
21
21
  }
22
22
  ];
23
23
  }
24
- export function buildCompactionMessages(evidence, highDensityCompaction = false) {
24
+ export function buildCompactionMessages(evidence) {
25
25
  return [
26
26
  { role: 'user', content: evidence, contextKind: 'contextual' },
27
27
  {
28
28
  role: 'user',
29
29
  contextKind: 'compact_control',
30
- content: highDensityCompaction ? highDensityCompactionPrompt() : compactionPrompt()
30
+ content: compactionPrompt()
31
31
  }
32
32
  ];
33
33
  }
@@ -26,7 +26,7 @@ export type MarAgentEvent = MarAgentEventBase & ({
26
26
  modelName: string;
27
27
  } | {
28
28
  type: 'model.performance';
29
- latencyMs: number;
29
+ latencyMs?: number | undefined;
30
30
  outputTokens?: number | undefined;
31
31
  outputDurationMs?: number | undefined;
32
32
  tokensPerSecond?: number | undefined;