@revojs/ai 0.2.32 → 0.2.35

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/dist/index.d.ts CHANGED
@@ -847,7 +847,7 @@ export declare class ModelContextProtocolClient {
847
847
  export declare class ModelContextProtocolConnection {
848
848
  readonly client: ModelContextProtocolClient;
849
849
  constructor(client: ModelContextProtocolClient);
850
- listTools(options?: ModelContextProtocolRequestOptions): Promise<Array<LanguageModelFunctionTool>>;
850
+ listTools(options?: ModelContextProtocolRequestOptions): Promise<Array<ToolDescription>>;
851
851
  executeTool(call: LanguageModelToolCall, options?: ModelContextProtocolRequestOptions): Promise<LanguageModelToolResultPart>;
852
852
  close(): Promise<void>;
853
853
  }
@@ -868,6 +868,7 @@ export declare function useModelsDev(id: string, resolve: (model: ModelsDevModel
868
868
  }>;
869
869
  export declare function modelsDevProtocol(model: ModelsDevModel, provider: ModelsDevProvider): ModelsDevProtocol | undefined;
870
870
  export declare function toToolInput(value: string | undefined): string;
871
+ export declare function toToolParameters(schema: JsonSchema): JSONObject;
871
872
  export declare function mergeHeaders(...headers: Array<Record<string, string | undefined> | undefined>): Record<string, string>;
872
873
  export declare function postJson(url: string, body: unknown, options?: {
873
874
  headers?: Record<string, string | undefined>;
package/dist/index.js CHANGED
@@ -110,7 +110,8 @@ var ModelContextProtocolClient = class {
110
110
  headers: {
111
111
  ...this.headers,
112
112
  "mcp-session-id": sessionId
113
- }
113
+ },
114
+ redirect: "manual"
114
115
  });
115
116
  await response.body?.cancel();
116
117
  if (!response.ok && response.status !== 405) throw new Error(`Model Context Protocol session termination failed with HTTP ${response.status}.`);
@@ -125,8 +126,13 @@ var ModelContextProtocolClient = class {
125
126
  method: "POST",
126
127
  headers,
127
128
  body: JSON.stringify(message),
128
- signal
129
+ signal,
130
+ redirect: "manual"
129
131
  });
132
+ if (response.type === "opaqueredirect" || response.status >= 300 && response.status < 400) {
133
+ await response.body?.cancel();
134
+ throw new Error("Model Context Protocol server redirected the request; configure its final endpoint.");
135
+ }
130
136
  if (!response.ok) {
131
137
  await response.body?.cancel();
132
138
  throw new Error(`Model Context Protocol request failed with HTTP ${response.status}.`);
@@ -187,7 +193,8 @@ var ModelContextProtocolConnection = class {
187
193
  type: "function",
188
194
  name: tool.name,
189
195
  description: tool.description,
190
- inputSchema: tool.inputSchema
196
+ inputSchema: tool.inputSchema,
197
+ annotations: tool.annotations
191
198
  });
192
199
  cursor = result.nextCursor;
193
200
  if (cursor !== void 0 && cursors.has(cursor)) throw new Error("Model Context Protocol server returned a repeated tools pagination cursor.");
@@ -628,6 +635,13 @@ function modelsDevProtocol(model, provider) {
628
635
  function toToolInput(value) {
629
636
  return value === void 0 || value.trim() === "" ? "{}" : value;
630
637
  }
638
+ function toToolParameters(schema) {
639
+ const parameters = {};
640
+ for (const [key, value] of Object.entries(toJsonSchema(schema))) if (!TOOL_PARAMETER_ROOT_KEYWORDS.has(key)) parameters[key] = value;
641
+ parameters.type = "object";
642
+ if (parameters.properties === null || typeof parameters.properties !== "object" || Array.isArray(parameters.properties)) parameters.properties = {};
643
+ return parameters;
644
+ }
631
645
  function mergeHeaders(...headers) {
632
646
  const merged = {};
633
647
  for (const record of headers) for (const [name, value] of Object.entries(record ?? {})) if (value !== void 0) merged[name] = value;
@@ -684,6 +698,16 @@ function toStream(read) {
684
698
  });
685
699
  }
686
700
  var modelsDevCache = { loadedAt: 0 };
701
+ var TOOL_PARAMETER_ROOT_KEYWORDS = /* @__PURE__ */ new Set([
702
+ "anyOf",
703
+ "oneOf",
704
+ "allOf",
705
+ "not",
706
+ "enum",
707
+ "if",
708
+ "then",
709
+ "else"
710
+ ]);
687
711
  var MODEL_CONTEXT_PROTOCOL_VERSIONS = [
688
712
  "2025-11-25",
689
713
  "2025-06-18",
@@ -707,4 +731,4 @@ var JSON_SCHEMA_DRAFTS = {
707
731
  "http://json-schema.org/draft-04/schema#": "4"
708
732
  };
709
733
  //#endregion
710
- export { MODEL_CONTEXT_PROTOCOL_TIMEOUT, MODEL_CONTEXT_PROTOCOL_VERSIONS, ModelContextProtocolClient, ModelContextProtocolConnection, ModelContextProtocolError, ModelContextProtocolErrorCode, defineProvider, defineTool, handleModelContextProtocol, mergeHeaders, modelsDevProtocol, postJson, readDataFrames, toStream, toToolInput, useAi, useModelContextProtocol, useModelsDev, useTools };
734
+ export { MODEL_CONTEXT_PROTOCOL_TIMEOUT, MODEL_CONTEXT_PROTOCOL_VERSIONS, ModelContextProtocolClient, ModelContextProtocolConnection, ModelContextProtocolError, ModelContextProtocolErrorCode, defineProvider, defineTool, handleModelContextProtocol, mergeHeaders, modelsDevProtocol, postJson, readDataFrames, toStream, toToolInput, toToolParameters, useAi, useModelContextProtocol, useModelsDev, useTools };
@@ -8,6 +8,7 @@ export interface AiConfig {
8
8
  name: string;
9
9
  version: string;
10
10
  instructions?: string;
11
+ route: boolean;
11
12
  };
12
13
  }
13
14
  declare const _default: import("revojs/module").Module<"ai", AiConfig, readonly [import("revojs/module").Module<"server", Record<string, never>, []>]>;
@@ -11,13 +11,14 @@ var module_default = defineModule({
11
11
  },
12
12
  modelContextProtocol: {
13
13
  name: "revojs",
14
- version: "1.0.0"
14
+ version: "1.0.0",
15
+ route: false
15
16
  }
16
17
  }),
