opencode-tbot 0.1.8 → 0.1.10
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/README.md +4 -4
- package/README.zh-CN.md +3 -3
- package/dist/cli.js +130 -24
- package/dist/cli.js.map +1 -1
- package/dist/plugin.js +253 -70
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
package/dist/plugin.js
CHANGED
|
@@ -255,58 +255,96 @@ var OpenCodeClient = class {
|
|
|
255
255
|
this.fetchFn = fetchFn;
|
|
256
256
|
}
|
|
257
257
|
async getHealth() {
|
|
258
|
+
const rawClient = getRawSdkClient(this.client);
|
|
259
|
+
if (rawClient?.get) return await this.requestRaw("get", { url: "/global/health" });
|
|
258
260
|
const healthEndpoint = this.client.global?.health;
|
|
259
261
|
if (typeof healthEndpoint === "function") return unwrapSdkData(await healthEndpoint.call(this.client.global, SDK_OPTIONS));
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
return unwrapSdkData(await rawClient.get({
|
|
263
|
-
url: "/global/health",
|
|
264
|
-
...SDK_OPTIONS
|
|
265
|
-
}));
|
|
262
|
+
if (!rawClient?.get) throw new Error("OpenCode SDK client does not expose a compatible health endpoint.");
|
|
263
|
+
return this.requestRaw("get", { url: "/global/health" });
|
|
266
264
|
}
|
|
267
265
|
async abortSession(sessionId) {
|
|
266
|
+
if (hasRawSdkMethod(this.client, "post")) return this.requestRaw("post", {
|
|
267
|
+
url: "/session/{sessionID}/abort",
|
|
268
|
+
path: { sessionID: sessionId }
|
|
269
|
+
});
|
|
268
270
|
return unwrapSdkData(await this.client.session.abort({ sessionID: sessionId }, SDK_OPTIONS));
|
|
269
271
|
}
|
|
270
272
|
async getPath() {
|
|
273
|
+
if (hasRawSdkMethod(this.client, "get")) return this.requestRaw("get", { url: "/path" });
|
|
271
274
|
return unwrapSdkData(await this.client.path.get(void 0, SDK_OPTIONS));
|
|
272
275
|
}
|
|
273
276
|
async listLspStatuses(directory) {
|
|
277
|
+
if (hasRawSdkMethod(this.client, "get")) return this.requestRaw("get", {
|
|
278
|
+
url: "/lsp",
|
|
279
|
+
...directory ? { query: { directory } } : {}
|
|
280
|
+
});
|
|
274
281
|
return unwrapSdkData(await this.client.lsp.status(directory ? { directory } : void 0, SDK_OPTIONS));
|
|
275
282
|
}
|
|
276
283
|
async listMcpStatuses(directory) {
|
|
284
|
+
if (hasRawSdkMethod(this.client, "get")) return this.requestRaw("get", {
|
|
285
|
+
url: "/mcp",
|
|
286
|
+
...directory ? { query: { directory } } : {}
|
|
287
|
+
});
|
|
277
288
|
return unwrapSdkData(await this.client.mcp.status(directory ? { directory } : void 0, SDK_OPTIONS));
|
|
278
289
|
}
|
|
279
290
|
async getSessionStatuses() {
|
|
291
|
+
if (hasRawSdkMethod(this.client, "get")) return this.requestRaw("get", { url: "/session/status" });
|
|
280
292
|
return unwrapSdkData(await this.client.session.status(void 0, SDK_OPTIONS));
|
|
281
293
|
}
|
|
282
294
|
async listProjects() {
|
|
295
|
+
if (hasRawSdkMethod(this.client, "get")) return this.requestRaw("get", { url: "/project" });
|
|
283
296
|
return unwrapSdkData(await this.client.project.list(void 0, SDK_OPTIONS));
|
|
284
297
|
}
|
|
285
298
|
async listSessions() {
|
|
299
|
+
if (hasRawSdkMethod(this.client, "get")) return this.requestRaw("get", { url: "/session" });
|
|
286
300
|
return unwrapSdkData(await this.client.session.list(void 0, SDK_OPTIONS));
|
|
287
301
|
}
|
|
288
302
|
async getCurrentProject() {
|
|
303
|
+
if (hasRawSdkMethod(this.client, "get")) return this.requestRaw("get", { url: "/project/current" });
|
|
289
304
|
return unwrapSdkData(await this.client.project.current(void 0, SDK_OPTIONS));
|
|
290
305
|
}
|
|
291
306
|
async createSessionForDirectory(directory, title) {
|
|
307
|
+
if (hasRawSdkMethod(this.client, "post")) return this.requestRaw("post", {
|
|
308
|
+
url: "/session",
|
|
309
|
+
query: { directory },
|
|
310
|
+
...title ? { body: { title } } : {}
|
|
311
|
+
});
|
|
292
312
|
return unwrapSdkData(await this.client.session.create(title ? {
|
|
293
313
|
directory,
|
|
294
314
|
title
|
|
295
315
|
} : { directory }, SDK_OPTIONS));
|
|
296
316
|
}
|
|
297
317
|
async renameSession(sessionId, title) {
|
|
318
|
+
if (hasRawSdkMethod(this.client, "patch")) return this.requestRaw("patch", {
|
|
319
|
+
url: "/session/{sessionID}",
|
|
320
|
+
path: { sessionID: sessionId },
|
|
321
|
+
body: { title }
|
|
322
|
+
});
|
|
298
323
|
return unwrapSdkData(await this.client.session.update({
|
|
299
324
|
sessionID: sessionId,
|
|
300
325
|
title
|
|
301
326
|
}, SDK_OPTIONS));
|
|
302
327
|
}
|
|
303
328
|
async listAgents() {
|
|
329
|
+
if (hasRawSdkMethod(this.client, "get")) return this.requestRaw("get", { url: "/agent" });
|
|
304
330
|
return unwrapSdkData(await this.client.app.agents(void 0, SDK_OPTIONS));
|
|
305
331
|
}
|
|
306
332
|
async listPendingPermissions(directory) {
|
|
333
|
+
if (hasRawSdkMethod(this.client, "get")) return this.requestRaw("get", {
|
|
334
|
+
url: "/permission",
|
|
335
|
+
...directory ? { query: { directory } } : {}
|
|
336
|
+
});
|
|
307
337
|
return unwrapSdkData(await this.client.permission.list(directory ? { directory } : void 0, SDK_OPTIONS));
|
|
308
338
|
}
|
|
309
339
|
async replyToPermission(requestId, reply, message) {
|
|
340
|
+
if (hasRawSdkMethod(this.client, "post")) return this.requestRaw("post", {
|
|
341
|
+
url: "/permission/{requestID}/reply",
|
|
342
|
+
path: { requestID: requestId },
|
|
343
|
+
body: {
|
|
344
|
+
reply,
|
|
345
|
+
...message?.trim() ? { message: message.trim() } : {}
|
|
346
|
+
}
|
|
347
|
+
});
|
|
310
348
|
return unwrapSdkData(await this.client.permission.reply({
|
|
311
349
|
requestID: requestId,
|
|
312
350
|
reply,
|
|
@@ -337,14 +375,7 @@ var OpenCodeClient = class {
|
|
|
337
375
|
}))];
|
|
338
376
|
if (parts.length === 0) throw new Error("Prompt requires text or file attachments.");
|
|
339
377
|
const knownMessageIds = await this.captureKnownMessageIds(input.sessionId);
|
|
340
|
-
const initialData =
|
|
341
|
-
sessionID: input.sessionId,
|
|
342
|
-
...input.agent ? { agent: input.agent } : {},
|
|
343
|
-
...input.structured ? { format: STRUCTURED_REPLY_SCHEMA } : {},
|
|
344
|
-
...input.model ? { model: input.model } : {},
|
|
345
|
-
...input.variant ? { variant: input.variant } : {},
|
|
346
|
-
parts
|
|
347
|
-
}, SDK_OPTIONS));
|
|
378
|
+
const initialData = await this.sendPromptRequest(input, parts);
|
|
348
379
|
return buildPromptSessionResult(await this.resolvePromptResponse(input, initialData, knownMessageIds), {
|
|
349
380
|
emptyResponseText: EMPTY_RESPONSE_TEXT,
|
|
350
381
|
finishedAt: Date.now(),
|
|
@@ -353,51 +384,75 @@ var OpenCodeClient = class {
|
|
|
353
384
|
});
|
|
354
385
|
}
|
|
355
386
|
async resolvePromptResponse(input, data, knownMessageIds) {
|
|
356
|
-
|
|
357
|
-
|
|
387
|
+
const structured = input.structured ?? false;
|
|
388
|
+
if (!shouldPollPromptMessage(data, structured)) return data;
|
|
389
|
+
const messageId = extractMessageId(data.info);
|
|
390
|
+
let expectedParentId = toAssistantMessage(data.info)?.parentID ?? null;
|
|
358
391
|
let bestCandidate = data;
|
|
359
|
-
|
|
360
|
-
initialMessageId: null,
|
|
361
|
-
knownMessageIds,
|
|
362
|
-
structured: input.structured ?? false
|
|
363
|
-
}) ?? data;
|
|
392
|
+
let hasWaited = false;
|
|
364
393
|
for (const delayMs of PROMPT_MESSAGE_POLL_DELAYS_MS) {
|
|
365
|
-
if (delayMs > 0)
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
394
|
+
if (delayMs > 0) {
|
|
395
|
+
await delay(delayMs);
|
|
396
|
+
hasWaited = true;
|
|
397
|
+
}
|
|
398
|
+
if (messageId) {
|
|
399
|
+
const next = await this.fetchPromptMessage(input.sessionId, messageId);
|
|
400
|
+
if (next) {
|
|
401
|
+
bestCandidate = selectPromptResponseCandidate([bestCandidate, next], {
|
|
402
|
+
initialMessageId: messageId,
|
|
403
|
+
initialParentId: expectedParentId,
|
|
404
|
+
knownMessageIds,
|
|
405
|
+
structured
|
|
406
|
+
}) ?? bestCandidate;
|
|
407
|
+
expectedParentId = toAssistantMessage(next.info)?.parentID ?? expectedParentId;
|
|
408
|
+
if (!shouldPollPromptMessage(next, structured)) return next;
|
|
376
409
|
}
|
|
377
|
-
continue;
|
|
378
410
|
}
|
|
379
|
-
data = next;
|
|
380
|
-
bestCandidate = next;
|
|
381
|
-
if (!shouldPollPromptMessage(data, input.structured ?? false)) return data;
|
|
382
411
|
const latest = await this.findLatestPromptResponse(input.sessionId, {
|
|
383
412
|
initialMessageId: messageId,
|
|
413
|
+
initialParentId: expectedParentId,
|
|
384
414
|
knownMessageIds,
|
|
385
|
-
structured
|
|
415
|
+
structured
|
|
386
416
|
});
|
|
387
417
|
if (latest) {
|
|
388
|
-
bestCandidate = latest
|
|
389
|
-
|
|
418
|
+
bestCandidate = selectPromptResponseCandidate([bestCandidate, latest], {
|
|
419
|
+
initialMessageId: messageId,
|
|
420
|
+
initialParentId: expectedParentId,
|
|
421
|
+
knownMessageIds,
|
|
422
|
+
structured
|
|
423
|
+
}) ?? bestCandidate;
|
|
424
|
+
expectedParentId = toAssistantMessage(latest.info)?.parentID ?? expectedParentId;
|
|
425
|
+
if (!shouldPollPromptMessage(latest, structured)) return latest;
|
|
390
426
|
}
|
|
427
|
+
if ((await this.fetchPromptSessionStatus(input.sessionId))?.type === "idle" && hasWaited) break;
|
|
391
428
|
}
|
|
392
|
-
|
|
429
|
+
const latest = await this.findLatestPromptResponse(input.sessionId, {
|
|
430
|
+
initialMessageId: messageId,
|
|
431
|
+
initialParentId: expectedParentId,
|
|
432
|
+
knownMessageIds,
|
|
433
|
+
structured
|
|
434
|
+
});
|
|
435
|
+
return selectPromptResponseCandidate([bestCandidate, latest], {
|
|
436
|
+
initialMessageId: messageId,
|
|
437
|
+
initialParentId: expectedParentId,
|
|
438
|
+
knownMessageIds,
|
|
439
|
+
structured
|
|
440
|
+
}) ?? bestCandidate;
|
|
393
441
|
}
|
|
394
442
|
async fetchPromptMessage(sessionId, messageId) {
|
|
395
|
-
if (typeof this.client.session.message !== "function") return null;
|
|
396
443
|
try {
|
|
397
|
-
return
|
|
444
|
+
if (hasRawSdkMethod(this.client, "get")) return normalizePromptResponse(await this.requestRaw("get", {
|
|
445
|
+
url: "/session/{sessionID}/message/{messageID}",
|
|
446
|
+
path: {
|
|
447
|
+
sessionID: sessionId,
|
|
448
|
+
messageID: messageId
|
|
449
|
+
}
|
|
450
|
+
}));
|
|
451
|
+
if (typeof this.client.session.message !== "function") return null;
|
|
452
|
+
return normalizePromptResponse(unwrapSdkData(await this.client.session.message({
|
|
398
453
|
sessionID: sessionId,
|
|
399
454
|
messageID: messageId
|
|
400
|
-
}, SDK_OPTIONS));
|
|
455
|
+
}, SDK_OPTIONS)));
|
|
401
456
|
} catch {
|
|
402
457
|
return null;
|
|
403
458
|
}
|
|
@@ -405,16 +460,27 @@ var OpenCodeClient = class {
|
|
|
405
460
|
async captureKnownMessageIds(sessionId) {
|
|
406
461
|
const messages = await this.fetchRecentPromptMessages(sessionId);
|
|
407
462
|
if (!messages) return /* @__PURE__ */ new Set();
|
|
408
|
-
return new Set(messages.map((message) => message.info
|
|
463
|
+
return new Set(messages.map((message) => extractMessageId(message.info)).filter((id) => typeof id === "string" && id.length > 0));
|
|
409
464
|
}
|
|
410
465
|
async fetchRecentPromptMessages(sessionId) {
|
|
411
|
-
if (typeof this.client.session.messages !== "function") return null;
|
|
412
466
|
try {
|
|
413
|
-
|
|
467
|
+
if (hasRawSdkMethod(this.client, "get")) return normalizePromptResponses(await this.requestRaw("get", {
|
|
468
|
+
url: "/session/{sessionID}/message",
|
|
469
|
+
path: { sessionID: sessionId },
|
|
470
|
+
query: { limit: PROMPT_MESSAGE_POLL_LIMIT }
|
|
471
|
+
}));
|
|
472
|
+
if (typeof this.client.session.messages !== "function") return null;
|
|
473
|
+
return normalizePromptResponses(unwrapSdkData(await this.client.session.messages({
|
|
414
474
|
sessionID: sessionId,
|
|
415
475
|
limit: PROMPT_MESSAGE_POLL_LIMIT
|
|
416
|
-
}, SDK_OPTIONS));
|
|
417
|
-
|
|
476
|
+
}, SDK_OPTIONS)));
|
|
477
|
+
} catch {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
async fetchPromptSessionStatus(sessionId) {
|
|
482
|
+
try {
|
|
483
|
+
return (await this.getSessionStatuses())[sessionId] ?? null;
|
|
418
484
|
} catch {
|
|
419
485
|
return null;
|
|
420
486
|
}
|
|
@@ -422,24 +488,10 @@ var OpenCodeClient = class {
|
|
|
422
488
|
async findLatestPromptResponse(sessionId, options) {
|
|
423
489
|
const messages = await this.fetchRecentPromptMessages(sessionId);
|
|
424
490
|
if (!messages || messages.length === 0) return null;
|
|
425
|
-
|
|
426
|
-
const assistant = toAssistantMessage(message.info);
|
|
427
|
-
const id = assistant?.id ?? null;
|
|
428
|
-
return {
|
|
429
|
-
createdAt: typeof assistant?.time?.created === "number" && Number.isFinite(assistant.time.created) ? assistant.time.created : 0,
|
|
430
|
-
id,
|
|
431
|
-
isInitial: !!id && id === options.initialMessageId,
|
|
432
|
-
isNew: !!id && !options.knownMessageIds.has(id),
|
|
433
|
-
isUsable: !shouldPollPromptMessage(message, options.structured),
|
|
434
|
-
message
|
|
435
|
-
};
|
|
436
|
-
}).sort((left, right) => Number(right.isUsable) - Number(left.isUsable) || Number(right.isNew) - Number(left.isNew) || Number(right.isInitial) - Number(left.isInitial) || right.createdAt - left.createdAt);
|
|
437
|
-
return (candidates.find((candidate) => candidate.isUsable && (candidate.isNew || candidate.isInitial)) ?? candidates.find((candidate) => candidate.isNew || candidate.isInitial) ?? null)?.message ?? null;
|
|
491
|
+
return selectPromptResponseCandidate(messages, options);
|
|
438
492
|
}
|
|
439
493
|
async loadModels() {
|
|
440
|
-
const [
|
|
441
|
-
const config = unwrapSdkData(configResponse);
|
|
442
|
-
const providerCatalog = unwrapSdkData(providersResponse);
|
|
494
|
+
const [config, providerCatalog] = await Promise.all([this.loadConfig(), this.loadProviderCatalog()]);
|
|
443
495
|
const providerAvailability = await resolveProviderAvailability(config, this.fetchFn);
|
|
444
496
|
const models = buildSelectableModels(config, providerCatalog.providers, providerAvailability);
|
|
445
497
|
this.modelCache = {
|
|
@@ -449,6 +501,43 @@ var OpenCodeClient = class {
|
|
|
449
501
|
};
|
|
450
502
|
return models;
|
|
451
503
|
}
|
|
504
|
+
async loadConfig() {
|
|
505
|
+
if (hasRawSdkMethod(this.client, "get")) return this.requestRaw("get", { url: "/config" });
|
|
506
|
+
return unwrapSdkData(await this.client.config.get(void 0, SDK_OPTIONS));
|
|
507
|
+
}
|
|
508
|
+
async loadProviderCatalog() {
|
|
509
|
+
if (hasRawSdkMethod(this.client, "get")) return this.requestRaw("get", { url: "/config/providers" });
|
|
510
|
+
return unwrapSdkData(await this.client.config.providers(void 0, SDK_OPTIONS));
|
|
511
|
+
}
|
|
512
|
+
async sendPromptRequest(input, parts) {
|
|
513
|
+
if (hasRawSdkMethod(this.client, "post")) return normalizePromptResponse(await this.requestRaw("post", {
|
|
514
|
+
url: "/session/{sessionID}/message",
|
|
515
|
+
path: { sessionID: input.sessionId },
|
|
516
|
+
body: {
|
|
517
|
+
...input.agent ? { agent: input.agent } : {},
|
|
518
|
+
...input.structured ? { format: STRUCTURED_REPLY_SCHEMA } : {},
|
|
519
|
+
...input.model ? { model: input.model } : {},
|
|
520
|
+
...input.variant ? { variant: input.variant } : {},
|
|
521
|
+
parts
|
|
522
|
+
}
|
|
523
|
+
}));
|
|
524
|
+
return normalizePromptResponse(unwrapSdkData(await this.client.session.prompt({
|
|
525
|
+
sessionID: input.sessionId,
|
|
526
|
+
...input.agent ? { agent: input.agent } : {},
|
|
527
|
+
...input.structured ? { format: STRUCTURED_REPLY_SCHEMA } : {},
|
|
528
|
+
...input.model ? { model: input.model } : {},
|
|
529
|
+
...input.variant ? { variant: input.variant } : {},
|
|
530
|
+
parts
|
|
531
|
+
}, SDK_OPTIONS)));
|
|
532
|
+
}
|
|
533
|
+
async requestRaw(method, options) {
|
|
534
|
+
const handler = getRawSdkClient(this.client)?.[method];
|
|
535
|
+
if (typeof handler !== "function") throw new Error(`OpenCode SDK client does not expose a compatible raw ${method.toUpperCase()} method.`);
|
|
536
|
+
return unwrapSdkData(await handler({
|
|
537
|
+
...SDK_OPTIONS,
|
|
538
|
+
...options
|
|
539
|
+
}));
|
|
540
|
+
}
|
|
452
541
|
};
|
|
453
542
|
function createOpenCodeClientFromSdkClient(client, fetchFn = fetch) {
|
|
454
543
|
return new OpenCodeClient(void 0, client, fetchFn);
|
|
@@ -539,7 +628,8 @@ function extractTextFromParts(parts) {
|
|
|
539
628
|
}
|
|
540
629
|
function buildPromptSessionResult(data, options) {
|
|
541
630
|
const assistantInfo = toAssistantMessage(data.info);
|
|
542
|
-
const
|
|
631
|
+
const structuredPayload = extractStructuredPayload(assistantInfo);
|
|
632
|
+
const bodyMd = options.structured ? extractStructuredMarkdown(structuredPayload) : null;
|
|
543
633
|
const responseParts = Array.isArray(data.parts) ? data.parts : [];
|
|
544
634
|
const fallbackText = extractTextFromParts(responseParts) || bodyMd || options.emptyResponseText;
|
|
545
635
|
return {
|
|
@@ -549,20 +639,72 @@ function buildPromptSessionResult(data, options) {
|
|
|
549
639
|
info: assistantInfo,
|
|
550
640
|
metrics: extractPromptMetrics(assistantInfo, options.startedAt, options.finishedAt),
|
|
551
641
|
parts: responseParts,
|
|
552
|
-
structured:
|
|
642
|
+
structured: structuredPayload ?? null
|
|
553
643
|
};
|
|
554
644
|
}
|
|
555
645
|
function shouldPollPromptMessage(data, structured) {
|
|
556
646
|
const assistantInfo = toAssistantMessage(data.info);
|
|
557
|
-
const bodyMd = structured ? extractStructuredMarkdown(assistantInfo
|
|
647
|
+
const bodyMd = structured ? extractStructuredMarkdown(extractStructuredPayload(assistantInfo)) : null;
|
|
558
648
|
const hasText = extractTextFromParts(Array.isArray(data.parts) ? data.parts : []).length > 0;
|
|
559
649
|
const hasAssistantError = !!assistantInfo?.error;
|
|
560
|
-
|
|
561
|
-
|
|
650
|
+
return !hasText && !bodyMd && !hasAssistantError;
|
|
651
|
+
}
|
|
652
|
+
function normalizePromptResponse(response) {
|
|
653
|
+
return {
|
|
654
|
+
info: isPlainRecord(response?.info) ? response.info : null,
|
|
655
|
+
parts: normalizePromptParts(response?.parts)
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
function normalizePromptResponses(responses) {
|
|
659
|
+
if (!Array.isArray(responses)) return null;
|
|
660
|
+
return responses.map((response) => normalizePromptResponse(response));
|
|
661
|
+
}
|
|
662
|
+
function normalizePromptParts(parts) {
|
|
663
|
+
return Array.isArray(parts) ? parts : [];
|
|
562
664
|
}
|
|
563
665
|
function toAssistantMessage(message) {
|
|
564
666
|
if (!message || typeof message !== "object") return null;
|
|
565
|
-
|
|
667
|
+
if ("role" in message && message.role !== "assistant") return null;
|
|
668
|
+
const normalized = {};
|
|
669
|
+
if ("agent" in message && typeof message.agent === "string" && message.agent.trim().length > 0) normalized.agent = message.agent;
|
|
670
|
+
if ("cost" in message && typeof message.cost === "number" && Number.isFinite(message.cost)) normalized.cost = message.cost;
|
|
671
|
+
const error = normalizeAssistantError("error" in message ? message.error : void 0);
|
|
672
|
+
if (error) normalized.error = error;
|
|
673
|
+
if ("finish" in message && typeof message.finish === "string" && message.finish.trim().length > 0) normalized.finish = message.finish;
|
|
674
|
+
if ("id" in message && typeof message.id === "string" && message.id.trim().length > 0) normalized.id = message.id;
|
|
675
|
+
if ("mode" in message && typeof message.mode === "string" && message.mode.trim().length > 0) normalized.mode = message.mode;
|
|
676
|
+
if ("modelID" in message && typeof message.modelID === "string" && message.modelID.trim().length > 0) normalized.modelID = message.modelID;
|
|
677
|
+
if ("parentID" in message && typeof message.parentID === "string" && message.parentID.trim().length > 0) normalized.parentID = message.parentID;
|
|
678
|
+
if ("path" in message && isPlainRecord(message.path)) normalized.path = {
|
|
679
|
+
...typeof message.path.cwd === "string" && message.path.cwd.trim().length > 0 ? { cwd: message.path.cwd } : {},
|
|
680
|
+
...typeof message.path.root === "string" && message.path.root.trim().length > 0 ? { root: message.path.root } : {}
|
|
681
|
+
};
|
|
682
|
+
if ("providerID" in message && typeof message.providerID === "string" && message.providerID.trim().length > 0) normalized.providerID = message.providerID;
|
|
683
|
+
if ("role" in message && message.role === "assistant") normalized.role = "assistant";
|
|
684
|
+
if ("sessionID" in message && typeof message.sessionID === "string" && message.sessionID.trim().length > 0) normalized.sessionID = message.sessionID;
|
|
685
|
+
const structuredPayload = extractStructuredPayload(message);
|
|
686
|
+
if (structuredPayload !== null) normalized.structured = structuredPayload;
|
|
687
|
+
if ("summary" in message && typeof message.summary === "boolean") normalized.summary = message.summary;
|
|
688
|
+
if ("time" in message && isPlainRecord(message.time)) normalized.time = {
|
|
689
|
+
...typeof message.time.created === "number" && Number.isFinite(message.time.created) ? { created: message.time.created } : {},
|
|
690
|
+
...typeof message.time.completed === "number" && Number.isFinite(message.time.completed) ? { completed: message.time.completed } : {}
|
|
691
|
+
};
|
|
692
|
+
if ("tokens" in message && isPlainRecord(message.tokens)) normalized.tokens = {
|
|
693
|
+
...typeof message.tokens.input === "number" && Number.isFinite(message.tokens.input) ? { input: message.tokens.input } : {},
|
|
694
|
+
...typeof message.tokens.output === "number" && Number.isFinite(message.tokens.output) ? { output: message.tokens.output } : {},
|
|
695
|
+
...typeof message.tokens.reasoning === "number" && Number.isFinite(message.tokens.reasoning) ? { reasoning: message.tokens.reasoning } : {},
|
|
696
|
+
...typeof message.tokens.total === "number" && Number.isFinite(message.tokens.total) ? { total: message.tokens.total } : {},
|
|
697
|
+
...isPlainRecord(message.tokens.cache) ? { cache: {
|
|
698
|
+
...typeof message.tokens.cache.read === "number" && Number.isFinite(message.tokens.cache.read) ? { read: message.tokens.cache.read } : {},
|
|
699
|
+
...typeof message.tokens.cache.write === "number" && Number.isFinite(message.tokens.cache.write) ? { write: message.tokens.cache.write } : {}
|
|
700
|
+
} } : {}
|
|
701
|
+
};
|
|
702
|
+
if ("variant" in message && typeof message.variant === "string" && message.variant.trim().length > 0) normalized.variant = message.variant;
|
|
703
|
+
return normalized;
|
|
704
|
+
}
|
|
705
|
+
function extractMessageId(message) {
|
|
706
|
+
if (!isPlainRecord(message)) return null;
|
|
707
|
+
return typeof message.id === "string" && message.id.trim().length > 0 ? message.id : null;
|
|
566
708
|
}
|
|
567
709
|
function delay(ms) {
|
|
568
710
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -622,6 +764,47 @@ function unwrapSdkData(response) {
|
|
|
622
764
|
function getRawSdkClient(client) {
|
|
623
765
|
return client.client ?? client._client ?? null;
|
|
624
766
|
}
|
|
767
|
+
function hasRawSdkMethod(client, method) {
|
|
768
|
+
return typeof getRawSdkClient(client)?.[method] === "function";
|
|
769
|
+
}
|
|
770
|
+
function normalizeAssistantError(value) {
|
|
771
|
+
if (!isPlainRecord(value) || typeof value.name !== "string" || value.name.trim().length === 0) return;
|
|
772
|
+
return {
|
|
773
|
+
...value,
|
|
774
|
+
name: value.name,
|
|
775
|
+
...isPlainRecord(value.data) ? { data: value.data } : {}
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
function extractStructuredPayload(message) {
|
|
779
|
+
if (!isPlainRecord(message)) return null;
|
|
780
|
+
if ("structured" in message && message.structured !== void 0) return message.structured;
|
|
781
|
+
if ("structured_output" in message && message.structured_output !== void 0) return message.structured_output;
|
|
782
|
+
return null;
|
|
783
|
+
}
|
|
784
|
+
function selectPromptResponseCandidate(candidates, options) {
|
|
785
|
+
const availableCandidates = candidates.filter((candidate) => !!candidate).filter((candidate) => toAssistantMessage(candidate.info) !== null);
|
|
786
|
+
if (availableCandidates.length === 0) return null;
|
|
787
|
+
return [...availableCandidates].sort((left, right) => comparePromptResponseCandidates(left, right, options))[0] ?? null;
|
|
788
|
+
}
|
|
789
|
+
function comparePromptResponseCandidates(left, right, options) {
|
|
790
|
+
const leftRank = getPromptResponseCandidateRank(left, options);
|
|
791
|
+
const rightRank = getPromptResponseCandidateRank(right, options);
|
|
792
|
+
return Number(rightRank.isUsable) - Number(leftRank.isUsable) || Number(rightRank.isInitial) - Number(leftRank.isInitial) || Number(rightRank.sharesParent) - Number(leftRank.sharesParent) || Number(rightRank.isNew) - Number(leftRank.isNew) || rightRank.createdAt - leftRank.createdAt;
|
|
793
|
+
}
|
|
794
|
+
function getPromptResponseCandidateRank(message, options) {
|
|
795
|
+
const assistant = toAssistantMessage(message.info);
|
|
796
|
+
const id = assistant?.id ?? null;
|
|
797
|
+
return {
|
|
798
|
+
createdAt: typeof assistant?.time?.created === "number" && Number.isFinite(assistant.time.created) ? assistant.time.created : 0,
|
|
799
|
+
isInitial: !!id && id === options.initialMessageId,
|
|
800
|
+
isNew: !!id && !options.knownMessageIds.has(id),
|
|
801
|
+
isUsable: !shouldPollPromptMessage(message, options.structured),
|
|
802
|
+
sharesParent: !!assistant?.parentID && assistant.parentID === options.initialParentId
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
function isPlainRecord(value) {
|
|
806
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
807
|
+
}
|
|
625
808
|
async function resolveProviderAvailability(config, fetchFn) {
|
|
626
809
|
const configuredProviders = Object.entries(config.provider ?? {});
|
|
627
810
|
const availabilityEntries = await Promise.all(configuredProviders.map(async ([providerId, providerConfig]) => [providerId, await fetchProviderAvailableModelIds(providerConfig, fetchFn)]));
|