@myagentroam/node 0.11.33 → 0.11.35

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.
package/dist/connector.js CHANGED
@@ -914,6 +914,7 @@ export class NodeConnector {
914
914
  persist: (session, nativeSessionId) => {
915
915
  this.database?.saveNativeSessionMetadata({
916
916
  ...(session.parentSessionId == null ? {} : { parentSessionId: session.parentSessionId }),
917
+ initializeParent: session.externalSessionId === null,
917
918
  runner: session.runner,
918
919
  externalSessionId: nativeSessionId,
919
920
  workspaceId: session.workspaceId,
package/dist/database.js CHANGED
@@ -315,7 +315,9 @@ export class NodeDatabase {
315
315
  const model = input.model === undefined ? (current?.model ?? null) : input.model;
316
316
  const effort = input.effort === undefined ? (current?.effort ?? null) : input.effort;
317
317
  const access = input.access === undefined ? (current?.access ?? null) : input.access;
318
- const parentSessionId = current === undefined ? (input.parentSessionId ?? null) : (current.parentSessionId ?? null);
318
+ const parentSessionId = current === undefined || input.initializeParent === true
319
+ ? (current?.parentSessionId ?? input.parentSessionId ?? null)
320
+ : (current.parentSessionId ?? null);
319
321
  const metadata = JSON.stringify({
320
322
  version: 1,
321
323
  parentSessionId,
@@ -5,7 +5,7 @@ export function hasMarctlContext(environment) {
5
5
  !!environment['MAR_CTL_NODE_ID'] &&
6
6
  !!environment['MAR_CTL_WORKSPACE_ID']);
7
7
  }
8
- export const marctlDescription = 'You are in a MAR-managed Workspace with marctl on PATH. Load this guide to create, coordinate, message or stop independent Sessions; inspect status/history/results; change titles, prompts or models; observe and decide approvals; manage Goals or scheduled tasks; or run commands/transfer files on other authorized MAR Nodes, even when marctl is not named. When creating an independent Session, prefer --runner mar-agent unless the user or applicable workflow specifies another Runner. Ordinary local shell work and built-in subagents alone do not require it.';
8
+ export const marctlDescription = 'You are in a MAR-managed Workspace with marctl on PATH. Load this guide to create, coordinate, message or stop independent Sessions; inspect status/history/results; change titles, prompts or models; observe and decide approvals; manage Goals or scheduled tasks for the current or other Sessions; or run commands/transfer files on other authorized MAR Nodes, even when marctl is not named. When creating an independent Session, prefer --runner mar-agent unless the user or applicable workflow specifies another Runner. Ordinary local shell work and built-in subagents alone do not require it.';
9
9
  export const marctlInstructions = [
10
10
  '## MAR Workspace CLI',
11
11
  'Use your native shell tool to run marctl. Reuse loaded guidance while it remains in context. Consult local marctl help sessions for unclear options (shared by all Session subcommands) and marctl --version when version matters; neither needs a network request. Capabilities and permissions still apply.',
@@ -22,7 +22,7 @@ export const marctlInstructions = [
22
22
  'show/config/history/graph/rename, prompt and schedule get/create/update may omit the Session ID to use the current Session. Without a current Session, specify an ID. send/goal/stop/wait/approval always require explicit target IDs.',
23
23
  'Use sessions schedule list/get/create/update for the same tasks as the built-in schedule MCP, which remains available in other Runners and is hidden in MAR Agent while its marctl skill is available. list is Workspace-scoped. create requires --cron and text (-m/--message-file, up to 20,000 characters). update requires --expected-revision from get and at least cron or text. get returns task (null if absent), with id, revision, objective, cron, timezone and enabled; applied updates also return task. Reuse that task instead of probing its shape or refetching unchanged state. Schedule text is trimmed at both ends; compare after the same trimming; a conclusive update response needs no extra get. Other-owner edits return a PENDING proposal, not an applied change. Scheduled execution uses normal user permissions. Follow existing approval rules and do not retry conflicts or uncertain writes blindly.',
24
24
  'Read results with sessions history <session-id> --limit 10 --json (default: latest 10 SEGMENTs, not messages; --limit 1..100). In segments[].items[], select kind === "assistant_message" and read payload.text; keep segment runId and user_message.payload.clientMessageId for queued-input correlation. Reuse the returned page; follow --cursor <nextCursor> only for missing evidence.',
25
- 'Use sessions send <session-id> --steer -m "Additional context: focus on the resume path." --json for decision-changing updates rather than routine reports: it may switch the current execution. Node decides delivery from actual state; an idle Session receives ordinary input. Choose exactly one of --steer or --queue, even when idle; missing, conflicting, repeated, or obsolete options are rejected locally before input is read or a request is sent. Use --queue to place input in a subsequent turn without interrupting active execution. New input resumes a paused queue using ordinary send admission after cancellation settles; later explicit stops still apply; with an active Goal, ordinary queued input waits until the Goal exits. start/send return clientMessageId and the accepted/queued result. A queued result may refer to the currently active Run: associate queueItemId/clientMessageId with history before deciding that input finished. There are no queue-item edit/delete/reorder commands; show returns only queuedCount.',
25
+ 'Use sessions send <session-id> --steer -m "Additional context: focus on the resume path." --json for time-sensitive, decision-changing updates rather than routine reports: it prioritizes the update and may switch the current execution. Node decides delivery from actual state; an idle Session receives ordinary input. Choose exactly one of --steer or --queue, even when idle; missing, conflicting, repeated, or obsolete options are rejected locally before input is read or a request is sent. Use --queue to place input in a subsequent turn without interrupting active execution; during normal active work it waits for the current execution and earlier queued work, and can be delayed by an active Goal. Do not use it when the recipient needs the information during current work. New input resumes a paused queue using ordinary send admission after cancellation settles; later explicit stops still apply; with an active Goal, ordinary queued input waits until the Goal exits. start/send return clientMessageId and the accepted/queued result. A queued result may refer to the currently active Run: associate queueItemId/clientMessageId with history before deciding that input finished. There are no queue-item edit/delete/reorder commands; show returns only queuedCount.',
26
26
  'Wait with sessions wait <session-id> --run <run-id> --timeout 5m --json through the existing Watch. Prefer --timeout 5m when blocked on task completion; use 30s for a short deadline. Continue useful independent work before waiting. If your shell tool returns a running process or cell, reuse its process/cell handle rather than starting another wait or polling show/list. A timeout may include progress, the last observed snapshot, not a fresh query. Timeout or cancelled waiting does not stop the task. Use sessions stop <session-id> --run <run-id> --json only to stop that active Run; ownership rules still apply.',
27
27
  'Use wait --until approval to return early when a Run needs a decision. Inspect show/history, then use sessions approval decide <session-id> --run <public-run-id> --approval <approval-id> --decision approve|reject --json for one explicitly authorized request. This does not grant authority or auto-approve tools. Acknowledgment is not completion; observe status/history and wait again as needed.',
28
28
  'Goal get/set/clear use the existing Session Goal semantics; see marctl help sessions. A Coordinator can work from ordinary messages or its existing schedule without a Goal. Worker completion never automatically wakes it. Actively wait/read results, or finish and reconcile on the next user message or scheduled input.',
@@ -1,4 +1,4 @@
1
- import { buildCompactEvidence, countModelTokens, generateModelText, MarAgentError } from '@myagentroam/agent';
1
+ import { buildCompactEvidence, countModelTokens, generateModelText, AgentError } from '@myagentroam/agent';
2
2
  import { highDensityCompactionPrompt } from './compact-prompt.js';
3
3
  import { marAgentRuntimeCompactConfigurationSchema } from '@myagentroam/protocol';
4
4
  /** Resolve optional dedicated credentials in the same factory batch without widening the SDK catalog. */
@@ -141,7 +141,7 @@ export async function generateMarAgentCompact(context, selected, signal) {
141
141
  }
142
142
  catch (error) {
143
143
  signal.throwIfAborted();
144
- if (error instanceof MarAgentError) {
144
+ if (error instanceof AgentError) {
145
145
  const status = error.details?.status;
146
146
  failure = {
147
147
  ...failure,
@@ -150,7 +150,7 @@ export async function generateMarAgentCompact(context, selected, signal) {
150
150
  ...(typeof error.details?.reason === 'string' ? { errorReason: error.details.reason } : {})
151
151
  };
152
152
  }
153
- await report('FAILED', 'MODEL_FAILED', error instanceof MarAgentError
153
+ await report('FAILED', 'MODEL_FAILED', error instanceof AgentError
154
154
  ? error.code
155
155
  : (failure.errorCode ?? 'MAR_AGENT_COMPACT_MODEL_FAILED'));
156
156
  return undefined;
@@ -1,9 +1,9 @@
1
- import { MarAgentError } from '@myagentroam/agent';
1
+ import { AgentError } from '@myagentroam/agent';
2
2
  /** Composes Node-owned tools without replacing another domain's execution handler. */
3
3
  export function combineExecutionExtensions(...sources) {
4
4
  const tools = sources.flatMap((source) => source.tools ?? []);
5
5
  if (new Set(tools.map((tool) => tool.name)).size !== tools.length)
6
- throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Host tool names conflict.');
6
+ throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Host tool names conflict.');
7
7
  return {
8
8
  tools,
9
9
  skills: sources.flatMap((source) => source.skills ?? []),
@@ -14,7 +14,7 @@ export function combineExecutionExtensions(...sources) {
14
14
  executeTool: async (call, context) => {
15
15
  const source = sources.find((source) => source.tools?.some((tool) => tool.name === call.name));
16
16
  if (!source?.executeTool)
17
- throw new MarAgentError('MAR_AGENT_TOOL_NOT_AVAILABLE', 'Host tool is unavailable.');
17
+ throw new AgentError('MAR_AGENT_TOOL_NOT_AVAILABLE', 'Host tool is unavailable.');
18
18
  return source.executeTool(call, context);
19
19
  }
20
20
  };
@@ -1,5 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { LocalAgentHost, MarAgentError, createMarAgent, generateSessionTitle, openMarAgentSessionCatalog } from '@myagentroam/agent';
2
+ import { LocalAgentHost } from '@myagentroam/agent/host';
3
+ import { AgentError, createAgent, generateSessionTitle, openAgentSessionCatalog } from '@myagentroam/agent';
3
4
  import { projectMarAgentHistory } from './history-projection.js';
4
5
  import { MarAgentConversationNormalizer } from './conversation-normalizer.js';
5
6
  import { hostedConversationGeneratedImagesDisplayDirectory, hostedConversationImageRunId, marAgentGeneratedImageSources, marAgentGeneratedImagesDirectory } from './generated-images.js';
@@ -28,10 +29,10 @@ export class MarAgentHostedConversationRuntime {
28
29
  #registerNativeImages;
29
30
  constructor(options = {}) {
30
31
  this.#publishModelResource = options.publishModelResource;
31
- this.#createAgent = options.createAgent ?? createMarAgent;
32
+ this.#createAgent = options.createAgent ?? createAgent;
32
33
  this.#generateTitle = options.generateTitle ?? generateSessionTitle;
33
34
  this.#createHost = options.createHost ?? ((input) => new LocalAgentHost(input));
34
- this.#openCatalog = options.openCatalog ?? openMarAgentSessionCatalog;
35
+ this.#openCatalog = options.openCatalog ?? openAgentSessionCatalog;
35
36
  this.#now = options.now ?? Date.now;
36
37
  this.#onEvent = options.onEvent;
37
38
  this.#webSearch = options.webSearch;
@@ -120,7 +121,7 @@ export class MarAgentHostedConversationRuntime {
120
121
  return { lastActivityAt: Date.parse(rolledBack.lastActivityAt) };
121
122
  }
122
123
  catch (error) {
123
- if (error instanceof MarAgentError)
124
+ if (error instanceof AgentError)
124
125
  throw new Error(error.code, { cause: error });
125
126
  throw error;
126
127
  }
@@ -383,7 +384,7 @@ export class MarAgentHostedConversationRuntime {
383
384
  mode: 'node',
384
385
  host,
385
386
  models: sdkModelConfigurations(models.filter((model) => input.models.some((candidate) => candidate.id === model.id))),
386
- runtimeExtensions: marAgentCompactExtensionSource(compactState),
387
+ extensions: marAgentCompactExtensionSource(compactState),
387
388
  defaultModelId: 'defaultModelId' in input ? input.defaultModelId : input.modelId,
388
389
  workspaceMapping: {
389
390
  logicalPath: '/workspace',
@@ -1,5 +1,5 @@
1
1
  import { dirname } from 'node:path';
2
- import { MarAgentError } from '@myagentroam/agent';
2
+ import { AgentError } from '@myagentroam/agent';
3
3
  import { codexImageGenToolDefinition, bytedArkImageGenToolDefinition, executeCodexImageGen } from './image-generation.js';
4
4
  import { marAgentGeneratedImagesDirectory } from './generated-images.js';
5
5
  import { normalizeGeneratedImageDisplayDirectory, validateImageGenerationConfiguration } from './image-generation-validation.js';
@@ -11,7 +11,7 @@ export function createImageGenerationExtensions(input) {
11
11
  const displayDirectory = normalizeGeneratedImageDisplayDirectory(input.displayDirectory);
12
12
  const codex = imageGeneration.provider === 'CODEX';
13
13
  if (!codex && imageGeneration.provider !== 'BYTED_ARK')
14
- throw new MarAgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Unsupported image provider.');
14
+ throw new AgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Unsupported image provider.');
15
15
  const tool = codex ? codexImageGenToolDefinition : bytedArkImageGenToolDefinition;
16
16
  return {
17
17
  tools: [tool],
@@ -29,11 +29,11 @@ export function createImageGenerationExtensions(input) {
29
29
  ],
30
30
  executeTool: async (call, context) => {
31
31
  if (call.name !== tool.name)
32
- throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Image tool is unavailable.');
32
+ throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Image tool is unavailable.');
33
33
  context.signal.throwIfAborted();
34
34
  const directory = marAgentGeneratedImagesDirectory(input.homeDirectory, context.sessionId);
35
35
  if (directory === undefined || call.callId === undefined)
36
- throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Image execution identity is invalid.');
36
+ throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Image execution identity is invalid.');
37
37
  return executeCodexImageGen(call.arguments, {
38
38
  configuration: { imageGeneration },
39
39
  sessionDirectory: dirname(directory),
@@ -47,10 +47,10 @@ export function createImageGenerationExtensions(input) {
47
47
  .executeTool({ name: 'view_image', arguments: { path } }, context);
48
48
  const image = output.images?.length === 1 ? output.images[0] : undefined;
49
49
  if (image === undefined || image.dataBase64 === undefined)
50
- throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_INVALID', 'Referenced image result is invalid.');
50
+ throw new AgentError('MAR_AGENT_TOOL_OUTPUT_INVALID', 'Referenced image result is invalid.');
51
51
  const data = Buffer.from(image.dataBase64, 'base64');
52
52
  if (data.byteLength === 0)
53
- throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_INVALID', 'Referenced image result is invalid.');
53
+ throw new AgentError('MAR_AGENT_TOOL_OUTPUT_INVALID', 'Referenced image result is invalid.');
54
54
  return { mimeType: image.mimeType, data };
55
55
  }
56
56
  });
@@ -1,5 +1,5 @@
1
1
  import { posix } from 'node:path';
2
- import { MarAgentError } from '@myagentroam/agent';
2
+ import { AgentError } from '@myagentroam/agent';
3
3
  export function validateImageGenerationConfiguration(configuration) {
4
4
  const imageGeneration = configuration.imageGeneration;
5
5
  if (imageGeneration === undefined)
@@ -32,7 +32,7 @@ export function normalizeGeneratedImageDisplayDirectory(value) {
32
32
  normalized === '/' ||
33
33
  normalized.length > 4096 ||
34
34
  normalized.includes('\0'))
35
- throw new MarAgentError('MAR_AGENT_HOST_INCOMPATIBLE', 'Generated image display directory is invalid.');
35
+ throw new AgentError('MAR_AGENT_HOST_INCOMPATIBLE', 'Generated image display directory is invalid.');
36
36
  return normalized;
37
37
  }
38
38
  function isAllowedImageGenerationEndpoint(endpoint) {
@@ -46,5 +46,5 @@ function isAllowedImageGenerationEndpoint(endpoint) {
46
46
  (endpoint.protocol === 'https:' || (endpoint.protocol === 'http:' && loopback)));
47
47
  }
48
48
  function invalidImageGenerationConfiguration() {
49
- throw new MarAgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Model image generation configuration is invalid.');
49
+ throw new AgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Model image generation configuration is invalid.');
50
50
  }
@@ -1,7 +1,7 @@
1
1
  import { createHash, randomUUID } from 'node:crypto';
2
2
  import { mkdir, rename, rm, writeFile } from 'node:fs/promises';
3
3
  import { basename, isAbsolute, join, posix } from 'node:path';
4
- import { MarAgentError } from '@myagentroam/agent';
4
+ import { AgentError } from '@myagentroam/agent';
5
5
  import { requestHttp, acquireCredential, appendCredentialHeaders } from '@myagentroam/agent/host/network';
6
6
  const IMAGE_MAX_BYTES = 20_971_520;
7
7
  const RESPONSE_MAX_BYTES = Math.ceil((IMAGE_MAX_BYTES * 4) / 3) + 4096;
@@ -59,12 +59,12 @@ export async function executeCodexImageGen(arguments_, input) {
59
59
  input.signal.throwIfAborted();
60
60
  const capability = input.configuration.imageGeneration;
61
61
  if (capability === undefined || capability.credentialProvider === undefined)
62
- throw new MarAgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Image generation requires an independent credential provider.');
62
+ throw new AgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Image generation requires an independent credential provider.');
63
63
  const request = parseInput(arguments_);
64
64
  const images = await selectedEditImages(request, input);
65
65
  const ark = capability.provider === 'BYTED_ARK';
66
66
  if (!ark && capability.provider !== 'CODEX')
67
- throw new MarAgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Unsupported image provider.');
67
+ throw new AgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Unsupported image provider.');
68
68
  const endpoint = images.length === 0 ? capability.generateEndpoint : capability.editEndpoint;
69
69
  const body = JSON.stringify(ark
70
70
  ? {
@@ -168,7 +168,7 @@ export async function executeCodexImageGen(arguments_, input) {
168
168
  ]
169
169
  };
170
170
  }
171
- throw new MarAgentError('MAR_AGENT_IMAGE_GENERATION_FAILED', 'Image generation failed.');
171
+ throw new AgentError('MAR_AGENT_IMAGE_GENERATION_FAILED', 'Image generation failed.');
172
172
  }
173
173
  function parseInput(value) {
174
174
  if (value === null || typeof value !== 'object' || Array.isArray(value))
@@ -211,7 +211,7 @@ async function selectedEditImages(request, input) {
211
211
  return [];
212
212
  const images = input.recentImages.slice(-request.numLastImagesToInclude);
213
213
  if (images.length !== request.numLastImagesToInclude)
214
- throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', `Requested the last ${request.numLastImagesToInclude} conversation images, but only ${images.length} were available.`);
214
+ throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', `Requested the last ${request.numLastImagesToInclude} conversation images, but only ${images.length} were available.`);
215
215
  return images.map(validateEditImage);
216
216
  }
217
217
  function validateEditImage(image) {
@@ -219,14 +219,14 @@ function validateEditImage(image) {
219
219
  !Buffer.isBuffer(image.data) ||
220
220
  image.data.byteLength === 0 ||
221
221
  image.data.byteLength > IMAGE_MAX_BYTES)
222
- throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Referenced image is invalid or unsupported.');
222
+ throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Referenced image is invalid or unsupported.');
223
223
  return { mimeType: image.mimeType, data: Buffer.from(image.data) };
224
224
  }
225
225
  async function readJsonResponse(response, signal) {
226
226
  const contentLength = Number(response.headers.get('content-length'));
227
227
  if (Number.isFinite(contentLength) && contentLength > RESPONSE_MAX_BYTES) {
228
228
  await response.body?.cancel().catch(() => undefined);
229
- throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Image response exceeded the size limit.');
229
+ throw new AgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Image response exceeded the size limit.');
230
230
  }
231
231
  if (response.body === null)
232
232
  return {};
@@ -238,7 +238,7 @@ async function readJsonResponse(response, signal) {
238
238
  };
239
239
  readSignal.addEventListener('abort', abort, { once: true });
240
240
  const onIdle = () => {
241
- readController.abort(new MarAgentError('MAR_AGENT_IMAGE_GENERATION_READ_TIMEOUT', 'Image response body read timed out waiting for data.', {
241
+ readController.abort(new AgentError('MAR_AGENT_IMAGE_GENERATION_READ_TIMEOUT', 'Image response body read timed out waiting for data.', {
242
242
  details: {
243
243
  reason: 'IMAGE_RESPONSE_READ_TIMEOUT',
244
244
  idleTimeoutMs: IMAGE_GENERATION_READ_IDLE_TIMEOUT_MS
@@ -261,7 +261,7 @@ async function readJsonResponse(response, signal) {
261
261
  readTimeout = setTimeout(onIdle, IMAGE_GENERATION_READ_IDLE_TIMEOUT_MS);
262
262
  bytes += chunk.value.byteLength;
263
263
  if (bytes > RESPONSE_MAX_BYTES)
264
- throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Image response exceeded the size limit.');
264
+ throw new AgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Image response exceeded the size limit.');
265
265
  chunks.push(chunk.value);
266
266
  }
267
267
  }
@@ -278,7 +278,7 @@ async function readJsonResponse(response, signal) {
278
278
  return JSON.parse(Buffer.concat(chunks, bytes).toString('utf8'));
279
279
  }
280
280
  catch (cause) {
281
- throw new MarAgentError('MAR_AGENT_IMAGE_GENERATION_RESPONSE_INVALID', 'Image response is invalid.', { cause });
281
+ throw new AgentError('MAR_AGENT_IMAGE_GENERATION_RESPONSE_INVALID', 'Image response is invalid.', { cause });
282
282
  }
283
283
  }
284
284
  async function waitForImageStep(operation, signal) {
@@ -307,18 +307,18 @@ function imageBase64(value) {
307
307
  ? data[0].b64_json
308
308
  : undefined;
309
309
  if (typeof first !== 'string' || first.length === 0 || first.length > RESPONSE_MAX_BYTES)
310
- throw new MarAgentError('MAR_AGENT_IMAGE_GENERATION_RESPONSE_INVALID', 'Image response is invalid.');
310
+ throw new AgentError('MAR_AGENT_IMAGE_GENERATION_RESPONSE_INVALID', 'Image response is invalid.');
311
311
  return first;
312
312
  }
313
313
  function decodePng(encoded) {
314
314
  if (encoded.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/u.test(encoded))
315
- throw new MarAgentError('MAR_AGENT_IMAGE_GENERATION_RESPONSE_INVALID', 'Image response is invalid.');
315
+ throw new AgentError('MAR_AGENT_IMAGE_GENERATION_RESPONSE_INVALID', 'Image response is invalid.');
316
316
  const data = Buffer.from(encoded, 'base64');
317
317
  if (data.byteLength === 0 ||
318
318
  data.byteLength > IMAGE_MAX_BYTES ||
319
319
  data.toString('base64') !== encoded ||
320
320
  !data.subarray(0, PNG_SIGNATURE.length).equals(PNG_SIGNATURE))
321
- throw new MarAgentError('MAR_AGENT_IMAGE_GENERATION_RESPONSE_INVALID', 'Image response is not a supported PNG.');
321
+ throw new AgentError('MAR_AGENT_IMAGE_GENERATION_RESPONSE_INVALID', 'Image response is not a supported PNG.');
322
322
  return data;
323
323
  }
324
324
  function generatedFileName(callId) {
@@ -349,8 +349,8 @@ function imageGenerationResponseError(status, value) {
349
349
  !/\b(?:authorization|bearer|api[_ -]?key|access[_ -]?token|refresh[_ -]?token|password|secret|proxy-authorization|chatgpt-account-id)\b|socks5:\/\//iu.test(rawMessage)
350
350
  ? rawMessage
351
351
  : fallbackMessage;
352
- return new MarAgentError(code, message, { details: { status } });
352
+ return new AgentError(code, message, { details: { status } });
353
353
  }
354
354
  function invalidInput() {
355
- throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Image generation input is invalid.');
355
+ throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Image generation input is invalid.');
356
356
  }
@@ -6,7 +6,7 @@ import { marctlExecutionEnvironment, marctlHostSkill } from './marctl-skill.js';
6
6
  import { createHash, randomUUID } from 'node:crypto';
7
7
  import { homedir } from 'node:os';
8
8
  import { nodeLog } from '../../operational.js';
9
- import { createMarAgent, generateSessionTitle } from '@myagentroam/agent';
9
+ import { createAgent, generateSessionTitle } from '@myagentroam/agent';
10
10
  import { marAgentReasoningEffortSchema, resolveMarAgentDefaultReasoningEffort } from '@myagentroam/protocol';
11
11
  import { boundedConversationItemId } from '../../util/node-operation-parsers.js';
12
12
  import { parseSecretEnvironment } from '../../util/secret-environment.js';
@@ -43,7 +43,7 @@ export class MarAgentManagedRunController {
43
43
  ...(options.retainEnvironment === undefined
44
44
  ? {}
45
45
  : { retainEnvironment: options.retainEnvironment }),
46
- createAgent: options.createAgent ?? createMarAgent,
46
+ createAgent: options.createAgent ?? createAgent,
47
47
  modelFactory: options.modelFactory ??
48
48
  new MarAgentRuntimeModelFactory({
49
49
  resolve: async () => {
@@ -4,7 +4,8 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
4
4
  import { getDefaultEnvironment, StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
5
5
  import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
6
6
  import { ToolListChangedNotificationSchema } from '@modelcontextprotocol/sdk/types.js';
7
- import { assertMcpToolDefinition, assertMcpToolCatalog, MarAgentError } from '@myagentroam/agent';
7
+ import { assertMcpToolDefinition, assertMcpToolCatalog } from '@myagentroam/agent/host';
8
+ import { AgentError } from '@myagentroam/agent';
8
9
  import { canonicalJson } from '../../util/canonical-json.js';
9
10
  import { ExecutorStdioClientTransport } from './executor-stdio-client-transport.js';
10
11
  export class MarAgentMcpClientCache {
@@ -175,11 +176,11 @@ export class MarAgentMcpClientPool {
175
176
  async call(name, arguments_, signal, expectedTool) {
176
177
  const binding = this.#tools.get(name);
177
178
  if (!binding || this.#closed)
178
- throw new MarAgentError('MAR_AGENT_MCP_TOOL_NOT_FOUND', 'MCP tool is no longer available.');
179
+ throw new AgentError('MAR_AGENT_MCP_TOOL_NOT_FOUND', 'MCP tool is no longer available.');
179
180
  if (expectedTool &&
180
181
  (binding.metadata.sourceIdentity !== expectedTool.sourceIdentity ||
181
182
  binding.metadata.definitionRevision !== expectedTool.definitionRevision))
182
- throw new MarAgentError('MAR_AGENT_MCP_TOOL_DEFINITION_CHANGED', 'MCP tool binding or definition changed.');
183
+ throw new AgentError('MAR_AGENT_MCP_TOOL_DEFINITION_CHANGED', 'MCP tool binding or definition changed.');
183
184
  signal?.throwIfAborted();
184
185
  const result = await binding.client.callTool({
185
186
  name: binding.nativeName,
@@ -1,4 +1,4 @@
1
- import { MarAgentError, SecretValue } from '@myagentroam/agent';
1
+ import { AgentError, SecretValue } from '@myagentroam/agent';
2
2
  import { marAgentRuntimeModelConfigurationSchema, resolveMarAgentDefaultReasoningEffort } from '@myagentroam/protocol';
3
3
  export function sdkModelConfigurations(models) {
4
4
  return models.map(({ imageGeneration: _imageGeneration, ...model }) => model);
@@ -84,6 +84,9 @@ export class MarAgentRuntimeModelFactory {
84
84
  responsesOptionalParameters: configuration.responsesOptionalParameters
85
85
  }),
86
86
  responsesPreviousResponseId: configuration.responsesPreviousResponseId,
87
+ ...(configuration.responsesConfigurationUpdates === undefined
88
+ ? {}
89
+ : { responsesConfigurationUpdates: configuration.responsesConfigurationUpdates }),
87
90
  enabled: configuration.enabled
88
91
  };
89
92
  const { apiKey, credential } = configuration;
@@ -95,11 +98,11 @@ export class MarAgentRuntimeModelFactory {
95
98
  apiKey: new SecretValue(credential.value)
96
99
  };
97
100
  if (credential?.type !== 'RUNTIME_TICKET')
98
- throw new MarAgentError('MAR_AGENT_RUNTIME_MODEL_CREDENTIAL_INVALID', 'The runtime model credential is invalid.');
101
+ throw new AgentError('MAR_AGENT_RUNTIME_MODEL_CREDENTIAL_INVALID', 'The runtime model credential is invalid.');
99
102
  if (context.runtimeScopeId === undefined ||
100
103
  context.runtimeScopeId !== credential.ticket.runtimeScopeId ||
101
104
  !credential.ticket.allowedModelIds.includes(configuration.id))
102
- throw new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_SCOPE_INVALID', 'The runtime credential does not authorize this execution or model.');
105
+ throw new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_SCOPE_INVALID', 'The runtime credential does not authorize this execution or model.');
103
106
  const provider = runtimeProvider(credential, configuration.id, context, tickets, providers, this.control, this.now);
104
107
  return {
105
108
  ...model,
@@ -117,7 +120,6 @@ export class MarAgentRuntimeModelFactory {
117
120
  }
118
121
  }
119
122
  : {}),
120
- responsesConfigurationUpdates: configuration.responsesConfigurationUpdates === true,
121
123
  credentialProvider: provider
122
124
  };
123
125
  });
@@ -141,7 +143,7 @@ function runtimeProvider(credential, consumerId, context, tickets, providers, co
141
143
  if (context.runtimeScopeId === undefined ||
142
144
  context.runtimeScopeId !== credential.ticket.runtimeScopeId ||
143
145
  !credential.ticket.allowedModelIds.includes(consumerId))
144
- throw new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_SCOPE_INVALID', 'The runtime credential does not authorize this execution or model.');
146
+ throw new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_SCOPE_INVALID', 'The runtime credential does not authorize this execution or model.');
145
147
  const key = `${credential.credentialId}\0${credential.ticket.runtimeScopeId}\0${credential.ticket.purpose ?? 'MODEL'}`;
146
148
  let state = tickets.get(key);
147
149
  if (state === undefined) {
@@ -153,7 +155,7 @@ function runtimeProvider(credential, consumerId, context, tickets, providers, co
153
155
  tickets.set(key, state);
154
156
  }
155
157
  else if (!sameRuntimeCredentialTicket(state.ticket, credential.ticket))
156
- throw new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_SCOPE_INVALID', 'The runtime credential does not authorize this execution or model.');
158
+ throw new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_SCOPE_INVALID', 'The runtime credential does not authorize this execution or model.');
157
159
  const provider = new ServerRuntimeCredentialProvider(control, state, consumerId, context.runtimeScopeId, context.executionId, now);
158
160
  providers.push(provider);
159
161
  return provider;
@@ -179,7 +181,7 @@ class ServerRuntimeCredentialProvider {
179
181
  }
180
182
  async acquire(reason) {
181
183
  if (this.#closed || this.state.released)
182
- throw new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_PROVIDER_CLOSED', 'The runtime credential provider is closed.');
184
+ throw new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_PROVIDER_CLOSED', 'The runtime credential provider is closed.');
183
185
  if (isReusableCredential(this.state.credential, this.now())) {
184
186
  if (isWithinRefreshWindow(this.state.ticket.expiresAt, this.now()))
185
187
  this.refreshAutomatically();
@@ -264,9 +266,9 @@ class ServerRuntimeCredentialProvider {
264
266
  reason
265
267
  }, signal);
266
268
  if (this.state.released)
267
- throw new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_PROVIDER_CLOSED', 'The runtime credential provider is closed.');
269
+ throw new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_PROVIDER_CLOSED', 'The runtime credential provider is closed.');
268
270
  if ('error' in response)
269
- throw new MarAgentError(response.error.code, response.error.message);
271
+ throw new AgentError(response.error.code, response.error.message);
270
272
  this.state.ticket = response.nextTicket;
271
273
  const credential = {
272
274
  revision: response.credential.revision,
@@ -333,11 +335,11 @@ function clearRefreshTimer(state) {
333
335
  }
334
336
  function waitForCredential(pending, signal) {
335
337
  if (signal.aborted)
336
- return Promise.reject(new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_PROVIDER_CLOSED', 'The runtime credential provider is closed.'));
338
+ return Promise.reject(new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_PROVIDER_CLOSED', 'The runtime credential provider is closed.'));
337
339
  return new Promise((resolve, reject) => {
338
340
  const abort = () => {
339
341
  cleanup();
340
- reject(new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_PROVIDER_CLOSED', 'The runtime credential provider is closed.'));
342
+ reject(new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_PROVIDER_CLOSED', 'The runtime credential provider is closed.'));
341
343
  };
342
344
  const cleanup = () => signal.removeEventListener('abort', abort);
343
345
  signal.addEventListener('abort', abort, { once: true });
@@ -1,7 +1,7 @@
1
1
  import { createHash, randomUUID } from 'node:crypto';
2
2
  import { homedir } from 'node:os';
3
3
  import { access, constants } from 'node:fs/promises';
4
- import { LocalAgentHost } from '@myagentroam/agent';
4
+ import { LocalAgentHost } from '@myagentroam/agent/host';
5
5
  import { marAgentRuntimeCompactConfigurationSchema } from '@myagentroam/protocol';
6
6
  import { nodeExecutionEnvironment } from '../../node-execution-environment.js';
7
7
  import { nodeLog } from '../../operational.js';
@@ -73,7 +73,7 @@ export async function createSessionRuntime(input, sessionKey, fingerprint, hostC
73
73
  host: localHost,
74
74
  models: sdkModelConfigurations(models.filter((model) => input.models.some((candidate) => candidate.id === model.id))),
75
75
  defaultModelId: input.model.id,
76
- runtimeExtensions: marAgentCompactExtensionSource(compactState),
76
+ extensions: marAgentCompactExtensionSource(compactState),
77
77
  ...(input.personalInstructions ? { systemInstruction: input.personalInstructions } : {})
78
78
  });
79
79
  const customTitle = dependencies.customTitle(input.sessionId) ?? undefined;
@@ -1,4 +1,4 @@
1
- import { MarAgentError } from '@myagentroam/agent';
1
+ import { AgentError } from '@myagentroam/agent';
2
2
  import { WEB_FETCH_MAX_URL_LENGTH, webFetchRequestSchema, webSearchRequestSchema } from '../../service/web-fetch-contracts.js';
3
3
  export const webSearchToolDefinition = {
4
4
  name: 'web_search',
@@ -49,13 +49,13 @@ export function createWebToolsExtensions(input) {
49
49
  isToolAvailable,
50
50
  executeTool: async (call, context) => {
51
51
  if (!isToolAvailable(call.name, context))
52
- throw new MarAgentError('MAR_AGENT_TOOL_NOT_AVAILABLE', 'Node web tool is unavailable.');
52
+ throw new AgentError('MAR_AGENT_TOOL_NOT_AVAILABLE', 'Node web tool is unavailable.');
53
53
  context.signal.throwIfAborted();
54
54
  const parsed = call.name === 'web_search'
55
55
  ? webSearchRequestSchema.safeParse(call.arguments)
56
56
  : webFetchRequestSchema.safeParse(call.arguments);
57
57
  if (!parsed.success)
58
- throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Node web tool input is invalid.');
58
+ throw new AgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Node web tool input is invalid.');
59
59
  try {
60
60
  if (call.name === 'web_search')
61
61
  return await input.webSearch(webSearchRequestSchema.parse(parsed.data), context.signal);
@@ -63,9 +63,9 @@ export function createWebToolsExtensions(input) {
63
63
  return await input.webFetch({ ...request, url: new URL(request.url).href }, context.signal);
64
64
  }
65
65
  catch (error) {
66
- if (context.signal.aborted || error instanceof MarAgentError)
66
+ if (context.signal.aborted || error instanceof AgentError)
67
67
  throw error;
68
- throw new MarAgentError(call.name === 'web_search' ? 'MAR_AGENT_WEB_SEARCH_FAILED' : 'MAR_AGENT_WEB_FETCH_FAILED', call.name === 'web_search' ? 'Web search failed.' : 'Web fetch failed.', { cause: error });
68
+ throw new AgentError(call.name === 'web_search' ? 'MAR_AGENT_WEB_SEARCH_FAILED' : 'MAR_AGENT_WEB_FETCH_FAILED', call.name === 'web_search' ? 'Web search failed.' : 'Web fetch failed.', { cause: error });
69
69
  }
70
70
  }
71
71
  };
@@ -1,7 +1,7 @@
1
1
  import { marAgentNodeModelSummarySchema, parseComposerTags, resolveMarAgentDefaultReasoningEffort, serializeComposerTag } from '@myagentroam/protocol';
2
2
  import { nodeLog } from '../operational.js';
3
3
  import { runnerErrorProjection } from '../util/runner-error.js';
4
- import { MarAgentError, openMarAgentSessionCatalog } from '@myagentroam/agent';
4
+ import { AgentError, openAgentSessionCatalog } from '@myagentroam/agent';
5
5
  import { homedir } from 'node:os';
6
6
  import { resolve } from 'node:path';
7
7
  import { AbstractRunner } from './abstract-runner.js';
@@ -94,7 +94,7 @@ export class MarAgentRunner extends AbstractRunner {
94
94
  async readToolResultResource(session, input) {
95
95
  if (!session.externalSessionId)
96
96
  throw new Error('SESSION_NOT_FOUND');
97
- const catalog = await openMarAgentSessionCatalog({ homeDirectory: this.homeDirectory });
97
+ const catalog = await openAgentSessionCatalog({ homeDirectory: this.homeDirectory });
98
98
  try {
99
99
  return await catalog.readToolResultResource(session.externalSessionId, {
100
100
  resourceRef: input.resourceRef,
@@ -268,7 +268,7 @@ export class MarAgentRunner extends AbstractRunner {
268
268
  async discoverSessions(context, workspace) {
269
269
  let catalog;
270
270
  try {
271
- catalog = await openMarAgentSessionCatalog({ homeDirectory: this.homeDirectory });
271
+ catalog = await openAgentSessionCatalog({ homeDirectory: this.homeDirectory });
272
272
  const activeCatalog = catalog;
273
273
  const listed = await activeCatalog.list({ limit: 200 });
274
274
  if (context.cleanup) {
@@ -336,13 +336,13 @@ export class MarAgentRunner extends AbstractRunner {
336
336
  async forkNative(session, boundary, title) {
337
337
  if (session.externalSessionId === null)
338
338
  throw new Error('SESSION_REWIND_UNAVAILABLE');
339
- const catalog = await openMarAgentSessionCatalog({ homeDirectory: this.homeDirectory });
339
+ const catalog = await openAgentSessionCatalog({ homeDirectory: this.homeDirectory });
340
340
  try {
341
341
  return (await catalog.fork(session.externalSessionId, { boundaryTurnId: boundary, title }))
342
342
  .id;
343
343
  }
344
344
  catch (error) {
345
- if (error instanceof MarAgentError)
345
+ if (error instanceof AgentError)
346
346
  throw new Error(error.code, { cause: error });
347
347
  throw error;
348
348
  }
@@ -354,7 +354,7 @@ export class MarAgentRunner extends AbstractRunner {
354
354
  if (session.externalSessionId === null)
355
355
  throw new Error('SESSION_ROLLBACK_UNAVAILABLE');
356
356
  await this.#releaseSessionResources?.(session.externalSessionId);
357
- const catalog = await openMarAgentSessionCatalog({ homeDirectory: this.homeDirectory });
357
+ const catalog = await openAgentSessionCatalog({ homeDirectory: this.homeDirectory });
358
358
  try {
359
359
  if (targetClientMessageId !== undefined && targetTurnBoundary === undefined)
360
360
  throw new Error('SESSION_ROLLBACK_TARGET_INVALID');
@@ -366,7 +366,7 @@ export class MarAgentRunner extends AbstractRunner {
366
366
  return Date.parse(rolledBack.lastActivityAt);
367
367
  }
368
368
  catch (error) {
369
- if (error instanceof MarAgentError)
369
+ if (error instanceof AgentError)
370
370
  throw new Error(error.code, { cause: error });
371
371
  throw error;
372
372
  }
@@ -381,12 +381,12 @@ export class MarAgentRunner extends AbstractRunner {
381
381
  if (session.externalSessionId === null)
382
382
  throw new Error('SESSION_CLEAR_UNAVAILABLE');
383
383
  await this.#releaseSessionResources?.(session.externalSessionId);
384
- const catalog = await openMarAgentSessionCatalog({ homeDirectory: this.homeDirectory });
384
+ const catalog = await openAgentSessionCatalog({ homeDirectory: this.homeDirectory });
385
385
  try {
386
386
  return Date.parse((await catalog.clear(session.externalSessionId)).lastActivityAt);
387
387
  }
388
388
  catch (error) {
389
- if (error instanceof MarAgentError)
389
+ if (error instanceof AgentError)
390
390
  throw new Error(error.code, { cause: error });
391
391
  throw error;
392
392
  }
@@ -398,7 +398,7 @@ export class MarAgentRunner extends AbstractRunner {
398
398
  if (session.runner !== this.name || session.externalSessionId !== nativeSessionId)
399
399
  return false;
400
400
  await this.#releaseSessionResources?.(nativeSessionId);
401
- const catalog = await openMarAgentSessionCatalog({ homeDirectory: this.homeDirectory });
401
+ const catalog = await openAgentSessionCatalog({ homeDirectory: this.homeDirectory });
402
402
  try {
403
403
  return (await catalog.delete(nativeSessionId)).deleted ? true : 'MISSING';
404
404
  }
@@ -409,7 +409,7 @@ export class MarAgentRunner extends AbstractRunner {
409
409
  async readManagedRunnerTitle(session, nativeSessionId) {
410
410
  if (session.runner !== this.name || session.externalSessionId !== nativeSessionId)
411
411
  return undefined;
412
- const catalog = await openMarAgentSessionCatalog({ homeDirectory: this.homeDirectory });
412
+ const catalog = await openAgentSessionCatalog({ homeDirectory: this.homeDirectory });
413
413
  try {
414
414
  let cursor;
415
415
  do {
@@ -426,7 +426,7 @@ export class MarAgentRunner extends AbstractRunner {
426
426
  }
427
427
  }
428
428
  async restartInputState(sessionId, clientMessageId) {
429
- const catalog = await openMarAgentSessionCatalog({ homeDirectory: this.homeDirectory });
429
+ const catalog = await openAgentSessionCatalog({ homeDirectory: this.homeDirectory });
430
430
  try {
431
431
  let cursor;
432
432
  const states = new Map();
@@ -460,7 +460,7 @@ export class MarAgentRunner extends AbstractRunner {
460
460
  async readOfficialConversation(session, input) {
461
461
  if (session.externalSessionId === null)
462
462
  return undefined;
463
- const catalog = await openMarAgentSessionCatalog({ homeDirectory: this.homeDirectory });
463
+ const catalog = await openAgentSessionCatalog({ homeDirectory: this.homeDirectory });
464
464
  try {
465
465
  const limit = input.limit ?? 10;
466
466
  let cursor = input.cursor;
@@ -524,7 +524,7 @@ export class MarAgentRunner extends AbstractRunner {
524
524
  return undefined;
525
525
  let catalog;
526
526
  try {
527
- catalog = await openMarAgentSessionCatalog({ homeDirectory: this.homeDirectory });
527
+ catalog = await openAgentSessionCatalog({ homeDirectory: this.homeDirectory });
528
528
  const usage = await catalog.contextUsage(session.externalSessionId);
529
529
  return usage === undefined
530
530
  ? undefined
@@ -545,7 +545,7 @@ export class MarAgentRunner extends AbstractRunner {
545
545
  async #readInputImage(sessionId, sequence, imageIndex, expected) {
546
546
  let catalog;
547
547
  try {
548
- catalog = await openMarAgentSessionCatalog({ homeDirectory: this.homeDirectory });
548
+ catalog = await openAgentSessionCatalog({ homeDirectory: this.homeDirectory });
549
549
  const image = await catalog.readImage(sessionId, { sequence, imageIndex });
550
550
  if (image === undefined ||
551
551
  image.name !== expected.name ||
@@ -1,11 +1,11 @@
1
1
  import { LINUX_BUBBLEWRAP_SANDBOX_POLICY_VERSION } from '@myagentroam/agent/sandbox/linux';
2
- import { MarAgentError } from '@myagentroam/agent';
2
+ import { AgentError } from '@myagentroam/agent';
3
3
  import { posix } from 'node:path';
4
4
  /** Compiles Node-owned hosted-conversation directories into the generic Agent sandbox profile. */
5
5
  export function hostedConversationSandboxProfile(input) {
6
6
  if ((input.generatedImagesDirectory === undefined) !==
7
7
  (input.generatedImagesLogicalPath === undefined))
8
- throw new MarAgentError('SANDBOX_POLICY_INVALID', 'Sandbox policy is invalid.');
8
+ throw new AgentError('SANDBOX_POLICY_INVALID', 'Sandbox policy is invalid.');
9
9
  const mounts = [
10
10
  {
11
11
  source: input.workspaceDirectory,
@@ -1,4 +1,4 @@
1
- import { testMarAgentModelTransport } from '@myagentroam/agent';
1
+ import { testAgentModelTransport } from '@myagentroam/agent';
2
2
  import { marAgentModelTransportTestInputSchema, marAgentModelTransportTestResultSchema } from '@myagentroam/protocol';
3
3
  import { runnerErrorProjection } from '../util/runner-error.js';
4
4
  export class MarAgentModelTransportTestService {
@@ -24,7 +24,7 @@ export class MarAgentModelTransportTestService {
24
24
  if (configuration === undefined)
25
25
  throw new Error('MAR_AGENT_MODEL_TEST_INPUT_INVALID');
26
26
  try {
27
- const completed = await (this.options.testTransport ?? testMarAgentModelTransport)(configuration, AbortSignal.timeout(this.#timeoutMs));
27
+ const { completed } = await (this.options.testTransport ?? testAgentModelTransport)(configuration, AbortSignal.timeout(this.#timeoutMs));
28
28
  return marAgentModelTransportTestResultSchema.parse(completed
29
29
  ? { success: true, code: null, message: null, httpStatus: null }
30
30
  : {
@@ -1,7 +1,7 @@
1
1
  import { createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from 'node:crypto';
2
2
  import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
- import { MarAgentError, openMarAgentSessionCatalog } from '@myagentroam/agent';
4
+ import { AgentError, openAgentSessionCatalog } from '@myagentroam/agent';
5
5
  import { modelResourceReadInputSchema } from '@myagentroam/protocol';
6
6
  const TTL_MS = 24 * 60 * 60_000;
7
7
  /** Only capability metadata lives here. The SDK owns the sole immutable image file. */
@@ -88,14 +88,14 @@ export class ModelResourcePublicationService {
88
88
  record.expiresAt !== input.expiresAt ||
89
89
  this.identity(record.source, record.resourceId) !== this.identity(source, input.resourceId))
90
90
  return undefined;
91
- const catalog = await openMarAgentSessionCatalog({
91
+ const catalog = await openAgentSessionCatalog({
92
92
  homeDirectory: record.source.homeDirectory
93
93
  });
94
94
  try {
95
95
  return await catalog.readResource(record.source.sessionId, record.resourceId);
96
96
  }
97
97
  catch (error) {
98
- if (error instanceof MarAgentError && error.code === 'MAR_AGENT_SESSION_NOT_FOUND')
98
+ if (error instanceof AgentError && error.code === 'MAR_AGENT_SESSION_NOT_FOUND')
99
99
  return undefined;
100
100
  throw error;
101
101
  }
@@ -1,4 +1,4 @@
1
- import { countModelTokens, generateModelText, marAgentReasoningEffortSchema } from '@myagentroam/agent';
1
+ import { countModelTokens, generateModelText, agentReasoningEffortSchema } from '@myagentroam/agent';
2
2
  const MAX_INPUT_TOKENS = 12_288;
3
3
  const MAX_OUTPUT_TOKENS = 2_048;
4
4
  const INPUT_CONTEXT_RESERVE_TOKENS = 64;
@@ -296,7 +296,7 @@ function validateInput(input) {
296
296
  model.maxOutputTokens <= 0)
297
297
  throw invalidInput();
298
298
  if (input.reasoningEffort !== undefined &&
299
- !marAgentReasoningEffortSchema.safeParse(input.reasoningEffort).success)
299
+ !agentReasoningEffortSchema.safeParse(input.reasoningEffort).success)
300
300
  throw invalidInput();
301
301
  if (!Array.isArray(input.history) ||
302
302
  !Array.isArray(input.referenceMessages) ||
@@ -1,4 +1,4 @@
1
- import { MarAgentError } from '@myagentroam/agent';
1
+ import { AgentError } from '@myagentroam/agent';
2
2
  import { createEnvelope, runtimeCredentialResolveRequestSchema, runtimeCredentialResolveResponseSchema } from '@myagentroam/protocol';
3
3
  const DEFAULT_TIMEOUT_MS = 15_000;
4
4
  /** Correlates the closed runtime-credential exchange on the authenticated control connection. */
@@ -33,7 +33,7 @@ export class RuntimeCredentialControlService {
33
33
  return true;
34
34
  const parsed = runtimeCredentialResolveResponseSchema.safeParse(envelope.payload);
35
35
  if (!parsed.success) {
36
- pending.reject(new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_RESPONSE_INVALID', 'The runtime credential response is invalid.'));
36
+ pending.reject(new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_RESPONSE_INVALID', 'The runtime credential response is invalid.'));
37
37
  return true;
38
38
  }
39
39
  pending.resolve(parsed.data);
@@ -41,9 +41,9 @@ export class RuntimeCredentialControlService {
41
41
  }
42
42
  resolve(request, signal) {
43
43
  if (this.#closed)
44
- return Promise.reject(new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_CONTROL_CLOSED', 'The runtime credential control service is closed.'));
44
+ return Promise.reject(new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_CONTROL_CLOSED', 'The runtime credential control service is closed.'));
45
45
  if (!this.#connected)
46
- return Promise.reject(new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_CONNECTION_INVALID', 'The runtime credential control connection is unavailable.'));
46
+ return Promise.reject(new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_CONNECTION_INVALID', 'The runtime credential control connection is unavailable.'));
47
47
  const parsed = runtimeCredentialResolveRequestSchema.parse(request);
48
48
  const envelope = createEnvelope('credential.resolve', parsed);
49
49
  const generation = this.#generation;
@@ -57,8 +57,8 @@ export class RuntimeCredentialControlService {
57
57
  pending.cleanup();
58
58
  action(value);
59
59
  };
60
- const abort = () => settle((error) => reject(error), new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_PROVIDER_CLOSED', 'The runtime credential provider is closed.'));
61
- const timer = setTimeout(() => settle((error) => reject(error), new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_REQUEST_TIMEOUT', 'The runtime credential request timed out.')), this.#timeoutMs);
60
+ const abort = () => settle((error) => reject(error), new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_PROVIDER_CLOSED', 'The runtime credential provider is closed.'));
61
+ const timer = setTimeout(() => settle((error) => reject(error), new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_REQUEST_TIMEOUT', 'The runtime credential request timed out.')), this.#timeoutMs);
62
62
  timer.unref();
63
63
  this.#pending.set(envelope.id, {
64
64
  generation,
@@ -75,7 +75,7 @@ export class RuntimeCredentialControlService {
75
75
  this.options.send(envelope);
76
76
  }
77
77
  catch (error) {
78
- settle((cause) => reject(cause), new MarAgentError('MAR_AGENT_RUNTIME_CREDENTIAL_REQUEST_SEND_FAILED', 'The runtime credential request could not be sent.', { cause: error }));
78
+ settle((cause) => reject(cause), new AgentError('MAR_AGENT_RUNTIME_CREDENTIAL_REQUEST_SEND_FAILED', 'The runtime credential request could not be sent.', { cause: error }));
79
79
  }
80
80
  });
81
81
  }
@@ -89,6 +89,6 @@ export class RuntimeCredentialControlService {
89
89
  }
90
90
  #rejectPending(code) {
91
91
  for (const pending of [...this.#pending.values()])
92
- pending.reject(new MarAgentError(code, 'The runtime credential control connection is no longer valid.'));
92
+ pending.reject(new AgentError(code, 'The runtime credential control connection is no longer valid.'));
93
93
  }
94
94
  }
@@ -4,13 +4,13 @@ import { TLSSocket } from 'node:tls';
4
4
  import { createBrotliDecompress, createGunzip, createInflate } from 'node:zlib';
5
5
  import { pipeline } from 'node:stream/promises';
6
6
  import { setTimeout as delay } from 'node:timers/promises';
7
- import { MarAgentError } from '@myagentroam/agent';
7
+ import { AgentError } from '@myagentroam/agent';
8
8
  import { chromium, errors } from 'playwright';
9
9
  import { WEB_FETCH_MAX_BYTES, webFetchRequestSchema } from './web-fetch-contracts.js';
10
10
  const TIMEOUT_MS = 30_000;
11
11
  const MAX_REDIRECTS = 5;
12
12
  const MAX_BROWSER_REQUESTS = 2;
13
- export class WebFetchError extends MarAgentError {
13
+ export class WebFetchError extends AgentError {
14
14
  code;
15
15
  status;
16
16
  publicMessage;
@@ -1,4 +1,4 @@
1
- import { MarAgentError } from '@myagentroam/agent';
1
+ import { AgentError } from '@myagentroam/agent';
2
2
  import { httpErrorResponseSchema } from '@myagentroam/protocol';
3
3
  export async function readWebSearchError(response) {
4
4
  let payload;
@@ -6,13 +6,13 @@ export async function readWebSearchError(response) {
6
6
  payload = await response.json();
7
7
  }
8
8
  catch {
9
- return new MarAgentError('MAR_AGENT_WEB_SEARCH_FAILED', 'Web search failed.', {
9
+ return new AgentError('MAR_AGENT_WEB_SEARCH_FAILED', 'Web search failed.', {
10
10
  details: { status: response.status }
11
11
  });
12
12
  }
13
13
  const parsed = httpErrorResponseSchema.safeParse(payload);
14
14
  if (!parsed.success)
15
- return new MarAgentError('MAR_AGENT_WEB_SEARCH_FAILED', 'Web search failed.', {
15
+ return new AgentError('MAR_AGENT_WEB_SEARCH_FAILED', 'Web search failed.', {
16
16
  details: { status: response.status }
17
17
  });
18
18
  const failure = parsed.data.error;
@@ -26,7 +26,7 @@ export async function readWebSearchError(response) {
26
26
  ...(failure.details === undefined ? [] : [`details: ${failure.details}`]),
27
27
  ...identifiers
28
28
  ].join('; ');
29
- return new MarAgentError(failure.code, detail.length === 0 ? failure.message : `${failure.message} (${detail})`, {
29
+ return new AgentError(failure.code, detail.length === 0 ? failure.message : `${failure.message} (${detail})`, {
30
30
  details: {
31
31
  status: response.status,
32
32
  requestId: failure.requestId,
@@ -1,4 +1,4 @@
1
- import { MarAgentError } from '@myagentroam/agent';
1
+ import { AgentError } from '@myagentroam/agent';
2
2
  import { readWebSearchError } from './web-search-error.js';
3
3
  import { WebFetchService } from './web-fetch-service.js';
4
4
  import { webFetchResultSchema } from './web-fetch-contracts.js';
@@ -21,7 +21,7 @@ export class WebToolService {
21
21
  });
22
22
  const parsed = webFetchResultSchema.safeParse(result);
23
23
  if (!parsed.success)
24
- throw new MarAgentError('MAR_AGENT_WEB_FETCH_FAILED', 'Web fetch returned an invalid result.');
24
+ throw new AgentError('MAR_AGENT_WEB_FETCH_FAILED', 'Web fetch returned an invalid result.');
25
25
  return parsed.data;
26
26
  };
27
27
  close() {
@@ -59,14 +59,14 @@ export class WebToolService {
59
59
  return { content, data: result };
60
60
  }
61
61
  catch (error) {
62
- if (error instanceof MarAgentError || signal.aborted)
62
+ if (error instanceof AgentError || signal.aborted)
63
63
  throw error;
64
- throw new MarAgentError('MAR_AGENT_WEB_SEARCH_FAILED', 'Web search failed.', {
64
+ throw new AgentError('MAR_AGENT_WEB_SEARCH_FAILED', 'Web search failed.', {
65
65
  cause: error
66
66
  });
67
67
  }
68
68
  }
69
69
  }
70
70
  function invalidResult() {
71
- return new MarAgentError('MAR_AGENT_WEB_SEARCH_FAILED', 'Web search returned an invalid result.');
71
+ return new AgentError('MAR_AGENT_WEB_SEARCH_FAILED', 'Web search returned an invalid result.');
72
72
  }
@@ -8,6 +8,7 @@ const REPOSITORY_READ_CONCURRENCY = 4;
8
8
  const WORKTREE_READ_CONCURRENCY = 4;
9
9
  const CHANGE_VISIBILITY_CONCURRENCY = 16;
10
10
  const SUBMODULE_LIMIT = 128;
11
+ const CHANGE_RESULT_LIMIT = 1000;
11
12
  export class WorkspaceChangeService {
12
13
  state;
13
14
  constructor(state) {
@@ -92,6 +93,7 @@ export class WorkspaceChangeService {
92
93
  ...(summary.tracking === undefined ? {} : { tracking: summary.tracking }),
93
94
  dirty: summary.changes.length > 0,
94
95
  status: summary.changes.length > 0 ? 'DIRTY' : 'CLEAN',
96
+ ...(summary.changesTruncated ? { changesTruncated: true } : {}),
95
97
  changes
96
98
  };
97
99
  };
@@ -190,6 +192,7 @@ export class WorkspaceChangeService {
190
192
  branch: repository.branch,
191
193
  ...(repository.tracking === undefined ? {} : { tracking: repository.tracking }),
192
194
  status: repository.dirty ? 'DIRTY' : 'CLEAN',
195
+ ...(repository.changesTruncated ? { changesTruncated: true } : {}),
193
196
  changes: repository.changes
194
197
  };
195
198
  }
@@ -229,6 +232,33 @@ export class WorkspaceChangeService {
229
232
  binary: false,
230
233
  diffAvailable: true
231
234
  });
235
+ let remainingChanges = CHANGE_RESULT_LIMIT;
236
+ const repositories = [
237
+ {
238
+ ...root,
239
+ source: 'ROOT',
240
+ physicalPath: currentWorktree?.path ?? repositoryRoot,
241
+ current: true,
242
+ ...(currentWorktree === undefined ? {} : { head: currentWorktree.head }),
243
+ status: root.dirty ? 'DIRTY' : 'CLEAN',
244
+ locked: currentWorktree?.locked ?? false,
245
+ prunable: currentWorktree?.prunable ?? false
246
+ },
247
+ ...children.map((repository) => ({ ...repository, source: 'SUBMODULE' })),
248
+ ...linkedRepositories
249
+ ].map(({ dirty: _dirty, ...repository }) => {
250
+ void _dirty;
251
+ const changes = repository.changes.slice(0, remainingChanges).map(decorate);
252
+ remainingChanges -= changes.length;
253
+ return {
254
+ ...repository,
255
+ changes,
256
+ ...(('changesTruncated' in repository && repository.changesTruncated) ||
257
+ changes.length < repository.changes.length
258
+ ? { changesTruncated: true }
259
+ : {})
260
+ };
261
+ });
232
262
  const value = {
233
263
  repositoryRoot,
234
264
  workspace: {
@@ -240,27 +270,12 @@ export class WorkspaceChangeService {
240
270
  partial: errors.length > 0 ||
241
271
  children.some((group) => group.status === 'UNAVAILABLE') ||
242
272
  linkedRepositories.some((group) => group.status === 'UNAVAILABLE') ||
243
- worktreeList.truncated,
273
+ worktreeList.truncated ||
274
+ repositories.some((group) => group.changesTruncated === true),
244
275
  ...(errors.length === 0 ? {} : { errors }),
245
276
  branch: root.branch,
246
- changes: root.changes.map(decorate),
247
- repositories: [
248
- {
249
- ...root,
250
- source: 'ROOT',
251
- physicalPath: currentWorktree?.path ?? repositoryRoot,
252
- current: true,
253
- ...(currentWorktree === undefined ? {} : { head: currentWorktree.head }),
254
- status: root.dirty ? 'DIRTY' : 'CLEAN',
255
- locked: currentWorktree?.locked ?? false,
256
- prunable: currentWorktree?.prunable ?? false
257
- },
258
- ...children.map((repository) => ({ ...repository, source: 'SUBMODULE' })),
259
- ...linkedRepositories
260
- ].map(({ dirty: _dirty, ...repository }) => {
261
- void _dirty;
262
- return { ...repository, changes: repository.changes.map(decorate) };
263
- }),
277
+ changes: repositories[0]?.changes ?? [],
278
+ repositories,
264
279
  worktrees,
265
280
  worktreesTruncated: worktreeList.truncated
266
281
  };
package/dist/workspace.js CHANGED
@@ -1400,6 +1400,8 @@ export async function readCurrentChangesSummary(workspacePath, isolateSubmoduleF
1400
1400
  return runReadOnlyGit(workspacePath, [...args, '--ignore-submodules=dirty'], options);
1401
1401
  });
1402
1402
  const records = result.text.split('\0');
1403
+ if (result.truncated)
1404
+ records.pop();
1403
1405
  const header = records.shift() ?? '';
1404
1406
  const output = [];
1405
1407
  for (let index = 0; index < records.length; index += 1) {
@@ -1434,6 +1436,7 @@ export async function readCurrentChangesSummary(workspacePath, isolateSubmoduleF
1434
1436
  branch,
1435
1437
  ...(head === undefined ? {} : { head }),
1436
1438
  ...(tracking === undefined ? {} : { tracking }),
1439
+ ...(result.truncated ? { changesTruncated: true } : {}),
1437
1440
  changes: output
1438
1441
  };
1439
1442
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/node",
3
- "version": "0.11.33",
3
+ "version": "0.11.35",
4
4
  "description": "MyAgentRoam Node runtime CLI.",
5
5
  "license": "Apache-2.0 AND GPL-2.0-or-later",
6
6
  "type": "module",
@@ -38,10 +38,10 @@
38
38
  "sharp": "0.35.5",
39
39
  "ws": "^8.21.3",
40
40
  "zod": "4.4.3",
41
- "@myagentroam/agent": "0.11.33",
42
- "@myagentroam/protocol": "0.11.33",
41
+ "@myagentroam/agent": "0.11.35",
43
42
  "@myagentroam/code-navigation": "0.11.0",
44
- "@myagentroam/marctl": "0.11.1"
43
+ "@myagentroam/marctl": "0.11.2",
44
+ "@myagentroam/protocol": "0.11.35"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/ws": "^8.18.1"