@wxip/dsh-sub2api 0.2.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.
- package/LICENSE +21 -0
- package/README.md +158 -0
- package/README.zh.md +160 -0
- package/assets/icons/claude.svg +1 -0
- package/assets/icons/grok.svg +1 -0
- package/assets/icons/openai.svg +1 -0
- package/cordis.patch.yml +11 -0
- package/lib/client.cjs +1098 -0
- package/lib/client.js +1107 -0
- package/lib/image-tools.d.ts +18 -0
- package/lib/index.d.ts +148 -0
- package/lib/index.js +1220 -0
- package/lib/invariant.d.ts +13 -0
- package/lib/invariant.js +9 -0
- package/lib/pi-ai-patch.d.ts +45 -0
- package/lib/pi-ai.d.ts +50 -0
- package/lib/routes.d.ts +43 -0
- package/package.json +160 -0
- package/src/client/icons.tsx +38 -0
- package/src/client/index.tsx +31 -0
- package/src/client/settings.tsx +847 -0
- package/src/client/toolview.tsx +76 -0
- package/src/image-tools.ts +590 -0
- package/src/index.ts +339 -0
- package/src/invariant.ts +17 -0
- package/src/pi-ai-patch.ts +94 -0
- package/src/pi-ai.ts +185 -0
- package/src/routes.ts +442 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load-time invariant checks for dsh-sub2api.
|
|
3
|
+
*
|
|
4
|
+
* The host half declares `inject: ['llm', 'settings', 'credentials']`; the
|
|
5
|
+
* loader surfaces a missing provider as a waiting row, so a dedicated
|
|
6
|
+
* invariant would only duplicate that signal. This module exists to keep the
|
|
7
|
+
* package's export surface stable (lib/invariant.js) and to host any future
|
|
8
|
+
* structural checks.
|
|
9
|
+
*
|
|
10
|
+
* @module dsh-sub2api/invariant
|
|
11
|
+
*/
|
|
12
|
+
export declare function invariant(condition: unknown, message: string): asserts condition;
|
|
13
|
+
export default invariant;
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Best-effort defense guard for pi-ai's prefix-token estimation.
|
|
3
|
+
*
|
|
4
|
+
* Background: pi-ai's `AssistantMessage.usage` is required in its types and
|
|
5
|
+
* `estimateContextTokens` dereferences `usage.totalTokens` on that contract.
|
|
6
|
+
* The harness path is already safe — `dsh-llm-pi-ai` attaches a zero `Usage`
|
|
7
|
+
* (`emptyPiUsage()`) to every reconstructed assistant message. The guard here
|
|
8
|
+
* only defends against *other* callers that build pi-ai contexts without
|
|
9
|
+
* `usage` (hand-rolled clients, future adapters), which would otherwise die
|
|
10
|
+
* with a bare `Cannot read properties of undefined (reading 'totalTokens')`
|
|
11
|
+
* deep inside estimation.
|
|
12
|
+
*
|
|
13
|
+
* This plugin cannot control the pi-ai version through npm — Node resolves
|
|
14
|
+
* pi-ai from the dsh install, not from this package. So the guard is applied
|
|
15
|
+
* as a precise idempotent edit to the bundled `estimate.js`:
|
|
16
|
+
*
|
|
17
|
+
* ```js
|
|
18
|
+
* assistant.stopReason !== "error" &&
|
|
19
|
+
* assistant.usage !== undefined &&
|
|
20
|
+
* calculateContextTokens(assistant.usage) > 0
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* It runs at plugin apply time — before any pi-ai request (pi-ai's API modules
|
|
24
|
+
* are lazy-loaded, so `estimate.js` is only imported on the first stream). A
|
|
25
|
+
* refusal to write (read-only install) only logs a warning; the harness path
|
|
26
|
+
* works without the guard, and an upstream pi-ai guard makes this a no-op.
|
|
27
|
+
*
|
|
28
|
+
* @module dsh-sub2api/pi-ai-patch
|
|
29
|
+
*/
|
|
30
|
+
/** Outcome of one patch attempt. */
|
|
31
|
+
export type PiAiPatchResult = {
|
|
32
|
+
kind: 'patched';
|
|
33
|
+
file: string;
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'already';
|
|
36
|
+
file: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'skipped';
|
|
39
|
+
reason: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Apply the multi-turn guard to the dsh-bundled pi-ai `estimate.js` when it is
|
|
43
|
+
* missing. Idempotent; only a byte-exact edit is ever made.
|
|
44
|
+
*/
|
|
45
|
+
export declare function applyPiAiMultiTurnPatch(): PiAiPatchResult;
|
package/lib/pi-ai.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-sub2api → dsh-llm-pi-ai profile bridge.
|
|
3
|
+
*
|
|
4
|
+
* The LLM routes this plugin used to own (`sub2api-openai` / `sub2api-claude`
|
|
5
|
+
* / `sub2api-grok`) are now served by the harness's pi-ai
|
|
6
|
+
* adapter (`dsh-llm-pi-ai`, mounted dormant by dsh-base): protocol
|
|
7
|
+
* serialization, streaming, usage mapping, replay, and retry handling all live
|
|
8
|
+
* in pi-ai. This module is the translation layer — it turns this plugin's
|
|
9
|
+
* `llm-sub2api:` settings section (gateway baseURL + per-group model catalogs
|
|
10
|
+
* + keys) into `llm-pi-ai:` provider profiles and writes them through the
|
|
11
|
+
* settings service, so routes register the moment the section lands and drop
|
|
12
|
+
* again when a key is cleared.
|
|
13
|
+
*
|
|
14
|
+
* Every sub2api group is translated as a *hand-declared* route — pi-ai ships
|
|
15
|
+
* no provider under these keys — with `api` naming the group's native wire
|
|
16
|
+
* protocol (openai→responses, claude→messages, grok→chat-completions),
|
|
17
|
+
* `baseURL` set to the shared gateway, and `models` carrying the configured
|
|
18
|
+
* catalog with each model's capacity, modalities, and reasoning levels mapped
|
|
19
|
+
* onto pi-ai's vocabulary (`none` becomes `off` with wire spelling `none`).
|
|
20
|
+
*
|
|
21
|
+
* @module dsh-sub2api/pi-ai
|
|
22
|
+
*/
|
|
23
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
24
|
+
import type { PiAiProviderProfile } from '@deepseek-ai/dsh-llm-pi-ai';
|
|
25
|
+
import type { Config } from './index.ts';
|
|
26
|
+
/./index.jstings namespace owned by dsh-llm-pi-ai. */
|
|
27
|
+
export declare const PI_AI_NS = "llm-pi-ai";
|
|
28
|
+
/** Route prefix this plugin's groups own in the llm-pi-ai profile dict. */
|
|
29
|
+
export declare const ROUTE_PREFIX: string;
|
|
30
|
+
export type { PiAiModelProfile, PiAiProviderProfile } from '@deepseek-ai/dsh-llm-pi-ai';
|
|
31
|
+
/** The llm-pi-ai settings section value this plugin writes. */
|
|
32
|
+
export interface PiAiSettingsSection {
|
|
33
|
+
providers?: Record<string, PiAiProviderProfile>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build the `llm-pi-ai` provider profile dict for every configured sub2api
|
|
37
|
+
* group. A group is emitted only when it has both a key and at least one
|
|
38
|
+
* model — a hand-declared pi-ai route needs a non-empty `models` list, and a
|
|
39
|
+
* keyless group would otherwise surface as an unauthenticated route.
|
|
40
|
+
*/
|
|
41
|
+
export declare function translateToPiAi(config: Config): Record<string, PiAiProviderProfile>;
|
|
42
|
+
/**
|
|
43
|
+
* Write the translated profiles into the `llm-pi-ai` settings section. Routes
|
|
44
|
+
* under this plugin's `sub2api-` prefix are replaced wholesale; any other
|
|
45
|
+
* route the user configured (e.g. through the built-in Models page) is
|
|
46
|
+
* preserved. The write goes through the settings service, so dsh-llm-pi-ai's
|
|
47
|
+
* own validation (schema + `assertServiceable`) refuses an unserviceable
|
|
48
|
+
* profile at the write site and the section keeps its last good value.
|
|
49
|
+
*/
|
|
50
|
+
export declare function syncPiAiProfiles(ctx: Context, config: Config): Promise<void>;
|
package/lib/routes.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP routes for the dsh-sub2api settings page.
|
|
3
|
+
*
|
|
4
|
+
* The browser half of a static plugin talks to the host through the web
|
|
5
|
+
* server (there is no package-private `host.call` seam outside dynamic
|
|
6
|
+
* packages), so this module exposes read/write endpoints for the plugin's
|
|
7
|
+
* settings section. Requests are restricted to trusted local origins — the
|
|
8
|
+
* same `trustedRequest` posture the oauth plugin uses — because these routes
|
|
9
|
+
* mutate configuration and echo credential state.
|
|
10
|
+
*
|
|
11
|
+
* @module dsh-sub2api/routes
|
|
12
|
+
*/
|
|
13
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
14
|
+
import { type CatalogModel, type Config, type ImageToolsConfig, type ProviderProfile } from './in./index.jsxport declare const ROUTES: {
|
|
15
|
+
readonly get: "/plugins/dsh-sub2api/config";
|
|
16
|
+
readonly set: "/plugins/dsh-sub2api/config";
|
|
17
|
+
readonly discover: "/plugins/dsh-sub2api/discover";
|
|
18
|
+
readonly usage: "/plugins/dsh-sub2api/usage";
|
|
19
|
+
readonly status: "/plugins/dsh-sub2api/status";
|
|
20
|
+
readonly attachment: "/plugins/dsh-sub2api/attachment";
|
|
21
|
+
};
|
|
22
|
+
export interface ConfigPayload {
|
|
23
|
+
baseURL: string;
|
|
24
|
+
catalogFormat: 'structured-v1';
|
|
25
|
+
providers: Record<string, {
|
|
26
|
+
keyConfigured: boolean;
|
|
27
|
+
models: CatalogModel[];
|
|
28
|
+
}>;
|
|
29
|
+
tools: ImageToolsConfig;
|
|
30
|
+
}
|
|
31
|
+
interface RouteContext {
|
|
32
|
+
config: () => Config;
|
|
33
|
+
setConfig: (config: Config) => void | Promise<void>;
|
|
34
|
+
listRegisteredRoutes: () => string[];
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the stored credential for one provider route. Used by discovery
|
|
37
|
+
* and usage probes when the settings form does not carry a freshly typed
|
|
38
|
+
* key (keys are write-only and stay in the credential store).
|
|
39
|
+
*/
|
|
40
|
+
resolveApiKey: (route: string, profile: ProviderProfile) => Promise<string>;
|
|
41
|
+
}
|
|
42
|
+
export declare function registerRoutes(ctx: Context, routes: RouteContext): void;
|
|
43
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wxip/dsh-sub2api",
|
|
3
|
+
"description": "Connect your sub2api gateway to DeepSeek Harness: OpenAI-compatible multi-provider routes (OpenAI / Claude / Grok) behind one base URL, with per-key model discovery, usage lookup, global image generation, and a settings page.",
|
|
4
|
+
"version": "0.2.2",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"dsh-plugin",
|
|
8
|
+
"deepseek-harness",
|
|
9
|
+
"sub2api",
|
|
10
|
+
"llm",
|
|
11
|
+
"openai",
|
|
12
|
+
"claude",
|
|
13
|
+
"grok",
|
|
14
|
+
"image-generation"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/GodD6366/dsh-sub2api#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/GodD6366/dsh-sub2api/issues"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/GodD6366/dsh-sub2api.git"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "lib/index.js",
|
|
26
|
+
"types": "lib/index.d.ts",
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public",
|
|
29
|
+
"registry": "https://registry.npmjs.org/"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsdown && node scripts/wrap-client.mjs",
|
|
36
|
+
"prepare": "node scripts/prepare.mjs",
|
|
37
|
+
"typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.client.json",
|
|
38
|
+
"check": "npm run typecheck && npm run build",
|
|
39
|
+
"patch:pi-ai": "node scripts/patch-pi-ai.mjs",
|
|
40
|
+
"test": "npm run build && node --test tests/*.test.mjs",
|
|
41
|
+
"release:npm": "npm run typecheck && npm test && npm publish --ignore-scripts --access public --registry=https://registry.npmjs.org/"
|
|
42
|
+
},
|
|
43
|
+
"exports": {
|
|
44
|
+
".": {
|
|
45
|
+
"types": "./lib/index.d.ts",
|
|
46
|
+
"default": "./lib/index.js"
|
|
47
|
+
},
|
|
48
|
+
"./client": "./lib/client.js",
|
|
49
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
50
|
+
"./package.json": "./package.json"
|
|
51
|
+
},
|
|
52
|
+
"files": [
|
|
53
|
+
"lib",
|
|
54
|
+
"src",
|
|
55
|
+
"assets",
|
|
56
|
+
"cordis.patch.yml",
|
|
57
|
+
"README.md",
|
|
58
|
+
"README.zh.md",
|
|
59
|
+
"LICENSE"
|
|
60
|
+
],
|
|
61
|
+
"dsh": {
|
|
62
|
+
"bundle": {
|
|
63
|
+
"patch": "./cordis.patch.yml"
|
|
64
|
+
},
|
|
65
|
+
"client": {
|
|
66
|
+
"inject": [
|
|
67
|
+
"@deepseek-ai/dsh-client-ui-renderer",
|
|
68
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
69
|
+
"@deepseek-ai/dsh-client-ui-slots"
|
|
70
|
+
],
|
|
71
|
+
"platform": "web"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"peerDependencies": {
|
|
75
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
76
|
+
"@deepseek-ai/dsh-attachment": "^0.2.0-rc.2",
|
|
77
|
+
"@deepseek-ai/dsh-credentials": "^0.2.0-rc.2",
|
|
78
|
+
"@deepseek-ai/dsh-fs": "^0.2.0-rc.2",
|
|
79
|
+
"@deepseek-ai/dsh-host-webserver": "^0.2.0-rc.2",
|
|
80
|
+
"@deepseek-ai/dsh-llm": "^0.2.0-rc.2",
|
|
81
|
+
"@deepseek-ai/dsh-llm-pi-ai": "^0.2.0-rc.2",
|
|
82
|
+
"@deepseek-ai/dsh-settings": "^0.2.0-rc.2",
|
|
83
|
+
"@deepseek-ai/dsh-system-prompt": "^0.2.0-rc.2",
|
|
84
|
+
"@deepseek-ai/dsh-tools": "^0.2.0-rc.2",
|
|
85
|
+
"@deepseek-ai/schemastery": "^3.18.4",
|
|
86
|
+
"react": "^18.2.0",
|
|
87
|
+
"@deepseek-ai/cordis-plugin-loader": "~1.0.5"
|
|
88
|
+
},
|
|
89
|
+
"peerDependenciesMeta": {
|
|
90
|
+
"@deepseek-ai/cordis": {
|
|
91
|
+
"optional": true
|
|
92
|
+
},
|
|
93
|
+
"@deepseek-ai/dsh-attachment": {
|
|
94
|
+
"optional": true
|
|
95
|
+
},
|
|
96
|
+
"@deepseek-ai/dsh-fs": {
|
|
97
|
+
"optional": true
|
|
98
|
+
},
|
|
99
|
+
"@deepseek-ai/dsh-llm": {
|
|
100
|
+
"optional": true
|
|
101
|
+
},
|
|
102
|
+
"@deepseek-ai/dsh-settings": {
|
|
103
|
+
"optional": true
|
|
104
|
+
},
|
|
105
|
+
"@deepseek-ai/dsh-system-prompt": {
|
|
106
|
+
"optional": true
|
|
107
|
+
},
|
|
108
|
+
"@deepseek-ai/dsh-tools": {
|
|
109
|
+
"optional": true
|
|
110
|
+
},
|
|
111
|
+
"react": {
|
|
112
|
+
"optional": true
|
|
113
|
+
},
|
|
114
|
+
"@deepseek-ai/dsh-credentials": {
|
|
115
|
+
"optional": true
|
|
116
|
+
},
|
|
117
|
+
"@deepseek-ai/dsh-host-webserver": {
|
|
118
|
+
"optional": true
|
|
119
|
+
},
|
|
120
|
+
"@deepseek-ai/dsh-llm-pi-ai": {
|
|
121
|
+
"optional": true
|
|
122
|
+
},
|
|
123
|
+
"@deepseek-ai/schemastery": {
|
|
124
|
+
"optional": true
|
|
125
|
+
},
|
|
126
|
+
"@deepseek-ai/cordis-plugin-loader": {
|
|
127
|
+
"optional": true
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"devDependencies": {
|
|
131
|
+
"@deepseek-ai/cordis": "~4.0.4",
|
|
132
|
+
"@deepseek-ai/dsh-attachment": "0.2.0-rc.2",
|
|
133
|
+
"@deepseek-ai/dsh-client-store": "0.2.0-rc.2",
|
|
134
|
+
"@deepseek-ai/dsh-client-ui-chat": "0.2.0-rc.2",
|
|
135
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.2",
|
|
136
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.2",
|
|
137
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.2",
|
|
138
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.2",
|
|
139
|
+
"@deepseek-ai/dsh-client-ui-tool": "0.2.0-rc.2",
|
|
140
|
+
"@deepseek-ai/dsh-credentials": "0.2.0-rc.2",
|
|
141
|
+
"@deepseek-ai/dsh-fs": "0.2.0-rc.2",
|
|
142
|
+
"@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2",
|
|
143
|
+
"@deepseek-ai/dsh-llm": "0.2.0-rc.2",
|
|
144
|
+
"@deepseek-ai/dsh-llm-pi-ai": "0.2.0-rc.2",
|
|
145
|
+
"@deepseek-ai/dsh-settings": "0.2.0-rc.2",
|
|
146
|
+
"@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2",
|
|
147
|
+
"@deepseek-ai/dsh-tools": "0.2.0-rc.2",
|
|
148
|
+
"@deepseek-ai/schemastery": "~3.18.4",
|
|
149
|
+
"@types/node": "^22.20.0",
|
|
150
|
+
"@types/react": "~18.3.1",
|
|
151
|
+
"react": "^18.2.0",
|
|
152
|
+
"react-test-renderer": "18.3.1",
|
|
153
|
+
"tsdown": "^0.4.0",
|
|
154
|
+
"typescript": "^5.7.0",
|
|
155
|
+
"@deepseek-ai/cordis-plugin-loader": "~1.0.5",
|
|
156
|
+
"@deepseek-ai/dsh-config-editor": "0.2.0-rc.2",
|
|
157
|
+
"@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2",
|
|
158
|
+
"@deepseek-ai/dsh-app-boot": "0.2.0-rc.2"
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider icons for the dsh-sub2api settings page.
|
|
3
|
+
*
|
|
4
|
+
* SVG source: lobehub/lobe-icons (`https://lobehub.com/icons`), the static SVG
|
|
5
|
+
* package. The three provider marks are embedded as React components so the
|
|
6
|
+
* settings page renders them without network requests.
|
|
7
|
+
*
|
|
8
|
+
* @module dsh-sub2api/client/icons
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { CSSProperties } from 'react'
|
|
12
|
+
|
|
13
|
+
export type ProviderIconName = 'openai' | 'claude' | 'grok'
|
|
14
|
+
|
|
15
|
+
const paths: Record<ProviderIconName, string> = {
|
|
16
|
+
openai:
|
|
17
|
+
'M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 00-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 01.476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 014.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 01-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 005.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0010.205 0a5.947 5.947 0 00-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 004.162 1.713z',
|
|
18
|
+
claude:
|
|
19
|
+
'M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z',
|
|
20
|
+
grok:
|
|
21
|
+
'M9.27 15.29l7.978-5.897c.391-.29.95-.177 1.137.272.98 2.369.542 5.215-1.41 7.169-1.951 1.954-4.667 2.382-7.149 1.406l-2.711 1.257c3.889 2.661 8.611 2.003 11.562-.953 2.341-2.344 3.066-5.539 2.388-8.42l.006.007c-.983-4.232.242-5.924 2.75-9.383.06-.082.12-.164.179-.248l-3.301 3.305v-.01L9.267 15.292M7.623 16.723c-2.792-2.67-2.31-6.801.071-9.184 1.761-1.763 4.647-2.483 7.166-1.425l2.705-1.25a7.808 7.808 0 00-1.829-1A8.975 8.975 0 005.984 5.83c-2.533 2.536-3.33 6.436-1.962 9.764 1.022 2.487-.653 4.246-2.34 6.022-.599.63-1.199 1.259-1.682 1.925l7.62-6.815',
|
|
22
|
+
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function ProviderIcon({ name, size = 18, style }: { name: ProviderIconName; size?: number; style?: CSSProperties }) {
|
|
26
|
+
return (
|
|
27
|
+
<svg
|
|
28
|
+
width={size}
|
|
29
|
+
height={size}
|
|
30
|
+
viewBox="0 0 24 24"
|
|
31
|
+
fill="currentColor"
|
|
32
|
+
style={{ flex: 'none', lineHeight: 1, ...style }}
|
|
33
|
+
aria-hidden="true"
|
|
34
|
+
>
|
|
35
|
+
<path d={paths[name]} fillRule="evenodd" />
|
|
36
|
+
</svg>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser half of dsh-sub2api: registers the settings section.
|
|
3
|
+
*
|
|
4
|
+
* @module dsh-sub2api/client
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
8
|
+
import type {} from '@deepseek-ai/dsh-client-ui-renderer/client'
|
|
9
|
+
import type {} from '@deepseek-ai/dsh-client-ui-settings/client'
|
|
10
|
+
import { Sub2ApiSettings } from './settings.tsx'
|
|
11
|
+
import { GenerateImageToolview } from './toolview.tsx'
|
|
12
|
+
|
|
13
|
+
export const name = 'dsh-sub2api-client'
|
|
14
|
+
export const inject = ['slots']
|
|
15
|
+
|
|
16
|
+
export function apply(ctx: Context): void {
|
|
17
|
+
ctx.slots.inject('settings.section', () => ctx.slots.register({
|
|
18
|
+
name: 'settings.section',
|
|
19
|
+
id: 'sub2api-models',
|
|
20
|
+
order: 12,
|
|
21
|
+
label: () => 'Sub2API 模型',
|
|
22
|
+
}, Sub2ApiSettings))
|
|
23
|
+
|
|
24
|
+
// Render generate_image results as an inline image inside the tool card:
|
|
25
|
+
// the tool result already carries an image content block (durable
|
|
26
|
+
// attachment), and this keyed toolview turns those bytes into an <img>.
|
|
27
|
+
ctx.slots.inject('tool.call.toolview', () => ctx.slots.register({
|
|
28
|
+
name: 'tool.call.toolview',
|
|
29
|
+
key: 'generate_image',
|
|
30
|
+
}, GenerateImageToolview))
|
|
31
|
+
}
|