@myagentroam/agent 0.9.133 → 0.9.135

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/cli/main.js CHANGED
@@ -187,6 +187,15 @@ async function modelsCommand(home, arguments_, codexAuthFile) {
187
187
  codeMode: booleanFlag(arguments_, '--code-mode', '--no-code-mode', existing?.codeMode ?? false),
188
188
  highDensityCompaction: booleanFlag(arguments_, '--high-density-compaction', '--no-high-density-compaction', existing?.highDensityCompaction ?? false),
189
189
  ...(credential === 'codex-auth-file' && fastMode ? { fastMode: true } : {}),
190
+ ...(protocol === 'OPENAI_RESPONSES' && existing?.serviceTier !== undefined
191
+ ? {
192
+ serviceTier: hasFastModeOption
193
+ ? fastMode
194
+ ? 'priority'
195
+ : 'default'
196
+ : existing.serviceTier
197
+ }
198
+ : {}),
190
199
  hostedWebSearch: booleanFlag(arguments_, '--web-search', '--no-web-search', existing?.hostedWebSearch ?? false),
191
200
  ...(responsesTransport === undefined ? {} : { responsesTransport }),
192
201
  ...(responsesEncoding === undefined ? {} : { responsesEncoding }),
@@ -29,8 +29,10 @@ export declare function serializeModel(model: CliModelConfiguration): {
29
29
  codeMode: boolean;
30
30
  highDensityCompaction: boolean;
31
31
  fastMode?: boolean | undefined;
32
+ serviceTier?: "default" | "auto" | "flex" | "priority" | "fast" | "ultrafast" | undefined;
32
33
  hostedWebSearch: boolean;
33
34
  responsesEncoding?: "STANDARD" | "LITE" | undefined;
35
+ responsesToolNamespace?: string | undefined;
34
36
  enabled: boolean;
35
37
  } | {
36
38
  credential: {
@@ -54,7 +56,9 @@ export declare function serializeModel(model: CliModelConfiguration): {
54
56
  codeMode: boolean;
55
57
  highDensityCompaction: boolean;
56
58
  fastMode?: boolean | undefined;
59
+ serviceTier?: "default" | "auto" | "flex" | "priority" | "fast" | "ultrafast" | undefined;
57
60
  hostedWebSearch: boolean;
58
61
  responsesEncoding?: "STANDARD" | "LITE" | undefined;
62
+ responsesToolNamespace?: string | undefined;
59
63
  enabled: boolean;
60
64
  };
@@ -71,6 +71,14 @@ declare const rawModelSchema: z.ZodObject<{
71
71
  codeMode: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
72
72
  highDensityCompaction: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
73
73
  fastMode: z.ZodOptional<z.ZodBoolean>;
74
+ serviceTier: z.ZodOptional<z.ZodEnum<{
75
+ default: "default";
76
+ auto: "auto";
77
+ flex: "flex";
78
+ priority: "priority";
79
+ fast: "fast";
80
+ ultrafast: "ultrafast";
81
+ }>>;
74
82
  hostedWebSearch: z.ZodBoolean;
75
83
  responsesTransport: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
76
84
  transport: z.ZodLiteral<"HTTP">;
@@ -85,6 +93,7 @@ declare const rawModelSchema: z.ZodObject<{
85
93
  STANDARD: "STANDARD";
86
94
  LITE: "LITE";
87
95
  }>>;
96
+ responsesToolNamespace: z.ZodOptional<z.ZodString>;
88
97
  responsesPreviousResponseId: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
89
98
  enabled: z.ZodBoolean;
90
99
  }, z.core.$strict>;
@@ -51,9 +51,14 @@ const rawModelSchema = z
51
51
  codeMode: z.boolean().optional().default(false),
52
52
  highDensityCompaction: z.boolean().optional().default(false),
53
53
  fastMode: z.boolean().optional(),
54
+ serviceTier: z.enum(['auto', 'default', 'flex', 'priority', 'fast', 'ultrafast']).optional(),
54
55
  hostedWebSearch: z.boolean(),
55
56
  responsesTransport: rawResponsesTransportSchema.optional(),
56
57
  responsesEncoding: z.enum(['STANDARD', 'LITE']).optional(),
58
+ responsesToolNamespace: z
59
+ .string()
60
+ .regex(/^[a-zA-Z][a-zA-Z0-9_]{0,63}$/u)
61
+ .optional(),
57
62
  responsesPreviousResponseId: z.boolean().optional().default(false),
58
63
  enabled: z.boolean()
59
64
  })
@@ -90,8 +95,17 @@ const rawModelSchema = z
90
95
  context.addIssue({ code: 'custom', message: 'Responses transport requires Responses.' });
91
96
  if (value.protocol !== 'OPENAI_RESPONSES' && value.responsesEncoding !== undefined)
92
97
  context.addIssue({ code: 'custom', message: 'Responses encoding requires Responses.' });
98
+ if (value.responsesToolNamespace !== undefined &&
99
+ (value.protocol !== 'OPENAI_RESPONSES' || value.responsesEncoding === 'LITE'))
100
+ context.addIssue({
101
+ code: 'custom',
102
+ path: ['responsesToolNamespace'],
103
+ message: 'Tool namespaces require Standard OpenAI Responses.'
104
+ });
93
105
  if (value.protocol !== 'OPENAI_RESPONSES' && value.fastMode === true)
94
106
  context.addIssue({ code: 'custom', message: 'Fast mode requires Responses.' });
107
+ if (value.protocol !== 'OPENAI_RESPONSES' && value.serviceTier !== undefined)
108
+ context.addIssue({ code: 'custom', message: 'Service tier requires Responses.' });
95
109
  });
