@agimon-ai/doompi-log 0.0.1-alpha.34 → 0.0.1-alpha.36
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/adapters/node/metricsSource.cjs +1 -1
- package/dist/adapters/node/metricsSource.cjs.map +1 -1
- package/dist/adapters/node/metricsSource.d.cts +3 -0
- package/dist/adapters/node/metricsSource.d.cts.map +1 -1
- package/dist/adapters/node/metricsSource.d.mts +3 -0
- package/dist/adapters/node/metricsSource.d.mts.map +1 -1
- package/dist/adapters/node/metricsSource.mjs +1 -1
- package/dist/adapters/node/metricsSource.mjs.map +1 -1
- package/dist/adapters/pi/extension.cjs +1 -1
- package/dist/adapters/pi/extension.cjs.map +1 -1
- package/dist/adapters/pi/extension.d.cts.map +1 -1
- package/dist/adapters/pi/extension.d.mts.map +1 -1
- package/dist/adapters/pi/extension.mjs +1 -1
- package/dist/adapters/pi/extension.mjs.map +1 -1
- package/dist/metricsSource.d.cts +2 -2
- package/dist/metricsSource.d.mts +2 -2
- package/dist/tui/logMetricsOverlay.cjs +1 -1
- package/dist/tui/logMetricsOverlay.cjs.map +1 -1
- package/dist/tui/logMetricsOverlay.d.cts +12 -2
- package/dist/tui/logMetricsOverlay.d.cts.map +1 -1
- package/dist/tui/logMetricsOverlay.d.mts +12 -2
- package/dist/tui/logMetricsOverlay.d.mts.map +1 -1
- package/dist/tui/logMetricsOverlay.mjs +1 -1
- package/dist/tui/logMetricsOverlay.mjs.map +1 -1
- package/dist/types/metricsSource.d.cts +16 -1
- package/dist/types/metricsSource.d.cts.map +1 -1
- package/dist/types/metricsSource.d.mts +16 -1
- package/dist/types/metricsSource.d.mts.map +1 -1
- package/package.json +12 -4
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../_virtual/_rolldown/runtime.cjs");let t=require("node:child_process"),n=require("node:module"),r=require("node:path");r=e.__toESM(r,1);let i=require("@agimon-ai/log-sink-mcp");const a=`total-tokens`;function o(){let e=(0,n.createRequire)(require("url").pathToFileURL(__filename).href).resolve(`@agimon-ai/log-sink-mcp/package.json`);return r.default.join(r.default.dirname(e),`dist`,`cli.mjs`)}function s(e){return new URLSearchParams({groupBy:e.groupBy,period:e.period,sort:a,limit:String(e.limit),toolLimit:`1`}).toString()}async function c(e,t,n){let r=await n(`${e}/api/metrics?${s(t)}`,{signal:AbortSignal.timeout(5e3)});if(!r.ok)throw Error(`sink responded ${r.status}`);let i=await r.json();if(i.error||!Array.isArray(i.timeline))throw Error(i.error??`sink is an older version`);return i}function l(e){return new Promise((
|
|
1
|
+
const e=require("../../_virtual/_rolldown/runtime.cjs");let t=require("node:child_process"),n=require("node:module"),r=require("node:path");r=e.__toESM(r,1);let i=require("@agimon-ai/log-sink-mcp");const a=`total-tokens`;function o(){let e=(0,n.createRequire)(require("url").pathToFileURL(__filename).href).resolve(`@agimon-ai/log-sink-mcp/package.json`);return r.default.join(r.default.dirname(e),`dist`,`cli.mjs`)}function s(e){return new URLSearchParams({groupBy:e.groupBy,period:e.period,sort:a,limit:String(e.limit),toolLimit:`1`}).toString()}async function c(e,t,n){let r=await n(`${e}/api/metrics?${s(t)}`,{signal:AbortSignal.timeout(5e3)});if(!r.ok)throw Error(`sink responded ${r.status}`);let i=await r.json();if(i.error||!Array.isArray(i.timeline))throw Error(i.error??`sink is an older version`);return i}function l(e,n){return new Promise((r,i)=>{(0,t.execFile)(process.execPath,[o(),`logs`,`metrics`,`--group-by`,e.groupBy,`--period`,e.period,`--sort`,a,`--limit`,String(e.limit),`--tool-limit`,`1`,...n===void 0?[]:[`--db-path`,n]],{timeout:3e4,maxBuffer:33554432},(e,t,n)=>{if(e){i(Error(n.trim()||e.message));return}try{r(JSON.parse(t))}catch{i(Error(`metrics CLI returned unparsable output`))}})})}function u(e){try{let t=(0,i.resolveLogSinkInstance)(e);return{scope:t.scope,dbPath:t.dbPath,...t.registeredName===void 0?{}:{registeredName:t.registeredName}}}catch{return}}function d(e={}){let t=e.fetchImpl??globalThis.fetch,n={env:e.env,cwd:e.cwd,packageName:e.packageName,serviceName:e.serviceName},r,a,o=u(n),s=e.cliRunner??(e=>l(e,o?.dbPath)),d=async()=>{if(a!==void 0)return a??void 0;try{a=(await(0,i.resolveLogSinkPort)({...n,healthCheck:!0}))?.endpoint??null}catch{a=null}return a??void 0};return{lastTransport:()=>r,instance:()=>o,async query(e){let n=await d();if(n&&t)try{let i=await c(n,e,t);return r=`http`,i}catch{a=null}let i=await s(e);return r=`cli`,i}}}exports.createMetricsSource=d;
|
|
2
2
|
//# sourceMappingURL=metricsSource.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsSource.cjs","names":["createRequire","path","resolveLogSinkPort"],"sources":["../../../src/adapters/node/metricsSource.ts"],"sourcesContent":["/**\n * Historical metrics access for the `SPC h l` overlay.\n *\n * Two transports, in order: the running sink's HTTP API, then the installed\n * CLI as a subprocess. The sink daemon is long-lived and often lags the\n * installed package, so a daemon that rejects newer query parameters is treated\n * as unavailable rather than fatal. The reader exported by log-sink-mcp is\n * deliberately not used in-process: better-sqlite3 is synchronous and a\n * one-day window blocks for seconds, which would freeze the TUI.\n */\nimport { execFile } from 'node:child_process';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport type { LogMetricsReport } from '@agimon-ai/log-sink-mcp';\nimport { resolveLogSinkPort } from '@agimon-ai/log-sink-mcp';\nimport type {
|
|
1
|
+
{"version":3,"file":"metricsSource.cjs","names":["createRequire","path","resolveLogSinkInstance","resolveLogSinkPort"],"sources":["../../../src/adapters/node/metricsSource.ts"],"sourcesContent":["/**\n * Historical metrics access for the `SPC h l` overlay.\n *\n * Two transports, in order: the running sink's HTTP API, then the installed\n * CLI as a subprocess. The sink daemon is long-lived and often lags the\n * installed package, so a daemon that rejects newer query parameters is treated\n * as unavailable rather than fatal. The reader exported by log-sink-mcp is\n * deliberately not used in-process: better-sqlite3 is synchronous and a\n * one-day window blocks for seconds, which would freeze the TUI.\n *\n * Both transports resolve the sink instance from the same identity the Pi\n * telemetry extension writes under. Without it log-sink falls back to\n * `npm_package_name`, which a running Pi process does not set, so the reader\n * would land on the local instance while the writer exported to the global one\n * and the panel would report an empty history that no session ever filled.\n */\nimport { execFile } from 'node:child_process';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport type { LogMetricsReport } from '@agimon-ai/log-sink-mcp';\nimport { resolveLogSinkInstance, resolveLogSinkPort } from '@agimon-ai/log-sink-mcp';\nimport type {\n MetricsInstance,\n MetricsQueryParams,\n MetricsSource,\n MetricsTransport,\n} from '../../types/metricsSource.ts';\n\nconst PACKAGE_NAME = '@agimon-ai/log-sink-mcp';\nconst HTTP_TIMEOUT_MS = 5000;\nconst CLI_TIMEOUT_MS = 30000;\n/** A day of dev telemetry is already ~140k records; keep the payload bounded. */\nconst MAX_CLI_BUFFER = 32 * 1024 * 1024;\nconst TOOL_LIMIT = '1';\n/** The panel ranks consumers, so ask for the biggest rather than the most recent. */\nconst TOKEN_SORT = 'total-tokens';\n\n/** The identity both transports resolve their sink instance from. */\ninterface ResolveIdentity {\n env?: NodeJS.ProcessEnv;\n cwd?: string;\n packageName?: string;\n serviceName?: string;\n}\n\nexport interface MetricsSourceOptions {\n env?: NodeJS.ProcessEnv;\n cwd?: string;\n /** Identity the sink is registered under; must match the telemetry writer's. */\n packageName?: string;\n serviceName?: string;\n /** Overrides transport discovery in tests. */\n fetchImpl?: typeof fetch;\n cliRunner?: (params: MetricsQueryParams) => Promise<LogMetricsReport>;\n}\n\nfunction cliEntryPoint(): string {\n const require = createRequire(import.meta.url);\n // The published bin is CJS; the ESM build sits beside it and starts faster.\n const packageJson = require.resolve(`${PACKAGE_NAME}/package.json`);\n return path.join(path.dirname(packageJson), 'dist', 'cli.mjs');\n}\n\nfunction searchParams(params: MetricsQueryParams): string {\n return new URLSearchParams({\n groupBy: params.groupBy,\n period: params.period,\n sort: TOKEN_SORT,\n limit: String(params.limit),\n toolLimit: TOOL_LIMIT,\n }).toString();\n}\n\nasync function queryHttp(\n endpoint: string,\n params: MetricsQueryParams,\n fetchImpl: typeof fetch,\n): Promise<LogMetricsReport> {\n const response = await fetchImpl(`${endpoint}/api/metrics?${searchParams(params)}`, {\n signal: AbortSignal.timeout(HTTP_TIMEOUT_MS),\n });\n if (!response.ok) throw new Error(`sink responded ${response.status}`);\n\n const body = (await response.json()) as LogMetricsReport & { error?: string };\n // An older daemon rejects unknown group-by values and omits the timeline.\n if (body.error || !Array.isArray(body.timeline)) throw new Error(body.error ?? 'sink is an older version');\n return body;\n}\n\n/**\n * The subprocess resolves an instance of its own from the inherited cwd and\n * environment, so the database is passed explicitly rather than left to agree\n * with this process by coincidence.\n */\nfunction runCli(params: MetricsQueryParams, dbPath: string | undefined): Promise<LogMetricsReport> {\n return new Promise((resolve, reject) => {\n execFile(\n process.execPath,\n [\n cliEntryPoint(),\n 'logs',\n 'metrics',\n '--group-by',\n params.groupBy,\n '--period',\n params.period,\n '--sort',\n TOKEN_SORT,\n '--limit',\n String(params.limit),\n '--tool-limit',\n TOOL_LIMIT,\n ...(dbPath === undefined ? [] : ['--db-path', dbPath]),\n ],\n { timeout: CLI_TIMEOUT_MS, maxBuffer: MAX_CLI_BUFFER },\n (error, stdout, stderr) => {\n if (error) {\n reject(new Error(stderr.trim() || error.message));\n return;\n }\n try {\n resolve(JSON.parse(stdout) as LogMetricsReport);\n } catch {\n reject(new Error('metrics CLI returned unparsable output'));\n }\n },\n );\n });\n}\n\n/**\n * A malformed `.logsink.yaml` must not take the overlay down with it. Both\n * transports still run when resolution fails; they fall back to log-sink's own\n * resolution and the panel reports an unknown instance.\n */\nfunction resolveInstance(identity: ResolveIdentity): MetricsInstance | undefined {\n try {\n const resolved = resolveLogSinkInstance(identity);\n return {\n scope: resolved.scope,\n dbPath: resolved.dbPath,\n ...(resolved.registeredName === undefined ? {} : { registeredName: resolved.registeredName }),\n };\n } catch {\n return undefined;\n }\n}\n\nexport function createMetricsSource(options: MetricsSourceOptions = {}): MetricsSource {\n const fetchImpl = options.fetchImpl ?? globalThis.fetch;\n const identity = {\n env: options.env,\n cwd: options.cwd,\n packageName: options.packageName,\n serviceName: options.serviceName,\n };\n let transport: MetricsTransport | undefined;\n let endpoint: string | undefined | null;\n const instance = resolveInstance(identity);\n const cliRunner = options.cliRunner ?? ((params: MetricsQueryParams) => runCli(params, instance?.dbPath));\n\n const resolveEndpoint = async (): Promise<string | undefined> => {\n if (endpoint !== undefined) return endpoint ?? undefined;\n try {\n const resolved = await resolveLogSinkPort({ ...identity, healthCheck: true });\n endpoint = resolved?.endpoint ?? null;\n } catch {\n endpoint = null;\n }\n return endpoint ?? undefined;\n };\n\n return {\n lastTransport: () => transport,\n instance: () => instance,\n async query(params) {\n const httpEndpoint = await resolveEndpoint();\n if (httpEndpoint && fetchImpl) {\n try {\n const report = await queryHttp(httpEndpoint, params, fetchImpl);\n transport = 'http';\n return report;\n } catch {\n // A stale or unhealthy daemon must not hide data the CLI can still read.\n endpoint = null;\n }\n }\n\n const report = await cliRunner(params);\n transport = 'cli';\n return report;\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -4,6 +4,9 @@ import { LogMetricsReport } from "@agimon-ai/log-sink-mcp";
|
|
|
4
4
|
interface MetricsSourceOptions {
|
|
5
5
|
env?: NodeJS.ProcessEnv;
|
|
6
6
|
cwd?: string;
|
|
7
|
+
/** Identity the sink is registered under; must match the telemetry writer's. */
|
|
8
|
+
packageName?: string;
|
|
9
|
+
serviceName?: string;
|
|
7
10
|
/** Overrides transport discovery in tests. */
|
|
8
11
|
fetchImpl?: typeof fetch;
|
|
9
12
|
cliRunner?: (params: MetricsQueryParams) => Promise<LogMetricsReport>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsSource.d.cts","names":[],"sources":["../../../src/adapters/node/metricsSource.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"metricsSource.d.cts","names":[],"sources":["../../../src/adapters/node/metricsSource.ts"],"mappings":";;;UA6CiB;EACf,MAAM,OAAO;EACb;;EAEA;EACA;;EAEA,mBAAmB;EACnB,aAAa,QAAQ,uBAAuB,QAAQ;;iBA+FtC,oBAAoB,UAAS,uBAA4B"}
|
|
@@ -4,6 +4,9 @@ import { LogMetricsReport } from "@agimon-ai/log-sink-mcp";
|
|
|
4
4
|
interface MetricsSourceOptions {
|
|
5
5
|
env?: NodeJS.ProcessEnv;
|
|
6
6
|
cwd?: string;
|
|
7
|
+
/** Identity the sink is registered under; must match the telemetry writer's. */
|
|
8
|
+
packageName?: string;
|
|
9
|
+
serviceName?: string;
|
|
7
10
|
/** Overrides transport discovery in tests. */
|
|
8
11
|
fetchImpl?: typeof fetch;
|
|
9
12
|
cliRunner?: (params: MetricsQueryParams) => Promise<LogMetricsReport>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsSource.d.mts","names":[],"sources":["../../../src/adapters/node/metricsSource.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"metricsSource.d.mts","names":[],"sources":["../../../src/adapters/node/metricsSource.ts"],"mappings":";;;UA6CiB;EACf,MAAM,OAAO;EACb;;EAEA;EACA;;EAEA,mBAAmB;EACnB,aAAa,QAAQ,uBAAuB,QAAQ;;iBA+FtC,oBAAoB,UAAS,uBAA4B"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createRequire as e}from"node:module";import{execFile as t}from"node:child_process";import n from"node:path";import{resolveLogSinkPort as
|
|
1
|
+
import{createRequire as e}from"node:module";import{execFile as t}from"node:child_process";import n from"node:path";import{resolveLogSinkInstance as r,resolveLogSinkPort as i}from"@agimon-ai/log-sink-mcp";const a=`total-tokens`;function o(){let t=e(import.meta.url).resolve(`@agimon-ai/log-sink-mcp/package.json`);return n.join(n.dirname(t),`dist`,`cli.mjs`)}function s(e){return new URLSearchParams({groupBy:e.groupBy,period:e.period,sort:a,limit:String(e.limit),toolLimit:`1`}).toString()}async function c(e,t,n){let r=await n(`${e}/api/metrics?${s(t)}`,{signal:AbortSignal.timeout(5e3)});if(!r.ok)throw Error(`sink responded ${r.status}`);let i=await r.json();if(i.error||!Array.isArray(i.timeline))throw Error(i.error??`sink is an older version`);return i}function l(e,n){return new Promise((r,i)=>{t(process.execPath,[o(),`logs`,`metrics`,`--group-by`,e.groupBy,`--period`,e.period,`--sort`,a,`--limit`,String(e.limit),`--tool-limit`,`1`,...n===void 0?[]:[`--db-path`,n]],{timeout:3e4,maxBuffer:33554432},(e,t,n)=>{if(e){i(Error(n.trim()||e.message));return}try{r(JSON.parse(t))}catch{i(Error(`metrics CLI returned unparsable output`))}})})}function u(e){try{let t=r(e);return{scope:t.scope,dbPath:t.dbPath,...t.registeredName===void 0?{}:{registeredName:t.registeredName}}}catch{return}}function d(e={}){let t=e.fetchImpl??globalThis.fetch,n={env:e.env,cwd:e.cwd,packageName:e.packageName,serviceName:e.serviceName},r,a,o=u(n),s=e.cliRunner??(e=>l(e,o?.dbPath)),d=async()=>{if(a!==void 0)return a??void 0;try{a=(await i({...n,healthCheck:!0}))?.endpoint??null}catch{a=null}return a??void 0};return{lastTransport:()=>r,instance:()=>o,async query(e){let n=await d();if(n&&t)try{let i=await c(n,e,t);return r=`http`,i}catch{a=null}let i=await s(e);return r=`cli`,i}}}export{d as createMetricsSource};
|
|
2
2
|
//# sourceMappingURL=metricsSource.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsSource.mjs","names":[],"sources":["../../../src/adapters/node/metricsSource.ts"],"sourcesContent":["/**\n * Historical metrics access for the `SPC h l` overlay.\n *\n * Two transports, in order: the running sink's HTTP API, then the installed\n * CLI as a subprocess. The sink daemon is long-lived and often lags the\n * installed package, so a daemon that rejects newer query parameters is treated\n * as unavailable rather than fatal. The reader exported by log-sink-mcp is\n * deliberately not used in-process: better-sqlite3 is synchronous and a\n * one-day window blocks for seconds, which would freeze the TUI.\n */\nimport { execFile } from 'node:child_process';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport type { LogMetricsReport } from '@agimon-ai/log-sink-mcp';\nimport { resolveLogSinkPort } from '@agimon-ai/log-sink-mcp';\nimport type {
|
|
1
|
+
{"version":3,"file":"metricsSource.mjs","names":[],"sources":["../../../src/adapters/node/metricsSource.ts"],"sourcesContent":["/**\n * Historical metrics access for the `SPC h l` overlay.\n *\n * Two transports, in order: the running sink's HTTP API, then the installed\n * CLI as a subprocess. The sink daemon is long-lived and often lags the\n * installed package, so a daemon that rejects newer query parameters is treated\n * as unavailable rather than fatal. The reader exported by log-sink-mcp is\n * deliberately not used in-process: better-sqlite3 is synchronous and a\n * one-day window blocks for seconds, which would freeze the TUI.\n *\n * Both transports resolve the sink instance from the same identity the Pi\n * telemetry extension writes under. Without it log-sink falls back to\n * `npm_package_name`, which a running Pi process does not set, so the reader\n * would land on the local instance while the writer exported to the global one\n * and the panel would report an empty history that no session ever filled.\n */\nimport { execFile } from 'node:child_process';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport type { LogMetricsReport } from '@agimon-ai/log-sink-mcp';\nimport { resolveLogSinkInstance, resolveLogSinkPort } from '@agimon-ai/log-sink-mcp';\nimport type {\n MetricsInstance,\n MetricsQueryParams,\n MetricsSource,\n MetricsTransport,\n} from '../../types/metricsSource.ts';\n\nconst PACKAGE_NAME = '@agimon-ai/log-sink-mcp';\nconst HTTP_TIMEOUT_MS = 5000;\nconst CLI_TIMEOUT_MS = 30000;\n/** A day of dev telemetry is already ~140k records; keep the payload bounded. */\nconst MAX_CLI_BUFFER = 32 * 1024 * 1024;\nconst TOOL_LIMIT = '1';\n/** The panel ranks consumers, so ask for the biggest rather than the most recent. */\nconst TOKEN_SORT = 'total-tokens';\n\n/** The identity both transports resolve their sink instance from. */\ninterface ResolveIdentity {\n env?: NodeJS.ProcessEnv;\n cwd?: string;\n packageName?: string;\n serviceName?: string;\n}\n\nexport interface MetricsSourceOptions {\n env?: NodeJS.ProcessEnv;\n cwd?: string;\n /** Identity the sink is registered under; must match the telemetry writer's. */\n packageName?: string;\n serviceName?: string;\n /** Overrides transport discovery in tests. */\n fetchImpl?: typeof fetch;\n cliRunner?: (params: MetricsQueryParams) => Promise<LogMetricsReport>;\n}\n\nfunction cliEntryPoint(): string {\n const require = createRequire(import.meta.url);\n // The published bin is CJS; the ESM build sits beside it and starts faster.\n const packageJson = require.resolve(`${PACKAGE_NAME}/package.json`);\n return path.join(path.dirname(packageJson), 'dist', 'cli.mjs');\n}\n\nfunction searchParams(params: MetricsQueryParams): string {\n return new URLSearchParams({\n groupBy: params.groupBy,\n period: params.period,\n sort: TOKEN_SORT,\n limit: String(params.limit),\n toolLimit: TOOL_LIMIT,\n }).toString();\n}\n\nasync function queryHttp(\n endpoint: string,\n params: MetricsQueryParams,\n fetchImpl: typeof fetch,\n): Promise<LogMetricsReport> {\n const response = await fetchImpl(`${endpoint}/api/metrics?${searchParams(params)}`, {\n signal: AbortSignal.timeout(HTTP_TIMEOUT_MS),\n });\n if (!response.ok) throw new Error(`sink responded ${response.status}`);\n\n const body = (await response.json()) as LogMetricsReport & { error?: string };\n // An older daemon rejects unknown group-by values and omits the timeline.\n if (body.error || !Array.isArray(body.timeline)) throw new Error(body.error ?? 'sink is an older version');\n return body;\n}\n\n/**\n * The subprocess resolves an instance of its own from the inherited cwd and\n * environment, so the database is passed explicitly rather than left to agree\n * with this process by coincidence.\n */\nfunction runCli(params: MetricsQueryParams, dbPath: string | undefined): Promise<LogMetricsReport> {\n return new Promise((resolve, reject) => {\n execFile(\n process.execPath,\n [\n cliEntryPoint(),\n 'logs',\n 'metrics',\n '--group-by',\n params.groupBy,\n '--period',\n params.period,\n '--sort',\n TOKEN_SORT,\n '--limit',\n String(params.limit),\n '--tool-limit',\n TOOL_LIMIT,\n ...(dbPath === undefined ? [] : ['--db-path', dbPath]),\n ],\n { timeout: CLI_TIMEOUT_MS, maxBuffer: MAX_CLI_BUFFER },\n (error, stdout, stderr) => {\n if (error) {\n reject(new Error(stderr.trim() || error.message));\n return;\n }\n try {\n resolve(JSON.parse(stdout) as LogMetricsReport);\n } catch {\n reject(new Error('metrics CLI returned unparsable output'));\n }\n },\n );\n });\n}\n\n/**\n * A malformed `.logsink.yaml` must not take the overlay down with it. Both\n * transports still run when resolution fails; they fall back to log-sink's own\n * resolution and the panel reports an unknown instance.\n */\nfunction resolveInstance(identity: ResolveIdentity): MetricsInstance | undefined {\n try {\n const resolved = resolveLogSinkInstance(identity);\n return {\n scope: resolved.scope,\n dbPath: resolved.dbPath,\n ...(resolved.registeredName === undefined ? {} : { registeredName: resolved.registeredName }),\n };\n } catch {\n return undefined;\n }\n}\n\nexport function createMetricsSource(options: MetricsSourceOptions = {}): MetricsSource {\n const fetchImpl = options.fetchImpl ?? globalThis.fetch;\n const identity = {\n env: options.env,\n cwd: options.cwd,\n packageName: options.packageName,\n serviceName: options.serviceName,\n };\n let transport: MetricsTransport | undefined;\n let endpoint: string | undefined | null;\n const instance = resolveInstance(identity);\n const cliRunner = options.cliRunner ?? ((params: MetricsQueryParams) => runCli(params, instance?.dbPath));\n\n const resolveEndpoint = async (): Promise<string | undefined> => {\n if (endpoint !== undefined) return endpoint ?? undefined;\n try {\n const resolved = await resolveLogSinkPort({ ...identity, healthCheck: true });\n endpoint = resolved?.endpoint ?? null;\n } catch {\n endpoint = null;\n }\n return endpoint ?? undefined;\n };\n\n return {\n lastTransport: () => transport,\n instance: () => instance,\n async query(params) {\n const httpEndpoint = await resolveEndpoint();\n if (httpEndpoint && fetchImpl) {\n try {\n const report = await queryHttp(httpEndpoint, params, fetchImpl);\n transport = 'http';\n return report;\n } catch {\n // A stale or unhealthy daemon must not hide data the CLI can still read.\n endpoint = null;\n }\n }\n\n const report = await cliRunner(params);\n transport = 'cli';\n return report;\n },\n };\n}\n"],"mappings":"4MA4BA,MAOM,EAAa,eAqBnB,SAAS,GAAwB,CAG/B,IAAM,EAFU,EAAc,YAAY,GAEhB,CAAC,CAAC,QAAQ,sCAA8B,EAClE,OAAO,EAAK,KAAK,EAAK,QAAQ,CAAW,EAAG,OAAQ,SAAS,CAC/D,CAEA,SAAS,EAAa,EAAoC,CACxD,OAAO,IAAI,gBAAgB,CACzB,QAAS,EAAO,QAChB,OAAQ,EAAO,OACf,KAAM,EACN,MAAO,OAAO,EAAO,KAAK,EAC1B,UAAW,GACb,CAAC,CAAC,CAAC,SAAS,CACd,CAEA,eAAe,EACb,EACA,EACA,EAC2B,CAC3B,IAAM,EAAW,MAAM,EAAU,GAAG,EAAS,eAAe,EAAa,CAAM,IAAK,CAClF,OAAQ,YAAY,QAAQ,GAAe,CAC7C,CAAC,EACD,GAAI,CAAC,EAAS,GAAI,MAAU,MAAM,kBAAkB,EAAS,QAAQ,EAErE,IAAM,EAAQ,MAAM,EAAS,KAAK,EAElC,GAAI,EAAK,OAAS,CAAC,MAAM,QAAQ,EAAK,QAAQ,EAAG,MAAU,MAAM,EAAK,OAAS,0BAA0B,EACzG,OAAO,CACT,CAOA,SAAS,EAAO,EAA4B,EAAuD,CACjG,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,EACE,QAAQ,SACR,CACE,EAAc,EACd,OACA,UACA,aACA,EAAO,QACP,WACA,EAAO,OACP,SACA,EACA,UACA,OAAO,EAAO,KAAK,EACnB,eACA,IACA,GAAI,IAAW,IAAA,GAAY,CAAC,EAAI,CAAC,YAAa,CAAM,CACtD,EACA,CAAE,QAAS,IAAgB,UAAW,QAAe,GACpD,EAAO,EAAQ,IAAW,CACzB,GAAI,EAAO,CACT,EAAW,MAAM,EAAO,KAAK,GAAK,EAAM,OAAO,CAAC,EAChD,MACF,CACA,GAAI,CACF,EAAQ,KAAK,MAAM,CAAM,CAAqB,CAChD,MAAQ,CACN,EAAW,MAAM,wCAAwC,CAAC,CAC5D,CACF,CACF,CACF,CAAC,CACH,CAOA,SAAS,EAAgB,EAAwD,CAC/E,GAAI,CACF,IAAM,EAAW,EAAuB,CAAQ,EAChD,MAAO,CACL,MAAO,EAAS,MAChB,OAAQ,EAAS,OACjB,GAAI,EAAS,iBAAmB,IAAA,GAAY,CAAC,EAAI,CAAE,eAAgB,EAAS,cAAe,CAC7F,CACF,MAAQ,CACN,MACF,CACF,CAEA,SAAgB,EAAoB,EAAgC,CAAC,EAAkB,CACrF,IAAM,EAAY,EAAQ,WAAa,WAAW,MAC5C,EAAW,CACf,IAAK,EAAQ,IACb,IAAK,EAAQ,IACb,YAAa,EAAQ,YACrB,YAAa,EAAQ,WACvB,EACI,EACA,EACE,EAAW,EAAgB,CAAQ,EACnC,EAAY,EAAQ,YAAe,GAA+B,EAAO,EAAQ,GAAU,MAAM,GAEjG,EAAkB,SAAyC,CAC/D,GAAI,IAAa,IAAA,GAAW,OAAO,GAAY,IAAA,GAC/C,GAAI,CAEF,GAAW,MADY,EAAmB,CAAE,GAAG,EAAU,YAAa,EAAK,CAAC,EAAA,EACvD,UAAY,IACnC,MAAQ,CACN,EAAW,IACb,CACA,OAAO,GAAY,IAAA,EACrB,EAEA,MAAO,CACL,kBAAqB,EACrB,aAAgB,EAChB,MAAM,MAAM,EAAQ,CAClB,IAAM,EAAe,MAAM,EAAgB,EAC3C,GAAI,GAAgB,EAClB,GAAI,CACF,IAAM,EAAS,MAAM,EAAU,EAAc,EAAQ,CAAS,EAE9D,MADA,GAAY,OACL,CACT,MAAQ,CAEN,EAAW,IACb,CAGF,IAAM,EAAS,MAAM,EAAU,CAAM,EAErC,MADA,GAAY,MACL,CACT,CACF,CACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../services/metrics.cjs"),t=require("../../tui/logMetricsOverlay.cjs"),n=require("../node/metricsSource.cjs");let r=require("@agimon-ai/doompi-extension-contracts/cordis-host"),i=require("@agimon-ai/doompi-extension-contracts/readiness"),a=require("@agimon-ai/doompi-extension-contracts/ui-hub"),o=require("@agimon-ai/doompi-telemetry");const s=`@agimon-ai/doompi-log`,c=`log-metrics`,l=new Set([`error`,`aborted`]);function u(e){return e===`1`||e?.toLowerCase()===`true`||e?.toLowerCase()===`yes`}function d(e){let t={"pi.mode":e.mode,"pi.session.id":e.sessionManager.getSessionId()};return e.thinkingLevel&&(t[`pi.thinking_level`]=e.thinkingLevel),e.model&&(t[`gen_ai.provider.name`]=e.model.provider,t[`gen_ai.request.model`]=e.model.id),t}function f(e){if(e.role!==`assistant`)return;let t={"gen_ai.response.model":e.responseModel??e.model,"gen_ai.response.finish_reasons":e.stopReason,"gen_ai.usage.input_tokens":e.usage.input,"gen_ai.usage.output_tokens":e.usage.output,"gen_ai.usage.cache_read_tokens":e.usage.cacheRead,"gen_ai.usage.cache_write_tokens":e.usage.cacheWrite,"gen_ai.usage.total_tokens":e.usage.totalTokens,"gen_ai.usage.cost":e.usage.cost.total};return e.usage.reasoning!==void 0&&(t[`gen_ai.usage.reasoning_tokens`]=e.usage.reasoning),t}function p(e){if(e.role!==`assistant`)return{"error.type":`AgentError`,outcome:`error`};let t=e.stopReason===`aborted`;return{"error.type":`ProviderError`,"error.code":e.stopReason,outcome:t?`aborted`:`error`}}function m(e){return{service:e.serviceName,backend:e.backend,endpoint:e.endpoint??`none`,endpointSource:e.endpointSource,traces:e.traces,redaction:!0,fileFallback:e.fileFallback}}function h(e,t,n={},r=!1){let a=n.env??process.env,c=n.metrics,h=new Map,g=!0,_=0,v,y,b,x=Promise.resolve(),S=e=>{x=x.then(e).catch(()=>void 0)};e.effect(()=>async()=>{g=!1,_+=1,b=void 0,h.clear(),v=void 0;let e=y;y=void 0,await e?.shutdown()},`${s}/telemetry`);let C=async(e,t,n)=>{!g||!y||(e===`debug`?await y.recordDebug(t,n):e===`warn`?await y.recordWarning(t,void 0,n):e===`error`?await y.recordError(t,void 0,n):await y.recordEvent(t,n))},w=e=>{if(!g)throw Error(`Log telemetry runtime is disposed.`);return y??=(0,o.createDoomTelemetry)({serviceName:n.serviceName??`pi`,packageName:s,cwd:e.cwd,env:a,allowFileFallback:n.allowFileFallback,telemetryFactory:n.telemetryFactory,warn:n.onDiagnostic,enableLogs:!0,enableTraces:a.AGENT_OTEL_TRACES===void 0||u(a.AGENT_OTEL_TRACES),onRecord:e=>{g&&c?.record(e.event,e.attributes)},onStatus:e=>{g&&n.onSinkStatus?.(m(e))}}),g&&n.onSinkStatus?.(m(y.status())),y},T=async e=>{let t=b;if(t){if(t.sessionManager!==e.sessionManager)throw Error(`Log readiness belongs to a stale Pi session.`);if(await t.operation,!g||t!==b)throw Error(`Log readiness belongs to a stale extension generation.`)}},E=(e,t)=>{let n=b,i=async()=>{if(n){if(!await n.operation.then(()=>!0,()=>!1)||!g||n!==b||n.sessionManager!==e.sessionManager)return}else if(!g)return;await t()};if(!r)return i();S(i)};return t.on(`session_start`,(t,n)=>{if(!g)return;let a=++_;h.clear(),v=void 0;let o=async e=>{e?.throwIfAborted(),w(n),await C(`info`,`pi.session.started`,{...d(n),"pi.session.reason":t.reason,"pi.session.previous":t.previousSessionFile!==void 0}),e?.throwIfAborted()},c=r?(0,i.readDoomReadinessCoordinator)(e):void 0;if(!c)return o();let l=b,u=(async()=>{l?.coordinator===c&&await l.operation.catch(()=>void 0),!(!g||a!==_)&&await c.start(s,`${n.sessionManager.getSessionId()}:${a}`,async e=>(await o(e),{value:void 0})).wait()})();u.catch(()=>void 0),b={sessionManager:n.sessionManager,coordinator:c,operation:u}}),t.on(`before_agent_start`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`info`,`pi.user_prompt`,{...d(t),"pi.user_message.length":e.prompt.length,"pi.user_message.image_count":e.images?.length??0})})}),t.on(`agent_start`,(e,t)=>{if(g)return E(t,async()=>{v=Date.now(),w(t),await C(`info`,`pi.agent.started`,d(t))})}),t.on(`turn_start`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`debug`,`pi.turn.started`,{...d(t),"pi.turn.index":e.turnIndex})})}),t.on(`turn_end`,(e,t)=>{if(g)return E(t,async()=>{w(t);let n=f(e.message);if(await C(`info`,`pi.turn.finished`,{...d(t),"pi.turn.index":e.turnIndex,"pi.tool_result.count":e.toolResults.length,...n}),e.message.role===`assistant`&&l.has(e.message.stopReason)&&await C(e.message.stopReason===`aborted`?`warn`:`error`,`pi.turn.failed`,{...d(t),"pi.turn.index":e.turnIndex,...p(e.message),...n}),n)for(let r of e.toolResults)await C(`debug`,`pi.tool_token_sample`,{...d(t),...n,"tool.name":r.toolName,token_attribution:`toolCallTurn`})})}),t.on(`tool_execution_start`,(e,t)=>{if(g)return E(t,async()=>{h.set(e.toolCallId,Date.now()),w(t),await C(`debug`,`pi.tool_call`,{...d(t),"tool.name":e.toolName,"tool.call.id":e.toolCallId})})}),t.on(`tool_execution_end`,(e,t)=>{if(g)return E(t,async()=>{let n=h.get(e.toolCallId);h.delete(e.toolCallId),w(t),await C(`info`,`pi.tool_result`,{...d(t),success:!e.isError,"tool.name":e.toolName,"tool.call.id":e.toolCallId,"tool.result.error":e.isError,...n===void 0?{}:{"tool.duration_ms":Date.now()-n}})})}),t.on(`after_provider_response`,(e,t)=>{if(g)return E(t,async()=>{w(t);let n={...d(t),"http.response.status_code":e.status};e.status>=400?await C(`error`,`pi.api_error`,n):await C(`debug`,`pi.api_response`,n)})}),t.on(`model_select`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`info`,`pi.model.selected`,{...d(t),"pi.model.source":e.source,"gen_ai.provider.name":e.model.provider,"gen_ai.request.model":e.model.id})})}),t.on(`agent_end`,(e,t)=>{if(!g)return;let n=_;return E(t,async()=>{w(t),await C(`info`,`pi.agent.finished`,{...d(t),"pi.message.count":e.messages.length,...v===void 0?{}:{"pi.agent.duration_ms":Date.now()-v}}),!(!g||n!==_)&&(v=void 0,await y?.flush())})}),t.on(`agent_settled`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`debug`,`pi.agent.settled`,d(t))})}),{waitForSession:T,async finishSession(e,t){if(!g)return;await x;let n=b;n&&await n.operation.catch(()=>void 0),g&&(n&&n!==b||y&&(w(t),await C(`info`,`pi.session.finished`,{...d(t),"pi.session.reason":e})))}}}function g(e,t={}){let n=e.registerLeader({source:t.source??`@agimon-ai/doompi-log`,bindings:[{id:`log.metrics`,path:[{key:`h`,label:`help`,detail:`package docs and logs`,order:70},{key:`l`,label:`logs`,detail:`telemetry`}],command:{name:c}}]});return()=>n.dispose()}async function _(e,n,r){await e.ui.custom((e,i,a,o)=>new t.LogMetricsOverlayComponent(e,i,n,o,r),{overlay:!0,overlayOptions:{anchor:`top-left`,width:`100%`,maxHeight:`100%`,margin:0}})}function v(t,r,i={},o=!1){let l=i.env??process.env,d=new e.LogMetricsAggregator,f=i.metricsSource
|
|
1
|
+
const e=require("../../services/metrics.cjs"),t=require("../../tui/logMetricsOverlay.cjs"),n=require("../node/metricsSource.cjs");let r=require("@agimon-ai/doompi-extension-contracts/cordis-host"),i=require("@agimon-ai/doompi-extension-contracts/readiness"),a=require("@agimon-ai/doompi-extension-contracts/ui-hub"),o=require("@agimon-ai/doompi-telemetry");const s=`@agimon-ai/doompi-log`,c=`log-metrics`,l=new Set([`error`,`aborted`]);function u(e){return e===`1`||e?.toLowerCase()===`true`||e?.toLowerCase()===`yes`}function d(e){let t={"pi.mode":e.mode,"pi.session.id":e.sessionManager.getSessionId()};return e.thinkingLevel&&(t[`pi.thinking_level`]=e.thinkingLevel),e.model&&(t[`gen_ai.provider.name`]=e.model.provider,t[`gen_ai.request.model`]=e.model.id),t}function f(e){if(e.role!==`assistant`)return;let t={"gen_ai.response.model":e.responseModel??e.model,"gen_ai.response.finish_reasons":e.stopReason,"gen_ai.usage.input_tokens":e.usage.input,"gen_ai.usage.output_tokens":e.usage.output,"gen_ai.usage.cache_read_tokens":e.usage.cacheRead,"gen_ai.usage.cache_write_tokens":e.usage.cacheWrite,"gen_ai.usage.total_tokens":e.usage.totalTokens,"gen_ai.usage.cost":e.usage.cost.total};return e.usage.reasoning!==void 0&&(t[`gen_ai.usage.reasoning_tokens`]=e.usage.reasoning),t}function p(e){if(e.role!==`assistant`)return{"error.type":`AgentError`,outcome:`error`};let t=e.stopReason===`aborted`;return{"error.type":`ProviderError`,"error.code":e.stopReason,outcome:t?`aborted`:`error`}}function m(e){return{service:e.serviceName,backend:e.backend,endpoint:e.endpoint??`none`,endpointSource:e.endpointSource,traces:e.traces,redaction:!0,fileFallback:e.fileFallback}}function h(e,t,n={},r=!1){let a=n.env??process.env,c=n.metrics,h=new Map,g=!0,_=0,v,y,b,x=Promise.resolve(),S=e=>{x=x.then(e).catch(()=>void 0)};e.effect(()=>async()=>{g=!1,_+=1,b=void 0,h.clear(),v=void 0;let e=y;y=void 0,await e?.shutdown()},`${s}/telemetry`);let C=async(e,t,n)=>{!g||!y||(e===`debug`?await y.recordDebug(t,n):e===`warn`?await y.recordWarning(t,void 0,n):e===`error`?await y.recordError(t,void 0,n):await y.recordEvent(t,n))},w=e=>{if(!g)throw Error(`Log telemetry runtime is disposed.`);return y??=(0,o.createDoomTelemetry)({serviceName:n.serviceName??`pi`,packageName:s,cwd:e.cwd,env:a,allowFileFallback:n.allowFileFallback,telemetryFactory:n.telemetryFactory,warn:n.onDiagnostic,enableLogs:!0,enableTraces:a.AGENT_OTEL_TRACES===void 0||u(a.AGENT_OTEL_TRACES),onRecord:e=>{g&&c?.record(e.event,e.attributes)},onStatus:e=>{g&&n.onSinkStatus?.(m(e))}}),g&&n.onSinkStatus?.(m(y.status())),y},T=async e=>{let t=b;if(t){if(t.sessionManager!==e.sessionManager)throw Error(`Log readiness belongs to a stale Pi session.`);if(await t.operation,!g||t!==b)throw Error(`Log readiness belongs to a stale extension generation.`)}},E=(e,t)=>{let n=b,i=async()=>{if(n){if(!await n.operation.then(()=>!0,()=>!1)||!g||n!==b||n.sessionManager!==e.sessionManager)return}else if(!g)return;await t()};if(!r)return i();S(i)};return t.on(`session_start`,(t,n)=>{if(!g)return;let a=++_;h.clear(),v=void 0;let o=async e=>{e?.throwIfAborted(),w(n),await C(`info`,`pi.session.started`,{...d(n),"pi.session.reason":t.reason,"pi.session.previous":t.previousSessionFile!==void 0}),e?.throwIfAborted()},c=r?(0,i.readDoomReadinessCoordinator)(e):void 0;if(!c)return o();let l=b,u=(async()=>{l?.coordinator===c&&await l.operation.catch(()=>void 0),!(!g||a!==_)&&await c.start(s,`${n.sessionManager.getSessionId()}:${a}`,async e=>(await o(e),{value:void 0})).wait()})();u.catch(()=>void 0),b={sessionManager:n.sessionManager,coordinator:c,operation:u}}),t.on(`before_agent_start`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`info`,`pi.user_prompt`,{...d(t),"pi.user_message.length":e.prompt.length,"pi.user_message.image_count":e.images?.length??0})})}),t.on(`agent_start`,(e,t)=>{if(g)return E(t,async()=>{v=Date.now(),w(t),await C(`info`,`pi.agent.started`,d(t))})}),t.on(`turn_start`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`debug`,`pi.turn.started`,{...d(t),"pi.turn.index":e.turnIndex})})}),t.on(`turn_end`,(e,t)=>{if(g)return E(t,async()=>{w(t);let n=f(e.message);if(await C(`info`,`pi.turn.finished`,{...d(t),"pi.turn.index":e.turnIndex,"pi.tool_result.count":e.toolResults.length,...n}),e.message.role===`assistant`&&l.has(e.message.stopReason)&&await C(e.message.stopReason===`aborted`?`warn`:`error`,`pi.turn.failed`,{...d(t),"pi.turn.index":e.turnIndex,...p(e.message),...n}),n)for(let r of e.toolResults)await C(`debug`,`pi.tool_token_sample`,{...d(t),...n,"tool.name":r.toolName,token_attribution:`toolCallTurn`})})}),t.on(`tool_execution_start`,(e,t)=>{if(g)return E(t,async()=>{h.set(e.toolCallId,Date.now()),w(t),await C(`debug`,`pi.tool_call`,{...d(t),"tool.name":e.toolName,"tool.call.id":e.toolCallId})})}),t.on(`tool_execution_end`,(e,t)=>{if(g)return E(t,async()=>{let n=h.get(e.toolCallId);h.delete(e.toolCallId),w(t),await C(`info`,`pi.tool_result`,{...d(t),success:!e.isError,"tool.name":e.toolName,"tool.call.id":e.toolCallId,"tool.result.error":e.isError,...n===void 0?{}:{"tool.duration_ms":Date.now()-n}})})}),t.on(`after_provider_response`,(e,t)=>{if(g)return E(t,async()=>{w(t);let n={...d(t),"http.response.status_code":e.status};e.status>=400?await C(`error`,`pi.api_error`,n):await C(`debug`,`pi.api_response`,n)})}),t.on(`model_select`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`info`,`pi.model.selected`,{...d(t),"pi.model.source":e.source,"gen_ai.provider.name":e.model.provider,"gen_ai.request.model":e.model.id})})}),t.on(`agent_end`,(e,t)=>{if(!g)return;let n=_;return E(t,async()=>{w(t),await C(`info`,`pi.agent.finished`,{...d(t),"pi.message.count":e.messages.length,...v===void 0?{}:{"pi.agent.duration_ms":Date.now()-v}}),!(!g||n!==_)&&(v=void 0,await y?.flush())})}),t.on(`agent_settled`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`debug`,`pi.agent.settled`,d(t))})}),{waitForSession:T,async finishSession(e,t){if(!g)return;await x;let n=b;n&&await n.operation.catch(()=>void 0),g&&(n&&n!==b||y&&(w(t),await C(`info`,`pi.session.finished`,{...d(t),"pi.session.reason":e})))}}}function g(e,t={}){let n=e.registerLeader({source:t.source??`@agimon-ai/doompi-log`,bindings:[{id:`log.metrics`,path:[{key:`h`,label:`help`,detail:`package docs and logs`,order:70},{key:`l`,label:`logs`,detail:`telemetry`}],command:{name:c}}]});return()=>n.dispose()}async function _(e,n,r){await e.ui.custom((e,i,a,o)=>new t.LogMetricsOverlayComponent(e,i,n,o,r),{overlay:!0,overlayOptions:{anchor:`top-left`,width:`100%`,maxHeight:`100%`,margin:0}})}function v(t,r,i={},o=!1){let l=i.env??process.env,d=new e.LogMetricsAggregator,f=i.metricsSource,p=e=>f??=n.createMetricsSource({env:l,cwd:e.cwd,packageName:s,serviceName:i.serviceName??`pi`}),m=!0,v,y;t.effect(()=>()=>{m=!1,v=void 0,y=void 0},`${s}/runtime`);let b=h(t,r,{...i,metrics:d,onDiagnostic:e=>{m&&(y=e,i.onDiagnostic?i.onDiagnostic(e):l.AGENT_OTEL_DIAGNOSTICS===`stderr`&&process.emitWarning(e))},onSinkStatus:e=>{m&&(v=e,i.onSinkStatus?.(e))}},o);return t.inject([a.DOOM_UI_HUB_SERVICE],e=>g((0,a.requireDoomUiHub)(e),{source:i.leaderSource})),r.registerCommand(c,{description:`Show session-local log metrics`,handler:async(e,t)=>{if(!m||(await b.waitForSession(t),!m))return;let n=p(t);await _(t,()=>({disabled:u(l.AGENT_TELEMETRY_DISABLED)||u(l.OTEL_SDK_DISABLED),snapshot:d.snapshot(),sink:v,transport:n.lastTransport(),instance:n.instance?.(),lastDiagnostic:y}),n.query)}}),b}function y(e,{pi:t}){let n=v(e,t,{},!0),r;t.on(`session_shutdown`,(e,t)=>(r??=n.finishSession(e.reason,t),r))}async function b(e){let t=await(0,r.connectDoomCordisHost)(e,s),n=t.root.plugin(y,{pi:e});try{await n}catch(e){try{await n.dispose()}finally{await t.dispose()}throw e}let i;e.on(`session_shutdown`,()=>i??=(async()=>{try{await n.dispose()}finally{await t.dispose()}})())}exports.doomLogExtension=b,exports.installDoomLogRuntime=v,exports.installPiTelemetryRuntime=h,exports.openLogMetricsOverlay=_,exports.registerLogMetricsLeaderBinding=g;
|
|
2
2
|
//# sourceMappingURL=extension.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.cjs","names":["createDoomTelemetry","readDoomReadinessCoordinator","LogMetricsOverlayComponent","LogMetricsAggregator","createMetricsSource","DOOM_UI_HUB_SERVICE","requireDoomUiHub","connectDoomCordisHost"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["/**\n * Pi telemetry wiring for the Doom harness.\n *\n * This extension deliberately emits metadata-only records. Prompt, message,\n * tool payload, file path, diagnostic text, exception, and stack data never\n * cross the shared telemetry boundary.\n */\n\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n type DoomReadinessCoordinator,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport {\n DOOM_UI_HUB_SERVICE,\n type DoomUiHubService,\n requireDoomUiHub,\n} from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext, TurnEndEvent } from '@earendil-works/pi-coding-agent';\nimport { LogMetricsAggregator, type LogMetricsRecorder } from '../../services/metrics.ts';\nimport { LogMetricsOverlayComponent, type LogMetricsView, type SinkStatus } from '../../tui/logMetricsOverlay.ts';\nimport type { MetricsQuery, MetricsSource } from '../../types/metricsSource.ts';\nimport { createMetricsSource } from '../node/metricsSource.ts';\n\nconst SERVICE_NAME = 'pi';\nconst PACKAGE_NAME = '@agimon-ai/doompi-log';\n/** Opt back into stderr diagnostics when debugging outside a live TUI. */\nconst DIAGNOSTICS_STDERR = 'stderr';\nconst LEADER_SOURCE = '@agimon-ai/doompi-log';\nconst LOG_METRICS_COMMAND = 'log-metrics';\nconst LOG_METRICS_DESCRIPTION = 'Show session-local log metrics';\nconst HELP_GROUP_ORDER = 70;\n/** Must match the Help group published by doompi-ui, or the registry drops this. */\nconst HELP_GROUP_DETAIL = 'package docs and logs';\nconst NO_ENDPOINT = 'none';\nconst API_ERROR_STATUS = 400;\nconst FAILURE_STOP_REASONS = new Set(['error', 'aborted']);\n\ntype TelemetryFactory = NonNullable<DoomTelemetryOptions['telemetryFactory']>;\ntype TelemetryAttributes = Record<string, string | number | boolean>;\ntype RecordLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface PiTelemetryExtensionOptions {\n allowFileFallback?: boolean;\n /** Overrides the telemetry service identity. */\n serviceName?: string;\n /** Overrides the leader contribution owner. */\n leaderSource?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: TelemetryFactory;\n /** Receives every sanitized record, whether or not a sink is live. */\n metrics?: LogMetricsRecorder;\n /** Called once the sink backend is resolved, so the overlay can report it. */\n onSinkStatus?: (status: SinkStatus | undefined) => void;\n /** Overrides the sink-history transport; injected in tests. */\n metricsSource?: MetricsSource;\n /** Receives telemetry lifecycle failures without writing into the TUI. */\n onDiagnostic?: (message: string) => void;\n}\n\nexport interface PiTelemetryRuntimeHandle {\n waitForSession(ctx: ExtensionContext): Promise<void>;\n finishSession(reason: string, ctx: ExtensionContext): Promise<void>;\n}\n\nfunction isEnabled(value: string | undefined): boolean {\n return value === '1' || value?.toLowerCase() === 'true' || value?.toLowerCase() === 'yes';\n}\n\nfunction contextAttributes(ctx: ExtensionContext): TelemetryAttributes {\n const attributes: TelemetryAttributes = {\n 'pi.mode': ctx.mode,\n 'pi.session.id': ctx.sessionManager.getSessionId(),\n };\n if (ctx.thinkingLevel) attributes['pi.thinking_level'] = ctx.thinkingLevel;\n if (ctx.model) {\n attributes['gen_ai.provider.name'] = ctx.model.provider;\n attributes['gen_ai.request.model'] = ctx.model.id;\n }\n return attributes;\n}\n\nfunction usageAttributes(message: TurnEndEvent['message']): TelemetryAttributes | undefined {\n if (message.role !== 'assistant') return undefined;\n const attributes: TelemetryAttributes = {\n 'gen_ai.response.model': message.responseModel ?? message.model,\n 'gen_ai.response.finish_reasons': message.stopReason,\n 'gen_ai.usage.input_tokens': message.usage.input,\n 'gen_ai.usage.output_tokens': message.usage.output,\n 'gen_ai.usage.cache_read_tokens': message.usage.cacheRead,\n 'gen_ai.usage.cache_write_tokens': message.usage.cacheWrite,\n 'gen_ai.usage.total_tokens': message.usage.totalTokens,\n 'gen_ai.usage.cost': message.usage.cost.total,\n };\n if (message.usage.reasoning !== undefined) attributes['gen_ai.usage.reasoning_tokens'] = message.usage.reasoning;\n return attributes;\n}\n\nfunction failureAttributes(message: TurnEndEvent['message']): TelemetryAttributes {\n if (message.role !== 'assistant') return { 'error.type': 'AgentError', outcome: 'error' };\n const aborted = message.stopReason === 'aborted';\n return {\n 'error.type': 'ProviderError',\n 'error.code': message.stopReason,\n outcome: aborted ? 'aborted' : 'error',\n };\n}\n\nfunction statusFromTelemetry(status: ReturnType<DoomTelemetry['status']>): SinkStatus {\n return {\n service: status.serviceName,\n backend: status.backend,\n endpoint: status.endpoint ?? NO_ENDPOINT,\n endpointSource: status.endpointSource,\n traces: status.traces,\n redaction: true,\n fileFallback: status.fileFallback,\n };\n}\n\nexport function installPiTelemetryRuntime(\n cordis: Context,\n pi: ExtensionAPI,\n options: PiTelemetryExtensionOptions = {},\n splitReadiness = false,\n): PiTelemetryRuntimeHandle {\n const env = options.env ?? process.env;\n const metrics = options.metrics;\n const toolStartedAt = new Map<string, number>();\n let active = true;\n let sessionGeneration = 0;\n let agentStartedAt: number | undefined;\n let telemetry: DoomTelemetry | undefined;\n let sessionReadiness:\n | {\n readonly sessionManager: object;\n readonly coordinator: DoomReadinessCoordinator;\n readonly operation: Promise<void>;\n }\n | undefined;\n let backgroundQueue = Promise.resolve();\n\n const enqueue = (operation: () => Promise<void>): void => {\n const scheduled = backgroundQueue.then(operation);\n // Telemetry is advisory and the coordinator owns startup failure notification.\n backgroundQueue = scheduled.catch(() => undefined);\n };\n\n cordis.effect(\n () => async () => {\n active = false;\n sessionGeneration += 1;\n sessionReadiness = undefined;\n toolStartedAt.clear();\n agentStartedAt = undefined;\n const ownedTelemetry = telemetry;\n telemetry = undefined;\n await ownedTelemetry?.shutdown();\n },\n `${PACKAGE_NAME}/telemetry`,\n );\n\n const emit = async (level: RecordLevel, name: string, attributes: TelemetryAttributes): Promise<void> => {\n if (!active || !telemetry) return;\n if (level === 'debug') await telemetry.recordDebug(name, attributes);\n else if (level === 'warn') await telemetry.recordWarning(name, undefined, attributes);\n else if (level === 'error') await telemetry.recordError(name, undefined, attributes);\n else await telemetry.recordEvent(name, attributes);\n };\n\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n if (!active) throw new Error('Log telemetry runtime is disposed.');\n telemetry ??= createDoomTelemetry({\n serviceName: options.serviceName ?? SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: ctx.cwd,\n env,\n allowFileFallback: options.allowFileFallback,\n telemetryFactory: options.telemetryFactory,\n warn: options.onDiagnostic,\n enableLogs: true,\n enableTraces: env.AGENT_OTEL_TRACES === undefined || isEnabled(env.AGENT_OTEL_TRACES),\n onRecord: (record) => {\n if (active) metrics?.record(record.event, record.attributes);\n },\n onStatus: (status) => {\n if (active) options.onSinkStatus?.(statusFromTelemetry(status));\n },\n });\n if (active) options.onSinkStatus?.(statusFromTelemetry(telemetry.status()));\n return telemetry;\n };\n\n const waitForSession = async (ctx: ExtensionContext): Promise<void> => {\n const current = sessionReadiness;\n if (!current) return;\n if (current.sessionManager !== ctx.sessionManager) {\n throw new Error('Log readiness belongs to a stale Pi session.');\n }\n await current.operation;\n if (!active || current !== sessionReadiness) {\n throw new Error('Log readiness belongs to a stale extension generation.');\n }\n };\n\n const enqueueForSession = (ctx: ExtensionContext, operation: () => Promise<void>): void | Promise<void> => {\n const expected = sessionReadiness;\n const run = async (): Promise<void> => {\n if (expected) {\n const ready = await expected.operation.then(\n () => true,\n () => false,\n );\n if (!ready || !active || expected !== sessionReadiness || expected.sessionManager !== ctx.sessionManager) {\n return;\n }\n } else if (!active) {\n return;\n }\n await operation();\n };\n if (!splitReadiness) return run();\n enqueue(run);\n return undefined;\n };\n\n pi.on('session_start', (event, ctx) => {\n if (!active) return undefined;\n const ownGeneration = ++sessionGeneration;\n toolStartedAt.clear();\n agentStartedAt = undefined;\n const initialize = async (signal?: AbortSignal): Promise<void> => {\n signal?.throwIfAborted();\n getTelemetry(ctx);\n await emit('info', 'pi.session.started', {\n ...contextAttributes(ctx),\n 'pi.session.reason': event.reason,\n 'pi.session.previous': event.previousSessionFile !== undefined,\n });\n signal?.throwIfAborted();\n };\n const coordinator = splitReadiness ? readDoomReadinessCoordinator(cordis) : undefined;\n if (!coordinator) return initialize();\n\n const previous = sessionReadiness;\n const operation = (async (): Promise<void> => {\n if (previous?.coordinator === coordinator) await previous.operation.catch(() => undefined);\n if (!active || ownGeneration !== sessionGeneration) return;\n const handle = coordinator.start(\n PACKAGE_NAME,\n `${ctx.sessionManager.getSessionId()}:${ownGeneration}`,\n async (signal) => {\n await initialize(signal);\n return { value: undefined };\n },\n );\n await handle.wait();\n })();\n // Config's coordinator owns the single user-facing failure notification.\n void operation.catch(() => undefined);\n sessionReadiness = { sessionManager: ctx.sessionManager, coordinator, operation };\n return undefined;\n });\n\n pi.on('before_agent_start', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('info', 'pi.user_prompt', {\n ...contextAttributes(ctx),\n 'pi.user_message.length': event.prompt.length,\n 'pi.user_message.image_count': event.images?.length ?? 0,\n });\n });\n });\n\n pi.on('agent_start', (_event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n agentStartedAt = Date.now();\n getTelemetry(ctx);\n await emit('info', 'pi.agent.started', contextAttributes(ctx));\n });\n });\n\n pi.on('turn_start', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('debug', 'pi.turn.started', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n });\n });\n });\n\n pi.on('turn_end', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n const usage = usageAttributes(event.message);\n await emit('info', 'pi.turn.finished', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n 'pi.tool_result.count': event.toolResults.length,\n ...usage,\n });\n if (event.message.role === 'assistant' && FAILURE_STOP_REASONS.has(event.message.stopReason)) {\n await emit(event.message.stopReason === 'aborted' ? 'warn' : 'error', 'pi.turn.failed', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n ...failureAttributes(event.message),\n ...usage,\n });\n }\n if (!usage) return;\n for (const result of event.toolResults) {\n await emit('debug', 'pi.tool_token_sample', {\n ...contextAttributes(ctx),\n ...usage,\n 'tool.name': result.toolName,\n token_attribution: 'toolCallTurn',\n });\n }\n });\n });\n\n pi.on('tool_execution_start', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n toolStartedAt.set(event.toolCallId, Date.now());\n getTelemetry(ctx);\n await emit('debug', 'pi.tool_call', {\n ...contextAttributes(ctx),\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n });\n });\n });\n\n pi.on('tool_execution_end', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n getTelemetry(ctx);\n await emit('info', 'pi.tool_result', {\n ...contextAttributes(ctx),\n success: !event.isError,\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n 'tool.result.error': event.isError,\n ...(startedAt === undefined ? {} : { 'tool.duration_ms': Date.now() - startedAt }),\n });\n });\n });\n\n pi.on('after_provider_response', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n const attributes = {\n ...contextAttributes(ctx),\n 'http.response.status_code': event.status,\n };\n if (event.status >= API_ERROR_STATUS) await emit('error', 'pi.api_error', attributes);\n else await emit('debug', 'pi.api_response', attributes);\n });\n });\n\n pi.on('model_select', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('info', 'pi.model.selected', {\n ...contextAttributes(ctx),\n 'pi.model.source': event.source,\n 'gen_ai.provider.name': event.model.provider,\n 'gen_ai.request.model': event.model.id,\n });\n });\n });\n\n pi.on('agent_end', (event, ctx) => {\n if (!active) return;\n const generation = sessionGeneration;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('info', 'pi.agent.finished', {\n ...contextAttributes(ctx),\n 'pi.message.count': event.messages.length,\n ...(agentStartedAt === undefined ? {} : { 'pi.agent.duration_ms': Date.now() - agentStartedAt }),\n });\n if (!active || generation !== sessionGeneration) return;\n agentStartedAt = undefined;\n await telemetry?.flush();\n });\n });\n\n pi.on('agent_settled', (_event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('debug', 'pi.agent.settled', contextAttributes(ctx));\n });\n });\n\n return {\n waitForSession,\n async finishSession(reason, ctx) {\n if (!active) return;\n await backgroundQueue;\n const current = sessionReadiness;\n if (current) await current.operation.catch(() => undefined);\n if (!active) return;\n if (current && current !== sessionReadiness) return;\n if (!telemetry) return;\n getTelemetry(ctx);\n await emit('info', 'pi.session.finished', {\n ...contextAttributes(ctx),\n 'pi.session.reason': reason,\n });\n },\n };\n}\n\nexport function registerLogMetricsLeaderBinding(hub: DoomUiHubService, options: { source?: string } = {}): () => void {\n const contribution = hub.registerLeader({\n source: options.source ?? LEADER_SOURCE,\n bindings: [\n {\n id: 'log.metrics',\n path: [\n { key: 'h', label: 'help', detail: HELP_GROUP_DETAIL, order: HELP_GROUP_ORDER },\n { key: 'l', label: 'logs', detail: 'telemetry' },\n ],\n command: { name: LOG_METRICS_COMMAND },\n },\n ],\n });\n return () => contribution.dispose();\n}\n\nexport async function openLogMetricsOverlay(\n ctx: ExtensionContext,\n getView: () => LogMetricsView,\n query?: MetricsQuery,\n): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new LogMetricsOverlayComponent(tui, theme, getView, done, query),\n {\n overlay: true,\n overlayOptions: {\n anchor: 'top-left',\n width: '100%',\n maxHeight: '100%',\n margin: 0,\n },\n },\n );\n}\n\nexport function installDoomLogRuntime(\n cordis: Context,\n pi: ExtensionAPI,\n options: PiTelemetryExtensionOptions = {},\n splitReadiness = false,\n): PiTelemetryRuntimeHandle {\n const env = options.env ?? process.env;\n const metrics = new LogMetricsAggregator();\n const metricsSource = options.metricsSource ?? createMetricsSource({ env });\n let active = true;\n let sink: SinkStatus | undefined;\n let lastDiagnostic: string | undefined;\n\n cordis.effect(\n () => () => {\n active = false;\n sink = undefined;\n lastDiagnostic = undefined;\n },\n `${PACKAGE_NAME}/runtime`,\n );\n\n const telemetryRuntime = installPiTelemetryRuntime(\n cordis,\n pi,\n {\n ...options,\n metrics,\n // Always supply a sink so doom-telemetry never falls back to\n // process.emitWarning, which writes raw stderr over the TUI frame.\n // Diagnostics surface in the Log Metrics overlay instead.\n onDiagnostic: (message) => {\n if (!active) return;\n lastDiagnostic = message;\n if (options.onDiagnostic) options.onDiagnostic(message);\n else if (env.AGENT_OTEL_DIAGNOSTICS === DIAGNOSTICS_STDERR) process.emitWarning(message);\n },\n onSinkStatus: (status) => {\n if (!active) return;\n sink = status;\n options.onSinkStatus?.(status);\n },\n },\n splitReadiness,\n );\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n return registerLogMetricsLeaderBinding(requireDoomUiHub(uiContext), { source: options.leaderSource });\n });\n pi.registerCommand(LOG_METRICS_COMMAND, {\n description: LOG_METRICS_DESCRIPTION,\n handler: async (_args, ctx) => {\n if (!active) return;\n await telemetryRuntime.waitForSession(ctx);\n if (!active) return;\n await openLogMetricsOverlay(\n ctx,\n () => ({\n disabled: isEnabled(env.AGENT_TELEMETRY_DISABLED) || isEnabled(env.OTEL_SDK_DISABLED),\n snapshot: metrics.snapshot(),\n sink,\n transport: metricsSource.lastTransport(),\n lastDiagnostic,\n }),\n metricsSource.query,\n );\n },\n });\n return telemetryRuntime;\n}\n\ninterface LogPluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction logPlugin(cordis: Context, { pi }: LogPluginConfig): void {\n const runtime = installDoomLogRuntime(cordis, pi, {}, true);\n let shutdown: Promise<void> | undefined;\n pi.on('session_shutdown', (event, ctx) => {\n shutdown ??= runtime.finishSession(event.reason, ctx);\n return shutdown;\n });\n}\n\n/** The package's single standard Pi factory. */\nexport async function doomLogExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_NAME);\n const fiber = connection.root.plugin(logPlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"extension.cjs","names":["createDoomTelemetry","readDoomReadinessCoordinator","LogMetricsOverlayComponent","LogMetricsAggregator","createMetricsSource","DOOM_UI_HUB_SERVICE","requireDoomUiHub","connectDoomCordisHost"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["/**\n * Pi telemetry wiring for the Doom harness.\n *\n * This extension deliberately emits metadata-only records. Prompt, message,\n * tool payload, file path, diagnostic text, exception, and stack data never\n * cross the shared telemetry boundary.\n */\n\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n type DoomReadinessCoordinator,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport {\n DOOM_UI_HUB_SERVICE,\n type DoomUiHubService,\n requireDoomUiHub,\n} from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext, TurnEndEvent } from '@earendil-works/pi-coding-agent';\nimport { LogMetricsAggregator, type LogMetricsRecorder } from '../../services/metrics.ts';\nimport { LogMetricsOverlayComponent, type LogMetricsView, type SinkStatus } from '../../tui/logMetricsOverlay.ts';\nimport type { MetricsQuery, MetricsSource } from '../../types/metricsSource.ts';\nimport { createMetricsSource } from '../node/metricsSource.ts';\n\nconst SERVICE_NAME = 'pi';\nconst PACKAGE_NAME = '@agimon-ai/doompi-log';\n/** Opt back into stderr diagnostics when debugging outside a live TUI. */\nconst DIAGNOSTICS_STDERR = 'stderr';\nconst LEADER_SOURCE = '@agimon-ai/doompi-log';\nconst LOG_METRICS_COMMAND = 'log-metrics';\nconst LOG_METRICS_DESCRIPTION = 'Show session-local log metrics';\nconst HELP_GROUP_ORDER = 70;\n/** Must match the Help group published by doompi-ui, or the registry drops this. */\nconst HELP_GROUP_DETAIL = 'package docs and logs';\nconst NO_ENDPOINT = 'none';\nconst API_ERROR_STATUS = 400;\nconst FAILURE_STOP_REASONS = new Set(['error', 'aborted']);\n\ntype TelemetryFactory = NonNullable<DoomTelemetryOptions['telemetryFactory']>;\ntype TelemetryAttributes = Record<string, string | number | boolean>;\ntype RecordLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface PiTelemetryExtensionOptions {\n allowFileFallback?: boolean;\n /** Overrides the telemetry service identity. */\n serviceName?: string;\n /** Overrides the leader contribution owner. */\n leaderSource?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: TelemetryFactory;\n /** Receives every sanitized record, whether or not a sink is live. */\n metrics?: LogMetricsRecorder;\n /** Called once the sink backend is resolved, so the overlay can report it. */\n onSinkStatus?: (status: SinkStatus | undefined) => void;\n /** Overrides the sink-history transport; injected in tests. */\n metricsSource?: MetricsSource;\n /** Receives telemetry lifecycle failures without writing into the TUI. */\n onDiagnostic?: (message: string) => void;\n}\n\nexport interface PiTelemetryRuntimeHandle {\n waitForSession(ctx: ExtensionContext): Promise<void>;\n finishSession(reason: string, ctx: ExtensionContext): Promise<void>;\n}\n\nfunction isEnabled(value: string | undefined): boolean {\n return value === '1' || value?.toLowerCase() === 'true' || value?.toLowerCase() === 'yes';\n}\n\nfunction contextAttributes(ctx: ExtensionContext): TelemetryAttributes {\n const attributes: TelemetryAttributes = {\n 'pi.mode': ctx.mode,\n 'pi.session.id': ctx.sessionManager.getSessionId(),\n };\n if (ctx.thinkingLevel) attributes['pi.thinking_level'] = ctx.thinkingLevel;\n if (ctx.model) {\n attributes['gen_ai.provider.name'] = ctx.model.provider;\n attributes['gen_ai.request.model'] = ctx.model.id;\n }\n return attributes;\n}\n\nfunction usageAttributes(message: TurnEndEvent['message']): TelemetryAttributes | undefined {\n if (message.role !== 'assistant') return undefined;\n const attributes: TelemetryAttributes = {\n 'gen_ai.response.model': message.responseModel ?? message.model,\n 'gen_ai.response.finish_reasons': message.stopReason,\n 'gen_ai.usage.input_tokens': message.usage.input,\n 'gen_ai.usage.output_tokens': message.usage.output,\n 'gen_ai.usage.cache_read_tokens': message.usage.cacheRead,\n 'gen_ai.usage.cache_write_tokens': message.usage.cacheWrite,\n 'gen_ai.usage.total_tokens': message.usage.totalTokens,\n 'gen_ai.usage.cost': message.usage.cost.total,\n };\n if (message.usage.reasoning !== undefined) attributes['gen_ai.usage.reasoning_tokens'] = message.usage.reasoning;\n return attributes;\n}\n\nfunction failureAttributes(message: TurnEndEvent['message']): TelemetryAttributes {\n if (message.role !== 'assistant') return { 'error.type': 'AgentError', outcome: 'error' };\n const aborted = message.stopReason === 'aborted';\n return {\n 'error.type': 'ProviderError',\n 'error.code': message.stopReason,\n outcome: aborted ? 'aborted' : 'error',\n };\n}\n\nfunction statusFromTelemetry(status: ReturnType<DoomTelemetry['status']>): SinkStatus {\n return {\n service: status.serviceName,\n backend: status.backend,\n endpoint: status.endpoint ?? NO_ENDPOINT,\n endpointSource: status.endpointSource,\n traces: status.traces,\n redaction: true,\n fileFallback: status.fileFallback,\n };\n}\n\nexport function installPiTelemetryRuntime(\n cordis: Context,\n pi: ExtensionAPI,\n options: PiTelemetryExtensionOptions = {},\n splitReadiness = false,\n): PiTelemetryRuntimeHandle {\n const env = options.env ?? process.env;\n const metrics = options.metrics;\n const toolStartedAt = new Map<string, number>();\n let active = true;\n let sessionGeneration = 0;\n let agentStartedAt: number | undefined;\n let telemetry: DoomTelemetry | undefined;\n let sessionReadiness:\n | {\n readonly sessionManager: object;\n readonly coordinator: DoomReadinessCoordinator;\n readonly operation: Promise<void>;\n }\n | undefined;\n let backgroundQueue = Promise.resolve();\n\n const enqueue = (operation: () => Promise<void>): void => {\n const scheduled = backgroundQueue.then(operation);\n // Telemetry is advisory and the coordinator owns startup failure notification.\n backgroundQueue = scheduled.catch(() => undefined);\n };\n\n cordis.effect(\n () => async () => {\n active = false;\n sessionGeneration += 1;\n sessionReadiness = undefined;\n toolStartedAt.clear();\n agentStartedAt = undefined;\n const ownedTelemetry = telemetry;\n telemetry = undefined;\n await ownedTelemetry?.shutdown();\n },\n `${PACKAGE_NAME}/telemetry`,\n );\n\n const emit = async (level: RecordLevel, name: string, attributes: TelemetryAttributes): Promise<void> => {\n if (!active || !telemetry) return;\n if (level === 'debug') await telemetry.recordDebug(name, attributes);\n else if (level === 'warn') await telemetry.recordWarning(name, undefined, attributes);\n else if (level === 'error') await telemetry.recordError(name, undefined, attributes);\n else await telemetry.recordEvent(name, attributes);\n };\n\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n if (!active) throw new Error('Log telemetry runtime is disposed.');\n telemetry ??= createDoomTelemetry({\n serviceName: options.serviceName ?? SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: ctx.cwd,\n env,\n allowFileFallback: options.allowFileFallback,\n telemetryFactory: options.telemetryFactory,\n warn: options.onDiagnostic,\n enableLogs: true,\n enableTraces: env.AGENT_OTEL_TRACES === undefined || isEnabled(env.AGENT_OTEL_TRACES),\n onRecord: (record) => {\n if (active) metrics?.record(record.event, record.attributes);\n },\n onStatus: (status) => {\n if (active) options.onSinkStatus?.(statusFromTelemetry(status));\n },\n });\n if (active) options.onSinkStatus?.(statusFromTelemetry(telemetry.status()));\n return telemetry;\n };\n\n const waitForSession = async (ctx: ExtensionContext): Promise<void> => {\n const current = sessionReadiness;\n if (!current) return;\n if (current.sessionManager !== ctx.sessionManager) {\n throw new Error('Log readiness belongs to a stale Pi session.');\n }\n await current.operation;\n if (!active || current !== sessionReadiness) {\n throw new Error('Log readiness belongs to a stale extension generation.');\n }\n };\n\n const enqueueForSession = (ctx: ExtensionContext, operation: () => Promise<void>): void | Promise<void> => {\n const expected = sessionReadiness;\n const run = async (): Promise<void> => {\n if (expected) {\n const ready = await expected.operation.then(\n () => true,\n () => false,\n );\n if (!ready || !active || expected !== sessionReadiness || expected.sessionManager !== ctx.sessionManager) {\n return;\n }\n } else if (!active) {\n return;\n }\n await operation();\n };\n if (!splitReadiness) return run();\n enqueue(run);\n return undefined;\n };\n\n pi.on('session_start', (event, ctx) => {\n if (!active) return undefined;\n const ownGeneration = ++sessionGeneration;\n toolStartedAt.clear();\n agentStartedAt = undefined;\n const initialize = async (signal?: AbortSignal): Promise<void> => {\n signal?.throwIfAborted();\n getTelemetry(ctx);\n await emit('info', 'pi.session.started', {\n ...contextAttributes(ctx),\n 'pi.session.reason': event.reason,\n 'pi.session.previous': event.previousSessionFile !== undefined,\n });\n signal?.throwIfAborted();\n };\n const coordinator = splitReadiness ? readDoomReadinessCoordinator(cordis) : undefined;\n if (!coordinator) return initialize();\n\n const previous = sessionReadiness;\n const operation = (async (): Promise<void> => {\n if (previous?.coordinator === coordinator) await previous.operation.catch(() => undefined);\n if (!active || ownGeneration !== sessionGeneration) return;\n const handle = coordinator.start(\n PACKAGE_NAME,\n `${ctx.sessionManager.getSessionId()}:${ownGeneration}`,\n async (signal) => {\n await initialize(signal);\n return { value: undefined };\n },\n );\n await handle.wait();\n })();\n // Config's coordinator owns the single user-facing failure notification.\n void operation.catch(() => undefined);\n sessionReadiness = { sessionManager: ctx.sessionManager, coordinator, operation };\n return undefined;\n });\n\n pi.on('before_agent_start', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('info', 'pi.user_prompt', {\n ...contextAttributes(ctx),\n 'pi.user_message.length': event.prompt.length,\n 'pi.user_message.image_count': event.images?.length ?? 0,\n });\n });\n });\n\n pi.on('agent_start', (_event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n agentStartedAt = Date.now();\n getTelemetry(ctx);\n await emit('info', 'pi.agent.started', contextAttributes(ctx));\n });\n });\n\n pi.on('turn_start', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('debug', 'pi.turn.started', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n });\n });\n });\n\n pi.on('turn_end', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n const usage = usageAttributes(event.message);\n await emit('info', 'pi.turn.finished', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n 'pi.tool_result.count': event.toolResults.length,\n ...usage,\n });\n if (event.message.role === 'assistant' && FAILURE_STOP_REASONS.has(event.message.stopReason)) {\n await emit(event.message.stopReason === 'aborted' ? 'warn' : 'error', 'pi.turn.failed', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n ...failureAttributes(event.message),\n ...usage,\n });\n }\n if (!usage) return;\n for (const result of event.toolResults) {\n await emit('debug', 'pi.tool_token_sample', {\n ...contextAttributes(ctx),\n ...usage,\n 'tool.name': result.toolName,\n token_attribution: 'toolCallTurn',\n });\n }\n });\n });\n\n pi.on('tool_execution_start', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n toolStartedAt.set(event.toolCallId, Date.now());\n getTelemetry(ctx);\n await emit('debug', 'pi.tool_call', {\n ...contextAttributes(ctx),\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n });\n });\n });\n\n pi.on('tool_execution_end', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n getTelemetry(ctx);\n await emit('info', 'pi.tool_result', {\n ...contextAttributes(ctx),\n success: !event.isError,\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n 'tool.result.error': event.isError,\n ...(startedAt === undefined ? {} : { 'tool.duration_ms': Date.now() - startedAt }),\n });\n });\n });\n\n pi.on('after_provider_response', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n const attributes = {\n ...contextAttributes(ctx),\n 'http.response.status_code': event.status,\n };\n if (event.status >= API_ERROR_STATUS) await emit('error', 'pi.api_error', attributes);\n else await emit('debug', 'pi.api_response', attributes);\n });\n });\n\n pi.on('model_select', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('info', 'pi.model.selected', {\n ...contextAttributes(ctx),\n 'pi.model.source': event.source,\n 'gen_ai.provider.name': event.model.provider,\n 'gen_ai.request.model': event.model.id,\n });\n });\n });\n\n pi.on('agent_end', (event, ctx) => {\n if (!active) return;\n const generation = sessionGeneration;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('info', 'pi.agent.finished', {\n ...contextAttributes(ctx),\n 'pi.message.count': event.messages.length,\n ...(agentStartedAt === undefined ? {} : { 'pi.agent.duration_ms': Date.now() - agentStartedAt }),\n });\n if (!active || generation !== sessionGeneration) return;\n agentStartedAt = undefined;\n await telemetry?.flush();\n });\n });\n\n pi.on('agent_settled', (_event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('debug', 'pi.agent.settled', contextAttributes(ctx));\n });\n });\n\n return {\n waitForSession,\n async finishSession(reason, ctx) {\n if (!active) return;\n await backgroundQueue;\n const current = sessionReadiness;\n if (current) await current.operation.catch(() => undefined);\n if (!active) return;\n if (current && current !== sessionReadiness) return;\n if (!telemetry) return;\n getTelemetry(ctx);\n await emit('info', 'pi.session.finished', {\n ...contextAttributes(ctx),\n 'pi.session.reason': reason,\n });\n },\n };\n}\n\nexport function registerLogMetricsLeaderBinding(hub: DoomUiHubService, options: { source?: string } = {}): () => void {\n const contribution = hub.registerLeader({\n source: options.source ?? LEADER_SOURCE,\n bindings: [\n {\n id: 'log.metrics',\n path: [\n { key: 'h', label: 'help', detail: HELP_GROUP_DETAIL, order: HELP_GROUP_ORDER },\n { key: 'l', label: 'logs', detail: 'telemetry' },\n ],\n command: { name: LOG_METRICS_COMMAND },\n },\n ],\n });\n return () => contribution.dispose();\n}\n\nexport async function openLogMetricsOverlay(\n ctx: ExtensionContext,\n getView: () => LogMetricsView,\n query?: MetricsQuery,\n): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new LogMetricsOverlayComponent(tui, theme, getView, done, query),\n {\n overlay: true,\n overlayOptions: {\n anchor: 'top-left',\n width: '100%',\n maxHeight: '100%',\n margin: 0,\n },\n },\n );\n}\n\nexport function installDoomLogRuntime(\n cordis: Context,\n pi: ExtensionAPI,\n options: PiTelemetryExtensionOptions = {},\n splitReadiness = false,\n): PiTelemetryRuntimeHandle {\n const env = options.env ?? process.env;\n const metrics = new LogMetricsAggregator();\n // Built lazily so the history transports resolve their sink instance from the\n // same cwd and package identity the telemetry writer registers under; at\n // install time there is no ExtensionContext to read `cwd` from yet.\n let metricsSource = options.metricsSource;\n const resolveMetricsSource = (ctx: ExtensionContext): MetricsSource =>\n (metricsSource ??= createMetricsSource({\n env,\n cwd: ctx.cwd,\n packageName: PACKAGE_NAME,\n serviceName: options.serviceName ?? SERVICE_NAME,\n }));\n let active = true;\n let sink: SinkStatus | undefined;\n let lastDiagnostic: string | undefined;\n\n cordis.effect(\n () => () => {\n active = false;\n sink = undefined;\n lastDiagnostic = undefined;\n },\n `${PACKAGE_NAME}/runtime`,\n );\n\n const telemetryRuntime = installPiTelemetryRuntime(\n cordis,\n pi,\n {\n ...options,\n metrics,\n // Always supply a sink so doom-telemetry never falls back to\n // process.emitWarning, which writes raw stderr over the TUI frame.\n // Diagnostics surface in the Log Metrics overlay instead.\n onDiagnostic: (message) => {\n if (!active) return;\n lastDiagnostic = message;\n if (options.onDiagnostic) options.onDiagnostic(message);\n else if (env.AGENT_OTEL_DIAGNOSTICS === DIAGNOSTICS_STDERR) process.emitWarning(message);\n },\n onSinkStatus: (status) => {\n if (!active) return;\n sink = status;\n options.onSinkStatus?.(status);\n },\n },\n splitReadiness,\n );\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n return registerLogMetricsLeaderBinding(requireDoomUiHub(uiContext), { source: options.leaderSource });\n });\n pi.registerCommand(LOG_METRICS_COMMAND, {\n description: LOG_METRICS_DESCRIPTION,\n handler: async (_args, ctx) => {\n if (!active) return;\n await telemetryRuntime.waitForSession(ctx);\n if (!active) return;\n const source = resolveMetricsSource(ctx);\n await openLogMetricsOverlay(\n ctx,\n () => ({\n disabled: isEnabled(env.AGENT_TELEMETRY_DISABLED) || isEnabled(env.OTEL_SDK_DISABLED),\n snapshot: metrics.snapshot(),\n sink,\n transport: source.lastTransport(),\n instance: source.instance?.(),\n lastDiagnostic,\n }),\n source.query,\n );\n },\n });\n return telemetryRuntime;\n}\n\ninterface LogPluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction logPlugin(cordis: Context, { pi }: LogPluginConfig): void {\n const runtime = installDoomLogRuntime(cordis, pi, {}, true);\n let shutdown: Promise<void> | undefined;\n pi.on('session_shutdown', (event, ctx) => {\n shutdown ??= runtime.finishSession(event.reason, ctx);\n return shutdown;\n });\n}\n\n/** The package's single standard Pi factory. */\nexport async function doomLogExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_NAME);\n const fiber = connection.root.plugin(logPlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n"],"mappings":"qWA0BA,MACM,EAAe,wBAIf,EAAsB,cAOtB,EAAuB,IAAI,IAAI,CAAC,QAAS,SAAS,CAAC,EA6BzD,SAAS,EAAU,EAAoC,CACrD,OAAO,IAAU,KAAO,GAAO,YAAY,IAAM,QAAU,GAAO,YAAY,IAAM,KACtF,CAEA,SAAS,EAAkB,EAA4C,CACrE,IAAM,EAAkC,CACtC,UAAW,EAAI,KACf,gBAAiB,EAAI,eAAe,aAAa,CACnD,EAMA,OALI,EAAI,gBAAe,EAAW,qBAAuB,EAAI,eACzD,EAAI,QACN,EAAW,wBAA0B,EAAI,MAAM,SAC/C,EAAW,wBAA0B,EAAI,MAAM,IAE1C,CACT,CAEA,SAAS,EAAgB,EAAmE,CAC1F,GAAI,EAAQ,OAAS,YAAa,OAClC,IAAM,EAAkC,CACtC,wBAAyB,EAAQ,eAAiB,EAAQ,MAC1D,iCAAkC,EAAQ,WAC1C,4BAA6B,EAAQ,MAAM,MAC3C,6BAA8B,EAAQ,MAAM,OAC5C,iCAAkC,EAAQ,MAAM,UAChD,kCAAmC,EAAQ,MAAM,WACjD,4BAA6B,EAAQ,MAAM,YAC3C,oBAAqB,EAAQ,MAAM,KAAK,KAC1C,EAEA,OADI,EAAQ,MAAM,YAAc,IAAA,KAAW,EAAW,iCAAmC,EAAQ,MAAM,WAChG,CACT,CAEA,SAAS,EAAkB,EAAuD,CAChF,GAAI,EAAQ,OAAS,YAAa,MAAO,CAAE,aAAc,aAAc,QAAS,OAAQ,EACxF,IAAM,EAAU,EAAQ,aAAe,UACvC,MAAO,CACL,aAAc,gBACd,aAAc,EAAQ,WACtB,QAAS,EAAU,UAAY,OACjC,CACF,CAEA,SAAS,EAAoB,EAAyD,CACpF,MAAO,CACL,QAAS,EAAO,YAChB,QAAS,EAAO,QAChB,SAAU,EAAO,UAAY,OAC7B,eAAgB,EAAO,eACvB,OAAQ,EAAO,OACf,UAAW,GACX,aAAc,EAAO,YACvB,CACF,CAEA,SAAgB,EACd,EACA,EACA,EAAuC,CAAC,EACxC,EAAiB,GACS,CAC1B,IAAM,EAAM,EAAQ,KAAO,QAAQ,IAC7B,EAAU,EAAQ,QAClB,EAAgB,IAAI,IACtB,EAAS,GACT,EAAoB,EACpB,EACA,EACA,EAOA,EAAkB,QAAQ,QAAQ,EAEhC,EAAW,GAAyC,CAGxD,EAFkB,EAAgB,KAAK,CAEb,CAAC,CAAC,UAAY,IAAA,EAAS,CACnD,EAEA,EAAO,WACC,SAAY,CAChB,EAAS,GACT,GAAqB,EACrB,EAAmB,IAAA,GACnB,EAAc,MAAM,EACpB,EAAiB,IAAA,GACjB,IAAM,EAAiB,EACvB,EAAY,IAAA,GACZ,MAAM,GAAgB,SAAS,CACjC,EACA,GAAG,EAAa,WAClB,EAEA,IAAM,EAAO,MAAO,EAAoB,EAAc,IAAmD,CACnG,CAAC,GAAU,CAAC,IACZ,IAAU,QAAS,MAAM,EAAU,YAAY,EAAM,CAAU,EAC1D,IAAU,OAAQ,MAAM,EAAU,cAAc,EAAM,IAAA,GAAW,CAAU,EAC3E,IAAU,QAAS,MAAM,EAAU,YAAY,EAAM,IAAA,GAAW,CAAU,EAC9E,MAAM,EAAU,YAAY,EAAM,CAAU,EACnD,EAEM,EAAgB,GAAyC,CAC7D,GAAI,CAAC,EAAQ,MAAU,MAAM,oCAAoC,EAmBjE,MAlBA,MAAA,EAAcA,EAAAA,oBAAAA,CAAoB,CAChC,YAAa,EAAQ,aAAe,KACpC,YAAa,EACb,IAAK,EAAI,IACT,MACA,kBAAmB,EAAQ,kBAC3B,iBAAkB,EAAQ,iBAC1B,KAAM,EAAQ,aACd,WAAY,GACZ,aAAc,EAAI,oBAAsB,IAAA,IAAa,EAAU,EAAI,iBAAiB,EACpF,SAAW,GAAW,CAChB,GAAQ,GAAS,OAAO,EAAO,MAAO,EAAO,UAAU,CAC7D,EACA,SAAW,GAAW,CAChB,GAAQ,EAAQ,eAAe,EAAoB,CAAM,CAAC,CAChE,CACF,CAAC,EACG,GAAQ,EAAQ,eAAe,EAAoB,EAAU,OAAO,CAAC,CAAC,EACnE,CACT,EAEM,EAAiB,KAAO,IAAyC,CACrE,IAAM,EAAU,EACX,KACL,IAAI,EAAQ,iBAAmB,EAAI,eACjC,MAAU,MAAM,8CAA8C,EAGhE,GADA,MAAM,EAAQ,UACV,CAAC,GAAU,IAAY,EACzB,MAAU,MAAM,wDAAwD,CAJV,CAMlE,EAEM,GAAqB,EAAuB,IAAyD,CACzG,IAAM,EAAW,EACX,EAAM,SAA2B,CACrC,GAAI,EAKE,IAAA,CAAC,MAJe,EAAS,UAAU,SAC/B,OACA,EACR,GACc,CAAC,GAAU,IAAa,GAAoB,EAAS,iBAAmB,EAAI,eACxF,MAAA,MAEG,GAAI,CAAC,EACV,OAEF,MAAM,EAAU,CAClB,EACA,GAAI,CAAC,EAAgB,OAAO,EAAI,EAChC,EAAQ,CAAG,CAEb,EAuLA,OArLA,EAAG,GAAG,iBAAkB,EAAO,IAAQ,CACrC,GAAI,CAAC,EAAQ,OACb,IAAM,EAAgB,EAAE,EACxB,EAAc,MAAM,EACpB,EAAiB,IAAA,GACjB,IAAM,EAAa,KAAO,IAAwC,CAChE,GAAQ,eAAe,EACvB,EAAa,CAAG,EAChB,MAAM,EAAK,OAAQ,qBAAsB,CACvC,GAAG,EAAkB,CAAG,EACxB,oBAAqB,EAAM,OAC3B,sBAAuB,EAAM,sBAAwB,IAAA,EACvD,CAAC,EACD,GAAQ,eAAe,CACzB,EACM,EAAc,GAAA,EAAiBC,EAAAA,6BAAAA,CAA6B,CAAM,EAAI,IAAA,GAC5E,GAAI,CAAC,EAAa,OAAO,EAAW,EAEpC,IAAM,EAAW,EACX,GAAa,SAA2B,CACxC,GAAU,cAAgB,GAAa,MAAM,EAAS,UAAU,UAAY,IAAA,EAAS,EACrF,GAAC,GAAU,IAAkB,IASjC,MARe,EAAY,MACzB,EACA,GAAG,EAAI,eAAe,aAAa,EAAE,GAAG,IACxC,KAAO,KACL,MAAM,EAAW,CAAM,EAChB,CAAE,MAAO,IAAA,EAAU,EAGnB,CAAC,CAAC,KAAK,CACpB,EAAA,CAAG,EAEH,EAAe,UAAY,IAAA,EAAS,EACpC,EAAmB,CAAE,eAAgB,EAAI,eAAgB,cAAa,WAAU,CAElF,CAAC,EAED,EAAG,GAAG,sBAAuB,EAAO,IAAQ,CACrC,KACL,OAAO,EAAkB,EAAK,SAAY,CACxC,EAAa,CAAG,EAChB,MAAM,EAAK,OAAQ,iBAAkB,CACnC,GAAG,EAAkB,CAAG,EACxB,yBAA0B,EAAM,OAAO,OACvC,8BAA+B,EAAM,QAAQ,QAAU,CACzD,CAAC,CACH,CAAC,CACH,CAAC,EAED,EAAG,GAAG,eAAgB,EAAQ,IAAQ,CAC/B,KACL,OAAO,EAAkB,EAAK,SAAY,CACxC,EAAiB,KAAK,IAAI,EAC1B,EAAa,CAAG,EAChB,MAAM,EAAK,OAAQ,mBAAoB,EAAkB,CAAG,CAAC,CAC/D,CAAC,CACH,CAAC,EAED,EAAG,GAAG,cAAe,EAAO,IAAQ,CAC7B,KACL,OAAO,EAAkB,EAAK,SAAY,CACxC,EAAa,CAAG,EAChB,MAAM,EAAK,QAAS,kBAAmB,CACrC,GAAG,EAAkB,CAAG,EACxB,gBAAiB,EAAM,SACzB,CAAC,CACH,CAAC,CACH,CAAC,EAED,EAAG,GAAG,YAAa,EAAO,IAAQ,CAC3B,KACL,OAAO,EAAkB,EAAK,SAAY,CACxC,EAAa,CAAG,EAChB,IAAM,EAAQ,EAAgB,EAAM,OAAO,EAC3C,SAAM,EAAK,OAAQ,mBAAoB,CACrC,GAAG,EAAkB,CAAG,EACxB,gBAAiB,EAAM,UACvB,uBAAwB,EAAM,YAAY,OAC1C,GAAG,CACL,CAAC,EACG,EAAM,QAAQ,OAAS,aAAe,EAAqB,IAAI,EAAM,QAAQ,UAAU,GACzF,MAAM,EAAK,EAAM,QAAQ,aAAe,UAAY,OAAS,QAAS,iBAAkB,CACtF,GAAG,EAAkB,CAAG,EACxB,gBAAiB,EAAM,UACvB,GAAG,EAAkB,EAAM,OAAO,EAClC,GAAG,CACL,CAAC,EAEE,EACL,IAAK,IAAM,KAAU,EAAM,YACzB,MAAM,EAAK,QAAS,uBAAwB,CAC1C,GAAG,EAAkB,CAAG,EACxB,GAAG,EACH,YAAa,EAAO,SACpB,kBAAmB,cACrB,CAAC,CAEL,CAAC,CACH,CAAC,EAED,EAAG,GAAG,wBAAyB,EAAO,IAAQ,CACvC,KACL,OAAO,EAAkB,EAAK,SAAY,CACxC,EAAc,IAAI,EAAM,WAAY,KAAK,IAAI,CAAC,EAC9C,EAAa,CAAG,EAChB,MAAM,EAAK,QAAS,eAAgB,CAClC,GAAG,EAAkB,CAAG,EACxB,YAAa,EAAM,SACnB,eAAgB,EAAM,UACxB,CAAC,CACH,CAAC,CACH,CAAC,EAED,EAAG,GAAG,sBAAuB,EAAO,IAAQ,CACrC,KACL,OAAO,EAAkB,EAAK,SAAY,CACxC,IAAM,EAAY,EAAc,IAAI,EAAM,UAAU,EACpD,EAAc,OAAO,EAAM,UAAU,EACrC,EAAa,CAAG,EAChB,MAAM,EAAK,OAAQ,iBAAkB,CACnC,GAAG,EAAkB,CAAG,EACxB,QAAS,CAAC,EAAM,QAChB,YAAa,EAAM,SACnB,eAAgB,EAAM,WACtB,oBAAqB,EAAM,QAC3B,GAAI,IAAc,IAAA,GAAY,CAAC,EAAI,CAAE,mBAAoB,KAAK,IAAI,EAAI,CAAU,CAClF,CAAC,CACH,CAAC,CACH,CAAC,EAED,EAAG,GAAG,2BAA4B,EAAO,IAAQ,CAC1C,KACL,OAAO,EAAkB,EAAK,SAAY,CACxC,EAAa,CAAG,EAChB,IAAM,EAAa,CACjB,GAAG,EAAkB,CAAG,EACxB,4BAA6B,EAAM,MACrC,EACI,EAAM,QAAU,IAAkB,MAAM,EAAK,QAAS,eAAgB,CAAU,EAC/E,MAAM,EAAK,QAAS,kBAAmB,CAAU,CACxD,CAAC,CACH,CAAC,EAED,EAAG,GAAG,gBAAiB,EAAO,IAAQ,CAC/B,KACL,OAAO,EAAkB,EAAK,SAAY,CACxC,EAAa,CAAG,EAChB,MAAM,EAAK,OAAQ,oBAAqB,CACtC,GAAG,EAAkB,CAAG,EACxB,kBAAmB,EAAM,OACzB,uBAAwB,EAAM,MAAM,SACpC,uBAAwB,EAAM,MAAM,EACtC,CAAC,CACH,CAAC,CACH,CAAC,EAED,EAAG,GAAG,aAAc,EAAO,IAAQ,CACjC,GAAI,CAAC,EAAQ,OACb,IAAM,EAAa,EACnB,OAAO,EAAkB,EAAK,SAAY,CACxC,EAAa,CAAG,EAChB,MAAM,EAAK,OAAQ,oBAAqB,CACtC,GAAG,EAAkB,CAAG,EACxB,mBAAoB,EAAM,SAAS,OACnC,GAAI,IAAmB,IAAA,GAAY,CAAC,EAAI,CAAE,uBAAwB,KAAK,IAAI,EAAI,CAAe,CAChG,CAAC,EACG,GAAC,GAAU,IAAe,KAC9B,EAAiB,IAAA,GACjB,MAAM,GAAW,MAAM,EACzB,CAAC,CACH,CAAC,EAED,EAAG,GAAG,iBAAkB,EAAQ,IAAQ,CACjC,KACL,OAAO,EAAkB,EAAK,SAAY,CACxC,EAAa,CAAG,EAChB,MAAM,EAAK,QAAS,mBAAoB,EAAkB,CAAG,CAAC,CAChE,CAAC,CACH,CAAC,EAEM,CACL,iBACA,MAAM,cAAc,EAAQ,EAAK,CAC/B,GAAI,CAAC,EAAQ,OACb,MAAM,EACN,IAAM,EAAU,EACZ,GAAS,MAAM,EAAQ,UAAU,UAAY,IAAA,EAAS,EACrD,IACD,GAAW,IAAY,GACtB,IACL,EAAa,CAAG,EAChB,MAAM,EAAK,OAAQ,sBAAuB,CACxC,GAAG,EAAkB,CAAG,EACxB,oBAAqB,CACvB,CAAC,GACH,CACF,CACF,CAEA,SAAgB,EAAgC,EAAuB,EAA+B,CAAC,EAAe,CACpH,IAAM,EAAe,EAAI,eAAe,CACtC,OAAQ,EAAQ,QAAU,wBAC1B,SAAU,CACR,CACE,GAAI,cACJ,KAAM,CACJ,CAAE,IAAK,IAAK,MAAO,OAAQ,OAAQ,wBAAmB,MAAO,EAAiB,EAC9E,CAAE,IAAK,IAAK,MAAO,OAAQ,OAAQ,WAAY,CACjD,EACA,QAAS,CAAE,KAAM,CAAoB,CACvC,CACF,CACF,CAAC,EACD,UAAa,EAAa,QAAQ,CACpC,CAEA,eAAsB,EACpB,EACA,EACA,EACe,CACf,MAAM,EAAI,GAAG,QACV,EAAK,EAAO,EAAc,IAAS,IAAIC,EAAAA,2BAA2B,EAAK,EAAO,EAAS,EAAM,CAAK,EACnG,CACE,QAAS,GACT,eAAgB,CACd,OAAQ,WACR,MAAO,OACP,UAAW,OACX,OAAQ,CACV,CACF,CACF,CACF,CAEA,SAAgB,EACd,EACA,EACA,EAAuC,CAAC,EACxC,EAAiB,GACS,CAC1B,IAAM,EAAM,EAAQ,KAAO,QAAQ,IAC7B,EAAU,IAAIC,EAAAA,qBAIhB,EAAgB,EAAQ,cACtB,EAAwB,GAC3B,IAAkBC,EAAAA,oBAAoB,CACrC,MACA,IAAK,EAAI,IACT,YAAa,EACb,YAAa,EAAQ,aAAe,IACtC,CAAC,EACC,EAAS,GACT,EACA,EAEJ,EAAO,eACO,CACV,EAAS,GACT,EAAO,IAAA,GACP,EAAiB,IAAA,EACnB,EACA,GAAG,EAAa,SAClB,EAEA,IAAM,EAAmB,EACvB,EACA,EACA,CACE,GAAG,EACH,UAIA,aAAe,GAAY,CACpB,IACL,EAAiB,EACb,EAAQ,aAAc,EAAQ,aAAa,CAAO,EAC7C,EAAI,yBAA2B,UAAoB,QAAQ,YAAY,CAAO,EACzF,EACA,aAAe,GAAW,CACnB,IACL,EAAO,EACP,EAAQ,eAAe,CAAM,EAC/B,CACF,EACA,CACF,EA0BA,OAxBA,EAAO,OAAO,CAACC,EAAAA,mBAAmB,EAAI,GAC7B,GAAA,EAAgCC,EAAAA,iBAAAA,CAAiB,CAAS,EAAG,CAAE,OAAQ,EAAQ,YAAa,CAAC,CACrG,EACD,EAAG,gBAAgB,EAAqB,CACtC,YAAa,iCACb,QAAS,MAAO,EAAO,IAAQ,CAG7B,GAFI,CAAC,IACL,MAAM,EAAiB,eAAe,CAAG,EACrC,CAAC,GAAQ,OACb,IAAM,EAAS,EAAqB,CAAG,EACvC,MAAM,EACJ,OACO,CACL,SAAU,EAAU,EAAI,wBAAwB,GAAK,EAAU,EAAI,iBAAiB,EACpF,SAAU,EAAQ,SAAS,EAC3B,OACA,UAAW,EAAO,cAAc,EAChC,SAAU,EAAO,WAAW,EAC5B,gBACF,GACA,EAAO,KACT,CACF,CACF,CAAC,EACM,CACT,CAMA,SAAS,EAAU,EAAiB,CAAE,MAA6B,CACjE,IAAM,EAAU,EAAsB,EAAQ,EAAI,CAAC,EAAG,EAAI,EACtD,EACJ,EAAG,GAAG,oBAAqB,EAAO,KAChC,IAAa,EAAQ,cAAc,EAAM,OAAQ,CAAG,EAC7C,EACR,CACH,CAGA,eAAsB,EAAiB,EAAiC,CACtE,IAAM,EAAa,MAAA,EAAMC,EAAAA,sBAAAA,CAAsB,EAAI,CAAY,EACzD,EAAQ,EAAW,KAAK,OAAO,EAAW,CAAE,IAAG,CAAC,EACtD,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CACd,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACA,MAAM,CACR,CACA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;;;KAwCK,mBAAmB,YAAY;UAInB;EACf;;EAEA;;EAEA;EACA,MAAM,OAAO;EACb,mBAAmB;;EAEnB,UAAU;;EAEV,gBAAgB,QAAQ;;EAExB,gBAAgB;;EAEhB,gBAAgB;;UAGD;EACf,eAAe,KAAK,mBAAmB;EACvC,cAAc,gBAAgB,KAAK,mBAAmB;;iBA4WxC,gCAAgC,KAAK,kBAAkB;EAAW;;iBAiB5D,sBACpB,KAAK,kBACL,eAAe,gBACf,QAAQ,eACP;iBAea,sBACd,QAAQ,SACR,IAAI,cACJ,UAAS,6BACT,2BACC;;
|
|
1
|
+
{"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;;;KAwCK,mBAAmB,YAAY;UAInB;EACf;;EAEA;;EAEA;EACA,MAAM,OAAO;EACb,mBAAmB;;EAEnB,UAAU;;EAEV,gBAAgB,QAAQ;;EAExB,gBAAgB;;EAEhB,gBAAgB;;UAGD;EACf,eAAe,KAAK,mBAAmB;EACvC,cAAc,gBAAgB,KAAK,mBAAmB;;iBA4WxC,gCAAgC,KAAK,kBAAkB;EAAW;;iBAiB5D,sBACpB,KAAK,kBACL,eAAe,gBACf,QAAQ,eACP;iBAea,sBACd,QAAQ,SACR,IAAI,cACJ,UAAS,6BACT,2BACC;;iBA4FmB,iBAAiB,IAAI,eAAe"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;;;KAwCK,mBAAmB,YAAY;UAInB;EACf;;EAEA;;EAEA;EACA,MAAM,OAAO;EACb,mBAAmB;;EAEnB,UAAU;;EAEV,gBAAgB,QAAQ;;EAExB,gBAAgB;;EAEhB,gBAAgB;;UAGD;EACf,eAAe,KAAK,mBAAmB;EACvC,cAAc,gBAAgB,KAAK,mBAAmB;;iBA4WxC,gCAAgC,KAAK,kBAAkB;EAAW;;iBAiB5D,sBACpB,KAAK,kBACL,eAAe,gBACf,QAAQ,eACP;iBAea,sBACd,QAAQ,SACR,IAAI,cACJ,UAAS,6BACT,2BACC;;
|
|
1
|
+
{"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;;;KAwCK,mBAAmB,YAAY;UAInB;EACf;;EAEA;;EAEA;EACA,MAAM,OAAO;EACb,mBAAmB;;EAEnB,UAAU;;EAEV,gBAAgB,QAAQ;;EAExB,gBAAgB;;EAEhB,gBAAgB;;UAGD;EACf,eAAe,KAAK,mBAAmB;EACvC,cAAc,gBAAgB,KAAK,mBAAmB;;iBA4WxC,gCAAgC,KAAK,kBAAkB;EAAW;;iBAiB5D,sBACpB,KAAK,kBACL,eAAe,gBACf,QAAQ,eACP;iBAea,sBACd,QAAQ,SACR,IAAI,cACJ,UAAS,6BACT,2BACC;;iBA4FmB,iBAAiB,IAAI,eAAe"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{LogMetricsAggregator as e}from"../../services/metrics.mjs";import{LogMetricsOverlayComponent as t}from"../../tui/logMetricsOverlay.mjs";import{createMetricsSource as n}from"../node/metricsSource.mjs";import{connectDoomCordisHost as r}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{readDoomReadinessCoordinator as i}from"@agimon-ai/doompi-extension-contracts/readiness";import{DOOM_UI_HUB_SERVICE as a,requireDoomUiHub as o}from"@agimon-ai/doompi-extension-contracts/ui-hub";import{createDoomTelemetry as s}from"@agimon-ai/doompi-telemetry";const c=`@agimon-ai/doompi-log`,l=`log-metrics`,u=new Set([`error`,`aborted`]);function d(e){return e===`1`||e?.toLowerCase()===`true`||e?.toLowerCase()===`yes`}function f(e){let t={"pi.mode":e.mode,"pi.session.id":e.sessionManager.getSessionId()};return e.thinkingLevel&&(t[`pi.thinking_level`]=e.thinkingLevel),e.model&&(t[`gen_ai.provider.name`]=e.model.provider,t[`gen_ai.request.model`]=e.model.id),t}function p(e){if(e.role!==`assistant`)return;let t={"gen_ai.response.model":e.responseModel??e.model,"gen_ai.response.finish_reasons":e.stopReason,"gen_ai.usage.input_tokens":e.usage.input,"gen_ai.usage.output_tokens":e.usage.output,"gen_ai.usage.cache_read_tokens":e.usage.cacheRead,"gen_ai.usage.cache_write_tokens":e.usage.cacheWrite,"gen_ai.usage.total_tokens":e.usage.totalTokens,"gen_ai.usage.cost":e.usage.cost.total};return e.usage.reasoning!==void 0&&(t[`gen_ai.usage.reasoning_tokens`]=e.usage.reasoning),t}function m(e){if(e.role!==`assistant`)return{"error.type":`AgentError`,outcome:`error`};let t=e.stopReason===`aborted`;return{"error.type":`ProviderError`,"error.code":e.stopReason,outcome:t?`aborted`:`error`}}function h(e){return{service:e.serviceName,backend:e.backend,endpoint:e.endpoint??`none`,endpointSource:e.endpointSource,traces:e.traces,redaction:!0,fileFallback:e.fileFallback}}function g(e,t,n={},r=!1){let a=n.env??process.env,o=n.metrics,l=new Map,g=!0,_=0,v,y,b,x=Promise.resolve(),S=e=>{x=x.then(e).catch(()=>void 0)};e.effect(()=>async()=>{g=!1,_+=1,b=void 0,l.clear(),v=void 0;let e=y;y=void 0,await e?.shutdown()},`${c}/telemetry`);let C=async(e,t,n)=>{!g||!y||(e===`debug`?await y.recordDebug(t,n):e===`warn`?await y.recordWarning(t,void 0,n):e===`error`?await y.recordError(t,void 0,n):await y.recordEvent(t,n))},w=e=>{if(!g)throw Error(`Log telemetry runtime is disposed.`);return y??=s({serviceName:n.serviceName??`pi`,packageName:c,cwd:e.cwd,env:a,allowFileFallback:n.allowFileFallback,telemetryFactory:n.telemetryFactory,warn:n.onDiagnostic,enableLogs:!0,enableTraces:a.AGENT_OTEL_TRACES===void 0||d(a.AGENT_OTEL_TRACES),onRecord:e=>{g&&o?.record(e.event,e.attributes)},onStatus:e=>{g&&n.onSinkStatus?.(h(e))}}),g&&n.onSinkStatus?.(h(y.status())),y},T=async e=>{let t=b;if(t){if(t.sessionManager!==e.sessionManager)throw Error(`Log readiness belongs to a stale Pi session.`);if(await t.operation,!g||t!==b)throw Error(`Log readiness belongs to a stale extension generation.`)}},E=(e,t)=>{let n=b,i=async()=>{if(n){if(!await n.operation.then(()=>!0,()=>!1)||!g||n!==b||n.sessionManager!==e.sessionManager)return}else if(!g)return;await t()};if(!r)return i();S(i)};return t.on(`session_start`,(t,n)=>{if(!g)return;let a=++_;l.clear(),v=void 0;let o=async e=>{e?.throwIfAborted(),w(n),await C(`info`,`pi.session.started`,{...f(n),"pi.session.reason":t.reason,"pi.session.previous":t.previousSessionFile!==void 0}),e?.throwIfAborted()},s=r?i(e):void 0;if(!s)return o();let u=b,d=(async()=>{u?.coordinator===s&&await u.operation.catch(()=>void 0),!(!g||a!==_)&&await s.start(c,`${n.sessionManager.getSessionId()}:${a}`,async e=>(await o(e),{value:void 0})).wait()})();d.catch(()=>void 0),b={sessionManager:n.sessionManager,coordinator:s,operation:d}}),t.on(`before_agent_start`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`info`,`pi.user_prompt`,{...f(t),"pi.user_message.length":e.prompt.length,"pi.user_message.image_count":e.images?.length??0})})}),t.on(`agent_start`,(e,t)=>{if(g)return E(t,async()=>{v=Date.now(),w(t),await C(`info`,`pi.agent.started`,f(t))})}),t.on(`turn_start`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`debug`,`pi.turn.started`,{...f(t),"pi.turn.index":e.turnIndex})})}),t.on(`turn_end`,(e,t)=>{if(g)return E(t,async()=>{w(t);let n=p(e.message);if(await C(`info`,`pi.turn.finished`,{...f(t),"pi.turn.index":e.turnIndex,"pi.tool_result.count":e.toolResults.length,...n}),e.message.role===`assistant`&&u.has(e.message.stopReason)&&await C(e.message.stopReason===`aborted`?`warn`:`error`,`pi.turn.failed`,{...f(t),"pi.turn.index":e.turnIndex,...m(e.message),...n}),n)for(let r of e.toolResults)await C(`debug`,`pi.tool_token_sample`,{...f(t),...n,"tool.name":r.toolName,token_attribution:`toolCallTurn`})})}),t.on(`tool_execution_start`,(e,t)=>{if(g)return E(t,async()=>{l.set(e.toolCallId,Date.now()),w(t),await C(`debug`,`pi.tool_call`,{...f(t),"tool.name":e.toolName,"tool.call.id":e.toolCallId})})}),t.on(`tool_execution_end`,(e,t)=>{if(g)return E(t,async()=>{let n=l.get(e.toolCallId);l.delete(e.toolCallId),w(t),await C(`info`,`pi.tool_result`,{...f(t),success:!e.isError,"tool.name":e.toolName,"tool.call.id":e.toolCallId,"tool.result.error":e.isError,...n===void 0?{}:{"tool.duration_ms":Date.now()-n}})})}),t.on(`after_provider_response`,(e,t)=>{if(g)return E(t,async()=>{w(t);let n={...f(t),"http.response.status_code":e.status};e.status>=400?await C(`error`,`pi.api_error`,n):await C(`debug`,`pi.api_response`,n)})}),t.on(`model_select`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`info`,`pi.model.selected`,{...f(t),"pi.model.source":e.source,"gen_ai.provider.name":e.model.provider,"gen_ai.request.model":e.model.id})})}),t.on(`agent_end`,(e,t)=>{if(!g)return;let n=_;return E(t,async()=>{w(t),await C(`info`,`pi.agent.finished`,{...f(t),"pi.message.count":e.messages.length,...v===void 0?{}:{"pi.agent.duration_ms":Date.now()-v}}),!(!g||n!==_)&&(v=void 0,await y?.flush())})}),t.on(`agent_settled`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`debug`,`pi.agent.settled`,f(t))})}),{waitForSession:T,async finishSession(e,t){if(!g)return;await x;let n=b;n&&await n.operation.catch(()=>void 0),g&&(n&&n!==b||y&&(w(t),await C(`info`,`pi.session.finished`,{...f(t),"pi.session.reason":e})))}}}function _(e,t={}){let n=e.registerLeader({source:t.source??`@agimon-ai/doompi-log`,bindings:[{id:`log.metrics`,path:[{key:`h`,label:`help`,detail:`package docs and logs`,order:70},{key:`l`,label:`logs`,detail:`telemetry`}],command:{name:l}}]});return()=>n.dispose()}async function v(e,n,r){await e.ui.custom((e,i,a,o)=>new t(e,i,n,o,r),{overlay:!0,overlayOptions:{anchor:`top-left`,width:`100%`,maxHeight:`100%`,margin:0}})}function y(t,r,i={},s=!1){let u=i.env??process.env,f=new e,p=i.metricsSource
|
|
1
|
+
import{LogMetricsAggregator as e}from"../../services/metrics.mjs";import{LogMetricsOverlayComponent as t}from"../../tui/logMetricsOverlay.mjs";import{createMetricsSource as n}from"../node/metricsSource.mjs";import{connectDoomCordisHost as r}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{readDoomReadinessCoordinator as i}from"@agimon-ai/doompi-extension-contracts/readiness";import{DOOM_UI_HUB_SERVICE as a,requireDoomUiHub as o}from"@agimon-ai/doompi-extension-contracts/ui-hub";import{createDoomTelemetry as s}from"@agimon-ai/doompi-telemetry";const c=`@agimon-ai/doompi-log`,l=`log-metrics`,u=new Set([`error`,`aborted`]);function d(e){return e===`1`||e?.toLowerCase()===`true`||e?.toLowerCase()===`yes`}function f(e){let t={"pi.mode":e.mode,"pi.session.id":e.sessionManager.getSessionId()};return e.thinkingLevel&&(t[`pi.thinking_level`]=e.thinkingLevel),e.model&&(t[`gen_ai.provider.name`]=e.model.provider,t[`gen_ai.request.model`]=e.model.id),t}function p(e){if(e.role!==`assistant`)return;let t={"gen_ai.response.model":e.responseModel??e.model,"gen_ai.response.finish_reasons":e.stopReason,"gen_ai.usage.input_tokens":e.usage.input,"gen_ai.usage.output_tokens":e.usage.output,"gen_ai.usage.cache_read_tokens":e.usage.cacheRead,"gen_ai.usage.cache_write_tokens":e.usage.cacheWrite,"gen_ai.usage.total_tokens":e.usage.totalTokens,"gen_ai.usage.cost":e.usage.cost.total};return e.usage.reasoning!==void 0&&(t[`gen_ai.usage.reasoning_tokens`]=e.usage.reasoning),t}function m(e){if(e.role!==`assistant`)return{"error.type":`AgentError`,outcome:`error`};let t=e.stopReason===`aborted`;return{"error.type":`ProviderError`,"error.code":e.stopReason,outcome:t?`aborted`:`error`}}function h(e){return{service:e.serviceName,backend:e.backend,endpoint:e.endpoint??`none`,endpointSource:e.endpointSource,traces:e.traces,redaction:!0,fileFallback:e.fileFallback}}function g(e,t,n={},r=!1){let a=n.env??process.env,o=n.metrics,l=new Map,g=!0,_=0,v,y,b,x=Promise.resolve(),S=e=>{x=x.then(e).catch(()=>void 0)};e.effect(()=>async()=>{g=!1,_+=1,b=void 0,l.clear(),v=void 0;let e=y;y=void 0,await e?.shutdown()},`${c}/telemetry`);let C=async(e,t,n)=>{!g||!y||(e===`debug`?await y.recordDebug(t,n):e===`warn`?await y.recordWarning(t,void 0,n):e===`error`?await y.recordError(t,void 0,n):await y.recordEvent(t,n))},w=e=>{if(!g)throw Error(`Log telemetry runtime is disposed.`);return y??=s({serviceName:n.serviceName??`pi`,packageName:c,cwd:e.cwd,env:a,allowFileFallback:n.allowFileFallback,telemetryFactory:n.telemetryFactory,warn:n.onDiagnostic,enableLogs:!0,enableTraces:a.AGENT_OTEL_TRACES===void 0||d(a.AGENT_OTEL_TRACES),onRecord:e=>{g&&o?.record(e.event,e.attributes)},onStatus:e=>{g&&n.onSinkStatus?.(h(e))}}),g&&n.onSinkStatus?.(h(y.status())),y},T=async e=>{let t=b;if(t){if(t.sessionManager!==e.sessionManager)throw Error(`Log readiness belongs to a stale Pi session.`);if(await t.operation,!g||t!==b)throw Error(`Log readiness belongs to a stale extension generation.`)}},E=(e,t)=>{let n=b,i=async()=>{if(n){if(!await n.operation.then(()=>!0,()=>!1)||!g||n!==b||n.sessionManager!==e.sessionManager)return}else if(!g)return;await t()};if(!r)return i();S(i)};return t.on(`session_start`,(t,n)=>{if(!g)return;let a=++_;l.clear(),v=void 0;let o=async e=>{e?.throwIfAborted(),w(n),await C(`info`,`pi.session.started`,{...f(n),"pi.session.reason":t.reason,"pi.session.previous":t.previousSessionFile!==void 0}),e?.throwIfAborted()},s=r?i(e):void 0;if(!s)return o();let u=b,d=(async()=>{u?.coordinator===s&&await u.operation.catch(()=>void 0),!(!g||a!==_)&&await s.start(c,`${n.sessionManager.getSessionId()}:${a}`,async e=>(await o(e),{value:void 0})).wait()})();d.catch(()=>void 0),b={sessionManager:n.sessionManager,coordinator:s,operation:d}}),t.on(`before_agent_start`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`info`,`pi.user_prompt`,{...f(t),"pi.user_message.length":e.prompt.length,"pi.user_message.image_count":e.images?.length??0})})}),t.on(`agent_start`,(e,t)=>{if(g)return E(t,async()=>{v=Date.now(),w(t),await C(`info`,`pi.agent.started`,f(t))})}),t.on(`turn_start`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`debug`,`pi.turn.started`,{...f(t),"pi.turn.index":e.turnIndex})})}),t.on(`turn_end`,(e,t)=>{if(g)return E(t,async()=>{w(t);let n=p(e.message);if(await C(`info`,`pi.turn.finished`,{...f(t),"pi.turn.index":e.turnIndex,"pi.tool_result.count":e.toolResults.length,...n}),e.message.role===`assistant`&&u.has(e.message.stopReason)&&await C(e.message.stopReason===`aborted`?`warn`:`error`,`pi.turn.failed`,{...f(t),"pi.turn.index":e.turnIndex,...m(e.message),...n}),n)for(let r of e.toolResults)await C(`debug`,`pi.tool_token_sample`,{...f(t),...n,"tool.name":r.toolName,token_attribution:`toolCallTurn`})})}),t.on(`tool_execution_start`,(e,t)=>{if(g)return E(t,async()=>{l.set(e.toolCallId,Date.now()),w(t),await C(`debug`,`pi.tool_call`,{...f(t),"tool.name":e.toolName,"tool.call.id":e.toolCallId})})}),t.on(`tool_execution_end`,(e,t)=>{if(g)return E(t,async()=>{let n=l.get(e.toolCallId);l.delete(e.toolCallId),w(t),await C(`info`,`pi.tool_result`,{...f(t),success:!e.isError,"tool.name":e.toolName,"tool.call.id":e.toolCallId,"tool.result.error":e.isError,...n===void 0?{}:{"tool.duration_ms":Date.now()-n}})})}),t.on(`after_provider_response`,(e,t)=>{if(g)return E(t,async()=>{w(t);let n={...f(t),"http.response.status_code":e.status};e.status>=400?await C(`error`,`pi.api_error`,n):await C(`debug`,`pi.api_response`,n)})}),t.on(`model_select`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`info`,`pi.model.selected`,{...f(t),"pi.model.source":e.source,"gen_ai.provider.name":e.model.provider,"gen_ai.request.model":e.model.id})})}),t.on(`agent_end`,(e,t)=>{if(!g)return;let n=_;return E(t,async()=>{w(t),await C(`info`,`pi.agent.finished`,{...f(t),"pi.message.count":e.messages.length,...v===void 0?{}:{"pi.agent.duration_ms":Date.now()-v}}),!(!g||n!==_)&&(v=void 0,await y?.flush())})}),t.on(`agent_settled`,(e,t)=>{if(g)return E(t,async()=>{w(t),await C(`debug`,`pi.agent.settled`,f(t))})}),{waitForSession:T,async finishSession(e,t){if(!g)return;await x;let n=b;n&&await n.operation.catch(()=>void 0),g&&(n&&n!==b||y&&(w(t),await C(`info`,`pi.session.finished`,{...f(t),"pi.session.reason":e})))}}}function _(e,t={}){let n=e.registerLeader({source:t.source??`@agimon-ai/doompi-log`,bindings:[{id:`log.metrics`,path:[{key:`h`,label:`help`,detail:`package docs and logs`,order:70},{key:`l`,label:`logs`,detail:`telemetry`}],command:{name:l}}]});return()=>n.dispose()}async function v(e,n,r){await e.ui.custom((e,i,a,o)=>new t(e,i,n,o,r),{overlay:!0,overlayOptions:{anchor:`top-left`,width:`100%`,maxHeight:`100%`,margin:0}})}function y(t,r,i={},s=!1){let u=i.env??process.env,f=new e,p=i.metricsSource,m=e=>p??=n({env:u,cwd:e.cwd,packageName:c,serviceName:i.serviceName??`pi`}),h=!0,y,b;t.effect(()=>()=>{h=!1,y=void 0,b=void 0},`${c}/runtime`);let x=g(t,r,{...i,metrics:f,onDiagnostic:e=>{h&&(b=e,i.onDiagnostic?i.onDiagnostic(e):u.AGENT_OTEL_DIAGNOSTICS===`stderr`&&process.emitWarning(e))},onSinkStatus:e=>{h&&(y=e,i.onSinkStatus?.(e))}},s);return t.inject([a],e=>_(o(e),{source:i.leaderSource})),r.registerCommand(l,{description:`Show session-local log metrics`,handler:async(e,t)=>{if(!h||(await x.waitForSession(t),!h))return;let n=m(t);await v(t,()=>({disabled:d(u.AGENT_TELEMETRY_DISABLED)||d(u.OTEL_SDK_DISABLED),snapshot:f.snapshot(),sink:y,transport:n.lastTransport(),instance:n.instance?.(),lastDiagnostic:b}),n.query)}}),x}function b(e,{pi:t}){let n=y(e,t,{},!0),r;t.on(`session_shutdown`,(e,t)=>(r??=n.finishSession(e.reason,t),r))}async function x(e){let t=await r(e,c),n=t.root.plugin(b,{pi:e});try{await n}catch(e){try{await n.dispose()}finally{await t.dispose()}throw e}let i;e.on(`session_shutdown`,()=>i??=(async()=>{try{await n.dispose()}finally{await t.dispose()}})())}export{x as doomLogExtension,y as installDoomLogRuntime,g as installPiTelemetryRuntime,v as openLogMetricsOverlay,_ as registerLogMetricsLeaderBinding};
|
|
2
2
|
//# sourceMappingURL=extension.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["/**\n * Pi telemetry wiring for the Doom harness.\n *\n * This extension deliberately emits metadata-only records. Prompt, message,\n * tool payload, file path, diagnostic text, exception, and stack data never\n * cross the shared telemetry boundary.\n */\n\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n type DoomReadinessCoordinator,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport {\n DOOM_UI_HUB_SERVICE,\n type DoomUiHubService,\n requireDoomUiHub,\n} from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext, TurnEndEvent } from '@earendil-works/pi-coding-agent';\nimport { LogMetricsAggregator, type LogMetricsRecorder } from '../../services/metrics.ts';\nimport { LogMetricsOverlayComponent, type LogMetricsView, type SinkStatus } from '../../tui/logMetricsOverlay.ts';\nimport type { MetricsQuery, MetricsSource } from '../../types/metricsSource.ts';\nimport { createMetricsSource } from '../node/metricsSource.ts';\n\nconst SERVICE_NAME = 'pi';\nconst PACKAGE_NAME = '@agimon-ai/doompi-log';\n/** Opt back into stderr diagnostics when debugging outside a live TUI. */\nconst DIAGNOSTICS_STDERR = 'stderr';\nconst LEADER_SOURCE = '@agimon-ai/doompi-log';\nconst LOG_METRICS_COMMAND = 'log-metrics';\nconst LOG_METRICS_DESCRIPTION = 'Show session-local log metrics';\nconst HELP_GROUP_ORDER = 70;\n/** Must match the Help group published by doompi-ui, or the registry drops this. */\nconst HELP_GROUP_DETAIL = 'package docs and logs';\nconst NO_ENDPOINT = 'none';\nconst API_ERROR_STATUS = 400;\nconst FAILURE_STOP_REASONS = new Set(['error', 'aborted']);\n\ntype TelemetryFactory = NonNullable<DoomTelemetryOptions['telemetryFactory']>;\ntype TelemetryAttributes = Record<string, string | number | boolean>;\ntype RecordLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface PiTelemetryExtensionOptions {\n allowFileFallback?: boolean;\n /** Overrides the telemetry service identity. */\n serviceName?: string;\n /** Overrides the leader contribution owner. */\n leaderSource?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: TelemetryFactory;\n /** Receives every sanitized record, whether or not a sink is live. */\n metrics?: LogMetricsRecorder;\n /** Called once the sink backend is resolved, so the overlay can report it. */\n onSinkStatus?: (status: SinkStatus | undefined) => void;\n /** Overrides the sink-history transport; injected in tests. */\n metricsSource?: MetricsSource;\n /** Receives telemetry lifecycle failures without writing into the TUI. */\n onDiagnostic?: (message: string) => void;\n}\n\nexport interface PiTelemetryRuntimeHandle {\n waitForSession(ctx: ExtensionContext): Promise<void>;\n finishSession(reason: string, ctx: ExtensionContext): Promise<void>;\n}\n\nfunction isEnabled(value: string | undefined): boolean {\n return value === '1' || value?.toLowerCase() === 'true' || value?.toLowerCase() === 'yes';\n}\n\nfunction contextAttributes(ctx: ExtensionContext): TelemetryAttributes {\n const attributes: TelemetryAttributes = {\n 'pi.mode': ctx.mode,\n 'pi.session.id': ctx.sessionManager.getSessionId(),\n };\n if (ctx.thinkingLevel) attributes['pi.thinking_level'] = ctx.thinkingLevel;\n if (ctx.model) {\n attributes['gen_ai.provider.name'] = ctx.model.provider;\n attributes['gen_ai.request.model'] = ctx.model.id;\n }\n return attributes;\n}\n\nfunction usageAttributes(message: TurnEndEvent['message']): TelemetryAttributes | undefined {\n if (message.role !== 'assistant') return undefined;\n const attributes: TelemetryAttributes = {\n 'gen_ai.response.model': message.responseModel ?? message.model,\n 'gen_ai.response.finish_reasons': message.stopReason,\n 'gen_ai.usage.input_tokens': message.usage.input,\n 'gen_ai.usage.output_tokens': message.usage.output,\n 'gen_ai.usage.cache_read_tokens': message.usage.cacheRead,\n 'gen_ai.usage.cache_write_tokens': message.usage.cacheWrite,\n 'gen_ai.usage.total_tokens': message.usage.totalTokens,\n 'gen_ai.usage.cost': message.usage.cost.total,\n };\n if (message.usage.reasoning !== undefined) attributes['gen_ai.usage.reasoning_tokens'] = message.usage.reasoning;\n return attributes;\n}\n\nfunction failureAttributes(message: TurnEndEvent['message']): TelemetryAttributes {\n if (message.role !== 'assistant') return { 'error.type': 'AgentError', outcome: 'error' };\n const aborted = message.stopReason === 'aborted';\n return {\n 'error.type': 'ProviderError',\n 'error.code': message.stopReason,\n outcome: aborted ? 'aborted' : 'error',\n };\n}\n\nfunction statusFromTelemetry(status: ReturnType<DoomTelemetry['status']>): SinkStatus {\n return {\n service: status.serviceName,\n backend: status.backend,\n endpoint: status.endpoint ?? NO_ENDPOINT,\n endpointSource: status.endpointSource,\n traces: status.traces,\n redaction: true,\n fileFallback: status.fileFallback,\n };\n}\n\nexport function installPiTelemetryRuntime(\n cordis: Context,\n pi: ExtensionAPI,\n options: PiTelemetryExtensionOptions = {},\n splitReadiness = false,\n): PiTelemetryRuntimeHandle {\n const env = options.env ?? process.env;\n const metrics = options.metrics;\n const toolStartedAt = new Map<string, number>();\n let active = true;\n let sessionGeneration = 0;\n let agentStartedAt: number | undefined;\n let telemetry: DoomTelemetry | undefined;\n let sessionReadiness:\n | {\n readonly sessionManager: object;\n readonly coordinator: DoomReadinessCoordinator;\n readonly operation: Promise<void>;\n }\n | undefined;\n let backgroundQueue = Promise.resolve();\n\n const enqueue = (operation: () => Promise<void>): void => {\n const scheduled = backgroundQueue.then(operation);\n // Telemetry is advisory and the coordinator owns startup failure notification.\n backgroundQueue = scheduled.catch(() => undefined);\n };\n\n cordis.effect(\n () => async () => {\n active = false;\n sessionGeneration += 1;\n sessionReadiness = undefined;\n toolStartedAt.clear();\n agentStartedAt = undefined;\n const ownedTelemetry = telemetry;\n telemetry = undefined;\n await ownedTelemetry?.shutdown();\n },\n `${PACKAGE_NAME}/telemetry`,\n );\n\n const emit = async (level: RecordLevel, name: string, attributes: TelemetryAttributes): Promise<void> => {\n if (!active || !telemetry) return;\n if (level === 'debug') await telemetry.recordDebug(name, attributes);\n else if (level === 'warn') await telemetry.recordWarning(name, undefined, attributes);\n else if (level === 'error') await telemetry.recordError(name, undefined, attributes);\n else await telemetry.recordEvent(name, attributes);\n };\n\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n if (!active) throw new Error('Log telemetry runtime is disposed.');\n telemetry ??= createDoomTelemetry({\n serviceName: options.serviceName ?? SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: ctx.cwd,\n env,\n allowFileFallback: options.allowFileFallback,\n telemetryFactory: options.telemetryFactory,\n warn: options.onDiagnostic,\n enableLogs: true,\n enableTraces: env.AGENT_OTEL_TRACES === undefined || isEnabled(env.AGENT_OTEL_TRACES),\n onRecord: (record) => {\n if (active) metrics?.record(record.event, record.attributes);\n },\n onStatus: (status) => {\n if (active) options.onSinkStatus?.(statusFromTelemetry(status));\n },\n });\n if (active) options.onSinkStatus?.(statusFromTelemetry(telemetry.status()));\n return telemetry;\n };\n\n const waitForSession = async (ctx: ExtensionContext): Promise<void> => {\n const current = sessionReadiness;\n if (!current) return;\n if (current.sessionManager !== ctx.sessionManager) {\n throw new Error('Log readiness belongs to a stale Pi session.');\n }\n await current.operation;\n if (!active || current !== sessionReadiness) {\n throw new Error('Log readiness belongs to a stale extension generation.');\n }\n };\n\n const enqueueForSession = (ctx: ExtensionContext, operation: () => Promise<void>): void | Promise<void> => {\n const expected = sessionReadiness;\n const run = async (): Promise<void> => {\n if (expected) {\n const ready = await expected.operation.then(\n () => true,\n () => false,\n );\n if (!ready || !active || expected !== sessionReadiness || expected.sessionManager !== ctx.sessionManager) {\n return;\n }\n } else if (!active) {\n return;\n }\n await operation();\n };\n if (!splitReadiness) return run();\n enqueue(run);\n return undefined;\n };\n\n pi.on('session_start', (event, ctx) => {\n if (!active) return undefined;\n const ownGeneration = ++sessionGeneration;\n toolStartedAt.clear();\n agentStartedAt = undefined;\n const initialize = async (signal?: AbortSignal): Promise<void> => {\n signal?.throwIfAborted();\n getTelemetry(ctx);\n await emit('info', 'pi.session.started', {\n ...contextAttributes(ctx),\n 'pi.session.reason': event.reason,\n 'pi.session.previous': event.previousSessionFile !== undefined,\n });\n signal?.throwIfAborted();\n };\n const coordinator = splitReadiness ? readDoomReadinessCoordinator(cordis) : undefined;\n if (!coordinator) return initialize();\n\n const previous = sessionReadiness;\n const operation = (async (): Promise<void> => {\n if (previous?.coordinator === coordinator) await previous.operation.catch(() => undefined);\n if (!active || ownGeneration !== sessionGeneration) return;\n const handle = coordinator.start(\n PACKAGE_NAME,\n `${ctx.sessionManager.getSessionId()}:${ownGeneration}`,\n async (signal) => {\n await initialize(signal);\n return { value: undefined };\n },\n );\n await handle.wait();\n })();\n // Config's coordinator owns the single user-facing failure notification.\n void operation.catch(() => undefined);\n sessionReadiness = { sessionManager: ctx.sessionManager, coordinator, operation };\n return undefined;\n });\n\n pi.on('before_agent_start', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('info', 'pi.user_prompt', {\n ...contextAttributes(ctx),\n 'pi.user_message.length': event.prompt.length,\n 'pi.user_message.image_count': event.images?.length ?? 0,\n });\n });\n });\n\n pi.on('agent_start', (_event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n agentStartedAt = Date.now();\n getTelemetry(ctx);\n await emit('info', 'pi.agent.started', contextAttributes(ctx));\n });\n });\n\n pi.on('turn_start', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('debug', 'pi.turn.started', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n });\n });\n });\n\n pi.on('turn_end', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n const usage = usageAttributes(event.message);\n await emit('info', 'pi.turn.finished', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n 'pi.tool_result.count': event.toolResults.length,\n ...usage,\n });\n if (event.message.role === 'assistant' && FAILURE_STOP_REASONS.has(event.message.stopReason)) {\n await emit(event.message.stopReason === 'aborted' ? 'warn' : 'error', 'pi.turn.failed', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n ...failureAttributes(event.message),\n ...usage,\n });\n }\n if (!usage) return;\n for (const result of event.toolResults) {\n await emit('debug', 'pi.tool_token_sample', {\n ...contextAttributes(ctx),\n ...usage,\n 'tool.name': result.toolName,\n token_attribution: 'toolCallTurn',\n });\n }\n });\n });\n\n pi.on('tool_execution_start', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n toolStartedAt.set(event.toolCallId, Date.now());\n getTelemetry(ctx);\n await emit('debug', 'pi.tool_call', {\n ...contextAttributes(ctx),\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n });\n });\n });\n\n pi.on('tool_execution_end', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n getTelemetry(ctx);\n await emit('info', 'pi.tool_result', {\n ...contextAttributes(ctx),\n success: !event.isError,\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n 'tool.result.error': event.isError,\n ...(startedAt === undefined ? {} : { 'tool.duration_ms': Date.now() - startedAt }),\n });\n });\n });\n\n pi.on('after_provider_response', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n const attributes = {\n ...contextAttributes(ctx),\n 'http.response.status_code': event.status,\n };\n if (event.status >= API_ERROR_STATUS) await emit('error', 'pi.api_error', attributes);\n else await emit('debug', 'pi.api_response', attributes);\n });\n });\n\n pi.on('model_select', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('info', 'pi.model.selected', {\n ...contextAttributes(ctx),\n 'pi.model.source': event.source,\n 'gen_ai.provider.name': event.model.provider,\n 'gen_ai.request.model': event.model.id,\n });\n });\n });\n\n pi.on('agent_end', (event, ctx) => {\n if (!active) return;\n const generation = sessionGeneration;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('info', 'pi.agent.finished', {\n ...contextAttributes(ctx),\n 'pi.message.count': event.messages.length,\n ...(agentStartedAt === undefined ? {} : { 'pi.agent.duration_ms': Date.now() - agentStartedAt }),\n });\n if (!active || generation !== sessionGeneration) return;\n agentStartedAt = undefined;\n await telemetry?.flush();\n });\n });\n\n pi.on('agent_settled', (_event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('debug', 'pi.agent.settled', contextAttributes(ctx));\n });\n });\n\n return {\n waitForSession,\n async finishSession(reason, ctx) {\n if (!active) return;\n await backgroundQueue;\n const current = sessionReadiness;\n if (current) await current.operation.catch(() => undefined);\n if (!active) return;\n if (current && current !== sessionReadiness) return;\n if (!telemetry) return;\n getTelemetry(ctx);\n await emit('info', 'pi.session.finished', {\n ...contextAttributes(ctx),\n 'pi.session.reason': reason,\n });\n },\n };\n}\n\nexport function registerLogMetricsLeaderBinding(hub: DoomUiHubService, options: { source?: string } = {}): () => void {\n const contribution = hub.registerLeader({\n source: options.source ?? LEADER_SOURCE,\n bindings: [\n {\n id: 'log.metrics',\n path: [\n { key: 'h', label: 'help', detail: HELP_GROUP_DETAIL, order: HELP_GROUP_ORDER },\n { key: 'l', label: 'logs', detail: 'telemetry' },\n ],\n command: { name: LOG_METRICS_COMMAND },\n },\n ],\n });\n return () => contribution.dispose();\n}\n\nexport async function openLogMetricsOverlay(\n ctx: ExtensionContext,\n getView: () => LogMetricsView,\n query?: MetricsQuery,\n): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new LogMetricsOverlayComponent(tui, theme, getView, done, query),\n {\n overlay: true,\n overlayOptions: {\n anchor: 'top-left',\n width: '100%',\n maxHeight: '100%',\n margin: 0,\n },\n },\n );\n}\n\nexport function installDoomLogRuntime(\n cordis: Context,\n pi: ExtensionAPI,\n options: PiTelemetryExtensionOptions = {},\n splitReadiness = false,\n): PiTelemetryRuntimeHandle {\n const env = options.env ?? process.env;\n const metrics = new LogMetricsAggregator();\n const metricsSource = options.metricsSource ?? createMetricsSource({ env });\n let active = true;\n let sink: SinkStatus | undefined;\n let lastDiagnostic: string | undefined;\n\n cordis.effect(\n () => () => {\n active = false;\n sink = undefined;\n lastDiagnostic = undefined;\n },\n `${PACKAGE_NAME}/runtime`,\n );\n\n const telemetryRuntime = installPiTelemetryRuntime(\n cordis,\n pi,\n {\n ...options,\n metrics,\n // Always supply a sink so doom-telemetry never falls back to\n // process.emitWarning, which writes raw stderr over the TUI frame.\n // Diagnostics surface in the Log Metrics overlay instead.\n onDiagnostic: (message) => {\n if (!active) return;\n lastDiagnostic = message;\n if (options.onDiagnostic) options.onDiagnostic(message);\n else if (env.AGENT_OTEL_DIAGNOSTICS === DIAGNOSTICS_STDERR) process.emitWarning(message);\n },\n onSinkStatus: (status) => {\n if (!active) return;\n sink = status;\n options.onSinkStatus?.(status);\n },\n },\n splitReadiness,\n );\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n return registerLogMetricsLeaderBinding(requireDoomUiHub(uiContext), { source: options.leaderSource });\n });\n pi.registerCommand(LOG_METRICS_COMMAND, {\n description: LOG_METRICS_DESCRIPTION,\n handler: async (_args, ctx) => {\n if (!active) return;\n await telemetryRuntime.waitForSession(ctx);\n if (!active) return;\n await openLogMetricsOverlay(\n ctx,\n () => ({\n disabled: isEnabled(env.AGENT_TELEMETRY_DISABLED) || isEnabled(env.OTEL_SDK_DISABLED),\n snapshot: metrics.snapshot(),\n sink,\n transport: metricsSource.lastTransport(),\n lastDiagnostic,\n }),\n metricsSource.query,\n );\n },\n });\n return telemetryRuntime;\n}\n\ninterface LogPluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction logPlugin(cordis: Context, { pi }: LogPluginConfig): void {\n const runtime = installDoomLogRuntime(cordis, pi, {}, true);\n let shutdown: Promise<void> | undefined;\n pi.on('session_shutdown', (event, ctx) => {\n shutdown ??= runtime.finishSession(event.reason, ctx);\n return shutdown;\n });\n}\n\n/** The package's single standard Pi factory. */\nexport async function doomLogExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_NAME);\n const fiber = connection.root.plugin(logPlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["/**\n * Pi telemetry wiring for the Doom harness.\n *\n * This extension deliberately emits metadata-only records. Prompt, message,\n * tool payload, file path, diagnostic text, exception, and stack data never\n * cross the shared telemetry boundary.\n */\n\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport {\n type DoomReadinessCoordinator,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport {\n DOOM_UI_HUB_SERVICE,\n type DoomUiHubService,\n requireDoomUiHub,\n} from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext, TurnEndEvent } from '@earendil-works/pi-coding-agent';\nimport { LogMetricsAggregator, type LogMetricsRecorder } from '../../services/metrics.ts';\nimport { LogMetricsOverlayComponent, type LogMetricsView, type SinkStatus } from '../../tui/logMetricsOverlay.ts';\nimport type { MetricsQuery, MetricsSource } from '../../types/metricsSource.ts';\nimport { createMetricsSource } from '../node/metricsSource.ts';\n\nconst SERVICE_NAME = 'pi';\nconst PACKAGE_NAME = '@agimon-ai/doompi-log';\n/** Opt back into stderr diagnostics when debugging outside a live TUI. */\nconst DIAGNOSTICS_STDERR = 'stderr';\nconst LEADER_SOURCE = '@agimon-ai/doompi-log';\nconst LOG_METRICS_COMMAND = 'log-metrics';\nconst LOG_METRICS_DESCRIPTION = 'Show session-local log metrics';\nconst HELP_GROUP_ORDER = 70;\n/** Must match the Help group published by doompi-ui, or the registry drops this. */\nconst HELP_GROUP_DETAIL = 'package docs and logs';\nconst NO_ENDPOINT = 'none';\nconst API_ERROR_STATUS = 400;\nconst FAILURE_STOP_REASONS = new Set(['error', 'aborted']);\n\ntype TelemetryFactory = NonNullable<DoomTelemetryOptions['telemetryFactory']>;\ntype TelemetryAttributes = Record<string, string | number | boolean>;\ntype RecordLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface PiTelemetryExtensionOptions {\n allowFileFallback?: boolean;\n /** Overrides the telemetry service identity. */\n serviceName?: string;\n /** Overrides the leader contribution owner. */\n leaderSource?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: TelemetryFactory;\n /** Receives every sanitized record, whether or not a sink is live. */\n metrics?: LogMetricsRecorder;\n /** Called once the sink backend is resolved, so the overlay can report it. */\n onSinkStatus?: (status: SinkStatus | undefined) => void;\n /** Overrides the sink-history transport; injected in tests. */\n metricsSource?: MetricsSource;\n /** Receives telemetry lifecycle failures without writing into the TUI. */\n onDiagnostic?: (message: string) => void;\n}\n\nexport interface PiTelemetryRuntimeHandle {\n waitForSession(ctx: ExtensionContext): Promise<void>;\n finishSession(reason: string, ctx: ExtensionContext): Promise<void>;\n}\n\nfunction isEnabled(value: string | undefined): boolean {\n return value === '1' || value?.toLowerCase() === 'true' || value?.toLowerCase() === 'yes';\n}\n\nfunction contextAttributes(ctx: ExtensionContext): TelemetryAttributes {\n const attributes: TelemetryAttributes = {\n 'pi.mode': ctx.mode,\n 'pi.session.id': ctx.sessionManager.getSessionId(),\n };\n if (ctx.thinkingLevel) attributes['pi.thinking_level'] = ctx.thinkingLevel;\n if (ctx.model) {\n attributes['gen_ai.provider.name'] = ctx.model.provider;\n attributes['gen_ai.request.model'] = ctx.model.id;\n }\n return attributes;\n}\n\nfunction usageAttributes(message: TurnEndEvent['message']): TelemetryAttributes | undefined {\n if (message.role !== 'assistant') return undefined;\n const attributes: TelemetryAttributes = {\n 'gen_ai.response.model': message.responseModel ?? message.model,\n 'gen_ai.response.finish_reasons': message.stopReason,\n 'gen_ai.usage.input_tokens': message.usage.input,\n 'gen_ai.usage.output_tokens': message.usage.output,\n 'gen_ai.usage.cache_read_tokens': message.usage.cacheRead,\n 'gen_ai.usage.cache_write_tokens': message.usage.cacheWrite,\n 'gen_ai.usage.total_tokens': message.usage.totalTokens,\n 'gen_ai.usage.cost': message.usage.cost.total,\n };\n if (message.usage.reasoning !== undefined) attributes['gen_ai.usage.reasoning_tokens'] = message.usage.reasoning;\n return attributes;\n}\n\nfunction failureAttributes(message: TurnEndEvent['message']): TelemetryAttributes {\n if (message.role !== 'assistant') return { 'error.type': 'AgentError', outcome: 'error' };\n const aborted = message.stopReason === 'aborted';\n return {\n 'error.type': 'ProviderError',\n 'error.code': message.stopReason,\n outcome: aborted ? 'aborted' : 'error',\n };\n}\n\nfunction statusFromTelemetry(status: ReturnType<DoomTelemetry['status']>): SinkStatus {\n return {\n service: status.serviceName,\n backend: status.backend,\n endpoint: status.endpoint ?? NO_ENDPOINT,\n endpointSource: status.endpointSource,\n traces: status.traces,\n redaction: true,\n fileFallback: status.fileFallback,\n };\n}\n\nexport function installPiTelemetryRuntime(\n cordis: Context,\n pi: ExtensionAPI,\n options: PiTelemetryExtensionOptions = {},\n splitReadiness = false,\n): PiTelemetryRuntimeHandle {\n const env = options.env ?? process.env;\n const metrics = options.metrics;\n const toolStartedAt = new Map<string, number>();\n let active = true;\n let sessionGeneration = 0;\n let agentStartedAt: number | undefined;\n let telemetry: DoomTelemetry | undefined;\n let sessionReadiness:\n | {\n readonly sessionManager: object;\n readonly coordinator: DoomReadinessCoordinator;\n readonly operation: Promise<void>;\n }\n | undefined;\n let backgroundQueue = Promise.resolve();\n\n const enqueue = (operation: () => Promise<void>): void => {\n const scheduled = backgroundQueue.then(operation);\n // Telemetry is advisory and the coordinator owns startup failure notification.\n backgroundQueue = scheduled.catch(() => undefined);\n };\n\n cordis.effect(\n () => async () => {\n active = false;\n sessionGeneration += 1;\n sessionReadiness = undefined;\n toolStartedAt.clear();\n agentStartedAt = undefined;\n const ownedTelemetry = telemetry;\n telemetry = undefined;\n await ownedTelemetry?.shutdown();\n },\n `${PACKAGE_NAME}/telemetry`,\n );\n\n const emit = async (level: RecordLevel, name: string, attributes: TelemetryAttributes): Promise<void> => {\n if (!active || !telemetry) return;\n if (level === 'debug') await telemetry.recordDebug(name, attributes);\n else if (level === 'warn') await telemetry.recordWarning(name, undefined, attributes);\n else if (level === 'error') await telemetry.recordError(name, undefined, attributes);\n else await telemetry.recordEvent(name, attributes);\n };\n\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n if (!active) throw new Error('Log telemetry runtime is disposed.');\n telemetry ??= createDoomTelemetry({\n serviceName: options.serviceName ?? SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: ctx.cwd,\n env,\n allowFileFallback: options.allowFileFallback,\n telemetryFactory: options.telemetryFactory,\n warn: options.onDiagnostic,\n enableLogs: true,\n enableTraces: env.AGENT_OTEL_TRACES === undefined || isEnabled(env.AGENT_OTEL_TRACES),\n onRecord: (record) => {\n if (active) metrics?.record(record.event, record.attributes);\n },\n onStatus: (status) => {\n if (active) options.onSinkStatus?.(statusFromTelemetry(status));\n },\n });\n if (active) options.onSinkStatus?.(statusFromTelemetry(telemetry.status()));\n return telemetry;\n };\n\n const waitForSession = async (ctx: ExtensionContext): Promise<void> => {\n const current = sessionReadiness;\n if (!current) return;\n if (current.sessionManager !== ctx.sessionManager) {\n throw new Error('Log readiness belongs to a stale Pi session.');\n }\n await current.operation;\n if (!active || current !== sessionReadiness) {\n throw new Error('Log readiness belongs to a stale extension generation.');\n }\n };\n\n const enqueueForSession = (ctx: ExtensionContext, operation: () => Promise<void>): void | Promise<void> => {\n const expected = sessionReadiness;\n const run = async (): Promise<void> => {\n if (expected) {\n const ready = await expected.operation.then(\n () => true,\n () => false,\n );\n if (!ready || !active || expected !== sessionReadiness || expected.sessionManager !== ctx.sessionManager) {\n return;\n }\n } else if (!active) {\n return;\n }\n await operation();\n };\n if (!splitReadiness) return run();\n enqueue(run);\n return undefined;\n };\n\n pi.on('session_start', (event, ctx) => {\n if (!active) return undefined;\n const ownGeneration = ++sessionGeneration;\n toolStartedAt.clear();\n agentStartedAt = undefined;\n const initialize = async (signal?: AbortSignal): Promise<void> => {\n signal?.throwIfAborted();\n getTelemetry(ctx);\n await emit('info', 'pi.session.started', {\n ...contextAttributes(ctx),\n 'pi.session.reason': event.reason,\n 'pi.session.previous': event.previousSessionFile !== undefined,\n });\n signal?.throwIfAborted();\n };\n const coordinator = splitReadiness ? readDoomReadinessCoordinator(cordis) : undefined;\n if (!coordinator) return initialize();\n\n const previous = sessionReadiness;\n const operation = (async (): Promise<void> => {\n if (previous?.coordinator === coordinator) await previous.operation.catch(() => undefined);\n if (!active || ownGeneration !== sessionGeneration) return;\n const handle = coordinator.start(\n PACKAGE_NAME,\n `${ctx.sessionManager.getSessionId()}:${ownGeneration}`,\n async (signal) => {\n await initialize(signal);\n return { value: undefined };\n },\n );\n await handle.wait();\n })();\n // Config's coordinator owns the single user-facing failure notification.\n void operation.catch(() => undefined);\n sessionReadiness = { sessionManager: ctx.sessionManager, coordinator, operation };\n return undefined;\n });\n\n pi.on('before_agent_start', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('info', 'pi.user_prompt', {\n ...contextAttributes(ctx),\n 'pi.user_message.length': event.prompt.length,\n 'pi.user_message.image_count': event.images?.length ?? 0,\n });\n });\n });\n\n pi.on('agent_start', (_event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n agentStartedAt = Date.now();\n getTelemetry(ctx);\n await emit('info', 'pi.agent.started', contextAttributes(ctx));\n });\n });\n\n pi.on('turn_start', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('debug', 'pi.turn.started', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n });\n });\n });\n\n pi.on('turn_end', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n const usage = usageAttributes(event.message);\n await emit('info', 'pi.turn.finished', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n 'pi.tool_result.count': event.toolResults.length,\n ...usage,\n });\n if (event.message.role === 'assistant' && FAILURE_STOP_REASONS.has(event.message.stopReason)) {\n await emit(event.message.stopReason === 'aborted' ? 'warn' : 'error', 'pi.turn.failed', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n ...failureAttributes(event.message),\n ...usage,\n });\n }\n if (!usage) return;\n for (const result of event.toolResults) {\n await emit('debug', 'pi.tool_token_sample', {\n ...contextAttributes(ctx),\n ...usage,\n 'tool.name': result.toolName,\n token_attribution: 'toolCallTurn',\n });\n }\n });\n });\n\n pi.on('tool_execution_start', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n toolStartedAt.set(event.toolCallId, Date.now());\n getTelemetry(ctx);\n await emit('debug', 'pi.tool_call', {\n ...contextAttributes(ctx),\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n });\n });\n });\n\n pi.on('tool_execution_end', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n getTelemetry(ctx);\n await emit('info', 'pi.tool_result', {\n ...contextAttributes(ctx),\n success: !event.isError,\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n 'tool.result.error': event.isError,\n ...(startedAt === undefined ? {} : { 'tool.duration_ms': Date.now() - startedAt }),\n });\n });\n });\n\n pi.on('after_provider_response', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n const attributes = {\n ...contextAttributes(ctx),\n 'http.response.status_code': event.status,\n };\n if (event.status >= API_ERROR_STATUS) await emit('error', 'pi.api_error', attributes);\n else await emit('debug', 'pi.api_response', attributes);\n });\n });\n\n pi.on('model_select', (event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('info', 'pi.model.selected', {\n ...contextAttributes(ctx),\n 'pi.model.source': event.source,\n 'gen_ai.provider.name': event.model.provider,\n 'gen_ai.request.model': event.model.id,\n });\n });\n });\n\n pi.on('agent_end', (event, ctx) => {\n if (!active) return;\n const generation = sessionGeneration;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('info', 'pi.agent.finished', {\n ...contextAttributes(ctx),\n 'pi.message.count': event.messages.length,\n ...(agentStartedAt === undefined ? {} : { 'pi.agent.duration_ms': Date.now() - agentStartedAt }),\n });\n if (!active || generation !== sessionGeneration) return;\n agentStartedAt = undefined;\n await telemetry?.flush();\n });\n });\n\n pi.on('agent_settled', (_event, ctx) => {\n if (!active) return;\n return enqueueForSession(ctx, async () => {\n getTelemetry(ctx);\n await emit('debug', 'pi.agent.settled', contextAttributes(ctx));\n });\n });\n\n return {\n waitForSession,\n async finishSession(reason, ctx) {\n if (!active) return;\n await backgroundQueue;\n const current = sessionReadiness;\n if (current) await current.operation.catch(() => undefined);\n if (!active) return;\n if (current && current !== sessionReadiness) return;\n if (!telemetry) return;\n getTelemetry(ctx);\n await emit('info', 'pi.session.finished', {\n ...contextAttributes(ctx),\n 'pi.session.reason': reason,\n });\n },\n };\n}\n\nexport function registerLogMetricsLeaderBinding(hub: DoomUiHubService, options: { source?: string } = {}): () => void {\n const contribution = hub.registerLeader({\n source: options.source ?? LEADER_SOURCE,\n bindings: [\n {\n id: 'log.metrics',\n path: [\n { key: 'h', label: 'help', detail: HELP_GROUP_DETAIL, order: HELP_GROUP_ORDER },\n { key: 'l', label: 'logs', detail: 'telemetry' },\n ],\n command: { name: LOG_METRICS_COMMAND },\n },\n ],\n });\n return () => contribution.dispose();\n}\n\nexport async function openLogMetricsOverlay(\n ctx: ExtensionContext,\n getView: () => LogMetricsView,\n query?: MetricsQuery,\n): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new LogMetricsOverlayComponent(tui, theme, getView, done, query),\n {\n overlay: true,\n overlayOptions: {\n anchor: 'top-left',\n width: '100%',\n maxHeight: '100%',\n margin: 0,\n },\n },\n );\n}\n\nexport function installDoomLogRuntime(\n cordis: Context,\n pi: ExtensionAPI,\n options: PiTelemetryExtensionOptions = {},\n splitReadiness = false,\n): PiTelemetryRuntimeHandle {\n const env = options.env ?? process.env;\n const metrics = new LogMetricsAggregator();\n // Built lazily so the history transports resolve their sink instance from the\n // same cwd and package identity the telemetry writer registers under; at\n // install time there is no ExtensionContext to read `cwd` from yet.\n let metricsSource = options.metricsSource;\n const resolveMetricsSource = (ctx: ExtensionContext): MetricsSource =>\n (metricsSource ??= createMetricsSource({\n env,\n cwd: ctx.cwd,\n packageName: PACKAGE_NAME,\n serviceName: options.serviceName ?? SERVICE_NAME,\n }));\n let active = true;\n let sink: SinkStatus | undefined;\n let lastDiagnostic: string | undefined;\n\n cordis.effect(\n () => () => {\n active = false;\n sink = undefined;\n lastDiagnostic = undefined;\n },\n `${PACKAGE_NAME}/runtime`,\n );\n\n const telemetryRuntime = installPiTelemetryRuntime(\n cordis,\n pi,\n {\n ...options,\n metrics,\n // Always supply a sink so doom-telemetry never falls back to\n // process.emitWarning, which writes raw stderr over the TUI frame.\n // Diagnostics surface in the Log Metrics overlay instead.\n onDiagnostic: (message) => {\n if (!active) return;\n lastDiagnostic = message;\n if (options.onDiagnostic) options.onDiagnostic(message);\n else if (env.AGENT_OTEL_DIAGNOSTICS === DIAGNOSTICS_STDERR) process.emitWarning(message);\n },\n onSinkStatus: (status) => {\n if (!active) return;\n sink = status;\n options.onSinkStatus?.(status);\n },\n },\n splitReadiness,\n );\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n return registerLogMetricsLeaderBinding(requireDoomUiHub(uiContext), { source: options.leaderSource });\n });\n pi.registerCommand(LOG_METRICS_COMMAND, {\n description: LOG_METRICS_DESCRIPTION,\n handler: async (_args, ctx) => {\n if (!active) return;\n await telemetryRuntime.waitForSession(ctx);\n if (!active) return;\n const source = resolveMetricsSource(ctx);\n await openLogMetricsOverlay(\n ctx,\n () => ({\n disabled: isEnabled(env.AGENT_TELEMETRY_DISABLED) || isEnabled(env.OTEL_SDK_DISABLED),\n snapshot: metrics.snapshot(),\n sink,\n transport: source.lastTransport(),\n instance: source.instance?.(),\n lastDiagnostic,\n }),\n source.query,\n );\n },\n });\n return telemetryRuntime;\n}\n\ninterface LogPluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction logPlugin(cordis: Context, { pi }: LogPluginConfig): void {\n const runtime = installDoomLogRuntime(cordis, pi, {}, true);\n let shutdown: Promise<void> | undefined;\n pi.on('session_shutdown', (event, ctx) => {\n shutdown ??= runtime.finishSession(event.reason, ctx);\n return shutdown;\n });\n}\n\n/** The package's single standard Pi factory. */\nexport async function doomLogExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_NAME);\n const fiber = connection.root.plugin(logPlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n"],"mappings":"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"}
|
package/dist/metricsSource.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { MetricsQuery, MetricsQueryParams, MetricsSource, MetricsTransport } from "./types/metricsSource.cjs";
|
|
1
|
+
import { MetricsInstance, MetricsQuery, MetricsQueryParams, MetricsSource, MetricsTransport } from "./types/metricsSource.cjs";
|
|
2
2
|
import { MetricsSourceOptions, createMetricsSource } from "./adapters/node/metricsSource.cjs";
|
|
3
|
-
export { type MetricsQuery, type MetricsQueryParams, type MetricsSource, type MetricsSourceOptions, type MetricsTransport, createMetricsSource };
|
|
3
|
+
export { type MetricsInstance, type MetricsQuery, type MetricsQueryParams, type MetricsSource, type MetricsSourceOptions, type MetricsTransport, createMetricsSource };
|
package/dist/metricsSource.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { MetricsQuery, MetricsQueryParams, MetricsSource, MetricsTransport } from "./types/metricsSource.mjs";
|
|
1
|
+
import { MetricsInstance, MetricsQuery, MetricsQueryParams, MetricsSource, MetricsTransport } from "./types/metricsSource.mjs";
|
|
2
2
|
import { MetricsSourceOptions, createMetricsSource } from "./adapters/node/metricsSource.mjs";
|
|
3
|
-
export { type MetricsQuery, type MetricsQueryParams, type MetricsSource, type MetricsSourceOptions, type MetricsTransport, createMetricsSource };
|
|
3
|
+
export { type MetricsInstance, type MetricsQuery, type MetricsQueryParams, type MetricsSource, type MetricsSourceOptions, type MetricsTransport, createMetricsSource };
|