@dsh-edge/dsh-edge-agent 0.0.0-stage → 0.1.1

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 (238) hide show
  1. package/CHANGELOG.md +142 -0
  2. package/LICENSE +21 -0
  3. package/README.md +372 -2
  4. package/config/edge.example.json +179 -0
  5. package/config/privacy-policy.json +202 -0
  6. package/cordis.desktop-safe.patch.yml +129 -0
  7. package/cordis.patch.yml +382 -0
  8. package/cordis.yml +374 -0
  9. package/lib/attestation.d.ts +2 -0
  10. package/lib/attestation.d.ts.map +1 -0
  11. package/lib/attestation.js +2 -0
  12. package/lib/audit-log.d.ts +2 -0
  13. package/lib/audit-log.d.ts.map +1 -0
  14. package/lib/audit-log.js +2 -0
  15. package/lib/client.js +87 -0
  16. package/lib/cloud-llm-adapter.d.ts +2 -0
  17. package/lib/cloud-llm-adapter.d.ts.map +1 -0
  18. package/lib/cloud-llm-adapter.js +2 -0
  19. package/lib/dsh-adapter/attestation.d.ts +42 -0
  20. package/lib/dsh-adapter/attestation.d.ts.map +1 -0
  21. package/lib/dsh-adapter/attestation.js +40 -0
  22. package/lib/dsh-adapter/audit-log.d.ts +139 -0
  23. package/lib/dsh-adapter/audit-log.d.ts.map +1 -0
  24. package/lib/dsh-adapter/audit-log.js +376 -0
  25. package/lib/dsh-adapter/cloud-egress.d.ts +181 -0
  26. package/lib/dsh-adapter/cloud-egress.d.ts.map +1 -0
  27. package/lib/dsh-adapter/cloud-egress.js +257 -0
  28. package/lib/dsh-adapter/cloud-llm-adapter.d.ts +416 -0
  29. package/lib/dsh-adapter/cloud-llm-adapter.d.ts.map +1 -0
  30. package/lib/dsh-adapter/cloud-llm-adapter.js +1472 -0
  31. package/lib/dsh-adapter/contract.d.ts +80 -0
  32. package/lib/dsh-adapter/contract.d.ts.map +1 -0
  33. package/lib/dsh-adapter/contract.js +194 -0
  34. package/lib/dsh-adapter/desktop-cookie-janitor.d.ts +214 -0
  35. package/lib/dsh-adapter/desktop-cookie-janitor.d.ts.map +1 -0
  36. package/lib/dsh-adapter/desktop-cookie-janitor.js +409 -0
  37. package/lib/dsh-adapter/dsh-edge-agent.d.ts +48 -0
  38. package/lib/dsh-adapter/dsh-edge-agent.d.ts.map +1 -0
  39. package/lib/dsh-adapter/dsh-edge-agent.js +64 -0
  40. package/lib/dsh-adapter/edge-config.d.ts +484 -0
  41. package/lib/dsh-adapter/edge-config.d.ts.map +1 -0
  42. package/lib/dsh-adapter/edge-config.js +898 -0
  43. package/lib/dsh-adapter/edge-context-view.d.ts +184 -0
  44. package/lib/dsh-adapter/edge-context-view.d.ts.map +1 -0
  45. package/lib/dsh-adapter/edge-context-view.js +483 -0
  46. package/lib/dsh-adapter/effective-model.d.ts +85 -0
  47. package/lib/dsh-adapter/effective-model.d.ts.map +1 -0
  48. package/lib/dsh-adapter/effective-model.js +171 -0
  49. package/lib/dsh-adapter/etscli-shell-guard.d.ts +244 -0
  50. package/lib/dsh-adapter/etscli-shell-guard.d.ts.map +1 -0
  51. package/lib/dsh-adapter/etscli-shell-guard.js +420 -0
  52. package/lib/dsh-adapter/etscli-tools.d.ts +112 -0
  53. package/lib/dsh-adapter/etscli-tools.d.ts.map +1 -0
  54. package/lib/dsh-adapter/etscli-tools.js +393 -0
  55. package/lib/dsh-adapter/file-logger.d.ts +294 -0
  56. package/lib/dsh-adapter/file-logger.d.ts.map +1 -0
  57. package/lib/dsh-adapter/file-logger.js +564 -0
  58. package/lib/dsh-adapter/function-call-external.d.ts +357 -0
  59. package/lib/dsh-adapter/function-call-external.d.ts.map +1 -0
  60. package/lib/dsh-adapter/function-call-external.js +1005 -0
  61. package/lib/dsh-adapter/host-egress-guard.d.ts +161 -0
  62. package/lib/dsh-adapter/host-egress-guard.d.ts.map +1 -0
  63. package/lib/dsh-adapter/host-egress-guard.js +213 -0
  64. package/lib/dsh-adapter/host-llm-trace.d.ts +198 -0
  65. package/lib/dsh-adapter/host-llm-trace.d.ts.map +1 -0
  66. package/lib/dsh-adapter/host-llm-trace.js +344 -0
  67. package/lib/dsh-adapter/http-api-routes.d.ts +61 -0
  68. package/lib/dsh-adapter/http-api-routes.d.ts.map +1 -0
  69. package/lib/dsh-adapter/http-api-routes.js +79 -0
  70. package/lib/dsh-adapter/http-api-sessions.d.ts +105 -0
  71. package/lib/dsh-adapter/http-api-sessions.d.ts.map +1 -0
  72. package/lib/dsh-adapter/http-api-sessions.js +173 -0
  73. package/lib/dsh-adapter/http-api.d.ts +221 -0
  74. package/lib/dsh-adapter/http-api.d.ts.map +1 -0
  75. package/lib/dsh-adapter/http-api.js +1811 -0
  76. package/lib/dsh-adapter/index.d.ts +62 -0
  77. package/lib/dsh-adapter/index.d.ts.map +1 -0
  78. package/lib/dsh-adapter/index.js +97 -0
  79. package/lib/dsh-adapter/input-guard-messages.d.ts +56 -0
  80. package/lib/dsh-adapter/input-guard-messages.d.ts.map +1 -0
  81. package/lib/dsh-adapter/input-guard-messages.js +136 -0
  82. package/lib/dsh-adapter/input-guard.d.ts +508 -0
  83. package/lib/dsh-adapter/input-guard.d.ts.map +1 -0
  84. package/lib/dsh-adapter/input-guard.js +2174 -0
  85. package/lib/dsh-adapter/intent-prompts.d.ts +77 -0
  86. package/lib/dsh-adapter/intent-prompts.d.ts.map +1 -0
  87. package/lib/dsh-adapter/intent-prompts.js +97 -0
  88. package/lib/dsh-adapter/intent-router.d.ts +710 -0
  89. package/lib/dsh-adapter/intent-router.d.ts.map +1 -0
  90. package/lib/dsh-adapter/intent-router.js +2802 -0
  91. package/lib/dsh-adapter/intent-signals.d.ts +208 -0
  92. package/lib/dsh-adapter/intent-signals.d.ts.map +1 -0
  93. package/lib/dsh-adapter/intent-signals.js +391 -0
  94. package/lib/dsh-adapter/invariant-install.d.ts +16 -0
  95. package/lib/dsh-adapter/invariant-install.d.ts.map +1 -0
  96. package/lib/dsh-adapter/invariant-install.js +15 -0
  97. package/lib/dsh-adapter/invariant.d.ts +16 -0
  98. package/lib/dsh-adapter/invariant.d.ts.map +1 -0
  99. package/lib/dsh-adapter/invariant.js +22 -0
  100. package/lib/dsh-adapter/llm-adapters.d.ts +19 -0
  101. package/lib/dsh-adapter/llm-adapters.d.ts.map +1 -0
  102. package/lib/dsh-adapter/llm-adapters.js +16 -0
  103. package/lib/dsh-adapter/llm-internal-caller.d.ts +92 -0
  104. package/lib/dsh-adapter/llm-internal-caller.d.ts.map +1 -0
  105. package/lib/dsh-adapter/llm-internal-caller.js +100 -0
  106. package/lib/dsh-adapter/llm-max-turns.d.ts +55 -0
  107. package/lib/dsh-adapter/llm-max-turns.d.ts.map +1 -0
  108. package/lib/dsh-adapter/llm-max-turns.js +127 -0
  109. package/lib/dsh-adapter/llm-trace-store.d.ts +131 -0
  110. package/lib/dsh-adapter/llm-trace-store.d.ts.map +1 -0
  111. package/lib/dsh-adapter/llm-trace-store.js +205 -0
  112. package/lib/dsh-adapter/llm-trace.d.ts +450 -0
  113. package/lib/dsh-adapter/llm-trace.d.ts.map +1 -0
  114. package/lib/dsh-adapter/llm-trace.js +463 -0
  115. package/lib/dsh-adapter/local-llm-adapter.d.ts +141 -0
  116. package/lib/dsh-adapter/local-llm-adapter.d.ts.map +1 -0
  117. package/lib/dsh-adapter/local-llm-adapter.js +787 -0
  118. package/lib/dsh-adapter/local-storage.d.ts +96 -0
  119. package/lib/dsh-adapter/local-storage.d.ts.map +1 -0
  120. package/lib/dsh-adapter/local-storage.js +198 -0
  121. package/lib/dsh-adapter/model-router.d.ts +79 -0
  122. package/lib/dsh-adapter/model-router.d.ts.map +1 -0
  123. package/lib/dsh-adapter/model-router.js +107 -0
  124. package/lib/dsh-adapter/ohttp-gateway.d.ts +49 -0
  125. package/lib/dsh-adapter/ohttp-gateway.d.ts.map +1 -0
  126. package/lib/dsh-adapter/ohttp-gateway.js +32 -0
  127. package/lib/dsh-adapter/openai-sse.d.ts +85 -0
  128. package/lib/dsh-adapter/openai-sse.d.ts.map +1 -0
  129. package/lib/dsh-adapter/openai-sse.js +462 -0
  130. package/lib/dsh-adapter/pii-utils.d.ts +96 -0
  131. package/lib/dsh-adapter/pii-utils.d.ts.map +1 -0
  132. package/lib/dsh-adapter/pii-utils.js +324 -0
  133. package/lib/dsh-adapter/plugin-host.d.ts +38 -0
  134. package/lib/dsh-adapter/plugin-host.d.ts.map +1 -0
  135. package/lib/dsh-adapter/plugin-host.js +38 -0
  136. package/lib/dsh-adapter/plugin.d.ts +46 -0
  137. package/lib/dsh-adapter/plugin.d.ts.map +1 -0
  138. package/lib/dsh-adapter/plugin.js +100 -0
  139. package/lib/dsh-adapter/privacy-policy.d.ts +237 -0
  140. package/lib/dsh-adapter/privacy-policy.d.ts.map +1 -0
  141. package/lib/dsh-adapter/privacy-policy.js +391 -0
  142. package/lib/dsh-adapter/prompt-guard.d.ts +152 -0
  143. package/lib/dsh-adapter/prompt-guard.d.ts.map +1 -0
  144. package/lib/dsh-adapter/prompt-guard.js +872 -0
  145. package/lib/dsh-adapter/realm-skill-bridge.d.ts +365 -0
  146. package/lib/dsh-adapter/realm-skill-bridge.d.ts.map +1 -0
  147. package/lib/dsh-adapter/realm-skill-bridge.js +1180 -0
  148. package/lib/dsh-adapter/sanitizer-pipeline.d.ts +140 -0
  149. package/lib/dsh-adapter/sanitizer-pipeline.d.ts.map +1 -0
  150. package/lib/dsh-adapter/sanitizer-pipeline.js +431 -0
  151. package/lib/dsh-adapter/secure-bridge.d.ts +47 -0
  152. package/lib/dsh-adapter/secure-bridge.d.ts.map +1 -0
  153. package/lib/dsh-adapter/secure-bridge.js +35 -0
  154. package/lib/dsh-adapter/session-attribution.d.ts +70 -0
  155. package/lib/dsh-adapter/session-attribution.d.ts.map +1 -0
  156. package/lib/dsh-adapter/session-attribution.js +76 -0
  157. package/lib/dsh-adapter/sessions.d.ts +86 -0
  158. package/lib/dsh-adapter/sessions.d.ts.map +1 -0
  159. package/lib/dsh-adapter/sessions.js +179 -0
  160. package/lib/dsh-adapter/tcm.d.ts +55 -0
  161. package/lib/dsh-adapter/tcm.d.ts.map +1 -0
  162. package/lib/dsh-adapter/tcm.js +94 -0
  163. package/lib/dsh-adapter/td-bus.d.ts +87 -0
  164. package/lib/dsh-adapter/td-bus.d.ts.map +1 -0
  165. package/lib/dsh-adapter/td-bus.js +196 -0
  166. package/lib/dsh-adapter/tool-runner.d.ts +185 -0
  167. package/lib/dsh-adapter/tool-runner.d.ts.map +1 -0
  168. package/lib/dsh-adapter/tool-runner.js +271 -0
  169. package/lib/dsh-adapter/tools.d.ts +118 -0
  170. package/lib/dsh-adapter/tools.d.ts.map +1 -0
  171. package/lib/dsh-adapter/tools.js +292 -0
  172. package/lib/dsh-adapter/types.d.ts +23 -0
  173. package/lib/dsh-adapter/types.d.ts.map +1 -0
  174. package/lib/dsh-adapter/types.js +16 -0
  175. package/lib/dsh-adapter/voice-input.d.ts +30 -0
  176. package/lib/dsh-adapter/voice-input.d.ts.map +1 -0
  177. package/lib/dsh-adapter/voice-input.js +34 -0
  178. package/lib/dsh-adapter/web-search-tavily-bocha.d.ts +152 -0
  179. package/lib/dsh-adapter/web-search-tavily-bocha.d.ts.map +1 -0
  180. package/lib/dsh-adapter/web-search-tavily-bocha.js +289 -0
  181. package/lib/http-api.d.ts +2 -0
  182. package/lib/http-api.d.ts.map +1 -0
  183. package/lib/http-api.js +2 -0
  184. package/lib/index.d.ts +48 -0
  185. package/lib/index.d.ts.map +1 -0
  186. package/lib/index.js +49 -0
  187. package/lib/intent-router.d.ts +2 -0
  188. package/lib/intent-router.d.ts.map +1 -0
  189. package/lib/intent-router.js +2 -0
  190. package/lib/llm-adapters.d.ts +2 -0
  191. package/lib/llm-adapters.d.ts.map +1 -0
  192. package/lib/llm-adapters.js +2 -0
  193. package/lib/local-llm-adapter.d.ts +2 -0
  194. package/lib/local-llm-adapter.d.ts.map +1 -0
  195. package/lib/local-llm-adapter.js +2 -0
  196. package/lib/local-storage.d.ts +2 -0
  197. package/lib/local-storage.d.ts.map +1 -0
  198. package/lib/local-storage.js +2 -0
  199. package/lib/model-router.d.ts +2 -0
  200. package/lib/model-router.d.ts.map +1 -0
  201. package/lib/model-router.js +2 -0
  202. package/lib/ohttp-gateway.d.ts +2 -0
  203. package/lib/ohttp-gateway.d.ts.map +1 -0
  204. package/lib/ohttp-gateway.js +2 -0
  205. package/lib/plugin-host.d.ts +2 -0
  206. package/lib/plugin-host.d.ts.map +1 -0
  207. package/lib/plugin-host.js +2 -0
  208. package/lib/privacy-policy.d.ts +2 -0
  209. package/lib/privacy-policy.d.ts.map +1 -0
  210. package/lib/privacy-policy.js +2 -0
  211. package/lib/prompt-guard.d.ts +2 -0
  212. package/lib/prompt-guard.d.ts.map +1 -0
  213. package/lib/prompt-guard.js +2 -0
  214. package/lib/sanitizer-pipeline.d.ts +2 -0
  215. package/lib/sanitizer-pipeline.d.ts.map +1 -0
  216. package/lib/sanitizer-pipeline.js +2 -0
  217. package/lib/secure-bridge.d.ts +2 -0
  218. package/lib/secure-bridge.d.ts.map +1 -0
  219. package/lib/secure-bridge.js +2 -0
  220. package/lib/sessions.d.ts +2 -0
  221. package/lib/sessions.d.ts.map +1 -0
  222. package/lib/sessions.js +2 -0
  223. package/lib/tcm.d.ts +2 -0
  224. package/lib/tcm.d.ts.map +1 -0
  225. package/lib/tcm.js +2 -0
  226. package/lib/td-bus.d.ts +2 -0
  227. package/lib/td-bus.d.ts.map +1 -0
  228. package/lib/td-bus.js +2 -0
  229. package/lib/tools.d.ts +2 -0
  230. package/lib/tools.d.ts.map +1 -0
  231. package/lib/tools.js +2 -0
  232. package/lib/voice-input.d.ts +2 -0
  233. package/lib/voice-input.d.ts.map +1 -0
  234. package/lib/voice-input.js +2 -0
  235. package/package.json +341 -3
  236. package/presets/agent-preset-edge.json +50 -0
  237. package/presets/edge.desktop-safe.patch.yml +503 -0
  238. package/presets/edge.patch.yml +557 -0
