@alook/daemon 0.1.24 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +1567 -194
- package/dist/index.js +1525 -204
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -98,7 +98,7 @@ var init_nanoid = () => {};
|
|
|
98
98
|
// src/cli/index.ts
|
|
99
99
|
import { Command, CommanderError } from "commander";
|
|
100
100
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
101
|
-
import { randomUUID as
|
|
101
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
102
102
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
103
103
|
|
|
104
104
|
// ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
|
|
@@ -14397,6 +14397,7 @@ var exports_community_machine_schema = {};
|
|
|
14397
14397
|
__export(exports_community_machine_schema, {
|
|
14398
14398
|
communityMachineToken: () => communityMachineToken,
|
|
14399
14399
|
communityMachineCredential: () => communityMachineCredential,
|
|
14400
|
+
communityMachineBackendQuota: () => communityMachineBackendQuota,
|
|
14400
14401
|
communityMachine: () => communityMachine,
|
|
14401
14402
|
communityDiagnosticReport: () => communityDiagnosticReport,
|
|
14402
14403
|
communityBotBinding: () => communityBotBinding,
|
|
@@ -16000,6 +16001,8 @@ var user = sqliteTable("user", {
|
|
|
16000
16001
|
email: text("email").unique().notNull(),
|
|
16001
16002
|
emailVerified: integer2("emailVerified", { mode: "boolean" }),
|
|
16002
16003
|
image: text("image"),
|
|
16004
|
+
avatarVersion: integer2("avatarVersion").notNull().default(0),
|
|
16005
|
+
avatarObjectKey: text("avatarObjectKey"),
|
|
16003
16006
|
createdAt: text("createdAt").notNull().$defaultFn(() => new Date().toISOString()),
|
|
16004
16007
|
updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString()),
|
|
16005
16008
|
isBot: integer2("isBot", { mode: "boolean" }).notNull().default(false),
|
|
@@ -16673,8 +16676,23 @@ var communityBotBinding = sqliteTable("community_bot_binding", {
|
|
|
16673
16676
|
runtime: text("runtime").notNull(),
|
|
16674
16677
|
instruction: text("instruction").notNull().default(""),
|
|
16675
16678
|
modelName: text("model_name"),
|
|
16679
|
+
reasoningEffort: text("reasoning_effort"),
|
|
16680
|
+
runtimeConfigRevision: integer2("runtime_config_revision").notNull().default(0),
|
|
16676
16681
|
createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
|
|
16677
16682
|
}, (t) => [index("idx_community_bot_binding_machine").on(t.machineId)]);
|
|
16683
|
+
var communityMachineBackendQuota = sqliteTable("community_machine_backend_quota", {
|
|
16684
|
+
machineId: text("machine_id").notNull().references(() => communityMachine.id, { onDelete: "cascade" }),
|
|
16685
|
+
agentBackendId: text("agent_backend_id").$type().notNull(),
|
|
16686
|
+
sourceEpoch: text("source_epoch").notNull(),
|
|
16687
|
+
status: text("status").$type().notNull(),
|
|
16688
|
+
planName: text("plan_name"),
|
|
16689
|
+
freshForSeconds: integer2("fresh_for_seconds"),
|
|
16690
|
+
limits: text("limits", { mode: "json" }).$type(),
|
|
16691
|
+
errorCode: text("error_code"),
|
|
16692
|
+
retryable: integer2("retryable", { mode: "boolean" }),
|
|
16693
|
+
observedAt: text("observed_at").notNull(),
|
|
16694
|
+
updatedAt: text("updated_at").notNull()
|
|
16695
|
+
}, (t) => [primaryKey({ columns: [t.machineId, t.agentBackendId] })]);
|
|
16678
16696
|
var communityAgentRunnerKey = sqliteTable("community_agent_runner_key", {
|
|
16679
16697
|
id: text("id").primaryKey().$defaultFn(() => "crkid_" + nanoid3()),
|
|
16680
16698
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
@@ -16853,6 +16871,11 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
|
|
|
16853
16871
|
config: exports_external.unknown(),
|
|
16854
16872
|
launchId: exports_external.string().min(1)
|
|
16855
16873
|
}),
|
|
16874
|
+
exports_external.object({
|
|
16875
|
+
type: exports_external.literal("agent:runtime_config_update"),
|
|
16876
|
+
agentId: exports_external.string().min(1),
|
|
16877
|
+
config: exports_external.unknown()
|
|
16878
|
+
}),
|
|
16856
16879
|
exports_external.object({
|
|
16857
16880
|
type: exports_external.literal("machine:reset_all"),
|
|
16858
16881
|
resets: exports_external.array(exports_external.object({
|
|
@@ -16899,7 +16922,8 @@ var MAX_MESSAGE_CONTENT_LENGTH = 4000;
|
|
|
16899
16922
|
var MAX_EMOJI_BYTES = 32;
|
|
16900
16923
|
var MAX_ATTACHMENTS_PER_MESSAGE = 10;
|
|
16901
16924
|
var MAX_ATTACHMENT_SIZE_BYTES = 25 * 1024 * 1024;
|
|
16902
|
-
var
|
|
16925
|
+
var MAX_ATTACHMENT_THUMBNAIL_EDGE_PX = 1024;
|
|
16926
|
+
var MAX_ATTACHMENT_THUMBNAIL_SIZE_BYTES = 512 * 1024;
|
|
16903
16927
|
var MAX_SERVER_ICON_SIZE_BYTES = 5 * 1024 * 1024;
|
|
16904
16928
|
var ALLOWED_ICON_MIME_TYPES = [
|
|
16905
16929
|
"image/png",
|
|
@@ -16908,6 +16932,92 @@ var ALLOWED_ICON_MIME_TYPES = [
|
|
|
16908
16932
|
"image/gif"
|
|
16909
16933
|
];
|
|
16910
16934
|
var MAX_ICON_SOURCE_FILE_SIZE_BYTES = 15 * 1024 * 1024;
|
|
16935
|
+
// ../shared/src/provider-telemetry.ts
|
|
16936
|
+
var safeToken = exports_external.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
|
|
16937
|
+
var boundedText = exports_external.string().min(1).refine((value) => new TextEncoder().encode(value).length <= 64, { message: "must be at most 64 UTF-8 bytes" });
|
|
16938
|
+
var DailyUsageMetricSchema = safeToken.nullable();
|
|
16939
|
+
var DailyUsageSnapshotSchema = exports_external.object({
|
|
16940
|
+
botId: exports_external.string().min(1),
|
|
16941
|
+
day: exports_external.string().regex(/^\d{4}-\d{2}-\d{2}$/),
|
|
16942
|
+
metrics: exports_external.object({
|
|
16943
|
+
input: DailyUsageMetricSchema,
|
|
16944
|
+
output: DailyUsageMetricSchema,
|
|
16945
|
+
cache: DailyUsageMetricSchema
|
|
16946
|
+
}).strict()
|
|
16947
|
+
}).strict();
|
|
16948
|
+
var QuotaProductIdentitySchema = exports_external.discriminatedUnion("kind", [
|
|
16949
|
+
exports_external.object({ kind: exports_external.literal("reported"), id: boundedText, displayName: boundedText }).strict(),
|
|
16950
|
+
exports_external.object({ kind: exports_external.literal("unknown"), displayName: boundedText }).strict()
|
|
16951
|
+
]);
|
|
16952
|
+
var QuotaModelIdentitySchema = exports_external.discriminatedUnion("kind", [
|
|
16953
|
+
exports_external.object({ kind: exports_external.literal("reported"), id: boundedText }).strict(),
|
|
16954
|
+
exports_external.object({ kind: exports_external.literal("not_applicable") }).strict(),
|
|
16955
|
+
exports_external.object({ kind: exports_external.literal("unknown") }).strict()
|
|
16956
|
+
]);
|
|
16957
|
+
var QuotaWindowIdentitySchema = exports_external.discriminatedUnion("kind", [
|
|
16958
|
+
exports_external.object({
|
|
16959
|
+
kind: exports_external.literal("rolling"),
|
|
16960
|
+
durationSeconds: exports_external.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
16961
|
+
displayName: boundedText
|
|
16962
|
+
}).strict(),
|
|
16963
|
+
exports_external.object({
|
|
16964
|
+
kind: exports_external.literal("calendar"),
|
|
16965
|
+
period: exports_external.enum(["day", "week", "month"]),
|
|
16966
|
+
displayName: boundedText
|
|
16967
|
+
}).strict(),
|
|
16968
|
+
exports_external.object({
|
|
16969
|
+
kind: exports_external.literal("provider_defined"),
|
|
16970
|
+
id: boundedText,
|
|
16971
|
+
durationSeconds: exports_external.number().int().positive().max(Number.MAX_SAFE_INTEGER).optional(),
|
|
16972
|
+
displayName: boundedText
|
|
16973
|
+
}).strict()
|
|
16974
|
+
]);
|
|
16975
|
+
var QuotaLimitSchema = exports_external.object({
|
|
16976
|
+
bucket: exports_external.object({
|
|
16977
|
+
limitId: boundedText,
|
|
16978
|
+
product: QuotaProductIdentitySchema,
|
|
16979
|
+
model: QuotaModelIdentitySchema,
|
|
16980
|
+
window: QuotaWindowIdentitySchema
|
|
16981
|
+
}).strict(),
|
|
16982
|
+
usedPercent: exports_external.number().finite().min(0).max(100),
|
|
16983
|
+
resetsAt: exports_external.string().datetime({ offset: true }).optional()
|
|
16984
|
+
}).strict();
|
|
16985
|
+
function quotaIdentity(limit) {
|
|
16986
|
+
const { product, model, window: window2, limitId } = limit.bucket;
|
|
16987
|
+
const productKey = product.kind === "reported" ? `reported:${product.id}` : "unknown";
|
|
16988
|
+
const modelKey = model.kind === "reported" ? `reported:${model.id}` : model.kind;
|
|
16989
|
+
const windowKey = window2.kind === "rolling" ? `rolling:${window2.durationSeconds}` : window2.kind === "calendar" ? `calendar:${window2.period}` : `provider_defined:${window2.id}:${window2.durationSeconds === undefined ? "absent" : window2.durationSeconds}`;
|
|
16990
|
+
return `${productKey}\x00${modelKey}\x00${windowKey}\x00${limitId}`;
|
|
16991
|
+
}
|
|
16992
|
+
var AvailableQuotaObservationSchema = exports_external.object({
|
|
16993
|
+
status: exports_external.literal("available"),
|
|
16994
|
+
sourceEpoch: exports_external.string().regex(/^[A-Za-z0-9_-]{22}$/),
|
|
16995
|
+
planName: boundedText.optional(),
|
|
16996
|
+
freshForSeconds: exports_external.number().int().positive().max(86400),
|
|
16997
|
+
limits: exports_external.array(QuotaLimitSchema).min(1).max(8)
|
|
16998
|
+
}).strict().superRefine((value, ctx) => {
|
|
16999
|
+
const identities = new Set;
|
|
17000
|
+
for (const [index2, limit] of value.limits.entries()) {
|
|
17001
|
+
const identity = quotaIdentity(limit);
|
|
17002
|
+
if (identities.has(identity)) {
|
|
17003
|
+
ctx.addIssue({ code: "custom", message: "duplicate quota bucket identity", path: ["limits", index2] });
|
|
17004
|
+
}
|
|
17005
|
+
identities.add(identity);
|
|
17006
|
+
}
|
|
17007
|
+
});
|
|
17008
|
+
var ProviderQuotaObservationSchema = exports_external.union([
|
|
17009
|
+
AvailableQuotaObservationSchema,
|
|
17010
|
+
exports_external.object({
|
|
17011
|
+
status: exports_external.literal("error"),
|
|
17012
|
+
sourceEpoch: exports_external.string().regex(/^[A-Za-z0-9_-]{22}$/),
|
|
17013
|
+
code: exports_external.enum(["unavailable", "unauthorized", "network", "provider_error", "invalid_response"]),
|
|
17014
|
+
retryable: exports_external.boolean()
|
|
17015
|
+
}).strict()
|
|
17016
|
+
]);
|
|
17017
|
+
var ProviderQuotaSnapshotSchema = exports_external.object({
|
|
17018
|
+
agentBackendId: exports_external.enum(["claude", "codex"]),
|
|
17019
|
+
observation: ProviderQuotaObservationSchema
|
|
17020
|
+
}).strict();
|
|
16911
17021
|
// ../shared/src/utils/slug.ts
|
|
16912
17022
|
init_nanoid();
|
|
16913
17023
|
var slugId = customAlphabet("0123456789abcdefghijklmnopqrstuvwxyz");
|
|
@@ -17422,12 +17532,60 @@ var CreateThreadRequestSchema = exports_external.object({
|
|
|
17422
17532
|
attachment_ids: exports_external.array(exports_external.string()).optional()
|
|
17423
17533
|
});
|
|
17424
17534
|
var RUNTIME_ID_RE = /^[A-Za-z0-9._@/-]+$/;
|
|
17535
|
+
var REASONING_EFFORT_RE = /^[A-Za-z0-9._-]+$/;
|
|
17536
|
+
var COMMUNITY_REASONING_EFFORT_MAX = 32;
|
|
17537
|
+
var COMMUNITY_REASONING_DESCRIPTION_MAX = 256;
|
|
17538
|
+
var COMMUNITY_REASONING_OPTIONS_MAX = 16;
|
|
17539
|
+
var COMMUNITY_REASONING_MODELS_MAX = 64;
|
|
17540
|
+
var ReasoningEffortSchema = exports_external.string().min(1).max(COMMUNITY_REASONING_EFFORT_MAX).regex(REASONING_EFFORT_RE, "invalid reasoning effort charset");
|
|
17541
|
+
var RuntimeReasoningOptionSchema = exports_external.object({
|
|
17542
|
+
value: ReasoningEffortSchema,
|
|
17543
|
+
description: exports_external.string().max(COMMUNITY_REASONING_DESCRIPTION_MAX).optional()
|
|
17544
|
+
});
|
|
17545
|
+
var RuntimeReasoningModelSchema = exports_external.object({
|
|
17546
|
+
id: exports_external.string().min(1).max(100),
|
|
17547
|
+
supportedReasoningEfforts: exports_external.array(exports_external.unknown()).max(COMMUNITY_REASONING_OPTIONS_MAX).transform((options) => {
|
|
17548
|
+
const seen = new Set;
|
|
17549
|
+
return options.flatMap((candidate) => {
|
|
17550
|
+
const parsed = RuntimeReasoningOptionSchema.safeParse(candidate);
|
|
17551
|
+
if (!parsed.success)
|
|
17552
|
+
return [];
|
|
17553
|
+
const option = parsed.data;
|
|
17554
|
+
if (seen.has(option.value))
|
|
17555
|
+
return [];
|
|
17556
|
+
seen.add(option.value);
|
|
17557
|
+
return [option];
|
|
17558
|
+
});
|
|
17559
|
+
}),
|
|
17560
|
+
defaultReasoningEffort: ReasoningEffortSchema.optional().catch(undefined)
|
|
17561
|
+
}).transform((model) => {
|
|
17562
|
+
const { defaultReasoningEffort, ...rest } = model;
|
|
17563
|
+
return defaultReasoningEffort !== undefined && model.supportedReasoningEfforts.some((option) => option.value === defaultReasoningEffort) ? { ...rest, defaultReasoningEffort } : rest;
|
|
17564
|
+
});
|
|
17565
|
+
var RuntimeReasoningCatalogSchema = exports_external.object({
|
|
17566
|
+
updateMode: exports_external.enum(["live_next_turn", "context_preserving_restart", "unsupported"]),
|
|
17567
|
+
defaultModelId: exports_external.string().min(1).max(100).optional().catch(undefined),
|
|
17568
|
+
models: exports_external.array(exports_external.unknown()).max(COMMUNITY_REASONING_MODELS_MAX).transform((models) => {
|
|
17569
|
+
const seen = new Set;
|
|
17570
|
+
return models.flatMap((candidate) => {
|
|
17571
|
+
const parsed = RuntimeReasoningModelSchema.safeParse(candidate);
|
|
17572
|
+
if (!parsed.success)
|
|
17573
|
+
return [];
|
|
17574
|
+
const model = parsed.data;
|
|
17575
|
+
if (seen.has(model.id))
|
|
17576
|
+
return [];
|
|
17577
|
+
seen.add(model.id);
|
|
17578
|
+
return [model];
|
|
17579
|
+
});
|
|
17580
|
+
})
|
|
17581
|
+
});
|
|
17425
17582
|
var CommunityMachineRuntimeSchema = exports_external.object({
|
|
17426
17583
|
id: exports_external.string().min(1).max(COMMUNITY_RUNTIME_ID_MAX).regex(RUNTIME_ID_RE, "invalid runtime id charset"),
|
|
17427
17584
|
version: exports_external.string().max(COMMUNITY_RUNTIME_VERSION_MAX).optional(),
|
|
17428
17585
|
status: exports_external.enum(["healthy", "unhealthy"]).catch("healthy").default("healthy"),
|
|
17429
17586
|
lastError: exports_external.string().max(128).optional(),
|
|
17430
|
-
lastErrorAt: exports_external.string().optional()
|
|
17587
|
+
lastErrorAt: exports_external.string().optional(),
|
|
17588
|
+
reasoning: RuntimeReasoningCatalogSchema.optional().catch(undefined)
|
|
17431
17589
|
});
|
|
17432
17590
|
var CommunityMachineRuntimeListSchema = exports_external.array(CommunityMachineRuntimeSchema).max(COMMUNITY_RUNTIME_LIST_MAX).transform((list) => {
|
|
17433
17591
|
const seen = new Set;
|
|
@@ -17479,7 +17637,8 @@ var HostReadyMessageSchema = exports_external.object({
|
|
|
17479
17637
|
platform: exports_external.string().optional(),
|
|
17480
17638
|
arch: exports_external.string().optional(),
|
|
17481
17639
|
osRelease: exports_external.string().optional(),
|
|
17482
|
-
daemonVersion: exports_external.string().optional()
|
|
17640
|
+
daemonVersion: exports_external.string().optional(),
|
|
17641
|
+
providerQuotas: exports_external.array(ProviderQuotaSnapshotSchema).max(2).optional().default([])
|
|
17483
17642
|
});
|
|
17484
17643
|
var CommunityDaemonReadySchema = exports_external.object({
|
|
17485
17644
|
runtimeReport: CommunityMachineRuntimeListSchema.optional(),
|
|
@@ -17500,7 +17659,9 @@ var SessionErrorFrameSchema = exports_external.object({
|
|
|
17500
17659
|
var AgentActivityMessageSchema = exports_external.object({
|
|
17501
17660
|
type: exports_external.literal("agent_activity"),
|
|
17502
17661
|
agentId: exports_external.string(),
|
|
17503
|
-
state: exports_external.enum(["idle", "starting", "running", "stopping"])
|
|
17662
|
+
state: exports_external.enum(["idle", "starting", "running", "stopping"]),
|
|
17663
|
+
dailyUsage: exports_external.array(DailyUsageSnapshotSchema).max(7).optional(),
|
|
17664
|
+
quota: ProviderQuotaSnapshotSchema.optional()
|
|
17504
17665
|
});
|
|
17505
17666
|
var AgentTypingMessageSchema = exports_external.object({
|
|
17506
17667
|
type: exports_external.literal("agent_typing"),
|
|
@@ -17575,15 +17736,17 @@ var CommunityBotCreateRequestSchema = exports_external.object({
|
|
|
17575
17736
|
machineId: exports_external.string().min(1),
|
|
17576
17737
|
runtime: exports_external.string().min(1),
|
|
17577
17738
|
image: BotImageUrlSchema.optional(),
|
|
17578
|
-
model: exports_external.string().trim().min(1).max(100).nullable().optional()
|
|
17739
|
+
model: exports_external.string().trim().min(1).max(100).nullable().optional(),
|
|
17740
|
+
reasoningEffort: ReasoningEffortSchema.nullable().optional()
|
|
17579
17741
|
});
|
|
17580
17742
|
var CommunityBotPatchRequestSchema = exports_external.object({
|
|
17581
17743
|
name: exports_external.string().trim().min(COMMUNITY_BOT_NAME_MIN).max(COMMUNITY_BOT_NAME_MAX).refine(isMentionSafeName, { message: MENTION_SAFE_NAME_MSG }).optional(),
|
|
17582
17744
|
description: exports_external.string().max(COMMUNITY_BOT_DESCRIPTION_MAX).optional(),
|
|
17583
17745
|
image: BotImageUrlSchema.nullable().optional(),
|
|
17584
17746
|
model: exports_external.string().trim().min(1).max(100).nullable().optional(),
|
|
17585
|
-
runtime: exports_external.string().trim().min(1).max(COMMUNITY_RUNTIME_ID_MAX).optional()
|
|
17586
|
-
|
|
17747
|
+
runtime: exports_external.string().trim().min(1).max(COMMUNITY_RUNTIME_ID_MAX).optional(),
|
|
17748
|
+
reasoningEffort: ReasoningEffortSchema.nullable().optional()
|
|
17749
|
+
}).refine((v) => v.name !== undefined || v.description !== undefined || v.image !== undefined || v.runtime !== undefined || ("reasoningEffort" in v) || ("model" in v), {
|
|
17587
17750
|
message: "at least one field must be provided"
|
|
17588
17751
|
});
|
|
17589
17752
|
var CommunityBotAddToServerRequestSchema = exports_external.object({
|
|
@@ -17785,6 +17948,7 @@ __export(exports_community_schema, {
|
|
|
17785
17948
|
communityChannelMember: () => communityChannelMember,
|
|
17786
17949
|
communityChannel: () => communityChannel,
|
|
17787
17950
|
communityCategory: () => communityCategory,
|
|
17951
|
+
communityBotDailyTokenUsage: () => communityBotDailyTokenUsage,
|
|
17788
17952
|
communityBotDailyActivity: () => communityBotDailyActivity,
|
|
17789
17953
|
communityBotApprovalRequest: () => communityBotApprovalRequest,
|
|
17790
17954
|
communityBotActivityEvent: () => communityBotActivityEvent,
|
|
@@ -18037,6 +18201,17 @@ var communityBotDailyActivity = sqliteTable("community_bot_daily_activity", {
|
|
|
18037
18201
|
handledCount: integer2("handled_count").notNull().default(0),
|
|
18038
18202
|
sentCount: integer2("sent_count").notNull().default(0)
|
|
18039
18203
|
}, (t) => [primaryKey({ columns: [t.botId, t.day] })]);
|
|
18204
|
+
var communityBotDailyTokenUsage = sqliteTable("community_bot_daily_token_usage", {
|
|
18205
|
+
botId: text("bot_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
18206
|
+
day: text("day").notNull(),
|
|
18207
|
+
inputTokens: integer2("input_tokens"),
|
|
18208
|
+
outputTokens: integer2("output_tokens"),
|
|
18209
|
+
cacheTokens: integer2("cache_tokens"),
|
|
18210
|
+
updatedAt: text("updated_at").notNull()
|
|
18211
|
+
}, (t) => [
|
|
18212
|
+
primaryKey({ columns: [t.botId, t.day] }),
|
|
18213
|
+
index("idx_community_bot_daily_token_usage_day").on(t.day)
|
|
18214
|
+
]);
|
|
18040
18215
|
var communityMessageMark = sqliteTable("community_message_mark", {
|
|
18041
18216
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
18042
18217
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
@@ -18161,7 +18336,8 @@ var listedMessageProjection = {
|
|
|
18161
18336
|
clientNonce: communityMessage.clientNonce,
|
|
18162
18337
|
authorName: user.name,
|
|
18163
18338
|
authorEmail: user.email,
|
|
18164
|
-
authorImage: user.image
|
|
18339
|
+
authorImage: user.image,
|
|
18340
|
+
authorAvatarVersion: user.avatarVersion
|
|
18165
18341
|
};
|
|
18166
18342
|
|
|
18167
18343
|
// ../shared/src/db/queries/user.ts
|
|
@@ -18171,6 +18347,7 @@ var publicUserColumns = {
|
|
|
18171
18347
|
email: user.email,
|
|
18172
18348
|
emailVerified: user.emailVerified,
|
|
18173
18349
|
image: user.image,
|
|
18350
|
+
avatarVersion: user.avatarVersion,
|
|
18174
18351
|
createdAt: user.createdAt,
|
|
18175
18352
|
updatedAt: user.updatedAt,
|
|
18176
18353
|
discriminator: user.discriminator
|
|
@@ -18181,6 +18358,12 @@ var internalUserColumns = {
|
|
|
18181
18358
|
ownerUserId: user.ownerUserId,
|
|
18182
18359
|
deletedAt: user.deletedAt
|
|
18183
18360
|
};
|
|
18361
|
+
var avatarPublishColumns = {
|
|
18362
|
+
id: user.id,
|
|
18363
|
+
image: user.image,
|
|
18364
|
+
avatarVersion: user.avatarVersion,
|
|
18365
|
+
avatarObjectKey: user.avatarObjectKey
|
|
18366
|
+
};
|
|
18184
18367
|
|
|
18185
18368
|
// ../shared/src/db/queries/community/channel.ts
|
|
18186
18369
|
var CHANNEL_COLUMNS = {
|
|
@@ -18233,7 +18416,8 @@ var friendApprovalProfileSchema = exports_external.strictObject({
|
|
|
18233
18416
|
id: string4,
|
|
18234
18417
|
name: string4,
|
|
18235
18418
|
discriminator: string4,
|
|
18236
|
-
image: nullableString
|
|
18419
|
+
image: nullableString,
|
|
18420
|
+
avatarVersion: exports_external.number().int().nonnegative()
|
|
18237
18421
|
});
|
|
18238
18422
|
var FriendApprovalPayloadSchema = exports_external.strictObject({
|
|
18239
18423
|
friendshipId: string4,
|
|
@@ -18259,6 +18443,7 @@ var messageSchema = exports_external.strictObject({
|
|
|
18259
18443
|
authorId: string4,
|
|
18260
18444
|
authorName: string4,
|
|
18261
18445
|
authorAvatar: string4.optional(),
|
|
18446
|
+
authorAvatarVersion: exports_external.number().int().nonnegative(),
|
|
18262
18447
|
content: string4,
|
|
18263
18448
|
type: exports_external.enum(["chat", "system"]),
|
|
18264
18449
|
systemKind: exports_external.literal("thread").optional(),
|
|
@@ -18266,6 +18451,7 @@ var messageSchema = exports_external.strictObject({
|
|
|
18266
18451
|
replyToId: nullableString.optional(),
|
|
18267
18452
|
replyTo: exports_external.strictObject({
|
|
18268
18453
|
id: string4,
|
|
18454
|
+
authorId: string4.optional(),
|
|
18269
18455
|
authorName: string4,
|
|
18270
18456
|
text: string4,
|
|
18271
18457
|
deleted: exports_external.boolean().optional()
|
|
@@ -18460,6 +18646,7 @@ var communityMemberJoinSchema = exports_external.strictObject({
|
|
|
18460
18646
|
name: string4,
|
|
18461
18647
|
discriminator: string4,
|
|
18462
18648
|
avatar: string4.optional(),
|
|
18649
|
+
avatarVersion: exports_external.number().int().nonnegative(),
|
|
18463
18650
|
role: string4,
|
|
18464
18651
|
joinedAt: string4
|
|
18465
18652
|
})
|
|
@@ -18562,6 +18749,22 @@ var communityStatusUpdateSchema = exports_external.strictObject({
|
|
|
18562
18749
|
statusEmoji: nullableString,
|
|
18563
18750
|
statusText: nullableString
|
|
18564
18751
|
});
|
|
18752
|
+
var communityIdentityUpdateSchema = exports_external.strictObject({
|
|
18753
|
+
type: exports_external.literal("community:identity.update"),
|
|
18754
|
+
userId: string4,
|
|
18755
|
+
avatar: string4,
|
|
18756
|
+
avatarVersion: exports_external.number().int().positive()
|
|
18757
|
+
});
|
|
18758
|
+
var communityProfileUpdateSchema = exports_external.strictObject({
|
|
18759
|
+
type: exports_external.literal("community:profile.update"),
|
|
18760
|
+
userId: string4,
|
|
18761
|
+
name: string4,
|
|
18762
|
+
discriminator: string4,
|
|
18763
|
+
aboutMe: string4,
|
|
18764
|
+
bannerColor: nullableString,
|
|
18765
|
+
kind: exports_external.enum(["human", "bot"]),
|
|
18766
|
+
ownerUserId: nullableString
|
|
18767
|
+
});
|
|
18565
18768
|
var machineRuntimeSchema = CommunityMachineRuntimeSchema.strict();
|
|
18566
18769
|
var CommunityMachineSummarySchema2 = exports_external.strictObject({
|
|
18567
18770
|
id: string4,
|
|
@@ -18650,6 +18853,8 @@ var CommunityWsEventDiscriminatedSchema = exports_external.discriminatedUnion("t
|
|
|
18650
18853
|
communityInboxChangedSchema,
|
|
18651
18854
|
communityPresenceUpdateSchema,
|
|
18652
18855
|
communityStatusUpdateSchema,
|
|
18856
|
+
communityIdentityUpdateSchema,
|
|
18857
|
+
communityProfileUpdateSchema,
|
|
18653
18858
|
communityMachineCreatedSchema,
|
|
18654
18859
|
communityMachineStatusSchema,
|
|
18655
18860
|
communityMachineUpdatedSchema,
|
|
@@ -18696,6 +18901,8 @@ var WS_EVENTS = {
|
|
|
18696
18901
|
INBOX_CHANGED: "community:inbox.changed",
|
|
18697
18902
|
PRESENCE_UPDATE: "community:presence.update",
|
|
18698
18903
|
STATUS_UPDATE: "community:status.update",
|
|
18904
|
+
IDENTITY_UPDATE: "community:identity.update",
|
|
18905
|
+
PROFILE_UPDATE: "community:profile.update",
|
|
18699
18906
|
MACHINE_CREATED: "community:machine.created",
|
|
18700
18907
|
MACHINE_STATUS: "community:machine.status",
|
|
18701
18908
|
MACHINE_UPDATED: "community:machine.updated",
|
|
@@ -19274,7 +19481,7 @@ import * as fs12 from "fs";
|
|
|
19274
19481
|
import * as path13 from "path";
|
|
19275
19482
|
import * as crypto5 from "crypto";
|
|
19276
19483
|
import * as os3 from "os";
|
|
19277
|
-
import { homedir as
|
|
19484
|
+
import { homedir as homedir6 } from "os";
|
|
19278
19485
|
|
|
19279
19486
|
// src/discovery.ts
|
|
19280
19487
|
import * as path9 from "path";
|
|
@@ -20054,6 +20261,9 @@ class ProcessLane {
|
|
|
20054
20261
|
return false;
|
|
20055
20262
|
return proc.kill("SIGINT");
|
|
20056
20263
|
}
|
|
20264
|
+
updateSettings(input) {
|
|
20265
|
+
return this.driver.updateSettings?.(input) ?? Promise.resolve({ status: "unsupported" });
|
|
20266
|
+
}
|
|
20057
20267
|
attachProcess(proc) {
|
|
20058
20268
|
proc.stdout?.on("data", (chunk2) => {
|
|
20059
20269
|
const chunkText = chunk2.toString();
|
|
@@ -20441,25 +20651,19 @@ class ClaudeEventNormalizer {
|
|
|
20441
20651
|
}
|
|
20442
20652
|
buildUsageTelemetry(event) {
|
|
20443
20653
|
const u = event?.usage;
|
|
20444
|
-
if (!u
|
|
20654
|
+
if (!u)
|
|
20445
20655
|
return null;
|
|
20656
|
+
const metric = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
20657
|
+
const cacheParts = [u.cache_read_input_tokens, u.cache_creation_input_tokens].filter((value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0);
|
|
20658
|
+
const cache = cacheParts.length > 0 && Number.isSafeInteger(cacheParts.reduce((sum, value) => sum + value, 0)) ? cacheParts.reduce((sum, value) => sum + value, 0) : null;
|
|
20446
20659
|
return {
|
|
20447
20660
|
kind: "telemetry",
|
|
20448
20661
|
name: "token_usage",
|
|
20449
20662
|
source: "claude_result_usage",
|
|
20450
|
-
|
|
20451
|
-
|
|
20452
|
-
|
|
20453
|
-
|
|
20454
|
-
cachedInputTokens: u?.cache_read_input_tokens,
|
|
20455
|
-
cacheCreationInputTokens: u?.cache_creation_input_tokens,
|
|
20456
|
-
totalCostUsd: event?.total_cost_usd,
|
|
20457
|
-
durationMs: event?.duration_ms,
|
|
20458
|
-
durationApiMs: event?.duration_api_ms,
|
|
20459
|
-
numTurns: event?.num_turns,
|
|
20460
|
-
resultSubtype: event?.subtype,
|
|
20461
|
-
resultIsError: event?.is_error,
|
|
20462
|
-
serviceTier: u?.service_tier
|
|
20663
|
+
usage: {
|
|
20664
|
+
input: metric(u.input_tokens),
|
|
20665
|
+
output: metric(u.output_tokens),
|
|
20666
|
+
cache
|
|
20463
20667
|
}
|
|
20464
20668
|
};
|
|
20465
20669
|
}
|
|
@@ -20691,49 +20895,153 @@ class ClaudeDriver {
|
|
|
20691
20895
|
}
|
|
20692
20896
|
|
|
20693
20897
|
// agent-driver/dist/adapters/codex/telemetry.js
|
|
20694
|
-
function
|
|
20898
|
+
function metric(value) {
|
|
20899
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
20900
|
+
}
|
|
20901
|
+
function nonCachedInput(input, cached2) {
|
|
20902
|
+
if (typeof input !== "number" || !Number.isSafeInteger(input) || input < 0 || typeof cached2 !== "number" || !Number.isSafeInteger(cached2) || cached2 < 0 || cached2 > input)
|
|
20903
|
+
return null;
|
|
20904
|
+
return input - cached2;
|
|
20905
|
+
}
|
|
20906
|
+
function canonicalId(value, fallback) {
|
|
20907
|
+
return typeof value === "string" && value.length > 0 && new TextEncoder().encode(value).length <= 64 ? value : fallback;
|
|
20908
|
+
}
|
|
20909
|
+
function mappedPlanName(value) {
|
|
20910
|
+
switch (value) {
|
|
20911
|
+
case "free":
|
|
20912
|
+
return "Free";
|
|
20913
|
+
case "plus":
|
|
20914
|
+
return "Plus";
|
|
20915
|
+
case "pro":
|
|
20916
|
+
return "Pro";
|
|
20917
|
+
case "team":
|
|
20918
|
+
return "Team";
|
|
20919
|
+
case "business":
|
|
20920
|
+
return "Business";
|
|
20921
|
+
case "enterprise":
|
|
20922
|
+
return "Enterprise";
|
|
20923
|
+
case "edu":
|
|
20924
|
+
return "Education";
|
|
20925
|
+
default:
|
|
20926
|
+
return;
|
|
20927
|
+
}
|
|
20928
|
+
}
|
|
20929
|
+
function quotaWindow(minutes, slot) {
|
|
20930
|
+
if (typeof minutes !== "number" || !Number.isSafeInteger(minutes) || minutes <= 0)
|
|
20931
|
+
return null;
|
|
20932
|
+
if (minutes === 1440)
|
|
20933
|
+
return { kind: "calendar", period: "day", displayName: "Daily usage limit" };
|
|
20934
|
+
if (minutes === 10080)
|
|
20935
|
+
return { kind: "calendar", period: "week", displayName: "Weekly usage limit" };
|
|
20936
|
+
if (minutes === 43200)
|
|
20937
|
+
return { kind: "calendar", period: "month", displayName: "Monthly usage limit" };
|
|
20938
|
+
return {
|
|
20939
|
+
kind: "rolling",
|
|
20940
|
+
durationSeconds: minutes * 60,
|
|
20941
|
+
displayName: slot === "primary" && minutes === 300 ? "5 hour usage limit" : `${minutes} minute usage limit`
|
|
20942
|
+
};
|
|
20943
|
+
}
|
|
20944
|
+
function resetIso(value) {
|
|
20945
|
+
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
20946
|
+
const date5 = new Date(value < 10000000000 ? value * 1000 : value);
|
|
20947
|
+
return Number.isNaN(date5.getTime()) ? undefined : date5.toISOString();
|
|
20948
|
+
}
|
|
20949
|
+
if (typeof value === "string") {
|
|
20950
|
+
const date5 = new Date(value);
|
|
20951
|
+
return Number.isNaN(date5.getTime()) ? undefined : date5.toISOString();
|
|
20952
|
+
}
|
|
20953
|
+
return;
|
|
20954
|
+
}
|
|
20955
|
+
function mapCodexQuotaSnapshots(snapshots, sourceEpoch) {
|
|
20956
|
+
const limits = [];
|
|
20957
|
+
let planName;
|
|
20958
|
+
for (const snapshot of snapshots) {
|
|
20959
|
+
const limitId = canonicalId(snapshot?.limitId ?? snapshot?.limit_id, "codex");
|
|
20960
|
+
const spark = /spark/i.test(limitId) || /spark/i.test(String(snapshot?.limitName ?? snapshot?.limit_name ?? ""));
|
|
20961
|
+
const product = spark ? { kind: "reported", id: "codex-spark", displayName: "Spark" } : { kind: "reported", id: "codex", displayName: "Codex" };
|
|
20962
|
+
const model = spark ? { kind: "reported", id: "gpt-5.3-codex-spark" } : { kind: "not_applicable" };
|
|
20963
|
+
planName ??= mappedPlanName(snapshot?.planType ?? snapshot?.plan_type);
|
|
20964
|
+
for (const slot of ["primary", "secondary"]) {
|
|
20965
|
+
const value = snapshot?.[slot];
|
|
20966
|
+
const window2 = quotaWindow(value?.windowDurationMins ?? value?.window_duration_mins, slot);
|
|
20967
|
+
const usedPercent = value?.usedPercent ?? value?.used_percent;
|
|
20968
|
+
if (!window2 || typeof usedPercent !== "number" || !Number.isFinite(usedPercent) || usedPercent < 0 || usedPercent > 100)
|
|
20969
|
+
continue;
|
|
20970
|
+
const resetsAt = resetIso(value?.resetsAt ?? value?.resets_at);
|
|
20971
|
+
limits.push({
|
|
20972
|
+
bucket: { limitId, product, model, window: window2 },
|
|
20973
|
+
usedPercent,
|
|
20974
|
+
...resetsAt ? { resetsAt } : {}
|
|
20975
|
+
});
|
|
20976
|
+
}
|
|
20977
|
+
}
|
|
20978
|
+
if (limits.length === 0) {
|
|
20979
|
+
return {
|
|
20980
|
+
kind: "telemetry",
|
|
20981
|
+
name: "rate_limits",
|
|
20982
|
+
source: "codex_account_rate_limits_updated",
|
|
20983
|
+
quota: { status: "error", sourceEpoch, code: "invalid_response", retryable: true }
|
|
20984
|
+
};
|
|
20985
|
+
}
|
|
20986
|
+
return {
|
|
20987
|
+
kind: "telemetry",
|
|
20988
|
+
name: "rate_limits",
|
|
20989
|
+
source: "codex_account_rate_limits_updated",
|
|
20990
|
+
quota: {
|
|
20991
|
+
status: "available",
|
|
20992
|
+
sourceEpoch,
|
|
20993
|
+
...planName ? { planName } : {},
|
|
20994
|
+
freshForSeconds: 300,
|
|
20995
|
+
limits
|
|
20996
|
+
}
|
|
20997
|
+
};
|
|
20998
|
+
}
|
|
20999
|
+
function mapCodexTelemetry(method, params, sourceEpoch) {
|
|
20695
21000
|
if (method === "thread/tokenUsage/updated") {
|
|
20696
|
-
const u = params?.
|
|
20697
|
-
|
|
20698
|
-
|
|
20699
|
-
|
|
20700
|
-
|
|
20701
|
-
|
|
20702
|
-
|
|
20703
|
-
|
|
20704
|
-
|
|
20705
|
-
|
|
20706
|
-
|
|
20707
|
-
|
|
20708
|
-
|
|
20709
|
-
modelContextWindow: u.modelContextWindow ?? u.model_context_window,
|
|
20710
|
-
cachedInputRatio: u.cachedInputRatio,
|
|
20711
|
-
contextUtilization: u.contextUtilization
|
|
20712
|
-
}
|
|
21001
|
+
const u = params?.tokenUsage?.last ?? params?.token_usage?.last;
|
|
21002
|
+
if (!u)
|
|
21003
|
+
return [];
|
|
21004
|
+
const input = u.inputTokens ?? u.input_tokens;
|
|
21005
|
+
const cached2 = u.cachedInputTokens ?? u.cached_input_tokens;
|
|
21006
|
+
return [{
|
|
21007
|
+
kind: "telemetry",
|
|
21008
|
+
name: "token_usage",
|
|
21009
|
+
source: "codex_thread_token_usage_updated",
|
|
21010
|
+
usage: {
|
|
21011
|
+
input: nonCachedInput(input, cached2),
|
|
21012
|
+
output: metric(u.outputTokens ?? u.output_tokens),
|
|
21013
|
+
cache: metric(cached2)
|
|
20713
21014
|
}
|
|
20714
|
-
];
|
|
21015
|
+
}];
|
|
20715
21016
|
}
|
|
20716
21017
|
if (method === "account/rateLimits/updated") {
|
|
20717
|
-
|
|
20718
|
-
return [
|
|
20719
|
-
{
|
|
20720
|
-
kind: "telemetry",
|
|
20721
|
-
name: "rate_limits",
|
|
20722
|
-
source: "codex_account_rate_limits_updated",
|
|
20723
|
-
attrs: {
|
|
20724
|
-
limitId: r.limitId,
|
|
20725
|
-
planType: r.planType,
|
|
20726
|
-
usedPercent: r.usedPercent,
|
|
20727
|
-
windowDurationMins: r.windowDurationMins,
|
|
20728
|
-
resetsAt: r.resetsAt
|
|
20729
|
-
}
|
|
20730
|
-
}
|
|
20731
|
-
];
|
|
21018
|
+
return [mapCodexQuotaSnapshots([params?.rateLimits ?? params ?? {}], sourceEpoch)];
|
|
20732
21019
|
}
|
|
20733
21020
|
return [];
|
|
20734
21021
|
}
|
|
20735
21022
|
|
|
20736
21023
|
// agent-driver/dist/adapters/codex/normalizer.js
|
|
21024
|
+
import { randomBytes } from "node:crypto";
|
|
21025
|
+
var codexQuotaSourceEpoch = randomBytes(16).toString("base64url");
|
|
21026
|
+
var codexQuotaSourceGeneration = 0;
|
|
21027
|
+
var codexAccountFingerprint = null;
|
|
21028
|
+
function rotateCodexQuotaSource() {
|
|
21029
|
+
codexQuotaSourceEpoch = randomBytes(16).toString("base64url");
|
|
21030
|
+
codexQuotaSourceGeneration += 1;
|
|
21031
|
+
codexAccountFingerprint = null;
|
|
21032
|
+
}
|
|
21033
|
+
function observeCodexAccount(result) {
|
|
21034
|
+
const account2 = result?.account;
|
|
21035
|
+
const fingerprint = account2 && typeof account2 === "object" ? JSON.stringify([
|
|
21036
|
+
account2.type ?? "unknown",
|
|
21037
|
+
account2.email ?? null,
|
|
21038
|
+
account2.planType ?? account2.plan_type ?? null
|
|
21039
|
+
]) : "none";
|
|
21040
|
+
if (codexAccountFingerprint !== null && codexAccountFingerprint !== fingerprint) {
|
|
21041
|
+
rotateCodexQuotaSource();
|
|
21042
|
+
}
|
|
21043
|
+
codexAccountFingerprint = fingerprint;
|
|
21044
|
+
}
|
|
20737
21045
|
function normalizeFileChangeInput(item) {
|
|
20738
21046
|
const paths = [];
|
|
20739
21047
|
const seen = new Set;
|
|
@@ -20756,6 +21064,12 @@ function normalizeFileChangeInput(item) {
|
|
|
20756
21064
|
}
|
|
20757
21065
|
|
|
20758
21066
|
class CodexEventNormalizer {
|
|
21067
|
+
quotaReadRequestIds = new Set;
|
|
21068
|
+
accountReadRequestIds = new Set;
|
|
21069
|
+
rateLimitSnapshots = new Map;
|
|
21070
|
+
quotaSnapshotInitialized = false;
|
|
21071
|
+
quotaSourceGeneration = codexQuotaSourceGeneration;
|
|
21072
|
+
pendingTurnUsage = null;
|
|
20759
21073
|
threadId = null;
|
|
20760
21074
|
turnId = null;
|
|
20761
21075
|
terminalTurn = null;
|
|
@@ -20766,10 +21080,69 @@ class CodexEventNormalizer {
|
|
|
20766
21080
|
get currentTurnId() {
|
|
20767
21081
|
return this.turnId;
|
|
20768
21082
|
}
|
|
21083
|
+
registerQuotaReadRequest(requestId) {
|
|
21084
|
+
this.quotaReadRequestIds.add(requestId);
|
|
21085
|
+
}
|
|
21086
|
+
registerAccountReadRequest(requestId) {
|
|
21087
|
+
this.accountReadRequestIds.add(requestId);
|
|
21088
|
+
}
|
|
21089
|
+
syncQuotaSourceGeneration() {
|
|
21090
|
+
if (this.quotaSourceGeneration === codexQuotaSourceGeneration)
|
|
21091
|
+
return;
|
|
21092
|
+
this.quotaSourceGeneration = codexQuotaSourceGeneration;
|
|
21093
|
+
this.rateLimitSnapshots.clear();
|
|
21094
|
+
this.quotaSnapshotInitialized = false;
|
|
21095
|
+
}
|
|
21096
|
+
quotaSnapshots(value) {
|
|
21097
|
+
const byLimitId = value?.rateLimitsByLimitId ?? value?.rate_limits_by_limit_id;
|
|
21098
|
+
if (byLimitId && typeof byLimitId === "object" && !Array.isArray(byLimitId)) {
|
|
21099
|
+
return Object.entries(byLimitId).flatMap(([key2, snapshot2]) => {
|
|
21100
|
+
if (!snapshot2 || typeof snapshot2 !== "object" || Array.isArray(snapshot2))
|
|
21101
|
+
return [];
|
|
21102
|
+
return [[key2, {
|
|
21103
|
+
...snapshot2,
|
|
21104
|
+
limitId: snapshot2.limitId ?? snapshot2.limit_id ?? key2
|
|
21105
|
+
}]];
|
|
21106
|
+
});
|
|
21107
|
+
}
|
|
21108
|
+
const snapshot = value?.rateLimits ?? value?.rate_limits ?? value;
|
|
21109
|
+
if (!snapshot || typeof snapshot !== "object" || Array.isArray(snapshot))
|
|
21110
|
+
return [];
|
|
21111
|
+
const record2 = snapshot;
|
|
21112
|
+
const key = typeof record2.limitId === "string" ? record2.limitId : typeof record2.limit_id === "string" ? record2.limit_id : "codex";
|
|
21113
|
+
return [[key, { ...record2, limitId: key }]];
|
|
21114
|
+
}
|
|
21115
|
+
replaceQuotaSnapshots(value) {
|
|
21116
|
+
this.syncQuotaSourceGeneration();
|
|
21117
|
+
this.rateLimitSnapshots.clear();
|
|
21118
|
+
for (const [key, snapshot] of this.quotaSnapshots(value)) {
|
|
21119
|
+
this.rateLimitSnapshots.set(key, snapshot);
|
|
21120
|
+
}
|
|
21121
|
+
this.quotaSnapshotInitialized = true;
|
|
21122
|
+
return [mapCodexQuotaSnapshots([...this.rateLimitSnapshots.values()], codexQuotaSourceEpoch)];
|
|
21123
|
+
}
|
|
21124
|
+
mergeQuotaSnapshots(value) {
|
|
21125
|
+
this.syncQuotaSourceGeneration();
|
|
21126
|
+
for (const [key, update] of this.quotaSnapshots(value)) {
|
|
21127
|
+
const merged = {
|
|
21128
|
+
...this.rateLimitSnapshots.get(key) ?? {},
|
|
21129
|
+
limitId: key
|
|
21130
|
+
};
|
|
21131
|
+
for (const [field, fieldValue] of Object.entries(update)) {
|
|
21132
|
+
if (fieldValue !== undefined && fieldValue !== null)
|
|
21133
|
+
merged[field] = fieldValue;
|
|
21134
|
+
}
|
|
21135
|
+
this.rateLimitSnapshots.set(key, merged);
|
|
21136
|
+
}
|
|
21137
|
+
if (!this.quotaSnapshotInitialized)
|
|
21138
|
+
return [];
|
|
21139
|
+
return [mapCodexQuotaSnapshots([...this.rateLimitSnapshots.values()], codexQuotaSourceEpoch)];
|
|
21140
|
+
}
|
|
20769
21141
|
adoptThreadId(threadId) {
|
|
20770
21142
|
if (threadId !== this.threadId) {
|
|
20771
21143
|
this.turnId = null;
|
|
20772
21144
|
this.terminalTurn = null;
|
|
21145
|
+
this.pendingTurnUsage = null;
|
|
20773
21146
|
}
|
|
20774
21147
|
this.threadId = threadId;
|
|
20775
21148
|
}
|
|
@@ -20787,6 +21160,25 @@ class CodexEventNormalizer {
|
|
|
20787
21160
|
const msg = tryParseJsonLine(line);
|
|
20788
21161
|
if (!msg)
|
|
20789
21162
|
return [];
|
|
21163
|
+
if (msg?.id !== undefined && this.accountReadRequestIds.delete(msg.id)) {
|
|
21164
|
+
if (!msg.error) {
|
|
21165
|
+
observeCodexAccount(msg.result);
|
|
21166
|
+
this.syncQuotaSourceGeneration();
|
|
21167
|
+
}
|
|
21168
|
+
return [];
|
|
21169
|
+
}
|
|
21170
|
+
if (msg?.id !== undefined && this.quotaReadRequestIds.delete(msg.id)) {
|
|
21171
|
+
this.syncQuotaSourceGeneration();
|
|
21172
|
+
if (msg.error) {
|
|
21173
|
+
return [{
|
|
21174
|
+
kind: "telemetry",
|
|
21175
|
+
name: "rate_limits",
|
|
21176
|
+
source: "codex_account_rate_limits_read",
|
|
21177
|
+
quota: { status: "error", sourceEpoch: codexQuotaSourceEpoch, code: "provider_error", retryable: true }
|
|
21178
|
+
}];
|
|
21179
|
+
}
|
|
21180
|
+
return this.replaceQuotaSnapshots(msg.result ?? {});
|
|
21181
|
+
}
|
|
20790
21182
|
if (msg?.error && msg.id !== undefined) {
|
|
20791
21183
|
return [{ kind: "error", message: msg.error?.message ?? "Codex RPC error" }];
|
|
20792
21184
|
}
|
|
@@ -20811,6 +21203,7 @@ class CodexEventNormalizer {
|
|
|
20811
21203
|
return [];
|
|
20812
21204
|
this.turnId = params.turn.id;
|
|
20813
21205
|
this.terminalTurn = null;
|
|
21206
|
+
this.pendingTurnUsage = null;
|
|
20814
21207
|
return [
|
|
20815
21208
|
{
|
|
20816
21209
|
kind: "turn_owner",
|
|
@@ -20839,24 +21232,36 @@ class CodexEventNormalizer {
|
|
|
20839
21232
|
case "turn/completed":
|
|
20840
21233
|
if (!this.acceptRootTerminal(params))
|
|
20841
21234
|
return [];
|
|
21235
|
+
const usage = this.pendingTurnUsage;
|
|
21236
|
+
this.pendingTurnUsage = null;
|
|
20842
21237
|
if (params.turn.status === "failed") {
|
|
20843
21238
|
return [
|
|
21239
|
+
...usage ? [usage] : [],
|
|
20844
21240
|
{ kind: "error", message: "Codex turn failed" },
|
|
20845
21241
|
{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }
|
|
20846
21242
|
];
|
|
20847
21243
|
}
|
|
20848
21244
|
if (params.turn.status === "interrupted") {
|
|
20849
|
-
return [{ kind: "error", message: "Codex turn interrupted" }, { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
21245
|
+
return [...usage ? [usage] : [], { kind: "error", message: "Codex turn interrupted" }, { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
20850
21246
|
}
|
|
20851
|
-
return [{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
21247
|
+
return [...usage ? [usage] : [], { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
20852
21248
|
case "error":
|
|
20853
21249
|
if (params?.willRetry === true) {
|
|
20854
21250
|
return [{ kind: "runtime_recovery", stage: "retrying", source: "codex_stream" }];
|
|
20855
21251
|
}
|
|
20856
21252
|
return [{ kind: "error", message: params?.error?.message ?? params?.message ?? "Codex error" }];
|
|
20857
|
-
case "thread/tokenUsage/updated":
|
|
21253
|
+
case "thread/tokenUsage/updated": {
|
|
21254
|
+
const usage2 = mapCodexTelemetry(method, params, codexQuotaSourceEpoch)[0];
|
|
21255
|
+
if (usage2)
|
|
21256
|
+
this.pendingTurnUsage = usage2;
|
|
21257
|
+
return [];
|
|
21258
|
+
}
|
|
20858
21259
|
case "account/rateLimits/updated":
|
|
20859
|
-
return
|
|
21260
|
+
return this.mergeQuotaSnapshots(params);
|
|
21261
|
+
case "account/updated":
|
|
21262
|
+
rotateCodexQuotaSource();
|
|
21263
|
+
this.syncQuotaSourceGeneration();
|
|
21264
|
+
return [];
|
|
20860
21265
|
default:
|
|
20861
21266
|
return [];
|
|
20862
21267
|
}
|
|
@@ -20969,7 +21374,53 @@ function resolveCodexHomeRootFromEnv(env = process.env, opts = {}) {
|
|
|
20969
21374
|
return path6.join(opts.defaultHomeDir ?? os.homedir(), ".codex");
|
|
20970
21375
|
}
|
|
20971
21376
|
|
|
21377
|
+
// agent-driver/dist/internal/errors.js
|
|
21378
|
+
var MAX_PUBLIC_ERROR_MESSAGE = 1000;
|
|
21379
|
+
var CREDENTIAL_NAME = String.raw`(?:[A-Za-z0-9]{1,32}[_-]){0,4}(?:api[_-]?key|access[_-]?key|secret(?:[_-]?access[_-]?key)?|client[_-]?secret|access[_-]?token|auth(?:orization)?|password|passwd|token|voucher)(?:[_-][A-Za-z0-9]{1,32}){0,4}`;
|
|
21380
|
+
var QUOTED_CREDENTIAL_ASSIGNMENT = new RegExp(String.raw`(["'])(${CREDENTIAL_NAME})\1\s*[:=]\s*(["'])[^"'\r\n]*\3`, "gi");
|
|
21381
|
+
var CREDENTIAL_ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9_-])((?:${CREDENTIAL_NAME})\s*[:=]\s*)(?!\[redacted\])[^\s,;}\]]+`, "gi");
|
|
21382
|
+
function scrubDriverErrorMessage(value, fallback = "Runtime operation failed") {
|
|
21383
|
+
const text2 = value instanceof Error ? value.message : String(value ?? "");
|
|
21384
|
+
const scrubbed = text2.replace(/\b(?:cmk|cmt|crk)_[A-Za-z0-9_-]+\b/g, "[redacted-token]").replace(/(Authorization\s*:\s*)(?:Bearer|Basic)\s+[^\s,;]+/gi, "$1[redacted]").replace(/Bearer\s+[A-Za-z0-9._\-]+/gi, "Bearer [redacted]").replace(/\b(?:sk|sk-ant|sk-proj|xox[abprs])-[A-Za-z0-9._\-]+/gi, "[redacted-token]").replace(QUOTED_CREDENTIAL_ASSIGNMENT, "$1$2$1:$3[redacted]$3").replace(CREDENTIAL_ASSIGNMENT, "$1[redacted]").replace(/(?<![A-Za-z0-9._%+\-])[A-Za-z0-9._%+\-]{1,320}@[A-Za-z0-9.\-]{1,255}\.[A-Za-z]{2,63}/g, "[redacted-email]").replace(/([?&])([^=\s]+)=([^&\s]+)/g, "$1$2=[redacted]").replace(/\/(?:Users|home)\/[^\r\n,;]+/g, "[redacted-path]").replace(/[A-Za-z]:\\Users\\[^\r\n,;]+/gi, "[redacted-path]").replace(/\\\\[^\\\s]+\\[^\r\n,;]+/g, "[redacted-path]").replace(/(?:[A-Za-z]:\\|\/)(?:[^\s/:]+[\\/]){1,}[^\s:]*/g, "[redacted-path]").trim();
|
|
21385
|
+
return (scrubbed || fallback).slice(0, MAX_PUBLIC_ERROR_MESSAGE);
|
|
21386
|
+
}
|
|
21387
|
+
function scrubDriverError(error51) {
|
|
21388
|
+
return {
|
|
21389
|
+
...error51,
|
|
21390
|
+
code: stableErrorCode(error51.code, "runtime_error"),
|
|
21391
|
+
message: scrubDriverErrorMessage(error51.message),
|
|
21392
|
+
...error51.details ? { details: scrubDetails(error51.details) } : {}
|
|
21393
|
+
};
|
|
21394
|
+
}
|
|
21395
|
+
function scrubDetails(details) {
|
|
21396
|
+
const scrubValue = (value, key) => {
|
|
21397
|
+
if (key && /api[_-]?key|access[_-]?token|auth(?:orization)?|password|passwd|secret|token/i.test(key)) {
|
|
21398
|
+
return "[redacted]";
|
|
21399
|
+
}
|
|
21400
|
+
if (typeof value === "string")
|
|
21401
|
+
return scrubDriverErrorMessage(value, "[redacted]");
|
|
21402
|
+
if (Array.isArray(value))
|
|
21403
|
+
return value.map((item) => scrubValue(item));
|
|
21404
|
+
if (value && typeof value === "object") {
|
|
21405
|
+
return Object.fromEntries(Object.entries(value).map(([childKey, child]) => [
|
|
21406
|
+
childKey,
|
|
21407
|
+
scrubValue(child, childKey)
|
|
21408
|
+
]));
|
|
21409
|
+
}
|
|
21410
|
+
return value;
|
|
21411
|
+
};
|
|
21412
|
+
return scrubValue(details);
|
|
21413
|
+
}
|
|
21414
|
+
function stableErrorCode(value, fallback) {
|
|
21415
|
+
const code = String(value ?? "");
|
|
21416
|
+
return /^[A-Za-z0-9_.-]{1,100}$/.test(code) ? code : fallback;
|
|
21417
|
+
}
|
|
21418
|
+
|
|
20972
21419
|
// agent-driver/dist/adapters/codex/index.js
|
|
21420
|
+
var SETTINGS_UPDATE_TIMEOUT_MS = 5000;
|
|
21421
|
+
var MODEL_LIST_TIMEOUT_MS = 5000;
|
|
21422
|
+
var MODEL_LIST_MAX = 64;
|
|
21423
|
+
var MODEL_EFFORT_MAX = 16;
|
|
20973
21424
|
function isCodexMissingRolloutError(message2) {
|
|
20974
21425
|
return /\bno\s+rollout\s+found\b/i.test(message2) || /\bmissing\s+rollout\b/i.test(message2) || /\brollout\b.*\b(not found|missing)\b/i.test(message2) || /\b(not found|missing)\b.*\brollout\b/i.test(message2);
|
|
20975
21426
|
}
|
|
@@ -20990,19 +21441,157 @@ class CodexDriver {
|
|
|
20990
21441
|
}
|
|
20991
21442
|
};
|
|
20992
21443
|
eventNormalizer = new CodexEventNormalizer;
|
|
21444
|
+
pendingAccountReadRequestIds = new Set;
|
|
20993
21445
|
requestId = 0;
|
|
20994
21446
|
codexHomeRoot = null;
|
|
20995
21447
|
proc = null;
|
|
20996
21448
|
pendingInitialPrompt = null;
|
|
20997
21449
|
pendingResumeFallbackParams = null;
|
|
21450
|
+
pendingSettingsUpdates = new Map;
|
|
20998
21451
|
nextRequestId() {
|
|
20999
21452
|
return ++this.requestId;
|
|
21000
21453
|
}
|
|
21454
|
+
requestAccountQuotaSnapshot() {
|
|
21455
|
+
if (!this.proc?.stdin || this.proc.stdin.destroyed)
|
|
21456
|
+
return;
|
|
21457
|
+
const accountReadRequestId = this.nextRequestId();
|
|
21458
|
+
this.pendingAccountReadRequestIds.add(accountReadRequestId);
|
|
21459
|
+
this.eventNormalizer.registerAccountReadRequest(accountReadRequestId);
|
|
21460
|
+
this.proc.stdin.write(jsonRpcRequest("account/read", { refreshToken: false }, accountReadRequestId) + `
|
|
21461
|
+
`);
|
|
21462
|
+
}
|
|
21463
|
+
requestQuotaSnapshot() {
|
|
21464
|
+
if (!this.proc?.stdin || this.proc.stdin.destroyed)
|
|
21465
|
+
return;
|
|
21466
|
+
const quotaReadRequestId = this.nextRequestId();
|
|
21467
|
+
this.eventNormalizer.registerQuotaReadRequest(quotaReadRequestId);
|
|
21468
|
+
this.proc.stdin.write(jsonRpcRequest("account/rateLimits/read", {}, quotaReadRequestId) + `
|
|
21469
|
+
`);
|
|
21470
|
+
}
|
|
21001
21471
|
get codexHome() {
|
|
21002
21472
|
return this.codexHomeRoot;
|
|
21003
21473
|
}
|
|
21004
|
-
probe(command) {
|
|
21005
|
-
|
|
21474
|
+
async probe(command) {
|
|
21475
|
+
const result = await probeCliRuntime("codex", {}, command);
|
|
21476
|
+
if (result.status !== "healthy")
|
|
21477
|
+
return result;
|
|
21478
|
+
return {
|
|
21479
|
+
...result,
|
|
21480
|
+
reasoning: await this.probeReasoningCatalog(command)
|
|
21481
|
+
};
|
|
21482
|
+
}
|
|
21483
|
+
async probeReasoningCatalog(command) {
|
|
21484
|
+
const spec = resolveSpawnSpec("codex", ["app-server", "--listen", "stdio://"], command);
|
|
21485
|
+
let proc;
|
|
21486
|
+
try {
|
|
21487
|
+
proc = spawnAgentProcess(spec.command, spec.args, {
|
|
21488
|
+
cwd: process.cwd(),
|
|
21489
|
+
env: { ...process.env, CI: "1" },
|
|
21490
|
+
shell: spec.shell
|
|
21491
|
+
});
|
|
21492
|
+
} catch {
|
|
21493
|
+
return;
|
|
21494
|
+
}
|
|
21495
|
+
return new Promise((resolve2) => {
|
|
21496
|
+
let settled = false;
|
|
21497
|
+
let buffer = "";
|
|
21498
|
+
let nextId = 0;
|
|
21499
|
+
let initializeId = 0;
|
|
21500
|
+
let listId = 0;
|
|
21501
|
+
const models = [];
|
|
21502
|
+
const seenModels = new Set;
|
|
21503
|
+
let defaultModelId;
|
|
21504
|
+
const finish = (catalog) => {
|
|
21505
|
+
if (settled)
|
|
21506
|
+
return;
|
|
21507
|
+
settled = true;
|
|
21508
|
+
clearTimeout(timer);
|
|
21509
|
+
const done = proc.pid ? killProcessTree(proc.pid, { graceMs: 250 }).catch(() => {}) : Promise.resolve().then(() => {
|
|
21510
|
+
proc.kill("SIGTERM");
|
|
21511
|
+
});
|
|
21512
|
+
done.finally(() => resolve2(catalog));
|
|
21513
|
+
};
|
|
21514
|
+
const requestModelPage = (cursor) => {
|
|
21515
|
+
listId = ++nextId;
|
|
21516
|
+
proc.stdin?.write(jsonRpcRequest("model/list", { limit: Math.min(MODEL_LIST_MAX - models.length, MODEL_LIST_MAX), includeHidden: false, ...cursor ? { cursor } : {} }, listId) + `
|
|
21517
|
+
`);
|
|
21518
|
+
};
|
|
21519
|
+
const consumeModel = (value) => {
|
|
21520
|
+
if (!value || typeof value !== "object" || models.length >= MODEL_LIST_MAX)
|
|
21521
|
+
return;
|
|
21522
|
+
const model = value;
|
|
21523
|
+
const id = typeof model.id === "string" ? model.id.trim() : "";
|
|
21524
|
+
if (!id || id.length > 100 || seenModels.has(id))
|
|
21525
|
+
return;
|
|
21526
|
+
const rawOptions = Array.isArray(model.supportedReasoningEfforts) ? model.supportedReasoningEfforts : [];
|
|
21527
|
+
const seenEfforts = new Set;
|
|
21528
|
+
const supportedReasoningEfforts = rawOptions.flatMap((raw) => {
|
|
21529
|
+
if (!raw || typeof raw !== "object")
|
|
21530
|
+
return [];
|
|
21531
|
+
const option = raw;
|
|
21532
|
+
const value2 = typeof option.reasoningEffort === "string" ? option.reasoningEffort.trim() : "";
|
|
21533
|
+
if (!value2 || value2.length > 32 || !/^[A-Za-z0-9._-]+$/.test(value2) || seenEfforts.has(value2))
|
|
21534
|
+
return [];
|
|
21535
|
+
seenEfforts.add(value2);
|
|
21536
|
+
const description = typeof option.description === "string" ? option.description.slice(0, 256) : undefined;
|
|
21537
|
+
return [{ value: value2, ...description ? { description } : {} }];
|
|
21538
|
+
}).slice(0, MODEL_EFFORT_MAX);
|
|
21539
|
+
const candidateDefault = typeof model.defaultReasoningEffort === "string" ? model.defaultReasoningEffort : undefined;
|
|
21540
|
+
seenModels.add(id);
|
|
21541
|
+
if (model.isDefault === true)
|
|
21542
|
+
defaultModelId = id;
|
|
21543
|
+
models.push({
|
|
21544
|
+
id,
|
|
21545
|
+
supportedReasoningEfforts,
|
|
21546
|
+
...candidateDefault && supportedReasoningEfforts.some((item) => item.value === candidateDefault) ? { defaultReasoningEffort: candidateDefault } : {}
|
|
21547
|
+
});
|
|
21548
|
+
};
|
|
21549
|
+
const onLine = (line) => {
|
|
21550
|
+
let message2;
|
|
21551
|
+
try {
|
|
21552
|
+
message2 = JSON.parse(line);
|
|
21553
|
+
} catch {
|
|
21554
|
+
return;
|
|
21555
|
+
}
|
|
21556
|
+
if (message2.id === initializeId) {
|
|
21557
|
+
if (message2.error)
|
|
21558
|
+
return finish();
|
|
21559
|
+
requestModelPage();
|
|
21560
|
+
return;
|
|
21561
|
+
}
|
|
21562
|
+
if (message2.id !== listId)
|
|
21563
|
+
return;
|
|
21564
|
+
if (message2.error || !message2.result || typeof message2.result !== "object")
|
|
21565
|
+
return finish();
|
|
21566
|
+
const result = message2.result;
|
|
21567
|
+
for (const model of Array.isArray(result.data) ? result.data : [])
|
|
21568
|
+
consumeModel(model);
|
|
21569
|
+
const cursor = typeof result.nextCursor === "string" ? result.nextCursor : undefined;
|
|
21570
|
+
if (cursor && models.length < MODEL_LIST_MAX)
|
|
21571
|
+
return requestModelPage(cursor);
|
|
21572
|
+
finish({
|
|
21573
|
+
updateMode: "live_next_turn",
|
|
21574
|
+
...defaultModelId ? { defaultModelId } : {},
|
|
21575
|
+
models
|
|
21576
|
+
});
|
|
21577
|
+
};
|
|
21578
|
+
const timer = setTimeout(() => finish(), MODEL_LIST_TIMEOUT_MS);
|
|
21579
|
+
timer.unref?.();
|
|
21580
|
+
proc.stdout?.on("data", (chunk2) => {
|
|
21581
|
+
buffer += chunk2.toString();
|
|
21582
|
+
const lines = buffer.split(`
|
|
21583
|
+
`);
|
|
21584
|
+
buffer = lines.pop() ?? "";
|
|
21585
|
+
for (const line of lines)
|
|
21586
|
+
if (line.trim())
|
|
21587
|
+
onLine(line);
|
|
21588
|
+
});
|
|
21589
|
+
proc.on("error", () => finish());
|
|
21590
|
+
proc.on("exit", () => finish());
|
|
21591
|
+
initializeId = ++nextId;
|
|
21592
|
+
proc.stdin?.write(jsonRpcRequest("initialize", { clientInfo: { name: "alook-agent-driver-probe", version: "0.1.24" }, capabilities: { experimentalApi: true } }, initializeId) + `
|
|
21593
|
+
`);
|
|
21594
|
+
});
|
|
21006
21595
|
}
|
|
21007
21596
|
async openLane(ctx, options) {
|
|
21008
21597
|
return createProcessLane(this, ctx, { onRawStdoutLine: options?.onRawStdoutLine });
|
|
@@ -21018,6 +21607,9 @@ class CodexDriver {
|
|
|
21018
21607
|
shell: spec.shell
|
|
21019
21608
|
});
|
|
21020
21609
|
this.proc = proc;
|
|
21610
|
+
proc.once("exit", () => {
|
|
21611
|
+
this.failPendingSettingsUpdates("settings_process_exited", "Codex exited before acknowledging the settings update");
|
|
21612
|
+
});
|
|
21021
21613
|
const initialPrompt = ctx.prompt?.trim() ? ctx.prompt : null;
|
|
21022
21614
|
this.pendingInitialPrompt = initialPrompt;
|
|
21023
21615
|
queueMicrotask(() => {
|
|
@@ -21046,11 +21638,21 @@ class CodexDriver {
|
|
|
21046
21638
|
proc.stdin?.write(jsonRpcRequest("thread/start", freshParams, this.nextRequestId()) + `
|
|
21047
21639
|
`);
|
|
21048
21640
|
}
|
|
21641
|
+
this.requestAccountQuotaSnapshot();
|
|
21049
21642
|
});
|
|
21050
21643
|
return { process: proc };
|
|
21051
21644
|
}
|
|
21052
21645
|
normalizeLine(line) {
|
|
21646
|
+
const settingsResponse = this.consumeSettingsUpdateResponse(line);
|
|
21647
|
+
if (settingsResponse)
|
|
21648
|
+
return [];
|
|
21649
|
+
const parsed = tryParseJsonLine(line);
|
|
21053
21650
|
const events = this.eventNormalizer.normalizeLine(line);
|
|
21651
|
+
if (typeof parsed?.id === "number" && this.pendingAccountReadRequestIds.delete(parsed.id)) {
|
|
21652
|
+
this.requestQuotaSnapshot();
|
|
21653
|
+
}
|
|
21654
|
+
if (parsed?.method === "account/updated")
|
|
21655
|
+
this.requestAccountQuotaSnapshot();
|
|
21054
21656
|
if (this.pendingResumeFallbackParams && this.proc?.stdin && !this.proc.stdin.destroyed) {
|
|
21055
21657
|
const rolloutErr = events.find((e) => e.kind === "error" && isCodexMissingRolloutError(e.message));
|
|
21056
21658
|
if (rolloutErr) {
|
|
@@ -21074,6 +21676,90 @@ class CodexDriver {
|
|
|
21074
21676
|
}
|
|
21075
21677
|
return events;
|
|
21076
21678
|
}
|
|
21679
|
+
updateSettings(input) {
|
|
21680
|
+
const threadId = this.eventNormalizer.currentSessionId;
|
|
21681
|
+
const stdin = this.proc?.stdin;
|
|
21682
|
+
if (!threadId || !stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false) {
|
|
21683
|
+
return Promise.resolve({
|
|
21684
|
+
status: "failed",
|
|
21685
|
+
error: this.settingsError("process", "settings_thread_unavailable", "Codex thread is not available for a settings update", true)
|
|
21686
|
+
});
|
|
21687
|
+
}
|
|
21688
|
+
const id = this.nextRequestId();
|
|
21689
|
+
return new Promise((resolve2) => {
|
|
21690
|
+
const timer = setTimeout(() => {
|
|
21691
|
+
if (!this.pendingSettingsUpdates.delete(id))
|
|
21692
|
+
return;
|
|
21693
|
+
resolve2({
|
|
21694
|
+
status: "failed",
|
|
21695
|
+
error: this.settingsError("timeout", "settings_update_timeout", "Codex did not acknowledge the settings update before the deadline", true)
|
|
21696
|
+
});
|
|
21697
|
+
}, SETTINGS_UPDATE_TIMEOUT_MS);
|
|
21698
|
+
timer.unref?.();
|
|
21699
|
+
this.pendingSettingsUpdates.set(id, { resolve: resolve2, timer });
|
|
21700
|
+
try {
|
|
21701
|
+
stdin.write(jsonRpcRequest("thread/settings/update", { threadId, effort: input.reasoningEffort }, id) + `
|
|
21702
|
+
`);
|
|
21703
|
+
} catch (error51) {
|
|
21704
|
+
clearTimeout(timer);
|
|
21705
|
+
this.pendingSettingsUpdates.delete(id);
|
|
21706
|
+
resolve2({
|
|
21707
|
+
status: "failed",
|
|
21708
|
+
error: this.settingsError("process", "settings_update_write_failed", String(error51), true)
|
|
21709
|
+
});
|
|
21710
|
+
}
|
|
21711
|
+
});
|
|
21712
|
+
}
|
|
21713
|
+
consumeSettingsUpdateResponse(line) {
|
|
21714
|
+
let value;
|
|
21715
|
+
try {
|
|
21716
|
+
value = JSON.parse(line);
|
|
21717
|
+
} catch {
|
|
21718
|
+
return false;
|
|
21719
|
+
}
|
|
21720
|
+
if (!value || typeof value !== "object")
|
|
21721
|
+
return false;
|
|
21722
|
+
const record2 = value;
|
|
21723
|
+
if (typeof record2.id !== "number")
|
|
21724
|
+
return false;
|
|
21725
|
+
const pending = this.pendingSettingsUpdates.get(record2.id);
|
|
21726
|
+
if (!pending)
|
|
21727
|
+
return false;
|
|
21728
|
+
clearTimeout(pending.timer);
|
|
21729
|
+
this.pendingSettingsUpdates.delete(record2.id);
|
|
21730
|
+
const error51 = record2.error;
|
|
21731
|
+
if (!error51 || typeof error51 !== "object") {
|
|
21732
|
+
pending.resolve({ status: "applied" });
|
|
21733
|
+
return true;
|
|
21734
|
+
}
|
|
21735
|
+
const rpcError = error51;
|
|
21736
|
+
const message2 = typeof rpcError.message === "string" ? rpcError.message : "Codex rejected the settings update";
|
|
21737
|
+
if (rpcError.code === -32601 || /method\s+not\s+found/i.test(message2)) {
|
|
21738
|
+
pending.resolve({
|
|
21739
|
+
status: "unsupported",
|
|
21740
|
+
error: this.settingsError("protocol", "settings_update_unsupported", "Codex does not support live reasoning settings updates", false)
|
|
21741
|
+
});
|
|
21742
|
+
} else {
|
|
21743
|
+
pending.resolve({
|
|
21744
|
+
status: "failed",
|
|
21745
|
+
error: this.settingsError("protocol", "settings_update_rejected", message2, true)
|
|
21746
|
+
});
|
|
21747
|
+
}
|
|
21748
|
+
return true;
|
|
21749
|
+
}
|
|
21750
|
+
settingsError(category, code, message2, retryable) {
|
|
21751
|
+
return { category, code, message: scrubDriverErrorMessage(message2), retryable };
|
|
21752
|
+
}
|
|
21753
|
+
failPendingSettingsUpdates(code, message2) {
|
|
21754
|
+
for (const [id, pending] of this.pendingSettingsUpdates) {
|
|
21755
|
+
clearTimeout(pending.timer);
|
|
21756
|
+
this.pendingSettingsUpdates.delete(id);
|
|
21757
|
+
pending.resolve({
|
|
21758
|
+
status: "failed",
|
|
21759
|
+
error: this.settingsError("process", code, message2, true)
|
|
21760
|
+
});
|
|
21761
|
+
}
|
|
21762
|
+
}
|
|
21077
21763
|
get currentSessionId() {
|
|
21078
21764
|
return this.eventNormalizer.currentSessionId;
|
|
21079
21765
|
}
|
|
@@ -21392,15 +22078,6 @@ class CursorAcpLane {
|
|
|
21392
22078
|
}
|
|
21393
22079
|
this.activePrompt = null;
|
|
21394
22080
|
this.openToolCalls.clear();
|
|
21395
|
-
const usage = record2(result.usage);
|
|
21396
|
-
if (usage) {
|
|
21397
|
-
this.events.emit("runtime_event", {
|
|
21398
|
-
kind: "telemetry",
|
|
21399
|
-
name: "token_usage",
|
|
21400
|
-
source: "cursor.acp",
|
|
21401
|
-
attrs: usage
|
|
21402
|
-
});
|
|
21403
|
-
}
|
|
21404
22081
|
this.events.emit("runtime_event", {
|
|
21405
22082
|
kind: "turn_end",
|
|
21406
22083
|
sessionId: this.sessionId ?? undefined,
|
|
@@ -21750,10 +22427,10 @@ class CursorDriver {
|
|
|
21750
22427
|
}
|
|
21751
22428
|
|
|
21752
22429
|
// agent-driver/dist/adapters/opencode/index.js
|
|
21753
|
-
import { randomBytes as
|
|
22430
|
+
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
21754
22431
|
|
|
21755
22432
|
// agent-driver/dist/adapters/opencode/service-lane.js
|
|
21756
|
-
import { randomBytes } from "node:crypto";
|
|
22433
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
21757
22434
|
import { EventEmitter as EventEmitter3 } from "node:events";
|
|
21758
22435
|
import { createServer as createServer2 } from "node:net";
|
|
21759
22436
|
var SUPPORTED_VERSION = "1.17.20";
|
|
@@ -21892,7 +22569,7 @@ class OpenCodeServiceLane {
|
|
|
21892
22569
|
this.ctx = ctx;
|
|
21893
22570
|
this.options = options;
|
|
21894
22571
|
this.fetchFn = options.fetch ?? fetch;
|
|
21895
|
-
this.password = options.password ??
|
|
22572
|
+
this.password = options.password ?? randomBytes2(32).toString("base64url");
|
|
21896
22573
|
}
|
|
21897
22574
|
get currentSessionId() {
|
|
21898
22575
|
return this.sessionId;
|
|
@@ -22506,12 +23183,20 @@ class OpenCodeServiceLane {
|
|
|
22506
23183
|
});
|
|
22507
23184
|
}
|
|
22508
23185
|
const tokens = record3(data.tokens);
|
|
22509
|
-
if (tokens) {
|
|
23186
|
+
if (tokens && data.finish !== "tool-calls") {
|
|
23187
|
+
const cache = record3(tokens.cache);
|
|
23188
|
+
const metric2 = (value2) => typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 0 ? value2 : null;
|
|
23189
|
+
const cacheParts = [cache?.read, cache?.write].filter((value2) => typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 0);
|
|
23190
|
+
const cacheTotal = cacheParts.reduce((sum, value2) => sum + value2, 0);
|
|
22510
23191
|
this.events.emit("runtime_event", {
|
|
22511
23192
|
kind: "telemetry",
|
|
22512
23193
|
name: "token_usage",
|
|
22513
23194
|
source: "opencode.v2",
|
|
22514
|
-
|
|
23195
|
+
usage: {
|
|
23196
|
+
input: metric2(tokens.input),
|
|
23197
|
+
output: metric2(tokens.output),
|
|
23198
|
+
cache: cacheParts.length > 0 && Number.isSafeInteger(cacheTotal) ? cacheTotal : null
|
|
23199
|
+
}
|
|
22515
23200
|
});
|
|
22516
23201
|
}
|
|
22517
23202
|
break;
|
|
@@ -22817,7 +23502,7 @@ class OpenCodeServiceLane {
|
|
|
22817
23502
|
return headers;
|
|
22818
23503
|
}
|
|
22819
23504
|
newMessageId() {
|
|
22820
|
-
return `msg_${
|
|
23505
|
+
return `msg_${randomBytes2(16).toString("hex")}`;
|
|
22821
23506
|
}
|
|
22822
23507
|
diagnostic(severity, message2) {
|
|
22823
23508
|
this.events.emit("runtime_event", {
|
|
@@ -22882,7 +23567,7 @@ class OpenCodeServiceLane {
|
|
|
22882
23567
|
|
|
22883
23568
|
// agent-driver/dist/adapters/opencode/index.js
|
|
22884
23569
|
function createOpenCodeMessageId() {
|
|
22885
|
-
return `msg_${
|
|
23570
|
+
return `msg_${randomBytes3(16).toString("hex")}`;
|
|
22886
23571
|
}
|
|
22887
23572
|
|
|
22888
23573
|
class OpenCodeDriver {
|
|
@@ -23660,48 +24345,6 @@ function assertInstructionFileName(name) {
|
|
|
23660
24345
|
}
|
|
23661
24346
|
}
|
|
23662
24347
|
|
|
23663
|
-
// agent-driver/dist/internal/errors.js
|
|
23664
|
-
var MAX_PUBLIC_ERROR_MESSAGE = 1000;
|
|
23665
|
-
var CREDENTIAL_NAME = String.raw`(?:[A-Za-z0-9]{1,32}[_-]){0,4}(?:api[_-]?key|access[_-]?key|secret(?:[_-]?access[_-]?key)?|client[_-]?secret|access[_-]?token|auth(?:orization)?|password|passwd|token|voucher)(?:[_-][A-Za-z0-9]{1,32}){0,4}`;
|
|
23666
|
-
var QUOTED_CREDENTIAL_ASSIGNMENT = new RegExp(String.raw`(["'])(${CREDENTIAL_NAME})\1\s*[:=]\s*(["'])[^"'\r\n]*\3`, "gi");
|
|
23667
|
-
var CREDENTIAL_ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9_-])((?:${CREDENTIAL_NAME})\s*[:=]\s*)(?!\[redacted\])[^\s,;}\]]+`, "gi");
|
|
23668
|
-
function scrubDriverErrorMessage(value, fallback = "Runtime operation failed") {
|
|
23669
|
-
const text2 = value instanceof Error ? value.message : String(value ?? "");
|
|
23670
|
-
const scrubbed = text2.replace(/\b(?:cmk|cmt|crk)_[A-Za-z0-9_-]+\b/g, "[redacted-token]").replace(/(Authorization\s*:\s*)(?:Bearer|Basic)\s+[^\s,;]+/gi, "$1[redacted]").replace(/Bearer\s+[A-Za-z0-9._\-]+/gi, "Bearer [redacted]").replace(/\b(?:sk|sk-ant|sk-proj|xox[abprs])-[A-Za-z0-9._\-]+/gi, "[redacted-token]").replace(QUOTED_CREDENTIAL_ASSIGNMENT, "$1$2$1:$3[redacted]$3").replace(CREDENTIAL_ASSIGNMENT, "$1[redacted]").replace(/(?<![A-Za-z0-9._%+\-])[A-Za-z0-9._%+\-]{1,320}@[A-Za-z0-9.\-]{1,255}\.[A-Za-z]{2,63}/g, "[redacted-email]").replace(/([?&])([^=\s]+)=([^&\s]+)/g, "$1$2=[redacted]").replace(/\/(?:Users|home)\/[^\r\n,;]+/g, "[redacted-path]").replace(/[A-Za-z]:\\Users\\[^\r\n,;]+/gi, "[redacted-path]").replace(/\\\\[^\\\s]+\\[^\r\n,;]+/g, "[redacted-path]").replace(/(?:[A-Za-z]:\\|\/)(?:[^\s/:]+[\\/]){1,}[^\s:]*/g, "[redacted-path]").trim();
|
|
23671
|
-
return (scrubbed || fallback).slice(0, MAX_PUBLIC_ERROR_MESSAGE);
|
|
23672
|
-
}
|
|
23673
|
-
function scrubDriverError(error51) {
|
|
23674
|
-
return {
|
|
23675
|
-
...error51,
|
|
23676
|
-
code: stableErrorCode(error51.code, "runtime_error"),
|
|
23677
|
-
message: scrubDriverErrorMessage(error51.message),
|
|
23678
|
-
...error51.details ? { details: scrubDetails(error51.details) } : {}
|
|
23679
|
-
};
|
|
23680
|
-
}
|
|
23681
|
-
function scrubDetails(details) {
|
|
23682
|
-
const scrubValue = (value, key) => {
|
|
23683
|
-
if (key && /api[_-]?key|access[_-]?token|auth(?:orization)?|password|passwd|secret|token/i.test(key)) {
|
|
23684
|
-
return "[redacted]";
|
|
23685
|
-
}
|
|
23686
|
-
if (typeof value === "string")
|
|
23687
|
-
return scrubDriverErrorMessage(value, "[redacted]");
|
|
23688
|
-
if (Array.isArray(value))
|
|
23689
|
-
return value.map((item) => scrubValue(item));
|
|
23690
|
-
if (value && typeof value === "object") {
|
|
23691
|
-
return Object.fromEntries(Object.entries(value).map(([childKey, child]) => [
|
|
23692
|
-
childKey,
|
|
23693
|
-
scrubValue(child, childKey)
|
|
23694
|
-
]));
|
|
23695
|
-
}
|
|
23696
|
-
return value;
|
|
23697
|
-
};
|
|
23698
|
-
return scrubValue(details);
|
|
23699
|
-
}
|
|
23700
|
-
function stableErrorCode(value, fallback) {
|
|
23701
|
-
const code = String(value ?? "");
|
|
23702
|
-
return /^[A-Za-z0-9_.-]{1,100}$/.test(code) ? code : fallback;
|
|
23703
|
-
}
|
|
23704
|
-
|
|
23705
24348
|
// agent-driver/dist/controller/logical-session.js
|
|
23706
24349
|
import { mkdirSync as mkdirSync4 } from "node:fs";
|
|
23707
24350
|
var SEMANTIC_ASSEMBLER_MAX_BYTES = 1048576;
|
|
@@ -23819,6 +24462,8 @@ class LogicalAgentSession {
|
|
|
23819
24462
|
toolBoundaryFlushDisabled = false;
|
|
23820
24463
|
safeBoundaryFlush;
|
|
23821
24464
|
safeBoundaryDelivery;
|
|
24465
|
+
settingsUpdateTail = Promise.resolve();
|
|
24466
|
+
settingsUpdatePending = false;
|
|
23822
24467
|
turnAdmission;
|
|
23823
24468
|
instructionsMaterialized = false;
|
|
23824
24469
|
lifecycleGeneration = 0;
|
|
@@ -23874,6 +24519,35 @@ class LogicalAgentSession {
|
|
|
23874
24519
|
send(message2) {
|
|
23875
24520
|
return this.admit("send", message2);
|
|
23876
24521
|
}
|
|
24522
|
+
updateSettings(input) {
|
|
24523
|
+
if (this.state === "closed" || this.state === "stopping" || this.finishing) {
|
|
24524
|
+
return Promise.resolve({
|
|
24525
|
+
status: "failed",
|
|
24526
|
+
error: driverError("process", "settings_session_closed", "Runtime session is closed", true)
|
|
24527
|
+
});
|
|
24528
|
+
}
|
|
24529
|
+
this.settingsUpdatePending = true;
|
|
24530
|
+
const operation = this.settingsUpdateTail.then(async () => {
|
|
24531
|
+
if (!this.lane?.updateSettings)
|
|
24532
|
+
return { status: "unsupported" };
|
|
24533
|
+
try {
|
|
24534
|
+
return await this.lane.updateSettings(input);
|
|
24535
|
+
} catch (error51) {
|
|
24536
|
+
return {
|
|
24537
|
+
status: "failed",
|
|
24538
|
+
error: driverError("process", "settings_update_failed", String(error51), true)
|
|
24539
|
+
};
|
|
24540
|
+
}
|
|
24541
|
+
});
|
|
24542
|
+
this.settingsUpdateTail = operation.then((result) => {
|
|
24543
|
+
if (result.status === "applied") {
|
|
24544
|
+
this.settingsUpdatePending = false;
|
|
24545
|
+
return;
|
|
24546
|
+
}
|
|
24547
|
+
return new Promise(() => {});
|
|
24548
|
+
});
|
|
24549
|
+
return operation;
|
|
24550
|
+
}
|
|
23877
24551
|
async interrupt(input) {
|
|
23878
24552
|
if (this.state === "closed" || this.state === "stopping" || this.finishing)
|
|
23879
24553
|
return { status: "closed" };
|
|
@@ -24035,7 +24709,7 @@ class LogicalAgentSession {
|
|
|
24035
24709
|
}
|
|
24036
24710
|
return receipt;
|
|
24037
24711
|
}
|
|
24038
|
-
if (this.state === "idle" && (this.queued.length > 0 || this.safeBoundaryFlush !== undefined || this.safeBoundaryDelivery !== undefined)) {
|
|
24712
|
+
if (this.state === "idle" && (this.queued.length > 0 || this.safeBoundaryFlush !== undefined || this.safeBoundaryDelivery !== undefined || this.settingsUpdatePending)) {
|
|
24039
24713
|
return this.queue(message2, "runtime_busy");
|
|
24040
24714
|
}
|
|
24041
24715
|
return this.startTurn([message2], "prompt");
|
|
@@ -24343,11 +25017,10 @@ class LogicalAgentSession {
|
|
|
24343
25017
|
}
|
|
24344
25018
|
return;
|
|
24345
25019
|
case "telemetry": {
|
|
24346
|
-
const details = jsonValue(event.attrs);
|
|
24347
25020
|
if (event.name === "token_usage") {
|
|
24348
|
-
this.emit({ type: "token_usage", turnId, source: event.source, usage:
|
|
25021
|
+
this.emit({ type: "token_usage", turnId, source: event.source, usage: event.usage });
|
|
24349
25022
|
} else {
|
|
24350
|
-
this.emit({ type: "rate_limits", turnId, source: event.source,
|
|
25023
|
+
this.emit({ type: "rate_limits", turnId, source: event.source, quota: event.quota });
|
|
24351
25024
|
}
|
|
24352
25025
|
return;
|
|
24353
25026
|
}
|
|
@@ -24448,7 +25121,7 @@ class LogicalAgentSession {
|
|
|
24448
25121
|
if (this.adapter.execution.lifetime === "turn") {
|
|
24449
25122
|
this.processTurnEnded = true;
|
|
24450
25123
|
} else {
|
|
24451
|
-
Promise.resolve().then(() => this.safeBoundaryFlush).then(() => this.startNextQueued());
|
|
25124
|
+
Promise.resolve().then(() => this.safeBoundaryFlush).then(() => this.settingsUpdateTail).then(() => this.startNextQueued());
|
|
24452
25125
|
}
|
|
24453
25126
|
}
|
|
24454
25127
|
flushSafeBoundaryQueue() {
|
|
@@ -24948,8 +25621,14 @@ function createAgentDriverSdkWithRegistry(options) {
|
|
|
24948
25621
|
assertAdapterCompatibility(String(registration.id), registration.capabilities, adapter);
|
|
24949
25622
|
const command = capabilities2.commandOverride ? input.command : undefined;
|
|
24950
25623
|
const result = await adapter.probe(command);
|
|
24951
|
-
if (result.status === "healthy")
|
|
24952
|
-
return {
|
|
25624
|
+
if (result.status === "healthy") {
|
|
25625
|
+
return {
|
|
25626
|
+
status: "healthy",
|
|
25627
|
+
version: result.version,
|
|
25628
|
+
capabilities: capabilities2,
|
|
25629
|
+
reasoning: result.reasoning
|
|
25630
|
+
};
|
|
25631
|
+
}
|
|
24953
25632
|
return {
|
|
24954
25633
|
status: "unhealthy",
|
|
24955
25634
|
error: {
|
|
@@ -24958,7 +25637,8 @@ function createAgentDriverSdkWithRegistry(options) {
|
|
|
24958
25637
|
message: `Backend ${input.backend} is unavailable`,
|
|
24959
25638
|
retryable: true
|
|
24960
25639
|
},
|
|
24961
|
-
capabilities: capabilities2
|
|
25640
|
+
capabilities: capabilities2,
|
|
25641
|
+
reasoning: result.reasoning
|
|
24962
25642
|
};
|
|
24963
25643
|
} catch (error51) {
|
|
24964
25644
|
const contractInvalid = error51 instanceof Error && (error51.message.startsWith("Adapter ") || error51.message.startsWith("Agent backend registration "));
|
|
@@ -25110,7 +25790,12 @@ async function detectRuntimes() {
|
|
|
25110
25790
|
const driver = getDriver(id);
|
|
25111
25791
|
const probe = await driver.probe();
|
|
25112
25792
|
if (probe.status === "healthy") {
|
|
25113
|
-
results.push({
|
|
25793
|
+
results.push({
|
|
25794
|
+
id,
|
|
25795
|
+
status: "healthy",
|
|
25796
|
+
version: probe.version,
|
|
25797
|
+
reasoning: probe.reasoning
|
|
25798
|
+
});
|
|
25114
25799
|
} else {
|
|
25115
25800
|
results.push({
|
|
25116
25801
|
id,
|
|
@@ -25226,7 +25911,7 @@ import * as path12 from "node:path";
|
|
|
25226
25911
|
import { WebSocket } from "ws";
|
|
25227
25912
|
|
|
25228
25913
|
// src/daemon/createDaemon.ts
|
|
25229
|
-
import { homedir as
|
|
25914
|
+
import { homedir as homedir5 } from "os";
|
|
25230
25915
|
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8 } from "node:fs";
|
|
25231
25916
|
|
|
25232
25917
|
// src/util/rotatingFileSink.ts
|
|
@@ -25914,23 +26599,43 @@ class WsControlChannel {
|
|
|
25914
26599
|
this.ws.send(JSON.stringify(frame));
|
|
25915
26600
|
}
|
|
25916
26601
|
resyncOnConnect() {
|
|
26602
|
+
const sendActivities = (activities, counts) => {
|
|
26603
|
+
for (const activity of activities) {
|
|
26604
|
+
this.sendFrame({ type: "agent_activity", ...activity });
|
|
26605
|
+
}
|
|
26606
|
+
this.log.info("resync sent", {
|
|
26607
|
+
ready: counts.ready,
|
|
26608
|
+
sessions: counts.sessions,
|
|
26609
|
+
activities: activities.length,
|
|
26610
|
+
pendingAuditEvents: this.pendingBotAuditEvents.size
|
|
26611
|
+
});
|
|
26612
|
+
};
|
|
25917
26613
|
if (this.resyncProvider) {
|
|
25918
|
-
const
|
|
25919
|
-
this.
|
|
25920
|
-
|
|
25921
|
-
|
|
25922
|
-
|
|
25923
|
-
|
|
25924
|
-
this.sendFrame({ type: "agent_activity", ...a });
|
|
26614
|
+
const socketAtStart = this.ws;
|
|
26615
|
+
const snapshot = this.resyncProvider();
|
|
26616
|
+
this.sendFrame({ type: "ready", ...snapshot.ready });
|
|
26617
|
+
for (const session2 of snapshot.sessions) {
|
|
26618
|
+
this.sendFrame({ type: "agent_session", ...session2 });
|
|
26619
|
+
}
|
|
25925
26620
|
for (const frame of this.pendingBotAuditEvents.values())
|
|
25926
26621
|
this.sendFrame(frame);
|
|
25927
26622
|
this.scheduleAuditRetry();
|
|
25928
|
-
|
|
25929
|
-
|
|
25930
|
-
|
|
25931
|
-
|
|
25932
|
-
|
|
25933
|
-
|
|
26623
|
+
const activities = snapshot.activities ?? [];
|
|
26624
|
+
const counts = {
|
|
26625
|
+
ready: snapshot.ready.runtimeReport.length,
|
|
26626
|
+
sessions: snapshot.sessions.length
|
|
26627
|
+
};
|
|
26628
|
+
if (activities instanceof Promise) {
|
|
26629
|
+
activities.then((resolved) => {
|
|
26630
|
+
if (this.ws === socketAtStart && this.statusValue === "open") {
|
|
26631
|
+
sendActivities(resolved, counts);
|
|
26632
|
+
}
|
|
26633
|
+
}).catch((err) => {
|
|
26634
|
+
this.log.warn("resync provider failed", { err: describeErr(err) });
|
|
26635
|
+
});
|
|
26636
|
+
} else {
|
|
26637
|
+
sendActivities(activities, counts);
|
|
26638
|
+
}
|
|
25934
26639
|
}
|
|
25935
26640
|
for (const hook of this.resyncHooks) {
|
|
25936
26641
|
try {
|
|
@@ -26736,6 +27441,29 @@ function reduceManager(state, event) {
|
|
|
26736
27441
|
a.inbox = [...a.inbox, event.message];
|
|
26737
27442
|
a.idleSince = null;
|
|
26738
27443
|
});
|
|
27444
|
+
case "runtime_config_queued":
|
|
27445
|
+
return mutate(state, event.agentId, (a) => {
|
|
27446
|
+
if (!a.inbox.some((message2) => message2.id === event.message.id)) {
|
|
27447
|
+
a.inbox = [...a.inbox, event.message];
|
|
27448
|
+
}
|
|
27449
|
+
syncExecutionProjection(a);
|
|
27450
|
+
a.idleSince = null;
|
|
27451
|
+
});
|
|
27452
|
+
case "runtime_config_applied": {
|
|
27453
|
+
const existing = state.agents[event.agentId];
|
|
27454
|
+
if (!existing)
|
|
27455
|
+
return { state, effects: [] };
|
|
27456
|
+
const agent2 = clone2(existing);
|
|
27457
|
+
if (agent2.status !== "running" || leaseIsWorking(agent2.execution.lease) || agent2.pendingAdmissions.length > 0 || agent2.inbox.length === 0)
|
|
27458
|
+
return { state, effects: [] };
|
|
27459
|
+
const messages = drainInbox(agent2);
|
|
27460
|
+
return commit(state, agent2, messages.map((message2) => ({
|
|
27461
|
+
type: "send",
|
|
27462
|
+
agentId: event.agentId,
|
|
27463
|
+
message: message2,
|
|
27464
|
+
mode: "idle"
|
|
27465
|
+
})));
|
|
27466
|
+
}
|
|
26739
27467
|
case "turn_started": {
|
|
26740
27468
|
const existing = state.agents[event.agentId];
|
|
26741
27469
|
if (!existing || existing.execution.sessionInstanceId !== event.sessionInstanceId)
|
|
@@ -26943,7 +27671,7 @@ function onTurnCompleted(state, agentId, sessionInstanceId, nowMs, turnId, endRe
|
|
|
26943
27671
|
agent2.stalledSessionId = null;
|
|
26944
27672
|
syncExecutionProjection(agent2);
|
|
26945
27673
|
const clearEffects = clearedStallSessionId === null ? [] : [{ type: "clear_stall_recovery", agentId, sessionId: clearedStallSessionId }];
|
|
26946
|
-
if (agent2.inbox.length > 0) {
|
|
27674
|
+
if (agent2.inbox.length > 0 && !agent2.resetting) {
|
|
26947
27675
|
const messages = drainInbox(agent2);
|
|
26948
27676
|
return commit(state, agent2, [
|
|
26949
27677
|
...clearEffects,
|
|
@@ -27203,6 +27931,144 @@ function toAgentBackendSelection(config2) {
|
|
|
27203
27931
|
function runtimeModelName(config2) {
|
|
27204
27932
|
return config2?.model.kind === "default" ? undefined : config2?.model.name;
|
|
27205
27933
|
}
|
|
27934
|
+
// agent-driver/dist/provider-quota.js
|
|
27935
|
+
import { execFile } from "node:child_process";
|
|
27936
|
+
import { readFile } from "node:fs/promises";
|
|
27937
|
+
import { homedir as homedir3 } from "node:os";
|
|
27938
|
+
import { join as join11 } from "node:path";
|
|
27939
|
+
import { promisify } from "node:util";
|
|
27940
|
+
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
27941
|
+
var execFileAsync = promisify(execFile);
|
|
27942
|
+
var claudeAccessToken = null;
|
|
27943
|
+
var claudeSourceEpoch = randomBytes5(16).toString("base64url");
|
|
27944
|
+
function parseCredentials(value) {
|
|
27945
|
+
try {
|
|
27946
|
+
const parsed = JSON.parse(value);
|
|
27947
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
27948
|
+
} catch {
|
|
27949
|
+
return null;
|
|
27950
|
+
}
|
|
27951
|
+
}
|
|
27952
|
+
async function claudeCredentials(options) {
|
|
27953
|
+
const platform = options.platform ?? process.platform;
|
|
27954
|
+
if (platform === "darwin") {
|
|
27955
|
+
try {
|
|
27956
|
+
const value = options.readKeychain ? await options.readKeychain() : (await execFileAsync("security", ["find-generic-password", "-s", "Claude Code-credentials", "-w"], {
|
|
27957
|
+
timeout: 3000,
|
|
27958
|
+
maxBuffer: 256 * 1024
|
|
27959
|
+
})).stdout;
|
|
27960
|
+
const parsed = parseCredentials(value.trim());
|
|
27961
|
+
if (parsed)
|
|
27962
|
+
return parsed;
|
|
27963
|
+
} catch {}
|
|
27964
|
+
}
|
|
27965
|
+
const env = options.env ?? process.env;
|
|
27966
|
+
const root = env.CLAUDE_CONFIG_DIR || join11(options.home ?? homedir3(), ".claude");
|
|
27967
|
+
try {
|
|
27968
|
+
const value = options.readCredentialsFile ? await options.readCredentialsFile(join11(root, ".credentials.json")) : await readFile(join11(root, ".credentials.json"), "utf8");
|
|
27969
|
+
return parseCredentials(value);
|
|
27970
|
+
} catch {
|
|
27971
|
+
return null;
|
|
27972
|
+
}
|
|
27973
|
+
}
|
|
27974
|
+
function mappedPlanName2(value) {
|
|
27975
|
+
switch (value) {
|
|
27976
|
+
case "free":
|
|
27977
|
+
return "Free";
|
|
27978
|
+
case "pro":
|
|
27979
|
+
return "Pro";
|
|
27980
|
+
case "max":
|
|
27981
|
+
return "Max";
|
|
27982
|
+
case "team":
|
|
27983
|
+
return "Team";
|
|
27984
|
+
case "enterprise":
|
|
27985
|
+
return "Enterprise";
|
|
27986
|
+
default:
|
|
27987
|
+
return;
|
|
27988
|
+
}
|
|
27989
|
+
}
|
|
27990
|
+
function resetIso2(value) {
|
|
27991
|
+
if (typeof value !== "string")
|
|
27992
|
+
return;
|
|
27993
|
+
const date5 = new Date(value);
|
|
27994
|
+
return Number.isNaN(date5.getTime()) ? undefined : date5.toISOString();
|
|
27995
|
+
}
|
|
27996
|
+
function claudeLimit(key, value) {
|
|
27997
|
+
if (!value || typeof value !== "object")
|
|
27998
|
+
return null;
|
|
27999
|
+
const row = value;
|
|
28000
|
+
if (typeof row.utilization !== "number" || !Number.isFinite(row.utilization) || row.utilization < 0 || row.utilization > 100)
|
|
28001
|
+
return null;
|
|
28002
|
+
const model = key.includes("sonnet") ? { kind: "reported", id: "claude-sonnet" } : key.includes("opus") ? { kind: "reported", id: "claude-opus" } : { kind: "not_applicable" };
|
|
28003
|
+
const window2 = key === "five_hour" ? { kind: "rolling", durationSeconds: 18000, displayName: "5 hour usage limit" } : { kind: "rolling", durationSeconds: 604800, displayName: "7 day usage limit" };
|
|
28004
|
+
const resetsAt = resetIso2(row.resets_at ?? row.resetsAt);
|
|
28005
|
+
return {
|
|
28006
|
+
bucket: {
|
|
28007
|
+
limitId: key,
|
|
28008
|
+
product: { kind: "reported", id: "claude", displayName: "Claude" },
|
|
28009
|
+
model,
|
|
28010
|
+
window: window2
|
|
28011
|
+
},
|
|
28012
|
+
usedPercent: row.utilization,
|
|
28013
|
+
...resetsAt ? { resetsAt } : {}
|
|
28014
|
+
};
|
|
28015
|
+
}
|
|
28016
|
+
async function readClaudeQuota(options) {
|
|
28017
|
+
const env = options.env ?? process.env;
|
|
28018
|
+
if (env.ANTHROPIC_API_KEY || env.ANTHROPIC_BASE_URL)
|
|
28019
|
+
return null;
|
|
28020
|
+
const credentials = await claudeCredentials(options);
|
|
28021
|
+
const token = credentials?.claudeAiOauth?.accessToken;
|
|
28022
|
+
if (typeof token !== "string" || token.length === 0)
|
|
28023
|
+
return null;
|
|
28024
|
+
if (claudeAccessToken !== token) {
|
|
28025
|
+
claudeAccessToken = token;
|
|
28026
|
+
claudeSourceEpoch = randomBytes5(16).toString("base64url");
|
|
28027
|
+
}
|
|
28028
|
+
let response;
|
|
28029
|
+
try {
|
|
28030
|
+
response = await (options.fetchUsage ?? fetch)("https://api.anthropic.com/api/oauth/usage", {
|
|
28031
|
+
headers: {
|
|
28032
|
+
authorization: `Bearer ${token}`,
|
|
28033
|
+
"anthropic-beta": "oauth-2025-04-20"
|
|
28034
|
+
},
|
|
28035
|
+
signal: AbortSignal.timeout(5000)
|
|
28036
|
+
});
|
|
28037
|
+
} catch {
|
|
28038
|
+
return { status: "error", sourceEpoch: claudeSourceEpoch, code: "network", retryable: true };
|
|
28039
|
+
}
|
|
28040
|
+
if (response.status === 401 || response.status === 403) {
|
|
28041
|
+
return { status: "error", sourceEpoch: claudeSourceEpoch, code: "unauthorized", retryable: false };
|
|
28042
|
+
}
|
|
28043
|
+
if (!response.ok) {
|
|
28044
|
+
return { status: "error", sourceEpoch: claudeSourceEpoch, code: "provider_error", retryable: response.status === 429 || response.status >= 500 };
|
|
28045
|
+
}
|
|
28046
|
+
let body;
|
|
28047
|
+
try {
|
|
28048
|
+
body = await response.json();
|
|
28049
|
+
} catch {
|
|
28050
|
+
return { status: "error", sourceEpoch: claudeSourceEpoch, code: "invalid_response", retryable: true };
|
|
28051
|
+
}
|
|
28052
|
+
if (!body || typeof body !== "object") {
|
|
28053
|
+
return { status: "error", sourceEpoch: claudeSourceEpoch, code: "invalid_response", retryable: true };
|
|
28054
|
+
}
|
|
28055
|
+
const record4 = body;
|
|
28056
|
+
const limits = ["five_hour", "seven_day", "seven_day_sonnet", "seven_day_opus"].map((key) => claudeLimit(key, record4[key])).filter((limit) => limit !== null);
|
|
28057
|
+
if (limits.length === 0) {
|
|
28058
|
+
return { status: "error", sourceEpoch: claudeSourceEpoch, code: "invalid_response", retryable: true };
|
|
28059
|
+
}
|
|
28060
|
+
const planName = mappedPlanName2(credentials?.claudeAiOauth?.subscriptionType);
|
|
28061
|
+
return {
|
|
28062
|
+
status: "available",
|
|
28063
|
+
sourceEpoch: claudeSourceEpoch,
|
|
28064
|
+
...planName ? { planName } : {},
|
|
28065
|
+
freshForSeconds: 300,
|
|
28066
|
+
limits
|
|
28067
|
+
};
|
|
28068
|
+
}
|
|
28069
|
+
async function readBuiltinProviderQuota(backend, options = {}) {
|
|
28070
|
+
return backend === "claude" ? readClaudeQuota(options) : null;
|
|
28071
|
+
}
|
|
27206
28072
|
// src/runtime/errorDiagnostics.ts
|
|
27207
28073
|
function scrubRuntimeErrorDiagnosticText(value) {
|
|
27208
28074
|
return scrubDriverErrorMessage(value);
|
|
@@ -27798,9 +28664,13 @@ class AgentProcessManager {
|
|
|
27798
28664
|
state;
|
|
27799
28665
|
sessions = new Map;
|
|
27800
28666
|
runtimeConfigs = new Map;
|
|
28667
|
+
appliedRuntimeConfigs = new Map;
|
|
28668
|
+
pendingRuntimeConfigUpdates = new Map;
|
|
28669
|
+
runtimeConfigApplyRunning = new Set;
|
|
27801
28670
|
resumeSessions = new Map;
|
|
27802
28671
|
launchIds = new Map;
|
|
27803
28672
|
liveSessions = new Map;
|
|
28673
|
+
liveBackendIds = new Map;
|
|
27804
28674
|
activeSpawnState = new Map;
|
|
27805
28675
|
publishedAgentActivity = new Map;
|
|
27806
28676
|
traceProcessNonce = randomUUID5();
|
|
@@ -27829,19 +28699,156 @@ class AgentProcessManager {
|
|
|
27829
28699
|
this.state = createInitialManagerState(this.opts.staleThresholdMs, this.opts.idleTimeoutMs, this.opts.resetStuckThresholdMs, this.opts.stoppingStuckThresholdMs, this.opts.idleResetTimeoutMs);
|
|
27830
28700
|
}
|
|
27831
28701
|
register(agentId, launch) {
|
|
27832
|
-
|
|
27833
|
-
this.runtimeConfigs.set(agentId, launch.runtimeConfig);
|
|
28702
|
+
const runtimeConfigAcceptance = launch?.runtimeConfig ? this.acceptRuntimeConfig(agentId, launch.runtimeConfig) : undefined;
|
|
27834
28703
|
if (launch?.sessionId)
|
|
27835
28704
|
this.resumeSessions.set(agentId, launch.sessionId);
|
|
27836
28705
|
if (launch?.launchId)
|
|
27837
28706
|
this.launchIds.set(agentId, launch.launchId);
|
|
27838
28707
|
this.dispatch({ type: "register", agentId });
|
|
28708
|
+
const registered = this.state.agents[agentId];
|
|
28709
|
+
if (launch?.runtimeConfig && launch.applyRuntimeConfig !== false && (runtimeConfigAcceptance === "accepted" || this.pendingRuntimeConfigUpdates.has(agentId)) && this.sessions.has(agentId) && registered && !isActivelyWorking(registered)) {
|
|
28710
|
+
this.convergeRuntimeConfig(agentId);
|
|
28711
|
+
}
|
|
28712
|
+
}
|
|
28713
|
+
async updateRuntimeConfig(agentId, config2) {
|
|
28714
|
+
const accepted = this.acceptRuntimeConfig(agentId, config2);
|
|
28715
|
+
if (accepted === "stale" || accepted === "idempotent")
|
|
28716
|
+
return accepted;
|
|
28717
|
+
const session2 = this.sessions.get(agentId);
|
|
28718
|
+
if (!session2) {
|
|
28719
|
+
this.pendingRuntimeConfigUpdates.delete(agentId);
|
|
28720
|
+
return "saved_for_start";
|
|
28721
|
+
}
|
|
28722
|
+
const agent2 = this.state.agents[agentId];
|
|
28723
|
+
if (agent2 && (agent2.turnActive || isActivelyWorking(agent2)))
|
|
28724
|
+
return "deferred";
|
|
28725
|
+
return this.convergeRuntimeConfig(agentId);
|
|
28726
|
+
}
|
|
28727
|
+
acceptRuntimeConfig(agentId, config2) {
|
|
28728
|
+
const desired = this.runtimeConfigs.get(agentId);
|
|
28729
|
+
const revision = config2.runtimeConfigRevision ?? 0;
|
|
28730
|
+
const desiredRevision = desired?.runtimeConfigRevision ?? 0;
|
|
28731
|
+
if (desired && revision < desiredRevision)
|
|
28732
|
+
return "stale";
|
|
28733
|
+
if (desired && revision === desiredRevision) {
|
|
28734
|
+
if (this.runtimeConfigTuple(desired) !== this.runtimeConfigTuple(config2)) {
|
|
28735
|
+
throw new Error(`Conflicting runtime config for ${agentId} at revision ${revision}`);
|
|
28736
|
+
}
|
|
28737
|
+
this.runtimeConfigs.set(agentId, config2);
|
|
28738
|
+
return "idempotent";
|
|
28739
|
+
}
|
|
28740
|
+
this.runtimeConfigs.set(agentId, config2);
|
|
28741
|
+
this.pendingRuntimeConfigUpdates.set(agentId, config2);
|
|
28742
|
+
return "accepted";
|
|
28743
|
+
}
|
|
28744
|
+
runtimeConfigTuple(config2) {
|
|
28745
|
+
return JSON.stringify({
|
|
28746
|
+
version: config2.version,
|
|
28747
|
+
runtime: config2.runtime,
|
|
28748
|
+
model: config2.model,
|
|
28749
|
+
mode: config2.mode,
|
|
28750
|
+
reasoningEffort: config2.reasoningEffort ?? null,
|
|
28751
|
+
provider: config2.provider ?? null,
|
|
28752
|
+
command: config2.command ?? null,
|
|
28753
|
+
disallowedTools: config2.disallowedTools ?? null,
|
|
28754
|
+
envVars: config2.envVars ?? null
|
|
28755
|
+
});
|
|
28756
|
+
}
|
|
28757
|
+
runtimeLaunchTuple(config2) {
|
|
28758
|
+
return JSON.stringify({
|
|
28759
|
+
version: config2.version,
|
|
28760
|
+
runtime: config2.runtime,
|
|
28761
|
+
model: config2.model,
|
|
28762
|
+
mode: config2.mode,
|
|
28763
|
+
provider: config2.provider ?? null,
|
|
28764
|
+
command: config2.command ?? null,
|
|
28765
|
+
disallowedTools: config2.disallowedTools ?? null,
|
|
28766
|
+
envVars: config2.envVars ?? null
|
|
28767
|
+
});
|
|
28768
|
+
}
|
|
28769
|
+
async convergeRuntimeConfig(agentId, restartOnFailure = true) {
|
|
28770
|
+
if (this.runtimeConfigApplyRunning.has(agentId))
|
|
28771
|
+
return "deferred";
|
|
28772
|
+
const session2 = this.sessions.get(agentId);
|
|
28773
|
+
if (!session2)
|
|
28774
|
+
return "saved_for_start";
|
|
28775
|
+
this.runtimeConfigApplyRunning.add(agentId);
|
|
28776
|
+
try {
|
|
28777
|
+
while (this.sessions.get(agentId) === session2) {
|
|
28778
|
+
const desired = this.pendingRuntimeConfigUpdates.get(agentId) ?? this.runtimeConfigs.get(agentId);
|
|
28779
|
+
if (!desired)
|
|
28780
|
+
return "idempotent";
|
|
28781
|
+
const desiredRevision = desired.runtimeConfigRevision ?? 0;
|
|
28782
|
+
const applied = this.appliedRuntimeConfigs.get(agentId);
|
|
28783
|
+
const appliedRevision = applied?.runtimeConfigRevision ?? -1;
|
|
28784
|
+
if (applied && desiredRevision <= appliedRevision) {
|
|
28785
|
+
this.pendingRuntimeConfigUpdates.delete(agentId);
|
|
28786
|
+
return desiredRevision === appliedRevision ? "idempotent" : "stale";
|
|
28787
|
+
}
|
|
28788
|
+
const canApplyNatively = applied && this.runtimeLaunchTuple(applied) === this.runtimeLaunchTuple(desired) && typeof session2.updateSettings === "function";
|
|
28789
|
+
let result = { status: "unsupported" };
|
|
28790
|
+
if (canApplyNatively) {
|
|
28791
|
+
try {
|
|
28792
|
+
result = await session2.updateSettings({
|
|
28793
|
+
reasoningEffort: desired.reasoningEffort ?? null
|
|
28794
|
+
});
|
|
28795
|
+
} catch (error51) {
|
|
28796
|
+
this.log.warn("runtime config live apply threw; restarting at safe boundary", {
|
|
28797
|
+
agentId,
|
|
28798
|
+
revision: desiredRevision,
|
|
28799
|
+
error: String(error51)
|
|
28800
|
+
});
|
|
28801
|
+
if (restartOnFailure)
|
|
28802
|
+
await this.restartForRuntimeConfig(agentId, session2);
|
|
28803
|
+
return "saved_for_start";
|
|
28804
|
+
}
|
|
28805
|
+
}
|
|
28806
|
+
if (result.status !== "applied") {
|
|
28807
|
+
this.log.warn("runtime config live apply unavailable; restarting at safe boundary", {
|
|
28808
|
+
agentId,
|
|
28809
|
+
revision: desiredRevision,
|
|
28810
|
+
status: result.status,
|
|
28811
|
+
code: result.error?.code
|
|
28812
|
+
});
|
|
28813
|
+
if (restartOnFailure)
|
|
28814
|
+
await this.restartForRuntimeConfig(agentId, session2);
|
|
28815
|
+
return "saved_for_start";
|
|
28816
|
+
}
|
|
28817
|
+
this.appliedRuntimeConfigs.set(agentId, desired);
|
|
28818
|
+
if ((this.pendingRuntimeConfigUpdates.get(agentId)?.runtimeConfigRevision ?? -1) === desiredRevision) {
|
|
28819
|
+
this.pendingRuntimeConfigUpdates.delete(agentId);
|
|
28820
|
+
}
|
|
28821
|
+
const latestRevision = this.runtimeConfigs.get(agentId)?.runtimeConfigRevision ?? 0;
|
|
28822
|
+
if (latestRevision <= desiredRevision) {
|
|
28823
|
+
this.dispatch({ type: "runtime_config_applied", agentId });
|
|
28824
|
+
return "applied";
|
|
28825
|
+
}
|
|
28826
|
+
}
|
|
28827
|
+
return "saved_for_start";
|
|
28828
|
+
} finally {
|
|
28829
|
+
this.runtimeConfigApplyRunning.delete(agentId);
|
|
28830
|
+
}
|
|
28831
|
+
}
|
|
28832
|
+
async restartForRuntimeConfig(agentId, session2) {
|
|
28833
|
+
if (this.sessions.get(agentId) !== session2)
|
|
28834
|
+
return;
|
|
28835
|
+
this.opts.timeline?.fenceSession(agentId);
|
|
28836
|
+
this.markResetting(agentId);
|
|
28837
|
+
await this.stop(agentId);
|
|
27839
28838
|
}
|
|
27840
28839
|
deliver(agentId, message2) {
|
|
27841
28840
|
const normalized = message2.id ? message2 : {
|
|
27842
28841
|
...message2,
|
|
27843
28842
|
id: message2.seq !== undefined ? `${agentId}:source:${message2.seq}` : `${agentId}:synthetic:${this.nextDeliveryOrdinal++}`
|
|
27844
28843
|
};
|
|
28844
|
+
if (this.sessions.has(agentId) && this.pendingRuntimeConfigUpdates.has(agentId)) {
|
|
28845
|
+
this.dispatch({
|
|
28846
|
+
type: "runtime_config_queued",
|
|
28847
|
+
agentId,
|
|
28848
|
+
message: normalized
|
|
28849
|
+
});
|
|
28850
|
+
return this.state.agents[agentId] !== undefined;
|
|
28851
|
+
}
|
|
27845
28852
|
const effects = this.dispatch({ type: "wake", agentId, message: normalized, nowMs: this.now() });
|
|
27846
28853
|
return effects.length > 0;
|
|
27847
28854
|
}
|
|
@@ -27885,7 +28892,11 @@ class AgentProcessManager {
|
|
|
27885
28892
|
this.emitErrorAudit(agentId, "reset", "resume_control_update_failed", "Reset aborted because resume control could not be persisted");
|
|
27886
28893
|
throw new Error("Reset aborted because resume control could not be persisted");
|
|
27887
28894
|
}
|
|
27888
|
-
this.register(agentId, {
|
|
28895
|
+
this.register(agentId, {
|
|
28896
|
+
runtimeConfig: opts.runtimeConfig,
|
|
28897
|
+
launchId: opts.launchId,
|
|
28898
|
+
applyRuntimeConfig: false
|
|
28899
|
+
});
|
|
27889
28900
|
if (!opts.forgetSession)
|
|
27890
28901
|
this.opts.timeline?.fenceSession(agentId);
|
|
27891
28902
|
this.abortCurrentTurn(agentId, opts.abortCause);
|
|
@@ -27986,6 +28997,9 @@ class AgentProcessManager {
|
|
|
27986
28997
|
const agent2 = this.state.agents[agentId];
|
|
27987
28998
|
return agent2 ? this.deriveActivity(agent2) : null;
|
|
27988
28999
|
}
|
|
29000
|
+
agentBackendId(agentId) {
|
|
29001
|
+
return this.liveBackendIds.get(agentId) ?? null;
|
|
29002
|
+
}
|
|
27989
29003
|
statusProjection(nowMs) {
|
|
27990
29004
|
return Object.values(this.state.agents).map((a) => ({
|
|
27991
29005
|
agentId: a.agentId,
|
|
@@ -28511,6 +29525,7 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
28511
29525
|
throw new Error(`AgentProcessManager: spawn for ${agentId} has no command`);
|
|
28512
29526
|
const prompt = this.withFooter(first.text);
|
|
28513
29527
|
const driver = this.opts.driverFor(agentId, this.runtimeConfigs.get(agentId));
|
|
29528
|
+
this.liveBackendIds.set(agentId, driver.id);
|
|
28514
29529
|
const base = this.opts.baseContextFor(agentId);
|
|
28515
29530
|
const configuredRuntime = this.runtimeConfigs.get(agentId) ?? base.config?.runtimeConfig;
|
|
28516
29531
|
this.log.info("spawning agent", {
|
|
@@ -28631,7 +29646,10 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
28631
29646
|
if (state.session && this.sessions.get(agentId) === state.session)
|
|
28632
29647
|
this.sessions.delete(agentId);
|
|
28633
29648
|
this.liveSessions.delete(agentId);
|
|
29649
|
+
if (this.activeSpawnState.get(agentId) === state)
|
|
29650
|
+
this.liveBackendIds.delete(agentId);
|
|
28634
29651
|
if (this.activeSpawnState.get(agentId) === state) {
|
|
29652
|
+
this.appliedRuntimeConfigs.delete(agentId);
|
|
28635
29653
|
this.activeSpawnState.delete(agentId);
|
|
28636
29654
|
this.nonCleanEndMarker.delete(agentId);
|
|
28637
29655
|
}
|
|
@@ -28679,6 +29697,10 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
28679
29697
|
state.session = session2;
|
|
28680
29698
|
state.sessionInstanceId = session2.sessionInstanceId;
|
|
28681
29699
|
this.sessions.set(agentId, session2);
|
|
29700
|
+
this.appliedRuntimeConfigs.set(agentId, runtimeConfig);
|
|
29701
|
+
if ((this.pendingRuntimeConfigUpdates.get(agentId)?.runtimeConfigRevision ?? -1) <= (runtimeConfig.runtimeConfigRevision ?? 0)) {
|
|
29702
|
+
this.pendingRuntimeConfigUpdates.delete(agentId);
|
|
29703
|
+
}
|
|
28682
29704
|
this.dispatch({
|
|
28683
29705
|
type: "attach_session",
|
|
28684
29706
|
agentId,
|
|
@@ -28912,6 +29934,12 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
28912
29934
|
runtime: runtimeId
|
|
28913
29935
|
});
|
|
28914
29936
|
}
|
|
29937
|
+
if (event.type === "token_usage") {
|
|
29938
|
+
this.opts.onTokenUsage?.({ agentId, backendId: runtimeId, usage: event.usage });
|
|
29939
|
+
}
|
|
29940
|
+
if (event.type === "rate_limits") {
|
|
29941
|
+
this.opts.onProviderQuota?.({ agentId, backendId: runtimeId, quota: event.quota });
|
|
29942
|
+
}
|
|
28915
29943
|
if (event.type === "turn_started") {
|
|
28916
29944
|
const timelineTurnOwner = {
|
|
28917
29945
|
sessionInstanceId: event.sessionInstanceId,
|
|
@@ -29026,7 +30054,7 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
29026
30054
|
this.logSessionEnded(agentId, "turn_end");
|
|
29027
30055
|
const marker = this.nonCleanEndMarker.get(agentId);
|
|
29028
30056
|
this.nonCleanEndMarker.delete(agentId);
|
|
29029
|
-
|
|
30057
|
+
const completionEvent = marker !== undefined ? {
|
|
29030
30058
|
type: "turn_completed",
|
|
29031
30059
|
agentId,
|
|
29032
30060
|
sessionInstanceId: event.sessionInstanceId,
|
|
@@ -29041,7 +30069,26 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
29041
30069
|
sessionInstanceId: event.sessionInstanceId,
|
|
29042
30070
|
nowMs: this.now(),
|
|
29043
30071
|
turnId: event.turnId
|
|
29044
|
-
}
|
|
30072
|
+
};
|
|
30073
|
+
if (this.pendingRuntimeConfigUpdates.has(agentId) && this.sessions.get(agentId) === owner.session) {
|
|
30074
|
+
this.convergeRuntimeConfig(agentId, false).then((result) => {
|
|
30075
|
+
if (result === "saved_for_start" && owner.session)
|
|
30076
|
+
this.markResetting(agentId);
|
|
30077
|
+
this.dispatch(completionEvent, owner);
|
|
30078
|
+
if (result === "saved_for_start" && owner.session) {
|
|
30079
|
+
this.restartForRuntimeConfig(agentId, owner.session);
|
|
30080
|
+
}
|
|
30081
|
+
}).catch((error51) => {
|
|
30082
|
+
this.log.error("runtime config convergence failed", { agentId, error: String(error51) });
|
|
30083
|
+
if (owner.session)
|
|
30084
|
+
this.markResetting(agentId);
|
|
30085
|
+
this.dispatch(completionEvent, owner);
|
|
30086
|
+
if (owner.session)
|
|
30087
|
+
this.restartForRuntimeConfig(agentId, owner.session);
|
|
30088
|
+
});
|
|
30089
|
+
return;
|
|
30090
|
+
}
|
|
30091
|
+
this.dispatch(completionEvent, owner);
|
|
29045
30092
|
}
|
|
29046
30093
|
}
|
|
29047
30094
|
}
|
|
@@ -29116,7 +30163,8 @@ class AgentRouter {
|
|
|
29116
30163
|
version: r.version,
|
|
29117
30164
|
status: r.status ?? "healthy",
|
|
29118
30165
|
lastError: r.lastError,
|
|
29119
|
-
lastErrorAt: r.lastErrorAt
|
|
30166
|
+
lastErrorAt: r.lastErrorAt,
|
|
30167
|
+
reasoning: r.reasoning
|
|
29120
30168
|
});
|
|
29121
30169
|
}
|
|
29122
30170
|
}
|
|
@@ -29125,7 +30173,7 @@ class AgentRouter {
|
|
|
29125
30173
|
this.opts.channel.onResync?.(() => ({
|
|
29126
30174
|
ready: this.buildReady(),
|
|
29127
30175
|
sessions: this.opts.manager.liveSessionReports(),
|
|
29128
|
-
activities: this.opts.manager.liveAgentActivities()
|
|
30176
|
+
activities: this.opts.resyncActivities ? this.opts.resyncActivities() : this.opts.manager.liveAgentActivities()
|
|
29129
30177
|
}));
|
|
29130
30178
|
await this.opts.channel.reportReady(this.buildReady());
|
|
29131
30179
|
}
|
|
@@ -29138,7 +30186,8 @@ class AgentRouter {
|
|
|
29138
30186
|
platform: this.opts.platform,
|
|
29139
30187
|
arch: this.opts.arch,
|
|
29140
30188
|
osRelease: this.opts.osRelease,
|
|
29141
|
-
daemonVersion: this.opts.daemonVersion
|
|
30189
|
+
daemonVersion: this.opts.daemonVersion,
|
|
30190
|
+
...this.opts.providerQuotas ? { providerQuotas: this.opts.providerQuotas() } : {}
|
|
29142
30191
|
};
|
|
29143
30192
|
}
|
|
29144
30193
|
healthyRuntimeIds() {
|
|
@@ -29360,6 +30409,27 @@ class AgentRouter {
|
|
|
29360
30409
|
rewakePrompt: MODEL_SWITCH_REWAKE_PROMPT
|
|
29361
30410
|
}));
|
|
29362
30411
|
break;
|
|
30412
|
+
case "agent:runtime_config_update": {
|
|
30413
|
+
this.log.info("agent:runtime_config_update received", {
|
|
30414
|
+
agentId: cmd.agentId,
|
|
30415
|
+
revision: cmd.config.runtimeConfigRevision ?? 0
|
|
30416
|
+
});
|
|
30417
|
+
try {
|
|
30418
|
+
const result = await this.opts.manager.updateRuntimeConfig(cmd.agentId, cmd.config);
|
|
30419
|
+
this.log.info("agent:runtime_config_update accepted", {
|
|
30420
|
+
agentId: cmd.agentId,
|
|
30421
|
+
revision: cmd.config.runtimeConfigRevision ?? 0,
|
|
30422
|
+
result
|
|
30423
|
+
});
|
|
30424
|
+
} catch (err) {
|
|
30425
|
+
this.log.warn("agent:runtime_config_update rejected", {
|
|
30426
|
+
agentId: cmd.agentId,
|
|
30427
|
+
revision: cmd.config.runtimeConfigRevision ?? 0,
|
|
30428
|
+
error: err instanceof Error ? err.message : String(err)
|
|
30429
|
+
});
|
|
30430
|
+
}
|
|
30431
|
+
break;
|
|
30432
|
+
}
|
|
29363
30433
|
case "agent:stop":
|
|
29364
30434
|
this.log.info("agent:stop received", { agentId: cmd.agentId });
|
|
29365
30435
|
try {
|
|
@@ -29417,8 +30487,8 @@ function createTypingScopeTracker() {
|
|
|
29417
30487
|
}
|
|
29418
30488
|
// src/timeline/timeline.ts
|
|
29419
30489
|
import * as fs9 from "node:fs";
|
|
29420
|
-
import { createHash as createHash2, randomBytes as
|
|
29421
|
-
import { basename as basename3, dirname as dirname5, join as
|
|
30490
|
+
import { createHash as createHash2, randomBytes as randomBytes6 } from "node:crypto";
|
|
30491
|
+
import { basename as basename3, dirname as dirname5, join as join12 } from "node:path";
|
|
29422
30492
|
|
|
29423
30493
|
// src/timeline/filelock.ts
|
|
29424
30494
|
import * as fs8 from "fs";
|
|
@@ -29761,7 +30831,7 @@ function scanTimelineFile(filePath) {
|
|
|
29761
30831
|
}
|
|
29762
30832
|
}
|
|
29763
30833
|
function atomicReplaceTimeline(filePath, lines) {
|
|
29764
|
-
const tempPath =
|
|
30834
|
+
const tempPath = join12(dirname5(filePath), `.${basename3(filePath)}.${process.pid}.${randomBytes6(12).toString("hex")}.tmp`);
|
|
29765
30835
|
let fd = null;
|
|
29766
30836
|
try {
|
|
29767
30837
|
fd = fs9.openSync(tempPath, "wx", 384);
|
|
@@ -29845,14 +30915,14 @@ function readRecentEntries(timelineDir, opts = {}) {
|
|
|
29845
30915
|
const filenames = recentFilenames(maxDays, now).reverse();
|
|
29846
30916
|
const entries = [];
|
|
29847
30917
|
for (const filename of filenames) {
|
|
29848
|
-
entries.push(...readJsonl(
|
|
30918
|
+
entries.push(...readJsonl(join12(timelineDir, filename)));
|
|
29849
30919
|
}
|
|
29850
30920
|
return entries;
|
|
29851
30921
|
}
|
|
29852
30922
|
function readResumeControlState(timelineDir) {
|
|
29853
30923
|
if (timelineDirectoryState(timelineDir) !== "safe")
|
|
29854
30924
|
return { kind: "missing" };
|
|
29855
|
-
const filePath =
|
|
30925
|
+
const filePath = join12(timelineDir, RESUME_CONTROL_FILENAME);
|
|
29856
30926
|
let source;
|
|
29857
30927
|
try {
|
|
29858
30928
|
source = fs9.lstatSync(filePath);
|
|
@@ -29928,8 +30998,8 @@ function updateResumeControlState(timelineDir, update) {
|
|
|
29928
30998
|
`;
|
|
29929
30999
|
if (Buffer.byteLength(body, "utf8") > RESUME_CONTROL_MAX_BYTES)
|
|
29930
31000
|
return false;
|
|
29931
|
-
const filePath =
|
|
29932
|
-
const tempPath =
|
|
31001
|
+
const filePath = join12(timelineDir, RESUME_CONTROL_FILENAME);
|
|
31002
|
+
const tempPath = join12(timelineDir, `.${RESUME_CONTROL_FILENAME}.${process.pid}.${randomBytes6(12).toString("hex")}.tmp`);
|
|
29933
31003
|
let fd = null;
|
|
29934
31004
|
try {
|
|
29935
31005
|
fd = fs9.openSync(tempPath, "wx", 384);
|
|
@@ -29959,7 +31029,7 @@ function appendTrackedEntry(timelineDir, entry, now = new Date) {
|
|
|
29959
31029
|
if (timelineDirectoryState(timelineDir) !== "safe")
|
|
29960
31030
|
return { status: "rejected", reason: "unsafe" };
|
|
29961
31031
|
const filename = filenameForDate(now);
|
|
29962
|
-
const filePath =
|
|
31032
|
+
const filePath = join12(timelineDir, filename);
|
|
29963
31033
|
const lockPath = lockPathFor(timelineDir, filename);
|
|
29964
31034
|
try {
|
|
29965
31035
|
if (!acquireLock(lockPath))
|
|
@@ -29987,7 +31057,7 @@ function updateTrackedEntry(timelineDir, handle, update) {
|
|
|
29987
31057
|
if (!DATE_FILENAME_PATTERN.test(handle.filename) || basename3(handle.filename) !== handle.filename) {
|
|
29988
31058
|
return { status: "rejected", reason: "unsafe" };
|
|
29989
31059
|
}
|
|
29990
|
-
const filePath =
|
|
31060
|
+
const filePath = join12(timelineDir, handle.filename);
|
|
29991
31061
|
const lockPath = lockPathFor(timelineDir, handle.filename);
|
|
29992
31062
|
try {
|
|
29993
31063
|
if (!acquireLock(lockPath))
|
|
@@ -30046,10 +31116,10 @@ async function sweepTimelineHistory(workingDirectoryBase, opts = {}) {
|
|
|
30046
31116
|
return;
|
|
30047
31117
|
}
|
|
30048
31118
|
for (const agentName of agentNames) {
|
|
30049
|
-
const agentDir =
|
|
31119
|
+
const agentDir = join12(workingDirectoryBase, agentName);
|
|
30050
31120
|
if (!isRealDirectory(agentDir))
|
|
30051
31121
|
continue;
|
|
30052
|
-
const timelineDir =
|
|
31122
|
+
const timelineDir = join12(agentDir, ".context_timeline");
|
|
30053
31123
|
if (!isRealDirectory(timelineDir))
|
|
30054
31124
|
continue;
|
|
30055
31125
|
let filenames;
|
|
@@ -30059,7 +31129,7 @@ async function sweepTimelineHistory(workingDirectoryBase, opts = {}) {
|
|
|
30059
31129
|
continue;
|
|
30060
31130
|
}
|
|
30061
31131
|
for (const filename of filenames) {
|
|
30062
|
-
const filePath =
|
|
31132
|
+
const filePath = join12(timelineDir, filename);
|
|
30063
31133
|
let source;
|
|
30064
31134
|
try {
|
|
30065
31135
|
source = fs9.lstatSync(filePath);
|
|
@@ -30803,8 +31873,8 @@ class MessageReminderScheduler {
|
|
|
30803
31873
|
|
|
30804
31874
|
// src/manager/agentDriverHost.ts
|
|
30805
31875
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
30806
|
-
import { homedir as
|
|
30807
|
-
import { join as
|
|
31876
|
+
import { homedir as homedir4 } from "node:os";
|
|
31877
|
+
import { join as join13 } from "node:path";
|
|
30808
31878
|
|
|
30809
31879
|
// src/drivers/gitIdentityEnv.ts
|
|
30810
31880
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
@@ -30929,7 +31999,7 @@ function createDaemonAgentDriverHost(ctx, onRawLine) {
|
|
|
30929
31999
|
hostUser: readHostGitIdentity() ?? undefined
|
|
30930
32000
|
}),
|
|
30931
32001
|
platformProtected: {
|
|
30932
|
-
ALOOK_HOME: process.env.ALOOK_HOME ??
|
|
32002
|
+
ALOOK_HOME: process.env.ALOOK_HOME ?? join13(homedir4(), ".alook"),
|
|
30933
32003
|
ALOOK_ID: ctx.agentId,
|
|
30934
32004
|
ALOOK_CLI: ctx.agentCliPath,
|
|
30935
32005
|
ALOOK_SERVER_URL: ctx.config.serverUrl,
|
|
@@ -31034,6 +32104,182 @@ class DaemonSelfSleepScheduler {
|
|
|
31034
32104
|
}
|
|
31035
32105
|
}
|
|
31036
32106
|
|
|
32107
|
+
// src/telemetry/dailyTokenUsage.ts
|
|
32108
|
+
import { chmod, mkdir, open, readFile as readFile2, rename, rm } from "node:fs/promises";
|
|
32109
|
+
import { dirname as dirname6, join as join14 } from "node:path";
|
|
32110
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
32111
|
+
function dayKey(at) {
|
|
32112
|
+
return at.toISOString().slice(0, 10);
|
|
32113
|
+
}
|
|
32114
|
+
function retainedDays(at) {
|
|
32115
|
+
const days = new Set;
|
|
32116
|
+
for (let offset = 0;offset < 7; offset += 1) {
|
|
32117
|
+
days.add(dayKey(new Date(at.getTime() - offset * 86400000)));
|
|
32118
|
+
}
|
|
32119
|
+
return days;
|
|
32120
|
+
}
|
|
32121
|
+
function isMetric(value) {
|
|
32122
|
+
return value === null || typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
32123
|
+
}
|
|
32124
|
+
function isSnapshot(value) {
|
|
32125
|
+
if (!value || typeof value !== "object")
|
|
32126
|
+
return false;
|
|
32127
|
+
const snapshot = value;
|
|
32128
|
+
const metrics = snapshot.metrics;
|
|
32129
|
+
return typeof snapshot.botId === "string" && snapshot.botId.length > 0 && typeof snapshot.day === "string" && /^\d{4}-\d{2}-\d{2}$/.test(snapshot.day) && !!metrics && isMetric(metrics.input) && isMetric(metrics.output) && isMetric(metrics.cache);
|
|
32130
|
+
}
|
|
32131
|
+
function mergeMetric(existing, delta, hasExistingSnapshot) {
|
|
32132
|
+
if (delta === null)
|
|
32133
|
+
return null;
|
|
32134
|
+
if (!Number.isSafeInteger(delta) || delta < 0) {
|
|
32135
|
+
throw new RangeError("token usage delta must be a non-negative safe integer");
|
|
32136
|
+
}
|
|
32137
|
+
if (!hasExistingSnapshot)
|
|
32138
|
+
return delta;
|
|
32139
|
+
if (existing === null)
|
|
32140
|
+
return null;
|
|
32141
|
+
const sum = existing + delta;
|
|
32142
|
+
if (!Number.isSafeInteger(sum))
|
|
32143
|
+
throw new RangeError("daily token usage exceeds safe integer range");
|
|
32144
|
+
return sum;
|
|
32145
|
+
}
|
|
32146
|
+
function emptySnapshot(botId, day) {
|
|
32147
|
+
return {
|
|
32148
|
+
botId,
|
|
32149
|
+
day,
|
|
32150
|
+
metrics: {
|
|
32151
|
+
input: null,
|
|
32152
|
+
output: null,
|
|
32153
|
+
cache: null
|
|
32154
|
+
}
|
|
32155
|
+
};
|
|
32156
|
+
}
|
|
32157
|
+
|
|
32158
|
+
class DailyTokenUsageStore {
|
|
32159
|
+
now;
|
|
32160
|
+
tail = Promise.resolve();
|
|
32161
|
+
loaded = false;
|
|
32162
|
+
data = { version: 1, bots: {} };
|
|
32163
|
+
filePath;
|
|
32164
|
+
constructor(workingDirectoryBase, now = () => new Date) {
|
|
32165
|
+
this.now = now;
|
|
32166
|
+
this.filePath = join14(workingDirectoryBase, ".telemetry", "daily-token-usage.json");
|
|
32167
|
+
}
|
|
32168
|
+
record(botId, delta) {
|
|
32169
|
+
return this.enqueue(async () => {
|
|
32170
|
+
await this.load();
|
|
32171
|
+
const at = this.now();
|
|
32172
|
+
this.prune(at);
|
|
32173
|
+
const day = dayKey(at);
|
|
32174
|
+
const snapshots = this.data.bots[botId] ?? [];
|
|
32175
|
+
const existing = snapshots.find((snapshot) => snapshot.day === day);
|
|
32176
|
+
const next = existing ?? emptySnapshot(botId, day);
|
|
32177
|
+
next.metrics = {
|
|
32178
|
+
input: mergeMetric(next.metrics.input, delta.input, existing !== undefined),
|
|
32179
|
+
output: mergeMetric(next.metrics.output, delta.output, existing !== undefined),
|
|
32180
|
+
cache: mergeMetric(next.metrics.cache, delta.cache, existing !== undefined)
|
|
32181
|
+
};
|
|
32182
|
+
if (!existing)
|
|
32183
|
+
snapshots.push(next);
|
|
32184
|
+
snapshots.sort((a, b) => a.day.localeCompare(b.day));
|
|
32185
|
+
this.data.bots[botId] = snapshots;
|
|
32186
|
+
await this.persist();
|
|
32187
|
+
});
|
|
32188
|
+
}
|
|
32189
|
+
snapshots(botId) {
|
|
32190
|
+
let result = [];
|
|
32191
|
+
return this.enqueue(async () => {
|
|
32192
|
+
await this.load();
|
|
32193
|
+
if (this.prune(this.now()))
|
|
32194
|
+
await this.persist();
|
|
32195
|
+
result = (this.data.bots[botId] ?? []).map((snapshot) => structuredClone(snapshot));
|
|
32196
|
+
}).then(() => result);
|
|
32197
|
+
}
|
|
32198
|
+
enqueue(operation) {
|
|
32199
|
+
const result = this.tail.then(operation, operation);
|
|
32200
|
+
this.tail = result.then(() => {
|
|
32201
|
+
return;
|
|
32202
|
+
}, () => {
|
|
32203
|
+
return;
|
|
32204
|
+
});
|
|
32205
|
+
return result;
|
|
32206
|
+
}
|
|
32207
|
+
async load() {
|
|
32208
|
+
if (this.loaded)
|
|
32209
|
+
return;
|
|
32210
|
+
let source;
|
|
32211
|
+
try {
|
|
32212
|
+
source = await readFile2(this.filePath, "utf8");
|
|
32213
|
+
} catch (error51) {
|
|
32214
|
+
if (!error51 || typeof error51 !== "object" || !("code" in error51) || error51.code !== "ENOENT") {
|
|
32215
|
+
throw error51;
|
|
32216
|
+
}
|
|
32217
|
+
this.data = { version: 1, bots: {} };
|
|
32218
|
+
this.loaded = true;
|
|
32219
|
+
return;
|
|
32220
|
+
}
|
|
32221
|
+
const parsed = JSON.parse(source);
|
|
32222
|
+
if (!parsed || typeof parsed !== "object" || parsed.version !== 1) {
|
|
32223
|
+
throw new Error("invalid daily token usage file version");
|
|
32224
|
+
}
|
|
32225
|
+
const bots = parsed.bots;
|
|
32226
|
+
if (!bots || typeof bots !== "object" || Array.isArray(bots)) {
|
|
32227
|
+
throw new Error("invalid daily token usage bots map");
|
|
32228
|
+
}
|
|
32229
|
+
const valid = {};
|
|
32230
|
+
for (const [botId, value] of Object.entries(bots)) {
|
|
32231
|
+
if (!Array.isArray(value) || !value.every(isSnapshot) || value.some((snapshot) => snapshot.botId !== botId)) {
|
|
32232
|
+
throw new Error(`invalid daily token usage snapshots for bot ${botId}`);
|
|
32233
|
+
}
|
|
32234
|
+
if (value.length > 0) {
|
|
32235
|
+
valid[botId] = value;
|
|
32236
|
+
}
|
|
32237
|
+
}
|
|
32238
|
+
this.data = { version: 1, bots: valid };
|
|
32239
|
+
this.loaded = true;
|
|
32240
|
+
}
|
|
32241
|
+
prune(at) {
|
|
32242
|
+
const keep = retainedDays(at);
|
|
32243
|
+
let changed = false;
|
|
32244
|
+
for (const [botId, snapshots] of Object.entries(this.data.bots)) {
|
|
32245
|
+
const retained = snapshots.filter((snapshot) => keep.has(snapshot.day)).sort((a, b) => a.day.localeCompare(b.day)).slice(-7);
|
|
32246
|
+
if (retained.length !== snapshots.length || retained.some((snapshot, index2) => snapshot !== snapshots[index2]))
|
|
32247
|
+
changed = true;
|
|
32248
|
+
if (retained.length === 0)
|
|
32249
|
+
delete this.data.bots[botId];
|
|
32250
|
+
else
|
|
32251
|
+
this.data.bots[botId] = retained;
|
|
32252
|
+
}
|
|
32253
|
+
return changed;
|
|
32254
|
+
}
|
|
32255
|
+
async persist() {
|
|
32256
|
+
const directory = dirname6(this.filePath);
|
|
32257
|
+
await mkdir(directory, { recursive: true, mode: 448 });
|
|
32258
|
+
const temporary = `${this.filePath}.${randomUUID7()}.tmp`;
|
|
32259
|
+
try {
|
|
32260
|
+
const file2 = await open(temporary, "wx", 384);
|
|
32261
|
+
try {
|
|
32262
|
+
await file2.writeFile(JSON.stringify(this.data), { encoding: "utf8" });
|
|
32263
|
+
await file2.sync();
|
|
32264
|
+
} finally {
|
|
32265
|
+
await file2.close();
|
|
32266
|
+
}
|
|
32267
|
+
await rename(temporary, this.filePath);
|
|
32268
|
+
await chmod(this.filePath, 384);
|
|
32269
|
+
try {
|
|
32270
|
+
const directoryHandle = await open(directory, "r");
|
|
32271
|
+
try {
|
|
32272
|
+
await directoryHandle.sync();
|
|
32273
|
+
} finally {
|
|
32274
|
+
await directoryHandle.close();
|
|
32275
|
+
}
|
|
32276
|
+
} catch {}
|
|
32277
|
+
} catch (error51) {
|
|
32278
|
+
await rm(temporary, { force: true }).catch(() => {});
|
|
32279
|
+
throw error51;
|
|
32280
|
+
}
|
|
32281
|
+
}
|
|
32282
|
+
}
|
|
31037
32283
|
// src/daemon/createDaemon.ts
|
|
31038
32284
|
var WARMUP_BACKOFF_MS = [250, 500, 1000, 2000, 4000];
|
|
31039
32285
|
var WARMUP_CEILING_MS = 30000;
|
|
@@ -31171,9 +32417,25 @@ function createBuiltinDaemonSessionFactory(onRuntimeRawLine) {
|
|
|
31171
32417
|
}
|
|
31172
32418
|
async function createDaemon(opts) {
|
|
31173
32419
|
const log2 = opts.logger ?? createLogger2({ header: "@alook/daemon" });
|
|
31174
|
-
const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${
|
|
32420
|
+
const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir5()}/.alook`) + "/daemon";
|
|
31175
32421
|
const workingDirectoryBase = opts.workingDirectoryBase ?? fallbackBase;
|
|
31176
32422
|
const workdirFor = (agentId) => `${workingDirectoryBase}/${agentId}`;
|
|
32423
|
+
const dailyTokenUsage2 = new DailyTokenUsageStore(workingDirectoryBase);
|
|
32424
|
+
const providerQuotaReader = opts.providerQuotaReader ?? (opts.sessionFactory ? async () => null : readBuiltinProviderQuota);
|
|
32425
|
+
const providerQuotaByBackend = new Map;
|
|
32426
|
+
let requestReadyQuotaResend = () => {};
|
|
32427
|
+
const recordProviderQuota = (backendId, quota) => {
|
|
32428
|
+
const previous = providerQuotaByBackend.get(backendId);
|
|
32429
|
+
if (previous?.observation.status === "available" && quota.status === "error" && previous.observation.sourceEpoch === quota.sourceEpoch)
|
|
32430
|
+
return;
|
|
32431
|
+
providerQuotaByBackend.set(backendId, {
|
|
32432
|
+
agentBackendId: backendId,
|
|
32433
|
+
observation: structuredClone(quota)
|
|
32434
|
+
});
|
|
32435
|
+
if (previous && previous.observation.sourceEpoch !== quota.sourceEpoch) {
|
|
32436
|
+
requestReadyQuotaResend();
|
|
32437
|
+
}
|
|
32438
|
+
};
|
|
31177
32439
|
sweepTimelineHistory(workingDirectoryBase).catch(() => {
|
|
31178
32440
|
log2.warn("timeline startup sweep failed");
|
|
31179
32441
|
});
|
|
@@ -31189,6 +32451,27 @@ async function createDaemon(opts) {
|
|
|
31189
32451
|
});
|
|
31190
32452
|
let channelRef = null;
|
|
31191
32453
|
let managerRef = null;
|
|
32454
|
+
const providerQuotaSnapshots = () => [...providerQuotaByBackend.values()].map((snapshot) => structuredClone(snapshot));
|
|
32455
|
+
const activityPayload = async (info) => {
|
|
32456
|
+
if (info.state !== "idle")
|
|
32457
|
+
return info;
|
|
32458
|
+
const backendId = managerRef?.agentBackendId(info.agentId);
|
|
32459
|
+
if (backendId === "claude") {
|
|
32460
|
+
const observed = await providerQuotaReader("claude");
|
|
32461
|
+
if (observed)
|
|
32462
|
+
recordProviderQuota("claude", observed);
|
|
32463
|
+
}
|
|
32464
|
+
const quota = backendId === "claude" || backendId === "codex" ? providerQuotaByBackend.get(backendId) : undefined;
|
|
32465
|
+
const dailyUsage = await dailyTokenUsage2.snapshots(info.agentId);
|
|
32466
|
+
return {
|
|
32467
|
+
...info,
|
|
32468
|
+
...dailyUsage.length > 0 ? { dailyUsage } : {},
|
|
32469
|
+
...quota ? { quota: structuredClone(quota) } : {}
|
|
32470
|
+
};
|
|
32471
|
+
};
|
|
32472
|
+
let reportAgentActivity = (info) => {
|
|
32473
|
+
channelRef?.reportAgentActivity?.(info);
|
|
32474
|
+
};
|
|
31192
32475
|
let reminderSchedulerRef = null;
|
|
31193
32476
|
const selfSleepScheduler = opts.onSelfSleep ? new DaemonSelfSleepScheduler({
|
|
31194
32477
|
onSleep: opts.onSelfSleep,
|
|
@@ -31253,7 +32536,7 @@ async function createDaemon(opts) {
|
|
|
31253
32536
|
function reassertAgentActivity(agentId) {
|
|
31254
32537
|
const state = managerRef?.agentActivity(agentId);
|
|
31255
32538
|
if (state)
|
|
31256
|
-
|
|
32539
|
+
reportAgentActivity({ agentId, state });
|
|
31257
32540
|
}
|
|
31258
32541
|
function startTypingHeartbeat(agentId) {
|
|
31259
32542
|
stopTypingHeartbeat(agentId);
|
|
@@ -31397,6 +32680,20 @@ async function createDaemon(opts) {
|
|
|
31397
32680
|
logger: log2.child("ws")
|
|
31398
32681
|
});
|
|
31399
32682
|
channelRef = channel2;
|
|
32683
|
+
const activityReportTails = new Map;
|
|
32684
|
+
reportAgentActivity = (info) => {
|
|
32685
|
+
const prior = activityReportTails.get(info.agentId) ?? Promise.resolve();
|
|
32686
|
+
const next = prior.then(async () => {
|
|
32687
|
+
await channel2.reportAgentActivity(await activityPayload(info));
|
|
32688
|
+
}).catch(() => {
|
|
32689
|
+
log2.warn("agent activity telemetry report failed", { agentId: info.agentId, state: info.state });
|
|
32690
|
+
});
|
|
32691
|
+
activityReportTails.set(info.agentId, next);
|
|
32692
|
+
next.finally(() => {
|
|
32693
|
+
if (activityReportTails.get(info.agentId) === next)
|
|
32694
|
+
activityReportTails.delete(info.agentId);
|
|
32695
|
+
});
|
|
32696
|
+
};
|
|
31400
32697
|
function restorePendingIdleResetEvents(agentId) {
|
|
31401
32698
|
for (const pending of timeline2.pendingIdleResetEvents(agentId)) {
|
|
31402
32699
|
channel2.restorePendingBotAuditEvent({
|
|
@@ -31515,7 +32812,7 @@ async function createDaemon(opts) {
|
|
|
31515
32812
|
onAgentSession: (info) => void channel2.reportAgentSession(info),
|
|
31516
32813
|
onAgentActivity: (info) => {
|
|
31517
32814
|
selfSleepScheduler?.observeAgentActivity(info.agentId, info.state === "running");
|
|
31518
|
-
|
|
32815
|
+
reportAgentActivity(info);
|
|
31519
32816
|
if (info.state === "starting" || info.state === "running") {
|
|
31520
32817
|
if (!typingHeartbeats.has(info.agentId)) {
|
|
31521
32818
|
startTypingHeartbeat(info.agentId);
|
|
@@ -31524,6 +32821,16 @@ async function createDaemon(opts) {
|
|
|
31524
32821
|
emitTypingStopsAndClear(info.agentId);
|
|
31525
32822
|
}
|
|
31526
32823
|
},
|
|
32824
|
+
onTokenUsage: ({ agentId, usage }) => {
|
|
32825
|
+
dailyTokenUsage2.record(agentId, usage).catch(() => {
|
|
32826
|
+
log2.warn("daily token usage persistence failed", { agentId });
|
|
32827
|
+
});
|
|
32828
|
+
},
|
|
32829
|
+
onProviderQuota: ({ backendId, quota }) => {
|
|
32830
|
+
if (backendId !== "claude" && backendId !== "codex")
|
|
32831
|
+
return;
|
|
32832
|
+
recordProviderQuota(backendId, quota);
|
|
32833
|
+
},
|
|
31527
32834
|
onBotAuditEvent: (agentId, event, context) => emitBotAuditEvent(agentId, event, context),
|
|
31528
32835
|
onAgentLocallyStopped: (info) => router?.markLocallyStopped(info.agentId),
|
|
31529
32836
|
onRuntimeRawLine,
|
|
@@ -31570,6 +32877,11 @@ async function createDaemon(opts) {
|
|
|
31570
32877
|
arch: opts.arch,
|
|
31571
32878
|
osRelease: opts.osRelease,
|
|
31572
32879
|
daemonVersion: opts.daemonVersion,
|
|
32880
|
+
providerQuotas: providerQuotaSnapshots,
|
|
32881
|
+
resyncActivities: async () => {
|
|
32882
|
+
const activities = await Promise.all(manager.liveAgentActivities().map((info) => activityPayload(info)));
|
|
32883
|
+
return activities.filter((activity) => manager.agentActivity(activity.agentId) === activity.state);
|
|
32884
|
+
},
|
|
31573
32885
|
typingTracker,
|
|
31574
32886
|
logger: log2.child("router"),
|
|
31575
32887
|
onBeforeAgent: async (agentId) => {
|
|
@@ -31585,6 +32897,10 @@ async function createDaemon(opts) {
|
|
|
31585
32897
|
await enrollAgent(agentId);
|
|
31586
32898
|
}
|
|
31587
32899
|
});
|
|
32900
|
+
requestReadyQuotaResend = () => {
|
|
32901
|
+
if (router)
|
|
32902
|
+
channel2.sendReady?.(router.buildReady());
|
|
32903
|
+
};
|
|
31588
32904
|
channel2.onCommand(createSelfUpdateCommandListener(opts.handleSelfUpdate));
|
|
31589
32905
|
channel2.onCommand(createDiagnosticsCommandListener({
|
|
31590
32906
|
handleDiagnosticCommand: opts.handleDiagnosticCommand,
|
|
@@ -31614,6 +32930,11 @@ async function createDaemon(opts) {
|
|
|
31614
32930
|
resyncPendingWakes();
|
|
31615
32931
|
resyncPendingDiagnostics();
|
|
31616
32932
|
});
|
|
32933
|
+
if (opts.runtimeReport.some((runtime) => runtime.id === "claude")) {
|
|
32934
|
+
const observed = await providerQuotaReader("claude");
|
|
32935
|
+
if (observed)
|
|
32936
|
+
recordProviderQuota("claude", observed);
|
|
32937
|
+
}
|
|
31617
32938
|
channel2.connect();
|
|
31618
32939
|
await router.start();
|
|
31619
32940
|
selfSleepScheduler?.start();
|
|
@@ -32424,7 +33745,7 @@ async function buildDiagnosticBundle(args) {
|
|
|
32424
33745
|
};
|
|
32425
33746
|
}
|
|
32426
33747
|
// src/diagnostics/coordinator.ts
|
|
32427
|
-
import { createHash as createHash4, randomBytes as
|
|
33748
|
+
import { createHash as createHash4, randomBytes as randomBytes7 } from "node:crypto";
|
|
32428
33749
|
import {
|
|
32429
33750
|
chmodSync as chmodSync2,
|
|
32430
33751
|
closeSync as closeSync4,
|
|
@@ -32440,7 +33761,7 @@ import {
|
|
|
32440
33761
|
unlinkSync as unlinkSync6,
|
|
32441
33762
|
writeSync
|
|
32442
33763
|
} from "node:fs";
|
|
32443
|
-
import { join as
|
|
33764
|
+
import { join as join15 } from "node:path";
|
|
32444
33765
|
class CoordinatorError extends Error {
|
|
32445
33766
|
code;
|
|
32446
33767
|
constructor(code) {
|
|
@@ -32450,7 +33771,7 @@ class CoordinatorError extends Error {
|
|
|
32450
33771
|
}
|
|
32451
33772
|
function defaultFsOps() {
|
|
32452
33773
|
return {
|
|
32453
|
-
randomSuffix: () =>
|
|
33774
|
+
randomSuffix: () => randomBytes7(12).toString("hex"),
|
|
32454
33775
|
open: (path11, flags, mode) => openSync4(path11, flags, mode),
|
|
32455
33776
|
write: (fd, bytes) => {
|
|
32456
33777
|
writeSync(fd, bytes);
|
|
@@ -32507,15 +33828,15 @@ function commandFrom(sidecar) {
|
|
|
32507
33828
|
}
|
|
32508
33829
|
function createDiagnosticReportCoordinator(args) {
|
|
32509
33830
|
const fsOps = args.fsOps ?? defaultFsOps();
|
|
32510
|
-
const dir =
|
|
33831
|
+
const dir = join15(args.machineDir, "diagnostics");
|
|
32511
33832
|
let stopped = false;
|
|
32512
33833
|
let active = null;
|
|
32513
33834
|
const retryCancels = new Set;
|
|
32514
33835
|
const checkpoint = (point) => {
|
|
32515
33836
|
args.checkpoint?.(point);
|
|
32516
33837
|
};
|
|
32517
|
-
const archivePath = (reportId) =>
|
|
32518
|
-
const sidecarPath = (reportId) =>
|
|
33838
|
+
const archivePath = (reportId) => join15(dir, `report-${reportId}.ndjson.gz`);
|
|
33839
|
+
const sidecarPath = (reportId) => join15(dir, `report-${reportId}.json`);
|
|
32519
33840
|
const ensureDir = () => {
|
|
32520
33841
|
if (existsSync7(dir)) {
|
|
32521
33842
|
const stat = lstatSync5(dir);
|
|
@@ -32549,7 +33870,7 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
32549
33870
|
let temp = "";
|
|
32550
33871
|
let fd = null;
|
|
32551
33872
|
for (let attempt = 0;attempt < 32; attempt += 1) {
|
|
32552
|
-
temp =
|
|
33873
|
+
temp = join15(dir, `.${sidecar.reportId}.${sidecar.phase}.${fsOps.randomSuffix()}.tmp`);
|
|
32553
33874
|
try {
|
|
32554
33875
|
fd = fsOps.open(temp, "wx", 384);
|
|
32555
33876
|
break;
|
|
@@ -32666,7 +33987,7 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
32666
33987
|
return ready;
|
|
32667
33988
|
};
|
|
32668
33989
|
const buildAndCommit = async (command, collecting) => {
|
|
32669
|
-
const temp =
|
|
33990
|
+
const temp = join15(dir, `.${command.reportId}.archive.${fsOps.randomSuffix()}.tmp`);
|
|
32670
33991
|
const artifact2 = await args.buildBundle({ command, outputPath: temp });
|
|
32671
33992
|
checkpoint("archive_temp_written");
|
|
32672
33993
|
const fd = fsOps.open(artifact2.path, "r+");
|
|
@@ -33514,7 +34835,7 @@ var LEGACY_DAEMON_ID_PATTERN = /^[a-f0-9]{12}$/;
|
|
|
33514
34835
|
var DEFAULT_SERVER_URL = "https://alook.ai";
|
|
33515
34836
|
var DEFAULT_WS_URL = "wss://alook.ai/api/ws/community-daemon";
|
|
33516
34837
|
function resolveDefaultBaseDir() {
|
|
33517
|
-
const root = process.env.ALOOK_PROJECT_ROOT || path13.join(
|
|
34838
|
+
const root = process.env.ALOOK_PROJECT_ROOT || path13.join(homedir6(), ".alook");
|
|
33518
34839
|
return path13.join(root, "daemon");
|
|
33519
34840
|
}
|
|
33520
34841
|
var DEFAULT_BASE_DIR = resolveDefaultBaseDir();
|
|
@@ -34567,6 +35888,61 @@ async function armMessageReminderFromEnv(input, env = process.env, fetchImpl = f
|
|
|
34567
35888
|
return { armed: false, reason: "local reminder returned an invalid response" };
|
|
34568
35889
|
}
|
|
34569
35890
|
|
|
35891
|
+
// src/cli/imageThumbnail.ts
|
|
35892
|
+
var RASTER_CONTENT_TYPES = new Set([
|
|
35893
|
+
"image/png",
|
|
35894
|
+
"image/jpeg",
|
|
35895
|
+
"image/webp",
|
|
35896
|
+
"image/gif"
|
|
35897
|
+
]);
|
|
35898
|
+
var QUALITIES = [80, 70, 60, 50, 40, 30, 20];
|
|
35899
|
+
var DIMENSION_ATTEMPTS = 10;
|
|
35900
|
+
var DIMENSION_SCALE = 0.85;
|
|
35901
|
+
async function prepareCommunityImageUpload(bytes, contentType) {
|
|
35902
|
+
if (!RASTER_CONTENT_TYPES.has(contentType))
|
|
35903
|
+
return {};
|
|
35904
|
+
let required2 = bytes.byteLength > MAX_ATTACHMENT_THUMBNAIL_SIZE_BYTES;
|
|
35905
|
+
try {
|
|
35906
|
+
const { default: sharp } = await import("sharp");
|
|
35907
|
+
const metadata = await sharp(bytes, { failOn: "error" }).metadata();
|
|
35908
|
+
const width = metadata.width;
|
|
35909
|
+
const height = metadata.height;
|
|
35910
|
+
if (!width || !height) {
|
|
35911
|
+
if (required2)
|
|
35912
|
+
throw new Error("missing image dimensions");
|
|
35913
|
+
return {};
|
|
35914
|
+
}
|
|
35915
|
+
required2 = required2 || Math.max(width, height) > MAX_ATTACHMENT_THUMBNAIL_EDGE_PX;
|
|
35916
|
+
if (!required2)
|
|
35917
|
+
return { width, height };
|
|
35918
|
+
const fittedScale = Math.min(1, MAX_ATTACHMENT_THUMBNAIL_EDGE_PX / Math.max(width, height));
|
|
35919
|
+
const fittedWidth = Math.max(1, Math.round(width * fittedScale));
|
|
35920
|
+
const fittedHeight = Math.max(1, Math.round(height * fittedScale));
|
|
35921
|
+
for (let attempt = 0;attempt < DIMENSION_ATTEMPTS; attempt++) {
|
|
35922
|
+
const scale = DIMENSION_SCALE ** attempt;
|
|
35923
|
+
const targetWidth = Math.max(1, Math.round(fittedWidth * scale));
|
|
35924
|
+
const targetHeight = Math.max(1, Math.round(fittedHeight * scale));
|
|
35925
|
+
for (const quality of QUALITIES) {
|
|
35926
|
+
const jpeg = await sharp(bytes, { failOn: "error" }).resize({
|
|
35927
|
+
width: targetWidth,
|
|
35928
|
+
height: targetHeight,
|
|
35929
|
+
fit: "inside",
|
|
35930
|
+
withoutEnlargement: true
|
|
35931
|
+
}).jpeg({ quality }).toBuffer();
|
|
35932
|
+
if (jpeg.byteLength <= MAX_ATTACHMENT_THUMBNAIL_SIZE_BYTES) {
|
|
35933
|
+
return { thumbnail: new Uint8Array(jpeg), width, height };
|
|
35934
|
+
}
|
|
35935
|
+
}
|
|
35936
|
+
}
|
|
35937
|
+
throw new Error("no policy-compliant JPEG candidate");
|
|
35938
|
+
} catch {
|
|
35939
|
+
if (required2) {
|
|
35940
|
+
throw new Error("could not generate a required image preview");
|
|
35941
|
+
}
|
|
35942
|
+
return {};
|
|
35943
|
+
}
|
|
35944
|
+
}
|
|
35945
|
+
|
|
34570
35946
|
// src/cli/index.ts
|
|
34571
35947
|
function messagesInLocalTime(messages) {
|
|
34572
35948
|
return messages.map((m) => ({ ...m, time: toLocalISO(m.time) }));
|
|
@@ -34773,7 +36149,7 @@ ${MESSAGE_SEND_STDIN_POLICY}`);
|
|
|
34773
36149
|
}
|
|
34774
36150
|
replyToSeq = n;
|
|
34775
36151
|
}
|
|
34776
|
-
const nonce =
|
|
36152
|
+
const nonce = randomUUID10();
|
|
34777
36153
|
const res = await sendWithRetry(api2, {
|
|
34778
36154
|
agentId: agent2,
|
|
34779
36155
|
channel: channel2,
|
|
@@ -34884,22 +36260,19 @@ async function cmdAttachmentUpload(opts) {
|
|
|
34884
36260
|
let height;
|
|
34885
36261
|
if (["image/png", "image/jpeg", "image/webp", "image/gif"].includes(contentType)) {
|
|
34886
36262
|
try {
|
|
34887
|
-
const
|
|
34888
|
-
|
|
34889
|
-
|
|
34890
|
-
if (
|
|
34891
|
-
width = metadata.width;
|
|
34892
|
-
height = metadata.height;
|
|
34893
|
-
}
|
|
34894
|
-
const jpeg = await image.resize({ width: 200, height: 200, fit: "inside", withoutEnlargement: true }).jpeg({ quality: 70 }).toBuffer();
|
|
34895
|
-
if (jpeg.byteLength <= MAX_ATTACHMENT_THUMBNAIL_SIZE_BYTES) {
|
|
36263
|
+
const prepared = await prepareCommunityImageUpload(bytes, contentType);
|
|
36264
|
+
width = prepared.width;
|
|
36265
|
+
height = prepared.height;
|
|
36266
|
+
if (prepared.thumbnail) {
|
|
34896
36267
|
thumbnail = {
|
|
34897
|
-
data:
|
|
36268
|
+
data: prepared.thumbnail,
|
|
34898
36269
|
filename: "thumbnail.jpg",
|
|
34899
36270
|
contentType: "image/jpeg"
|
|
34900
36271
|
};
|
|
34901
36272
|
}
|
|
34902
|
-
} catch {
|
|
36273
|
+
} catch (error51) {
|
|
36274
|
+
throw new CliError(`message attachment upload: ${error51.message}`);
|
|
36275
|
+
}
|
|
34903
36276
|
}
|
|
34904
36277
|
const result = await api2.attachmentUpload({
|
|
34905
36278
|
agentId: agent2,
|