@myagentroam/agent 0.11.20 → 0.11.22

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 (81) hide show
  1. package/dist/agent-core/error.d.ts +1 -1
  2. package/dist/agent-core/error.js +20 -14
  3. package/dist/agent-core/extensions/compaction.d.ts +6 -0
  4. package/dist/agent-core/extensions/compaction.js +16 -2
  5. package/dist/agent-core/extensions/model-request.d.ts +5 -9
  6. package/dist/agent-core/extensions/model-request.js +14 -3
  7. package/dist/agent-core/extensions/prompt-input.js +3 -1
  8. package/dist/agent-core/host/contracts.d.ts +8 -0
  9. package/dist/agent-core/host/local-agent-host.d.ts +2 -0
  10. package/dist/agent-core/host/local-agent-host.js +3 -0
  11. package/dist/agent-core/model/anthropic-messages.js +15 -26
  12. package/dist/agent-core/model/catalog-file.d.ts +2 -0
  13. package/dist/agent-core/model/configuration.d.ts +3 -1
  14. package/dist/agent-core/model/configuration.js +1 -0
  15. package/dist/agent-core/model/contracts.d.ts +5 -8
  16. package/dist/agent-core/model/image.d.ts +17 -0
  17. package/dist/agent-core/model/image.js +53 -0
  18. package/dist/agent-core/model/openai-responses.d.ts +7 -2
  19. package/dist/agent-core/model/openai-responses.js +81 -27
  20. package/dist/agent-core/runtime/compaction/retained-context.js +2 -9
  21. package/dist/agent-core/runtime/context/gc-runtime.d.ts +3 -1
  22. package/dist/agent-core/runtime/context/gc-runtime.js +17 -6
  23. package/dist/agent-core/runtime/context/gc-tokens.js +13 -0
  24. package/dist/agent-core/runtime/context/gc.d.ts +2 -1
  25. package/dist/agent-core/runtime/context/gc.js +75 -12
  26. package/dist/agent-core/runtime/context/projection.js +4 -0
  27. package/dist/agent-core/runtime/context/request-budget.d.ts +2 -4
  28. package/dist/agent-core/runtime/context/restore.d.ts +2 -0
  29. package/dist/agent-core/runtime/context/restore.js +19 -3
  30. package/dist/agent-core/runtime/contracts.d.ts +2 -3
  31. package/dist/agent-core/runtime/execution.d.ts +1 -1
  32. package/dist/agent-core/runtime/execution.js +10 -4
  33. package/dist/agent-core/runtime/resource-publication.d.ts +8 -0
  34. package/dist/agent-core/runtime/resource-publication.js +60 -0
  35. package/dist/agent-core/sdk/agent.js +16 -0
  36. package/dist/agent-core/sdk/model-runtime.js +2 -0
  37. package/dist/agent-core/sdk/resource-input.d.ts +31 -0
  38. package/dist/agent-core/sdk/resource-input.js +342 -0
  39. package/dist/agent-core/sdk/session.js +144 -39
  40. package/dist/agent-core/session/catalog.d.ts +4 -0
  41. package/dist/agent-core/session/catalog.js +4 -0
  42. package/dist/agent-core/session/context-gc-checkpoint.d.ts +6 -4
  43. package/dist/agent-core/session/context-gc-checkpoint.js +41 -16
  44. package/dist/agent-core/session/inline-media.d.ts +45 -0
  45. package/dist/agent-core/session/inline-media.js +163 -0
  46. package/dist/agent-core/session/store/contracts.d.ts +11 -0
  47. package/dist/agent-core/session/store/history.d.ts +1 -1
  48. package/dist/agent-core/session/store/history.js +26 -2
  49. package/dist/agent-core/session/store/images.d.ts +4 -6
  50. package/dist/agent-core/session/store/images.js +18 -111
  51. package/dist/agent-core/session/store/jsonl-store.d.ts +9 -0
  52. package/dist/agent-core/session/store/jsonl-store.js +100 -28
  53. package/dist/agent-core/session/store/resources.d.ts +26 -0
  54. package/dist/agent-core/session/store/resources.js +196 -0
  55. package/dist/agent-core/session/store/types.d.ts +7 -6
  56. package/dist/agent-core/session/transaction-recovery.js +1 -1
  57. package/dist/agent-core/tools/code-mode/cells.js +3 -4
  58. package/dist/agent-core/tools/code-mode/index.js +32 -8
  59. package/dist/agent-core/tools/code-mode/observations.d.ts +5 -16
  60. package/dist/agent-core/tools/code-mode/quickjs-engine.js +23 -26
  61. package/dist/agent-core/tools/contracts.d.ts +15 -5
  62. package/dist/agent-core/tools/execution-limits.d.ts +3 -1
  63. package/dist/agent-core/tools/execution-limits.js +3 -1
  64. package/dist/agent-core/tools/execution.d.ts +2 -1
  65. package/dist/agent-core/tools/execution.js +31 -4
  66. package/dist/agent-core/tools/input-diagnostics/source-preview.d.ts +10 -0
  67. package/dist/agent-core/tools/input-diagnostics/source-preview.js +64 -0
  68. package/dist/agent-core/tools/local/apply-patch-parser.js +2 -53
  69. package/dist/agent-core/tools/local/apply-patch.js +1 -1
  70. package/dist/agent-core/tools/local/image-processing.d.ts +24 -0
  71. package/dist/agent-core/tools/local/image-processing.js +135 -0
  72. package/dist/agent-core/tools/local/read.js +1 -1
  73. package/dist/agent-core/tools/local/view-image.d.ts +4 -0
  74. package/dist/agent-core/tools/local/view-image.js +154 -25
  75. package/dist/agent-core/tools/output-projection.d.ts +2 -4
  76. package/dist/agent-core/tools/output-projection.js +81 -10
  77. package/dist/agent-core/tools/runtime-context.d.ts +1 -0
  78. package/dist/agent-core/tools/runtime.js +20 -1
  79. package/dist/cli/main.js +2 -1
  80. package/dist/index.d.ts +1 -1
  81. package/package.json +2 -1
