@alook/daemon 0.1.25 → 0.1.27
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 +766 -232
- package/dist/index.js +754 -220
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -16646,6 +16646,7 @@ var communityMachine = sqliteTable("community_machine", {
|
|
|
16646
16646
|
arch: text("arch").notNull().default(""),
|
|
16647
16647
|
osRelease: text("os_release").notNull().default(""),
|
|
16648
16648
|
daemonVersion: text("daemon_version").notNull().default(""),
|
|
16649
|
+
timeZone: text("time_zone"),
|
|
16649
16650
|
metadata: text("metadata"),
|
|
16650
16651
|
availableRuntimes: text("available_runtimes", { mode: "json" }).$type().notNull().default([]),
|
|
16651
16652
|
status: text("status").notNull().default("offline"),
|
|
@@ -17536,7 +17537,7 @@ var REASONING_EFFORT_RE = /^[A-Za-z0-9._-]+$/;
|
|
|
17536
17537
|
var COMMUNITY_REASONING_EFFORT_MAX = 32;
|
|
17537
17538
|
var COMMUNITY_REASONING_DESCRIPTION_MAX = 256;
|
|
17538
17539
|
var COMMUNITY_REASONING_OPTIONS_MAX = 16;
|
|
17539
|
-
var COMMUNITY_REASONING_MODELS_MAX =
|
|
17540
|
+
var COMMUNITY_REASONING_MODELS_MAX = 512;
|
|
17540
17541
|
var ReasoningEffortSchema = exports_external.string().min(1).max(COMMUNITY_REASONING_EFFORT_MAX).regex(REASONING_EFFORT_RE, "invalid reasoning effort charset");
|
|
17541
17542
|
var RuntimeReasoningOptionSchema = exports_external.object({
|
|
17542
17543
|
value: ReasoningEffortSchema,
|
|
@@ -17544,6 +17545,7 @@ var RuntimeReasoningOptionSchema = exports_external.object({
|
|
|
17544
17545
|
});
|
|
17545
17546
|
var RuntimeReasoningModelSchema = exports_external.object({
|
|
17546
17547
|
id: exports_external.string().min(1).max(100),
|
|
17548
|
+
displayName: exports_external.string().min(1).max(COMMUNITY_REASONING_DESCRIPTION_MAX).optional().catch(undefined),
|
|
17547
17549
|
supportedReasoningEfforts: exports_external.array(exports_external.unknown()).max(COMMUNITY_REASONING_OPTIONS_MAX).transform((options) => {
|
|
17548
17550
|
const seen = new Set;
|
|
17549
17551
|
return options.flatMap((candidate) => {
|
|
@@ -17638,6 +17640,7 @@ var HostReadyMessageSchema = exports_external.object({
|
|
|
17638
17640
|
arch: exports_external.string().optional(),
|
|
17639
17641
|
osRelease: exports_external.string().optional(),
|
|
17640
17642
|
daemonVersion: exports_external.string().optional(),
|
|
17643
|
+
timeZone: exports_external.string().min(1).max(128).optional(),
|
|
17641
17644
|
providerQuotas: exports_external.array(ProviderQuotaSnapshotSchema).max(2).optional().default([])
|
|
17642
17645
|
});
|
|
17643
17646
|
var CommunityDaemonReadySchema = exports_external.object({
|
|
@@ -17660,6 +17663,8 @@ var AgentActivityMessageSchema = exports_external.object({
|
|
|
17660
17663
|
type: exports_external.literal("agent_activity"),
|
|
17661
17664
|
agentId: exports_external.string(),
|
|
17662
17665
|
state: exports_external.enum(["idle", "starting", "running", "stopping"]),
|
|
17666
|
+
usageTimeZone: exports_external.string().min(1).max(128).optional(),
|
|
17667
|
+
usageDay: exports_external.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
|
17663
17668
|
dailyUsage: exports_external.array(DailyUsageSnapshotSchema).max(7).optional(),
|
|
17664
17669
|
quota: ProviderQuotaSnapshotSchema.optional()
|
|
17665
17670
|
});
|
|
@@ -17925,6 +17930,42 @@ var BotAuditEventAckFrameSchema = exports_external.strictObject({
|
|
|
17925
17930
|
type: exports_external.literal("bot_audit_event_ack"),
|
|
17926
17931
|
eventId: exports_external.string().min(1).max(128)
|
|
17927
17932
|
});
|
|
17933
|
+
// ../shared/src/utils/day-key.ts
|
|
17934
|
+
function utcDayKey(now) {
|
|
17935
|
+
const d = now instanceof Date ? now : new Date(now);
|
|
17936
|
+
return d.toISOString().slice(0, 10);
|
|
17937
|
+
}
|
|
17938
|
+
function calendarDayKeyDaysAgo(day, days) {
|
|
17939
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(day);
|
|
17940
|
+
if (!match)
|
|
17941
|
+
throw new RangeError("invalid calendar day key");
|
|
17942
|
+
const year = Number(match[1]);
|
|
17943
|
+
const month = Number(match[2]);
|
|
17944
|
+
const date5 = Number(match[3]);
|
|
17945
|
+
const parsed = new Date(Date.UTC(year, month - 1, date5));
|
|
17946
|
+
if (parsed.getUTCFullYear() !== year || parsed.getUTCMonth() !== month - 1 || parsed.getUTCDate() !== date5) {
|
|
17947
|
+
throw new RangeError("invalid calendar day key");
|
|
17948
|
+
}
|
|
17949
|
+
parsed.setUTCDate(parsed.getUTCDate() - days);
|
|
17950
|
+
return utcDayKey(parsed);
|
|
17951
|
+
}
|
|
17952
|
+
function dayKeyInTimeZone(now, timeZone) {
|
|
17953
|
+
const date5 = now instanceof Date ? now : new Date(now);
|
|
17954
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
17955
|
+
timeZone,
|
|
17956
|
+
year: "numeric",
|
|
17957
|
+
month: "2-digit",
|
|
17958
|
+
day: "2-digit"
|
|
17959
|
+
}).formatToParts(date5);
|
|
17960
|
+
const values = new Map(parts.map((part) => [part.type, part.value]));
|
|
17961
|
+
const year = values.get("year");
|
|
17962
|
+
const month = values.get("month");
|
|
17963
|
+
const day = values.get("day");
|
|
17964
|
+
if (!year || !month || !day)
|
|
17965
|
+
throw new RangeError("unable to format calendar day key");
|
|
17966
|
+
return `${year}-${month}-${day}`;
|
|
17967
|
+
}
|
|
17968
|
+
|
|
17928
17969
|
// ../shared/src/db/community-schema.ts
|
|
17929
17970
|
var exports_community_schema = {};
|
|
17930
17971
|
__export(exports_community_schema, {
|
|
@@ -20338,8 +20379,8 @@ function resolveLaunchFieldsOrDefault(input) {
|
|
|
20338
20379
|
const envVars = Object.fromEntries(Object.entries(normalized.environment ?? {}).filter(([key]) => !controlled.has(key)));
|
|
20339
20380
|
const providerEnv = {};
|
|
20340
20381
|
const model = normalized.model.kind === "default" ? undefined : normalized.model.name;
|
|
20341
|
-
if (
|
|
20342
|
-
providerEnv.ANTHROPIC_CUSTOM_MODEL_OPTION =
|
|
20382
|
+
if (model && normalized.provider?.kind === "custom_endpoint") {
|
|
20383
|
+
providerEnv.ANTHROPIC_CUSTOM_MODEL_OPTION = model;
|
|
20343
20384
|
}
|
|
20344
20385
|
if (normalized.provider?.kind === "custom_endpoint") {
|
|
20345
20386
|
providerEnv.ANTHROPIC_BASE_URL = normalized.provider.apiUrl;
|
|
@@ -20521,6 +20562,66 @@ function buildClaudeArgs(config2) {
|
|
|
20521
20562
|
return args;
|
|
20522
20563
|
}
|
|
20523
20564
|
|
|
20565
|
+
// agent-driver/dist/internal/token-usage.js
|
|
20566
|
+
function validIdentityPart(value) {
|
|
20567
|
+
return value.trim().length > 0 && Buffer.byteLength(value, "utf8") <= 512;
|
|
20568
|
+
}
|
|
20569
|
+
function identityKey(identity) {
|
|
20570
|
+
if (!validIdentityPart(identity.runtime) || !validIdentityPart(identity.backendSessionId) || !validIdentityPart(identity.providerRecordId))
|
|
20571
|
+
return null;
|
|
20572
|
+
return JSON.stringify([identity.runtime, identity.backendSessionId, identity.providerRecordId]);
|
|
20573
|
+
}
|
|
20574
|
+
function metric(value) {
|
|
20575
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
20576
|
+
}
|
|
20577
|
+
function cacheMetric(read, write) {
|
|
20578
|
+
const present = [read, write].filter((value) => value !== undefined);
|
|
20579
|
+
if (present.length === 0)
|
|
20580
|
+
return null;
|
|
20581
|
+
const metrics = present.map(metric);
|
|
20582
|
+
if (metrics.some((value) => value === null))
|
|
20583
|
+
return null;
|
|
20584
|
+
const total = metrics.reduce((sum, value) => sum + value, 0);
|
|
20585
|
+
return Number.isSafeInteger(total) ? total : null;
|
|
20586
|
+
}
|
|
20587
|
+
|
|
20588
|
+
class SettledUsageProjector {
|
|
20589
|
+
active = new Set;
|
|
20590
|
+
project(record2) {
|
|
20591
|
+
const key = identityKey(record2);
|
|
20592
|
+
if (!key || this.active.has(key))
|
|
20593
|
+
return null;
|
|
20594
|
+
this.active.add(key);
|
|
20595
|
+
const cache = cacheMetric(record2.cacheRead, record2.cacheWrite);
|
|
20596
|
+
const rawInput = metric(record2.input);
|
|
20597
|
+
const input = record2.inputIncludesCache ? rawInput !== null && cache !== null && cache <= rawInput ? rawInput - cache : null : rawInput;
|
|
20598
|
+
const rawOutput = metric(record2.output);
|
|
20599
|
+
const reasoning = metric(record2.reasoning);
|
|
20600
|
+
const output = record2.outputIncludesReasoning ? rawOutput : rawOutput !== null && reasoning !== null && Number.isSafeInteger(rawOutput + reasoning) ? rawOutput + reasoning : null;
|
|
20601
|
+
if (input === null && output === null && cache === null) {
|
|
20602
|
+
this.active.delete(key);
|
|
20603
|
+
return null;
|
|
20604
|
+
}
|
|
20605
|
+
return {
|
|
20606
|
+
kind: "telemetry",
|
|
20607
|
+
name: "token_usage",
|
|
20608
|
+
source: record2.source,
|
|
20609
|
+
usage: { input, output, cache }
|
|
20610
|
+
};
|
|
20611
|
+
}
|
|
20612
|
+
release(identity) {
|
|
20613
|
+
const key = identityKey(identity);
|
|
20614
|
+
if (key)
|
|
20615
|
+
this.active.delete(key);
|
|
20616
|
+
}
|
|
20617
|
+
reset() {
|
|
20618
|
+
this.active.clear();
|
|
20619
|
+
}
|
|
20620
|
+
get activeCount() {
|
|
20621
|
+
return this.active.size;
|
|
20622
|
+
}
|
|
20623
|
+
}
|
|
20624
|
+
|
|
20524
20625
|
// agent-driver/dist/internal/utils.js
|
|
20525
20626
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
20526
20627
|
function jsonRpcRequest(method, params, id) {
|
|
@@ -20540,9 +20641,13 @@ var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
|
|
|
20540
20641
|
class ClaudeEventNormalizer {
|
|
20541
20642
|
turnProtocol;
|
|
20542
20643
|
currentSession = null;
|
|
20644
|
+
usageProjector = new SettledUsageProjector;
|
|
20543
20645
|
constructor(turnProtocol) {
|
|
20544
20646
|
this.turnProtocol = turnProtocol;
|
|
20545
20647
|
}
|
|
20648
|
+
beginTurn() {
|
|
20649
|
+
this.usageProjector.reset();
|
|
20650
|
+
}
|
|
20546
20651
|
get currentSessionId() {
|
|
20547
20652
|
return this.currentSession;
|
|
20548
20653
|
}
|
|
@@ -20634,7 +20739,7 @@ class ClaudeEventNormalizer {
|
|
|
20634
20739
|
const turnOwner = rawOwner ? this.turnProtocol?.claimResult(rawOwner) ?? (this.turnProtocol ? null : `claude:${rawOwner}`) : null;
|
|
20635
20740
|
if (this.turnProtocol && !turnOwner)
|
|
20636
20741
|
return;
|
|
20637
|
-
const usage = this.buildUsageTelemetry(event);
|
|
20742
|
+
const usage = this.buildUsageTelemetry(event, rawOwner);
|
|
20638
20743
|
if (usage)
|
|
20639
20744
|
out.push(usage);
|
|
20640
20745
|
if (event.is_error || event.subtype === "error_during_execution") {
|
|
@@ -20649,23 +20754,26 @@ class ClaudeEventNormalizer {
|
|
|
20649
20754
|
acceptsTurnWork() {
|
|
20650
20755
|
return this.turnProtocol?.acceptsTurnWork() ?? true;
|
|
20651
20756
|
}
|
|
20652
|
-
buildUsageTelemetry(event) {
|
|
20757
|
+
buildUsageTelemetry(event, rootRequestId) {
|
|
20653
20758
|
const u = event?.usage;
|
|
20654
20759
|
if (!u)
|
|
20655
20760
|
return null;
|
|
20656
|
-
const
|
|
20657
|
-
|
|
20658
|
-
|
|
20659
|
-
|
|
20660
|
-
|
|
20661
|
-
|
|
20761
|
+
const backendSessionId = event.session_id ?? this.currentSession;
|
|
20762
|
+
if (typeof backendSessionId !== "string" || !backendSessionId)
|
|
20763
|
+
return null;
|
|
20764
|
+
const providerRecordId = rootRequestId ?? (typeof event.request_id === "string" ? event.request_id : "invocation-result");
|
|
20765
|
+
return this.usageProjector.project({
|
|
20766
|
+
runtime: "claude",
|
|
20767
|
+
backendSessionId,
|
|
20768
|
+
providerRecordId,
|
|
20662
20769
|
source: "claude_result_usage",
|
|
20663
|
-
|
|
20664
|
-
|
|
20665
|
-
|
|
20666
|
-
|
|
20667
|
-
|
|
20668
|
-
|
|
20770
|
+
input: u.input_tokens,
|
|
20771
|
+
output: u.output_tokens,
|
|
20772
|
+
cacheRead: u.cache_read_input_tokens,
|
|
20773
|
+
cacheWrite: u.cache_creation_input_tokens,
|
|
20774
|
+
inputIncludesCache: false,
|
|
20775
|
+
outputIncludesReasoning: true
|
|
20776
|
+
});
|
|
20669
20777
|
}
|
|
20670
20778
|
}
|
|
20671
20779
|
|
|
@@ -20674,6 +20782,7 @@ import { execFileSync as execFileSync2 } from "child_process";
|
|
|
20674
20782
|
import * as fs5 from "fs";
|
|
20675
20783
|
import * as path5 from "path";
|
|
20676
20784
|
var PROBE_TIMEOUT_MS = 5000;
|
|
20785
|
+
var PROBE_OUTPUT_MAX_BYTES = 1024 * 1024;
|
|
20677
20786
|
function resolveCommandOnPath(command, deps = {}) {
|
|
20678
20787
|
if (deps.which)
|
|
20679
20788
|
return deps.which(command);
|
|
@@ -20724,6 +20833,23 @@ function probeCommandVersion(command, args = [], deps = {}, platform = process.p
|
|
|
20724
20833
|
return { ok: false, error: String(code) };
|
|
20725
20834
|
}
|
|
20726
20835
|
}
|
|
20836
|
+
function probeCommandOutput(command, args, platform = process.platform) {
|
|
20837
|
+
try {
|
|
20838
|
+
const output = execFileSync2(command, args, {
|
|
20839
|
+
encoding: "utf8",
|
|
20840
|
+
timeout: PROBE_TIMEOUT_MS,
|
|
20841
|
+
maxBuffer: PROBE_OUTPUT_MAX_BYTES,
|
|
20842
|
+
shell: needsWindowsShimShell(command, platform),
|
|
20843
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
20844
|
+
input: "",
|
|
20845
|
+
env: { ...process.env, CI: "1" }
|
|
20846
|
+
});
|
|
20847
|
+
return { ok: true, output };
|
|
20848
|
+
} catch (err) {
|
|
20849
|
+
const code = err?.code ?? "command_probe_failed";
|
|
20850
|
+
return { ok: false, error: String(code) };
|
|
20851
|
+
}
|
|
20852
|
+
}
|
|
20727
20853
|
function resolveHomePath(relativePath, deps = {}) {
|
|
20728
20854
|
return path5.join(deps.homeDir || process.env.HOME || ".", relativePath);
|
|
20729
20855
|
}
|
|
@@ -20830,6 +20956,14 @@ class ClaudeTurnProtocol {
|
|
|
20830
20956
|
}
|
|
20831
20957
|
|
|
20832
20958
|
// agent-driver/dist/adapters/claude/index.js
|
|
20959
|
+
var CLAUDE_MODEL_CATALOG = {
|
|
20960
|
+
updateMode: "unsupported",
|
|
20961
|
+
models: ["opus", "sonnet", "haiku"].map((id) => ({
|
|
20962
|
+
id,
|
|
20963
|
+
supportedReasoningEfforts: []
|
|
20964
|
+
}))
|
|
20965
|
+
};
|
|
20966
|
+
|
|
20833
20967
|
class ClaudeDriver {
|
|
20834
20968
|
id = "claude";
|
|
20835
20969
|
instructionDelivery = { kind: "workspace_file", canonical: "AGENTS.md", aliases: ["CLAUDE.md"] };
|
|
@@ -20842,14 +20976,17 @@ class ClaudeDriver {
|
|
|
20842
20976
|
turnProtocol = new ClaudeTurnProtocol;
|
|
20843
20977
|
eventNormalizer = new ClaudeEventNormalizer(this.turnProtocol);
|
|
20844
20978
|
beginTurn() {
|
|
20845
|
-
|
|
20979
|
+
const receipt = this.turnProtocol.beginTurn();
|
|
20980
|
+
this.eventNormalizer.beginTurn();
|
|
20981
|
+
return receipt;
|
|
20846
20982
|
}
|
|
20847
20983
|
probe(command) {
|
|
20848
20984
|
const explicit = command?.trim();
|
|
20849
|
-
|
|
20850
|
-
|
|
20851
|
-
|
|
20852
|
-
|
|
20985
|
+
const base = explicit ? (() => {
|
|
20986
|
+
const result = probeCommandVersion(explicit);
|
|
20987
|
+
return result.ok ? { status: "healthy", version: result.version } : { status: "unhealthy", lastError: result.error };
|
|
20988
|
+
})() : probeClaude();
|
|
20989
|
+
return base.status === "healthy" ? { ...base, reasoning: CLAUDE_MODEL_CATALOG } : base;
|
|
20853
20990
|
}
|
|
20854
20991
|
async openLane(ctx, options) {
|
|
20855
20992
|
return createProcessLane(this, ctx, { onRawStdoutLine: options?.onRawStdoutLine });
|
|
@@ -20895,14 +21032,6 @@ class ClaudeDriver {
|
|
|
20895
21032
|
}
|
|
20896
21033
|
|
|
20897
21034
|
// agent-driver/dist/adapters/codex/telemetry.js
|
|
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
21035
|
function canonicalId(value, fallback) {
|
|
20907
21036
|
return typeof value === "string" && value.length > 0 && new TextEncoder().encode(value).length <= 64 ? value : fallback;
|
|
20908
21037
|
}
|
|
@@ -20996,28 +21125,24 @@ function mapCodexQuotaSnapshots(snapshots, sourceEpoch) {
|
|
|
20996
21125
|
}
|
|
20997
21126
|
};
|
|
20998
21127
|
}
|
|
20999
|
-
function
|
|
21000
|
-
|
|
21001
|
-
|
|
21002
|
-
|
|
21003
|
-
|
|
21004
|
-
|
|
21005
|
-
|
|
21006
|
-
|
|
21007
|
-
|
|
21008
|
-
|
|
21009
|
-
|
|
21010
|
-
|
|
21011
|
-
|
|
21012
|
-
|
|
21013
|
-
|
|
21014
|
-
|
|
21015
|
-
|
|
21016
|
-
}
|
|
21017
|
-
if (method === "account/rateLimits/updated") {
|
|
21018
|
-
return [mapCodexQuotaSnapshots([params?.rateLimits ?? params ?? {}], sourceEpoch)];
|
|
21019
|
-
}
|
|
21020
|
-
return [];
|
|
21128
|
+
function mapCodexSettledUsage(params, projector) {
|
|
21129
|
+
const backendSessionId = params?.threadId ?? params?.thread_id;
|
|
21130
|
+
const providerRecordId = params?.responseId ?? params?.response_id;
|
|
21131
|
+
const usage = params?.usage;
|
|
21132
|
+
if (typeof backendSessionId !== "string" || typeof providerRecordId !== "string" || !usage)
|
|
21133
|
+
return null;
|
|
21134
|
+
return projector.project({
|
|
21135
|
+
runtime: "codex",
|
|
21136
|
+
backendSessionId,
|
|
21137
|
+
providerRecordId,
|
|
21138
|
+
source: "codex_raw_response_completed",
|
|
21139
|
+
input: usage.inputTokens ?? usage.input_tokens,
|
|
21140
|
+
output: usage.outputTokens ?? usage.output_tokens,
|
|
21141
|
+
cacheRead: usage.cachedInputTokens ?? usage.cached_input_tokens,
|
|
21142
|
+
cacheWrite: usage.cacheWriteInputTokens ?? usage.cache_write_input_tokens,
|
|
21143
|
+
inputIncludesCache: true,
|
|
21144
|
+
outputIncludesReasoning: true
|
|
21145
|
+
});
|
|
21021
21146
|
}
|
|
21022
21147
|
|
|
21023
21148
|
// agent-driver/dist/adapters/codex/normalizer.js
|
|
@@ -21069,7 +21194,8 @@ class CodexEventNormalizer {
|
|
|
21069
21194
|
rateLimitSnapshots = new Map;
|
|
21070
21195
|
quotaSnapshotInitialized = false;
|
|
21071
21196
|
quotaSourceGeneration = codexQuotaSourceGeneration;
|
|
21072
|
-
|
|
21197
|
+
usageProjector = new SettledUsageProjector;
|
|
21198
|
+
usageRecordsBySessionAndTurn = new Map;
|
|
21073
21199
|
threadId = null;
|
|
21074
21200
|
turnId = null;
|
|
21075
21201
|
terminalTurn = null;
|
|
@@ -21142,7 +21268,8 @@ class CodexEventNormalizer {
|
|
|
21142
21268
|
if (threadId !== this.threadId) {
|
|
21143
21269
|
this.turnId = null;
|
|
21144
21270
|
this.terminalTurn = null;
|
|
21145
|
-
this.
|
|
21271
|
+
this.usageProjector.reset();
|
|
21272
|
+
this.usageRecordsBySessionAndTurn.clear();
|
|
21146
21273
|
}
|
|
21147
21274
|
this.threadId = threadId;
|
|
21148
21275
|
}
|
|
@@ -21191,6 +21318,22 @@ class CodexEventNormalizer {
|
|
|
21191
21318
|
}
|
|
21192
21319
|
handleNotification(method, params) {
|
|
21193
21320
|
const notificationThreadId = typeof params?.threadId === "string" ? params.threadId : null;
|
|
21321
|
+
if (method === "rawResponse/completed")
|
|
21322
|
+
return this.handleSettledUsage(params);
|
|
21323
|
+
if (method === "turn/completed" && notificationThreadId !== null && notificationThreadId !== this.threadId) {
|
|
21324
|
+
const turnId = this.notificationTurnId(params);
|
|
21325
|
+
if (turnId)
|
|
21326
|
+
this.releaseUsageForTurn(notificationThreadId, turnId);
|
|
21327
|
+
return [];
|
|
21328
|
+
}
|
|
21329
|
+
if (method === "item/completed" && notificationThreadId !== null && notificationThreadId !== this.threadId) {
|
|
21330
|
+
const turnId = this.notificationTurnId(params);
|
|
21331
|
+
const itemType = params?.item?.type ?? params?.type;
|
|
21332
|
+
if (turnId && itemType === "contextCompaction") {
|
|
21333
|
+
this.releaseUsageForTurn(notificationThreadId, turnId);
|
|
21334
|
+
}
|
|
21335
|
+
return [];
|
|
21336
|
+
}
|
|
21194
21337
|
if (this.threadId !== null && notificationThreadId !== null && notificationThreadId !== this.threadId)
|
|
21195
21338
|
return [];
|
|
21196
21339
|
if (this.isRootWorkNotification(method) && !this.acceptRootWork(params))
|
|
@@ -21203,7 +21346,6 @@ class CodexEventNormalizer {
|
|
|
21203
21346
|
return [];
|
|
21204
21347
|
this.turnId = params.turn.id;
|
|
21205
21348
|
this.terminalTurn = null;
|
|
21206
|
-
this.pendingTurnUsage = null;
|
|
21207
21349
|
return [
|
|
21208
21350
|
{
|
|
21209
21351
|
kind: "turn_owner",
|
|
@@ -21219,7 +21361,7 @@ class CodexEventNormalizer {
|
|
|
21219
21361
|
case "item/started":
|
|
21220
21362
|
return this.handleItemStarted(params);
|
|
21221
21363
|
case "item/completed":
|
|
21222
|
-
return this.
|
|
21364
|
+
return this.handleItemCompletedAndReleaseUsage(params);
|
|
21223
21365
|
case "rawResponseItem/completed":
|
|
21224
21366
|
return [{ kind: "internal_progress", source: "codex_raw_item", itemType: "rawResponseItem" }];
|
|
21225
21367
|
case "configWarning":
|
|
@@ -21232,30 +21374,24 @@ class CodexEventNormalizer {
|
|
|
21232
21374
|
case "turn/completed":
|
|
21233
21375
|
if (!this.acceptRootTerminal(params))
|
|
21234
21376
|
return [];
|
|
21235
|
-
|
|
21236
|
-
this.pendingTurnUsage = null;
|
|
21377
|
+
this.releaseUsageForTurn(params.threadId, params.turn.id);
|
|
21237
21378
|
if (params.turn.status === "failed") {
|
|
21238
21379
|
return [
|
|
21239
|
-
...usage ? [usage] : [],
|
|
21240
21380
|
{ kind: "error", message: "Codex turn failed" },
|
|
21241
21381
|
{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }
|
|
21242
21382
|
];
|
|
21243
21383
|
}
|
|
21244
21384
|
if (params.turn.status === "interrupted") {
|
|
21245
|
-
return [
|
|
21385
|
+
return [{ kind: "error", message: "Codex turn interrupted" }, { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
21246
21386
|
}
|
|
21247
|
-
return [
|
|
21387
|
+
return [{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
|
|
21248
21388
|
case "error":
|
|
21249
21389
|
if (params?.willRetry === true) {
|
|
21250
21390
|
return [{ kind: "runtime_recovery", stage: "retrying", source: "codex_stream" }];
|
|
21251
21391
|
}
|
|
21252
21392
|
return [{ kind: "error", message: params?.error?.message ?? params?.message ?? "Codex error" }];
|
|
21253
|
-
case "thread/tokenUsage/updated":
|
|
21254
|
-
const usage2 = mapCodexTelemetry(method, params, codexQuotaSourceEpoch)[0];
|
|
21255
|
-
if (usage2)
|
|
21256
|
-
this.pendingTurnUsage = usage2;
|
|
21393
|
+
case "thread/tokenUsage/updated":
|
|
21257
21394
|
return [];
|
|
21258
|
-
}
|
|
21259
21395
|
case "account/rateLimits/updated":
|
|
21260
21396
|
return this.mergeQuotaSnapshots(params);
|
|
21261
21397
|
case "account/updated":
|
|
@@ -21266,6 +21402,42 @@ class CodexEventNormalizer {
|
|
|
21266
21402
|
return [];
|
|
21267
21403
|
}
|
|
21268
21404
|
}
|
|
21405
|
+
handleSettledUsage(params) {
|
|
21406
|
+
const notificationTurnId = this.notificationTurnId(params);
|
|
21407
|
+
if (this.turnId === null && this.terminalTurn?.state === "closed" && notificationTurnId === this.terminalTurn.turnId && params?.threadId === this.terminalTurn.threadId)
|
|
21408
|
+
return [];
|
|
21409
|
+
const backendSessionId = params?.threadId ?? params?.thread_id;
|
|
21410
|
+
const providerRecordId = params?.responseId ?? params?.response_id;
|
|
21411
|
+
if (!notificationTurnId || typeof backendSessionId !== "string" || typeof providerRecordId !== "string")
|
|
21412
|
+
return [];
|
|
21413
|
+
const usage = mapCodexSettledUsage(params, this.usageProjector);
|
|
21414
|
+
if (!usage)
|
|
21415
|
+
return [];
|
|
21416
|
+
const recordsByTurn = this.usageRecordsBySessionAndTurn.get(backendSessionId) ?? new Map;
|
|
21417
|
+
const recordIds = recordsByTurn.get(notificationTurnId) ?? new Set;
|
|
21418
|
+
recordIds.add(providerRecordId);
|
|
21419
|
+
recordsByTurn.set(notificationTurnId, recordIds);
|
|
21420
|
+
this.usageRecordsBySessionAndTurn.set(backendSessionId, recordsByTurn);
|
|
21421
|
+
return [usage];
|
|
21422
|
+
}
|
|
21423
|
+
releaseUsageForTurn(backendSessionId, turnId) {
|
|
21424
|
+
const recordsByTurn = this.usageRecordsBySessionAndTurn.get(backendSessionId);
|
|
21425
|
+
for (const providerRecordId of recordsByTurn?.get(turnId) ?? []) {
|
|
21426
|
+
this.usageProjector.release({ runtime: "codex", backendSessionId, providerRecordId });
|
|
21427
|
+
}
|
|
21428
|
+
recordsByTurn?.delete(turnId);
|
|
21429
|
+
if (recordsByTurn?.size === 0)
|
|
21430
|
+
this.usageRecordsBySessionAndTurn.delete(backendSessionId);
|
|
21431
|
+
}
|
|
21432
|
+
handleItemCompletedAndReleaseUsage(params) {
|
|
21433
|
+
const events = this.handleItemCompleted(params);
|
|
21434
|
+
const turnId = this.notificationTurnId(params);
|
|
21435
|
+
const itemType = params?.item?.type ?? params?.type;
|
|
21436
|
+
if (turnId && itemType === "contextCompaction" && turnId !== this.turnId && typeof params?.threadId === "string") {
|
|
21437
|
+
this.releaseUsageForTurn(params.threadId, turnId);
|
|
21438
|
+
}
|
|
21439
|
+
return events;
|
|
21440
|
+
}
|
|
21269
21441
|
isRootWorkNotification(method) {
|
|
21270
21442
|
return method === "item/reasoning/textDelta" || method === "item/reasoning/summaryTextDelta" || method === "item/agentMessage/delta" || method === "item/started" || method === "item/completed" || method === "rawResponseItem/completed";
|
|
21271
21443
|
}
|
|
@@ -21416,10 +21588,59 @@ function stableErrorCode(value, fallback) {
|
|
|
21416
21588
|
return /^[A-Za-z0-9_.-]{1,100}$/.test(code) ? code : fallback;
|
|
21417
21589
|
}
|
|
21418
21590
|
|
|
21591
|
+
// agent-driver/dist/internal/modelCatalog.js
|
|
21592
|
+
var RUNTIME_MODEL_CATALOG_MAX = 512;
|
|
21593
|
+
var RUNTIME_MODEL_ID_MAX = 100;
|
|
21594
|
+
function normalizeRuntimeModelId(value) {
|
|
21595
|
+
if (typeof value !== "string")
|
|
21596
|
+
return;
|
|
21597
|
+
const id = value.trim();
|
|
21598
|
+
if (!id || id.length > RUNTIME_MODEL_ID_MAX || /\s/.test(id))
|
|
21599
|
+
return;
|
|
21600
|
+
return id;
|
|
21601
|
+
}
|
|
21602
|
+
function catalogFromIds(ids) {
|
|
21603
|
+
const seen = new Set;
|
|
21604
|
+
const models = [];
|
|
21605
|
+
for (const rawId of ids) {
|
|
21606
|
+
const id = normalizeRuntimeModelId(rawId);
|
|
21607
|
+
if (!id || seen.has(id))
|
|
21608
|
+
continue;
|
|
21609
|
+
if (models.length >= RUNTIME_MODEL_CATALOG_MAX)
|
|
21610
|
+
return;
|
|
21611
|
+
seen.add(id);
|
|
21612
|
+
models.push({ id, supportedReasoningEfforts: [] });
|
|
21613
|
+
}
|
|
21614
|
+
if (models.length === 0)
|
|
21615
|
+
return;
|
|
21616
|
+
return { updateMode: "unsupported", models };
|
|
21617
|
+
}
|
|
21618
|
+
function parseOpenCodeModelCatalog(output) {
|
|
21619
|
+
const ids = output.split(/\r?\n/).flatMap((line) => {
|
|
21620
|
+
const id = normalizeRuntimeModelId(line);
|
|
21621
|
+
return id && /^[^/]+\/.+$/.test(id) ? [id] : [];
|
|
21622
|
+
});
|
|
21623
|
+
return catalogFromIds(ids);
|
|
21624
|
+
}
|
|
21625
|
+
function parsePiModelCatalog(values) {
|
|
21626
|
+
if (!Array.isArray(values))
|
|
21627
|
+
return;
|
|
21628
|
+
const ids = values.flatMap((value) => {
|
|
21629
|
+
if (!value || typeof value !== "object")
|
|
21630
|
+
return [];
|
|
21631
|
+
const model = value;
|
|
21632
|
+
const provider = normalizeRuntimeModelId(model.provider);
|
|
21633
|
+
const id = normalizeRuntimeModelId(model.id);
|
|
21634
|
+
return provider && id && !provider.includes("/") ? [`${provider}/${id}`] : [];
|
|
21635
|
+
});
|
|
21636
|
+
return catalogFromIds(ids);
|
|
21637
|
+
}
|
|
21638
|
+
|
|
21419
21639
|
// agent-driver/dist/adapters/codex/index.js
|
|
21420
21640
|
var SETTINGS_UPDATE_TIMEOUT_MS = 5000;
|
|
21421
21641
|
var MODEL_LIST_TIMEOUT_MS = 5000;
|
|
21422
|
-
var
|
|
21642
|
+
var MODEL_LIST_OUTPUT_MAX_BYTES = 1024 * 1024;
|
|
21643
|
+
var MODEL_LIST_MAX = RUNTIME_MODEL_CATALOG_MAX;
|
|
21423
21644
|
var MODEL_EFFORT_MAX = 16;
|
|
21424
21645
|
function isCodexMissingRolloutError(message2) {
|
|
21425
21646
|
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);
|
|
@@ -21495,11 +21716,13 @@ class CodexDriver {
|
|
|
21495
21716
|
return new Promise((resolve2) => {
|
|
21496
21717
|
let settled = false;
|
|
21497
21718
|
let buffer = "";
|
|
21719
|
+
let outputBytes = 0;
|
|
21498
21720
|
let nextId = 0;
|
|
21499
21721
|
let initializeId = 0;
|
|
21500
21722
|
let listId = 0;
|
|
21501
21723
|
const models = [];
|
|
21502
21724
|
const seenModels = new Set;
|
|
21725
|
+
let overflow = false;
|
|
21503
21726
|
let defaultModelId;
|
|
21504
21727
|
const finish = (catalog) => {
|
|
21505
21728
|
if (settled)
|
|
@@ -21517,12 +21740,16 @@ class CodexDriver {
|
|
|
21517
21740
|
`);
|
|
21518
21741
|
};
|
|
21519
21742
|
const consumeModel = (value) => {
|
|
21520
|
-
if (!value || typeof value !== "object"
|
|
21743
|
+
if (!value || typeof value !== "object")
|
|
21521
21744
|
return;
|
|
21522
21745
|
const model = value;
|
|
21523
|
-
const id =
|
|
21524
|
-
if (!id ||
|
|
21746
|
+
const id = normalizeRuntimeModelId(model.id);
|
|
21747
|
+
if (!id || seenModels.has(id))
|
|
21748
|
+
return;
|
|
21749
|
+
if (models.length >= MODEL_LIST_MAX) {
|
|
21750
|
+
overflow = true;
|
|
21525
21751
|
return;
|
|
21752
|
+
}
|
|
21526
21753
|
const rawOptions = Array.isArray(model.supportedReasoningEfforts) ? model.supportedReasoningEfforts : [];
|
|
21527
21754
|
const seenEfforts = new Set;
|
|
21528
21755
|
const supportedReasoningEfforts = rawOptions.flatMap((raw) => {
|
|
@@ -21566,9 +21793,15 @@ class CodexDriver {
|
|
|
21566
21793
|
const result = message2.result;
|
|
21567
21794
|
for (const model of Array.isArray(result.data) ? result.data : [])
|
|
21568
21795
|
consumeModel(model);
|
|
21796
|
+
if (overflow)
|
|
21797
|
+
return finish();
|
|
21569
21798
|
const cursor = typeof result.nextCursor === "string" ? result.nextCursor : undefined;
|
|
21570
|
-
if (cursor && models.length
|
|
21799
|
+
if (cursor && models.length >= MODEL_LIST_MAX)
|
|
21800
|
+
return finish();
|
|
21801
|
+
if (cursor)
|
|
21571
21802
|
return requestModelPage(cursor);
|
|
21803
|
+
if (models.length === 0)
|
|
21804
|
+
return finish();
|
|
21572
21805
|
finish({
|
|
21573
21806
|
updateMode: "live_next_turn",
|
|
21574
21807
|
...defaultModelId ? { defaultModelId } : {},
|
|
@@ -21578,7 +21811,11 @@ class CodexDriver {
|
|
|
21578
21811
|
const timer = setTimeout(() => finish(), MODEL_LIST_TIMEOUT_MS);
|
|
21579
21812
|
timer.unref?.();
|
|
21580
21813
|
proc.stdout?.on("data", (chunk2) => {
|
|
21581
|
-
|
|
21814
|
+
const text2 = chunk2.toString();
|
|
21815
|
+
outputBytes += Buffer.byteLength(text2);
|
|
21816
|
+
if (outputBytes > MODEL_LIST_OUTPUT_MAX_BYTES)
|
|
21817
|
+
return finish();
|
|
21818
|
+
buffer += text2;
|
|
21582
21819
|
const lines = buffer.split(`
|
|
21583
21820
|
`);
|
|
21584
21821
|
buffer = lines.pop() ?? "";
|
|
@@ -21781,9 +22018,189 @@ class CodexDriver {
|
|
|
21781
22018
|
|
|
21782
22019
|
// agent-driver/dist/adapters/cursor/acp-lane.js
|
|
21783
22020
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
22021
|
+
|
|
22022
|
+
// agent-driver/dist/adapters/cursor/catalog-probe.js
|
|
21784
22023
|
var ACP_PROTOCOL_VERSION = 1;
|
|
21785
|
-
var HANDSHAKE_TIMEOUT_MS = 15000;
|
|
21786
22024
|
var AUTH_METHOD_ID = "cursor_login";
|
|
22025
|
+
var CATALOG_PROBE_TIMEOUT_MS = 15000;
|
|
22026
|
+
var CATALOG_PROBE_OUTPUT_MAX_BYTES = 1024 * 1024;
|
|
22027
|
+
var MODEL_DISPLAY_NAME_MAX = 256;
|
|
22028
|
+
var MODEL_OPTION_NESTING_MAX = 16;
|
|
22029
|
+
function record2(value) {
|
|
22030
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
22031
|
+
}
|
|
22032
|
+
function normalizeDisplayName(value) {
|
|
22033
|
+
if (typeof value !== "string")
|
|
22034
|
+
return;
|
|
22035
|
+
const displayName = value.trim();
|
|
22036
|
+
return displayName && displayName.length <= MODEL_DISPLAY_NAME_MAX ? displayName : undefined;
|
|
22037
|
+
}
|
|
22038
|
+
function flattenCursorAcpSelectOptions(value, depth = 0) {
|
|
22039
|
+
if (!Array.isArray(value) || depth > MODEL_OPTION_NESTING_MAX)
|
|
22040
|
+
return [];
|
|
22041
|
+
const options = [];
|
|
22042
|
+
for (const item of value) {
|
|
22043
|
+
if (Array.isArray(item)) {
|
|
22044
|
+
options.push(...flattenCursorAcpSelectOptions(item, depth + 1));
|
|
22045
|
+
continue;
|
|
22046
|
+
}
|
|
22047
|
+
const candidate = record2(item);
|
|
22048
|
+
if (!candidate)
|
|
22049
|
+
continue;
|
|
22050
|
+
const exactValue = normalizeRuntimeModelId(candidate.value);
|
|
22051
|
+
if (exactValue) {
|
|
22052
|
+
const name = normalizeDisplayName(candidate.name);
|
|
22053
|
+
options.push({ value: exactValue, ...name ? { name } : {} });
|
|
22054
|
+
}
|
|
22055
|
+
if (Array.isArray(candidate.options)) {
|
|
22056
|
+
options.push(...flattenCursorAcpSelectOptions(candidate.options, depth + 1));
|
|
22057
|
+
}
|
|
22058
|
+
}
|
|
22059
|
+
return options;
|
|
22060
|
+
}
|
|
22061
|
+
function parseCursorAcpModelCatalog(session2) {
|
|
22062
|
+
const payload = record2(session2);
|
|
22063
|
+
const configOptions = Array.isArray(payload?.configOptions) ? payload.configOptions : [];
|
|
22064
|
+
const modelConfig = configOptions.map(record2).find((option) => option?.id === "model") ?? null;
|
|
22065
|
+
if (!modelConfig)
|
|
22066
|
+
return;
|
|
22067
|
+
const seen = new Set;
|
|
22068
|
+
const models = [];
|
|
22069
|
+
for (const option of flattenCursorAcpSelectOptions(modelConfig.options)) {
|
|
22070
|
+
if (option.value === "default[]" || seen.has(option.value))
|
|
22071
|
+
continue;
|
|
22072
|
+
if (models.length >= RUNTIME_MODEL_CATALOG_MAX)
|
|
22073
|
+
return;
|
|
22074
|
+
seen.add(option.value);
|
|
22075
|
+
models.push({
|
|
22076
|
+
id: option.value,
|
|
22077
|
+
...option.name ? { displayName: option.name } : {},
|
|
22078
|
+
supportedReasoningEfforts: []
|
|
22079
|
+
});
|
|
22080
|
+
}
|
|
22081
|
+
return models.length > 0 ? { updateMode: "unsupported", models } : undefined;
|
|
22082
|
+
}
|
|
22083
|
+
async function cleanupProbeProcess(process3) {
|
|
22084
|
+
if (process3.pid) {
|
|
22085
|
+
await killProcessTree(process3.pid, { graceMs: 250 }).catch(() => {});
|
|
22086
|
+
return;
|
|
22087
|
+
}
|
|
22088
|
+
if (process3.exitCode === null && process3.signalCode === null)
|
|
22089
|
+
process3.kill("SIGTERM");
|
|
22090
|
+
}
|
|
22091
|
+
async function probeCursorAcpCatalog(command, options = {}) {
|
|
22092
|
+
const cwd = options.cwd ?? process.cwd();
|
|
22093
|
+
const spec = resolveSpawnSpec("cursor-agent", ["acp"], command);
|
|
22094
|
+
let processHandle;
|
|
22095
|
+
try {
|
|
22096
|
+
processHandle = (options.spawn ?? spawnAgentProcess)(spec.command, spec.args, {
|
|
22097
|
+
cwd,
|
|
22098
|
+
env: { ...process.env, CI: "1" },
|
|
22099
|
+
shell: spec.shell
|
|
22100
|
+
});
|
|
22101
|
+
} catch {
|
|
22102
|
+
return;
|
|
22103
|
+
}
|
|
22104
|
+
return new Promise((resolve2) => {
|
|
22105
|
+
let settled = false;
|
|
22106
|
+
let buffer = "";
|
|
22107
|
+
let outputBytes = 0;
|
|
22108
|
+
let requestId = 0;
|
|
22109
|
+
let expectedId = 0;
|
|
22110
|
+
let expectedMethod = "";
|
|
22111
|
+
const finish = (catalog) => {
|
|
22112
|
+
if (settled)
|
|
22113
|
+
return;
|
|
22114
|
+
settled = true;
|
|
22115
|
+
clearTimeout(timer);
|
|
22116
|
+
const cleanup = options.cleanup ?? cleanupProbeProcess;
|
|
22117
|
+
Promise.resolve().then(() => cleanup(processHandle)).catch(() => {}).finally(() => resolve2(catalog));
|
|
22118
|
+
};
|
|
22119
|
+
const request = (method, params) => {
|
|
22120
|
+
if (settled)
|
|
22121
|
+
return;
|
|
22122
|
+
const stdin = processHandle.stdin;
|
|
22123
|
+
if (!stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false)
|
|
22124
|
+
return finish();
|
|
22125
|
+
expectedId = ++requestId;
|
|
22126
|
+
expectedMethod = method;
|
|
22127
|
+
try {
|
|
22128
|
+
stdin.write(`${jsonRpcRequest(method, params, expectedId)}
|
|
22129
|
+
`);
|
|
22130
|
+
} catch {
|
|
22131
|
+
finish();
|
|
22132
|
+
}
|
|
22133
|
+
};
|
|
22134
|
+
const onLine = (line) => {
|
|
22135
|
+
const parsed = tryParseJsonLine(line);
|
|
22136
|
+
const message2 = record2(parsed);
|
|
22137
|
+
if (!message2)
|
|
22138
|
+
return finish();
|
|
22139
|
+
if (message2.id !== expectedId)
|
|
22140
|
+
return;
|
|
22141
|
+
if (message2.error !== undefined)
|
|
22142
|
+
return finish();
|
|
22143
|
+
if (!Object.prototype.hasOwnProperty.call(message2, "result"))
|
|
22144
|
+
return finish();
|
|
22145
|
+
if (expectedMethod === "authenticate") {
|
|
22146
|
+
request("session/new", { cwd, mcpServers: [] });
|
|
22147
|
+
return;
|
|
22148
|
+
}
|
|
22149
|
+
const result = record2(message2.result);
|
|
22150
|
+
if (!result)
|
|
22151
|
+
return finish();
|
|
22152
|
+
if (expectedMethod === "initialize") {
|
|
22153
|
+
const authMethods = Array.isArray(result.authMethods) ? result.authMethods : [];
|
|
22154
|
+
if (result.protocolVersion !== ACP_PROTOCOL_VERSION || !authMethods.some((method) => record2(method)?.id === AUTH_METHOD_ID))
|
|
22155
|
+
return finish();
|
|
22156
|
+
request("authenticate", { methodId: AUTH_METHOD_ID });
|
|
22157
|
+
return;
|
|
22158
|
+
}
|
|
22159
|
+
if (expectedMethod !== "session/new" || typeof result.sessionId !== "string" || !result.sessionId.trim())
|
|
22160
|
+
return finish();
|
|
22161
|
+
finish(parseCursorAcpModelCatalog(result));
|
|
22162
|
+
};
|
|
22163
|
+
const timer = setTimeout(() => finish(), options.timeoutMs ?? CATALOG_PROBE_TIMEOUT_MS);
|
|
22164
|
+
timer.unref?.();
|
|
22165
|
+
processHandle.stdout?.on("data", (chunk2) => {
|
|
22166
|
+
if (settled)
|
|
22167
|
+
return;
|
|
22168
|
+
const text2 = chunk2.toString();
|
|
22169
|
+
outputBytes += Buffer.byteLength(text2);
|
|
22170
|
+
if (outputBytes > (options.outputMaxBytes ?? CATALOG_PROBE_OUTPUT_MAX_BYTES))
|
|
22171
|
+
return finish();
|
|
22172
|
+
buffer += text2;
|
|
22173
|
+
const lines = buffer.split(`
|
|
22174
|
+
`);
|
|
22175
|
+
buffer = lines.pop() ?? "";
|
|
22176
|
+
for (const line of lines)
|
|
22177
|
+
if (line.trim())
|
|
22178
|
+
onLine(line);
|
|
22179
|
+
});
|
|
22180
|
+
processHandle.stderr?.on("data", (chunk2) => {
|
|
22181
|
+
if (settled)
|
|
22182
|
+
return;
|
|
22183
|
+
outputBytes += Buffer.byteLength(chunk2.toString());
|
|
22184
|
+
if (outputBytes > (options.outputMaxBytes ?? CATALOG_PROBE_OUTPUT_MAX_BYTES))
|
|
22185
|
+
finish();
|
|
22186
|
+
});
|
|
22187
|
+
processHandle.on("error", () => finish());
|
|
22188
|
+
processHandle.on("exit", () => finish());
|
|
22189
|
+
request("initialize", {
|
|
22190
|
+
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
22191
|
+
clientCapabilities: {
|
|
22192
|
+
fs: { readTextFile: false, writeTextFile: false },
|
|
22193
|
+
terminal: false
|
|
22194
|
+
},
|
|
22195
|
+
clientInfo: { name: "alook-agent-driver-probe", version: "0.1.25" }
|
|
22196
|
+
});
|
|
22197
|
+
});
|
|
22198
|
+
}
|
|
22199
|
+
|
|
22200
|
+
// agent-driver/dist/adapters/cursor/acp-lane.js
|
|
22201
|
+
var ACP_PROTOCOL_VERSION2 = 1;
|
|
22202
|
+
var HANDSHAKE_TIMEOUT_MS = 15000;
|
|
22203
|
+
var AUTH_METHOD_ID2 = "cursor_login";
|
|
21787
22204
|
var PROMPT_STOP_REASONS = new Set([
|
|
21788
22205
|
"end_turn",
|
|
21789
22206
|
"max_tokens",
|
|
@@ -21807,16 +22224,16 @@ class CursorAcpRpcError extends Error {
|
|
|
21807
22224
|
this.code = code;
|
|
21808
22225
|
}
|
|
21809
22226
|
}
|
|
21810
|
-
function
|
|
22227
|
+
function record3(value) {
|
|
21811
22228
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
21812
22229
|
}
|
|
21813
22230
|
function safeLabel(value) {
|
|
21814
22231
|
return typeof value === "string" && /^[a-z0-9_-]{1,64}$/i.test(value) ? value : "unknown";
|
|
21815
22232
|
}
|
|
21816
22233
|
function rpcErrorMessage(error51) {
|
|
21817
|
-
const payload =
|
|
22234
|
+
const payload = record3(error51);
|
|
21818
22235
|
const message2 = typeof payload?.message === "string" && payload.message.trim() ? payload.message : "Cursor ACP request failed";
|
|
21819
|
-
const data =
|
|
22236
|
+
const data = record3(payload?.data);
|
|
21820
22237
|
const detail = typeof data?.message === "string" && data.message.trim() ? data.message : undefined;
|
|
21821
22238
|
return detail ? `${message2}: ${detail}` : message2;
|
|
21822
22239
|
}
|
|
@@ -21824,26 +22241,6 @@ function isMissingSessionError(error51) {
|
|
|
21824
22241
|
const message2 = error51 instanceof Error ? error51.message : String(error51);
|
|
21825
22242
|
return /\bsession\b.*\b(not found|missing|unknown|invalid)\b/i.test(message2) || /\b(not found|missing|unknown|invalid)\b.*\bsession\b/i.test(message2);
|
|
21826
22243
|
}
|
|
21827
|
-
function flattenSelectOptions(value) {
|
|
21828
|
-
if (!Array.isArray(value))
|
|
21829
|
-
return [];
|
|
21830
|
-
const out = [];
|
|
21831
|
-
for (const item of value) {
|
|
21832
|
-
if (Array.isArray(item)) {
|
|
21833
|
-
out.push(...flattenSelectOptions(item));
|
|
21834
|
-
continue;
|
|
21835
|
-
}
|
|
21836
|
-
const candidate = record2(item);
|
|
21837
|
-
if (!candidate)
|
|
21838
|
-
continue;
|
|
21839
|
-
if (typeof candidate.value === "string") {
|
|
21840
|
-
out.push({ value: candidate.value, ...typeof candidate.name === "string" ? { name: candidate.name } : {} });
|
|
21841
|
-
}
|
|
21842
|
-
if (Array.isArray(candidate.options))
|
|
21843
|
-
out.push(...flattenSelectOptions(candidate.options));
|
|
21844
|
-
}
|
|
21845
|
-
return out;
|
|
21846
|
-
}
|
|
21847
22244
|
|
|
21848
22245
|
class CursorAcpLane {
|
|
21849
22246
|
factory;
|
|
@@ -21967,30 +22364,30 @@ class CursorAcpLane {
|
|
|
21967
22364
|
}
|
|
21968
22365
|
}
|
|
21969
22366
|
async handshake(ctx) {
|
|
21970
|
-
const initialize =
|
|
21971
|
-
protocolVersion:
|
|
22367
|
+
const initialize = record3(await this.call("initialize", {
|
|
22368
|
+
protocolVersion: ACP_PROTOCOL_VERSION2,
|
|
21972
22369
|
clientCapabilities: {
|
|
21973
22370
|
fs: { readTextFile: false, writeTextFile: false },
|
|
21974
22371
|
terminal: false
|
|
21975
22372
|
},
|
|
21976
22373
|
clientInfo: { name: "alook-agent-driver", version: "0.1.14" }
|
|
21977
22374
|
}));
|
|
21978
|
-
if (initialize?.protocolVersion !==
|
|
22375
|
+
if (initialize?.protocolVersion !== ACP_PROTOCOL_VERSION2) {
|
|
21979
22376
|
throw new CursorAcpIncompatibleError("Installed Cursor ACP does not support protocol version 1");
|
|
21980
22377
|
}
|
|
21981
|
-
const capabilities =
|
|
22378
|
+
const capabilities = record3(initialize.agentCapabilities);
|
|
21982
22379
|
if (capabilities?.loadSession !== true) {
|
|
21983
22380
|
throw new CursorAcpIncompatibleError("Installed Cursor ACP does not support persistent session loading");
|
|
21984
22381
|
}
|
|
21985
22382
|
const authMethods = Array.isArray(initialize.authMethods) ? initialize.authMethods : [];
|
|
21986
|
-
if (!authMethods.some((method) =>
|
|
22383
|
+
if (!authMethods.some((method) => record3(method)?.id === AUTH_METHOD_ID2)) {
|
|
21987
22384
|
throw new CursorAcpIncompatibleError("Installed Cursor ACP does not expose Cursor login authentication");
|
|
21988
22385
|
}
|
|
21989
|
-
await this.call("authenticate", { methodId:
|
|
22386
|
+
await this.call("authenticate", { methodId: AUTH_METHOD_ID2 });
|
|
21990
22387
|
let session2;
|
|
21991
22388
|
if (ctx.config.sessionId) {
|
|
21992
22389
|
try {
|
|
21993
|
-
session2 =
|
|
22390
|
+
session2 = record3(await this.call("session/load", {
|
|
21994
22391
|
sessionId: ctx.config.sessionId,
|
|
21995
22392
|
cwd: ctx.workingDirectory,
|
|
21996
22393
|
mcpServers: []
|
|
@@ -22002,15 +22399,25 @@ class CursorAcpLane {
|
|
|
22002
22399
|
throw error51;
|
|
22003
22400
|
}
|
|
22004
22401
|
} else {
|
|
22005
|
-
session2 =
|
|
22402
|
+
session2 = record3(await this.call("session/new", { cwd: ctx.workingDirectory, mcpServers: [] }));
|
|
22006
22403
|
}
|
|
22007
|
-
if (!session2
|
|
22404
|
+
if (!session2)
|
|
22405
|
+
throw new Error("Cursor ACP did not return a valid session response");
|
|
22406
|
+
const returnedSessionId = session2.sessionId;
|
|
22407
|
+
if (returnedSessionId !== undefined && (typeof returnedSessionId !== "string" || !returnedSessionId.trim())) {
|
|
22008
22408
|
throw new Error("Cursor ACP did not return a valid session id");
|
|
22009
22409
|
}
|
|
22010
|
-
if (ctx.config.sessionId
|
|
22011
|
-
|
|
22410
|
+
if (ctx.config.sessionId) {
|
|
22411
|
+
if (returnedSessionId !== undefined && returnedSessionId !== ctx.config.sessionId) {
|
|
22412
|
+
throw new CursorAcpResetRequiredError("Cursor ACP loaded a different session; reset this agent before continuing");
|
|
22413
|
+
}
|
|
22414
|
+
this.sessionId = ctx.config.sessionId;
|
|
22415
|
+
} else {
|
|
22416
|
+
if (typeof returnedSessionId !== "string") {
|
|
22417
|
+
throw new Error("Cursor ACP did not return a valid session id");
|
|
22418
|
+
}
|
|
22419
|
+
this.sessionId = returnedSessionId;
|
|
22012
22420
|
}
|
|
22013
|
-
this.sessionId = session2.sessionId;
|
|
22014
22421
|
await this.configureModel(session2, ctx);
|
|
22015
22422
|
}
|
|
22016
22423
|
async configureModel(session2, ctx) {
|
|
@@ -22018,24 +22425,30 @@ class CursorAcpLane {
|
|
|
22018
22425
|
if (!requestedModel)
|
|
22019
22426
|
return;
|
|
22020
22427
|
const configOptions = Array.isArray(session2.configOptions) ? session2.configOptions : [];
|
|
22021
|
-
const modelConfig = configOptions.map(
|
|
22428
|
+
const modelConfig = configOptions.map(record3).find((option) => option?.id === "model") ?? null;
|
|
22022
22429
|
if (!modelConfig) {
|
|
22023
22430
|
throw new CursorAcpIncompatibleError("Installed Cursor ACP does not support model configuration");
|
|
22024
22431
|
}
|
|
22025
|
-
const options =
|
|
22026
|
-
const match = options.find((option) => option.value === requestedModel)
|
|
22432
|
+
const options = flattenCursorAcpSelectOptions(modelConfig.options);
|
|
22433
|
+
const match = options.find((option) => option.value === requestedModel);
|
|
22027
22434
|
if (!match) {
|
|
22028
22435
|
throw new CursorAcpIncompatibleError(`Configured Cursor model is unavailable through ACP: ${requestedModel}`);
|
|
22029
22436
|
}
|
|
22437
|
+
let response;
|
|
22030
22438
|
try {
|
|
22031
|
-
await this.call("session/set_config_option", {
|
|
22439
|
+
response = record3(await this.call("session/set_config_option", {
|
|
22032
22440
|
sessionId: this.sessionId,
|
|
22033
22441
|
configId: "model",
|
|
22034
22442
|
value: match.value
|
|
22035
|
-
});
|
|
22443
|
+
}));
|
|
22036
22444
|
} catch {
|
|
22037
22445
|
throw new CursorAcpIncompatibleError("Installed Cursor ACP rejected model configuration");
|
|
22038
22446
|
}
|
|
22447
|
+
const confirmedOptions = Array.isArray(response?.configOptions) ? response.configOptions : [];
|
|
22448
|
+
const confirmedModel = confirmedOptions.map(record3).find((option) => option?.id === "model") ?? null;
|
|
22449
|
+
if (confirmedModel?.currentValue !== match.value) {
|
|
22450
|
+
throw new CursorAcpIncompatibleError("Cursor ACP did not confirm the exact configured model");
|
|
22451
|
+
}
|
|
22039
22452
|
}
|
|
22040
22453
|
admitPrompt(text2) {
|
|
22041
22454
|
if (!this.sessionId)
|
|
@@ -22071,7 +22484,7 @@ class CursorAcpLane {
|
|
|
22071
22484
|
completePrompt(active, value) {
|
|
22072
22485
|
if (this.activePrompt?.requestId !== active.requestId)
|
|
22073
22486
|
return;
|
|
22074
|
-
const result =
|
|
22487
|
+
const result = record3(value);
|
|
22075
22488
|
if (!result || typeof result.stopReason !== "string" || !PROMPT_STOP_REASONS.has(result.stopReason)) {
|
|
22076
22489
|
this.failPrompt(active, new Error("Cursor ACP prompt response did not contain a supported stopReason"));
|
|
22077
22490
|
return;
|
|
@@ -22213,7 +22626,7 @@ class CursorAcpLane {
|
|
|
22213
22626
|
});
|
|
22214
22627
|
}
|
|
22215
22628
|
handleMessage(value) {
|
|
22216
|
-
const message2 =
|
|
22629
|
+
const message2 = record3(value);
|
|
22217
22630
|
if (!message2 || message2.jsonrpc !== "2.0") {
|
|
22218
22631
|
this.protocolFailure("Cursor ACP emitted an invalid JSON-RPC message");
|
|
22219
22632
|
return;
|
|
@@ -22241,7 +22654,7 @@ class CursorAcpLane {
|
|
|
22241
22654
|
if (pending.kind === "prompt") {
|
|
22242
22655
|
this.pending.delete(id);
|
|
22243
22656
|
if (message2.error !== undefined) {
|
|
22244
|
-
const payload =
|
|
22657
|
+
const payload = record3(message2.error);
|
|
22245
22658
|
this.failPrompt(pending.active, new CursorAcpRpcError(pending.method, typeof payload?.code === "number" ? payload.code : undefined, rpcErrorMessage(message2.error)));
|
|
22246
22659
|
} else if (!("result" in message2)) {
|
|
22247
22660
|
this.failPrompt(pending.active, new Error("Cursor ACP response omitted result"));
|
|
@@ -22251,7 +22664,7 @@ class CursorAcpLane {
|
|
|
22251
22664
|
return;
|
|
22252
22665
|
}
|
|
22253
22666
|
if (message2.error !== undefined) {
|
|
22254
|
-
const payload =
|
|
22667
|
+
const payload = record3(message2.error);
|
|
22255
22668
|
this.settleRequest(id, false, new CursorAcpRpcError(pending.method, typeof payload?.code === "number" ? payload.code : undefined, rpcErrorMessage(message2.error)));
|
|
22256
22669
|
return;
|
|
22257
22670
|
}
|
|
@@ -22283,9 +22696,9 @@ class CursorAcpLane {
|
|
|
22283
22696
|
this.diagnostic("warning", `Unsupported Cursor ACP client request: ${safeLabel(method)}`);
|
|
22284
22697
|
return;
|
|
22285
22698
|
}
|
|
22286
|
-
const payload =
|
|
22699
|
+
const payload = record3(params);
|
|
22287
22700
|
const sameSession = payload?.sessionId === this.sessionId;
|
|
22288
|
-
const options = Array.isArray(payload?.options) ? payload.options.map(
|
|
22701
|
+
const options = Array.isArray(payload?.options) ? payload.options.map(record3).filter(Boolean) : [];
|
|
22289
22702
|
const allowOnce = options.find((option) => option.kind === "allow_once" && typeof option.optionId === "string" && option.optionId.trim().length > 0);
|
|
22290
22703
|
if (!this.ready || !this.activePrompt || !sameSession || !allowOnce) {
|
|
22291
22704
|
this.write({ jsonrpc: "2.0", id, result: { outcome: { outcome: "cancelled" } } });
|
|
@@ -22306,7 +22719,7 @@ class CursorAcpLane {
|
|
|
22306
22719
|
this.diagnostic("warning", `Unsupported Cursor ACP notification: ${safeLabel(method)}`);
|
|
22307
22720
|
}
|
|
22308
22721
|
handleSessionUpdate(params) {
|
|
22309
|
-
const payload =
|
|
22722
|
+
const payload = record3(params);
|
|
22310
22723
|
if (!payload || payload.sessionId !== this.sessionId) {
|
|
22311
22724
|
this.diagnostic("warning", "Cursor ACP emitted an update for a different session");
|
|
22312
22725
|
return;
|
|
@@ -22315,18 +22728,18 @@ class CursorAcpLane {
|
|
|
22315
22728
|
this.diagnostic("warning", "Cursor ACP emitted a session update without an active prompt");
|
|
22316
22729
|
return;
|
|
22317
22730
|
}
|
|
22318
|
-
const update =
|
|
22731
|
+
const update = record3(payload.update) ?? {};
|
|
22319
22732
|
const updateType = update?.sessionUpdate;
|
|
22320
22733
|
switch (updateType) {
|
|
22321
22734
|
case "agent_message_chunk": {
|
|
22322
|
-
const content =
|
|
22735
|
+
const content = record3(update.content);
|
|
22323
22736
|
if (content?.type === "text" && typeof content.text === "string") {
|
|
22324
22737
|
this.events.emit("runtime_event", { kind: "assistant_message_delta", text: content.text });
|
|
22325
22738
|
}
|
|
22326
22739
|
return;
|
|
22327
22740
|
}
|
|
22328
22741
|
case "agent_thought_chunk": {
|
|
22329
|
-
const content =
|
|
22742
|
+
const content = record3(update.content);
|
|
22330
22743
|
if (content?.type === "text" && typeof content.text === "string") {
|
|
22331
22744
|
this.events.emit("runtime_event", { kind: "assistant_reasoning_delta", text: content.text });
|
|
22332
22745
|
}
|
|
@@ -22398,6 +22811,7 @@ class CursorAcpLane {
|
|
|
22398
22811
|
|
|
22399
22812
|
// agent-driver/dist/adapters/cursor/index.js
|
|
22400
22813
|
class CursorDriver {
|
|
22814
|
+
catalogProbe;
|
|
22401
22815
|
id = "cursor";
|
|
22402
22816
|
instructionDelivery = { kind: "workspace_file", canonical: "AGENTS.md", aliases: ["CLAUDE.md"] };
|
|
22403
22817
|
execution = {
|
|
@@ -22406,8 +22820,23 @@ class CursorDriver {
|
|
|
22406
22820
|
wakeStart: "immediate",
|
|
22407
22821
|
terminalOwnership: "transport_request"
|
|
22408
22822
|
};
|
|
22409
|
-
|
|
22410
|
-
|
|
22823
|
+
constructor(catalogProbe = probeCursorAcpCatalog) {
|
|
22824
|
+
this.catalogProbe = catalogProbe;
|
|
22825
|
+
}
|
|
22826
|
+
async probe(command) {
|
|
22827
|
+
const result = probeCliRuntime("cursor-agent", {}, command);
|
|
22828
|
+
if (result.status !== "healthy")
|
|
22829
|
+
return result;
|
|
22830
|
+
let reasoning;
|
|
22831
|
+
try {
|
|
22832
|
+
reasoning = await this.catalogProbe(command);
|
|
22833
|
+
} catch {
|
|
22834
|
+
reasoning = undefined;
|
|
22835
|
+
}
|
|
22836
|
+
return {
|
|
22837
|
+
...result,
|
|
22838
|
+
reasoning
|
|
22839
|
+
};
|
|
22411
22840
|
}
|
|
22412
22841
|
async openLane(ctx, options) {
|
|
22413
22842
|
return new CursorAcpLane(this, ctx, { onRawStdoutLine: options?.onRawStdoutLine });
|
|
@@ -22464,7 +22893,7 @@ class OpenCodeHttpError extends Error {
|
|
|
22464
22893
|
this.status = status;
|
|
22465
22894
|
}
|
|
22466
22895
|
}
|
|
22467
|
-
function
|
|
22896
|
+
function record4(value) {
|
|
22468
22897
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
22469
22898
|
}
|
|
22470
22899
|
function safeLabel2(value) {
|
|
@@ -22511,7 +22940,7 @@ function parseModelRef(model) {
|
|
|
22511
22940
|
return { providerID: model.slice(0, slash), id: model.slice(slash + 1) };
|
|
22512
22941
|
}
|
|
22513
22942
|
function messageFromError(value) {
|
|
22514
|
-
const payload =
|
|
22943
|
+
const payload = record4(value);
|
|
22515
22944
|
const message2 = typeof payload?.message === "string" && payload.message.trim() ? payload.message : undefined;
|
|
22516
22945
|
return message2 ? "OpenCode turn failed" : "OpenCode reported an inconsistent turn outcome";
|
|
22517
22946
|
}
|
|
@@ -22553,6 +22982,7 @@ class OpenCodeServiceLane {
|
|
|
22553
22982
|
lastDurableSeq = 0;
|
|
22554
22983
|
durableSeqById = new Map;
|
|
22555
22984
|
durableIdBySeq = new Map;
|
|
22985
|
+
usageProjector = new SettledUsageProjector;
|
|
22556
22986
|
toolNames = new Map;
|
|
22557
22987
|
handledPermissions = new Set;
|
|
22558
22988
|
permissionFlights = new Map;
|
|
@@ -22845,7 +23275,7 @@ class OpenCodeServiceLane {
|
|
|
22845
23275
|
const healthTimeoutMs = Math.max(1, Math.min(1000, deadline - Date.now(), this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS));
|
|
22846
23276
|
const { response, body } = await this.fetchJsonWithTimeout("/global/health", { method: "GET" }, "health", healthTimeoutMs);
|
|
22847
23277
|
if (response.ok) {
|
|
22848
|
-
const health =
|
|
23278
|
+
const health = record4(body);
|
|
22849
23279
|
if (health?.healthy !== true || health.version !== SUPPORTED_VERSION) {
|
|
22850
23280
|
throw new OpenCodeIncompatibleError(`Installed OpenCode service must be version ${SUPPORTED_VERSION}`);
|
|
22851
23281
|
}
|
|
@@ -22866,8 +23296,8 @@ class OpenCodeServiceLane {
|
|
|
22866
23296
|
const { response, body } = await this.fetchJsonWithTimeout("/doc", { method: "GET" }, "OpenAPI");
|
|
22867
23297
|
if (!response.ok)
|
|
22868
23298
|
throw new OpenCodeIncompatibleError("Installed OpenCode service does not expose its OpenAPI document");
|
|
22869
|
-
const document =
|
|
22870
|
-
const paths =
|
|
23299
|
+
const document = record4(body);
|
|
23300
|
+
const paths = record4(document?.paths);
|
|
22871
23301
|
const required2 = [
|
|
22872
23302
|
"/api/session",
|
|
22873
23303
|
"/api/session/active",
|
|
@@ -22880,7 +23310,7 @@ class OpenCodeServiceLane {
|
|
|
22880
23310
|
"/api/session/{sessionID}/permission/{requestID}/reply",
|
|
22881
23311
|
"/api/event"
|
|
22882
23312
|
];
|
|
22883
|
-
if (!paths || required2.some((path7) => !
|
|
23313
|
+
if (!paths || required2.some((path7) => !record4(paths[path7]))) {
|
|
22884
23314
|
throw new OpenCodeIncompatibleError("Installed OpenCode service is missing required v2 session capabilities");
|
|
22885
23315
|
}
|
|
22886
23316
|
}
|
|
@@ -22893,7 +23323,7 @@ class OpenCodeServiceLane {
|
|
|
22893
23323
|
}
|
|
22894
23324
|
if (!response2.ok)
|
|
22895
23325
|
throw new OpenCodeHttpError(response2.status, "session resume");
|
|
22896
|
-
const session3 =
|
|
23326
|
+
const session3 = record4(record4(body2)?.data);
|
|
22897
23327
|
if (session3?.id !== resumeId) {
|
|
22898
23328
|
throw new OpenCodeResetRequiredError("OpenCode v2 returned a different resumed session; reset this agent before continuing");
|
|
22899
23329
|
}
|
|
@@ -22914,8 +23344,8 @@ class OpenCodeServiceLane {
|
|
|
22914
23344
|
}, "session create");
|
|
22915
23345
|
if (!response.ok)
|
|
22916
23346
|
throw new OpenCodeHttpError(response.status, "session create");
|
|
22917
|
-
const payload =
|
|
22918
|
-
const session2 =
|
|
23347
|
+
const payload = record4(responseBody);
|
|
23348
|
+
const session2 = record4(payload?.data);
|
|
22919
23349
|
if (typeof session2?.id !== "string" || !/^ses/.test(session2.id)) {
|
|
22920
23350
|
throw new Error("OpenCode v2 did not return a valid session id");
|
|
22921
23351
|
}
|
|
@@ -23072,7 +23502,7 @@ class OpenCodeServiceLane {
|
|
|
23072
23502
|
const { response, body: responseBody } = await this.fetchJsonWithTimeout(`/api/session/${encodeURIComponent(this.sessionId)}/history?after=${historyCursor}&limit=${HISTORY_PAGE_LIMIT}`, { method: "GET" }, "session history");
|
|
23073
23503
|
if (!response.ok)
|
|
23074
23504
|
throw new OpenCodeHttpError(response.status, "session history");
|
|
23075
|
-
const body =
|
|
23505
|
+
const body = record4(responseBody);
|
|
23076
23506
|
if (!Array.isArray(body?.data) || typeof body.hasMore !== "boolean") {
|
|
23077
23507
|
throw new OpenCodeProtocolError("OpenCode session history returned an invalid page");
|
|
23078
23508
|
}
|
|
@@ -23090,10 +23520,11 @@ class OpenCodeServiceLane {
|
|
|
23090
23520
|
return run;
|
|
23091
23521
|
}
|
|
23092
23522
|
async handleDurableEvent(value, project) {
|
|
23093
|
-
const event =
|
|
23094
|
-
const durable =
|
|
23095
|
-
const data =
|
|
23096
|
-
|
|
23523
|
+
const event = record4(value);
|
|
23524
|
+
const durable = record4(event?.durable);
|
|
23525
|
+
const data = record4(event?.data);
|
|
23526
|
+
const backendSessionId = this.sessionId;
|
|
23527
|
+
if (!event || !backendSessionId || typeof event.id !== "string" || typeof event.type !== "string" || !durable || durable.aggregateID !== this.sessionId || !Number.isInteger(durable.seq) || Number(durable.seq) < 0 || data?.sessionID !== this.sessionId) {
|
|
23097
23528
|
throw new OpenCodeProtocolError("OpenCode session stream emitted an invalid durable event");
|
|
23098
23529
|
}
|
|
23099
23530
|
const seq = Number(durable.seq);
|
|
@@ -23182,22 +23613,28 @@ class OpenCodeServiceLane {
|
|
|
23182
23613
|
...!successful ? { message: "OpenCode reported an unsupported final step outcome" } : {}
|
|
23183
23614
|
});
|
|
23184
23615
|
}
|
|
23185
|
-
const tokens =
|
|
23186
|
-
if (tokens
|
|
23187
|
-
const cache =
|
|
23188
|
-
const
|
|
23189
|
-
|
|
23190
|
-
|
|
23191
|
-
|
|
23192
|
-
|
|
23193
|
-
|
|
23616
|
+
const tokens = record4(data.tokens);
|
|
23617
|
+
if (tokens) {
|
|
23618
|
+
const cache = record4(tokens.cache);
|
|
23619
|
+
const identity = {
|
|
23620
|
+
runtime: "opencode",
|
|
23621
|
+
backendSessionId,
|
|
23622
|
+
providerRecordId: event.id
|
|
23623
|
+
};
|
|
23624
|
+
const usage = this.usageProjector.project({
|
|
23625
|
+
...identity,
|
|
23194
23626
|
source: "opencode.v2",
|
|
23195
|
-
|
|
23196
|
-
|
|
23197
|
-
|
|
23198
|
-
|
|
23199
|
-
|
|
23627
|
+
input: tokens.input,
|
|
23628
|
+
output: tokens.output,
|
|
23629
|
+
reasoning: tokens.reasoning,
|
|
23630
|
+
cacheRead: cache?.read,
|
|
23631
|
+
cacheWrite: cache?.write,
|
|
23632
|
+
inputIncludesCache: false,
|
|
23633
|
+
outputIncludesReasoning: false
|
|
23200
23634
|
});
|
|
23635
|
+
if (usage)
|
|
23636
|
+
this.events.emit("runtime_event", usage);
|
|
23637
|
+
this.usageProjector.release(identity);
|
|
23201
23638
|
}
|
|
23202
23639
|
break;
|
|
23203
23640
|
}
|
|
@@ -23211,8 +23648,8 @@ class OpenCodeServiceLane {
|
|
|
23211
23648
|
return seq;
|
|
23212
23649
|
}
|
|
23213
23650
|
async handleLiveEvent(value) {
|
|
23214
|
-
const event =
|
|
23215
|
-
const data =
|
|
23651
|
+
const event = record4(value);
|
|
23652
|
+
const data = record4(event?.data);
|
|
23216
23653
|
if (event?.type !== "permission.v2.asked" || data?.sessionID !== this.sessionId)
|
|
23217
23654
|
return;
|
|
23218
23655
|
if (typeof data.id !== "string" || !/^per/.test(data.id)) {
|
|
@@ -23226,11 +23663,11 @@ class OpenCodeServiceLane {
|
|
|
23226
23663
|
const { response, body: responseBody } = await this.fetchJsonWithTimeout(`/api/session/${encodeURIComponent(this.sessionId)}/permission`, { method: "GET" }, "permission list");
|
|
23227
23664
|
if (!response.ok)
|
|
23228
23665
|
throw new OpenCodeHttpError(response.status, "permission list");
|
|
23229
|
-
const body =
|
|
23666
|
+
const body = record4(responseBody);
|
|
23230
23667
|
if (!Array.isArray(body?.data))
|
|
23231
23668
|
throw new OpenCodeProtocolError("OpenCode permission list returned invalid data");
|
|
23232
23669
|
for (const item of body.data) {
|
|
23233
|
-
const permission =
|
|
23670
|
+
const permission = record4(item);
|
|
23234
23671
|
if (permission?.sessionID === this.sessionId && typeof permission.id === "string") {
|
|
23235
23672
|
await this.replyPermission(permission.id);
|
|
23236
23673
|
}
|
|
@@ -23297,8 +23734,8 @@ class OpenCodeServiceLane {
|
|
|
23297
23734
|
}, "prompt admission");
|
|
23298
23735
|
if (!response.ok)
|
|
23299
23736
|
throw new OpenCodeHttpError(response.status, "prompt admission");
|
|
23300
|
-
const body =
|
|
23301
|
-
const admitted =
|
|
23737
|
+
const body = record4(responseBody);
|
|
23738
|
+
const admitted = record4(body?.data);
|
|
23302
23739
|
if (admitted?.id !== messageId || admitted.sessionID !== this.sessionId || admitted.delivery !== delivery || !Number.isInteger(admitted.admittedSeq) || Number(admitted.admittedSeq) < 0) {
|
|
23303
23740
|
throw new OpenCodeProtocolError("OpenCode prompt admission returned an invalid receipt");
|
|
23304
23741
|
}
|
|
@@ -23365,8 +23802,8 @@ class OpenCodeServiceLane {
|
|
|
23365
23802
|
const { response, body: responseBody } = await this.fetchJsonWithTimeout("/api/session/active", { method: "GET" }, "active session query");
|
|
23366
23803
|
if (!response.ok)
|
|
23367
23804
|
throw new OpenCodeHttpError(response.status, "active session query");
|
|
23368
|
-
const body =
|
|
23369
|
-
const active =
|
|
23805
|
+
const body = record4(responseBody);
|
|
23806
|
+
const active = record4(body?.data);
|
|
23370
23807
|
if (!active)
|
|
23371
23808
|
throw new OpenCodeProtocolError("OpenCode active session query returned invalid data");
|
|
23372
23809
|
if (!this.barrierStillCurrent(root, identity, generation))
|
|
@@ -23571,6 +24008,7 @@ function createOpenCodeMessageId() {
|
|
|
23571
24008
|
}
|
|
23572
24009
|
|
|
23573
24010
|
class OpenCodeDriver {
|
|
24011
|
+
outputProbe;
|
|
23574
24012
|
id = "opencode";
|
|
23575
24013
|
instructionDelivery = { kind: "workspace_file", canonical: "AGENTS.md", aliases: ["CLAUDE.md"] };
|
|
23576
24014
|
execution = {
|
|
@@ -23579,8 +24017,19 @@ class OpenCodeDriver {
|
|
|
23579
24017
|
wakeStart: "immediate",
|
|
23580
24018
|
terminalOwnership: "transport_request"
|
|
23581
24019
|
};
|
|
24020
|
+
constructor(outputProbe = probeCommandOutput) {
|
|
24021
|
+
this.outputProbe = outputProbe;
|
|
24022
|
+
}
|
|
23582
24023
|
probe(command) {
|
|
23583
|
-
|
|
24024
|
+
const result = probeCliRuntime("opencode", {}, command);
|
|
24025
|
+
if (result.status !== "healthy")
|
|
24026
|
+
return result;
|
|
24027
|
+
const spec = resolveSpawnSpec("opencode", ["models", "--pure"], command);
|
|
24028
|
+
const output = this.outputProbe(spec.command, spec.args);
|
|
24029
|
+
return {
|
|
24030
|
+
...result,
|
|
24031
|
+
reasoning: output.ok ? parseOpenCodeModelCatalog(output.output) : undefined
|
|
24032
|
+
};
|
|
23584
24033
|
}
|
|
23585
24034
|
beginTurn() {
|
|
23586
24035
|
return createOpenCodeMessageId();
|
|
@@ -23834,6 +24283,7 @@ function createPiSessionDependencies(ctx, loadSdk = loadPiSdkModule) {
|
|
|
23834
24283
|
|
|
23835
24284
|
// agent-driver/dist/adapters/pi/index.js
|
|
23836
24285
|
var PI_SDK_PACKAGE_NAME2 = "@earendil-works/pi-coding-agent";
|
|
24286
|
+
var PI_MODEL_PROBE_TIMEOUT_MS = 5000;
|
|
23837
24287
|
function isPiSdkPackageJson(pkgJsonPath) {
|
|
23838
24288
|
if (!existsSync3(pkgJsonPath))
|
|
23839
24289
|
return false;
|
|
@@ -23903,6 +24353,11 @@ function readPiSdkVersion() {
|
|
|
23903
24353
|
} catch {}
|
|
23904
24354
|
return resolvePiSdkVersionFromPath();
|
|
23905
24355
|
}
|
|
24356
|
+
function piUsageState(state) {
|
|
24357
|
+
state.usageProjector ??= new SettledUsageProjector;
|
|
24358
|
+
state.pendingUsageRecordIds ??= new Set;
|
|
24359
|
+
return { projector: state.usageProjector, pending: state.pendingUsageRecordIds };
|
|
24360
|
+
}
|
|
23906
24361
|
function mapPiSdkEvent(event, sessionId, state) {
|
|
23907
24362
|
if (event?.type === "message_update") {
|
|
23908
24363
|
const d = event.assistantMessageEvent ?? {};
|
|
@@ -23923,6 +24378,35 @@ function mapPiSdkEvent(event, sessionId, state) {
|
|
|
23923
24378
|
}
|
|
23924
24379
|
}
|
|
23925
24380
|
switch (event?.type) {
|
|
24381
|
+
case "message_end": {
|
|
24382
|
+
const message2 = event.message;
|
|
24383
|
+
if (message2?.role !== "assistant" || !message2.usage)
|
|
24384
|
+
return [];
|
|
24385
|
+
state.usageRecordSequence = (state.usageRecordSequence ?? 0) + 1;
|
|
24386
|
+
const providerRecordId = typeof message2.responseId === "string" && message2.responseId ? message2.responseId : `live:${message2.timestamp ?? "unknown"}:${state.usageRecordSequence}`;
|
|
24387
|
+
const { projector, pending } = piUsageState(state);
|
|
24388
|
+
const identity = { runtime: "pi", backendSessionId: sessionId, providerRecordId };
|
|
24389
|
+
const usage = projector.project({
|
|
24390
|
+
...identity,
|
|
24391
|
+
source: "pi_message_end",
|
|
24392
|
+
input: message2.usage.input,
|
|
24393
|
+
output: message2.usage.output,
|
|
24394
|
+
cacheRead: message2.usage.cacheRead,
|
|
24395
|
+
cacheWrite: message2.usage.cacheWrite,
|
|
24396
|
+
inputIncludesCache: false,
|
|
24397
|
+
outputIncludesReasoning: true
|
|
24398
|
+
});
|
|
24399
|
+
pending.add(providerRecordId);
|
|
24400
|
+
return usage ? [usage] : [];
|
|
24401
|
+
}
|
|
24402
|
+
case "turn_end": {
|
|
24403
|
+
const { projector, pending } = piUsageState(state);
|
|
24404
|
+
for (const providerRecordId of pending) {
|
|
24405
|
+
projector.release({ runtime: "pi", backendSessionId: sessionId, providerRecordId });
|
|
24406
|
+
}
|
|
24407
|
+
pending.clear();
|
|
24408
|
+
return [];
|
|
24409
|
+
}
|
|
23926
24410
|
case "auto_retry_start":
|
|
23927
24411
|
return [{ kind: "runtime_recovery", stage: "retrying", source: "pi_auto_retry" }];
|
|
23928
24412
|
case "auto_retry_end":
|
|
@@ -23942,6 +24426,8 @@ function mapPiSdkEvent(event, sessionId, state) {
|
|
|
23942
24426
|
|
|
23943
24427
|
class PiDriver {
|
|
23944
24428
|
dependenciesFor;
|
|
24429
|
+
loadSdk;
|
|
24430
|
+
readVersion;
|
|
23945
24431
|
id = "pi";
|
|
23946
24432
|
instructionDelivery = { kind: "workspace_file", canonical: "AGENTS.md", aliases: ["CLAUDE.md"] };
|
|
23947
24433
|
execution = {
|
|
@@ -23952,15 +24438,36 @@ class PiDriver {
|
|
|
23952
24438
|
};
|
|
23953
24439
|
sessionId = null;
|
|
23954
24440
|
terminalSequence = 0;
|
|
23955
|
-
constructor(dependenciesFor = createPiSessionDependencies) {
|
|
24441
|
+
constructor(dependenciesFor = createPiSessionDependencies, loadSdk = loadPiSdkModule, readVersion = readPiSdkVersion) {
|
|
23956
24442
|
this.dependenciesFor = dependenciesFor;
|
|
24443
|
+
this.loadSdk = loadSdk;
|
|
24444
|
+
this.readVersion = readVersion;
|
|
23957
24445
|
}
|
|
23958
|
-
probe() {
|
|
23959
|
-
const version3 =
|
|
24446
|
+
async probe() {
|
|
24447
|
+
const version3 = this.readVersion();
|
|
23960
24448
|
if (!version3) {
|
|
23961
24449
|
return { status: "unhealthy", lastError: "sdk_not_installed" };
|
|
23962
24450
|
}
|
|
23963
|
-
|
|
24451
|
+
let timer;
|
|
24452
|
+
try {
|
|
24453
|
+
const reasoning = await Promise.race([
|
|
24454
|
+
this.loadSdk().then(async (sdk) => {
|
|
24455
|
+
const authStorage = sdk.AuthStorage.create();
|
|
24456
|
+
const registry2 = sdk.ModelRegistry.create(authStorage);
|
|
24457
|
+
return parsePiModelCatalog(await registry2.getAvailable());
|
|
24458
|
+
}),
|
|
24459
|
+
new Promise((resolve3) => {
|
|
24460
|
+
timer = setTimeout(() => resolve3(undefined), PI_MODEL_PROBE_TIMEOUT_MS);
|
|
24461
|
+
timer.unref?.();
|
|
24462
|
+
})
|
|
24463
|
+
]);
|
|
24464
|
+
return { status: "healthy", version: version3, reasoning };
|
|
24465
|
+
} catch {
|
|
24466
|
+
return { status: "healthy", version: version3, reasoning: undefined };
|
|
24467
|
+
} finally {
|
|
24468
|
+
if (timer)
|
|
24469
|
+
clearTimeout(timer);
|
|
24470
|
+
}
|
|
23964
24471
|
}
|
|
23965
24472
|
async openLane(ctx) {
|
|
23966
24473
|
const deps = this.dependenciesFor(ctx);
|
|
@@ -25868,14 +26375,14 @@ function createLogger2(options = {}) {
|
|
|
25868
26375
|
`));
|
|
25869
26376
|
const err = options.err ?? ((line) => process.stderr.write(line + `
|
|
25870
26377
|
`));
|
|
25871
|
-
const
|
|
26378
|
+
const record5 = options.record;
|
|
25872
26379
|
const emit = (level, message2, data) => {
|
|
25873
26380
|
if (LEVEL_RANK[level] < minRank)
|
|
25874
26381
|
return;
|
|
25875
26382
|
const time3 = now();
|
|
25876
26383
|
const line = `${time3} ${header} ${level.toUpperCase().padEnd(5)} ${message2}${formatData(data)}`;
|
|
25877
26384
|
try {
|
|
25878
|
-
|
|
26385
|
+
record5?.({ time: time3, header, level, message: message2, fields: recordFields(data) });
|
|
25879
26386
|
} catch {}
|
|
25880
26387
|
(level === "warn" || level === "error" ? err : out)(line);
|
|
25881
26388
|
};
|
|
@@ -27019,20 +27526,20 @@ function parseLocalMessageReminderBody(body, agentId) {
|
|
|
27019
27526
|
}
|
|
27020
27527
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
27021
27528
|
return null;
|
|
27022
|
-
const
|
|
27023
|
-
if (Object.keys(
|
|
27529
|
+
const record5 = value;
|
|
27530
|
+
if (Object.keys(record5).sort().join(",") !== "channel,remindAfterMs,sentSeq")
|
|
27024
27531
|
return null;
|
|
27025
|
-
if (typeof
|
|
27532
|
+
if (typeof record5.channel !== "string" || !isCanonicalChannelScope(record5.channel))
|
|
27026
27533
|
return null;
|
|
27027
|
-
if (!Number.isSafeInteger(
|
|
27534
|
+
if (!Number.isSafeInteger(record5.sentSeq) || record5.sentSeq < 1)
|
|
27028
27535
|
return null;
|
|
27029
|
-
if (!Number.isSafeInteger(
|
|
27536
|
+
if (!Number.isSafeInteger(record5.remindAfterMs) || record5.remindAfterMs !== 0 && record5.remindAfterMs < LOCAL_MESSAGE_REMINDER_MIN_MS || record5.remindAfterMs > LOCAL_MESSAGE_REMINDER_MAX_MS)
|
|
27030
27537
|
return null;
|
|
27031
27538
|
return {
|
|
27032
27539
|
agentId,
|
|
27033
|
-
channel:
|
|
27034
|
-
sentSeq:
|
|
27035
|
-
remindAfterMs:
|
|
27540
|
+
channel: record5.channel,
|
|
27541
|
+
sentSeq: record5.sentSeq,
|
|
27542
|
+
remindAfterMs: record5.remindAfterMs
|
|
27036
27543
|
};
|
|
27037
27544
|
}
|
|
27038
27545
|
async function handleLocalMessageReminder(req, res, agentId, onArm) {
|
|
@@ -27378,13 +27885,13 @@ function reduceManager(state, event) {
|
|
|
27378
27885
|
const existing = state.agents[event.agentId];
|
|
27379
27886
|
if (!existing || existing.execution.sessionInstanceId !== event.sessionInstanceId)
|
|
27380
27887
|
return { state, effects: [] };
|
|
27381
|
-
const
|
|
27382
|
-
if (!
|
|
27888
|
+
const record5 = existing.pendingAdmissions.find((entry) => entry.sessionInstanceId === event.sessionInstanceId && entry.commandId === event.commandId);
|
|
27889
|
+
if (!record5)
|
|
27383
27890
|
return { state, effects: [] };
|
|
27384
27891
|
const agent2 = clone2(existing);
|
|
27385
27892
|
agent2.pendingAdmissions = agent2.pendingAdmissions.filter((entry) => entry.sessionInstanceId !== event.sessionInstanceId || entry.commandId !== event.commandId);
|
|
27386
27893
|
syncExecutionProjection(agent2);
|
|
27387
|
-
return commit(state, agent2, event.outcome === "failed" ? recoveryEffects(agent2, [
|
|
27894
|
+
return commit(state, agent2, event.outcome === "failed" ? recoveryEffects(agent2, [record5]) : []);
|
|
27388
27895
|
}
|
|
27389
27896
|
case "admission_acknowledged": {
|
|
27390
27897
|
const existing = state.agents[event.agentId];
|
|
@@ -27902,11 +28409,11 @@ function syncExecutionProjection(agent2) {
|
|
|
27902
28409
|
agent2.lastDeliverAt = agent2.pendingAdmissions.length > 0 ? Math.max(...agent2.pendingAdmissions.map((entry) => entry.admittedAt)) : null;
|
|
27903
28410
|
}
|
|
27904
28411
|
function recoveryEffects(agent2, records) {
|
|
27905
|
-
return records.filter((
|
|
28412
|
+
return records.filter((record5) => record5.requeueOnFailure).map((record5) => ({
|
|
27906
28413
|
type: "requeue_delivery",
|
|
27907
28414
|
agentId: agent2.agentId,
|
|
27908
|
-
message:
|
|
27909
|
-
mode:
|
|
28415
|
+
message: record5.exactAgentMsg,
|
|
28416
|
+
mode: record5.mode
|
|
27910
28417
|
}));
|
|
27911
28418
|
}
|
|
27912
28419
|
function commit(state, agent2, effects) {
|
|
@@ -28052,8 +28559,8 @@ async function readClaudeQuota(options) {
|
|
|
28052
28559
|
if (!body || typeof body !== "object") {
|
|
28053
28560
|
return { status: "error", sourceEpoch: claudeSourceEpoch, code: "invalid_response", retryable: true };
|
|
28054
28561
|
}
|
|
28055
|
-
const
|
|
28056
|
-
const limits = ["five_hour", "seven_day", "seven_day_sonnet", "seven_day_opus"].map((key) => claudeLimit(key,
|
|
28562
|
+
const record5 = body;
|
|
28563
|
+
const limits = ["five_hour", "seven_day", "seven_day_sonnet", "seven_day_opus"].map((key) => claudeLimit(key, record5[key])).filter((limit) => limit !== null);
|
|
28057
28564
|
if (limits.length === 0) {
|
|
28058
28565
|
return { status: "error", sourceEpoch: claudeSourceEpoch, code: "invalid_response", retryable: true };
|
|
28059
28566
|
}
|
|
@@ -30178,6 +30685,7 @@ class AgentRouter {
|
|
|
30178
30685
|
await this.opts.channel.reportReady(this.buildReady());
|
|
30179
30686
|
}
|
|
30180
30687
|
buildReady() {
|
|
30688
|
+
const timeZone = typeof this.opts.timeZone === "function" ? this.opts.timeZone() : this.opts.timeZone;
|
|
30181
30689
|
return {
|
|
30182
30690
|
runtimeReport: [...this.runtimes.values()],
|
|
30183
30691
|
capabilities: [CONTROL_HEARTBEAT_CAPABILITY],
|
|
@@ -30187,6 +30695,7 @@ class AgentRouter {
|
|
|
30187
30695
|
arch: this.opts.arch,
|
|
30188
30696
|
osRelease: this.opts.osRelease,
|
|
30189
30697
|
daemonVersion: this.opts.daemonVersion,
|
|
30698
|
+
timeZone,
|
|
30190
30699
|
...this.opts.providerQuotas ? { providerQuotas: this.opts.providerQuotas() } : {}
|
|
30191
30700
|
};
|
|
30192
30701
|
}
|
|
@@ -30228,11 +30737,10 @@ class AgentRouter {
|
|
|
30228
30737
|
return;
|
|
30229
30738
|
if (existing.status === "healthy" && !existing.lastError && !existing.lastErrorAt)
|
|
30230
30739
|
return;
|
|
30231
|
-
|
|
30232
|
-
|
|
30233
|
-
|
|
30234
|
-
|
|
30235
|
-
});
|
|
30740
|
+
const healthy = { ...existing, status: "healthy" };
|
|
30741
|
+
delete healthy.lastError;
|
|
30742
|
+
delete healthy.lastErrorAt;
|
|
30743
|
+
this.runtimes.set(id, healthy);
|
|
30236
30744
|
this.log.info("runtime marked healthy again", { runtimeId: id });
|
|
30237
30745
|
this.scheduleReadyFrameResend();
|
|
30238
30746
|
}
|
|
@@ -31813,15 +32321,15 @@ class MessageReminderScheduler {
|
|
|
31813
32321
|
const startedAt = this.now();
|
|
31814
32322
|
const dueAt = startedAt + input.remindAfterMs;
|
|
31815
32323
|
const sentRef = `${input.channel}#${input.sentSeq}`;
|
|
31816
|
-
const
|
|
32324
|
+
const record5 = {
|
|
31817
32325
|
...input,
|
|
31818
32326
|
sentRef,
|
|
31819
32327
|
startedAt,
|
|
31820
32328
|
dueAt,
|
|
31821
32329
|
timer: undefined
|
|
31822
32330
|
};
|
|
31823
|
-
|
|
31824
|
-
if (this.reminders.get(key) !==
|
|
32331
|
+
record5.timer = this.setTimer(() => {
|
|
32332
|
+
if (this.reminders.get(key) !== record5)
|
|
31825
32333
|
return;
|
|
31826
32334
|
this.reminders.delete(key);
|
|
31827
32335
|
try {
|
|
@@ -31832,8 +32340,8 @@ class MessageReminderScheduler {
|
|
|
31832
32340
|
Promise.resolve(delivery).catch(() => {});
|
|
31833
32341
|
} catch {}
|
|
31834
32342
|
}, input.remindAfterMs);
|
|
31835
|
-
|
|
31836
|
-
this.reminders.set(key,
|
|
32343
|
+
record5.timer.unref?.();
|
|
32344
|
+
this.reminders.set(key, record5);
|
|
31837
32345
|
return { armed: true, dueAt };
|
|
31838
32346
|
}
|
|
31839
32347
|
observe(agentId, channel2, latestSeq) {
|
|
@@ -32108,15 +32616,12 @@ class DaemonSelfSleepScheduler {
|
|
|
32108
32616
|
import { chmod, mkdir, open, readFile as readFile2, rename, rm } from "node:fs/promises";
|
|
32109
32617
|
import { dirname as dirname6, join as join14 } from "node:path";
|
|
32110
32618
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
32111
|
-
function
|
|
32112
|
-
|
|
32619
|
+
function oldestRetainedDay(at, timeZone) {
|
|
32620
|
+
const today = dayKeyInTimeZone(at, timeZone);
|
|
32621
|
+
return calendarDayKeyDaysAgo(today, 8);
|
|
32113
32622
|
}
|
|
32114
|
-
function
|
|
32115
|
-
|
|
32116
|
-
for (let offset = 0;offset < 7; offset += 1) {
|
|
32117
|
-
days.add(dayKey(new Date(at.getTime() - offset * 86400000)));
|
|
32118
|
-
}
|
|
32119
|
-
return days;
|
|
32623
|
+
function oldestVisibleDay(today) {
|
|
32624
|
+
return calendarDayKeyDaysAgo(today, 6);
|
|
32120
32625
|
}
|
|
32121
32626
|
function isMetric(value) {
|
|
32122
32627
|
return value === null || typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
@@ -32161,16 +32666,25 @@ class DailyTokenUsageStore {
|
|
|
32161
32666
|
loaded = false;
|
|
32162
32667
|
data = { version: 1, bots: {} };
|
|
32163
32668
|
filePath;
|
|
32164
|
-
|
|
32669
|
+
resolveTimeZone;
|
|
32670
|
+
constructor(workingDirectoryBase, now = () => new Date, timeZone = () => Intl.DateTimeFormat().resolvedOptions().timeZone) {
|
|
32165
32671
|
this.now = now;
|
|
32672
|
+
this.resolveTimeZone = typeof timeZone === "string" ? () => timeZone : timeZone;
|
|
32673
|
+
this.timeZone;
|
|
32166
32674
|
this.filePath = join14(workingDirectoryBase, ".telemetry", "daily-token-usage.json");
|
|
32167
32675
|
}
|
|
32676
|
+
get timeZone() {
|
|
32677
|
+
const timeZone = this.resolveTimeZone();
|
|
32678
|
+
dayKeyInTimeZone(0, timeZone);
|
|
32679
|
+
return timeZone;
|
|
32680
|
+
}
|
|
32168
32681
|
record(botId, delta) {
|
|
32169
32682
|
return this.enqueue(async () => {
|
|
32170
32683
|
await this.load();
|
|
32171
32684
|
const at = this.now();
|
|
32172
|
-
this.
|
|
32173
|
-
|
|
32685
|
+
const timeZone = this.timeZone;
|
|
32686
|
+
this.prune(at, timeZone);
|
|
32687
|
+
const day = dayKeyInTimeZone(at, timeZone);
|
|
32174
32688
|
const snapshots = this.data.bots[botId] ?? [];
|
|
32175
32689
|
const existing = snapshots.find((snapshot) => snapshot.day === day);
|
|
32176
32690
|
const next = existing ?? emptySnapshot(botId, day);
|
|
@@ -32187,13 +32701,27 @@ class DailyTokenUsageStore {
|
|
|
32187
32701
|
});
|
|
32188
32702
|
}
|
|
32189
32703
|
snapshots(botId) {
|
|
32704
|
+
return this.usageWindow(botId).then((window2) => window2.snapshots);
|
|
32705
|
+
}
|
|
32706
|
+
usageWindow(botId) {
|
|
32190
32707
|
let result = [];
|
|
32708
|
+
let usageDay = "";
|
|
32709
|
+
let usageTimeZone = "";
|
|
32191
32710
|
return this.enqueue(async () => {
|
|
32192
32711
|
await this.load();
|
|
32193
|
-
|
|
32712
|
+
const at = this.now();
|
|
32713
|
+
const timeZone = this.timeZone;
|
|
32714
|
+
usageTimeZone = timeZone;
|
|
32715
|
+
usageDay = dayKeyInTimeZone(at, timeZone);
|
|
32716
|
+
if (this.prune(at, timeZone))
|
|
32194
32717
|
await this.persist();
|
|
32195
|
-
|
|
32196
|
-
|
|
32718
|
+
const oldestDay = oldestVisibleDay(usageDay);
|
|
32719
|
+
result = (this.data.bots[botId] ?? []).filter((snapshot) => snapshot.day >= oldestDay && snapshot.day <= usageDay).map((snapshot) => structuredClone(snapshot));
|
|
32720
|
+
}).then(() => ({
|
|
32721
|
+
usageDay,
|
|
32722
|
+
usageTimeZone,
|
|
32723
|
+
snapshots: result
|
|
32724
|
+
}));
|
|
32197
32725
|
}
|
|
32198
32726
|
enqueue(operation) {
|
|
32199
32727
|
const result = this.tail.then(operation, operation);
|
|
@@ -32238,11 +32766,11 @@ class DailyTokenUsageStore {
|
|
|
32238
32766
|
this.data = { version: 1, bots: valid };
|
|
32239
32767
|
this.loaded = true;
|
|
32240
32768
|
}
|
|
32241
|
-
prune(at) {
|
|
32242
|
-
const
|
|
32769
|
+
prune(at, timeZone) {
|
|
32770
|
+
const oldestDay = oldestRetainedDay(at, timeZone);
|
|
32243
32771
|
let changed = false;
|
|
32244
32772
|
for (const [botId, snapshots] of Object.entries(this.data.bots)) {
|
|
32245
|
-
const retained = snapshots.filter((snapshot) =>
|
|
32773
|
+
const retained = snapshots.filter((snapshot) => snapshot.day >= oldestDay).sort((a, b) => a.day.localeCompare(b.day));
|
|
32246
32774
|
if (retained.length !== snapshots.length || retained.some((snapshot, index2) => snapshot !== snapshots[index2]))
|
|
32247
32775
|
changed = true;
|
|
32248
32776
|
if (retained.length === 0)
|
|
@@ -32286,6 +32814,7 @@ var WARMUP_CEILING_MS = 30000;
|
|
|
32286
32814
|
var RUNTIME_RAW_TRACE_MAX_BYTES = 8 * 1024 * 1024;
|
|
32287
32815
|
var RUNTIME_RAW_TRACE_AGENT_IDS_ENV = "ALOOK_RUNTIME_RAW_TRACE_AGENT_IDS";
|
|
32288
32816
|
var STATUS_WRITE_INTERVAL_MS = 5000;
|
|
32817
|
+
var TOKEN_USAGE_BACKENDS = new Set(["claude", "codex", "opencode", "pi"]);
|
|
32289
32818
|
function parseRuntimeRawTraceAgentIds(value) {
|
|
32290
32819
|
return new Set((value ?? "").split(",").map((agentId) => agentId.trim()).filter((agentId) => agentId.length > 0 && agentId !== "*"));
|
|
32291
32820
|
}
|
|
@@ -32462,10 +32991,14 @@ async function createDaemon(opts) {
|
|
|
32462
32991
|
recordProviderQuota("claude", observed);
|
|
32463
32992
|
}
|
|
32464
32993
|
const quota = backendId === "claude" || backendId === "codex" ? providerQuotaByBackend.get(backendId) : undefined;
|
|
32465
|
-
const
|
|
32994
|
+
const usageWindow = backendId && TOKEN_USAGE_BACKENDS.has(backendId) ? await dailyTokenUsage2.usageWindow(info.agentId) : null;
|
|
32466
32995
|
return {
|
|
32467
32996
|
...info,
|
|
32468
|
-
...
|
|
32997
|
+
...usageWindow ? {
|
|
32998
|
+
usageTimeZone: usageWindow.usageTimeZone,
|
|
32999
|
+
usageDay: usageWindow.usageDay,
|
|
33000
|
+
...usageWindow.snapshots.length > 0 ? { dailyUsage: usageWindow.snapshots } : {}
|
|
33001
|
+
} : {},
|
|
32469
33002
|
...quota ? { quota: structuredClone(quota) } : {}
|
|
32470
33003
|
};
|
|
32471
33004
|
};
|
|
@@ -32877,6 +33410,7 @@ async function createDaemon(opts) {
|
|
|
32877
33410
|
arch: opts.arch,
|
|
32878
33411
|
osRelease: opts.osRelease,
|
|
32879
33412
|
daemonVersion: opts.daemonVersion,
|
|
33413
|
+
timeZone: () => dailyTokenUsage2.timeZone,
|
|
32880
33414
|
providerQuotas: providerQuotaSnapshots,
|
|
32881
33415
|
resyncActivities: async () => {
|
|
32882
33416
|
const activities = await Promise.all(manager.liveAgentActivities().map((info) => activityPayload(info)));
|
|
@@ -34128,11 +34662,11 @@ async function strictOutcome(response, allowed) {
|
|
|
34128
34662
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
34129
34663
|
return { kind: "retryable" };
|
|
34130
34664
|
}
|
|
34131
|
-
const
|
|
34132
|
-
if (Object.keys(
|
|
34665
|
+
const record5 = value;
|
|
34666
|
+
if (Object.keys(record5).length !== 2 || record5.kind !== "terminal") {
|
|
34133
34667
|
return { kind: "retryable" };
|
|
34134
34668
|
}
|
|
34135
|
-
const status =
|
|
34669
|
+
const status = record5.status;
|
|
34136
34670
|
if (status !== "uploaded" && status !== "failed" || allowed[status] !== response.status) {
|
|
34137
34671
|
return { kind: "retryable" };
|
|
34138
34672
|
}
|
|
@@ -34626,7 +35160,7 @@ function createDaemonProcessLogger(daemonDir, foreground) {
|
|
|
34626
35160
|
`) : quiet,
|
|
34627
35161
|
err: foreground ? (line2) => process.stderr.write(line2 + `
|
|
34628
35162
|
`) : quiet,
|
|
34629
|
-
record: (
|
|
35163
|
+
record: (record5) => sink.write(JSON.stringify(record5))
|
|
34630
35164
|
});
|
|
34631
35165
|
return { logger, logPath, sink };
|
|
34632
35166
|
}
|
|
@@ -35369,18 +35903,18 @@ function readCredentialFile(filePath) {
|
|
|
35369
35903
|
} catch {}
|
|
35370
35904
|
return null;
|
|
35371
35905
|
}
|
|
35372
|
-
function writeCredentialFile(filePath,
|
|
35373
|
-
writePrivateJsonAtomic2(filePath,
|
|
35906
|
+
function writeCredentialFile(filePath, record5) {
|
|
35907
|
+
writePrivateJsonAtomic2(filePath, record5);
|
|
35374
35908
|
}
|
|
35375
35909
|
function readDaemonLaunchRecord(baseDir, machineId) {
|
|
35376
|
-
const
|
|
35377
|
-
if (!
|
|
35910
|
+
const record5 = readCredentialFile(credentialFilePathByMachineId(baseDir, machineId));
|
|
35911
|
+
if (!record5 || !("schemaVersion" in record5) || record5.schemaVersion !== 1 || !parseReleaseVersion(record5.daemonVersion)) {
|
|
35378
35912
|
throw new Error("daemon launch record is missing or requires a manual start upgrade");
|
|
35379
35913
|
}
|
|
35380
|
-
validateMachineId(
|
|
35381
|
-
if (
|
|
35914
|
+
validateMachineId(record5.machineId);
|
|
35915
|
+
if (record5.machineId !== machineId)
|
|
35382
35916
|
throw new Error("daemon launch record machine mismatch");
|
|
35383
|
-
return
|
|
35917
|
+
return record5;
|
|
35384
35918
|
}
|
|
35385
35919
|
function findExistingCredentialForBearer(baseDir, bearer) {
|
|
35386
35920
|
const dir = daemonsDir(baseDir);
|
|
@@ -35545,23 +36079,23 @@ async function daemonResume(opts) {
|
|
|
35545
36079
|
if (!/^[A-Za-z0-9_-]{16,128}$/.test(opts.requestId))
|
|
35546
36080
|
throw new Error("invalid replacement request id");
|
|
35547
36081
|
const baseDir = opts.baseDir || process.env.ALOOK_DATA_DIR || DEFAULT_BASE_DIR;
|
|
35548
|
-
const
|
|
36082
|
+
const record5 = readDaemonLaunchRecord(baseDir, opts.id);
|
|
35549
36083
|
if (false) {}
|
|
35550
36084
|
await daemonStart({
|
|
35551
|
-
machineKey:
|
|
35552
|
-
serverUrl:
|
|
35553
|
-
wsUrl:
|
|
36085
|
+
machineKey: record5.credential,
|
|
36086
|
+
serverUrl: record5.serverUrl,
|
|
36087
|
+
wsUrl: record5.wsUrl,
|
|
35554
36088
|
baseDir,
|
|
35555
36089
|
resumeRequestId: opts.requestId
|
|
35556
36090
|
});
|
|
35557
36091
|
}
|
|
35558
36092
|
async function daemonStartById(opts) {
|
|
35559
36093
|
const baseDir = opts.baseDir || process.env.ALOOK_DATA_DIR || DEFAULT_BASE_DIR;
|
|
35560
|
-
const
|
|
36094
|
+
const record5 = readDaemonLaunchRecord(baseDir, opts.id);
|
|
35561
36095
|
await daemonStart({
|
|
35562
|
-
machineKey:
|
|
35563
|
-
serverUrl:
|
|
35564
|
-
wsUrl:
|
|
36096
|
+
machineKey: record5.credential,
|
|
36097
|
+
serverUrl: record5.serverUrl,
|
|
36098
|
+
wsUrl: record5.wsUrl,
|
|
35565
36099
|
baseDir,
|
|
35566
36100
|
foreground: opts.foreground
|
|
35567
36101
|
});
|