@myagentroam/agent 0.9.74 → 0.9.75

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.
@@ -2,7 +2,7 @@ import type { ExecutionMode } from '../sdk/types.js';
2
2
  import { type ExecutionBudgetPromptState } from './execution-budget.js';
3
3
  import { type RetainedSessionResources } from './resources.js';
4
4
  import { type CurrentAgentModel, type SubagentModelOption } from './subagent.js';
5
- export declare const MAR_AGENT_PROMPT_VERSION = "1.42";
5
+ export declare const MAR_AGENT_PROMPT_VERSION = "1.43";
6
6
  export declare function buildSystemPrompt(input: {
7
7
  mode: ExecutionMode;
8
8
  platform: string;
@@ -6,7 +6,7 @@ import { outputStylePrompt } from './output.js';
6
6
  import { retainedSessionResourcesPrompt } from './resources.js';
7
7
  import { subagentModelOptionsPrompt, subagentPrompt, currentAgentModelPrompt } from './subagent.js';
8
8
  import { interactionPrompt, longRunningPrompt, safetyPrompt, toolUsagePrompt, workflowPrompt } from './workflow.js';
9
- export const MAR_AGENT_PROMPT_VERSION = '1.42';
9
+ export const MAR_AGENT_PROMPT_VERSION = '1.43';
10
10
  export function buildSystemPrompt(input) {
11
11
  const toolNames = new Set(input.tools);
12
12
  const hasLongRunningCapability = [
@@ -10,7 +10,7 @@ export function toolUsagePrompt(tools) {
10
10
  if (names.has('exec'))
11
11
  clauses.push('Use exec for platform-native commands, scripts, verification, and mechanical edits. Prefer rg or rg --files for search. Batch independent lookups and already-decided commands, preserving failure ordering. Use scripts for mechanical substitutions instead of reproducing long unchanged text in a patch; inspect actual effects afterward.');
12
12
  if (names.has('read'))
13
- clauses.push('Use read to batch known files and ranges. Batch only already-located, bounded ranges that are likely to fit together; for large files or documents, locate relevant sections before reading them. Read only what can affect the next decision, continue only relevant incomplete results using returned metadata, and avoid rereading unchanged content.');
13
+ clauses.push('Use read to batch known files and ranges. Batch only already-located, bounded ranges that are likely to fit together; for large files or documents, locate relevant sections before reading them. Read only what can affect the next decision, continue only relevant incomplete results using returned metadata, and avoid rereading unchanged content. Do not edit from an incomplete oversized-line preview. Obtain exact source with exec; if it still cannot fit, use a preconditioned deterministic replacement and verify the result.');
14
14
  if (names.has('apply_patch'))
15
15
  clauses.push('Prefer apply_patch for precise local edits. After a conflict, use the reported evidence to refresh only the affected context before retrying.');
16
16
  if (names.has('apply_patch') || names.has('exec'))
@@ -2,8 +2,12 @@ export declare const MODEL_TOKEN_ESTIMATOR: "UTF8_BYTES_V1";
2
2
  /** Local budget estimate only; provider usage remains authoritative. */
3
3
  export declare function countModelTokens(value: string): number;
4
4
  export declare function modelTokenBudgetBytes(maximumTokens: number): number;
5
- export declare function truncateModelText(value: string, maximumTokens: number, omittedLabel?: string): {
5
+ export declare function truncateModelText(value: string, maximumTokens: number, omittedLabel?: string, reported?: {
6
+ readonly originalTokenCount?: number;
7
+ readonly totalLines?: number;
8
+ }): {
6
9
  content: string;
7
10
  truncated: boolean;
8
11
  omittedTokens: number;
9
12
  };
13
+ export declare function countTextLines(value: string): number;
@@ -7,13 +7,13 @@ export function countModelTokens(value) {
7
7
  export function modelTokenBudgetBytes(maximumTokens) {
8
8
  return Math.max(0, Math.floor(maximumTokens)) * BYTES_PER_TOKEN;
9
9
  }
10
- export function truncateModelText(value, maximumTokens, omittedLabel = 'tool output') {
10
+ export function truncateModelText(value, maximumTokens, omittedLabel = 'tool output', reported) {
11
11
  const tokens = countModelTokens(value);
12
12
  if (tokens <= maximumTokens)
13
13
  return { content: value, truncated: false, omittedTokens: 0 };
14
14
  const maximumBytes = modelTokenBudgetBytes(maximumTokens);
15
15
  const bytes = Buffer.from(value, 'utf8');
16
- const warning = `Warning: truncated output (original token count: ${tokens})\nTotal output lines: ${lineCount(value)}\n\n`;
16
+ const warning = `Warning: truncated output (original token count: ${reported?.originalTokenCount ?? tokens})\nTotal output lines: ${reported?.totalLines ?? countTextLines(value)}\n\n`;
17
17
  let retainedBytes = Math.max(0, maximumBytes - 16 * BYTES_PER_TOKEN);
18
18
  for (let attempt = 0; attempt < 8; attempt++) {
19
19
  let head = Math.ceil(retainedBytes / 2);
@@ -48,7 +48,7 @@ export function truncateModelText(value, maximumTokens, omittedLabel = 'tool out
48
48
  omittedTokens: tokens
49
49
  };
50
50
  }
51
- function lineCount(value) {
51
+ export function countTextLines(value) {
52
52
  let lines = value.length === 0 ? 0 : 1;
53
53
  for (let index = 0; index < value.length; index++)
54
54
  if (value.charCodeAt(index) === 10)
package/dist/sdk/agent.js CHANGED
@@ -12,7 +12,7 @@ import { AGENT_EXECUTION_POLICY } from '../runtime/execution-policy.js';
12
12
  import { RolloutBudget, resolveRolloutBudgetOptions } from '../runtime/rollout-budget.js';
13
13
  import { ContextGcRuntime } from '../runtime/context-gc-runtime.js';
14
14
  import { buildContextProjection } from '../runtime/context-projection.js';
15
- import { countModelTokens, truncateModelText } from '../runtime/token-budget.js';
15
+ import { countModelTokens, countTextLines, truncateModelText } from '../runtime/token-budget.js';
16
16
  import { TOOL_EXECUTION_LIMITS } from '../tools/execution-limits.js';
17
17
  import { DEFAULT_COMPACTION_FOCUS, CompactionOperation, buildCompactionInput, buildCompactionMessages, buildCompactedHistory, compactedHistoryMessages, continuationMessage } from '../runtime/compact.js';
18
18
  import { buildSystemPrompt, MAR_AGENT_PROMPT_VERSION } from '../prompts/index.js';
@@ -930,7 +930,7 @@ export async function createMarAgent(options) {
930
930
  }
931
931
  })
932
932
  });
933
- const modelOutput = boundedModelToolOutput(output.content);
933
+ const modelOutput = boundedModelToolOutput(call.name, output.content, output.data);
934
934
  const eventSummary = output.content.slice(0, AGENT_EXECUTION_POLICY.toolEventSummaryCharacters);
935
935
  const structuredData = structuredToolEventData(call.name, output.data);
936
936
  const artifacts = structuredToolArtifacts(call.name, output.artifacts);
@@ -1660,8 +1660,17 @@ function estimatedRequestTokens(system, messages, tools, images) {
1660
1660
  return (countModelTokens(`${system}${stableJson(textMessages)}${stableJson(tools)}`) +
1661
1661
  transientImageCount * AGENT_EXECUTION_POLICY.estimatedTokensPerImage);
1662
1662
  }
1663
- function boundedModelToolOutput(value) {
1664
- const result = truncateModelText(value, AGENT_EXECUTION_POLICY.modelToolOutputTokens);
1663
+ function boundedModelToolOutput(toolName, value, data) {
1664
+ const execDiagnostics = toolName === 'exec' &&
1665
+ isRecord(data) &&
1666
+ typeof data.stdout === 'string' &&
1667
+ typeof data.stderr === 'string'
1668
+ ? {
1669
+ originalTokenCount: countModelTokens(data.stdout) + countModelTokens(data.stderr),
1670
+ totalLines: countTextLines(data.stdout) + countTextLines(data.stderr)
1671
+ }
1672
+ : undefined;
1673
+ const result = truncateModelText(value, AGENT_EXECUTION_POLICY.modelToolOutputTokens, 'tool output', execDiagnostics);
1665
1674
  return { content: result.content, truncated: result.truncated };
1666
1675
  }
1667
1676
  function stableJson(value) {
@@ -208,6 +208,30 @@ function boundedUtf8Prefix(value, maximumBytes) {
208
208
  }
209
209
  return { value: `${result}${marker}`, truncated: true };
210
210
  }
211
+ function oversizedLinePreview(value, retainedBytes, lineNumber) {
212
+ const bytes = Buffer.from(value, 'utf8');
213
+ if (retainedBytes >= bytes.length)
214
+ return { value, shownBytes: bytes.length, omittedBytes: 0 };
215
+ const headTarget = Math.floor(retainedBytes / 2);
216
+ const tailTarget = retainedBytes - headTarget;
217
+ let head = Math.min(headTarget, bytes.length);
218
+ while (head > 0 && isUtf8ContinuationByte(bytes[head]))
219
+ head--;
220
+ let tail = Math.max(head, bytes.length - tailTarget);
221
+ while (tail < bytes.length && isUtf8ContinuationByte(bytes[tail]))
222
+ tail++;
223
+ const shownBytes = head + bytes.length - tail;
224
+ const omittedBytes = bytes.length - shownBytes;
225
+ const marker = `...[${omittedBytes} bytes omitted from line ${lineNumber}]...`;
226
+ return {
227
+ value: `${bytes.toString('utf8', 0, head)}${marker}${bytes.toString('utf8', tail)}`,
228
+ shownBytes,
229
+ omittedBytes
230
+ };
231
+ }
232
+ function isUtf8ContinuationByte(value) {
233
+ return value !== undefined && (value & 0xc0) === 0x80;
234
+ }
211
235
  function formatBatchReadResult(result, index, maximumBytes) {
212
236
  const visiblePath = boundedUtf8Prefix(result.path, 128);
213
237
  const path = escapeAttribute(visiblePath.value);
@@ -265,8 +289,59 @@ function formatBatchReadResult(result, index, maximumBytes) {
265
289
  high = middle - 1;
266
290
  }
267
291
  const content = render(low);
268
- if (Buffer.byteLength(content) <= maximumBytes)
292
+ if (low > 0 && Buffer.byteLength(content) <= maximumBytes)
269
293
  return { content, previewComplete: low === lines.length };
294
+ if (lines.length > 0) {
295
+ const lineNumber = result.startLine;
296
+ const prefix = `${lineNumber}\t`;
297
+ const formattedLine = lines[0];
298
+ const sourceLine = formattedLine.startsWith(prefix)
299
+ ? formattedLine.slice(prefix.length)
300
+ : formattedLine;
301
+ const sourceLineBytes = Buffer.byteLength(sourceLine);
302
+ const renderOversizedLine = (retainedBytes) => {
303
+ const preview = oversizedLinePreview(sourceLine, retainedBytes, lineNumber);
304
+ const metadata = {
305
+ path: visiblePath.value,
306
+ ...(visiblePath.truncated ? { pathTruncated: true } : {}),
307
+ encoding: result.encoding,
308
+ newline: result.newline,
309
+ startLine: lineNumber,
310
+ endLine: lineNumber,
311
+ eof: false,
312
+ truncated: true,
313
+ previewComplete: false,
314
+ oversizedLine: {
315
+ line: lineNumber,
316
+ bytes: sourceLineBytes,
317
+ shownBytes: preview.shownBytes,
318
+ omittedBytes: preview.omittedBytes
319
+ }
320
+ };
321
+ return [
322
+ `<read_result index="${index}" path="${path}"${pathTruncatedAttribute}>`,
323
+ `${prefix}${preview.value}`,
324
+ `<read_metadata>${JSON.stringify(metadata)}</read_metadata>`,
325
+ '</read_result>'
326
+ ].join('\n');
327
+ };
328
+ let minimum = renderOversizedLine(0);
329
+ if (Buffer.byteLength(minimum) <= maximumBytes) {
330
+ let retainedLow = 0;
331
+ let retainedHigh = sourceLineBytes;
332
+ while (retainedLow < retainedHigh) {
333
+ const middle = Math.ceil((retainedLow + retainedHigh) / 2);
334
+ const candidate = renderOversizedLine(middle);
335
+ if (Buffer.byteLength(candidate) <= maximumBytes) {
336
+ retainedLow = middle;
337
+ minimum = candidate;
338
+ }
339
+ else
340
+ retainedHigh = middle - 1;
341
+ }
342
+ return { content: minimum, previewComplete: false };
343
+ }
344
+ }
270
345
  return {
271
346
  content: `<read_error index="${index}" code="MAR_AGENT_TOOL_OUTPUT_LIMIT">Model-visible read metadata exceeds this item's output share.</read_error>`,
272
347
  previewComplete: false
@@ -46,7 +46,7 @@ export const readToolDefinition = {
46
46
  }
47
47
  }
48
48
  },
49
- description: `Read one or more known text files/ranges. Strict UTF-8 with optional BOM is the default; BOM-declared UTF-16LE/UTF-16BE is supported. Invalid text returns an item error instead of replacement characters. Always pass reads; use one item for a single file and up to ${TOOL_EXECUTION_LIMITS.readMaxBatchItems} items for a batch. Batch only already-located, bounded ranges whose combined content is likely to fit the model-visible output budget; for exploration, locate relevant files, symbols, or headings first, then read the smallest useful ranges. Results retain input order, use 1-based line numbers, and include <read_metadata> with path, encoding, newline, exact visible range, eof, truncation, nextOffset, and whether previewComplete. Items fail independently and run with bounded concurrency. Each item returns at most ${TOOL_EXECUTION_LIMITS.readMaxLines} lines/${TOOL_EXECUTION_LIMITS.readMaxBytes} bytes; the structured call shares a ${TOOL_EXECUTION_LIMITS.readMaxBatchBytes}-byte budget, while ordinary model-visible content fairly shares the common tool-output budget across all items. Structured data.results items provide text as decoded source for the returned range, preserving line endings and excluding BOM; content is numbered display text. Large files support bounded range reads. If previewComplete is false, continue only the still-relevant item from nextOffset. Relative paths use the workspace; absolute paths are allowed. Prefer exec with rg for search and read for known files.`,
49
+ description: `Read one or more known text files/ranges. Strict UTF-8 with optional BOM is the default; BOM-declared UTF-16LE/UTF-16BE is supported. Invalid text returns an item error instead of replacement characters. Always pass reads; use one item for a single file and up to ${TOOL_EXECUTION_LIMITS.readMaxBatchItems} items for a batch. Batch only already-located, bounded ranges whose combined content is likely to fit the model-visible output budget; for exploration, locate relevant files, symbols, or headings first, then read the smallest useful ranges. Results retain input order, use 1-based line numbers, and include <read_metadata> with path, encoding, newline, exact visible range, eof, truncation, nextOffset, and whether previewComplete. Items fail independently and run with bounded concurrency. Each item returns at most ${TOOL_EXECUTION_LIMITS.readMaxLines} lines/${TOOL_EXECUTION_LIMITS.readMaxBytes} bytes; the structured call shares a ${TOOL_EXECUTION_LIMITS.readMaxBatchBytes}-byte budget, while ordinary model-visible content fairly shares the common tool-output budget across all items. Structured data.results items provide text as decoded source for the returned range, preserving line endings and excluding BOM; content is numbered display text. Large files support bounded range reads. If previewComplete is false and nextOffset is present, continue only the still-relevant item from nextOffset. An oversized single line instead returns a head/tail preview with no line continuation cursor; use exec to obtain exact source before editing omitted content. Relative paths use the workspace; absolute paths are allowed. Prefer exec with rg for search and read for known files.`,
50
50
  inputSchema: {
51
51
  type: 'object',
52
52
  properties: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/agent",
3
- "version": "0.9.74",
3
+ "version": "0.9.75",
4
4
  "description": "Embeddable MAR coding agent SDK and CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",