17
18
  modules: [server],
18
19
  setup(config) {
19
20
  const { fromModule } = useModule(import.meta.url);
20
- addRoutes(config, fromModule("../routes"));
21
+ if (config.ai.modelContextProtocol.route) addRoutes(config, fromModule("../routes"));
21
22
  return {
22
23
  variables: { server: {
23
24
  anthropicApiKey: {
@@ -1,5 +1,4 @@
1
- import { mergeHeaders, postJson, readDataFrames, toStream, toToolInput } from "../index.js";
2
- import { toJsonSchema } from "revojs/shared";
1
+ import { mergeHeaders, postJson, readDataFrames, toStream, toToolInput, toToolParameters } from "../index.js";
3
2
  //#region src/protocols/anthropic-messages.ts
4
3
  function toUsage(inputTokens, cacheRead, cacheWrite, outputTokens) {
5
4
  const raw = {};
@@ -156,7 +155,7 @@ function toBody(options, stream) {
156
155
  else tools.push({
157
156
  name: tool.name,
158
157
  description: tool.description,
159
- input_schema: toJsonSchema(tool.inputSchema)
158
+ input_schema: toToolParameters(tool.inputSchema)
160
159
  });
161
160
  if (cache && tools.length > 0) tools[tools.length - 1].cache_control = { type: "ephemeral" };
162
161
  if (cache && Array.isArray(lastContent)) {
@@ -1,4 +1,4 @@
1
- import { mergeHeaders, postJson, readDataFrames, toStream } from "../index.js";
1
+ import { mergeHeaders, postJson, readDataFrames, toStream, toToolParameters } from "../index.js";
2
2
  import { toJsonSchema } from "revojs/shared";
3
3
  //#region src/protocols/google-models.ts
4
4
  function toBase64(data) {
@@ -96,6 +96,14 @@ function toBody(options) {
96
96
  } catch {
97
97
  args = {};
98
98
  }
99
+ const signature = part.providerOptions?.google?.thoughtSignature;
100
+ if (typeof signature === "string") return [{
101
+ functionCall: {
102
+ name: part.toolName,
103
+ args
104
+ },
105
+ thoughtSignature: signature
106
+ }];
99
107
  return [{ functionCall: {
100
108
  name: part.toolName,
101
109
  args
@@ -115,6 +123,14 @@ function toBody(options) {
115
123
  });
116
124
  return [];
117
125
  });
126
+ let signed = false;
127
+ for (const part of parts) if (part.functionCall !== void 0 && part.thoughtSignature !== void 0) signed = true;
128
+ if (!signed) {
129
+ for (const part of parts) if (part.functionCall !== void 0) {
130
+ part.thoughtSignature = SKIP_THOUGHT_SIGNATURE;
131
+ break;
132
+ }
133
+ }
118
134
  if (parts.length > 0) contents.push({
119
135
  role: "model",
120
136
  parts
@@ -135,7 +151,7 @@ function toBody(options) {
135
151
  return [{
136
152
  name: tool.name,
137
153
  description: tool.description,
138
- parameters: toJsonSchema(tool.inputSchema)
154
+ parameters: toToolParameters(tool.inputSchema)
139
155
  }];
140
156
  });
141
157
  return [{
@@ -221,12 +237,14 @@ async function* readParts(response, warnings) {
221
237
  }
222
238
  if (part.functionCall !== void 0) {
223
239
  toolCalls = true;
224
- yield {
240
+ const call = {
225
241
  type: "tool-call",
226
242
  toolCallId: `gemini-tool-${toolCount++}`,
227
243
  toolName: part.functionCall.name ?? "",
228
244
  input: JSON.stringify(part.functionCall.args ?? {})
229
245
  };
246
+ if (part.thoughtSignature !== void 0) call.providerMetadata = { google: { thoughtSignature: part.thoughtSignature } };
247
+ yield call;
230
248
  continue;
231
249
  }
232
250
  if (typeof part.text === "string" && part.text.length > 0) {
@@ -280,12 +298,14 @@ function geminiGenerateProtocol(config) {
280
298
  }
281
299
  if (part.functionCall !== void 0) {
282
300
  toolCalls = true;
283
- content.push({
301
+ const call = {
284
302
  type: "tool-call",
285
303
  toolCallId: `gemini-tool-${toolCount++}`,
286
304
  toolName: part.functionCall.name ?? "",
287
305
  input: JSON.stringify(part.functionCall.args ?? {})
288
- });
306
+ };
307
+ if (part.thoughtSignature !== void 0) call.providerMetadata = { google: { thoughtSignature: part.thoughtSignature } };
308
+ content.push(call);
289
309
  continue;
290
310
  }
291
311
  if (typeof part.text === "string" && part.text.length > 0) content.push({
@@ -321,5 +341,6 @@ function geminiStreamProtocol(config) {
321
341
  };
322
342
  };
323
343
  }
344
+ var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
324
345
  //#endregion
325
346
  export { geminiGenerateProtocol, geminiStreamProtocol };
@@ -1,4 +1,4 @@
1
- import { mergeHeaders, postJson, readDataFrames, toStream, toToolInput } from "../index.js";
1
+ import { mergeHeaders, postJson, readDataFrames, toStream, toToolInput, toToolParameters } from "../index.js";
2
2
  import { toJsonSchema } from "revojs/shared";
3
3
  //#region src/protocols/openai-chat-completions.ts
4
4
  function toMessages(prompt) {
@@ -91,7 +91,7 @@ function toBody(config, options, stream) {
91
91
  function: {
92
92
  name: tool.name,
93
93
  description: tool.description,
94
- parameters: toJsonSchema(tool.inputSchema),
94
+ parameters: toToolParameters(tool.inputSchema),
95
95
  strict: tool.strict
96
96
  }
97
97
  }) } : {},
@@ -214,7 +214,7 @@ async function* readParts(response, warnings) {
214
214
  let accumulator = tools.get(index);
215
215
  if (accumulator === void 0) {
216
216
  accumulator = {
217
- streamId: `openai-tool-${index}`,
217
+ streamId: partial.id ?? `openai-tool-${index}`,
218
218
  callId: partial.id ?? "",
219
219
  name: "",
220
220
  arguments: ""
@@ -1,4 +1,4 @@
1
- import { mergeHeaders, postJson, readDataFrames, toStream, toToolInput } from "../index.js";
1
+ import { mergeHeaders, postJson, readDataFrames, toStream, toToolInput, toToolParameters } from "../index.js";
2
2
  import { toJsonSchema } from "revojs/shared";
3
3
  //#region src/protocols/openai-responses.ts
4
4
  function toUsage(usage) {
@@ -142,7 +142,7 @@ function toBody(options, stream) {
142
142
  type: "function",
143
143
  name: tool.name,
144
144
  description: tool.description,
145
- parameters: toJsonSchema(tool.inputSchema),
145
+ parameters: toToolParameters(tool.inputSchema),
146
146
  strict: tool.strict
147
147
  }) } : {},
148
148
  ...options.toolChoice !== void 0 ? { tool_choice: options.toolChoice.type === "tool" ? {
@@ -188,17 +188,17 @@ async function* readParts(response, warnings) {
188
188
  continue;
189
189
  }
190
190
  if (event.type === "response.output_item.added" && event.item?.type === "function_call") {
191
- const streamId = event.item.id ?? event.item.call_id ?? `responses-tool-${event.output_index ?? tools.size}`;
191
+ const itemId = event.item.id ?? event.item.call_id ?? `responses-tool-${event.output_index ?? tools.size}`;
192
192
  const record = {
193
- streamId,
193
+ streamId: event.item.call_id ?? itemId,
194
194
  callId: event.item.call_id ?? "",
195
195
  name: event.item.name ?? "",
196
196
  arguments: ""
197
197
  };
198
- tools.set(streamId, record);
198
+ tools.set(itemId, record);
199
199
  yield {
200
200
  type: "tool-input-start",
201
- id: streamId,
201
+ id: record.streamId,
202
202
  toolName: record.name
203
203
  };
204
204
  continue;
@@ -255,7 +255,7 @@ async function* readParts(response, warnings) {
255
255
  record.arguments += event.delta;
256
256
  yield {
257
257
  type: "tool-input-delta",
258
- id: event.item_id,
258
+ id: record.streamId,
259
259
  delta: event.delta
260
260
  };
261
261
  }
@@ -265,7 +265,7 @@ async function* readParts(response, warnings) {
265
265
  const itemId = event.item.id ?? "";
266
266
  if (event.item.type === "function_call") {
267
267
  const record = tools.get(itemId);
268
- const streamId = record?.streamId ?? itemId;
268
+ const streamId = record?.streamId ?? event.item.call_id ?? itemId;
269
269
  tools.delete(itemId);
270
270
  hasToolCall = true;
271
271
  yield {
@@ -308,7 +308,7 @@ async function* readParts(response, warnings) {
308
308
  type: "reasoning-end",
309
309
  id
310
310
  };
311
- for (const [id, record] of tools) {
311
+ for (const record of tools.values()) {
312
312
  yield {
313
313
  type: "tool-input-end",
314
314
  id: record.streamId
@@ -316,7 +316,7 @@ async function* readParts(response, warnings) {
316
316
  hasToolCall = true;
317
317
  yield {
318
318
  type: "tool-call",
319
- toolCallId: record.callId || id,
319
+ toolCallId: record.callId || record.streamId,
320
320
  toolName: record.name,
321
321
  input: toToolInput(record.arguments)
322
322
  };
@@ -2,6 +2,7 @@ import { defineProvider, modelsDevProtocol, useModelsDev } from "../index.js";
2
2
  import { messagesGenerateProtocol, messagesStreamProtocol } from "../protocols/anthropic-messages.js";
3
3
  import { chatCompletionsGenerateProtocol, chatCompletionsStreamProtocol } from "../protocols/openai-chat-completions.js";
4
4
  import { responsesGenerateProtocol, responsesStreamProtocol } from "../protocols/openai-responses.js";
5
+ import { geminiGenerateProtocol, geminiStreamProtocol } from "../protocols/google-models.js";
5
6
  import { useVariables } from "revojs";
6
7
  //#region src/providers/opencode-go.ts
7
8
  var opencode_go_default = defineProvider({ setup(scope) {
@@ -47,6 +48,16 @@ var opencode_go_default = defineProvider({ setup(scope) {
47
48
  };
48
49
  return useModelsDev("opencode-go", (model, provider) => {
49
50
  const protocol = modelsDevProtocol(model, provider);
51
+ if (protocol === "google-models") {
52
+ const google = {
53
+ baseURL: model.provider?.api ?? "https://opencode.ai/inference/go/google/v1beta",
54
+ apiKey: variables.opencodeApiKey
55
+ };
56
+ return {
57
+ textGenerate: withSession(geminiGenerateProtocol(google)),
58
+ textStream: withSession(geminiStreamProtocol(google))
59
+ };
60
+ }
50
61
  return protocol === void 0 ? void 0 : protocols[protocol];
51
62
  });
52
63
  } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revojs/ai",
3
- "version": "0.2.32",
3
+ "version": "0.2.35",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",