@qilin-agent/session-telemetry 0.0.0-stage → 3.1.4

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kkutysllb
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,64 @@
1
+ # Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
2
+ # section, a hash of its English and Chinese blocks outside code blocks and generated regions.
3
+ # After editing either side, bring the other along and re-record with:
4
+ # pnpm run verify-translation-pairing --write packages/session/session-telemetry/README.md
5
+ /:
6
+ en: 5c553664bfb6ebaa
7
+ zh: 0ad10e1597cb65bc
8
+ /qilin-agent-session-telemetry:
9
+ en: 90a76261e0971942
10
+ zh: 95b8990c999aaef6
11
+ /qilin-agent-session-telemetry/summary:
12
+ en: 2ee6fcb4e68f6c9b
13
+ zh: 8ddc8d1f3c645757
14
+ /qilin-agent-session-telemetry/table-of-contents:
15
+ en: d152484eb41ac6b4
16
+ zh: 09388d293f9be9cb
17
+ /qilin-agent-session-telemetry/use-this-package:
18
+ en: f103da7913199503
19
+ zh: 623f7a102c451289
20
+ /qilin-agent-session-telemetry/use-this-package/choosing-and-mounting-a-backend:
21
+ en: cc1b92c9563ec9e9
22
+ zh: 6e80c5e002a6c83d
23
+ /qilin-agent-session-telemetry/use-this-package/the-backend-contract:
24
+ en: e3cc8ee7774a0ad5
25
+ zh: 3c039339870b8cf9
26
+ /qilin-agent-session-telemetry/use-this-package/what-gets-captured:
27
+ en: 5b7fbbe1c55997e8
28
+ zh: d62d9118fd8df2f4
29
+ /qilin-agent-session-telemetry/use-this-package/the-sharing-disclosure:
30
+ en: 5c325a8aaadf17c7
31
+ zh: 5c493d2333f82b28
32
+ /qilin-agent-session-telemetry/use-this-package/redacting-records:
33
+ en: 22ed345bf7746611
34
+ zh: a57d2eaa878c8cce
35
+ /qilin-agent-session-telemetry/understand-the-implementation:
36
+ en: cad1e9d195916553
37
+ zh: 2192f3ce5e2196bd
38
+ /qilin-agent-session-telemetry/understand-the-implementation/design-concept:
39
+ en: 5527f8d2222119fb
40
+ zh: 3173640a2f0a0676
41
+ /qilin-agent-session-telemetry/understand-the-implementation/source-map:
42
+ en: 5dc345ec3dda38b8
43
+ zh: 189d673734a2c20e
44
+ /qilin-agent-session-telemetry/understand-the-implementation/capture-flow:
45
+ en: f86c2777668ae89e
46
+ zh: 710c28c18f3f4402
47
+ /qilin-agent-session-telemetry/understand-the-implementation/the-handoff-cursor:
48
+ en: c213358e20f27173
49
+ zh: 84a5501335891f0b
50
+ /qilin-agent-session-telemetry/further-exploration:
51
+ en: 57e55389f43b5b28
52
+ zh: 1f7187573723e735
53
+ /qilin-agent-session-telemetry/model-experience:
54
+ en: 6a6b429828997572
55
+ zh: bde61df9dab8f840
56
+ /qilin-agent-session-telemetry/model-experience/kv-cache-effect:
57
+ en: 7593cf5d0d2cedd6
58
+ zh: f57cc48a1b5cbfa9
59
+ /qilin-agent-session-telemetry/known-limitations-and-deferred-work:
60
+ en: dc950b1f59a057ec
61
+ zh: 6f353d426b03abb1
62
+ /qilin-agent-session-telemetry/known-limitations-and-deferred-work/dev-note:
63
+ en: e67f633dc6fe7773
64
+ zh: 3bb0c20c93f16f98
package/README.md CHANGED
@@ -1,3 +1,129 @@
1
- # Temporary Holding Version
1
+ ---
2
+ description: "Session-telemetry capture seam for deployments and backend authors choosing a reporting backend, mounting redaction rules, or implementing the backend contract."
3
+ kind: "package-library"
4
+ ---
2
5
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
6
+ # @qilin-agent/session-telemetry
7
+
8
+ English | [中文](README.zh.md)
9
+
10
+ ## Summary
11
+
12
+ Session telemetry lets deployments send ordered copies of session activity for reporting while preserving the canonical session log. Deployments choose one reporting backend and can redact each outbound copy before delivery; without redaction rules, captured data leaves the process unchanged. The handoff is non-blocking, so reporting does not delay session processing. Delivery is best effort, and queued records may be lost if the process crashes.
13
+
14
+ ## Table of Contents
15
+
16
+ - [Use this package](#use-this-package)
17
+ - [Understand the implementation](#understand-the-implementation)
18
+ - [Further Exploration](#further-exploration)
19
+ - [Model Experience](#model-experience)
20
+ - [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
21
+ - [Dev Note](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## Use this package
27
+
28
+ As a deployment, choose a backend, mount it, and add redaction rules when records must not leave the process as captured. As a backend author, implement the three-member contract and compose the coordinator with a capture mode.
29
+
30
+ ### Choosing and mounting a backend
31
+
32
+ Load exactly one backend plugin; it registers `ctx.sessionTelemetry` with the capture coordinator and its delivery pipeline. A duplicate load throws. The required [`sharing` member](#the-sharing-disclosure) reports the deployment mode, not per-session admission or delivery. A consumer may report "not configured" only when no telemetry service is mounted. The `/feedback` command confirms recording without reading this policy.
33
+
34
+ ### The backend contract
35
+
36
+ A backend implements three members: `emit(record)` must be a non-blocking enqueue because it runs synchronously on the session-event path; optional `flush()` is a fire-and-forget hint after a turn ends, which most backends omit in favor of their SDK's own batching schedule; `shutdown()` drains queued records and resolves when the SDK stops, and disposal awaits it. A backend that implements `flush()` must order concurrent flushes with the final `shutdown()` drain.
37
+
38
+ ### What gets captured
39
+
40
+ Capture runs in one of two modes. `live` capture follows session events as they are appended, replays already-live sessions at mount time, and records lifecycle markers; `on-demand` capture reads the canonical session log only when the backend requests a prefix through `captureSession(session, throughSeq?)`. Coordinator options select whether stored history is included. Every canonical session event maps to one ledger record in order. An `assistant/message` or `assistant/attempt` record carries its complete embedded compact stream, including failed and retried output. Each ledger record also carries `session.id`, `session.format_version`, the numeric event identity, optional header facts, and a pre-mapped severity (`error` for `tool/result.isError`, `turn/end` error reasons, and `agent-error`; `info` otherwise).
41
+
42
+ Ledger records carry `sourceEvent` with the owning Session id and a copied event envelope excluding `data`. The redaction waterfall receives `body` as the only payload copy. Backends can reconstruct a complete exported event from the envelope and redacted body without bypassing redaction.
43
+
44
+ ### The sharing disclosure
45
+
46
+ <a id="the-sharing-disclosure"></a>
47
+
48
+ Every backend discloses its deployment mode through `sharing`: `full`, `feedback-only`, or `disabled`. A backend may additionally restrict eligible Sessions. This property is not a delivery receipt; handoff is a non-blocking enqueue, and batching, retry, and loss policy belong to the backend SDK.
49
+
50
+ ### Redacting records
51
+
52
+ <a id="the-redact-waterfall"></a>
53
+
54
+ Every outbound record passes the `sessionTelemetry/record` waterfall after the coordinator copies its canonical event. This package ships no rules: with no listener mounted, records reach the backend exactly as captured, so exported data is as clean as the rules a deployment mounts. Listeners stack by transforming `next()`'s return value; a throwing listener withholds that one record fail-closed. Redaction applies to the outbound copy only — the canonical session log is never rewritten.
55
+
56
+ -----
57
+
58
+ <a id="understand-the-implementation"></a>
59
+ ## Understand the implementation
60
+
61
+ <details>
62
+ <summary>Implementation internals — click to expand</summary>
63
+
64
+ This section explains the capture design; the observable behavior is fully covered in [Use this package](#use-this-package).
65
+
66
+ ### Design concept
67
+
68
+ The capture package owns complete event capture, redaction, and handoff cursors. Redaction rules must preserve `sourceEvent` for OTel upload; returning a fresh record without it withholds the event with a diagnostic. Its cloned envelope excludes `data`, which is carried only in `body`. The OTel backend owns byte/count scheduling and uses SDK transport/retries. The [revival Agent Note](../../../.agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.md) owns capture and redaction rationale.
69
+
70
+ ### Source map
71
+
72
+ | File | Role |
73
+ |---|---|
74
+ | [`src/index.ts`](src/index.ts) | Service Definition: `SessionTelemetryBackend`/`SessionTelemetrySink` contract, record vocabulary, `session-telemetry/record` waterfall declaration |
75
+ | [`src/coordinator.ts`](src/coordinator.ts) | Capture: live listeners, lifecycle-local on-demand replay, redaction, handoff cursor, containment |
76
+
77
+ ### Capture flow
78
+
79
+ Live capture registers Session events, flush hints, shutdown markers, and agent/error observers through the composing fiber’s effects. On-demand capture registers only the disposal effect and reads the requested canonical-log prefix under its history policy. Synchronous handlers contain failures so they cannot affect the agent loop or other listeners.
80
+
81
+ ### The handoff cursor
82
+
83
+ A module-scope `WeakMap<Session, seq>` records the highest sequence handed off, not delivered. Re-adopting the same object resumes after that cursor. Capture starts at `firstLifecycleSeq`: a new fork includes its child-owned marker and closers, while a restored Session excludes its stored prefix, including prior child turns; explicit `includeHistory: true` starts an unhanded object at seq 0, including restored or fork history. The backend owns capture authorization. Stored history does not itself authorize capture; the OTel backend waits for new explicit feedback. Receivers deduplicate repeated records by `(session.id, session.format_version, event.seq)`.
84
+
85
+ </details>
86
+
87
+ -----
88
+
89
+ <a id="further-exploration"></a>
90
+ ## Further Exploration
91
+
92
+ Read these pages when the seam contract is not enough. They move from the shipped backend to the subsystem reference and the decision evidence.
93
+
94
+ - [OpenTelemetry telemetry backend](../session-telemetry-otel/README.md) — the shipped backend deployments load, with mode and exporter configuration.
95
+ - [Session telemetry subsystem](../../../docs/subsystems/session-telemetry.md) — the capability split and type declarations.
96
+ - [Session telemetry revival decision](../../../.agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.md) — rationale, trade-offs, and rejected alternatives.
97
+ - [Session package map](../README.md) — adjacent persistence, projection, title, and telemetry packages.
98
+
99
+ -----
100
+
101
+ <a id="model-experience"></a>
102
+ ## Model Experience
103
+
104
+ None, as the seam observes the session stream and hands redacted copies outward; it registers nothing model-facing.
105
+
106
+ #### KV Cache effect
107
+
108
+ None; the package neither assembles nor sends a provider request.
109
+
110
+ ## Known Limitations and Deferred Work
111
+
112
+ <a id="known-limitations-and-deferred-work"></a>
113
+
114
+
115
+ These limits define the delivery and data-protection guarantees a deployment gets. They are current package constraints.
116
+
117
+ - **Best-effort delivery** — the cursor marks handed-off, not delivered; a session torn down inside a reload window cannot be re-adopted, and whatever sits in a backend queue at crash time is lost. A durable outbox (spool, per-sink cursors, at-least-once) is deferred until a deployment states a crash-loss requirement.
118
+ - **No built-in redaction rules** — with no `sessionTelemetry/record` listener mounted, records leave the process exactly as captured, including any credentials embedded in file contents or command output; a deployment exporting to a shared collector owns its rule set.
119
+ - **On-demand redaction uses current state** — uncaptured events exist only in the canonical session log; a later `captureSession()` deep-copies and redacts their current values with the policy mounted at that time, and there is no capture-time telemetry snapshot or durable pre-capture spool.
120
+
121
+ <a id="dev-note"></a>
122
+ ### Dev Note
123
+
124
+ <details>
125
+ <summary>Working context for maintainers — click to expand</summary>
126
+
127
+ None.
128
+
129
+ </details>
package/README.zh.md ADDED
@@ -0,0 +1,129 @@
1
+ ---
2
+ description: "面向部署方与后端作者的会话遥测捕获 seam 说明,用于选择上报后端、挂载脱敏规则或实现后端约定。"
3
+ kind: "package-library"
4
+ ---
5
+
6
+ # @qilin-agent/session-telemetry
7
+
8
+ [English](README.md) | 中文
9
+
10
+ ## 概述
11
+
12
+ 会话遥测让部署方发送会话活动的有序副本用于上报,同时保留权威会话日志。部署方选择一个上报后端,并可在投递前脱敏每个外发副本;如果没有脱敏规则,捕获的数据将原样离开进程。交接以非阻塞方式完成,因此上报不会延迟会话处理。投递采用尽力而为方式;如果进程崩溃,队列中的记录可能丢失。
13
+
14
+ ## 目录
15
+
16
+ - [使用本包](#use-this-package)
17
+ - [理解实现](#understand-the-implementation)
18
+ - [进一步探索](#further-exploration)
19
+ - [模型体验](#model-experience)
20
+ - [已知限制与延期工作](#known-limitations-and-deferred-work)
21
+ - [开发备注](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## 使用本包
27
+
28
+ 作为部署方,选择一个后端并挂载它,当记录不能以捕获原样离开进程时添加脱敏规则。作为后端作者,实现三成员约定,并以一种捕获模式组装协调器。
29
+
30
+ ### 选择并挂载后端
31
+
32
+ 只加载一个后端插件;它把捕获协调器与投递流水线注册为 `ctx.sessionTelemetry`。重复加载会抛出异常。必需的 [`sharing` 成员](#the-sharing-disclosure) 报告部署模式,不代表会话准入或投递。只有在未挂载任何遥测服务时,消费方才可报告「未配置」。`/feedback` 命令确认记录,不读取此策略。
33
+
34
+ ### 后端约定
35
+
36
+ 后端实现三个成员:`emit(record)` 必须是非阻塞入队,因为它会在会话事件路径上同步执行;可选的 `flush()` 是轮次结束后的即发即忘提示,多数后端为了遵循 SDK 自身的批处理计划而省略它;`shutdown()` 排空已入队记录,并在 SDK 停止后结束,dispose(资源释放)会等待它。实现 `flush()` 的后端必须安排并发 flush 与最终 `shutdown()` 排空的先后顺序。
37
+
38
+ ### 捕获内容
39
+
40
+ 捕获以两种模式之一运行。`live` 捕获在追加时跟随会话事件、在挂载时回放已存活会话并记录生命周期标记;`on-demand` 捕获只在后端通过 `captureSession(session, throughSeq?)` 请求前缀时读取权威会话日志。协调器选项决定是否包含存储历史。每条权威会话事件都按顺序映射为一条 ledger 记录。`assistant/message` 或 `assistant/attempt` 记录会携带完整的嵌入式紧凑流,包括失败和重试输出。每条 ledger 记录还携带 `session.id`、`session.format_version`、数值型事件标识、可选 header 事实与预先映射的严重级别(`tool/result.isError`、`turn/end` 的错误原因与 `agent-error` 映射为 `error`;其余为 `info`)。
41
+
42
+ ledger 记录携带 `sourceEvent`,其中包含所属 Session id 和不含 `data` 的事件信封副本。脱敏 waterfall 接收的 `body` 是唯一的载荷副本。后端可从信封和脱敏后的 body 重建完整导出事件,而不绕过脱敏。
43
+
44
+ ### 共享披露
45
+
46
+ <a id="the-sharing-disclosure"></a>
47
+
48
+ 每个后端通过 `sharing` 披露部署模式:`full`、`feedback-only` 或 `disabled`。后端还可限制符合条件的会话。该属性不是投递回执;交接是非阻塞入队,批处理、重试与丢失策略属于后端 SDK。
49
+
50
+ ### 脱敏记录
51
+
52
+ <a id="the-redact-waterfall"></a>
53
+
54
+ 协调器复制权威事件后,每条外发记录都会立即经过 `sessionTelemetry/record` waterfall(瀑布式事件)。本包不带任何规则:未挂载监听器时,记录以捕获时的原样到达后端,因此导出数据能干净到什么程度,恰恰取决于部署方挂载了什么规则。监听器通过变换 `next()` 的返回值来堆叠;抛出异常的监听器以 fail-closed 方式拦下这一条记录。脱敏只作用于外发副本——权威会话日志永不改写。
55
+
56
+ -----
57
+
58
+ <a id="understand-the-implementation"></a>
59
+ ## 理解实现
60
+
61
+ <details>
62
+ <summary>实现细节——点击展开</summary>
63
+
64
+ 本节解释捕获设计;可观察行为已在[使用本包](#use-this-package)中完整说明。
65
+
66
+ ### 设计理念
67
+
68
+ 捕获包负责完整事件捕获、脱敏和交接游标。脱敏规则必须保留 `sourceEvent` 才能通过 OTel 上传;返回不含它的新记录会阻止该事件上传并产生诊断。复制的 envelope 不含 `data`,数据仅由 `body` 携带。OTel 后端负责字节/条数调度并使用 SDK 传输和重试。[恢复遥测决策记录](../../../.agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.zh.md) 说明捕获和脱敏依据。
69
+
70
+ ### 源码地图
71
+
72
+ | 文件 | 职责 |
73
+ |---|---|
74
+ | [`src/index.ts`](src/index.ts) | Service Definition:`SessionTelemetryBackend`/`SessionTelemetrySink` 约定、记录词汇、`session-telemetry/record` waterfall 声明 |
75
+ | [`src/coordinator.ts`](src/coordinator.ts) | 捕获:live 监听器、生命周期本地 on-demand 回放、脱敏、handoff 游标、异常隔离 |
76
+
77
+ ### 捕获流程
78
+
79
+ 实时捕获通过组合 fiber 的 effect 注册 Session 事件、刷新提示、关闭标记与 agent/error 观察器。按需捕获只注册释放 effect,并按历史策略读取请求的权威日志前缀。同步处理器隔离失败,避免影响 agent loop(智能体循环)或其他监听器。
80
+
81
+ ### handoff 游标
82
+
83
+ 模块级 `WeakMap<Session, seq>` 记录已经移交的最高序号,而不是已送达的最高序号。再次接管同一对象时从该游标之后继续。采集从 `firstLifecycleSeq` 开始:新 fork 包含子会话自有的标记与 fork 结束事件;恢复的 Session 排除已存储前缀,包括先前的子会话轮次。显式 `includeHistory: true` 会让尚未移交的对象从 seq 0 开始,包括恢复或 fork 历史。Backend 负责采集授权;已有存储历史本身不构成授权,OTel backend 等待新的显式反馈。接收方通过 `(session.id, session.format_version, event.seq)` 对重复记录去重。
84
+
85
+ </details>
86
+
87
+ -----
88
+
89
+ <a id="further-exploration"></a>
90
+ ## 进一步探索
91
+
92
+ 当 seam 约定不够用时阅读以下页面。它们从随附后端逐步进入子系统参考与决策证据。
93
+
94
+ - [OpenTelemetry 遥测后端](../session-telemetry-otel/README.zh.md)——部署方加载的随附后端,含模式与导出器配置。
95
+ - [会话遥测子系统](../../../docs/subsystems/session-telemetry.zh.md)——能力拆分与类型声明。
96
+ - [会话遥测复活决策](../../../.agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.zh.md)——理由、权衡与被否决的替代方案。
97
+ - [会话包映射](../README.zh.md)——相邻的持久化、投影、标题与遥测包。
98
+
99
+ -----
100
+
101
+ <a id="model-experience"></a>
102
+ ## 模型体验
103
+
104
+ 无,因为该 seam 观察会话流并把脱敏后的副本交给外部;它不注册任何面向模型的内容。
105
+
106
+ #### KV Cache 影响
107
+
108
+ 无;本包既不组装也不发送提供方请求。
109
+
110
+ ## 已知限制与延期工作
111
+
112
+ <a id="known-limitations-and-deferred-work"></a>
113
+
114
+
115
+ 这些限制定义部署方能得到的投递与数据保护保证。它们是当前包约束。
116
+
117
+ - **尽力而为的投递**——游标标记的是已交接而非已投递;在重载窗口内被拆除的会话无法重新收养,崩溃时留在后端队列中的内容会丢失。持久化 outbox(spool、每 sink 游标、at-least-once)推迟到有部署方提出明确的崩溃丢失要求时再实现。
118
+ - **不内置脱敏规则**——未挂载 `sessionTelemetry/record` 监听器时,记录以捕获时的原样离开进程,包括文件内容或命令输出中内嵌的任何凭据;向共享 collector 导出的部署方自行负责其规则集。
119
+ - **按需脱敏使用当前状态**——未捕获的事件只存在于权威会话日志中;后续的 `captureSession()` 会使用当时挂载的策略,深拷贝并脱敏其当前值,且不存在捕获时的遥测快照或持久化的捕获前 spool。
120
+
121
+ <a id="dev-note"></a>
122
+ ### 开发备注
123
+
124
+ <details>
125
+ <summary>维护者的工作上下文——点击展开</summary>
126
+
127
+ 无。
128
+
129
+ </details>
package/lib/index.js ADDED
@@ -0,0 +1,279 @@
1
+ import { Service } from "@qilin-agent/kylin";
2
+ import { SessionLogOffset, SessionSeq } from "@qilin-agent/session";
3
+ //#region lib/types/coordinator.js
4
+ /**
5
+ * Capture coordinator for the telemetry capability. Live capture subscribes to
6
+ * the session firehose plus the one live-bus relay (`agent/error`). Both
7
+ * capture paths build one logical record per canonical Session event and run
8
+ * each through the
9
+ * `session-telemetry/record` waterfall (deployment-mounted redaction rules;
10
+ * pass-through when none), then hands the result to the backend. Live capture
11
+ * follows the session firehose; on-demand capture replays the canonical log
12
+ * only when requested. Every synchronous handler is self-contained so a
13
+ * failing backend can never starve other subscribers (cordis `emit` is
14
+ * stop-on-throw) or touch the agent loop. Composed by a backend in its
15
+ * constructor.
16
+ *
17
+ * @module @qilin-agent/session-telemetry/coordinator
18
+ */
19
+ /**
20
+ * The handoff cursor: per session, the highest `seq` handed to a backend.
21
+ * Deliberately MODULE-scope ambient state — a narrow, documented exception
22
+ * to the registrations-are-effects discipline: cordis has no HMR
23
+ * state-handover API, and keying by the `Session` object (which belongs to
24
+ * the session store and outlives any telemetry fiber) is the only in-process
25
+ * lifetime that lets a re-adopting fiber resume instead of re-handing
26
+ * history. Entries die with their sessions; a missing entry safely means
27
+ * "re-hand everything". Advanced only at emit time — the cursor marks
28
+ * handed-off, not delivered.
29
+ */
30
+ const handoffCursor = /* @__PURE__ */ new WeakMap();
31
+ /**
32
+ * Install the telemetry capture side onto a context for one backend.
33
+ *
34
+ * Live capture registers its own `session/created` / `session/event` /
35
+ * `session/disposed` listener set plus the `agent/error` relay, all through
36
+ * `ctx.effect()`/`ctx.on()` on the composing fiber, and sweeps already-live
37
+ * sessions (a hot reload does not replay `session/created`). A `session/disposed` captures the session's `shutdown`
38
+ * operational record at its own termination edge and retires it from the
39
+ * adopted set. On-demand capture registers none of those continuous listeners;
40
+ * {@link captureSession} reads the canonical log explicitly and never creates
41
+ * operational records. Disposal captures shutdown markers for live-adopted
42
+ * sessions, then awaits the backend's `shutdown()`; a failure there warns
43
+ * instead of throwing — best-effort reporting must not fail application
44
+ * teardown.
45
+ */
46
+ var SessionTelemetryCoordinator = class {
47
+ ctx;
48
+ backend;
49
+ options;
50
+ /**
51
+ * Sessions adopted by THIS fiber and still live, for double-adoption
52
+ * protection and the teardown sweep of unmarked sessions;
53
+ * `session/disposed` marks and retires entries.
54
+ */
55
+ adopted = /* @__PURE__ */ new Set();
56
+ /**
57
+ * @param ctx - the composing backend's context; listeners bind to its fiber.
58
+ * @param backend - the backend receiving records; owned elsewhere, never disposed here beyond `shutdown()` forwarding.
59
+ * @param options - capture mode and history policy.
60
+ */
61
+ constructor(ctx, backend, options = {}) {
62
+ this.ctx = ctx;
63
+ this.backend = backend;
64
+ this.options = options;
65
+ if ((options.capture ?? "live") === "live") {
66
+ ctx.on("session/created", (session) => {
67
+ this.adopt(session);
68
+ });
69
+ ctx.on("session/disposed", (session) => {
70
+ this.contain(() => {
71
+ if (!this.adopted.delete(session)) return;
72
+ this.deliver(session, { record: this.redact(shutdownRecord(session)) });
73
+ });
74
+ });
75
+ ctx.on("session/event", (session, event) => {
76
+ this.contain(() => {
77
+ this.captureEvent(session, event);
78
+ });
79
+ });
80
+ ctx.on("session/flush", (session) => {
81
+ this.contain(() => {
82
+ this.hintFlush(session);
83
+ });
84
+ });
85
+ ctx.on("agent/error", ({ agent, turn, step, error }) => {
86
+ this.contain(() => {
87
+ this.relayAgentError(agent, turn, step, error);
88
+ });
89
+ });
90
+ for (const session of ctx.sessions.list()) this.adopt(session);
91
+ }
92
+ ctx.effect(() => async () => {
93
+ for (const session of this.adopted) this.contain(() => {
94
+ this.deliver(session, { record: this.redact(shutdownRecord(session)) });
95
+ });
96
+ try {
97
+ await this.backend.shutdown();
98
+ } catch (error) {
99
+ this.ctx.logger.warn(`telemetry: backend shutdown failed: ${String(error)}`);
100
+ }
101
+ }, "telemetry capture");
102
+ }
103
+ /**
104
+ * Copy, redact, and hand over the canonical session-log suffix after the handoff
105
+ * cursor, optionally stopping at an inclusive sequence boundary. Redaction
106
+ * runs during this call, so an on-demand caller retains no copied records
107
+ * before requesting capture and uses the policy mounted at that time.
108
+ * Backend and policy failures remain contained per event and do not starve
109
+ * later events in the same replay.
110
+ * @param session - session whose current canonical-log prefix may be handed over.
111
+ * @param throughSeq - optional last sequence included in this capture.
112
+ */
113
+ captureSession(session, throughSeq) {
114
+ const start = session.firstLifecycleSeq;
115
+ const cursor = handoffCursor.get(session) ?? (this.options.includeHistory === true || start === 0 ? -1 : SessionSeq(start - 1));
116
+ for (const event of session.snapshotEvents(SessionLogOffset(cursor + 1))) {
117
+ if (throughSeq !== void 0 && event.seq > throughSeq) break;
118
+ this.contain(() => {
119
+ this.captureEvent(session, event);
120
+ });
121
+ }
122
+ }
123
+ /**
124
+ * Adopt a session and replay after its handoff cursor, then follow live events.
125
+ * New fork objects include child-owned seed markers and closers. Restored
126
+ * objects start after the stored prefix, including restored forks. includeHistory starts either object at seq 0;
127
+ * re-adopting the same object resumes after its cursor.
128
+ * @param session - the live session to adopt; a second adoption is a no-op.
129
+ */
130
+ adopt(session) {
131
+ if (this.adopted.has(session)) return;
132
+ this.adopted.add(session);
133
+ this.captureSession(session);
134
+ }
135
+ /** Copy, redact, and hand one canonical event to the backend. */
136
+ captureEvent(session, event) {
137
+ const { data, ...envelope } = event;
138
+ this.deliver(session, {
139
+ record: this.redact({
140
+ sourceEvent: {
141
+ sessionId: session.id,
142
+ envelope: structuredClone(envelope)
143
+ },
144
+ channel: "ledger",
145
+ time: event.time,
146
+ severity: severityOf(event),
147
+ attributes: identityOf(session, event),
148
+ body: structuredClone(data)
149
+ }),
150
+ seq: event.seq
151
+ });
152
+ }
153
+ /**
154
+ * Run the `session-telemetry/record` waterfall at capture time. The innermost `next`
155
+ * passes the record through unchanged — this package ships no rules; exported
156
+ * data is as clean as the listeners a deployment mounts. Callers run inside
157
+ * {@link contain}, so a throwing rule withholds the record instead of
158
+ * reaching the loop (fail-closed). On-demand capture invokes this waterfall
159
+ * while reading the canonical session log, not when the event was appended.
160
+ */
161
+ redact(record) {
162
+ return this.ctx.waterfall("session-telemetry/record", record, () => record);
163
+ }
164
+ /** Hand one redacted record to the backend, then advance its ledger cursor. */
165
+ deliver(session, pending) {
166
+ this.backend.emit(pending.record);
167
+ if (pending.seq !== void 0) handoffCursor.set(session, pending.seq);
168
+ }
169
+ /** Forward the turn-end boundary to the backend's optional flush hint. */
170
+ hintFlush(session) {
171
+ if (this.adopted.has(session)) this.backend.flush?.();
172
+ }
173
+ /** Relay one `agent/error` bus emission as an `agent-error` operational record. */
174
+ relayAgentError(agent, turn, step, error) {
175
+ const detail = errorDetail(error);
176
+ this.deliver(agent.session, { record: this.redact({
177
+ channel: "ops",
178
+ time: Date.now(),
179
+ severity: "error",
180
+ attributes: {
181
+ "telemetry.op": "agent-error",
182
+ "session.id": String(agent.session.id),
183
+ "agent.id": agent.id,
184
+ "error.name": detail.name,
185
+ turn,
186
+ step
187
+ },
188
+ body: detail
189
+ }) });
190
+ }
191
+ /**
192
+ * Run one capture-side step with its exception contained: cordis `emit`
193
+ * is stop-on-throw, so a throwing listener would starve every subscriber
194
+ * registered after this plugin — nothing from the backend may escape.
195
+ */
196
+ contain(step) {
197
+ try {
198
+ step();
199
+ } catch (error) {
200
+ this.ctx.logger.warn(`telemetry: capture step failed: ${String(error)}`);
201
+ }
202
+ }
203
+ };
204
+ /**
205
+ * Build the per-session clean-exit marker: emitted at the session's own
206
+ * disposal edge, or at coordinator dispose for sessions still alive then.
207
+ */
208
+ function shutdownRecord(session) {
209
+ return {
210
+ channel: "ops",
211
+ time: Date.now(),
212
+ severity: "info",
213
+ attributes: {
214
+ "telemetry.op": "shutdown",
215
+ "session.id": String(session.id)
216
+ },
217
+ body: { op: "shutdown" }
218
+ };
219
+ }
220
+ /** Map an event's own outcome flag to the pre-baked alerting severity. */
221
+ function severityOf(event) {
222
+ switch (event.type) {
223
+ case "tool/result": return event.data.message.isError === true ? "error" : "info";
224
+ case "turn/end": return event.data.reason.kind === "error" ? "error" : "info";
225
+ default: return "info";
226
+ }
227
+ }
228
+ /** Normalize the live bus's arbitrary thrown value into the stable operational-record shape. */
229
+ function errorDetail(error) {
230
+ const normalized = error instanceof Error ? error : new Error(String(error));
231
+ return {
232
+ name: normalized.name,
233
+ message: normalized.message
234
+ };
235
+ }
236
+ /** Build the minimal identity attributes: envelope plus self-contained header facts. */
237
+ function identityOf(session, event) {
238
+ const attributes = {
239
+ "session.id": String(session.id),
240
+ "session.format_version": session.header.version,
241
+ "event.type": event.type,
242
+ "event.seq": event.seq
243
+ };
244
+ const { cwd, parentSession, isSeeded } = session.header;
245
+ if (cwd !== void 0) attributes["session.cwd"] = cwd;
246
+ if (parentSession !== void 0) attributes["session.parent_id"] = String(parentSession);
247
+ if (isSeeded) attributes["session.seed_length"] = session.inheritedEventCount;
248
+ return attributes;
249
+ }
250
+ //#endregion
251
+ //#region lib/types/index.js
252
+ /**
253
+ * SessionTelemetryBackend Service Definition for the QiLin.
254
+ *
255
+ * This package owns the CAPTURE side of session-event reporting — the complete
256
+ * one-record-per-event ledger mirror, what records carry, when
257
+ * they are captured (adoption, the per-append firehose, lifecycle
258
+ * forwarding), live versus on-demand canonical-log capture, and the HMR
259
+ * cursor. Everything downstream of
260
+ * {@link SessionTelemetryBackend.emit} — batching, retry, queueing, and loss policy — is the
261
+ * reporting SDK's territory and is deliberately not modelled here. The
262
+ * design and its trade-offs are pinned in
263
+ * .agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.md.
264
+ *
265
+ * @module @qilin-agent/session-telemetry
266
+ */
267
+ /**
268
+ * Loadable form of the backend contract: one implementation per context —
269
+ * the cordis `Service` registration under the `telemetry` key throws on a
270
+ * duplicate, cordis' standard behavior. A backend composes a
271
+ * {@link SessionTelemetryCoordinator} in its constructor to install the capture side.
272
+ */
273
+ var SessionTelemetryBackend = class extends Service {
274
+ constructor(ctx) {
275
+ super(ctx, "sessionTelemetry");
276
+ }
277
+ };
278
+ //#endregion
279
+ export { SessionTelemetryBackend, SessionTelemetryCoordinator };
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Capture coordinator for the telemetry capability. Live capture subscribes to
3
+ * the session firehose plus the one live-bus relay (`agent/error`). Both
4
+ * capture paths build one logical record per canonical Session event and run
5
+ * each through the
6
+ * `session-telemetry/record` waterfall (deployment-mounted redaction rules;
7
+ * pass-through when none), then hands the result to the backend. Live capture
8
+ * follows the session firehose; on-demand capture replays the canonical log
9
+ * only when requested. Every synchronous handler is self-contained so a
10
+ * failing backend can never starve other subscribers (cordis `emit` is
11
+ * stop-on-throw) or touch the agent loop. Composed by a backend in its
12
+ * constructor.
13
+ *
14
+ * @module @qilin-agent/session-telemetry/coordinator
15
+ */
16
+ import type { Context } from '@qilin-agent/kylin';
17
+ import { type Session, type SessionSeq as SessionSeqType } from '@qilin-agent/session';
18
+ import type { SessionTelemetrySink } from './index.ts';
19
+ /** Whether capture follows live events or reads the canonical log only when requested. */
20
+ export type SessionTelemetryCapture = 'live' | 'on-demand';
21
+ /** Backend-selected capture mode and history policy. */
22
+ export interface SessionTelemetryCaptureOptions {
23
+ /** Follow live events, or wait for explicit capture; defaults to live. */
24
+ capture?: SessionTelemetryCapture;
25
+ /** Include inherited fork history and stored history from earlier lifecycles; defaults to false. */
26
+ includeHistory?: boolean;
27
+ }
28
+ /**
29
+ * Install the telemetry capture side onto a context for one backend.
30
+ *
31
+ * Live capture registers its own `session/created` / `session/event` /
32
+ * `session/disposed` listener set plus the `agent/error` relay, all through
33
+ * `ctx.effect()`/`ctx.on()` on the composing fiber, and sweeps already-live
34
+ * sessions (a hot reload does not replay `session/created`). A `session/disposed` captures the session's `shutdown`
35
+ * operational record at its own termination edge and retires it from the
36
+ * adopted set. On-demand capture registers none of those continuous listeners;
37
+ * {@link captureSession} reads the canonical log explicitly and never creates
38
+ * operational records. Disposal captures shutdown markers for live-adopted
39
+ * sessions, then awaits the backend's `shutdown()`; a failure there warns
40
+ * instead of throwing — best-effort reporting must not fail application
41
+ * teardown.
42
+ */
43
+ export declare class SessionTelemetryCoordinator {
44
+ private readonly ctx;
45
+ private readonly backend;
46
+ private readonly options;
47
+ /**
48
+ * Sessions adopted by THIS fiber and still live, for double-adoption
49
+ * protection and the teardown sweep of unmarked sessions;
50
+ * `session/disposed` marks and retires entries.
51
+ */
52
+ private readonly adopted;
53
+ /**
54
+ * @param ctx - the composing backend's context; listeners bind to its fiber.
55
+ * @param backend - the backend receiving records; owned elsewhere, never disposed here beyond `shutdown()` forwarding.
56
+ * @param options - capture mode and history policy.
57
+ */
58
+ constructor(ctx: Context, backend: SessionTelemetrySink, options?: SessionTelemetryCaptureOptions);
59
+ /**
60
+ * Copy, redact, and hand over the canonical session-log suffix after the handoff
61
+ * cursor, optionally stopping at an inclusive sequence boundary. Redaction
62
+ * runs during this call, so an on-demand caller retains no copied records
63
+ * before requesting capture and uses the policy mounted at that time.
64
+ * Backend and policy failures remain contained per event and do not starve
65
+ * later events in the same replay.
66
+ * @param session - session whose current canonical-log prefix may be handed over.
67
+ * @param throughSeq - optional last sequence included in this capture.
68
+ */
69
+ captureSession(session: Session, throughSeq?: SessionSeqType): void;
70
+ /**
71
+ * Adopt a session and replay after its handoff cursor, then follow live events.
72
+ * New fork objects include child-owned seed markers and closers. Restored
73
+ * objects start after the stored prefix, including restored forks. includeHistory starts either object at seq 0;
74
+ * re-adopting the same object resumes after its cursor.
75
+ * @param session - the live session to adopt; a second adoption is a no-op.
76
+ */
77
+ private adopt;
78
+ /** Copy, redact, and hand one canonical event to the backend. */
79
+ private captureEvent;
80
+ /**
81
+ * Run the `session-telemetry/record` waterfall at capture time. The innermost `next`
82
+ * passes the record through unchanged — this package ships no rules; exported
83
+ * data is as clean as the listeners a deployment mounts. Callers run inside
84
+ * {@link contain}, so a throwing rule withholds the record instead of
85
+ * reaching the loop (fail-closed). On-demand capture invokes this waterfall
86
+ * while reading the canonical session log, not when the event was appended.
87
+ */
88
+ private redact;
89
+ /** Hand one redacted record to the backend, then advance its ledger cursor. */
90
+ private deliver;
91
+ /** Forward the turn-end boundary to the backend's optional flush hint. */
92
+ private hintFlush;
93
+ /** Relay one `agent/error` bus emission as an `agent-error` operational record. */
94
+ private relayAgentError;
95
+ /**
96
+ * Run one capture-side step with its exception contained: cordis `emit`
97
+ * is stop-on-throw, so a throwing listener would starve every subscriber
98
+ * registered after this plugin — nothing from the backend may escape.
99
+ */
100
+ private contain;
101
+ }
102
+ //# sourceMappingURL=coordinator.d.ts.map
@@ -0,0 +1,163 @@
1
+ /**
2
+ * SessionTelemetryBackend Service Definition for the QiLin.
3
+ *
4
+ * This package owns the CAPTURE side of session-event reporting — the complete
5
+ * one-record-per-event ledger mirror, what records carry, when
6
+ * they are captured (adoption, the per-append firehose, lifecycle
7
+ * forwarding), live versus on-demand canonical-log capture, and the HMR
8
+ * cursor. Everything downstream of
9
+ * {@link SessionTelemetryBackend.emit} — batching, retry, queueing, and loss policy — is the
10
+ * reporting SDK's territory and is deliberately not modelled here. The
11
+ * design and its trade-offs are pinned in
12
+ * .agents/notes/implemented/feature/2026-07-23-session-telemetry-otel-revival.md.
13
+ *
14
+ * @module @qilin-agent/session-telemetry
15
+ */
16
+ import { Context, Service } from '@qilin-agent/kylin';
17
+ import type { SessionEvent, SessionId } from '@qilin-agent/session';
18
+ declare module '@qilin-agent/kylin' {
19
+ interface Context {
20
+ sessionTelemetry: SessionTelemetryBackend;
21
+ }
22
+ interface Events {
23
+ /**
24
+ * Transform one outbound record before it reaches the backend. This
25
+ * waterfall is the Service Definition's redaction extension point. It ships NO rules
26
+ * of its own: the
27
+ * innermost `next()` passes the record through unchanged, and with no
28
+ * listener mounted records reach the backend as captured, so exported
29
+ * data is exactly as clean as the rules a deployment mounts. Listeners
30
+ * stack by transforming `next()`'s return value; returning without
31
+ * `next()` replaces everything beneath. Dispatched synchronously on the
32
+ * capture hot path inside the coordinator's containment: a throwing
33
+ * listener withholds that one record (fail-closed) and never reaches the
34
+ * agent loop. Live capture dispatches at append time; on-demand capture
35
+ * dispatches while reading the canonical log. Redaction applies to the
36
+ * exported copy only; the canonical session log is never rewritten.
37
+ * @param record - the candidate record, already the coordinator's own deep
38
+ * copy; listeners return a (possibly new) record and must not mutate it.
39
+ * @mode waterfall
40
+ */
41
+ 'session-telemetry/record'(record: SessionTelemetryRecord, next: () => SessionTelemetryRecord): SessionTelemetryRecord;
42
+ }
43
+ }
44
+ /**
45
+ * Severity of a telemetry record, pre-mapped at capture so a receiver can
46
+ * alert with zero configuration: `error` for events whose own outcome flag
47
+ * says so (the tool-result block's `isError`, `turn/end` error reasons) and for
48
+ * `agent-error` operational records. Captured events otherwise default to
49
+ * `info`; `warn` remains available to `session-telemetry/record` policies and
50
+ * backends.
51
+ */
52
+ export type SessionTelemetrySeverity = 'info' | 'warn' | 'error';
53
+ /**
54
+ * One logical record handed to a backend — the capture contract's whole outbound
55
+ * vocabulary. Ledger records mirror session-log events one-to-one;
56
+ * operational records (`channel: 'ops'`) carry the two signals with no log
57
+ * home (`agent-error`, `shutdown`) and deliberately omit `event.seq`-style
58
+ * identity so they can never be mistaken for ledger rows.
59
+ */
60
+ export interface SessionTelemetryRecord {
61
+ /** Canonical envelope without data; body carries the separately redacted payload. Absent for operational records. */
62
+ sourceEvent?: {
63
+ sessionId: SessionId;
64
+ envelope: Omit<SessionEvent, 'data'>;
65
+ };
66
+ /** Ledger (session-log mirror) or ops (operational signal) channel; backends keep the two under separate instrumentation scopes. */
67
+ channel: 'ledger' | 'ops';
68
+ /** Unix epoch milliseconds — the source event's append time for ledger records, the emission time for ops records. */
69
+ time: number;
70
+ /** Pre-mapped alerting severity; see {@link SessionTelemetrySeverity}. */
71
+ severity: SessionTelemetrySeverity;
72
+ /**
73
+ * Identity attributes, deliberately minimal: ledger records carry
74
+ * `session.id`, `session.format_version`, `event.type`, `event.seq`, plus optional
75
+ * `session.cwd` / `session.parent_id`; a seeded Session also carries
76
+ * `session.seed_length` from its exact inherited event count;
77
+ * ops records carry `telemetry.op`, `session.id`, and (for `agent-error`)
78
+ * `agent.id`, `turn`, `step`, `error.name`. Anything recoverable from the
79
+ * body is intentionally NOT duplicated here.
80
+ */
81
+ attributes: Record<string, string | number>;
82
+ /**
83
+ * The complete payload: a deep copy of the session event's `data` for
84
+ * ledger records (JSON-serializable by `Session.append`'s own
85
+ * validation), or the op payload for ops records. Never mutated after
86
+ * handoff.
87
+ */
88
+ body: unknown;
89
+ }
90
+ /**
91
+ * The minimum backend contract the coordinator requires. {@link SessionTelemetryBackend} is
92
+ * its service-registered form; tests compose the coordinator with a bare
93
+ * implementation of this interface.
94
+ */
95
+ export interface SessionTelemetrySink {
96
+ /**
97
+ * Hand one record to the backend's pipeline. MUST be a non-blocking
98
+ * enqueue — the coordinator calls this synchronously from the
99
+ * `session/event` hot path or an explicit canonical-log capture, so anything
100
+ * slower than a queue push would tax the agent loop or feedback handling.
101
+ * Errors thrown here are contained by the coordinator and logged; they
102
+ * never reach the loop.
103
+ * @param record - the logical record to report; owned by the backend after the call.
104
+ */
105
+ emit(record: SessionTelemetryRecord): void;
106
+ /**
107
+ * Optional hint that a turn ended. A backend may forward it to its SDK's
108
+ * flush so records are exported after each turn. Called
109
+ * fire-and-forget; implementations must not block and must not throw
110
+ * meaningfully (the coordinator contains exceptions). Most backends should
111
+ * leave this unimplemented and let their SDK's own batching cadence govern
112
+ * export timing: a backend that does implement it owns the interaction
113
+ * between its concurrent flushes and {@link shutdown}'s drain (the OTel
114
+ * backend leaves it unimplemented for exactly that hazard — see the
115
+ * revival Agent Note).
116
+ */
117
+ flush?(): void;
118
+ /**
119
+ * Forward the fiber's disposal to the SDK: flush whatever is queued and
120
+ * reach quiescence, per the SDK's own shutdown contract. Everything
121
+ * emitted before this call must still be delivered — including records
122
+ * enqueued while a {@link flush} hint is in flight, so a backend whose SDK
123
+ * guards against concurrent flushes orders behind the outstanding one (the
124
+ * coordinator emits its dispose-time `shutdown` markers immediately before
125
+ * calling this). Awaited by the coordinator's dispose; a rejection is
126
+ * logged as a warning and never fails application teardown.
127
+ * The coordinator captures dispose-time shutdown markers immediately before
128
+ * this call for live capture; on-demand capture creates no ops records.
129
+ * @returns resolves when the backend's pipeline has quiesced.
130
+ */
131
+ shutdown(): Promise<void>;
132
+ }
133
+ /**
134
+ * Deployment-selected session-sharing mode, not confirmation of SDK delivery.
135
+ */
136
+ export type SessionTelemetrySharingStatus = 'full' | 'feedback-only' | 'disabled';
137
+ /**
138
+ * Loadable form of the backend contract: one implementation per context —
139
+ * the cordis `Service` registration under the `telemetry` key throws on a
140
+ * duplicate, cordis' standard behavior. A backend composes a
141
+ * {@link SessionTelemetryCoordinator} in its constructor to install the capture side.
142
+ */
143
+ export declare abstract class SessionTelemetryBackend extends Service implements SessionTelemetrySink {
144
+ constructor(ctx: Context);
145
+ /**
146
+ * Deployment-selected sharing mode, independent of SDK delivery.
147
+ */
148
+ abstract readonly sharing: SessionTelemetrySharingStatus;
149
+ /**
150
+ * See {@link SessionTelemetrySink.emit} — that declaration is the contract's one home.
151
+ * @param record - the logical record to report; owned by the backend after the call.
152
+ */
153
+ abstract emit(record: SessionTelemetryRecord): void;
154
+ /** See {@link SessionTelemetrySink.flush}. */
155
+ flush?(): void;
156
+ /**
157
+ * See {@link SessionTelemetrySink.shutdown}.
158
+ * @returns resolves when the backend's pipeline has quiesced.
159
+ */
160
+ abstract shutdown(): Promise<void>;
161
+ }
162
+ export { SessionTelemetryCoordinator, type SessionTelemetryCapture, type SessionTelemetryCaptureOptions } from './coordinator.ts';
163
+ //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,42 @@
1
1
  {
2
2
  "name": "@qilin-agent/session-telemetry",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "description": "SessionTelemetryBackend seam for the QiLin: session-event capture, projection, redaction, and handoff to a reporting backend",
4
+ "version": "3.1.4",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/kkutysllb/QiLin.git",
11
+ "directory": "packages/session/session-telemetry"
12
+ },
13
+ "engines": {
14
+ "node": "^22.19.0 || >=24.0.0"
15
+ },
16
+ "type": "module",
17
+ "main": "lib/index.js",
18
+ "types": "lib/types/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./lib/types/index.d.ts",
22
+ "default": "./lib/index.js"
23
+ },
24
+ "./src/*": "./src/*",
25
+ "./package.json": "./package.json"
26
+ },
27
+ "files": [
28
+ "lib/index.js",
29
+ "lib/types/**/*.d.ts"
30
+ ],
31
+ "license": "MIT",
32
+ "peerDependencies": {
33
+ "@qilin-agent/kylin": "~4.0.3",
34
+ "@qilin-agent/agent": "3.1.4",
35
+ "@qilin-agent/session": "3.1.4"
36
+ },
37
+ "devDependencies": {
38
+ "@qilin-agent/kylin": "~4.0.3",
39
+ "@qilin-agent/session": "3.1.4",
40
+ "@qilin-agent/agent": "3.1.4"
41
+ }
6
42
  }