@deepseek-ai/dsh-llm 0.1.2-alpha.5 → 0.1.3-alpha.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/README.i18n.yaml +2 -2
- package/README.md +7 -4
- package/README.zh.md +7 -4
- package/lib/index.js +548 -6
- package/lib/typert.host.js +20 -5
- package/lib/typert.remote-client.js +3 -3
- package/lib/types/assistant-stream.d.ts +166 -0
- package/lib/types/assistant-stream.js +458 -0
- package/lib/types/brand.d.ts +8 -0
- package/lib/types/brand.js +8 -0
- package/lib/types/content.d.ts +26 -1
- package/lib/types/content.js +63 -0
- package/lib/types/index.d.ts +14 -0
- package/lib/types/index.js +46 -7
- package/lib/types/types.d.ts +14 -1
- package/package.json +13 -9
package/lib/types/content.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Content-block structure helpers. @module @deepseek-ai/dsh-llm/content */
|
|
2
2
|
import type { ContentBlock } from './types.ts';
|
|
3
3
|
import type { Message } from './message.ts';
|
|
4
|
-
import type { AttachmentStore, ImageAttachmentRef, RequestImageAttachment } from '@deepseek-ai/dsh-attachment';
|
|
4
|
+
import type { AttachmentStore, FileAttachmentRef, ImageAttachmentRef, RequestImageAttachment } from '@deepseek-ai/dsh-attachment';
|
|
5
5
|
/** Execution-world path that model tools can use to read one normalized attachment. */
|
|
6
6
|
export interface ImageAttachmentAccess {
|
|
7
7
|
/** Absolute path to immutable normalized bytes; callers must treat it as read-only. */
|
|
@@ -57,6 +57,31 @@ export declare function offloadedImageText(ref: ImageAttachmentRef, access?: Ima
|
|
|
57
57
|
* @returns whether any nested block is an image.
|
|
58
58
|
*/
|
|
59
59
|
export declare function contentHasImage(content: readonly ContentBlock[]): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* True when typed model content contains a file block, walking nested
|
|
62
|
+
* tool-result content on the same recursion every file policy shares.
|
|
63
|
+
* @param content - typed model content blocks.
|
|
64
|
+
* @returns whether any nested block is a file.
|
|
65
|
+
*/
|
|
66
|
+
export declare function contentHasFile(content: readonly ContentBlock[]): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Stable model-facing handle for one durable file reference: the address of
|
|
69
|
+
* the verbatim stored copy and the instruction to read it on demand. This is
|
|
70
|
+
* the only representation a provider ever receives for a file.
|
|
71
|
+
* @param ref - durable verbatim file reference.
|
|
72
|
+
* @param readonlyPath - execution-world path of the stored copy, when resolvable.
|
|
73
|
+
* @returns deterministic handle text naming the file, its size, and its address.
|
|
74
|
+
*/
|
|
75
|
+
export declare function fileHandleText(ref: FileAttachmentRef, readonlyPath: string | undefined): string;
|
|
76
|
+
/**
|
|
77
|
+
* Project durable file history into deterministic handle text for every model
|
|
78
|
+
* route. Unlike images, no provider receives file blocks natively, so this
|
|
79
|
+
* projection is unconditional in request assembly.
|
|
80
|
+
* @param messages - complete request history.
|
|
81
|
+
* @param resolvePath - resolve one reference's current execution-world read path.
|
|
82
|
+
* @returns the original list without files, otherwise shallow message copies with handle text.
|
|
83
|
+
*/
|
|
84
|
+
export declare function projectFilesToText(messages: readonly Message[], resolvePath: (ref: FileAttachmentRef) => string | undefined): readonly Message[];
|
|
60
85
|
/** Byte accounting and quantized removal policy for one request representation. */
|
|
61
86
|
export interface RequestImageOffloadPolicy {
|
|
62
87
|
/** Image count accepted by the route; omission leaves count unbounded. */
|
package/lib/types/content.js
CHANGED
|
@@ -89,6 +89,69 @@ export function contentHasImage(content) {
|
|
|
89
89
|
return content.some(block => block.type === 'image'
|
|
90
90
|
|| (block.type === 'tool-result' && contentHasImage(block.content)));
|
|
91
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* True when typed model content contains a file block, walking nested
|
|
94
|
+
* tool-result content on the same recursion every file policy shares.
|
|
95
|
+
* @param content - typed model content blocks.
|
|
96
|
+
* @returns whether any nested block is a file.
|
|
97
|
+
*/
|
|
98
|
+
export function contentHasFile(content) {
|
|
99
|
+
return content.some(block => block.type === 'file'
|
|
100
|
+
|| (block.type === 'tool-result' && contentHasFile(block.content)));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Stable model-facing handle for one durable file reference: the address of
|
|
104
|
+
* the verbatim stored copy and the instruction to read it on demand. This is
|
|
105
|
+
* the only representation a provider ever receives for a file.
|
|
106
|
+
* @param ref - durable verbatim file reference.
|
|
107
|
+
* @param readonlyPath - execution-world path of the stored copy, when resolvable.
|
|
108
|
+
* @returns deterministic handle text naming the file, its size, and its address.
|
|
109
|
+
*/
|
|
110
|
+
export function fileHandleText(ref, readonlyPath) {
|
|
111
|
+
const digest = String(ref.attachmentId).slice('sha256:'.length, 'sha256:'.length + 8);
|
|
112
|
+
const identity = `File ${quoted(ref.name)} (${ref.bytes} bytes, sha256:${digest})`;
|
|
113
|
+
if (readonlyPath === undefined) {
|
|
114
|
+
return `[${identity} was uploaded, but the current execution environment cannot access a readable path. Report that limitation if its contents are needed; do not claim to have read it.]`;
|
|
115
|
+
}
|
|
116
|
+
return `[${identity}: verbatim read-only copy saved at ${quoted(readonlyPath)}. Read that path with your file tools when its contents are needed; copy it to a writable location before modifying it. When delegating file work, include this saved path in the delegation prompt; only subagents sharing this execution environment can read it.]`;
|
|
117
|
+
}
|
|
118
|
+
/** Replace every file occurrence, including nested tool results, with handle text. */
|
|
119
|
+
function replaceFilesWithHandles(blocks, resolvePath) {
|
|
120
|
+
let next;
|
|
121
|
+
for (const [index, block] of blocks.entries()) {
|
|
122
|
+
if (block.type === 'file') {
|
|
123
|
+
next ??= blocks.slice(0, index);
|
|
124
|
+
next.push({ type: 'text', text: fileHandleText(block.attachment, resolvePath(block.attachment)) });
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (block.type === 'tool-result') {
|
|
128
|
+
const content = replaceFilesWithHandles(block.content, resolvePath);
|
|
129
|
+
if (content !== block.content) {
|
|
130
|
+
next ??= blocks.slice(0, index);
|
|
131
|
+
next.push({ ...block, content });
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
next?.push(block);
|
|
136
|
+
}
|
|
137
|
+
return next ?? blocks;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Project durable file history into deterministic handle text for every model
|
|
141
|
+
* route. Unlike images, no provider receives file blocks natively, so this
|
|
142
|
+
* projection is unconditional in request assembly.
|
|
143
|
+
* @param messages - complete request history.
|
|
144
|
+
* @param resolvePath - resolve one reference's current execution-world read path.
|
|
145
|
+
* @returns the original list without files, otherwise shallow message copies with handle text.
|
|
146
|
+
*/
|
|
147
|
+
export function projectFilesToText(messages, resolvePath) {
|
|
148
|
+
if (!messages.some(message => contentHasFile(message.content)))
|
|
149
|
+
return messages;
|
|
150
|
+
return messages.map((message) => {
|
|
151
|
+
const content = replaceFilesWithHandles(message.content, resolvePath);
|
|
152
|
+
return content === message.content ? message : { ...message, content };
|
|
153
|
+
});
|
|
154
|
+
}
|
|
92
155
|
/** Base64 length of raw image bytes, including padding. */
|
|
93
156
|
function base64Length(bytes) {
|
|
94
157
|
return Math.ceil(bytes / 3) * 4;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -12,12 +12,14 @@ import type { ResolvedRetryPolicy } from './retry-policy.ts';
|
|
|
12
12
|
import type { ProviderRequestId } from './brand.ts';
|
|
13
13
|
import type { LlmCallConfig, LlmCallConfigAdapterDefaults } from './call-config.ts';
|
|
14
14
|
import { HarnessError } from './error.ts';
|
|
15
|
+
import type { FileAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
15
16
|
export * from './attribution.ts';
|
|
16
17
|
export * from './brand.ts';
|
|
17
18
|
export * from './error.ts';
|
|
18
19
|
export * from './api-key.ts';
|
|
19
20
|
export * from './types.ts';
|
|
20
21
|
export * from './content.ts';
|
|
22
|
+
export * from './assistant-stream.ts';
|
|
21
23
|
export * from './message.ts';
|
|
22
24
|
export * from './retry-policy.ts';
|
|
23
25
|
export { BlockAssembler } from './assembler.ts';
|
|
@@ -322,6 +324,13 @@ export declare class LlmRuntime extends TypertRemoteService {
|
|
|
322
324
|
* @returns the owning adapter's image pricing for the route, when declared.
|
|
323
325
|
*/
|
|
324
326
|
imageRequestPricing(provider: string, model: string): LlmImageRequestPricing | undefined;
|
|
327
|
+
/**
|
|
328
|
+
* Resolve the exact text one durable file occurrence contributes to every
|
|
329
|
+
* provider request in the current execution environment.
|
|
330
|
+
* @param ref - durable verbatim file reference from model history.
|
|
331
|
+
* @returns the same deterministic handle text used at adapter dispatch.
|
|
332
|
+
*/
|
|
333
|
+
fileRequestText(ref: FileAttachmentRef): string;
|
|
325
334
|
/** Detach typed adapter-owned modality metadata. */
|
|
326
335
|
private detachedModalities;
|
|
327
336
|
/**
|
|
@@ -370,6 +379,11 @@ export declare class LlmRuntime extends TypertRemoteService {
|
|
|
370
379
|
private registration;
|
|
371
380
|
/** Remove replay state whose historical route is owned by another adapter. */
|
|
372
381
|
private forAdapter;
|
|
382
|
+
/**
|
|
383
|
+
* Resolve the current execution-world read path of one durable file
|
|
384
|
+
* reference through the mounted attachment and filesystem providers.
|
|
385
|
+
*/
|
|
386
|
+
private fileReadPath;
|
|
373
387
|
/**
|
|
374
388
|
* Final adapter boundary. Adapter selection, dispatch, iterator construction,
|
|
375
389
|
* and iteration failures become one terminal failure chunk. Middleware and
|
package/lib/types/index.js
CHANGED
|
@@ -47,13 +47,14 @@ import { callConfigEquals } from "./call-config.js";
|
|
|
47
47
|
import { HarnessError, INVALID_CREDENTIAL_CODE } from "./error.js";
|
|
48
48
|
import { normalizeLlmFailure } from "./adapter-failure.js";
|
|
49
49
|
import { normalizeApiKey } from "./api-key.js";
|
|
50
|
-
import { contentHasImage, projectImagesForTextModel } from "./content.js";
|
|
50
|
+
import { contentHasFile, contentHasImage, fileHandleText, projectFilesToText, projectImagesForTextModel, } from "./content.js";
|
|
51
51
|
export * from "./attribution.js";
|
|
52
52
|
export * from "./brand.js";
|
|
53
53
|
export * from "./error.js";
|
|
54
54
|
export * from "./api-key.js";
|
|
55
55
|
export * from "./types.js";
|
|
56
56
|
export * from "./content.js";
|
|
57
|
+
export * from "./assistant-stream.js";
|
|
57
58
|
export * from "./message.js";
|
|
58
59
|
export * from "./retry-policy.js";
|
|
59
60
|
export { BlockAssembler } from "./assembler.js";
|
|
@@ -529,6 +530,15 @@ let LlmRuntime = (() => {
|
|
|
529
530
|
imageRequestPricing(provider, model) {
|
|
530
531
|
return this.adapters.get(provider)?.adapter.imageRequestPricing(provider, model);
|
|
531
532
|
}
|
|
533
|
+
/**
|
|
534
|
+
* Resolve the exact text one durable file occurrence contributes to every
|
|
535
|
+
* provider request in the current execution environment.
|
|
536
|
+
* @param ref - durable verbatim file reference from model history.
|
|
537
|
+
* @returns the same deterministic handle text used at adapter dispatch.
|
|
538
|
+
*/
|
|
539
|
+
fileRequestText(ref) {
|
|
540
|
+
return fileHandleText(ref, this.fileReadPath(ref));
|
|
541
|
+
}
|
|
532
542
|
/** Detach typed adapter-owned modality metadata. */
|
|
533
543
|
detachedModalities(modalities) {
|
|
534
544
|
return modalities === undefined ? undefined : [...modalities];
|
|
@@ -769,6 +779,27 @@ let LlmRuntime = (() => {
|
|
|
769
779
|
const filtered = { ...options, messages };
|
|
770
780
|
return Object.isFrozen(options) ? deepFreeze(filtered) : filtered;
|
|
771
781
|
}
|
|
782
|
+
/**
|
|
783
|
+
* Resolve the current execution-world read path of one durable file
|
|
784
|
+
* reference through the mounted attachment and filesystem providers.
|
|
785
|
+
*/
|
|
786
|
+
fileReadPath(ref) {
|
|
787
|
+
let hostPath;
|
|
788
|
+
try {
|
|
789
|
+
hostPath = this.ctx.get('attachments')?.fileHostPath(ref);
|
|
790
|
+
}
|
|
791
|
+
catch {
|
|
792
|
+
// A malformed durable reference degrades this occurrence to the no-path
|
|
793
|
+
// handle instead of failing every later request over the same log.
|
|
794
|
+
return undefined;
|
|
795
|
+
}
|
|
796
|
+
if (hostPath === undefined)
|
|
797
|
+
return undefined;
|
|
798
|
+
// Structural face: dsh-llm cannot depend on the filesystem package, and
|
|
799
|
+
// only this one mapping method is consumed.
|
|
800
|
+
const fs = this.ctx.get('fs');
|
|
801
|
+
return fs?.processPathFromHostPath(hostPath);
|
|
802
|
+
}
|
|
772
803
|
/**
|
|
773
804
|
* Final adapter boundary. Adapter selection, dispatch, iterator construction,
|
|
774
805
|
* and iteration failures become one terminal failure chunk. Middleware and
|
|
@@ -801,13 +832,21 @@ let LlmRuntime = (() => {
|
|
|
801
832
|
: Object.isFrozen(options)
|
|
802
833
|
? deepFreeze({ ...options, ...resolvedConfig })
|
|
803
834
|
: { ...options, ...resolvedConfig };
|
|
804
|
-
|
|
835
|
+
// Files are never dispatched natively: every route receives handle text.
|
|
836
|
+
let projectedMessages = resolvedOptions.messages;
|
|
837
|
+
if (projectedMessages.some(message => contentHasFile(message.content))) {
|
|
838
|
+
projectedMessages = projectFilesToText(projectedMessages, ref => this.fileReadPath(ref));
|
|
839
|
+
}
|
|
840
|
+
if (modelInfo.inputModalities !== undefined
|
|
805
841
|
&& !modelInfo.inputModalities.includes('image')
|
|
806
|
-
&&
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
842
|
+
&& projectedMessages.some(message => contentHasImage(message.content))) {
|
|
843
|
+
projectedMessages = projectImagesForTextModel(projectedMessages);
|
|
844
|
+
}
|
|
845
|
+
const projectedOptions = projectedMessages === resolvedOptions.messages
|
|
846
|
+
? resolvedOptions
|
|
847
|
+
: Object.isFrozen(resolvedOptions)
|
|
848
|
+
? deepFreeze({ ...resolvedOptions, messages: projectedMessages })
|
|
849
|
+
: { ...resolvedOptions, messages: projectedMessages };
|
|
811
850
|
const stream = dispatch(this.forAdapter(projectedOptions, adapter));
|
|
812
851
|
iterator = stream[Symbol.asyncIterator]();
|
|
813
852
|
}
|
package/lib/types/types.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* mapped interfaces make the content, source, and finish unions extensible.
|
|
5
5
|
*/
|
|
6
6
|
import type { Branded } from '@deepseek-ai/dsh-brand';
|
|
7
|
-
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
7
|
+
import type { FileAttachmentRef, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
8
8
|
import type { ToolCallId, ProviderRequestId, ReasoningEffortId } from './brand.ts';
|
|
9
9
|
import type { Message } from './message.ts';
|
|
10
10
|
declare module '@deepseek-ai/cordis' {
|
|
@@ -56,6 +56,18 @@ export interface ImageBlock {
|
|
|
56
56
|
/** Immutable bytes and intrinsic display metadata owned by the attachment service. */
|
|
57
57
|
attachment: ImageAttachmentRef;
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* A durable verbatim file reference, valid in user content. Files never reach
|
|
61
|
+
* a provider natively: request assembly projects every occurrence to
|
|
62
|
+
* deterministic handle text (name, byte size, and the read-only saved path),
|
|
63
|
+
* so adapters and providers see text in its place while the durable log keeps
|
|
64
|
+
* the structured reference for presentation and authorization.
|
|
65
|
+
*/
|
|
66
|
+
export interface FileBlock {
|
|
67
|
+
type: 'file';
|
|
68
|
+
/** Immutable verbatim bytes and display metadata owned by the attachment service. */
|
|
69
|
+
attachment: FileAttachmentRef;
|
|
70
|
+
}
|
|
59
71
|
/** A tool invocation requested by the model. */
|
|
60
72
|
export interface ToolCallBlock {
|
|
61
73
|
type: 'tool-call';
|
|
@@ -80,6 +92,7 @@ export interface ContentBlockMap {
|
|
|
80
92
|
'text': TextBlock;
|
|
81
93
|
'reasoning': ReasoningBlock;
|
|
82
94
|
'image': ImageBlock;
|
|
95
|
+
'file': FileBlock;
|
|
83
96
|
'tool-call': ToolCallBlock;
|
|
84
97
|
'tool-result': ToolResultBlock;
|
|
85
98
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-llm",
|
|
3
3
|
"description": "Provider-neutral LLM service interface for the DeepSeek Harness",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
"types": "./lib/types/message.d.ts",
|
|
35
35
|
"default": "./lib/types/message.js"
|
|
36
36
|
},
|
|
37
|
+
"./assistant-stream": {
|
|
38
|
+
"types": "./lib/types/assistant-stream.d.ts",
|
|
39
|
+
"default": "./lib/types/assistant-stream.js"
|
|
40
|
+
},
|
|
37
41
|
"./typert": {
|
|
38
42
|
"types": "./lib/typert.host.d.ts",
|
|
39
43
|
"default": "./lib/typert.host.js"
|
|
@@ -61,16 +65,16 @@
|
|
|
61
65
|
},
|
|
62
66
|
"dependencies": {
|
|
63
67
|
"zod": "^4.4.3",
|
|
64
|
-
"@deepseek-ai/dsh-util-crypto": "^0.1.
|
|
68
|
+
"@deepseek-ai/dsh-util-crypto": "^0.1.3-alpha.2",
|
|
69
|
+
"@deepseek-ai/dsh-util-values": "^0.1.3-alpha.2",
|
|
70
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.3-alpha.2",
|
|
65
71
|
"@deepseek-ai/schemastery": "^3.18.2",
|
|
66
|
-
"@deepseek-ai/dsh-
|
|
67
|
-
"@deepseek-ai/dsh-
|
|
68
|
-
"@deepseek-ai/dsh-util-values": "^0.1.2-alpha.5",
|
|
69
|
-
"@deepseek-ai/dsh-typert-protocol": "^0.1.2-alpha.5"
|
|
72
|
+
"@deepseek-ai/dsh-brand": "^0.1.3-alpha.2",
|
|
73
|
+
"@deepseek-ai/dsh-timeout": "^0.1.3-alpha.2"
|
|
70
74
|
},
|
|
71
75
|
"devDependencies": {
|
|
72
|
-
"@deepseek-ai/dsh-
|
|
73
|
-
"@deepseek-ai/
|
|
74
|
-
"@deepseek-ai/
|
|
76
|
+
"@deepseek-ai/dsh-attachment": "^0.1.3-alpha.2",
|
|
77
|
+
"@deepseek-ai/dsh-invariants": "^0.1.3-alpha.2",
|
|
78
|
+
"@deepseek-ai/cordis": "^4.0.2"
|
|
75
79
|
}
|
|
76
80
|
}
|