dsh-lcx-codex 0.4.3-pre.4 → 0.4.3

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.
Files changed (42) hide show
  1. package/README.md +68 -126
  2. package/THIRD_PARTY_NOTICES.md +64 -0
  3. package/lib/auxiliary-usage.js +63 -0
  4. package/lib/client.js +1363 -295
  5. package/lib/dsh-compat.js +80 -18
  6. package/lib/dsh-responses.js +75 -8
  7. package/lib/grok-native-search.js +151 -79
  8. package/lib/index.js +159 -101
  9. package/lib/invocation-policy-scope.js +261 -0
  10. package/lib/json-store.js +11 -4
  11. package/lib/pi-responses-runtime.js +1571 -0
  12. package/lib/responses-request.js +1 -1
  13. package/lib/responses-stream.js +152 -84
  14. package/lib/route.js +17 -3
  15. package/lib/search-accounting.js +86 -0
  16. package/lib/search-usage.js +86 -0
  17. package/lib/transport.js +38 -10
  18. package/lib/types/client/index.d.ts +12 -0
  19. package/lib/types/client/search-media.d.ts +16 -0
  20. package/lib/web-run-output.js +22 -0
  21. package/lib/web-search-alpha.js +230 -28
  22. package/lib/web-search-capability.js +26 -1
  23. package/lib/web-search-hosted.js +119 -9
  24. package/lib/web-search-ref-store.js +88 -7
  25. package/package.json +45 -24
  26. package/lib/types/compact-v2.d.ts +0 -104
  27. package/lib/types/dsh-compat.d.ts +0 -78
  28. package/lib/types/dsh-responses.d.ts +0 -82
  29. package/lib/types/grok-native-search.d.ts +0 -39
  30. package/lib/types/json-store.d.ts +0 -10
  31. package/lib/types/native-checkpoint.d.ts +0 -213
  32. package/lib/types/responses-request.d.ts +0 -59
  33. package/lib/types/responses-stream.d.ts +0 -64
  34. package/lib/types/route.d.ts +0 -153
  35. package/lib/types/service-mutex.d.ts +0 -14
  36. package/lib/types/token-budget.d.ts +0 -50
  37. package/lib/types/transport.d.ts +0 -21
  38. package/lib/types/web-run-output.d.ts +0 -29
  39. package/lib/types/web-search-alpha.d.ts +0 -286
  40. package/lib/types/web-search-capability.d.ts +0 -26
  41. package/lib/types/web-search-hosted.d.ts +0 -246
  42. package/lib/types/web-search-ref-store.d.ts +0 -22
package/README.md CHANGED
@@ -4,183 +4,125 @@
4
4
 
5
5
  # LCX Codex
6
6
 
7
- **为 DeepSeek Harness 中的 GPT 提供 Responses 生命周期能力,并为 Grok 接入原生 Web / X Search。**
7
+ **让 DeepSeek Harness 里的 GPT Grok 更适合长任务、联网搜索和连续工作。**
8
8
 
