@oh-my-pi/pi-ai 4.4.5 → 4.4.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-ai",
3
- "version": "4.4.5",
3
+ "version": "4.4.8",
4
4
  "description": "Unified LLM API with automatic model discovery and provider configuration",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -695,7 +695,7 @@ function buildRequest(
695
695
  }
696
696
 
697
697
  if (context.tools && context.tools.length > 0) {
698
- request.tools = convertTools(context.tools);
698
+ request.tools = convertTools(context.tools, model);
699
699
  if (options.toolChoice) {
700
700
  request.toolConfig = {
701
701
  functionCallingConfig: {
@@ -211,51 +211,89 @@ export function sanitizeSchemaForGoogle(value: unknown): unknown {
211
211
  return value;
212
212
  }
213
213
 
214
+ const obj = value as Record<string, unknown>;
214
215
  const result: Record<string, unknown> = {};
215
- let constValue: unknown | undefined;
216
216
 
217
- for (const [key, entry] of Object.entries(value)) {
218
- if (UNSUPPORTED_SCHEMA_FIELDS.has(key)) {
219
- continue;
217
+ // Collapse anyOf/oneOf of const values into enum
218
+ for (const combiner of ["anyOf", "oneOf"] as const) {
219
+ if (Array.isArray(obj[combiner])) {
220
+ const variants = obj[combiner] as Record<string, unknown>[];
221
+
222
+ // Check if ALL variants have a const field
223
+ const allHaveConst = variants.every((v) => v && typeof v === "object" && "const" in v);
224
+
225
+ if (allHaveConst && variants.length > 0) {
226
+ // Extract all const values into enum
227
+ result.enum = variants.map((v) => v.const);
228
+
229
+ // Inherit type from first variant if present
230
+ const firstType = variants[0]?.type;
231
+ if (firstType) {
232
+ result.type = firstType;
233
+ }
234
+
235
+ // Copy description and other top-level fields (not the combiner)
236
+ for (const [key, entry] of Object.entries(obj)) {
237
+ if (key !== combiner && !(key in result)) {
238
+ result[key] = sanitizeSchemaForGoogle(entry);
239
+ }
240
+ }
241
+ return result;
242
+ }
220
243
  }
244
+ }
245
+
246
+ // Regular field processing
247
+ let constValue: unknown;
248
+ for (const [key, entry] of Object.entries(obj)) {
249
+ if (UNSUPPORTED_SCHEMA_FIELDS.has(key)) continue;
221
250
  if (key === "const") {
222
251
  constValue = entry;
223
252
  continue;
224
253
  }
225
- if (key === "additionalProperties" && entry === false) {
226
- continue;
227
- }
254
+ if (key === "additionalProperties" && entry === false) continue;
228
255
  result[key] = sanitizeSchemaForGoogle(entry);
229
256
  }
230
257
 
231
258
  if (constValue !== undefined) {
232
- const existingEnum = Array.isArray(result.enum) ? [...result.enum] : undefined;
233
- const enumValues = existingEnum ?? [];
234
- if (!enumValues.some((item) => Object.is(item, constValue))) {
235
- enumValues.push(constValue);
259
+ // Convert const to enum, merging with existing enum if present
260
+ const existingEnum = Array.isArray(result.enum) ? result.enum : [];
261
+ if (!existingEnum.some((item) => Object.is(item, constValue))) {
262
+ existingEnum.push(constValue);
263
+ }
264
+ result.enum = existingEnum;
265
+ if (!result.type) {
266
+ result.type =
267
+ typeof constValue === "string"
268
+ ? "string"
269
+ : typeof constValue === "number"
270
+ ? "number"
271
+ : typeof constValue === "boolean"
272
+ ? "boolean"
273
+ : undefined;
236
274
  }
237
- result.enum = enumValues;
238
275
  }
239
276
 
240
277
  return result;
241
278
  }
242
279
 
280
+ function sanitizeToolForGoogle(tool: Tool): Tool {
281
+ return {
282
+ name: tool.name,
283
+ description: tool.description,
284
+ parameters: sanitizeSchemaForGoogle(tool.parameters) as any,
285
+ };
286
+ }
287
+
243
288
  /**
244
289
  * Convert tools to Gemini function declarations format.
245
290
  */
246
291
  export function convertTools(
247
292
  tools: Tool[],
293
+ _model: Model<"google-generative-ai" | "google-gemini-cli" | "google-vertex">,
248
294
  ): { functionDeclarations: { name: string; description?: string; parameters: Schema }[] }[] | undefined {
249
295
  if (tools.length === 0) return undefined;
250
- return [
251
- {
252
- functionDeclarations: tools.map((tool) => ({
253
- name: tool.name,
254
- description: tool.description,
255
- parameters: sanitizeSchemaForGoogle(tool.parameters) as Schema,
256
- })),
257
- },
258
- ];
296
+ return [{ functionDeclarations: tools.map(sanitizeToolForGoogle) }];
259
297
  }
260
298
 
261
299
  /**
@@ -326,7 +326,7 @@ function buildParams(
326
326
  const config: GenerateContentConfig = {
327
327
  ...(Object.keys(generationConfig).length > 0 && generationConfig),
328
328
  ...(context.systemPrompt && { systemInstruction: sanitizeSurrogates(context.systemPrompt) }),
329
- ...(context.tools && context.tools.length > 0 && { tools: convertTools(context.tools) }),
329
+ ...(context.tools && context.tools.length > 0 && { tools: convertTools(context.tools, model) }),
330
330
  };
331
331
 
332
332
  if (context.tools && context.tools.length > 0 && options.toolChoice) {
@@ -297,7 +297,7 @@ function buildParams(
297
297
  const config: GenerateContentConfig = {
298
298
  ...(Object.keys(generationConfig).length > 0 && generationConfig),
299
299
  ...(context.systemPrompt && { systemInstruction: sanitizeSurrogates(context.systemPrompt) }),
300
- ...(context.tools && context.tools.length > 0 && { tools: convertTools(context.tools) }),
300
+ ...(context.tools && context.tools.length > 0 && { tools: convertTools(context.tools, model) }),
301
301
  };
302
302
 
303
303
  if (context.tools && context.tools.length > 0 && options.toolChoice) {
@@ -11,7 +11,7 @@ import { type TUnsafe, Type } from "@sinclair/typebox";
11
11
  *
12
12
  * type Operation = Static<typeof OperationSchema>; // "add" | "subtract" | "multiply" | "divide"
13
13
  */
14
- export function StringEnum<T extends readonly string[]>(
14
+ export function StringEnum<const T extends readonly string[]>(
15
15
  values: T,
16
16
  options?: { description?: string; default?: T[number] },
17
17
  ): TUnsafe<T[number]> {