dsh-edge 0.1.0

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 (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +183 -0
  4. package/README.zh.md +183 -0
  5. package/THIRD_PARTY_NOTICES.md +199 -0
  6. package/dist/_headers +3 -0
  7. package/dist/assets/fonts/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  8. package/dist/assets/fonts/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  9. package/dist/assets/fonts/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  10. package/dist/assets/fonts/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  11. package/dist/assets/fonts/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  12. package/dist/assets/fonts/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  13. package/dist/assets/fonts/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  14. package/dist/assets/fonts/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  15. package/dist/assets/fonts/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  16. package/dist/assets/fonts/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  17. package/dist/assets/fonts/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  18. package/dist/assets/fonts/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  19. package/dist/assets/fonts/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  20. package/dist/assets/fonts/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  21. package/dist/assets/fonts/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  22. package/dist/assets/fonts/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  23. package/dist/assets/fonts/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  24. package/dist/assets/fonts/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  25. package/dist/assets/fonts/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  26. package/dist/assets/fonts/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  27. package/dist/assets/fonts/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  28. package/dist/assets/fonts/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  29. package/dist/assets/fonts/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  30. package/dist/assets/fonts/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  31. package/dist/assets/fonts/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  32. package/dist/assets/fonts/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  33. package/dist/assets/fonts/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  34. package/dist/assets/fonts/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  35. package/dist/assets/fonts/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  36. package/dist/assets/fonts/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  37. package/dist/assets/fonts/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  38. package/dist/assets/fonts/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  39. package/dist/assets/fonts/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  40. package/dist/assets/fonts/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  41. package/dist/assets/fonts/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  42. package/dist/assets/fonts/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  43. package/dist/assets/fonts/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  44. package/dist/assets/fonts/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  45. package/dist/assets/fonts/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  46. package/dist/assets/fonts/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  47. package/dist/assets/fonts/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  48. package/dist/assets/fonts/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  49. package/dist/assets/fonts/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  50. package/dist/assets/fonts/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  51. package/dist/assets/fonts/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  52. package/dist/assets/fonts/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  53. package/dist/assets/fonts/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  54. package/dist/assets/fonts/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  55. package/dist/assets/fonts/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  56. package/dist/assets/fonts/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  57. package/dist/assets/fonts/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  58. package/dist/assets/fonts/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  59. package/dist/assets/fonts/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  60. package/dist/assets/fonts/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  61. package/dist/assets/fonts/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  62. package/dist/assets/fonts/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  63. package/dist/assets/fonts/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  64. package/dist/assets/fonts/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  65. package/dist/assets/fonts/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  66. package/dist/assets/index-C-1AiF3k.js +112 -0
  67. package/dist/assets/index-CSGf6Qzd.css +1 -0
  68. package/dist/assets/langs/c-BIGW1oBm.js +2 -0
  69. package/dist/assets/langs/cpp-DIPi6g--.js +2 -0
  70. package/dist/assets/langs/csharp-DSvCPggb.js +2 -0
  71. package/dist/assets/langs/css-CLj8gQPS.js +2 -0
  72. package/dist/assets/langs/go-C27-OAKa.js +2 -0
  73. package/dist/assets/langs/html-CfGypltT.js +2 -0
  74. package/dist/assets/langs/ini-BEwlwnbL.js +2 -0
  75. package/dist/assets/langs/java-CylS5w8V.js +2 -0
  76. package/dist/assets/langs/kotlin-BdnUsdx6.js +2 -0
  77. package/dist/assets/langs/less-B1dDrJ26.js +2 -0
  78. package/dist/assets/langs/lua-BaeVxFsk.js +2 -0
  79. package/dist/assets/langs/markdown-Cvjx9yec.js +2 -0
  80. package/dist/assets/langs/mdx-Cmh6b_Ma.js +2 -0
  81. package/dist/assets/langs/php-D-uCvoST.js +2 -0
  82. package/dist/assets/langs/python-B6aJPvgy.js +2 -0
  83. package/dist/assets/langs/ruby-DEItuUFs.js +2 -0
  84. package/dist/assets/langs/rust-B1yitclQ.js +2 -0
  85. package/dist/assets/langs/scss-D5BDwBP9.js +2 -0
  86. package/dist/assets/langs/sql-CRqJ_cUM.js +2 -0
  87. package/dist/assets/langs/swift-D82vCrfD.js +2 -0
  88. package/dist/assets/langs/toml-vGWfd6FD.js +2 -0
  89. package/dist/assets/langs/xml-sdJ4AIDG.js +2 -0
  90. package/dist/assets/langs/yaml-Buea-lGh.js +2 -0
  91. package/dist/assets/vendor-Cjbwl5VI.js +411 -0
  92. package/dist/assets/vendor-CjyC-hUb.css +1 -0
  93. package/dist/favicon.svg +8 -0
  94. package/dist/index.html +35 -0
  95. package/dist/manifest.webmanifest +16 -0
  96. package/dist/plugins/@deepseek-ai/dsh-api-gateway/client.js +420 -0
  97. package/dist/plugins/@deepseek-ai/dsh-api-remotes/client.js +5937 -0
  98. package/dist/plugins/@deepseek-ai/dsh-client-connection/client.js +10207 -0
  99. package/dist/plugins/@deepseek-ai/dsh-client-locale/client.js +1231 -0
  100. package/dist/plugins/@deepseek-ai/dsh-client-modules/client.js +259 -0
  101. package/dist/plugins/@deepseek-ai/dsh-client-runtime/client.js +10539 -0
  102. package/dist/plugins/@deepseek-ai/dsh-client-ui-agent-preset/client.js +1725 -0
  103. package/dist/plugins/@deepseek-ai/dsh-client-ui-commands/client.js +1116 -0
  104. package/dist/plugins/@deepseek-ai/dsh-client-ui-conversation/client.js +9832 -0
  105. package/dist/plugins/@deepseek-ai/dsh-client-ui-deliverables/client.js +373 -0
  106. package/dist/plugins/@deepseek-ai/dsh-client-ui-edge/client.js +549 -0
  107. package/dist/plugins/@deepseek-ai/dsh-client-ui-input-trigger/client.js +859 -0
  108. package/dist/plugins/@deepseek-ai/dsh-client-ui-jobs/client.js +280 -0
  109. package/dist/plugins/@deepseek-ai/dsh-client-ui-layout/client.js +456 -0
  110. package/dist/plugins/@deepseek-ai/dsh-client-ui-model-selection/client.js +804 -0
  111. package/dist/plugins/@deepseek-ai/dsh-client-ui-permission-presets/client.js +461 -0
  112. package/dist/plugins/@deepseek-ai/dsh-client-ui-settings/client.js +254 -0
  113. package/dist/plugins/@deepseek-ai/dsh-client-ui-settings-general/client.js +609 -0
  114. package/dist/plugins/@deepseek-ai/dsh-client-ui-sidebar/client.js +292 -0
  115. package/dist/plugins/@deepseek-ai/dsh-client-ui-skill/client.js +327 -0
  116. package/dist/plugins/@deepseek-ai/dsh-client-ui-subagent/client.js +710 -0
  117. package/dist/plugins/@deepseek-ai/dsh-client-ui-theme/client.js +1312 -0
  118. package/dist/plugins/@deepseek-ai/dsh-client-ui-tool/client.js +1630 -0
  119. package/dist/plugins/@deepseek-ai/dsh-client-ui-trajectory/client.js +7370 -0
  120. package/dist/plugins/@deepseek-ai/dsh-client-ui-user-questions/client.js +700 -0
  121. package/dist/plugins/@deepseek-ai/dsh-client-ui-workflow-run/client.js +474 -0
  122. package/dist/plugins/@deepseek-ai/dsh-client-ui-workspace/client.js +2426 -0
  123. package/dist/plugins/@deepseek-ai/dsh-typert-registry/client.js +1372 -0
  124. package/package.json +97 -0
  125. package/scripts/assemble-web.mjs +230 -0
  126. package/scripts/bundle-size.d.mts +2 -0
  127. package/scripts/bundle-size.mjs +26 -0
  128. package/scripts/bundle.mjs +53 -0
  129. package/scripts/cli.d.mts +39 -0
  130. package/scripts/cli.mjs +496 -0
  131. package/scripts/install.d.mts +149 -0
  132. package/scripts/install.mjs +989 -0
  133. package/scripts/legal-files.mjs +24 -0
  134. package/scripts/verify-packed.mjs +32 -0
  135. package/scripts/wrangler-config.d.mts +18 -0
  136. package/scripts/wrangler-config.mjs +84 -0
  137. package/src/agent.ts +119 -0
  138. package/src/auth.ts +352 -0
  139. package/src/deepseek.ts +231 -0
  140. package/src/deployment.ts +147 -0
  141. package/src/direct-shell-core-empty.ts +10 -0
  142. package/src/direct-shell-protocol.ts +5 -0
  143. package/src/direct-shell.ts +341 -0
  144. package/src/do-session-persistence.ts +1064 -0
  145. package/src/edge-api.ts +796 -0
  146. package/src/edge-credentials.ts +56 -0
  147. package/src/edge-remotes.ts +41 -0
  148. package/src/edge-workspace-store.ts +339 -0
  149. package/src/http.ts +212 -0
  150. package/src/index.ts +196 -0
  151. package/src/instance.ts +1007 -0
  152. package/src/isolated-direct-shell-unavailable.ts +11 -0
  153. package/src/protocol.ts +39 -0
  154. package/src/release.ts +9 -0
  155. package/src/session-store.ts +1110 -0
  156. package/src/sse.ts +86 -0
  157. package/src/web-search.ts +38 -0
  158. package/src/workspace.ts +270 -0
  159. package/wrangler.jsonc +56 -0
@@ -0,0 +1,231 @@
1
+ import type { AnonymousUserId } from '@deepseek-ai/dsh-anonymous-user-id'
2
+ import type { CredentialRef } from '@deepseek-ai/dsh-credentials'
3
+ import {
4
+ LlmAdapter,
5
+ LlmError,
6
+ assertUsableApiKey,
7
+ resolveRetryPolicy,
8
+ type GenerateOptions,
9
+ type LlmModelInfo,
10
+ type LlmProviderInfo,
11
+ type LlmResolvedModelInfo,
12
+ type ResolvedRetryPolicy,
13
+ type StreamChunk,
14
+ } from '@deepseek-ai/dsh-llm'
15
+ import type { SessionId } from '@deepseek-ai/dsh-session'
16
+ import {
17
+ DEFAULT_CONTEXT_WINDOW,
18
+ DeepSeekAdapter,
19
+ type DeepSeekConnectionOptions,
20
+ } from '@deepseek-ai/dsh-llm-deepseek'
21
+
22
+ const API_KEY_REF = 'DEEPSEEK_API_KEY' as CredentialRef
23
+ const DEFAULT_BASE_URL = 'https://api.deepseek.com'
24
+ const DEFAULT_MAX_TOKENS = 8_192
25
+ const DEFAULT_MODEL = 'deepseek-v4-flash'
26
+ const DEFAULT_REASONING_EFFORT = 'off'
27
+ const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 120_000
28
+ const MAX_TIMER_DELAY_MS = 2_147_483_647
29
+ const MODEL_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,127}$/
30
+
31
+ export type EdgeReasoningEffort = 'off' | 'low' | 'high' | 'max'
32
+
33
+ /** Resolve and validate the DeepSeek HTTP endpoint selected by deployment configuration. */
34
+ export function resolveEdgeBaseURL(raw?: string): string {
35
+ const value = raw ?? DEFAULT_BASE_URL
36
+ let parsed: URL
37
+ try {
38
+ parsed = new URL(value)
39
+ } catch {
40
+ throw new Error('dsh-edge: DEEPSEEK_BASE_URL must be a valid HTTP(S) URL')
41
+ }
42
+ if ((parsed.protocol !== 'http:' && parsed.protocol !== 'https:')
43
+ || parsed.username.length > 0
44
+ || parsed.password.length > 0) {
45
+ throw new Error('dsh-edge: DEEPSEEK_BASE_URL must be a valid HTTP(S) URL without credentials')
46
+ }
47
+ return value
48
+ }
49
+
50
+ /** Resolve the DeepSeek model id selected by Worker deployment configuration. */
51
+ export function resolveEdgeModel(raw?: string): string {
52
+ if (raw === undefined) return DEFAULT_MODEL
53
+ if (!MODEL_PATTERN.test(raw)) {
54
+ throw new Error('dsh-edge: DEEPSEEK_MODEL must be a valid model id of at most 128 characters')
55
+ }
56
+ return raw
57
+ }
58
+
59
+ /** Resolve the DeepSeek thinking policy selected by Worker deployment configuration. */
60
+ export function resolveEdgeReasoningEffort(raw?: string): EdgeReasoningEffort {
61
+ if (raw === undefined) return DEFAULT_REASONING_EFFORT
62
+ if (raw !== 'off' && raw !== 'low' && raw !== 'high' && raw !== 'max') {
63
+ throw new Error('dsh-edge: DEEPSEEK_REASONING_EFFORT must be one of off, low, high, or max')
64
+ }
65
+ return raw
66
+ }
67
+
68
+ /** Resolve the optional Worker deployment override before an SSE turn opens. */
69
+ export function resolveEdgeStreamIdleTimeoutMs(raw?: string): number {
70
+ if (raw === undefined) return DEFAULT_STREAM_IDLE_TIMEOUT_MS
71
+ if (!/^[1-9]\d*$/.test(raw)) {
72
+ throw new Error(
73
+ 'dsh-edge: DEEPSEEK_STREAM_IDLE_TIMEOUT_MS must be a positive integer',
74
+ )
75
+ }
76
+ const value = Number(raw)
77
+ if (!Number.isSafeInteger(value) || value > MAX_TIMER_DELAY_MS) {
78
+ throw new Error(
79
+ `dsh-edge: DEEPSEEK_STREAM_IDLE_TIMEOUT_MS must be no greater than ${MAX_TIMER_DELAY_MS}`,
80
+ )
81
+ }
82
+ return value
83
+ }
84
+
85
+ /** Resolve the request output cap selected by Worker deployment configuration. */
86
+ export function resolveEdgeMaxOutputTokens(raw?: string): number {
87
+ if (raw === undefined) return DEFAULT_MAX_TOKENS
88
+ if (!/^[1-9]\d*$/.test(raw)) {
89
+ throw new Error(
90
+ 'dsh-edge: DEEPSEEK_MAX_OUTPUT_TOKENS must be a positive integer',
91
+ )
92
+ }
93
+ const value = Number(raw)
94
+ if (!Number.isSafeInteger(value)) {
95
+ throw new Error(
96
+ `dsh-edge: DEEPSEEK_MAX_OUTPUT_TOKENS must be no greater than ${Number.MAX_SAFE_INTEGER}`,
97
+ )
98
+ }
99
+ return value
100
+ }
101
+
102
+ /** Construct one turn-scoped DSH DeepSeek adapter that resolves its bearer token per operation. */
103
+ function createEdgeDeepSeekModel(options: {
104
+ resolveApiKey: () => Promise<string | undefined>
105
+ baseURL?: string
106
+ maxTokens?: number
107
+ reasoningEffort?: EdgeReasoningEffort
108
+ streamIdleTimeoutMs?: number
109
+ }): DeepSeekAdapter {
110
+ const connection: DeepSeekConnectionOptions = {
111
+ apiKeyEnv: API_KEY_REF,
112
+ baseURL: options.baseURL ?? DEFAULT_BASE_URL,
113
+ defaults: { reasoningEffort: options.reasoningEffort ?? DEFAULT_REASONING_EFFORT },
114
+ maxTokens: options.maxTokens ?? DEFAULT_MAX_TOKENS,
115
+ defaultContextWindow: DEFAULT_CONTEXT_WINDOW,
116
+ models: [],
117
+ streamIdleTimeoutMs: options.streamIdleTimeoutMs ?? DEFAULT_STREAM_IDLE_TIMEOUT_MS,
118
+ retryPolicy: resolveRetryPolicy(undefined, 'dsh-edge.retryPolicy'),
119
+ }
120
+ const anonymousRequestId = crypto.randomUUID() as AnonymousUserId
121
+ return new DeepSeekAdapter({
122
+ options: () => connection,
123
+ resolveApiKey: async () => {
124
+ const apiKey = await options.resolveApiKey()
125
+ if (apiKey === undefined) {
126
+ throw new LlmError(
127
+ 'dsh-edge: no API key for provider route "deepseek-official"; configure the DEEPSEEK_API_KEY Worker secret',
128
+ 'MISSING_CREDENTIAL',
129
+ )
130
+ }
131
+ return assertUsableApiKey(apiKey, 'dsh-edge', API_KEY_REF)
132
+ },
133
+ // Provider telemetry must not derive identity from the owner or Durable Object id.
134
+ resolveUserId: () => anonymousRequestId,
135
+ })
136
+ }
137
+
138
+ /**
139
+ * One upstream LLM route with per-turn deployment configuration selected by
140
+ * the loop-stamped session id. Credentials resolve independently through the
141
+ * upstream credential service for each model operation.
142
+ */
143
+ export class EdgeDeepSeekAdapter extends LlmAdapter {
144
+ private readonly active = new Map<SessionId, LlmAdapter>()
145
+ private metadataMaxTokens = DEFAULT_MAX_TOKENS
146
+ private metadataReasoningEffort: EdgeReasoningEffort = DEFAULT_REASONING_EFFORT
147
+ private metadata: DeepSeekAdapter
148
+
149
+ constructor(private readonly resolveApiKey?: () => Promise<string | undefined>) {
150
+ super()
151
+ this.metadata = createEdgeDeepSeekModel({
152
+ resolveApiKey: () => Promise.resolve('dsh-edge-model-metadata'),
153
+ })
154
+ }
155
+
156
+ bind(sessionId: SessionId, options: {
157
+ baseURL?: string
158
+ maxTokens?: number
159
+ reasoningEffort?: EdgeReasoningEffort
160
+ streamIdleTimeoutMs?: number
161
+ }): () => void {
162
+ this.configureDefaults(
163
+ options.maxTokens ?? DEFAULT_MAX_TOKENS,
164
+ options.reasoningEffort ?? DEFAULT_REASONING_EFFORT,
165
+ )
166
+ return this.bindAdapter(sessionId, createEdgeDeepSeekModel({
167
+ ...options,
168
+ resolveApiKey: this.resolveApiKey ?? (() => Promise.resolve(undefined)),
169
+ }))
170
+ }
171
+
172
+ private configureDefaults(
173
+ maxTokens: number,
174
+ reasoningEffort: EdgeReasoningEffort,
175
+ ): void {
176
+ if (maxTokens === this.metadataMaxTokens
177
+ && reasoningEffort === this.metadataReasoningEffort) return
178
+ if (this.active.size > 0) {
179
+ throw new LlmError(
180
+ 'dsh-edge: deployment model defaults changed while another session is active',
181
+ 'EDGE_MODEL_BUSY',
182
+ )
183
+ }
184
+ this.metadata = createEdgeDeepSeekModel({
185
+ resolveApiKey: () => Promise.resolve('dsh-edge-model-metadata'),
186
+ maxTokens,
187
+ reasoningEffort,
188
+ })
189
+ this.metadataMaxTokens = maxTokens
190
+ this.metadataReasoningEffort = reasoningEffort
191
+ }
192
+
193
+ bindAdapter(sessionId: SessionId, adapter: LlmAdapter): () => void {
194
+ if (this.active.has(sessionId)) {
195
+ throw new LlmError(`dsh-edge: model is already bound for session "${sessionId}"`, 'EDGE_MODEL_BUSY')
196
+ }
197
+ this.active.set(sessionId, adapter)
198
+ return () => {
199
+ if (this.active.get(sessionId) === adapter) this.active.delete(sessionId)
200
+ }
201
+ }
202
+
203
+ override providerInfo(provider: string): LlmProviderInfo {
204
+ return this.metadata.providerInfo(provider)
205
+ }
206
+
207
+ override providerRetryPolicy(provider: string): ResolvedRetryPolicy {
208
+ return this.metadata.providerRetryPolicy(provider)
209
+ }
210
+
211
+ override listModels(provider: string): Promise<readonly LlmModelInfo[]> {
212
+ return this.metadata.listModels(provider)
213
+ }
214
+
215
+ override resolveModel(
216
+ provider: string,
217
+ model: string,
218
+ signal?: AbortSignal,
219
+ ): Promise<LlmResolvedModelInfo> {
220
+ return this.metadata.resolveModel(provider, model, signal)
221
+ }
222
+
223
+ override stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
224
+ const sessionId = options.sessionId
225
+ const adapter = sessionId === undefined ? undefined : this.active.get(sessionId)
226
+ if (adapter === undefined) {
227
+ throw new LlmError('dsh-edge: no request-scoped DeepSeek configuration is bound', 'EDGE_MODEL_NOT_BOUND')
228
+ }
229
+ return adapter.stream(options)
230
+ }
231
+ }
@@ -0,0 +1,147 @@
1
+ /** Deployment configuration shared by Edge health and turn admission. */
2
+
3
+ import type { EdgeReasoningEffort } from './deepseek.ts'
4
+ import {
5
+ resolveEdgeBaseURL,
6
+ resolveEdgeMaxOutputTokens,
7
+ resolveEdgeModel,
8
+ resolveEdgeReasoningEffort,
9
+ resolveEdgeStreamIdleTimeoutMs,
10
+ } from './deepseek.ts'
11
+ import { resolveDeepSeekApiKey } from './http.ts'
12
+ import { resolveEdgeSearchBaseURL } from './web-search.ts'
13
+ import {
14
+ resolveEdgeCommandTimeoutPolicy,
15
+ type EdgeCommandTimeoutPolicy,
16
+ } from './workspace.ts'
17
+ import { DSH_EDGE_UPSTREAM_VERSION, DSH_EDGE_VERSION } from './release.ts'
18
+
19
+ declare const __DSH_EDGE_DEPLOYMENT_ID__: string | undefined
20
+
21
+ const LOCAL_DEPLOYMENT_ID = 'local-development'
22
+
23
+ /** Worker variables that control one Edge model and shell turn. */
24
+ export interface EdgeDeploymentConfigSource {
25
+ LOADER?: unknown
26
+ DEEPSEEK_API_KEY?: string
27
+ DEEPSEEK_BASE_URL?: string
28
+ DEEPSEEK_MAX_OUTPUT_TOKENS?: string
29
+ DEEPSEEK_MODEL?: string
30
+ DEEPSEEK_REASONING_EFFORT?: string
31
+ DEEPSEEK_SEARCH_BASE_URL?: string
32
+ DEEPSEEK_STREAM_IDLE_TIMEOUT_MS?: string
33
+ DSH_EDGE_DEFAULT_COMMAND_TIMEOUT_MS?: string
34
+ DSH_EDGE_MAX_COMMAND_TIMEOUT_MS?: string
35
+ }
36
+
37
+ /** Validated deployment choices consumed by one Edge turn. */
38
+ export interface EdgeDeploymentConfig {
39
+ baseURL: string
40
+ maxTokens: number
41
+ model: string
42
+ reasoningEffort: EdgeReasoningEffort
43
+ searchBaseURL: string
44
+ streamIdleTimeoutMs: number
45
+ commandTimeoutPolicy: EdgeCommandTimeoutPolicy
46
+ }
47
+
48
+ /** Secret-free deployment facts safe to project to the authenticated owner. */
49
+ export interface EdgeDeploymentProfile {
50
+ shell: 'just-bash-direct' | 'just-bash-isolated'
51
+ storage: 'durable-object-sqlite-vfs'
52
+ deploymentId: string
53
+ apiKeyConfigured: boolean
54
+ baseURL: string
55
+ maxTokens: number
56
+ model: string
57
+ reasoningEffort: EdgeReasoningEffort
58
+ searchBaseURL: string
59
+ streamIdleTimeoutMs: number
60
+ commandTimeoutPolicy: EdgeCommandTimeoutPolicy
61
+ }
62
+
63
+ /** Identify the exact Worker artifact that answered a readiness request. */
64
+ export function resolveEdgeDeploymentId(): string {
65
+ return typeof __DSH_EDGE_DEPLOYMENT_ID__ === 'string'
66
+ ? __DSH_EDGE_DEPLOYMENT_ID__
67
+ : LOCAL_DEPLOYMENT_ID
68
+ }
69
+
70
+ /** Resolve every deployment choice before health succeeds or a turn is claimed. */
71
+ export function resolveEdgeDeploymentConfig(
72
+ source: EdgeDeploymentConfigSource,
73
+ ): EdgeDeploymentConfig {
74
+ resolveDeepSeekApiKey(source.DEEPSEEK_API_KEY)
75
+ return {
76
+ baseURL: resolveEdgeBaseURL(source.DEEPSEEK_BASE_URL),
77
+ maxTokens: resolveEdgeMaxOutputTokens(source.DEEPSEEK_MAX_OUTPUT_TOKENS),
78
+ model: resolveEdgeModel(source.DEEPSEEK_MODEL),
79
+ reasoningEffort: resolveEdgeReasoningEffort(source.DEEPSEEK_REASONING_EFFORT),
80
+ searchBaseURL: resolveEdgeSearchBaseURL(source.DEEPSEEK_SEARCH_BASE_URL),
81
+ streamIdleTimeoutMs: resolveEdgeStreamIdleTimeoutMs(
82
+ source.DEEPSEEK_STREAM_IDLE_TIMEOUT_MS,
83
+ ),
84
+ commandTimeoutPolicy: resolveEdgeCommandTimeoutPolicy(
85
+ source.DSH_EDGE_DEFAULT_COMMAND_TIMEOUT_MS,
86
+ source.DSH_EDGE_MAX_COMMAND_TIMEOUT_MS,
87
+ ),
88
+ }
89
+ }
90
+
91
+ /** Whether the deployment supplies a non-blank DeepSeek Worker binding. */
92
+ export function edgeDeploymentApiKeyConfigured(source: EdgeDeploymentConfigSource): boolean {
93
+ return typeof source.DEEPSEEK_API_KEY === 'string'
94
+ && source.DEEPSEEK_API_KEY.trim().length > 0
95
+ }
96
+
97
+ /** Omit URL components that commonly carry credentials from the browser projection. */
98
+ function projectedEdgeBaseURL(raw?: string): string {
99
+ const value = resolveEdgeBaseURL(raw)
100
+ const parsed = new URL(value)
101
+ if (parsed.search.length === 0 && parsed.hash.length === 0) return value
102
+ parsed.search = ''
103
+ parsed.hash = ''
104
+ return parsed.href
105
+ }
106
+
107
+ /** Resolve the effective runtime profile without retaining or returning a credential value. */
108
+ export function resolveEdgeDeploymentProfile(
109
+ source: EdgeDeploymentConfigSource,
110
+ ): EdgeDeploymentProfile {
111
+ return {
112
+ shell: source.LOADER === undefined ? 'just-bash-direct' : 'just-bash-isolated',
113
+ storage: 'durable-object-sqlite-vfs',
114
+ deploymentId: resolveEdgeDeploymentId(),
115
+ apiKeyConfigured: edgeDeploymentApiKeyConfigured(source),
116
+ baseURL: projectedEdgeBaseURL(source.DEEPSEEK_BASE_URL),
117
+ maxTokens: resolveEdgeMaxOutputTokens(source.DEEPSEEK_MAX_OUTPUT_TOKENS),
118
+ model: resolveEdgeModel(source.DEEPSEEK_MODEL),
119
+ reasoningEffort: resolveEdgeReasoningEffort(source.DEEPSEEK_REASONING_EFFORT),
120
+ searchBaseURL: resolveEdgeSearchBaseURL(source.DEEPSEEK_SEARCH_BASE_URL),
121
+ streamIdleTimeoutMs: resolveEdgeStreamIdleTimeoutMs(
122
+ source.DEEPSEEK_STREAM_IDLE_TIMEOUT_MS,
123
+ ),
124
+ commandTimeoutPolicy: resolveEdgeCommandTimeoutPolicy(
125
+ source.DSH_EDGE_DEFAULT_COMMAND_TIMEOUT_MS,
126
+ source.DSH_EDGE_MAX_COMMAND_TIMEOUT_MS,
127
+ ),
128
+ }
129
+ }
130
+
131
+ /** Validate the default turn configuration and return the public runtime identity. */
132
+ export function resolveEdgeDeploymentHealth(source: EdgeDeploymentConfigSource) {
133
+ resolveEdgeDeploymentConfig(source)
134
+ const profile = resolveEdgeDeploymentProfile(source)
135
+ return {
136
+ ok: true,
137
+ service: 'dsh-edge',
138
+ storage: profile.storage,
139
+ shell: profile.shell,
140
+ agent: 'upstream-react-loop-agent',
141
+ access: 'single-owner-cookie',
142
+ deploymentId: profile.deploymentId,
143
+ version: DSH_EDGE_VERSION,
144
+ upstreamVersion: DSH_EDGE_UPSTREAM_VERSION,
145
+ status: 'ready',
146
+ } as const
147
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Direct-build replacement for Computer's embedded Dynamic Worker modules.
3
+ *
4
+ * Direct deployments have no Loader binding, so they cannot select
5
+ * `WorkerShellBackend`. The alias keeps Computer's filesystem and command
6
+ * adapters available without uploading an unreachable shell runtime.
7
+ */
8
+ const directShellCore = Object.freeze({})
9
+
10
+ export default directShellCore
@@ -0,0 +1,5 @@
1
+ /** Byte ceiling shared by shell execution, retention, and truncation rendering. */
2
+ export const EDGE_SHELL_OUTPUT_LIMIT_BYTES = 65_536
3
+
4
+ /** Standard shell-event result used when direct just-bash stops at its output budget. */
5
+ export const DIRECT_SHELL_OUTPUT_TRUNCATED = 'dsh-edge:direct-output-truncated'