@myagentroam/agent 0.9.133 → 0.9.134
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.
|
@@ -31,6 +31,7 @@ export declare function serializeModel(model: CliModelConfiguration): {
|
|
|
31
31
|
fastMode?: boolean | undefined;
|
|
32
32
|
hostedWebSearch: boolean;
|
|
33
33
|
responsesEncoding?: "STANDARD" | "LITE" | undefined;
|
|
34
|
+
responsesToolNamespace?: string | undefined;
|
|
34
35
|
enabled: boolean;
|
|
35
36
|
} | {
|
|
36
37
|
credential: {
|
|
@@ -56,5 +57,6 @@ export declare function serializeModel(model: CliModelConfiguration): {
|
|
|
56
57
|
fastMode?: boolean | undefined;
|
|
57
58
|
hostedWebSearch: boolean;
|
|
58
59
|
responsesEncoding?: "STANDARD" | "LITE" | undefined;
|
|
60
|
+
responsesToolNamespace?: string | undefined;
|
|
59
61
|
enabled: boolean;
|
|
60
62
|
};
|
|
@@ -85,6 +85,7 @@ declare const rawModelSchema: z.ZodObject<{
|
|
|
85
85
|
STANDARD: "STANDARD";
|
|
86
86
|
LITE: "LITE";
|
|
87
87
|
}>>;
|
|
88
|
+
responsesToolNamespace: z.ZodOptional<z.ZodString>;
|
|
88
89
|
responsesPreviousResponseId: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
89
90
|
enabled: z.ZodBoolean;
|
|
90
91
|
}, z.core.$strict>;
|
|
@@ -54,6 +54,10 @@ const rawModelSchema = z
|
|
|
54
54
|
hostedWebSearch: z.boolean(),
|
|
55
55
|
responsesTransport: rawResponsesTransportSchema.optional(),
|
|
56
56
|
responsesEncoding: z.enum(['STANDARD', 'LITE']).optional(),
|
|
57
|
+
responsesToolNamespace: z
|
|
58
|
+
.string()
|
|
59
|
+
.regex(/^[a-zA-Z][a-zA-Z0-9_]{0,63}$/u)
|
|
60
|
+
.optional(),
|
|
57
61
|
responsesPreviousResponseId: z.boolean().optional().default(false),
|
|
58
62
|
enabled: z.boolean()
|
|
59
63
|
})
|
|
@@ -90,6 +94,13 @@ const rawModelSchema = z
|
|
|
90
94
|
context.addIssue({ code: 'custom', message: 'Responses transport requires Responses.' });
|
|
91
95
|
if (value.protocol !== 'OPENAI_RESPONSES' && value.responsesEncoding !== undefined)
|
|
92
96
|
context.addIssue({ code: 'custom', message: 'Responses encoding requires Responses.' });
|
|
97
|
+
if (value.responsesToolNamespace !== undefined &&
|
|
98
|
+
(value.protocol !== 'OPENAI_RESPONSES' || value.responsesEncoding === 'LITE'))
|
|
99
|
+
context.addIssue({
|
|
100
|
+
code: 'custom',
|
|
101
|
+
path: ['responsesToolNamespace'],
|
|
102
|
+
message: 'Tool namespaces require Standard OpenAI Responses.'
|
|
103
|
+
});
|
|
93
104
|
if (value.protocol !== 'OPENAI_RESPONSES' && value.fastMode === true)
|
|
94
105
|
context.addIssue({ code: 'custom', message: 'Fast mode requires Responses.' });
|
|
95
106
|
});
|
|
@@ -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 ||
|
|
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';
|
|
@@ -1306,12 +1315,21 @@ const NON_SEMANTIC_OPENAI_RESPONSES_EVENTS = new Set([
|
|
|
1306
1315
|
'response.reasoning_summary_text.delta',
|
|
1307
1316
|
'responsesapi.websocket_timing'
|
|
1308
1317
|
]);
|
|
1318
|
+
function isRetryableResponsesUpstreamError(code, message) {
|
|
1319
|
+
if (isRetryableUpstreamOverloadCode(code))
|
|
1320
|
+
return true;
|
|
1321
|
+
if (code !== 'invalid_request_error')
|
|
1322
|
+
return false;
|
|
1323
|
+
// Exact compatibility exception, not a general access/authentication retry rule.
|
|
1324
|
+
const summary = message?.startsWith(`${code}: `) ? message.slice(code.length + 2) : message;
|
|
1325
|
+
return summary === 'Unable to verify Daybreak Blue access. Please try again.';
|
|
1326
|
+
}
|
|
1309
1327
|
export function isOpenAiResponsesRecoverableStreamError(error) {
|
|
1310
1328
|
return (error instanceof MarAgentError &&
|
|
1311
1329
|
error.retryable &&
|
|
1312
1330
|
(error.details?.reason === OPENAI_RESPONSES_EARLY_EOF_REASON ||
|
|
1313
1331
|
error.details?.reason === OPENAI_RESPONSES_WEBSOCKET_CONNECTION_LIMIT_REASON ||
|
|
1314
|
-
|
|
1332
|
+
isRetryableResponsesUpstreamError(error.code, error.message)));
|
|
1315
1333
|
}
|
|
1316
1334
|
function isWebSocketConnectionLimitCode(code) {
|
|
1317
1335
|
return code?.trim().toLowerCase() === 'websocket_connection_limit_reached';
|
|
@@ -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
|
-
|
|
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(
|
|
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(
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
if (
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
2244
|
+
const record = decode(line, invalidFinalLineMayBeIgnored);
|
|
2186
2245
|
invalidFinalLineMayBeIgnored = false;
|
|
2187
2246
|
pendingLineParts = [];
|
|
2188
2247
|
lineEnd = index;
|
|
2189
|
-
if (
|
|
2190
|
-
|
|
2191
|
-
break;
|
|
2192
|
-
}
|
|
2248
|
+
if (record !== undefined)
|
|
2249
|
+
yield record;
|
|
2193
2250
|
}
|
|
2194
|
-
if (
|
|
2251
|
+
if (lineEnd > 0)
|
|
2195
2252
|
pendingLineParts.unshift(Buffer.from(value.subarray(0, lineEnd)));
|
|
2196
2253
|
position = start;
|
|
2197
2254
|
}
|
|
2198
|
-
if (
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
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();
|