@ljwei-stak/dsh-model-route-bot 0.66.3 → 0.67.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.
- package/.dsh-plugin/bot-product.mjs +81 -5
- package/.dsh-plugin/client.js +17490 -1791
- package/README.i18n.yaml +4 -4
- package/README.md +409 -364
- package/README.zh.md +409 -364
- package/apps/integration-client/README.md +31 -7
- package/apps/integration-client/api.mjs +14 -3
- package/apps/integration-client/binding-editor.jsx +308 -109
- package/apps/integration-client/binding-model.mjs +262 -0
- package/apps/integration-client/binding.css +144 -0
- package/apps/integration-client/bot-model-status.mjs +18 -0
- package/apps/integration-client/bot-profile-identity.jsx +197 -0
- package/apps/integration-client/bot-profile.css +57 -0
- package/apps/integration-client/bot-profile.mjs +97 -0
- package/apps/integration-client/bot-settings-dialog.css +18 -0
- package/apps/integration-client/bot-settings-dialog.jsx +111 -0
- package/apps/integration-client/bot-thread-header-bridge.css +20 -0
- package/apps/integration-client/bot-thread-header.jsx +278 -0
- package/apps/integration-client/bot-threads-panel.jsx +378 -0
- package/apps/integration-client/bot-threads.css +169 -0
- package/apps/integration-client/chat-design.mjs +250 -0
- package/apps/integration-client/chat-ui.jsx +175 -0
- package/apps/integration-client/chat.css +477 -0
- package/apps/integration-client/composer-draft-binding.mjs +50 -0
- package/apps/integration-client/composer-draft-bound.jsx +14 -0
- package/apps/integration-client/composer-draft-host.jsx +142 -0
- package/apps/integration-client/composer-draft-session.jsx +287 -0
- package/apps/integration-client/composer-draft-witness.mjs +115 -0
- package/apps/integration-client/composer-draft.css +4 -0
- package/apps/integration-client/composer-draft.mjs +322 -0
- package/apps/integration-client/contact-attention.jsx +54 -0
- package/apps/integration-client/data-panel.jsx +439 -0
- package/apps/integration-client/data.css +69 -0
- package/apps/integration-client/desktop-bridge.mjs +1 -0
- package/apps/integration-client/desktop-http-socket.mjs +49 -0
- package/apps/integration-client/desktop-keyboard.mjs +32 -0
- package/apps/integration-client/desktop-pane.jsx +99 -30
- package/apps/integration-client/desktop-stream.mjs +13 -3
- package/apps/integration-client/desktop-tools.jsx +19 -0
- package/apps/integration-client/desktop-touch.mjs +27 -0
- package/apps/integration-client/desktop.css +41 -0
- package/apps/integration-client/independent-chat-controller.mjs +224 -0
- package/apps/integration-client/independent-chat-entry.jsx +61 -0
- package/apps/integration-client/independent-chat-navigation.mjs +21 -0
- package/apps/integration-client/independent-chat-page.jsx +148 -0
- package/apps/integration-client/independent-chat-rich.jsx +64 -0
- package/apps/integration-client/independent-chat-rich.mjs +30 -0
- package/apps/integration-client/independent-chat.css +73 -0
- package/apps/integration-client/index.jsx +24 -16
- package/apps/integration-client/library-panel.jsx +4 -1
- package/apps/integration-client/licenses/jsqr-1.4.0-LICENSE.txt +202 -0
- package/apps/integration-client/main-route-editor.jsx +94 -0
- package/apps/integration-client/main-route-model.mjs +100 -0
- package/apps/integration-client/model-picker.css +37 -0
- package/apps/integration-client/model-picker.jsx +83 -0
- package/apps/integration-client/native-activity.css +141 -0
- package/apps/integration-client/native-activity.jsx +276 -0
- package/apps/integration-client/native-activity.mjs +384 -0
- package/apps/integration-client/notifications-panel.jsx +186 -0
- package/apps/integration-client/notifications.css +126 -0
- package/apps/integration-client/pairing-qr.jsx +79 -0
- package/apps/integration-client/panels.jsx +126 -115
- package/apps/integration-client/product-slots.jsx +46 -0
- package/apps/integration-client/routine-recorder.mjs +23 -2
- package/apps/integration-client/secure-pairing.jsx +84 -0
- package/apps/integration-client/tasks-panel.jsx +32 -10
- package/apps/integration-client/ui-icons.jsx +17 -0
- package/apps/integration-client/usage-explorer.jsx +43 -0
- package/apps/integration-client/usage-report.mjs +71 -0
- package/apps/integration-client/usage.css +34 -0
- package/apps/integration-client/web-panel-model.mjs +140 -0
- package/apps/integration-client/web-panel-page.jsx +221 -0
- package/apps/integration-client/web-panel-pins-live.jsx +28 -0
- package/apps/integration-client/web-panel.css +139 -0
- package/apps/integration-client/workspace-model.mjs +67 -0
- package/apps/integration-client/workspace-navigation.mjs +56 -0
- package/apps/integration-client/workspace-ui.jsx +173 -0
- package/apps/integration-client/workspace.css +332 -0
- package/modules/bot-runtime/SOURCE.json +176 -50
- package/modules/bot-runtime/index.mjs +169 -13
- package/modules/bot-runtime/product-overlay/OVERLAY.json +128 -2
- package/modules/bot-runtime/product-overlay/base/src/client/header.js +244 -0
- package/modules/bot-runtime/product-overlay/base/src/client/learning-card.js +202 -0
- package/modules/bot-runtime/product-overlay/base/src/client/model-menu.js +371 -0
- package/modules/bot-runtime/product-overlay/base/src/client/secret-card.js +363 -0
- package/modules/bot-runtime/product-overlay/base/src/client/sources.js +68 -0
- package/modules/bot-runtime/product-overlay/base/src/client/turn-error.js +260 -0
- package/modules/bot-runtime/product-overlay/base/src/host/channel.js +647 -0
- package/modules/bot-runtime/product-overlay/base/src/host/memory.js +2050 -0
- package/modules/bot-runtime/product-overlay/base/src/host/models.js +314 -0
- package/modules/bot-runtime/product-overlay/base/src/host/parts.js +1473 -0
- package/modules/bot-runtime/product-overlay/base/src/host/privacy.js +368 -0
- package/modules/bot-runtime/product-overlay/base/src/host/roster.js +776 -0
- package/modules/bot-runtime/product-overlay/base/src/host/store.js +512 -0
- package/modules/bot-runtime/product-overlay/base/src/host/usage.js +653 -0
- package/modules/bot-runtime/product-overlay/patches/src/client/details-drawer.js.patch +48 -2
- package/modules/bot-runtime/product-overlay/patches/src/client/header.js.patch +41 -0
- package/modules/bot-runtime/product-overlay/patches/src/client/index.js.patch +33 -1
- package/modules/bot-runtime/product-overlay/patches/src/client/learning-card.js.patch +20 -0
- package/modules/bot-runtime/product-overlay/patches/src/client/model-menu.js.patch +24 -0
- package/modules/bot-runtime/product-overlay/patches/src/client/secret-card.js.patch +25 -0
- package/modules/bot-runtime/product-overlay/patches/src/client/sources.js.patch +52 -0
- package/modules/bot-runtime/product-overlay/patches/src/client/turn-error.js.patch +23 -0
- package/modules/bot-runtime/product-overlay/patches/src/host/channel.js.patch +46 -0
- package/modules/bot-runtime/product-overlay/patches/src/host/memory.js.patch +11 -0
- package/modules/bot-runtime/product-overlay/patches/src/host/models.js.patch +16 -0
- package/modules/bot-runtime/product-overlay/patches/src/host/parts.js.patch +95 -0
- package/modules/bot-runtime/product-overlay/patches/src/host/privacy.js.patch +11 -0
- package/modules/bot-runtime/product-overlay/patches/src/host/roster.js.patch +145 -0
- package/modules/bot-runtime/product-overlay/patches/src/host/store.js.patch +68 -0
- package/modules/bot-runtime/product-overlay/patches/src/host/usage.js.patch +11 -0
- package/modules/bot-runtime/read-model.mjs +19 -4
- package/modules/bot-runtime/vendor/ds-bot/src/client/details-drawer.js +15 -5
- package/modules/bot-runtime/vendor/ds-bot/src/client/header.js +9 -2
- package/modules/bot-runtime/vendor/ds-bot/src/client/index.js +9 -2
- package/modules/bot-runtime/vendor/ds-bot/src/client/learning-card.js +2 -2
- package/modules/bot-runtime/vendor/ds-bot/src/client/model-menu.js +5 -3
- package/modules/bot-runtime/vendor/ds-bot/src/client/secret-card.js +3 -3
- package/modules/bot-runtime/vendor/ds-bot/src/client/sources.js +25 -2
- package/modules/bot-runtime/vendor/ds-bot/src/client/turn-error.js +3 -2
- package/modules/bot-runtime/vendor/ds-bot/src/host/channel.js +14 -2
- package/modules/bot-runtime/vendor/ds-bot/src/host/memory.js +1 -1
- package/modules/bot-runtime/vendor/ds-bot/src/host/models.js +7 -0
- package/modules/bot-runtime/vendor/ds-bot/src/host/parts.js +26 -9
- package/modules/bot-runtime/vendor/ds-bot/src/host/privacy.js +1 -1
- package/modules/bot-runtime/vendor/ds-bot/src/host/roster.js +112 -3
- package/modules/bot-runtime/vendor/ds-bot/src/host/store.js +34 -1
- package/modules/bot-runtime/vendor/ds-bot/src/host/usage.js +1 -1
- package/modules/independent-runtime/index.mjs +152 -62
- package/modules/independent-runtime/remote-tools.mjs +8 -5
- package/modules/openmaus-protocol/NOTICE +10 -0
- package/modules/openmaus-protocol/README.md +15 -0
- package/modules/openmaus-protocol/SOURCE.json +68 -0
- package/modules/openmaus-protocol/dist/protocol.mjs +1203 -0
- package/modules/openmaus-protocol/index.mjs +1 -0
- package/modules/openmaus-protocol/transport.mjs +77 -0
- package/modules/openmaus-protocol/vendor/LICENSE +202 -0
- package/modules/openmaus-protocol/vendor/companion/src/e2e/README.md +405 -0
- package/modules/openmaus-protocol/vendor/companion/src/e2e/credentials.ts +128 -0
- package/modules/openmaus-protocol/vendor/companion/src/e2e/descriptor.ts +84 -0
- package/modules/openmaus-protocol/vendor/companion/src/e2e/noise.ts +456 -0
- package/modules/openmaus-protocol/vendor/companion/src/e2e/phone.ts +104 -0
- package/modules/openmaus-protocol/vendor/companion/src/e2e/session.ts +417 -0
- package/modules/openmaus-protocol/vendor/companion/src/e2e/vectors/v1.json +2565 -0
- package/modules/openmaus-protocol/vendor/companion/src/e2e/vectors/v1.sha256 +1 -0
- package/modules/openmaus-protocol/vendor/companion/src/e2e/yamux.ts +335 -0
- package/package.json +20 -6
- package/packages/bot-acp/README.md +156 -0
- package/packages/bot-acp/licenses/LICENSE-OpenMausBot +202 -0
- package/packages/bot-acp/licenses/NOTICE.md +27 -0
- package/packages/bot-acp/src/acp-adapter.mjs +795 -0
- package/packages/bot-acp/src/acp-host.mjs +148 -0
- package/packages/bot-acp/src/native-launch.mjs +121 -0
- package/packages/bot-acp/src/permission-policy.mjs +283 -0
- package/packages/bot-acp/src/rpc-codec.mjs +265 -0
- package/packages/bot-acp/src/session-core.mjs +581 -0
- package/packages/bot-acp/src/stdio-rpc.mjs +329 -0
- package/packages/bot-engines/README.md +281 -0
- package/packages/bot-engines/licenses/LICENSE-OpenMausBot +202 -0
- package/packages/bot-engines/licenses/NOTICE.md +32 -0
- package/packages/bot-engines/src/claude-engine.mjs +772 -0
- package/packages/bot-engines/src/claude-llm-adapter.mjs +797 -0
- package/packages/bot-engines/src/claude-llm-turn.mjs +292 -0
- package/packages/bot-engines/src/claude-permission-broker.mjs +130 -0
- package/packages/bot-engines/src/claude-permission-proxy.mjs +87 -0
- package/packages/bot-engines/src/claude-protocol.mjs +177 -0
- package/packages/bot-engines/src/driver-catalog.mjs +334 -0
- package/packages/bot-engines/src/host-loop-request.mjs +95 -0
- package/packages/bot-engines/src/host-registrations.mjs +105 -0
- package/packages/capability-broker/src/cli-bootstrap.mjs +86 -16
- package/packages/capability-broker/src/cli-bridge-response.mjs +80 -0
- package/packages/capability-broker/src/cli-stdio-bridge.mjs +21 -8
- package/packages/cli-runtime/src/codex-session-core.mjs +4 -0
- package/packages/cli-runtime/src/native-cli-output.mjs +57 -0
- package/packages/cli-runtime/src/native-peer.ps1 +51 -3
- package/packages/cli-runtime/src/native-process.mjs +77 -14
- package/packages/model-router-plugin/README.md +3 -3
- package/packages/model-router-plugin/package.json +1 -1
- package/packages/orchestration/src/binding-product.mjs +19 -0
- package/packages/orchestration/src/bot-data-actions.mjs +45 -0
- package/packages/orchestration/src/bot-data-chart.mjs +109 -0
- package/packages/orchestration/src/bot-data-context.mjs +44 -0
- package/packages/orchestration/src/bot-data-engine.mjs +809 -0
- package/packages/orchestration/src/bot-data-io.mjs +186 -0
- package/packages/orchestration/src/bot-data-sql.mjs +195 -0
- package/packages/orchestration/src/bot-data-surface.mjs +144 -0
- package/packages/orchestration/src/bot-data-tools.mjs +68 -0
- package/packages/orchestration/src/bot-data-worker.mjs +228 -0
- package/packages/orchestration/src/bot-independent-execution.mjs +195 -0
- package/packages/orchestration/src/bot-independent-stream.mjs +74 -0
- package/packages/orchestration/src/bot-loop.mjs +152 -19
- package/packages/orchestration/src/bot-notifications.mjs +159 -0
- package/packages/orchestration/src/bot-policy.mjs +43 -4
- package/packages/orchestration/src/bot-profile.mjs +171 -0
- package/packages/orchestration/src/bot-routine.mjs +4 -4
- package/packages/orchestration/src/bot-runtime-assembly.mjs +255 -8
- package/packages/orchestration/src/bot-runtime-switch.mjs +13 -2
- package/packages/orchestration/src/bot-serving.mjs +164 -0
- package/packages/orchestration/src/bot-session-store.mjs +105 -9
- package/packages/orchestration/src/bot-settings.mjs +50 -11
- package/packages/orchestration/src/bot-thread-admission.mjs +84 -0
- package/packages/orchestration/src/bot-thread-host.mjs +187 -0
- package/packages/orchestration/src/bot-threads.mjs +790 -0
- package/packages/orchestration/src/data-product-access.mjs +37 -0
- package/packages/orchestration/src/data-tool-contract.mjs +291 -0
- package/packages/orchestration/src/desktop-http-carrier.mjs +120 -0
- package/packages/orchestration/src/desktop-proxy.mjs +311 -0
- package/packages/orchestration/src/desktop-sessions.mjs +43 -9
- package/packages/orchestration/src/ds-lifecycle.mjs +31 -4
- package/packages/orchestration/src/grant-refresh-queue.mjs +17 -0
- package/packages/orchestration/src/independent-chat-page.mjs +39 -0
- package/packages/orchestration/src/independent-chat-service.mjs +308 -0
- package/packages/orchestration/src/independent-context-state.mjs +44 -0
- package/packages/orchestration/src/independent-message-wire.mjs +84 -0
- package/packages/orchestration/src/independent-tool-catalog.mjs +175 -0
- package/packages/orchestration/src/independent-tool-families.mjs +73 -0
- package/packages/orchestration/src/independent-tool-host.mjs +344 -0
- package/packages/orchestration/src/main-bot-grant.mjs +15 -0
- package/packages/orchestration/src/main-model-routes.mjs +208 -0
- package/packages/orchestration/src/model-accounting.mjs +99 -35
- package/packages/orchestration/src/model-auxiliary-dispatch.mjs +187 -0
- package/packages/orchestration/src/model-loop-frame.mjs +179 -0
- package/packages/orchestration/src/model-prepared-generation.mjs +175 -0
- package/packages/orchestration/src/model-request-bounds.mjs +111 -0
- package/packages/orchestration/src/native-activity-contract.mjs +491 -0
- package/packages/orchestration/src/native-activity-service.mjs +102 -0
- package/packages/orchestration/src/native-activity-store.mjs +249 -0
- package/packages/orchestration/src/native-conversation-tools.mjs +78 -0
- package/packages/orchestration/src/native-data-tools.mjs +100 -0
- package/packages/orchestration/src/native-remote-actions.mjs +742 -0
- package/packages/orchestration/src/native-team-tools.mjs +73 -0
- package/packages/orchestration/src/pairing-invite.mjs +37 -0
- package/packages/orchestration/src/product-composition.mjs +1559 -1001
- package/packages/orchestration/src/remote-machines.mjs +82 -14
- package/packages/orchestration/src/routine-execution.mjs +5 -3
- package/packages/orchestration/src/routine-session.mjs +19 -13
- package/packages/orchestration/src/secure-pairing-host.mjs +112 -0
- package/packages/orchestration/src/task-journal.mjs +29 -0
- package/packages/orchestration/src/task-product.mjs +17 -0
- package/packages/orchestration/src/team-assignment-store.mjs +120 -0
- package/packages/orchestration/src/team-bridge.mjs +282 -0
- package/packages/orchestration/src/team-scheduler.mjs +83 -0
- package/packages/orchestration/src/team-sdk-tools.mjs +84 -0
- package/packages/orchestration/src/team-tool-contract.mjs +284 -0
- package/packages/orchestration/src/ui-host-namespace.mjs +23 -0
- package/packages/orchestration/src/web-panel-actions.mjs +103 -0
- package/packages/orchestration/src/web-panel-framing.mjs +227 -0
- package/packages/orchestration/src/web-panel-store.mjs +206 -0
- package/remote-computer-agent/README.md +39 -29
- package/remote-computer-agent/build.mjs +3 -0
- package/remote-computer-agent/dist/OPENMAUSBOT_LICENSE +202 -0
- package/remote-computer-agent/dist/OPENMAUSBOT_NOTICE +10 -0
- package/remote-computer-agent/dist/OPENMAUSBOT_SOURCE.json +68 -0
- package/remote-computer-agent/dist/cli-stdio-bridge.mjs +215 -25
- package/remote-computer-agent/dist/cli-stdio-bridge.mjs.map +4 -4
- package/remote-computer-agent/dist/cli.mjs +1688 -168
- package/remote-computer-agent/dist/cli.mjs.map +4 -4
- package/remote-computer-agent/dist/index.mjs +1579 -122
- package/remote-computer-agent/dist/index.mjs.map +4 -4
- package/remote-computer-agent/dist/native-peer.ps1 +51 -3
- package/remote-computer-agent/package-lock.json +308 -2
- package/remote-computer-agent/package.json +2 -1
- package/remote-computer-agent/pair-device.ps1 +20 -0
- package/remote-computer-agent/setup.ps1 +38 -16
- package/remote-computer-agent/src/cli.ts +24 -3
- package/remote-computer-agent/src/desktop-session.ts +11 -3
- package/remote-computer-agent/src/e2e-server.ts +81 -0
- package/remote-computer-agent/src/pairing-page.ts +35 -0
- package/remote-computer-agent/src/protocol.ts +25 -25
- package/remote-computer-agent/src/secure-pairing.ts +105 -0
- package/remote-computer-agent/src/store.ts +20 -5
- package/remote-computer-agent/src/transport.ts +39 -15
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { createElement as h, useEffect, useMemo, useState, useSyncExternalStore } from 'react'
|
|
2
|
+
import { currentPart, isHiddenTurn } from './text.js'
|
|
3
|
+
import { CheckIcon, CopyIcon } from './icons.js'
|
|
4
|
+
import { ModelKeyCard, manageModels } from './model-menu.js'
|
|
5
|
+
import { knownFailure } from './diagnostics.js'
|
|
6
|
+
import { hostText, t } from './i18n.js'
|
|
7
|
+
|
|
8
|
+
// -------------------------------------------------------------------------
|
|
9
|
+
// A failed turn in a Bot's chat: what went wrong and what the user can do about it,
|
|
10
|
+
// in place of DSH's row. The copy and the fixes go by DSH's stable failure code, never
|
|
11
|
+
// by the provider's message, which shows only under Technical details. The chat node
|
|
12
|
+
// carries no HTTP status or request id; the host keeps them, with the failing route's
|
|
13
|
+
// provider, on the Bot as `blocked` while a credential or balance failure stands.
|
|
14
|
+
|
|
15
|
+
const OFFICIAL = 'deepseek-official'
|
|
16
|
+
const ACCOUNT = 'deepseek-account'
|
|
17
|
+
const TOP_UP_URL = 'https://platform.deepseek.com/top_up'
|
|
18
|
+
// How long a sign-in started here waits for the account's models before the user picks.
|
|
19
|
+
const ACCOUNT_MODELS_WAIT_MS = 20_000
|
|
20
|
+
const SIGNED_OUT = new Set(['ACCOUNT_SIGN_IN_REQUIRED', 'ACCOUNT_SIGNED_OUT', 'ACCOUNT_TOKEN_INVALID'])
|
|
21
|
+
// Failures of an API key route; the account route never has them.
|
|
22
|
+
const KEY_CODES = new Set(['MISSING_CREDENTIAL', 'INVALID_CREDENTIAL', 'AUTH'])
|
|
23
|
+
// Until the credentials change the host keeps these on the Bot, and a retry would fail
|
|
24
|
+
// the same way, so Retry waits for the fix.
|
|
25
|
+
const CREDENTIAL_CODES = new Set([...KEY_CODES, ...SIGNED_OUT])
|
|
26
|
+
|
|
27
|
+
// The sentence for one failure. `status` is the HTTP status, when the host has it.
|
|
28
|
+
export function failureText(code, { name, provider, status }) {
|
|
29
|
+
switch (code) {
|
|
30
|
+
case 'MISSING_CREDENTIAL': return t("{name}'s model has no API key yet.", { name })
|
|
31
|
+
case 'INVALID_CREDENTIAL': return t('This API key is not in the right format.')
|
|
32
|
+
case 'AUTH': return status === undefined
|
|
33
|
+
? t('{provider} did not accept the current API key.', { provider })
|
|
34
|
+
: t('{provider} did not accept the current API key ({status}).', { provider, status })
|
|
35
|
+
case 'QUOTA': return status === undefined
|
|
36
|
+
? t('{provider} is out of balance or quota.', { provider })
|
|
37
|
+
: t('{provider} is out of balance or quota ({status}).', { provider, status })
|
|
38
|
+
case 'ACCOUNT_QUOTA': return t('The DeepSeek account balance is too low.')
|
|
39
|
+
case 'ACCOUNT_SIGN_IN_REQUIRED':
|
|
40
|
+
case 'ACCOUNT_SIGNED_OUT':
|
|
41
|
+
case 'ACCOUNT_TOKEN_INVALID': return t('The DeepSeek account sign-in has expired.')
|
|
42
|
+
case 'TRANSPORT':
|
|
43
|
+
case 'TIMEOUT': return t('Could not reach the model service.')
|
|
44
|
+
case 'RATE_LIMIT': return t('Too many requests. Wait a moment, then try again.')
|
|
45
|
+
case 'SERVER': return t('The model service failed.')
|
|
46
|
+
case 'INTERRUPTED': return t('DeepSeek Harness stopped before this turn finished.')
|
|
47
|
+
default: return knownFailure(code) ?? t('This turn failed.')
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// The fixes one failure offers, the one to try first leading. Each is offered only
|
|
52
|
+
// where this window can carry it out. A Bot moved onto the account route since a key
|
|
53
|
+
// failure has nothing left to fix there.
|
|
54
|
+
export function fixesFor(code, { canSignIn, official, topUp, onAccount = false }) {
|
|
55
|
+
if (onAccount && KEY_CODES.has(code)) return []
|
|
56
|
+
if (SIGNED_OUT.has(code)) return canSignIn ? ['sign-in-again'] : ['model']
|
|
57
|
+
switch (code) {
|
|
58
|
+
case 'MISSING_CREDENTIAL': return ['key', canSignIn ? 'sign-in' : null, 'model'].filter(Boolean)
|
|
59
|
+
case 'INVALID_CREDENTIAL': return ['rekey', 'model']
|
|
60
|
+
case 'AUTH': return ['rekey', canSignIn ? 'use-account' : null, 'model'].filter(Boolean)
|
|
61
|
+
case 'QUOTA': return official ? ['top-up'] : []
|
|
62
|
+
case 'ACCOUNT_QUOTA': return topUp ? ['top-up'] : []
|
|
63
|
+
default: return []
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const retryShown = (code, blocked) => !CREDENTIAL_CODES.has(code) || blocked === undefined
|
|
68
|
+
|
|
69
|
+
const FIX_LABELS = {
|
|
70
|
+
key: () => t('Enter API key'),
|
|
71
|
+
rekey: () => t('Enter the key again'),
|
|
72
|
+
'sign-in': signedIn => (signedIn ? t('Use the DeepSeek account') : t('Sign in with a DeepSeek account')),
|
|
73
|
+
'use-account': () => t('Use a DeepSeek account instead'),
|
|
74
|
+
'sign-in-again': () => t('Sign in again'),
|
|
75
|
+
model: () => t('Pick another model'),
|
|
76
|
+
'top-up': () => t('Top up ↗'),
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const NO_SUBSCRIBE = () => () => {}
|
|
80
|
+
const NO_VIEW = () => null
|
|
81
|
+
|
|
82
|
+
// The shell account plugin's view of the DeepSeek account: its sign-in status and links.
|
|
83
|
+
function useAccountView(actions) {
|
|
84
|
+
const entry = actions.signInEntry?.() ?? null
|
|
85
|
+
const ops = useMemo(() => entry?.inject?.() ?? {}, [entry])
|
|
86
|
+
const source = ops.hooks?.account
|
|
87
|
+
const read = source ? () => source.getSnapshot()?.view ?? null : NO_VIEW
|
|
88
|
+
return useSyncExternalStore(source?.subscribe ?? NO_SUBSCRIBE, read, read)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// The DeepSeek account's own top-up page.
|
|
92
|
+
const topUpOf = (view) => {
|
|
93
|
+
const url = view?.links?.topUpUrl
|
|
94
|
+
return typeof url === 'string' && url.startsWith('https://') ? url : undefined
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// The account route's model for a Bot moved onto it: the DSH default when it is one,
|
|
98
|
+
// else the first one listed. The account lists its models only once it is signed in,
|
|
99
|
+
// a moment after the sign-in itself.
|
|
100
|
+
export function accountModel(roster) {
|
|
101
|
+
const models = (roster.models ?? []).filter(model => model.provider === ACCOUNT)
|
|
102
|
+
return (models.find(model => model.ref === roster.defaultModel) ?? models[0])?.ref
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const providerOf = (bot, roster) => {
|
|
106
|
+
const ref = bot?.model ?? bot?.appliedModel
|
|
107
|
+
if (!ref) return undefined
|
|
108
|
+
return (roster.models ?? []).find(model => model.ref === ref)?.provider ?? ref.split('/')[0]
|
|
109
|
+
}
|
|
110
|
+
// A provider without a key may not be in the catalog yet, so DeepSeek's own two routes
|
|
111
|
+
// keep a readable name instead of their id.
|
|
112
|
+
const KNOWN_PROVIDERS = { 'deepseek-official': 'DeepSeek', 'deepseek-account': 'DeepSeek account' }
|
|
113
|
+
const providerName = (roster, provider) => (provider === undefined
|
|
114
|
+
? t('The model service')
|
|
115
|
+
: (roster.models ?? []).find(model => model.provider === provider)?.providerName
|
|
116
|
+
?? (KNOWN_PROVIDERS[provider] ? t(KNOWN_PROVIDERS[provider]) : provider))
|
|
117
|
+
|
|
118
|
+
// What Technical details lists, and copies in English for a report.
|
|
119
|
+
export function failureFacts(data, blocked) {
|
|
120
|
+
const facts = []
|
|
121
|
+
if (data.code) facts.push(['Code', t('Code'), data.code])
|
|
122
|
+
if (blocked?.status !== undefined) facts.push(['HTTP status', t('HTTP status'), String(blocked.status)])
|
|
123
|
+
if (blocked?.requestId) facts.push(['Request ID', t('Request ID'), blocked.requestId])
|
|
124
|
+
// DSH already blanks an AUTH message; it never shows here either way.
|
|
125
|
+
if (data.code !== 'AUTH' && data.message) facts.push(['Message', t('Provider message'), data.message])
|
|
126
|
+
return facts
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function TechnicalDetails({ facts }) {
|
|
130
|
+
const [copied, setCopied] = useState(false)
|
|
131
|
+
if (facts.length === 0) return null
|
|
132
|
+
const copy = () => {
|
|
133
|
+
const text = facts.map(([name, , value]) => `${name}: ${value}`).join('\n')
|
|
134
|
+
void navigator.clipboard?.writeText(text).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1000) }).catch(() => {})
|
|
135
|
+
}
|
|
136
|
+
return h('details', { className: 'bt-fail-tech' },
|
|
137
|
+
h('summary', null, t('Technical details')),
|
|
138
|
+
h('dl', null, facts.map(([name, label, value]) => [h('dt', { key: `${name}:t` }, label), h('dd', { key: `${name}:d` }, value)])),
|
|
139
|
+
h('button', { type: 'button', className: 'bt-mini bt-fail-copy', onClick: copy }, copied ? h(CheckIcon) : h(CopyIcon), copied ? t('Copied') : t('Copy')))
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function FailureCell({ node, sessionId, useRoster, useTurnClock, actions }) {
|
|
143
|
+
const roster = useRoster(value => value)
|
|
144
|
+
const data = node?.data ?? {}
|
|
145
|
+
const bot = roster.byId?.[sessionId]
|
|
146
|
+
// A later turn, or a later part of the Bot's chat, has moved past this failure.
|
|
147
|
+
const later = useTurnClock(state => Object.keys(state[sessionId] ?? {}).some(turn => Number(turn) > data.turn))
|
|
148
|
+
const account = useAccountView(actions)
|
|
149
|
+
const signedIn = account?.status === 'credential-stored'
|
|
150
|
+
const topUp = topUpOf(account)
|
|
151
|
+
const [keying, setKeying] = useState(false)
|
|
152
|
+
const [retry, setRetry] = useState('idle')
|
|
153
|
+
const [error, setError] = useState('')
|
|
154
|
+
// A sign-in started here to leave a failing key route, with the model the Bot was on.
|
|
155
|
+
const [joining, setJoining] = useState(null)
|
|
156
|
+
const blocked = bot?.blocked?.code === data.code ? bot.blocked : undefined
|
|
157
|
+
const provider = blocked?.provider ?? providerOf(bot, roster)
|
|
158
|
+
const text = failureText(data.code, { name: bot?.name ?? t('This Bot'), provider: providerName(roster, provider), status: blocked?.status })
|
|
159
|
+
const facts = failureFacts(data, blocked)
|
|
160
|
+
const current = bot !== undefined && currentPart(bot) === sessionId && !later
|
|
161
|
+
// The key route never takes the account's credential, so a sign-in alone leaves the Bot
|
|
162
|
+
// failing; it moves onto the account route. With no account model listed yet, the
|
|
163
|
+
// user picks one.
|
|
164
|
+
const moveToAccount = () => {
|
|
165
|
+
const model = accountModel(roster)
|
|
166
|
+
if (model === undefined) { actions.showDetails?.(sessionId); return }
|
|
167
|
+
if (model === bot.model) return
|
|
168
|
+
setError('')
|
|
169
|
+
void Promise.resolve(actions.updateBot(bot.id, { model })).catch(failure => setError(hostText(failure?.message ?? String(failure))))
|
|
170
|
+
}
|
|
171
|
+
const listed = accountModel(roster)
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
if (joining === null || !signedIn) return undefined
|
|
174
|
+
// A model the user picked meanwhile stands.
|
|
175
|
+
if (bot === undefined || bot.model !== joining.from) { setJoining(null); return undefined }
|
|
176
|
+
if (listed !== undefined) { setJoining(null); moveToAccount(); return undefined }
|
|
177
|
+
// The account's models come with the next listing; without them for a while, the
|
|
178
|
+
// user picks.
|
|
179
|
+
void actions.refreshModels?.()
|
|
180
|
+
const timer = setTimeout(() => { setJoining(null); actions.showDetails?.(sessionId) }, ACCOUNT_MODELS_WAIT_MS)
|
|
181
|
+
return () => clearTimeout(timer)
|
|
182
|
+
}, [joining, signedIn, listed])
|
|
183
|
+
const settled = () => h('div', { className: 'bt-fail', 'data-settled': '', role: 'status' },
|
|
184
|
+
h('div', { className: 'bt-fail-head' }, h('span', { className: 'bt-fail-dot', 'aria-hidden': true }), h('span', { className: 'bt-fail-text' }, text)),
|
|
185
|
+
h(TechnicalDetails, { facts }))
|
|
186
|
+
if (!current) return settled()
|
|
187
|
+
const official = provider === OFFICIAL
|
|
188
|
+
const canSignIn = typeof actions.signIn === 'function' && actions.canSignIn?.() === true
|
|
189
|
+
const keyHere = typeof actions.setProviderKey === 'function' && provider !== undefined
|
|
190
|
+
const keyElsewhere = official && actions.openHarnessOnboarding ? () => actions.openHarnessOnboarding(OFFICIAL) : manageModels(actions)
|
|
191
|
+
const viaAccount = () => {
|
|
192
|
+
if (signedIn) { moveToAccount(); return }
|
|
193
|
+
setJoining({ from: bot.model })
|
|
194
|
+
actions.signIn()
|
|
195
|
+
}
|
|
196
|
+
const runs = {
|
|
197
|
+
key: keyHere ? () => setKeying(value => !value) : keyElsewhere,
|
|
198
|
+
rekey: keyHere ? () => setKeying(value => !value) : keyElsewhere,
|
|
199
|
+
'sign-in': viaAccount,
|
|
200
|
+
'use-account': viaAccount,
|
|
201
|
+
'sign-in-again': () => actions.signIn(),
|
|
202
|
+
model: actions.showDetails ? () => actions.showDetails(sessionId) : undefined,
|
|
203
|
+
}
|
|
204
|
+
const fixes = fixesFor(data.code, { canSignIn, official, topUp: topUp !== undefined, onAccount: provider === ACCOUNT }).filter(fix => fix === 'top-up' || runs[fix] !== undefined)
|
|
205
|
+
// A turn another Bot asked for answers that Bot, which was already told it failed.
|
|
206
|
+
// Retry would answer the user's last message instead, so it is not offered.
|
|
207
|
+
const asked = isHiddenTurn(roster, sessionId, data.turn)
|
|
208
|
+
const retrying = !asked && typeof actions.resume === 'function' && retryShown(data.code, blocked)
|
|
209
|
+
// Once a credential failure is fixed, going on is the next step.
|
|
210
|
+
const retryFirst = retrying && (fixes.length === 0 || CREDENTIAL_CODES.has(data.code))
|
|
211
|
+
const resume = () => {
|
|
212
|
+
setRetry('busy')
|
|
213
|
+
setError('')
|
|
214
|
+
void Promise.resolve(actions.resume(bot.id))
|
|
215
|
+
.then(() => setRetry('sent'), (failure) => { setRetry('idle'); setError(hostText(failure?.message ?? String(failure))) })
|
|
216
|
+
}
|
|
217
|
+
const button = (fix, primary) => {
|
|
218
|
+
const className = primary ? 'bt-send bt-fail-go' : 'bt-soft bt-soft-sm'
|
|
219
|
+
if (fix === 'top-up') {
|
|
220
|
+
return h('a', { key: fix, className: `${className} bt-fail-link`, href: data.code === 'ACCOUNT_QUOTA' ? topUp : TOP_UP_URL, target: '_blank', rel: 'noopener noreferrer' }, FIX_LABELS[fix]())
|
|
221
|
+
}
|
|
222
|
+
const toggles = keyHere && (fix === 'key' || fix === 'rekey')
|
|
223
|
+
return h('button', { key: fix, type: 'button', className, 'aria-expanded': toggles ? keying : undefined, onClick: () => runs[fix]() }, FIX_LABELS[fix](signedIn))
|
|
224
|
+
}
|
|
225
|
+
const retryButton = primary => h('button', { key: 'retry', type: 'button', className: primary ? 'bt-send bt-fail-go' : 'bt-soft bt-soft-sm', disabled: retry !== 'idle', onClick: resume }, retry === 'idle' ? t('Retry') : t('Retrying…'))
|
|
226
|
+
const row = retryFirst
|
|
227
|
+
? [retryButton(true), ...fixes.map(fix => button(fix, false))]
|
|
228
|
+
: [...fixes.map((fix, index) => button(fix, index === 0)), retrying ? retryButton(false) : null]
|
|
229
|
+
// With nothing to do here the card reads as one a later turn moved past.
|
|
230
|
+
if (!row.some(Boolean)) return settled()
|
|
231
|
+
return h('div', { className: 'bt-fail', role: 'status' },
|
|
232
|
+
h('div', { className: 'bt-fail-head' }, h('span', { className: 'bt-fail-dot', 'aria-hidden': true }), h('span', { className: 'bt-fail-text' }, text)),
|
|
233
|
+
h('div', { className: 'bt-fail-actions' }, row),
|
|
234
|
+
keying && keyHere ? h(ModelKeyCard, { model: { provider, providerName: providerName(roster, provider) }, actions, onSaved: () => setKeying(false) }) : null,
|
|
235
|
+
error ? h('div', { className: 'bt-fail-error', role: 'alert' }, error) : null,
|
|
236
|
+
h(TechnicalDetails, { facts }))
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export const TURN_ERROR_CSS = `
|
|
240
|
+
.bt-fail{display:flex;flex-direction:column;gap:10px;margin:4px 0 6px;width:max-content;max-width:min(550px,86%);padding:12px 14px;border-radius:16px;background:var(--bt-card);box-shadow:inset 0 0 0 1px var(--bt-line);box-sizing:border-box;color:var(--bt-ink);font-size:14px;line-height:20px}
|
|
241
|
+
.bt-fail[data-settled]{gap:4px;padding:2px 0;background:none;box-shadow:none;color:var(--bt-ink-2);font-size:13px;line-height:18px}
|
|
242
|
+
.bt-fail-head{display:flex;align-items:flex-start;gap:8px;min-width:0}
|
|
243
|
+
.bt-fail-dot{flex:none;width:7px;height:7px;margin-top:6.5px;border-radius:50%;background:var(--bt-danger)}
|
|
244
|
+
.bt-fail[data-settled] .bt-fail-dot{margin-top:5.5px}
|
|
245
|
+
.bt-fail-text{min-width:0;overflow-wrap:anywhere}
|
|
246
|
+
.bt-fail-actions{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-left:15px}
|
|
247
|
+
.bt-fail-actions .bt-fail-go{height:28px;padding:0 12px;font:inherit;font-size:12px}
|
|
248
|
+
.bt-fail-link{display:inline-flex;align-items:center;box-sizing:border-box;text-decoration:none}
|
|
249
|
+
.bt-fail:has(.bt-model-key){width:min(480px,86%)}
|
|
250
|
+
.bt-fail .bt-q.bt-model-key{margin:0 0 0 15px;width:auto;padding:0;background:none;box-shadow:none;border-radius:0;animation:none}
|
|
251
|
+
.bt-fail-error{margin-left:15px;font-size:12px;line-height:17px;color:var(--bt-danger);overflow-wrap:anywhere}
|
|
252
|
+
.bt-fail-tech{margin-left:15px;font-size:12px;line-height:17px;color:var(--bt-ink-2)}
|
|
253
|
+
.bt-fail-tech summary{width:max-content;cursor:pointer;color:var(--bt-ink-3)}
|
|
254
|
+
.bt-fail-tech summary:hover{color:var(--bt-ink-2)}
|
|
255
|
+
.bt-fail-tech dl{display:grid;grid-template-columns:auto minmax(0,1fr);gap:2px 10px;margin:6px 0}
|
|
256
|
+
.bt-fail-tech dt{color:var(--bt-ink-3)}
|
|
257
|
+
.bt-fail-tech dd{margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px;overflow-wrap:anywhere;white-space:pre-wrap;user-select:text}
|
|
258
|
+
.bt-fail-copy{display:inline-flex;align-items:center;gap:4px}
|
|
259
|
+
.bt-fail-copy svg{width:13px;height:13px}
|
|
260
|
+
`
|