@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
@@ -8,4 +8,8 @@ export declare class ViewImageTool {
8
8
  constructor(paths: WorkspacePathResolver);
9
9
  execute(arguments_: unknown, signal?: AbortSignal): Promise<ToolExecutionResult>;
10
10
  }
11
+ /** Resolve Session-owned bytes without using the resource's public URL or original path. */
12
+ export declare function viewResourceImage(arguments_: unknown, readResource: (resourceId: string) => Promise<{
13
+ dataBase64: string;
14
+ } | undefined>, signal?: AbortSignal): Promise<ToolExecutionResult>;
11
15
  export declare function detectImageMime(data: Buffer): ViewImageResult['mimeType'];
@@ -2,17 +2,39 @@ import { createHash } from 'node:crypto';
2
2
  import { open } from 'node:fs/promises';
3
3
  import { MarAgentError } from '../../error.js';
4
4
  import { TOOL_EXECUTION_LIMITS } from '../execution-limits.js';
5
+ import { processImage, readImageMetadata } from './image-processing.js';
5
6
  export const viewImageToolDefinition = {
6
7
  name: 'view_image',
7
8
  allowedCallers: ['direct', 'programmatic'],
8
9
  parallelSafety: 'safe',
9
- description: `Read one known local PNG, JPEG, or WebP image and provide its actual pixels to the vision-capable model. Relative paths use the workspace; absolute paths are allowed. The file must be a regular file no larger than ${TOOL_EXECUTION_LIMITS.viewImageMaxBytes} bytes. MIME is detected from file content, not its extension. Use this instead of installing OCR or converting the image through exec.`,
10
+ description: 'View a PNG, JPEG, or WebP image by path or Session resourceId. Relative paths use the workspace; absolute paths are allowed. Use this tool instead of converting images through exec.',
10
11
  inputSchema: {
11
12
  type: 'object',
12
13
  properties: {
13
- path: { type: 'string', description: 'Relative workspace path or absolute image path.' }
14
+ path: { type: 'string', description: 'Relative workspace path or absolute image path.' },
15
+ resourceId: { type: 'string', description: 'Session image resource ID, instead of path.' },
16
+ region: {
17
+ type: 'object',
18
+ description: 'For close inspection of a specific area; coordinates use oriented source pixels.',
19
+ properties: {
20
+ x: { type: 'integer', minimum: 0 },
21
+ y: { type: 'integer', minimum: 0 },
22
+ width: { type: 'integer', minimum: 1 },
23
+ height: { type: 'integer', minimum: 1 }
24
+ },
25
+ required: ['x', 'y', 'width', 'height'],
26
+ additionalProperties: false
27
+ },
28
+ resize: {
29
+ type: 'object',
30
+ description: 'For a smaller overview; fit the image or cropped region within these dimensions without enlargement.',
31
+ properties: {
32
+ maxWidth: { type: 'integer', minimum: 1 },
33
+ maxHeight: { type: 'integer', minimum: 1 }
34
+ },
35
+ additionalProperties: false
36
+ }
14
37
  },
15
- required: ['path'],
16
38
  additionalProperties: false
17
39
  }
18
40
  };
@@ -23,6 +45,8 @@ export class ViewImageTool {
23
45
  }
