@alook/daemon 0.1.23 → 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 +1623 -201
- package/dist/index.js +1575 -205
- package/package.json +4 -2
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({
|
|
@@ -16892,13 +16915,15 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
|
|
|
16892
16915
|
import * as fs from "fs";
|
|
16893
16916
|
import * as path from "path";
|
|
16894
16917
|
// ../shared/src/constants/community.ts
|
|
16918
|
+
var MAX_FOLDER_NAME_LENGTH = 100;
|
|
16895
16919
|
var MAX_PROFILE_NAME_LENGTH = 100;
|
|
16896
16920
|
var MAX_PROFILE_ABOUT_LENGTH = 1000;
|
|
16897
16921
|
var MAX_MESSAGE_CONTENT_LENGTH = 4000;
|
|
16898
16922
|
var MAX_EMOJI_BYTES = 32;
|
|
16899
16923
|
var MAX_ATTACHMENTS_PER_MESSAGE = 10;
|
|
16900
16924
|
var MAX_ATTACHMENT_SIZE_BYTES = 25 * 1024 * 1024;
|
|
16901
|
-
var
|
|
16925
|
+
var MAX_ATTACHMENT_THUMBNAIL_EDGE_PX = 1024;
|
|
16926
|
+
var MAX_ATTACHMENT_THUMBNAIL_SIZE_BYTES = 512 * 1024;
|
|
16902
16927
|
var MAX_SERVER_ICON_SIZE_BYTES = 5 * 1024 * 1024;
|
|
16903
16928
|
var ALLOWED_ICON_MIME_TYPES = [
|
|
16904
16929
|
"image/png",
|
|
@@ -16907,6 +16932,92 @@ var ALLOWED_ICON_MIME_TYPES = [
|
|
|
16907
16932
|
"image/gif"
|
|
16908
16933
|
];
|
|
16909
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();
|
|
16910
17021
|
// ../shared/src/utils/slug.ts
|
|
16911
17022
|
init_nanoid();
|
|
16912
17023
|
var slugId = customAlphabet("0123456789abcdefghijklmnopqrstuvwxyz");
|
|
@@ -17063,10 +17174,13 @@ var ActivateTokenRuntimeSchema = exports_external.object({
|
|
|
17063
17174
|
type: exports_external.string().min(1),
|
|
17064
17175
|
version: exports_external.string().optional().default("")
|
|
17065
17176
|
});
|
|
17177
|
+
var COMMUNITY_RUNTIME_ID_MAX = 64;
|
|
17178
|
+
var COMMUNITY_RUNTIME_VERSION_MAX = 64;
|
|
17179
|
+
var COMMUNITY_RUNTIME_LIST_MAX = 64;
|
|
17066
17180
|
var ActivateTokenRequestSchema = exports_external.object({
|
|
17067
17181
|
token: exports_external.string().min(1),
|
|
17068
17182
|
hostname: exports_external.string().min(1),
|
|
17069
|
-
runtimes: exports_external.array(ActivateTokenRuntimeSchema).min(1)
|
|
17183
|
+
runtimes: exports_external.array(ActivateTokenRuntimeSchema).min(1).max(COMMUNITY_RUNTIME_LIST_MAX)
|
|
17070
17184
|
});
|
|
17071
17185
|
var RegisterDaemonRequestSchema = exports_external.object({
|
|
17072
17186
|
workspace_id: exports_external.string().min(1).optional(),
|
|
@@ -17074,7 +17188,7 @@ var RegisterDaemonRequestSchema = exports_external.object({
|
|
|
17074
17188
|
device_name: exports_external.string().optional().default(""),
|
|
17075
17189
|
cli_version: exports_external.string().optional().default(""),
|
|
17076
17190
|
workspaces_root: exports_external.string().optional().default(""),
|
|
17077
|
-
runtimes: exports_external.array(DaemonRuntimeItemSchema).min(1)
|
|
17191
|
+
runtimes: exports_external.array(DaemonRuntimeItemSchema).min(1).max(COMMUNITY_RUNTIME_LIST_MAX)
|
|
17078
17192
|
});
|
|
17079
17193
|
var DeregisterRequestSchema = exports_external.object({
|
|
17080
17194
|
daemon_id: exports_external.string().min(1)
|
|
@@ -17417,16 +17531,61 @@ var CreateThreadRequestSchema = exports_external.object({
|
|
|
17417
17531
|
content: exports_external.string().optional().default(""),
|
|
17418
17532
|
attachment_ids: exports_external.array(exports_external.string()).optional()
|
|
17419
17533
|
});
|
|
17420
|
-
var COMMUNITY_RUNTIME_ID_MAX = 64;
|
|
17421
|
-
var COMMUNITY_RUNTIME_VERSION_MAX = 64;
|
|
17422
|
-
var COMMUNITY_RUNTIME_LIST_MAX = 64;
|
|
17423
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
|
+
});
|
|
17424
17582
|
var CommunityMachineRuntimeSchema = exports_external.object({
|
|
17425
17583
|
id: exports_external.string().min(1).max(COMMUNITY_RUNTIME_ID_MAX).regex(RUNTIME_ID_RE, "invalid runtime id charset"),
|
|
17426
17584
|
version: exports_external.string().max(COMMUNITY_RUNTIME_VERSION_MAX).optional(),
|
|
17427
17585
|
status: exports_external.enum(["healthy", "unhealthy"]).catch("healthy").default("healthy"),
|
|
17428
17586
|
lastError: exports_external.string().max(128).optional(),
|
|
17429
|
-
lastErrorAt: exports_external.string().optional()
|
|
17587
|
+
lastErrorAt: exports_external.string().optional(),
|
|
17588
|
+
reasoning: RuntimeReasoningCatalogSchema.optional().catch(undefined)
|
|
17430
17589
|
});
|
|
17431
17590
|
var CommunityMachineRuntimeListSchema = exports_external.array(CommunityMachineRuntimeSchema).max(COMMUNITY_RUNTIME_LIST_MAX).transform((list) => {
|
|
17432
17591
|
const seen = new Set;
|
|
@@ -17439,6 +17598,17 @@ var CommunityMachineRuntimeListSchema = exports_external.array(CommunityMachineR
|
|
|
17439
17598
|
}
|
|
17440
17599
|
return out;
|
|
17441
17600
|
});
|
|
17601
|
+
var CommunityRunningAgentListSchema = exports_external.array(exports_external.string()).transform((list) => {
|
|
17602
|
+
const seen = new Set;
|
|
17603
|
+
const out = [];
|
|
17604
|
+
for (const id of list) {
|
|
17605
|
+
if (seen.has(id))
|
|
17606
|
+
continue;
|
|
17607
|
+
seen.add(id);
|
|
17608
|
+
out.push(id);
|
|
17609
|
+
}
|
|
17610
|
+
return out;
|
|
17611
|
+
});
|
|
17442
17612
|
var CommunityMachineSummarySchema = exports_external.object({
|
|
17443
17613
|
id: exports_external.string(),
|
|
17444
17614
|
hostname: exports_external.string(),
|
|
@@ -17462,16 +17632,17 @@ var HostReadyMessageSchema = exports_external.object({
|
|
|
17462
17632
|
type: exports_external.literal("ready"),
|
|
17463
17633
|
runtimeReport: CommunityMachineRuntimeListSchema,
|
|
17464
17634
|
capabilities: exports_external.array(exports_external.string().min(1).max(64)).max(16).optional().default([]),
|
|
17465
|
-
runningAgents:
|
|
17635
|
+
runningAgents: CommunityRunningAgentListSchema.default([]),
|
|
17466
17636
|
hostname: exports_external.string().optional(),
|
|
17467
17637
|
platform: exports_external.string().optional(),
|
|
17468
17638
|
arch: exports_external.string().optional(),
|
|
17469
17639
|
osRelease: exports_external.string().optional(),
|
|
17470
|
-
daemonVersion: exports_external.string().optional()
|
|
17640
|
+
daemonVersion: exports_external.string().optional(),
|
|
17641
|
+
providerQuotas: exports_external.array(ProviderQuotaSnapshotSchema).max(2).optional().default([])
|
|
17471
17642
|
});
|
|
17472
17643
|
var CommunityDaemonReadySchema = exports_external.object({
|
|
17473
17644
|
runtimeReport: CommunityMachineRuntimeListSchema.optional(),
|
|
17474
|
-
runningAgents:
|
|
17645
|
+
runningAgents: CommunityRunningAgentListSchema.default([]),
|
|
17475
17646
|
hostname: exports_external.string().optional(),
|
|
17476
17647
|
os: exports_external.string().optional(),
|
|
17477
17648
|
arch: exports_external.string().optional(),
|
|
@@ -17488,7 +17659,9 @@ var SessionErrorFrameSchema = exports_external.object({
|
|
|
17488
17659
|
var AgentActivityMessageSchema = exports_external.object({
|
|
17489
17660
|
type: exports_external.literal("agent_activity"),
|
|
17490
17661
|
agentId: exports_external.string(),
|
|
17491
|
-
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()
|
|
17492
17665
|
});
|
|
17493
17666
|
var AgentTypingMessageSchema = exports_external.object({
|
|
17494
17667
|
type: exports_external.literal("agent_typing"),
|
|
@@ -17563,15 +17736,17 @@ var CommunityBotCreateRequestSchema = exports_external.object({
|
|
|
17563
17736
|
machineId: exports_external.string().min(1),
|
|
17564
17737
|
runtime: exports_external.string().min(1),
|
|
17565
17738
|
image: BotImageUrlSchema.optional(),
|
|
17566
|
-
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()
|
|
17567
17741
|
});
|
|
17568
17742
|
var CommunityBotPatchRequestSchema = exports_external.object({
|
|
17569
17743
|
name: exports_external.string().trim().min(COMMUNITY_BOT_NAME_MIN).max(COMMUNITY_BOT_NAME_MAX).refine(isMentionSafeName, { message: MENTION_SAFE_NAME_MSG }).optional(),
|
|
17570
17744
|
description: exports_external.string().max(COMMUNITY_BOT_DESCRIPTION_MAX).optional(),
|
|
17571
17745
|
image: BotImageUrlSchema.nullable().optional(),
|
|
17572
17746
|
model: exports_external.string().trim().min(1).max(100).nullable().optional(),
|
|
17573
|
-
runtime: exports_external.string().trim().min(1).max(COMMUNITY_RUNTIME_ID_MAX).optional()
|
|
17574
|
-
|
|
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), {
|
|
17575
17750
|
message: "at least one field must be provided"
|
|
17576
17751
|
});
|
|
17577
17752
|
var CommunityBotAddToServerRequestSchema = exports_external.object({
|
|
@@ -17773,6 +17948,7 @@ __export(exports_community_schema, {
|
|
|
17773
17948
|
communityChannelMember: () => communityChannelMember,
|
|
17774
17949
|
communityChannel: () => communityChannel,
|
|
17775
17950
|
communityCategory: () => communityCategory,
|
|
17951
|
+
communityBotDailyTokenUsage: () => communityBotDailyTokenUsage,
|
|
17776
17952
|
communityBotDailyActivity: () => communityBotDailyActivity,
|
|
17777
17953
|
communityBotApprovalRequest: () => communityBotApprovalRequest,
|
|
17778
17954
|
communityBotActivityEvent: () => communityBotActivityEvent,
|
|
@@ -18025,6 +18201,17 @@ var communityBotDailyActivity = sqliteTable("community_bot_daily_activity", {
|
|
|
18025
18201
|
handledCount: integer2("handled_count").notNull().default(0),
|
|
18026
18202
|
sentCount: integer2("sent_count").notNull().default(0)
|
|
18027
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
|
+
]);
|
|
18028
18215
|
var communityMessageMark = sqliteTable("community_message_mark", {
|
|
18029
18216
|
id: text("id").primaryKey().$defaultFn(() => nanoid3()),
|
|
18030
18217
|
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
|
|
@@ -18149,7 +18336,8 @@ var listedMessageProjection = {
|
|
|
18149
18336
|
clientNonce: communityMessage.clientNonce,
|
|
18150
18337
|
authorName: user.name,
|
|
18151
18338
|
authorEmail: user.email,
|
|
18152
|
-
authorImage: user.image
|
|
18339
|
+
authorImage: user.image,
|
|
18340
|
+
authorAvatarVersion: user.avatarVersion
|
|
18153
18341
|
};
|
|
18154
18342
|
|
|
18155
18343
|
// ../shared/src/db/queries/user.ts
|
|
@@ -18159,6 +18347,7 @@ var publicUserColumns = {
|
|
|
18159
18347
|
email: user.email,
|
|
18160
18348
|
emailVerified: user.emailVerified,
|
|
18161
18349
|
image: user.image,
|
|
18350
|
+
avatarVersion: user.avatarVersion,
|
|
18162
18351
|
createdAt: user.createdAt,
|
|
18163
18352
|
updatedAt: user.updatedAt,
|
|
18164
18353
|
discriminator: user.discriminator
|
|
@@ -18169,6 +18358,12 @@ var internalUserColumns = {
|
|
|
18169
18358
|
ownerUserId: user.ownerUserId,
|
|
18170
18359
|
deletedAt: user.deletedAt
|
|
18171
18360
|
};
|
|
18361
|
+
var avatarPublishColumns = {
|
|
18362
|
+
id: user.id,
|
|
18363
|
+
image: user.image,
|
|
18364
|
+
avatarVersion: user.avatarVersion,
|
|
18365
|
+
avatarObjectKey: user.avatarObjectKey
|
|
18366
|
+
};
|
|
18172
18367
|
|
|
18173
18368
|
// ../shared/src/db/queries/community/channel.ts
|
|
18174
18369
|
var CHANNEL_COLUMNS = {
|
|
@@ -18221,7 +18416,8 @@ var friendApprovalProfileSchema = exports_external.strictObject({
|
|
|
18221
18416
|
id: string4,
|
|
18222
18417
|
name: string4,
|
|
18223
18418
|
discriminator: string4,
|
|
18224
|
-
image: nullableString
|
|
18419
|
+
image: nullableString,
|
|
18420
|
+
avatarVersion: exports_external.number().int().nonnegative()
|
|
18225
18421
|
});
|
|
18226
18422
|
var FriendApprovalPayloadSchema = exports_external.strictObject({
|
|
18227
18423
|
friendshipId: string4,
|
|
@@ -18247,6 +18443,7 @@ var messageSchema = exports_external.strictObject({
|
|
|
18247
18443
|
authorId: string4,
|
|
18248
18444
|
authorName: string4,
|
|
18249
18445
|
authorAvatar: string4.optional(),
|
|
18446
|
+
authorAvatarVersion: exports_external.number().int().nonnegative(),
|
|
18250
18447
|
content: string4,
|
|
18251
18448
|
type: exports_external.enum(["chat", "system"]),
|
|
18252
18449
|
systemKind: exports_external.literal("thread").optional(),
|
|
@@ -18254,6 +18451,7 @@ var messageSchema = exports_external.strictObject({
|
|
|
18254
18451
|
replyToId: nullableString.optional(),
|
|
18255
18452
|
replyTo: exports_external.strictObject({
|
|
18256
18453
|
id: string4,
|
|
18454
|
+
authorId: string4.optional(),
|
|
18257
18455
|
authorName: string4,
|
|
18258
18456
|
text: string4,
|
|
18259
18457
|
deleted: exports_external.boolean().optional()
|
|
@@ -18448,6 +18646,7 @@ var communityMemberJoinSchema = exports_external.strictObject({
|
|
|
18448
18646
|
name: string4,
|
|
18449
18647
|
discriminator: string4,
|
|
18450
18648
|
avatar: string4.optional(),
|
|
18649
|
+
avatarVersion: exports_external.number().int().nonnegative(),
|
|
18451
18650
|
role: string4,
|
|
18452
18651
|
joinedAt: string4
|
|
18453
18652
|
})
|
|
@@ -18550,6 +18749,22 @@ var communityStatusUpdateSchema = exports_external.strictObject({
|
|
|
18550
18749
|
statusEmoji: nullableString,
|
|
18551
18750
|
statusText: nullableString
|
|
18552
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
|
+
});
|
|
18553
18768
|
var machineRuntimeSchema = CommunityMachineRuntimeSchema.strict();
|
|
18554
18769
|
var CommunityMachineSummarySchema2 = exports_external.strictObject({
|
|
18555
18770
|
id: string4,
|
|
@@ -18638,6 +18853,8 @@ var CommunityWsEventDiscriminatedSchema = exports_external.discriminatedUnion("t
|
|
|
18638
18853
|
communityInboxChangedSchema,
|
|
18639
18854
|
communityPresenceUpdateSchema,
|
|
18640
18855
|
communityStatusUpdateSchema,
|
|
18856
|
+
communityIdentityUpdateSchema,
|
|
18857
|
+
communityProfileUpdateSchema,
|
|
18641
18858
|
communityMachineCreatedSchema,
|
|
18642
18859
|
communityMachineStatusSchema,
|
|
18643
18860
|
communityMachineUpdatedSchema,
|
|
@@ -18684,6 +18901,8 @@ var WS_EVENTS = {
|
|
|
18684
18901
|
INBOX_CHANGED: "community:inbox.changed",
|
|
18685
18902
|
PRESENCE_UPDATE: "community:presence.update",
|
|
18686
18903
|
STATUS_UPDATE: "community:status.update",
|
|
18904
|
+
IDENTITY_UPDATE: "community:identity.update",
|
|
18905
|
+
PROFILE_UPDATE: "community:profile.update",
|
|
18687
18906
|
MACHINE_CREATED: "community:machine.created",
|
|
18688
18907
|
MACHINE_STATUS: "community:machine.status",
|
|
18689
18908
|
MACHINE_UPDATED: "community:machine.updated",
|
|
@@ -18760,6 +18979,43 @@ var COMMUNITY_BROWSER_EVENT_BATCH_ENVELOPE_BYTES = 1024;
|
|
|
18760
18979
|
var COMMUNITY_BROWSER_EVENT_BATCH_MAX_BYTES = MESSAGE_DELIVERY_MAX_EVENTS_PER_USER * COMMUNITY_BROWSER_EVENT_MAX_BYTES + COMMUNITY_BROWSER_EVENT_BATCH_ENVELOPE_BYTES;
|
|
18761
18980
|
// ../shared/src/db/index.ts
|
|
18762
18981
|
var allSchema = { ...exports_schema, ...exports_community_schema, ...exports_community_machine_schema };
|
|
18982
|
+
// ../shared/src/community-server-rail.ts
|
|
18983
|
+
var MAX_SERVER_RAIL_COMMANDS = 3;
|
|
18984
|
+
var idSchema = exports_external.string().trim().min(1);
|
|
18985
|
+
var idsSchema = exports_external.array(idSchema);
|
|
18986
|
+
var reorderServersSchema = exports_external.strictObject({
|
|
18987
|
+
kind: exports_external.literal("reorder-servers"),
|
|
18988
|
+
serverIds: idsSchema
|
|
18989
|
+
});
|
|
18990
|
+
var reorderFoldersSchema = exports_external.strictObject({
|
|
18991
|
+
kind: exports_external.literal("reorder-folders"),
|
|
18992
|
+
folderIds: idsSchema
|
|
18993
|
+
});
|
|
18994
|
+
var replaceFolderItemsSchema = exports_external.strictObject({
|
|
18995
|
+
kind: exports_external.literal("replace-folder-items"),
|
|
18996
|
+
folderId: idSchema,
|
|
18997
|
+
serverIds: idsSchema.min(1)
|
|
18998
|
+
});
|
|
18999
|
+
var deleteFolderSchema = exports_external.strictObject({
|
|
19000
|
+
kind: exports_external.literal("delete-folder"),
|
|
19001
|
+
folderId: idSchema
|
|
19002
|
+
});
|
|
19003
|
+
var createFolderSchema = exports_external.strictObject({
|
|
19004
|
+
kind: exports_external.literal("create-folder"),
|
|
19005
|
+
clientId: idSchema,
|
|
19006
|
+
name: exports_external.string().trim().min(1).max(MAX_FOLDER_NAME_LENGTH),
|
|
19007
|
+
serverIds: idsSchema.min(1)
|
|
19008
|
+
});
|
|
19009
|
+
var serverRailCommandSchema = exports_external.discriminatedUnion("kind", [
|
|
19010
|
+
reorderServersSchema,
|
|
19011
|
+
reorderFoldersSchema,
|
|
19012
|
+
replaceFolderItemsSchema,
|
|
19013
|
+
deleteFolderSchema,
|
|
19014
|
+
createFolderSchema
|
|
19015
|
+
]);
|
|
19016
|
+
var serverRailCommitRequestSchema = exports_external.strictObject({
|
|
19017
|
+
commands: exports_external.array(serverRailCommandSchema).min(1).max(MAX_SERVER_RAIL_COMMANDS)
|
|
19018
|
+
});
|
|
18763
19019
|
// ../shared/src/db/queries/task.ts
|
|
18764
19020
|
var DEFAULT_STALE_SECONDS = Number(process.env.ALOOK_STALE_DISPATCH_TIMEOUT_S) || 20;
|
|
18765
19021
|
var DEFAULT_STALE_RUNNING_SECONDS = Number(process.env.ALOOK_STALE_RUNNING_TIMEOUT_S) || 3600;
|
|
@@ -19225,7 +19481,7 @@ import * as fs12 from "fs";
|
|
|
19225
19481
|
import * as path13 from "path";
|
|
19226
19482
|
import * as crypto5 from "crypto";
|
|
19227
19483
|
import * as os3 from "os";
|
|
19228
|
-
import { homedir as
|
|
19484
|
+
import { homedir as homedir6 } from "os";
|
|
19229
19485
|
|
|
19230
19486
|
// src/discovery.ts
|
|
19231
19487
|
import * as path9 from "path";
|
|
@@ -20005,6 +20261,9 @@ class ProcessLane {
|
|
|
20005
20261
|
return false;
|
|
20006
20262
|
return proc.kill("SIGINT");
|
|
20007
20263
|
}
|
|
20264
|
+
updateSettings(input) {
|
|
20265
|
+
return this.driver.updateSettings?.(input) ?? Promise.resolve({ status: "unsupported" });
|
|
20266
|
+
}
|
|
20008
20267
|
attachProcess(proc) {
|
|
20009
20268
|
proc.stdout?.on("data", (chunk2) => {
|
|
20010
20269
|
const chunkText = chunk2.toString();
|
|
@@ -20392,25 +20651,19 @@ class ClaudeEventNormalizer {
|
|
|
20392
20651
|
}
|
|
20393
20652
|
buildUsageTelemetry(event) {
|
|
20394
20653
|
const u = event?.usage;
|
|
20395
|
-
if (!u
|
|
20654
|
+
if (!u)
|
|
20396
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;
|
|
20397
20659
|
return {
|
|
20398
20660
|
kind: "telemetry",
|
|
20399
20661
|
name: "token_usage",
|
|
20400
20662
|
source: "claude_result_usage",
|
|
20401
|
-
|
|
20402
|
-
|
|
20403
|
-
|
|
20404
|
-
|
|
20405
|
-
cachedInputTokens: u?.cache_read_input_tokens,
|
|
20406
|
-
cacheCreationInputTokens: u?.cache_creation_input_tokens,
|
|
20407
|
-
totalCostUsd: event?.total_cost_usd,
|
|
20408
|
-
durationMs: event?.duration_ms,
|
|
20409
|
-
durationApiMs: event?.duration_api_ms,
|
|
20410
|
-
numTurns: event?.num_turns,
|
|
20411
|
-
resultSubtype: event?.subtype,
|
|
20412
|
-
resultIsError: event?.is_error,
|
|
20413
|
-
serviceTier: u?.service_tier
|
|
20663
|
+
usage: {
|
|
20664
|
+
input: metric(u.input_tokens),
|
|
20665
|
+
output: metric(u.output_tokens),
|
|
20666
|
+
cache
|
|
20414
20667
|
}
|
|
20415
20668
|
};
|
|
20416
20669
|
}
|
|
@@ -20642,49 +20895,153 @@ class ClaudeDriver {
|
|
|
20642
20895
|
}
|
|
20643
20896
|
|
|
20644
20897
|
// agent-driver/dist/adapters/codex/telemetry.js
|
|
20645
|
-
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) {
|
|
20646
21000
|
if (method === "thread/tokenUsage/updated") {
|
|
20647
|
-
const u = params?.
|
|
20648
|
-
|
|
20649
|
-
|
|
20650
|
-
|
|
20651
|
-
|
|
20652
|
-
|
|
20653
|
-
|
|
20654
|
-
|
|
20655
|
-
|
|
20656
|
-
|
|
20657
|
-
|
|
20658
|
-
|
|
20659
|
-
|
|
20660
|
-
modelContextWindow: u.modelContextWindow ?? u.model_context_window,
|
|
20661
|
-
cachedInputRatio: u.cachedInputRatio,
|
|
20662
|
-
contextUtilization: u.contextUtilization
|
|
20663
|
-
}
|
|
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)
|
|
20664
21014
|
}
|
|
20665
|
-
];
|
|
21015
|
+
}];
|
|
20666
21016
|
}
|
|
20667
21017
|
if (method === "account/rateLimits/updated") {
|
|
20668
|
-
|
|
20669
|
-
return [
|
|
20670
|
-
{
|
|
20671
|
-
kind: "telemetry",
|
|
20672
|
-
name: "rate_limits",
|
|
20673
|
-
source: "codex_account_rate_limits_updated",
|
|
20674
|
-
attrs: {
|
|
20675
|
-
limitId: r.limitId,
|
|
20676
|
-
planType: r.planType,
|
|
20677
|
-
usedPercent: r.usedPercent,
|
|
20678
|
-
windowDurationMins: r.windowDurationMins,
|
|
20679
|
-
resetsAt: r.resetsAt
|
|
20680
|
-
}
|
|
20681
|
-
}
|
|
20682
|
-
];
|
|
21018
|
+
return [mapCodexQuotaSnapshots([params?.rateLimits ?? params ?? {}], sourceEpoch)];
|
|
20683
21019
|
}
|
|
20684
21020
|
return [];
|
|
20685
21021
|
}
|
|
20686
21022
|
|
|
20687
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
|
+
}
|
|
20688
21045
|
function normalizeFileChangeInput(item) {
|
|
20689
21046
|
const paths = [];
|
|
20690
21047
|
const seen = new Set;
|
|
@@ -20707,6 +21064,12 @@ function normalizeFileChangeInput(item) {
|
|
|
20707
21064
|
}
|
|
20708
21065
|
|
|
20709
21066
|
class CodexEventNormalizer {
|
|
21067
|
+
quotaReadRequestIds = new Set;
|
|
21068
|
+
accountReadRequestIds = new Set;
|
|
21069
|
+
rateLimitSnapshots = new Map;
|
|
21070
|
+
quotaSnapshotInitialized = false;
|
|
21071
|
+
quotaSourceGeneration = codexQuotaSourceGeneration;
|
|
21072
|
+
pendingTurnUsage = null;
|
|
20710
21073
|
threadId = null;
|
|
20711
21074
|
turnId = null;
|
|
20712
21075
|
terminalTurn = null;
|
|
@@ -20717,10 +21080,69 @@ class CodexEventNormalizer {
|
|
|
20717
21080
|
get currentTurnId() {
|
|
20718
21081
|
return this.turnId;
|
|
20719
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
|
+
}
|
|
20720
21141
|
adoptThreadId(threadId) {
|
|
20721
21142
|
if (threadId !== this.threadId) {
|
|
20722
21143
|
this.turnId = null;
|
|
20723
21144
|
this.terminalTurn = null;
|
|
21145
|
+
this.pendingTurnUsage = null;
|
|
20724
21146
|
}
|
|
20725
21147
|
this.threadId = threadId;
|
|
20726
21148
|
}
|
|
@@ -20738,6 +21160,25 @@ class CodexEventNormalizer {
|
|
|
20738
21160
|
const msg = tryParseJsonLine(line);
|
|
20739
21161
|
if (!msg)
|
|
20740
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
|
+
}
|
|
20741
21182
|
if (msg?.error && msg.id !== undefined) {
|
|
20742
21183
|
return [{ kind: "error", message: msg.error?.message ?? "Codex RPC error" }];
|
|
20743
21184
|
}
|
|
@@ -20762,6 +21203,7 @@ class CodexEventNormalizer {
|
|
|
20762
21203
|
return [];
|
|
20763
21204
|
this.turnId = params.turn.id;
|
|
20764
21205
|
this.terminalTurn = null;
|
|
21206
|
+
this.pendingTurnUsage = null;
|
|
20765
21207
|
return [
|
|
20766
21208
|
{
|
|
20767
21209
|
kind: "turn_owner",
|
|
@@ -20790,24 +21232,36 @@ class CodexEventNormalizer {
|
|
|
20790
21232
|
case "turn/completed":
|
|
20791
21233
|
if (!this.acceptRootTerminal(params))
|
|
20792
21234
|
return [];
|
|
21235
|
+
const usage = this.pendingTurnUsage;
|
|
21236
|
+
this.pendingTurnUsage = null;
|
|
20793
21237
|
if (params.turn.status === "failed") {
|
|
20794
21238
|
return [
|
|
21239
|
+
...usage ? [usage] : [],
|
|
20795
21240
|
{ kind: "error", message: "Codex turn failed" },
|
|
20796
21241
|
{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }
|
|
20797
21242
|
];
|
|
20798
21243
|
}
|
|
20799
21244
|
if (params.turn.status === "interrupted") {
|
|
20800
|
-
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) }];
|
|
20801
21246
|
}
|
|
20802
|
-
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) }];
|
|
20803
21248
|
case "error":
|
|
20804
21249
|
if (params?.willRetry === true) {
|
|
20805
21250
|
return [{ kind: "runtime_recovery", stage: "retrying", source: "codex_stream" }];
|
|
20806
21251
|
}
|
|
20807
21252
|
return [{ kind: "error", message: params?.error?.message ?? params?.message ?? "Codex error" }];
|
|
20808
|
-
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
|
+
}
|
|
20809
21259
|
case "account/rateLimits/updated":
|
|
20810
|
-
return
|
|
21260
|
+
return this.mergeQuotaSnapshots(params);
|
|
21261
|
+
case "account/updated":
|
|
21262
|
+
rotateCodexQuotaSource();
|
|
21263
|
+
this.syncQuotaSourceGeneration();
|
|
21264
|
+
return [];
|
|
20811
21265
|
default:
|
|
20812
21266
|
return [];
|
|
20813
21267
|
}
|
|
@@ -20920,7 +21374,53 @@ function resolveCodexHomeRootFromEnv(env = process.env, opts = {}) {
|
|
|
20920
21374
|
return path6.join(opts.defaultHomeDir ?? os.homedir(), ".codex");
|
|
20921
21375
|
}
|
|
20922
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
|
+
|
|
20923
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;
|
|
20924
21424
|
function isCodexMissingRolloutError(message2) {
|
|
20925
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);
|
|
20926
21426
|
}
|
|
@@ -20941,19 +21441,157 @@ class CodexDriver {
|
|
|
20941
21441
|
}
|
|
20942
21442
|
};
|
|
20943
21443
|
eventNormalizer = new CodexEventNormalizer;
|
|
21444
|
+
pendingAccountReadRequestIds = new Set;
|
|
20944
21445
|
requestId = 0;
|
|
20945
21446
|
codexHomeRoot = null;
|
|
20946
21447
|
proc = null;
|
|
20947
21448
|
pendingInitialPrompt = null;
|
|
20948
21449
|
pendingResumeFallbackParams = null;
|
|
21450
|
+
pendingSettingsUpdates = new Map;
|
|
20949
21451
|
nextRequestId() {
|
|
20950
21452
|
return ++this.requestId;
|
|
20951
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
|
+
}
|
|
20952
21471
|
get codexHome() {
|
|
20953
21472
|
return this.codexHomeRoot;
|
|
20954
21473
|
}
|
|
20955
|
-
probe(command) {
|
|
20956
|
-
|
|
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
|
+
});
|
|
20957
21595
|
}
|
|
20958
21596
|
async openLane(ctx, options) {
|
|
20959
21597
|
return createProcessLane(this, ctx, { onRawStdoutLine: options?.onRawStdoutLine });
|
|
@@ -20969,6 +21607,9 @@ class CodexDriver {
|
|
|
20969
21607
|
shell: spec.shell
|
|
20970
21608
|
});
|
|
20971
21609
|
this.proc = proc;
|
|
21610
|
+
proc.once("exit", () => {
|
|
21611
|
+
this.failPendingSettingsUpdates("settings_process_exited", "Codex exited before acknowledging the settings update");
|
|
21612
|
+
});
|
|
20972
21613
|
const initialPrompt = ctx.prompt?.trim() ? ctx.prompt : null;
|
|
20973
21614
|
this.pendingInitialPrompt = initialPrompt;
|
|
20974
21615
|
queueMicrotask(() => {
|
|
@@ -20997,11 +21638,21 @@ class CodexDriver {
|
|
|
20997
21638
|
proc.stdin?.write(jsonRpcRequest("thread/start", freshParams, this.nextRequestId()) + `
|
|
20998
21639
|
`);
|
|
20999
21640
|
}
|
|
21641
|
+
this.requestAccountQuotaSnapshot();
|
|
21000
21642
|
});
|
|
21001
21643
|
return { process: proc };
|
|
21002
21644
|
}
|
|
21003
21645
|
normalizeLine(line) {
|
|
21646
|
+
const settingsResponse = this.consumeSettingsUpdateResponse(line);
|
|
21647
|
+
if (settingsResponse)
|
|
21648
|
+
return [];
|
|
21649
|
+
const parsed = tryParseJsonLine(line);
|
|
21004
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();
|
|
21005
21656
|
if (this.pendingResumeFallbackParams && this.proc?.stdin && !this.proc.stdin.destroyed) {
|
|
21006
21657
|
const rolloutErr = events.find((e) => e.kind === "error" && isCodexMissingRolloutError(e.message));
|
|
21007
21658
|
if (rolloutErr) {
|
|
@@ -21025,6 +21676,90 @@ class CodexDriver {
|
|
|
21025
21676
|
}
|
|
21026
21677
|
return events;
|
|
21027
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
|
+
}
|
|
21028
21763
|
get currentSessionId() {
|
|
21029
21764
|
return this.eventNormalizer.currentSessionId;
|
|
21030
21765
|
}
|
|
@@ -21343,15 +22078,6 @@ class CursorAcpLane {
|
|
|
21343
22078
|
}
|
|
21344
22079
|
this.activePrompt = null;
|
|
21345
22080
|
this.openToolCalls.clear();
|
|
21346
|
-
const usage = record2(result.usage);
|
|
21347
|
-
if (usage) {
|
|
21348
|
-
this.events.emit("runtime_event", {
|
|
21349
|
-
kind: "telemetry",
|
|
21350
|
-
name: "token_usage",
|
|
21351
|
-
source: "cursor.acp",
|
|
21352
|
-
attrs: usage
|
|
21353
|
-
});
|
|
21354
|
-
}
|
|
21355
22081
|
this.events.emit("runtime_event", {
|
|
21356
22082
|
kind: "turn_end",
|
|
21357
22083
|
sessionId: this.sessionId ?? undefined,
|
|
@@ -21701,10 +22427,10 @@ class CursorDriver {
|
|
|
21701
22427
|
}
|
|
21702
22428
|
|
|
21703
22429
|
// agent-driver/dist/adapters/opencode/index.js
|
|
21704
|
-
import { randomBytes as
|
|
22430
|
+
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
21705
22431
|
|
|
21706
22432
|
// agent-driver/dist/adapters/opencode/service-lane.js
|
|
21707
|
-
import { randomBytes } from "node:crypto";
|
|
22433
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
21708
22434
|
import { EventEmitter as EventEmitter3 } from "node:events";
|
|
21709
22435
|
import { createServer as createServer2 } from "node:net";
|
|
21710
22436
|
var SUPPORTED_VERSION = "1.17.20";
|
|
@@ -21843,7 +22569,7 @@ class OpenCodeServiceLane {
|
|
|
21843
22569
|
this.ctx = ctx;
|
|
21844
22570
|
this.options = options;
|
|
21845
22571
|
this.fetchFn = options.fetch ?? fetch;
|
|
21846
|
-
this.password = options.password ??
|
|
22572
|
+
this.password = options.password ?? randomBytes2(32).toString("base64url");
|
|
21847
22573
|
}
|
|
21848
22574
|
get currentSessionId() {
|
|
21849
22575
|
return this.sessionId;
|
|
@@ -22457,12 +23183,20 @@ class OpenCodeServiceLane {
|
|
|
22457
23183
|
});
|
|
22458
23184
|
}
|
|
22459
23185
|
const tokens = record3(data.tokens);
|
|
22460
|
-
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);
|
|
22461
23191
|
this.events.emit("runtime_event", {
|
|
22462
23192
|
kind: "telemetry",
|
|
22463
23193
|
name: "token_usage",
|
|
22464
23194
|
source: "opencode.v2",
|
|
22465
|
-
|
|
23195
|
+
usage: {
|
|
23196
|
+
input: metric2(tokens.input),
|
|
23197
|
+
output: metric2(tokens.output),
|
|
23198
|
+
cache: cacheParts.length > 0 && Number.isSafeInteger(cacheTotal) ? cacheTotal : null
|
|
23199
|
+
}
|
|
22466
23200
|
});
|
|
22467
23201
|
}
|
|
22468
23202
|
break;
|
|
@@ -22768,7 +23502,7 @@ class OpenCodeServiceLane {
|
|
|
22768
23502
|
return headers;
|
|
22769
23503
|
}
|
|
22770
23504
|
newMessageId() {
|
|
22771
|
-
return `msg_${
|
|
23505
|
+
return `msg_${randomBytes2(16).toString("hex")}`;
|
|
22772
23506
|
}
|
|
22773
23507
|
diagnostic(severity, message2) {
|
|
22774
23508
|
this.events.emit("runtime_event", {
|
|
@@ -22833,7 +23567,7 @@ class OpenCodeServiceLane {
|
|
|
22833
23567
|
|
|
22834
23568
|
// agent-driver/dist/adapters/opencode/index.js
|
|
22835
23569
|
function createOpenCodeMessageId() {
|
|
22836
|
-
return `msg_${
|
|
23570
|
+
return `msg_${randomBytes3(16).toString("hex")}`;
|
|
22837
23571
|
}
|
|
22838
23572
|
|
|
22839
23573
|
class OpenCodeDriver {
|
|
@@ -23611,48 +24345,6 @@ function assertInstructionFileName(name) {
|
|
|
23611
24345
|
}
|
|
23612
24346
|
}
|
|
23613
24347
|
|
|
23614
|
-
// agent-driver/dist/internal/errors.js
|
|
23615
|
-
var MAX_PUBLIC_ERROR_MESSAGE = 1000;
|
|
23616
|
-
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}`;
|
|
23617
|
-
var QUOTED_CREDENTIAL_ASSIGNMENT = new RegExp(String.raw`(["'])(${CREDENTIAL_NAME})\1\s*[:=]\s*(["'])[^"'\r\n]*\3`, "gi");
|
|
23618
|
-
var CREDENTIAL_ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9_-])((?:${CREDENTIAL_NAME})\s*[:=]\s*)(?!\[redacted\])[^\s,;}\]]+`, "gi");
|
|
23619
|
-
function scrubDriverErrorMessage(value, fallback = "Runtime operation failed") {
|
|
23620
|
-
const text2 = value instanceof Error ? value.message : String(value ?? "");
|
|
23621
|
-
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();
|
|
23622
|
-
return (scrubbed || fallback).slice(0, MAX_PUBLIC_ERROR_MESSAGE);
|
|
23623
|
-
}
|
|
23624
|
-
function scrubDriverError(error51) {
|
|
23625
|
-
return {
|
|
23626
|
-
...error51,
|
|
23627
|
-
code: stableErrorCode(error51.code, "runtime_error"),
|
|
23628
|
-
message: scrubDriverErrorMessage(error51.message),
|
|
23629
|
-
...error51.details ? { details: scrubDetails(error51.details) } : {}
|
|
23630
|
-
};
|
|
23631
|
-
}
|
|
23632
|
-
function scrubDetails(details) {
|
|
23633
|
-
const scrubValue = (value, key) => {
|
|
23634
|
-
if (key && /api[_-]?key|access[_-]?token|auth(?:orization)?|password|passwd|secret|token/i.test(key)) {
|
|
23635
|
-
return "[redacted]";
|
|
23636
|
-
}
|
|
23637
|
-
if (typeof value === "string")
|
|
23638
|
-
return scrubDriverErrorMessage(value, "[redacted]");
|
|
23639
|
-
if (Array.isArray(value))
|
|
23640
|
-
return value.map((item) => scrubValue(item));
|
|
23641
|
-
if (value && typeof value === "object") {
|
|
23642
|
-
return Object.fromEntries(Object.entries(value).map(([childKey, child]) => [
|
|
23643
|
-
childKey,
|
|
23644
|
-
scrubValue(child, childKey)
|
|
23645
|
-
]));
|
|
23646
|
-
}
|
|
23647
|
-
return value;
|
|
23648
|
-
};
|
|
23649
|
-
return scrubValue(details);
|
|
23650
|
-
}
|
|
23651
|
-
function stableErrorCode(value, fallback) {
|
|
23652
|
-
const code = String(value ?? "");
|
|
23653
|
-
return /^[A-Za-z0-9_.-]{1,100}$/.test(code) ? code : fallback;
|
|
23654
|
-
}
|
|
23655
|
-
|
|
23656
24348
|
// agent-driver/dist/controller/logical-session.js
|
|
23657
24349
|
import { mkdirSync as mkdirSync4 } from "node:fs";
|
|
23658
24350
|
var SEMANTIC_ASSEMBLER_MAX_BYTES = 1048576;
|
|
@@ -23770,6 +24462,8 @@ class LogicalAgentSession {
|
|
|
23770
24462
|
toolBoundaryFlushDisabled = false;
|
|
23771
24463
|
safeBoundaryFlush;
|
|
23772
24464
|
safeBoundaryDelivery;
|
|
24465
|
+
settingsUpdateTail = Promise.resolve();
|
|
24466
|
+
settingsUpdatePending = false;
|
|
23773
24467
|
turnAdmission;
|
|
23774
24468
|
instructionsMaterialized = false;
|
|
23775
24469
|
lifecycleGeneration = 0;
|
|
@@ -23825,6 +24519,35 @@ class LogicalAgentSession {
|
|
|
23825
24519
|
send(message2) {
|
|
23826
24520
|
return this.admit("send", message2);
|
|
23827
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
|
+
}
|
|
23828
24551
|
async interrupt(input) {
|
|
23829
24552
|
if (this.state === "closed" || this.state === "stopping" || this.finishing)
|
|
23830
24553
|
return { status: "closed" };
|
|
@@ -23986,7 +24709,7 @@ class LogicalAgentSession {
|
|
|
23986
24709
|
}
|
|
23987
24710
|
return receipt;
|
|
23988
24711
|
}
|
|
23989
|
-
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)) {
|
|
23990
24713
|
return this.queue(message2, "runtime_busy");
|
|
23991
24714
|
}
|
|
23992
24715
|
return this.startTurn([message2], "prompt");
|
|
@@ -24294,11 +25017,10 @@ class LogicalAgentSession {
|
|
|
24294
25017
|
}
|
|
24295
25018
|
return;
|
|
24296
25019
|
case "telemetry": {
|
|
24297
|
-
const details = jsonValue(event.attrs);
|
|
24298
25020
|
if (event.name === "token_usage") {
|
|
24299
|
-
this.emit({ type: "token_usage", turnId, source: event.source, usage:
|
|
25021
|
+
this.emit({ type: "token_usage", turnId, source: event.source, usage: event.usage });
|
|
24300
25022
|
} else {
|
|
24301
|
-
this.emit({ type: "rate_limits", turnId, source: event.source,
|
|
25023
|
+
this.emit({ type: "rate_limits", turnId, source: event.source, quota: event.quota });
|
|
24302
25024
|
}
|
|
24303
25025
|
return;
|
|
24304
25026
|
}
|
|
@@ -24399,7 +25121,7 @@ class LogicalAgentSession {
|
|
|
24399
25121
|
if (this.adapter.execution.lifetime === "turn") {
|
|
24400
25122
|
this.processTurnEnded = true;
|
|
24401
25123
|
} else {
|
|
24402
|
-
Promise.resolve().then(() => this.safeBoundaryFlush).then(() => this.startNextQueued());
|
|
25124
|
+
Promise.resolve().then(() => this.safeBoundaryFlush).then(() => this.settingsUpdateTail).then(() => this.startNextQueued());
|
|
24403
25125
|
}
|
|
24404
25126
|
}
|
|
24405
25127
|
flushSafeBoundaryQueue() {
|
|
@@ -24899,8 +25621,14 @@ function createAgentDriverSdkWithRegistry(options) {
|
|
|
24899
25621
|
assertAdapterCompatibility(String(registration.id), registration.capabilities, adapter);
|
|
24900
25622
|
const command = capabilities2.commandOverride ? input.command : undefined;
|
|
24901
25623
|
const result = await adapter.probe(command);
|
|
24902
|
-
if (result.status === "healthy")
|
|
24903
|
-
return {
|
|
25624
|
+
if (result.status === "healthy") {
|
|
25625
|
+
return {
|
|
25626
|
+
status: "healthy",
|
|
25627
|
+
version: result.version,
|
|
25628
|
+
capabilities: capabilities2,
|
|
25629
|
+
reasoning: result.reasoning
|
|
25630
|
+
};
|
|
25631
|
+
}
|
|
24904
25632
|
return {
|
|
24905
25633
|
status: "unhealthy",
|
|
24906
25634
|
error: {
|
|
@@ -24909,7 +25637,8 @@ function createAgentDriverSdkWithRegistry(options) {
|
|
|
24909
25637
|
message: `Backend ${input.backend} is unavailable`,
|
|
24910
25638
|
retryable: true
|
|
24911
25639
|
},
|
|
24912
|
-
capabilities: capabilities2
|
|
25640
|
+
capabilities: capabilities2,
|
|
25641
|
+
reasoning: result.reasoning
|
|
24913
25642
|
};
|
|
24914
25643
|
} catch (error51) {
|
|
24915
25644
|
const contractInvalid = error51 instanceof Error && (error51.message.startsWith("Adapter ") || error51.message.startsWith("Agent backend registration "));
|
|
@@ -25061,7 +25790,12 @@ async function detectRuntimes() {
|
|
|
25061
25790
|
const driver = getDriver(id);
|
|
25062
25791
|
const probe = await driver.probe();
|
|
25063
25792
|
if (probe.status === "healthy") {
|
|
25064
|
-
results.push({
|
|
25793
|
+
results.push({
|
|
25794
|
+
id,
|
|
25795
|
+
status: "healthy",
|
|
25796
|
+
version: probe.version,
|
|
25797
|
+
reasoning: probe.reasoning
|
|
25798
|
+
});
|
|
25065
25799
|
} else {
|
|
25066
25800
|
results.push({
|
|
25067
25801
|
id,
|
|
@@ -25177,7 +25911,7 @@ import * as path12 from "node:path";
|
|
|
25177
25911
|
import { WebSocket } from "ws";
|
|
25178
25912
|
|
|
25179
25913
|
// src/daemon/createDaemon.ts
|
|
25180
|
-
import { homedir as
|
|
25914
|
+
import { homedir as homedir5 } from "os";
|
|
25181
25915
|
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8 } from "node:fs";
|
|
25182
25916
|
|
|
25183
25917
|
// src/util/rotatingFileSink.ts
|
|
@@ -25865,23 +26599,43 @@ class WsControlChannel {
|
|
|
25865
26599
|
this.ws.send(JSON.stringify(frame));
|
|
25866
26600
|
}
|
|
25867
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
|
+
};
|
|
25868
26613
|
if (this.resyncProvider) {
|
|
25869
|
-
const
|
|
25870
|
-
this.
|
|
25871
|
-
|
|
25872
|
-
|
|
25873
|
-
|
|
25874
|
-
|
|
25875
|
-
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
|
+
}
|
|
25876
26620
|
for (const frame of this.pendingBotAuditEvents.values())
|
|
25877
26621
|
this.sendFrame(frame);
|
|
25878
26622
|
this.scheduleAuditRetry();
|
|
25879
|
-
|
|
25880
|
-
|
|
25881
|
-
|
|
25882
|
-
|
|
25883
|
-
|
|
25884
|
-
|
|
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
|
+
}
|
|
25885
26639
|
}
|
|
25886
26640
|
for (const hook of this.resyncHooks) {
|
|
25887
26641
|
try {
|
|
@@ -26687,6 +27441,29 @@ function reduceManager(state, event) {
|
|
|
26687
27441
|
a.inbox = [...a.inbox, event.message];
|
|
26688
27442
|
a.idleSince = null;
|
|
26689
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
|
+
}
|
|
26690
27467
|
case "turn_started": {
|
|
26691
27468
|
const existing = state.agents[event.agentId];
|
|
26692
27469
|
if (!existing || existing.execution.sessionInstanceId !== event.sessionInstanceId)
|
|
@@ -26894,7 +27671,7 @@ function onTurnCompleted(state, agentId, sessionInstanceId, nowMs, turnId, endRe
|
|
|
26894
27671
|
agent2.stalledSessionId = null;
|
|
26895
27672
|
syncExecutionProjection(agent2);
|
|
26896
27673
|
const clearEffects = clearedStallSessionId === null ? [] : [{ type: "clear_stall_recovery", agentId, sessionId: clearedStallSessionId }];
|
|
26897
|
-
if (agent2.inbox.length > 0) {
|
|
27674
|
+
if (agent2.inbox.length > 0 && !agent2.resetting) {
|
|
26898
27675
|
const messages = drainInbox(agent2);
|
|
26899
27676
|
return commit(state, agent2, [
|
|
26900
27677
|
...clearEffects,
|
|
@@ -27154,6 +27931,144 @@ function toAgentBackendSelection(config2) {
|
|
|
27154
27931
|
function runtimeModelName(config2) {
|
|
27155
27932
|
return config2?.model.kind === "default" ? undefined : config2?.model.name;
|
|
27156
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
|
+
}
|
|
27157
28072
|
// src/runtime/errorDiagnostics.ts
|
|
27158
28073
|
function scrubRuntimeErrorDiagnosticText(value) {
|
|
27159
28074
|
return scrubDriverErrorMessage(value);
|
|
@@ -27749,9 +28664,13 @@ class AgentProcessManager {
|
|
|
27749
28664
|
state;
|
|
27750
28665
|
sessions = new Map;
|
|
27751
28666
|
runtimeConfigs = new Map;
|
|
28667
|
+
appliedRuntimeConfigs = new Map;
|
|
28668
|
+
pendingRuntimeConfigUpdates = new Map;
|
|
28669
|
+
runtimeConfigApplyRunning = new Set;
|
|
27752
28670
|
resumeSessions = new Map;
|
|
27753
28671
|
launchIds = new Map;
|
|
27754
28672
|
liveSessions = new Map;
|
|
28673
|
+
liveBackendIds = new Map;
|
|
27755
28674
|
activeSpawnState = new Map;
|
|
27756
28675
|
publishedAgentActivity = new Map;
|
|
27757
28676
|
traceProcessNonce = randomUUID5();
|
|
@@ -27780,19 +28699,156 @@ class AgentProcessManager {
|
|
|
27780
28699
|
this.state = createInitialManagerState(this.opts.staleThresholdMs, this.opts.idleTimeoutMs, this.opts.resetStuckThresholdMs, this.opts.stoppingStuckThresholdMs, this.opts.idleResetTimeoutMs);
|
|
27781
28700
|
}
|
|
27782
28701
|
register(agentId, launch) {
|
|
27783
|
-
|
|
27784
|
-
this.runtimeConfigs.set(agentId, launch.runtimeConfig);
|
|
28702
|
+
const runtimeConfigAcceptance = launch?.runtimeConfig ? this.acceptRuntimeConfig(agentId, launch.runtimeConfig) : undefined;
|
|
27785
28703
|
if (launch?.sessionId)
|
|
27786
28704
|
this.resumeSessions.set(agentId, launch.sessionId);
|
|
27787
28705
|
if (launch?.launchId)
|
|
27788
28706
|
this.launchIds.set(agentId, launch.launchId);
|
|
27789
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);
|
|
27790
28838
|
}
|
|
27791
28839
|
deliver(agentId, message2) {
|
|
27792
28840
|
const normalized = message2.id ? message2 : {
|
|
27793
28841
|
...message2,
|
|
27794
28842
|
id: message2.seq !== undefined ? `${agentId}:source:${message2.seq}` : `${agentId}:synthetic:${this.nextDeliveryOrdinal++}`
|
|
27795
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
|
+
}
|
|
27796
28852
|
const effects = this.dispatch({ type: "wake", agentId, message: normalized, nowMs: this.now() });
|
|
27797
28853
|
return effects.length > 0;
|
|
27798
28854
|
}
|
|
@@ -27836,7 +28892,11 @@ class AgentProcessManager {
|
|
|
27836
28892
|
this.emitErrorAudit(agentId, "reset", "resume_control_update_failed", "Reset aborted because resume control could not be persisted");
|
|
27837
28893
|
throw new Error("Reset aborted because resume control could not be persisted");
|
|
27838
28894
|
}
|
|
27839
|
-
this.register(agentId, {
|
|
28895
|
+
this.register(agentId, {
|
|
28896
|
+
runtimeConfig: opts.runtimeConfig,
|
|
28897
|
+
launchId: opts.launchId,
|
|
28898
|
+
applyRuntimeConfig: false
|
|
28899
|
+
});
|
|
27840
28900
|
if (!opts.forgetSession)
|
|
27841
28901
|
this.opts.timeline?.fenceSession(agentId);
|
|
27842
28902
|
this.abortCurrentTurn(agentId, opts.abortCause);
|
|
@@ -27937,6 +28997,9 @@ class AgentProcessManager {
|
|
|
27937
28997
|
const agent2 = this.state.agents[agentId];
|
|
27938
28998
|
return agent2 ? this.deriveActivity(agent2) : null;
|
|
27939
28999
|
}
|
|
29000
|
+
agentBackendId(agentId) {
|
|
29001
|
+
return this.liveBackendIds.get(agentId) ?? null;
|
|
29002
|
+
}
|
|
27940
29003
|
statusProjection(nowMs) {
|
|
27941
29004
|
return Object.values(this.state.agents).map((a) => ({
|
|
27942
29005
|
agentId: a.agentId,
|
|
@@ -28462,6 +29525,7 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
28462
29525
|
throw new Error(`AgentProcessManager: spawn for ${agentId} has no command`);
|
|
28463
29526
|
const prompt = this.withFooter(first.text);
|
|
28464
29527
|
const driver = this.opts.driverFor(agentId, this.runtimeConfigs.get(agentId));
|
|
29528
|
+
this.liveBackendIds.set(agentId, driver.id);
|
|
28465
29529
|
const base = this.opts.baseContextFor(agentId);
|
|
28466
29530
|
const configuredRuntime = this.runtimeConfigs.get(agentId) ?? base.config?.runtimeConfig;
|
|
28467
29531
|
this.log.info("spawning agent", {
|
|
@@ -28582,7 +29646,10 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
28582
29646
|
if (state.session && this.sessions.get(agentId) === state.session)
|
|
28583
29647
|
this.sessions.delete(agentId);
|
|
28584
29648
|
this.liveSessions.delete(agentId);
|
|
29649
|
+
if (this.activeSpawnState.get(agentId) === state)
|
|
29650
|
+
this.liveBackendIds.delete(agentId);
|
|
28585
29651
|
if (this.activeSpawnState.get(agentId) === state) {
|
|
29652
|
+
this.appliedRuntimeConfigs.delete(agentId);
|
|
28586
29653
|
this.activeSpawnState.delete(agentId);
|
|
28587
29654
|
this.nonCleanEndMarker.delete(agentId);
|
|
28588
29655
|
}
|
|
@@ -28630,6 +29697,10 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
28630
29697
|
state.session = session2;
|
|
28631
29698
|
state.sessionInstanceId = session2.sessionInstanceId;
|
|
28632
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
|
+
}
|
|
28633
29704
|
this.dispatch({
|
|
28634
29705
|
type: "attach_session",
|
|
28635
29706
|
agentId,
|
|
@@ -28863,6 +29934,12 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
28863
29934
|
runtime: runtimeId
|
|
28864
29935
|
});
|
|
28865
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
|
+
}
|
|
28866
29943
|
if (event.type === "turn_started") {
|
|
28867
29944
|
const timelineTurnOwner = {
|
|
28868
29945
|
sessionInstanceId: event.sessionInstanceId,
|
|
@@ -28977,7 +30054,7 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
28977
30054
|
this.logSessionEnded(agentId, "turn_end");
|
|
28978
30055
|
const marker = this.nonCleanEndMarker.get(agentId);
|
|
28979
30056
|
this.nonCleanEndMarker.delete(agentId);
|
|
28980
|
-
|
|
30057
|
+
const completionEvent = marker !== undefined ? {
|
|
28981
30058
|
type: "turn_completed",
|
|
28982
30059
|
agentId,
|
|
28983
30060
|
sessionInstanceId: event.sessionInstanceId,
|
|
@@ -28992,7 +30069,26 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
28992
30069
|
sessionInstanceId: event.sessionInstanceId,
|
|
28993
30070
|
nowMs: this.now(),
|
|
28994
30071
|
turnId: event.turnId
|
|
28995
|
-
}
|
|
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);
|
|
28996
30092
|
}
|
|
28997
30093
|
}
|
|
28998
30094
|
}
|
|
@@ -29067,7 +30163,8 @@ class AgentRouter {
|
|
|
29067
30163
|
version: r.version,
|
|
29068
30164
|
status: r.status ?? "healthy",
|
|
29069
30165
|
lastError: r.lastError,
|
|
29070
|
-
lastErrorAt: r.lastErrorAt
|
|
30166
|
+
lastErrorAt: r.lastErrorAt,
|
|
30167
|
+
reasoning: r.reasoning
|
|
29071
30168
|
});
|
|
29072
30169
|
}
|
|
29073
30170
|
}
|
|
@@ -29076,7 +30173,7 @@ class AgentRouter {
|
|
|
29076
30173
|
this.opts.channel.onResync?.(() => ({
|
|
29077
30174
|
ready: this.buildReady(),
|
|
29078
30175
|
sessions: this.opts.manager.liveSessionReports(),
|
|
29079
|
-
activities: this.opts.manager.liveAgentActivities()
|
|
30176
|
+
activities: this.opts.resyncActivities ? this.opts.resyncActivities() : this.opts.manager.liveAgentActivities()
|
|
29080
30177
|
}));
|
|
29081
30178
|
await this.opts.channel.reportReady(this.buildReady());
|
|
29082
30179
|
}
|
|
@@ -29089,7 +30186,8 @@ class AgentRouter {
|
|
|
29089
30186
|
platform: this.opts.platform,
|
|
29090
30187
|
arch: this.opts.arch,
|
|
29091
30188
|
osRelease: this.opts.osRelease,
|
|
29092
|
-
daemonVersion: this.opts.daemonVersion
|
|
30189
|
+
daemonVersion: this.opts.daemonVersion,
|
|
30190
|
+
...this.opts.providerQuotas ? { providerQuotas: this.opts.providerQuotas() } : {}
|
|
29093
30191
|
};
|
|
29094
30192
|
}
|
|
29095
30193
|
healthyRuntimeIds() {
|
|
@@ -29311,6 +30409,27 @@ class AgentRouter {
|
|
|
29311
30409
|
rewakePrompt: MODEL_SWITCH_REWAKE_PROMPT
|
|
29312
30410
|
}));
|
|
29313
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
|
+
}
|
|
29314
30433
|
case "agent:stop":
|
|
29315
30434
|
this.log.info("agent:stop received", { agentId: cmd.agentId });
|
|
29316
30435
|
try {
|
|
@@ -29368,8 +30487,8 @@ function createTypingScopeTracker() {
|
|
|
29368
30487
|
}
|
|
29369
30488
|
// src/timeline/timeline.ts
|
|
29370
30489
|
import * as fs9 from "node:fs";
|
|
29371
|
-
import { createHash as createHash2, randomBytes as
|
|
29372
|
-
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";
|
|
29373
30492
|
|
|
29374
30493
|
// src/timeline/filelock.ts
|
|
29375
30494
|
import * as fs8 from "fs";
|
|
@@ -29712,7 +30831,7 @@ function scanTimelineFile(filePath) {
|
|
|
29712
30831
|
}
|
|
29713
30832
|
}
|
|
29714
30833
|
function atomicReplaceTimeline(filePath, lines) {
|
|
29715
|
-
const tempPath =
|
|
30834
|
+
const tempPath = join12(dirname5(filePath), `.${basename3(filePath)}.${process.pid}.${randomBytes6(12).toString("hex")}.tmp`);
|
|
29716
30835
|
let fd = null;
|
|
29717
30836
|
try {
|
|
29718
30837
|
fd = fs9.openSync(tempPath, "wx", 384);
|
|
@@ -29796,14 +30915,14 @@ function readRecentEntries(timelineDir, opts = {}) {
|
|
|
29796
30915
|
const filenames = recentFilenames(maxDays, now).reverse();
|
|
29797
30916
|
const entries = [];
|
|
29798
30917
|
for (const filename of filenames) {
|
|
29799
|
-
entries.push(...readJsonl(
|
|
30918
|
+
entries.push(...readJsonl(join12(timelineDir, filename)));
|
|
29800
30919
|
}
|
|
29801
30920
|
return entries;
|
|
29802
30921
|
}
|
|
29803
30922
|
function readResumeControlState(timelineDir) {
|
|
29804
30923
|
if (timelineDirectoryState(timelineDir) !== "safe")
|
|
29805
30924
|
return { kind: "missing" };
|
|
29806
|
-
const filePath =
|
|
30925
|
+
const filePath = join12(timelineDir, RESUME_CONTROL_FILENAME);
|
|
29807
30926
|
let source;
|
|
29808
30927
|
try {
|
|
29809
30928
|
source = fs9.lstatSync(filePath);
|
|
@@ -29879,8 +30998,8 @@ function updateResumeControlState(timelineDir, update) {
|
|
|
29879
30998
|
`;
|
|
29880
30999
|
if (Buffer.byteLength(body, "utf8") > RESUME_CONTROL_MAX_BYTES)
|
|
29881
31000
|
return false;
|
|
29882
|
-
const filePath =
|
|
29883
|
-
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`);
|
|
29884
31003
|
let fd = null;
|
|
29885
31004
|
try {
|
|
29886
31005
|
fd = fs9.openSync(tempPath, "wx", 384);
|
|
@@ -29910,7 +31029,7 @@ function appendTrackedEntry(timelineDir, entry, now = new Date) {
|
|
|
29910
31029
|
if (timelineDirectoryState(timelineDir) !== "safe")
|
|
29911
31030
|
return { status: "rejected", reason: "unsafe" };
|
|
29912
31031
|
const filename = filenameForDate(now);
|
|
29913
|
-
const filePath =
|
|
31032
|
+
const filePath = join12(timelineDir, filename);
|
|
29914
31033
|
const lockPath = lockPathFor(timelineDir, filename);
|
|
29915
31034
|
try {
|
|
29916
31035
|
if (!acquireLock(lockPath))
|
|
@@ -29938,7 +31057,7 @@ function updateTrackedEntry(timelineDir, handle, update) {
|
|
|
29938
31057
|
if (!DATE_FILENAME_PATTERN.test(handle.filename) || basename3(handle.filename) !== handle.filename) {
|
|
29939
31058
|
return { status: "rejected", reason: "unsafe" };
|
|
29940
31059
|
}
|
|
29941
|
-
const filePath =
|
|
31060
|
+
const filePath = join12(timelineDir, handle.filename);
|
|
29942
31061
|
const lockPath = lockPathFor(timelineDir, handle.filename);
|
|
29943
31062
|
try {
|
|
29944
31063
|
if (!acquireLock(lockPath))
|
|
@@ -29997,10 +31116,10 @@ async function sweepTimelineHistory(workingDirectoryBase, opts = {}) {
|
|
|
29997
31116
|
return;
|
|
29998
31117
|
}
|
|
29999
31118
|
for (const agentName of agentNames) {
|
|
30000
|
-
const agentDir =
|
|
31119
|
+
const agentDir = join12(workingDirectoryBase, agentName);
|
|
30001
31120
|
if (!isRealDirectory(agentDir))
|
|
30002
31121
|
continue;
|
|
30003
|
-
const timelineDir =
|
|
31122
|
+
const timelineDir = join12(agentDir, ".context_timeline");
|
|
30004
31123
|
if (!isRealDirectory(timelineDir))
|
|
30005
31124
|
continue;
|
|
30006
31125
|
let filenames;
|
|
@@ -30010,7 +31129,7 @@ async function sweepTimelineHistory(workingDirectoryBase, opts = {}) {
|
|
|
30010
31129
|
continue;
|
|
30011
31130
|
}
|
|
30012
31131
|
for (const filename of filenames) {
|
|
30013
|
-
const filePath =
|
|
31132
|
+
const filePath = join12(timelineDir, filename);
|
|
30014
31133
|
let source;
|
|
30015
31134
|
try {
|
|
30016
31135
|
source = fs9.lstatSync(filePath);
|
|
@@ -30754,8 +31873,8 @@ class MessageReminderScheduler {
|
|
|
30754
31873
|
|
|
30755
31874
|
// src/manager/agentDriverHost.ts
|
|
30756
31875
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
30757
|
-
import { homedir as
|
|
30758
|
-
import { join as
|
|
31876
|
+
import { homedir as homedir4 } from "node:os";
|
|
31877
|
+
import { join as join13 } from "node:path";
|
|
30759
31878
|
|
|
30760
31879
|
// src/drivers/gitIdentityEnv.ts
|
|
30761
31880
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
@@ -30880,7 +31999,7 @@ function createDaemonAgentDriverHost(ctx, onRawLine) {
|
|
|
30880
31999
|
hostUser: readHostGitIdentity() ?? undefined
|
|
30881
32000
|
}),
|
|
30882
32001
|
platformProtected: {
|
|
30883
|
-
ALOOK_HOME: process.env.ALOOK_HOME ??
|
|
32002
|
+
ALOOK_HOME: process.env.ALOOK_HOME ?? join13(homedir4(), ".alook"),
|
|
30884
32003
|
ALOOK_ID: ctx.agentId,
|
|
30885
32004
|
ALOOK_CLI: ctx.agentCliPath,
|
|
30886
32005
|
ALOOK_SERVER_URL: ctx.config.serverUrl,
|
|
@@ -30985,6 +32104,182 @@ class DaemonSelfSleepScheduler {
|
|
|
30985
32104
|
}
|
|
30986
32105
|
}
|
|
30987
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
|
+
}
|
|
30988
32283
|
// src/daemon/createDaemon.ts
|
|
30989
32284
|
var WARMUP_BACKOFF_MS = [250, 500, 1000, 2000, 4000];
|
|
30990
32285
|
var WARMUP_CEILING_MS = 30000;
|
|
@@ -31122,9 +32417,25 @@ function createBuiltinDaemonSessionFactory(onRuntimeRawLine) {
|
|
|
31122
32417
|
}
|
|
31123
32418
|
async function createDaemon(opts) {
|
|
31124
32419
|
const log2 = opts.logger ?? createLogger2({ header: "@alook/daemon" });
|
|
31125
|
-
const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${
|
|
32420
|
+
const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir5()}/.alook`) + "/daemon";
|
|
31126
32421
|
const workingDirectoryBase = opts.workingDirectoryBase ?? fallbackBase;
|
|
31127
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
|
+
};
|
|
31128
32439
|
sweepTimelineHistory(workingDirectoryBase).catch(() => {
|
|
31129
32440
|
log2.warn("timeline startup sweep failed");
|
|
31130
32441
|
});
|
|
@@ -31140,6 +32451,27 @@ async function createDaemon(opts) {
|
|
|
31140
32451
|
});
|
|
31141
32452
|
let channelRef = null;
|
|
31142
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
|
+
};
|
|
31143
32475
|
let reminderSchedulerRef = null;
|
|
31144
32476
|
const selfSleepScheduler = opts.onSelfSleep ? new DaemonSelfSleepScheduler({
|
|
31145
32477
|
onSleep: opts.onSelfSleep,
|
|
@@ -31204,7 +32536,7 @@ async function createDaemon(opts) {
|
|
|
31204
32536
|
function reassertAgentActivity(agentId) {
|
|
31205
32537
|
const state = managerRef?.agentActivity(agentId);
|
|
31206
32538
|
if (state)
|
|
31207
|
-
|
|
32539
|
+
reportAgentActivity({ agentId, state });
|
|
31208
32540
|
}
|
|
31209
32541
|
function startTypingHeartbeat(agentId) {
|
|
31210
32542
|
stopTypingHeartbeat(agentId);
|
|
@@ -31348,6 +32680,20 @@ async function createDaemon(opts) {
|
|
|
31348
32680
|
logger: log2.child("ws")
|
|
31349
32681
|
});
|
|
31350
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
|
+
};
|
|
31351
32697
|
function restorePendingIdleResetEvents(agentId) {
|
|
31352
32698
|
for (const pending of timeline2.pendingIdleResetEvents(agentId)) {
|
|
31353
32699
|
channel2.restorePendingBotAuditEvent({
|
|
@@ -31466,7 +32812,7 @@ async function createDaemon(opts) {
|
|
|
31466
32812
|
onAgentSession: (info) => void channel2.reportAgentSession(info),
|
|
31467
32813
|
onAgentActivity: (info) => {
|
|
31468
32814
|
selfSleepScheduler?.observeAgentActivity(info.agentId, info.state === "running");
|
|
31469
|
-
|
|
32815
|
+
reportAgentActivity(info);
|
|
31470
32816
|
if (info.state === "starting" || info.state === "running") {
|
|
31471
32817
|
if (!typingHeartbeats.has(info.agentId)) {
|
|
31472
32818
|
startTypingHeartbeat(info.agentId);
|
|
@@ -31475,6 +32821,16 @@ async function createDaemon(opts) {
|
|
|
31475
32821
|
emitTypingStopsAndClear(info.agentId);
|
|
31476
32822
|
}
|
|
31477
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
|
+
},
|
|
31478
32834
|
onBotAuditEvent: (agentId, event, context) => emitBotAuditEvent(agentId, event, context),
|
|
31479
32835
|
onAgentLocallyStopped: (info) => router?.markLocallyStopped(info.agentId),
|
|
31480
32836
|
onRuntimeRawLine,
|
|
@@ -31521,6 +32877,11 @@ async function createDaemon(opts) {
|
|
|
31521
32877
|
arch: opts.arch,
|
|
31522
32878
|
osRelease: opts.osRelease,
|
|
31523
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
|
+
},
|
|
31524
32885
|
typingTracker,
|
|
31525
32886
|
logger: log2.child("router"),
|
|
31526
32887
|
onBeforeAgent: async (agentId) => {
|
|
@@ -31536,6 +32897,10 @@ async function createDaemon(opts) {
|
|
|
31536
32897
|
await enrollAgent(agentId);
|
|
31537
32898
|
}
|
|
31538
32899
|
});
|
|
32900
|
+
requestReadyQuotaResend = () => {
|
|
32901
|
+
if (router)
|
|
32902
|
+
channel2.sendReady?.(router.buildReady());
|
|
32903
|
+
};
|
|
31539
32904
|
channel2.onCommand(createSelfUpdateCommandListener(opts.handleSelfUpdate));
|
|
31540
32905
|
channel2.onCommand(createDiagnosticsCommandListener({
|
|
31541
32906
|
handleDiagnosticCommand: opts.handleDiagnosticCommand,
|
|
@@ -31565,6 +32930,11 @@ async function createDaemon(opts) {
|
|
|
31565
32930
|
resyncPendingWakes();
|
|
31566
32931
|
resyncPendingDiagnostics();
|
|
31567
32932
|
});
|
|
32933
|
+
if (opts.runtimeReport.some((runtime) => runtime.id === "claude")) {
|
|
32934
|
+
const observed = await providerQuotaReader("claude");
|
|
32935
|
+
if (observed)
|
|
32936
|
+
recordProviderQuota("claude", observed);
|
|
32937
|
+
}
|
|
31568
32938
|
channel2.connect();
|
|
31569
32939
|
await router.start();
|
|
31570
32940
|
selfSleepScheduler?.start();
|
|
@@ -32375,7 +33745,7 @@ async function buildDiagnosticBundle(args) {
|
|
|
32375
33745
|
};
|
|
32376
33746
|
}
|
|
32377
33747
|
// src/diagnostics/coordinator.ts
|
|
32378
|
-
import { createHash as createHash4, randomBytes as
|
|
33748
|
+
import { createHash as createHash4, randomBytes as randomBytes7 } from "node:crypto";
|
|
32379
33749
|
import {
|
|
32380
33750
|
chmodSync as chmodSync2,
|
|
32381
33751
|
closeSync as closeSync4,
|
|
@@ -32391,7 +33761,7 @@ import {
|
|
|
32391
33761
|
unlinkSync as unlinkSync6,
|
|
32392
33762
|
writeSync
|
|
32393
33763
|
} from "node:fs";
|
|
32394
|
-
import { join as
|
|
33764
|
+
import { join as join15 } from "node:path";
|
|
32395
33765
|
class CoordinatorError extends Error {
|
|
32396
33766
|
code;
|
|
32397
33767
|
constructor(code) {
|
|
@@ -32401,7 +33771,7 @@ class CoordinatorError extends Error {
|
|
|
32401
33771
|
}
|
|
32402
33772
|
function defaultFsOps() {
|
|
32403
33773
|
return {
|
|
32404
|
-
randomSuffix: () =>
|
|
33774
|
+
randomSuffix: () => randomBytes7(12).toString("hex"),
|
|
32405
33775
|
open: (path11, flags, mode) => openSync4(path11, flags, mode),
|
|
32406
33776
|
write: (fd, bytes) => {
|
|
32407
33777
|
writeSync(fd, bytes);
|
|
@@ -32458,15 +33828,15 @@ function commandFrom(sidecar) {
|
|
|
32458
33828
|
}
|
|
32459
33829
|
function createDiagnosticReportCoordinator(args) {
|
|
32460
33830
|
const fsOps = args.fsOps ?? defaultFsOps();
|
|
32461
|
-
const dir =
|
|
33831
|
+
const dir = join15(args.machineDir, "diagnostics");
|
|
32462
33832
|
let stopped = false;
|
|
32463
33833
|
let active = null;
|
|
32464
33834
|
const retryCancels = new Set;
|
|
32465
33835
|
const checkpoint = (point) => {
|
|
32466
33836
|
args.checkpoint?.(point);
|
|
32467
33837
|
};
|
|
32468
|
-
const archivePath = (reportId) =>
|
|
32469
|
-
const sidecarPath = (reportId) =>
|
|
33838
|
+
const archivePath = (reportId) => join15(dir, `report-${reportId}.ndjson.gz`);
|
|
33839
|
+
const sidecarPath = (reportId) => join15(dir, `report-${reportId}.json`);
|
|
32470
33840
|
const ensureDir = () => {
|
|
32471
33841
|
if (existsSync7(dir)) {
|
|
32472
33842
|
const stat = lstatSync5(dir);
|
|
@@ -32500,7 +33870,7 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
32500
33870
|
let temp = "";
|
|
32501
33871
|
let fd = null;
|
|
32502
33872
|
for (let attempt = 0;attempt < 32; attempt += 1) {
|
|
32503
|
-
temp =
|
|
33873
|
+
temp = join15(dir, `.${sidecar.reportId}.${sidecar.phase}.${fsOps.randomSuffix()}.tmp`);
|
|
32504
33874
|
try {
|
|
32505
33875
|
fd = fsOps.open(temp, "wx", 384);
|
|
32506
33876
|
break;
|
|
@@ -32617,7 +33987,7 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
32617
33987
|
return ready;
|
|
32618
33988
|
};
|
|
32619
33989
|
const buildAndCommit = async (command, collecting) => {
|
|
32620
|
-
const temp =
|
|
33990
|
+
const temp = join15(dir, `.${command.reportId}.archive.${fsOps.randomSuffix()}.tmp`);
|
|
32621
33991
|
const artifact2 = await args.buildBundle({ command, outputPath: temp });
|
|
32622
33992
|
checkpoint("archive_temp_written");
|
|
32623
33993
|
const fd = fsOps.open(artifact2.path, "r+");
|
|
@@ -33465,7 +34835,7 @@ var LEGACY_DAEMON_ID_PATTERN = /^[a-f0-9]{12}$/;
|
|
|
33465
34835
|
var DEFAULT_SERVER_URL = "https://alook.ai";
|
|
33466
34836
|
var DEFAULT_WS_URL = "wss://alook.ai/api/ws/community-daemon";
|
|
33467
34837
|
function resolveDefaultBaseDir() {
|
|
33468
|
-
const root = process.env.ALOOK_PROJECT_ROOT || path13.join(
|
|
34838
|
+
const root = process.env.ALOOK_PROJECT_ROOT || path13.join(homedir6(), ".alook");
|
|
33469
34839
|
return path13.join(root, "daemon");
|
|
33470
34840
|
}
|
|
33471
34841
|
var DEFAULT_BASE_DIR = resolveDefaultBaseDir();
|
|
@@ -34518,6 +35888,61 @@ async function armMessageReminderFromEnv(input, env = process.env, fetchImpl = f
|
|
|
34518
35888
|
return { armed: false, reason: "local reminder returned an invalid response" };
|
|
34519
35889
|
}
|
|
34520
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
|
+
|
|
34521
35946
|
// src/cli/index.ts
|
|
34522
35947
|
function messagesInLocalTime(messages) {
|
|
34523
35948
|
return messages.map((m) => ({ ...m, time: toLocalISO(m.time) }));
|
|
@@ -34724,7 +36149,7 @@ ${MESSAGE_SEND_STDIN_POLICY}`);
|
|
|
34724
36149
|
}
|
|
34725
36150
|
replyToSeq = n;
|
|
34726
36151
|
}
|
|
34727
|
-
const nonce =
|
|
36152
|
+
const nonce = randomUUID10();
|
|
34728
36153
|
const res = await sendWithRetry(api2, {
|
|
34729
36154
|
agentId: agent2,
|
|
34730
36155
|
channel: channel2,
|
|
@@ -34835,22 +36260,19 @@ async function cmdAttachmentUpload(opts) {
|
|
|
34835
36260
|
let height;
|
|
34836
36261
|
if (["image/png", "image/jpeg", "image/webp", "image/gif"].includes(contentType)) {
|
|
34837
36262
|
try {
|
|
34838
|
-
const
|
|
34839
|
-
|
|
34840
|
-
|
|
34841
|
-
if (
|
|
34842
|
-
width = metadata.width;
|
|
34843
|
-
height = metadata.height;
|
|
34844
|
-
}
|
|
34845
|
-
const jpeg = await image.resize({ width: 200, height: 200, fit: "inside", withoutEnlargement: true }).jpeg({ quality: 70 }).toBuffer();
|
|
34846
|
-
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) {
|
|
34847
36267
|
thumbnail = {
|
|
34848
|
-
data:
|
|
36268
|
+
data: prepared.thumbnail,
|
|
34849
36269
|
filename: "thumbnail.jpg",
|
|
34850
36270
|
contentType: "image/jpeg"
|
|
34851
36271
|
};
|
|
34852
36272
|
}
|
|
34853
|
-
} catch {
|
|
36273
|
+
} catch (error51) {
|
|
36274
|
+
throw new CliError(`message attachment upload: ${error51.message}`);
|
|
36275
|
+
}
|
|
34854
36276
|
}
|
|
34855
36277
|
const result = await api2.attachmentUpload({
|
|
34856
36278
|
agentId: agent2,
|