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

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 +158 -0
  2. package/LICENSE +21 -0
  3. package/README.md +181 -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 +253 -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
package/cordis.yml ADDED
@@ -0,0 +1,374 @@
1
+ # dsh-edge-agent — edge-side private agent built on the DSH Cordis plugin
2
+ # mechanism. Run with: dsh --config cordis.yml
3
+ #
4
+ # Boot a session:
5
+ # pnpm install
6
+ # pnpm compile
7
+ # DEEPSEEK_API_KEY=... pnpm dsh -- --profile edge-standard "你好"
8
+ #
9
+ # Layout:
10
+ # 1. User-interaction / approval seams (model-facing)
11
+ # 2. Core DSH services: sessions, agent-spine, llm, subagent, tools, fs
12
+ # 3. The dsh-edge-agent plugin tree (19 core + 1 http-api)
13
+ # 4. Sandbox + telemetry
14
+
15
+ # ─────────────────────────────────────────────────────────────────────────────
16
+ # 1. user-interaction / approval seams
17
+ # ─────────────────────────────────────────────────────────────────────────────
18
+
19
+ # User-interaction service: hosts `ctx.userQuestions`. dsh-edge-agent mounts
20
+ # the same DSH default provider that any other bundle would.
21
+ - id: user-questions
22
+ name: '@deepseek-ai/dsh-user-questions'
23
+
24
+ # Approval waterfall. The edge-agent does NOT auto-approve by default;
25
+ # users opt into danger-full-access through DSH_EDGE_PERMISSION_MODE.
26
+ - id: approval
27
+ name: '@deepseek-ai/dsh-user-approval'
28
+ config:
29
+ policy: !!js "process.platform === 'win32' ? 'never' : ((process.env.DSH_EDGE_PERMISSION_MODE ?? 'ask') === 'danger-full-access' ? 'never' : 'ask')"
30
+
31
+ # ─────────────────────────────────────────────────────────────────────────────
32
+ # 2. Core DSH services (sessions, agent, llm, subagent, tools, fs)
33
+ # ─────────────────────────────────────────────────────────────────────────────
34
+
35
+ # Durable session log (JSONL) — every session event is appended here so
36
+ # /resume, /compact, and the threat-detection bus can replay.
37
+ - id: sessions
38
+ name: '@deepseek-ai/dsh-session-persistence-jsonl'
39
+ config:
40
+ root: !!js (process.env.DSH_EDGE_SESSION_ROOT ?? (process.env.USERPROFILE ?? process.env.HOME) + '/.dsh-edge-agent/sessions')
41
+
42
+ - id: session-query
43
+ name: '@deepseek-ai/dsh-session-query'
44
+
45
+ # Token accounting + manual /compact.
46
+ - id: token-meter
47
+ name: '@deepseek-ai/dsh-token-meter'
48
+
49
+ - id: compact
50
+ name: '@deepseek-ai/dsh-compaction-basic'
51
+
52
+ # Subagent registry, fork provider, and delegation tools.
53
+ - id: subagent
54
+ name: '@deepseek-ai/dsh-subagent'
55
+
56
+ - id: subagent-fork
57
+ name: '@deepseek-ai/dsh-subagent-fork-in-process'
58
+ config:
59
+ providerName: fork
60
+
61
+ - id: tool-subagent
62
+ name: '@deepseek-ai/dsh-tool-subagent'
63
+ config:
64
+ provider: fork
65
+ toolName: subagent_fork
66
+ backgroundMode: continuable
67
+ maxDepth: 1
68
+
69
+ # Filesystem service + observation policy + model-facing fs tools.
70
+ - id: fs
71
+ name: '@deepseek-ai/dsh-fs-local'
72
+ config:
73
+ cwd: !!js process.cwd()
74
+
75
+ - id: fs-policy
76
+ name: '@deepseek-ai/dsh-fs-observation-policy'
77
+
78
+ # Model-facing filesystem tools (read/write/edit/read_image)
79
+ - id: tool-fs
80
+ name: '@deepseek-ai/dsh-tool-fs'
81
+ config:
82
+ readLimit: 2000
83
+ readMaxBytes: 51200
84
+
85
+ # todo_write tool (mirrors the dsh-base bundle default).
86
+ - id: tool-todo
87
+ name: '@deepseek-ai/dsh-tool-todo'
88
+ config:
89
+ allowParallelInProgress: true
90
+
91
+ # Compaction basic — only one row; the dsh-edge-agent plugin tree is
92
+ # responsible for its own realm-aware tool registry (`tools`).
93
+
94
+ # ─────────────────────────────────────────────────────────────────────────────
95
+ # 3. dsh-edge-agent plugin tree
96
+ # ─────────────────────────────────────────────────────────────────────────────
97
+
98
+ # The main aggregator plugin: mounts every sub-plugin in boot order and
99
+ # registers the model-facing `services` namespace. The subpath exports
100
+ # pattern lets each row below be reused independently of this aggregator.
101
+ - id: dsh-edge-agent
102
+ name: '@dsh-edge/dsh-edge-agent'
103
+ inject: [agents, llm, sessions, invariants]
104
+ config:
105
+ teeType: !!js process.env.DSH_EDGE_TEE_TYPE ?? 'simulated'
106
+ storageRoot: !!js process.env.DSH_EDGE_STORAGE_ROOT ?? ((process.env.USERPROFILE ?? process.env.HOME) + '/.dsh-edge-agent')
107
+ policyPath: !!js process.env.DSH_EDGE_POLICY_PATH ?? ((process.env.USERPROFILE ?? process.env.HOME) + '/.dsh-edge-agent/policy.json')
108
+ defaultDataLevel: !!js process.env.DSH_EDGE_DEFAULT_DATA_LEVEL ?? 'sanitized'
109
+ allowFallbackTls: !!js process.env.DSH_EDGE_ALLOW_FALLBACK_TLS === 'true'
110
+ sessionWindowSize: !!js parseInt(process.env.DSH_EDGE_SESSION_WINDOW_SIZE ?? '32', 10)
111
+
112
+ # Trusted Computing Module — TEE-aware key management, encryption, sealing,
113
+ # and remote-attestation primitives. MUST mount first (every privacy/security
114
+ # plugin depends on its key store).
115
+ - id: tcm
116
+ name: '@dsh-edge/dsh-edge-agent/tcm'
117
+ config:
118
+ teeType: !!js process.env.DSH_EDGE_TEE_TYPE ?? 'simulated'
119
+ keyStorePath: !!js (process.env.DSH_EDGE_STORAGE_ROOT ?? ((process.env.USERPROFILE ?? process.env.HOME) + '/.dsh-edge-agent')) + '/keys'
120
+ teeInference: !!js process.env.DSH_EDGE_TEE_INFERENCE === 'true'
121
+ secureMemoryLimit: !!js parseInt(process.env.DSH_EDGE_SECURE_MEM ?? String(64 * 1024 * 1024), 10)
122
+
123
+ # Encrypted SQLite-backed key/value. Each value is AES-256-GCM encrypted via
124
+ # the TCM service before being written to disk.
125
+ - id: local-storage
126
+ name: '@dsh-edge/dsh-edge-agent/local-storage'
127
+ inject: [tcm]
128
+ config:
129
+ root: !!js (process.env.DSH_EDGE_STORAGE_ROOT ?? ((process.env.USERPROFILE ?? process.env.HOME) + '/.dsh-edge-agent')) + '/storage'
130
+ filename: !!js process.env.DSH_EDGE_STORAGE_FILE ?? 'storage.enc.db'
131
+
132
+ # Encrypted session lifecycle.
133
+ - id: sessions-edge
134
+ name: '@dsh-edge/dsh-edge-agent/sessions'
135
+ inject: [tcm, localStorage]
136
+ config:
137
+ defaultTtlSeconds: !!js parseInt(process.env.DSH_EDGE_SESSION_TTL ?? String(60 * 60), 10)
138
+ maxConcurrentSessions: !!js parseInt(process.env.DSH_EDGE_MAX_SESSIONS ?? '8', 10)
139
+
140
+ # Tamper-evident audit log. HMAC-chained so any tampering is detected.
141
+ - id: audit-log
142
+ name: '@dsh-edge/dsh-edge-agent/audit-log'
143
+ inject: [tcm, localStorage]
144
+ config:
145
+ minLevel: !!js process.env.DSH_EDGE_AUDIT_LEVEL ?? 'info'
146
+ sensitiveFields: !!js (process.env.DSH_EDGE_AUDIT_SENSITIVE_FIELDS ?? '').split(',').filter(Boolean)
147
+ enableAlerts: !!js process.env.DSH_EDGE_AUDIT_ALERTS !== 'false'
148
+ alertThresholds:
149
+ cloudRequestsPerMinute: !!js parseInt(process.env.DSH_EDGE_AUDIT_CLOUD_RATE ?? '20', 10)
150
+ sanitizationFailures: !!js parseInt(process.env.DSH_EDGE_AUDIT_SAN_FAIL ?? '3', 10)
151
+ permissionDenied: !!js parseInt(process.env.DSH_EDGE_AUDIT_PERM_DENIED ?? '5', 10)
152
+ flushIntervalMs: !!js parseInt(process.env.DSH_EDGE_AUDIT_FLUSH_MS ?? '500', 10)
153
+
154
+ # Hot-reloadable privacy policy engine.
155
+ - id: privacy-policy
156
+ name: '@dsh-edge/dsh-edge-agent/privacy-policy'
157
+ inject: [tcm, localStorage, auditLog]
158
+ config:
159
+ policyPath: !!js process.env.DSH_EDGE_POLICY_PATH ?? ((process.env.USERPROFILE ?? process.env.HOME) + '/.dsh-edge-agent/policy.json')
160
+ hotReload: !!js process.env.DSH_EDGE_POLICY_HOT_RELOAD !== 'false'
161
+ watchIntervalMs: !!js parseInt(process.env.DSH_EDGE_POLICY_WATCH_MS ?? '5000', 10)
162
+
163
+ # Realm-aware tool registry (LOCAL / CLOUD / SANITIZED).
164
+ - id: tools
165
+ name: '@dsh-edge/dsh-edge-agent/tools'
166
+ inject: [auditLog]
167
+ config:
168
+ defaultRateLimitPerMinute: !!js parseInt(process.env.DSH_EDGE_TOOL_RATE ?? '60', 10)
169
+ enableToolIsolation: !!js process.env.DSH_EDGE_TOOL_ISOLATION !== 'false'
170
+
171
+ # Realm-aware skill + tool isolation bridge. Reads skill-realms.json to tag
172
+ # every discovered skill/tool as LOCAL | CLOUD | hidden, then enforces the
173
+ # mapping at agent/pre-step (catalog filtering) and tools/pre-execute (deny
174
+ # cross-realm calls). Hot-reloads the config file without restart.
175
+ - id: realm-skill-bridge
176
+ name: '@dsh-edge/dsh-edge-agent/realm-skill-bridge'
177
+ inject: [auditLog]
178
+ config:
179
+ configPath: !!js process.env.DSH_EDGE_REALM_CONFIG ?? ((process.env.USERPROFILE ?? process.env.HOME) + '/.dsh-edge-agent/skill-realms.json')
180
+ hotReload: !!js process.env.DSH_EDGE_REALM_HOT_RELOAD !== 'false'
181
+ watchIntervalMs: !!js parseInt(process.env.DSH_EDGE_REALM_WATCH_MS ?? '5000', 10)
182
+
183
+ # Input/output safety scanning. MVP: checkInput only with 4 default rules.
184
+ - id: prompt-guard
185
+ name: '@dsh-edge/dsh-edge-agent/prompt-guard'
186
+ inject: [tcm, privacyPolicy, auditLog, llm]
187
+ config:
188
+ rules: []
189
+ enableModelDetection: !!js process.env.DSH_EDGE_GUARD_MODEL !== 'false'
190
+ modelDetectionProvider: !!js process.env.DSH_EDGE_GUARD_MODEL_PROVIDER ?? 'local-llm'
191
+ modelDetectionModel: !!js process.env.DSH_EDGE_GUARD_MODEL_MODEL ?? 'qwen3-4b'
192
+ modelDetectionTimeoutMs: !!js parseInt(process.env.DSH_EDGE_GUARD_MODEL_TIMEOUT_MS ?? '4000', 10)
193
+ modelDetectionMaxInputLength: !!js parseInt(process.env.DSH_EDGE_GUARD_MODEL_MAX_INPUT ?? '2000', 10)
194
+
195
+ # Intent classification → routing decision.
196
+ - id: intent-router
197
+ name: '@dsh-edge/dsh-edge-agent/intent-router'
198
+ inject: [llm, promptGuard, privacyPolicy, auditLog, sessions, localStorage]
199
+ config:
200
+ confidenceThreshold: !!js parseFloat(process.env.DSH_EDGE_INTENT_CONFIDENCE_THRESHOLD ?? '0.6')
201
+ llmTimeoutMs: !!js parseInt(process.env.DSH_EDGE_INTENT_LLM_TIMEOUT_MS ?? '4000', 10)
202
+ recentMessagesLimit: !!js parseInt(process.env.DSH_EDGE_INTENT_RECENT_LIMIT ?? '3', 10)
203
+ maxInputLength: !!js parseInt(process.env.DSH_EDGE_INTENT_MAX_INPUT ?? '2000', 10)
204
+ fallbackKeywords: !!js (process.env.DSH_EDGE_INTENT_FALLBACK_KEYWORDS ?? '').split(',').filter(Boolean)
205
+ cloudKeywords: !!js (process.env.DSH_EDGE_INTENT_CLOUD_KEYWORDS ?? '').split(',').filter(Boolean)
206
+
207
+ # Model router — single `llm` surface, routes to local/cloud adapters.
208
+ - id: model-router
209
+ name: '@dsh-edge/dsh-edge-agent/model-router'
210
+ inject: [llm, privacyPolicy, auditLog]
211
+ config:
212
+ defaultModel: !!js process.env.DSH_EDGE_DEFAULT_MODEL ?? 'local-llm'
213
+ localModels: !!js (process.env.DSH_EDGE_LOCAL_MODELS ?? 'local-llm,local-llm-llama3').split(',').filter(Boolean)
214
+ cloudModels: !!js (process.env.DSH_EDGE_CLOUD_MODELS ?? 'cloud-llm,cloud-llm-v3').split(',').filter(Boolean)
215
+
216
+ # Local LLM adapter (OpenAI-compatible endpoint).
217
+ #
218
+ # NOTE: Pre-fix (2026-09-11), this row passed `modelPath` / `contextSize` /
219
+ # `threads` which are NOT in the plugin's Schema — Schemastery silently dropped
220
+ # them. Meanwhile `baseUrl` / `defaultModel` / `apiKeyEnv` were never wired,
221
+ # so .env.sh's DSH_EDGE_LOCAL_LLM_BASEURL etc. never reached the adapter.
222
+ # Rewritten to match `Schema.object({providers, baseUrl, defaultModel, apiKeyEnv})`
223
+ # in src/dsh-adapter/local-llm-adapter.ts.
224
+ #
225
+ # `apiKeyEnv` lets the adapter read a bearer from any env var (e.g. for
226
+ # cloud-hosted OpenAI-compatible endpoints like DashScope, OpenRouter, etc).
227
+ # Leave undefined to skip the Authorization header (plain llama.cpp server).
228
+ - id: local-llm-adapter
229
+ name: '@dsh-edge/dsh-edge-agent/local-llm-adapter'
230
+ config:
231
+ providers: !!js (process.env.DSH_EDGE_LOCAL_MODELS ?? 'local-llm').split(',').filter(Boolean)
232
+ baseUrl: !!js process.env.DSH_EDGE_LOCAL_LLM_BASEURL ?? 'http://127.0.0.1:8080/v1'
233
+ defaultModel: !!js process.env.DSH_EDGE_LOCAL_LLM_MODEL ?? 'qwen3-4b'
234
+ apiKeyEnv: !!js process.env.DSH_EDGE_LOCAL_LLM_APIKEY_ENV ?? undefined
235
+
236
+ # Cloud LLM adapter (DeepSeek / other providers). Routes through secure-bridge.
237
+ - id: cloud-llm-adapter
238
+ name: '@dsh-edge/dsh-edge-agent/cloud-llm-adapter'
239
+ inject: [secureBridge, auditLog]
240
+ config:
241
+ providers: !!js (process.env.DSH_EDGE_CLOUD_MODELS ?? 'cloud-llm').split(',').filter(Boolean)
242
+ # §7.100: 空 = DELEGATE 模式(继承宿主 profile 提供商);显式配端点才直连
243
+ baseUrl: !!js process.env.DEEPSEEK_BASE_URL || ''
244
+ apiKeyEnv: !!js process.env.DSH_EDGE_CLOUD_KEY_ENV ?? 'DEEPSEEK_API_KEY'
245
+
246
+ # Forward / reverse PII sanitization (SANITIZED realm).
247
+ - id: sanitizer-pipeline
248
+ name: '@dsh-edge/dsh-edge-agent/sanitizer-pipeline'
249
+ inject: [localStorage, privacyPolicy]
250
+ config:
251
+ enableAutoDetection: !!js process.env.DSH_EDGE_SAN_AUTO !== 'false'
252
+ maxReplacementsPerSession: !!js parseInt(process.env.DSH_EDGE_SAN_MAX ?? '1024', 10)
253
+ # 会话映射表持有明文 PII,必须有生命周期上限。http-api 删会话时会主动
254
+ # purge;以下两项是防止调用方漏调的兜底(2026-08-30)。
255
+ sessionTtlMs: !!js parseInt(process.env.DSH_EDGE_SAN_TTL_MS ?? '900000', 10)
256
+ maxSessions: !!js parseInt(process.env.DSH_EDGE_SAN_MAX_SESSIONS ?? '1000', 10)
257
+ sweepIntervalMs: !!js parseInt(process.env.DSH_EDGE_SAN_SWEEP_MS ?? '60000', 10)
258
+
259
+ # OHTTP gateway (RFC 9458) — HPKE ciphertext to a relay that cannot link
260
+ # user identity to request content.
261
+ - id: ohttp-gateway
262
+ name: '@dsh-edge/dsh-edge-agent/ohttp-gateway'
263
+ inject: [tcm, auditLog]
264
+ config:
265
+ relayUrl: !!js process.env.DSH_EDGE_OHTTP_RELAY ?? ''
266
+ targetUrl: !!js process.env.DSH_EDGE_OHTTP_TARGET ?? ''
267
+ publicKey: !!js process.env.DSH_EDGE_OHTTP_PUBKEY ?? ''
268
+ keyId: !!js process.env.DSH_EDGE_OHTTP_KEY_ID ?? ''
269
+ allowFallbackTls: !!js process.env.DSH_EDGE_ALLOW_FALLBACK_TLS === 'true'
270
+
271
+ # Outbound channel for cloud-bound requests.
272
+ - id: secure-bridge
273
+ name: '@dsh-edge/dsh-edge-agent/secure-bridge'
274
+ inject: [tcm, ohttp, privacyPolicy, auditLog]
275
+ config:
276
+ mode: !!js process.env.DSH_EDGE_BRIDGE_MODE ?? 'ohttp'
277
+ domainAllowList: !!js (process.env.DSH_EDGE_BRIDGE_ALLOW ?? '').split(',').filter(Boolean)
278
+ domainDenyList: !!js (process.env.DSH_EDGE_BRIDGE_DENY ?? '').split(',').filter(Boolean)
279
+ requestTimeoutMs: !!js parseInt(process.env.DSH_EDGE_BRIDGE_TIMEOUT_MS ?? '30000', 10)
280
+
281
+ # TEE attestation token generation + verification.
282
+ - id: attestation
283
+ name: '@dsh-edge/dsh-edge-agent/attestation'
284
+ inject: [tcm, auditLog]
285
+ config:
286
+ verifierUrl: !!js process.env.DSH_EDGE_ATTEST_VERIFIER ?? undefined
287
+ nonceTtlSeconds: !!js parseInt(process.env.DSH_EDGE_ATTEST_NONCE_TTL ?? '60', 10)
288
+
289
+ # Threat detection bus. Subscribes to high-volume events and raises a
290
+ # quarantine action when patterns indicate abuse. Phase D: real state
291
+ # machine; http-api reads getThreatLevel() and blocks at blockLevel.
292
+ - id: td-bus
293
+ name: '@dsh-edge/dsh-edge-agent/td-bus'
294
+ inject: [auditLog, privacyPolicy]
295
+ config:
296
+ windowSeconds: !!js parseInt(process.env.DSH_EDGE_TD_WINDOW ?? '60', 10)
297
+ thresholds:
298
+ cloudRequestsPerMinute: !!js parseInt(process.env.DSH_EDGE_TD_CLOUD_RATE ?? '20', 10)
299
+ failedSanitizationStreak: !!js parseInt(process.env.DSH_EDGE_TD_SAN ?? '3', 10)
300
+ permissionDeniedStreak: !!js parseInt(process.env.DSH_EDGE_TD_PERM ?? '5', 10)
301
+ blockLevel: !!js process.env.DSH_EDGE_TD_BLOCK_LEVEL ?? 'critical'
302
+
303
+ # Voice input (Whisper-tiny). MVP off by default.
304
+ - id: voice-input
305
+ name: '@dsh-edge/dsh-edge-agent/voice-input'
306
+ inject: [sessions, auditLog]
307
+ config:
308
+ modelPath: !!js process.env.DSH_EDGE_VOICE_MODEL ?? ((process.env.USERPROFILE ?? process.env.HOME) + '/.dsh-edge-agent/models/whisper-tiny.bin')
309
+ vadSilenceThreshold: !!js parseFloat(process.env.DSH_EDGE_VOICE_VAD ?? '0.6')
310
+ sampleRate: !!js parseInt(process.env.DSH_EDGE_VOICE_SR ?? '16000', 10)
311
+
312
+ # Plugin-interop anchor (Community Consensus v0.15 unified grant store,
313
+ # runtime generation id, Host Descriptor). Mounted ahead of any third-party
314
+ # plugin row.
315
+ - id: plugin-host
316
+ name: '@dsh-edge/dsh-edge-agent/plugin-host'
317
+ inject: [agents, sessions]
318
+ config:
319
+ enableThirdParty: !!js process.env.DSH_EDGE_PLUGINS_THIRD_PARTY === 'true'
320
+ grantStorePath: !!js (process.env.DSH_EDGE_STORAGE_ROOT ?? ((process.env.USERPROFILE ?? process.env.HOME) + '/.dsh-edge-agent')) + '/grants.json'
321
+
322
+ # ─────────────────────────────────────────────────────────────────────────────
323
+ # 4. Sandbox + telemetry
324
+ # ─────────────────────────────────────────────────────────────────────────────
325
+
326
+ # Sandbox confinement. The edge agent defaults to workspace-write; cloud
327
+ # requests are gated by secure-bridge, not the sandbox.
328
+ - id: sandbox-policy
329
+ name: '@deepseek-ai/dsh-sandbox-local'
330
+ config:
331
+ mode: !!js "process.platform === 'win32' ? 'danger-full-access' : (process.env.DSH_EDGE_PERMISSION_MODE ?? 'workspace-write')"
332
+ workspaceRoot: !!js process.cwd()
333
+
334
+ # Subprocess + bash capability. Edge agent uses a tighter timeout than the
335
+ # default coding agent (60s vs the dsh-base 10min) because edge sessions are
336
+ # shorter-lived.
337
+ - id: subprocess
338
+ name: '@deepseek-ai/dsh-subprocess-local'
339
+
340
+ - id: bash
341
+ name: '@deepseek-ai/dsh-bash-local'
342
+ config:
343
+ cwd: !!js process.cwd()
344
+ timeoutMs: !!js parseInt(process.env.DSH_EDGE_BASH_TIMEOUT_MS ?? '60000', 10)
345
+
346
+ # Model-facing bash tool
347
+ - id: tool-bash
348
+ name: '@deepseek-ai/dsh-tool-bash'
349
+ config:
350
+ enableRunInBackground: false
351
+
352
+ # Model-facing web tools (web_search + web_fetch)
353
+ - id: tool-web
354
+ name: '@deepseek-ai/dsh-tool-web'
355
+ config:
356
+ search: true
357
+ fetch: true
358
+ searchMaxResults: 8
359
+ fetchTimeoutMs: 30000
360
+ searchTimeoutMs: 30000
361
+
362
+ # DeepSeek web search provider (Anthropic-compatible API)
363
+ - id: web-search-deepseek
364
+ name: '@deepseek-ai/dsh-web-search-deepseek'
365
+ config:
366
+ apiKeyEnv: DEEPSEEK_API_KEY
367
+ baseURL: https://api.deepseek.com/anthropic/v1
368
+ model: deepseek-v4-flash
369
+
370
+ # Telemetry (DSH built-in).
371
+ - id: telemetry
372
+ name: '@deepseek-ai/dsh-telemetry'
373
+ config:
374
+ enabled: !!js process.env.DSH_EDGE_TELEMETRY === 'true'
@@ -0,0 +1,2 @@
1
+ export * from './dsh-adapter/attestation.js';
2
+ //# sourceMappingURL=attestation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attestation.d.ts","sourceRoot":"","sources":["../src/attestation.ts"],"names":[],"mappings":"AACA,cAAc,8BAA8B,CAAA"}
@@ -0,0 +1,2 @@
1
+ // @module dsh-edge-agent/attestation
2
+ export * from './dsh-adapter/attestation.js';
@@ -0,0 +1,2 @@
1
+ export * from './dsh-adapter/audit-log.js';
2
+ //# sourceMappingURL=audit-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-log.d.ts","sourceRoot":"","sources":["../src/audit-log.ts"],"names":[],"mappings":"AACA,cAAc,4BAA4B,CAAA"}
@@ -0,0 +1,2 @@
1
+ // @module dsh-edge-agent/audit-log
2
+ export * from './dsh-adapter/audit-log.js';
package/lib/client.js ADDED
@@ -0,0 +1,87 @@
1
+ /* dsh-edge-agent client bundle — generated by scripts/build-client.mjs.
2
+ Format: DSH webview module-system registration (classic script). */
3
+ window.__ModuleLoader__.load({
4
+ id: "@dsh-edge/dsh-edge-agent",
5
+ factory: function (require) {
6
+ var module = { exports: {} };
7
+ var exports = module.exports;
8
+ (function () {
9
+ "use strict";var re=Object.defineProperty;var Fe=Object.getOwnPropertyDescriptor;var De=Object.getOwnPropertyNames;var Oe=Object.prototype.hasOwnProperty;var _e=(e,n)=>{for(var o in n)re(e,o,{get:n[o],enumerable:!0})},Ne=(e,n,o,i)=>{if(n&&typeof n=="object"||typeof n=="function")for(let s of De(n))!Oe.call(e,s)&&s!==o&&re(e,s,{get:()=>n[s],enumerable:!(i=Fe(n,s))||i.enumerable});return e};var Ae=e=>Ne(re({},"__esModule",{value:!0}),e);var Lt={};_e(Lt,{EdgeView:()=>Me,apply:()=>Tt,h:()=>L.createElement,inject:()=>Rt,name:()=>xt,render:()=>Ct});module.exports=Ae(Lt);var L=require("react"),je=require("react-dom/client");var fe="api/dsh-edge/context",pe="api/dsh-edge/trace";var We=2e3,le=200,U=new Map,ie=new Set,H,Y=0;function Be(){for(let e of[...ie])try{e()}catch{}}function we(e){let n=U.get(e);return n||(n={cursor:0,rows:[],summary:{sessionId:e,turns:0},failures:0},U.set(e,n)),n}async function ge(e){for(let n of e){let o=we(n);try{let i=await fetch(fe,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({sessionId:n,cursor:o.cursor})});if(!i.ok){o.failures+=1;continue}let s=await i.json();o.failures=0,typeof s.cursor=="number"&&s.cursor>o.cursor&&(o.cursor=s.cursor),Array.isArray(s.rows)&&(o.rows=[...o.rows,...s.rows.filter(r=>r&&typeof r.kind=="string"&&typeof r.panel=="string")],o.rows.length>le*4&&(o.rows=o.rows.slice(-le*4))),s.summary&&typeof s.summary=="object"&&(o.summary=s.summary)}catch{o.failures+=1}}Be()}function Ge(){H===void 0&&(ge([...U.keys()]),H=setInterval(()=>{Y!==0&&ge([...U.keys()])},We))}function Ue(){Y>0||H===void 0||(clearInterval(H),H=void 0)}async function be(e){try{let n=await fetch(pe,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({traceId:e})});if(!n.ok){let s=`HTTP ${n.status}`;try{let r=await n.json();typeof r?.error=="string"&&r.error.length>0&&(s=r.error)}catch{}return{ok:!1,error:s}}let o=await n.json(),i;try{i=JSON.stringify(o,null,2)??String(o)}catch{i=String(o)}return{ok:!0,text:i}}catch(n){return{ok:!1,error:n instanceof Error?n.message:String(n)}}}var V={attach(e,n){return Y+=1,we(e),ie.add(n),Ge(),n(),()=>{Y-=1,ie.delete(n),Ue()}},rowsFor(e,n,o,i){return this.currentRows(e,o,i).filter(s=>s.panel===n)},currentRows(e,n,o){let i=U.get(e);if(!i)return[];let s=[];for(let r of i.rows)o!==void 0&&r.ts<o||s.push(r);return s.slice(-le)},summaryFor(e){return U.get(e)?.summary??{sessionId:e,turns:0}},failing(e){return(U.get(e)?.failures??0)>=3}};var he="dsh-edge-agent-styles",qe=`
10
+ /* The host's tab body is overflow:hidden (SidebarRight.module.css .tabBody) and
11
+ hands scrolling to the occupant \u2014 without an explicit scroll container here
12
+ the flow + panels below the fold were simply clipped (observed desktop
13
+ 10-23: threat panel unreachable). flex:none keeps sections at natural height
14
+ inside the scroller instead of shrinking. */
15
+ .dsh-edge-view { font-size: 12px; line-height: 1.5; padding: 8px 10px; display: flex; flex-direction: column; gap: 10px; height: 100%; overflow-y: auto; box-sizing: border-box; }
16
+ .dsh-edge-view > * { flex: none; }
17
+ .dsh-edge-tab-title { font-weight: 500; }
18
+ .dsh-edge-flow { display: flex; flex-direction: column; padding: 6px 8px; border-radius: 6px; background: color-mix(in srgb, currentColor 4%, transparent); }
19
+ /* \xA77.107: every node renders with the same three levels \u2014 label line,
20
+ verdict line, evidence lines. The label used to share a baseline with
21
+ the verdict, so a long verdict wrapped under the label and the column
22
+ lost its grid. */
23
+ .dsh-edge-flow-node { display: flex; flex-direction: column; font-size: 12px; line-height: 1.5; }
24
+ .dsh-edge-flow-head { display: flex; align-items: center; gap: 6px; }
25
+ .dsh-edge-flow-arrow { width: 8px; text-align: center; opacity: 0.35; font-size: 10px; line-height: 1.1; margin-left: 3px; }
26
+ .dsh-edge-flow-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; align-self: center; background: color-mix(in srgb, currentColor 25%, transparent); }
27
+ .dsh-edge-flow-label { flex: none; font-weight: 600; }
28
+ .dsh-edge-flow-detail { padding-left: 14px; opacity: 0.85; overflow-wrap: anywhere; }
29
+ .dsh-edge-flow-sub { font-size: 11px; line-height: 1.5; opacity: 0.55; padding-left: 26px; overflow-wrap: anywhere; }
30
+ .dsh-edge-flow-node--ok .dsh-edge-flow-dot { background: #16a34a; }
31
+ .dsh-edge-flow-node--warn .dsh-edge-flow-dot { background: #d97706; }
32
+ .dsh-edge-flow-node--stop .dsh-edge-flow-dot { background: #dc2626; }
33
+ .dsh-edge-flow-node--run .dsh-edge-flow-dot { background: #2563eb; }
34
+ .dsh-edge-flow-node--info .dsh-edge-flow-dot { background: #64748b; }
35
+ .dsh-edge-flow-node--wait { opacity: 0.5; }
36
+ .dsh-edge-verdict { font-size: 12px; font-weight: 600; padding: 5px 8px; border-radius: 6px; border-left: 2px solid currentColor; background: color-mix(in srgb, currentColor 5%, transparent); }
37
+ .dsh-edge-verdict--local { color: #16a34a; }
38
+ .dsh-edge-verdict--cloud { color: inherit; }
39
+ .dsh-edge-verdict--wait { opacity: 0.55; font-weight: 400; }
40
+ /* \xA77.145: \u672A\u7ED1\u5B9A\u4F1A\u8BDD \u2014\u2014 \u660E\u8BF4\u300C\u73B0\u5728\u6CA1\u6709\u4F1A\u8BDD\u300D\uFF0C\u5168\u5C40\u4FE1\u53F7\u53E6\u8D77\u4E00\u7EC4\u3002 */
41
+ .dsh-edge-unbound { display: flex; flex-direction: column; gap: 3px; padding: 6px 8px; border-radius: 6px; border-left: 2px solid color-mix(in srgb, currentColor 35%, transparent); background: color-mix(in srgb, currentColor 5%, transparent); }
42
+ .dsh-edge-unbound b { font-weight: 600; }
43
+ .dsh-edge-unbound span { opacity: 0.7; font-size: 11px; line-height: 1.5; }
44
+ .dsh-edge-groups { display: flex; flex-direction: column; gap: 8px; }
45
+ .dsh-edge-summary { display: flex; flex-wrap: wrap; gap: 10px; padding: 6px 8px; border-radius: 6px; background: color-mix(in srgb, currentColor 6%, transparent); }
46
+ .dsh-edge-summary b { font-weight: 600; }
47
+ .dsh-edge-panel h4 { margin: 0 0 4px 0; font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.65; font-weight: 600; }
48
+ .dsh-edge-rows { display: flex; flex-direction: column; gap: 3px; max-height: 240px; overflow-y: auto; }
49
+ .dsh-edge-row { padding: 3px 6px; border-radius: 4px; background: color-mix(in srgb, currentColor 4%, transparent); }
50
+ .dsh-edge-row-head { display: flex; gap: 6px; align-items: baseline; }
51
+ .dsh-edge-row .ts { opacity: 0.5; flex: none; font-variant-numeric: tabular-nums; font-size: 11px; }
52
+ .dsh-edge-row .k { font-weight: 600; overflow-wrap: anywhere; }
53
+ .dsh-edge-row .f { opacity: 0.75; font-size: 11px; line-height: 1.35; margin-top: 1px; overflow-wrap: anywhere; }
54
+ .dsh-edge-row.warn { background: color-mix(in srgb, #d97706 14%, transparent); }
55
+ .dsh-edge-row.error, .dsh-edge-row.security { background: color-mix(in srgb, #dc2626 14%, transparent); }
56
+ .dsh-edge-empty, .dsh-edge-stale { opacity: 0.5; font-style: italic; }
57
+ .dsh-edge-stale { color: #dc2626; opacity: 0.8; }
58
+ /* \xA77.133: the LLM call log \u2014 one line per call, body on demand. */
59
+ .dsh-edge-trace { display: flex; flex-direction: column; gap: 4px; }
60
+ .dsh-edge-trace-count { margin-left: auto; opacity: 0.5; font-variant-numeric: tabular-nums; }
61
+ .dsh-edge-trace-list { display: flex; flex-direction: column; gap: 4px; }
62
+ .dsh-edge-trace-item { padding: 4px 6px; border-radius: 4px; background: color-mix(in srgb, currentColor 4%, transparent); }
63
+ .dsh-edge-trace-head { display: flex; gap: 6px; align-items: baseline; width: 100%; text-align: left; background: none; border: none; color: inherit; font: inherit; padding: 0; cursor: pointer; }
64
+ .dsh-edge-trace-badge { flex: none; font-size: 10px; font-weight: 700; letter-spacing: 0.03em; padding: 0 3px; border-radius: 3px; background: color-mix(in srgb, currentColor 15%, transparent); }
65
+ .dsh-edge-trace-badge--req { color: #2563eb; }
66
+ .dsh-edge-trace-badge--resp { color: #16a34a; }
67
+ .dsh-edge-trace-model { flex: 1 1 auto; font-weight: 600; overflow-wrap: anywhere; }
68
+ .dsh-edge-trace-caller { flex: none; font-size: 10px; opacity: 0.65; border: 1px solid color-mix(in srgb, currentColor 25%, transparent); border-radius: 3px; padding: 0 3px; }
69
+ .dsh-edge-trace-caller--main { opacity: 0.9; }
70
+ .dsh-edge-trace-sum { font-size: 11px; opacity: 0.8; padding-left: 2px; overflow-wrap: anywhere; }
71
+ .dsh-edge-trace-meta { font-size: 10px; opacity: 0.45; overflow-wrap: anywhere; }
72
+ .dsh-edge-trace-body { margin-top: 4px; }
73
+ .dsh-edge-trace-body-err { font-size: 11px; color: #d97706; }
74
+ .dsh-edge-trace-pre { margin: 0; max-height: 260px; overflow: auto; padding: 5px 6px; border-radius: 4px; background: color-mix(in srgb, currentColor 6%, transparent); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere; }
75
+ /* \xA77.134: \u6309\u7C7B\u522B\u5206\u7EC4 + \u8BF7\u6C42/\u54CD\u5E94\u6210\u5BF9\uFF08\u4E0A\u8BF7\u6C42\u3001\u4E0B\u54CD\u5E94\uFF09\u3002 */
76
+ .dsh-edge-trace-group { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; }
77
+ .dsh-edge-trace-group-head { display: flex; gap: 6px; align-items: baseline; padding: 1px 2px; border-bottom: 1px solid color-mix(in srgb, currentColor 15%, transparent); }
78
+ .dsh-edge-trace-group-name { font-size: 11px; font-weight: 700; letter-spacing: 0.02em; }
79
+ .dsh-edge-trace-pair { display: flex; flex-direction: column; gap: 2px; padding: 4px 6px; border-radius: 4px; background: color-mix(in srgb, currentColor 4%, transparent); }
80
+ .dsh-edge-trace-half { padding-left: 6px; border-left: 2px solid transparent; }
81
+ .dsh-edge-trace-half--req { border-left-color: #2563eb; }
82
+ .dsh-edge-trace-half--resp { border-left-color: #16a34a; }
83
+ `;function me(e){let n=e??(typeof document<"u"?document:void 0);if(n===void 0||n.getElementById(he)!==null)return;let o=n.createElement("style");o.id=he,o.textContent=qe,n.head.appendChild(o)}var Z={"tab.title":"Edge","panel.intent":"Intent","panel.route":"Route","panel.interception":"Interception","panel.threat":"Threat","summary.turns":"turns","summary.tokens":"tokens","summary.noTokens":"no usage reported","summary.age":"age","row.empty":"no events yet","row.stale":"edge host unreachable","guide.description":"Intent classification \xB7 model routing \xB7 guard / sanitizer events \xB7 threat levels","verdict.local":"This turn: answered locally \u2014 data never left the device","verdict.cloud":"This turn: answered by the cloud route","verdict.sanitized":" (PII sanitized first)","verdict.waiting":"This turn: awaiting classification","flow.guard":"attack check","flow.intent":"intent verdict","flow.sanitize":"PII scrub","flow.route":"routing","flow.answer":"answer egress","flow.wait":"waiting","flow.running":"running\u2026","flow.guard.injection":"injection pattern hit (warned, passed)","flow.guard.failopen":"model check failed \u2192 regex tier held","flow.guard.public":"clean (public data)","flow.guard.skipped":"rules tier only","flow.guard.running":"model judging\u2026","flow.intent.rejected":"policy denied","flow.intent.viaEntity":"entity rule","flow.intent.viaLlm":"LLM verdict","flow.intent.viaDefault":"default fallback (classifier silent)","flow.intent.viaPolicy":"privacy rule decided (classifier skipped)","flow.intent.noWebNeed":"no public-web need \u2192 kept on device","flow.intent.noWebNeedWhy":"the classifier asked for the cloud, but the request was not a public-web search","flow.intent.defaultNoCause":"classifier silent \u2014 defaultCategory applied","flow.answer.carried":"carried from last route","flow.answer.running":"answering\u2026","flow.answer.failed":"answer failed","flow.sanitize.hits":"scrubbed","flow.sanitize.done":"scrubbed","flow.sanitize.failed":"scrub failed \u2192 answered locally","flow.sanitize.localSkip":"not needed (local)","flow.sanitize.clean":"no PII found","flow.route.blocked":"blocked","flow.route.fallback":"answered locally (cloud unavailable)","flow.route.kept":"as selected","flow.answer.pending":"route not settled yet","flow.answer.local":"local model \xB7 stayed on device","flow.answer.cloud":"cloud:","flow.lbl.cause":"cause","flow.lbl.judge":"verdict","flow.lbl.model":"model","flow.lbl.input":"input","flow.lbl.elapsed":"took","flow.lbl.scanned":"scanned","flow.lbl.chars":"chars","flow.lbl.msgs":"messages","flow.lbl.rule":"rule","flow.lbl.confidence":"confidence","flow.lbl.pool":"cloud pool","flow.lbl.verdict":"verdict","flow.lbl.override":"override","flow.lbl.entity":"entity","flow.lbl.llmSay":"LLM said","flow.lbl.overridden":"\u2014 overridden by rule","flow.lbl.classifier":"classifier","flow.lbl.reason":"reason","flow.lbl.entry":"entry","flow.lbl.edgePool":"edge cloud pool","flow.lbl.used":"used","flow.lbl.hostOwn":"not used (host route)","flow.lbl.steps":"steps","flow.lbl.total":"total","flow.lbl.context":"last context","flow.lbl.in":"in","flow.lbl.out":"out","flow.lbl.route":"route","flow.class.public":"public","flow.class.internal":"internal","flow.class.confidential":"confidential","flow.class.secret":"secret","flow.g.guardrule":"warn-tier pattern hit","flow.g.regexOn":"regex tier still on duty","flow.s.done":"scrubbed","flow.sanitize.unit":"spans","flow.s.localWhy":"answer never leaves the device \u2014 nothing to scrub","flow.s.cleanWhy":"checked, no PII in the outbound text","flow.s.desanitized":"placeholders restored in the answer","flow.a.localKeep":"question, context and answer all stayed on this machine","flow.a.cloudSend":"outbound text was checked / scrubbed first","flow.lbl.risk":"risk","flow.lbl.why":"why","flow.lbl.hit":"hit","flow.lbl.regex":"regex","flow.lbl.keyword":"keyword","flow.lbl.semantic":"meaning","flow.lbl.path":"path","flow.lbl.jev":"decision model","flow.lbl.ph":"placeholder","flow.lbl.raw":"raw","flow.lbl.scope":"scope","flow.lbl.global":"global","flow.lbl.session":"session","flow.lbl.watched":"signals watched","flow.lbl.decidedBy":"decided by","flow.lbl.endpoint":"endpoint","flow.lbl.rerouted":"selection \u2192 actual","flow.lbl.onDevice":"on this device","flow.lbl.offDevice":"OFF-DEVICE","flow.intent.byJev":"decision model (LLM classifier not called)","flow.intent.byDeviceCommand":"device-command regex (classifier not called)","flow.intent.byLlm":"LLM classifier","flow.intent.byCache":"cached verdict","flow.intent.byRules":"keyword rules","flow.intent.byGate":"public-web gate","flow.intent.byUnknown":"unknown path","flow.intent.viaJev":"decision model","flow.intent.viaDeviceCommand":"device-command regex verdict","flow.intent.viaCache":"cached verdict","flow.intent.viaRules":"keyword rules","flow.guard.unsafe":"unsafe","flow.threat":"threat watch","flow.threat.calm":"quiet in this window","flow.threat.escalated":"threat escalated","flow.threat.rate":"rate limit hit","flow.threat.blocked":"blocked as threat","trace.title":"LLM calls","trace.empty":"no LLM call recorded in this turn","trace.req":"REQ","trace.resp":"RESP","trace.caller.guard":"guard check","trace.caller.classifier":"classifier","trace.caller.host":"host internal call","trace.caller.conversation":"conversation","trace.lbl.messages":"msgs","trace.lbl.chars":"chars","trace.lbl.dropped":"dropped","trace.lbl.toolCalls":"tool calls","trace.lbl.tools":"tools","trace.body.loading":"loading body\u2026","trace.body.gone":"body no longer in memory (only the latest calls are kept)","trace.body.error":"could not load body","trace.group.other":"other calls","unbound.title":"not bound to a session yet","unbound.hint":"No turn of this session is on the page yet \u2014 what follows are global signals, not one round. Start a turn and this becomes that session's record.","unbound.globalTitle":"global signals","unbound.empty":"no global signals right now"},ee={"tab.title":"Edge","panel.intent":"\u610F\u56FE","panel.route":"\u8DEF\u7531","panel.interception":"\u62E6\u622A","panel.threat":"\u5A01\u80C1","summary.turns":"\u8F6E\u6B21","summary.tokens":"token","summary.noTokens":"\u672A\u4E0A\u62A5\u7528\u91CF","summary.age":"\u65F6\u957F","row.empty":"\u6682\u65E0\u4E8B\u4EF6","row.stale":"edge \u670D\u52A1\u4E0D\u53EF\u8FBE","guide.description":"\u610F\u56FE\u5206\u7C7B \xB7 \u6A21\u578B\u8DEF\u7531 \xB7 \u9632\u62A4/\u8131\u654F\u4E8B\u4EF6 \xB7 \u5A01\u80C1\u6863\u4F4D","verdict.local":"\u672C\u8F6E\uFF1A\u672C\u5730\u6A21\u578B\u4F5C\u7B54 \u2014\u2014 \u6570\u636E\u672A\u79BB\u5F00\u8BBE\u5907","verdict.cloud":"\u672C\u8F6E\uFF1A\u4E91\u7AEF\u4F5C\u7B54","verdict.sanitized":"\uFF08\u5DF2\u5148\u8131\u654F\uFF09","verdict.waiting":"\u672C\u8F6E\uFF1A\u7B49\u5F85\u610F\u56FE\u5224\u5B9A","flow.guard":"\u653B\u51FB\u68C0\u6D4B","flow.intent":"\u610F\u56FE\u5224\u5B9A","flow.sanitize":"PII \u8131\u654F","flow.route":"\u8DEF\u7531\u51B3\u7B56","flow.answer":"\u7B54\u6848\u51FA\u53E3","flow.wait":"\u7B49\u5F85","flow.running":"\u8FDB\u884C\u4E2D\u2026","flow.guard.injection":"\u547D\u4E2D\u6CE8\u5165\u7279\u5F81\uFF08\u544A\u8B66\u653E\u884C\uFF09","flow.guard.failopen":"\u6A21\u578B\u68C0\u6D4B\u5931\u8D25 \u2192 \u6B63\u5219\u6863\u515C\u5E95","flow.guard.public":"\u5E72\u51C0\uFF08\u516C\u5F00\u7EA7\uFF09","flow.guard.skipped":"\u4EC5\u89C4\u5219\u6863","flow.guard.running":"\u6A21\u578B\u5224\u5B9A\u4E2D\u2026","flow.intent.rejected":"\u7B56\u7565\u62D2\u7EDD","flow.intent.viaEntity":"\u5B9E\u4F53\u89C4\u5219\u88C1\u51B3","flow.intent.viaLlm":"LLM \u88C1\u51B3","flow.intent.viaDefault":"\u9ED8\u8BA4\u6863\u515C\u5E95\uFF08\u5206\u7C7B\u5668\u672A\u56DE\u8BDD\uFF09","flow.intent.viaPolicy":"\u9690\u79C1\u89C4\u5219\u547D\u4E2D\uFF08\u672A\u8D70\u5206\u7C7B\u5668\uFF09","flow.intent.noWebNeed":"\u65E0\u516C\u7F51\u68C0\u7D22\u9700\u6C42 \u2192 \u7559\u5728\u672C\u5730","flow.intent.noWebNeedWhy":"\u5206\u7C7B\u5668\u5224\u4E86\u4E91\u7AEF\uFF0C\u4F46\u672C\u8F6E\u4E0D\u662F\u516C\u7F51\u68C0\u7D22\uFF0C\u62A4\u680F\u628A\u5B83\u6309\u56DE\u672C\u5730","flow.intent.defaultNoCause":"\u5206\u7C7B\u5668\u672A\u56DE\u8BDD\uFF0C\u8D70 defaultCategory \u515C\u5E95","flow.answer.carried":"\u6CBF\u7528\u4E0A\u4E00\u8F6E\u8DEF\u7531","flow.answer.running":"\u4F5C\u7B54\u4E2D\u2026","flow.answer.failed":"\u4F5C\u7B54\u5931\u8D25","flow.sanitize.hits":"\u5DF2\u66FF\u6362","flow.sanitize.done":"\u5DF2\u8131\u654F","flow.sanitize.failed":"\u8131\u654F\u5931\u8D25 \u2192 \u8F6C\u672C\u5730\u4F5C\u7B54","flow.sanitize.localSkip":"\u65E0\u9700\uFF08\u672C\u5730\u4F5C\u7B54\uFF09","flow.sanitize.clean":"\u672A\u53D1\u73B0 PII","flow.route.blocked":"\u5DF2\u62E6\u622A","flow.route.fallback":"\u8F6C\u672C\u5730\u4F5C\u7B54\uFF08\u4E91\u4E0D\u53EF\u7528\uFF09","flow.route.kept":"\u6309\u539F\u9009\u62E9","flow.answer.pending":"\u8DEF\u7531\u672A\u5B9A","flow.answer.local":"\u672C\u5730\u6A21\u578B \xB7 \u672A\u51FA\u8BBE\u5907","flow.answer.cloud":"\u4E91\u7AEF\uFF1A","flow.lbl.cause":"\u539F\u56E0","flow.lbl.judge":"\u5224\u5B9A","flow.lbl.model":"\u6A21\u578B","flow.lbl.input":"\u8F93\u5165","flow.lbl.elapsed":"\u7528\u65F6","flow.lbl.scanned":"\u68C0\u6D4B","flow.lbl.chars":"\u5B57","flow.lbl.msgs":"\u6761\u6D88\u606F","flow.lbl.rule":"\u547D\u4E2D\u89C4\u5219","flow.lbl.confidence":"\u7F6E\u4FE1","flow.lbl.pool":"\u4E91\u6C60","flow.lbl.verdict":"\u88C1\u51B3","flow.lbl.override":"\u6539\u5224","flow.lbl.entity":"\u5B9E\u4F53","flow.lbl.llmSay":"LLM \u539F\u5224","flow.lbl.overridden":"\u2014\u2014\u88AB\u89C4\u5219\u6539\u5224","flow.lbl.classifier":"\u5206\u7C7B\u5668","flow.lbl.reason":"\u7406\u7531","flow.lbl.entry":"\u5165\u53E3","flow.lbl.edgePool":"edge \u4E91\u6C60","flow.lbl.used":"\u5DF2\u4F7F\u7528","flow.lbl.hostOwn":"\u672A\u4F7F\u7528\uFF08\u8D70\u5BBF\u4E3B\u8DEF\u7531\uFF09","flow.lbl.steps":"\u6B65\u6570","flow.lbl.total":"\u7528\u65F6\u5408\u8BA1","flow.lbl.context":"\u672B\u8F6E\u4E0A\u4E0B\u6587","flow.lbl.in":"\u5165","flow.lbl.out":"\u51FA","flow.lbl.route":"\u8DEF\u7531","flow.class.public":"\u516C\u5F00\u7EA7","flow.class.internal":"\u5185\u90E8\u7EA7","flow.class.confidential":"\u673A\u5BC6\u7EA7","flow.class.secret":"\u654F\u611F\u7EA7","flow.g.guardrule":"\u547D\u4E2D\u544A\u8B66\u7EA7\u6CE8\u5165\u7279\u5F81","flow.g.regexOn":"\u6B63\u5219\u6863\u4ECD\u5728\u6267\u52E4","flow.s.done":"\u5DF2\u8131\u654F","flow.sanitize.unit":"\u5904","flow.s.localWhy":"\u7B54\u6848\u4E0D\u51FA\u8BBE\u5907\uFF0C\u65E0\u9700\u8131\u654F","flow.s.cleanWhy":"\u5DF2\u68C0\u67E5\uFF0C\u51FA\u5411\u6587\u672C\u65E0 PII","flow.s.desanitized":"\u7B54\u6848\u4E2D\u7684\u5360\u4F4D\u7B26\u5DF2\u8FD8\u539F","flow.a.localKeep":"\u95EE\u9898\u3001\u4E0A\u4E0B\u6587\u3001\u7B54\u6848\u5168\u90E8\u7559\u5728\u672C\u673A","flow.a.cloudSend":"\u51FA\u7F51\u6587\u672C\u5DF2\u5148\u884C\u68C0\u67E5/\u8131\u654F","flow.lbl.risk":"\u98CE\u9669\u7B49\u7EA7","flow.lbl.why":"\u7406\u7531","flow.lbl.hit":"\u547D\u4E2D","flow.lbl.regex":"\u6B63\u5219","flow.lbl.keyword":"\u5173\u952E\u5B57","flow.lbl.semantic":"\u8BED\u4E49","flow.lbl.path":"\u8DEF\u5F84","flow.lbl.jev":"\u51B3\u7B56\u6A21\u578B","flow.lbl.ph":"\u5360\u4F4D\u7B26","flow.lbl.raw":"\u539F\u59CB","flow.lbl.scope":"\u8303\u56F4","flow.lbl.global":"\u5168\u5C40","flow.lbl.session":"\u4F1A\u8BDD","flow.lbl.watched":"\u5DF2\u68C0\u4FE1\u53F7","flow.lbl.decidedBy":"\u88C1\u51B3\u8005","flow.lbl.endpoint":"\u771F\u5B9E\u843D\u70B9","flow.lbl.rerouted":"\u4F1A\u8BDD\u9009\u578B \u2192 \u5B9E\u9645\u843D\u70B9","flow.lbl.onDevice":"\u672C\u673A","flow.lbl.offDevice":"\u4E0D\u5728\u672C\u673A","flow.intent.byJev":"\u51B3\u7B56\u6A21\u578B\uFF08LLM \u5206\u7C7B\u5668\u672A\u8C03\u7528\uFF09","flow.intent.byDeviceCommand":"\u8BBE\u5907\u6307\u4EE4\u6B63\u5219\uFF08\u5206\u7C7B\u5668\u672A\u8C03\u7528\uFF09","flow.intent.byLlm":"LLM \u5206\u7C7B\u5668","flow.intent.byCache":"\u7F13\u5B58\u547D\u4E2D","flow.intent.byRules":"\u5173\u952E\u8BCD\u89C4\u5219","flow.intent.byGate":"\u516C\u7F51\u68C0\u7D22\u95F8\u95E8","flow.intent.byUnknown":"\u672A\u77E5\u8DEF\u5F84","flow.intent.viaJev":"\u51B3\u7B56\u6A21\u578B\u88C1\u51B3","flow.intent.viaDeviceCommand":"\u8BBE\u5907\u6307\u4EE4\u6B63\u5219\u88C1\u51B3","flow.intent.viaCache":"\u7F13\u5B58\u547D\u4E2D","flow.intent.viaRules":"\u5173\u952E\u8BCD\u89C4\u5219\u88C1\u51B3","flow.guard.unsafe":"\u5224\u5B9A\u4E0D\u5B89\u5168","flow.threat":"\u5A01\u80C1\u76D1\u63A7","flow.threat.calm":"\u672C\u8F6E\u7A97\u53E3\u65E0\u5F02\u5E38","flow.threat.escalated":"\u5A01\u80C1\u7B49\u7EA7\u5347\u7EA7","flow.threat.rate":"\u9891\u7387\u9650\u5236\u89E6\u53D1","flow.threat.blocked":"\u5A01\u80C1\u8BF7\u6C42\u5DF2\u963B\u65AD","trace.title":"LLM \u8C03\u7528","trace.empty":"\u672C\u8F6E\u6CA1\u6709\u8BB0\u5F55\u5230 LLM \u8C03\u7528","trace.req":"\u8BF7\u6C42","trace.resp":"\u54CD\u5E94","trace.caller.guard":"\u5B89\u68C0","trace.caller.classifier":"\u5206\u7C7B\u5668","trace.caller.host":"\u5BBF\u4E3B\u5185\u90E8\u8C03\u7528","trace.caller.conversation":"\u4E3B\u5BF9\u8BDD","trace.lbl.messages":"\u6761\u6D88\u606F","trace.lbl.chars":"\u5B57\u7B26","trace.lbl.dropped":"\u5DF2\u4E22\u5F03","trace.lbl.toolCalls":"\u5DE5\u5177\u8C03\u7528","trace.lbl.tools":"\u5DE5\u5177","trace.body.loading":"\u62C9\u53D6\u6B63\u6587\u4E2D\u2026","trace.body.gone":"\u6B63\u6587\u5DF2\u4E0D\u5728\u5185\u5B58\uFF08\u53EA\u4FDD\u7559\u6700\u8FD1\u7684\u8C03\u7528\uFF09","trace.body.error":"\u53D6\u6B63\u6587\u5931\u8D25","trace.group.other":"\u5176\u4ED6\u8C03\u7528","unbound.title":"\u5C1A\u672A\u7ED1\u5B9A\u4F1A\u8BDD","unbound.hint":"\u8FD9\u4E00\u9875\u8FD8\u6CA1\u6709\u5C5E\u4E8E\u8FD9\u4E2A\u4F1A\u8BDD\u7684\u4E00\u8F6E \u2014\u2014 \u4E0B\u9762\u662F\u5168\u5C40\u4FE1\u53F7\uFF0C\u4E0D\u662F\u67D0\u4E00\u8F6E\u3002\u5F00\u59CB\u4E00\u8F6E\u5BF9\u8BDD\u540E\uFF0C\u8FD9\u91CC\u4F1A\u53D8\u6210\u8BE5\u4F1A\u8BDD\u7684\u8BB0\u5F55\u3002","unbound.globalTitle":"\u5168\u5C40\u4FE1\u53F7","unbound.empty":"\u6682\u65E0\u5168\u5C40\u4FE1\u53F7"},ye=e=>ee[e]??Z[e]??e;function ve(e){typeof e=="function"&&(ye=n=>{try{let o=e(n);return o===n?ee[n]??Z[n]??n:o}catch{return ee[n]??Z[n]??n}})}function t(e){return ye(e)}var te="dsh-edge-agent",ke={zh:ee,en:Z};var A=require("react");function Je(e,n){if(e===void 0||n===void 0)return"\u2014";let o=Math.max(0,Math.round((n-e)/1e3));if(o<60)return`${o}s`;let i=Math.floor(o/60);return i<60?`${i}m${o%60}s`:`${Math.floor(i/60)}h${i%60}m`}function Ve(e){if(e===void 0)return t("summary.noTokens");let n=e.input??0,o=e.output??0;return`${n} in / ${o} out`}function $e(e){let{summary:n}=e;return(0,A.createElement)("div",{class:"dsh-edge-summary"},(0,A.createElement)("span",null,t("summary.turns")," ",(0,A.createElement)("b",null,String(n.turns))),(0,A.createElement)("span",null,t("summary.tokens")," ",(0,A.createElement)("b",null,Ve(n.tokens))),(0,A.createElement)("span",null,t("summary.age")," ",(0,A.createElement)("b",null,Je(n.startedAt,n.lastSeenAt))))}var F=require("react");var m=(e,n)=>[...e].reverse().find(n),l=(e,n)=>e?.payload[n],xe=e=>typeof e.payload.rationale=="string"?e.payload.rationale:"",Q=e=>typeof e=="number"?`${(e/1e3).toFixed(1)}s`:"?",g=e=>typeof e=="string"?e:typeof e=="number"||typeof e=="boolean"?String(e):"?",se=e=>typeof e=="number"?e:void 0,ne=e=>typeof e=="number"?`${(e*100).toFixed(0)}%`:"?";function Ke(e){let n=`flow.class.${e}`,o=t(n);return o===n?e:`${o}\uFF08${e}\uFF09`}function W(e,n=44){return e.length<=n?e:`${e.slice(0,n-1)}\u2026`}function K(e){return Array.isArray(e)?e.filter(n=>typeof n=="string"):[]}function Qe(e){return e.length>0?e:t("flow.intent.byUnknown")}function He(e){let n=m(e,a=>a.kind==="guard.model-detect.end"),o=m(e,a=>a.kind==="guard.model-detect.unsafe"),i=m(e,a=>/^guard\.model-detect\.(error|timeout|provider_error)$/.test(a.kind)),s=m(e,a=>/^guard\.model-detect\.skip/.test(a.kind)),r=m(e,a=>a.kind==="guard.model-detect.start"),u=m(e,a=>a.kind==="input.injection.warned"||a.kind==="input.injection");if(u!==void 0&&o===void 0&&n===void 0){let a=K(l(u,"patterns")),p=K(l(u,"patternSources")),d=[];return a.length>0&&d.push(`${t("flow.lbl.hit")} ${a.join(", ")}`),p.length>0&&d.push(`${t("flow.lbl.regex")} ${W(p[0],40)}`),d.length===0&&d.push(t("flow.g.guardrule")),{label:t("flow.guard"),tone:"warn",detail:t("flow.guard.injection"),sub:d}}if(i!==void 0&&(n===void 0||i.ts>n.ts))return{label:t("flow.guard"),tone:"warn",detail:t("flow.guard.failopen"),sub:[`${t("flow.lbl.cause")} ${g(l(i,"reason"))} \xB7 ${Q(l(i,"durationMs"))}`,t("flow.g.regexOn")]};if(o!==void 0){let a=K(l(o,"threats")),p=[];a.length>0&&p.push(`${t("flow.lbl.hit")} ${a.join(", ")}`);let d=l(o,"rationale");return typeof d=="string"&&d.length>0&&p.push(`${t("flow.lbl.why")} ${W(d,40)}`),p.push(`${t("flow.lbl.model")} ${g(l(o,"provider"))}/${g(l(o,"model"))} \xB7 ${Q(l(o,"durationMs"))}`),{label:t("flow.guard"),tone:"stop",detail:`${t("flow.guard.unsafe")} \xB7 ${g(l(o,"dataClass"))}`,sub:p}}if(n!==void 0){let a=typeof n.payload.dataClass=="string"?n.payload.dataClass:"?",p=[`${t("flow.lbl.model")} ${g(l(n,"modelProvider")??l(n,"provider"))}/${g(l(n,"model"))}`,`${t("flow.lbl.elapsed")} ${Q(l(n,"durationMs"))} \xB7 ${t("flow.lbl.scanned")} ${g(l(n,"textLen"))} ${t("flow.lbl.chars")}`],d=l(n,"rationale");if(typeof d=="string"&&d.length>0&&p.push(`${t("flow.lbl.why")} ${W(d,40)}`),u!==void 0){let y=K(l(u,"patterns"));y.length>0&&p.push(`${t("flow.lbl.hit")} ${y.join(", ")}`)}return{label:t("flow.guard"),tone:"ok",detail:a==="public"?t("flow.guard.public"):Ke(a),sub:p}}if(s!==void 0){let a=[],p=l(s,"reason");typeof p=="string"&&p.length>0&&a.push(`${t("flow.lbl.cause")} ${p}`);let d=l(s,"rationale");return typeof d=="string"&&d.length>0&&a.push(`${t("flow.lbl.why")} ${W(d,40)}`),{label:t("flow.guard"),tone:"ok",detail:t("flow.guard.skipped"),sub:a}}return r!==void 0?{label:t("flow.guard"),tone:"run",detail:t("flow.guard.running"),sub:[]}:{label:t("flow.guard"),tone:"wait",detail:t("flow.wait"),sub:[]}}function Xe(e){let n=m(e,a=>a.kind==="intent.classify.end"),o=m(e,a=>a.kind==="intent.classify.entity_override"),i=m(e,a=>a.kind==="intent.rules.rejected"),s=m(e,a=>a.kind==="intent.classify.start"),r=m(e,a=>a.kind==="intent.jev.response"),u=m(e,a=>a.kind==="input-guard.policy.route-applied");if(i!==void 0&&(n===void 0||i.ts>n.ts)){let a=[],p=l(i,"riskScore");typeof p=="number"&&a.push(`${t("flow.lbl.risk")} ${p.toFixed(2)}`);let d=l(i,"intent");return typeof d=="string"&&d.length>0&&a.push(`${t("flow.lbl.hit")} ${d}`),{label:t("flow.intent"),tone:"stop",detail:t("flow.intent.rejected"),sub:a}}if(n!==void 0){let a=g(l(n,"category")),p=ne(l(n,"confidence")),d=[`${t("flow.lbl.verdict")} ${a} \xB7 ${p} \xB7 ${g(l(n,"rationale"))}`];o!==void 0&&o.ts<=n.ts&&(d.push(`${t("flow.lbl.override")} ${g(l(o,"from"))} \u2192 ${g(l(o,"to"))} \xB7 ${t("flow.lbl.entity")} ${g(l(o,"entity"))}`),d.push(`${t("flow.lbl.llmSay")} ${g(l(o,"llmRationale"))} \xB7 ${ne(l(o,"llmConfidence"))} ${t("flow.lbl.overridden")}`));let y=m(e,P=>P.kind==="intent.classify.start"),c=l(n,"textLen")??l(y,"textLen"),v=l(n,"path"),$=typeof v=="string"?v:"",T=g(l(y,"classifier")),w=g(l(y,"modelProvider")??T),h=l(y,"classifierEndpoint"),b=l(y,"classifierIsLocal"),R=$.startsWith("jev-adopt")||$.startsWith("jev-reject"),x=$.startsWith("llm"),G=R?t("flow.intent.byJev"):x?t("flow.intent.byLlm"):$==="cache"?t("flow.intent.byCache"):$.startsWith("rules-")?t("flow.intent.byRules"):$==="gate-no-web-need"?t("flow.intent.byGate"):$==="device-command"?t("flow.intent.byDeviceCommand"):Qe($),M=g(l(y,"model")),N=x&&M!=="?"?` ${w}/${M}`:x?` ${w}`:"";if(d.push(`${t("flow.lbl.decidedBy")} ${G}${N}`),typeof h=="string"&&h.length>0){let P=b===!0?t("flow.lbl.onDevice"):t("flow.lbl.offDevice");d.push(`${t("flow.lbl.endpoint")} ${W(h,34)} \xB7 ${P}`)}d.push(`${t("flow.lbl.elapsed")} ${Q(l(n,"durationMs"))} \xB7 ${t("flow.lbl.scanned")} ${g(c)} ${t("flow.lbl.chars")}`);let I=l(n,"keyword");typeof I=="string"&&I.length>0&&d.push(`${t("flow.lbl.keyword")} ${W(I,30)}`);let D=l(n,"semantic");typeof D=="string"&&D.length>0&&d.push(`${t("flow.lbl.semantic")} ${W(D,40)}`),typeof v=="string"&&v.length>0&&!R&&!x&&$!=="cache"&&d.push(`${t("flow.lbl.path")} ${v}`);let O=l(n,"jevIntent"),f=l(n,"jevConfidence"),E=l(n,"jevRiskScore"),S=[];if(typeof O=="string"&&O.length>0&&S.push(`intent=${O}`),typeof f=="number"&&S.push(`confidence=${f.toFixed(2)}`),typeof E=="number"&&S.push(`riskScore=${E.toFixed(2)}`),S.length>0){let P=r!==void 0?g(l(r,"provider")):"?",oe=r!==void 0?g(l(r,"model")):"?";d.push(`${t("flow.lbl.jev")} ${P}/${oe} \xB7 ${S.join(" \xB7 ")}`)}let C=xe(n).startsWith("default:"),j=xe(n)==="no-web-need";if(C){let P=m(e,oe=>/^intent\.(classify\.llm_error|llm\.(timeout|error|provider_error))$/u.test(oe.kind));P!==void 0?d.push(`${t("flow.lbl.cause")} ${g(l(P,"error")??l(P,"reason"))} \u2192 ${g(P.kind)}`):d.push(t("flow.intent.defaultNoCause"))}j&&d.push(t("flow.intent.noWebNeedWhy"));let _=C?t("flow.intent.viaDefault"):o!==void 0&&o.ts<=n.ts?t("flow.intent.viaEntity"):R?t("flow.intent.viaJev"):x?t("flow.intent.viaLlm"):$==="cache"?t("flow.intent.viaCache"):$.startsWith("rules-")?t("flow.intent.viaRules"):$==="device-command"?t("flow.intent.viaDeviceCommand"):t("flow.intent.viaLlm");return{label:t("flow.intent"),tone:C?"warn":"ok",detail:j?`${a} ${p} \xB7 ${t("flow.intent.noWebNeed")}`:`${a} ${p} \xB7 ${_}`,sub:d}}if(u!==void 0){let a=g(l(u,"policyRealm")),p=ne(l(u,"policyConfidence")),d=g(l(u,"policyPattern")),y=g(l(u,"policyRationale")),c=[];return d!=="?"&&c.push(`${t("flow.lbl.rule")} ${W(d)}`),y!=="?"&&c.push(`${t("flow.lbl.reason")} ${y}`),c.push(`${t("flow.lbl.confidence")} ${p}`),{label:t("flow.intent"),tone:"ok",detail:`${a} \xB7 ${t("flow.intent.viaPolicy")}`,sub:c}}return s!==void 0?{label:t("flow.intent"),tone:"run",detail:t("flow.running"),sub:[]}:{label:t("flow.intent"),tone:"wait",detail:t("flow.wait"),sub:[]}}function Ye(e,n){let o=m(e,r=>r.kind==="sanitizer.sanitized"||r.kind==="input-guard.sanitized"||r.kind==="guard.rule.sanitized"),i=m(e,r=>/^input-guard\.sanitize\.(downgraded|failed)$/.test(r.kind)),s=m(e,r=>r.kind==="sanitizer.desanitized");if(i!==void 0)return{label:t("flow.sanitize"),tone:"warn",detail:t("flow.sanitize.failed"),sub:[`${t("flow.lbl.cause")} ${g(l(i,"reason"))??"-"}`]};if(o!==void 0){let r=typeof o.payload.count=="number"?o.payload.count:typeof o.payload.replacementCount=="number"?o.payload.replacementCount:typeof o.payload.replacements=="number"?o.payload.replacements:void 0,u=[typeof r=="number"?`${t("flow.sanitize.hits")} ${r} ${t("flow.sanitize.unit")}`:t("flow.sanitize.done")],a=K(l(o,"piiTypes"));a.length>0&&u.push(`${t("flow.lbl.hit")} ${a.join(", ")}`);let p=K(l(o,"placeholders"));return p.length>0&&u.push(`${t("flow.lbl.ph")} ${p.join(", ")}`),s!==void 0&&u.push(t("flow.s.desanitized")),{label:t("flow.sanitize"),tone:"ok",detail:t("flow.s.done"),sub:u}}return n==="LOCAL"?{label:t("flow.sanitize"),tone:"ok",detail:t("flow.sanitize.localSkip"),sub:[t("flow.s.localWhy")]}:n!==void 0?{label:t("flow.sanitize"),tone:"ok",detail:t("flow.sanitize.clean"),sub:[t("flow.s.cleanWhy")]}:{label:t("flow.sanitize"),tone:"wait",detail:t("flow.wait"),sub:[]}}function Ze(e){let n=m(e,r=>r.kind==="input-guard.routed"),o=m(e,r=>r.kind==="input-guard.intent.local"),i=m(e,r=>/^input-guard\.blocked\./.test(r.kind)),s=m(e,r=>/route-missing/.test(r.kind));if(i!==void 0){let r=i.kind.replace("input-guard.blocked.",""),u=g(l(i,"reason")),a=g(l(i,"rationale")),p=g(l(i,"riskLevel")),d=u!=="?"?u:a!=="?"?a:"?",y=[`${t("flow.lbl.cause")} ${d}`],c=[p!=="?"?`${t("flow.lbl.risk")} ${p}`:null,se(l(i,"confidence"))!==void 0?`${t("flow.lbl.confidence")} ${ne(l(i,"confidence"))}`:null].filter(v=>v!==null);return c.length>0&&y.push(c.join(" \xB7 ")),{label:t("flow.route"),tone:"stop",detail:`${t("flow.route.blocked")} \xB7 ${r}`,sub:y}}if(s!==void 0)return{label:t("flow.route"),tone:"warn",detail:t("flow.route.fallback"),sub:[`${t("flow.lbl.cause")} ${g(l(s,"reason"))}`]};if(n!==void 0){let r=g(l(n,"category")),u=[];if(o!==void 0){let a=g(l(o,"provider")),p=g(l(o,"model"));(a!=="?"||p!=="?")&&u.push(`${t("flow.lbl.route")} ${a}/${p}`)}return u.push(`${t("flow.lbl.entry")} ${g(l(n,"routeSource"))} \xB7 ${t("flow.lbl.pool")} ${n.payload.edgeRouteUsed===!0?t("flow.lbl.used"):t("flow.lbl.hostOwn")}`),{label:t("flow.route"),tone:"ok",detail:`${r} \xB7 ${t("flow.route.kept")}`,sub:u}}return et(e)?{label:t("flow.route"),tone:"run",detail:t("flow.running"),sub:[]}:{label:t("flow.route"),tone:"wait",detail:t("flow.wait"),sub:[]}}var et=e=>e.some(n=>n.kind.startsWith("intent.classify."));function tt(e){let n=m(e,r=>r.kind==="td-bus.escalated"),o=m(e,r=>r.kind==="input.rate-limit"||r.kind==="input.global-rate-limit"),i=m(e,r=>r.kind==="http.chat.threat-blocked");if(i!==void 0)return{label:t("flow.threat"),tone:"stop",detail:t("flow.threat.blocked"),sub:[`${t("flow.lbl.cause")} ${g(l(i,"reason"))??"-"}`]};if(n!==void 0)return{label:t("flow.threat"),tone:"warn",detail:t("flow.threat.escalated"),sub:[`${g(l(n,"from"))} \u2192 ${g(l(n,"to"))} \xB7 ${g(l(n,"count"))}/${g(l(n,"threshold"))}`]};if(o!==void 0){let r=o.kind==="input.global-rate-limit";return{label:t("flow.threat"),tone:"warn",detail:t("flow.threat.rate"),sub:[`${t("flow.lbl.scope")} ${r?t("flow.lbl.global"):t("flow.lbl.session")}`]}}let s=e.filter(r=>r.kind.startsWith("guard.")||r.kind.startsWith("input.")||r.kind.startsWith("td-bus.")).length;return{label:t("flow.threat"),tone:"ok",detail:t("flow.threat.calm"),sub:[`${t("flow.lbl.watched")} ${s}`]}}function nt(e,n){let o=f=>{let E=l(f,"internal");if(E!=null)return!1;let S=l(f,"tools");return!(typeof S=="number"&&S===0)},i=f=>f.kind==="llm.local.end"||f.kind==="llm.cloud.end",s=f=>f.kind==="llm.local.start"||f.kind==="llm.cloud.start",r=f=>/^llm\.(local|cloud)\.delegate\.end$/.test(f.kind),u=f=>/^llm\.(local|cloud)\.delegate\.resolved$/.test(f.kind),a=f=>{let E=g(l(f,"from"));if(E!=="?")return{pool:E,provider:g(l(f,"toProvider")),model:g(l(f,"toModel"))};let S=g(l(f,"provider"));return{pool:S,provider:S,model:g(l(f,"model")??l(f,"route"))}},p=m(e,f=>f.kind==="llm.host.route"),d=m(e,f=>(i(f)||r(f))&&o(f)),y=m(e,f=>(s(f)||u(f))&&o(f)),c=m(e,f=>/^llm\.(local|cloud)\.(http_error|network_error|sse_interrupted)$/.test(f.kind)&&o(f));if(y!==void 0&&(d===void 0||y.ts>d.ts)&&(c===void 0||c.ts<y.ts)&&y!==void 0){let{provider:f,model:E}=a(y),S=[`${t("flow.lbl.route")} ${f}/${E}`],C=[],j=l(y,"messageCount");typeof j=="number"&&C.push(`messageCount=${j}`);let _=l(y,"promptLen");return typeof _=="number"&&C.push(`promptLen=${_}`),C.length>0&&S.push(`${t("flow.lbl.raw")} ${C.join(" \xB7 ")}`),{label:t("flow.answer"),tone:"run",detail:t("flow.answer.running"),sub:S}}if(c!==void 0&&(d===void 0||c.ts>d.ts)){let f=g(l(c,"provider")),E=g(l(c,"model")??l(c,"route")),S=l(c,"status"),C=l(c,"error"),j=typeof S=="number"?`status=${S}`:typeof C=="string"&&C.length>0&&C!=="[object Object]"?C:c.kind;return{label:t("flow.answer"),tone:"warn",detail:t("flow.answer.failed"),sub:[`${t("flow.lbl.route")} ${f}/${E}`,`${t("flow.lbl.cause")} ${j} \xB7 ${t("flow.lbl.elapsed")} ${Q(l(c,"durationMs"))}`]}}let $=m(e,f=>f.kind==="input-guard.reroute.local"),T=$!==void 0?l($,"from"):void 0,w=$!==void 0?l($,"to"):void 0,h=d!==void 0?{...a(d),carried:!1}:p!==void 0?{pool:g(l(p,"provider")),provider:g(l(p,"provider")),model:g(l(p,"model")),carried:!1}:w!==void 0&&g(w.provider)!=="?"?{pool:g(w.provider),provider:g(w.provider),model:g(w.model),carried:!1}:n.lastRoute!==void 0?{pool:n.lastRoute.provider,provider:n.lastRoute.provider,model:n.lastRoute.model,carried:!0}:void 0;if(h===void 0)return{label:t("flow.answer"),tone:"wait",detail:t("flow.answer.pending"),sub:[]};let{pool:b,provider:R,model:x,carried:G}=h,M=b.startsWith("local-llm"),N=e.filter(f=>(f.kind==="llm.local.end"||f.kind==="llm.local.delegate.end")&&o(f)),I=[`${t("flow.lbl.route")} ${b}/${x}${G?` \xB7 ${t("flow.answer.carried")}`:""}`,M?t("flow.a.localKeep"):t("flow.a.cloudSend")];R!=="?"&&R!==b&&I.push(`${t("flow.lbl.endpoint")} ${R}/${x}`);{let f=g(T?.provider),E=g(w?.provider);f!=="?"&&E!=="?"&&I.push(`${t("flow.lbl.rerouted")} ${f}/${g(T?.model)} \u2192 ${E}/${g(w?.model)}`)}if(M&&N.length>0){let f=N.reduce((_,P)=>_+(typeof P.payload.durationMs=="number"?P.payload.durationMs:0),0),E=N.at(-1),S=r(E),C=se(S?l(m(e,_=>u(_)&&o(_)),"messageCount"):l(E,"promptLen")),j=C===void 0?"":` \xB7 ${t("flow.lbl.context")} ${C} ${S?t("flow.lbl.msgs"):t("flow.lbl.chars")}`;I.push(`${t("flow.lbl.steps")} \xD7${N.length} \xB7 ${t("flow.lbl.total")} ${Q(f)}${j}`)}let D=d??p;if(D!==void 0){let f=[],E=l(D,"route");typeof E=="string"&&E.length>0&&E!==x&&f.push(`route=${E}`);let S=l(D,"durationMs");typeof S=="number"&&f.push(`durationMs=${S}`);let C=l(D,"promptLen");typeof C=="number"&&f.push(`promptLen=${C}`);let j=l(D,"resultLen");typeof j=="number"&&f.push(`resultLen=${j}`),f.length>0&&I.push(`${t("flow.lbl.raw")} ${f.join(" \xB7 ")}`)}let O=n.tokens;return O!==void 0&&(O.input!==void 0||O.output!==void 0)&&I.push(`token ${O.input??0} ${t("flow.lbl.in")} / ${O.output??0} ${t("flow.lbl.out")}`),{label:t("flow.answer"),tone:M?"ok":"info",detail:M?`${t("flow.answer.local")} \xB7 ${x}`:`${t("flow.answer.cloud")} ${R}/${x}`,sub:I}}var ot="\u2502";function Re(e){let{rows:n,summary:o}=e,i=m(n,p=>p.kind==="intent.classify.end"),s=m(n,p=>p.kind==="input-guard.policy.route-applied"),r=i!==void 0?String(i.payload.category??""):s!==void 0?String(s.payload.policyRealm??""):void 0,u=[He(n),Xe(n),Ye(n,r),Ze(n),nt(n,o),tt(n)],a=u.flatMap((p,d)=>[(0,F.createElement)("div",{key:`n${d}`,class:`dsh-edge-flow-node dsh-edge-flow-node--${p.tone}`},(0,F.createElement)("div",{class:"dsh-edge-flow-head"},(0,F.createElement)("span",{class:"dsh-edge-flow-dot"}),(0,F.createElement)("span",{class:"dsh-edge-flow-label"},p.label)),(0,F.createElement)("div",{class:"dsh-edge-flow-detail"},p.detail),p.sub.length>0?(0,F.createElement)("div",{class:"dsh-edge-flow-sub"},...p.sub.map((y,c)=>(0,F.createElement)("div",{key:c},y))):null),...d<u.length-1?[(0,F.createElement)("div",{key:`a${d}`,class:"dsh-edge-flow-arrow"},ot)]:[]]);return(0,F.createElement)("div",{class:"dsh-edge-flow"},...a)}var k=require("react");var rt=["guard","intent","route","host","other"];function lt(e){return e.caller==="prompt-guard"?"guard":e.caller==="intent-classifier"?"intent":typeof e.caller=="string"&&e.caller.length>0?"other":e.toolCount===0?"host":"route"}function it(e){switch(e){case"guard":return t("flow.guard");case"intent":return t("flow.intent");case"route":return t("flow.route");case"host":return t("trace.caller.host");case"other":return t("trace.group.other")}}var Ee=e=>typeof e=="string"?e:typeof e=="number"||typeof e=="boolean"?String(e):"?",st=e=>typeof e=="number"?e:void 0;function at(e){if(e.kind!=="llm.trace.index")return;let n=e.payload??{},o=typeof n.traceId=="string"?n.traceId:"";if(o.length===0)return;let i=n.kind==="RESP"?"RESP":"REQ",s={traceId:o,kind:i,provider:Ee(n.provider),model:Ee(n.model)};typeof n.caller=="string"&&(s.caller=n.caller);for(let r of["messageCount","droppedMessages","promptLength","contentLength","toolCallCount","toolCount","durationMs","bodyBytes"]){let u=st(n[r]);u!==void 0&&(s[r]=u)}for(let r of["finishReason","error","baseUrl","callId"])typeof n[r]=="string"&&(s[r]=n[r]);return s}function dt(e){let n=new Map;for(let o of e){let i=o.callId!==void 0&&o.callId.length>0?o.callId:`solo:${o.traceId}`,s=n.get(i);s===void 0&&(s={key:i,group:lt(o)},n.set(i,s)),o.kind==="REQ"?s.req=o:s.resp=o}return[...n.values()]}function ct(e){return e.caller==="prompt-guard"?t("trace.caller.guard"):e.caller==="intent-classifier"?t("trace.caller.classifier"):typeof e.caller=="string"&&e.caller.length>0?e.caller:e.toolCount===0?t("trace.caller.host"):t("trace.caller.conversation")}function ut(e){return e===void 0?"":e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(1)} MB`}function ft(e){let n=[];return e.kind==="REQ"?(e.messageCount!==void 0&&n.push(`${e.messageCount} ${t("trace.lbl.messages")}`),e.promptLength!==void 0&&n.push(`${e.promptLength} ${t("trace.lbl.chars")}`),e.droppedMessages!==void 0&&e.droppedMessages>0&&n.push(`${t("trace.lbl.dropped")} ${e.droppedMessages}`)):(e.contentLength!==void 0&&n.push(`${e.contentLength} ${t("trace.lbl.chars")}`),e.toolCallCount!==void 0&&n.push(`${t("trace.lbl.toolCalls")} ${e.toolCallCount}`),e.durationMs!==void 0&&n.push(`${t("flow.lbl.elapsed")} ${(e.durationMs/1e3).toFixed(1)}s`)),n.join(" \xB7 ")}function Se(e){let{rows:n}=e,[o,i]=(0,k.useState)(void 0),[s,r]=(0,k.useState)(void 0),u=[];for(let c of n){let v=at(c);v!==void 0&&u.push(v)}u.reverse(),(0,k.useEffect)(()=>{if(o===void 0){r(void 0);return}let c=!1;return r({id:o}),be(o).then(v=>{c||r(v.ok?{id:o,text:v.text}:{id:o,error:v.error})}),()=>{c=!0}},[o]);let a=(0,k.createElement)("div",{class:"dsh-edge-flow-head"},(0,k.createElement)("span",{class:"dsh-edge-flow-dot"}),(0,k.createElement)("span",{class:"dsh-edge-flow-label"},t("trace.title")),(0,k.createElement)("span",{class:"dsh-edge-trace-count"},`${u.length}`));if(u.length===0)return(0,k.createElement)("div",{class:"dsh-edge-panel dsh-edge-trace"},a,(0,k.createElement)("div",{class:"dsh-edge-empty"},t("trace.empty")));let p=new Map;for(let c of dt(u)){let v=p.get(c.group);v===void 0?p.set(c.group,[c]):v.push(c)}let d=c=>{let v=o===c.traceId,$=s?.id===c.traceId?s:void 0,T=[];c.baseUrl!==void 0&&c.baseUrl.length>0&&T.push(c.baseUrl),c.toolCount!==void 0&&c.toolCount>0&&T.push(`${t("trace.lbl.tools")} ${c.toolCount}`),c.finishReason!==void 0&&c.finishReason.length>0&&T.push(c.finishReason),c.error!==void 0&&c.error.length>0&&T.push(`${t("flow.lbl.cause")} ${c.error}`);let w=ut(c.bodyBytes);return w.length>0&&T.push(w),(0,k.createElement)("div",{class:`dsh-edge-trace-half dsh-edge-trace-half--${c.kind.toLowerCase()}`},(0,k.createElement)("button",{class:"dsh-edge-trace-head",type:"button",onClick:()=>i(v?void 0:c.traceId)},(0,k.createElement)("span",{class:`dsh-edge-trace-badge dsh-edge-trace-badge--${c.kind.toLowerCase()}`},c.kind==="REQ"?t("trace.req"):t("trace.resp")),(0,k.createElement)("span",{class:"dsh-edge-trace-model"},`${c.provider}/${c.model}`),(0,k.createElement)("span",{class:`dsh-edge-trace-caller${c.caller===void 0&&c.toolCount!==0?" dsh-edge-trace-caller--main":""}`},ct(c))),(0,k.createElement)("div",{class:"dsh-edge-trace-sum"},ft(c)),T.length>0?(0,k.createElement)("div",{class:"dsh-edge-trace-meta"},T.join(" \xB7 ")):null,v?(0,k.createElement)("div",{class:"dsh-edge-trace-body"},$===void 0?(0,k.createElement)("div",{class:"dsh-edge-empty"},t("trace.body.loading")):$.error!==void 0?(0,k.createElement)("div",{class:"dsh-edge-trace-body-err"},$.error==="trace-not-found"?t("trace.body.gone"):`${t("trace.body.error")} \xB7 ${$.error}`):(0,k.createElement)("pre",{class:"dsh-edge-trace-pre"},$.text??"")):null)},y=[];for(let c of rt){let v=p.get(c);if(v===void 0||v.length===0)continue;let $=v.map(T=>{let w=[];return T.req!==void 0&&w.push(d(T.req)),T.resp!==void 0&&w.push(d(T.resp)),(0,k.createElement)("div",{key:T.key,class:"dsh-edge-trace-pair"},...w)});y.push((0,k.createElement)("div",{key:c,class:"dsh-edge-trace-group"},(0,k.createElement)("div",{class:"dsh-edge-trace-group-head"},(0,k.createElement)("span",{class:"dsh-edge-trace-group-name"},it(c)),(0,k.createElement)("span",{class:"dsh-edge-trace-count"},`${v.length}`)),(0,k.createElement)("div",{class:"dsh-edge-trace-list"},...$)))}return(0,k.createElement)("div",{class:"dsh-edge-panel dsh-edge-trace"},a,...y)}var z=require("react");var B=require("react");function pt(e){let n=new Date(e),o=(i,s=2)=>String(i).padStart(s,"0");return`${o(n.getHours())}:${o(n.getMinutes())}:${o(n.getSeconds())}`}function gt(e){let n=e.indexOf(".");return n>0?e.slice(n+1):e}var wt={intent:["category","keyword","semantic","targetRealm","confidence","rationale","classifier","textLen"],route:["provider","model","toProvider","toModel","resolved","baseUrl","status","durationMs","promptLen"],interception:["reason","realm","targetRealm","rule","count","confidence","rationale","category","edgeRouteUsed","routeSource","dataClass","provider","model","textLen","durationMs"],threat:["from","to","count","threshold","reason"]},bt=24,ht={semantic:60};function mt(e,n){let o=wt[n]??[],i=[];for(let s of o){let r=e.payload[s];if(typeof r=="number")i.push(`${s}=${Math.round(r*100)/100}`);else if(typeof r=="boolean")i.push(`${s}=${r}`);else if(typeof r=="string"&&r.length>0){let u=ht[s]??bt;i.push(`${s}=${r.length>u?`${r.slice(0,u-1)}\u2026`:r}`)}}return i.join(" ")}function yt(e){return e==="warn"?"warn":e==="error"||e==="security"?"security":""}function Te(e){let{rows:n,panel:o,empty:i}=e;if(n.length===0)return(0,B.createElement)("div",{class:"dsh-edge-empty"},i);let s=[...n].reverse();return(0,B.createElement)("div",{class:"dsh-edge-rows"},...s.map(r=>{let u=mt(r,o);return(0,B.createElement)("div",{class:`dsh-edge-row ${yt(r.level)}`,key:`${r.seq}`},(0,B.createElement)("div",{class:"dsh-edge-row-head"},(0,B.createElement)("span",{class:"ts"},pt(r.ts)),(0,B.createElement)("span",{class:"k"},gt(r.kind))),u.length>0?(0,B.createElement)("div",{class:"f"},u):null)}))}var ae="_global",vt=-1;function de(e){return e.turn===vt}function ce(e){return typeof e!="string"||e.length===0?!1:e!==ae}function Ce(e,n,o){return ce(e)?o>0?!1:!n.some(i=>!de(i)):!0}function kt(e){let n=[],o=new Map;for(let i of e){let s=typeof i.panel=="string"&&i.panel.length>0?i.panel:"other",r=o.get(s);r===void 0&&(r=[],o.set(s,r),n.push(s)),r.push(i)}return n.map(i=>({panel:i,rows:o.get(i)??[]}))}var $t={intent:"panel.intent",route:"panel.route",interception:"panel.interception",threat:"panel.threat"};function Le(e){let n=kt(e.rows);return(0,z.createElement)("div",{class:"dsh-edge-view"},(0,z.createElement)("div",{class:"dsh-edge-unbound"},(0,z.createElement)("b",null,t("unbound.title")),(0,z.createElement)("span",null,t("unbound.hint"))),n.length===0?(0,z.createElement)("div",{class:"dsh-edge-empty"},t("unbound.empty")):(0,z.createElement)("div",{class:"dsh-edge-groups"},...n.map(o=>(0,z.createElement)("div",{class:"dsh-edge-panel",key:o.panel},(0,z.createElement)("h4",null,t($t[o.panel]??"unbound.globalTitle")),(0,z.createElement)(Te,{rows:o.rows,panel:o.panel,empty:t("unbound.empty")})))),e.failing===!0?(0,z.createElement)("div",{class:"dsh-edge-stale"},t("row.stale")):null)}function Ie(e){let n=d=>d.at(-1),o=n(e.filter(d=>d.kind==="intent.classify.end")),i=n(e.filter(d=>d.kind==="input-guard.policy.route-applied")),s=n(e.filter(d=>d.kind==="input-guard.routed")),r=n(e.filter(d=>d.kind==="llm.host.route")),u=e.some(d=>d.kind==="sanitizer.sanitized"||d.kind==="guard.rule.sanitized"),a=o?.payload.category??i?.payload.policyRealm??s?.payload.category;return a===void 0&&r===void 0?{text:t("verdict.waiting"),tone:"wait"}:a==="LOCAL"||r!==void 0&&String(r.payload.provider??"").startsWith("local-llm")?{text:t("verdict.local"),tone:"local"}:{text:t("verdict.cloud")+(u?t("verdict.sanitized"):""),tone:"cloud"}}var xt="dsh-edge-agent-client",Rt=["slots","locale"],q="dsh-edge-agent",ue="edge",Et=5e3,Pe=[0,80,300,900,2500];function X(e,n){if(!(e===null||typeof e!="object"))try{return e[n]}catch{return}}function ze(e){if(e===null||typeof e!="object")return;if(typeof X(e,"list")=="function")return e;let n=[];n.push(X(e,"agentPresets"));let o=X(e,"remote");o!==void 0&&n.push(X(o,"agentPresets"));for(let i of n)if(i!=null&&typeof X(i,"list")=="function")return i}function St(e){try{let n=e.remote;return ze(n)}catch{return}}function Me(e){let o=ce(e.sessionId)?e.sessionId:ae,[,i]=(0,L.useState)(0);(0,L.useEffect)(()=>(me(),V.attach(o,()=>i(a=>a+1))),[o]);let s=V.summaryFor(o),r=V.currentRows(o,s.turns,s.turnStartTs);if(Ce(e.sessionId,r,s.turns))return(0,L.createElement)(Le,{rows:r.filter(de),failing:V.failing(o)});let u=Ie(r);return(0,L.createElement)("div",{class:"dsh-edge-view"},(0,L.createElement)($e,{summary:s}),(0,L.createElement)("div",{class:`dsh-edge-verdict dsh-edge-verdict--${u.tone}`},u.text),(0,L.createElement)(Re,{rows:r,summary:s}),(0,L.createElement)(Se,{rows:r}),V.failing(o)?(0,L.createElement)("div",{class:"dsh-edge-stale"},t("row.stale")):null)}function J(e,n){let o=n instanceof Error?n.message:String(n);console.error(`[dsh-edge-agent] ${e} failed: ${o}`)}function Tt(e){e.inject(["locale"],w=>{let b=w.locale;if(!(b===void 0||typeof b.register!="function"||typeof b.bind!="function"))try{b.register(te,ke),ve(b.bind(te))}catch(R){J("locale registration",R)}});let n=!1,o,i=!0,s=!1,r=new Set,u,a,p=w=>{if(!(u===void 0||typeof u.tabsIn!="function"))try{return u.tabsIn(w).find(h=>h.kind===q)}catch(h){J("edge tab lookup",h);return}},d=w=>{let h;try{h=e.get?.("sessions")}catch{return}let b=h;if(!(b===void 0||typeof b.list?.getSnapshot!="function"))try{let x=b.list.getSnapshot()?.byId?.[w]?.projectionValues?.agentPreset;return typeof x=="string"?x:void 0}catch(R){J("session preset lookup",R);return}},y=w=>{let h=d(w);return h!==void 0?h===ue:s},c=(w,h)=>{let b=setTimeout(()=>{if(a=void 0,!(!n||u===void 0)&&u.mounted?.getSnapshot()===w&&!(!i||!y(w))){if(p(w)!==void 0){r.add(w);return}try{u.openTab(q),r.add(w)}catch(R){let x=h+1;if(x>=Pe.length){J("edge tab auto-open",R);return}c(w,x)}}},Pe[h]);a={sessionId:w,attempt:h,timer:b}},v=()=>{if(!n||u===void 0)return;let w=u.mounted?.getSnapshot();if(!(typeof w!="string"||w==="")&&!r.has(w)&&!(!i||!y(w))){if(a!==void 0){if(a.sessionId===w)return;clearTimeout(a.timer),a=void 0}c(w,0)}},$=()=>{if(u!==void 0)return;let w;try{w=e.get?.("sidebarRight")}catch{return}let h=w;if(h===void 0||typeof h.openTab!="function")return;u=h;let b=h.mounted;b!==void 0&&typeof b.subscribe=="function"&&b.subscribe(()=>{v()}),v()},T=()=>{o===void 0&&e.inject(["sidebarRightTabs"],w=>{if(o!==void 0)return;let b=w.sidebarRightTabs;if(!(b===void 0||typeof b.register!="function")){try{o=b.register({id:q,kind:q,title:()=>t("tab.title"),guide:[{id:`${q}-guide`,order:30,title:()=>t("tab.title"),description:()=>t("guide.description")}]}),n=!0}catch(R){J("sidebar tab type registration",R)}v()}})};e.inject(["remote","remote.agentPresets"],w=>{let h=ze(w)??St(e);if(h===void 0||typeof h.list!="function")return;let b=async()=>{try{$();let x=await h.list();if(!x.ok)return;let G=x.value?.presets;if(!Array.isArray(G))return;let M=G.find(I=>I.id===ue),N=G.find(I=>I.isDefault===!0);i=M!==void 0&&M.broken===void 0,s=N?.id===ue,v()}catch(x){J("preset roster read",x)}};b();let R=setInterval(()=>{b()},Et);e.effect?.(()=>()=>{clearInterval(R);let x=o;o=void 0,n=!1,typeof x=="function"&&x()},"dsh-edge-agent: preset roster watcher")}),T(),e.inject(["slots"],w=>{let b=w.slots;if(!(b===void 0||typeof b.register!="function"||typeof b.inject!="function"))try{b.inject("sidebar.right.pane.tab",()=>b.register({name:"sidebar.right.pane.tab",key:q,locale:te},R=>(0,L.createElement)(Me,{...R}))),b.inject("sidebar.right.pane.tab.title",()=>b.register({name:"sidebar.right.pane.tab.title",key:q},()=>(0,L.createElement)("span",{className:"dsh-edge-tab-title"},t("tab.title"))))}catch(R){J("sidebar tab body registration",R)}})}function Ct(e,n){let o=(0,je.createRoot)(n);return o.render(e),()=>o.unmount()}
84
+ })();
85
+ return module.exports;
86
+ },
87
+ });
@@ -0,0 +1,2 @@
1
+ export * from './dsh-adapter/cloud-llm-adapter.js';
2
+ //# sourceMappingURL=cloud-llm-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-llm-adapter.d.ts","sourceRoot":"","sources":["../src/cloud-llm-adapter.ts"],"names":[],"mappings":"AACA,cAAc,oCAAoC,CAAA"}
@@ -0,0 +1,2 @@
1
+ // @module dsh-edge-agent/cloud-llm-adapter
2
+ export * from './dsh-adapter/cloud-llm-adapter.js';