@@ -9,7 +9,7 @@ export declare class MarAgentError extends Error {
9
9
  cause?: unknown;
10
10
  });
11
11
  }
12
- export declare function describeMarAgentError(error: unknown, fallbackCode: string, fallbackMessage?: string): {
12
+ export declare function describeMarAgentError(error: unknown, fallbackCode: string, fallbackMessage?: string, includeCauses?: boolean): {
13
13
  code: string;
14
14
  message: string;
15
15
  };
@@ -13,7 +13,7 @@ export class MarAgentError extends Error {
13
13
  }
14
14
  }
15
15
  const MAX_ERROR_MESSAGE_CHARACTERS = 1_000;
16
- export function describeMarAgentError(error, fallbackCode, fallbackMessage = 'MAR Agent operation failed.') {
16
+ export function describeMarAgentError(error, fallbackCode, fallbackMessage = 'MAR Agent operation failed.', includeCauses = true) {
17
17
  const code = diagnosticCode(error) ?? fallbackCode;
18
18
  const messages = [];
19
19
  const seen = new Set();
@@ -22,8 +22,13 @@ export function describeMarAgentError(error, fallbackCode, fallbackMessage = 'MA
22
22
  seen.add(current);
23
23
  const currentCode = diagnosticCode(current);
24
24
  const message = diagnosticMessage(current, currentCode);
25
- if (message && !messages.includes(message))
26
- messages.push(message);
25
+ const summary = message && currentCode !== undefined && currentCode !== code
26
+ ? `${currentCode}: ${message}`
27
+ : message;
28
+ if (summary && !messages.includes(summary))
29
+ messages.push(summary);
30
+ if (!includeCauses)
31
+ break;
27
32
  current = diagnosticCause(current);
28
33
  }
29
34
  return {
@@ -40,23 +45,24 @@ function diagnosticCode(value) {
40
45
  return typeof code === 'string' && code.trim().length > 0 ? code.trim().slice(0, 80) : undefined;
41
46
  }
42
47
  function diagnosticMessage(value, code) {
43
- const message = value instanceof Error
44
- ? value.message
45
- : value !== null &&
46
- typeof value === 'object' &&
47
- 'message' in value &&
48
- typeof value.message === 'string'
48
+ const message = value instanceof MarAgentError
49
+ ? value.publicMessage
50
+ : value instanceof Error
49
51
  ? value.message
50
- : typeof value === 'string'
51
- ? value
52
- : undefined;
52
+ : value !== null &&
53
+ typeof value === 'object' &&
54
+ 'message' in value &&
55
+ typeof value.message === 'string'
56
+ ? value.message
57
+ : typeof value === 'string'
58
+ ? value
59
+ : undefined;
53
60
  const normalized = message?.trim();
54
61
  if (!normalized)
55
62
  return undefined;
56
- const withoutDuplicatedCode = code !== undefined && normalized.startsWith(`${code}: `)
63
+ return code !== undefined && normalized.startsWith(`${code}: `)
57
64
  ? normalized.slice(code.length + 2)
58
65
  : normalized;
59
- return code === undefined ? withoutDuplicatedCode : `${code}: ${withoutDuplicatedCode}`;
60
66
  }
61
67
  function diagnosticCause(value) {
62
68
  if (value === null || typeof value !== 'object' || !('cause' in value))
@@ -10,6 +10,12 @@ export interface CoreCompactDiagnostic {
10
10
  readonly elapsedMs: number;
11
11
  readonly reason?: 'INPUT_BUDGET_EXHAUSTED' | 'MODEL_INCOMPLETE' | 'MODEL_FAILED';
12
12
  readonly errorCode?: string;
13
+ readonly trigger?: 'manual' | 'automatic';
14
+ readonly causeCode?: string;
15
+ readonly errorReason?: string;
16
+ readonly httpStatus?: number;
17
+ readonly retryable?: boolean;
18
+ readonly transport?: 'HTTP' | 'WEBSOCKET';
13
19
  }
14
20
  export interface CoreCompactMessage {
15
21
  readonly role: 'user' | 'assistant' | 'tool' | 'tool_call';
@@ -35,6 +35,7 @@ export function compactExtensionDiagnostic(value) {
35
35
  value.length > 0 &&
36
36
  value.length <= limit &&
37
37
  !/[\r\n]/u.test(value);
38
+ const code = (value) => typeof value === 'string' && /^[A-Za-z][A-Za-z0-9_.-]{0,127}$/u.test(value);
38
39
  if (!label(input.modelId, 128) ||
39
40
  !label(input.reasoningEffort, 32) ||
40
41
  typeof input.state !== 'string' ||
@@ -61,8 +62,21 @@ export function compactExtensionDiagnostic(value) {
61
62
  ['INPUT_BUDGET_EXHAUSTED', 'MODEL_INCOMPLETE', 'MODEL_FAILED'].includes(input.reason)
62
63
  ? { reason: input.reason }
63
64
  : {}),
64
- ...(typeof input.errorCode === 'string' && /^[A-Z][A-Z0-9_]{0,127}$/u.test(input.errorCode)
65
- ? { errorCode: input.errorCode }
65
+ ...(code(input.errorCode) ? { errorCode: input.errorCode } : {}),
66
+ ...(input.trigger === 'manual' || input.trigger === 'automatic'
67
+ ? { trigger: input.trigger }
68
+ : {}),
69
+ ...(code(input.causeCode) ? { causeCode: input.causeCode } : {}),
70
+ ...(code(input.errorReason) ? { errorReason: input.errorReason } : {}),
71
+ ...(typeof input.httpStatus === 'number' &&
72
+ Number.isInteger(input.httpStatus) &&
73
+ input.httpStatus >= 100 &&
74
+ input.httpStatus <= 599
75
+ ? { httpStatus: input.httpStatus }
76
+ : {}),
77
+ ...(typeof input.retryable === 'boolean' ? { retryable: input.retryable } : {}),
78
+ ...(input.transport === 'HTTP' || input.transport === 'WEBSOCKET'
79
+ ? { transport: input.transport }
66
80
  : {})
67
81
  };
68
82
  }
@@ -13,10 +13,7 @@ export type CoreModelMessage = {
13
13
  readonly callId?: string;
14
14
  readonly name?: string;
15
15
  readonly arguments?: unknown;
16
- readonly images?: readonly {
17
- readonly mimeType: string;
18
- readonly dataBase64: string;
19
- }[];
16
+ readonly images?: readonly import('../model/image.js').ModelImage[];
20
17
  };
21
18
  export interface CoreModelRequest {
22
19
  readonly modelId: string;
@@ -26,10 +23,7 @@ export interface CoreModelRequest {
26
23
  readonly tools: readonly ClientToolDefinition[];
27
24
  readonly toolChoice?: 'auto' | 'none';
28
25
  readonly reasoningEffort?: MarAgentReasoningEffort;
29
- readonly images?: readonly {
30
- readonly mimeType: string;
31
- readonly dataBase64: string;
32
- }[];
26
+ readonly images?: readonly import('../model/image.js').ModelImage[];
33
27
  }
34
28
  export interface CoreRequestSnapshot {
35
29
  readonly id: string;
@@ -54,7 +48,9 @@ export declare class ExtensionRequestBridge {
54
48
  #private;
55
49
  readonly modelId: string;
56
50
  readonly original: ModelRequest;
51
+ private readonly committedPrefix;
52
+ rewroteCommittedInput: boolean;
57
53
  readonly view: CoreModelRequest;
58
- constructor(modelId: string, original: ModelRequest, sourceMessages?: readonly CoreModelMessage[]);
54
+ constructor(modelId: string, original: ModelRequest, sourceMessages?: readonly CoreModelMessage[], committedPrefix?: number);
59
55
  lower(view: CoreModelRequest): ModelRequest;
60
56
  }
@@ -59,11 +59,14 @@ function freezeSnapshot(value) {
59
59
  export class ExtensionRequestBridge {
60
60
  modelId;
61
61
  original;
62
+ committedPrefix;
62
63
  #messages = new Map();
64
+ rewroteCommittedInput = false;
63
65
  view;
64
- constructor(modelId, original, sourceMessages) {
66
+ constructor(modelId, original, sourceMessages, committedPrefix = 0) {
65
67
  this.modelId = modelId;
66
68
  this.original = original;
69
+ this.committedPrefix = committedPrefix;
67
70
  const messages = original.messages.map((original, index) => {
68
71
  const sourceRef = sourceMessages?.[index]?.sourceRef ?? randomUUID();
69
72
  const view = original.role === 'provider'
@@ -82,7 +85,7 @@ export class ExtensionRequestBridge {
82
85
  : {}),
83
86
  ...(original.images !== undefined ? { images: structuredClone(original.images) } : {})
84
87
  };
85
- this.#messages.set(sourceRef, { original, view: structuredClone(view) });
88
+ this.#messages.set(sourceRef, { original, view: structuredClone(view), index });
86
89
  return view;
87
90
  });
88
91
  this.view = {
@@ -113,7 +116,11 @@ export class ExtensionRequestBridge {
113
116
  Array.isArray(tool.inputSchema)))
114
117
  throw new MarAgentError('MAR_AGENT_EXTENSION_MODEL_REQUEST_INVALID', 'Model request view is invalid.');
115
118
  const seen = new Set();
116
- const messages = view.messages.map((message) => {
119
+ if (view.messages.length < this.committedPrefix ||
120
+ view.system !== this.original.system ||
121
+ !isDeepStrictEqual(view.systemBlocks, this.original.systemBlocks))
122
+ this.rewroteCommittedInput = true;
123
+ const messages = view.messages.map((message, index) => {
117
124
  if (!message || typeof message !== 'object')
118
125
  throw new MarAgentError('MAR_AGENT_EXTENSION_MODEL_REQUEST_INVALID', 'Message view is invalid.');
119
126
  const source = message.sourceRef ? this.#messages.get(message.sourceRef) : undefined;
@@ -122,8 +129,12 @@ export class ExtensionRequestBridge {
122
129
  throw new MarAgentError('MAR_AGENT_EXTENSION_MODEL_REQUEST_INVALID', 'Message source reference is invalid.');
123
130
  seen.add(message.sourceRef);
124
131
  }
132
+ if (index < this.committedPrefix && source?.index !== index)
133
+ this.rewroteCommittedInput = true;
125
134
  if (source && isDeepStrictEqual(message, source.view))
126
135
  return source.original;
136
+ if (index < this.committedPrefix)
137
+ this.rewroteCommittedInput = true;
127
138
  if (message.role === 'opaque' ||
128
139
  typeof message.content !== 'string' ||
129
140
  !['user', 'assistant', 'tool', 'tool_call'].includes(message.role))
@@ -1,4 +1,5 @@
1
1
  import { MarAgentError } from '../error.js';
2
+ import { isModelImageUrl } from '../model/image.js';
2
3
  export function captureCorePromptInput(input) {
3
4
  if (!input ||
4
5
  typeof input.text !== 'string' ||
@@ -14,7 +15,8 @@ export function captureCorePromptInput(input) {
14
15
  !Array.from(input.images).every((image) => image &&
15
16
  typeof image.name === 'string' &&
16
17
  typeof image.mimeType === 'string' &&
17
- typeof image.dataBase64 === 'string'))))
18
+ typeof image.dataBase64 === 'string' &&
19
+ (image.url === undefined || isModelImageUrl(image.url))))))
18
20
  throw new MarAgentError('MAR_AGENT_SESSION_INPUT_INVALID', 'Prompt content is invalid.');
19
21
  return structuredClone({
20
22
  text: input.text,
@@ -55,6 +55,14 @@ export interface HostSessionResourceSnapshot {
55
55
  export interface MarAgentHost {
56
56
  /** Independent model consumption facts, including child and auxiliary calls. */
57
57
  modelUsage?: import('../model/usage-observer.js').ModelUsageObserver | undefined;
58
+ publishModelResource?: (image: import('../session/store/resources.js').SessionResource, context: {
59
+ sessionId: string;
60
+ executionId: string;
61
+ homeDirectory: string;
62
+ }) => Promise<{
63
+ url: string;
64
+ urlExpiresAt: number;
65
+ } | undefined>;
58
66
  readonly extensionPorts?: CoreHostExtensionPorts;
59
67
  describe(): Promise<HostDescription>;
60
68
  executeTool(call: ToolCall, context: ToolExecutionContext): Promise<ToolExecutionResult>;
@@ -27,6 +27,7 @@ export declare class LocalAgentHost implements MarAgentHost {
27
27
  readonly extensionPorts: import('./contracts.js').CoreHostExtensionPorts;
28
28
  readonly events: MarAgentEvent[];
29
29
  readonly requestToolApproval: MarAgentHost['requestToolApproval'];
30
+ readonly publishModelResource?: NonNullable<MarAgentHost['publishModelResource']>;
30
31
  constructor(input: {
31
32
  mcp?: import('../extensions/mcp.js').CoreMcpBackend;
32
33
  operationTools?: CoreHostToolsBackend;
@@ -34,6 +35,7 @@ export declare class LocalAgentHost implements MarAgentHost {
34
35
  callMcpOperation?: (input: ToolCall, call: CoreOperationContext, expected: NonNullable<McpToolCallContext['expectedTool']>) => Promise<ToolExecutionResult>;
35
36
  network?: CoreNetworkBackend | false;
36
37
  modelUsage?: import('../model/usage-observer.js').ModelUsageObserver;
38
+ publishModelResource?: MarAgentHost['publishModelResource'];
37
39
  homeDirectory: string;
38
40
  workspace: string;
39
41
  mode?: 'normal' | 'node';
@@ -32,6 +32,7 @@ export class LocalAgentHost {
32
32
  #extensions;
33
33
  events = [];
34
34
  requestToolApproval;
35
+ publishModelResource;
35
36
  #mode;
36
37
  #environment;
37
38
  #sessionEnvironment;
@@ -41,6 +42,8 @@ export class LocalAgentHost {
41
42
  constructor(input) {
42
43
  this.modelUsage = input.modelUsage;
43
44
  this.requestToolApproval = input.approval;
45
+ if (input.publishModelResource !== undefined)
46
+ this.publishModelResource = input.publishModelResource;
44
47
  this.#home = resolve(input.homeDirectory);
45
48
  this.#workspace = resolve(input.workspace);
46
49
  this.#environment = input.environment ?? process.env;
@@ -1,9 +1,11 @@
1
1
  import { observeModelRequestUsage } from './usage-observer.js';
2
2
  import { jsonToolInput } from './tool-input.js';
3
3
  import { observationModelParts } from '../tools/code-mode/observations.js';
4
+ import { modelImageKey, modelImageUrl } from './image.js';
4
5
  import { stableToolSchema } from '../tools/definition-projection.js';
5
6
  import { randomUUID } from 'node:crypto';
6
7
  import { MarAgentError } from '../error.js';
8
+ import { assertInlineMediaBudget } from '../session/inline-media.js';
7
9
  import { resolveModelDefaultReasoningEffort } from './configuration.js';
8
10
  import { isRetryableUpstreamOverloadCode, number, parseSse, record, text, observeModelStreamEvent, modelStreamEventObservedAt } from './sse.js';
9
11
  import { fetchModelResponse, modelRetryMaxAttempts, isRetryableModelRequestError, isRetryableModelTransportError, modelRetryDelay, waitForModelRetry } from './http.js';
@@ -93,6 +95,7 @@ export class AnthropicMessagesAdapter {
93
95
  }
94
96
  }
95
97
  async *startAttempt(request, signal) {
98
+ assertInlineMediaBudget(request);
96
99
  const apiKey = this.configuration.apiKey;
97
100
  if (apiKey === undefined)
98
101
  throw new MarAgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Anthropic Messages requires a static API key.');
@@ -588,22 +591,14 @@ function anthropicMessages(messages, images, tools = [], modelId, automaticCache
588
591
  ? { type: 'text', text: part.text }
589
592
  : {
590
593
  type: 'image',
591
- source: {
592
- type: 'base64',
593
- media_type: part.image.mimeType,
594
- data: part.image.dataBase64
595
- }
594
+ source: anthropicImageSource(part.image)
596
595
  }) ??
597
596
  (message.textBlocks !== undefined
598
597
  ? [
599
598
  ...anthropicTextBlocks(message.content, message.textBlocks),
600
599
  ...(message.images ?? []).map((image) => ({
601
600
  type: 'image',
602
- source: {
603
- type: 'base64',
604
- media_type: image.mimeType,
605
- data: image.dataBase64
606
- }
601
+ source: anthropicImageSource(image)
607
602
  }))
608
603
  ]
609
604
  : message.images?.length
@@ -611,11 +606,7 @@ function anthropicMessages(messages, images, tools = [], modelId, automaticCache
611
606
  { type: 'text', text: message.content },
612
607
  ...message.images.map((image) => ({
613
608
  type: 'image',
614
- source: {
615
- type: 'base64',
616
- media_type: image.mimeType,
617
- data: image.dataBase64
618
- }
609
+ source: anthropicImageSource(image)
619
610
  }))
620
611
  ]
621
612
  : message.content)
@@ -646,11 +637,7 @@ function anthropicMessages(messages, images, tools = [], modelId, automaticCache
646
637
  ? [
647
638
  ...userImages.map((image) => ({
648
639
  type: 'image',
649
- source: {
650
- type: 'base64',
651
- media_type: image.mimeType,
652
- data: image.dataBase64
653
- }
640
+ source: anthropicImageSource(image)
654
641
  })),
655
642
  ...anthropicTextBlocks(message.content, message.textBlocks)
656
643
  ]
@@ -658,11 +645,7 @@ function anthropicMessages(messages, images, tools = [], modelId, automaticCache
658
645
  ? [
659
646
  ...userImages.map((image) => ({
660
647
  type: 'image',
661
- source: {
662
- type: 'base64',
663
- media_type: image.mimeType,
664
- data: image.dataBase64
665
- }
648
+ source: anthropicImageSource(image)
666
649
  })),
667
650
  { type: 'text', text: message.content }
668
651
  ]
@@ -690,13 +673,19 @@ function isRealUserMessage(message) {
690
673
  function uniqueModelImages(...groups) {
691
674
  const seen = new Set();
692
675
  return groups.flatMap((group) => (group ?? []).flatMap((image) => {
693
- const key = `${image.mimeType}\u0000${image.dataBase64}`;
676
+ const key = modelImageKey(image);
694
677
  if (seen.has(key))
695
678
  return [];
696
679
  seen.add(key);
697
680
  return [image];
698
681
  }));
699
682
  }
683
+ function anthropicImageSource(image) {
684
+ const url = modelImageUrl(image);
685
+ return url === image.url
686
+ ? { type: 'url', url }
687
+ : { type: 'base64', media_type: image.mimeType, data: image.dataBase64 };
688
+ }
700
689
  function isObject(value) {
701
690
  return value !== null && typeof value === 'object' && !Array.isArray(value);
702
691
  }
@@ -12,6 +12,7 @@ export declare function writeModelCatalog(home: string, catalog: CliModelCatalog
12
12
  export declare function serializeModel(model: CliModelConfiguration): {
13
13
  apiKey: string;
14
14
  conversationModel?: boolean;
15
+ useResourceUrl?: boolean;
15
16
  responsesConfigurationUpdates?: boolean;
16
17
  codexCredential?: boolean;
17
18
  responsesTransport?: import("./configuration.js").ResponsesTransport;
@@ -46,6 +47,7 @@ export declare function serializeModel(model: CliModelConfiguration): {
46
47
  type: "CODEX_AUTH_FILE";
47
48
  };
48
49
  conversationModel?: boolean;
50
+ useResourceUrl?: boolean;
49
51
  responsesConfigurationUpdates?: boolean;
50
52
  codexCredential?: boolean;
51
53
  responsesTransport?: import("./configuration.js").ResponsesTransport;
@@ -70,6 +70,7 @@ declare const rawModelSchema: z.ZodObject<{
70
70
  conversationModel: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
71
71
  titleGeneration: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
72
72
  codeMode: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
73
+ useResourceUrl: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
73
74
  fastMode: z.ZodOptional<z.ZodBoolean>;
74
75
  serviceTier: z.ZodOptional<z.ZodEnum<{
75
76
  default: "default";
@@ -100,8 +101,9 @@ declare const rawModelSchema: z.ZodObject<{
100
101
  }, z.core.$strict>>;
101
102
  enabled: z.ZodBoolean;
102
103
  }, z.core.$strict>;
103
- export interface MarAgentModelConfiguration extends Omit<z.infer<typeof rawModelSchema>, 'apiKey' | 'responsesPreviousResponseId' | 'responsesTransport' | 'conversationModel'> {
104
+ export interface MarAgentModelConfiguration extends Omit<z.infer<typeof rawModelSchema>, 'apiKey' | 'responsesPreviousResponseId' | 'responsesTransport' | 'conversationModel' | 'useResourceUrl'> {
104
105
  conversationModel?: boolean;
106
+ useResourceUrl?: boolean;
105
107
  apiKey?: SecretValue;
106
108
  credentialProvider?: ModelCredentialProvider;
107
109
  /** Whether this Responses endpoint accepts native configuration_update input items. */
@@ -50,6 +50,7 @@ const rawModelSchema = z
50
50
  conversationModel: z.boolean().optional().default(true),
51
51
  titleGeneration: z.boolean().optional().default(false),
52
52
  codeMode: z.boolean().optional().default(false),
53
+ useResourceUrl: z.boolean().optional().default(false),
53
54
  fastMode: z.boolean().optional(),
54
55
  serviceTier: z.enum(['auto', 'default', 'flex', 'priority', 'fast', 'ultrafast']).optional(),
55
56
  hostedWebSearch: z.boolean(),
@@ -1,4 +1,5 @@
1
1
  import type { ClientToolDefinition } from '../tools/contracts.js';
2
+ import type { ModelImage } from './image.js';
2
3
  import type { MarAgentModelConfiguration, MarAgentReasoningEffort, ModelCredentialAcquireReason } from './configuration.js';
3
4
  export type { ClientToolDefinition, ToolCaller } from '../tools/contracts.js';
4
5
  export interface ModelTextBlock {
@@ -41,10 +42,7 @@ export interface ModelMessage {
41
42
  provider?: 'OPENAI_RESPONSES' | 'ANTHROPIC_MESSAGES';
42
43
  providerModelId?: string;
43
44
  item?: Record<string, unknown>;
44
- images?: readonly {
45
- mimeType: string;
46
- dataBase64: string;
47
- }[];
45
+ images?: readonly ModelImage[];
48
46
  observations?: readonly import('../tools/code-mode/observations.js').CodeObservation[];
49
47
  /** Runtime-only location used by the GC evidence adapter, never a Provider call. */
50
48
  observationId?: string;
@@ -112,10 +110,7 @@ export interface ModelRequest {
112
110
  /** Stable request-level effort while native configuration updates select the current effort. */
113
111
  requestReasoningEffort?: MarAgentReasoningEffort;
114
112
  promptCacheKey?: string;
115
- images?: readonly {
116
- mimeType: string;
117
- dataBase64: string;
118
- }[];
113
+ images?: readonly ModelImage[];
119
114
  onAttemptDiagnostic?: (diagnostic: ModelAttemptDiagnostic) => Promise<void> | void;
120
115
  }
121
116
  export interface ModelUsage {
@@ -228,5 +223,7 @@ export interface ModelTurnSession {
228
223
  start(request: ModelRequest, signal: AbortSignal): AsyncIterable<ModelEvent>;
229
224
  /** Drops incremental response state after a local context replacement. */
230
225
  resetContinuation?(): void;
226
+ continuationInputCount?(): number;
227
+ commitContinuationInput?(messageCount: number): void;
231
228
  close(): Promise<void>;
232
229
  }
@@ -0,0 +1,17 @@
1
+ export interface ModelImage {
2
+ readonly resourceInputVersion?: 1;
3
+ readonly mimeType: string;
4
+ readonly dataBase64?: string;
5
+ readonly resourceId?: string;
6
+ readonly byteSize?: number;
7
+ /** Fixed published resource; image bytes are persisted separately. */
8
+ readonly url?: string;
9
+ readonly urlExpiresAt?: number;
10
+ }
11
+ export declare function modelImageUrl(image: ModelImage): string;
12
+ export declare function modelImageKey(image: ModelImage): string;
13
+ /** Only immutable URL references may enter durable model history. */
14
+ export declare function persistedModelImages(images: readonly ModelImage[] | undefined): ModelImage[];
15
+ /** Durable images contain a URL or resource reference, never inline image bytes. */
16
+ export declare function parseModelImages(value: unknown): ModelImage[] | undefined;
17
+ export declare function isModelImageUrl(value: unknown): value is string;
@@ -0,0 +1,53 @@
1
+ export function modelImageUrl(image) {
2
+ if (image.url !== undefined && isModelImageUrl(image.url))
3
+ return image.url;
4
+ if (typeof image.dataBase64 !== 'string' || image.dataBase64.length === 0)
5
+ throw new Error('Model image has no usable source.');
6
+ return `data:${image.mimeType};base64,${image.dataBase64}`;
7
+ }
8
+ export function modelImageKey(image) {
9
+ return `${image.mimeType}\u0000${modelImageUrl(image)}`;
10
+ }
11
+ /** Only immutable URL references may enter durable model history. */
12
+ export function persistedModelImages(images) {
13
+ return (images ?? [])
14
+ .filter((image) => isModelImageUrl(image.url) || image.resourceId !== undefined)
15
+ .map((image) => ({
16
+ resourceInputVersion: 1,
17
+ mimeType: image.mimeType,
18
+ ...(image.url === undefined ? {} : { url: image.url }),
19
+ ...(image.urlExpiresAt === undefined ? {} : { urlExpiresAt: image.urlExpiresAt }),
20
+ ...(image.resourceId === undefined ? {} : { resourceId: image.resourceId }),
21
+ ...(image.byteSize === undefined ? {} : { byteSize: image.byteSize })
22
+ }));
23
+ }
24
+ /** Durable images contain a URL or resource reference, never inline image bytes. */
25
+ export function parseModelImages(value) {
26
+ if (!Array.isArray(value) ||
27
+ !value.every((image) => image &&
28
+ image.resourceInputVersion === 1 &&
29
+ typeof image.mimeType === 'string' &&
30
+ (image.url === undefined || isModelImageUrl(image.url)) &&
31
+ (image.resourceId === undefined ||
32
+ (typeof image.resourceId === 'string' && /^[a-f0-9]{64}$/u.test(image.resourceId))) &&
33
+ (image.byteSize === undefined ||
34
+ (Number.isSafeInteger(image.byteSize) && image.byteSize > 0)) &&
35
+ (image.urlExpiresAt === undefined ||
36
+ (Number.isSafeInteger(image.urlExpiresAt) && image.urlExpiresAt > 0)) &&
37
+ (image.url !== undefined || image.resourceId !== undefined)))
38
+ return undefined;
39
+ return persistedModelImages(value);
40
+ }
41
+ export function isModelImageUrl(value) {
42
+ if (typeof value !== 'string' || value.length === 0 || value.length > 8192)
43
+ return false;
44
+ try {
45
+ const url = new URL(value);
46
+ return ((url.protocol === 'https:' || url.protocol === 'http:') &&
47
+ url.username === '' &&
48
+ url.password === '');
49
+ }
50
+ catch {
51
+ return false;
52
+ }
53
+ }
@@ -15,12 +15,16 @@ interface ResponsesSessionState {
15
15
  connectionId?: string;
16
16
  proxyType?: 'DIRECT' | 'SOCKS5';
17
17
  lastRequest?: ResponsesRequestBody;
18
+ lastMessageCount?: number;
19
+ lastInputItemCount?: number;
20
+ lastSystem?: string;
18
21
  lastResponse?: {
19
22
  readonly responseId: string;
20
23
  readonly outputItems: readonly Record<string, unknown>[];
21
24
  };
22
25
  }
23
26
  interface PreparedResponsesRequest {
27
+ readonly inputItemCount: number;
24
28
  readonly fullBody: ResponsesRequestBody;
25
29
  readonly body: ResponsesRequestBody;
26
30
  readonly continuation: boolean;
@@ -47,9 +51,10 @@ declare class OpenAiResponsesTurnSession implements ModelTurnSession {
47
51
  start(request: ModelRequest, signal: AbortSignal): AsyncIterable<ModelEvent>;
48
52
  close(): Promise<void>;
49
53
  resetContinuation(): void;
54
+ continuationInputCount(): number;
55
+ commitContinuationInput(messageCount: number): void;
50
56
  captureCompletedResponseId(responseId: string | undefined): void;
51
57
  prepareRequest(request: ModelRequest): PreparedResponsesRequest;
52
- fullRequestBody(): ResponsesRequestBody;
53
58
  currentTurnState(): string | undefined;
54
59
  beginAttempt(): void;
55
60
  captureWebSocketDiagnostic(diagnostic: ResponsesWebSocketDiagnostic): void;
@@ -68,5 +73,5 @@ declare class OpenAiResponsesTurnSession implements ModelTurnSession {
68
73
  private connectWebSocket;
69
74
  }
70
75
  export declare function isOpenAiResponsesRecoverableStreamError(error: unknown): error is MarAgentError;
71
- export declare function openAiInput(messages: ModelRequest['messages'], images: ModelRequest['images'] | undefined, modelId: string, requireEncryptedReasoning: boolean, configurationUpdates?: boolean, nativeTools?: boolean, tools?: ModelRequest['tools']): Record<string, unknown>[];
76
+ export declare function openAiInput(messages: ModelRequest['messages'], images: ModelRequest['images'] | undefined, modelId: string, requireEncryptedReasoning: boolean, configurationUpdates?: boolean, nativeTools?: boolean, tools?: ModelRequest['tools'], previousOutputItems?: readonly Record<string, unknown>[]): Record<string, unknown>[];
72
77
  export {};