@myagentroam/agent 0.11.67 → 0.11.69

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'
@@ -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;
@@ -6,6 +6,7 @@ import { createReadStream } from 'node:fs';
6
6
  import { lstat, open } from 'node:fs/promises';
7
7
  import { TextDecoder } from 'node:util';
8
8
  import { AgentError } from '../../error.js';
9
+ import { toolEventSummary } from '../../runtime/event-projection.js';
9
10
  import { TOOL_EXECUTION_LIMITS } from '../execution-limits.js';
10
11
  export const readToolDefinition = {
11
12
  name: 'read',
@@ -85,6 +86,52 @@ export const readToolDefinition = {
85
86
  additionalProperties: false
86
87
  }
87
88
  };
89
+ /** Produce public text and offsets together, independently of model-visible markup. */
90
+ export function formatReadEventOutput(results) {
91
+ let source = '';
92
+ const projected = [];
93
+ for (const item of results.slice(0, TOOL_EXECUTION_LIMITS.readMaxBatchItems)) {
94
+ const path = item.path.slice(0, 4096).replace(/[\uD800-\uDBFF]$/u, '');
95
+ source += `${source ? '\n\n' : ''}${path}\n`;
96
+ if ('error' in item) {
97
+ const error = {
98
+ code: item.error.code.slice(0, 80),
99
+ message: item.error.message.slice(0, 1000)
100
+ };
101
+ source += `${error.code}: ${error.message}`;
102
+ projected.push({ path, error });
103
+ }
104
+ else {
105
+ const start = source.length;
106
+ source += item.text;
107
+ projected.push({
108
+ path,
109
+ startLine: item.startLine,
110
+ ...(item.endLine === undefined ? {} : { endLine: item.endLine }),
111
+ ...(item.text.length === 0 ? { empty: true } : {}),
112
+ contentRange: { start, end: source.length }
113
+ });
114
+ }
115
+ }
116
+ const preview = toolEventSummary(source);
117
+ const retained = preview.retainedLength;
118
+ for (const item of projected) {
119
+ const range = item.contentRange;
120
+ if (!range)
121
+ continue;
122
+ if (range.start > retained || (range.start === retained && range.end > range.start)) {
123
+ delete item.contentRange;
124
+ }
125
+ else {
126
+ range.end = Math.min(range.end, retained);
127
+ }
128
+ }
129
+ return {
130
+ source,
131
+ ...preview,
132
+ data: { mode: 'batch', results: projected, truncated: preview.truncated }
133
+ };
134
+ }
88
135
  export class ReadTool {
89
136
  paths;
90
137
  constructor(paths) {
@@ -300,6 +300,12 @@ export function structuredToolEventData(toolName, value) {
300
300
  typeof result.path === 'string' &&
301
301
  (result.startLine === undefined || isNonnegativeInteger(result.startLine)) &&
302
302
  (result.endLine === undefined || isNonnegativeInteger(result.endLine)) &&
303
+ (result.empty === undefined || result.empty === true) &&
304
+ (result.contentRange === undefined ||
305
+ (isRecord(result.contentRange) &&
306
+ isNonnegativeInteger(result.contentRange.start) &&
307
+ isNonnegativeInteger(result.contentRange.end) &&
308
+ result.contentRange.end >= result.contentRange.start)) &&
303
309
  (result.error === undefined ||
304
310
  (isRecord(result.error) &&
305
311
  typeof result.error.code === 'string' &&
@@ -314,6 +320,8 @@ export function structuredToolEventData(toolName, value) {
314
320
  ? { startLine: item.startLine }
315
321
  : {}),
316
322
  ...('endLine' in item && item.endLine !== undefined ? { endLine: item.endLine } : {}),
323
+ ...(item.contentRange === undefined ? {} : { contentRange: { ...item.contentRange } }),
324
+ ...(item.empty === true ? { empty: true } : {}),
317
325
  ...('error' in item ? { error: { ...item.error } } : {})
318
326
  }))
319
327
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/agent",
3
- "version": "0.11.67",
3
+ "version": "0.11.69",
4
4
  "description": "Embeddable MAR coding agent SDK and CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",