24
46
  async execute(arguments_, signal) {
25
47
  const input = parseViewImageInput(arguments_);
48
+ if (input.path === undefined)
49
+ return invalidInput();
26
50
  signal?.throwIfAborted();
27
51
  const path = await this.paths.resolve(input.path);
28
52
  const handle = await open(path, 'r');
@@ -30,13 +54,22 @@ export class ViewImageTool {
30
54
  const stat = await handle.stat({ bigint: true });
31
55
  if (!stat.isFile())
32
56
  throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Path is not a regular file.');
33
- if (stat.size > BigInt(TOOL_EXECUTION_LIMITS.viewImageMaxBytes))
34
- throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', `Image exceeds the ${TOOL_EXECUTION_LIMITS.viewImageMaxBytes}-byte limit.`);
57
+ if (stat.size > BigInt(TOOL_EXECUTION_LIMITS.viewImageMaxSourceBytes))
58
+ throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', `Image exceeds the ${TOOL_EXECUTION_LIMITS.viewImageMaxSourceBytes}-byte source limit. Use an external image tool to reduce it first.`);
59
+ const hasTransform = input.region !== undefined || input.resize !== undefined;
60
+ if (!hasTransform && stat.size > BigInt(TOOL_EXECUTION_LIMITS.viewImageMaxBytes))
61
+ throw imageOutputLimit('Image exceeds 3 MiB. Use resize or region.');
35
62
  signal?.throwIfAborted();
36
- const data = await handle.readFile();
63
+ const data = Buffer.allocUnsafe(Number(stat.size));
64
+ let offset = 0;
65
+ while (offset < data.byteLength) {
66
+ signal?.throwIfAborted();
67
+ const { bytesRead } = await handle.read(data, offset, data.byteLength - offset, offset);
68
+ if (bytesRead === 0)
69
+ incompleteImage();
70
+ offset += bytesRead;
71
+ }
37
72
  signal?.throwIfAborted();
38
- if (data.byteLength > TOOL_EXECUTION_LIMITS.viewImageMaxBytes)
39
- throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', `Image exceeds the ${TOOL_EXECUTION_LIMITS.viewImageMaxBytes}-byte limit.`);
40
73
  const after = await handle.stat({ bigint: true });
41
74
  signal?.throwIfAborted();
42
75
  if (stat.size !== after.size ||
@@ -44,34 +77,130 @@ export class ViewImageTool {
44
77
  stat.mtimeNs !== after.mtimeNs ||
45
78
  stat.ctimeNs !== after.ctimeNs)
46
79
  return incompleteImage();
47
- const mimeType = detectImageMime(data);
48
- validateImageContainer(data, mimeType);
49
- const metadata = {
50
- path: input.path,
51
- mimeType,
52
- bytes: data.byteLength,
53
- sha256: createHash('sha256').update(data).digest('hex')
54
- };
55
- return {
56
- content: `Viewed image ${input.path} (${mimeType}, ${data.byteLength} bytes).`,
57
- data: metadata,
58
- images: [{ mimeType, dataBase64: data.toString('base64') }]
59
- };
80
+ return await renderViewImage(data, input, signal);
60
81
  }
61
82
  finally {
62
83
  await handle.close();
63
84
  }
64
85
  }
65
86
  }
