|
9 | 9 | //! - Core AI capabilities traits ([`CompletionFeatures`], [`EmbeddingFeatures`]). |
10 | 10 |
|
11 | 11 | use candid::Principal; |
12 | | -use serde::ser::{SerializeMap, SerializeSeq, Serializer}; |
13 | 12 | use serde::{Deserialize, Serialize}; |
14 | 13 | use serde_json::{Map, json}; |
15 | 14 | use std::collections::BTreeMap; |
@@ -376,113 +375,13 @@ pub struct FunctionDefinition { |
376 | 375 | pub description: String, |
377 | 376 |
|
378 | 377 | /// JSON schema defining the function's parameters. |
379 | | - #[serde(serialize_with = "serialize_openapi_schema_ordered")] |
380 | 378 | pub parameters: Json, |
381 | 379 |
|
382 | 380 | /// Whether to enable strict schema adherence when generating the function call. If set to true, the model will follow the exact schema defined in the parameters field. Only a subset of JSON Schema is supported when strict is true. |
383 | 381 | #[serde(skip_serializing_if = "Option::is_none")] |
384 | 382 | pub strict: Option<bool>, |
385 | 383 | } |
386 | 384 |
|
387 | | -pub fn serialize_optional_openapi_schema_ordered<S>( |
388 | | - value: &Option<Json>, |
389 | | - serializer: S, |
390 | | -) -> Result<S::Ok, S::Error> |
391 | | -where |
392 | | - S: Serializer, |
393 | | -{ |
394 | | - match value { |
395 | | - None => serializer.serialize_none(), |
396 | | - Some(v) => serialize_openapi_schema_ordered(v, serializer), |
397 | | - } |
398 | | -} |
399 | | - |
400 | | -pub fn serialize_openapi_schema_ordered<S>(value: &Json, serializer: S) -> Result<S::Ok, S::Error> |
401 | | -where |
402 | | - S: Serializer, |
403 | | -{ |
404 | | - struct Ordered<'a>(&'a Json); |
405 | | - |
406 | | - impl<'a> serde::Serialize for Ordered<'a> { |
407 | | - fn serialize<S2>(&self, serializer: S2) -> Result<S2::Ok, S2::Error> |
408 | | - where |
409 | | - S2: Serializer, |
410 | | - { |
411 | | - serialize_openapi_schema_ordered(self.0, serializer) |
412 | | - } |
413 | | - } |
414 | | - |
415 | | - match value { |
416 | | - Json::Null => serializer.serialize_none(), |
417 | | - Json::Bool(b) => serializer.serialize_bool(*b), |
418 | | - Json::Number(n) => n.serialize(serializer), |
419 | | - Json::String(s) => serializer.serialize_str(s), |
420 | | - Json::Array(items) => { |
421 | | - let mut seq = serializer.serialize_seq(Some(items.len()))?; |
422 | | - for item in items { |
423 | | - seq.serialize_element(&Ordered(item))?; |
424 | | - } |
425 | | - seq.end() |
426 | | - } |
427 | | - Json::Object(map) => { |
428 | | - // Gemini preview models can be sensitive to schema key order. |
429 | | - // Emit a deterministic, schema-friendly ordering recursively: |
430 | | - // 1) common schema keys in a fixed order |
431 | | - // 2) remaining keys in lexical order |
432 | | - |
433 | | - // https://ai.google.dev/api/caching#FunctionDeclaration |
434 | | - const FIXED_ORDER: [&str; 23] = [ |
435 | | - "name", |
436 | | - "type", |
437 | | - "format", |
438 | | - "title", |
439 | | - "description", |
440 | | - "nullable", |
441 | | - "enum", |
442 | | - "maxItems", |
443 | | - "minItems", |
444 | | - "properties", |
445 | | - "required", |
446 | | - "minProperties", |
447 | | - "maxProperties", |
448 | | - "minLength", |
449 | | - "maxLength", |
450 | | - "pattern", |
451 | | - "example", |
452 | | - "anyOf", |
453 | | - "propertyOrdering", |
454 | | - "default", |
455 | | - "items", |
456 | | - "minimum", |
457 | | - "maximum", |
458 | | - ]; |
459 | | - |
460 | | - let mut out = serializer.serialize_map(Some(map.len()))?; |
461 | | - |
462 | | - for key in FIXED_ORDER { |
463 | | - if let Some(v) = map.get(key) { |
464 | | - out.serialize_entry(key, &Ordered(v))?; |
465 | | - } |
466 | | - } |
467 | | - |
468 | | - let mut rest_keys: Vec<&str> = map |
469 | | - .keys() |
470 | | - .map(|k| k.as_str()) |
471 | | - .filter(|k| !FIXED_ORDER.contains(k)) |
472 | | - .collect(); |
473 | | - rest_keys.sort_unstable(); |
474 | | - |
475 | | - for key in rest_keys { |
476 | | - if let Some(v) = map.get(key) { |
477 | | - out.serialize_entry(key, &Ordered(v))?; |
478 | | - } |
479 | | - } |
480 | | - |
481 | | - out.end() |
482 | | - } |
483 | | - } |
484 | | -} |
485 | | - |
486 | 385 | impl FunctionDefinition { |
487 | 386 | /// Modifies the function name with a prefix. |
488 | 387 | pub fn name_with_prefix(mut self, prefix: &str) -> Self { |
|
0 commit comments