@@ -0,0 +1,463 @@
1
+ /**
2
+ * llm-trace — 详细的 LLM request / response 追踪,写进 ops log。
3
+ *
4
+ * ## 为什么需要这个模块
5
+ *
6
+ * 现状(§7.118, 2026-10-26):adapters 只在 ops log 里记**长度**——
7
+ * `promptLen=121853 systemLen=225 resultLen=5006`。真正想看"到底发了什么、
8
+ * 回了什么"的时候,唯一去处是把 `DSH_EDGE_LOG_LEVEL` 降到 `debug`,而
9
+ * `LLM_MESSAGES` / `LLM_RESPONSE_TEXT` 那两条全量 dump 才会出现:
10
+ *
11
+ * - 全量 dump 没有脱敏 → 用户原文、工具回显、可能夹带的凭据直接落盘;
12
+ * - 全量 dump 没有截断 → 一条 120KB 的 prompt 能撑爆一行日志;
13
+ * - `debug` 级别默认被压制 → 运维默认看不到,而需要看的人往往是在出事之后。
14
+ *
15
+ * 这个模块把"详细"拆成三个**可独立关闭**的维度,并给每一维加上硬边界:
16
+ *
17
+ * 1. **脱敏**(`redactPii` / `redactSecrets`)——PII 走 `pii-utils` 的
18
+ * 10 类规则,凭据走本模块自己的密钥掩码(`pii-utils` 的 api-key 规则
19
+ * 匹配不到 `sk-cp-` / `tvly-` 这类带前缀的厂商密钥,见
20
+ * `SECRET_PATTERNS`)。
21
+ * 2. **截断**(`maxChars` / `maxMessages`)——每个字段独立上限,且**截断
22
+ * 必须显式可见**(`truncated: true` + `…[+N chars]`),绝不让"日志里
23
+ * 看起来是完整的"成为可能。
24
+ * 3. **分级**(`includeRequest` / `includeResponse`)——只要 request 或
25
+ * 只要 response,各自可关。
26
+ *
27
+ * ## 落盘位置
28
+ *
29
+ * 走 `ctx.logger.info` —— 即 ops log 的默认级别。**不是** debug:运维在
30
+ * 出事后 tail 的是 ops log,不是 debug 日志。
31
+ *
32
+ * ## 安全边界
33
+ *
34
+ * - 本模块**不**写明文密钥:`authorization` 头、`apiKey` 参数一律不进 trace。
35
+ * - 本模块**不**改变任何出网行为:它只在本地组装一个日志对象。
36
+ * - 本模块对畸形输入**永不抛错**:trace 是观测手段,不能把主链路带崩。
37
+ *
38
+ * @module dsh-edge-agent/llm-trace
39
+ */
40
+ import { redactString } from './pii-utils.js';
41
+ import { nextTraceId } from './llm-trace-store.js';
42
+ import { realSessionId } from './session-attribution.js';
43
+ /**
44
+ * 出厂默认。
45
+ *
46
+ * `maxChars=2000` 的取舍:一条 message 的正文通常在几百字,2000 足够看清
47
+ * 上下文;整轮 12 条 message × 2000 字 ≈ 24KB 一行,日志文件按 50MB 轮转,
48
+ * 完全可控。想看全量请走 `DSH_EDGE_LOG_LEVEL=debug` 的旧通道,不要把这个值
49
+ * 调到很大 —— 那是拿磁盘换眼睛。
50
+ */
51
+ export const DEFAULT_LLM_TRACE_CONFIG = {
52
+ enabled: true,
53
+ includeRequest: true,
54
+ includeResponse: true,
55
+ maxChars: 2000,
56
+ maxMessages: 12,
57
+ maxBodyChars: 20000,
58
+ redactPii: true,
59
+ redactSecrets: true,
60
+ };
61
+ /**
62
+ * 从 `config/edge.json` 解析 trace 配置。
63
+ *
64
+ * 缺省逐字段回落到 `DEFAULT_LLM_TRACE_CONFIG`;`maxChars<=0` 视为"不截断"
65
+ * 但会在 trace 里标注 `truncated:false`,让读日志的人知道这是显式选择。
66
+ */
67
+ export function resolveLlmTraceConfig(cfg) {
68
+ const raw = cfg?.audit?.llmTrace;
69
+ if (!raw)
70
+ return { ...DEFAULT_LLM_TRACE_CONFIG };
71
+ const pick = (k) => raw[k] === undefined ? DEFAULT_LLM_TRACE_CONFIG[k] : raw[k];
72
+ return {
73
+ enabled: pick('enabled'),
74
+ includeRequest: pick('includeRequest'),
75
+ includeResponse: pick('includeResponse'),
76
+ maxChars: pick('maxChars'),
77
+ maxMessages: pick('maxMessages'),
78
+ maxBodyChars: pick('maxBodyChars'),
79
+ redactPii: pick('redactPii'),
80
+ redactSecrets: pick('redactSecrets'),
81
+ };
82
+ }
83
+ /* ── 凭据掩码 ───────────────────────────────────────────────────────────── */
84
+ /**
85
+ * 凭据字面量掩码(不依赖 pii-utils)。
86
+ *
87
+ * `pii-utils` 的 `api-key` 规则是
88
+ * `sk-(?:proj-|ant-|live-|test-|org-)?[a-zA-Z0-9]{20,}`,它**匹配不到**
89
+ * 厂商自定义前缀的密钥:`sk-cp-…`(MiniMax)在 `cp-` 处断了,且下一段含
90
+ * `_` 也不在字符类里;`tvly-…`(Tavily)、`sk-ws-…`(DashScope)同理。
91
+ * 实测 `config/edge.json` 里的三把真 key 全部逃逸。
92
+ *
93
+ * 所以这里独立覆盖"厂商前缀 + 通用形态"两类,并加两条**收敛条件**避免误伤
94
+ * 普通英文词:
95
+ *
96
+ * - 厂商前缀密钥要求"长度 ≥16 **且** 至少含一个数字"。真密钥几乎必然带
97
+ * 数字;而 `key-representation`、`api-key-description` 这类正常词不含
98
+ * 数字,不会被误掩。字符类放宽到 `[A-Za-z0-9._-]`(含 `.`),否则
99
+ * DashScope 的 `sk-ws-EXAMPLE0.dot0.…`(JWS 风格带点)会在第一个
100
+ * 点处断掉而逃逸。
101
+ * - 另加一条全大写形态(`tvly-PLACEHOLDER_REPLACE_ME`),这类占位符不含
102
+ * 数字但仍是凭据位。
103
+ */
104
+ export const SECRET_PATTERNS = [
105
+ // Authorization / Bearer 头:整个 token 换成固定掩码。
106
+ { name: 'bearer', pattern: /\b(Bearer|Basic)\s+[A-Za-z0-9._~+/=-]{8,}/gi },
107
+ // 厂商前缀密钥(含数字):sk-cp-… / sk-ws-… / xai-… / pk-…
108
+ {
109
+ name: 'vendor-key',
110
+ pattern: /\b(?:sk|key|pk|tvly|xai|rk|ak)[-_](?=[A-Za-z0-9._-]*\d)[A-Za-z0-9._-]{16,}/gi,
111
+ },
112
+ // 厂商前缀密钥(全大写占位形态):tvly-PLACEHOLDER_REPLACE_ME
113
+ { name: 'vendor-key-caps', pattern: /\b(?:sk|key|pk|tvly|xai|rk|ak)[-_][A-Z0-9_]{12,}\b/g },
114
+ // 标签式:apiKey=xxx / "api_key": "xxx" / secret: xxx / token=xxx
115
+ {
116
+ name: 'labeled-secret',
117
+ pattern: /\b(api[_-]?key|apikey|secret|access[_-]?token|refresh[_-]?token|authorization|password|passwd|pwd|token)\b\s*["']?\s*[:=]\s*["']?[A-Za-z0-9._~+/=-]{8,}/gi,
118
+ },
119
+ ];
120
+ /** 掩码后的固定占位符。 */
121
+ export const SECRET_MASK = '[REDACTED]';
122
+ /**
123
+ * 把文本里的凭据字面量替换成 `SECRET_MASK`。
124
+ *
125
+ * 顺序有意义:先打标签式(`apiKey=…`),再打 `Bearer`,最后打裸厂商前缀 ——
126
+ * 否则 `Bearer sk-cp-xxx` 会被前两条先吃掉,留下一截尾巴。
127
+ */
128
+ export function maskSecrets(text) {
129
+ let out = text;
130
+ const hits = new Set();
131
+ for (const { name, pattern } of SECRET_PATTERNS) {
132
+ // 克隆正则,避免共享实例的 lastIndex 在并发调用间串扰(同 pii-utils 的做法)
133
+ const re = new RegExp(pattern.source, pattern.flags);
134
+ if (!re.test(out))
135
+ continue;
136
+ hits.add(name);
137
+ out = out.replace(new RegExp(pattern.source, pattern.flags), (m) => {
138
+ // 标签式:保留标签名,只换值,保留可读性。
139
+ const idx = m.search(/[:=]/);
140
+ if (idx >= 0)
141
+ return `${m.slice(0, idx + 1)}${SECRET_MASK}`;
142
+ // Bearer:保留前缀(`Bearer `),换掉 token。
143
+ const sp = m.search(/\s/);
144
+ if (sp > 0 && /^(Bearer|Basic)$/i.test(m.slice(0, sp))) {
145
+ return `${m.slice(0, sp + 1)}${SECRET_MASK}`;
146
+ }
147
+ return SECRET_MASK;
148
+ });
149
+ }
150
+ return { text: out, hits: [...hits] };
151
+ }
152
+ /**
153
+ * 按字符数截断,**显式标注**溢出了多少。
154
+ *
155
+ * 不用 `…` 单字符收尾 —— 它和原文里的省略号没法区分。统一用
156
+ * `…[+N chars]`,`grep` 得到的就是真的。
157
+ */
158
+ export function truncateForLog(text, maxChars) {
159
+ if (typeof text !== 'string')
160
+ return { text: '', length: 0, truncated: false };
161
+ const length = text.length;
162
+ if (maxChars <= 0 || length <= maxChars)
163
+ return { text, length, truncated: false };
164
+ const dropped = length - maxChars;
165
+ return { text: `${text.slice(0, maxChars)}…[+${dropped} chars]`, length, truncated: true };
166
+ }
167
+ /**
168
+ * 对一段要进日志的文本走完整条链:凭据掩码 → PII 脱敏 → 截断。
169
+ *
170
+ * 顺序同样有讲究:先掩码再脱敏,避免 PII 规则把密钥的一部分改写成别的形态
171
+ * 而逃过掩码;截断放最后,保证掩码与脱敏作用在**完整**文本上(否则密钥可能
172
+ * 恰好落在被切掉的那一段里……不对,那样反而安全了,但 PII 的部分掩码会因
173
+ * 截断而失配。结论:先处理完再截,语义最直观)。
174
+ */
175
+ export function sanitizeTraceText(text, cfg) {
176
+ if (typeof text !== 'string' || text.length === 0) {
177
+ return { text: '', length: 0, truncated: false };
178
+ }
179
+ let out = text;
180
+ if (cfg.redactSecrets)
181
+ out = maskSecrets(out).text;
182
+ if (cfg.redactPii)
183
+ out = redactString(out).redacted;
184
+ return truncateForLog(out, cfg.maxChars);
185
+ }
186
+ /* ── body 快照(§7.144)────────────────────────────────────────────────── */
187
+ /**
188
+ * 把任意 body 序列化成**可安全记录**的文本。
189
+ *
190
+ * 三个坑:
191
+ * - **循环引用** → `JSON.stringify` 直接抛 `TypeError`。body 里出现循环
192
+ * (宿主 options 被塞回 body 这类)就会把观测路径变成故障源。
193
+ * - **BigInt** → 同样抛。
194
+ * - **不可序列化的值**(函数 / Symbol)→ `JSON.stringify` 会静默丢掉,
195
+ * 让人以为"没发这个字段"。用 replacer 把它们替换成占位符,**显式**告诉
196
+ * 读日志的人「这里有个记不住的值」,而不是让它凭空消失。
197
+ */
198
+ export function serializeTraceBody(value) {
199
+ if (typeof value === 'string')
200
+ return value;
201
+ const seen = new WeakSet();
202
+ try {
203
+ return JSON.stringify(value, (_key, v) => {
204
+ if (typeof v === 'bigint')
205
+ return `[bigint ${v.toString()}]`;
206
+ if (typeof v === 'function')
207
+ return '[function]';
208
+ if (typeof v === 'symbol')
209
+ return '[symbol]';
210
+ if (typeof v === 'object' && v !== null) {
211
+ if (seen.has(v))
212
+ return '[circular]';
213
+ seen.add(v);
214
+ }
215
+ return v;
216
+ }) ?? '';
217
+ }
218
+ catch {
219
+ return '[unserializable body]';
220
+ }
221
+ }
222
+ /**
223
+ * body 快照的脱敏 + 截断。
224
+ *
225
+ * 走与正文同一条链(凭据掩码 → PII 脱敏 → 截断),只是上限换成
226
+ * `maxBodyChars`(body 比单条 message 大得多,按 2000 截就没意义了)。
227
+ */
228
+ export function buildBodySnapshot(value, config) {
229
+ if (value === undefined || value === null)
230
+ return undefined;
231
+ const text = serializeTraceBody(value);
232
+ if (text.length === 0)
233
+ return undefined;
234
+ return sanitizeTraceText(text, { ...config, maxChars: config.maxBodyChars });
235
+ }
236
+ /**
237
+ * 把 `options.messages` 的 content 摊平成纯文本。
238
+ *
239
+ * dsh-llm 的 `Message.content` 有两种形态:content-block 数组(`{type:'text',
240
+ * text}`)和裸字符串。两种都要认,否则一半消息在 trace 里是空的。
241
+ */
242
+ export function messageContentToText(content) {
243
+ if (typeof content === 'string')
244
+ return content;
245
+ if (!Array.isArray(content))
246
+ return '';
247
+ return content
248
+ .filter((b) => typeof b === 'object' && b !== null && b.type === 'text')
249
+ .map((b) => (typeof b.text === 'string' ? b.text : ''))
250
+ .join('');
251
+ }
252
+ /**
253
+ * 构造 request trace。
254
+ *
255
+ * 保留**最后** `maxMessages` 条 message(而不是前 `maxMessages` 条):多轮
256
+ * 对话里真正决定这次请求的是最近几轮,开头的 system 指令已经被压进
257
+ * `system` 字段了。
258
+ */
259
+ export function buildRequestTrace(input) {
260
+ const { config } = input;
261
+ const all = input.messages ?? [];
262
+ const keepFrom = Math.max(0, all.length - Math.max(0, config.maxMessages));
263
+ const kept = all.slice(keepFrom);
264
+ const promptLength = all.reduce((n, m) => n + messageContentToText(m.content).length, 0);
265
+ const messages = kept.map((m, i) => {
266
+ const raw = messageContentToText(m.content);
267
+ const trace = {
268
+ index: keepFrom + i,
269
+ role: m.role,
270
+ length: raw.length,
271
+ };
272
+ if (m.source?.kind)
273
+ trace.kind = m.source.kind;
274
+ if (m.source?.provider)
275
+ trace.provider = m.source.provider;
276
+ // 空正文的消息(比如只有 tool_calls 的 assistant 回合)留空,不写 `text`
277
+ // 字段 —— 让读日志的人分得清"没有正文"和"正文被截断成空"。
278
+ if (raw.length > 0)
279
+ trace.text = sanitizeTraceText(raw, config);
280
+ return trace;
281
+ });
282
+ const trace = {
283
+ sessionId: input.sessionId,
284
+ provider: input.provider,
285
+ model: input.model,
286
+ messageCount: all.length,
287
+ droppedMessages: all.length - kept.length,
288
+ promptLength,
289
+ messages,
290
+ };
291
+ if (input.baseUrl)
292
+ trace.baseUrl = input.baseUrl;
293
+ if (input.system && input.system.length > 0) {
294
+ trace.system = sanitizeTraceText(input.system, config);
295
+ }
296
+ // §7.144: 完整请求体快照(真正发出去的那一坨)。
297
+ const body = buildBodySnapshot(input.rawBody, config);
298
+ if (body !== undefined)
299
+ trace.body = body;
300
+ const toolNames = (input.tools ?? [])
301
+ .map((t) => t.name ?? t.function?.name)
302
+ .filter((n) => typeof n === 'string' && n.length > 0);
303
+ if (toolNames.length > 0)
304
+ trace.tools = toolNames;
305
+ if (input.params)
306
+ trace.params = input.params;
307
+ return trace;
308
+ }
309
+ /** 构造 response trace。 */
310
+ export function buildResponseTrace(input) {
311
+ const { config } = input;
312
+ const trace = {
313
+ sessionId: input.sessionId,
314
+ provider: input.provider,
315
+ model: input.model,
316
+ toolCalls: [],
317
+ };
318
+ if (input.attempt !== undefined)
319
+ trace.attempt = input.attempt;
320
+ if (input.durationMs !== undefined)
321
+ trace.durationMs = input.durationMs;
322
+ if (input.finishReason)
323
+ trace.finishReason = input.finishReason;
324
+ if (input.content && input.content.length > 0) {
325
+ trace.content = sanitizeTraceText(input.content, config);
326
+ }
327
+ for (const call of input.toolCalls ?? []) {
328
+ const t = { name: call.name };
329
+ if (call.id)
330
+ t.id = call.id;
331
+ if (call.arguments && call.arguments.length > 0) {
332
+ t.arguments = sanitizeTraceText(call.arguments, config);
333
+ }
334
+ trace.toolCalls.push(t);
335
+ }
336
+ if (input.usage)
337
+ trace.usage = input.usage;
338
+ // §7.144: 完整响应体快照。
339
+ const body = buildBodySnapshot(input.rawBody, config);
340
+ if (body !== undefined)
341
+ trace.body = body;
342
+ if (input.error) {
343
+ trace.error = truncateForLog(input.error, Math.max(200, config.maxChars)).text;
344
+ }
345
+ return trace;
346
+ }
347
+ /* ── 输出格式化 ─────────────────────────────────────────────────────────── */
348
+ /**
349
+ * 把 trace 压成**单行**字符串。
350
+ *
351
+ * ops log 的 `formatLine` 会把换行折成 `⏎`,所以这里自己保证单行:
352
+ * `JSON.stringify` 已经把字符串内的换行转义成 `\n`,但仍可能出现裸的
353
+ * 控制字符(U+2028/2029 等),统一替换掉,避免日志文件出现"一行日志占了
354
+ * 三行物理行"的破事。
355
+ */
356
+ export function formatTraceLine(tag, trace) {
357
+ let json;
358
+ try {
359
+ json = JSON.stringify(trace);
360
+ }
361
+ catch {
362
+ // 循环引用 / BigInt 之类的破值:退回一个可读的占位,绝不让日志路径抛错。
363
+ json = JSON.stringify({ error: 'trace-not-serializable' });
364
+ }
365
+ const singleLine = json.replace(/[\u0000-\u001f\u007f\u2028\u2029]/g, ' ');
366
+ return `[${tag}] ${singleLine}`;
367
+ }
368
+ /**
369
+ * 构造索引行 payload。
370
+ *
371
+ * 从 trace 对象里**提取标量**——不复制正文。正文另存 store。
372
+ */
373
+ export function buildTraceIndex(traceId, kind, trace, caller, extra) {
374
+ const t = (trace ?? {});
375
+ const out = {
376
+ traceId,
377
+ kind,
378
+ provider: typeof t.provider === 'string' ? t.provider : '?',
379
+ model: typeof t.model === 'string' ? t.model : '?',
380
+ };
381
+ if (caller !== undefined)
382
+ out.caller = caller;
383
+ // §7.147: 索引行带上会话归属。trace 对象里本来就有 sessionId
384
+ // (`LlmRequestTrace.sessionId` / `LlmResponseTrace.sessionId`),只是没被
385
+ // 抄进索引行 —— 于是 195 条索引行全部落全局桶。
386
+ //
387
+ // 用 `sessionIdField()` 而不是直接抄:trace 里的 sessionId 在「会话建立
388
+ // 之前」的调用上是 `'<pre-session>'` **哨兵**(ops log 的显示约定,§7.52),
389
+ // 抄进载荷会造出一个不存在的桶。哨兵 ⇒ 不写这个键 ⇒ 归全局桶。
390
+ const sessionId = realSessionId(t.sessionId);
391
+ if (sessionId !== undefined)
392
+ out.sessionId = sessionId;
393
+ if (typeof t.baseUrl === 'string')
394
+ out.baseUrl = t.baseUrl;
395
+ if (typeof t.messageCount === 'number')
396
+ out.messageCount = t.messageCount;
397
+ if (typeof t.droppedMessages === 'number')
398
+ out.droppedMessages = t.droppedMessages;
399
+ if (typeof t.promptLength === 'number')
400
+ out.promptLength = t.promptLength;
401
+ if (typeof t.content?.length === 'number')
402
+ out.contentLength = t.content.length;
403
+ if (Array.isArray(t.toolCalls))
404
+ out.toolCallCount = t.toolCalls.length;
405
+ if (typeof t.durationMs === 'number')
406
+ out.durationMs = t.durationMs;
407
+ if (typeof t.finishReason === 'string')
408
+ out.finishReason = t.finishReason;
409
+ if (typeof t.error === 'string')
410
+ out.error = t.error;
411
+ // 工具数:response trace 里没有请求的工具表,由调用方通过 extra 补上;
412
+ // request trace 自己带 tools[]。
413
+ if (extra?.toolCount !== undefined)
414
+ out.toolCount = extra.toolCount;
415
+ else if (Array.isArray(t.tools))
416
+ out.toolCount = t.tools.length;
417
+ if (extra?.callId !== undefined)
418
+ out.callId = extra.callId;
419
+ let bytes = 0;
420
+ try {
421
+ bytes = JSON.stringify(trace)?.length ?? 0;
422
+ }
423
+ catch {
424
+ bytes = 0;
425
+ }
426
+ out.bodyBytes = bytes;
427
+ return out;
428
+ }
429
+ /**
430
+ * §7.133: 一次 LLM 调用的**统一出口**。
431
+ *
432
+ * 三条通路同时写:
433
+ * 1. ops log(§7.118 的老行为,`LLM_REQUEST` / `LLM_RESPONSE` 单行)
434
+ * 2. audit 索引行(`llm.trace.index`)→ Edge 面板列出这次调用
435
+ * 3. 正文 store(`LlmTraceStore`)→ 面板点开时取
436
+ *
437
+ * 检测调用(安检 / 分类器)经 `caller` 标出来 —— §7.132 的
438
+ * `edgeInternalCaller` 是同一个标记体系。**标记的来源是 options**:
439
+ * adapter 调 `emitTrace` 时把 `options` 传进来,由 `internalCallerOf()`
440
+ * 读出标记。所以检测调用的 trace 与主对话的 trace 走的是**同一段代码**,
441
+ * 不存在「检测调用忘了记」的第二套实现。
442
+ */
443
+ export function emitTrace(sink, kind, tag, trace, caller, extra) {
444
+ try {
445
+ // 老通路:ops log(§7.118)—— 保持不变,运维 tail ops log 的习惯不破。
446
+ sink.logger?.info?.(formatTraceLine(tag, trace));
447
+ const traceId = sink.nextTraceId?.() ?? nextTraceId();
448
+ // 正文进 store
449
+ sink.store?.put(traceId, { kind, ...(caller !== undefined ? { caller } : {}), trace });
450
+ // 索引行进 audit —— 面板 fold 认这个 kind
451
+ void sink.log({
452
+ level: 'info',
453
+ kind: 'llm.trace.index',
454
+ source: 'llm-trace',
455
+ payload: buildTraceIndex(traceId, kind, trace, caller, extra),
456
+ }).catch(() => { });
457
+ return traceId;
458
+ }
459
+ catch {
460
+ // 观测失败不拖垮主链路 —— 与本模块既有纪律一致。
461
+ return undefined;
462
+ }
463
+ }
@@ -0,0 +1,141 @@
1
+ /**
2
+ * local-llm-adapter — M4 multi-model + routing.
3
+ *
4
+ * Registers one or more provider routes on the shared `ctx.llm`
5
+ * runtime, all backed by a real OpenAI-compatible `/chat/completions`
6
+ * endpoint. Defaults to `http://127.0.0.1:8080/v1` (llama.cpp's
7
+ * `server` binary); the reachable endpoint in this repo is
8
+ * `http://192.0.2.101:8701/v1`. No in-process mock — every call
9
+ * leaves the process.
10
+ *
11
+ * The wire-protocol parser lives in `./openai-sse.js` so changes to
12
+ * the SSE framing land in one place and are shared by the cloud
13
+ * adapter. The body builder flips `stream: true` and merges adapter
14
+ * defaults (model, temperature) so the upstream server sees the same
15
+ * shape the dsh agent loop emits.
16
+ *
17
+ * @module dsh-edge-agent/local-llm-adapter
18
+ */
19
+ import type { Context, LoggerService } from '@deepseek-ai/cordis';
20
+ import Schema from '@deepseek-ai/schemastery';
21
+ import { LlmAdapter } from '@deepseek-ai/dsh-llm';
22
+ import type { GenerateOptions, LlmModelInfo, LlmProviderInfo, LlmResolvedModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm';
23
+ export declare const name = "local-llm-adapter";
24
+ export declare const inject: readonly ["llm", "auditLog", "inputGuard"];
25
+ /**
26
+ * §7.42 (2026-09-05) P0-2: per-session runaway guard. If the local LLM emits
27
+ * more than this many consecutive REAL tool-call responses (finishKind=
28
+ * 'tool-calls' with toolCalls.size > 0 — malformed cases are handled by P0-1
29
+ * above and rewritten to finishKind='stop' before reaching the counter), the
30
+ * adapter throws `LlmError('MAX_TURNS_EXCEEDED')` to terminate the agent loop.
31
+ * 20 is conservative: a healthy tool-use turn rarely exceeds 3-5 iterations;
32
+ * 20 catches runaways without tripping on legitimate long chains.
33
+ *
34
+ * §7.47.5 (2026-09-13): shared with cloud-llm-adapter via ./llm-max-turns.ts
35
+ * so cross-adapter sessions (e.g. classifier fallback LOCAL → CLOUD) keep
36
+ * a single counter. See llm-max-turns.ts for the rationale.
37
+ */
38
+ /** Minimal interface our adapter needs from the audit-log service. */
39
+ interface AuditLike {
40
+ log(entry: {
41
+ level: 'debug' | 'info' | 'warn' | 'error' | 'security';
42
+ kind: string;
43
+ source: string;
44
+ payload: Record<string, unknown>;
45
+ }): Promise<unknown>;
46
+ }
47
+ /**
48
+ * 2026-08-31: input-guard 注入用于清洗孤儿 tool_call。
49
+ * qwen3 对 orphan tool_call 不像 DeepSeek 那么严格(不会 400),
50
+ * 但统一清洗可避免 LLM 上下文里出现悬空调用、提升模型行为稳定性。
51
+ */
52
+ interface InputGuardLike {
53
+ sanitizeOrphanToolCalls(messages: ReadonlyArray<Record<string, unknown>>, sessionId?: string): {
54
+ messages: Array<Record<string, unknown>>;
55
+ orphanCount: number;
56
+ syntheticInjected: number;
57
+ };
58
+ }
59
+ /** Minimal duck-typed handle for Cordis `LoggerService`. Used by tests to stub
60
+ * logger behavior; `apply()` injects the live `ctx.logger` from Cordis. */
61
+ type LoggerLike = Pick<LoggerService, 'info' | 'warn' | 'error' | 'debug'>;
62
+ export interface Config {
63
+ /** Provider route ids this adapter owns. */
64
+ providers: string[];
65
+ /** OpenAI-compatible endpoint. `/chat/completions` is appended.
66
+ *
67
+ * Undefined/empty means "no local-LLM endpoint configured". §7.171: that is
68
+ * no longer "no route at all" — the adapter falls back to DELEGATE mode
69
+ * (forward to the host provider), symmetric with `llm.cloud`. Set
70
+ * `llm.local.delegate=false` to restore the opt-in semantics (register
71
+ * nothing). It must not fall back to a hard-coded port — a default like
72
+ * `127.0.0.1:8080` collides with unrelated daemons that listen there
73
+ * (observed 2026-10-21: TeleAgent's scheduler daemon owns 8080 and answers
74
+ * 401 "Missing bearer token"), which turned every turn into a failed
75
+ * local-LLM call even though the operator never asked for a local model. */
76
+ baseUrl?: string;
77
+ /** Default model id when the request omits one. */
78
+ defaultModel: string;
79
+ /** Optional bearer header for an authenticated endpoint.
80
+ *
81
+ * §7.102: the value is now the literal key, not an env-slot name. The
82
+ * key lives in config/edge.json (gitignored) and reaches the adapter
83
+ * through this field. `apiKeyEnv` is kept as a deprecated alias for
84
+ * callers that still pass an env-slot name — it is read from
85
+ * process.env when present, but new deployments should use `apiKey`. */
86
+ apiKey?: string;
87
+ /** @deprecated Use `apiKey` (literal). Kept so an env-slot name still
88
+ * works for a transition period. */
89
+ apiKeyEnv?: string;
90
+ /** §7.4? (2026-09-17) LAN minicpm5-2b Jinja2 tojson(ensure_ascii) bug
91
+ * workaround: when true, omit `body.tools` from wire request so the
92
+ * server template `{% if tools %}` block is never evaluated. Model
93
+ * falls back to plain-text tool defs in system prompt's
94
+ * <available_tools>. Defaults to false. */
95
+ stripTools?: boolean;
96
+ /** §7.87.5 (2026-09-19): disable chain-of-thought for thinking-capable
97
+ * models (qwen3.5 / QwQ / DeepSeek-R1). When false (default), the wire
98
+ * body gets `chat_template_kwargs={enable_thinking: false}` so the model
99
+ * returns final answer directly instead of burning max_tokens on reasoning.
100
+ * Pass-through no-op for non-thinking servers. */
101
+ enableThinking?: boolean;
102
+ /** §7.106 (2026-10-23): also send `reasoning_effort:"none"` with think-off.
103
+ * ollama /v1 honors that dialect; strict gateways 400 unknown params
104
+ * (minimax measured). Opt-in per pool via `llm.local.reasoningEffortNone`. */
105
+ reasoningEffortNone?: boolean;
106
+ /** §7.171 (2026-11-10): baseUrl 留空时是否走 DELEGATE(转发宿主提供商),
107
+ * 与 `llm.cloud` 对称。默认 true(`llm.local.delegate` 未写 = 委托)。
108
+ *
109
+ * false = kill switch:回到 opt-in 语义(不注册任何路由),LOCAL 意图
110
+ * fail-closed 报错。**文件与本字段任一为 false 即关闭** —— 关闭方向上取
111
+ * 「最严」,避免任一侧漏配就意外出网。 */
112
+ delegate?: boolean;
113
+ /** §7.171: delegate 模式下的显式目标 provider route id(压过宿主选择)。 */
114
+ delegateProvider?: string;
115
+ /** §7.171: delegate 模式下的 wire model override(压过宿主选择)。 */
116
+ delegateModel?: string;
117
+ }
118
+ export declare const Config: Schema<Config>;
119
+ export interface LocalLlmAdapter {
120
+ readonly providers: string[];
121
+ stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
122
+ }
123
+ /**
124
+ * Adapter facade. Owns one real-HTTP inner adapter per configured
125
+ * provider route so `ctx.llm.registerAdapter([...], this)` can route
126
+ * any of them through the same instance — keeping the `dispose`
127
+ * set in lockstep with the registration.
128
+ */
129
+ export declare class LocalLlmAdapterImpl extends LlmAdapter {
130
+ private readonly providersList;
131
+ private readonly innerByProvider;
132
+ constructor(config: Config, auditLog?: AuditLike, inputGuard?: InputGuardLike, logger?: LoggerLike);
133
+ get providers(): string[];
134
+ providerInfo(provider: string): LlmProviderInfo;
135
+ listModels(provider: string): Promise<readonly LlmModelInfo[]>;
136
+ resolveModel(provider: string, model: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
137
+ stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
138
+ }
139
+ export declare function apply(ctx: Context, config: Config): Promise<() => Promise<void>>;
140
+ export {};
141
+ //# sourceMappingURL=local-llm-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-llm-adapter.d.ts","sourceRoot":"","sources":["../../src/dsh-adapter/local-llm-adapter.ts"],"names":[],"mappings":"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"}