@askdkc/dsh-cli 0.13.1 → 0.13.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.
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/** Convert DSH conversation blocks into low-level SDK prompts without an agent loop. */
|
|
2
2
|
import { LlmError, projectToolUpdates, fileHandleText } from '@deepseek-ai/dsh-llm';
|
|
3
3
|
import { projectReplay, requireReplaySignature } from './opencode-replay.js';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
4
5
|
export async function encodePrompt(options, model, attachments, warn) {
|
|
5
6
|
const prompt = [];
|
|
6
7
|
const names = new Map();
|
|
7
8
|
const callIds = new Map();
|
|
9
|
+
const wireIds = new Set();
|
|
8
10
|
if (options.system)
|
|
9
11
|
prompt.push({ role: 'system', content: options.system });
|
|
10
12
|
const projection = projectToolUpdates(options.messages, options.tools, undefined, options.toolHistory);
|
|
@@ -61,14 +63,24 @@ export async function encodePrompt(options, model, attachments, warn) {
|
|
|
61
63
|
else if (block.type === 'file')
|
|
62
64
|
content.push({ type: 'text', text: fileHandleText(block.attachment, attachments?.()?.fileHostPath(block.attachment)) });
|
|
63
65
|
else if (block.type === 'reasoning' && message.role === 'assistant') {
|
|
66
|
+
if (replay.foreign)
|
|
67
|
+
continue;
|
|
64
68
|
requireReplaySignature(block, model.protocol, providerOptions);
|
|
65
69
|
content.push({ type: 'reasoning', text: block.text, providerOptions });
|
|
66
70
|
}
|
|
67
71
|
else if (block.type === 'tool-call' && message.role === 'assistant') {
|
|
68
|
-
|
|
72
|
+
// Foreign pi Responses ids contain an opaque item suffix. Give the
|
|
73
|
+
// call/result pair a portable id without restoring that foreign item.
|
|
74
|
+
if (replay.foreign && model.protocol === 'responses' && block.id.includes('|'))
|
|
75
|
+
callIds.set(block.id, `dsh_${createHash('sha256').update(block.id).digest('hex').slice(0, 48)}`);
|
|
76
|
+
if (model.protocol === 'responses' && block.id.includes('|') && !callIds.has(block.id))
|
|
69
77
|
throw new LlmError('Cannot restore legacy Responses tool call pairing', 'INVALID_REPLAY_STATE');
|
|
70
78
|
if (names.has(block.id))
|
|
71
79
|
throw new LlmError('Duplicate stored tool call id', 'INVALID_REPLAY_STATE');
|
|
80
|
+
const wireId = callIds.get(block.id) ?? block.id;
|
|
81
|
+
if (wireIds.has(wireId))
|
|
82
|
+
throw new LlmError('Duplicate wire tool call id', 'INVALID_REPLAY_STATE');
|
|
83
|
+
wireIds.add(wireId);
|
|
72
84
|
if (model.protocol === 'google' && model.reasoning && !providerOptions?.google?.thoughtSignature && !message.content.slice(0, index).some(part => part.type === 'tool-call'))
|
|
73
85
|
throw new LlmError('Cannot replay Google tool call without its verified thought signature', 'INVALID_REPLAY_STATE');
|
|
74
86
|
names.set(block.id, block.name);
|
|
@@ -79,7 +91,7 @@ export async function encodePrompt(options, model, attachments, warn) {
|
|
|
79
91
|
catch {
|
|
80
92
|
throw new LlmError('Stored tool arguments are not valid JSON', 'INVALID_REPLAY_STATE');
|
|
81
93
|
}
|
|
82
|
-
content.push({ type: 'tool-call', toolCallId:
|
|
94
|
+
content.push({ type: 'tool-call', toolCallId: wireId, toolName: block.name, input, providerOptions });
|
|
83
95
|
}
|
|
84
96
|
else if (block.type === 'image') {
|
|
85
97
|
if (message.role === 'assistant')
|
|
@@ -87,7 +99,8 @@ export async function encodePrompt(options, model, attachments, warn) {
|
|
|
87
99
|
content.push(await imagePart(block));
|
|
88
100
|
}
|
|
89
101
|
}
|
|
90
|
-
|
|
102
|
+
if (content.length || !replay.foreign)
|
|
103
|
+
prompt.push({ role: message.role, content });
|
|
91
104
|
}
|
|
92
105
|
return prompt;
|
|
93
106
|
}
|
|
@@ -8,6 +8,7 @@ export interface ReplayProjection {
|
|
|
8
8
|
blocks: (SharedV4ProviderOptions | undefined)[];
|
|
9
9
|
callIds: Map<string, string>;
|
|
10
10
|
trusted: boolean;
|
|
11
|
+
foreign: boolean;
|
|
11
12
|
}
|
|
12
13
|
/** Validate the entire aligned envelope before restoring any signature or item id. */
|
|
13
14
|
export declare function projectReplay(source: unknown, content: readonly ContentBlock[], model: OpenCodeModel, route: string, warn?: (reason: string) => void): ReplayProjection;
|
|
@@ -33,9 +33,14 @@ function completeResponseSignatures(blocks, content) {
|
|
|
33
33
|
const APIS = { messages: 'anthropic-messages', responses: 'openai-responses', chat: 'openai-completions', google: 'google-generative-ai' };
|
|
34
34
|
/** Validate the entire aligned envelope before restoring any signature or item id. */
|
|
35
35
|
export function projectReplay(source, content, model, route, warn) {
|
|
36
|
-
const empty = () => ({ blocks: content.map(() => undefined), callIds: new Map(), trusted: false });
|
|
37
36
|
const message = record(source);
|
|
38
37
|
const envelope = record(message?.replayState);
|
|
38
|
+
// A model switch deliberately discards provider-specific replay data. It is
|
|
39
|
+
// distinct from a damaged native envelope, whose signature checks still apply.
|
|
40
|
+
const foreign = typeof message?.provider === 'string' && !!message.provider && typeof message.model === 'string' && !!message.model && (message.provider !== route || message.model !== model.id);
|
|
41
|
+
const empty = () => ({ blocks: content.map(() => undefined), callIds: new Map(), trusted: false, foreign });
|
|
42
|
+
if (foreign)
|
|
43
|
+
return empty();
|
|
39
44
|
if (!envelope) {
|
|
40
45
|
if (message?.replayState !== undefined)
|
|
41
46
|
warn?.('OpenCode history: malformed replay envelope; retaining message content');
|
|
@@ -122,7 +127,7 @@ export function projectReplay(source, content, model, route, warn) {
|
|
|
122
127
|
});
|
|
123
128
|
if (model.protocol === 'responses')
|
|
124
129
|
completeResponseSignatures(blocks, content);
|
|
125
|
-
return { blocks, callIds, trusted: true };
|
|
130
|
+
return { blocks, callIds, trusted: true, foreign: false };
|
|
126
131
|
}
|
|
127
132
|
catch (error) {
|
|
128
133
|
warn?.(`OpenCode history: ${error instanceof Error ? error.message : 'invalid replay'}; retaining message content`);
|