@chatcode/chatcode-cli 3.0.4 → 3.0.5-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +6 -6
- package/README.md +10 -4
- package/README.zh.md +10 -4
- package/lib/bin.js +23 -9
- package/lib/{command-errors-Ca64Lgba.js → command-errors-CsRCh0gk.js} +12 -12
- package/lib/{command-trees-CVc4Xu_z.js → command-trees-CD_43rxX.js} +2 -2
- package/lib/{component-identity-6aEut5Yt.js → component-identity-DGA2-TeB.js} +3 -3
- package/lib/{dump-config-ZzrfvtnX.js → dump-config-D8kXfdTs.js} +1 -1
- package/lib/dump-config-DuCc-QB7.js +2 -0
- package/lib/{dump-config-schema-BlO-eZ-J.js → dump-config-schema-CtZbroi6.js} +2 -2
- package/lib/{extension-events-C7MUpqVE.js → extension-events-D0BjYRqT.js} +21 -21
- package/lib/{host-access-CLbyAGT5.js → host-access-DLJjuR07.js} +1 -1
- package/lib/{keymap-82JwLLHe.js → keymap-C4cs2IBN.js} +2 -2
- package/lib/{plugin-BlQlWIR5.js → plugin-CGtTByud.js} +801 -456
- package/lib/{plugin-BZdazFXS.js → plugin-CYw-MBRn.js} +1 -1
- package/lib/{profile-boot-B0aEEQIR.js → profile-boot-CffsubnV.js} +7 -7
- package/lib/profile-boot.js +1 -1
- package/lib/{scenes-BNS0ZFyQ.js → scenes-CbAGK5Uy.js} +3 -3
- package/lib/{settings-sections-CXH24cu5.js → settings-sections-DYKDa04e.js} +3 -3
- package/lib/{statusBarSettings-BAMzn8fX.js → statusBarSettings-T1m8xad4.js} +3 -3
- package/lib/{themes-DXUIvP7m.js → themes-BY2ui1Dv.js} +12 -12
- package/lib/tui-compat-command-trees.js +1 -1
- package/lib/tui-compat-extensions.js +3 -3
- package/lib/tui-compat-plugin-host.js +5 -5
- package/lib/tui-compat-scenes.js +1 -1
- package/lib/tui-compat-settings-sections.js +1 -1
- package/lib/tui-compat-working-activity.js +1 -1
- package/lib/tui-compat-workspaces.js +1 -1
- package/lib/tui-compat.js +7 -7
- package/lib/types/bin.d.ts +9 -0
- package/lib/types/tui-compat.d.ts +1 -1
- package/lib/types/web-instance-process.d.ts +20 -0
- package/lib/{web-instance-DbP7IHPv.js → web-instance-D_Ppi2Zo.js} +176 -14
- package/lib/{web-instance-B0jec7cq.js → web-instance-amvCJWnq.js} +1 -1
- package/lib/{workspaces-CUJXNU5W.js → workspaces-D5VKbESy.js} +2 -2
- package/package.json +23 -24
- package/runtime/manifest.json +2 -2
- package/runtime/node_modules/@deepseek-ai/dsh-agent-default-model/lib/index.js +7 -3
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/client.js +11 -3
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/client/contract/snapshot.d.ts +1 -0
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/client/sessions/assistant-stream.d.ts +2 -0
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/client/sessions/assistant-stream.js +4 -0
- package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/client/sessions/session.js +10 -3
- package/runtime/node_modules/@deepseek-ai/dsh-app-boot/lib/index.js +32 -11
- package/runtime/node_modules/@deepseek-ai/dsh-atomic-write/lib/index.js +62 -11
- package/runtime/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/darwin-lock.d.ts +7 -0
- package/runtime/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/index.d.ts +7 -2
- package/runtime/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/linux-lock.d.ts +1 -1
- package/runtime/node_modules/@deepseek-ai/dsh-client-locale/lib/client.js +7 -7
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-agent-preset/lib/client.js +62 -62
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-approval/lib/client.js +10 -10
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-attachment/lib/client.js +49 -49
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-chat/lib/client.js +204 -204
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-commands/lib/client.js +16 -16
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-conversation/lib/client.js +159 -157
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-conversation/lib/types/client/service.d.ts +4 -2
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-cordis/lib/client.js +74 -74
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-deliverables/lib/client.js +129 -123
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-deliverables/lib/index.js +19 -14
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-deliverables/lib/types/changes.d.ts +2 -2
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-deliverables/lib/types/client/Deliverables.d.ts +1 -2
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-deliverables/lib/types/client/locales.d.ts +2 -1
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-deliverables/lib/types/client/present-open.d.ts +1 -1
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-deliverables/package.json +2 -4
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-directory-picker-browse/lib/client.js +39 -39
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-goal/lib/client.js +16 -16
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-input-trigger/lib/client.js +23 -23
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-jobs/lib/client.js +37 -37
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-layout/lib/client.js +9 -9
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-message-feedback/lib/client.js +12 -12
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-model-selection/lib/client.js +119 -32
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-model-selection/lib/types/client/catalog.d.ts +13 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-model-selection/lib/types/client/directory.d.ts +2 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-model-selection/lib/types/client/effort-preferences.d.ts +20 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-model-selection/lib/types/client/slots.d.ts +2 -1
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-open-in-app/lib/client.js +8 -8
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-permission-presets/lib/client.js +18 -18
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-plan/lib/client.js +22 -22
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-plugin-manager/lib/client.js +128 -128
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-schedule/lib/client.js +182 -182
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-settings-account/lib/client.js +130 -130
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-settings-general/lib/client.js +50 -50
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-settings-models/lib/client.js +88 -88
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-settings-plugin-inventory/lib/client.js +36 -36
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-settings-plugins/lib/client.js +13 -13
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-settings-subagent/lib/client.js +27 -27
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-shortcuts/lib/client.js +42 -42
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-sidebar/lib/client.js +44 -44
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-sidebar-browser/lib/client.js +25 -25
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-sidebar-documentpreview/lib/client.excel.js +9 -9
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-sidebar-documentpreview/lib/client.js +70 -70
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-sidebar-documentpreview/lib/client.pdf.js +9 -9
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-sidebar-files/lib/client.js +18 -18
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-sidebar-right/lib/client.js +26 -26
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-sidebar-terminal/lib/client.js +16 -16
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-sidebar-terminal/lib/client.terminal.js +11 -11
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-skill/lib/client.js +20 -20
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-subagent/lib/client.js +37 -37
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-theme/lib/client.js +27 -27
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-tool/lib/client.js +95 -95
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-trajectory/lib/client.js +197 -197
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-user-questions/lib/client.js +49 -49
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workflow-run/lib/client.js +24 -24
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/client.js +656 -152
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/ArchivedSessions.d.ts +9 -2
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/locales.d.ts +46 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/session-actions/DeleteSession.d.ts +9 -10
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/session-actions/deletion.d.ts +57 -0
- package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/package.json +2 -0
- package/runtime/node_modules/@deepseek-ai/dsh-experimental-client-ui-agent-team/lib/client.js +32 -32
- package/runtime/node_modules/@deepseek-ai/dsh-experimental-client-ui-voice-input/lib/client.js +24 -24
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/index.js +899 -453
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/adapter.d.ts +4 -20
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/chat-completions/adapter.d.ts +8 -0
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/chat-completions/serialize.d.ts +10 -0
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/chat-completions/sse.d.ts +24 -0
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/chat-completions/translate.d.ts +37 -0
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/chat-completions/types.d.ts +159 -0
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/file-store.d.ts +3 -0
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/files-api.d.ts +4 -0
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/index.d.ts +1 -0
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/protocol-adapter.d.ts +41 -0
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/protocol.d.ts +35 -0
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/transport.d.ts +2 -1
- package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/types.d.ts +2 -2
- package/runtime/node_modules/@deepseek-ai/dsh-mcp-client/lib/index.js +5 -4
- package/runtime/node_modules/@deepseek-ai/dsh-session-log-export/lib/client.js +4 -4
- package/runtime/node_modules/@deepseek-ai/dsh-session-log-export/lib/index.js +1 -1
- package/runtime/node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/index.js +2 -2
- package/runtime/node_modules/@deepseek-ai/dsh-tool-cordis/lib/types/api-catalog.js +12 -10
- package/runtime/node_modules/@deepseek-ai/dsh-workspace-changes/lib/index.js +208 -39
- package/runtime/node_modules/@deepseek-ai/dsh-workspace-changes/lib/types/archive.d.ts +47 -0
- package/runtime/node_modules/@deepseek-ai/dsh-workspace-changes/lib/types/archive.js +129 -0
- package/runtime/node_modules/@deepseek-ai/dsh-workspace-changes/lib/types/index.d.ts +2 -0
- package/runtime/node_modules/@deepseek-ai/dsh-workspace-changes/lib/types/index.js +31 -8
- package/runtime/node_modules/@deepseek-ai/dsh-workspace-changes/lib/types/recorder.d.ts +7 -2
- package/runtime/node_modules/@deepseek-ai/dsh-workspace-changes/lib/types/recorder.js +35 -19
- package/runtime/node_modules/@deepseek-ai/dsh-workspace-changes/lib/types/types.d.ts +11 -10
- package/runtime/node_modules/@deepseek-ai/dsh-workspace-changes/package.json +1 -0
- package/scripts/link-embedded-runtime.mjs +1 -1
- package/lib/dump-config-CDixiJNt.js +0 -2
- package/lib/{home-migration-BjDmRwBB.js → home-migration-lRjtl2fP.js} +1 -1
- package/lib/{startup-diagnostics-C_hRCp-q.js → startup-diagnostics-4mLHYTFc.js} +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import z from "@deepseek-ai/schemastery";
|
|
2
2
|
import { isVolatile } from "@deepseek-ai/cosmokit";
|
|
3
|
-
import { IMAGE_OFFLOAD_REQUIRED_CODE, LlmAdapter, LlmError, ProviderRequestId, ReasoningEffortId, RetryPolicySchema, ToolCallId, attributionHeaders, contentHasImage, isContextWindowExceededError, isQuotaExceededError, offloadedImageText, projectOffloadedImages, requestImageHandleText, requiredImageOffload, resolveImageAttachmentAccess, resolveRetryPolicy, textOnlyImageText } from "@deepseek-ai/dsh-llm";
|
|
3
|
+
import { EMPTY_RESPONSE_CODE, IMAGE_OFFLOAD_REQUIRED_CODE, LlmAdapter, LlmError, ProviderRequestId, ReasoningEffortId, RetryPolicySchema, ToolCallId, attributionHeaders, contentHasImage, isContextWindowExceededError, isQuotaExceededError, offloadedImageText, projectOffloadedImages, requestImageHandleText, requiredImageOffload, resolveImageAttachmentAccess, resolveRetryPolicy, textOnlyImageText } from "@deepseek-ai/dsh-llm";
|
|
4
4
|
import { MAX_TIMER_DELAY_MS, deadline, idleWatchdog, timeoutOf } from "@deepseek-ai/dsh-timeout";
|
|
5
5
|
import { ImageVariantId, longEdgeDimensions, requestImageDimensions } from "@deepseek-ai/dsh-attachment";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
@@ -9,8 +9,9 @@ import { dirname, join } from "node:path";
|
|
|
9
9
|
import { withFileLock, writeFileAtomic } from "@deepseek-ai/dsh-atomic-write";
|
|
10
10
|
import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
11
11
|
import { EventSourceParserStream } from "eventsource-parser/stream";
|
|
12
|
+
import { assertNever, deepEqualJson } from "@deepseek-ai/dsh-util-values";
|
|
13
|
+
import { brandString } from "@deepseek-ai/dsh-brand";
|
|
12
14
|
import { getOrCreateAnonymousUserId } from "@deepseek-ai/dsh-anonymous-user-id";
|
|
13
|
-
import { deepEqualJson } from "@deepseek-ai/dsh-util-values";
|
|
14
15
|
//#region lib/types/defaults.js
|
|
15
16
|
/** Shared provider limits and Chat Files API defaults. */
|
|
16
17
|
/** Default maximum idle interval while an adapter stream read is outstanding. */
|
|
@@ -638,6 +639,7 @@ function providerErrorDetail$1(value) {
|
|
|
638
639
|
}
|
|
639
640
|
/** Direct Files client retaining the configured URL root and refusing redirects before credentials can leave its origin. */
|
|
640
641
|
var DeepSeekFilesClient = class {
|
|
642
|
+
protocol;
|
|
641
643
|
baseURL;
|
|
642
644
|
authHeaders;
|
|
643
645
|
fetchImpl;
|
|
@@ -645,17 +647,33 @@ var DeepSeekFilesClient = class {
|
|
|
645
647
|
* @param options - endpoint, authentication headers, and optional test transport.
|
|
646
648
|
*/
|
|
647
649
|
constructor(options) {
|
|
650
|
+
this.protocol = options.protocol ?? "messages";
|
|
648
651
|
this.authHeaders = options.headers;
|
|
649
652
|
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
650
|
-
this.baseURL = messagesApiRoot(options.baseURL);
|
|
653
|
+
this.baseURL = this.protocol === "messages" ? messagesApiRoot(options.baseURL) : options.baseURL.replace(/\/+$/u, "");
|
|
654
|
+
}
|
|
655
|
+
parseFile(value, operation) {
|
|
656
|
+
if (this.protocol === "messages") return parseFileObject(value, operation);
|
|
657
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw invalidResponse(operation);
|
|
658
|
+
const wire = value;
|
|
659
|
+
if (typeof wire.id !== "string" || wire.id.length === 0 || wire.object !== "file" || typeof wire.bytes !== "number" || !Number.isSafeInteger(wire.bytes) || wire.bytes < 0 || typeof wire.created_at !== "number" || !Number.isSafeInteger(wire.created_at) || wire.created_at < 0 || typeof wire.filename !== "string" || wire.filename.length === 0 || wire.purpose !== "user_data" || wire.expires_at !== void 0 && (typeof wire.expires_at !== "number" || !Number.isSafeInteger(wire.expires_at) || wire.expires_at < 0)) throw invalidResponse(operation);
|
|
660
|
+
return {
|
|
661
|
+
id: DeepSeekFileId(wire.id),
|
|
662
|
+
bytes: wire.bytes,
|
|
663
|
+
createdAt: wire.created_at,
|
|
664
|
+
filename: wire.filename,
|
|
665
|
+
...typeof wire.expires_at === "number" ? { expiresAt: wire.expires_at } : {}
|
|
666
|
+
};
|
|
651
667
|
}
|
|
652
668
|
async request(path, init, signal) {
|
|
653
669
|
let response;
|
|
654
670
|
try {
|
|
655
671
|
const headers = new Headers(attributionHeaders());
|
|
656
672
|
for (const [name, value] of Object.entries(this.authHeaders)) headers.set(name, value);
|
|
657
|
-
|
|
658
|
-
|
|
673
|
+
if (this.protocol === "messages") {
|
|
674
|
+
headers.set("anthropic-version", "2023-06-01");
|
|
675
|
+
headers.set("anthropic-beta", MESSAGES_FILES_BETA);
|
|
676
|
+
}
|
|
659
677
|
response = await this.fetchImpl(`${this.baseURL}${path}`, {
|
|
660
678
|
...init,
|
|
661
679
|
redirect: "error",
|
|
@@ -684,13 +702,22 @@ var DeepSeekFilesClient = class {
|
|
|
684
702
|
if (input.data.byteLength > 134217728) throw new LlmError("DeepSeek Files API upload exceeds 128 MiB.", "INVALID_REQUEST");
|
|
685
703
|
if (!Number.isSafeInteger(input.expiresAfterSeconds) || input.expiresAfterSeconds < 3600 || input.expiresAfterSeconds > 2592e3) throw new LlmError("DeepSeek file expiry must be between 3600 and 2592000 seconds.", "INVALID_REQUEST");
|
|
686
704
|
const form = new FormData();
|
|
705
|
+
if (this.protocol === "chat-completions") form.set("purpose", "user_data");
|
|
687
706
|
form.set("expires_after[anchor]", "created_at");
|
|
688
707
|
form.set("expires_after[seconds]", String(input.expiresAfterSeconds));
|
|
689
708
|
form.set("file", new Blob([Uint8Array.from(input.data).buffer], { type: input.mediaType }), input.filename);
|
|
690
|
-
const
|
|
709
|
+
const response = await this.request("/files", {
|
|
691
710
|
method: "POST",
|
|
692
711
|
body: form
|
|
693
|
-
}, input.signal)
|
|
712
|
+
}, input.signal);
|
|
713
|
+
const file = this.parseFile(await responseJson(response, "upload"), "upload");
|
|
714
|
+
if (this.protocol === "chat-completions") {
|
|
715
|
+
if (file.expiresAt === void 0) throw invalidResponse("upload");
|
|
716
|
+
return {
|
|
717
|
+
...file,
|
|
718
|
+
expiresAt: file.expiresAt
|
|
719
|
+
};
|
|
720
|
+
}
|
|
694
721
|
return {
|
|
695
722
|
...file,
|
|
696
723
|
expiresAt: file.createdAt + input.expiresAfterSeconds
|
|
@@ -702,17 +729,17 @@ var DeepSeekFilesClient = class {
|
|
|
702
729
|
* @returns the validated page with null cursors omitted.
|
|
703
730
|
*/
|
|
704
731
|
async list(options = {}) {
|
|
705
|
-
const query = new URLSearchParams();
|
|
706
|
-
if (options.after !== void 0) query.set("after_id", options.after);
|
|
732
|
+
const query = new URLSearchParams(this.protocol === "chat-completions" ? { purpose: "user_data" } : {});
|
|
733
|
+
if (options.after !== void 0) query.set(this.protocol === "messages" ? "after_id" : "after", options.after);
|
|
707
734
|
if (options.limit !== void 0) query.set("limit", String(options.limit));
|
|
708
735
|
const value = await responseJson(await this.request(`/files?${query.toString()}`, { method: "GET" }, options.signal), "list");
|
|
709
736
|
if (value === null || typeof value !== "object" || Array.isArray(value)) throw invalidResponse("list");
|
|
710
737
|
const wire = value;
|
|
711
738
|
const firstId = wire.first_id ?? void 0;
|
|
712
739
|
const lastId = wire.last_id ?? void 0;
|
|
713
|
-
if (!Array.isArray(wire.data) || typeof wire.has_more !== "boolean" || firstId !== void 0 && typeof firstId !== "string" || lastId !== void 0 && typeof lastId !== "string") throw invalidResponse("list");
|
|
740
|
+
if (this.protocol === "chat-completions" && wire.object !== "list" || !Array.isArray(wire.data) || typeof wire.has_more !== "boolean" || firstId !== void 0 && typeof firstId !== "string" || lastId !== void 0 && typeof lastId !== "string") throw invalidResponse("list");
|
|
714
741
|
return {
|
|
715
|
-
data: wire.data.map((item) =>
|
|
742
|
+
data: wire.data.map((item) => this.parseFile(item, "list")),
|
|
716
743
|
...typeof firstId === "string" ? { firstId: DeepSeekFileId(firstId) } : {},
|
|
717
744
|
...typeof lastId === "string" ? { lastId: DeepSeekFileId(lastId) } : {},
|
|
718
745
|
hasMore: wire.has_more
|
|
@@ -725,7 +752,8 @@ var DeepSeekFilesClient = class {
|
|
|
725
752
|
* @returns the validated file object.
|
|
726
753
|
*/
|
|
727
754
|
async retrieve(fileId, signal) {
|
|
728
|
-
|
|
755
|
+
const response = await this.request(`/files/${encodeURIComponent(fileId)}`, { method: "GET" }, signal);
|
|
756
|
+
return this.parseFile(await responseJson(response, "retrieve"), "retrieve");
|
|
729
757
|
}
|
|
730
758
|
/**
|
|
731
759
|
* Delete one provider file.
|
|
@@ -736,7 +764,7 @@ var DeepSeekFilesClient = class {
|
|
|
736
764
|
const value = await responseJson(await this.request(`/files/${encodeURIComponent(fileId)}`, { method: "DELETE" }, signal), "delete");
|
|
737
765
|
if (value === null || typeof value !== "object" || Array.isArray(value)) throw invalidResponse("delete");
|
|
738
766
|
const wire = value;
|
|
739
|
-
if (wire.id !== fileId || wire.type !== "file_deleted") throw invalidResponse("delete");
|
|
767
|
+
if (wire.id !== fileId || (this.protocol === "messages" ? wire.type !== "file_deleted" : wire.object !== "file" || wire.deleted !== true)) throw invalidResponse("delete");
|
|
740
768
|
}
|
|
741
769
|
};
|
|
742
770
|
//#endregion
|
|
@@ -910,8 +938,8 @@ var DeepSeekUploadIndex = class {
|
|
|
910
938
|
const MAX_IMAGE_BYTES = 32 * 1024 * 1024;
|
|
911
939
|
const OWNED_FILE_PREFIX = "dsh-";
|
|
912
940
|
/** The Files resource's parent URL identifies the upload namespace. */
|
|
913
|
-
function fileScope(connection) {
|
|
914
|
-
return deepSeekFileScope(messagesApiRoot(connection.baseURL), JSON.stringify(Object.entries(connection.headers).sort(([left], [right]) => left.localeCompare(right))));
|
|
941
|
+
function fileScope(connection, protocol) {
|
|
942
|
+
return deepSeekFileScope(protocol === "messages" ? messagesApiRoot(connection.baseURL) : `chat-completions:${connection.baseURL.replace(/\/+$/u, "")}`, JSON.stringify(Object.entries(connection.headers).sort(([left], [right]) => left.localeCompare(right))));
|
|
915
943
|
}
|
|
916
944
|
function abortReason(signal) {
|
|
917
945
|
const reason = signal.reason;
|
|
@@ -964,6 +992,7 @@ function filename(version) {
|
|
|
964
992
|
}
|
|
965
993
|
/** User-scoped durable file-id reuse for the DeepSeek route. */
|
|
966
994
|
var DeepSeekFileStore = class {
|
|
995
|
+
protocol;
|
|
967
996
|
index;
|
|
968
997
|
now;
|
|
969
998
|
fetchImpl;
|
|
@@ -972,12 +1001,14 @@ var DeepSeekFileStore = class {
|
|
|
972
1001
|
* @param options - testable index, clock, and transport boundaries.
|
|
973
1002
|
*/
|
|
974
1003
|
constructor(options = {}) {
|
|
1004
|
+
this.protocol = options.protocol ?? "messages";
|
|
975
1005
|
this.index = options.index ?? new DeepSeekUploadIndex();
|
|
976
1006
|
this.now = options.now ?? Date.now;
|
|
977
1007
|
this.fetchImpl = options.fetch;
|
|
978
1008
|
}
|
|
979
1009
|
client(connection) {
|
|
980
1010
|
return new DeepSeekFilesClient({
|
|
1011
|
+
protocol: this.protocol,
|
|
981
1012
|
baseURL: connection.baseURL,
|
|
982
1013
|
headers: connection.headers,
|
|
983
1014
|
...this.fetchImpl === void 0 ? {} : { fetch: this.fetchImpl }
|
|
@@ -993,7 +1024,7 @@ var DeepSeekFileStore = class {
|
|
|
993
1024
|
*/
|
|
994
1025
|
ensureUploaded(version, connection, policy, signal) {
|
|
995
1026
|
signal?.throwIfAborted();
|
|
996
|
-
const key = `${fileScope(connection)}\0${version.variantId}`;
|
|
1027
|
+
const key = `${fileScope(connection, this.protocol)}\0${version.variantId}`;
|
|
997
1028
|
let active = this.inflight.get(key);
|
|
998
1029
|
if (active?.controller.signal.aborted) {
|
|
999
1030
|
this.inflight.delete(key);
|
|
@@ -1022,7 +1053,7 @@ var DeepSeekFileStore = class {
|
|
|
1022
1053
|
}
|
|
1023
1054
|
async ensureUploadedOnce(version, connection, policy, signal) {
|
|
1024
1055
|
if (version.bytes > 33554432) throw new LlmError("DeepSeek image exceeds the 32 MiB per-image limit.", "INVALID_REQUEST");
|
|
1025
|
-
const scope = fileScope(connection);
|
|
1056
|
+
const scope = fileScope(connection, this.protocol);
|
|
1026
1057
|
const now = this.now();
|
|
1027
1058
|
const marginMs = policy.refreshMarginSeconds * 1e3;
|
|
1028
1059
|
const cached = await this.index.get(scope, version.variantId, now, marginMs);
|
|
@@ -1074,7 +1105,7 @@ var DeepSeekFileStore = class {
|
|
|
1074
1105
|
* @param connection - endpoint and API-key snapshot.
|
|
1075
1106
|
*/
|
|
1076
1107
|
async invalidate(version, fileId, connection) {
|
|
1077
|
-
await this.index.remove(fileScope(connection), version.variantId, fileId);
|
|
1108
|
+
await this.index.remove(fileScope(connection, this.protocol), version.variantId, fileId);
|
|
1078
1109
|
}
|
|
1079
1110
|
/**
|
|
1080
1111
|
* Delete the indexed remote file for one attachment and remove its local mapping.
|
|
@@ -1085,7 +1116,7 @@ var DeepSeekFileStore = class {
|
|
|
1085
1116
|
* @returns whether an indexed file existed and was deleted.
|
|
1086
1117
|
*/
|
|
1087
1118
|
async release(version, connection, policy, signal) {
|
|
1088
|
-
const scope = fileScope(connection);
|
|
1119
|
+
const scope = fileScope(connection, this.protocol);
|
|
1089
1120
|
const record = await this.index.get(scope, version.variantId, this.now(), policy.refreshMarginSeconds * 1e3);
|
|
1090
1121
|
if (record === void 0) return false;
|
|
1091
1122
|
await this.client(connection).delete(record.fileId, signal);
|
|
@@ -1137,7 +1168,7 @@ var DeepSeekFileStore = class {
|
|
|
1137
1168
|
total += deleted;
|
|
1138
1169
|
if (deleted < 1e3) break;
|
|
1139
1170
|
}
|
|
1140
|
-
await this.index.clear(fileScope(connection));
|
|
1171
|
+
await this.index.clear(fileScope(connection, this.protocol));
|
|
1141
1172
|
return total;
|
|
1142
1173
|
}
|
|
1143
1174
|
};
|
|
@@ -1452,177 +1483,465 @@ async function prepareFileIds(messages, versions, files) {
|
|
|
1452
1483
|
return ids;
|
|
1453
1484
|
}
|
|
1454
1485
|
//#endregion
|
|
1455
|
-
//#region lib/types/
|
|
1456
|
-
/**
|
|
1457
|
-
/**
|
|
1458
|
-
* @param
|
|
1459
|
-
* @
|
|
1460
|
-
* @returns the validated object.
|
|
1461
|
-
*/
|
|
1462
|
-
function object(value, code = "MALFORMED_RESPONSE") {
|
|
1463
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new LlmError("DeepSeek Messages expected a JSON object", code);
|
|
1464
|
-
return value;
|
|
1465
|
-
}
|
|
1466
|
-
/** Construct response metadata without duplicating the assistant text.
|
|
1467
|
-
* @param model - requested model identity.
|
|
1468
|
-
* @param blocks - metadata in emitted block order.
|
|
1469
|
-
* @returns the versioned envelope persisted by the existing assembler.
|
|
1486
|
+
//#region lib/types/transport.js
|
|
1487
|
+
/** Normalize HTTP and in-band Messages errors into provider-neutral failures. */
|
|
1488
|
+
/** Read only provider error fields used by bounded Files recovery.
|
|
1489
|
+
* @param raw - decoded HTTP error response.
|
|
1490
|
+
* @returns code, type, and message text, without unrelated response fields.
|
|
1470
1491
|
*/
|
|
1471
|
-
function
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1492
|
+
function providerErrorDetail(raw) {
|
|
1493
|
+
const error = typeof raw === "object" && raw !== null && "error" in raw ? raw.error : void 0;
|
|
1494
|
+
if (typeof error !== "object" || error === null) return "";
|
|
1495
|
+
const fields = error;
|
|
1496
|
+
return [
|
|
1497
|
+
fields.code,
|
|
1498
|
+
fields.type,
|
|
1499
|
+
fields.message
|
|
1500
|
+
].filter((value) => typeof value === "string").join(" ");
|
|
1480
1501
|
}
|
|
1481
|
-
/**
|
|
1482
|
-
* @param
|
|
1483
|
-
* @param
|
|
1484
|
-
* @param
|
|
1485
|
-
* @
|
|
1502
|
+
/** Classify a provider error without trusting arbitrary response fields.
|
|
1503
|
+
* @param raw - decoded response or in-band error event.
|
|
1504
|
+
* @param status - HTTP status when the error preceded streaming.
|
|
1505
|
+
* @param headers - response headers for retry delay and request identity.
|
|
1506
|
+
* @param protocol - API family used in fallback diagnostics; defaults to Messages.
|
|
1507
|
+
* @returns a stable error consumed by LlmRuntime and llm-retry.
|
|
1486
1508
|
*/
|
|
1487
|
-
function
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
if (
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
const
|
|
1503
|
-
const
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
const block = object(value, "INVALID_REPLAY_STATE");
|
|
1509
|
-
if (block.type !== message.content[index]?.type || block.type !== "text" && block.type !== "reasoning" && block.type !== "tool-call") return fail("block type mismatch");
|
|
1510
|
-
if (block.signature !== void 0 && (block.type !== "reasoning" || typeof block.signature !== "string")) return fail("invalid signature");
|
|
1511
|
-
return {
|
|
1512
|
-
type: block.type,
|
|
1513
|
-
...typeof block.signature === "string" ? { signature: block.signature } : {}
|
|
1514
|
-
};
|
|
1509
|
+
function providerError(raw, status, headers, protocol = "Messages") {
|
|
1510
|
+
const envelope = typeof raw === "object" && raw !== null ? raw : {};
|
|
1511
|
+
const error = typeof envelope.error === "object" && envelope.error !== null ? envelope.error : {};
|
|
1512
|
+
const message = typeof error.message === "string" ? error.message : `DeepSeek ${protocol} request failed (${status ?? "stream error"})`;
|
|
1513
|
+
const type = typeof error.type === "string" ? error.type : "";
|
|
1514
|
+
const detail = `${type} ${typeof error.code === "string" ? error.code : ""} ${message}`;
|
|
1515
|
+
let code;
|
|
1516
|
+
if (status === 401 || status === 403 || ["authentication_error", "permission_error"].includes(type)) code = "AUTH";
|
|
1517
|
+
else if (isQuotaExceededError(detail) || status === 402) code = "QUOTA";
|
|
1518
|
+
else if (status === 429 || type === "rate_limit_error") code = "RATE_LIMIT";
|
|
1519
|
+
else if (isContextWindowExceededError(detail)) code = "CONTEXT_WINDOW_EXCEEDED";
|
|
1520
|
+
else if (status === 400 || status === 413 || type === "invalid_request_error") code = "INVALID_REQUEST";
|
|
1521
|
+
else if (status !== void 0 && status >= 500 || ["api_error", "overloaded_error"].includes(type)) code = "SERVER";
|
|
1522
|
+
else code = status === void 0 ? "SERVER" : `HTTP_${status}`;
|
|
1523
|
+
const retry = headers?.get("retry-after");
|
|
1524
|
+
const delay = retry == null ? NaN : /^\d+(?:\.\d+)?$/u.test(retry) ? Number(retry) * 1e3 : Date.parse(retry) - Date.now();
|
|
1525
|
+
const id = headers?.get("request-id") ?? headers?.get("x-request-id") ?? headers?.get("x-deepseek-request-id");
|
|
1526
|
+
return new LlmError(message, code, {
|
|
1527
|
+
...status === void 0 ? {} : { status },
|
|
1528
|
+
...id ? { requestId: ProviderRequestId(id) } : {},
|
|
1529
|
+
...Number.isFinite(delay) && delay > 0 ? { providerRetryAfterMs: delay } : {}
|
|
1515
1530
|
});
|
|
1516
|
-
return response.model === model ? blocks : void 0;
|
|
1517
1531
|
}
|
|
1518
1532
|
//#endregion
|
|
1519
|
-
//#region lib/types/
|
|
1520
|
-
/**
|
|
1521
|
-
function
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
value = JSON.parse(raw);
|
|
1529
|
-
} catch (_invalidToolHistoryJson) {
|
|
1530
|
-
return {};
|
|
1531
|
-
}
|
|
1532
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
1533
|
-
}
|
|
1534
|
-
function assistant(message, model, onReplayDegrade) {
|
|
1535
|
-
const replay = readReplay(message, model, onReplayDegrade);
|
|
1536
|
-
return message.content.map((block, index) => {
|
|
1537
|
-
switch (block.type) {
|
|
1538
|
-
case "text": return {
|
|
1539
|
-
type: "text",
|
|
1540
|
-
text: block.text
|
|
1541
|
-
};
|
|
1542
|
-
case "reasoning": return {
|
|
1543
|
-
type: "thinking",
|
|
1544
|
-
thinking: block.text,
|
|
1545
|
-
...replay?.[index]?.signature === void 0 ? {} : { signature: replay[index].signature }
|
|
1546
|
-
};
|
|
1547
|
-
case "tool-call": return {
|
|
1548
|
-
type: "tool_use",
|
|
1549
|
-
id: block.id,
|
|
1550
|
-
name: block.name,
|
|
1551
|
-
input: toolInput(block.arguments)
|
|
1552
|
-
};
|
|
1553
|
-
default: return unsupported(`assistant content ${block.type}`);
|
|
1533
|
+
//#region lib/types/protocol-adapter.js
|
|
1534
|
+
/** Shared cancellation, image recovery, authentication, and delivery lifecycle for DeepSeek protocols. */
|
|
1535
|
+
var __addDisposableResource = function(env, value, async) {
|
|
1536
|
+
if (value !== null && value !== void 0) {
|
|
1537
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
1538
|
+
var dispose, inner;
|
|
1539
|
+
if (async) {
|
|
1540
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
1541
|
+
dispose = value[Symbol.asyncDispose];
|
|
1554
1542
|
}
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
* @param images - request versions for retained images.
|
|
1567
|
-
* @param access - execution-world paths for image descriptions.
|
|
1568
|
-
* @param onReplayDegrade - diagnostic for discarded native replay metadata.
|
|
1569
|
-
* @param fileIds - resolved Files references; omission selects inline image bytes.
|
|
1570
|
-
* @returns the Messages API JSON body.
|
|
1571
|
-
*/
|
|
1572
|
-
function serialize(options, connection, history, images, access, onReplayDegrade, fileIds) {
|
|
1573
|
-
const model = connection.models.find((entry) => entry.id === options.model);
|
|
1574
|
-
const inHistory = model?.systemPromptUpdate === "in-history";
|
|
1575
|
-
const input = (blocks) => blocks.flatMap((block) => {
|
|
1576
|
-
if (block.type === "text") return block.text ? [{
|
|
1577
|
-
type: "text",
|
|
1578
|
-
text: block.text
|
|
1579
|
-
}] : [];
|
|
1580
|
-
if (block.type === "reasoning" || block.type === "tool-call") return [];
|
|
1581
|
-
if (block.type !== "image") return unsupported(`user/tool-result content ${block.type}`);
|
|
1582
|
-
const version = images.get(block.attachment.attachmentId);
|
|
1583
|
-
if (version === void 0) throw new LlmError("DeepSeek Messages request image is missing", "INVALID_REQUEST");
|
|
1584
|
-
const fileId = fileIds?.get(block.attachment.attachmentId);
|
|
1585
|
-
if (fileIds !== void 0 && fileId === void 0) throw new LlmError("DeepSeek Messages request file id is missing", "INVALID_REQUEST");
|
|
1586
|
-
return [{
|
|
1587
|
-
type: "text",
|
|
1588
|
-
text: requestImageHandleText(block.attachment, version, access(block.attachment))
|
|
1589
|
-
}, fileId === void 0 ? {
|
|
1590
|
-
type: "image",
|
|
1591
|
-
source: {
|
|
1592
|
-
type: "base64",
|
|
1593
|
-
media_type: version.mediaType,
|
|
1594
|
-
data: Buffer.from(version.data).toString("base64")
|
|
1543
|
+
if (dispose === void 0) {
|
|
1544
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
1545
|
+
dispose = value[Symbol.dispose];
|
|
1546
|
+
if (async) inner = dispose;
|
|
1547
|
+
}
|
|
1548
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
1549
|
+
if (inner) dispose = function() {
|
|
1550
|
+
try {
|
|
1551
|
+
inner.call(this);
|
|
1552
|
+
} catch (e) {
|
|
1553
|
+
return Promise.reject(e);
|
|
1595
1554
|
}
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1555
|
+
};
|
|
1556
|
+
env.stack.push({
|
|
1557
|
+
value,
|
|
1558
|
+
dispose,
|
|
1559
|
+
async
|
|
1560
|
+
});
|
|
1561
|
+
} else if (async) env.stack.push({ async: true });
|
|
1562
|
+
return value;
|
|
1563
|
+
};
|
|
1564
|
+
var __disposeResources = (function(SuppressedError) {
|
|
1565
|
+
return function(env) {
|
|
1566
|
+
function fail(e) {
|
|
1567
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
1568
|
+
env.hasError = true;
|
|
1569
|
+
}
|
|
1570
|
+
var r, s = 0;
|
|
1571
|
+
function next() {
|
|
1572
|
+
while (r = env.stack.pop()) try {
|
|
1573
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
1574
|
+
if (r.dispose) {
|
|
1575
|
+
var result = r.dispose.call(r.value);
|
|
1576
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
|
|
1577
|
+
fail(e);
|
|
1578
|
+
return next();
|
|
1579
|
+
});
|
|
1580
|
+
} else s |= 1;
|
|
1581
|
+
} catch (e) {
|
|
1582
|
+
fail(e);
|
|
1601
1583
|
}
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
const systemUpdates = [];
|
|
1607
|
-
const flushSystemUpdates = () => {
|
|
1608
|
-
if (systemUpdates.length === 0) return;
|
|
1609
|
-
if (messages.at(-1)?.role !== "user") return unsupported("system update without a preceding user or tool-result turn");
|
|
1610
|
-
messages.push(...systemUpdates.splice(0));
|
|
1584
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
1585
|
+
if (env.hasError) throw env.error;
|
|
1586
|
+
}
|
|
1587
|
+
return next();
|
|
1611
1588
|
};
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1589
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
|
|
1590
|
+
var e = new Error(message);
|
|
1591
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
1592
|
+
});
|
|
1593
|
+
/** Provider adapter with protocol-independent request ownership and image recovery. */
|
|
1594
|
+
var DeepSeekProtocolAdapter = class extends LlmAdapter {
|
|
1595
|
+
dependencies;
|
|
1596
|
+
protocol;
|
|
1597
|
+
files;
|
|
1598
|
+
imageAccess = (ref) => {
|
|
1599
|
+
const attachments = this.dependencies.resolveAttachments?.();
|
|
1600
|
+
return attachments === void 0 ? void 0 : this.dependencies.resolveImageAccess?.(attachments, ref);
|
|
1601
|
+
};
|
|
1602
|
+
/**
|
|
1603
|
+
* @param dependencies - request-local configuration, authentication, and Host services.
|
|
1604
|
+
* @param protocol - serializer, resource URLs, and stream decoder.
|
|
1605
|
+
*/
|
|
1606
|
+
constructor(dependencies, protocol) {
|
|
1607
|
+
super();
|
|
1608
|
+
this.dependencies = dependencies;
|
|
1609
|
+
this.protocol = protocol;
|
|
1610
|
+
this.files = dependencies.resolveFiles?.() ?? new DeepSeekFileStore({ protocol: protocol.files });
|
|
1611
|
+
}
|
|
1612
|
+
providerInfo(provider) {
|
|
1613
|
+
return {
|
|
1614
|
+
id: provider,
|
|
1615
|
+
name: this.dependencies.providerName ?? "DeepSeek"
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
providerRetryPolicy(_provider) {
|
|
1619
|
+
return this.dependencies.options().retryPolicy;
|
|
1620
|
+
}
|
|
1621
|
+
async listModels(provider) {
|
|
1622
|
+
return this.dependencies.discoverModels?.(provider) ?? [];
|
|
1623
|
+
}
|
|
1624
|
+
resolveModel(provider, model, _signal) {
|
|
1625
|
+
return Promise.resolve(this.describe(this.dependencies.options(), provider, model));
|
|
1626
|
+
}
|
|
1627
|
+
imageRequestPricing(_provider, model) {
|
|
1628
|
+
return deepSeekImageRequestPricing(this.dependencies.options(), model, this.imageAccess);
|
|
1629
|
+
}
|
|
1630
|
+
prepareCall(provider, model, _signal) {
|
|
1631
|
+
const connection = this.dependencies.options();
|
|
1632
|
+
return Promise.resolve({
|
|
1633
|
+
model: this.describe(connection, provider, model),
|
|
1634
|
+
stream: (options) => this.generate(options, connection)
|
|
1635
|
+
});
|
|
1636
|
+
}
|
|
1637
|
+
stream(options) {
|
|
1638
|
+
return this.generate(options, this.dependencies.options());
|
|
1639
|
+
}
|
|
1640
|
+
describe(connection, provider, model) {
|
|
1641
|
+
const info = modelInfo(connection, provider, model);
|
|
1642
|
+
if (this.protocol.files === "messages") return info;
|
|
1643
|
+
const { toolUpdate: _toolUpdate, ...supported } = info;
|
|
1644
|
+
return supported;
|
|
1645
|
+
}
|
|
1646
|
+
async *generate(options, connection) {
|
|
1647
|
+
const env_1 = {
|
|
1648
|
+
stack: [],
|
|
1649
|
+
error: void 0,
|
|
1650
|
+
hasError: false
|
|
1651
|
+
};
|
|
1652
|
+
try {
|
|
1653
|
+
const consumer = new AbortController();
|
|
1654
|
+
const watchdog = __addDisposableResource(env_1, idleWatchdog(options.signal === void 0 ? consumer.signal : AbortSignal.any([consumer.signal, options.signal]), connection.streamIdleTimeoutMs, "MESSAGES_IDLE"), false);
|
|
1655
|
+
const iterator = this.request(options, connection, watchdog.signal, () => {
|
|
1656
|
+
watchdog.pulse();
|
|
1657
|
+
});
|
|
1658
|
+
try {
|
|
1659
|
+
while (true) {
|
|
1660
|
+
const next = await watchdog.next(iterator);
|
|
1661
|
+
if (next.done) return;
|
|
1662
|
+
yield next.value;
|
|
1663
|
+
}
|
|
1664
|
+
} catch (error) {
|
|
1665
|
+
if (timeoutOf(watchdog.signal, "MESSAGES_IDLE") !== void 0) throw new LlmError(`DeepSeek ${this.protocol.name} stream idle timeout`, "TIMEOUT", { cause: error });
|
|
1666
|
+
if (options.signal?.aborted) throw new LlmError(`DeepSeek ${this.protocol.name} request aborted`, "ABORTED", { cause: error });
|
|
1667
|
+
if (error instanceof LlmError) throw error;
|
|
1668
|
+
throw new LlmError(`DeepSeek ${this.protocol.name} transport failed`, "TRANSPORT", { cause: error });
|
|
1669
|
+
} finally {
|
|
1670
|
+
consumer.abort();
|
|
1671
|
+
try {
|
|
1672
|
+
await iterator.return(void 0);
|
|
1673
|
+
} catch (_abortedRequestCleanup) {}
|
|
1674
|
+
}
|
|
1675
|
+
} catch (e_1) {
|
|
1676
|
+
env_1.error = e_1;
|
|
1677
|
+
env_1.hasError = true;
|
|
1678
|
+
} finally {
|
|
1679
|
+
__disposeResources(env_1);
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
async *request(options, connection, signal, activity) {
|
|
1683
|
+
signal.throwIfAborted();
|
|
1684
|
+
const { messages, versions } = await prepareImages(options.messages, connection, options.model, this.dependencies.resolveAttachments?.(), this.imageAccess, signal);
|
|
1685
|
+
const auth = await this.dependencies.resolveAuth(connection);
|
|
1686
|
+
try {
|
|
1687
|
+
const files = new RequestFiles(this.files, {
|
|
1688
|
+
baseURL: connection.baseURL,
|
|
1689
|
+
headers: auth.headers
|
|
1690
|
+
}, connection.filePolicy, connection.filesApiTimeoutMs, signal, activity);
|
|
1691
|
+
let inline = false;
|
|
1692
|
+
while (true) {
|
|
1693
|
+
signal.throwIfAborted();
|
|
1694
|
+
files.beginAttempt();
|
|
1695
|
+
let fileIds;
|
|
1696
|
+
if (!inline) try {
|
|
1697
|
+
fileIds = await prepareFileIds(messages, versions, files);
|
|
1698
|
+
} catch (error) {
|
|
1699
|
+
if (!(error instanceof FileResolutionFailure)) throw error;
|
|
1700
|
+
inline = true;
|
|
1701
|
+
continue;
|
|
1702
|
+
}
|
|
1703
|
+
const history = inline ? inlineImages(messages, versions, connection) : messages;
|
|
1704
|
+
const { body, headers } = this.protocol.prepare(options, connection, history, versions, this.imageAccess, (reason) => {
|
|
1705
|
+
this.dependencies.onReplayDegrade?.({
|
|
1706
|
+
provider: options.provider,
|
|
1707
|
+
model: options.model,
|
|
1708
|
+
reason
|
|
1709
|
+
});
|
|
1710
|
+
}, fileIds);
|
|
1711
|
+
const extensions = await prepareRequestExtensions(body, {
|
|
1712
|
+
signal,
|
|
1713
|
+
...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },
|
|
1714
|
+
...options.purpose === void 0 ? {} : { purpose: options.purpose }
|
|
1715
|
+
}, this.dependencies.prepareExtensions, (fields, error) => {
|
|
1716
|
+
this.dependencies.onExtensionsOmitted?.({
|
|
1717
|
+
provider: options.provider,
|
|
1718
|
+
model: options.model,
|
|
1719
|
+
fields,
|
|
1720
|
+
error
|
|
1721
|
+
});
|
|
1722
|
+
});
|
|
1723
|
+
signal.throwIfAborted();
|
|
1724
|
+
const response = await fetch(this.protocol.endpoint(connection.baseURL), {
|
|
1725
|
+
method: "POST",
|
|
1726
|
+
signal,
|
|
1727
|
+
body: extensions.payload,
|
|
1728
|
+
redirect: "error",
|
|
1729
|
+
headers: {
|
|
1730
|
+
...attributionHeaders(),
|
|
1731
|
+
"content-type": "application/json",
|
|
1732
|
+
"accept": "text/event-stream",
|
|
1733
|
+
...auth.headers,
|
|
1734
|
+
...headers,
|
|
1735
|
+
"x-deepseek-harness-user-id": this.dependencies.resolveUserId(),
|
|
1736
|
+
...options.sessionId === void 0 ? {} : { "x-deepseek-harness-session-id": String(options.sessionId) },
|
|
1737
|
+
...options.purpose === "compaction" ? { "x-deepseek-harness-compact": "1" } : {}
|
|
1738
|
+
}
|
|
1739
|
+
});
|
|
1740
|
+
if (!response.ok) {
|
|
1741
|
+
const text = await response.text();
|
|
1742
|
+
let raw;
|
|
1743
|
+
try {
|
|
1744
|
+
raw = JSON.parse(text);
|
|
1745
|
+
} catch (_nonJsonGatewayError) {}
|
|
1746
|
+
const detail = providerErrorDetail(raw);
|
|
1747
|
+
if (await files.retry(detail)) continue;
|
|
1748
|
+
const failure = providerError(raw, response.status, response.headers, this.protocol.name);
|
|
1749
|
+
throw new LlmError(files.errorMessage(response.status, failure.message, detail), failure.code, {
|
|
1750
|
+
...failure.failure,
|
|
1751
|
+
cause: new Error(text)
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
await extensions.accept();
|
|
1755
|
+
if (response.body === null) throw new LlmError(`DeepSeek ${this.protocol.name} returned no response body`, "EMPTY_RESPONSE");
|
|
1756
|
+
yield* this.protocol.translate(response.body, activity, options.model);
|
|
1757
|
+
return;
|
|
1758
|
+
}
|
|
1759
|
+
} catch (error) {
|
|
1760
|
+
if (auth.onRequestError !== void 0) {
|
|
1761
|
+
let mapped;
|
|
1762
|
+
try {
|
|
1763
|
+
mapped = await auth.onRequestError(error);
|
|
1764
|
+
} catch (_credentialUpdateFailed) {
|
|
1765
|
+
throw error;
|
|
1766
|
+
}
|
|
1767
|
+
throw mapped;
|
|
1768
|
+
}
|
|
1769
|
+
throw error;
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
};
|
|
1773
|
+
//#endregion
|
|
1774
|
+
//#region lib/types/replay.js
|
|
1775
|
+
/** Minimal native thinking metadata; durable Harness blocks own all response text. */
|
|
1776
|
+
/** Reject malformed JSON objects at provider and durable-data reads.
|
|
1777
|
+
* @param value - untrusted decoded JSON.
|
|
1778
|
+
* @param code - owning failure category.
|
|
1779
|
+
* @returns the validated object.
|
|
1780
|
+
*/
|
|
1781
|
+
function object(value, code = "MALFORMED_RESPONSE") {
|
|
1782
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new LlmError("DeepSeek Messages expected a JSON object", code);
|
|
1783
|
+
return value;
|
|
1784
|
+
}
|
|
1785
|
+
/** Construct response metadata without duplicating the assistant text.
|
|
1786
|
+
* @param model - requested model identity.
|
|
1787
|
+
* @param blocks - metadata in emitted block order.
|
|
1788
|
+
* @returns the versioned envelope persisted by the existing assembler.
|
|
1789
|
+
*/
|
|
1790
|
+
function replayState(model, blocks) {
|
|
1791
|
+
return {
|
|
1792
|
+
response: {
|
|
1793
|
+
kind: "deepseek-messages",
|
|
1794
|
+
version: 1,
|
|
1795
|
+
model
|
|
1796
|
+
},
|
|
1797
|
+
blocks
|
|
1798
|
+
};
|
|
1799
|
+
}
|
|
1800
|
+
/** Validate native replay, discarding unusable metadata before serializing durable content.
|
|
1801
|
+
* @param message - durable assistant content and source metadata.
|
|
1802
|
+
* @param model - target model; cross-model signatures are not portable.
|
|
1803
|
+
* @param onDegrade - diagnostic for unusable metadata; receives no message content or signatures.
|
|
1804
|
+
* @returns index-aligned metadata, absent for foreign, cross-model or degraded history.
|
|
1805
|
+
*/
|
|
1806
|
+
function readReplay(message, model, onDegrade) {
|
|
1807
|
+
try {
|
|
1808
|
+
return validateReplay(message, model);
|
|
1809
|
+
} catch (error) {
|
|
1810
|
+
/* v8 ignore next -- the validator only throws INVALID_REPLAY_STATE; preserve future non-replay failures. */
|
|
1811
|
+
if (!(error instanceof LlmError) || error.code !== "INVALID_REPLAY_STATE") throw error;
|
|
1812
|
+
onDegrade?.(error.message);
|
|
1813
|
+
return;
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
function validateReplay(message, model) {
|
|
1817
|
+
if (message.source.kind !== "model" || message.source.replayState === void 0) return void 0;
|
|
1818
|
+
const fail = (detail) => {
|
|
1819
|
+
throw new LlmError(`DeepSeek Messages replay: ${detail}`, "INVALID_REPLAY_STATE");
|
|
1820
|
+
};
|
|
1821
|
+
const envelope = object(message.source.replayState, "INVALID_REPLAY_STATE");
|
|
1822
|
+
const response = object(envelope.response, "INVALID_REPLAY_STATE");
|
|
1823
|
+
if (response.kind !== "deepseek-messages" || response.version !== 1) return fail("unsupported kind or version");
|
|
1824
|
+
if (response.model !== message.source.model) return fail("model does not match assistant source model");
|
|
1825
|
+
if (!Array.isArray(envelope.blocks) || envelope.blocks.length !== message.content.length) return fail("block count mismatch");
|
|
1826
|
+
const blocks = envelope.blocks.map((value, index) => {
|
|
1827
|
+
const block = object(value, "INVALID_REPLAY_STATE");
|
|
1828
|
+
if (block.type !== message.content[index]?.type || block.type !== "text" && block.type !== "reasoning" && block.type !== "tool-call") return fail("block type mismatch");
|
|
1829
|
+
if (block.signature !== void 0 && (block.type !== "reasoning" || typeof block.signature !== "string")) return fail("invalid signature");
|
|
1830
|
+
return {
|
|
1831
|
+
type: block.type,
|
|
1832
|
+
...typeof block.signature === "string" ? { signature: block.signature } : {}
|
|
1833
|
+
};
|
|
1834
|
+
});
|
|
1835
|
+
return response.model === model ? blocks : void 0;
|
|
1836
|
+
}
|
|
1837
|
+
//#endregion
|
|
1838
|
+
//#region lib/types/serialize.js
|
|
1839
|
+
/** Map system snapshots, tool changes, and conversation turns to Messages using the configured route capability. */
|
|
1840
|
+
function unsupported(type) {
|
|
1841
|
+
throw new LlmError(`DeepSeek Messages cannot represent ${type}`, "UNSUPPORTED_CONTENT");
|
|
1842
|
+
}
|
|
1843
|
+
/** Historical arguments that Messages cannot represent use empty input; durable content stays unchanged. */
|
|
1844
|
+
function toolInput(raw) {
|
|
1845
|
+
let value;
|
|
1846
|
+
try {
|
|
1847
|
+
value = JSON.parse(raw);
|
|
1848
|
+
} catch (_invalidToolHistoryJson) {
|
|
1849
|
+
return {};
|
|
1850
|
+
}
|
|
1851
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
1852
|
+
}
|
|
1853
|
+
function assistant(message, model, onReplayDegrade) {
|
|
1854
|
+
const replay = readReplay(message, model, onReplayDegrade);
|
|
1855
|
+
return message.content.map((block, index) => {
|
|
1856
|
+
switch (block.type) {
|
|
1857
|
+
case "text": return {
|
|
1858
|
+
type: "text",
|
|
1859
|
+
text: block.text
|
|
1860
|
+
};
|
|
1861
|
+
case "reasoning": return {
|
|
1862
|
+
type: "thinking",
|
|
1863
|
+
thinking: block.text,
|
|
1864
|
+
...replay?.[index]?.signature === void 0 ? {} : { signature: replay[index].signature }
|
|
1865
|
+
};
|
|
1866
|
+
case "tool-call": return {
|
|
1867
|
+
type: "tool_use",
|
|
1868
|
+
id: block.id,
|
|
1869
|
+
name: block.name,
|
|
1870
|
+
input: toolInput(block.arguments)
|
|
1871
|
+
};
|
|
1872
|
+
default: return unsupported(`assistant content ${block.type}`);
|
|
1873
|
+
}
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
/** Serialize one complete request using already prepared image bytes.
|
|
1877
|
+
* User and tool-result content omits reasoning and tool-call blocks.
|
|
1878
|
+
* Empty user messages are skipped; empty tool results retain their call ids.
|
|
1879
|
+
* Developer messages, already projected for this route by `LlmRuntime`, become
|
|
1880
|
+
* system-role updates after the preceding user turn, with tool changes as
|
|
1881
|
+
* `tool_addition` and `tool_removal` references to the declared tool.
|
|
1882
|
+
* @param options - provider-neutral request.
|
|
1883
|
+
* @param connection - validated defaults and thinking policy.
|
|
1884
|
+
* @param history - image-projected history with complete system snapshots; durable messages remain unchanged.
|
|
1885
|
+
* @param images - request versions for retained images.
|
|
1886
|
+
* @param access - execution-world paths for image descriptions.
|
|
1887
|
+
* @param onReplayDegrade - diagnostic for discarded native replay metadata.
|
|
1888
|
+
* @param fileIds - resolved Files references; omission selects inline image bytes.
|
|
1889
|
+
* @returns the Messages API JSON body.
|
|
1890
|
+
*/
|
|
1891
|
+
function serialize$1(options, connection, history, images, access, onReplayDegrade, fileIds) {
|
|
1892
|
+
const model = connection.models.find((entry) => entry.id === options.model);
|
|
1893
|
+
const inHistory = model?.systemPromptUpdate === "in-history";
|
|
1894
|
+
const input = (blocks) => blocks.flatMap((block) => {
|
|
1895
|
+
if (block.type === "text") return block.text ? [{
|
|
1896
|
+
type: "text",
|
|
1897
|
+
text: block.text
|
|
1898
|
+
}] : [];
|
|
1899
|
+
if (block.type === "reasoning" || block.type === "tool-call") return [];
|
|
1900
|
+
if (block.type !== "image") return unsupported(`user/tool-result content ${block.type}`);
|
|
1901
|
+
const version = images.get(block.attachment.attachmentId);
|
|
1902
|
+
if (version === void 0) throw new LlmError("DeepSeek Messages request image is missing", "INVALID_REQUEST");
|
|
1903
|
+
const fileId = fileIds?.get(block.attachment.attachmentId);
|
|
1904
|
+
if (fileIds !== void 0 && fileId === void 0) throw new LlmError("DeepSeek Messages request file id is missing", "INVALID_REQUEST");
|
|
1905
|
+
return [{
|
|
1906
|
+
type: "text",
|
|
1907
|
+
text: requestImageHandleText(block.attachment, version, access(block.attachment))
|
|
1908
|
+
}, fileId === void 0 ? {
|
|
1909
|
+
type: "image",
|
|
1910
|
+
source: {
|
|
1911
|
+
type: "base64",
|
|
1912
|
+
media_type: version.mediaType,
|
|
1913
|
+
data: Buffer.from(version.data).toString("base64")
|
|
1914
|
+
}
|
|
1915
|
+
} : {
|
|
1916
|
+
type: "image",
|
|
1917
|
+
source: {
|
|
1918
|
+
type: "file",
|
|
1919
|
+
file_id: fileId
|
|
1920
|
+
}
|
|
1921
|
+
}];
|
|
1922
|
+
});
|
|
1923
|
+
const messages = [];
|
|
1924
|
+
let historySystem;
|
|
1925
|
+
const systemUpdates = [];
|
|
1926
|
+
const flushSystemUpdates = () => {
|
|
1927
|
+
if (systemUpdates.length === 0) return;
|
|
1928
|
+
if (messages.at(-1)?.role !== "user") return unsupported("system update without a preceding user or tool-result turn");
|
|
1929
|
+
messages.push(...systemUpdates.splice(0));
|
|
1930
|
+
};
|
|
1931
|
+
for (const message of history) {
|
|
1932
|
+
if (message.role === "developer") {
|
|
1933
|
+
const content = message.content.flatMap((block) => {
|
|
1934
|
+
switch (block.type) {
|
|
1935
|
+
case "text": return block.text.length === 0 ? [] : [{
|
|
1936
|
+
type: "text",
|
|
1937
|
+
text: block.text
|
|
1938
|
+
}];
|
|
1939
|
+
case "tool-addition": return [{
|
|
1940
|
+
type: "tool_addition",
|
|
1941
|
+
tool: {
|
|
1942
|
+
type: "tool_reference",
|
|
1943
|
+
name: block.toolName
|
|
1944
|
+
}
|
|
1626
1945
|
}];
|
|
1627
1946
|
case "tool-removal": return [{
|
|
1628
1947
|
type: "tool_removal",
|
|
@@ -1713,52 +2032,6 @@ function serialize(options, connection, history, images, access, onReplayDegrade
|
|
|
1713
2032
|
};
|
|
1714
2033
|
}
|
|
1715
2034
|
//#endregion
|
|
1716
|
-
//#region lib/types/transport.js
|
|
1717
|
-
/** Normalize HTTP and in-band Messages errors into provider-neutral failures. */
|
|
1718
|
-
/** Read only provider error fields used by bounded Files recovery.
|
|
1719
|
-
* @param raw - decoded HTTP error response.
|
|
1720
|
-
* @returns code, type, and message text, without unrelated response fields.
|
|
1721
|
-
*/
|
|
1722
|
-
function providerErrorDetail(raw) {
|
|
1723
|
-
const error = typeof raw === "object" && raw !== null && "error" in raw ? raw.error : void 0;
|
|
1724
|
-
if (typeof error !== "object" || error === null) return "";
|
|
1725
|
-
const fields = error;
|
|
1726
|
-
return [
|
|
1727
|
-
fields.code,
|
|
1728
|
-
fields.type,
|
|
1729
|
-
fields.message
|
|
1730
|
-
].filter((value) => typeof value === "string").join(" ");
|
|
1731
|
-
}
|
|
1732
|
-
/** Classify a provider error without trusting arbitrary response fields.
|
|
1733
|
-
* @param raw - decoded response or in-band error event.
|
|
1734
|
-
* @param status - HTTP status when the error preceded streaming.
|
|
1735
|
-
* @param headers - response headers for retry delay and request identity.
|
|
1736
|
-
* @returns a stable error consumed by LlmRuntime and llm-retry.
|
|
1737
|
-
*/
|
|
1738
|
-
function providerError(raw, status, headers) {
|
|
1739
|
-
const envelope = typeof raw === "object" && raw !== null ? raw : {};
|
|
1740
|
-
const error = typeof envelope.error === "object" && envelope.error !== null ? envelope.error : {};
|
|
1741
|
-
const message = typeof error.message === "string" ? error.message : `DeepSeek Messages request failed (${status ?? "stream error"})`;
|
|
1742
|
-
const type = typeof error.type === "string" ? error.type : "";
|
|
1743
|
-
const detail = `${type} ${typeof error.code === "string" ? error.code : ""} ${message}`;
|
|
1744
|
-
let code;
|
|
1745
|
-
if (status === 401 || status === 403 || ["authentication_error", "permission_error"].includes(type)) code = "AUTH";
|
|
1746
|
-
else if (isQuotaExceededError(detail) || status === 402) code = "QUOTA";
|
|
1747
|
-
else if (status === 429 || type === "rate_limit_error") code = "RATE_LIMIT";
|
|
1748
|
-
else if (isContextWindowExceededError(detail)) code = "CONTEXT_WINDOW_EXCEEDED";
|
|
1749
|
-
else if (status === 400 || status === 413 || type === "invalid_request_error") code = "INVALID_REQUEST";
|
|
1750
|
-
else if (status !== void 0 && status >= 500 || ["api_error", "overloaded_error"].includes(type)) code = "SERVER";
|
|
1751
|
-
else code = status === void 0 ? "SERVER" : `HTTP_${status}`;
|
|
1752
|
-
const retry = headers?.get("retry-after");
|
|
1753
|
-
const delay = retry == null ? NaN : /^\d+(?:\.\d+)?$/u.test(retry) ? Number(retry) * 1e3 : Date.parse(retry) - Date.now();
|
|
1754
|
-
const id = headers?.get("request-id") ?? headers?.get("x-request-id") ?? headers?.get("x-deepseek-request-id");
|
|
1755
|
-
return new LlmError(message, code, {
|
|
1756
|
-
...status === void 0 ? {} : { status },
|
|
1757
|
-
...id ? { requestId: ProviderRequestId(id) } : {},
|
|
1758
|
-
...Number.isFinite(delay) && delay > 0 ? { providerRetryAfterMs: delay } : {}
|
|
1759
|
-
});
|
|
1760
|
-
}
|
|
1761
|
-
//#endregion
|
|
1762
2035
|
//#region lib/types/sse.js
|
|
1763
2036
|
/** SSE framing delegated to eventsource-parser; JSON errors remain provider failures. */
|
|
1764
2037
|
/** Decode complete SSE frames without treating an unterminated tail as an event.
|
|
@@ -1766,7 +2039,7 @@ function providerError(raw, status, headers) {
|
|
|
1766
2039
|
* @param activity - pulse the idle watchdog for events and heartbeat comments.
|
|
1767
2040
|
* @returns JSON events, including message_stop; the translator owns completion.
|
|
1768
2041
|
*/
|
|
1769
|
-
async function* parseSse(body, activity) {
|
|
2042
|
+
async function* parseSse$1(body, activity) {
|
|
1770
2043
|
const events = body.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream({ onComment: activity }));
|
|
1771
2044
|
for await (const frame of events) {
|
|
1772
2045
|
activity();
|
|
@@ -1907,7 +2180,7 @@ function stopReason(raw) {
|
|
|
1907
2180
|
* @param model - requested model id stored in durable replay state.
|
|
1908
2181
|
* @returns blocks, one final usage value, and exactly one terminal finish.
|
|
1909
2182
|
*/
|
|
1910
|
-
async function* translate(events, model) {
|
|
2183
|
+
async function* translate$1(events, model) {
|
|
1911
2184
|
const blocks = /* @__PURE__ */ new Map();
|
|
1912
2185
|
const usage = {
|
|
1913
2186
|
inputTokens: 0,
|
|
@@ -1986,248 +2259,421 @@ async function* translate(events, model) {
|
|
|
1986
2259
|
object(parsed);
|
|
1987
2260
|
}
|
|
1988
2261
|
usage.totalTokens = usage.inputTokens + usage.outputTokens + (usage.cacheReadTokens ?? 0) + (usage.cacheWriteTokens ?? 0);
|
|
1989
|
-
yield {
|
|
1990
|
-
type: "usage",
|
|
1991
|
-
usage
|
|
1992
|
-
};
|
|
1993
|
-
yield {
|
|
1994
|
-
type: "finish",
|
|
1995
|
-
reason,
|
|
1996
|
-
replayState: replayState(model, [...blocks.values()].map((block) => block.replay))
|
|
1997
|
-
};
|
|
1998
|
-
return;
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
|
-
throw new LlmError("DeepSeek Messages stream ended before message_stop", "STREAM_CLOSED");
|
|
2002
|
-
}
|
|
2003
|
-
//#endregion
|
|
2004
|
-
//#region lib/types/adapter.js
|
|
2005
|
-
/** Direct Messages transport with one cancellable lifecycle per model request. */
|
|
2006
|
-
var __addDisposableResource = function(env, value, async) {
|
|
2007
|
-
if (value !== null && value !== void 0) {
|
|
2008
|
-
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
2009
|
-
var dispose, inner;
|
|
2010
|
-
if (async) {
|
|
2011
|
-
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
2012
|
-
dispose = value[Symbol.asyncDispose];
|
|
2013
|
-
}
|
|
2014
|
-
if (dispose === void 0) {
|
|
2015
|
-
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
2016
|
-
dispose = value[Symbol.dispose];
|
|
2017
|
-
if (async) inner = dispose;
|
|
2018
|
-
}
|
|
2019
|
-
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
2020
|
-
if (inner) dispose = function() {
|
|
2021
|
-
try {
|
|
2022
|
-
inner.call(this);
|
|
2023
|
-
} catch (e) {
|
|
2024
|
-
return Promise.reject(e);
|
|
2025
|
-
}
|
|
2026
|
-
};
|
|
2027
|
-
env.stack.push({
|
|
2028
|
-
value,
|
|
2029
|
-
dispose,
|
|
2030
|
-
async
|
|
2031
|
-
});
|
|
2032
|
-
} else if (async) env.stack.push({ async: true });
|
|
2033
|
-
return value;
|
|
2034
|
-
};
|
|
2035
|
-
var __disposeResources = (function(SuppressedError) {
|
|
2036
|
-
return function(env) {
|
|
2037
|
-
function fail(e) {
|
|
2038
|
-
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
2039
|
-
env.hasError = true;
|
|
2040
|
-
}
|
|
2041
|
-
var r, s = 0;
|
|
2042
|
-
function next() {
|
|
2043
|
-
while (r = env.stack.pop()) try {
|
|
2044
|
-
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
2045
|
-
if (r.dispose) {
|
|
2046
|
-
var result = r.dispose.call(r.value);
|
|
2047
|
-
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
|
|
2048
|
-
fail(e);
|
|
2049
|
-
return next();
|
|
2050
|
-
});
|
|
2051
|
-
} else s |= 1;
|
|
2052
|
-
} catch (e) {
|
|
2053
|
-
fail(e);
|
|
2054
|
-
}
|
|
2055
|
-
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
2056
|
-
if (env.hasError) throw env.error;
|
|
2262
|
+
yield {
|
|
2263
|
+
type: "usage",
|
|
2264
|
+
usage
|
|
2265
|
+
};
|
|
2266
|
+
yield {
|
|
2267
|
+
type: "finish",
|
|
2268
|
+
reason,
|
|
2269
|
+
replayState: replayState(model, [...blocks.values()].map((block) => block.replay))
|
|
2270
|
+
};
|
|
2271
|
+
return;
|
|
2057
2272
|
}
|
|
2058
|
-
return next();
|
|
2059
|
-
};
|
|
2060
|
-
})(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
|
|
2061
|
-
var e = new Error(message);
|
|
2062
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
2063
|
-
});
|
|
2064
|
-
/** DeepSeek provider using Messages content and native thinking replay. */
|
|
2065
|
-
var DeepSeekAdapter = class extends LlmAdapter {
|
|
2066
|
-
dependencies;
|
|
2067
|
-
files;
|
|
2068
|
-
imageAccess = (ref) => {
|
|
2069
|
-
const attachments = this.dependencies.resolveAttachments?.();
|
|
2070
|
-
return attachments === void 0 ? void 0 : this.dependencies.resolveImageAccess?.(attachments, ref);
|
|
2071
|
-
};
|
|
2072
|
-
constructor(dependencies) {
|
|
2073
|
-
super();
|
|
2074
|
-
this.dependencies = dependencies;
|
|
2075
|
-
this.files = dependencies.resolveFiles?.() ?? new DeepSeekFileStore();
|
|
2076
2273
|
}
|
|
2077
|
-
|
|
2274
|
+
throw new LlmError("DeepSeek Messages stream ended before message_stop", "STREAM_CLOSED");
|
|
2275
|
+
}
|
|
2276
|
+
//#endregion
|
|
2277
|
+
//#region lib/types/adapter.js
|
|
2278
|
+
const messages = {
|
|
2279
|
+
name: "Messages",
|
|
2280
|
+
files: "messages",
|
|
2281
|
+
endpoint: (baseURL) => `${messagesApiRoot(baseURL)}/messages`,
|
|
2282
|
+
prepare: (...args) => {
|
|
2283
|
+
const body = serialize$1(...args);
|
|
2284
|
+
const betas = [...args[6] !== void 0 && args[6].size > 0 ? [MESSAGES_FILES_BETA] : [], ...body.messages.some((message) => message.content.some((block) => block.type === "tool_addition" || block.type === "tool_removal")) ? [MESSAGES_TOOL_CHANGES_BETA] : []];
|
|
2078
2285
|
return {
|
|
2079
|
-
|
|
2080
|
-
|
|
2286
|
+
body,
|
|
2287
|
+
headers: {
|
|
2288
|
+
"anthropic-version": "2023-06-01",
|
|
2289
|
+
...betas.length === 0 ? {} : { "anthropic-beta": betas.join(",") }
|
|
2290
|
+
}
|
|
2081
2291
|
};
|
|
2292
|
+
},
|
|
2293
|
+
translate: (stream, activity, model) => translate$1(parseSse$1(stream, activity), model)
|
|
2294
|
+
};
|
|
2295
|
+
/** DeepSeek provider using Messages content and native thinking replay. */
|
|
2296
|
+
var DeepSeekAdapter = class extends DeepSeekProtocolAdapter {
|
|
2297
|
+
/** @param dependencies - request-local configuration, credentials, and Host services. */
|
|
2298
|
+
constructor(dependencies) {
|
|
2299
|
+
super(dependencies, messages);
|
|
2082
2300
|
}
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2301
|
+
};
|
|
2302
|
+
//#endregion
|
|
2303
|
+
//#region lib/types/chat-completions/serialize.js
|
|
2304
|
+
/** DeepSeek Chat Completions serialization with verbatim reasoning and tool arguments. */
|
|
2305
|
+
function text(blocks) {
|
|
2306
|
+
return blocks.filter((block) => block.type === "text").map((block) => block.text).join("");
|
|
2307
|
+
}
|
|
2308
|
+
/**
|
|
2309
|
+
* Serialize prepared history without rewriting durable reasoning or tool arguments.
|
|
2310
|
+
* Tool-result images follow their complete consecutive tool-result group in a user message.
|
|
2311
|
+
* @param args - request, validated connection, prepared history/images, access resolver, replay reporter, and Files ids.
|
|
2312
|
+
* @returns a streaming Chat Completions request with usage enabled.
|
|
2313
|
+
*/
|
|
2314
|
+
function serialize(...args) {
|
|
2315
|
+
const [options, connection, history, images, access, , fileIds] = args;
|
|
2316
|
+
const messages = [];
|
|
2317
|
+
let pendingImages = [];
|
|
2318
|
+
const flushImages = () => {
|
|
2319
|
+
if (pendingImages.length === 0) return;
|
|
2320
|
+
messages.push({
|
|
2321
|
+
role: "user",
|
|
2322
|
+
content: [{
|
|
2323
|
+
type: "text",
|
|
2324
|
+
text: "Attached image(s) from tool result:"
|
|
2325
|
+
}, ...pendingImages]
|
|
2326
|
+
});
|
|
2327
|
+
pendingImages = [];
|
|
2328
|
+
};
|
|
2329
|
+
const parts = (blocks) => blocks.flatMap((block) => {
|
|
2330
|
+
if (block.type === "text") return block.text ? [{
|
|
2331
|
+
type: "text",
|
|
2332
|
+
text: block.text
|
|
2333
|
+
}] : [];
|
|
2334
|
+
if (block.type !== "image") return [];
|
|
2335
|
+
const version = images.get(block.attachment.attachmentId);
|
|
2336
|
+
if (version === void 0) throw new LlmError("DeepSeek Chat Completions request image is missing", "INVALID_REQUEST");
|
|
2337
|
+
const fileId = fileIds?.get(block.attachment.attachmentId);
|
|
2338
|
+
if (fileIds !== void 0 && fileId === void 0) throw new LlmError("DeepSeek Chat Completions request file id is missing", "INVALID_REQUEST");
|
|
2339
|
+
return [{
|
|
2340
|
+
type: "text",
|
|
2341
|
+
text: requestImageHandleText(block.attachment, version, access(block.attachment))
|
|
2342
|
+
}, fileId === void 0 ? {
|
|
2343
|
+
type: "image_url",
|
|
2344
|
+
image_url: { url: `data:${version.mediaType};base64,${Buffer.from(version.data).toString("base64")}` }
|
|
2345
|
+
} : {
|
|
2346
|
+
type: "file",
|
|
2347
|
+
file_id: fileId
|
|
2348
|
+
}];
|
|
2349
|
+
});
|
|
2350
|
+
if (options.system !== void 0) messages.push({
|
|
2351
|
+
role: "system",
|
|
2352
|
+
content: options.system
|
|
2353
|
+
});
|
|
2354
|
+
for (const message of history) {
|
|
2355
|
+
if (message.role === "developer" || message.content.some((block) => block.type === "tool-addition" || block.type === "tool-removal")) throw new LlmError("DeepSeek Chat Completions does not support native tool updates", "UNSUPPORTED_CONTENT");
|
|
2356
|
+
if (message.role !== "tool") flushImages();
|
|
2357
|
+
switch (message.role) {
|
|
2358
|
+
case "system":
|
|
2359
|
+
messages.push({
|
|
2360
|
+
role: "system",
|
|
2361
|
+
content: text(message.content)
|
|
2362
|
+
});
|
|
2363
|
+
break;
|
|
2364
|
+
case "assistant": {
|
|
2365
|
+
const reasoning = message.content.filter((block) => block.type === "reasoning").map((block) => block.text).join("");
|
|
2366
|
+
const calls = message.content.filter((block) => block.type === "tool-call").map((block) => ({
|
|
2367
|
+
id: block.id,
|
|
2368
|
+
type: "function",
|
|
2369
|
+
function: {
|
|
2370
|
+
name: block.name,
|
|
2371
|
+
arguments: block.arguments
|
|
2372
|
+
}
|
|
2373
|
+
}));
|
|
2374
|
+
messages.push({
|
|
2375
|
+
role: "assistant",
|
|
2376
|
+
content: text(message.content),
|
|
2377
|
+
...reasoning.length === 0 ? {} : { reasoning_content: reasoning },
|
|
2378
|
+
...calls.length === 0 ? {} : { tool_calls: calls }
|
|
2379
|
+
});
|
|
2380
|
+
break;
|
|
2381
|
+
}
|
|
2382
|
+
case "tool": {
|
|
2383
|
+
const content = parts(message.content);
|
|
2384
|
+
messages.push({
|
|
2385
|
+
role: "tool",
|
|
2386
|
+
tool_call_id: message.toolCallId,
|
|
2387
|
+
content: content.filter((part) => part.type === "text").map((part) => part.text).join("") || "(no output)"
|
|
2388
|
+
});
|
|
2389
|
+
pendingImages.push(...content.filter((part) => part.type !== "text"));
|
|
2390
|
+
break;
|
|
2391
|
+
}
|
|
2392
|
+
case "user": {
|
|
2393
|
+
const content = parts(message.content);
|
|
2394
|
+
messages.push({
|
|
2395
|
+
role: "user",
|
|
2396
|
+
content: content.every((part) => part.type === "text") ? content.map((part) => part.text).join("") : content
|
|
2397
|
+
});
|
|
2398
|
+
break;
|
|
2399
|
+
}
|
|
2400
|
+
/* v8 ignore next 2 -- closed-union exhaustiveness guard */
|
|
2401
|
+
default: return assertNever(message);
|
|
2402
|
+
}
|
|
2088
2403
|
}
|
|
2089
|
-
|
|
2090
|
-
|
|
2404
|
+
flushImages();
|
|
2405
|
+
const effort = resolveEffort(options.purpose === "session-title" ? "off" : options.reasoningEffort ?? connection.defaults.reasoningEffort);
|
|
2406
|
+
if (connection.defaults.thinking === "disabled" && effort !== void 0 && effort !== "off") throw new LlmError("DeepSeek deployment has thinking disabled", "UNSUPPORTED_REASONING_EFFORT");
|
|
2407
|
+
if (options.tools?.some((tool) => tool.deferLoading === true)) throw new LlmError("DeepSeek Chat Completions does not support deferred tools", "UNSUPPORTED_CONTENT");
|
|
2408
|
+
const thinking = effort === void 0 ? connection.defaults.thinking : effort === "off" ? "disabled" : "enabled";
|
|
2409
|
+
return {
|
|
2410
|
+
model: options.model,
|
|
2411
|
+
messages,
|
|
2412
|
+
stream: true,
|
|
2413
|
+
stream_options: { include_usage: true },
|
|
2414
|
+
...thinking === void 0 ? {} : { thinking: { type: thinking } },
|
|
2415
|
+
...effort === "low" || effort === "high" || effort === "max" ? { reasoning_effort: effort } : {},
|
|
2416
|
+
...options.maxTokens === void 0 ? {} : { max_tokens: options.maxTokens },
|
|
2417
|
+
...options.temperature === void 0 ? {} : { temperature: options.temperature },
|
|
2418
|
+
...options.stop === void 0 ? {} : { stop: options.stop },
|
|
2419
|
+
...options.tools?.length ? { tools: options.tools.map((tool) => ({
|
|
2420
|
+
type: "function",
|
|
2421
|
+
function: {
|
|
2422
|
+
name: tool.name,
|
|
2423
|
+
description: tool.description,
|
|
2424
|
+
parameters: tool.parameters
|
|
2425
|
+
}
|
|
2426
|
+
})) } : {}
|
|
2427
|
+
};
|
|
2428
|
+
}
|
|
2429
|
+
function resolveEffort(value) {
|
|
2430
|
+
switch (value) {
|
|
2431
|
+
case void 0: return;
|
|
2432
|
+
case "off": return "off";
|
|
2433
|
+
case "low": return "low";
|
|
2434
|
+
case "high": return "high";
|
|
2435
|
+
case "max": return "max";
|
|
2436
|
+
default: throw new LlmError(`DeepSeek Chat Completions does not support reasoning effort ${value}`, "UNSUPPORTED_REASONING_EFFORT");
|
|
2091
2437
|
}
|
|
2092
|
-
|
|
2093
|
-
|
|
2438
|
+
}
|
|
2439
|
+
/**
|
|
2440
|
+
* Parse an SSE byte stream into data payloads. Yields `[DONE]` as the final
|
|
2441
|
+
* value and returns; throws `LlmError('STREAM_CLOSED')` when the stream ends
|
|
2442
|
+
* without it (truncated response — the model call cannot be trusted).
|
|
2443
|
+
* @param stream - raw SSE bytes; reads may split anywhere, including mid-UTF-8 sequence.
|
|
2444
|
+
* @param onComment - optional transport-activity callback; comments never enter the yielded payload stream.
|
|
2445
|
+
* @returns each event's data payload in arrival order, the `[DONE]` sentinel last.
|
|
2446
|
+
*/
|
|
2447
|
+
async function* parseSse(stream, onComment) {
|
|
2448
|
+
const events = stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream({ onComment }));
|
|
2449
|
+
for await (const { data } of events) {
|
|
2450
|
+
yield data;
|
|
2451
|
+
if (data === "[DONE]") return;
|
|
2094
2452
|
}
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2453
|
+
throw new LlmError("SSE stream ended without [DONE]", "STREAM_CLOSED");
|
|
2454
|
+
}
|
|
2455
|
+
//#endregion
|
|
2456
|
+
//#region lib/types/chat-completions/translate.js
|
|
2457
|
+
/**
|
|
2458
|
+
* Translate DeepSeek SSE payloads with one stateful harness block per content, reasoning, or tool
|
|
2459
|
+
* call index. An empty initial reasoning delta does not open a block. Finish reason and the latest
|
|
2460
|
+
* usage are deferred until `[DONE]`, covering both finish-attached and trailing usage-only shapes
|
|
2461
|
+
* while ensuring no chunk follows `finish`.
|
|
2462
|
+
*
|
|
2463
|
+
* Translate DeepSeek wire chunks into the harness `StreamChunk` protocol.
|
|
2464
|
+
* @module dsh-llm-deepseek/translate
|
|
2465
|
+
*/
|
|
2466
|
+
/**
|
|
2467
|
+
* Map the wire finish_reason vocabulary to the harness FinishReason.
|
|
2468
|
+
* @param reason - the wire `finish_reason` string.
|
|
2469
|
+
* @returns the mapped reason; unrecognized values (content_filter, …) become `{kind: 'error'}` with the uppercased value as `code`.
|
|
2470
|
+
*/
|
|
2471
|
+
function mapFinishReason(reason) {
|
|
2472
|
+
switch (reason) {
|
|
2473
|
+
case "stop": return { kind: "stop" };
|
|
2474
|
+
case "tool_calls": return { kind: "tool-calls" };
|
|
2475
|
+
case "length": return { kind: "max-tokens" };
|
|
2476
|
+
default: return {
|
|
2477
|
+
kind: "error",
|
|
2478
|
+
failure: {
|
|
2479
|
+
message: `model stopped: ${reason}`,
|
|
2480
|
+
code: reason.toUpperCase()
|
|
2481
|
+
}
|
|
2482
|
+
};
|
|
2101
2483
|
}
|
|
2102
|
-
|
|
2103
|
-
|
|
2484
|
+
}
|
|
2485
|
+
/**
|
|
2486
|
+
* Map wire usage fields. DeepSeek's `prompt_tokens` INCLUDES cache hits
|
|
2487
|
+
* (`prompt_tokens = prompt_cache_hit_tokens + prompt_cache_miss_tokens`,
|
|
2488
|
+
* api/create-chat-completion); the harness TokenUsage convention is
|
|
2489
|
+
* DISJOINT counts, so cache reads are subtracted out of `inputTokens`.
|
|
2490
|
+
* @param usage - wire usage from the finish chunk or the trailing usage-only chunk.
|
|
2491
|
+
* @returns disjoint harness counts; an exact total is present only when the
|
|
2492
|
+
* aggregate prompt/completion counters are valid and agree with any wire total.
|
|
2493
|
+
*/
|
|
2494
|
+
function mapUsage(usage) {
|
|
2495
|
+
const cacheRead = usage.prompt_tokens_details?.cached_tokens ?? usage.prompt_cache_hit_tokens;
|
|
2496
|
+
const reasoning = usage.completion_tokens_details?.reasoning_tokens;
|
|
2497
|
+
const combined = usage.prompt_tokens + usage.completion_tokens;
|
|
2498
|
+
const hasExactTotal = Number.isSafeInteger(usage.prompt_tokens) && usage.prompt_tokens >= 0 && Number.isSafeInteger(usage.completion_tokens) && usage.completion_tokens >= 0 && Number.isSafeInteger(combined) && (usage.total_tokens === void 0 || usage.total_tokens === combined);
|
|
2499
|
+
return {
|
|
2500
|
+
inputTokens: usage.prompt_tokens - (cacheRead ?? 0),
|
|
2501
|
+
outputTokens: usage.completion_tokens,
|
|
2502
|
+
...hasExactTotal ? { totalTokens: combined } : {},
|
|
2503
|
+
...cacheRead !== void 0 ? { cacheReadTokens: cacheRead } : {},
|
|
2504
|
+
...reasoning !== void 0 ? { reasoningTokens: reasoning } : {}
|
|
2505
|
+
};
|
|
2506
|
+
}
|
|
2507
|
+
/**
|
|
2508
|
+
* Accept one streamed identity field for a tool call. `id` and `name` are
|
|
2509
|
+
* identity, not accumulation: the wire sends each once, on the call's first
|
|
2510
|
+
* delta. A continuation delta that re-sends the field empty — or `null`, which
|
|
2511
|
+
* some OpenAI-compatible gateways fill in — means "no update", never "clear".
|
|
2512
|
+
* @param current - the identity established by an earlier delta of this call.
|
|
2513
|
+
* @param incoming - the field as parsed from this delta. The wire type is a
|
|
2514
|
+
* claim about a remote encoder, so anything but a non-empty string leaves the
|
|
2515
|
+
* established value alone rather than overwriting it.
|
|
2516
|
+
* @returns the identity in force after this delta.
|
|
2517
|
+
*/
|
|
2518
|
+
function acceptIdentity(current, incoming) {
|
|
2519
|
+
return typeof incoming === "string" && incoming.length > 0 ? incoming : current;
|
|
2520
|
+
}
|
|
2521
|
+
/** Assemble the final ContentBlock for one open block. */
|
|
2522
|
+
function closeBlock(block) {
|
|
2523
|
+
switch (block.kind) {
|
|
2524
|
+
case "text": return {
|
|
2525
|
+
type: "text",
|
|
2526
|
+
text: block.text
|
|
2527
|
+
};
|
|
2528
|
+
case "reasoning": return {
|
|
2529
|
+
type: "reasoning",
|
|
2530
|
+
text: block.text
|
|
2531
|
+
};
|
|
2532
|
+
case "tool-call": return {
|
|
2533
|
+
type: "tool-call",
|
|
2534
|
+
id: brandString(block.callId ?? ""),
|
|
2535
|
+
name: block.name ?? "",
|
|
2536
|
+
arguments: block.text
|
|
2537
|
+
};
|
|
2104
2538
|
}
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2539
|
+
}
|
|
2540
|
+
/**
|
|
2541
|
+
* Consume SSE data payloads (ending with `[DONE]`) and yield StreamChunks.
|
|
2542
|
+
* Malformed JSON payloads abort the stream with `MALFORMED_RESPONSE`.
|
|
2543
|
+
* @param payloads - SSE data payloads from {@link parseSse}, `[DONE]`-terminated.
|
|
2544
|
+
* @returns deltas as they arrive; `block-end`s, `usage`, and `finish` are all deferred to the `[DONE]` sentinel.
|
|
2545
|
+
* A `stop` (or absent) finish with no opened blocks is a degenerate provider completion and maps to an
|
|
2546
|
+
* `EMPTY_RESPONSE` error finish instead of a successful empty message.
|
|
2547
|
+
*/
|
|
2548
|
+
async function* translate(payloads) {
|
|
2549
|
+
let nextIndex = 0;
|
|
2550
|
+
let textBlock;
|
|
2551
|
+
let reasoningBlock;
|
|
2552
|
+
const toolBlocks = /* @__PURE__ */ new Map();
|
|
2553
|
+
const order = [];
|
|
2554
|
+
let pendingFinish;
|
|
2555
|
+
let pendingUsage;
|
|
2556
|
+
function open(kind) {
|
|
2557
|
+
const block = {
|
|
2558
|
+
index: nextIndex++,
|
|
2559
|
+
kind,
|
|
2560
|
+
text: ""
|
|
2110
2561
|
};
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
const watchdog = __addDisposableResource(env_1, idleWatchdog(options.signal === void 0 ? consumer.signal : AbortSignal.any([consumer.signal, options.signal]), connection.streamIdleTimeoutMs, "MESSAGES_IDLE"), false);
|
|
2114
|
-
const iterator = this.request(options, connection, watchdog.signal, () => {
|
|
2115
|
-
watchdog.pulse();
|
|
2116
|
-
});
|
|
2117
|
-
try {
|
|
2118
|
-
while (true) {
|
|
2119
|
-
const next = await watchdog.next(iterator);
|
|
2120
|
-
if (next.done) return;
|
|
2121
|
-
yield next.value;
|
|
2122
|
-
}
|
|
2123
|
-
} catch (error) {
|
|
2124
|
-
if (timeoutOf(watchdog.signal, "MESSAGES_IDLE") !== void 0) throw new LlmError("DeepSeek Messages stream idle timeout", "TIMEOUT", { cause: error });
|
|
2125
|
-
if (options.signal?.aborted) throw new LlmError("DeepSeek Messages request aborted", "ABORTED", { cause: error });
|
|
2126
|
-
if (error instanceof LlmError) throw error;
|
|
2127
|
-
throw new LlmError("DeepSeek Messages transport failed", "TRANSPORT", { cause: error });
|
|
2128
|
-
} finally {
|
|
2129
|
-
consumer.abort();
|
|
2130
|
-
try {
|
|
2131
|
-
await iterator.return(void 0);
|
|
2132
|
-
} catch (_abortedRequestCleanup) {}
|
|
2133
|
-
}
|
|
2134
|
-
} catch (e_1) {
|
|
2135
|
-
env_1.error = e_1;
|
|
2136
|
-
env_1.hasError = true;
|
|
2137
|
-
} finally {
|
|
2138
|
-
__disposeResources(env_1);
|
|
2139
|
-
}
|
|
2562
|
+
order.push(block);
|
|
2563
|
+
return block;
|
|
2140
2564
|
}
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2565
|
+
for await (const payload of payloads) {
|
|
2566
|
+
if (payload === "[DONE]") {
|
|
2567
|
+
for (const block of order) yield {
|
|
2568
|
+
type: "block-end",
|
|
2569
|
+
index: block.index,
|
|
2570
|
+
block: closeBlock(block)
|
|
2571
|
+
};
|
|
2572
|
+
if (pendingUsage) yield {
|
|
2573
|
+
type: "usage",
|
|
2574
|
+
usage: pendingUsage
|
|
2575
|
+
};
|
|
2576
|
+
const reason = pendingFinish ?? { kind: "stop" };
|
|
2577
|
+
yield {
|
|
2578
|
+
type: "finish",
|
|
2579
|
+
reason: reason.kind === "stop" && order.length === 0 ? {
|
|
2580
|
+
kind: "error",
|
|
2581
|
+
failure: {
|
|
2582
|
+
message: "model returned a completed response with no content",
|
|
2583
|
+
code: EMPTY_RESPONSE_CODE
|
|
2584
|
+
}
|
|
2585
|
+
} : reason
|
|
2586
|
+
};
|
|
2587
|
+
return;
|
|
2588
|
+
}
|
|
2589
|
+
let chunk;
|
|
2145
2590
|
try {
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2591
|
+
chunk = JSON.parse(payload);
|
|
2592
|
+
} catch (_invalidProviderJson) {
|
|
2593
|
+
throw new LlmError(`malformed SSE payload: ${payload.slice(0, 120)}`, "MALFORMED_RESPONSE");
|
|
2594
|
+
}
|
|
2595
|
+
for (const choice of chunk.choices ?? []) {
|
|
2596
|
+
const delta = choice.delta;
|
|
2597
|
+
const reasoning = delta?.reasoning_content;
|
|
2598
|
+
if (typeof reasoning === "string" && reasoning.length > 0) {
|
|
2599
|
+
if (!reasoningBlock) {
|
|
2600
|
+
reasoningBlock = open("reasoning");
|
|
2601
|
+
yield {
|
|
2602
|
+
type: "block-start",
|
|
2603
|
+
index: reasoningBlock.index,
|
|
2604
|
+
blockType: "reasoning"
|
|
2605
|
+
};
|
|
2161
2606
|
}
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
error
|
|
2179
|
-
});
|
|
2180
|
-
});
|
|
2181
|
-
signal.throwIfAborted();
|
|
2182
|
-
const betas = [...fileIds !== void 0 && fileIds.size > 0 ? [MESSAGES_FILES_BETA] : [], ...body.messages.some((message) => message.content.some((block) => block.type === "tool_addition" || block.type === "tool_removal")) ? [MESSAGES_TOOL_CHANGES_BETA] : []];
|
|
2183
|
-
const response = await fetch(`${messagesApiRoot(connection.baseURL)}/messages`, {
|
|
2184
|
-
method: "POST",
|
|
2185
|
-
signal,
|
|
2186
|
-
body: extensions.payload,
|
|
2187
|
-
redirect: "error",
|
|
2188
|
-
headers: {
|
|
2189
|
-
...attributionHeaders(),
|
|
2190
|
-
"content-type": "application/json",
|
|
2191
|
-
"accept": "text/event-stream",
|
|
2192
|
-
...auth.headers,
|
|
2193
|
-
"anthropic-version": "2023-06-01",
|
|
2194
|
-
...betas.length === 0 ? {} : { "anthropic-beta": betas.join(",") },
|
|
2195
|
-
"x-deepseek-harness-user-id": this.dependencies.resolveUserId(),
|
|
2196
|
-
...options.sessionId === void 0 ? {} : { "x-deepseek-harness-session-id": String(options.sessionId) },
|
|
2197
|
-
...options.purpose === "compaction" ? { "x-deepseek-harness-compact": "1" } : {}
|
|
2198
|
-
}
|
|
2199
|
-
});
|
|
2200
|
-
if (!response.ok) {
|
|
2201
|
-
const text = await response.text();
|
|
2202
|
-
let raw;
|
|
2203
|
-
try {
|
|
2204
|
-
raw = JSON.parse(text);
|
|
2205
|
-
} catch (_nonJsonGatewayError) {}
|
|
2206
|
-
const detail = providerErrorDetail(raw);
|
|
2207
|
-
if (await files.retry(detail)) continue;
|
|
2208
|
-
const failure = providerError(raw, response.status, response.headers);
|
|
2209
|
-
throw new LlmError(files.errorMessage(response.status, failure.message, detail), failure.code, {
|
|
2210
|
-
...failure.failure,
|
|
2211
|
-
cause: new Error(text)
|
|
2212
|
-
});
|
|
2607
|
+
reasoningBlock.text += reasoning;
|
|
2608
|
+
yield {
|
|
2609
|
+
type: "reasoning-delta",
|
|
2610
|
+
index: reasoningBlock.index,
|
|
2611
|
+
text: reasoning
|
|
2612
|
+
};
|
|
2613
|
+
}
|
|
2614
|
+
const content = delta?.content;
|
|
2615
|
+
if (typeof content === "string" && content.length > 0) {
|
|
2616
|
+
if (!textBlock) {
|
|
2617
|
+
textBlock = open("text");
|
|
2618
|
+
yield {
|
|
2619
|
+
type: "block-start",
|
|
2620
|
+
index: textBlock.index,
|
|
2621
|
+
blockType: "text"
|
|
2622
|
+
};
|
|
2213
2623
|
}
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2624
|
+
textBlock.text += content;
|
|
2625
|
+
yield {
|
|
2626
|
+
type: "text-delta",
|
|
2627
|
+
index: textBlock.index,
|
|
2628
|
+
text: content
|
|
2629
|
+
};
|
|
2218
2630
|
}
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2631
|
+
for (const call of delta?.tool_calls ?? []) {
|
|
2632
|
+
let block = toolBlocks.get(call.index);
|
|
2633
|
+
if (!block) {
|
|
2634
|
+
block = open("tool-call");
|
|
2635
|
+
toolBlocks.set(call.index, block);
|
|
2636
|
+
yield {
|
|
2637
|
+
type: "block-start",
|
|
2638
|
+
index: block.index,
|
|
2639
|
+
blockType: "tool-call"
|
|
2640
|
+
};
|
|
2226
2641
|
}
|
|
2227
|
-
|
|
2642
|
+
block.callId = acceptIdentity(block.callId, call.id);
|
|
2643
|
+
block.name = acceptIdentity(block.name, call.function?.name);
|
|
2644
|
+
const fragment = call.function?.arguments ?? "";
|
|
2645
|
+
block.text += fragment;
|
|
2646
|
+
yield {
|
|
2647
|
+
type: "tool-call-delta",
|
|
2648
|
+
index: block.index,
|
|
2649
|
+
id: brandString(block.callId ?? ""),
|
|
2650
|
+
...block.name !== void 0 ? { name: block.name } : {},
|
|
2651
|
+
argumentsDelta: fragment
|
|
2652
|
+
};
|
|
2228
2653
|
}
|
|
2229
|
-
|
|
2654
|
+
if (typeof choice.finish_reason === "string") pendingFinish = mapFinishReason(choice.finish_reason);
|
|
2230
2655
|
}
|
|
2656
|
+
if (chunk.usage) pendingUsage = mapUsage(chunk.usage);
|
|
2657
|
+
}
|
|
2658
|
+
throw new LlmError("SSE payload stream ended without [DONE]", "STREAM_CLOSED");
|
|
2659
|
+
}
|
|
2660
|
+
//#endregion
|
|
2661
|
+
//#region lib/types/chat-completions/adapter.js
|
|
2662
|
+
const chatCompletions = {
|
|
2663
|
+
name: "Chat Completions",
|
|
2664
|
+
files: "chat-completions",
|
|
2665
|
+
endpoint: (baseURL) => `${baseURL.replace(/\/+$/u, "")}/chat/completions`,
|
|
2666
|
+
prepare: (...args) => ({
|
|
2667
|
+
body: serialize(...args),
|
|
2668
|
+
headers: {}
|
|
2669
|
+
}),
|
|
2670
|
+
translate: (stream, activity) => translate(parseSse(stream, activity))
|
|
2671
|
+
};
|
|
2672
|
+
/** DeepSeek OpenAI-compatible transport with raw reasoning replay and Files recovery. */
|
|
2673
|
+
var DeepSeekChatCompletionsAdapter = class extends DeepSeekProtocolAdapter {
|
|
2674
|
+
/** @param dependencies - explicit API root, request authentication, defaults, and Host services. */
|
|
2675
|
+
constructor(dependencies) {
|
|
2676
|
+
super(dependencies, chatCompletions);
|
|
2231
2677
|
}
|
|
2232
2678
|
};
|
|
2233
2679
|
//#endregion
|
|
@@ -2275,4 +2721,4 @@ function registerDeepSeekProvider(ctx, provider, dependencies) {
|
|
|
2275
2721
|
});
|
|
2276
2722
|
}
|
|
2277
2723
|
//#endregion
|
|
2278
|
-
export { Config, DEFAULT_CONTEXT_WINDOW, DEFAULT_FILES_API_TIMEOUT_MS, DEFAULT_FILE_EXPIRY_SECONDS, DEFAULT_FILE_QUOTA_CLEANUP_BATCH, DEFAULT_FILE_REFRESH_MARGIN_SECONDS, DEFAULT_IMAGE_OFFLOAD_BYTE_QUANTUM, DEFAULT_IMAGE_OFFLOAD_COUNT_QUANTUM, DEFAULT_INLINE_IMAGE_OFFLOAD_BYTE_QUANTUM, DEFAULT_LOW_DETAIL_IMAGE_PIXEL_BUDGET, DEFAULT_MAX_IMAGES_PER_REQUEST, DEFAULT_MAX_INLINE_REQUEST_IMAGE_BYTES, DEFAULT_MAX_REQUEST_FILES_BYTES, DEFAULT_MAX_TOKENS, DEFAULT_REQUEST_IMAGE_MAX_BYTES, DEFAULT_STREAM_IDLE_TIMEOUT_MS, DeepSeekAdapter, DeepSeekFileId, DeepSeekFileStore, DeepSeekFilesClient, DeepSeekUploadIndex, MAX_FILE_EXPIRY_SECONDS, MAX_FILE_UPLOAD_BYTES, MAX_IMAGE_BYTES, MAX_STORED_FILE_BYTES, MAX_STORED_FILE_COUNT, MIN_FILE_EXPIRY_SECONDS, PUBLIC_BASE_URL, REQUEST_IMAGE_MAX_DIMENSION, catalogModelInfo, deepSeekConfigFields, deepSeekFileScope, deepSeekImageRequestPricing, deepSeekImageTokens, deepSeekRequestImageDimensions, plainOptions, registerDeepSeekProvider, resolveAdapterOptions, resolveRequestImageMaxBytes, resolveRequestImageTarget };
|
|
2724
|
+
export { Config, DEFAULT_CONTEXT_WINDOW, DEFAULT_FILES_API_TIMEOUT_MS, DEFAULT_FILE_EXPIRY_SECONDS, DEFAULT_FILE_QUOTA_CLEANUP_BATCH, DEFAULT_FILE_REFRESH_MARGIN_SECONDS, DEFAULT_IMAGE_OFFLOAD_BYTE_QUANTUM, DEFAULT_IMAGE_OFFLOAD_COUNT_QUANTUM, DEFAULT_INLINE_IMAGE_OFFLOAD_BYTE_QUANTUM, DEFAULT_LOW_DETAIL_IMAGE_PIXEL_BUDGET, DEFAULT_MAX_IMAGES_PER_REQUEST, DEFAULT_MAX_INLINE_REQUEST_IMAGE_BYTES, DEFAULT_MAX_REQUEST_FILES_BYTES, DEFAULT_MAX_TOKENS, DEFAULT_REQUEST_IMAGE_MAX_BYTES, DEFAULT_STREAM_IDLE_TIMEOUT_MS, DeepSeekAdapter, DeepSeekChatCompletionsAdapter, DeepSeekFileId, DeepSeekFileStore, DeepSeekFilesClient, DeepSeekUploadIndex, MAX_FILE_EXPIRY_SECONDS, MAX_FILE_UPLOAD_BYTES, MAX_IMAGE_BYTES, MAX_STORED_FILE_BYTES, MAX_STORED_FILE_COUNT, MIN_FILE_EXPIRY_SECONDS, PUBLIC_BASE_URL, REQUEST_IMAGE_MAX_DIMENSION, catalogModelInfo, deepSeekConfigFields, deepSeekFileScope, deepSeekImageRequestPricing, deepSeekImageTokens, deepSeekRequestImageDimensions, plainOptions, registerDeepSeekProvider, resolveAdapterOptions, resolveRequestImageMaxBytes, resolveRequestImageTarget };
|