@myagentroam/agent 0.11.68 → 0.11.70

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.
@@ -6,7 +6,7 @@ import { CodeModeTool, codeModeToolDefinition, codeExecWaitToolDefinition } from
6
6
  import { normalizeToolInput } from '../tools/input.js';
7
7
  import { execToolInput, execToolDefinition, execWaitToolDefinition, formatExecResult } from '../tools/local/exec.js';
8
8
  import { ExecTool } from './local-exec-tool.js';
9
- import { ReadTool, formatBatchReadOutput, readToolDefinition } from '../tools/local/read.js';
9
+ import { ReadTool, formatBatchReadOutput, formatReadEventOutput, readToolDefinition } from '../tools/local/read.js';
10
10
  import { WorkspacePathResolver } from '../tools/shared/path-resolver.js';
11
11
  import { ViewImageTool, viewImageToolDefinition } from '../tools/local/view-image.js';
12
12
  const definitions = [
@@ -58,9 +58,15 @@ export class LocalToolRegistry {
58
58
  async (arguments_, context) => {
59
59
  const result = await read.execute(arguments_, context.signal);
60
60
  const formatted = formatBatchReadOutput(result.results);
61
+ const publicResult = formatReadEventOutput(result.results);
61
62
  return {
62
63
  content: formatted.content,
63
64
  data: result,
65
+ eventSummary: publicResult.source,
66
+ eventData: {
67
+ ...publicResult.data,
68
+ truncated: result.truncated || publicResult.truncated
69
+ },
64
70
  truncated: result.truncated || formatted.truncated
65
71
  };
66
72
  }
@@ -4,6 +4,7 @@ import type { EventPayload, AgentEvent } from './events.js';
4
4
  export declare function toolEventSummary(text: string): {
5
5
  summary: string;
6
6
  truncated: boolean;
7
+ retainedLength: number;
7
8
  };
8
9
  /** Keep streaming deltas live-only; exec output has one durable copy in model context records. */
9
10
  export declare function eventForPersistence(event: AgentEvent): AgentEvent | undefined;
@@ -4,10 +4,10 @@ import { publicToolMetadata } from './public-tool-metadata.js';
4
4
  export function toolEventSummary(text) {
5
5
  const limit = AGENT_EXECUTION_POLICY.toolEventSummaryCharacters;
6
6
  if (text.length <= limit)
7
- return { summary: text, truncated: false };
7
+ return { summary: text, truncated: false, retainedLength: text.length };
8
8
  const marker = '... [tool event summary truncated]';
9
9
  const prefix = text.slice(0, limit - marker.length).replace(/[\uD800-\uDBFF]$/u, '');
10
- return { summary: prefix + marker, truncated: true };
10
+ return { summary: prefix + marker, truncated: true, retainedLength: prefix.length };
11
11
  }
12
12
  /** Keep streaming deltas live-only; exec output has one durable copy in model context records. */
13
13
  export function eventForPersistence(event) {
@@ -1,5 +1,6 @@
1
1
  export type PublicToolMetadata = ({
2
2
  query?: string;
3
+ sourcesOnly?: true;
3
4
  sources?: {
4
5
  url: string;
5
6
  title?: string;
@@ -16,6 +17,10 @@ export type PublicToolMetadata = ({
16
17
  name: string;
17
18
  description?: string;
18
19
  source?: string;
20
+ } | {
21
+ tools: string[];
22
+ } | {
23
+ status: 'accepted';
19
24
  }) & {
20
25
  hostedToolKind?: 'WEB_SEARCH' | 'WEB_FETCH';
21
26
  };
@@ -1,6 +1,12 @@
1
1
  /** Public metadata only; page bodies and skill instructions stay in the bounded output. */
2
2
  export function publicToolMetadata(toolName, value) {
3
3
  const text = (key, limit) => typeof value[key] === 'string' ? value[key].slice(0, limit) : undefined;
4
+ if (toolName === 'tool_search' &&
5
+ Array.isArray(value.tools) &&
6
+ value.tools.every((name) => typeof name === 'string'))
7
+ return { tools: value.tools.slice(0, 20).map((name) => name.slice(0, 512)) };
8
+ if (toolName === 'smart_compact' && value.status === 'accepted')
9
+ return { status: 'accepted' };
4
10
  if (toolName === 'web_search') {
5
11
  const entries = Array.isArray(value.results)
6
12
  ? value.results
@@ -21,7 +27,21 @@ export function publicToolMetadata(toolName, value) {
21
27
  }
22
28
  ];
23
29
  });
30
+ const sourcesComplete = entries !== undefined &&
31
+ sources !== undefined &&
32
+ entries.length <= 20 &&
33
+ entries.length === sources.length &&
34
+ value.truncated !== true &&
35
+ value.sourcesTruncated !== true &&
36
+ entries.every((entry, index) => {
37
+ const source = entry;
38
+ const projected = sources[index];
39
+ return (source.url === projected.url &&
40
+ source.title === projected.title &&
41
+ source.snippet === projected.snippet);
42
+ });
24
43
  return {
44
+ ...(value.sourcesOnly === true && sourcesComplete ? { sourcesOnly: true } : {}),
25
45
  ...(text('query', 500) === undefined ? {} : { query: text('query', 500) }),
26
46
  ...(sources === undefined
27
47
  ? {}
@@ -40,7 +40,10 @@ export function createCodeToolDispatch(input) {
40
40
  ...(expected ? { expectedMcpTool: expected } : {})
41
41
  }, 'programmatic');
42
42
  const bounded = boundedModelToolOutput(call.name, result.content, result.data);
43
- const data = call.name === 'exec' || call.name === 'exec_wait'
43
+ const data = call.name === 'read' ||
44
+ call.name === 'web_search' ||
45
+ call.name === 'exec' ||
46
+ call.name === 'exec_wait'
44
47
  ? structuredToolEventData(call.name, result.eventData ?? result.data)
45
48
  : result.eventData === undefined
46
49
  ? structuredToolEventData(call.name, result.data)
@@ -63,7 +66,7 @@ export function createCodeToolDispatch(input) {
63
66
  truncated: result.truncated === true || bounded.truncated || preview.truncated,
64
67
  ...(result.artifacts ? { artifacts: result.artifacts } : {})
65
68
  });
66
- const { eventData: _eventData, ...guestResult } = result;
69
+ const { eventData: _eventData, eventSummary: _eventSummary, ...guestResult } = result;
67
70
  return {
68
71
  ...guestResult,
69
72
  ...((call.name === 'exec' || call.name === 'exec_wait') && data !== undefined
@@ -198,6 +198,11 @@ export interface ReadEventData {
198
198
  path: string;
199
199
  startLine?: number;
200
200
  endLine?: number;
201
+ contentRange?: {
202
+ start: number;
203
+ end: number;
204
+ };
205
+ empty?: true;
201
206
  error?: {
202
207
  code: string;
203
208
  message: string;
@@ -128,7 +128,9 @@ export async function executeRoundTools(calls, scope) {
128
128
  : typeof output.eventSummary === 'string'
129
129
  ? output.eventSummary
130
130
  : '');
131
- const structuredData = call.name === 'exec' ||
131
+ const structuredData = call.name === 'read' ||
132
+ call.name === 'web_search' ||
133
+ call.name === 'exec' ||
132
134
  call.name === 'exec_wait' ||
133
135
  call.name === 'code_exec' ||
134
136
  call.name === 'code_exec_wait'
@@ -32,6 +32,7 @@ export function formatExecResult(result) {
32
32
  export const execToolDefinition = {
33
33
  name: 'exec',
34
34
  allowedCallers: ['direct', 'programmatic'],
35
+ codeModeExposure: 'both',
35
36
  parallelSafety: 'safe',
36
37
  description: 'Start a platform-native command, script, or program in workspace/default cwd. Returns a stable processId (p_ plus 12 lowercase hex characters), status, bounded stdout/stderr, cumulative byte counts, dropped-byte counts, exitCode and truncated. A completed status does not imply exitCode 0; inspect stderr/exitCode. For subsequent waiting, stdin writes or cancellation, call exec_wait directly with processId, not exec. Truncation does not stop the process. Cancelling the initial wait does not terminate the process. waitOutcome distinguishes snapshot, completion, and timeout. A foreground wait may return interrupted with reason=steer; the process keeps running.',
37
38
  outputSchema: {
@@ -1,4 +1,5 @@
1
1
  import type { ClientToolDefinition } from '../contracts.js';
2
+ import type { ReadEventData } from '../contracts.js';
2
3
  import { WorkspacePathResolver } from '../shared/path-resolver.js';
3
4
  export type { ReadEventData } from '../contracts.js';
4
5
  export declare const readToolDefinition: ClientToolDefinition;
@@ -31,6 +32,13 @@ export interface BatchReadResult {
31
32
  results: Array<ReadResult | ReadErrorResult>;
32
33
  truncated: boolean;
33
34
  }
35
+ /** Produce public text and offsets together, independently of model-visible markup. */
36
+ export declare function formatReadEventOutput(results: BatchReadResult['results']): {
37
+ source: string;
38
+ summary: string;
39
+ truncated: boolean;
40
+ data: ReadEventData;
41
+ };
34
42
  export declare class ReadTool {
35
43
  #private;
36
44
  private readonly paths;
@@ -85,6 +85,62 @@ export const readToolDefinition = {
85
85
  additionalProperties: false
86
86
  }
87
87
  };
88
+ /** Produce public text and offsets together, independently of model-visible markup. */
89
+ export function formatReadEventOutput(results) {
90
+ let source = '';
91
+ const items = results
92
+ .slice(0, TOOL_EXECUTION_LIMITS.readMaxBatchItems)
93
+ .map((item) => {
94
+ const path = item.path.slice(0, 4096).replace(/[\uD800-\uDBFF]$/u, '');
95
+ if ('error' in item) {
96
+ const error = {
97
+ code: item.error.code.slice(0, 80),
98
+ message: item.error.message.slice(0, 1000)
99
+ };
100
+ return { body: `${error.code}: ${error.message}`, result: { path, error } };
101
+ }
102
+ return {
103
+ body: item.text,
104
+ result: {
105
+ path,
106
+ startLine: item.startLine,
107
+ ...(item.endLine === undefined ? {} : { endLine: item.endLine }),
108
+ ...(item.text.length === 0 ? { empty: true } : {})
109
+ }
110
+ };
111
+ });
112
+ const maximum = AGENT_EXECUTION_POLICY.toolEventSummaryCharacters;
113
+ const completeLength = items.reduce((length, { body, result }) => length + result.path.length + 1 + body.length, Math.max(0, items.length - 1) * 2);
114
+ let truncated = items.length < results.length;
115
+ const projected = [];
116
+ for (const [index, { body, result }] of items.entries()) {
117
+ const path = result.path;
118
+ const separator = index === 0 ? '' : '\n\n';
119
+ const remaining = items.length - index;
120
+ const budget = completeLength <= maximum
121
+ ? maximum - source.length - separator.length
122
+ : Math.floor((maximum - source.length - separator.length - 2 * (remaining - 1)) / remaining);
123
+ // Keep full paths in metadata; long display labels must leave room for each body.
124
+ const pathBudget = Math.max(Math.floor(budget / 2), budget - body.length - 1);
125
+ const label = path.length <= pathBudget
126
+ ? path
127
+ : `${path.slice(0, pathBudget - 3).replace(/[\uD800-\uDBFF]$/u, '')}...`;
128
+ const preview = body.slice(0, budget - label.length - 1).replace(/[\uD800-\uDBFF]$/u, '');
129
+ truncated ||= label.length < path.length || preview.length < body.length;
130
+ source += `${separator}${label}\n`;
131
+ const start = source.length;
132
+ source += preview;
133
+ if (!result.error)
134
+ result.contentRange = { start, end: source.length };
135
+ projected.push(result);
136
+ }
137
+ return {
138
+ source,
139
+ summary: source,
140
+ truncated,
141
+ data: { mode: 'batch', results: projected, truncated }
142
+ };
143
+ }
88
144
  export class ReadTool {
89
145
  paths;
90
146
  constructor(paths) {
@@ -174,6 +174,8 @@ export function publicCodeObservations(values, data) {
174
174
  export function publicOutputTruncation(toolName, data) {
175
175
  if (!isRecord(data))
176
176
  return undefined;
177
+ if (toolName === 'read' && data.mode === 'batch' && data.truncated === true)
178
+ return 'SOURCE';
177
179
  if (toolName === 'code_exec' || toolName === 'code_exec_wait') {
178
180
  if (data.outputSourceTruncated === true)
179
181
  return 'SOURCE';
@@ -300,6 +302,12 @@ export function structuredToolEventData(toolName, value) {
300
302
  typeof result.path === 'string' &&
301
303
  (result.startLine === undefined || isNonnegativeInteger(result.startLine)) &&
302
304
  (result.endLine === undefined || isNonnegativeInteger(result.endLine)) &&
305
+ (result.empty === undefined || result.empty === true) &&
306
+ (result.contentRange === undefined ||
307
+ (isRecord(result.contentRange) &&
308
+ isNonnegativeInteger(result.contentRange.start) &&
309
+ isNonnegativeInteger(result.contentRange.end) &&
310
+ result.contentRange.end >= result.contentRange.start)) &&
303
311
  (result.error === undefined ||
304
312
  (isRecord(result.error) &&
305
313
  typeof result.error.code === 'string' &&
@@ -314,6 +322,8 @@ export function structuredToolEventData(toolName, value) {
314
322
  ? { startLine: item.startLine }
315
323
  : {}),
316
324
  ...('endLine' in item && item.endLine !== undefined ? { endLine: item.endLine } : {}),
325
+ ...(item.contentRange === undefined ? {} : { contentRange: { ...item.contentRange } }),
326
+ ...(item.empty === true ? { empty: true } : {}),
317
327
  ...('error' in item ? { error: { ...item.error } } : {})
318
328
  }))
319
329
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/agent",
3
- "version": "0.11.68",
3
+ "version": "0.11.70",
4
4
  "description": "Embeddable MAR coding agent SDK and CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",