9
- [![npm prerelease](https://img.shields.io/npm/v/dsh-lcx-codex/prelatest?label=prelatest)](https://www.npmjs.com/package/dsh-lcx-codex)
10
- [![DSH](https://img.shields.io/badge/DSH-0.1.3--alpha.2-16803c)](#安装)
9
+ [![npm](https://img.shields.io/npm/v/dsh-lcx-codex?label=latest)](https://www.npmjs.com/package/dsh-lcx-codex)
10
+ [![DSH](https://img.shields.io/badge/DSH-0.1.5--rc.1-16803c)](#安装)
11
11
  [![License](https://img.shields.io/badge/license-MIT-555)](LICENSE)
12
12
 
13
13
  **简体中文** · [English](README_EN.md) · [更新日志](CHANGELOG.md) · [问题反馈](https://github.com/kk3ya03-star/dsh-lcx-codex/issues)
14
14
 
15
15
  </div>
16
16
 
17
- LCX Codex 是 [DeepSeek Harness](https://github.com/deepseek-ai/DeepSeek-Harness)(DSH)的社区插件。它按当前模型启用对应能力:GPT 可使用远程原生压缩、Hosted / Alpha Search;Grok 可直接使用 xAI Responses 的原生 `web_search` 与 `x_search`。其他模型继续走 DSH 原生路径。
17
+ LCX Codex 是 [DeepSeek Harness](https://github.com/deepseek-ai/DeepSeek-Harness)(DSH)的社区插件。
18
18
 
19
- 模型、接口、API Key / credential、会话和工具仍由 DSH 管理,不需要在插件里再配置一遍。GPT 与 Grok 的功能开关彼此独立;当前 Grok 原生搜索支持 API Key / API 网关调用,不包含 xAI OAuth / SuperGrok 登录。
19
+ 它不会替代 DSH,也不需要你重新配置模型、接口或 API Key。模型、凭据、会话和工具仍由 DSH 管理;LCX 只在需要时为 GPT Grok 增加额外能力。
20
20
 
21
- ## 安装
22
-
23
- 本页对应 **`0.4.3-pre.4` 预发布版**,适配 **DSH `0.1.3-alpha.2`**。稳定版仍为 `0.4.2`,使用旧版 DSH `0.1.1-rc.2` 的用户请看[稳定版说明](https://github.com/kk3ya03-star/dsh-lcx-codex/blob/v0.4.2/README.md)。
24
-
25
- 安装前,请确认 DSH Web 能正常启动,并已配置需要使用的 GPT Responses 或 Grok Responses API 路由。Node.js 要求 `^22.19.0 || >=24.0.0`;Windows 启动出现 `fs-ext` 报错时,先看下方[故障排查](#故障排查)。
26
-
27
- ```sh
28
- dsh plugin --profile web add dsh-lcx-codex@0.4.3-pre.4
29
- dsh web
30
- ```
31
-
32
- 以后升级预发布版,可执行 `dsh plugin --profile web add dsh-lcx-codex@prelatest`。不带版本或标签安装会得到稳定版,**不是本页介绍的新版本**。
33
-
34
- **从 `0.4.2` 升级:** 旧插件配置和 v3/v4 压缩检查点不再兼容,请重新配置插件并新建会话。新版 v5 GPT 检查点仍支持重启续聊。
21
+ ## 你可以用它做什么
35
22
 
36
- ## 启用
37
-
38
- 打开 DSH Web 的插件设置,展开 **Responses / Codex 能力**,按需打开开关并保存:
39
-
40
- | 开关 | 什么时候开 |
23
+ | 能力 | 适合场景 |
41
24
  | --- | --- |
42
- | 启用 LCX | 使用 GPT Responses 生命周期、Native V2 压缩及 GPT 搜索能力时。 |
43
- | GPT Hosted Search | 当前模型是 GPT,且需要普通联网查询时。 |
44
- | 高级 Hosted 工具 | GPT 需要搜图、限定网站或使用其他 Hosted 搜索条件时。 |
45
- | Alpha | GPT 需要连续 `open / find / click / screenshot` 网页操作时,属于实验功能。 |
46
- | Grok 原生 Web Search | 当前模型是 Grok,并希望使用 xAI 服务端原生网页搜索时。 |
47
- | Grok 原生 X Search | 当前模型是 Grok,并希望直接搜索 X 内容时。 |
48
-
49
- **六个开关默认均关闭。** GPT 四项由“启用 LCX”控制;Grok 两项独立,不要求打开 GPT 的 LCX 主开关。模型、推理等级、图片输入、endpoint 与 credential 都继续在 DSH 的模型/provider 配置中管理。
50
-
51
- 模型切换不需要重启插件:
25
+ | GPT 联网搜索 | GPT 直接通过 DSH `web_search` 查询网页。 |
26
+ | GPT 高级搜索 | 搜图片、限定网站、加入位置等额外搜索条件。 |
27
+ | Grok 原生 Web / X Search | 直接使用 xAI Responses Web Search 和 X Search。 |
28
+ | 长对话压缩 | GPT 长任务接近上下文上限时自动尝试远程压缩,并继续当前会话。 |
29
+ | 搜索媒体预览 | 在回答下方直接预览可用的图片和视频链接。 |
30
+ | Alpha 网页操作 | 实验性连续网页阅读能力,适合需要进一步打开、查找页面内容的任务。 |
52
31
 
53
- - GPT 只启用已打开的 GPT / LCX 能力;
54
- - Grok → 只启用已打开的原生 Web / X Search;开启任意 Grok 原生搜索时,该请求不会同时暴露 DSH `web_search`,但 `web_fetch` 和其他 DSH/MCP 工具仍可用;
55
- - Claude、Gemini、DeepSeek 等其他模型 → 保持 DSH 原生会话、搜索、工具和压缩行为。
32
+ 其他模型继续使用 DSH 原生路径,不会因为安装 LCX 而被接管。
56
33
 
57
- ## 搜索与搜图
58
-
59
- ### GPT 联网查询
60
-
61
- GPT 普通查询沿用 DSH 的单一 `web_search` 工具入口;开启 **GPT Hosted Search** 后,LCX 按当前 GPT Responses route 执行 Hosted Search。需要域名、位置、search context 或图片等额外参数时,可启用 `websearch_gpt_advanced`。
34
+ ## 安装
62
35
 
63
- 例如:
36
+ 当前稳定版:**`dsh-lcx-codex@0.4.3`**
64
37
 
65
- > 只搜索 Python 官方文档,查找 asyncio.TaskGroup 的用法。
38
+ 兼容环境:
66
39
 
67
- ### Grok 原生 Web / X Search
40
+ - DSH `0.1.5-rc.1` 起的 `0.1.5` 系列(当前完整验证基线:`0.1.5-rc.1`)
41
+ - Node.js `^22.19.0 || >=24.0.0`
68
42
 
69
- Grok 使用 xAI Responses 的服务端工具,而不是把搜索包装成 DSH function tool:
43
+ 安装:
70
44
 
71
- ```text
72
- { type: "web_search" }
73
- { type: "x_search" }
45
+ ```sh
46
+ dsh plugin --profile web add dsh-lcx-codex@0.4.3
47
+ dsh web
74
48
  ```
75
49
 
76
- 开启任意 Grok 原生搜索后,Grok 请求会移除 DSH `web_search`,避免重复搜索语义;`web_fetch`、`read` 及其他 DSH/MCP function tools 仍保持可用。原生搜索结果可以继续进入本地工具调用,再回到同一 Grok agentic workflow;插件会保存 xAI 必需的 provider-native replay state,但不会把服务端搜索伪装成 DSH 本地工具调用。
77
-
78
- 当前支持 **API Key / API Gateway** 路由;OAuth / SuperGrok / X Premium 订阅登录不在本版范围内。搜索来源 URL 会尽量保留,但具体 citation 展示形式仍受上游兼容网关返回格式影响。
79
-
80
- ### GPT 搜索图片并显示
81
-
82
- 开启高级 Hosted 工具后,可以这样说:
83
-
84
- > 搜索金门大桥的照片,选一张直接显示在回复里,并附上来源网页。
85
-
86
- **不需要自己填写 JSON 参数。** 模型负责选择图片搜索参数;如果只返回文字,可以补充“请使用高级 Hosted 的图片搜索,并把图片显示出来”。
87
-
88
- 搜索工具提供图片链接与来源,DSH 用现有的 Markdown 渲染器显示图片。这是**搜索已有图片,不是生成图片**,也不代表模型已经读取了图片像素。图片能否显示还取决于原站链接是否可访问。
89
-
90
- ### Alpha 网页操作
91
-
92
- `websearch_alpha` 支持 `search / open / find / click / screenshot` 等动作,用于 GPT 连续查阅网页。它操作的是**上游搜索服务中的网页内容**,不会操作你的本机浏览器或 DSH 界面。
50
+ 后续稳定版更新可以使用:
93
51
 
94
- Alpha 需要单独开启,且接口通过能力探测后才会出现。目前网页引用仍可能偶发失效,`screenshot` 尚未验证能返回可显示的图片。**日常 GPT 搜索/搜图和 Grok 原生搜索都不需要开启 Alpha。**
95
-
96
- ## 长对话与压缩
97
-
98
- 开启 LCX 后,插件将 DSH 的压缩请求交给上游 GPT 接口执行 **Native V2 远程原生压缩**,再将结果接回当前会话。会话保存、工具执行和压缩事务仍由 DSH 负责。
99
-
100
- | 上下文占用 | 处理方式 |
101
- | --- | --- |
102
- | 低于 `90%` | 正常对话,不提前裁剪工具结果。 |
103
- | `90%` 至 `95%` | 优先尝试远程原生压缩。 |
104
- | 达到 `95%` | 允许 DSH 紧急裁剪工具结果,再按流程压缩。 |
52
+ ```sh
53
+ dsh plugin --profile web add dsh-lcx-codex@latest
54
+ ```
105
55
 
106
- 也可以输入 `/compact` 手动压缩。这些阈值是固定策略,不需要额外设置;实际能否压缩取决于是否有可压缩的历史以及接口支持情况。
56
+ 不指定版本或使用 `@latest` 都会安装当前稳定版。需要预发布版本时可使用 `@prelatest`;`0.4.3-pre.13` 作为本次正式版之前的已验证预发布历史继续保留。
107
57
 
108
- 压缩后可以继续对话、重启恢复或切换 GPT 模型。遇到不兼容的模型或接口配置时,插件改用可迁移的历史,不会强行复用原生状态。首次建立检查点时,部分可恢复失败可以回退到 DSH 基础压缩;并非所有失败都会回退。
58
+ 本版已在官方 DSH `0.1.5-rc.1` 完整验证。后续同一 `0.1.5` 系列版本可以直接安装并进行兼容评估,不再需要仅因为 RC 版本号变化而发布新的 LCX 版本。
109
59
 
110
- ## 缓存
60
+ ## 启用功能
111
61
 
112
- 缓存由上游服务实现,插件只负责保持与当前 provider 兼容的缓存/session identity。
62
+ 打开 DSH Web 的插件设置,找到 **Responses / Codex 能力**。
113
63
 
114
- - **GPT**:延续 LCX 既有策略;前台会话与其子代理可共享父会话的 prompt-cache identity,以复用公共请求前缀。真正的 DSH Session、工具执行与私有历史仍各自独立。
115
- - **Grok**:严格跟随 DSH/Pi 原生语义;每个前台/子代理使用自己的 DSH Session ID 作为 prompt cache / session affinity identity,sibling 子代理不会共享 opaque replay state。
64
+ ### 使用 GPT
116
65
 
117
- Pi `0.85.1` 的显式缓存模式支持 `30m` 长保留参数;`cacheRetention=none` 时不发送 prompt cache key。压缩、切换模型或改变工具列表后,缓存可能需要重新建立。
66
+ 通常打开:
118
67
 
119
- ## 故障排查
68
+ 1. **启用 LCX**
69
+ 2. **GPT Hosted Search**(需要联网时)
120
70
 
121
- **DSH 在 Windows 启动时报 `fs-ext` 错误?**
71
+ 按需再打开:
122
72
 
123
- DSH `0.1.3-alpha.2` 会在启动时加载 `fs-ext`,即使 Windows 实际不使用它。当它的原生模块不可用时,DSH 会在启动阶段退出。这是 **DSH 的依赖加载问题,不是插件压缩或会话锁损坏**。
73
+ - **高级 Hosted 工具**:需要图片搜索、限定域名、位置等高级搜索条件时使用;它依赖 GPT Hosted Search。
74
+ - **Alpha**:实验性网页连续操作。日常联网搜索不需要开启。
124
75
 
125
- 本版 Windows 实测使用了一个最小 DSH 修正:仅在非 Windows 平台加载 `fs-ext`,保留原有 Win32 会话锁。插件不会自动修改 DSH;未经该修正的 Windows 环境不保证能启动。不要用关闭会话锁来绕过问题。
76
+ ### 使用 Grok
126
77
 
78
+ Grok 原生搜索与 GPT 的 LCX 主开关相互独立:
127
79
 
128
- 具体处理方法(仅适用于 `@deepseek-ai/dsh-session-persistence-jsonl@0.1.3-alpha.2`):
80
+ - **Grok 原生 Web Search**:搜索网页。
81
+ - **Grok 原生 X Search**:搜索 X 内容。
129
82
 
130
- 1. 先停止正在运行的 DSH,并从错误堆栈找到实际加载的 `@deepseek-ai/dsh-session-persistence-jsonl/lib/index.js`。不要修改其他 Node 安装或其他 DSH 副本。全局安装通常在 `npm root -g` 返回目录中的 DSH 依赖树内;以堆栈的绝对路径为准。
131
- 2. 检查该包相邻的 `package.json`,确认版本为 `0.1.3-alpha.2`,并把 `lib/index.js` 复制为 `lib/index.js.before-win32-fs-ext.bak`;备份已存在时保留它。
132
- 3. 用编辑器将下面唯一一行:
83
+ 开启 Grok 原生搜索后,LCX 会使用 xAI 的服务端搜索能力,同时保留页面读取和其他 DSH / MCP 工具。
133
84
 
134
- ```js
135
- import { flock } from "fs-ext";
136
- ```
85
+ ### 搜索媒体预览
137
86
 
138
- 替换为:
87
+ **搜索媒体预览**可以独立开启。它只改变回答的显示方式,不会修改模型提示词、搜索请求、聊天历史或缓存。
139
88
 
140
- ```js
141
- const flock = process.platform === "win32"
142
- ? undefined
143
- : (await import("fs-ext")).flock;
144
- ```
89
+ 可识别的图片会显示缩略图并支持放大;直接视频链接可以点击播放。媒体加载失败时,原来的文字和链接仍会保留。
145
90
 
146
- 只改模块加载这一处,保留其余代码和 Win32 会话锁。如果版本或原始行不符,请停止套用此修正。
147
- 4. 保存后重新运行 `dsh web`,新建会话并发送一条消息,确认启动和会话写入正常。此修正不保证解决其他启动错误。
148
- 5. 恢复时先停止 DSH,再用备份覆盖 `index.js`。重新安装或升级 DSH 可能覆盖此本地修改;不要把这个旧版本修正直接套到新版本。
91
+ ## 常见用法
149
92
 
150
- 这是一项用户自行选择的 DSH 本地兼容修正,不是插件安装步骤自动执行的补丁。项目的 Windows 验证使用的正是上述加载方式。
93
+ 直接像平时一样和模型说话,不需要手写工具参数。例如:
151
94
 
152
- **安装后没有变化?**
95
+ > 搜索 Python 官方文档,告诉我 `asyncio.TaskGroup` 应该怎么用。
153
96
 
154
- 检查安装和启动是否使用同一个 `web` 配置,并确认对应模型的开关已保存。GPT 主开关与 Grok Web/X 开关彼此独立。
97
+ > 搜索几张金门大桥的照片,显示一张,并给我来源网页。
155
98
 
156
- **对话正常,但搜索或压缩失败?**
99
+ > 用 Grok 搜一下 X 上最近关于这个项目的讨论。
157
100
 
158
- 普通 Responses 对话可用,不代表接口同时支持 Native V2、Hosted/Alpha Grok 原生 Web/X Search。请确认当前通道提供对应服务端能力;Sub2API、NewAPI 或其他网关名称本身不是能力保证。
101
+ 长任务也不需要自己盯着上下文。启用 LCX 后,兼容的 GPT 路由会在对话变得很长时自动尝试远程压缩并继续工作;你也可以使用 `/compact` 手动压缩。
159
102
 
160
- ## 版本与验证范围
103
+ ## 兼容性与已知限制
161
104
 
162
- 本版使用 DSH `0.1.3-alpha.2`、DSH host Pi `0.85.1` 和插件 Pi `0.85.1`。插件单独声明 Pi 依赖,不替换 DSH 的依赖。
105
+ - `0.4.3` 的当前完整验证基线是 DSH `0.1.5-rc.1`。同一 `0.1.5` 系列后续版本处于可安装、可评估范围,但仍会单独记录兼容验证结果;`0.1.6` 及更高版本不会自动视为兼容。
106
+ - 从较旧的 LCX / DSH 版本升级时,建议新建会话;旧版保存的压缩状态不保证兼容。
107
+ - Grok 原生搜索支持 API Key / API 网关路由;xAI OAuth / SuperGrok 登录不在当前范围。
108
+ - Alpha 仍是实验功能。搜索可以正常使用,但连续 `open / find` 等操作在部分路由上仍可能失败;截图也不保证能作为可显示图片返回。
109
+ - 修改 DSH profile 中的插件启用状态后,已经打开的浏览器页面可能需要刷新。
110
+ - 不同 API 网关支持的能力可能不同。普通聊天可用,不代表搜索、长对话压缩或 Alpha 等功能也一定可用。
163
111
 
164
- 本版两项展示修复已通过流式/非流式和冷恢复回归;以下真实运行覆盖继承自 pre.3,不代表重新执行了全部在线测试。
112
+ ## 遇到问题
165
113
 
166
- 发布前完整测试为 **243/243 PASS**,strict host/client typecheck 与 4 个 DSH schema 均通过。真实运行覆盖 GPT Hosted/Native V2 回归、DeepSeek 原生 DSH 搜索回归,以及 Grok 4.5/4.6 原生 Web/X Search、Web/X → 本地 `read` → continuation、provider-native replay、完整 DSH 重启后的续聊、Grok 父/子代理 session/cache 隔离。GPT 已验证的父 cache-sharing 策略保持不变。
114
+ **安装后看不到变化**:确认安装和启动使用的是同一个 `web` profile,并检查对应功能开关是否已经保存。
167
115
 
168
- 仍需保留的预发布限制:Windows DSH `0.1.3-alpha.2` 的 `fs-ext` 启动问题需要文档中的最小 host loading 修正;Alpha 引用及 screenshot 展示、代理/NO_PROXY、更广的并发/取消和后台 continuable subagent 矩阵仍未全面覆盖;Grok OAuth 不支持,citation 渲染仍可能受上游网关格式影响。详细变更见 [v0.4.3-pre.4 发布说明](https://github.com/kk3ya03-star/dsh-lcx-codex/releases/tag/v0.4.3-pre.4)。
116
+ **对话正常,但搜索或压缩失败**:先确认当前 GPT / Grok Responses 路由确实提供对应服务端能力。网关名称本身不代表一定支持所有功能。
169
117
 
170
- ## 开发与反馈
118
+ 提交 [Issue](https://github.com/kk3ya03-star/dsh-lcx-codex/issues) 时,请附上插件版本、DSH 版本、Node.js 版本和复现步骤。不要上传 API Key、完整请求或未脱敏的会话日志。
171
119
 
172
- ```sh
173
- npm ci --ignore-scripts
174
- npm ci --prefix scripts/runtime-alpha2 --ignore-scripts
175
- node scripts/link-dsh-runtime.mjs scripts/runtime-alpha2
176
- node scripts/check-generated.mjs
177
- npm run typecheck
178
- npm test
179
- npm run test:schema
180
- ```
120
+ ## 更多信息
181
121
 
182
- 实现细节见[架构说明](ARCHITECTURE.md)。提交 [Issue](https://github.com/kk3ya03-star/dsh-lcx-codex/issues) 时,请附上插件、DSH、Node.js 版本及复现步骤,不要上传 API Key、完整请求或未脱敏的会话日志。
122
+ - [更新日志](CHANGELOG.md)
123
+ - [架构说明](ARCHITECTURE.md)
124
+ - [第三方许可](THIRD_PARTY_NOTICES.md)
183
125
 
184
126
  ## 许可证
185
127
 
186
- [MIT](LICENSE)。独立社区插件,与 OpenAI、DeepSeek、Sub2API、NewAPI 无隶属或官方背书关系。DeepSeek 名称及标识归其权利人所有。
128
+ [MIT](LICENSE)。独立社区插件,与 OpenAI、DeepSeek、Sub2API、NewAPI 无隶属或官方背书关系。
@@ -0,0 +1,64 @@
1
+ # Third-party notices
2
+
3
+ `lib/pi-responses-runtime.js` is generated from public exports of the packages below. The build recipe in `scripts/build-pi-runtime.mjs` verifies that no other third-party package contributes output bytes.
4
+
5
+ ## @earendil-works/pi-ai 0.85.1
6
+
7
+ Upstream source: https://github.com/earendil-works/pi/tree/v0.85.1/packages/ai
8
+
9
+ Included public Responses helpers and model catalogs:
10
+
11
+ - `api/openai-responses-shared`
12
+ - `api/constrained-sampling`
13
+ - `api/openai-prompt-cache`
14
+ - `utils/event-stream`
15
+ - model helpers from the package root
16
+ - Responses-bearing catalogs for `cloudflare-ai-gateway`, `github-copilot`, `openai`, `opencode`, `opencode-go`, and `xai`
17
+
18
+ MIT License
19
+
20
+ Copyright (c) 2025 Mario Zechner
21
+
22
+ Permission is hereby granted, free of charge, to any person obtaining a copy
23
+ of this software and associated documentation files (the "Software"), to deal
24
+ in the Software without restriction, including without limitation the rights
25
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26
+ copies of the Software, and to permit persons to whom the Software is
27
+ furnished to do so, subject to the following conditions:
28
+
29
+ The above copyright notice and this permission notice shall be included in all
30
+ copies or substantial portions of the Software.
31
+
32
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38
+ SOFTWARE.
39
+
40
+ ## partial-json 0.1.7
41
+
42
+ Upstream source: https://github.com/promplate/partial-json-parser-js
43
+
44
+ MIT License
45
+
46
+ Copyright (c) 2023 Promplate Dev Team
47
+
48
+ Permission is hereby granted, free of charge, to any person obtaining a copy
49
+ of this software and associated documentation files (the "Software"), to deal
50
+ in the Software without restriction, including without limitation the rights
51
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
52
+ copies of the Software, and to permit persons to whom the Software is
53
+ furnished to do so, subject to the following conditions:
54
+
55
+ The above copyright notice and this permission notice shall be included in all
56
+ copies or substantial portions of the Software.
57
+
58
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
64
+ SOFTWARE.
@@ -0,0 +1,63 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ const calls = new AsyncLocalStorage();
3
+ const object = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
4
+ const count = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
5
+ /** Collect only authoritative Responses billing, independently of context size. */
6
+ export function recordHostedUsage(response, requestId, provider, model) {
7
+ const store = calls.getStore();
8
+ if (!store || !object(response) || !object(response.usage))
9
+ return;
10
+ const u = response.usage;
11
+ const input = u.input_tokens, output = u.output_tokens, total = u.total_tokens;
12
+ const cached = object(u.input_tokens_details) ? u.input_tokens_details.cached_tokens : undefined;
13
+ if (!count(input) || !count(output) || !count(total) || !count(cached)
14
+ || cached > input || input + output !== total)
15
+ return;
16
+ store.push({ requestId, provider, model, usage: {
17
+ inputTokens: input - cached, outputTokens: output, totalTokens: total,
18
+ cacheReadTokens: cached, cacheWriteTokens: 0,
19
+ } });
20
+ }
21
+ /** Extend only LCX-owned search output; rendering and request schemas stay intact. */
22
+ export function withAuxiliaryUsage(tool) {
23
+ const schema = tool.output.schema;
24
+ if (schema.type !== "object")
25
+ throw new Error("Search accounting requires an object output");
26
+ return {
27
+ ...tool,
28
+ output: {
29
+ ...tool.output,
30
+ schema: { ...schema, properties: { ...schema.properties, auxiliaryUsage: {
31
+ type: "array", items: { type: "object", additionalProperties: true },
32
+ } } },
33
+ render(args, value) {
34
+ if (!object(value))
35
+ return tool.output.render(args, value);
36
+ const { auxiliaryUsage: _billing, ...original } = value;
37
+ return tool.output.render(args, original);
38
+ },
39
+ presentationMeta(args, value) {
40
+ if (!object(value))
41
+ return tool.output.presentationMeta?.(args, value) ?? {};
42
+ const { auxiliaryUsage, ...original } = value;
43
+ const meta = tool.output.presentationMeta?.(args, original) ?? {};
44
+ if (!Array.isArray(auxiliaryUsage) || auxiliaryUsage.length === 0)
45
+ return meta;
46
+ if (!object(meta))
47
+ throw new Error("Search accounting requires object presentation metadata");
48
+ return { ...meta, auxiliaryUsage };
49
+ },
50
+ },
51
+ async execute(args, exec) {
52
+ const records = [];
53
+ return calls.run(records, async () => {
54
+ const value = await tool.execute(args, exec);
55
+ if (records.length === 0)
56
+ return value;
57
+ if (!object(value))
58
+ throw new Error("Search accounting requires an object result");
59
+ return { ...value, auxiliaryUsage: records };
60
+ });
61
+ },
62
+ };
63
+ }