96
110
  export function resolveModelDefaultReasoningEffort(model) {
97
111
  const configured = marAgentReasoningEffortSchema.safeParse(model.defaultReasoningEffort);
@@ -513,7 +513,7 @@ export class OpenAiResponsesAdapter {
513
513
  const status = upstreamHttpStatus(event.status, topLevel.status, record(event.response).status, nested.status);
514
514
  const connectionLimit = this.configuration.responsesTransport?.transport === 'WEBSOCKET' &&
515
515
  isWebSocketConnectionLimitCode(code);
516
- const retryable = connectionLimit || isRetryableUpstreamOverloadCode(code);
516
+ const retryable = connectionLimit || isRetryableResponsesUpstreamError(code, message);
517
517
  throw new MarAgentError(code ?? 'MAR_AGENT_MODEL_PROTOCOL_ERROR', message ?? 'OpenAI Responses request failed.', {
518
518
  details: {
519
519
  ...(status === undefined ? {} : { status }),
@@ -852,6 +852,15 @@ function responsesRequestBody(configuration, request, messages, prefixIdentity =
852
852
  parameters: strictFunctionSchema(tool.inputSchema),
853
853
  strict: true
854
854
  });
855
+ if (configuration.responsesToolNamespace && tools.length > 0) {
856
+ const nested = tools.splice(0);
857
+ tools.push({
858
+ type: 'namespace',
859
+ name: configuration.responsesToolNamespace,
860
+ description: 'Client-side agent tools.',
861
+ tools: nested
862
+ });
863
+ }
855
864
  if (request.allowTools !== false && configuration.hostedWebSearch)
856
865
  tools.push({ type: 'web_search' });
857
866
  const toolChoice = request.toolChoice ?? 'auto';
@@ -878,7 +887,11 @@ function responsesRequestBody(configuration, request, messages, prefixIdentity =
878
887
  }
879
888
  return {
880
889
  model: configuration.modelId,
881
- ...(configuration.fastMode === true ? { service_tier: 'priority' } : {}),
890
+ ...(configuration.serviceTier !== undefined
891
+ ? { service_tier: configuration.serviceTier }
892
+ : configuration.fastMode === true
893
+ ? { service_tier: 'priority' }
894
+ : {}),
882
895
  ...(lite
883
896
  ? {
884
897
  tool_choice: toolChoice,
@@ -1306,12 +1319,21 @@ const NON_SEMANTIC_OPENAI_RESPONSES_EVENTS = new Set([
1306
1319
  'response.reasoning_summary_text.delta',
1307
1320
  'responsesapi.websocket_timing'
1308
1321
  ]);
1322
+ function isRetryableResponsesUpstreamError(code, message) {
1323
+ if (isRetryableUpstreamOverloadCode(code))
1324
+ return true;
1325
+ if (code !== 'invalid_request_error')
1326
+ return false;
1327
+ // Exact compatibility exception, not a general access/authentication retry rule.
1328
+ const summary = message?.startsWith(`${code}: `) ? message.slice(code.length + 2) : message;
1329
+ return summary === 'Unable to verify Daybreak Blue access. Please try again.';
1330
+ }
1309
1331
  export function isOpenAiResponsesRecoverableStreamError(error) {
1310
1332
  return (error instanceof MarAgentError &&
1311
1333
  error.retryable &&
1312
1334
  (error.details?.reason === OPENAI_RESPONSES_EARLY_EOF_REASON ||
1313
1335
  error.details?.reason === OPENAI_RESPONSES_WEBSOCKET_CONNECTION_LIMIT_REASON ||
1314
- isRetryableUpstreamOverloadCode(error.code)));
1336
+ isRetryableResponsesUpstreamError(error.code, error.message)));
1315
1337
  }
1316
1338
  function isWebSocketConnectionLimitCode(code) {
1317
1339
  return code?.trim().toLowerCase() === 'websocket_connection_limit_reached';
package/dist/sdk/agent.js CHANGED
@@ -1551,6 +1551,10 @@ function resolveAgentModels(configurations, requestedDefaultModelId) {
1551
1551
  throw new MarAgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Responses encoding is invalid.');
1552
1552
  if (model.fastMode === true && model.protocol !== 'OPENAI_RESPONSES')
1553
1553
  throw new MarAgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Fast mode requires Responses.');
1554
+ if (model.serviceTier !== undefined &&
1555
+ (model.protocol !== 'OPENAI_RESPONSES' ||
1556
+ !['auto', 'default', 'flex', 'priority', 'fast', 'ultrafast'].includes(model.serviceTier)))
1557
+ throw new MarAgentError('MAR_AGENT_MODEL_CONFIG_INVALID', 'Responses service tier is invalid.');
1554
1558
  if (model.credentialProvider !== undefined)
1555
1559
  credentialProviders.add(model.credentialProvider);
1556
1560
  }
@@ -156,7 +156,8 @@ export class JsonlSessionStore {
156
156
  indexDirty: false,
157
157
  dirtySessionVersions: new Map(),
158
158
  pendingPublishIds: new Set(),
159
- segments: new Map()
159
+ segments: new Map(),
160
+ executionModelReads: new Map()
160
161
  };
161
162
  }
162
163
  /** Merge dirty metadata with disk membership; only createdIds publish locally new entries. */
@@ -1213,11 +1214,15 @@ export class JsonlSessionStore {
1213
1214
  async executionConfiguration(sessionId) {
1214
1215
  this.#assertOpen();
1215
1216
  await this.#refreshIndex();
1216
- const meta = this.#shared.index.sessions.find((session) => session.id === sessionId);
1217
+ let meta = this.#shared.index.sessions.find((session) => session.id === sessionId);
1217
1218
  if (meta === undefined)
1218
1219
  throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1219
- if (meta.resume?.executionModelIndexed !== true)
1220
- await this.#ensureExecutionModelIndexed(meta);
1220
+ if (meta.resume?.executionModelIndexed !== true) {
1221
+ await this.#ensureExecutionModelIndexed(sessionId);
1222
+ meta = this.#shared.index.sessions.find((session) => session.id === sessionId);
1223
+ if (meta === undefined)
1224
+ throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1225
+ }
1221
1226
  return meta.resume?.modelId === undefined
1222
1227
  ? undefined
1223
1228
  : {
@@ -1326,22 +1331,66 @@ export class JsonlSessionStore {
1326
1331
  contextRecords: state.contextRecords
1327
1332
  };
1328
1333
  }
1329
- async #ensureExecutionModelIndexed(meta) {
1330
- try {
1331
- await this.#rebuildExecutionState(meta);
1332
- }
1333
- catch (error) {
1334
- if (!(error instanceof MarAgentError) || error.code !== 'MAR_AGENT_SESSION_NOT_FOUND')
1335
- throw error;
1336
- const resume = meta.resume;
1337
- if (resume?.version !== 1 || !Number.isSafeInteger(resume.todoRevision))
1334
+ async #ensureExecutionModelIndexed(sessionId) {
1335
+ const pending = this.#shared.executionModelReads.get(sessionId);
1336
+ if (pending !== undefined)
1337
+ return pending;
1338
+ const read = this.#backfillExecutionModel(sessionId).finally(() => {
1339
+ if (this.#shared.executionModelReads.get(sessionId) === read)
1340
+ this.#shared.executionModelReads.delete(sessionId);
1341
+ });
1342
+ this.#shared.executionModelReads.set(sessionId, read);
1343
+ return read;
1344
+ }
1345
+ async #backfillExecutionModel(sessionId) {
1346
+ for (;;) {
1347
+ const before = this.#shared.index.sessions.find((session) => session.id === sessionId);
1348
+ if (before === undefined)
1349
+ throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1350
+ if (before.resume?.executionModelIndexed === true)
1338
1351
  return;
1352
+ const nextSequence = before.nextSequence;
1353
+ const transactionId = before.storageTransactionId;
1354
+ const model = await this.#readLatestExecutionModel(sessionId);
1355
+ // Refresh can replace metadata objects while unrelated sessions are being read.
1356
+ // Merge only into the current entry, and retry if the authoritative history changed.
1357
+ await this.#refreshIndex();
1358
+ const current = this.#shared.index.sessions.find((session) => session.id === sessionId);
1359
+ if (current === undefined)
1360
+ throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
1361
+ if (current.resume?.executionModelIndexed === true)
1362
+ return;
1363
+ if (current.nextSequence !== nextSequence || current.storageTransactionId !== transactionId)
1364
+ continue;
1365
+ // A missing resume index stays incomplete (no compact boundary); execution
1366
+ // recovery will rebuild it separately instead of doing so during discovery.
1367
+ const resume = (current.resume ??= { version: 1, todoRevision: 0 });
1339
1368
  resume.executionModelIndexed = true;
1340
1369
  delete resume.modelId;
1341
1370
  delete resume.modelName;
1342
1371
  delete resume.reasoningEffort;
1372
+ if (model !== undefined)
1373
+ Object.assign(resume, model);
1343
1374
  this.#shared.index.revision++;
1344
- this.#markIndexDirty(meta.id);
1375
+ this.#markIndexDirty(sessionId);
1376
+ return;
1377
+ }
1378
+ }
1379
+ async #readLatestExecutionModel(sessionId) {
1380
+ try {
1381
+ for (const path of (await this.#segmentPaths(sessionId)).reverse())
1382
+ for await (const record of readRecordsFromTail(path)) {
1383
+ const model = executionModelFromRecord(record);
1384
+ if (model !== undefined)
1385
+ return model;
1386
+ }
1387
+ return undefined;
1388
+ }
1389
+ catch (error) {
1390
+ if (error.code === 'ENOENT' ||
1391
+ (error instanceof MarAgentError && error.code === 'MAR_AGENT_SESSION_NOT_FOUND'))
1392
+ return undefined;
1393
+ throw error;
1345
1394
  }
1346
1395
  }
1347
1396
  async delete(sessionId) {
@@ -2133,6 +2182,21 @@ async function repairSegmentTail(path) {
2133
2182
  }
2134
2183
  }
2135
2184
  async function readRecordPageFromTail(path, beforeSequence, limit) {
2185
+ const newestFirst = [];
2186
+ for await (const record of readRecordsFromTail(path)) {
2187
+ if (!(record.sequence < beforeSequence))
2188
+ continue;
2189
+ newestFirst.push(record);
2190
+ if (newestFirst.length > limit)
2191
+ break;
2192
+ }
2193
+ return {
2194
+ records: newestFirst.slice(0, limit).reverse(),
2195
+ hasEarlier: newestFirst.length > limit
2196
+ };
2197
+ }
2198
+ /** Decode complete records newest-first, releasing the file as soon as a reader stops. */
2199
+ async function* readRecordsFromTail(path) {
2136
2200
  const handle = await open(path, 'r');
2137
2201
  try {
2138
2202
  const size = (await handle.stat()).size;
@@ -2140,26 +2204,21 @@ async function readRecordPageFromTail(path, beforeSequence, limit) {
2140
2204
  let pendingLineParts = [];
2141
2205
  let invalidFinalLineMayBeIgnored = false;
2142
2206
  let inspectedFileEnd = false;
2143
- let pageComplete = false;
2144
- const newestFirst = [];
2145
- const accept = (line, allowInvalidFinalLine) => {
2207
+ const decode = (line, allowInvalidFinalLine) => {
2146
2208
  if (line.length === 0)
2147
- return;
2148
- let record;
2209
+ return undefined;
2149
2210
  try {
2150
- record = JSON.parse(line.toString('utf8'));
2211
+ return JSON.parse(line.toString('utf8'));
2151
2212
  }
2152
2213
  catch (cause) {
2153
2214
  if (allowInvalidFinalLine)
2154
- return;
2215
+ return undefined;
2155
2216
  throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Session history is corrupt.', {
2156
2217
  cause
2157
2218
  });
2158
2219
  }
2159
- if (record.sequence < beforeSequence)
2160
- newestFirst.push(record);
2161
2220
  };
2162
- while (position > 0 && newestFirst.length <= limit) {
2221
+ while (position > 0) {
2163
2222
  const start = Math.max(0, position - REVERSE_READ_CHUNK_BYTES);
2164
2223
  const chunk = Buffer.allocUnsafe(position - start);
2165
2224
  let bytesRead = 0;
@@ -2182,26 +2241,22 @@ async function readRecordPageFromTail(path, beforeSequence, limit) {
2182
2241
  const line = pendingLineParts.length === 0
2183
2242
  ? currentPart
2184
2243
  : Buffer.concat([currentPart, ...pendingLineParts]);
2185
- accept(line, invalidFinalLineMayBeIgnored);
2244
+ const record = decode(line, invalidFinalLineMayBeIgnored);
2186
2245
  invalidFinalLineMayBeIgnored = false;
2187
2246
  pendingLineParts = [];
2188
2247
  lineEnd = index;
2189
- if (newestFirst.length > limit) {
2190
- pageComplete = true;
2191
- break;
2192
- }
2248
+ if (record !== undefined)
2249
+ yield record;
2193
2250
  }
2194
- if (!pageComplete && lineEnd > 0)
2251
+ if (lineEnd > 0)
2195
2252
  pendingLineParts.unshift(Buffer.from(value.subarray(0, lineEnd)));
2196
2253
  position = start;
2197
2254
  }
2198
- if (position === 0 && newestFirst.length <= limit && pendingLineParts.length > 0)
2199
- accept(Buffer.concat(pendingLineParts), invalidFinalLineMayBeIgnored);
2200
- const hasEarlier = newestFirst.length > limit;
2201
- return {
2202
- records: newestFirst.slice(0, limit).reverse(),
2203
- hasEarlier
2204
- };
2255
+ if (pendingLineParts.length > 0) {
2256
+ const record = decode(Buffer.concat(pendingLineParts), invalidFinalLineMayBeIgnored);
2257
+ if (record !== undefined)
2258
+ yield record;
2259
+ }
2205
2260
  }
2206
2261
  finally {
2207
2262
  await handle.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/agent",
3
- "version": "0.9.133",
3
+ "version": "0.9.135",
4
4
  "description": "Embeddable MAR coding agent SDK and CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",