@agentconnect.md/daemon 1.0.0-rc.309 → 1.0.0-rc.310
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/{acp-host-BDcV2bZY.js → acp-host-DEjB1yFS.js} +5 -4
- package/dist/{acp-host-BDcV2bZY.js.map → acp-host-DEjB1yFS.js.map} +1 -1
- package/dist/{chat-BUFOmSMl.js → chat-CfRG8UQR.js} +2 -2
- package/dist/{chat-BUFOmSMl.js.map → chat-CfRG8UQR.js.map} +1 -1
- package/dist/index.js +3 -3
- package/dist/{login-CcV7neWZ.js → login-H-H07Q2J.js} +2 -2
- package/dist/{login-CcV7neWZ.js.map → login-H-H07Q2J.js.map} +1 -1
- package/dist/run-foreground-BVC7qytz.js +2 -0
- package/dist/{run-foreground-DoM1PkHn.js → run-foreground-BZ63Vsmq.js} +340 -38
- package/dist/{run-foreground-DoM1PkHn.js.map → run-foreground-BZ63Vsmq.js.map} +1 -1
- package/package.json +1 -1
- package/dist/run-foreground-B-FPE0tJ.js +0 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as agentChildEnv, i as selectAgent, o as loadConfig } from "./load-agents-CROyMyq9.js";
|
|
2
2
|
import { l as resolveRoot } from "./paths-DEcUO8lC.js";
|
|
3
|
-
import { C as resolveRuntimes, a as prepareWorkspace, f as memoryProviderFor, t as AcpHost } from "./acp-host-
|
|
3
|
+
import { C as resolveRuntimes, a as prepareWorkspace, f as memoryProviderFor, t as AcpHost } from "./acp-host-DEjB1yFS.js";
|
|
4
4
|
import { createInterface } from "node:readline";
|
|
5
5
|
//#region src/cli/chat.ts
|
|
6
6
|
function renderUpdate(out) {
|
|
@@ -84,4 +84,4 @@ async function runChat(opts) {
|
|
|
84
84
|
//#endregion
|
|
85
85
|
export { renderUpdate, runChat };
|
|
86
86
|
|
|
87
|
-
//# sourceMappingURL=chat-
|
|
87
|
+
//# sourceMappingURL=chat-CfRG8UQR.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-
|
|
1
|
+
{"version":3,"file":"chat-CfRG8UQR.js","names":[],"sources":["../src/cli/chat.ts"],"sourcesContent":["import { createInterface } from 'node:readline'\nimport type { ContentBlock, SessionUpdate } from '@agentclientprotocol/sdk'\nimport { loadConfig } from '../config/load-config.js'\nimport { resolveRuntimes } from '../runtimes/registry.js'\nimport { selectAgent } from '../agents/load-agents.js'\nimport { agentChildEnv } from '../agents/agent-env.js'\nimport { memoryProviderFor } from '../agents/memory-provider.js'\nimport { prepareWorkspace } from '../workspace/workspace-manager.js'\nimport { AcpHost } from '../acp/acp-host.js'\nimport { resolveRoot } from '../paths.js'\n\nexport function renderUpdate(out: NodeJS.WritableStream) {\n return (_sessionId: string, update: SessionUpdate): void => {\n if (update.sessionUpdate === 'agent_message_chunk' && update.content.type === 'text') {\n out.write(update.content.text)\n } else if (update.sessionUpdate === 'tool_call') {\n const title = ('title' in update && update.title) || update.toolCallId || 'tool'\n out.write(`\\n[tool] ${title}\\n`)\n }\n }\n}\n\nexport interface RunChatOpts {\n agentsDir?: string\n agentName?: string\n message?: string\n configPath?: string\n root?: string\n out?: NodeJS.WritableStream\n input?: NodeJS.ReadableStream\n}\n\nexport async function runChat(opts: RunChatOpts): Promise<void> {\n const out = opts.out ?? process.stdout\n const root = resolveRoot(opts.root)\n const cfg = loadConfig({\n root: opts.root,\n configPath: opts.configPath,\n optional: true,\n overrides: { agentsDir: opts.agentsDir }\n })\n const agent = selectAgent(cfg.agentsDir!, opts.agentName)\n\n const runtimes = await resolveRuntimes(cfg, root, { neededRuntimes: [agent.runtime], mode: 'cache-first' })\n const runtime = runtimes[agent.runtime]\n if (!runtime) {\n const available = Object.keys(runtimes).sort().join(', ') || '(none)'\n throw new Error(`runtime \"${agent.runtime}\" not found. Available: ${available}`)\n }\n\n const host = new AcpHost(runtime, {\n onUpdate: renderUpdate(out),\n // Memory-backend env for parity with the daemon (managed disables the runtime's\n // own memory; native redirects it under the agent root).\n env: { ...agentChildEnv(agent), ...memoryProviderFor(agent, runtime).runtimeEnv() },\n configPrefs: {\n model: agent.runtimeOverrides?.model,\n permissionMode: agent.permissionMode,\n reasoningEffort: agent.reasoningEffort,\n fastMode: agent.fastMode\n }\n })\n // The adapter child runs in its own process group (see AcpHost.start), so a\n // terminal Ctrl-C no longer kills it as a side effect — Node's default SIGINT\n // exit would skip the finally below and leak it. Stop the host, then re-exit.\n // Registered BEFORE start(): a first-run `npx -y` runtime download takes long\n // enough that Ctrl-C mid-start is common, and the spawn happens early in start().\n const onSigint = () => {\n void host.stop().finally(() => process.exit(130))\n }\n process.once('SIGINT', onSigint)\n try {\n await host.start()\n const cwd = await prepareWorkspace(agent)\n const sessionId = await host.newSession(cwd)\n\n const send = async (text: string) => {\n const blocks: ContentBlock[] = [{ type: 'text', text }]\n await host.prompt(sessionId, blocks)\n out.write('\\n')\n }\n\n if (typeof opts.message === 'string' && opts.message.length > 0) {\n await send(opts.message)\n return\n }\n\n const rl = createInterface({ input: opts.input ?? process.stdin })\n out.write(`Chatting with ${agent.name} (${agent.id}). Type .exit to quit.\\n> `)\n try {\n for await (const line of rl) {\n const text = line.trim()\n if (text === '.exit' || text === '.quit') break\n if (text.length > 0) await send(text)\n out.write('> ')\n }\n } finally {\n rl.close()\n }\n } finally {\n process.removeListener('SIGINT', onSigint)\n await host.stop()\n }\n}\n"],"mappings":";;;;;AAWA,SAAgB,aAAa,KAA4B;CACvD,QAAQ,YAAoB,WAAgC;EAC1D,IAAI,OAAO,kBAAkB,yBAAyB,OAAO,QAAQ,SAAS,QAC5E,IAAI,MAAM,OAAO,QAAQ,IAAI;OACxB,IAAI,OAAO,kBAAkB,aAAa;GAC/C,MAAM,QAAS,WAAW,UAAU,OAAO,SAAU,OAAO,cAAc;GAC1E,IAAI,MAAM,YAAY,MAAM,GAAG;EACjC;CACF;AACF;AAYA,eAAsB,QAAQ,MAAkC;CAC9D,MAAM,MAAM,KAAK,OAAO,QAAQ;CAChC,MAAM,OAAO,YAAY,KAAK,IAAI;CAClC,MAAM,MAAM,WAAW;EACrB,MAAM,KAAK;EACX,YAAY,KAAK;EACjB,UAAU;EACV,WAAW,EAAE,WAAW,KAAK,UAAU;CACzC,CAAC;CACD,MAAM,QAAQ,YAAY,IAAI,WAAY,KAAK,SAAS;CAExD,MAAM,WAAW,MAAM,gBAAgB,KAAK,MAAM;EAAE,gBAAgB,CAAC,MAAM,OAAO;EAAG,MAAM;CAAc,CAAC;CAC1G,MAAM,UAAU,SAAS,MAAM;CAC/B,IAAI,CAAC,SAAS;EACZ,MAAM,YAAY,OAAO,KAAK,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,KAAK;EAC7D,MAAM,IAAI,MAAM,YAAY,MAAM,QAAQ,0BAA0B,WAAW;CACjF;CAEA,MAAM,OAAO,IAAI,QAAQ,SAAS;EAChC,UAAU,aAAa,GAAG;EAG1B,KAAK;GAAE,GAAG,cAAc,KAAK;GAAG,GAAG,kBAAkB,OAAO,OAAO,CAAC,CAAC,WAAW;EAAE;EAClF,aAAa;GACX,OAAO,MAAM,kBAAkB;GAC/B,gBAAgB,MAAM;GACtB,iBAAiB,MAAM;GACvB,UAAU,MAAM;EAClB;CACF,CAAC;CAMD,MAAM,iBAAiB;EACrB,KAAU,KAAK,CAAC,CAAC,cAAc,QAAQ,KAAK,GAAG,CAAC;CAClD;CACA,QAAQ,KAAK,UAAU,QAAQ;CAC/B,IAAI;EACF,MAAM,KAAK,MAAM;EACjB,MAAM,MAAM,MAAM,iBAAiB,KAAK;EACxC,MAAM,YAAY,MAAM,KAAK,WAAW,GAAG;EAE3C,MAAM,OAAO,OAAO,SAAiB;GACnC,MAAM,SAAyB,CAAC;IAAE,MAAM;IAAQ;GAAK,CAAC;GACtD,MAAM,KAAK,OAAO,WAAW,MAAM;GACnC,IAAI,MAAM,IAAI;EAChB;EAEA,IAAI,OAAO,KAAK,YAAY,YAAY,KAAK,QAAQ,SAAS,GAAG;GAC/D,MAAM,KAAK,KAAK,OAAO;GACvB;EACF;EAEA,MAAM,KAAK,gBAAgB,EAAE,OAAO,KAAK,SAAS,QAAQ,MAAM,CAAC;EACjE,IAAI,MAAM,iBAAiB,MAAM,KAAK,IAAI,MAAM,GAAG,2BAA2B;EAC9E,IAAI;GACF,WAAW,MAAM,QAAQ,IAAI;IAC3B,MAAM,OAAO,KAAK,KAAK;IACvB,IAAI,SAAS,WAAW,SAAS,SAAS;IAC1C,IAAI,KAAK,SAAS,GAAG,MAAM,KAAK,IAAI;IACpC,IAAI,MAAM,IAAI;GAChB;EACF,UAAU;GACR,GAAG,MAAM;EACX;CACF,UAAU;EACR,QAAQ,eAAe,UAAU,QAAQ;EACzC,MAAM,KAAK,KAAK;CAClB;AACF"}
|
package/dist/index.js
CHANGED
|
@@ -68492,9 +68492,9 @@ const telemetry = startDaemonOpenTelemetry({ serviceVersion: DAEMON_VERSION });
|
|
|
68492
68492
|
const [{ Command }, { fileURLToPath }, { runChat }, { runLogin }, { runForeground }, { resolveController }, { acquireSingletonLock }, { resolveRoot }] = await Promise.all([
|
|
68493
68493
|
import("./commander-B5QVEFzH.js"),
|
|
68494
68494
|
import("node:url"),
|
|
68495
|
-
import("./chat-
|
|
68496
|
-
import("./login-
|
|
68497
|
-
import("./run-foreground-
|
|
68495
|
+
import("./chat-CfRG8UQR.js"),
|
|
68496
|
+
import("./login-H-H07Q2J.js"),
|
|
68497
|
+
import("./run-foreground-BVC7qytz.js"),
|
|
68498
68498
|
import("./service-6w0WKhdx.js"),
|
|
68499
68499
|
import("./lock-CA9Bm8_s.js"),
|
|
68500
68500
|
import("./paths-CcRUjFjy.js")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as DAEMON_VERSION } from "./version-DGaRXjBK.js";
|
|
2
2
|
import { d as encode, l as buildEnvelope, t as isFrame, u as decodeEnvelope } from "./dist-BG425zHm.js";
|
|
3
|
-
import { i as ClientTransport, t as runForeground } from "./run-foreground-
|
|
3
|
+
import { i as ClientTransport, t as runForeground } from "./run-foreground-BZ63Vsmq.js";
|
|
4
4
|
import { l as ConfigSchema } from "./load-agents-CROyMyq9.js";
|
|
5
5
|
import { l as resolveRoot, t as configPath } from "./paths-DEcUO8lC.js";
|
|
6
6
|
import { n as resolveController } from "./service-BQVw7wbz.js";
|
|
@@ -229,4 +229,4 @@ async function runLogin(opts, partial = {}) {
|
|
|
229
229
|
//#endregion
|
|
230
230
|
export { buildInstallOpts, persistCredentials, runLogin };
|
|
231
231
|
|
|
232
|
-
//# sourceMappingURL=login-
|
|
232
|
+
//# sourceMappingURL=login-H-H07Q2J.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login-CcV7neWZ.js","names":["realRunForeground"],"sources":["../src/cp/auth-probe.ts","../src/cli/login.ts"],"sourcesContent":["/**\n * `probeAuth` — a one-shot CP auth check used by `agentconnect login`. It dials\n * the CP, sends ONLY the `auth` frame (no `register`), and resolves with the\n * authoritative daemonId from `auth/ok`, or a human-readable failure reason on\n * a `4401` close, a correlated `error`, a dial failure, or a timeout. It always\n * closes the socket and never leaves a connection open.\n */\nimport { buildEnvelope, decodeEnvelope, encode, isFrame } from '@agentconnect.md/protocol'\nimport { ClientTransport, type Transport } from '@agentconnect.md/connection'\nimport { CP_SUBPROTOCOL, CP_WS_PATH } from './client.js'\n\nexport interface ProbeResult {\n ok: boolean\n daemonId?: string\n reason?: string\n}\n\nexport interface ProbeOpts {\n url: string\n token: string\n daemonId?: string\n agentVersion?: string\n timeoutMs?: number\n /** Injectable for tests; defaults to dialing the real WebSocket. */\n connect?: () => Promise<Transport>\n}\n\nexport async function probeAuth(opts: ProbeOpts): Promise<ProbeResult> {\n const timeoutMs = opts.timeoutMs ?? 10_000\n const dial = opts.connect ?? (() => ClientTransport.dial(opts.url, { subprotocol: CP_SUBPROTOCOL, path: CP_WS_PATH }))\n\n let transport: Transport\n try {\n transport = await dial()\n } catch (err) {\n return { ok: false, reason: `cannot reach ${opts.url}: ${(err as Error).message}` }\n }\n\n const authPayload: Record<string, unknown> = {\n apiKey: opts.token,\n agentVersion: opts.agentVersion ?? 'probe'\n }\n if (opts.daemonId) authPayload.daemonId = opts.daemonId\n const frame = buildEnvelope('auth', authPayload)\n\n return await new Promise<ProbeResult>((resolve) => {\n let settled = false\n const done = (r: ProbeResult): void => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n try {\n transport.close(1000, 'probe done')\n } catch {\n // socket may already be closed\n }\n resolve(r)\n }\n\n const timer = setTimeout(\n () => done({ ok: false, reason: `timed out after ${timeoutMs}ms waiting for auth/ok` }),\n timeoutMs\n )\n\n transport.onMessage((text) => {\n const decoded = decodeEnvelope(text)\n if (!decoded.ok) return\n const f = decoded.frame\n if (f.corr !== frame.id) return\n if (f.type === 'error') {\n const e = f.payload as { code: string; message: string }\n done({ ok: false, reason: `${e.code}: ${e.message}` })\n return\n }\n if (isFrame('auth/ok')(f)) {\n const ok = f.payload as { daemonId: string }\n done({ ok: true, daemonId: ok.daemonId })\n }\n })\n\n transport.onClose((code) => {\n if (code === 4401) done({ ok: false, reason: 'authentication failed (4401) — check the daemon token' })\n else done({ ok: false, reason: `connection closed (${code}) before auth/ok` })\n })\n\n transport.send(encode(frame))\n })\n}\n","/**\n * `agentconnect login` — interactive onboarding. It tests the Control Plane auth\n * flow, persists credentials only on success, then offers to install the OS\n * service. If installed it starts the service (`up`) and returns; otherwise it\n * runs the daemon in the foreground (the same path as `agentconnect run`).\n *\n * `persistCredentials` is the pure config-merge half (token-only onboarding:\n * `daemonId` is omitted unless given — the first connect adopts it from the\n * token's `sub`). `runLogin` is the orchestrator, with injectable deps for tests.\n */\nimport { readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { createInterface } from 'node:readline'\nimport { fileURLToPath } from 'node:url'\nimport { ConfigSchema } from '../config/config-schema.js'\nimport { resolveRoot, configPath } from '../paths.js'\nimport { DAEMON_VERSION } from '../version.js'\nimport { probeAuth, type ProbeResult } from '../cp/auth-probe.js'\nimport { resolveController, type InstallOpts } from '../service/index.js'\nimport { runForeground as realRunForeground } from './run-foreground.js'\n\nexport interface PersistCredsOpts {\n cpUrl: string\n cpKey: string\n daemonId?: string\n root?: string\n configPath?: string\n}\n\n/** Merge url/token into config.json (validated), returning the written path. */\nexport function persistCredentials(opts: PersistCredsOpts): string {\n const root = resolveRoot(opts.root)\n const file = opts.configPath ?? configPath(root)\n const raw: Record<string, unknown> = existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) : { version: 1 }\n\n const cp = (raw.controlPlane as Record<string, unknown> | undefined) ?? {}\n raw.controlPlane = { ...cp, url: opts.cpUrl, key: opts.cpKey, enabled: true }\n if (opts.daemonId) raw.daemonId = opts.daemonId\n\n ConfigSchema.parse(raw) // fail before writing if the merge is invalid\n\n mkdirSync(dirname(file), { recursive: true })\n writeFileSync(file, JSON.stringify(raw, null, 2) + '\\n')\n return file\n}\n\nexport interface RunLoginOpts {\n cpUrl?: string\n cpKey?: string\n daemonId?: string\n root?: string\n configPath?: string\n /** The resolved CLI entry path. Must be supplied by the CLI entry point\n * (index.ts) so the correct bundle path is used rather than inferring it\n * from login.ts's own import.meta.url (which is the same bundle but the\n * `../` path calculation would be wrong). Falls back to import.meta.url\n * for the pure test path where login.ts is loaded standalone. */\n cliEntry?: string\n}\n\n/**\n * Build the InstallOpts for the OS service installer.\n *\n * Exported as a pure helper so it can be unit-tested independently of the\n * full `runLogin` orchestration. The caller (index.ts) passes `cliEntry` so\n * the correct bundle path always flows through; if omitted we fall back to\n * `import.meta.url` (correct only when login.ts is the entry, e.g. in tests).\n */\nexport function buildInstallOpts(opts: { root?: string; cliEntry?: string }): InstallOpts {\n return {\n execPath: process.execPath,\n cliEntry: opts.cliEntry ?? fileURLToPath(import.meta.url),\n includeRootEnv: resolveRoot(opts.root) !== resolveRoot(undefined)\n }\n}\n\nexport interface LoginDeps {\n probe: (o: { url: string; token: string }) => Promise<ProbeResult>\n installService: () => Promise<void>\n runForeground: () => Promise<void>\n out: NodeJS.WritableStream\n input: NodeJS.ReadableStream\n isTTY: boolean\n}\n\nfunction realDeps(opts: RunLoginOpts): LoginDeps {\n return {\n probe: (o) => probeAuth({ url: o.url, token: o.token, agentVersion: DAEMON_VERSION }),\n installService: async () => {\n const controller = resolveController({ root: opts.root })\n await controller.install(buildInstallOpts(opts))\n await controller.up()\n },\n runForeground: () =>\n realRunForeground({\n root: opts.root,\n overrides: { cpUrl: opts.cpUrl, cpKey: opts.cpKey, daemonId: opts.daemonId }\n }),\n out: process.stdout,\n input: process.stdin,\n isTTY: Boolean(process.stdin.isTTY)\n }\n}\n\n/** Read the next line from a readline interface via async iterator. */\nasync function nextLine(\n iter: AsyncIterableIterator<string>,\n prompt: string,\n out: NodeJS.WritableStream\n): Promise<string> {\n out.write(prompt)\n const { value, done } = await iter.next()\n if (done) throw new Error(`unexpected end of input waiting for: ${prompt}`)\n return (value as string).trim()\n}\n\nexport async function runLogin(opts: RunLoginOpts, partial: Partial<LoginDeps> = {}): Promise<void> {\n const deps: LoginDeps = { ...realDeps(opts), ...partial }\n const { out } = deps\n\n // ── Non-interactive: flags required; probe; persist. No prompts, no handoff. ──\n if (!deps.isTTY) {\n if (!opts.cpUrl) throw new Error('login requires --cp-url <url>')\n if (!opts.cpKey) throw new Error('login requires --cp-key <key>')\n const r = await deps.probe({ url: opts.cpUrl, token: opts.cpKey })\n if (!r.ok) throw new Error(`authentication failed: ${r.reason}`)\n persistCredentials({ ...opts, cpUrl: opts.cpUrl, cpKey: opts.cpKey })\n out.write(`✓ authenticated${r.daemonId ? ` (daemon ${r.daemonId})` : ''} — credentials saved\\n`)\n return\n }\n\n // Both interactive handoffs read `<root>/config.json`: the installed service\n // runs `… run` (no `--config`), and the foreground `Daemon` loads by root. A\n // custom `--config` would persist credentials the daemon never reads, so the\n // install/run branch would look successful but start without them. Reject it;\n // `--root` is the knob that keeps persist + service + foreground in sync.\n if (opts.configPath) {\n throw new Error(\n 'interactive login does not support --config — use --root <dir> so the daemon and the installed service read the same config'\n )\n }\n\n // ── Interactive ──\n const rl = createInterface({ input: deps.input, output: out })\n const iter = rl[Symbol.asyncIterator]()\n let url = opts.cpUrl\n let token = opts.cpKey\n try {\n if (!url) url = await nextLine(iter, 'Control Plane URL: ', out)\n\n for (let attempt = 0; ; attempt++) {\n if (!token) token = await nextLine(iter, 'Daemon API key: ', out)\n out.write(`Testing connection to ${url}…\\n`)\n const r = await deps.probe({ url: url!, token: token! })\n if (r.ok) {\n out.write(`✓ authenticated${r.daemonId ? ` (daemon ${r.daemonId})` : ''}\\n`)\n break\n }\n out.write(`✗ ${r.reason}\\n`)\n if (attempt >= 1) throw new Error('authentication failed')\n token = undefined // re-prompt on retry\n }\n\n persistCredentials({ ...opts, cpUrl: url!, cpKey: token! })\n\n const ans = (await nextLine(iter, 'Install AgentConnect as a background service? (y/N) ', out)).toLowerCase()\n if (ans === 'y' || ans === 'yes') {\n await deps.installService()\n out.write('Service installed and started. Manage it with `agentconnect up` / `down` / `status`.\\n')\n return\n }\n out.write('Starting in the foreground (Ctrl-C to stop)…\\n')\n } finally {\n rl.close()\n }\n\n await deps.runForeground()\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"login-H-H07Q2J.js","names":["realRunForeground"],"sources":["../src/cp/auth-probe.ts","../src/cli/login.ts"],"sourcesContent":["/**\n * `probeAuth` — a one-shot CP auth check used by `agentconnect login`. It dials\n * the CP, sends ONLY the `auth` frame (no `register`), and resolves with the\n * authoritative daemonId from `auth/ok`, or a human-readable failure reason on\n * a `4401` close, a correlated `error`, a dial failure, or a timeout. It always\n * closes the socket and never leaves a connection open.\n */\nimport { buildEnvelope, decodeEnvelope, encode, isFrame } from '@agentconnect.md/protocol'\nimport { ClientTransport, type Transport } from '@agentconnect.md/connection'\nimport { CP_SUBPROTOCOL, CP_WS_PATH } from './client.js'\n\nexport interface ProbeResult {\n ok: boolean\n daemonId?: string\n reason?: string\n}\n\nexport interface ProbeOpts {\n url: string\n token: string\n daemonId?: string\n agentVersion?: string\n timeoutMs?: number\n /** Injectable for tests; defaults to dialing the real WebSocket. */\n connect?: () => Promise<Transport>\n}\n\nexport async function probeAuth(opts: ProbeOpts): Promise<ProbeResult> {\n const timeoutMs = opts.timeoutMs ?? 10_000\n const dial = opts.connect ?? (() => ClientTransport.dial(opts.url, { subprotocol: CP_SUBPROTOCOL, path: CP_WS_PATH }))\n\n let transport: Transport\n try {\n transport = await dial()\n } catch (err) {\n return { ok: false, reason: `cannot reach ${opts.url}: ${(err as Error).message}` }\n }\n\n const authPayload: Record<string, unknown> = {\n apiKey: opts.token,\n agentVersion: opts.agentVersion ?? 'probe'\n }\n if (opts.daemonId) authPayload.daemonId = opts.daemonId\n const frame = buildEnvelope('auth', authPayload)\n\n return await new Promise<ProbeResult>((resolve) => {\n let settled = false\n const done = (r: ProbeResult): void => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n try {\n transport.close(1000, 'probe done')\n } catch {\n // socket may already be closed\n }\n resolve(r)\n }\n\n const timer = setTimeout(\n () => done({ ok: false, reason: `timed out after ${timeoutMs}ms waiting for auth/ok` }),\n timeoutMs\n )\n\n transport.onMessage((text) => {\n const decoded = decodeEnvelope(text)\n if (!decoded.ok) return\n const f = decoded.frame\n if (f.corr !== frame.id) return\n if (f.type === 'error') {\n const e = f.payload as { code: string; message: string }\n done({ ok: false, reason: `${e.code}: ${e.message}` })\n return\n }\n if (isFrame('auth/ok')(f)) {\n const ok = f.payload as { daemonId: string }\n done({ ok: true, daemonId: ok.daemonId })\n }\n })\n\n transport.onClose((code) => {\n if (code === 4401) done({ ok: false, reason: 'authentication failed (4401) — check the daemon token' })\n else done({ ok: false, reason: `connection closed (${code}) before auth/ok` })\n })\n\n transport.send(encode(frame))\n })\n}\n","/**\n * `agentconnect login` — interactive onboarding. It tests the Control Plane auth\n * flow, persists credentials only on success, then offers to install the OS\n * service. If installed it starts the service (`up`) and returns; otherwise it\n * runs the daemon in the foreground (the same path as `agentconnect run`).\n *\n * `persistCredentials` is the pure config-merge half (token-only onboarding:\n * `daemonId` is omitted unless given — the first connect adopts it from the\n * token's `sub`). `runLogin` is the orchestrator, with injectable deps for tests.\n */\nimport { readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { createInterface } from 'node:readline'\nimport { fileURLToPath } from 'node:url'\nimport { ConfigSchema } from '../config/config-schema.js'\nimport { resolveRoot, configPath } from '../paths.js'\nimport { DAEMON_VERSION } from '../version.js'\nimport { probeAuth, type ProbeResult } from '../cp/auth-probe.js'\nimport { resolveController, type InstallOpts } from '../service/index.js'\nimport { runForeground as realRunForeground } from './run-foreground.js'\n\nexport interface PersistCredsOpts {\n cpUrl: string\n cpKey: string\n daemonId?: string\n root?: string\n configPath?: string\n}\n\n/** Merge url/token into config.json (validated), returning the written path. */\nexport function persistCredentials(opts: PersistCredsOpts): string {\n const root = resolveRoot(opts.root)\n const file = opts.configPath ?? configPath(root)\n const raw: Record<string, unknown> = existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) : { version: 1 }\n\n const cp = (raw.controlPlane as Record<string, unknown> | undefined) ?? {}\n raw.controlPlane = { ...cp, url: opts.cpUrl, key: opts.cpKey, enabled: true }\n if (opts.daemonId) raw.daemonId = opts.daemonId\n\n ConfigSchema.parse(raw) // fail before writing if the merge is invalid\n\n mkdirSync(dirname(file), { recursive: true })\n writeFileSync(file, JSON.stringify(raw, null, 2) + '\\n')\n return file\n}\n\nexport interface RunLoginOpts {\n cpUrl?: string\n cpKey?: string\n daemonId?: string\n root?: string\n configPath?: string\n /** The resolved CLI entry path. Must be supplied by the CLI entry point\n * (index.ts) so the correct bundle path is used rather than inferring it\n * from login.ts's own import.meta.url (which is the same bundle but the\n * `../` path calculation would be wrong). Falls back to import.meta.url\n * for the pure test path where login.ts is loaded standalone. */\n cliEntry?: string\n}\n\n/**\n * Build the InstallOpts for the OS service installer.\n *\n * Exported as a pure helper so it can be unit-tested independently of the\n * full `runLogin` orchestration. The caller (index.ts) passes `cliEntry` so\n * the correct bundle path always flows through; if omitted we fall back to\n * `import.meta.url` (correct only when login.ts is the entry, e.g. in tests).\n */\nexport function buildInstallOpts(opts: { root?: string; cliEntry?: string }): InstallOpts {\n return {\n execPath: process.execPath,\n cliEntry: opts.cliEntry ?? fileURLToPath(import.meta.url),\n includeRootEnv: resolveRoot(opts.root) !== resolveRoot(undefined)\n }\n}\n\nexport interface LoginDeps {\n probe: (o: { url: string; token: string }) => Promise<ProbeResult>\n installService: () => Promise<void>\n runForeground: () => Promise<void>\n out: NodeJS.WritableStream\n input: NodeJS.ReadableStream\n isTTY: boolean\n}\n\nfunction realDeps(opts: RunLoginOpts): LoginDeps {\n return {\n probe: (o) => probeAuth({ url: o.url, token: o.token, agentVersion: DAEMON_VERSION }),\n installService: async () => {\n const controller = resolveController({ root: opts.root })\n await controller.install(buildInstallOpts(opts))\n await controller.up()\n },\n runForeground: () =>\n realRunForeground({\n root: opts.root,\n overrides: { cpUrl: opts.cpUrl, cpKey: opts.cpKey, daemonId: opts.daemonId }\n }),\n out: process.stdout,\n input: process.stdin,\n isTTY: Boolean(process.stdin.isTTY)\n }\n}\n\n/** Read the next line from a readline interface via async iterator. */\nasync function nextLine(\n iter: AsyncIterableIterator<string>,\n prompt: string,\n out: NodeJS.WritableStream\n): Promise<string> {\n out.write(prompt)\n const { value, done } = await iter.next()\n if (done) throw new Error(`unexpected end of input waiting for: ${prompt}`)\n return (value as string).trim()\n}\n\nexport async function runLogin(opts: RunLoginOpts, partial: Partial<LoginDeps> = {}): Promise<void> {\n const deps: LoginDeps = { ...realDeps(opts), ...partial }\n const { out } = deps\n\n // ── Non-interactive: flags required; probe; persist. No prompts, no handoff. ──\n if (!deps.isTTY) {\n if (!opts.cpUrl) throw new Error('login requires --cp-url <url>')\n if (!opts.cpKey) throw new Error('login requires --cp-key <key>')\n const r = await deps.probe({ url: opts.cpUrl, token: opts.cpKey })\n if (!r.ok) throw new Error(`authentication failed: ${r.reason}`)\n persistCredentials({ ...opts, cpUrl: opts.cpUrl, cpKey: opts.cpKey })\n out.write(`✓ authenticated${r.daemonId ? ` (daemon ${r.daemonId})` : ''} — credentials saved\\n`)\n return\n }\n\n // Both interactive handoffs read `<root>/config.json`: the installed service\n // runs `… run` (no `--config`), and the foreground `Daemon` loads by root. A\n // custom `--config` would persist credentials the daemon never reads, so the\n // install/run branch would look successful but start without them. Reject it;\n // `--root` is the knob that keeps persist + service + foreground in sync.\n if (opts.configPath) {\n throw new Error(\n 'interactive login does not support --config — use --root <dir> so the daemon and the installed service read the same config'\n )\n }\n\n // ── Interactive ──\n const rl = createInterface({ input: deps.input, output: out })\n const iter = rl[Symbol.asyncIterator]()\n let url = opts.cpUrl\n let token = opts.cpKey\n try {\n if (!url) url = await nextLine(iter, 'Control Plane URL: ', out)\n\n for (let attempt = 0; ; attempt++) {\n if (!token) token = await nextLine(iter, 'Daemon API key: ', out)\n out.write(`Testing connection to ${url}…\\n`)\n const r = await deps.probe({ url: url!, token: token! })\n if (r.ok) {\n out.write(`✓ authenticated${r.daemonId ? ` (daemon ${r.daemonId})` : ''}\\n`)\n break\n }\n out.write(`✗ ${r.reason}\\n`)\n if (attempt >= 1) throw new Error('authentication failed')\n token = undefined // re-prompt on retry\n }\n\n persistCredentials({ ...opts, cpUrl: url!, cpKey: token! })\n\n const ans = (await nextLine(iter, 'Install AgentConnect as a background service? (y/N) ', out)).toLowerCase()\n if (ans === 'y' || ans === 'yes') {\n await deps.installService()\n out.write('Service installed and started. Manage it with `agentconnect up` / `down` / `status`.\\n')\n return\n }\n out.write('Starting in the foreground (Ctrl-C to stop)…\\n')\n } finally {\n rl.close()\n }\n\n await deps.runForeground()\n}\n"],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@ import { C as _coercedNumber, T as NEVER, a as array, d as literal, f as looseOb
|
|
|
6
6
|
import { a as RELAY_DAEMON_WS_PATH, c as SHARED_CONFIG_ACTION_ID, d as encode, f as MAX_FRAME_BYTES, g as ZodIssueCode, h as RESERVED_MCP_SERVER_NAME, i as RELAY_DAEMON_SUBPROTOCOL, l as buildEnvelope, n as gitRepoLabel, o as buildRelayDaemonFrame, r as normalizeGitUrl, s as decodeRelayDaemonFrame, u as decodeEnvelope } from "./dist-BG425zHm.js";
|
|
7
7
|
import { a as agentChildEnv, c as persistRelays, i as selectAgent, n as findAgentFiles, o as loadConfig, r as loadAgents, s as persistDaemonId } from "./load-agents-CROyMyq9.js";
|
|
8
8
|
import { l as resolveRoot, o as mcpSocketPath, u as statePath } from "./paths-DEcUO8lC.js";
|
|
9
|
-
import { C as resolveRuntimes, S as cachedRuntimeVersions, _ as resolveInMemoryDir, a as prepareWorkspace, b as toolsForIntegrations, c as sessionGitEnv, d as memoryKindOf, f as memoryProviderFor, g as listMemory, h as MemoryTooLargeError, i as prefetchWorkspace, l as simpleGit, m as MemoryPathError, n as turnFailureReason, o as initGitInjection, p as MemoryConflictError, r as installedRuntimes, s as probeGitVersion, t as AcpHost, u as createMemoryProvider, v as writeMemoryFile, x as cachedRuntimeNames, y as MEMORY_TOOL_NAMES } from "./acp-host-
|
|
9
|
+
import { C as resolveRuntimes, S as cachedRuntimeVersions, _ as resolveInMemoryDir, a as prepareWorkspace, b as toolsForIntegrations, c as sessionGitEnv, d as memoryKindOf, f as memoryProviderFor, g as listMemory, h as MemoryTooLargeError, i as prefetchWorkspace, l as simpleGit, m as MemoryPathError, n as turnFailureReason, o as initGitInjection, p as MemoryConflictError, r as installedRuntimes, s as probeGitVersion, t as AcpHost, u as createMemoryProvider, v as writeMemoryFile, x as cachedRuntimeNames, y as MEMORY_TOOL_NAMES } from "./acp-host-DEjB1yFS.js";
|
|
10
10
|
import { i as GitCredentialCache, n as gitcredSocketPath, r as writeGitcredShim, t as GitCredServer } from "./gitcred-server-Bu-Svl7L.js";
|
|
11
11
|
import { B as ToolListChangedNotificationSchema, D as ListPromptsResultSchema, E as ListChangedOptionsBaseSchema, F as PromptListChangedNotificationSchema, G as isZ4Schema, H as isJSONRPCRequest, I as ReadResourceResultSchema, J as encodeFrame, K as safeParse, L as ResourceListChangedNotificationSchema, M as ListToolsResultSchema, O as ListResourceTemplatesResultSchema, P as McpError, R as SUPPORTED_PROTOCOL_VERSIONS, S as InitializeResultSchema, T as LATEST_PROTOCOL_VERSION, U as isJSONRPCResultResponse, V as isInitializedNotification, W as getObjectShape, _ as ElicitResultSchema, a as AjvJsonSchemaValidator, b as GetPromptResultSchema, c as mergeCapabilities, d as CompleteResultSchema, f as CreateMessageRequestSchema, g as ElicitRequestSchema, h as CreateTaskResultSchema, i as assertToolsCallTaskCapability, k as ListResourcesResultSchema, m as CreateMessageResultWithToolsSchema, n as serializeMessage, o as require_fast_deep_equal, p as CreateMessageResultSchema, q as decodeFrames, r as assertClientRequestTaskCapability, s as Protocol, t as ReadBuffer, u as CallToolResultSchema, v as EmptyResultSchema, w as JSONRPCMessageSchema, y as ErrorCode } from "./stdio-DnS8WcXi.js";
|
|
12
12
|
import { createRequire } from "node:module";
|
|
@@ -6712,11 +6712,10 @@ var LocalStore = class {
|
|
|
6712
6712
|
writeUsage(key, u) {
|
|
6713
6713
|
this.db.prepare("UPDATE sessions SET usage = ? WHERE key = ?").run(JSON.stringify(u), key);
|
|
6714
6714
|
}
|
|
6715
|
-
/** Record the latest token counts for a session
|
|
6716
|
-
* running session total
|
|
6717
|
-
*
|
|
6718
|
-
*
|
|
6719
|
-
* created by the SessionManager first). */
|
|
6715
|
+
/** Record the latest token counts for a session when an adapter reports a
|
|
6716
|
+
* running session total. This is latest-wins over the token fields — never
|
|
6717
|
+
* additive. Only provided fields are updated; the context/cost snapshot is
|
|
6718
|
+
* left intact. No-op on an unknown key (the row is created first). */
|
|
6720
6719
|
setTokenUsage(key, counts) {
|
|
6721
6720
|
const u = this.getUsage(key);
|
|
6722
6721
|
if (counts.totalTokens !== void 0) u.totalTokens = counts.totalTokens;
|
|
@@ -6727,6 +6726,22 @@ var LocalStore = class {
|
|
|
6727
6726
|
if (counts.cachedWriteTokens !== void 0) u.cachedWriteTokens = counts.cachedWriteTokens;
|
|
6728
6727
|
this.writeUsage(key, u);
|
|
6729
6728
|
}
|
|
6729
|
+
/** Add one turn's token counts to the session total. codex-acp currently maps
|
|
6730
|
+
* Codex's `last_token_usage` into PromptResponse.usage, so its values are a
|
|
6731
|
+
* per-turn delta even though other ACP adapters return a session snapshot. */
|
|
6732
|
+
addTokenUsage(key, counts) {
|
|
6733
|
+
const u = this.getUsage(key);
|
|
6734
|
+
const add = (field, value) => {
|
|
6735
|
+
if (value !== void 0) u[field] = (u[field] ?? 0) + value;
|
|
6736
|
+
};
|
|
6737
|
+
add("totalTokens", counts.totalTokens);
|
|
6738
|
+
add("inputTokens", counts.inputTokens);
|
|
6739
|
+
add("outputTokens", counts.outputTokens);
|
|
6740
|
+
add("thoughtTokens", counts.thoughtTokens);
|
|
6741
|
+
add("cachedReadTokens", counts.cachedReadTokens);
|
|
6742
|
+
add("cachedWriteTokens", counts.cachedWriteTokens);
|
|
6743
|
+
this.writeUsage(key, u);
|
|
6744
|
+
}
|
|
6730
6745
|
/** Overwrite the session's context-window + cost snapshot (latest `usage_update`
|
|
6731
6746
|
* wins). Only provided fields are updated. No-op on an unknown key. */
|
|
6732
6747
|
setUsageSnapshot(key, snap) {
|
|
@@ -6737,6 +6752,17 @@ var LocalStore = class {
|
|
|
6737
6752
|
if (snap.costCurrency !== void 0) u.costCurrency = snap.costCurrency;
|
|
6738
6753
|
this.writeUsage(key, u);
|
|
6739
6754
|
}
|
|
6755
|
+
/** Add one turn's fallback cost to the session running total. Refuse to mix
|
|
6756
|
+
* currencies; a later ACP usage_update can still replace the total snapshot. */
|
|
6757
|
+
addCost(key, amount, currency) {
|
|
6758
|
+
if (!Number.isFinite(amount) || amount <= 0 || !currency) return false;
|
|
6759
|
+
const u = this.getUsage(key);
|
|
6760
|
+
if (u.costCurrency !== void 0 && u.costCurrency !== currency) return false;
|
|
6761
|
+
u.costAmount = (u.costAmount ?? 0) + amount;
|
|
6762
|
+
u.costCurrency = currency;
|
|
6763
|
+
this.writeUsage(key, u);
|
|
6764
|
+
return true;
|
|
6765
|
+
}
|
|
6740
6766
|
/** Most-recent activity across an agent's non-closed sessions (epoch ms), or null
|
|
6741
6767
|
* if it has none. Drives idle-host reaping (#111): a host with no recent session
|
|
6742
6768
|
* activity AND no in-flight turn is past its idle window. */
|
|
@@ -215101,6 +215127,239 @@ var SystemMetrics = class {
|
|
|
215101
215127
|
}
|
|
215102
215128
|
};
|
|
215103
215129
|
//#endregion
|
|
215130
|
+
//#region src/usage/openai-public-pricing.ts
|
|
215131
|
+
/**
|
|
215132
|
+
* Best-effort OpenAI Standard API list-price estimates for Codex turns.
|
|
215133
|
+
*
|
|
215134
|
+
* These values are deliberately static: the daemon must remain deterministic and
|
|
215135
|
+
* must not fetch pricing at runtime. Refresh the manifest with the repo-local
|
|
215136
|
+
* `$update-model-pricing` skill and keep the focused tests in sync.
|
|
215137
|
+
*
|
|
215138
|
+
* Source: https://developers.openai.com/api/docs/pricing
|
|
215139
|
+
* Verified: 2026-07-11
|
|
215140
|
+
*/
|
|
215141
|
+
const OPENAI_PUBLIC_PRICING_AS_OF = "2026-07-11";
|
|
215142
|
+
const TOKENS_PER_MILLION = 1e6;
|
|
215143
|
+
const LONG_CONTEXT_THRESHOLD = 272e3;
|
|
215144
|
+
/** Exact public model ids only. Never prefix-match an unknown future model. */
|
|
215145
|
+
const MODEL_PRICING = {
|
|
215146
|
+
"gpt-5.6-sol": {
|
|
215147
|
+
standard: {
|
|
215148
|
+
input: 5,
|
|
215149
|
+
cachedInput: .5,
|
|
215150
|
+
cacheWrite: 6.25,
|
|
215151
|
+
output: 30
|
|
215152
|
+
},
|
|
215153
|
+
longContext: {
|
|
215154
|
+
input: 10,
|
|
215155
|
+
cachedInput: 1,
|
|
215156
|
+
cacheWrite: 12.5,
|
|
215157
|
+
output: 45
|
|
215158
|
+
}
|
|
215159
|
+
},
|
|
215160
|
+
"gpt-5.6-terra": {
|
|
215161
|
+
standard: {
|
|
215162
|
+
input: 2.5,
|
|
215163
|
+
cachedInput: .25,
|
|
215164
|
+
cacheWrite: 3.125,
|
|
215165
|
+
output: 15
|
|
215166
|
+
},
|
|
215167
|
+
longContext: {
|
|
215168
|
+
input: 5,
|
|
215169
|
+
cachedInput: .5,
|
|
215170
|
+
cacheWrite: 6.25,
|
|
215171
|
+
output: 22.5
|
|
215172
|
+
}
|
|
215173
|
+
},
|
|
215174
|
+
"gpt-5.6-luna": {
|
|
215175
|
+
standard: {
|
|
215176
|
+
input: 1,
|
|
215177
|
+
cachedInput: .1,
|
|
215178
|
+
cacheWrite: 1.25,
|
|
215179
|
+
output: 6
|
|
215180
|
+
},
|
|
215181
|
+
longContext: {
|
|
215182
|
+
input: 2,
|
|
215183
|
+
cachedInput: .2,
|
|
215184
|
+
cacheWrite: 2.5,
|
|
215185
|
+
output: 9
|
|
215186
|
+
}
|
|
215187
|
+
},
|
|
215188
|
+
"gpt-5.5": {
|
|
215189
|
+
standard: {
|
|
215190
|
+
input: 5,
|
|
215191
|
+
cachedInput: .5,
|
|
215192
|
+
output: 30
|
|
215193
|
+
},
|
|
215194
|
+
longContext: {
|
|
215195
|
+
input: 10,
|
|
215196
|
+
cachedInput: 1,
|
|
215197
|
+
output: 45
|
|
215198
|
+
}
|
|
215199
|
+
},
|
|
215200
|
+
"gpt-5.5-pro": {
|
|
215201
|
+
standard: {
|
|
215202
|
+
input: 30,
|
|
215203
|
+
output: 180
|
|
215204
|
+
},
|
|
215205
|
+
longContext: {
|
|
215206
|
+
input: 60,
|
|
215207
|
+
output: 270
|
|
215208
|
+
}
|
|
215209
|
+
},
|
|
215210
|
+
"gpt-5.4": {
|
|
215211
|
+
standard: {
|
|
215212
|
+
input: 2.5,
|
|
215213
|
+
cachedInput: .25,
|
|
215214
|
+
output: 15
|
|
215215
|
+
},
|
|
215216
|
+
longContext: {
|
|
215217
|
+
input: 5,
|
|
215218
|
+
cachedInput: .5,
|
|
215219
|
+
output: 22.5
|
|
215220
|
+
}
|
|
215221
|
+
},
|
|
215222
|
+
"gpt-5.4-pro": {
|
|
215223
|
+
standard: {
|
|
215224
|
+
input: 30,
|
|
215225
|
+
output: 180
|
|
215226
|
+
},
|
|
215227
|
+
longContext: {
|
|
215228
|
+
input: 60,
|
|
215229
|
+
output: 270
|
|
215230
|
+
}
|
|
215231
|
+
},
|
|
215232
|
+
"gpt-5.4-mini": { standard: {
|
|
215233
|
+
input: .75,
|
|
215234
|
+
cachedInput: .075,
|
|
215235
|
+
output: 4.5
|
|
215236
|
+
} },
|
|
215237
|
+
"gpt-5.3-codex": { standard: {
|
|
215238
|
+
input: 1.75,
|
|
215239
|
+
cachedInput: .175,
|
|
215240
|
+
output: 14
|
|
215241
|
+
} },
|
|
215242
|
+
"gpt-5.2-codex": { standard: {
|
|
215243
|
+
input: 1.75,
|
|
215244
|
+
cachedInput: .175,
|
|
215245
|
+
output: 14
|
|
215246
|
+
} },
|
|
215247
|
+
"gpt-5.2": { standard: {
|
|
215248
|
+
input: 1.75,
|
|
215249
|
+
cachedInput: .175,
|
|
215250
|
+
output: 14
|
|
215251
|
+
} },
|
|
215252
|
+
"gpt-5.2-pro": { standard: {
|
|
215253
|
+
input: 21,
|
|
215254
|
+
output: 168
|
|
215255
|
+
} },
|
|
215256
|
+
"gpt-5.1-codex-max": { standard: {
|
|
215257
|
+
input: 1.25,
|
|
215258
|
+
cachedInput: .125,
|
|
215259
|
+
output: 10
|
|
215260
|
+
} },
|
|
215261
|
+
"gpt-5.1-codex": { standard: {
|
|
215262
|
+
input: 1.25,
|
|
215263
|
+
cachedInput: .125,
|
|
215264
|
+
output: 10
|
|
215265
|
+
} },
|
|
215266
|
+
"gpt-5.1": { standard: {
|
|
215267
|
+
input: 1.25,
|
|
215268
|
+
cachedInput: .125,
|
|
215269
|
+
output: 10
|
|
215270
|
+
} },
|
|
215271
|
+
"gpt-5-codex": { standard: {
|
|
215272
|
+
input: 1.25,
|
|
215273
|
+
cachedInput: .125,
|
|
215274
|
+
output: 10
|
|
215275
|
+
} },
|
|
215276
|
+
"gpt-5": { standard: {
|
|
215277
|
+
input: 1.25,
|
|
215278
|
+
cachedInput: .125,
|
|
215279
|
+
output: 10
|
|
215280
|
+
} },
|
|
215281
|
+
"gpt-5.1-codex-mini": { standard: {
|
|
215282
|
+
input: .25,
|
|
215283
|
+
cachedInput: .025,
|
|
215284
|
+
output: 2
|
|
215285
|
+
} },
|
|
215286
|
+
"gpt-5-mini": { standard: {
|
|
215287
|
+
input: .25,
|
|
215288
|
+
cachedInput: .025,
|
|
215289
|
+
output: 2
|
|
215290
|
+
} },
|
|
215291
|
+
"codex-mini-latest": { standard: {
|
|
215292
|
+
input: 1.5,
|
|
215293
|
+
cachedInput: .375,
|
|
215294
|
+
output: 6
|
|
215295
|
+
} }
|
|
215296
|
+
};
|
|
215297
|
+
/** Aliases/snapshots that official model pages explicitly map to the rate above. */
|
|
215298
|
+
const MODEL_ALIASES = {
|
|
215299
|
+
"gpt-5.6": "gpt-5.6-sol",
|
|
215300
|
+
"gpt-5.5-2026-04-23": "gpt-5.5",
|
|
215301
|
+
"gpt-5.5-pro-2026-04-23": "gpt-5.5-pro",
|
|
215302
|
+
"gpt-5.4-2026-03-05": "gpt-5.4",
|
|
215303
|
+
"gpt-5.4-mini-2026-03-17": "gpt-5.4-mini",
|
|
215304
|
+
"gpt-5.4-pro-2026-03-05": "gpt-5.4-pro",
|
|
215305
|
+
"gpt-5.2-2025-12-11": "gpt-5.2",
|
|
215306
|
+
"gpt-5.2-pro-2025-12-11": "gpt-5.2-pro",
|
|
215307
|
+
"gpt-5.1-2025-11-13": "gpt-5.1",
|
|
215308
|
+
"gpt-5-2025-08-07": "gpt-5",
|
|
215309
|
+
"gpt-5-mini-2025-08-07": "gpt-5-mini"
|
|
215310
|
+
};
|
|
215311
|
+
function validCount(value) {
|
|
215312
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
215313
|
+
}
|
|
215314
|
+
/**
|
|
215315
|
+
* Estimate one Codex turn at public OpenAI Standard API token rates.
|
|
215316
|
+
*
|
|
215317
|
+
* codex-acp maps provider usage into disjoint ACP buckets: `inputTokens` is
|
|
215318
|
+
* non-cached input and `cachedReadTokens` is the cached subset it removed.
|
|
215319
|
+
* `thoughtTokens` is intentionally absent: reasoning is already a subset of output
|
|
215320
|
+
* and charging it again would double-count. The current adapter does not expose
|
|
215321
|
+
* GPT-5.6 cache writes, so those tokens remain in input at the regular input rate;
|
|
215322
|
+
* that known approximation is preferable to inventing an unavailable split.
|
|
215323
|
+
*/
|
|
215324
|
+
function estimateOpenAiTurnCost(model, usage) {
|
|
215325
|
+
const rawModel = model?.trim();
|
|
215326
|
+
if (!rawModel) return {
|
|
215327
|
+
ok: false,
|
|
215328
|
+
reason: "model_missing"
|
|
215329
|
+
};
|
|
215330
|
+
const normalizedModel = MODEL_ALIASES[rawModel] ?? rawModel;
|
|
215331
|
+
const pricing = MODEL_PRICING[normalizedModel];
|
|
215332
|
+
if (!pricing) return {
|
|
215333
|
+
ok: false,
|
|
215334
|
+
reason: "model_unknown"
|
|
215335
|
+
};
|
|
215336
|
+
if (usage.inputTokens === void 0 || usage.outputTokens === void 0) return {
|
|
215337
|
+
ok: false,
|
|
215338
|
+
reason: "usage_incomplete"
|
|
215339
|
+
};
|
|
215340
|
+
if (!validCount(usage.inputTokens) || !validCount(usage.outputTokens)) return {
|
|
215341
|
+
ok: false,
|
|
215342
|
+
reason: "usage_invalid"
|
|
215343
|
+
};
|
|
215344
|
+
const cachedRead = usage.cachedReadTokens ?? 0;
|
|
215345
|
+
const cachedWrite = usage.cachedWriteTokens ?? 0;
|
|
215346
|
+
if (!validCount(cachedRead) || !validCount(cachedWrite)) return {
|
|
215347
|
+
ok: false,
|
|
215348
|
+
reason: "usage_invalid"
|
|
215349
|
+
};
|
|
215350
|
+
const isLongContext = usage.inputTokens + cachedRead + cachedWrite > LONG_CONTEXT_THRESHOLD && pricing.longContext !== void 0;
|
|
215351
|
+
const rates = isLongContext ? pricing.longContext : pricing.standard;
|
|
215352
|
+
return {
|
|
215353
|
+
ok: true,
|
|
215354
|
+
amount: (usage.inputTokens * rates.input + cachedRead * (rates.cachedInput ?? rates.input) + cachedWrite * (rates.cacheWrite ?? rates.input) + usage.outputTokens * rates.output) / TOKENS_PER_MILLION,
|
|
215355
|
+
currency: "USD",
|
|
215356
|
+
model: normalizedModel,
|
|
215357
|
+
pricingAsOf: OPENAI_PUBLIC_PRICING_AS_OF,
|
|
215358
|
+
basis: "public-api-standard",
|
|
215359
|
+
longContext: isLongContext
|
|
215360
|
+
};
|
|
215361
|
+
}
|
|
215362
|
+
//#endregion
|
|
215104
215363
|
//#region src/daemon.ts
|
|
215105
215364
|
/** Format an error for logs, surfacing a JSON-RPC/ACP RequestError's `code` and
|
|
215106
215365
|
* `data` — for an agent-side `Internal error` the actionable detail (the adapter's
|
|
@@ -216125,6 +216384,18 @@ var Daemon = class Daemon {
|
|
|
216125
216384
|
this.hostStartedAt.set(agentId, this.clock.now());
|
|
216126
216385
|
return host;
|
|
216127
216386
|
}
|
|
216387
|
+
/** Whether this agent is backed by Codex ACP. Registry ids are canonical, while
|
|
216388
|
+
* command/args matching keeps user-defined runtime aliases working. */
|
|
216389
|
+
isCodexRuntime(agentId) {
|
|
216390
|
+
const agent = this.agents.get(agentId);
|
|
216391
|
+
if (!agent) return false;
|
|
216392
|
+
const runtime = this.runtimes[agent.runtime];
|
|
216393
|
+
return [
|
|
216394
|
+
agent.runtime,
|
|
216395
|
+
runtime?.command,
|
|
216396
|
+
...runtime?.args ?? []
|
|
216397
|
+
].filter((part) => typeof part === "string").some((part) => /(?:^|[\\/])codex-acp(?:@[^\\/]*)?$/.test(part.toLowerCase()));
|
|
216398
|
+
}
|
|
216128
216399
|
/** The bare Telegram message id from a normalized `telegram:<chatId>:<messageId>`
|
|
216129
216400
|
* msgId (the last segment; chat ids may be negative, so split, don't parse). */
|
|
216130
216401
|
telegramMessageId(msg) {
|
|
@@ -218118,6 +218389,8 @@ var Daemon = class Daemon {
|
|
|
218118
218389
|
...this.telegramReplyTarget(msg) !== void 0 ? { tgReplyTo: this.telegramReplyTarget(msg) } : {},
|
|
218119
218390
|
statusThread,
|
|
218120
218391
|
conn: replyConn,
|
|
218392
|
+
runtimeCostReported: false,
|
|
218393
|
+
usageReportSent: false,
|
|
218121
218394
|
applyChain: Promise.resolve(),
|
|
218122
218395
|
done,
|
|
218123
218396
|
resolveDone,
|
|
@@ -218149,6 +218422,9 @@ var Daemon = class Daemon {
|
|
|
218149
218422
|
this.log.info(`dispatch: skipped ready turn ${msg.msgId} (${readyGate})`);
|
|
218150
218423
|
return null;
|
|
218151
218424
|
}
|
|
218425
|
+
const modelOptions = host.modelOptions?.(sessionId) ?? null;
|
|
218426
|
+
const advertisedModel = modelOptions?.current;
|
|
218427
|
+
const turnModel = modelOptions === null ? override ?? agent.runtimeOverrides?.model : advertisedModel === "default" ? void 0 : advertisedModel;
|
|
218152
218428
|
if (!wasRunning) this.showActivity(replyConn, msg.channel, statusThread, "is thinking…");
|
|
218153
218429
|
this.emitStatusBar(p);
|
|
218154
218430
|
const { stopReason, usage } = await host.prompt(sessionId, blocks);
|
|
@@ -218156,28 +218432,28 @@ var Daemon = class Daemon {
|
|
|
218156
218432
|
if (p.outputSuppressed === "loop protection") finalPhase = "problem";
|
|
218157
218433
|
return null;
|
|
218158
218434
|
}
|
|
218159
|
-
if (usage)
|
|
218160
|
-
|
|
218161
|
-
|
|
218162
|
-
|
|
218163
|
-
|
|
218164
|
-
|
|
218165
|
-
|
|
218166
|
-
|
|
218167
|
-
|
|
218168
|
-
|
|
218169
|
-
|
|
218170
|
-
|
|
218171
|
-
|
|
218172
|
-
|
|
218173
|
-
|
|
218174
|
-
|
|
218175
|
-
|
|
218176
|
-
|
|
218177
|
-
});
|
|
218178
|
-
} catch (err) {
|
|
218179
|
-
this.log.debug(`usage report emit failed (session ${sessionId}): ${err.message}`);
|
|
218435
|
+
if (usage) {
|
|
218436
|
+
const counts = {
|
|
218437
|
+
totalTokens: usage.totalTokens,
|
|
218438
|
+
inputTokens: usage.inputTokens,
|
|
218439
|
+
outputTokens: usage.outputTokens,
|
|
218440
|
+
thoughtTokens: usage.thoughtTokens ?? void 0,
|
|
218441
|
+
cachedReadTokens: usage.cachedReadTokens ?? void 0,
|
|
218442
|
+
cachedWriteTokens: usage.cachedWriteTokens ?? void 0
|
|
218443
|
+
};
|
|
218444
|
+
if (this.isCodexRuntime(agentId)) {
|
|
218445
|
+
this.store.addTokenUsage(key, counts);
|
|
218446
|
+
if (!p.runtimeCostReported) {
|
|
218447
|
+
const estimate = estimateOpenAiTurnCost(turnModel, counts);
|
|
218448
|
+
if (estimate.ok) {
|
|
218449
|
+
if (!this.store.addCost(key, estimate.amount, estimate.currency)) this.log.debug(`cost fallback skipped for session ${sessionId}: existing currency differs from USD`);
|
|
218450
|
+
} else this.log.debug(`cost fallback unavailable for session ${sessionId} model=${turnModel ?? "(unknown)"}: ${estimate.reason}`);
|
|
218451
|
+
}
|
|
218452
|
+
} else this.store.setTokenUsage(key, counts);
|
|
218180
218453
|
}
|
|
218454
|
+
this.emitStatusBar(p);
|
|
218455
|
+
this.emitStoredUsageReport(sessionId, agentId, msg.platform, msg.channel, key);
|
|
218456
|
+
p.usageReportSent = true;
|
|
218181
218457
|
this.clearIdle(p);
|
|
218182
218458
|
if (p.webchat) {
|
|
218183
218459
|
if (p.webchat.replyText.trim()) this.store.appendTranscript({
|
|
@@ -218735,7 +219011,7 @@ var Daemon = class Daemon {
|
|
|
218735
219011
|
const agent = this.agents.get(agentId);
|
|
218736
219012
|
const usage = this.store.getUsage(sessionKey);
|
|
218737
219013
|
const host = this.hosts.get(agentId);
|
|
218738
|
-
const model = host?.modelOptions?.();
|
|
219014
|
+
const model = host?.modelOptions?.(acpSessionId);
|
|
218739
219015
|
const effort = host?.effortOptions?.();
|
|
218740
219016
|
const permissionMode = host?.permissionModeOptions?.();
|
|
218741
219017
|
const fast = host?.fastModeOption?.();
|
|
@@ -219008,19 +219284,45 @@ var Daemon = class Daemon {
|
|
|
219008
219284
|
rec.resolve({ action: "cancel" });
|
|
219009
219285
|
}
|
|
219010
219286
|
}
|
|
219287
|
+
/** Emit the daemon's latest merged usage snapshot. Used both at normal turn end
|
|
219288
|
+
* and when a late ACP usage_update corrects an already-reported fallback. */
|
|
219289
|
+
emitStoredUsageReport(sessionId, agentId, platform, channel, key, late = false) {
|
|
219290
|
+
const usage = this.store.getUsage(key);
|
|
219291
|
+
if (Object.keys(usage).length === 0) return;
|
|
219292
|
+
try {
|
|
219293
|
+
this.cpClient?.emitUsageReport({
|
|
219294
|
+
sessionId,
|
|
219295
|
+
agentId,
|
|
219296
|
+
platform,
|
|
219297
|
+
channel,
|
|
219298
|
+
lastActivityAt: new Date(this.clock.now()).toISOString(),
|
|
219299
|
+
usage
|
|
219300
|
+
});
|
|
219301
|
+
} catch (err) {
|
|
219302
|
+
this.log.debug(`${late ? "late " : ""}usage report emit failed (session ${sessionId}): ${err.message}`);
|
|
219303
|
+
}
|
|
219304
|
+
}
|
|
219011
219305
|
onAcpUpdate(_agentId, sessionId, update) {
|
|
219012
219306
|
const p = this.pending.get(sessionId);
|
|
219013
|
-
if (
|
|
219014
|
-
if (p.outputSuppressed) return;
|
|
219307
|
+
if (p?.outputSuppressed) return;
|
|
219015
219308
|
if (update?.sessionUpdate === "usage_update") {
|
|
219016
|
-
this.store.
|
|
219017
|
-
|
|
219018
|
-
|
|
219019
|
-
|
|
219020
|
-
|
|
219021
|
-
|
|
219022
|
-
|
|
219309
|
+
const rec = p ? void 0 : this.store.getSessionByAcpId(sessionId);
|
|
219310
|
+
const key = p?.sessionKey ?? rec?.key;
|
|
219311
|
+
if (key) {
|
|
219312
|
+
if (p && update.cost?.amount !== void 0) p.runtimeCostReported = true;
|
|
219313
|
+
this.store.setUsageSnapshot(key, {
|
|
219314
|
+
contextUsed: update.used,
|
|
219315
|
+
contextSize: update.size,
|
|
219316
|
+
costAmount: update.cost?.amount ?? void 0,
|
|
219317
|
+
costCurrency: update.cost?.currency ?? void 0
|
|
219318
|
+
});
|
|
219319
|
+
if (p) {
|
|
219320
|
+
this.emitStatusBar(p);
|
|
219321
|
+
if (p.usageReportSent) this.emitStoredUsageReport(sessionId, p.agentId, p.platform, p.channel, key, true);
|
|
219322
|
+
} else if (rec) this.emitStoredUsageReport(sessionId, rec.agentId, rec.platform, rec.channel, key, true);
|
|
219323
|
+
}
|
|
219023
219324
|
}
|
|
219325
|
+
if (!p) return;
|
|
219024
219326
|
if (update?.sessionUpdate === "session_info_update" && update.title !== void 0) {
|
|
219025
219327
|
this.store.setSessionTitle(p.sessionKey, update.title);
|
|
219026
219328
|
this.emitSessionMetadataSnapshot({
|
|
@@ -220150,4 +220452,4 @@ async function runForeground(opts, deps = {}) {
|
|
|
220150
220452
|
//#endregion
|
|
220151
220453
|
export { ClientTransport as i, CP_SUBPROTOCOL as n, CP_WS_PATH as r, runForeground as t };
|
|
220152
220454
|
|
|
220153
|
-
//# sourceMappingURL=run-foreground-
|
|
220455
|
+
//# sourceMappingURL=run-foreground-BZ63Vsmq.js.map
|