@opencode/ai 0.0.0-dev-19545 → 0.0.0-dev-19551
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.
|
@@ -10,6 +10,7 @@ import { BedrockAuth } from "./utils/bedrock-auth.js";
|
|
|
10
10
|
import { BedrockCache } from "./utils/bedrock-cache.js";
|
|
11
11
|
import { BedrockMedia } from "./utils/bedrock-media.js";
|
|
12
12
|
import { Lifecycle } from "./utils/lifecycle.js";
|
|
13
|
+
import { MistralToolID } from "./utils/mistral-tool-id.js";
|
|
13
14
|
import { ToolSchemaProjection } from "./utils/tool-schema.js";
|
|
14
15
|
import { ToolStream } from "./utils/tool-stream.js";
|
|
15
16
|
const ADAPTER = "bedrock-converse";
|
|
@@ -201,9 +202,9 @@ const removeEmptyToolInputKeys = (input) => {
|
|
|
201
202
|
return input;
|
|
202
203
|
return Object.fromEntries(Object.entries(input).flatMap(([key, value]) => (key === "" ? [] : [[key, removeEmptyToolInputKeys(value)]])));
|
|
203
204
|
};
|
|
204
|
-
const lowerToolCall = (part) => ({
|
|
205
|
+
const lowerToolCall = (part, normalizeID) => ({
|
|
205
206
|
toolUse: {
|
|
206
|
-
toolUseId: part.id,
|
|
207
|
+
toolUseId: normalizeID(part.id),
|
|
207
208
|
// Models can emit names that Converse rejects when replayed in history.
|
|
208
209
|
name: part.name.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64) || "_",
|
|
209
210
|
input: removeEmptyToolInputKeys(part.input),
|
|
@@ -230,10 +231,10 @@ const lowerToolResultContent = Effect.fn("BedrockConverse.lowerToolResultContent
|
|
|
230
231
|
}
|
|
231
232
|
return content;
|
|
232
233
|
});
|
|
233
|
-
const lowerToolResult = Effect.fn("BedrockConverse.lowerToolResult")(function* (part, documentNames) {
|
|
234
|
+
const lowerToolResult = Effect.fn("BedrockConverse.lowerToolResult")(function* (part, documentNames, normalizeID) {
|
|
234
235
|
return {
|
|
235
236
|
toolResult: {
|
|
236
|
-
toolUseId: part.id,
|
|
237
|
+
toolUseId: normalizeID(part.id),
|
|
237
238
|
content: yield* lowerToolResultContent(part, documentNames),
|
|
238
239
|
status: part.result.type === "error" ? "error" : "success",
|
|
239
240
|
},
|
|
@@ -242,6 +243,8 @@ const lowerToolResult = Effect.fn("BedrockConverse.lowerToolResult")(function* (
|
|
|
242
243
|
const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (request, breakpoints) {
|
|
243
244
|
const messages = [];
|
|
244
245
|
const documentNames = new Set();
|
|
246
|
+
// Mistral can reject replay IDs even when they satisfy Converse's broader ID syntax.
|
|
247
|
+
const normalizeID = request.model.id.includes("mistral.") ? MistralToolID.normalizer(request) : (id) => id;
|
|
245
248
|
const providerMetadataKey = request.model.route.providerMetadataKey ?? String(request.model.provider);
|
|
246
249
|
for (const message of request.messages) {
|
|
247
250
|
if (message.role === "system") {
|
|
@@ -306,7 +309,7 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (requ
|
|
|
306
309
|
continue;
|
|
307
310
|
}
|
|
308
311
|
if (part.type === "tool-call") {
|
|
309
|
-
content.push(lowerToolCall(part));
|
|
312
|
+
content.push(lowerToolCall(part, normalizeID));
|
|
310
313
|
continue;
|
|
311
314
|
}
|
|
312
315
|
}
|
|
@@ -318,7 +321,7 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (requ
|
|
|
318
321
|
for (const part of message.content) {
|
|
319
322
|
if (!ProviderShared.supportsContent(part, ["tool-result"]))
|
|
320
323
|
return yield* ProviderShared.unsupportedContent("Bedrock Converse", "tool", ["tool-result"]);
|
|
321
|
-
content.push(yield* lowerToolResult(part, documentNames));
|
|
324
|
+
content.push(yield* lowerToolResult(part, documentNames, normalizeID));
|
|
322
325
|
const cachePoint = BedrockCache.block(breakpoints, part.cache);
|
|
323
326
|
if (cachePoint)
|
|
324
327
|
content.push(cachePoint);
|
|
@@ -9,10 +9,10 @@ import { AIError, InvalidProviderOutputError, LLMEvent, ProviderInternalError, U
|
|
|
9
9
|
import { classifyProviderFailure } from "../provider-error.js";
|
|
10
10
|
import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared.js";
|
|
11
11
|
import { Lifecycle } from "./utils/lifecycle.js";
|
|
12
|
+
import { MistralToolID } from "./utils/mistral-tool-id.js";
|
|
12
13
|
import { ToolStream } from "./utils/tool-stream.js";
|
|
13
14
|
const ADAPTER = "mistral-chat";
|
|
14
15
|
const DONE = "[DONE]";
|
|
15
|
-
const TOOL_ID = /^[A-Za-z0-9]{9}$/;
|
|
16
16
|
export const DEFAULT_BASE_URL = "https://api.mistral.ai/v1";
|
|
17
17
|
export const PATH = "/chat/completions";
|
|
18
18
|
const MistralTextContent = Schema.Struct({
|
|
@@ -140,34 +140,6 @@ const MistralEvent = Schema.StructWithRest(Schema.Struct({
|
|
|
140
140
|
error: optionalNull(MistralError),
|
|
141
141
|
}), [Schema.Record(Schema.String, Schema.Unknown)]);
|
|
142
142
|
const MistralStreamEvent = Schema.Union([Schema.Literal(DONE), Protocol.jsonEvent(MistralEvent)]);
|
|
143
|
-
const hashID = (value) => {
|
|
144
|
-
const hash = (seed) => {
|
|
145
|
-
let result = seed;
|
|
146
|
-
for (const char of value)
|
|
147
|
-
result = Math.imul(result ^ char.charCodeAt(0), 16777619);
|
|
148
|
-
return (result >>> 0).toString(36);
|
|
149
|
-
};
|
|
150
|
-
return `${hash(2166136261).padStart(7, "0")}${hash(2246822519).padStart(7, "0")}`.slice(-9);
|
|
151
|
-
};
|
|
152
|
-
const toolIDNormalizer = (request) => {
|
|
153
|
-
const ids = request.messages.flatMap((message) => message.content.flatMap((part) => (part.type === "tool-call" || part.type === "tool-result" ? [part.id] : [])));
|
|
154
|
-
const used = new Set(ids.filter((id) => TOOL_ID.test(id)));
|
|
155
|
-
const normalized = new Map();
|
|
156
|
-
return (id) => {
|
|
157
|
-
if (TOOL_ID.test(id))
|
|
158
|
-
return id;
|
|
159
|
-
const previous = normalized.get(id);
|
|
160
|
-
if (previous)
|
|
161
|
-
return previous;
|
|
162
|
-
let attempt = 0;
|
|
163
|
-
let candidate = hashID(id);
|
|
164
|
-
while (used.has(candidate))
|
|
165
|
-
candidate = hashID(`${id}:${++attempt}`);
|
|
166
|
-
used.add(candidate);
|
|
167
|
-
normalized.set(id, candidate);
|
|
168
|
-
return candidate;
|
|
169
|
-
};
|
|
170
|
-
};
|
|
171
143
|
const lowerMedia = Effect.fn("MistralChat.lowerMedia")(function* (part) {
|
|
172
144
|
const media = ProviderShared.normalizeMedia(part);
|
|
173
145
|
const url = typeof part.data === "string" && /^(?:https?:|data:)/.test(part.data) ? part.data : media.dataUrl;
|
|
@@ -269,7 +241,7 @@ const lowerToolResults = Effect.fn("MistralChat.lowerToolResults")(function* (me
|
|
|
269
241
|
return output;
|
|
270
242
|
});
|
|
271
243
|
const lowerMessages = Effect.fn("MistralChat.lowerMessages")(function* (request) {
|
|
272
|
-
const normalizeID =
|
|
244
|
+
const normalizeID = MistralToolID.normalizer(request);
|
|
273
245
|
const messages = request.system.length === 0 ? [] : [{ role: "system", content: ProviderShared.joinText(request.system) }];
|
|
274
246
|
for (const message of request.messages) {
|
|
275
247
|
if (message.role === "system") {
|
|
@@ -439,15 +411,15 @@ const appendContent = (state, events, content) => {
|
|
|
439
411
|
}, state);
|
|
440
412
|
};
|
|
441
413
|
const normalizeStreamToolID = (state, source) => {
|
|
442
|
-
if (
|
|
414
|
+
if (MistralToolID.valid.test(source))
|
|
443
415
|
return { id: source, state: { ...state, usedToolIDs: new Set([...state.usedToolIDs, source]) } };
|
|
444
416
|
const previous = state.toolIDs.get(source);
|
|
445
417
|
if (previous)
|
|
446
418
|
return { id: previous, state };
|
|
447
419
|
let attempt = 0;
|
|
448
|
-
let id =
|
|
420
|
+
let id = MistralToolID.hash(source);
|
|
449
421
|
while (state.usedToolIDs.has(id))
|
|
450
|
-
id =
|
|
422
|
+
id = MistralToolID.hash(`${source}:${++attempt}`);
|
|
451
423
|
return {
|
|
452
424
|
id,
|
|
453
425
|
state: {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { LLMRequest } from "../../schema/index.js";
|
|
2
|
+
export declare const valid: RegExp;
|
|
3
|
+
export declare const hash: (value: string) => string;
|
|
4
|
+
export declare const normalizer: (request: LLMRequest) => (id: string) => string;
|
|
5
|
+
export * as MistralToolID from "./mistral-tool-id.js";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const valid = /^[A-Za-z0-9]{9}$/;
|
|
2
|
+
export const hash = (value) => {
|
|
3
|
+
const hash = (seed) => {
|
|
4
|
+
let result = seed;
|
|
5
|
+
for (const char of value)
|
|
6
|
+
result = Math.imul(result ^ char.charCodeAt(0), 16777619);
|
|
7
|
+
return (result >>> 0).toString(36);
|
|
8
|
+
};
|
|
9
|
+
return `${hash(2166136261).padStart(7, "0")}${hash(2246822519).padStart(7, "0")}`.slice(-9);
|
|
10
|
+
};
|
|
11
|
+
export const normalizer = (request) => {
|
|
12
|
+
const ids = request.messages.flatMap((message) => message.content.flatMap((part) => (part.type === "tool-call" || part.type === "tool-result" ? [part.id] : [])));
|
|
13
|
+
// Reserve valid IDs before projecting any history, including IDs encountered later.
|
|
14
|
+
const used = new Set(ids.filter((id) => valid.test(id)));
|
|
15
|
+
const normalized = new Map();
|
|
16
|
+
return (id) => {
|
|
17
|
+
if (valid.test(id))
|
|
18
|
+
return id;
|
|
19
|
+
const previous = normalized.get(id);
|
|
20
|
+
if (previous)
|
|
21
|
+
return previous;
|
|
22
|
+
let attempt = 0;
|
|
23
|
+
let candidate = hash(id);
|
|
24
|
+
while (used.has(candidate))
|
|
25
|
+
candidate = hash(`${id}:${++attempt}`);
|
|
26
|
+
used.add(candidate);
|
|
27
|
+
normalized.set(id, candidate);
|
|
28
|
+
return candidate;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
export * as MistralToolID from "./mistral-tool-id.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
-
"version": "0.0.0-dev-
|
|
3
|
+
"version": "0.0.0-dev-19551",
|
|
4
4
|
"name": "@opencode/ai",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@clack/prompts": "1.0.0-alpha.1",
|
|
32
32
|
"@effect/platform-node": "4.0.0-rc.112",
|
|
33
|
-
"@opencode/http-recorder": "0.0.0-dev-
|
|
33
|
+
"@opencode/http-recorder": "0.0.0-dev-19551",
|
|
34
34
|
"@tsconfig/bun": "1.0.9",
|
|
35
35
|
"@types/bun": "1.4.0",
|
|
36
36
|
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"@aws-sdk/credential-providers": "3.1057.0",
|
|
41
41
|
"@smithy/eventstream-codec": "4.2.14",
|
|
42
42
|
"@smithy/util-utf8": "4.2.2",
|
|
43
|
-
"@opencode/schema": "0.0.0-dev-
|
|
43
|
+
"@opencode/schema": "0.0.0-dev-19551",
|
|
44
44
|
"aws4fetch": "1.0.20",
|
|
45
45
|
"effect": "4.0.0-rc.112",
|
|
46
46
|
"google-auth-library": "10.5.0"
|