87
+ /** Resolve Session-owned bytes without using the resource's public URL or original path. */
88
+ export async function viewResourceImage(arguments_, readResource, signal) {
89
+ const input = parseViewImageInput(arguments_);
90
+ if (input.resourceId === undefined)
91
+ return invalidInput();
92
+ signal?.throwIfAborted();
93
+ const resource = await readResource(input.resourceId);
94
+ signal?.throwIfAborted();
95
+ if (!resource)
96
+ throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Image resource was not found in this Session.');
97
+ const data = Buffer.from(resource.dataBase64, 'base64');
98
+ if (data.length > TOOL_EXECUTION_LIMITS.viewImageMaxSourceBytes)
99
+ throw imageOutputLimit('Image exceeds the source limit.');
100
+ if (!input.region && !input.resize && data.length > TOOL_EXECUTION_LIMITS.viewImageMaxBytes)
101
+ throw imageOutputLimit('Image exceeds 3 MiB. Use resize or region.');
102
+ return renderViewImage(data, input, signal);
103
+ }
104
+ async function renderViewImage(data, input, signal) {
105
+ const mimeType = detectImageMime(data);
106
+ validateImageContainer(data, mimeType);
107
+ const sourceMetadata = await readImageMetadata(data, mimeType, signal);
108
+ if (input.region &&
109
+ (input.region.x > sourceMetadata.width ||
110
+ input.region.y > sourceMetadata.height ||
111
+ input.region.width > sourceMetadata.width - input.region.x ||
112
+ input.region.height > sourceMetadata.height - input.region.y))
113
+ throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Image region is outside the oriented source dimensions.');
114
+ const visual = input.region !== undefined || input.resize !== undefined
115
+ ? await processImage(data, sourceMetadata, input, signal)
116
+ : {
117
+ bytes: data,
118
+ width: sourceMetadata.width,
119
+ height: sourceMetadata.height,
120
+ mimeType
121
+ };
122
+ signal?.throwIfAborted();
123
+ const resultMetadata = {
124
+ ...(input.path ? { path: input.path } : { resourceId: input.resourceId }),
125
+ mimeType: visual.mimeType,
126
+ bytes: visual.bytes.byteLength,
127
+ width: visual.width,
128
+ height: visual.height,
129
+ ...('sourceWidth' in visual && visual.sourceWidth !== undefined
130
+ ? { sourceWidth: visual.sourceWidth, sourceHeight: visual.sourceHeight }
131
+ : {}),
132
+ ...('region' in visual && visual.region ? { region: visual.region } : {}),
133
+ sha256: createHash('sha256').update(visual.bytes).digest('hex')
134
+ };
135
+ return {
136
+ content: describeImageResult(resultMetadata),
137
+ data: resultMetadata,
138
+ images: [{ mimeType: visual.mimeType, dataBase64: visual.bytes.toString('base64') }]
139
+ };
140
+ }
66
141
  function parseViewImageInput(value) {
67
142
  if (!value || typeof value !== 'object')
68
143
  return invalidInput();
69
144
  const input = value;
70
- if (Object.keys(input).some((key) => key !== 'path') ||
71
- typeof input.path !== 'string' ||
72
- input.path.length === 0)
145
+ if (Object.keys(input).some((key) => !['path', 'resourceId', 'region', 'resize'].includes(key)) ||
146
+ (input.path == null) === (input.resourceId == null) ||
147
+ (input.path != null && (typeof input.path !== 'string' || input.path.length === 0)) ||
148
+ (input.resourceId != null &&
149
+ (typeof input.resourceId !== 'string' || input.resourceId.length === 0)))
150
+ return invalidInput();
151
+ return {
152
+ ...(typeof input.path === 'string'
153
+ ? { path: input.path }
154
+ : { resourceId: input.resourceId }),
155
+ ...(input.region == null ? {} : { region: parseRegion(input.region) }),
156
+ ...(input.resize == null ? {} : { resize: parseResize(input.resize) })
157
+ };
158
+ }
159
+ function parseRegion(value) {
160
+ if (!isRecord(value) ||
161
+ Object.keys(value).some((key) => !['x', 'y', 'width', 'height'].includes(key)) ||
162
+ !Number.isSafeInteger(value.x) ||
163
+ value.x < 0 ||
164
+ !Number.isSafeInteger(value.y) ||
165
+ value.y < 0 ||
166
+ !isPositiveSafeInteger(value.width) ||
167
+ !isPositiveSafeInteger(value.height))
168
+ return invalidInput();
169
+ return {
170
+ x: value.x,
171
+ y: value.y,
172
+ width: value.width,
173
+ height: value.height
174
+ };
175
+ }
176
+ function parseResize(value) {
177
+ if (!isRecord(value) ||
178
+ (value.maxWidth == null && value.maxHeight == null) ||
179
+ Object.keys(value).some((key) => key !== 'maxWidth' && key !== 'maxHeight') ||
180
+ (value.maxWidth != null && !isPositiveSafeInteger(value.maxWidth)) ||
181
+ (value.maxHeight != null && !isPositiveSafeInteger(value.maxHeight)))
73
182
  return invalidInput();
74
- return { path: input.path };
183
+ return {
184
+ ...(value.maxWidth == null ? {} : { maxWidth: value.maxWidth }),
185
+ ...(value.maxHeight == null ? {} : { maxHeight: value.maxHeight })
186
+ };
187
+ }
188
+ function isRecord(value) {
189
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
190
+ }
191
+ function isPositiveSafeInteger(value) {
192
+ return Number.isSafeInteger(value) && value > 0;
193
+ }
194
+ function describeImageResult(result) {
195
+ const details = [`${result.width}×${result.height} px`, result.mimeType, `${result.bytes} bytes`];
196
+ if (result.sourceWidth !== undefined && result.sourceHeight !== undefined)
197
+ details.push(`source ${result.sourceWidth}×${result.sourceHeight} px`);
198
+ if (result.region)
199
+ details.push(`region ${result.region.x},${result.region.y} ${result.region.width}×${result.region.height} px`);
200
+ return `Viewed image ${result.path ?? result.resourceId} (${details.join(', ')}).`;
201
+ }
202
+ function imageOutputLimit(message) {
203
+ return new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', message);
75
204
  }
