remote-codex 0.11.30 → 0.11.32
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 +12 -4
- package/apps/relay-server/dist/index.js +2956 -164
- package/apps/supervisor-api/dist/index.js +521 -64
- package/apps/supervisor-web/dist/apple-touch-icon.png +0 -0
- package/apps/supervisor-web/dist/assets/index-CGHHTNkM.js +21 -0
- package/apps/supervisor-web/dist/assets/index-CdjTdnJt.css +1 -0
- package/apps/supervisor-web/dist/assets/thread-ui-B9eC2H4u.js +3677 -0
- package/apps/supervisor-web/dist/favicon-16x16.png +0 -0
- package/apps/supervisor-web/dist/favicon-32x32.png +0 -0
- package/apps/supervisor-web/dist/favicon-48x48.png +0 -0
- package/apps/supervisor-web/dist/icon-192.png +0 -0
- package/apps/supervisor-web/dist/icon-512.png +0 -0
- package/apps/supervisor-web/dist/index.html +10 -4
- package/apps/supervisor-web/dist/remote-codex-icon.png +0 -0
- package/apps/supervisor-web/dist/site.webmanifest +19 -0
- package/bin/remote-codex.mjs +6 -3
- package/config/codex-model-pricing.json +44 -0
- package/package.json +1 -1
- package/packages/agent-runtime/src/model-pricing.ts +66 -6
- package/packages/agent-runtime/src/types.ts +13 -0
- package/packages/claude/src/runtimeAdapter.test.ts +64 -0
- package/packages/claude/src/runtimeAdapter.ts +64 -0
- package/packages/codex/src/appServerManager.ts +16 -0
- package/packages/codex/src/modelPricing.test.ts +84 -0
- package/packages/codex/src/runtimeAdapter.test.ts +44 -0
- package/packages/codex/src/runtimeAdapter.ts +66 -0
- package/packages/codex/src/types.ts +3 -1
- package/packages/db/migrations/0029_thread_turn_delivery.sql +19 -0
- package/packages/db/src/repositories.ts +96 -1
- package/packages/db/src/schema.ts +20 -0
- package/packages/opencode/src/runtimeAdapter.ts +15 -0
- package/packages/shared/src/index.ts +203 -7
- package/scripts/run-web-service.mjs +2 -2
- package/scripts/service-manager.mjs +2 -2
- package/apps/supervisor-web/dist/assets/index-BnpZn_3_.js +0 -6
- package/apps/supervisor-web/dist/assets/index-CJFMmjP5.css +0 -1
- package/apps/supervisor-web/dist/assets/thread-ui-C0VPL4Uk.js +0 -3677
|
@@ -291,19 +291,35 @@ function parsePricingConfig(raw) {
|
|
|
291
291
|
if (!isPositiveNumber(entry.inputUsdPerMillion) || !isPositiveNumber(entry.cachedInputUsdPerMillion) || !isPositiveNumber(entry.outputUsdPerMillion) || typeof entry.supportsFastMode !== "boolean") {
|
|
292
292
|
throw new Error(`Pricing config model "${modelKey2}" has invalid fields.`);
|
|
293
293
|
}
|
|
294
|
+
if (entry.cacheWriteInputUsdPerMillion !== void 0 && !isPositiveNumber(entry.cacheWriteInputUsdPerMillion)) {
|
|
295
|
+
throw new Error(`Pricing config model "${modelKey2}" cacheWriteInputUsdPerMillion must be a non-negative number.`);
|
|
296
|
+
}
|
|
294
297
|
if (entry.fastMultiplier !== void 0 && !isPositiveNumber(entry.fastMultiplier)) {
|
|
295
298
|
throw new Error(`Pricing config model "${modelKey2}" fastMultiplier must be a non-negative number.`);
|
|
296
299
|
}
|
|
297
300
|
if (entry.contextWindowTokens !== void 0 && !isPositiveNumber(entry.contextWindowTokens)) {
|
|
298
301
|
throw new Error(`Pricing config model "${modelKey2}" contextWindowTokens must be a non-negative number.`);
|
|
299
302
|
}
|
|
303
|
+
for (const field of [
|
|
304
|
+
"longContextThresholdTokens",
|
|
305
|
+
"longContextInputMultiplier",
|
|
306
|
+
"longContextOutputMultiplier"
|
|
307
|
+
]) {
|
|
308
|
+
if (entry[field] !== void 0 && !isPositiveNumber(entry[field])) {
|
|
309
|
+
throw new Error(`Pricing config model "${modelKey2}" ${field} must be a non-negative number.`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
300
312
|
models[modelKey2] = {
|
|
301
313
|
inputUsdPerMillion: entry.inputUsdPerMillion,
|
|
302
314
|
cachedInputUsdPerMillion: entry.cachedInputUsdPerMillion,
|
|
315
|
+
...entry.cacheWriteInputUsdPerMillion !== void 0 ? { cacheWriteInputUsdPerMillion: entry.cacheWriteInputUsdPerMillion } : {},
|
|
303
316
|
outputUsdPerMillion: entry.outputUsdPerMillion,
|
|
304
317
|
supportsFastMode: entry.supportsFastMode,
|
|
305
318
|
...entry.fastMultiplier !== void 0 ? { fastMultiplier: entry.fastMultiplier } : {},
|
|
306
|
-
...entry.contextWindowTokens !== void 0 ? { contextWindowTokens: entry.contextWindowTokens } : {}
|
|
319
|
+
...entry.contextWindowTokens !== void 0 ? { contextWindowTokens: entry.contextWindowTokens } : {},
|
|
320
|
+
...entry.longContextThresholdTokens !== void 0 ? { longContextThresholdTokens: entry.longContextThresholdTokens } : {},
|
|
321
|
+
...entry.longContextInputMultiplier !== void 0 ? { longContextInputMultiplier: entry.longContextInputMultiplier } : {},
|
|
322
|
+
...entry.longContextOutputMultiplier !== void 0 ? { longContextOutputMultiplier: entry.longContextOutputMultiplier } : {}
|
|
307
323
|
};
|
|
308
324
|
}
|
|
309
325
|
return {
|
|
@@ -396,23 +412,32 @@ function estimateTurnPrice(usage, snapshot) {
|
|
|
396
412
|
return null;
|
|
397
413
|
}
|
|
398
414
|
const nonCachedInputTokens = Math.max(
|
|
399
|
-
usage.total.inputTokens - usage.total.cachedInputTokens,
|
|
415
|
+
usage.total.inputTokens - usage.total.cachedInputTokens - (usage.total.cacheWriteInputTokens ?? 0),
|
|
400
416
|
0
|
|
401
417
|
);
|
|
402
418
|
const cachedInputTokens = Math.max(usage.total.cachedInputTokens, 0);
|
|
419
|
+
const cacheWriteInputTokens = Math.max(
|
|
420
|
+
usage.total.cacheWriteInputTokens ?? 0,
|
|
421
|
+
0
|
|
422
|
+
);
|
|
403
423
|
const outputTokens = Math.max(usage.total.outputTokens, 0);
|
|
404
|
-
const
|
|
405
|
-
const
|
|
406
|
-
const
|
|
407
|
-
const
|
|
424
|
+
const tierMultiplier = tierKey === "fast" && modelPricing.fastMultiplier !== void 0 ? modelPricing.fastMultiplier : tier.multiplier;
|
|
425
|
+
const usesLongContextPricing = typeof modelPricing.longContextThresholdTokens === "number" && usage.total.inputTokens > modelPricing.longContextThresholdTokens;
|
|
426
|
+
const inputMultiplier = tierMultiplier * (usesLongContextPricing ? modelPricing.longContextInputMultiplier ?? 1 : 1);
|
|
427
|
+
const outputMultiplier = tierMultiplier * (usesLongContextPricing ? modelPricing.longContextOutputMultiplier ?? 1 : 1);
|
|
428
|
+
const inputUsd = nonCachedInputTokens * modelPricing.inputUsdPerMillion * inputMultiplier / TOKEN_PRICE_DENOMINATOR;
|
|
429
|
+
const cachedInputUsd = cachedInputTokens * modelPricing.cachedInputUsdPerMillion * inputMultiplier / TOKEN_PRICE_DENOMINATOR;
|
|
430
|
+
const cacheWriteInputUsd = cacheWriteInputTokens * (modelPricing.cacheWriteInputUsdPerMillion ?? modelPricing.inputUsdPerMillion) * inputMultiplier / TOKEN_PRICE_DENOMINATOR;
|
|
431
|
+
const outputUsd = outputTokens * modelPricing.outputUsdPerMillion * outputMultiplier / TOKEN_PRICE_DENOMINATOR;
|
|
408
432
|
return {
|
|
409
433
|
pricingModelKey,
|
|
410
434
|
pricingTierKey: tierKey,
|
|
411
435
|
currency: pricingConfig.currency,
|
|
412
436
|
inputUsd,
|
|
413
437
|
cachedInputUsd,
|
|
438
|
+
cacheWriteInputUsd,
|
|
414
439
|
outputUsd,
|
|
415
|
-
totalUsd: inputUsd + cachedInputUsd + outputUsd
|
|
440
|
+
totalUsd: inputUsd + cachedInputUsd + cacheWriteInputUsd + outputUsd
|
|
416
441
|
};
|
|
417
442
|
}
|
|
418
443
|
|
|
@@ -6357,6 +6382,7 @@ __export(schema_exports, {
|
|
|
6357
6382
|
threadGoals: () => threadGoals,
|
|
6358
6383
|
threadHistoryItems: () => threadHistoryItems,
|
|
6359
6384
|
threadPendingSteers: () => threadPendingSteers,
|
|
6385
|
+
threadPromptRequests: () => threadPromptRequests,
|
|
6360
6386
|
threadTurnMetadata: () => threadTurnMetadata,
|
|
6361
6387
|
threads: () => threads,
|
|
6362
6388
|
viewerSessions: () => viewerSessions,
|
|
@@ -6393,6 +6419,7 @@ var threads = sqliteTable("threads", {
|
|
|
6393
6419
|
fastBaseModel: text("fast_base_model"),
|
|
6394
6420
|
fastBaseReasoningEffort: text("fast_base_reasoning_effort"),
|
|
6395
6421
|
collaborationMode: text("collaboration_mode").notNull().default("default"),
|
|
6422
|
+
activeTurnCollaborationMode: text("active_turn_collaboration_mode"),
|
|
6396
6423
|
approvalMode: text("approval_mode"),
|
|
6397
6424
|
sandboxMode: text("sandbox_mode"),
|
|
6398
6425
|
status: text("status"),
|
|
@@ -6468,9 +6495,27 @@ var threadPendingSteers = sqliteTable("thread_pending_steers", {
|
|
|
6468
6495
|
clientRequestId: text("client_request_id"),
|
|
6469
6496
|
displayPrompt: text("display_prompt").notNull(),
|
|
6470
6497
|
submittedPrompt: text("submitted_prompt").notNull(),
|
|
6498
|
+
delivery: text("delivery").notNull().default("steer"),
|
|
6499
|
+
turnConfigJson: text("turn_config_json"),
|
|
6471
6500
|
createdAt: text("created_at").notNull(),
|
|
6472
6501
|
updatedAt: text("updated_at").notNull()
|
|
6473
6502
|
});
|
|
6503
|
+
var threadPromptRequests = sqliteTable(
|
|
6504
|
+
"thread_prompt_requests",
|
|
6505
|
+
{
|
|
6506
|
+
id: text("id").primaryKey(),
|
|
6507
|
+
threadId: text("thread_id").notNull(),
|
|
6508
|
+
clientRequestId: text("client_request_id").notNull(),
|
|
6509
|
+
status: text("status").notNull(),
|
|
6510
|
+
createdAt: text("created_at").notNull(),
|
|
6511
|
+
updatedAt: text("updated_at").notNull()
|
|
6512
|
+
},
|
|
6513
|
+
(table) => ({
|
|
6514
|
+
threadClientRequestUnique: uniqueIndex(
|
|
6515
|
+
"thread_prompt_requests_thread_client_request_idx"
|
|
6516
|
+
).on(table.threadId, table.clientRequestId)
|
|
6517
|
+
})
|
|
6518
|
+
);
|
|
6474
6519
|
var threadHistoryItems = sqliteTable(
|
|
6475
6520
|
"thread_history_items",
|
|
6476
6521
|
{
|
|
@@ -6704,6 +6749,7 @@ function createThreadRecord(db, input) {
|
|
|
6704
6749
|
fastBaseModel: input.fastBaseModel ?? null,
|
|
6705
6750
|
fastBaseReasoningEffort: input.fastBaseReasoningEffort ?? null,
|
|
6706
6751
|
collaborationMode: input.collaborationMode ?? "default",
|
|
6752
|
+
activeTurnCollaborationMode: input.activeTurnCollaborationMode ?? null,
|
|
6707
6753
|
approvalMode: input.approvalMode,
|
|
6708
6754
|
sandboxMode: input.sandboxMode ?? null,
|
|
6709
6755
|
status: "idle",
|
|
@@ -6843,6 +6889,8 @@ function createThreadPendingSteerRecord(db, input) {
|
|
|
6843
6889
|
clientRequestId: input.clientRequestId ?? null,
|
|
6844
6890
|
displayPrompt: input.displayPrompt,
|
|
6845
6891
|
submittedPrompt: input.submittedPrompt,
|
|
6892
|
+
delivery: input.delivery ?? "steer",
|
|
6893
|
+
turnConfigJson: input.turnConfigJson ?? null,
|
|
6846
6894
|
createdAt: now,
|
|
6847
6895
|
updatedAt: now
|
|
6848
6896
|
};
|
|
@@ -6855,6 +6903,48 @@ function deleteThreadPendingSteerRecordById(db, id) {
|
|
|
6855
6903
|
function deleteThreadPendingSteerRecordsByThreadId(db, threadId) {
|
|
6856
6904
|
db.delete(threadPendingSteers).where(eq(threadPendingSteers.threadId, threadId)).run();
|
|
6857
6905
|
}
|
|
6906
|
+
function getThreadPromptRequestRecord(db, threadId, clientRequestId) {
|
|
6907
|
+
return db.select().from(threadPromptRequests).where(
|
|
6908
|
+
and(
|
|
6909
|
+
eq(threadPromptRequests.threadId, threadId),
|
|
6910
|
+
eq(threadPromptRequests.clientRequestId, clientRequestId)
|
|
6911
|
+
)
|
|
6912
|
+
).get();
|
|
6913
|
+
}
|
|
6914
|
+
function createThreadPromptRequestRecord(db, threadId, clientRequestId) {
|
|
6915
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6916
|
+
db.insert(threadPromptRequests).values({
|
|
6917
|
+
id: randomUUID(),
|
|
6918
|
+
threadId,
|
|
6919
|
+
clientRequestId,
|
|
6920
|
+
status: "processing",
|
|
6921
|
+
createdAt: now,
|
|
6922
|
+
updatedAt: now
|
|
6923
|
+
}).onConflictDoNothing().run();
|
|
6924
|
+
return getThreadPromptRequestRecord(db, threadId, clientRequestId);
|
|
6925
|
+
}
|
|
6926
|
+
function markThreadPromptRequestAccepted(db, threadId, clientRequestId) {
|
|
6927
|
+
db.update(threadPromptRequests).set({ status: "accepted", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(
|
|
6928
|
+
and(
|
|
6929
|
+
eq(threadPromptRequests.threadId, threadId),
|
|
6930
|
+
eq(threadPromptRequests.clientRequestId, clientRequestId)
|
|
6931
|
+
)
|
|
6932
|
+
).run();
|
|
6933
|
+
}
|
|
6934
|
+
function deleteExpiredThreadPromptRequestRecords(db, cutoff) {
|
|
6935
|
+
return db.delete(threadPromptRequests).where(lt(threadPromptRequests.updatedAt, cutoff)).run();
|
|
6936
|
+
}
|
|
6937
|
+
function deleteThreadPromptRequestRecord(db, threadId, clientRequestId) {
|
|
6938
|
+
db.delete(threadPromptRequests).where(
|
|
6939
|
+
and(
|
|
6940
|
+
eq(threadPromptRequests.threadId, threadId),
|
|
6941
|
+
eq(threadPromptRequests.clientRequestId, clientRequestId)
|
|
6942
|
+
)
|
|
6943
|
+
).run();
|
|
6944
|
+
}
|
|
6945
|
+
function deleteThreadPromptRequestRecordsByThreadId(db, threadId) {
|
|
6946
|
+
db.delete(threadPromptRequests).where(eq(threadPromptRequests.threadId, threadId)).run();
|
|
6947
|
+
}
|
|
6858
6948
|
function listThreadActivityNotesByThreadId(db, threadId) {
|
|
6859
6949
|
return db.select().from(threadActivityNotes).where(eq(threadActivityNotes.threadId, threadId)).orderBy(threadActivityNotes.createdAt).all();
|
|
6860
6950
|
}
|
|
@@ -7838,6 +7928,14 @@ var CodexAppServerManager = class extends EventEmitter3 {
|
|
|
7838
7928
|
});
|
|
7839
7929
|
return response.data.map(mapModel);
|
|
7840
7930
|
}
|
|
7931
|
+
async readAccount() {
|
|
7932
|
+
await this.ensureReady();
|
|
7933
|
+
return this.client.request("account/read", { refreshToken: false });
|
|
7934
|
+
}
|
|
7935
|
+
async readAccountRateLimits() {
|
|
7936
|
+
await this.ensureReady();
|
|
7937
|
+
return this.client.request("account/rateLimits/read", null);
|
|
7938
|
+
}
|
|
7841
7939
|
async listThreads() {
|
|
7842
7940
|
await this.ensureReady();
|
|
7843
7941
|
const response = await this.client.request("thread/list", {
|
|
@@ -10525,6 +10623,16 @@ function mapCodexNotification(event) {
|
|
|
10525
10623
|
return null;
|
|
10526
10624
|
}
|
|
10527
10625
|
}
|
|
10626
|
+
function formatRateLimitWindowLabel(durationMinutes, fallback) {
|
|
10627
|
+
if (durationMinutes === null) return fallback;
|
|
10628
|
+
if (durationMinutes % (60 * 24) === 0) {
|
|
10629
|
+
return `${durationMinutes / (60 * 24)}d`;
|
|
10630
|
+
}
|
|
10631
|
+
if (durationMinutes % 60 === 0) {
|
|
10632
|
+
return `${durationMinutes / 60}h`;
|
|
10633
|
+
}
|
|
10634
|
+
return `${durationMinutes}m`;
|
|
10635
|
+
}
|
|
10528
10636
|
function mapCodexRuntimeError(error) {
|
|
10529
10637
|
if (error instanceof AgentRuntimeError) {
|
|
10530
10638
|
throw error;
|
|
@@ -10642,6 +10750,51 @@ var CodexRuntimeAdapter = class extends EventEmitter4 {
|
|
|
10642
10750
|
getStatus() {
|
|
10643
10751
|
return mapStatus(this.manager.getStatus());
|
|
10644
10752
|
}
|
|
10753
|
+
async getSubscriptionUsage() {
|
|
10754
|
+
const account = await codexRuntimeCall(() => this.manager.readAccount());
|
|
10755
|
+
if (account.account?.type === "apiKey") {
|
|
10756
|
+
return {
|
|
10757
|
+
provider: "codex",
|
|
10758
|
+
authKind: "apiKey",
|
|
10759
|
+
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10760
|
+
stale: false,
|
|
10761
|
+
windows: []
|
|
10762
|
+
};
|
|
10763
|
+
}
|
|
10764
|
+
if (account.account?.type !== "chatgpt") {
|
|
10765
|
+
return null;
|
|
10766
|
+
}
|
|
10767
|
+
const response = await codexRuntimeCall(
|
|
10768
|
+
() => this.manager.readAccountRateLimits()
|
|
10769
|
+
);
|
|
10770
|
+
const buckets = response.rateLimitsByLimitId;
|
|
10771
|
+
const snapshot = (buckets && (buckets.codex ?? Object.values(buckets)[0])) ?? response.rateLimits;
|
|
10772
|
+
const record = snapshot && typeof snapshot === "object" ? snapshot : {};
|
|
10773
|
+
const windows = ["primary", "secondary"].flatMap((id) => {
|
|
10774
|
+
const value = record[id];
|
|
10775
|
+
if (!value || typeof value !== "object") return [];
|
|
10776
|
+
const window = value;
|
|
10777
|
+
const usedPercent = Number(window.usedPercent);
|
|
10778
|
+
if (!Number.isFinite(usedPercent)) return [];
|
|
10779
|
+
const duration = Number(window.windowDurationMins);
|
|
10780
|
+
const durationMinutes = Number.isFinite(duration) ? duration : null;
|
|
10781
|
+
const resetsAt = Number(window.resetsAt);
|
|
10782
|
+
return [{
|
|
10783
|
+
id,
|
|
10784
|
+
durationMinutes,
|
|
10785
|
+
label: formatRateLimitWindowLabel(durationMinutes, id),
|
|
10786
|
+
usedPercent: Math.max(0, Math.min(100, usedPercent)),
|
|
10787
|
+
resetsAt: Number.isFinite(resetsAt) ? new Date(resetsAt * 1e3).toISOString() : null
|
|
10788
|
+
}];
|
|
10789
|
+
});
|
|
10790
|
+
return {
|
|
10791
|
+
provider: "codex",
|
|
10792
|
+
authKind: "subscription",
|
|
10793
|
+
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10794
|
+
stale: false,
|
|
10795
|
+
windows
|
|
10796
|
+
};
|
|
10797
|
+
}
|
|
10645
10798
|
start() {
|
|
10646
10799
|
return codexRuntimeCall(() => this.manager.start());
|
|
10647
10800
|
}
|
|
@@ -11970,6 +12123,7 @@ function addClaudeUsage(left, right) {
|
|
|
11970
12123
|
totalTokens: left.totalTokens + right.totalTokens,
|
|
11971
12124
|
inputTokens: left.inputTokens + right.inputTokens,
|
|
11972
12125
|
cachedInputTokens: left.cachedInputTokens + right.cachedInputTokens,
|
|
12126
|
+
cacheWriteInputTokens: left.cacheWriteInputTokens + right.cacheWriteInputTokens,
|
|
11973
12127
|
outputTokens: left.outputTokens + right.outputTokens,
|
|
11974
12128
|
reasoningOutputTokens: left.reasoningOutputTokens + right.reasoningOutputTokens
|
|
11975
12129
|
};
|
|
@@ -11995,6 +12149,7 @@ function normalizeClaudeUsage(value) {
|
|
|
11995
12149
|
totalTokens: totalTokens2,
|
|
11996
12150
|
inputTokens,
|
|
11997
12151
|
cachedInputTokens: cacheReadInputTokens,
|
|
12152
|
+
cacheWriteInputTokens: cacheCreationInputTokens,
|
|
11998
12153
|
outputTokens,
|
|
11999
12154
|
reasoningOutputTokens: 0
|
|
12000
12155
|
};
|
|
@@ -12346,11 +12501,44 @@ var ClaudeRuntimeAdapter = class extends EventEmitter5 {
|
|
|
12346
12501
|
sessionModels = /* @__PURE__ */ new Map();
|
|
12347
12502
|
sessionApprovalModes = /* @__PURE__ */ new Map();
|
|
12348
12503
|
liveUserPrompts = /* @__PURE__ */ new Map();
|
|
12504
|
+
subscriptionUsageWindows = /* @__PURE__ */ new Map();
|
|
12505
|
+
subscriptionUsageObservedAt = null;
|
|
12349
12506
|
clientApp;
|
|
12350
12507
|
sdkLoadError = null;
|
|
12351
12508
|
getStatus() {
|
|
12352
12509
|
return { ...this.status };
|
|
12353
12510
|
}
|
|
12511
|
+
async getSubscriptionUsage() {
|
|
12512
|
+
const observedAt = this.subscriptionUsageObservedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
12513
|
+
const windows = [...this.subscriptionUsageWindows.entries()].map(([id, window]) => ({
|
|
12514
|
+
id,
|
|
12515
|
+
durationMinutes: id === "five_hour" ? 300 : 10080,
|
|
12516
|
+
label: id === "five_hour" ? "5h" : "7d",
|
|
12517
|
+
usedPercent: window.usedPercent,
|
|
12518
|
+
resetsAt: window.resetsAt
|
|
12519
|
+
}));
|
|
12520
|
+
return {
|
|
12521
|
+
provider: "claude",
|
|
12522
|
+
authKind: windows.length > 0 ? "subscription" : "unknown",
|
|
12523
|
+
observedAt,
|
|
12524
|
+
stale: false,
|
|
12525
|
+
windows
|
|
12526
|
+
};
|
|
12527
|
+
}
|
|
12528
|
+
captureRateLimit(message) {
|
|
12529
|
+
if (message.type !== "rate_limit_event") {
|
|
12530
|
+
return;
|
|
12531
|
+
}
|
|
12532
|
+
const info = message.rate_limit_info;
|
|
12533
|
+
if (!info || info.rateLimitType !== "five_hour" && info.rateLimitType !== "seven_day" || typeof info.utilization !== "number" || !Number.isFinite(info.utilization)) {
|
|
12534
|
+
return;
|
|
12535
|
+
}
|
|
12536
|
+
this.subscriptionUsageWindows.set(info.rateLimitType, {
|
|
12537
|
+
usedPercent: Math.max(0, Math.min(100, info.utilization * 100)),
|
|
12538
|
+
resetsAt: typeof info.resetsAt === "number" ? new Date(info.resetsAt * 1e3).toISOString() : null
|
|
12539
|
+
});
|
|
12540
|
+
this.subscriptionUsageObservedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
12541
|
+
}
|
|
12354
12542
|
updateToolboxItemsFromSystemInit(message) {
|
|
12355
12543
|
this.managementSchema.toolboxItems = buildClaudeToolboxItems(
|
|
12356
12544
|
normalizeClaudeSlashCommands(message.slash_commands)
|
|
@@ -12498,6 +12686,7 @@ var ClaudeRuntimeAdapter = class extends EventEmitter5 {
|
|
|
12498
12686
|
try {
|
|
12499
12687
|
for await (const message of query) {
|
|
12500
12688
|
rawMessages.push(message);
|
|
12689
|
+
this.captureRateLimit(message);
|
|
12501
12690
|
if (message.type === "system" && message.subtype === "init") {
|
|
12502
12691
|
this.updateToolboxItemsFromSystemInit(message);
|
|
12503
12692
|
const sessionId = message.session_id;
|
|
@@ -12745,6 +12934,7 @@ var ClaudeRuntimeAdapter = class extends EventEmitter5 {
|
|
|
12745
12934
|
try {
|
|
12746
12935
|
for await (const message of state.query) {
|
|
12747
12936
|
rawMessages.push(message);
|
|
12937
|
+
this.captureRateLimit(message);
|
|
12748
12938
|
this.consumeMessage(state, message);
|
|
12749
12939
|
const status = queryResultStatus(message);
|
|
12750
12940
|
if (status) {
|
|
@@ -14278,6 +14468,9 @@ function openCodeUsageFromTokens(tokens) {
|
|
|
14278
14468
|
const cachedInputTokens = nonNegativeNumberValue(
|
|
14279
14469
|
tokens.cachedInputTokens ?? tokens.cached_input_tokens ?? cache?.read
|
|
14280
14470
|
) ?? 0;
|
|
14471
|
+
const cacheWriteInputTokens = nonNegativeNumberValue(
|
|
14472
|
+
tokens.cacheWriteInputTokens ?? tokens.cache_write_input_tokens ?? tokens.cacheWriteTokens ?? tokens.cache_write_tokens ?? cache?.write
|
|
14473
|
+
) ?? 0;
|
|
14281
14474
|
const totalTokens2 = nonNegativeNumberValue(tokens.total ?? tokens.totalTokens ?? tokens.total_tokens) ?? inputTokens + outputTokens;
|
|
14282
14475
|
if (totalTokens2 <= 0) {
|
|
14283
14476
|
return null;
|
|
@@ -14287,6 +14480,7 @@ function openCodeUsageFromTokens(tokens) {
|
|
|
14287
14480
|
totalTokens: totalTokens2,
|
|
14288
14481
|
inputTokens,
|
|
14289
14482
|
cachedInputTokens,
|
|
14483
|
+
...cacheWriteInputTokens > 0 ? { cacheWriteInputTokens } : {},
|
|
14290
14484
|
outputTokens,
|
|
14291
14485
|
reasoningOutputTokens
|
|
14292
14486
|
},
|
|
@@ -14344,6 +14538,9 @@ function turnTokenUsage(messages, model) {
|
|
|
14344
14538
|
totalTokens: sum.totalTokens + usage.totalTokens,
|
|
14345
14539
|
inputTokens: sum.inputTokens + usage.inputTokens,
|
|
14346
14540
|
cachedInputTokens: sum.cachedInputTokens + usage.cachedInputTokens,
|
|
14541
|
+
...(sum.cacheWriteInputTokens ?? 0) + (usage.cacheWriteInputTokens ?? 0) > 0 ? {
|
|
14542
|
+
cacheWriteInputTokens: (sum.cacheWriteInputTokens ?? 0) + (usage.cacheWriteInputTokens ?? 0)
|
|
14543
|
+
} : {},
|
|
14347
14544
|
outputTokens: sum.outputTokens + usage.outputTokens,
|
|
14348
14545
|
reasoningOutputTokens: sum.reasoningOutputTokens + usage.reasoningOutputTokens
|
|
14349
14546
|
}), firstRecord);
|
|
@@ -16040,6 +16237,7 @@ var ThreadAuxiliaryStateStore = class {
|
|
|
16040
16237
|
clientRequestId: record.clientRequestId ?? null,
|
|
16041
16238
|
turnId: record.turnId,
|
|
16042
16239
|
prompt: record.displayPrompt,
|
|
16240
|
+
delivery: record.delivery === "continuation" ? "continuation" : "steer",
|
|
16043
16241
|
createdAt: record.createdAt
|
|
16044
16242
|
}));
|
|
16045
16243
|
}
|
|
@@ -16056,6 +16254,11 @@ var ThreadAuxiliaryStateStore = class {
|
|
|
16056
16254
|
hasPendingSteersForTurn(localThreadId, turnId) {
|
|
16057
16255
|
return this.listPendingSteerRecordsForTurn(localThreadId, turnId).length > 0;
|
|
16058
16256
|
}
|
|
16257
|
+
hasQueuedContinuationsForTurn(localThreadId, turnId) {
|
|
16258
|
+
return this.listPendingSteerRecordsForTurn(localThreadId, turnId).some(
|
|
16259
|
+
(record) => record.delivery === "continuation"
|
|
16260
|
+
);
|
|
16261
|
+
}
|
|
16059
16262
|
deletePendingSteerRecord(localThreadId, id, turnId) {
|
|
16060
16263
|
deleteThreadPendingSteerRecordById(this.db, id);
|
|
16061
16264
|
this.callbacks.invalidateThreadDetailCache(localThreadId);
|
|
@@ -17311,11 +17514,18 @@ function shouldResetThreadContextUsageForTurnStart(current) {
|
|
|
17311
17514
|
}
|
|
17312
17515
|
function buildTurnTokenBreakdown(payload) {
|
|
17313
17516
|
const usage = isRecord12(payload) ? payload : null;
|
|
17517
|
+
const inputDetails = isRecord12(
|
|
17518
|
+
usage?.inputTokensDetails ?? usage?.input_tokens_details
|
|
17519
|
+
) ? usage?.inputTokensDetails ?? usage?.input_tokens_details : null;
|
|
17520
|
+
const cache = isRecord12(usage?.cache) ? usage.cache : null;
|
|
17314
17521
|
const totalTokens2 = numberOrNull2(usage?.totalTokens ?? usage?.total_tokens);
|
|
17315
17522
|
const inputTokens = numberOrNull2(usage?.inputTokens ?? usage?.input_tokens);
|
|
17316
17523
|
const cachedInputTokens = numberOrNull2(
|
|
17317
|
-
usage?.cachedInputTokens ?? usage?.cached_input_tokens
|
|
17524
|
+
usage?.cachedInputTokens ?? usage?.cached_input_tokens ?? inputDetails?.cachedTokens ?? inputDetails?.cached_tokens ?? cache?.read
|
|
17318
17525
|
);
|
|
17526
|
+
const cacheWriteInputTokens = numberOrNull2(
|
|
17527
|
+
usage?.cacheWriteInputTokens ?? usage?.cache_write_input_tokens ?? usage?.cacheWriteTokens ?? usage?.cache_write_tokens ?? usage?.cacheCreationInputTokens ?? usage?.cache_creation_input_tokens ?? inputDetails?.cacheWriteTokens ?? inputDetails?.cache_write_tokens ?? cache?.write
|
|
17528
|
+
) ?? 0;
|
|
17319
17529
|
const outputTokens = numberOrNull2(usage?.outputTokens ?? usage?.output_tokens);
|
|
17320
17530
|
const reasoningOutputTokens = numberOrNull2(
|
|
17321
17531
|
usage?.reasoningOutputTokens ?? usage?.reasoning_output_tokens
|
|
@@ -17327,6 +17537,7 @@ function buildTurnTokenBreakdown(payload) {
|
|
|
17327
17537
|
totalTokens: totalTokens2,
|
|
17328
17538
|
inputTokens,
|
|
17329
17539
|
cachedInputTokens,
|
|
17540
|
+
cacheWriteInputTokens,
|
|
17330
17541
|
outputTokens,
|
|
17331
17542
|
reasoningOutputTokens
|
|
17332
17543
|
};
|
|
@@ -17336,6 +17547,7 @@ function zeroTurnTokenBreakdown() {
|
|
|
17336
17547
|
totalTokens: 0,
|
|
17337
17548
|
inputTokens: 0,
|
|
17338
17549
|
cachedInputTokens: 0,
|
|
17550
|
+
cacheWriteInputTokens: 0,
|
|
17339
17551
|
outputTokens: 0,
|
|
17340
17552
|
reasoningOutputTokens: 0
|
|
17341
17553
|
};
|
|
@@ -17348,6 +17560,10 @@ function subtractTurnTokenBreakdowns(current, previous) {
|
|
|
17348
17560
|
current.cachedInputTokens - previous.cachedInputTokens,
|
|
17349
17561
|
0
|
|
17350
17562
|
),
|
|
17563
|
+
cacheWriteInputTokens: Math.max(
|
|
17564
|
+
current.cacheWriteInputTokens - previous.cacheWriteInputTokens,
|
|
17565
|
+
0
|
|
17566
|
+
),
|
|
17351
17567
|
outputTokens: Math.max(current.outputTokens - previous.outputTokens, 0),
|
|
17352
17568
|
reasoningOutputTokens: Math.max(
|
|
17353
17569
|
current.reasoningOutputTokens - previous.reasoningOutputTokens,
|
|
@@ -17406,12 +17622,16 @@ function cumulativeTotalFromStoredThreadTurnTokenUsageState(state) {
|
|
|
17406
17622
|
return null;
|
|
17407
17623
|
}
|
|
17408
17624
|
if (!state.baselineTotal) {
|
|
17409
|
-
return
|
|
17625
|
+
return {
|
|
17626
|
+
...state.usage.total,
|
|
17627
|
+
cacheWriteInputTokens: state.usage.total.cacheWriteInputTokens ?? 0
|
|
17628
|
+
};
|
|
17410
17629
|
}
|
|
17411
17630
|
return {
|
|
17412
17631
|
totalTokens: state.baselineTotal.totalTokens + state.usage.total.totalTokens,
|
|
17413
17632
|
inputTokens: state.baselineTotal.inputTokens + state.usage.total.inputTokens,
|
|
17414
17633
|
cachedInputTokens: state.baselineTotal.cachedInputTokens + state.usage.total.cachedInputTokens,
|
|
17634
|
+
cacheWriteInputTokens: state.baselineTotal.cacheWriteInputTokens + (state.usage.total.cacheWriteInputTokens ?? 0),
|
|
17415
17635
|
outputTokens: state.baselineTotal.outputTokens + state.usage.total.outputTokens,
|
|
17416
17636
|
reasoningOutputTokens: state.baselineTotal.reasoningOutputTokens + state.usage.total.reasoningOutputTokens
|
|
17417
17637
|
};
|
|
@@ -17838,6 +18058,7 @@ var ThreadRuntimeEventProjector = class {
|
|
|
17838
18058
|
const turnItems = event.turn.items;
|
|
17839
18059
|
updateThreadRecord(db, record.id, {
|
|
17840
18060
|
providerTurnId: null,
|
|
18061
|
+
activeTurnCollaborationMode: null,
|
|
17841
18062
|
status: event.turn.status === "failed" ? "failed" : event.turn.status === "interrupted" ? "interrupted" : "idle",
|
|
17842
18063
|
lastError: event.turn.error?.message ?? null,
|
|
17843
18064
|
lastTurnCompletedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -17859,7 +18080,9 @@ var ThreadRuntimeEventProjector = class {
|
|
|
17859
18080
|
}
|
|
17860
18081
|
}
|
|
17861
18082
|
callbacks.clearTerminalPendingRequests(record.id, true);
|
|
17862
|
-
if (event.turn.status === "completed" &&
|
|
18083
|
+
if (event.turn.status === "completed" && !preservePendingSteers && callbacks.normalizeCollaborationMode(
|
|
18084
|
+
record.activeTurnCollaborationMode ?? record.collaborationMode
|
|
18085
|
+
) === "plan" && turnItems.some((item) => item.kind === "plan") && !callbacks.hasPendingAskUserQuestion(record.id)) {
|
|
17863
18086
|
callbacks.createPendingPlanDecisionRequest(record.id, turnId, true);
|
|
17864
18087
|
} else {
|
|
17865
18088
|
callbacks.dismissPlanDecisionTurn(record.id);
|
|
@@ -17891,6 +18114,7 @@ var ThreadRuntimeEventProjector = class {
|
|
|
17891
18114
|
const turnId = liveState.displayTurnIdForRuntimeTurn(record.id, event.providerTurnId) ?? event.providerTurnId;
|
|
17892
18115
|
updateThreadRecord(db, record.id, {
|
|
17893
18116
|
providerTurnId: null,
|
|
18117
|
+
activeTurnCollaborationMode: null,
|
|
17894
18118
|
status: "failed",
|
|
17895
18119
|
lastError: event.error,
|
|
17896
18120
|
lastTurnCompletedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -18763,6 +18987,7 @@ function normalizeReasoningEffort(value) {
|
|
|
18763
18987
|
case "high":
|
|
18764
18988
|
case "xhigh":
|
|
18765
18989
|
case "max":
|
|
18990
|
+
case "ultra":
|
|
18766
18991
|
return value;
|
|
18767
18992
|
default:
|
|
18768
18993
|
return null;
|
|
@@ -18779,6 +19004,7 @@ function normalizeReasoningEffort2(value) {
|
|
|
18779
19004
|
case "high":
|
|
18780
19005
|
case "xhigh":
|
|
18781
19006
|
case "max":
|
|
19007
|
+
case "ultra":
|
|
18782
19008
|
return value;
|
|
18783
19009
|
default:
|
|
18784
19010
|
return null;
|
|
@@ -19221,6 +19447,7 @@ var ThreadPromptTurnCoordinator = class {
|
|
|
19221
19447
|
model: input.effectiveModel,
|
|
19222
19448
|
reasoningEffort: input.normalizedReasoning,
|
|
19223
19449
|
collaborationMode: input.collaborationMode,
|
|
19450
|
+
activeTurnCollaborationMode: input.collaborationMode,
|
|
19224
19451
|
sandboxMode: input.sandboxMode
|
|
19225
19452
|
};
|
|
19226
19453
|
if (isAutoGeneratedTitle(record.title)) {
|
|
@@ -19343,7 +19570,8 @@ var ThreadPromptTurnCoordinator = class {
|
|
|
19343
19570
|
turnId: steerTurnId,
|
|
19344
19571
|
clientRequestId: input.clientRequestId,
|
|
19345
19572
|
displayPrompt: input.displayPrompt,
|
|
19346
|
-
submittedPrompt: input.prompt
|
|
19573
|
+
submittedPrompt: input.prompt,
|
|
19574
|
+
delivery: "steer"
|
|
19347
19575
|
});
|
|
19348
19576
|
this.callbacks.invalidateThreadDetailCache(localThreadId);
|
|
19349
19577
|
this.callbacks.emitThreadUpdated(localThreadId, {
|
|
@@ -19392,7 +19620,16 @@ var ThreadPromptTurnCoordinator = class {
|
|
|
19392
19620
|
turnId: displayTurnId,
|
|
19393
19621
|
clientRequestId: input.clientRequestId,
|
|
19394
19622
|
displayPrompt: input.displayPrompt,
|
|
19395
|
-
submittedPrompt: input.prompt
|
|
19623
|
+
submittedPrompt: input.prompt,
|
|
19624
|
+
delivery: "continuation",
|
|
19625
|
+
turnConfigJson: JSON.stringify({
|
|
19626
|
+
effectiveModel: input.effectiveModel,
|
|
19627
|
+
normalizedReasoning: input.normalizedReasoning,
|
|
19628
|
+
collaborationMode: input.collaborationMode,
|
|
19629
|
+
sandboxMode: input.sandboxMode,
|
|
19630
|
+
performanceMode: input.performanceMode,
|
|
19631
|
+
startNewTurn: input.collaborationMode !== (record.activeTurnCollaborationMode === "plan" ? "plan" : "default")
|
|
19632
|
+
})
|
|
19396
19633
|
});
|
|
19397
19634
|
this.callbacks.invalidateThreadDetailCache(localThreadId);
|
|
19398
19635
|
this.callbacks.emitThreadUpdated(localThreadId, {
|
|
@@ -19598,7 +19835,7 @@ var ThreadSessionCoordinator = class {
|
|
|
19598
19835
|
if (!isRemoteThreadBootstrapError(error)) {
|
|
19599
19836
|
throw error;
|
|
19600
19837
|
}
|
|
19601
|
-
return { status: "bootstrap_unavailable" };
|
|
19838
|
+
return { status: "bootstrap_unavailable", error };
|
|
19602
19839
|
}
|
|
19603
19840
|
const effectiveModel = input.resumeInput.model ?? input.currentModel ?? response.model ?? null;
|
|
19604
19841
|
const resumedReasoning = this.providerRuntime.normalizeReasoningForModel(
|
|
@@ -19774,6 +20011,37 @@ var ThreadSessionLifecycleCoordinator = class {
|
|
|
19774
20011
|
fastMode: record.fastMode
|
|
19775
20012
|
});
|
|
19776
20013
|
if (resumed.status === "bootstrap_unavailable") {
|
|
20014
|
+
if (!this.canRecreateUnmaterializedThread(record, resumed.error)) {
|
|
20015
|
+
return;
|
|
20016
|
+
}
|
|
20017
|
+
const workspace = getWorkspaceRecordById(this.db, record.workspaceId);
|
|
20018
|
+
const model = input.model ?? record.model;
|
|
20019
|
+
if (!workspace || !model) {
|
|
20020
|
+
return;
|
|
20021
|
+
}
|
|
20022
|
+
const recreated = await this.sessionCoordinator.startThreadSession({
|
|
20023
|
+
workspacePath: workspace.absPath,
|
|
20024
|
+
threadInput: {
|
|
20025
|
+
workspaceId: workspace.id,
|
|
20026
|
+
title: record.title,
|
|
20027
|
+
provider: record.provider,
|
|
20028
|
+
model,
|
|
20029
|
+
reasoningEffort: record.reasoningEffort,
|
|
20030
|
+
approvalMode: record.approvalMode ?? "yolo"
|
|
20031
|
+
},
|
|
20032
|
+
defaultTitle: record.title
|
|
20033
|
+
});
|
|
20034
|
+
updateThreadRecord(this.db, record.id, {
|
|
20035
|
+
...buildThreadPatch(
|
|
20036
|
+
recreated.response.session,
|
|
20037
|
+
model,
|
|
20038
|
+
recreated.response.reasoningEffort ?? recreated.reasoningEffort
|
|
20039
|
+
),
|
|
20040
|
+
providerSessionId: recreated.response.providerSessionId,
|
|
20041
|
+
sandboxMode: recreated.sandboxMode,
|
|
20042
|
+
isConnected: true
|
|
20043
|
+
});
|
|
20044
|
+
this.callbacks.invalidateThreadDetailCache(localThreadId);
|
|
19777
20045
|
return;
|
|
19778
20046
|
}
|
|
19779
20047
|
updateThreadRecord(
|
|
@@ -19797,6 +20065,9 @@ var ThreadSessionLifecycleCoordinator = class {
|
|
|
19797
20065
|
}
|
|
19798
20066
|
this.callbacks.invalidateThreadDetailCache(localThreadId);
|
|
19799
20067
|
}
|
|
20068
|
+
canRecreateUnmaterializedThread(record, error) {
|
|
20069
|
+
return record.provider === "codex" && record.source === "supervisor" && listThreadTurnMetadataByThreadId(this.db, record.id).length === 0 && error instanceof AgentRuntimeError && error.provider === "codex" && error.code === "remote_error" && /thread not loaded|no rollout found/i.test(error.message);
|
|
20070
|
+
}
|
|
19800
20071
|
disconnectThread(localThreadId) {
|
|
19801
20072
|
const record = getThreadRecordById(this.db, localThreadId);
|
|
19802
20073
|
if (!record) {
|
|
@@ -19996,6 +20267,7 @@ var ThreadDeletionCoordinator = class {
|
|
|
19996
20267
|
deleteThreadGoalRecordsByThreadId(this.db, localThreadId);
|
|
19997
20268
|
deleteThreadHistoryItemRecordsByThreadId(this.db, localThreadId);
|
|
19998
20269
|
deleteThreadPendingSteerRecordsByThreadId(this.db, localThreadId);
|
|
20270
|
+
deleteThreadPromptRequestRecordsByThreadId(this.db, localThreadId);
|
|
19999
20271
|
deleteThreadTurnMetadataByThreadId(this.db, localThreadId);
|
|
20000
20272
|
deleteThreadRecord(this.db, localThreadId);
|
|
20001
20273
|
return { id: localThreadId };
|
|
@@ -21921,7 +22193,7 @@ var ThreadService = class {
|
|
|
21921
22193
|
normalizeCollaborationMode,
|
|
21922
22194
|
normalizeReasoningEffort: normalizeReasoningEffort2,
|
|
21923
22195
|
normalizeThreadGoalStatusForThread: (goal, record) => this.goalCoordinator.normalizeThreadGoalStatusForThread(goal, record),
|
|
21924
|
-
shouldPreservePendingSteersForCompletedTurn: (record, turnId) =>
|
|
22196
|
+
shouldPreservePendingSteersForCompletedTurn: (record, turnId) => this.shouldPreserveCompletedPendingSteer(record.id, turnId),
|
|
21925
22197
|
scheduleQueuedContinuationDrain: (localThreadId, turnId) => this.scheduleQueuedContinuationDrain(localThreadId, turnId),
|
|
21926
22198
|
persistLiveHistoryItem: (localThreadId, turnId, item) => this.historyPersistence.persistLiveHistoryItem(localThreadId, turnId, item),
|
|
21927
22199
|
persistFinalTurnOrderingHints: (localThreadId, turnId, items) => this.historyPersistence.persistFinalTurnOrderingHints(localThreadId, turnId, items),
|
|
@@ -21955,6 +22227,7 @@ var ThreadService = class {
|
|
|
21955
22227
|
config;
|
|
21956
22228
|
liveState = new ThreadLiveStateStore();
|
|
21957
22229
|
queuedContinuationDrains = /* @__PURE__ */ new Set();
|
|
22230
|
+
promptRequestsInFlight = /* @__PURE__ */ new Map();
|
|
21958
22231
|
detailAssembler;
|
|
21959
22232
|
usageAccounting;
|
|
21960
22233
|
requestCoordinator;
|
|
@@ -22273,6 +22546,57 @@ var ThreadService = class {
|
|
|
22273
22546
|
return this.getThreadDetail(localThreadId);
|
|
22274
22547
|
}
|
|
22275
22548
|
async sendPrompt(localThreadId, input, options = {}) {
|
|
22549
|
+
const clientRequestId = input.clientRequestId?.trim();
|
|
22550
|
+
if (!clientRequestId) {
|
|
22551
|
+
return this.sendPromptOnce(localThreadId, input, options);
|
|
22552
|
+
}
|
|
22553
|
+
const requestKey = `${localThreadId}:${clientRequestId}`;
|
|
22554
|
+
const activeRequest = this.promptRequestsInFlight.get(requestKey);
|
|
22555
|
+
if (activeRequest) {
|
|
22556
|
+
return activeRequest;
|
|
22557
|
+
}
|
|
22558
|
+
const request = this.sendPromptIdempotently(
|
|
22559
|
+
localThreadId,
|
|
22560
|
+
{ ...input, clientRequestId },
|
|
22561
|
+
options
|
|
22562
|
+
);
|
|
22563
|
+
this.promptRequestsInFlight.set(requestKey, request);
|
|
22564
|
+
try {
|
|
22565
|
+
return await request;
|
|
22566
|
+
} finally {
|
|
22567
|
+
if (this.promptRequestsInFlight.get(requestKey) === request) {
|
|
22568
|
+
this.promptRequestsInFlight.delete(requestKey);
|
|
22569
|
+
}
|
|
22570
|
+
}
|
|
22571
|
+
}
|
|
22572
|
+
async sendPromptIdempotently(localThreadId, input, options) {
|
|
22573
|
+
deleteExpiredThreadPromptRequestRecords(
|
|
22574
|
+
this.db,
|
|
22575
|
+
new Date(Date.now() - 7 * 24 * 60 * 60 * 1e3).toISOString()
|
|
22576
|
+
);
|
|
22577
|
+
const existing = getThreadPromptRequestRecord(
|
|
22578
|
+
this.db,
|
|
22579
|
+
localThreadId,
|
|
22580
|
+
input.clientRequestId
|
|
22581
|
+
);
|
|
22582
|
+
if (existing) {
|
|
22583
|
+
const record = this.requireThreadRecord(localThreadId);
|
|
22584
|
+
return this.toThreadDto(
|
|
22585
|
+
record,
|
|
22586
|
+
await this.listLoadedProviderSessionIds(record.provider)
|
|
22587
|
+
);
|
|
22588
|
+
}
|
|
22589
|
+
createThreadPromptRequestRecord(this.db, localThreadId, input.clientRequestId);
|
|
22590
|
+
try {
|
|
22591
|
+
const result = await this.sendPromptOnce(localThreadId, input, options);
|
|
22592
|
+
markThreadPromptRequestAccepted(this.db, localThreadId, input.clientRequestId);
|
|
22593
|
+
return result;
|
|
22594
|
+
} catch (error) {
|
|
22595
|
+
deleteThreadPromptRequestRecord(this.db, localThreadId, input.clientRequestId);
|
|
22596
|
+
throw error;
|
|
22597
|
+
}
|
|
22598
|
+
}
|
|
22599
|
+
async sendPromptOnce(localThreadId, input, options = {}) {
|
|
22276
22600
|
let record = this.requireThreadRecord(localThreadId);
|
|
22277
22601
|
await this.importCoordinator.assertImportedThreadReadyForPrompt({
|
|
22278
22602
|
source: record.source,
|
|
@@ -22338,7 +22662,10 @@ var ThreadService = class {
|
|
|
22338
22662
|
};
|
|
22339
22663
|
const hasActiveProviderTurn = Boolean(record.providerTurnId) && (record.status === "running" || !turnConfig.supportsRunningTurnInput && !record.lastTurnCompletedAt) && record.status !== "failed" && record.status !== "interrupted";
|
|
22340
22664
|
if (hasActiveProviderTurn && record.providerTurnId) {
|
|
22341
|
-
|
|
22665
|
+
const activeTurnCollaborationMode = normalizeCollaborationMode(
|
|
22666
|
+
record.activeTurnCollaborationMode ?? record.collaborationMode
|
|
22667
|
+
);
|
|
22668
|
+
if (!turnConfig.supportsRunningTurnInput || activeTurnCollaborationMode !== turnConfig.collaborationMode) {
|
|
22342
22669
|
return this.promptTurnCoordinator.queueContinuationPromptTurn(localThreadId, {
|
|
22343
22670
|
...connectedRecord,
|
|
22344
22671
|
providerTurnId: record.providerTurnId
|
|
@@ -22682,7 +23009,7 @@ var ThreadService = class {
|
|
|
22682
23009
|
if (!record) {
|
|
22683
23010
|
return false;
|
|
22684
23011
|
}
|
|
22685
|
-
return
|
|
23012
|
+
return this.auxiliaryState.hasQueuedContinuationsForTurn(localThreadId, turnId);
|
|
22686
23013
|
}
|
|
22687
23014
|
shouldPreserveMissingPendingSteer(localThreadId, turnId) {
|
|
22688
23015
|
const record = getThreadRecordById(this.db, localThreadId);
|
|
@@ -22692,14 +23019,11 @@ var ThreadService = class {
|
|
|
22692
23019
|
if (record.status === "failed" || record.status === "interrupted") {
|
|
22693
23020
|
return false;
|
|
22694
23021
|
}
|
|
22695
|
-
if (this.runtimeSupportsLiveRunningTurnInput(record.provider)) {
|
|
22696
|
-
return false;
|
|
22697
|
-
}
|
|
22698
23022
|
const activeDisplayTurnId = this.liveState.displayTurnIdForRuntimeTurn(
|
|
22699
23023
|
localThreadId,
|
|
22700
23024
|
record.providerTurnId
|
|
22701
23025
|
);
|
|
22702
|
-
return record.providerTurnId === turnId || activeDisplayTurnId === turnId;
|
|
23026
|
+
return (record.providerTurnId === turnId || activeDisplayTurnId === turnId) && this.auxiliaryState.hasQueuedContinuationsForTurn(localThreadId, turnId);
|
|
22703
23027
|
}
|
|
22704
23028
|
scheduleQueuedContinuationDrain(localThreadId, turnId) {
|
|
22705
23029
|
const key = `${localThreadId}:${turnId}`;
|
|
@@ -22723,7 +23047,7 @@ var ThreadService = class {
|
|
|
22723
23047
|
const pending = this.auxiliaryState.listPendingSteerRecordsForTurn(
|
|
22724
23048
|
localThreadId,
|
|
22725
23049
|
turnId
|
|
22726
|
-
)
|
|
23050
|
+
).find((entry) => entry.delivery === "continuation");
|
|
22727
23051
|
if (!pending) {
|
|
22728
23052
|
return;
|
|
22729
23053
|
}
|
|
@@ -22742,7 +23066,8 @@ var ThreadService = class {
|
|
|
22742
23066
|
const developerInstructions = combineDeveloperInstructions([
|
|
22743
23067
|
pluginDeveloperInstructions(this.pluginService)
|
|
22744
23068
|
]);
|
|
22745
|
-
const
|
|
23069
|
+
const queuedConfig = parseQueuedTurnConfig(pending.turnConfigJson);
|
|
23070
|
+
const turnConfig = queuedConfig ?? await this.sessionCoordinator.resolvePromptTurnConfig({
|
|
22746
23071
|
provider: record.provider,
|
|
22747
23072
|
currentModel: record.model,
|
|
22748
23073
|
currentReasoningEffort: record.reasoningEffort,
|
|
@@ -22752,14 +23077,16 @@ var ThreadService = class {
|
|
|
22752
23077
|
approvalMode: record.approvalMode ?? "yolo",
|
|
22753
23078
|
promptInput: {}
|
|
22754
23079
|
});
|
|
22755
|
-
|
|
22756
|
-
|
|
22757
|
-
|
|
22758
|
-
|
|
22759
|
-
|
|
22760
|
-
|
|
22761
|
-
|
|
22762
|
-
|
|
23080
|
+
if (!queuedConfig?.startNewTurn) {
|
|
23081
|
+
const queuedUserItemId = `queued-continuation:${pending.id}:user`;
|
|
23082
|
+
this.historyPersistence.persistProjectedHistoryItem(localThreadId, turnId, {
|
|
23083
|
+
id: queuedUserItemId,
|
|
23084
|
+
kind: "userMessage",
|
|
23085
|
+
text: pending.displayPrompt,
|
|
23086
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23087
|
+
sequence: this.liveState.recordTurnItemOrder(localThreadId, turnId, queuedUserItemId)
|
|
23088
|
+
});
|
|
23089
|
+
}
|
|
22763
23090
|
await this.promptTurnCoordinator.startPromptTurn(localThreadId, {
|
|
22764
23091
|
...record,
|
|
22765
23092
|
providerSessionId
|
|
@@ -22773,8 +23100,7 @@ var ThreadService = class {
|
|
|
22773
23100
|
sandboxMode: turnConfig.sandboxMode,
|
|
22774
23101
|
performanceMode: turnConfig.performanceMode,
|
|
22775
23102
|
workspacePath: workspace.absPath,
|
|
22776
|
-
hidden: true,
|
|
22777
|
-
displayTurnId: turnId
|
|
23103
|
+
...queuedConfig?.startNewTurn ? {} : { hidden: true, displayTurnId: turnId }
|
|
22778
23104
|
});
|
|
22779
23105
|
this.auxiliaryState.deletePendingSteerRecord(localThreadId, pending.id, turnId);
|
|
22780
23106
|
}
|
|
@@ -22862,6 +23188,27 @@ var ThreadService = class {
|
|
|
22862
23188
|
);
|
|
22863
23189
|
}
|
|
22864
23190
|
};
|
|
23191
|
+
function parseQueuedTurnConfig(value) {
|
|
23192
|
+
if (!value) {
|
|
23193
|
+
return null;
|
|
23194
|
+
}
|
|
23195
|
+
try {
|
|
23196
|
+
const parsed = JSON.parse(value);
|
|
23197
|
+
if (parsed.collaborationMode !== "default" && parsed.collaborationMode !== "plan" || parsed.performanceMode !== "fast" && parsed.performanceMode !== "standard" || typeof parsed.startNewTurn !== "boolean") {
|
|
23198
|
+
return null;
|
|
23199
|
+
}
|
|
23200
|
+
return {
|
|
23201
|
+
effectiveModel: typeof parsed.effectiveModel === "string" ? parsed.effectiveModel : null,
|
|
23202
|
+
normalizedReasoning: parsed.normalizedReasoning ?? null,
|
|
23203
|
+
collaborationMode: parsed.collaborationMode,
|
|
23204
|
+
sandboxMode: parsed.sandboxMode ?? "workspace-write",
|
|
23205
|
+
performanceMode: parsed.performanceMode,
|
|
23206
|
+
startNewTurn: parsed.startNewTurn
|
|
23207
|
+
};
|
|
23208
|
+
} catch {
|
|
23209
|
+
return null;
|
|
23210
|
+
}
|
|
23211
|
+
}
|
|
22865
23212
|
|
|
22866
23213
|
// src/routes/agent-runtimes.ts
|
|
22867
23214
|
import fs15 from "fs/promises";
|
|
@@ -22934,6 +23281,17 @@ async function registerAgentRuntimeRoutes(app2) {
|
|
|
22934
23281
|
const { provider: provider2 } = providerParamSchema.parse(request.params);
|
|
22935
23282
|
return runtimeDto(app2, provider2);
|
|
22936
23283
|
});
|
|
23284
|
+
app2.get("/api/agent-runtimes/:provider/subscription-usage", async (request) => {
|
|
23285
|
+
const { provider: provider2 } = providerParamSchema.parse(request.params);
|
|
23286
|
+
const runtime = app2.services.agentRuntimes.getOptional(provider2);
|
|
23287
|
+
if (!runtime) {
|
|
23288
|
+
throw providerNotConfigured(provider2);
|
|
23289
|
+
}
|
|
23290
|
+
if (!runtime.getSubscriptionUsage) {
|
|
23291
|
+
return { usage: null };
|
|
23292
|
+
}
|
|
23293
|
+
return { usage: await runtime.getSubscriptionUsage() };
|
|
23294
|
+
});
|
|
22937
23295
|
app2.post("/api/agent-runtimes/:provider/restart", async (request) => {
|
|
22938
23296
|
const { provider: provider2 } = providerParamSchema.parse(request.params);
|
|
22939
23297
|
const runtime = app2.services.agentRuntimes.getOptional(provider2);
|
|
@@ -23340,9 +23698,11 @@ function parseProviderHostFileParams(params) {
|
|
|
23340
23698
|
}
|
|
23341
23699
|
async function registerSystemRoutes(app2) {
|
|
23342
23700
|
app2.get("/healthz", async () => {
|
|
23701
|
+
const activeTurnCount = app2.services.database.sqlite.prepare("SELECT COUNT(*) AS count FROM threads WHERE status = 'running'").get();
|
|
23343
23702
|
return {
|
|
23344
23703
|
status: "ok",
|
|
23345
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
23704
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23705
|
+
activeTurnCount: activeTurnCount.count
|
|
23346
23706
|
};
|
|
23347
23707
|
});
|
|
23348
23708
|
app2.get("/readyz", async () => {
|
|
@@ -23519,7 +23879,8 @@ var reasoningEffortValues = [
|
|
|
23519
23879
|
"medium",
|
|
23520
23880
|
"high",
|
|
23521
23881
|
"xhigh",
|
|
23522
|
-
"max"
|
|
23882
|
+
"max",
|
|
23883
|
+
"ultra"
|
|
23523
23884
|
];
|
|
23524
23885
|
var createThreadSchema = z5.object({
|
|
23525
23886
|
workspaceId: z5.string().uuid(),
|
|
@@ -24963,7 +25324,16 @@ async function registerWorkspaceRoutes(app2) {
|
|
|
24963
25324
|
await cloneRepository(body.gitUrl.trim(), targetPath);
|
|
24964
25325
|
validated = await validateWorkspacePath(app2.services.config.workspaceRoot, targetPath);
|
|
24965
25326
|
} else {
|
|
24966
|
-
|
|
25327
|
+
const requestedPath = body.absPath.trim();
|
|
25328
|
+
const isWorkspaceName = !path22.isAbsolute(requestedPath) && /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(requestedPath) && requestedPath !== "." && requestedPath !== "..";
|
|
25329
|
+
if (!path22.isAbsolute(requestedPath) && !isWorkspaceName) {
|
|
25330
|
+
throw new HttpError(400, {
|
|
25331
|
+
code: "bad_request",
|
|
25332
|
+
message: "Use a simple directory name, an absolute path, or a Git URL."
|
|
25333
|
+
});
|
|
25334
|
+
}
|
|
25335
|
+
const targetPath = isWorkspaceName ? path22.join(settings.devHome, requestedPath) : requestedPath;
|
|
25336
|
+
validated = await validateWorkspacePath(app2.services.config.workspaceRoot, targetPath, {
|
|
24967
25337
|
devHome: settings.devHome,
|
|
24968
25338
|
createMissingLeaf: true
|
|
24969
25339
|
});
|
|
@@ -27915,6 +28285,7 @@ var RelayTunnelClient = class {
|
|
|
27915
28285
|
reconnectDelayMs = RELAY_RECONNECT_INITIAL_DELAY_MS;
|
|
27916
28286
|
stopped = false;
|
|
27917
28287
|
relayClientCleanup = /* @__PURE__ */ new Map();
|
|
28288
|
+
pendingActivity = /* @__PURE__ */ new Map();
|
|
27918
28289
|
validateConfig() {
|
|
27919
28290
|
if (!this.config.serverUrl || !this.config.agentToken) {
|
|
27920
28291
|
throw new Error(
|
|
@@ -27929,7 +28300,10 @@ var RelayTunnelClient = class {
|
|
|
27929
28300
|
if (this.socket) {
|
|
27930
28301
|
return;
|
|
27931
28302
|
}
|
|
27932
|
-
const url = new URL(
|
|
28303
|
+
const url = new URL(
|
|
28304
|
+
"/supervisor/tunnel",
|
|
28305
|
+
this.config.serverUrl ?? void 0
|
|
28306
|
+
);
|
|
27933
28307
|
url.searchParams.set("token", this.config.agentToken ?? "");
|
|
27934
28308
|
url.searchParams.set("deviceToken", this.config.agentToken ?? "");
|
|
27935
28309
|
const socket = new WebSocket(url);
|
|
@@ -27943,6 +28317,7 @@ var RelayTunnelClient = class {
|
|
|
27943
28317
|
this.clearConnectTimeout();
|
|
27944
28318
|
this.reconnectDelayMs = RELAY_RECONNECT_INITIAL_DELAY_MS;
|
|
27945
28319
|
this.sendHeartbeat();
|
|
28320
|
+
this.flushPendingActivity();
|
|
27946
28321
|
this.clearHeartbeat();
|
|
27947
28322
|
this.heartbeatHandle = setInterval(() => {
|
|
27948
28323
|
this.sendHeartbeat();
|
|
@@ -27967,6 +28342,29 @@ var RelayTunnelClient = class {
|
|
|
27967
28342
|
this.socket?.close();
|
|
27968
28343
|
this.socket = null;
|
|
27969
28344
|
}
|
|
28345
|
+
sendActivity(payload) {
|
|
28346
|
+
const key = `${payload.threadId}\0${payload.turnId}`;
|
|
28347
|
+
const socket = this.socket;
|
|
28348
|
+
if (socket?.readyState !== WebSocket.OPEN) {
|
|
28349
|
+
this.pendingActivity.set(key, payload);
|
|
28350
|
+
return;
|
|
28351
|
+
}
|
|
28352
|
+
const sent = this.sendEnvelope(socket, {
|
|
28353
|
+
type: "relay.activity",
|
|
28354
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28355
|
+
payload
|
|
28356
|
+
});
|
|
28357
|
+
if (sent) {
|
|
28358
|
+
this.pendingActivity.delete(key);
|
|
28359
|
+
} else {
|
|
28360
|
+
this.pendingActivity.set(key, payload);
|
|
28361
|
+
}
|
|
28362
|
+
}
|
|
28363
|
+
flushPendingActivity() {
|
|
28364
|
+
for (const payload of this.pendingActivity.values()) {
|
|
28365
|
+
this.sendActivity(payload);
|
|
28366
|
+
}
|
|
28367
|
+
}
|
|
27970
28368
|
sendHeartbeat() {
|
|
27971
28369
|
const socket = this.socket;
|
|
27972
28370
|
if (socket?.readyState !== WebSocket.OPEN) {
|
|
@@ -27986,9 +28384,12 @@ var RelayTunnelClient = class {
|
|
|
27986
28384
|
}
|
|
27987
28385
|
if (parsed.type !== "relay.request") {
|
|
27988
28386
|
if (parsed.type === "relay.client.connected") {
|
|
27989
|
-
const cleanup = this.handleClientConnected(
|
|
27990
|
-
|
|
27991
|
-
|
|
28387
|
+
const cleanup = this.handleClientConnected(
|
|
28388
|
+
parsed.clientId,
|
|
28389
|
+
(message) => {
|
|
28390
|
+
this.sendClientMessage(parsed.clientId, message);
|
|
28391
|
+
}
|
|
28392
|
+
);
|
|
27992
28393
|
this.relayClientCleanup.set(parsed.clientId, cleanup);
|
|
27993
28394
|
return;
|
|
27994
28395
|
}
|
|
@@ -27998,9 +28399,13 @@ var RelayTunnelClient = class {
|
|
|
27998
28399
|
return;
|
|
27999
28400
|
}
|
|
28000
28401
|
if (parsed.type === "relay.client.message") {
|
|
28001
|
-
await this.handleClientMessage(
|
|
28002
|
-
|
|
28003
|
-
|
|
28402
|
+
await this.handleClientMessage(
|
|
28403
|
+
parsed.clientId,
|
|
28404
|
+
parsed.payload,
|
|
28405
|
+
(message) => {
|
|
28406
|
+
this.sendClientMessage(parsed.clientId, message);
|
|
28407
|
+
}
|
|
28408
|
+
);
|
|
28004
28409
|
return;
|
|
28005
28410
|
}
|
|
28006
28411
|
return;
|
|
@@ -28010,15 +28415,12 @@ var RelayTunnelClient = class {
|
|
|
28010
28415
|
if (socket?.readyState !== WebSocket.OPEN) {
|
|
28011
28416
|
return;
|
|
28012
28417
|
}
|
|
28013
|
-
this.sendEnvelope(
|
|
28014
|
-
|
|
28015
|
-
|
|
28016
|
-
|
|
28017
|
-
|
|
28018
|
-
|
|
28019
|
-
payload: response
|
|
28020
|
-
}
|
|
28021
|
-
);
|
|
28418
|
+
this.sendEnvelope(socket, {
|
|
28419
|
+
type: "relay.response",
|
|
28420
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28421
|
+
requestId: parsed.requestId,
|
|
28422
|
+
payload: response
|
|
28423
|
+
});
|
|
28022
28424
|
}
|
|
28023
28425
|
sendClientMessage(clientId, message) {
|
|
28024
28426
|
const socket = this.socket;
|
|
@@ -28035,8 +28437,10 @@ var RelayTunnelClient = class {
|
|
|
28035
28437
|
sendEnvelope(socket, message) {
|
|
28036
28438
|
try {
|
|
28037
28439
|
socket.send(JSON.stringify(message));
|
|
28440
|
+
return true;
|
|
28038
28441
|
} catch {
|
|
28039
28442
|
this.closeAndReconnect(socket);
|
|
28443
|
+
return false;
|
|
28040
28444
|
}
|
|
28041
28445
|
}
|
|
28042
28446
|
closeAndReconnect(socket) {
|
|
@@ -28104,10 +28508,7 @@ var DEFAULT_WEBVIEW_CORS_ORIGINS = /* @__PURE__ */ new Set([
|
|
|
28104
28508
|
"https://localhost",
|
|
28105
28509
|
"https://appassets.androidplatform.net"
|
|
28106
28510
|
]);
|
|
28107
|
-
var WEBVIEW_CORS_ALLOW_HEADERS = [
|
|
28108
|
-
"authorization",
|
|
28109
|
-
"content-type"
|
|
28110
|
-
].join(", ");
|
|
28511
|
+
var WEBVIEW_CORS_ALLOW_HEADERS = ["authorization", "content-type"].join(", ");
|
|
28111
28512
|
var WEBVIEW_CORS_ALLOW_METHODS = [
|
|
28112
28513
|
"GET",
|
|
28113
28514
|
"POST",
|
|
@@ -28121,7 +28522,9 @@ function webViewCorsOrigins(env) {
|
|
|
28121
28522
|
return null;
|
|
28122
28523
|
}
|
|
28123
28524
|
const configured = env.REMOTE_CODEX_WEBVIEW_CORS_ORIGINS?.split(",").map((origin) => origin.trim()).filter(Boolean);
|
|
28124
|
-
return new Set(
|
|
28525
|
+
return new Set(
|
|
28526
|
+
configured?.length ? configured : DEFAULT_WEBVIEW_CORS_ORIGINS
|
|
28527
|
+
);
|
|
28125
28528
|
}
|
|
28126
28529
|
function applyWebViewCorsHeaders(reply, origin) {
|
|
28127
28530
|
reply.header("access-control-allow-origin", origin);
|
|
@@ -28170,7 +28573,11 @@ function createServiceLifecycle() {
|
|
|
28170
28573
|
});
|
|
28171
28574
|
}
|
|
28172
28575
|
const repoRoot = findRepoRoot();
|
|
28173
|
-
const restartScript = path28.join(
|
|
28576
|
+
const restartScript = path28.join(
|
|
28577
|
+
repoRoot,
|
|
28578
|
+
"scripts",
|
|
28579
|
+
"service-restart.mjs"
|
|
28580
|
+
);
|
|
28174
28581
|
if (!fs26.existsSync(restartScript) || !fs26.existsSync(path28.join(repoRoot, "pnpm-workspace.yaml"))) {
|
|
28175
28582
|
throw new HttpError(503, {
|
|
28176
28583
|
code: "service_unavailable",
|
|
@@ -28230,7 +28637,9 @@ function buildApp(options = {}) {
|
|
|
28230
28637
|
},
|
|
28231
28638
|
disableRequestLogging: config.disableRequestLogging
|
|
28232
28639
|
});
|
|
28233
|
-
const allowedWebViewCorsOrigins = webViewCorsOrigins(
|
|
28640
|
+
const allowedWebViewCorsOrigins = webViewCorsOrigins(
|
|
28641
|
+
options.env ?? process.env
|
|
28642
|
+
);
|
|
28234
28643
|
app2.addHook("onRequest", async (request, reply) => {
|
|
28235
28644
|
if (!allowedWebViewCorsOrigins) {
|
|
28236
28645
|
return;
|
|
@@ -28244,15 +28653,22 @@ function buildApp(options = {}) {
|
|
|
28244
28653
|
return reply.code(204).send();
|
|
28245
28654
|
}
|
|
28246
28655
|
});
|
|
28247
|
-
app2.register(
|
|
28248
|
-
|
|
28249
|
-
|
|
28250
|
-
|
|
28656
|
+
app2.register(
|
|
28657
|
+
multipart,
|
|
28658
|
+
{
|
|
28659
|
+
limits: {
|
|
28660
|
+
files: MAX_PROMPT_ATTACHMENTS2,
|
|
28661
|
+
fileSize: MAX_PROMPT_ATTACHMENT_BYTES2
|
|
28662
|
+
}
|
|
28251
28663
|
}
|
|
28252
|
-
|
|
28664
|
+
);
|
|
28253
28665
|
const backendPluginHost = new BackendPluginHost(app2);
|
|
28254
28666
|
backendPluginHost.register(createTerminalPluginBackendContribution());
|
|
28255
|
-
const relaySocketBridge = createRelaySocketBridge(
|
|
28667
|
+
const relaySocketBridge = createRelaySocketBridge(
|
|
28668
|
+
app2,
|
|
28669
|
+
eventBus,
|
|
28670
|
+
backendPluginHost
|
|
28671
|
+
);
|
|
28256
28672
|
const relayTunnelClient = config.mode === "relay" ? options.relayTunnelClient ?? new RelayTunnelClient(
|
|
28257
28673
|
config.relay,
|
|
28258
28674
|
createRelayRequestHandler(app2),
|
|
@@ -28260,6 +28676,31 @@ function buildApp(options = {}) {
|
|
|
28260
28676
|
relaySocketBridge.handleMessage
|
|
28261
28677
|
) : null;
|
|
28262
28678
|
relayTunnelClient?.validateConfig();
|
|
28679
|
+
const cleanupRelayActivity = relayTunnelClient ? eventBus.onThreadEvent((event) => {
|
|
28680
|
+
if (event.type === "thread.turn.started") {
|
|
28681
|
+
relayTunnelClient.sendActivity({
|
|
28682
|
+
kind: "turn_started",
|
|
28683
|
+
threadId: event.threadId,
|
|
28684
|
+
turnId: event.payload.turnId
|
|
28685
|
+
});
|
|
28686
|
+
return;
|
|
28687
|
+
}
|
|
28688
|
+
if (event.type === "thread.turn.completed") {
|
|
28689
|
+
relayTunnelClient.sendActivity({
|
|
28690
|
+
kind: "turn_terminal",
|
|
28691
|
+
threadId: event.threadId,
|
|
28692
|
+
turnId: event.payload.turnId
|
|
28693
|
+
});
|
|
28694
|
+
return;
|
|
28695
|
+
}
|
|
28696
|
+
if (event.type === "thread.turn.failed" && event.payload.willRetry !== true) {
|
|
28697
|
+
relayTunnelClient.sendActivity({
|
|
28698
|
+
kind: "turn_terminal",
|
|
28699
|
+
threadId: event.threadId,
|
|
28700
|
+
turnId: event.payload.turnId
|
|
28701
|
+
});
|
|
28702
|
+
}
|
|
28703
|
+
}) : null;
|
|
28263
28704
|
app2.decorate("services", {
|
|
28264
28705
|
config,
|
|
28265
28706
|
database,
|
|
@@ -28440,6 +28881,7 @@ function buildApp(options = {}) {
|
|
|
28440
28881
|
});
|
|
28441
28882
|
});
|
|
28442
28883
|
app2.addHook("onClose", async () => {
|
|
28884
|
+
cleanupRelayActivity?.();
|
|
28443
28885
|
await shellService.stop();
|
|
28444
28886
|
relayTunnelClient?.stop();
|
|
28445
28887
|
await Promise.all(agentRuntimes.all().map((runtime) => runtime.stop()));
|
|
@@ -28612,6 +29054,21 @@ if (fs27.existsSync(".env")) {
|
|
|
28612
29054
|
}
|
|
28613
29055
|
var app = buildApp();
|
|
28614
29056
|
var { host, port } = app.services.config;
|
|
29057
|
+
var closing = false;
|
|
29058
|
+
async function shutdown(signal) {
|
|
29059
|
+
if (closing) return;
|
|
29060
|
+
closing = true;
|
|
29061
|
+
app.log.info(`Supervisor API received ${signal}; closing cleanly.`);
|
|
29062
|
+
try {
|
|
29063
|
+
await app.close();
|
|
29064
|
+
process.exit(0);
|
|
29065
|
+
} catch (error) {
|
|
29066
|
+
app.log.error(error);
|
|
29067
|
+
process.exit(1);
|
|
29068
|
+
}
|
|
29069
|
+
}
|
|
29070
|
+
process.once("SIGTERM", () => void shutdown("SIGTERM"));
|
|
29071
|
+
process.once("SIGINT", () => void shutdown("SIGINT"));
|
|
28615
29072
|
app.listen({ host, port }).then(() => {
|
|
28616
29073
|
app.log.info(`Supervisor API listening on http://${host}:${port}`);
|
|
28617
29074
|
}).catch((error) => {
|