@myagentroam/agent 0.9.155 → 0.9.157

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.
@@ -160,13 +160,16 @@ export class AnthropicMessagesAdapter {
160
160
  delta: text(block.text) ?? ''
161
161
  };
162
162
  else if (blockType === 'server_tool_use') {
163
- const kind = text(block.name) === 'web_fetch' ? 'WEB_FETCH' : 'WEB_SEARCH';
163
+ const toolName = text(block.name) ?? 'unknown';
164
+ const kind = toolName === 'web_fetch' ? 'WEB_FETCH' : 'WEB_SEARCH';
164
165
  const summary = anthropicHostedInputSummary(record(block.input));
165
- hostedTools.set(id, { kind, summary });
166
+ hostedTools.set(id, { kind, toolName, summary });
166
167
  yield {
167
168
  type: 'hosted_tool',
168
169
  itemId: id,
169
170
  kind,
171
+ toolName,
172
+ ...(Object.keys(summary).length ? { input: summary } : {}),
170
173
  status: 'RUNNING',
171
174
  summary
172
175
  };
@@ -188,6 +191,19 @@ export class AnthropicMessagesAdapter {
188
191
  type: 'hosted_tool',
189
192
  itemId: toolId,
190
193
  kind: hosted.kind,
194
+ toolName: hosted.toolName,
195
+ ...(Object.keys(anthropicHostedInputSummary(hosted.summary)).length
196
+ ? { input: anthropicHostedInputSummary(hosted.summary) }
197
+ : {}),
198
+ ...(sources.length
199
+ ? {
200
+ output: {
201
+ sources,
202
+ ...(summary.sourcesTruncated ? { sourcesTruncated: true } : {})
203
+ }
204
+ }
205
+ : {}),
206
+ ...(summary.sourcesTruncated ? { truncated: true } : {}),
191
207
  status: anthropicHostedResultFailed(result) ? 'FAILED' : 'COMPLETED',
192
208
  summary
193
209
  };
@@ -267,6 +283,8 @@ export class AnthropicMessagesAdapter {
267
283
  type: 'hosted_tool',
268
284
  itemId: block.id,
269
285
  kind: hosted.kind,
286
+ toolName: hosted.toolName,
287
+ input: anthropicHostedInputSummary(record(input)),
270
288
  status: 'RUNNING',
271
289
  summary
272
290
  };
@@ -118,6 +118,10 @@ export type ModelEvent = {
118
118
  itemId: string;
119
119
  kind: 'WEB_SEARCH' | 'WEB_FETCH';
120
120
  status: 'RUNNING' | 'COMPLETED' | 'FAILED';
121
+ toolName?: string;
122
+ input?: Record<string, unknown>;
123
+ output?: unknown;
124
+ truncated?: boolean;
121
125
  summary: {
122
126
  query?: string | undefined;
123
127
  url?: string | undefined;
@@ -475,11 +475,25 @@ export class OpenAiResponsesAdapter {
475
475
  ? 'WEB_FETCH'
476
476
  : (previous?.kind ?? 'WEB_SEARCH');
477
477
  const summary = { ...previous?.summary, ...hostedWebActionSummary(action) };
478
- hostedWebCalls.set(itemId, { kind, summary });
478
+ const projected = hostedWebActionInput(action);
479
+ const input = { ...previous?.input, ...projected.input };
480
+ const truncated = previous?.truncated === true || projected.truncated;
481
+ hostedWebCalls.set(itemId, { kind, summary, input, truncated });
482
+ const output = {
483
+ ...(summary.title === undefined ? {} : { title: summary.title }),
484
+ ...(summary.sources === undefined ? {} : { sources: summary.sources }),
485
+ ...(summary.sourcesTruncated === undefined
486
+ ? {}
487
+ : { sourcesTruncated: summary.sourcesTruncated })
488
+ };
479
489
  yield {
480
490
  type: 'hosted_tool',
481
491
  itemId,
482
492
  kind,
493
+ toolName: 'web_search',
494
+ ...(Object.keys(input).length ? { input } : {}),
495
+ ...(Object.keys(output).length ? { output } : {}),
496
+ ...(truncated || summary.sourcesTruncated === true ? { truncated: true } : {}),
483
497
  status: type.endsWith('.failed')
484
498
  ? 'FAILED'
485
499
  : type.endsWith('.completed') || type === 'response.output_item.done'
@@ -1510,6 +1524,29 @@ const RESPONSE_ITEM_TYPES = new Set([
1510
1524
  ]);
1511
1525
  // A freeform patch item can contain the complete 4 MiB patch plus its JSON envelope.
1512
1526
  const MAX_RESPONSE_ITEM_BYTES = 5 * 1024 * 1024;
1527
+ function hostedWebActionInput(action) {
1528
+ const input = {};
1529
+ let truncated = false;
1530
+ for (const [key, limit] of [
1531
+ ['type', 128],
1532
+ ['query', 10_000],
1533
+ ['url', 2_048],
1534
+ ['pattern', 10_000]
1535
+ ]) {
1536
+ const value = action[key];
1537
+ if (typeof value !== 'string')
1538
+ continue;
1539
+ input[key] = value.slice(0, limit);
1540
+ truncated ||= value.length > limit;
1541
+ }
1542
+ if (Array.isArray(action.queries)) {
1543
+ const queries = action.queries.filter((value) => typeof value === 'string');
1544
+ input.queries = queries.slice(0, 10).map((value) => value.slice(0, 10_000));
1545
+ truncated ||=
1546
+ queries.length > 10 || queries.slice(0, 10).some((value) => value.length > 10_000);
1547
+ }
1548
+ return { input, truncated };
1549
+ }
1513
1550
  function hostedWebActionSummary(action) {
1514
1551
  const queries = Array.isArray(action.queries)
1515
1552
  ? action.queries
@@ -1,5 +1,9 @@
1
- import type { ModelUsage } from '../model/contracts.js';
2
- import type { MarAgentEvent } from './events.js';
1
+ import type { ModelEvent, ModelUsage } from '../model/contracts.js';
2
+ import type { EventPayload, MarAgentEvent } from './events.js';
3
3
  /** Keep streaming deltas live-only; exec output has one durable copy in model context records. */
4
4
  export declare function eventForPersistence(event: MarAgentEvent): MarAgentEvent | undefined;
5
5
  export declare function publicModelUsage(usage: ModelUsage): Omit<ModelUsage, 'rolloutBudgetUnits'>;
6
+ /** Provider-hosted calls are ordinary public tools, never local execution requests. */
7
+ export declare function publicHostedToolEvents(event: Extract<ModelEvent, {
8
+ type: 'hosted_tool';
9
+ }>): readonly EventPayload[];
@@ -1,3 +1,4 @@
1
+ import { AGENT_EXECUTION_POLICY } from './execution-policy.js';
1
2
  /** Keep streaming deltas live-only; exec output has one durable copy in model context records. */
2
3
  export function eventForPersistence(event) {
3
4
  if (event.type === 'message.delta' ||
@@ -15,3 +16,47 @@ export function publicModelUsage(usage) {
15
16
  void rolloutBudgetUnits;
16
17
  return publicUsage;
17
18
  }
19
+ /** Provider-hosted calls are ordinary public tools, never local execution requests. */
20
+ export function publicHostedToolEvents(event) {
21
+ const toolName = event.toolName ?? (event.kind === 'WEB_SEARCH' ? 'web_search' : 'web_fetch');
22
+ const legacyInput = {
23
+ ...(event.summary.query === undefined ? {} : { query: event.summary.query }),
24
+ ...(event.summary.url === undefined ? {} : { url: event.summary.url })
25
+ };
26
+ const input = event.input ?? (Object.keys(legacyInput).length ? legacyInput : undefined);
27
+ const legacyOutput = {
28
+ ...(event.summary.title === undefined ? {} : { title: event.summary.title }),
29
+ ...(event.summary.sources?.length ? { sources: event.summary.sources.slice(0, 20) } : {}),
30
+ ...(event.summary.sourcesTruncated === true || (event.summary.sources?.length ?? 0) > 20
31
+ ? { sourcesTruncated: true }
32
+ : {})
33
+ };
34
+ const output = event.output ?? (Object.keys(legacyOutput).length ? legacyOutput : undefined);
35
+ const text = typeof output === 'string' ? output : output === undefined ? '' : JSON.stringify(output);
36
+ const summary = text.slice(0, AGENT_EXECUTION_POLICY.toolEventSummaryCharacters);
37
+ const truncated = event.truncated === true ||
38
+ legacyOutput.sourcesTruncated === true ||
39
+ summary.length < text.length;
40
+ const started = {
41
+ type: 'tool.started',
42
+ toolName,
43
+ callId: event.itemId,
44
+ ...(input === undefined ? {} : { input }),
45
+ ...(truncated ? { truncated: true } : {})
46
+ };
47
+ if (event.status === 'RUNNING')
48
+ return [started];
49
+ if (event.status === 'FAILED')
50
+ return [
51
+ started,
52
+ {
53
+ type: 'tool.failed',
54
+ toolName,
55
+ callId: event.itemId,
56
+ code: 'HOSTED_TOOL_FAILED',
57
+ message: summary || 'Hosted tool failed.',
58
+ truncated
59
+ }
60
+ ];
61
+ return [started, { type: 'tool.completed', toolName, callId: event.itemId, summary, truncated }];
62
+ }
@@ -46,6 +46,7 @@ export type MarAgentEvent = MarAgentEventBase & ({
46
46
  type: 'reasoning.summary';
47
47
  text: string;
48
48
  } | {
49
+ /** Legacy persisted event; the Catalog exposes standard tool events instead. */
49
50
  type: 'hosted_tool.updated';
50
51
  itemId: string;
51
52
  kind: 'WEB_SEARCH' | 'WEB_FETCH';
@@ -71,6 +72,7 @@ export type MarAgentEvent = MarAgentEventBase & ({
71
72
  callId: string;
72
73
  parentCallId?: string;
73
74
  input?: unknown;
75
+ truncated?: boolean;
74
76
  } | {
75
77
  type: 'tool.completed';
76
78
  toolName: string;
@@ -88,6 +90,7 @@ export type MarAgentEvent = MarAgentEventBase & ({
88
90
  parentCallId?: string;
89
91
  code: string;
90
92
  message?: string;
93
+ truncated?: boolean;
91
94
  } | {
92
95
  type: 'usage.updated';
93
96
  inputTokens?: number | undefined;
@@ -3,7 +3,7 @@ import { isProviderContextOverflow, recoverModelStream } from '../model/recovery
3
3
  import { modelStreamEventObservedAt } from '../model/sse.js';
4
4
  import { modelOutputContinuationMessage } from '../prompts/output.js';
5
5
  import { executeRoundTools } from '../tools/execution.js';
6
- import { publicModelUsage } from './event-projection.js';
6
+ import { publicHostedToolEvents, publicModelUsage } from './event-projection.js';
7
7
  import { PlanOutputPrefix, splitPlanOutput } from './plan-output.js';
8
8
  /** Own the single model/tool loop; the SDK owns its handle, terminal events and cleanup. */
9
9
  export class ExecutionLoop {
@@ -215,13 +215,8 @@ export class ExecutionLoop {
215
215
  }
216
216
  else if (event.type === 'hosted_tool') {
217
217
  if (mode !== 'compact')
218
- await input.publish({
219
- type: 'hosted_tool.updated',
220
- itemId: event.itemId,
221
- kind: event.kind,
222
- status: event.status,
223
- summary: event.summary
224
- });
218
+ for (const toolEvent of publicHostedToolEvents(event))
219
+ await input.publish(toolEvent);
225
220
  }
226
221
  else if (event.type === 'citation') {
227
222
  if (mode !== 'compact')
@@ -1,4 +1,5 @@
1
1
  import { MarAgentError } from '../error.js';
2
+ import { publicHostedToolEvents } from '../runtime/event-projection.js';
2
3
  import { JsonlSessionStore } from './jsonl-store.js';
3
4
  const MAX_INPUT_IMAGE_BYTES = 5 * 1024 * 1024;
4
5
  const INPUT_IMAGE_MIME_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);
@@ -39,6 +40,22 @@ export async function openMarAgentSessionCatalog(input) {
39
40
  }
40
41
  ];
41
42
  }
43
+ if (isMarAgentEvent(record.payload) && record.payload.type === 'hosted_tool.updated') {
44
+ const legacy = record.payload;
45
+ return publicHostedToolEvents({ ...legacy, type: 'hosted_tool' }).map((event) => ({
46
+ kind: 'event',
47
+ sequence: record.sequence,
48
+ event: {
49
+ sequence: legacy.sequence,
50
+ timestamp: legacy.timestamp,
51
+ sessionId: legacy.sessionId,
52
+ executionId: legacy.executionId,
53
+ ...(legacy.turnId === undefined ? {} : { turnId: legacy.turnId }),
54
+ ...event,
55
+ eventId: `${legacy.eventId}:${event.type}`
56
+ }
57
+ }));
58
+ }
42
59
  if (isMarAgentEvent(record.payload))
43
60
  return [{ kind: 'event', sequence: record.sequence, event: record.payload }];
44
61
  return [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/agent",
3
- "version": "0.9.155",
3
+ "version": "0.9.157",
4
4
  "description": "Embeddable MAR coding agent SDK and CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",