76
205
  export function detectImageMime(data) {
77
206
  if (data.length >= 8 &&
@@ -3,10 +3,8 @@ import type { ApplyPatchResult, ApplyPatchPartialResult, CodeCellEventData, Exec
3
3
  import type { ToolRuntimeImage } from './runtime-context.js';
4
4
  import type { SleepResult } from './agent/sleep.js';
5
5
  import { type PublicToolMetadata } from './public-metadata.js';
6
- export declare function currentExecutionImages(modelInputImages: readonly {
7
- readonly mimeType: string;
8
- readonly dataBase64: string;
9
- }[] | undefined, toolImages: readonly ToolRuntimeImage[]): ToolRuntimeImage[];
6
+ import type { ModelImage } from '../model/image.js';
7
+ export declare function currentExecutionImages(modelInputImages: readonly ModelImage[] | undefined, toolImages: readonly ToolRuntimeImage[]): ToolRuntimeImage[];
10
8
  export declare function boundedModelToolOutput(toolName: string, value: string, data: unknown): {
11
9
  content: string;
12
10
  truncated: boolean;
@@ -6,7 +6,9 @@ import { TOOL_EXECUTION_LIMITS } from './execution-limits.js';
6
6
  import { publicToolMetadata } from './public-metadata.js';
7
7
  export function currentExecutionImages(modelInputImages, toolImages) {
8
8
  return [
9
- ...(modelInputImages ?? []).map((image) => ({
9
+ ...(modelInputImages ?? [])
10
+ .filter((image) => image.dataBase64 !== undefined)
11
+ .map((image) => ({
10
12
  mimeType: image.mimeType,
11
13
  data: Buffer.from(image.dataBase64, 'base64')
12
14
  })),
@@ -148,15 +150,8 @@ export function structuredToolEventData(toolName, value) {
148
150
  }))
149
151
  };
150
152
  }
151
- if (toolName === 'view_image' &&
152
- typeof value.path === 'string' &&
153
- (value.mimeType === 'image/png' ||
154
- value.mimeType === 'image/jpeg' ||
155
- value.mimeType === 'image/webp') &&
156
- isNonnegativeInteger(value.bytes) &&
157
- typeof value.sha256 === 'string' &&
158
- /^[a-f0-9]{64}$/u.test(value.sha256))
159
- return value;
153
+ if (toolName === 'view_image')
154
+ return parseViewImageResult(value);
160
155
  if ((toolName === 'exec' || toolName === 'exec_wait') &&
161
156
  (value.status === 'running' || value.status === 'completed' || value.status === 'cancelled') &&
162
157
  typeof value.stdout === 'string' &&
@@ -175,6 +170,82 @@ export function structuredToolEventData(toolName, value) {
175
170
  return parseApplyPatchResult(value);
176
171
  return undefined;
177
172
  }
173
+ function parseViewImageResult(value) {
174
+ if (!((typeof value.path === 'string' && value.path.length > 0 && value.resourceId === undefined) ||
175
+ (typeof value.resourceId === 'string' &&
176
+ value.resourceId.length > 0 &&
177
+ value.path === undefined)) ||
178
+ (value.mimeType !== 'image/png' &&
179
+ value.mimeType !== 'image/jpeg' &&
180
+ value.mimeType !== 'image/webp') ||
181
+ !isPositiveSafeInteger(value.bytes) ||
182
+ value.bytes > TOOL_EXECUTION_LIMITS.viewImageMaxBytes ||
183
+ !isPositiveSafeInteger(value.width) ||
184
+ !isPositiveSafeInteger(value.height) ||
185
+ !withinImagePixelLimit(value.width, value.height) ||
186
+ typeof value.sha256 !== 'string' ||
187
+ !/^[a-f0-9]{64}$/u.test(value.sha256))
188
+ return undefined;
189
+ const hasSourceWidth = Object.hasOwn(value, 'sourceWidth');
190
+ const hasSourceHeight = Object.hasOwn(value, 'sourceHeight');
191
+ if (hasSourceWidth !== hasSourceHeight)
192
+ return undefined;
193
+ if (hasSourceWidth &&
194
+ (!isPositiveSafeInteger(value.sourceWidth) ||
195
+ !isPositiveSafeInteger(value.sourceHeight) ||
196
+ !withinImagePixelLimit(value.sourceWidth, value.sourceHeight) ||
197
+ value.width > value.sourceWidth ||
198
+ value.height > value.sourceHeight))
199
+ return undefined;
200
+ let region;
201
+ if (Object.hasOwn(value, 'region')) {
202
+ if (!isRecord(value.region))
203
+ return undefined;
204
+ const candidate = value.region;
205
+ if (Object.keys(candidate).some((key) => !['x', 'y', 'width', 'height'].includes(key)) ||
206
+ !isNonnegativeSafeInteger(candidate.x) ||
207
+ !isNonnegativeSafeInteger(candidate.y) ||
208
+ !isPositiveSafeInteger(candidate.width) ||
209
+ !isPositiveSafeInteger(candidate.height) ||
210
+ !hasSourceWidth ||
211
+ candidate.x > value.sourceWidth ||
212
+ candidate.y > value.sourceHeight ||
213
+ candidate.width > value.sourceWidth - candidate.x ||
214
+ candidate.height > value.sourceHeight - candidate.y ||
215
+ value.width > candidate.width ||
216
+ value.height > candidate.height)
217
+ return undefined;
218
+ region = {
219
+ x: candidate.x,
220
+ y: candidate.y,
221
+ width: candidate.width,
222
+ height: candidate.height
223
+ };
224
+ }
225
+ return {
226
+ ...(typeof value.path === 'string'
227
+ ? { path: value.path }
228
+ : { resourceId: value.resourceId }),
229
+ mimeType: value.mimeType,
230
+ bytes: value.bytes,
231
+ width: value.width,
232
+ height: value.height,
233
+ ...(hasSourceWidth
234
+ ? { sourceWidth: value.sourceWidth, sourceHeight: value.sourceHeight }
235
+ : {}),
236
+ ...(region ? { region } : {}),
237
+ sha256: value.sha256
238
+ };
239
+ }
240
+ function withinImagePixelLimit(width, height) {
241
+ return width <= Math.floor(TOOL_EXECUTION_LIMITS.viewImageMaxPixels / height);
242
+ }
243
+ function isPositiveSafeInteger(value) {
244
+ return Number.isSafeInteger(value) && value > 0;
245
+ }
246
+ function isNonnegativeSafeInteger(value) {
247
+ return Number.isSafeInteger(value) && value >= 0;
248
+ }
178
249
  /** Partial patch facts are allowlisted; arbitrary error details never become public event data. */
179
250
  export function structuredToolFailureData(toolName, error) {
180
251
  return toolName === 'apply_patch' &&
@@ -44,6 +44,7 @@ export interface ToolRuntimeImage {
44
44
  }
45
45
  export interface ToolRuntimeContext {
46
46
  host: MarAgentHost;
47
+ imageStore?: import('../session/store/contracts.js').SessionStore;
47
48
  todo: TodoStore;
48
49
  requestSmartCompact?: () => void;
49
50
  subagents?: SubagentController;
@@ -4,6 +4,7 @@ import { AGENT_TOOL_HANDLERS, BUILTIN_TOOL_DEFINITIONS } from './registry.js';
4
4
  import { normalizeToolInput } from './input.js';
5
5
  import { validateToolResult } from './output-projection.js';
6
6
  import { withToolResultExtensions } from './result-extensions.js';
7
+ import { viewResourceImage } from './local/view-image.js';
7
8
  export async function executeRegisteredTool(name, arguments_, callId, context, caller = 'direct') {
8
9
  return withToolResultExtensions(context.writeToolResultResource, async () => {
9
10
  if (context.invokeTool)
@@ -18,6 +19,17 @@ export async function executeCapturedTool(kind, call, context) {
18
19
  : undefined;
19
20
  if (definition)
20
21
  call = { ...call, arguments: normalizeToolInput(call.arguments, definition.inputSchema) };
22
+ if (kind !== 'mcp' &&
23
+ call.name === 'view_image' &&
24
+ call.arguments !== null &&
25
+ typeof call.arguments === 'object' &&
26
+ 'resourceId' in call.arguments &&
27
+ call.arguments.resourceId != null) {
28
+ const store = context.imageStore;
29
+ if (!store)
30
+ throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Session image resources are unavailable.');
31
+ return viewResourceImage(call.arguments, (resourceId) => store.readResource(context.sessionId, resourceId), context.signal);
32
+ }
21
33
  if (kind === 'builtin') {
22
34
  const handler = AGENT_TOOL_HANDLERS.get(call.name);
23
35
  if (handler)
@@ -40,7 +52,14 @@ export async function executeCapturedTool(kind, call, context) {
40
52
  sessionId: context.sessionId,
41
53
  executionId: context.executionId,
42
54
  ...(context.modelId === undefined ? {} : { modelId: context.modelId }),
43
- ...(context.recentImages === undefined ? {} : { recentImages: context.recentImages }),
55
+ ...(context.recentImages === undefined
56
+ ? {}
57
+ : {
58
+ recentImages: context.recentImages.map((image) => ({
59
+ ...image,
60
+ data: Buffer.from(image.data)
61
+ }))
62
+ }),
44
63
  ...(context.codeMode === undefined ? {} : { codeMode: context.codeMode })
45
64
  });
46
65
  }
package/dist/cli/main.js CHANGED
@@ -155,6 +155,7 @@ async function modelsCommand(home, arguments_, codexAuthFile) {
155
155
  .map((effort) => parseReasoningEffort(effort, '--reasoning-efforts'));
156
156
  const defaultReasoningEffortOption = option('--default-reasoning-effort');
157
157
  const model = {
158
+ useResourceUrl: existing?.useResourceUrl ?? false,
158
159
  id,
159
160
  name: required(option('--name', existing?.name), '--name'),
160
161
  protocol,
@@ -472,6 +473,6 @@ function parseExecutionInvocation(input) {
472
473
  }
473
474
  main().catch((error) => {
474
475
  const diagnostic = describeMarAgentError(error, 'MAR_AGENT_CLI_FAILED', 'CLI command failed.');
475
- process.stderr.write(`${diagnostic.message}\n`);
476
+ process.stderr.write(`${diagnostic.code}: ${diagnostic.message}\n`);
476
477
  process.exitCode = cliExitCode(diagnostic.code);
477
478
  });
package/dist/index.d.ts CHANGED
@@ -41,7 +41,7 @@ export type { CoreProcessesApi, CoreProcessesBackend, CoreProcessInput, CoreProc
41
41
  export type { CreateMarAgentOptions, CreateSessionInput, ExecutionHandle, CompactInput, SteerInput, SteerResult, MarAgent, MarAgentSession, SessionTitleUpdateInput } from './agent-core/sdk/types.js';
42
42
  export { openMarAgentSessionCatalog, type MarAgentContextUsage, type MarAgentHistoryEntry, type MarAgentHistoryPage, type MarAgentSessionCatalog, type MarAgentSessionDeleteResult, type MarAgentSessionImage, type MarAgentSessionPage, type MarAgentSessionSummary } from './agent-core/session/catalog.js';
43
43
  export type { SessionListInput, SessionSource } from './agent-core/session/types.js';
44
- export type { SessionStore, SessionStoreMaintenance, SessionStoreSession, SessionRecordInput, SessionStoreCompactInput, SessionRecord, SessionExecutionState, CompactHistoryMessage, CompactUserInput, SessionInputImage, SessionInputImageMetadata, SessionInputImageData, RestoredSessionInputImage, CodeModeStateEntry, TodoSnapshot, TodoItem, CodeToolCallRecord, CodeObservation, ModelMessage, ModelUsage, ModelInputMetadata, ModelTextBlock, ModelContextualBlock, EnvironmentContextState, ContextGcCheckpointDraft, ContextGcBase, ContextGcPlatform, ContextGcEconomicsPolicy, ContextGcMetrics, ContextGcReplacement, ContextGcTarget, ContextGcReadItemReplacement, ContextGcWebToolName, ContextGcSubagentToolName, AvailableToolResultResource } from './agent-core/session/store/contracts.js';
44
+ export type { SessionStore, SessionResource, SessionStoreMaintenance, SessionStoreSession, SessionRecordInput, SessionStoreCompactInput, SessionRecord, SessionExecutionState, CompactHistoryMessage, CompactUserInput, SessionInputImage, SessionInputImageMetadata, SessionInputImageData, RestoredSessionInputImage, CodeModeStateEntry, TodoSnapshot, TodoItem, CodeToolCallRecord, CodeObservation, ModelMessage, ModelUsage, ModelInputMetadata, ModelTextBlock, ModelContextualBlock, EnvironmentContextState, ContextGcCheckpointDraft, ContextGcBase, ContextGcPlatform, ContextGcEconomicsPolicy, ContextGcMetrics, ContextGcReplacement, ContextGcTarget, ContextGcReadItemReplacement, ContextGcWebToolName, ContextGcSubagentToolName, AvailableToolResultResource } from './agent-core/session/store/contracts.js';
45
45
  export type { OpenMarAgentSessionCatalogInput } from './agent-core/session/catalog.js';
46
46
  export type { ApplyPatchFileResult, ApplyPatchResult, ApplyPatchPartialResult, ClientToolDefinition, MarAgentToolArtifact, MarAgentToolImageArtifact, McpCatalogTool, McpToolCallContext, McpToolCatalog, McpToolCatalogContext, ToolCall, ToolCaller, ToolExecutionContext, ToolExecutionResult } from './agent-core/tools/contracts.js';
47
47
  export { MCP_DEFINITION_LIMITS, assertMcpToolCatalog, assertMcpToolDefinition } from './agent-core/tools/mcp/catalog.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/agent",
3
- "version": "0.11.20",
3
+ "version": "0.11.22",
4
4
  "description": "Embeddable MAR coding agent SDK and CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -36,6 +36,7 @@
36
36
  "dependencies": {
37
37
  "@jitl/quickjs-wasmfile-release-sync": "0.32.0",
38
38
  "quickjs-emscripten-core": "0.32.0",
39
+ "sharp": "0.35.5",
39
40
  "undici": "7.29.0",
40
41
  "ws": "8.21.3",
41
42
  "zod": "4.4.3"