@xiaoso/dsh-tool-plus 0.1.0-beta.2 → 0.1.0-beta.3
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.en.md +122 -0
- package/README.md +3 -2
- package/THIRD_PARTY_NOTICES.md +4 -35
- package/lib/abort-B7izMMna.mjs +51 -0
- package/lib/amazon-bedrock-D-shAr1X.mjs +917 -0
- package/lib/anthropic-BWsZFzU8.mjs +262 -0
- package/lib/anthropic-CMT1Qj1t.mjs +3115 -0
- package/lib/api-key-login-CpzSezsi.mjs +157 -0
- package/lib/aws-credentials-8Mgn5MAy.mjs +867 -0
- package/lib/azure-openai-responses-CNkHiLUh.mjs +274 -0
- package/lib/bun-shim.mjs +172 -7
- package/lib/bundled-references-CSuBco5p.mjs +55 -0
- package/lib/callback-server-BEFNf-jf.mjs +398 -0
- package/lib/client.js +110 -40
- package/lib/cursor-BIQfBC6V.mjs +135 -0
- package/lib/cursor-DNk6eXDd.mjs +5470 -0
- package/lib/cursor-MjSm74IJ.mjs +273 -0
- package/lib/device-code-OI_tQcmc.mjs +51 -0
- package/lib/devin-CldyPD8K.mjs +95 -0
- package/lib/devin-CzRpTUOA.mjs +114 -0
- package/lib/devin-DXOeNyU7.mjs +542 -0
- package/lib/error-B3bevhrs.mjs +1449 -0
- package/lib/event-stream-BDPi64mK.mjs +151 -0
- package/lib/github-copilot-4GaMtQmg.mjs +208 -0
- package/lib/github-copilot-B2HGSIJK.mjs +104 -0
- package/lib/gitlab-duo-akICyfeD.mjs +155 -0
- package/lib/gitlab-duo-workflow-CSEgYk3N.mjs +91 -0
- package/lib/google-antigravity-Dlkdhahq.mjs +198 -0
- package/lib/google-auth-DhqpOYrX.mjs +232 -0
- package/lib/google-gemini-cli-BG_LRdIV.mjs +850 -0
- package/lib/google-gemini-cli-zJhiOcND.mjs +211 -0
- package/lib/google-oauth-shared-CwNWYdmR.mjs +147 -0
- package/lib/google-shared-DzhCb9b0.mjs +760 -0
- package/lib/google-vertex-kscbkyRb.mjs +99 -0
- package/lib/google-zyDOG9x7.mjs +30 -0
- package/lib/identity-DnB63pS7.mjs +219 -0
- package/lib/idle-iterator-C6XbWcuB.mjs +366 -0
- package/lib/index.mjs +2865 -2745
- package/lib/kimi-DMVI-zrZ.mjs +236 -0
- package/lib/markit-M0jhziqU.mjs +1417 -0
- package/lib/minimax-code-BK-3eBbz.mjs +53 -0
- package/lib/models-CfT4coYT.mjs +104660 -0
- package/lib/ollama-BQMGPxtV.mjs +589 -0
- package/lib/openai-codex-CQL_kvYL.mjs +255 -0
- package/lib/openai-codex-responses-Cz-2qpC7.mjs +3144 -0
- package/lib/openai-completions-i8doczAk.mjs +1360 -0
- package/lib/openai-reasoning-fallback-DGVVLgd1.mjs +286 -0
- package/lib/openai-responses-DTkBiiy-.mjs +867 -0
- package/lib/opencode-DaJjcUbf.mjs +38 -0
- package/lib/perplexity-9b-RQ0mV.mjs +194 -0
- package/lib/proxy-ZtUcl6r5.mjs +190 -0
- package/lib/scrapers-CL-WgdU1.mjs +9198 -0
- package/lib/scrapers-CipyKyCH.mjs +9198 -0
- package/lib/scrapers-DGfrYhtw.mjs +9198 -0
- package/lib/scrapers-DSUPYoUF.mjs +9198 -0
- package/lib/scrapers-DZ2GXmp7.mjs +9198 -0
- package/lib/src-DTid0g4K.mjs +5001 -0
- package/lib/stream-C_RAoxJC.mjs +10236 -0
- package/lib/stream-markup-healing-2toHXWXM.mjs +491 -0
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/config/fields.d.ts +1 -1
- package/lib/types/config/settings.d.ts +16 -2
- package/lib/types/tools/omp/sdk.d.ts +6 -0
- package/lib/types/tools/omp/tools/fetch.d.ts +2 -0
- package/lib/types/tools/omp/tools/read.d.ts +2 -8
- package/lib/types/tools/omp/utils/image-loading.d.ts +10 -36
- package/lib/types/tools/read/adapter/index.d.ts +4 -1
- package/lib/types/tools/read-image/index.d.ts +4 -0
- package/lib/types/tools/shared/bun-shim.d.ts +35 -3
- package/lib/types/tools/shared/image-bridge.d.ts +98 -0
- package/lib/types/tools/shared/omp-prompt.d.ts +4 -2
- package/lib/utils-2Wq2eATG.mjs +8119 -0
- package/lib/utils-BnX8O3vi.mjs +12303 -0
- package/lib/utils-CE8N8P4Q.mjs +12315 -0
- package/lib/utils-C_MrQ_0z.mjs +12301 -0
- package/lib/utils-D0Z1fyoO.mjs +12299 -0
- package/lib/utils-DppGHXQB.mjs +51 -0
- package/lib/utils-W8WdSBpX.mjs +12315 -0
- package/lib/vision-guard-BDD4OrKo.mjs +92 -0
- package/lib/wafer-DRU0EjZX.mjs +17 -0
- package/lib/xai-oauth-DPHDXKD7.mjs +446 -0
- package/lib/xiaomi-Dd87KSg5.mjs +157 -0
- package/lib/zai-CFeOt-53.mjs +203 -0
- package/lib/zip-D6QXpvaJ.mjs +1316 -0
- package/package.json +14 -10
- package/presets/package.json +1 -1
- package/presets/tool-plus-ptc/preset.yml +1 -1
- package/presets/tool-plus-standard/preset.yml +1 -1
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
import { installBunShim as __installBunShim } from "./bun-shim.mjs";
|
|
2
|
+
__installBunShim();
|
|
3
|
+
import { C as error, S as debug, T as warn, _ as parseStreamingJsonThrottled, g as parseStreamingJson } from "./src-DTid0g4K.mjs";
|
|
4
|
+
import { l as finalize, o as DevinApiError, r as ValidationError, s as ProviderResponseError, w as create, x as attach, y as Flag } from "./error-B3bevhrs.mjs";
|
|
5
|
+
import { a as normalizeSystemPrompts, g as isDemotedThinking, k as toolWireSchema, m as transformMessages } from "./utils-2Wq2eATG.mjs";
|
|
6
|
+
import { t as calculateCost } from "./models-CfT4coYT.mjs";
|
|
7
|
+
import { t as AssistantMessageEventStream } from "./event-stream-BDPi64mK.mjs";
|
|
8
|
+
import { E as create$1, c as messageDesc, i as fromBinary, r as fileDesc, t as toBinary } from "./to-binary-B1BEBIPC.mjs";
|
|
9
|
+
import { a as ChatMessagePromptSchema, c as PromptCacheOptionsSchema, d as ImageDataSchema, f as MetadataSchema, l as ChatToolCallSchema, m as file_buf_validate_validate, n as GetChatMessageResponseSchema, o as ChatToolChoiceSchema, p as file_exa_codeium_common_pb_codeium_common, s as ChatToolDefinitionSchema, t as GetChatMessageRequestSchema, u as CompletionConfigurationSchema } from "./api_server_pb-CDZgLMta.mjs";
|
|
10
|
+
import { t as deterministicUuid } from "./deterministic-id-D-yIV_eI.mjs";
|
|
11
|
+
import { gunzipSync, gzipSync } from "node:zlib";
|
|
12
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-catalog@17.3.5/node_modules/@oh-my-pi/pi-catalog/src/discovery/devin-gen/exa/auth_pb/auth_pb.ts
|
|
13
|
+
/**
|
|
14
|
+
* Describes the file exa/auth_pb/auth.proto.
|
|
15
|
+
*/
|
|
16
|
+
const file_exa_auth_pb_auth = /*@__PURE__*/ fileDesc("ChZleGEvYXV0aF9wYi9hdXRoLnByb3RvEgtleGEuYXV0aF9wYiJGChFHZXRVc2VySnd0UmVxdWVzdBIxCghtZXRhZGF0YRgBIAEoCzIfLmV4YS5jb2RlaXVtX2NvbW1vbl9wYi5NZXRhZGF0YSJFChJHZXRVc2VySnd0UmVzcG9uc2USEAoIdXNlcl9qd3QYASABKAkSHQoVY3VzdG9tX2FwaV9zZXJ2ZXJfdXJsGAIgASgJMlwKC0F1dGhTZXJ2aWNlEk0KCkdldFVzZXJKd3QSHi5leGEuYXV0aF9wYi5HZXRVc2VySnd0UmVxdWVzdBofLmV4YS5hdXRoX3BiLkdldFVzZXJKd3RSZXNwb25zZWIGcHJvdG8z", [file_buf_validate_validate, file_exa_codeium_common_pb_codeium_common]);
|
|
17
|
+
/**
|
|
18
|
+
* Describes the message exa.auth_pb.GetUserJwtRequest.
|
|
19
|
+
* Use `create(GetUserJwtRequestSchema)` to create a new message.
|
|
20
|
+
*/
|
|
21
|
+
const GetUserJwtRequestSchema = /*@__PURE__*/ messageDesc(file_exa_auth_pb_auth, 0);
|
|
22
|
+
/**
|
|
23
|
+
* Describes the message exa.auth_pb.GetUserJwtResponse.
|
|
24
|
+
* Use `create(GetUserJwtResponseSchema)` to create a new message.
|
|
25
|
+
*/
|
|
26
|
+
const GetUserJwtResponseSchema = /*@__PURE__*/ messageDesc(file_exa_auth_pb_auth, 1);
|
|
27
|
+
const CHAT_MESSAGE_PATH = "/exa.api_server_pb.ApiServerService/GetChatMessage";
|
|
28
|
+
const DEVIN_IDE_VERSION = "3.2.23";
|
|
29
|
+
const DEVIN_EXTENSION_VERSION = "1.48.2";
|
|
30
|
+
const DEVIN_SESSION_TOKEN_PREFIX = "devin-session-token$";
|
|
31
|
+
const DEVIN_AUTH_PATH = "/exa.auth_pb.AuthService/GetUserJwt";
|
|
32
|
+
const DEVIN_DEFAULT_STOP_PATTERNS = [
|
|
33
|
+
"<|user|>",
|
|
34
|
+
"<|bot|>",
|
|
35
|
+
"<|context_request|>",
|
|
36
|
+
"<|endoftext|>",
|
|
37
|
+
"<|end_of_turn|>"
|
|
38
|
+
];
|
|
39
|
+
/** Connect streaming framing: flag byte bit 0x01 = gzip payload, 0x02 = end-of-stream JSON trailers. */
|
|
40
|
+
const CONNECT_COMPRESSED_FLAG = 1;
|
|
41
|
+
const CONNECT_END_STREAM_FLAG = 2;
|
|
42
|
+
/**
|
|
43
|
+
* Hard upper bound on a single Connect frame payload. The 4-byte length prefix
|
|
44
|
+
* is otherwise attacker-controlled (up to `2**32 - 1`), so a malicious or buggy
|
|
45
|
+
* peer could force {@link streamDevin}'s reader to buffer gigabytes via
|
|
46
|
+
* `Buffer.concat` before the idle-timeout wrapper aborts. Well above any
|
|
47
|
+
* legitimate Cascade response but tight enough that a corrupt length prefix
|
|
48
|
+
* fails fast instead of consuming memory.
|
|
49
|
+
*/
|
|
50
|
+
const MAX_CONNECT_FRAME_PAYLOAD = 16777216;
|
|
51
|
+
/**
|
|
52
|
+
* Recovery heuristic for opaque Devin `invalid_argument` trailers. This is not
|
|
53
|
+
* asserted to be the backend's hard limit: small requests can hit the same
|
|
54
|
+
* intermittent error, while compactable message history this large is likely
|
|
55
|
+
* to benefit from the existing context-overflow maintenance path.
|
|
56
|
+
*/
|
|
57
|
+
const LARGE_HISTORY_RECOVERY_BYTES = 524288;
|
|
58
|
+
const streamDevin = (model, context, options) => {
|
|
59
|
+
const stream = new AssistantMessageEventStream();
|
|
60
|
+
(async () => {
|
|
61
|
+
const startTime = performance.now();
|
|
62
|
+
let firstTokenTime;
|
|
63
|
+
const output = {
|
|
64
|
+
role: "assistant",
|
|
65
|
+
content: [],
|
|
66
|
+
api: "devin-agent",
|
|
67
|
+
provider: model.provider,
|
|
68
|
+
model: model.id,
|
|
69
|
+
usage: {
|
|
70
|
+
input: 0,
|
|
71
|
+
output: 0,
|
|
72
|
+
cacheRead: 0,
|
|
73
|
+
cacheWrite: 0,
|
|
74
|
+
totalTokens: 0,
|
|
75
|
+
cost: {
|
|
76
|
+
input: 0,
|
|
77
|
+
output: 0,
|
|
78
|
+
cacheRead: 0,
|
|
79
|
+
cacheWrite: 0,
|
|
80
|
+
total: 0
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
stopReason: "stop",
|
|
84
|
+
timestamp: Date.now()
|
|
85
|
+
};
|
|
86
|
+
let currentTextBlock = null;
|
|
87
|
+
let currentThinkingBlock = null;
|
|
88
|
+
const toolBlocks = /* @__PURE__ */ new Map();
|
|
89
|
+
const toolPartialJson = /* @__PURE__ */ new Map();
|
|
90
|
+
const toolLastParseLen = /* @__PURE__ */ new Map();
|
|
91
|
+
let activeToolCallId;
|
|
92
|
+
let latestStopReason = 0;
|
|
93
|
+
const markFirstToken = () => {
|
|
94
|
+
if (firstTokenTime === void 0) firstTokenTime = performance.now();
|
|
95
|
+
};
|
|
96
|
+
const endTextBlock = () => {
|
|
97
|
+
const block = currentTextBlock;
|
|
98
|
+
if (!block) return;
|
|
99
|
+
currentTextBlock = null;
|
|
100
|
+
stream.push({
|
|
101
|
+
type: "text_end",
|
|
102
|
+
contentIndex: output.content.indexOf(block),
|
|
103
|
+
content: block.text,
|
|
104
|
+
partial: output
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
const endThinkingBlock = () => {
|
|
108
|
+
const block = currentThinkingBlock;
|
|
109
|
+
if (!block) return;
|
|
110
|
+
currentThinkingBlock = null;
|
|
111
|
+
stream.push({
|
|
112
|
+
type: "thinking_end",
|
|
113
|
+
contentIndex: output.content.indexOf(block),
|
|
114
|
+
content: block.thinking,
|
|
115
|
+
partial: output
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
try {
|
|
119
|
+
const fetchImpl = options?.fetch ?? fetch;
|
|
120
|
+
const baseUrl = (model.baseUrl || "https://server.codeium.com").replace(/\/+$/, "");
|
|
121
|
+
const apiKey = normalizeDevinSessionToken(options?.apiKey);
|
|
122
|
+
const auth = await fetchDevinAuthMetadata(apiKey, baseUrl, fetchImpl, options?.signal);
|
|
123
|
+
const chatBaseUrl = auth.baseUrl ?? baseUrl;
|
|
124
|
+
const request = buildDevinChatRequest(model, context, options, apiKey, auth.userJwt);
|
|
125
|
+
const reqBytes = toBinary(GetChatMessageRequestSchema, request);
|
|
126
|
+
const gz = gzipSync(reqBytes);
|
|
127
|
+
debug("devin: sending chat request", {
|
|
128
|
+
model: model.id,
|
|
129
|
+
tools: context.tools?.length ?? 0,
|
|
130
|
+
requestBytes: reqBytes.byteLength,
|
|
131
|
+
compressedBytes: gz.byteLength
|
|
132
|
+
});
|
|
133
|
+
const frame = Buffer.alloc(5 + gz.length);
|
|
134
|
+
frame[0] = CONNECT_COMPRESSED_FLAG;
|
|
135
|
+
frame.writeUInt32BE(gz.length, 1);
|
|
136
|
+
frame.set(gz, 5);
|
|
137
|
+
const response = await fetchImpl(chatBaseUrl + CHAT_MESSAGE_PATH, {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers: {
|
|
140
|
+
"content-type": "application/connect+proto",
|
|
141
|
+
"connect-protocol-version": "1",
|
|
142
|
+
"connect-content-encoding": "gzip",
|
|
143
|
+
"accept-encoding": "identity",
|
|
144
|
+
"user-agent": "connect-go/1.18.1 (go1.26.3)",
|
|
145
|
+
"connect-accept-encoding": "gzip",
|
|
146
|
+
...options?.headers ?? {}
|
|
147
|
+
},
|
|
148
|
+
body: frame,
|
|
149
|
+
signal: options?.signal
|
|
150
|
+
});
|
|
151
|
+
if (!response.ok) {
|
|
152
|
+
const text = await response.text();
|
|
153
|
+
throw new DevinApiError(`Devin API error ${response.status} ${response.statusText}: ${text}`, response.status);
|
|
154
|
+
}
|
|
155
|
+
if (!response.body) throw new ProviderResponseError("Devin API error: response body is empty", {
|
|
156
|
+
provider: model.provider,
|
|
157
|
+
kind: "empty-body"
|
|
158
|
+
});
|
|
159
|
+
const body = response.body;
|
|
160
|
+
stream.push({
|
|
161
|
+
type: "start",
|
|
162
|
+
partial: output
|
|
163
|
+
});
|
|
164
|
+
const reader = body.getReader();
|
|
165
|
+
let pending = Buffer.alloc(0);
|
|
166
|
+
for (;;) {
|
|
167
|
+
const { done, value } = await reader.read();
|
|
168
|
+
if (value && value.length > 0) pending = pending.length === 0 ? Buffer.from(value.buffer, value.byteOffset, value.byteLength) : Buffer.concat([pending, value]);
|
|
169
|
+
while (pending.length >= 5) {
|
|
170
|
+
const flag = pending[0];
|
|
171
|
+
const len = pending.readUInt32BE(1);
|
|
172
|
+
if (len > MAX_CONNECT_FRAME_PAYLOAD) throw new ProviderResponseError(`Devin Connect frame length ${len} exceeds ${MAX_CONNECT_FRAME_PAYLOAD}-byte cap`, {
|
|
173
|
+
provider: model.provider,
|
|
174
|
+
kind: "envelope"
|
|
175
|
+
});
|
|
176
|
+
if (pending.length < 5 + len) break;
|
|
177
|
+
const payload = pending.subarray(5, 5 + len);
|
|
178
|
+
pending = pending.subarray(5 + len);
|
|
179
|
+
if (flag & CONNECT_END_STREAM_FLAG) {
|
|
180
|
+
const trailerError = readConnectTrailerError((flag & CONNECT_COMPRESSED_FLAG ? gunzipSync(payload) : payload).toString("utf8").trim());
|
|
181
|
+
if (trailerError) {
|
|
182
|
+
const error = new ValidationError(trailerError.formatted);
|
|
183
|
+
if (firstTokenTime === void 0 && trailerError.code.toLowerCase() === "invalid_argument" && /\binternal error\b/i.test(trailerError.message)) {
|
|
184
|
+
let activeTailCount = 0;
|
|
185
|
+
const lastRole = context.messages.at(-1)?.role;
|
|
186
|
+
if (lastRole === "user" || lastRole === "developer") {
|
|
187
|
+
activeTailCount = 1;
|
|
188
|
+
if (lastRole === "developer") for (let i = context.messages.length - 2; i >= 0; i--) {
|
|
189
|
+
const role = context.messages[i].role;
|
|
190
|
+
if (role !== "user" && role !== "developer") break;
|
|
191
|
+
activeTailCount++;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const shrinkablePrompts = activeTailCount > 0 ? request.chatMessagePrompts.slice(0, -activeTailCount) : request.chatMessagePrompts;
|
|
195
|
+
const historyBytes = toBinary(GetChatMessageRequestSchema, create$1(GetChatMessageRequestSchema, { chatMessagePrompts: shrinkablePrompts })).byteLength;
|
|
196
|
+
if (historyBytes >= LARGE_HISTORY_RECOVERY_BYTES) {
|
|
197
|
+
attach(error, create(Flag.ContextOverflow));
|
|
198
|
+
warn("devin: treating large-history invalid_argument as context overflow", {
|
|
199
|
+
model: model.id,
|
|
200
|
+
historyBytes,
|
|
201
|
+
requestBytes: reqBytes.byteLength,
|
|
202
|
+
compressedBytes: gz.byteLength
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const raw = flag & CONNECT_COMPRESSED_FLAG ? gunzipSync(payload) : payload;
|
|
211
|
+
const msg = fromBinary(GetChatMessageResponseSchema, raw);
|
|
212
|
+
if (msg.messageId && !output.responseId) output.responseId = msg.messageId;
|
|
213
|
+
if (msg.deltaThinking) {
|
|
214
|
+
markFirstToken();
|
|
215
|
+
const block = currentThinkingBlock ?? {
|
|
216
|
+
type: "thinking",
|
|
217
|
+
thinking: ""
|
|
218
|
+
};
|
|
219
|
+
if (currentThinkingBlock !== block) {
|
|
220
|
+
output.content.push(block);
|
|
221
|
+
currentThinkingBlock = block;
|
|
222
|
+
stream.push({
|
|
223
|
+
type: "thinking_start",
|
|
224
|
+
contentIndex: output.content.length - 1,
|
|
225
|
+
partial: output
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
block.thinking += msg.deltaThinking;
|
|
229
|
+
if (msg.deltaSignature) block.thinkingSignature = msg.deltaSignature;
|
|
230
|
+
stream.push({
|
|
231
|
+
type: "thinking_delta",
|
|
232
|
+
contentIndex: output.content.indexOf(block),
|
|
233
|
+
delta: msg.deltaThinking,
|
|
234
|
+
partial: output
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
if (msg.deltaText) {
|
|
238
|
+
markFirstToken();
|
|
239
|
+
endThinkingBlock();
|
|
240
|
+
const block = currentTextBlock ?? {
|
|
241
|
+
type: "text",
|
|
242
|
+
text: ""
|
|
243
|
+
};
|
|
244
|
+
if (currentTextBlock !== block) {
|
|
245
|
+
output.content.push(block);
|
|
246
|
+
currentTextBlock = block;
|
|
247
|
+
stream.push({
|
|
248
|
+
type: "text_start",
|
|
249
|
+
contentIndex: output.content.length - 1,
|
|
250
|
+
partial: output
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
block.text += msg.deltaText;
|
|
254
|
+
stream.push({
|
|
255
|
+
type: "text_delta",
|
|
256
|
+
contentIndex: output.content.indexOf(block),
|
|
257
|
+
delta: msg.deltaText,
|
|
258
|
+
partial: output
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
if (msg.deltaToolCalls.length > 0) {
|
|
262
|
+
markFirstToken();
|
|
263
|
+
endTextBlock();
|
|
264
|
+
endThinkingBlock();
|
|
265
|
+
for (const tc of msg.deltaToolCalls) {
|
|
266
|
+
const toolCallId = tc.id || activeToolCallId;
|
|
267
|
+
if (!toolCallId) continue;
|
|
268
|
+
let block = toolBlocks.get(toolCallId);
|
|
269
|
+
if (!block) {
|
|
270
|
+
block = {
|
|
271
|
+
type: "toolCall",
|
|
272
|
+
id: toolCallId,
|
|
273
|
+
name: tc.name,
|
|
274
|
+
arguments: {}
|
|
275
|
+
};
|
|
276
|
+
output.content.push(block);
|
|
277
|
+
toolBlocks.set(toolCallId, block);
|
|
278
|
+
toolPartialJson.set(toolCallId, "");
|
|
279
|
+
stream.push({
|
|
280
|
+
type: "toolcall_start",
|
|
281
|
+
contentIndex: output.content.length - 1,
|
|
282
|
+
partial: output
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
if (tc.name) block.name = tc.name;
|
|
286
|
+
activeToolCallId = toolCallId;
|
|
287
|
+
if (!tc.argumentsJson) continue;
|
|
288
|
+
const previousJson = toolPartialJson.get(toolCallId) ?? "";
|
|
289
|
+
const accumulated = tc.argumentsJson.startsWith(previousJson) ? tc.argumentsJson : previousJson + tc.argumentsJson;
|
|
290
|
+
const delta = accumulated.slice(previousJson.length);
|
|
291
|
+
toolPartialJson.set(toolCallId, accumulated);
|
|
292
|
+
const throttled = parseStreamingJsonThrottled(accumulated, toolLastParseLen.get(toolCallId) ?? 0);
|
|
293
|
+
if (throttled) {
|
|
294
|
+
block.arguments = throttled.value;
|
|
295
|
+
toolLastParseLen.set(toolCallId, throttled.parsedLen);
|
|
296
|
+
}
|
|
297
|
+
stream.push({
|
|
298
|
+
type: "toolcall_delta",
|
|
299
|
+
contentIndex: output.content.indexOf(block),
|
|
300
|
+
delta,
|
|
301
|
+
partial: output
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (msg.stopReason !== 0) latestStopReason = msg.stopReason;
|
|
306
|
+
if (msg.usage) {
|
|
307
|
+
output.usage.input = Number(msg.usage.inputTokens);
|
|
308
|
+
output.usage.output = Number(msg.usage.outputTokens);
|
|
309
|
+
output.usage.cacheRead = Number(msg.usage.cacheReadTokens);
|
|
310
|
+
output.usage.cacheWrite = Number(msg.usage.cacheWriteTokens);
|
|
311
|
+
output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (done) break;
|
|
315
|
+
}
|
|
316
|
+
endTextBlock();
|
|
317
|
+
endThinkingBlock();
|
|
318
|
+
for (const [id, block] of toolBlocks) {
|
|
319
|
+
block.arguments = parseStreamingJson(toolPartialJson.get(id));
|
|
320
|
+
stream.push({
|
|
321
|
+
type: "toolcall_end",
|
|
322
|
+
contentIndex: output.content.indexOf(block),
|
|
323
|
+
toolCall: block,
|
|
324
|
+
partial: output
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
const doneReason = toolBlocks.size > 0 ? "toolUse" : latestStopReason === 3 ? "length" : "stop";
|
|
328
|
+
output.stopReason = doneReason;
|
|
329
|
+
calculateCost(model, output.usage);
|
|
330
|
+
output.duration = performance.now() - startTime;
|
|
331
|
+
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
332
|
+
stream.push({
|
|
333
|
+
type: "done",
|
|
334
|
+
reason: doneReason,
|
|
335
|
+
message: output
|
|
336
|
+
});
|
|
337
|
+
stream.end();
|
|
338
|
+
} catch (error$1) {
|
|
339
|
+
error("devin: stream failed", { error: String(error$1) });
|
|
340
|
+
const result = await finalize(error$1, {
|
|
341
|
+
api: model.api,
|
|
342
|
+
signal: options?.signal
|
|
343
|
+
});
|
|
344
|
+
output.stopReason = result.stopReason;
|
|
345
|
+
output.errorStatus = result.status;
|
|
346
|
+
output.errorId = result.id;
|
|
347
|
+
output.errorMessage = result.message;
|
|
348
|
+
output.duration = performance.now() - startTime;
|
|
349
|
+
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
350
|
+
stream.push({
|
|
351
|
+
type: "error",
|
|
352
|
+
reason: result.stopReason,
|
|
353
|
+
error: output
|
|
354
|
+
});
|
|
355
|
+
stream.end();
|
|
356
|
+
}
|
|
357
|
+
})();
|
|
358
|
+
return stream;
|
|
359
|
+
};
|
|
360
|
+
function normalizeDevinSessionToken(apiKey) {
|
|
361
|
+
if (!apiKey) return "";
|
|
362
|
+
return apiKey.startsWith(DEVIN_SESSION_TOKEN_PREFIX) ? apiKey : `${DEVIN_SESSION_TOKEN_PREFIX}${apiKey}`;
|
|
363
|
+
}
|
|
364
|
+
async function fetchDevinAuthMetadata(apiKey, baseUrl, fetchImpl, signal) {
|
|
365
|
+
const request = create$1(GetUserJwtRequestSchema, { metadata: create$1(MetadataSchema, {
|
|
366
|
+
apiKey,
|
|
367
|
+
ideName: "windsurf",
|
|
368
|
+
ideVersion: DEVIN_IDE_VERSION,
|
|
369
|
+
extensionName: "windsurf",
|
|
370
|
+
extensionVersion: DEVIN_EXTENSION_VERSION,
|
|
371
|
+
locale: "en"
|
|
372
|
+
}) });
|
|
373
|
+
const response = await fetchImpl(`${baseUrl}${DEVIN_AUTH_PATH}`, {
|
|
374
|
+
method: "POST",
|
|
375
|
+
headers: {
|
|
376
|
+
"content-type": "application/proto",
|
|
377
|
+
"connect-protocol-version": "1",
|
|
378
|
+
accept: "*/*"
|
|
379
|
+
},
|
|
380
|
+
body: toBinary(GetUserJwtRequestSchema, request),
|
|
381
|
+
signal
|
|
382
|
+
});
|
|
383
|
+
const payload = new Uint8Array(await response.arrayBuffer());
|
|
384
|
+
if (!response.ok) throw new DevinApiError(`Devin auth error ${response.status} ${response.statusText}: ${new TextDecoder().decode(payload)}`, response.status);
|
|
385
|
+
const decoded = decodeDevinUserJwtResponse(payload);
|
|
386
|
+
if (!decoded.userJwt) throw new ProviderResponseError("Devin auth error: GetUserJwt returned an empty user JWT", {
|
|
387
|
+
provider: "devin",
|
|
388
|
+
kind: "runtime"
|
|
389
|
+
});
|
|
390
|
+
const customBaseUrl = decoded.customApiServerUrl.trim();
|
|
391
|
+
return {
|
|
392
|
+
userJwt: decoded.userJwt,
|
|
393
|
+
...customBaseUrl ? { baseUrl: customBaseUrl.replace(/\/+$/, "") } : void 0
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
function decodeDevinUserJwtResponse(payload) {
|
|
397
|
+
try {
|
|
398
|
+
return fromBinary(GetUserJwtResponseSchema, payload);
|
|
399
|
+
} catch {
|
|
400
|
+
return fromBinary(GetUserJwtResponseSchema, gunzipSync(payload));
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Build a {@link GetChatMessageRequest} for one Cascade turn. Auth rides inside
|
|
405
|
+
* `Metadata.apiKey`; the system prompt is the flattened `prompt` string and the
|
|
406
|
+
* conversation history maps to `chatMessagePrompts`.
|
|
407
|
+
*/
|
|
408
|
+
function buildDevinChatRequest(model, context, options, apiKey, userJwt) {
|
|
409
|
+
const cascadeId = options?.conversationId ?? options?.sessionId ?? crypto.randomUUID();
|
|
410
|
+
const stopPatterns = options?.stopSequences && options.stopSequences.length > 0 ? [...DEVIN_DEFAULT_STOP_PATTERNS, ...options.stopSequences] : DEVIN_DEFAULT_STOP_PATTERNS;
|
|
411
|
+
const messages = transformMessages(context.messages, model);
|
|
412
|
+
return create$1(GetChatMessageRequestSchema, {
|
|
413
|
+
metadata: create$1(MetadataSchema, {
|
|
414
|
+
apiKey,
|
|
415
|
+
userJwt,
|
|
416
|
+
ideName: "windsurf",
|
|
417
|
+
ideVersion: DEVIN_IDE_VERSION,
|
|
418
|
+
extensionName: "windsurf",
|
|
419
|
+
extensionVersion: DEVIN_EXTENSION_VERSION,
|
|
420
|
+
locale: "en"
|
|
421
|
+
}),
|
|
422
|
+
prompt: normalizeSystemPrompts(context.systemPrompt).join("\n\n"),
|
|
423
|
+
chatMessagePrompts: buildChatMessagePrompts(messages, cascadeId, model),
|
|
424
|
+
chatModelUid: options?.chatModelUid ?? model.requestModelId ?? model.id,
|
|
425
|
+
requestType: 5,
|
|
426
|
+
plannerMode: 1,
|
|
427
|
+
toolChoice: create$1(ChatToolChoiceSchema, { choice: {
|
|
428
|
+
case: "optionName",
|
|
429
|
+
value: "auto"
|
|
430
|
+
} }),
|
|
431
|
+
systemPromptCacheOptions: create$1(PromptCacheOptionsSchema, { type: 1 }),
|
|
432
|
+
disableParallelToolCalls: true,
|
|
433
|
+
cascadeId,
|
|
434
|
+
executionId: crypto.randomUUID(),
|
|
435
|
+
configuration: create$1(CompletionConfigurationSchema, {
|
|
436
|
+
numCompletions: 1n,
|
|
437
|
+
maxTokens: BigInt(options?.maxTokens ?? model.maxTokens ?? 64e3),
|
|
438
|
+
maxNewlines: 200n,
|
|
439
|
+
temperature: options?.temperature ?? .4,
|
|
440
|
+
firstTemperature: options?.temperature ?? .4,
|
|
441
|
+
topK: 50n,
|
|
442
|
+
topP: options?.topP ?? 1,
|
|
443
|
+
stopPatterns,
|
|
444
|
+
fimEotProbThreshold: 1
|
|
445
|
+
}),
|
|
446
|
+
tools: (context.tools ?? []).map((tool) => create$1(ChatToolDefinitionSchema, {
|
|
447
|
+
name: tool.name,
|
|
448
|
+
description: tool.description,
|
|
449
|
+
jsonSchemaString: JSON.stringify(toolWireSchema(tool)),
|
|
450
|
+
strict: tool.strict ?? false
|
|
451
|
+
}))
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
/** Map omp `Message` history onto Cascade `ChatMessagePrompt`s (USER / SYSTEM / TOOL channels). */
|
|
455
|
+
function buildChatMessagePrompts(messages, cascadeId, model) {
|
|
456
|
+
const prompts = [];
|
|
457
|
+
for (const [index, msg] of messages.entries()) if (msg.role === "user" || msg.role === "developer") {
|
|
458
|
+
let promptText = "";
|
|
459
|
+
const images = [];
|
|
460
|
+
if (typeof msg.content === "string") promptText = msg.content;
|
|
461
|
+
else for (const part of msg.content) if (part.type === "text") promptText += part.text;
|
|
462
|
+
else if (part.type === "image") images.push(create$1(ImageDataSchema, {
|
|
463
|
+
base64Data: part.data,
|
|
464
|
+
mimeType: part.mimeType
|
|
465
|
+
}));
|
|
466
|
+
prompts.push(create$1(ChatMessagePromptSchema, {
|
|
467
|
+
messageId: deterministicUuid(`${cascadeId}\0${index}\0${msg.role}`),
|
|
468
|
+
source: 1,
|
|
469
|
+
prompt: promptText,
|
|
470
|
+
images
|
|
471
|
+
}));
|
|
472
|
+
} else if (msg.role === "assistant") {
|
|
473
|
+
const isNativeDevinMessage = msg.api === model.api && msg.provider === model.provider && msg.model === model.id;
|
|
474
|
+
let promptText = "";
|
|
475
|
+
let thinkingText = "";
|
|
476
|
+
let signature = "";
|
|
477
|
+
const toolCalls = [];
|
|
478
|
+
for (const part of msg.content) if (part.type === "text") promptText += `${part.text}${isDemotedThinking(part) ? "\n" : ""}`;
|
|
479
|
+
else if (part.type === "thinking") {
|
|
480
|
+
thinkingText += part.thinking;
|
|
481
|
+
if (isNativeDevinMessage && !signature && part.thinkingSignature) signature = part.thinkingSignature;
|
|
482
|
+
} else if (part.type === "toolCall") toolCalls.push(create$1(ChatToolCallSchema, {
|
|
483
|
+
id: part.id,
|
|
484
|
+
name: part.name,
|
|
485
|
+
argumentsJson: JSON.stringify(part.arguments)
|
|
486
|
+
}));
|
|
487
|
+
if (!promptText && !thinkingText && !signature && toolCalls.length === 0) continue;
|
|
488
|
+
prompts.push(create$1(ChatMessagePromptSchema, {
|
|
489
|
+
messageId: isNativeDevinMessage && msg.responseId ? msg.responseId : `bot-${deterministicUuid(`${cascadeId}\0${index}\0assistant`)}`,
|
|
490
|
+
source: 2,
|
|
491
|
+
prompt: promptText,
|
|
492
|
+
thinking: thinkingText,
|
|
493
|
+
signature,
|
|
494
|
+
signatureType: "",
|
|
495
|
+
toolCalls
|
|
496
|
+
}));
|
|
497
|
+
} else {
|
|
498
|
+
let resultText = "";
|
|
499
|
+
const images = [];
|
|
500
|
+
for (const part of msg.content) if (part.type === "text") resultText += part.text;
|
|
501
|
+
else if (part.type === "image") images.push(create$1(ImageDataSchema, {
|
|
502
|
+
base64Data: part.data,
|
|
503
|
+
mimeType: part.mimeType
|
|
504
|
+
}));
|
|
505
|
+
prompts.push(create$1(ChatMessagePromptSchema, {
|
|
506
|
+
messageId: deterministicUuid(`${cascadeId}\0${index}\0tool\0${msg.toolCallId}`),
|
|
507
|
+
source: 4,
|
|
508
|
+
toolCallId: msg.toolCallId,
|
|
509
|
+
toolResultIsError: msg.isError,
|
|
510
|
+
prompt: resultText,
|
|
511
|
+
images
|
|
512
|
+
}));
|
|
513
|
+
}
|
|
514
|
+
return prompts;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Parse a Connect end-of-stream JSON trailer and return its structured error
|
|
518
|
+
* when it carries `{ error: { code, message } }`, else `null`. The trailer is
|
|
519
|
+
* untrusted server output, so the shape is checked with guards rather than asserted.
|
|
520
|
+
*/
|
|
521
|
+
function readConnectTrailerError(text) {
|
|
522
|
+
if (text.length === 0) return null;
|
|
523
|
+
let parsed;
|
|
524
|
+
try {
|
|
525
|
+
parsed = JSON.parse(text);
|
|
526
|
+
} catch {
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
if (!parsed || typeof parsed !== "object" || !("error" in parsed)) return null;
|
|
530
|
+
const err = parsed.error;
|
|
531
|
+
if (!err || typeof err !== "object") return null;
|
|
532
|
+
const code = "code" in err && typeof err.code === "string" ? err.code : "";
|
|
533
|
+
const message = "message" in err && typeof err.message === "string" ? err.message : "";
|
|
534
|
+
if (!code && !message) return null;
|
|
535
|
+
return {
|
|
536
|
+
code,
|
|
537
|
+
message,
|
|
538
|
+
formatted: `Devin stream error${code ? ` ${code}` : ""}: ${message}`
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
//#endregion
|
|
542
|
+
export { streamDevin };
|