@sayknow-cli/ai 0.4.2 → 0.4.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.
Files changed (186) hide show
  1. package/dist/types/api-registry.d.ts +30 -0
  2. package/dist/types/auth-broker/client.d.ts +67 -0
  3. package/dist/types/auth-broker/index.d.ts +5 -0
  4. package/dist/types/auth-broker/refresher.d.ts +25 -0
  5. package/dist/types/auth-broker/remote-store.d.ts +99 -0
  6. package/dist/types/auth-broker/server.d.ts +32 -0
  7. package/dist/types/auth-broker/types.d.ts +110 -0
  8. package/dist/types/auth-broker/wire-schemas.d.ts +443 -0
  9. package/dist/types/auth-gateway/http.d.ts +40 -0
  10. package/dist/types/auth-gateway/index.d.ts +3 -0
  11. package/dist/types/auth-gateway/server.d.ts +36 -0
  12. package/dist/types/auth-gateway/types.d.ts +115 -0
  13. package/dist/types/auth-storage.d.ts +699 -0
  14. package/dist/types/cli.d.ts +2 -0
  15. package/dist/types/context-cap-policy.d.ts +10 -0
  16. package/dist/types/index.d.ts +53 -0
  17. package/dist/types/model-cache.d.ts +19 -0
  18. package/dist/types/model-manager.d.ts +64 -0
  19. package/dist/types/model-retirements.d.ts +6 -0
  20. package/dist/types/model-thinking.d.ts +74 -0
  21. package/dist/types/models.d.ts +21 -0
  22. package/dist/types/provider-details.d.ts +24 -0
  23. package/dist/types/provider-models/bundled-references.d.ts +4 -0
  24. package/dist/types/provider-models/descriptors.d.ts +48 -0
  25. package/dist/types/provider-models/google.d.ts +20 -0
  26. package/dist/types/provider-models/index.d.ts +5 -0
  27. package/dist/types/provider-models/ollama.d.ts +7 -0
  28. package/dist/types/provider-models/openai-compat.d.ts +256 -0
  29. package/dist/types/provider-models/special.d.ts +19 -0
  30. package/dist/types/providers/amazon-bedrock.d.ts +60 -0
  31. package/dist/types/providers/anthropic-messages-server-schema.d.ts +450 -0
  32. package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
  33. package/dist/types/providers/anthropic.d.ts +209 -0
  34. package/dist/types/providers/aws-credential-config.d.ts +19 -0
  35. package/dist/types/providers/aws-credentials.d.ts +43 -0
  36. package/dist/types/providers/aws-eventstream.d.ts +38 -0
  37. package/dist/types/providers/aws-sigv4.d.ts +55 -0
  38. package/dist/types/providers/azure-openai-responses.d.ts +15 -0
  39. package/dist/types/providers/composer-discipline.d.ts +26 -0
  40. package/dist/types/providers/cursor/client-version.d.ts +10 -0
  41. package/dist/types/providers/cursor/gen/agent_pb.d.ts +13022 -0
  42. package/dist/types/providers/cursor.d.ts +45 -0
  43. package/dist/types/providers/error-message.d.ts +27 -0
  44. package/dist/types/providers/github-copilot-headers.d.ts +40 -0
  45. package/dist/types/providers/gitlab-duo.d.ts +27 -0
  46. package/dist/types/providers/google-auth.d.ts +24 -0
  47. package/dist/types/providers/google-gemini-cli.d.ts +75 -0
  48. package/dist/types/providers/google-gemini-headers.d.ts +43 -0
  49. package/dist/types/providers/google-shared.d.ts +179 -0
  50. package/dist/types/providers/google-types.d.ts +138 -0
  51. package/dist/types/providers/google-vertex.d.ts +7 -0
  52. package/dist/types/providers/google.d.ts +4 -0
  53. package/dist/types/providers/grammar.d.ts +1 -0
  54. package/dist/types/providers/kimi.d.ts +27 -0
  55. package/dist/types/providers/mock.d.ts +177 -0
  56. package/dist/types/providers/ollama.d.ts +41 -0
  57. package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
  58. package/dist/types/providers/openai-bounded-rate-limits.d.ts +3 -0
  59. package/dist/types/providers/openai-chat-server-schema.d.ts +815 -0
  60. package/dist/types/providers/openai-chat-server.d.ts +16 -0
  61. package/dist/types/providers/openai-codex/constants.d.ts +26 -0
  62. package/dist/types/providers/openai-codex/request-transformer.d.ts +50 -0
  63. package/dist/types/providers/openai-codex/response-handler.d.ts +18 -0
  64. package/dist/types/providers/openai-codex-responses.d.ts +68 -0
  65. package/dist/types/providers/openai-completions-compat.d.ts +27 -0
  66. package/dist/types/providers/openai-completions.d.ts +33 -0
  67. package/dist/types/providers/openai-request-transform.d.ts +4 -0
  68. package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
  69. package/dist/types/providers/openai-responses-server.d.ts +17 -0
  70. package/dist/types/providers/openai-responses-shared.d.ts +104 -0
  71. package/dist/types/providers/openai-responses.d.ts +32 -0
  72. package/dist/types/providers/pi-native-client.d.ts +13 -0
  73. package/dist/types/providers/pi-native-server.d.ts +60 -0
  74. package/dist/types/providers/register-builtins.d.ts +31 -0
  75. package/dist/types/providers/synthetic.d.ts +26 -0
  76. package/dist/types/providers/transform-messages.d.ts +14 -0
  77. package/dist/types/providers/vision-guard.d.ts +8 -0
  78. package/dist/types/rate-limit-utils.d.ts +19 -0
  79. package/dist/types/stream.d.ts +43 -0
  80. package/dist/types/types.d.ts +882 -0
  81. package/dist/types/usage/claude.d.ts +3 -0
  82. package/dist/types/usage/gemini.d.ts +2 -0
  83. package/dist/types/usage/github-copilot.d.ts +7 -0
  84. package/dist/types/usage/google-antigravity.d.ts +2 -0
  85. package/dist/types/usage/grok-cli.d.ts +10 -0
  86. package/dist/types/usage/kimi.d.ts +2 -0
  87. package/dist/types/usage/minimax-code.d.ts +2 -0
  88. package/dist/types/usage/openai-codex.d.ts +3 -0
  89. package/dist/types/usage/shared.d.ts +1 -0
  90. package/dist/types/usage/zai.d.ts +2 -0
  91. package/dist/types/usage.d.ts +258 -0
  92. package/dist/types/utils/abort.d.ts +19 -0
  93. package/dist/types/utils/anthropic-auth.d.ts +31 -0
  94. package/dist/types/utils/discovery/antigravity.d.ts +67 -0
  95. package/dist/types/utils/discovery/codex.d.ts +38 -0
  96. package/dist/types/utils/discovery/cursor.d.ts +23 -0
  97. package/dist/types/utils/discovery/gemini.d.ts +25 -0
  98. package/dist/types/utils/discovery/index.d.ts +4 -0
  99. package/dist/types/utils/discovery/openai-compatible.d.ts +74 -0
  100. package/dist/types/utils/event-stream.d.ts +39 -0
  101. package/dist/types/utils/fallback-transport.d.ts +66 -0
  102. package/dist/types/utils/fireworks-model-id.d.ts +10 -0
  103. package/dist/types/utils/foundry.d.ts +1 -0
  104. package/dist/types/utils/h2-fetch.d.ts +22 -0
  105. package/dist/types/utils/http-inspector.d.ts +35 -0
  106. package/dist/types/utils/idle-iterator.d.ts +67 -0
  107. package/dist/types/utils/json-parse.d.ts +18 -0
  108. package/dist/types/utils/oauth/alibaba-coding-plan.d.ts +18 -0
  109. package/dist/types/utils/oauth/anthropic.d.ts +22 -0
  110. package/dist/types/utils/oauth/api-key-login.d.ts +35 -0
  111. package/dist/types/utils/oauth/api-key-validation.d.ts +27 -0
  112. package/dist/types/utils/oauth/callback-server.d.ts +60 -0
  113. package/dist/types/utils/oauth/cerebras.d.ts +1 -0
  114. package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
  115. package/dist/types/utils/oauth/cursor.d.ts +15 -0
  116. package/dist/types/utils/oauth/deepinfra.d.ts +1 -0
  117. package/dist/types/utils/oauth/deepseek.d.ts +10 -0
  118. package/dist/types/utils/oauth/firepass.d.ts +1 -0
  119. package/dist/types/utils/oauth/fireworks.d.ts +1 -0
  120. package/dist/types/utils/oauth/fugu.d.ts +1 -0
  121. package/dist/types/utils/oauth/github-copilot.d.ts +38 -0
  122. package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
  123. package/dist/types/utils/oauth/glm-zcode.d.ts +71 -0
  124. package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
  125. package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
  126. package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
  127. package/dist/types/utils/oauth/huggingface.d.ts +19 -0
  128. package/dist/types/utils/oauth/index.d.ts +39 -0
  129. package/dist/types/utils/oauth/kagi.d.ts +17 -0
  130. package/dist/types/utils/oauth/kilo.d.ts +5 -0
  131. package/dist/types/utils/oauth/kimi.d.ts +21 -0
  132. package/dist/types/utils/oauth/litellm.d.ts +18 -0
  133. package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
  134. package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
  135. package/dist/types/utils/oauth/moonshot.d.ts +1 -0
  136. package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
  137. package/dist/types/utils/oauth/nvidia.d.ts +18 -0
  138. package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
  139. package/dist/types/utils/oauth/ollama.d.ts +18 -0
  140. package/dist/types/utils/oauth/openai-codex.d.ts +21 -0
  141. package/dist/types/utils/oauth/opencode.d.ts +18 -0
  142. package/dist/types/utils/oauth/parallel.d.ts +17 -0
  143. package/dist/types/utils/oauth/perplexity.d.ts +9 -0
  144. package/dist/types/utils/oauth/pkce.d.ts +8 -0
  145. package/dist/types/utils/oauth/qianfan.d.ts +17 -0
  146. package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
  147. package/dist/types/utils/oauth/synthetic.d.ts +1 -0
  148. package/dist/types/utils/oauth/tavily.d.ts +17 -0
  149. package/dist/types/utils/oauth/together.d.ts +1 -0
  150. package/dist/types/utils/oauth/types.d.ts +45 -0
  151. package/dist/types/utils/oauth/venice.d.ts +18 -0
  152. package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
  153. package/dist/types/utils/oauth/vllm.d.ts +16 -0
  154. package/dist/types/utils/oauth/xai.d.ts +30 -0
  155. package/dist/types/utils/oauth/xiaomi.d.ts +25 -0
  156. package/dist/types/utils/oauth/zai.d.ts +18 -0
  157. package/dist/types/utils/oauth/zenmux.d.ts +1 -0
  158. package/dist/types/utils/overflow.d.ts +14 -0
  159. package/dist/types/utils/parse-bind.d.ts +23 -0
  160. package/dist/types/utils/provider-response.d.ts +3 -0
  161. package/dist/types/utils/retry-after.d.ts +3 -0
  162. package/dist/types/utils/retry-budget.d.ts +1 -0
  163. package/dist/types/utils/retry.d.ts +27 -0
  164. package/dist/types/utils/schema/adapt.d.ts +24 -0
  165. package/dist/types/utils/schema/compatibility.d.ts +30 -0
  166. package/dist/types/utils/schema/dereference.d.ts +11 -0
  167. package/dist/types/utils/schema/draft.d.ts +10 -0
  168. package/dist/types/utils/schema/equality.d.ts +4 -0
  169. package/dist/types/utils/schema/fields.d.ts +49 -0
  170. package/dist/types/utils/schema/index.d.ts +14 -0
  171. package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
  172. package/dist/types/utils/schema/meta-validator.d.ts +2 -0
  173. package/dist/types/utils/schema/normalize.d.ts +93 -0
  174. package/dist/types/utils/schema/root-combinator.d.ts +12 -0
  175. package/dist/types/utils/schema/spill.d.ts +8 -0
  176. package/dist/types/utils/schema/stamps.d.ts +25 -0
  177. package/dist/types/utils/schema/types.d.ts +4 -0
  178. package/dist/types/utils/schema/wire.d.ts +54 -0
  179. package/dist/types/utils/schema/zod-decontaminate.d.ts +31 -0
  180. package/dist/types/utils/sse-debug.d.ts +10 -0
  181. package/dist/types/utils/tool-call-healing.d.ts +71 -0
  182. package/dist/types/utils/tool-choice-capability.d.ts +41 -0
  183. package/dist/types/utils/tool-choice.d.ts +50 -0
  184. package/dist/types/utils/validation.d.ts +17 -0
  185. package/dist/types/utils.d.ts +89 -0
  186. package/package.json +25 -24
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Schema compatibility audits.
3
+ *
4
+ * Each provider has a different idea of what JSON Schema features it accepts
5
+ * for tool definitions. The normalizers in `normalize.ts`, `strict-mode`,
6
+ * and `adapt.ts` rewrite incoming schemas to fit. This module is the
7
+ * *audit* counterpart: it walks a (presumably already-sanitized) schema and
8
+ * reports any feature the target provider would reject. Tests use it to lock
9
+ * down the contract; the runtime uses it to fail-open with diagnostic logs
10
+ * rather than silently shipping a broken tool definition.
11
+ */
12
+ export type SchemaCompatibilityProvider = "openai-strict" | "google" | "cloud-code-assist-claude";
13
+ export interface SchemaCompatibilityViolation {
14
+ path: string;
15
+ rule: string;
16
+ message: string;
17
+ key?: string;
18
+ value?: unknown;
19
+ }
20
+ export interface SchemaCompatibilityResult {
21
+ provider: SchemaCompatibilityProvider;
22
+ compatible: boolean;
23
+ violations: SchemaCompatibilityViolation[];
24
+ }
25
+ export interface StrictSchemaEnforcementResult {
26
+ schema: Record<string, unknown>;
27
+ strict: boolean;
28
+ }
29
+ export declare function validateSchemaCompatibility(schema: unknown, provider: SchemaCompatibilityProvider): SchemaCompatibilityResult;
30
+ export declare function validateStrictSchemaEnforcement(originalSchema: Record<string, unknown>, result: StrictSchemaEnforcementResult): SchemaCompatibilityResult;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Dereference all local `$ref` pointers in a JSON Schema, inlining definitions
3
+ * from `$defs` / `definitions`. The `$defs` block is stripped from the output.
4
+ *
5
+ * Non-local refs (e.g. `http://...`) are left untouched.
6
+ * Circular references are broken with `{}`.
7
+ *
8
+ * @returns A new schema object with all local refs inlined, or the input unchanged
9
+ * if it's not an object or has no `$defs`/`definitions`.
10
+ */
11
+ export declare function dereferenceJsonSchema(schema: unknown): unknown;
@@ -0,0 +1,10 @@
1
+ export declare const JSON_SCHEMA_DRAFT_2020_12_URI = "https://json-schema.org/draft/2020-12/schema";
2
+ /** Pre-check entrypoint. Exposed so callers can decide whether to take the upgrade path at all. */
3
+ export declare function schemaNeedsDraft202012Upgrade(schema: unknown): boolean;
4
+ /**
5
+ * Upgrade legacy JSON Schema shapes to the draft 2020-12 form emitted by Zod.
6
+ *
7
+ * This keeps extension/MCP/TypeBox schemas compatible with providers whose tool
8
+ * validators reject draft-07 tuple and dependency keywords.
9
+ */
10
+ export declare function upgradeJsonSchemaTo202012(schema: unknown): unknown;
@@ -0,0 +1,4 @@
1
+ import type { JsonObject } from "./types";
2
+ export declare function areJsonValuesEqual(left: unknown, right: unknown): boolean;
3
+ export declare function mergeCompatibleEnumSchemas(existing: unknown, incoming: unknown): JsonObject | null;
4
+ export declare function mergePropertySchemas(existing: unknown, incoming: unknown): unknown;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Field classification sets for JSON Schema sanitization across providers.
3
+ *
4
+ * Each set serves a different provider need. They overlap intentionally —
5
+ * co-locating them makes the overlap visible and maintainable.
6
+ *
7
+ * All keysets here are static and small (≤ ~40 entries) so they live as
8
+ * `Record<string, true>` literals — `k in REC` resolves through hidden
9
+ * class inline caches without the per-call hashtable cost of `Set.has`.
10
+ */
11
+ /**
12
+ * Google Generative AI unsupported schema fields.
13
+ * Stripped during normalizeSchemaForGoogle / normalizeSchemaForCCA.
14
+ */
15
+ export declare const UNSUPPORTED_SCHEMA_FIELDS: Record<string, true>;
16
+ /**
17
+ * Human-meaningful validation/decorative keywords that can be preserved in a
18
+ * sibling description when a provider-specific normalizer strips them from the
19
+ * wire schema.
20
+ */
21
+ export declare const LIFTABLE_TO_DESCRIPTION_FIELDS: Record<string, true>;
22
+ /**
23
+ * Non-structural schema keys stripped during OpenAI strict mode sanitization.
24
+ * These are decorative/validation-only keywords that don't affect the structural
25
+ * shape OpenAI's strict mode enforces.
26
+ */
27
+ export declare const NON_STRUCTURAL_SCHEMA_KEYS: Record<string, true>;
28
+ /**
29
+ * Cloud Code Assist type-specific allowed keys per JSON Schema type.
30
+ * Used when collapsing mixed-type combiner variants for CCA Anthropic model.
31
+ */
32
+ export declare const CLOUD_CODE_ASSIST_TYPE_SPECIFIC_KEYS: Record<string, Record<string, true>>;
33
+ /**
34
+ * Cloud Code Assist shared schema keys allowed on any type.
35
+ * Used alongside CLOUD_CODE_ASSIST_TYPE_SPECIFIC_KEYS for CCA combiner collapsing.
36
+ */
37
+ export declare const CLOUD_CODE_ASSIST_SHARED_SCHEMA_KEYS: Record<string, true>;
38
+ /**
39
+ * Combinator keys used across schema sanitization modules.
40
+ * Defined once to avoid duplication in strict-mode.ts and normalize.ts.
41
+ */
42
+ export declare const COMBINATOR_KEYS: readonly ["anyOf", "allOf", "oneOf"];
43
+ /**
44
+ * Cloud Code Assist Anthropic model unsupported schema fields.
45
+ * Much smaller than UNSUPPORTED_SCHEMA_FIELDS (Google) because CCA supports
46
+ * validation keywords like additionalProperties, minLength, pattern, etc.
47
+ * Meta/reference keywords plus object-key validators that CCA cannot resolve are stripped.
48
+ */
49
+ export declare const CCA_UNSUPPORTED_SCHEMA_FIELDS: Record<string, true>;
@@ -0,0 +1,14 @@
1
+ export * from "./adapt";
2
+ export * from "./compatibility";
3
+ export * from "./dereference";
4
+ export * from "./draft";
5
+ export * from "./equality";
6
+ export * from "./fields";
7
+ export * from "./json-schema-validator";
8
+ export * from "./meta-validator";
9
+ export * from "./normalize";
10
+ export * from "./root-combinator";
11
+ export * from "./spill";
12
+ export * from "./types";
13
+ export * from "./wire";
14
+ export * from "./zod-decontaminate";
@@ -0,0 +1,12 @@
1
+ export interface JsonSchemaValidationIssue {
2
+ path: PropertyKey[];
3
+ message: string;
4
+ expectedTypes?: string[];
5
+ keyword?: string;
6
+ }
7
+ export interface JsonSchemaValidationResult {
8
+ success: boolean;
9
+ issues: JsonSchemaValidationIssue[];
10
+ }
11
+ export declare function validateJsonSchemaValue(schema: unknown, value: unknown): JsonSchemaValidationResult;
12
+ export declare function isJsonSchemaValueValid(schema: unknown, value: unknown): boolean;
@@ -0,0 +1,2 @@
1
+ /** Validate that `schema` is structurally a valid JSON Schema (subset). */
2
+ export declare function isValidJsonSchema(schema: unknown): boolean;
@@ -0,0 +1,93 @@
1
+ import { type DescriptionSpillFormat } from "./spill";
2
+ import { type JsonObject } from "./types";
3
+ export type ResidualSchemaIncompatibility = "type-array" | "type-null" | "nullable" | "combiners";
4
+ export interface NormalizeSchemaOptions {
5
+ unsupportedFields: (key: string) => boolean;
6
+ normalizeFieldNames: boolean;
7
+ collapseNullFields: boolean;
8
+ normalizeTypeArrayToNullable: boolean;
9
+ stripNullableKeyword: boolean;
10
+ autoPropertyOrdering: boolean;
11
+ ensureObjectProperties: boolean;
12
+ liftStrippedToDescription: false | {
13
+ keys?: (key: string) => boolean;
14
+ format?: DescriptionSpillFormat;
15
+ };
16
+ mergeObjectCombiners: boolean;
17
+ collapseSameTypeCombiners: boolean;
18
+ collapseMixedTypeCombiners: boolean;
19
+ stripResidualCombinersFixpoint: boolean;
20
+ extractNullableFromUnions: boolean;
21
+ rejectResidualIncompatibilities?: ReadonlyArray<ResidualSchemaIncompatibility>;
22
+ validateAndFallback?: {
23
+ fallback: unknown;
24
+ };
25
+ }
26
+ /** Copy all keys from a schema except the specified combiner key. */
27
+ export declare function copySchemaWithout(schema: JsonObject, combiner: string): JsonObject;
28
+ /**
29
+ * Recursively strip any remaining anyOf/oneOf that same-type or mixed-type
30
+ * collapse can handle. This is needed because object-combiner merging can
31
+ * create new anyOf in merged subtrees after child normalization already ran.
32
+ */
33
+ export declare function stripResidualCombiners(value: unknown, epoch?: number): unknown;
34
+ export declare function normalizeSchema(value: unknown, options: NormalizeSchemaOptions): unknown;
35
+ export declare function normalizeSchemaForGoogle(value: unknown): unknown;
36
+ export declare function normalizeSchemaForCCA(value: unknown): unknown;
37
+ export declare function normalizeSchemaForMCP(value: unknown): unknown;
38
+ /**
39
+ * OpenAI Responses rejects `oneOf` in tool schemas even when strict mode is
40
+ * disabled, and rejects every schema node with `type: "object"` unless it has
41
+ * a `properties` member. Normalize only schema-valued positions so literal
42
+ * payloads under `enum`, `const`, `default`, and `examples` remain unchanged.
43
+ *
44
+ * Identity-preserving: returns the input reference unchanged when no rewrite
45
+ * occurred so callers can dedupe via reference equality (and the strict-mode
46
+ * cache stays warm). If a node has both `oneOf` and `anyOf`, the two are
47
+ * concatenated (the wire payload accepts a single union; preserving both
48
+ * would not survive).
49
+ */
50
+ export declare function sanitizeSchemaForOpenAIResponses(schema: JsonObject): JsonObject;
51
+ /**
52
+ * Alias for {@link sanitizeSchemaForOpenAIResponses} matching the
53
+ * `normalizeSchemaFor*` dispatcher naming used elsewhere in this module.
54
+ */
55
+ export declare const normalizeSchemaForOpenAIResponses: (schema: JsonObject) => JsonObject;
56
+ /**
57
+ * First pass of strict-mode preparation.
58
+ *
59
+ * Rewrites everything strict mode forbids into something it accepts:
60
+ * - Drops non-structural keywords (`format`, `pattern`, `examples`, …),
61
+ * `const`, `nullable`, and `additionalProperties` (re-added by
62
+ * `enforceStrictSchema` as `false`).
63
+ * - `type: [a, b]` → `anyOf: [{type: a, …}, {type: b, …}]`, copying only the
64
+ * keywords each variant can use (e.g. `properties` stays only on the
65
+ * object variant).
66
+ * - `const` → single-entry `enum`.
67
+ * - Description carries a `(default: X)` suffix so the model still sees the
68
+ * documented default after the keyword is stripped.
69
+ * - `nullable: true` wraps the whole node in `anyOf:[T,{type:"null"}]`.
70
+ *
71
+ * Recurses into properties, items, prefixItems, combinators, and $defs. The
72
+ * `cache` WeakMap dedupes shared subgraphs; the `epoch` is the cycle guard.
73
+ */
74
+ export declare function sanitizeSchemaForStrictMode(schema: Record<string, unknown>, epoch?: number, cache?: WeakMap<Record<string, unknown>, Record<string, unknown>>, root?: Record<string, unknown>): Record<string, unknown>;
75
+ /**
76
+ * Recursively enforces JSON Schema constraints required by OpenAI/OpenAI code backend strict mode:
77
+ * - `additionalProperties: false` on every object node
78
+ * - every key in `properties` present in `required`
79
+ *
80
+ * Properties absent from the original `required` array were TypeBox-optional.
81
+ * They are made nullable (`anyOf: [T, { type: "null" }]`) so the model can
82
+ * signal omission by outputting null rather than omitting the key entirely.
83
+ *
84
+ * @throws {Error} When a schema node has no `type`, array-based combinator
85
+ * (`anyOf`/`allOf`/`oneOf`), object-based combinator (`not`), or `$ref` —
86
+ * i.e. the node is not representable in strict mode. Prefer
87
+ * {@link tryEnforceStrictSchema} which catches this and degrades gracefully.
88
+ */
89
+ export declare function enforceStrictSchema(schema: Record<string, unknown>, cache?: WeakMap<Record<string, unknown>, Record<string, unknown>>): Record<string, unknown>;
90
+ export declare function tryEnforceStrictSchema(schema: Record<string, unknown>): {
91
+ schema: Record<string, unknown>;
92
+ strict: boolean;
93
+ };
@@ -0,0 +1,12 @@
1
+ /** True when a JSON Schema node describes an object (explicit `type` or `properties`). */
2
+ export declare function isJsonSchemaObjectNode(schema: Record<string, unknown>): boolean;
3
+ /**
4
+ * Flatten a provider-emitted tool ROOT whose top level is a `oneOf`/`anyOf`/`allOf`
5
+ * combinator into one `type: "object"` schema: merge object-branch properties,
6
+ * derive the discriminant (`action`) enum, keep the common required set, and demote
7
+ * leftover combinators plus per-branch guidance into the description. Nested
8
+ * combinators (inside individual properties) are left untouched.
9
+ *
10
+ * Idempotent: a root that already lacks top-level combinators is returned unchanged.
11
+ */
12
+ export declare function flattenToolRootCombinators(schema: Record<string, unknown>): Record<string, unknown>;
@@ -0,0 +1,8 @@
1
+ import type { JsonObject } from "./types";
2
+ export type DescriptionSpillFormat = "spill" | "paren";
3
+ /**
4
+ * Demote stripped JSON Schema keywords into a node's `description` so the model
5
+ * still receives the constraint as natural-language context after the wire
6
+ * schema drops it.
7
+ */
8
+ export declare function spillToDescription(node: JsonObject, entries: ReadonlyArray<readonly [string, unknown]>, format?: DescriptionSpillFormat): void;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Symbol-keyed lazy memoization stamped directly onto the host object.
3
+ *
4
+ * Faster than a module-level `WeakMap` in V8/JSC because the symbol slot is
5
+ * resolved through the object's hidden class instead of a side-table hash
6
+ * lookup. The slot is defined as a non-enumerable property so the stamp
7
+ * does not leak through `{...spread}`, `Object.keys`, `JSON.stringify`, or
8
+ * `toEqual`-style deep equality.
9
+ *
10
+ * Caveats: the stamp lives as long as the host object, even after callers
11
+ * release their references to the cached value — only use this for caches
12
+ * whose lifetime should match the host. Frozen hosts will throw on write in
13
+ * strict mode; callers that may receive frozen input must handle that.
14
+ */
15
+ export declare function stamp<T extends object, V>(target: T, key: symbol, compute: (target: T) => V): V;
16
+ export declare function epochNext(): number;
17
+ /**
18
+ * Marks `target` as visited for this `epoch`. Returns `true` the first time
19
+ * it is called for a given (target, epoch) pair and `false` on every
20
+ * subsequent call within the same epoch.
21
+ */
22
+ export declare function once<T extends object>(target: T, epoch: number): boolean;
23
+ /** Returns `true` on first entry, `false` if `target` is already on the current path. */
24
+ export declare function enter<T extends object>(target: T): boolean;
25
+ export declare function exit<T extends object>(target: T): void;
@@ -0,0 +1,4 @@
1
+ export type JsonObject = Record<string, unknown>;
2
+ export declare function isJsonObject(value: unknown): value is JsonObject;
3
+ /** True when `value` is a plain JSON object with no own enumerable keys. */
4
+ export declare function isJsonObjectEmpty(value: JsonObject): boolean;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Compute the wire (JSON Schema) representation of a tool's parameters and
3
+ * convert TypeBox-style schemas into Zod for internal validation.
4
+ *
5
+ * Tools may author parameters in two shapes:
6
+ * 1. Zod (canonical going forward) — converted to JSON Schema on demand.
7
+ * 2. TypeBox / plain JSON Schema (legacy + extension compat) — upgraded to
8
+ * draft 2020-12 without converting through Zod.
9
+ *
10
+ * Both are normalized at the boundary so providers and validators see the same
11
+ * JSON Schema dialect.
12
+ */
13
+ import { type ZodType } from "zod/v4";
14
+ import type { Tool } from "../../types";
15
+ /**
16
+ * True when `value` is a live Zod schema instance.
17
+ *
18
+ * The check is stricter than "has a `_zod` property" because a JSON
19
+ * round-trip preserves the `_zod` key as a plain object and would otherwise
20
+ * fool the predicate — see issue #1101, where MCP servers ship
21
+ * `JSON.stringify(zodSchemaInstance)` as a tool's `inputSchema` and the
22
+ * resulting plain object then explodes `z.toJSONSchema` because the prototype
23
+ * (and every Zod parsing method) is gone.
24
+ *
25
+ * Live Zod instances always carry a `.parse` function on the prototype;
26
+ * impostors do not.
27
+ */
28
+ export declare function isZodSchema(value: unknown): value is ZodType;
29
+ /**
30
+ * Normalize `{}` (empty JSON Schema = `z.unknown()` / unconstrained value) to
31
+ * boolean `true` in every schema-valued position. JSON Schema draft 2020-12
32
+ * §4.3.1: `{}` and `true` are semantically equivalent ("any JSON value").
33
+ * Grammar-constrained samplers (llama.cpp, etc.) treat the object form as
34
+ * "generate an empty object" rather than "any JSON value", causing open-typed
35
+ * fields like `extra.title` (from `z.record(z.string(), z.unknown())`) to
36
+ * always emit `{}` instead of the intended string/number/etc. (issue #1179).
37
+ *
38
+ * Mutates in place. Provider-agnostic — applied to every tool wire schema so
39
+ * Anthropic, Google, OpenAI, Ollama, Bedrock, and Cursor all see the
40
+ * normalized form, regardless of whether the source was Zod or TypeBox.
41
+ */
42
+ export declare function normalizeEmptySchemas(node: unknown): void;
43
+ /** Convert a Zod schema into the JSON Schema shape providers consume. */
44
+ export declare function zodToWireSchema(schema: ZodType): Record<string, unknown>;
45
+ /**
46
+ * Resolve a tool's parameters to a JSON Schema object suitable for sending
47
+ * over the wire. Zod schemas are converted (and cached); legacy TypeBox / raw
48
+ * JSON Schema parameters are upgraded to draft 2020-12 (and cached).
49
+ *
50
+ * Both branches finish with `normalizeEmptySchemas` so every provider —
51
+ * OpenAI, Anthropic, Google, Ollama, Bedrock, Cursor — sees `{}` normalized
52
+ * to `true` in schema-valued positions (issue #1179).
53
+ */
54
+ export declare function toolWireSchema(tool: Tool): Record<string, unknown>;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Defensive rewrite for nodes that look like `JSON.stringify(zodSchemaInstance)`
3
+ * output rather than JSON Schema. MCP servers using Zod 4 sometimes ship a
4
+ * serialised schema instance directly as a tool's `inputSchema`, because the
5
+ * fields Zod surfaces on its instances (`type`, `enum`, `options`, `def`) shadow
6
+ * (and clash with) JSON Schema keywords. The resulting payload is neither valid
7
+ * Zod nor valid JSON Schema 2020-12 and Anthropic's strict validator rejects
8
+ * the whole tool list.
9
+ *
10
+ * Symptoms we've observed (gitnexus_impact.direction):
11
+ * {
12
+ * def: { type: "enum", entries: { upstream: "upstream", ... } },
13
+ * type: "enum", // <- invalid `type` value
14
+ * enum: { upstream: "upstream", ... }, // <- `enum` MUST be an array
15
+ * options: ["upstream", "downstream"],
16
+ * }
17
+ *
18
+ * This module recognises the shape (`def.type === node.type` and `def.type` is
19
+ * a known Zod kind) and rewrites it to clean JSON Schema where deterministic.
20
+ * For Zod kinds we don't fully model, we strip the toxic siblings (`def`,
21
+ * `options`, object-shaped `enum`) and drop an invalid `type` so the remainder
22
+ * passes meta-schema validation as a permissive node.
23
+ *
24
+ * Pure / identity-preserving: returns the input reference when nothing changes.
25
+ */
26
+ /**
27
+ * Walks a JSON value and rewrites every Zod-instance-shaped node into clean
28
+ * JSON Schema 2020-12. Identity-preserving when no rewrite fires. Tolerates
29
+ * self-referential graphs — a revisited node returns as-is.
30
+ */
31
+ export declare function decontaminateZodInstance(value: unknown): unknown;
@@ -0,0 +1,10 @@
1
+ import type { ServerSentEvent } from "@sayknow-cli/utils";
2
+ import type { RawSseEvent } from "../types";
3
+ type FetchFunction = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
4
+ type FetchWithPreconnect = FetchFunction & {
5
+ preconnect?: typeof fetch.preconnect;
6
+ };
7
+ type RawSseObserver = (event: RawSseEvent) => void;
8
+ export declare function notifyRawSseEvent(observer: RawSseObserver | undefined, event: ServerSentEvent | RawSseEvent): void;
9
+ export declare function wrapFetchForSseDebug(fetchImpl: FetchWithPreconnect, observer: RawSseObserver | undefined): FetchWithPreconnect;
10
+ export {};
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Streaming-safe filter for the Kimi K2 chat-template "tool-call section"
3
+ * grammar.
4
+ *
5
+ * Some providers hosting Kimi K2 (the native `kimi-code` API, OpenRouter,
6
+ * Fireworks, and others) leak the raw chat-template special tokens into
7
+ * `delta.content` instead of emitting structured `tool_calls`. Visually
8
+ * that looks like:
9
+ *
10
+ * <|tool_calls_section_begin|>
11
+ * <|tool_call_begin|>functions.read:0<|tool_call_argument_begin|>{"path":"foo"}<|tool_call_end|>
12
+ * <|tool_calls_section_end|>
13
+ *
14
+ * Without healing, the user sees the raw markers and the agent loop never
15
+ * sees a tool call. This module reconstructs the embedded calls and strips
16
+ * the markers from visible text. It is stream-aware: any partial token at
17
+ * the end of a chunk is held back until the next chunk arrives.
18
+ */
19
+ export interface HealedToolCall {
20
+ readonly id: string;
21
+ readonly name: string;
22
+ readonly arguments: string;
23
+ }
24
+ /**
25
+ * State machine that consumes streamed text, emits visible text with all
26
+ * Kimi tool-call markers stripped, and accumulates the embedded tool calls
27
+ * for the caller to drain after each `feed()`.
28
+ *
29
+ * One instance per stream. Feed only the channel that may carry leaked
30
+ * markers (typically `delta.content`); mixing reasoning + content into the
31
+ * same accumulator corrupts the holdback buffer if both channels race in
32
+ * the same chunk.
33
+ */
34
+ export declare class ToolCallHealer {
35
+ #private;
36
+ /**
37
+ * Feed a chunk of streamed text. Returns the portion safe to emit
38
+ * downstream (with all tokens stripped). Any partial token suffix is
39
+ * held back until the next chunk arrives or {@link flushPending} is
40
+ * called.
41
+ */
42
+ feed(text: string): string;
43
+ /**
44
+ * Like {@link feed}, but discards any tool calls that the chunk completes.
45
+ * Used when the upstream provider also emits structured `delta.tool_calls`
46
+ * for the same chunk: the healer still strips leaked marker text from the
47
+ * visible output, but the structured payload remains the single source of
48
+ * truth for the call list.
49
+ */
50
+ consumeWithoutCalls(text: string): string;
51
+ /**
52
+ * Drain accumulated tool calls. The internal list is cleared so a
53
+ * subsequent section in the same stream (rare) yields fresh calls.
54
+ */
55
+ drainCompleted(): HealedToolCall[];
56
+ /**
57
+ * Flush any held-back fragment when the stream ends. If we were mid-call
58
+ * the partial is dropped (emitting raw token bytes would surface markers
59
+ * to the user); otherwise the fragment is returned verbatim so a literal
60
+ * `<|` in prose is not silently lost.
61
+ */
62
+ flushPending(): string;
63
+ /** True once any tool-call section in this stream has fully closed. */
64
+ get sectionClosed(): boolean;
65
+ }
66
+ /**
67
+ * Cheap test for whether a given model is known to leak Kimi-K2 chat-template
68
+ * tool-call tokens into visible text. Used to gate the per-stream healer so
69
+ * non-Kimi providers do not pay for the scan.
70
+ */
71
+ export declare function modelMayLeakKimiToolCalls(provider: string, modelId: string): boolean;
@@ -0,0 +1,41 @@
1
+ import type { Api, Model, ToolChoice, ToolChoiceCompat, ToolChoiceSupport, ToolChoiceSupportSource } from "../types";
2
+ /**
3
+ * Claude Mythos accepts tools but rejects forced tool use (Anthropic 400:
4
+ * "tool_choice forces tool use is not compatible with this model"). Catalog
5
+ * generation and dynamic discovery use this to default `toolChoiceSupport`.
6
+ */
7
+ export declare function isClaudeForcedToolChoiceIncapableModelId(modelId: string): boolean;
8
+ /** Derives the effective static tool-choice support from compatibility flags. */
9
+ export declare function deriveToolChoiceSupport(compat: ToolChoiceCompat | undefined): {
10
+ support: ToolChoiceSupport;
11
+ source: "static" | "derived";
12
+ };
13
+ /** Returns the registry key used for runtime tool-choice capability overrides. */
14
+ export declare function toolChoiceRegistryKey(model: Model<Api>): string;
15
+ /** Returns the current runtime tool-choice capability override for a model. */
16
+ export declare function getToolChoiceCapabilityOverride(model: Model<Api>): ToolChoiceSupport | undefined;
17
+ /** Clears runtime tool-choice capability overrides for tests. */
18
+ export declare function clearToolChoiceIncapabilityRegistryForTests(): void;
19
+ /** Records a discovered maximum supported tool-choice level for a model. */
20
+ export declare function markToolChoiceIncapability(model: Model<Api>, maxSupport: ToolChoiceSupport, reason?: string): void;
21
+ /**
22
+ * Resolves a requested tool_choice against static and runtime capability limits.
23
+ * `compat` overrides `model.compat` for transports that layer URL/provider
24
+ * detection on top of explicit model overrides (e.g. resolveOpenAICompat).
25
+ */
26
+ export declare function resolveToolChoice(model: Model<Api>, requested: ToolChoice | undefined, compat?: ToolChoiceCompat): ResolveToolChoiceResult;
27
+ /** Detects provider errors indicating forced tool_choice is unsupported. */
28
+ export declare function isForcedToolChoiceUnsupportedError(error: unknown, sentForcedToolChoice: boolean): boolean;
29
+ export type { ToolChoiceCompat, ToolChoiceSupport, ToolChoiceSupportSource } from "../types";
30
+ export interface ResolveToolChoiceResult {
31
+ requestedChoice: ToolChoice | undefined;
32
+ requestedLevel: ToolChoiceSupport;
33
+ resolvedChoice: ToolChoice | undefined;
34
+ resolvedLevel: ToolChoiceSupport;
35
+ support: ToolChoiceSupport;
36
+ supportSource: ToolChoiceSupportSource;
37
+ degraded: boolean;
38
+ reason?: string;
39
+ registryKey: string;
40
+ targetToolName?: string;
41
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Utility functions for mapping unified ToolChoice to provider-specific formats.
3
+ */
4
+ import type { ToolChoice } from "../types";
5
+ /** OpenAI Completions API tool choice format */
6
+ export type OpenAICompletionsToolChoice = "auto" | "none" | "required" | {
7
+ type: "function";
8
+ function: {
9
+ name: string;
10
+ };
11
+ } | undefined;
12
+ /** OpenAI Responses API tool choice format (flat structure) */
13
+ export type OpenAIResponsesToolChoice = "auto" | "none" | "required" | {
14
+ type: "function";
15
+ name: string;
16
+ } | {
17
+ type: "custom";
18
+ name: string;
19
+ } | undefined;
20
+ /** Anthropic-compatible tool choice format */
21
+ export type AnthropicToolChoice = "auto" | "none" | "any" | {
22
+ type: "tool";
23
+ name: string;
24
+ } | undefined;
25
+ /**
26
+ * Map unified ToolChoice to OpenAI Completions API format.
27
+ * - "any" → "required"
28
+ * - { type: "tool", name } → { type: "function", function: { name } }
29
+ */
30
+ export declare function mapToOpenAICompletionsToolChoice(choice?: ToolChoice): OpenAICompletionsToolChoice;
31
+ /**
32
+ * Returns true when an OpenAI-completions `tool_choice` value forces a tool
33
+ * call (`"required"` or a function-name pin), as opposed to leaving it open
34
+ * (`"auto"`, `"none"`, or unset). Accepts `unknown` because the param shape
35
+ * pulled from the OpenAI SDK (`ChatCompletionToolChoiceOption`) widens with
36
+ * each release; this check only needs the open/forced bit.
37
+ */
38
+ export declare function isForcedToolChoice(choice: unknown): boolean;
39
+ /**
40
+ * Map unified ToolChoice to OpenAI Responses API format.
41
+ * - "any" → "required"
42
+ * - { type: "tool", name } → { type: "function", name } (flat structure)
43
+ */
44
+ export declare function mapToOpenAIResponsesToolChoice(choice?: ToolChoice): OpenAIResponsesToolChoice;
45
+ /**
46
+ * Map unified ToolChoice to Anthropic-compatible format.
47
+ * - "required" → "any"
48
+ * - { type: "function", ... } → { type: "tool", name }
49
+ */
50
+ export declare function mapToAnthropicToolChoice(choice?: ToolChoice): AnthropicToolChoice;
@@ -0,0 +1,17 @@
1
+ import type { Tool, ToolCall } from "../types";
2
+ /**
3
+ * Finds a tool by name and validates the tool call arguments against its schema.
4
+ * @param tools Array of tool definitions
5
+ * @param toolCall The tool call from the LLM
6
+ * @returns The validated arguments
7
+ * @throws Error if tool is not found or validation fails
8
+ */
9
+ export declare function validateToolCall(tools: Tool[], toolCall: ToolCall): ToolCall["arguments"];
10
+ /**
11
+ * Validates tool call arguments against the tool's schema (Zod or plain JSON
12
+ * Schema). Applies LLM-quirk coercions (numeric strings, JSON-string
13
+ * containers, null-for-optional, null-for-default) before declaring failure.
14
+ *
15
+ * @throws Error with a formatted message when validation cannot be reconciled.
16
+ */
17
+ export declare function validateToolArguments(tool: Tool, toolCall: ToolCall): ToolCall["arguments"];