@fgv/ts-extras 5.1.0-32 → 5.1.0-34
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/packlets/ai-assist/apiClient.js +4 -4
- package/dist/packlets/ai-assist/apiClient.js.map +1 -1
- package/dist/packlets/ai-assist/chatRequestBuilders.js +86 -3
- package/dist/packlets/ai-assist/chatRequestBuilders.js.map +1 -1
- package/dist/packlets/ai-assist/converters.js +31 -1
- package/dist/packlets/ai-assist/converters.js.map +1 -1
- package/dist/packlets/ai-assist/index.js +3 -2
- package/dist/packlets/ai-assist/index.js.map +1 -1
- package/dist/packlets/ai-assist/model.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +176 -32
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +511 -0
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/common.js +95 -0
- package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js +34 -10
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +215 -15
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
- package/dist/packlets/ai-assist/streamingClient.js +18 -0
- package/dist/packlets/ai-assist/streamingClient.js.map +1 -1
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js +23 -0
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -1
- package/dist/packlets/ai-assist/toolFormats.js +106 -10
- package/dist/packlets/ai-assist/toolFormats.js.map +1 -1
- package/dist/packlets/crypto-utils/index.browser.js +3 -2
- package/dist/packlets/crypto-utils/index.browser.js.map +1 -1
- package/dist/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js +287 -0
- package/dist/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/index.browser.js +36 -0
- package/dist/packlets/crypto-utils/keystore/index.browser.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/index.js +2 -0
- package/dist/packlets/crypto-utils/keystore/index.js.map +1 -1
- package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -1
- package/dist/ts-extras.d.ts +492 -6
- package/lib/packlets/ai-assist/apiClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/apiClient.js +3 -3
- package/lib/packlets/ai-assist/apiClient.js.map +1 -1
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +29 -5
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts.map +1 -1
- package/lib/packlets/ai-assist/chatRequestBuilders.js +86 -3
- package/lib/packlets/ai-assist/chatRequestBuilders.js.map +1 -1
- package/lib/packlets/ai-assist/converters.d.ts +9 -1
- package/lib/packlets/ai-assist/converters.d.ts.map +1 -1
- package/lib/packlets/ai-assist/converters.js +31 -1
- package/lib/packlets/ai-assist/converters.js.map +1 -1
- package/lib/packlets/ai-assist/index.d.ts +4 -3
- package/lib/packlets/ai-assist/index.d.ts.map +1 -1
- package/lib/packlets/ai-assist/index.js +5 -1
- package/lib/packlets/ai-assist/index.js.map +1 -1
- package/lib/packlets/ai-assist/model.d.ts +183 -3
- package/lib/packlets/ai-assist/model.d.ts.map +1 -1
- package/lib/packlets/ai-assist/model.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +58 -5
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +175 -31
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +158 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +517 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +51 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.js +97 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts +16 -2
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js +34 -10
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +15 -2
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +214 -14
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
- package/lib/packlets/ai-assist/streamingClient.d.ts +17 -0
- package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingClient.js +20 -1
- package/lib/packlets/ai-assist/streamingClient.js.map +1 -1
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts +18 -2
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts.map +1 -1
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js +24 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -1
- package/lib/packlets/ai-assist/toolFormats.d.ts +40 -9
- package/lib/packlets/ai-assist/toolFormats.d.ts.map +1 -1
- package/lib/packlets/ai-assist/toolFormats.js +107 -10
- package/lib/packlets/ai-assist/toolFormats.js.map +1 -1
- package/lib/packlets/crypto-utils/index.browser.d.ts +1 -1
- package/lib/packlets/crypto-utils/index.browser.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/index.browser.js +3 -2
- package/lib/packlets/crypto-utils/index.browser.js.map +1 -1
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.d.ts +148 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js +324 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.d.ts +10 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.js +76 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.d.ts +1 -0
- package/lib/packlets/crypto-utils/keystore/index.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/keystore/index.js +4 -1
- package/lib/packlets/crypto-utils/keystore/index.js.map +1 -1
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts +6 -3
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts.map +1 -1
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -1
- package/package.json +15 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thinkingOptionsResolver.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/thinkingOptionsResolver.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Merge logic and runtime validation for thinking/reasoning options.\n * @packageDocumentation\n */\n\nimport { type JsonObject } from '@fgv/ts-json-base';\nimport { fail, Result, succeed } from '@fgv/ts-utils';\n\nimport type {\n IThinkingConfig,\n IThinkingProviderConfig,\n IAnthropicThinkingConfig,\n IOpenAiThinkingConfig,\n IXAiThinkingConfig\n} from './model';\n\n// ============================================================================\n// Provider discriminator\n// ============================================================================\n\n/**\n * Coarse provider family used to discriminate thinking config blocks.\n * Maps from AiProviderId to the IThinkingProviderConfig `provider` discriminator.\n * @internal\n */\nexport type ThinkingProviderDiscriminator = 'anthropic' | 'openai' | 'google' | 'xai';\n\n/**\n * Maps an AiProviderId (registry key) to the coarse family discriminator used\n * in IThinkingProviderConfig. Returns undefined for providers without thinking support.\n * @internal\n */\nexport function providerDiscriminatorForId(providerId: string): ThinkingProviderDiscriminator | undefined {\n switch (providerId) {\n case 'anthropic':\n return 'anthropic';\n case 'openai':\n return 'openai';\n case 'google-gemini':\n return 'google';\n case 'xai-grok':\n return 'xai';\n default:\n return undefined;\n }\n}\n\n// ============================================================================\n// Resolved wire shape\n// ============================================================================\n\n/**\n * Resolved thinking wire parameters for a specific provider, after merging\n * all applicable config blocks. Ready for provider-specific wire encoding.\n * @internal\n */\nexport interface IResolvedThinkingConfig {\n /** Anthropic: output_config.effort value */\n readonly anthropicEffort?: IAnthropicThinkingConfig['effort'];\n /** OpenAI Chat: reasoning_effort value; OpenAI Responses: reasoning.effort */\n readonly openAiEffort?: IOpenAiThinkingConfig['effort'];\n /** Gemini: generationConfig.thinkingConfig.thinkingBudget */\n readonly geminiThinkingBudget?: number;\n /** xAI: reasoning_effort value (omit for grok-4) */\n readonly xaiEffort?: IXAiThinkingConfig['effort'];\n /** Other/passthrough: merged verbatim into wire request */\n readonly otherParams?: JsonObject;\n}\n\n// ============================================================================\n// Common-subset mapping\n// ============================================================================\n\n/**\n * Maps generic effort to Anthropic wire effort. @internal\n */\nfunction genericEffortToAnthropic(effort: 'low' | 'medium' | 'high'): IAnthropicThinkingConfig['effort'] {\n return effort; // 1:1 mapping for the common subset\n}\n\n/**\n * Maps generic effort to OpenAI wire effort. @internal\n */\nfunction genericEffortToOpenAi(effort: 'low' | 'medium' | 'high'): IOpenAiThinkingConfig['effort'] {\n return effort; // 1:1 mapping for the common subset\n}\n\n/**\n * Maps generic effort to Gemini thinkingBudget. @internal\n */\nfunction genericEffortToGemini(effort: 'low' | 'medium' | 'high'): number {\n switch (effort) {\n case 'low':\n return 1024;\n case 'medium':\n return 4096;\n case 'high':\n return 8192;\n }\n}\n\n/**\n * Maps generic effort to xAI reasoning_effort. @internal\n */\nfunction genericEffortToXai(effort: 'low' | 'medium' | 'high'): IXAiThinkingConfig['effort'] {\n return effort; // 1:1 mapping for the common subset\n}\n\n// ============================================================================\n// Block applicability\n// ============================================================================\n\n/**\n * Returns true when a provider config block applies to the given resolved model\n * and provider discriminator.\n *\n * Applicability rules:\n * - provider must match the coarse discriminator\n * - if models array is present, resolved model must match (exact or base-name prefix)\n * - if models array is absent, the block is provider-generic (applies to all)\n *\n * Prefix matching supports versioned IDs: `'claude-sonnet-4-5'` matches resolved\n * `'claude-sonnet-4-5-20250929'`. An entry matches when it equals the resolved model\n * or when the resolved model starts with the entry followed by a `-`.\n *\n * 'other' blocks require models to be present (enforced by the type).\n * @internal\n */\nfunction modelNameMatches(resolvedModel: string, name: string): boolean {\n return resolvedModel === name || resolvedModel.startsWith(`${name}-`);\n}\n\nfunction blockApplies(\n block: IThinkingProviderConfig,\n resolvedModel: string,\n discriminator: ThinkingProviderDiscriminator\n): boolean {\n if (block.provider !== discriminator && block.provider !== 'other') {\n return false;\n }\n if (block.provider === 'other') {\n return block.models.some((name) => modelNameMatches(resolvedModel, name));\n }\n if (block.models !== undefined) {\n return (block.models as ReadonlyArray<string>).some((name) => modelNameMatches(resolvedModel, name));\n }\n return true; // provider-generic block\n}\n\n/**\n * Returns true when a block is model-specific (has a models array).\n * Used to partition blocks into merge tiers.\n * @internal\n */\nfunction isModelSpecific(block: IThinkingProviderConfig): boolean {\n if (block.provider === 'other') {\n return true; // other blocks always require models\n }\n return block.models !== undefined;\n}\n\n// ============================================================================\n// Merge function\n// ============================================================================\n\n/**\n * Resolves the effective thinking wire parameters for a specific resolved model\n * by merging all applicable config blocks in precedence order.\n *\n * Precedence (later tier wins; within tier, later declaration wins):\n * 1. Generic effort (top-level IThinkingConfig.effort) → common-subset mapping\n * 2. Provider-generic blocks (matching provider, no models filter)\n * 3. Model-specific blocks (matching provider + models array includes resolved model)\n * 4. Other blocks (provider: 'other', models includes resolved model) — same tier as 3\n *\n * Blocks whose provider does not match are silently skipped.\n *\n * Note: when the resolved OpenAI effort is `'none'`, reasoning is disabled and\n * temperature is accepted; see {@link IOpenAiThinkingConfig.effort} for the full\n * hybrid-mode semantics.\n *\n * @param config - The caller's IThinkingConfig\n * @param resolvedModel - The concrete model string after registry resolution\n * @param discriminator - Coarse provider family\n * @returns Merged effective config for wire encoding\n * @internal\n */\nexport function mergeThinkingConfig(\n config: IThinkingConfig,\n resolvedModel: string,\n discriminator: ThinkingProviderDiscriminator\n): Result<IResolvedThinkingConfig> {\n let resolved: IResolvedThinkingConfig = {};\n\n // Tier 1: generic effort → common-subset mapping\n if (config.effort !== undefined) {\n switch (discriminator) {\n case 'anthropic':\n resolved = { ...resolved, anthropicEffort: genericEffortToAnthropic(config.effort) };\n break;\n case 'openai':\n resolved = { ...resolved, openAiEffort: genericEffortToOpenAi(config.effort) };\n break;\n case 'google':\n resolved = { ...resolved, geminiThinkingBudget: genericEffortToGemini(config.effort) };\n break;\n case 'xai':\n resolved = { ...resolved, xaiEffort: genericEffortToXai(config.effort) };\n break;\n }\n }\n\n if (!config.providers) {\n return succeed(resolved);\n }\n\n // Partition into tiers 2 and 3+4\n const applicableBlocks = config.providers.filter((b) => blockApplies(b, resolvedModel, discriminator));\n const genericBlocks = applicableBlocks.filter((b) => !isModelSpecific(b));\n const specificBlocks = applicableBlocks.filter((b) => isModelSpecific(b));\n\n // Tier 2: provider-generic blocks (declaration order; later wins)\n for (const block of genericBlocks) {\n resolved = applyBlock(resolved, block, discriminator);\n }\n\n // Tier 3+4: model-specific + other blocks (declaration order; later wins)\n for (const block of specificBlocks) {\n resolved = applyBlock(resolved, block, discriminator);\n }\n\n return succeed(resolved);\n}\n\n/**\n * Applies a single config block to the accumulated resolved config.\n * @internal\n */\nfunction applyBlock(\n current: IResolvedThinkingConfig,\n block: IThinkingProviderConfig,\n discriminator: ThinkingProviderDiscriminator\n): IResolvedThinkingConfig {\n if (block.provider === 'other') {\n const merged =\n current.otherParams !== undefined ? { ...current.otherParams, ...block.config } : block.config;\n return { ...current, otherParams: merged };\n }\n\n switch (discriminator) {\n case 'anthropic':\n if (block.provider === 'anthropic') {\n if (block.config.effort !== undefined) {\n return { ...current, anthropicEffort: block.config.effort };\n }\n }\n break;\n case 'openai':\n if (block.provider === 'openai') {\n if (block.config.effort !== undefined) {\n return { ...current, openAiEffort: block.config.effort };\n }\n }\n break;\n case 'google':\n if (block.provider === 'google') {\n const updated: IResolvedThinkingConfig = { ...current };\n if (block.config.thinkingBudget !== undefined) {\n return { ...updated, geminiThinkingBudget: block.config.thinkingBudget };\n }\n return updated;\n }\n /* c8 ignore next - blockApplies guarantees provider match; unreachable for google */\n break;\n case 'xai':\n if (block.provider === 'xai') {\n if (block.config.effort !== undefined) {\n return { ...current, xaiEffort: block.config.effort };\n }\n }\n break;\n }\n return current;\n}\n\n// ============================================================================\n// Temperature conflict check\n// ============================================================================\n\n/**\n * Returns a Result.fail if temperature conflicts with thinking mode for the\n * given provider, otherwise succeed(undefined).\n *\n * Per D4: temperature + thinking = Result.fail for Anthropic, OpenAI (when\n * effective effort is non-null and non-'none'), and xAI (conservative default\n * pending live verification). Gemini accepts temperature alongside thinking.\n *\n * @internal\n */\nexport function checkTemperatureConflict(\n resolved: IResolvedThinkingConfig,\n discriminator: ThinkingProviderDiscriminator,\n temperature: number | undefined\n): Result<undefined> {\n if (temperature === undefined) {\n return succeed(undefined);\n }\n\n switch (discriminator) {\n case 'anthropic':\n if (resolved.anthropicEffort !== undefined) {\n return fail(\n 'thinking mode is not compatible with temperature on provider anthropic: remove temperature or disable thinking'\n );\n }\n break;\n case 'openai':\n // 'none' disables reasoning; temperature is accepted in that case\n if (resolved.openAiEffort !== undefined && resolved.openAiEffort !== 'none') {\n return fail(\n 'thinking mode is not compatible with temperature on provider openai: remove temperature or disable thinking'\n );\n }\n break;\n case 'xai':\n // Conservative default: fail if xAI effort is active (per D8 — live verification pending)\n if (resolved.xaiEffort !== undefined && resolved.xaiEffort !== 'none') {\n return fail(\n 'thinking mode is not compatible with temperature on provider xai: remove temperature or disable thinking'\n );\n }\n break;\n case 'google':\n // Gemini accepts temperature alongside thinkingConfig — no conflict\n break;\n }\n return succeed(undefined);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"thinkingOptionsResolver.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/thinkingOptionsResolver.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Merge logic and runtime validation for thinking/reasoning options.\n * @packageDocumentation\n */\n\nimport { type JsonObject } from '@fgv/ts-json-base';\nimport { fail, Result, succeed } from '@fgv/ts-utils';\n\nimport type {\n IThinkingConfig,\n IThinkingProviderConfig,\n IAnthropicThinkingConfig,\n IOpenAiThinkingConfig,\n IXAiThinkingConfig\n} from './model';\n\n// ============================================================================\n// Provider discriminator\n// ============================================================================\n\n/**\n * Coarse provider family used to discriminate thinking config blocks.\n * Maps from AiProviderId to the IThinkingProviderConfig `provider` discriminator.\n * @internal\n */\nexport type ThinkingProviderDiscriminator = 'anthropic' | 'openai' | 'google' | 'xai';\n\n/**\n * Maps an AiProviderId (registry key) to the coarse family discriminator used\n * in IThinkingProviderConfig. Returns undefined for providers without thinking support.\n * @internal\n */\nexport function providerDiscriminatorForId(providerId: string): ThinkingProviderDiscriminator | undefined {\n switch (providerId) {\n case 'anthropic':\n return 'anthropic';\n case 'openai':\n return 'openai';\n case 'google-gemini':\n return 'google';\n case 'xai-grok':\n return 'xai';\n default:\n return undefined;\n }\n}\n\n// ============================================================================\n// Resolved wire shape\n// ============================================================================\n\n/**\n * Resolved thinking wire parameters for a specific provider, after merging\n * all applicable config blocks. Ready for provider-specific wire encoding.\n *\n * Callers that pre-resolve thinking config outside of the standard streaming\n * helpers (e.g. `executeClientToolTurn`) accept this type via the\n * `resolvedThinking` parameter and pass it directly to the adapter layer.\n * @public\n */\nexport interface IResolvedThinkingConfig {\n /** Anthropic: effort level; emit-site converts to `thinking.budget_tokens` via `anthropicEffortToBudgetTokens`. */\n readonly anthropicEffort?: IAnthropicThinkingConfig['effort'];\n /** OpenAI Chat: reasoning_effort value; OpenAI Responses: reasoning.effort */\n readonly openAiEffort?: IOpenAiThinkingConfig['effort'];\n /** Gemini: generationConfig.thinkingConfig.thinkingBudget */\n readonly geminiThinkingBudget?: number;\n /** xAI: reasoning_effort value (omit for grok-4) */\n readonly xaiEffort?: IXAiThinkingConfig['effort'];\n /** Other/passthrough: merged verbatim into wire request */\n readonly otherParams?: JsonObject;\n}\n\n// ============================================================================\n// Common-subset mapping\n// ============================================================================\n\n/**\n * Maps generic effort to Anthropic wire effort. @internal\n */\nfunction genericEffortToAnthropic(effort: 'low' | 'medium' | 'high'): IAnthropicThinkingConfig['effort'] {\n return effort; // 1:1 mapping for the common subset\n}\n\n/**\n * Maps Anthropic effort level to the `thinking.budget_tokens` integer that the\n * Anthropic API requires when `thinking.type === 'enabled'`.\n *\n * Policy: low = 2048, medium = 8192, high = 24000, max = 32000. The lower three\n * align with the Anthropic-published minimum-meaningful budget, a mid-range\n * default, and a \"deep thinking\" allotment respectively. `max` targets Opus 4.6's\n * deepest budget and stays within typical model limits.\n *\n * @public\n */\nexport function anthropicEffortToBudgetTokens(\n effort: NonNullable<IAnthropicThinkingConfig['effort']>\n): number {\n switch (effort) {\n case 'low':\n return 2048;\n case 'medium':\n return 8192;\n case 'high':\n return 24000;\n case 'max':\n return 32000;\n }\n}\n\n/**\n * Maps generic effort to OpenAI wire effort. @internal\n */\nfunction genericEffortToOpenAi(effort: 'low' | 'medium' | 'high'): IOpenAiThinkingConfig['effort'] {\n return effort; // 1:1 mapping for the common subset\n}\n\n/**\n * Maps generic effort to Gemini thinkingBudget. @internal\n */\nfunction genericEffortToGemini(effort: 'low' | 'medium' | 'high'): number {\n switch (effort) {\n case 'low':\n return 1024;\n case 'medium':\n return 4096;\n case 'high':\n return 8192;\n }\n}\n\n/**\n * Maps generic effort to xAI reasoning_effort. @internal\n */\nfunction genericEffortToXai(effort: 'low' | 'medium' | 'high'): IXAiThinkingConfig['effort'] {\n return effort; // 1:1 mapping for the common subset\n}\n\n// ============================================================================\n// Block applicability\n// ============================================================================\n\n/**\n * Returns true when a provider config block applies to the given resolved model\n * and provider discriminator.\n *\n * Applicability rules:\n * - provider must match the coarse discriminator\n * - if models array is present, resolved model must match (exact or base-name prefix)\n * - if models array is absent, the block is provider-generic (applies to all)\n *\n * Prefix matching supports versioned IDs: `'claude-sonnet-4-5'` matches resolved\n * `'claude-sonnet-4-5-20250929'`. An entry matches when it equals the resolved model\n * or when the resolved model starts with the entry followed by a `-`.\n *\n * 'other' blocks require models to be present (enforced by the type).\n * @internal\n */\nfunction modelNameMatches(resolvedModel: string, name: string): boolean {\n return resolvedModel === name || resolvedModel.startsWith(`${name}-`);\n}\n\nfunction blockApplies(\n block: IThinkingProviderConfig,\n resolvedModel: string,\n discriminator: ThinkingProviderDiscriminator\n): boolean {\n if (block.provider !== discriminator && block.provider !== 'other') {\n return false;\n }\n if (block.provider === 'other') {\n return block.models.some((name) => modelNameMatches(resolvedModel, name));\n }\n if (block.models !== undefined) {\n return (block.models as ReadonlyArray<string>).some((name) => modelNameMatches(resolvedModel, name));\n }\n return true; // provider-generic block\n}\n\n/**\n * Returns true when a block is model-specific (has a models array).\n * Used to partition blocks into merge tiers.\n * @internal\n */\nfunction isModelSpecific(block: IThinkingProviderConfig): boolean {\n if (block.provider === 'other') {\n return true; // other blocks always require models\n }\n return block.models !== undefined;\n}\n\n// ============================================================================\n// Merge function\n// ============================================================================\n\n/**\n * Resolves the effective thinking wire parameters for a specific resolved model\n * by merging all applicable config blocks in precedence order.\n *\n * Precedence (later tier wins; within tier, later declaration wins):\n * 1. Generic effort (top-level IThinkingConfig.effort) → common-subset mapping\n * 2. Provider-generic blocks (matching provider, no models filter)\n * 3. Model-specific blocks (matching provider + models array includes resolved model)\n * 4. Other blocks (provider: 'other', models includes resolved model) — same tier as 3\n *\n * Blocks whose provider does not match are silently skipped.\n *\n * Note: when the resolved OpenAI effort is `'none'`, reasoning is disabled and\n * temperature is accepted; see {@link IOpenAiThinkingConfig.effort} for the full\n * hybrid-mode semantics.\n *\n * @param config - The caller's IThinkingConfig\n * @param resolvedModel - The concrete model string after registry resolution\n * @param discriminator - Coarse provider family\n * @returns Merged effective config for wire encoding\n * @internal\n */\nexport function mergeThinkingConfig(\n config: IThinkingConfig,\n resolvedModel: string,\n discriminator: ThinkingProviderDiscriminator\n): Result<IResolvedThinkingConfig> {\n let resolved: IResolvedThinkingConfig = {};\n\n // Tier 1: generic effort → common-subset mapping\n if (config.effort !== undefined) {\n switch (discriminator) {\n case 'anthropic':\n resolved = { ...resolved, anthropicEffort: genericEffortToAnthropic(config.effort) };\n break;\n case 'openai':\n resolved = { ...resolved, openAiEffort: genericEffortToOpenAi(config.effort) };\n break;\n case 'google':\n resolved = { ...resolved, geminiThinkingBudget: genericEffortToGemini(config.effort) };\n break;\n case 'xai':\n resolved = { ...resolved, xaiEffort: genericEffortToXai(config.effort) };\n break;\n }\n }\n\n if (!config.providers) {\n return succeed(resolved);\n }\n\n // Partition into tiers 2 and 3+4\n const applicableBlocks = config.providers.filter((b) => blockApplies(b, resolvedModel, discriminator));\n const genericBlocks = applicableBlocks.filter((b) => !isModelSpecific(b));\n const specificBlocks = applicableBlocks.filter((b) => isModelSpecific(b));\n\n // Tier 2: provider-generic blocks (declaration order; later wins)\n for (const block of genericBlocks) {\n resolved = applyBlock(resolved, block, discriminator);\n }\n\n // Tier 3+4: model-specific + other blocks (declaration order; later wins)\n for (const block of specificBlocks) {\n resolved = applyBlock(resolved, block, discriminator);\n }\n\n return succeed(resolved);\n}\n\n/**\n * Applies a single config block to the accumulated resolved config.\n * @internal\n */\nfunction applyBlock(\n current: IResolvedThinkingConfig,\n block: IThinkingProviderConfig,\n discriminator: ThinkingProviderDiscriminator\n): IResolvedThinkingConfig {\n if (block.provider === 'other') {\n const merged =\n current.otherParams !== undefined ? { ...current.otherParams, ...block.config } : block.config;\n return { ...current, otherParams: merged };\n }\n\n switch (discriminator) {\n case 'anthropic':\n if (block.provider === 'anthropic') {\n if (block.config.effort !== undefined) {\n return { ...current, anthropicEffort: block.config.effort };\n }\n }\n break;\n case 'openai':\n if (block.provider === 'openai') {\n if (block.config.effort !== undefined) {\n return { ...current, openAiEffort: block.config.effort };\n }\n }\n break;\n case 'google':\n if (block.provider === 'google') {\n const updated: IResolvedThinkingConfig = { ...current };\n if (block.config.thinkingBudget !== undefined) {\n return { ...updated, geminiThinkingBudget: block.config.thinkingBudget };\n }\n return updated;\n }\n /* c8 ignore next - blockApplies guarantees provider match; unreachable for google */\n break;\n case 'xai':\n if (block.provider === 'xai') {\n if (block.config.effort !== undefined) {\n return { ...current, xaiEffort: block.config.effort };\n }\n }\n break;\n }\n return current;\n}\n\n// ============================================================================\n// Temperature conflict check\n// ============================================================================\n\n/**\n * Returns a Result.fail if temperature conflicts with thinking mode for the\n * given provider, otherwise succeed(undefined).\n *\n * Per D4: temperature + thinking = Result.fail for Anthropic, OpenAI (when\n * effective effort is non-null and non-'none'), and xAI (conservative default\n * pending live verification). Gemini accepts temperature alongside thinking.\n *\n * @internal\n */\nexport function checkTemperatureConflict(\n resolved: IResolvedThinkingConfig,\n discriminator: ThinkingProviderDiscriminator,\n temperature: number | undefined\n): Result<undefined> {\n if (temperature === undefined) {\n return succeed(undefined);\n }\n\n switch (discriminator) {\n case 'anthropic':\n if (resolved.anthropicEffort !== undefined) {\n return fail(\n 'thinking mode is not compatible with temperature on provider anthropic: remove temperature or disable thinking'\n );\n }\n break;\n case 'openai':\n // 'none' disables reasoning; temperature is accepted in that case\n if (resolved.openAiEffort !== undefined && resolved.openAiEffort !== 'none') {\n return fail(\n 'thinking mode is not compatible with temperature on provider openai: remove temperature or disable thinking'\n );\n }\n break;\n case 'xai':\n // Conservative default: fail if xAI effort is active (per D8 — live verification pending)\n if (resolved.xaiEffort !== undefined && resolved.xaiEffort !== 'none') {\n return fail(\n 'thinking mode is not compatible with temperature on provider xai: remove temperature or disable thinking'\n );\n }\n break;\n case 'google':\n // Gemini accepts temperature alongside thinkingConfig — no conflict\n break;\n }\n return succeed(undefined);\n}\n"]}
|
|
@@ -70,9 +70,21 @@ function webSearchToResponsesApi(config) {
|
|
|
70
70
|
}
|
|
71
71
|
return tool;
|
|
72
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Formats a client tool config for the xAI/OpenAI Responses API.
|
|
75
|
+
* @internal
|
|
76
|
+
*/
|
|
77
|
+
function clientToolToResponsesApi(config) {
|
|
78
|
+
return {
|
|
79
|
+
type: 'function',
|
|
80
|
+
name: config.name,
|
|
81
|
+
description: config.description,
|
|
82
|
+
parameters: config.parametersSchema.toJson()
|
|
83
|
+
};
|
|
84
|
+
}
|
|
73
85
|
/**
|
|
74
86
|
* Formats tool configs for the xAI/OpenAI Responses API.
|
|
75
|
-
* @param tools - The resolved tool configs
|
|
87
|
+
* @param tools - The resolved tool configs (server-side and/or client-defined)
|
|
76
88
|
* @returns Provider-native tool objects for the `tools` request field
|
|
77
89
|
* @public
|
|
78
90
|
*/
|
|
@@ -81,10 +93,12 @@ export function toResponsesApiTools(tools) {
|
|
|
81
93
|
switch (t.type) {
|
|
82
94
|
case 'web_search':
|
|
83
95
|
return webSearchToResponsesApi(t);
|
|
96
|
+
case 'client_tool':
|
|
97
|
+
return clientToolToResponsesApi(t);
|
|
84
98
|
/* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
|
|
85
99
|
default: {
|
|
86
|
-
const _exhaustive = t
|
|
87
|
-
return { type:
|
|
100
|
+
const _exhaustive = t;
|
|
101
|
+
return { type: `unknown:${JSON.stringify(_exhaustive)}` };
|
|
88
102
|
}
|
|
89
103
|
}
|
|
90
104
|
});
|
|
@@ -112,9 +126,21 @@ function webSearchToAnthropic(config) {
|
|
|
112
126
|
}
|
|
113
127
|
return tool;
|
|
114
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Formats a client tool config for the Anthropic Messages API.
|
|
131
|
+
* Note: Anthropic client tools have no `type` field (unlike server tools).
|
|
132
|
+
* @internal
|
|
133
|
+
*/
|
|
134
|
+
function clientToolToAnthropic(config) {
|
|
135
|
+
return {
|
|
136
|
+
name: config.name,
|
|
137
|
+
description: config.description,
|
|
138
|
+
input_schema: config.parametersSchema.toJson()
|
|
139
|
+
};
|
|
140
|
+
}
|
|
115
141
|
/**
|
|
116
142
|
* Formats tool configs for the Anthropic Messages API.
|
|
117
|
-
* @param tools - The resolved tool configs
|
|
143
|
+
* @param tools - The resolved tool configs (server-side and/or client-defined)
|
|
118
144
|
* @returns Provider-native tool objects for the `tools` request field
|
|
119
145
|
* @public
|
|
120
146
|
*/
|
|
@@ -123,10 +149,12 @@ export function toAnthropicTools(tools) {
|
|
|
123
149
|
switch (t.type) {
|
|
124
150
|
case 'web_search':
|
|
125
151
|
return webSearchToAnthropic(t);
|
|
152
|
+
case 'client_tool':
|
|
153
|
+
return clientToolToAnthropic(t);
|
|
126
154
|
/* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
|
|
127
155
|
default: {
|
|
128
|
-
const _exhaustive = t
|
|
129
|
-
return { type:
|
|
156
|
+
const _exhaustive = t;
|
|
157
|
+
return { type: `unknown:${JSON.stringify(_exhaustive)}` };
|
|
130
158
|
}
|
|
131
159
|
}
|
|
132
160
|
});
|
|
@@ -134,27 +162,95 @@ export function toAnthropicTools(tools) {
|
|
|
134
162
|
// ============================================================================
|
|
135
163
|
// Gemini generateContent API format
|
|
136
164
|
// ============================================================================
|
|
165
|
+
/**
|
|
166
|
+
* Sanitizes a draft-07 JSON Schema (as emitted by `JsonSchema.object(...).toJson()`)
|
|
167
|
+
* into the OpenAPI 3.0 Schema Object subset that Gemini's `function_declarations[].parameters`
|
|
168
|
+
* accepts.
|
|
169
|
+
*
|
|
170
|
+
* @remarks
|
|
171
|
+
* Gemini's function-declaration schema is **not** full JSON Schema — it is a subset of
|
|
172
|
+
* the OpenAPI 3.0 Schema Object and **rejects** (rather than ignores) draft-07-only
|
|
173
|
+
* keywords. `JsonSchema` objects are strict-by-default, so `.toJson()` emits
|
|
174
|
+
* `additionalProperties: false` on every object node, which 400s the whole request on
|
|
175
|
+
* Gemini. This helper recursively strips the unsupported keywords so any
|
|
176
|
+
* `JsonSchema`-authored client tool works on Gemini without consumer awareness of the
|
|
177
|
+
* dialect difference. Stripping is infallible, so it returns a plain value rather than a
|
|
178
|
+
* `Result`.
|
|
179
|
+
*
|
|
180
|
+
* `additionalProperties` and `$schema` are stripped only where they appear as schema
|
|
181
|
+
* *keywords* (siblings of `type`/`properties`/etc.). Inside a `properties` map the keys
|
|
182
|
+
* are user-defined parameter names, not keywords, so they are preserved verbatim while
|
|
183
|
+
* each property's subschema value is still recursively sanitized — a tool parameter
|
|
184
|
+
* legitimately named `additionalProperties` survives.
|
|
185
|
+
*
|
|
186
|
+
* @internal
|
|
187
|
+
*/
|
|
188
|
+
export function toGeminiParameterSchema(schema) {
|
|
189
|
+
if (Array.isArray(schema)) {
|
|
190
|
+
return schema.map(toGeminiParameterSchema);
|
|
191
|
+
}
|
|
192
|
+
if (schema !== null && typeof schema === 'object') {
|
|
193
|
+
const out = {};
|
|
194
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
195
|
+
if (key === 'additionalProperties' || key === '$schema') {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (key === 'properties' && value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
199
|
+
// `properties` maps user-defined parameter names to subschemas: recurse each
|
|
200
|
+
// subschema value but never treat a parameter name as a strippable keyword.
|
|
201
|
+
const properties = {};
|
|
202
|
+
for (const [name, propSchema] of Object.entries(value)) {
|
|
203
|
+
properties[name] = toGeminiParameterSchema(propSchema);
|
|
204
|
+
}
|
|
205
|
+
out[key] = properties;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
out[key] = toGeminiParameterSchema(value);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return out;
|
|
212
|
+
}
|
|
213
|
+
return schema;
|
|
214
|
+
}
|
|
137
215
|
/**
|
|
138
216
|
* Formats tool configs for the Gemini generateContent API.
|
|
139
|
-
*
|
|
140
|
-
* @
|
|
217
|
+
*
|
|
218
|
+
* @remarks
|
|
219
|
+
* Gemini uses `google_search` for search grounding (no per-tool config).
|
|
220
|
+
* Client-defined tools are accumulated into a single `function_declarations` entry.
|
|
221
|
+
* Each client tool's parameters schema is sanitized to Gemini's OpenAPI-subset
|
|
222
|
+
* dialect via {@link toGeminiParameterSchema} (the raw draft-07 `.toJson()` output
|
|
223
|
+
* carries `additionalProperties`, which Gemini rejects).
|
|
224
|
+
*
|
|
225
|
+
* @param tools - The resolved tool configs (server-side and/or client-defined)
|
|
141
226
|
* @returns Provider-native tool objects for the `tools` request field
|
|
142
227
|
* @public
|
|
143
228
|
*/
|
|
144
229
|
export function toGeminiTools(tools) {
|
|
145
230
|
const result = [];
|
|
231
|
+
const functionDeclarations = [];
|
|
146
232
|
for (const t of tools) {
|
|
147
233
|
switch (t.type) {
|
|
148
234
|
case 'web_search':
|
|
149
235
|
result.push({ google_search: {} });
|
|
150
236
|
break;
|
|
237
|
+
case 'client_tool':
|
|
238
|
+
functionDeclarations.push({
|
|
239
|
+
name: t.name,
|
|
240
|
+
description: t.description,
|
|
241
|
+
parameters: toGeminiParameterSchema(t.parametersSchema.toJson())
|
|
242
|
+
});
|
|
243
|
+
break;
|
|
151
244
|
/* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
|
|
152
245
|
default: {
|
|
153
|
-
const _exhaustive = t
|
|
154
|
-
result.push({ type:
|
|
246
|
+
const _exhaustive = t;
|
|
247
|
+
result.push({ type: `unknown:${JSON.stringify(_exhaustive)}` });
|
|
155
248
|
}
|
|
156
249
|
}
|
|
157
250
|
}
|
|
251
|
+
if (functionDeclarations.length > 0) {
|
|
252
|
+
result.push({ function_declarations: functionDeclarations });
|
|
253
|
+
}
|
|
158
254
|
return result;
|
|
159
255
|
}
|
|
160
256
|
//# sourceMappingURL=toolFormats.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolFormats.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/toolFormats.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Provider-specific tool format translation and tool resolution logic.\n * @packageDocumentation\n */\n\nimport { type JsonObject } from '@fgv/ts-json-base';\n\nimport {\n type AiServerToolConfig,\n type IAiProviderDescriptor,\n type IAiToolEnablement,\n type IAiWebSearchToolConfig\n} from './model';\n\n// ============================================================================\n// Tool resolution\n// ============================================================================\n\n/**\n * Resolves the effective tools for a completion call.\n *\n * - If per-call tools are provided, they override settings-level tools entirely.\n * - Otherwise, settings-level enabled tools are used.\n * - Only tools supported by the provider are included.\n * - Returns an empty array if no tools are enabled (= no tools sent).\n *\n * @param descriptor - The provider descriptor (used to filter by supported tools)\n * @param settingsTools - Tool enablement from provider settings (optional)\n * @param perCallTools - Per-call tool override (optional)\n * @returns The resolved list of tool configs to include in the request\n * @public\n */\nexport function resolveEffectiveTools(\n descriptor: IAiProviderDescriptor,\n settingsTools?: ReadonlyArray<IAiToolEnablement>,\n perCallTools?: ReadonlyArray<AiServerToolConfig>\n): ReadonlyArray<AiServerToolConfig> {\n const supported = new Set(descriptor.supportedTools);\n\n if (perCallTools !== undefined) {\n return perCallTools.filter((t) => supported.has(t.type));\n }\n\n if (settingsTools === undefined) {\n return [];\n }\n\n return settingsTools\n .filter((e) => e.enabled && supported.has(e.type))\n .map((e): AiServerToolConfig => e.config ?? { type: e.type });\n}\n\n// ============================================================================\n// OpenAI / xAI Responses API format\n// ============================================================================\n\n/**\n * Formats a web search tool config for the xAI/OpenAI Responses API.\n * @internal\n */\nfunction webSearchToResponsesApi(config: IAiWebSearchToolConfig): JsonObject {\n const tool: Record<string, unknown> = { type: 'web_search' };\n\n if (config.allowedDomains || config.blockedDomains) {\n const filters: Record<string, unknown> = {};\n if (config.allowedDomains) {\n filters.allowed_domains = [...config.allowedDomains];\n }\n if (config.blockedDomains) {\n filters.excluded_domains = [...config.blockedDomains];\n }\n tool.filters = filters;\n }\n\n if (config.enableImageUnderstanding) {\n tool.enable_image_understanding = true;\n }\n\n return tool as JsonObject;\n}\n\n/**\n * Formats tool configs for the xAI/OpenAI Responses API.\n * @param tools - The resolved tool configs\n * @returns Provider-native tool objects for the `tools` request field\n * @public\n */\nexport function toResponsesApiTools(tools: ReadonlyArray<AiServerToolConfig>): ReadonlyArray<JsonObject> {\n return tools.map((t) => {\n switch (t.type) {\n case 'web_search':\n return webSearchToResponsesApi(t);\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = t.type;\n return { type: String(_exhaustive) } as JsonObject;\n }\n }\n });\n}\n\n// ============================================================================\n// Anthropic Messages API format\n// ============================================================================\n\n/**\n * Formats a web search tool config for the Anthropic Messages API.\n * @internal\n */\nfunction webSearchToAnthropic(config: IAiWebSearchToolConfig): JsonObject {\n const tool: Record<string, unknown> = {\n type: 'web_search_20250305',\n name: 'web_search'\n };\n\n if (config.maxUses !== undefined) {\n tool.max_uses = config.maxUses;\n }\n if (config.allowedDomains) {\n tool.allowed_domains = [...config.allowedDomains];\n }\n if (config.blockedDomains) {\n tool.blocked_domains = [...config.blockedDomains];\n }\n\n return tool as JsonObject;\n}\n\n/**\n * Formats tool configs for the Anthropic Messages API.\n * @param tools - The resolved tool configs\n * @returns Provider-native tool objects for the `tools` request field\n * @public\n */\nexport function toAnthropicTools(tools: ReadonlyArray<AiServerToolConfig>): ReadonlyArray<JsonObject> {\n return tools.map((t) => {\n switch (t.type) {\n case 'web_search':\n return webSearchToAnthropic(t);\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = t.type;\n return { type: String(_exhaustive) } as JsonObject;\n }\n }\n });\n}\n\n// ============================================================================\n// Gemini generateContent API format\n// ============================================================================\n\n/**\n * Formats tool configs for the Gemini generateContent API.\n * Gemini uses `google_search` for search grounding — no per-tool config options.\n * @param tools - The resolved tool configs\n * @returns Provider-native tool objects for the `tools` request field\n * @public\n */\nexport function toGeminiTools(tools: ReadonlyArray<AiServerToolConfig>): ReadonlyArray<JsonObject> {\n const result: JsonObject[] = [];\n\n for (const t of tools) {\n switch (t.type) {\n case 'web_search':\n result.push({ google_search: {} } as JsonObject);\n break;\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = t.type;\n result.push({ type: String(_exhaustive) } as JsonObject);\n }\n }\n }\n\n return result;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"toolFormats.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/toolFormats.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Provider-specific tool format translation and tool resolution logic.\n * @packageDocumentation\n */\n\nimport { type JsonObject, type JsonValue } from '@fgv/ts-json-base';\n\nimport {\n type AiServerToolConfig,\n type AiToolConfig,\n type IAiClientToolConfig,\n type IAiProviderDescriptor,\n type IAiToolEnablement,\n type IAiWebSearchToolConfig\n} from './model';\n\n// ============================================================================\n// Tool resolution\n// ============================================================================\n\n/**\n * Resolves the effective tools for a completion call.\n *\n * - If per-call tools are provided, they override settings-level tools entirely.\n * - Otherwise, settings-level enabled tools are used.\n * - Only tools supported by the provider are included.\n * - Returns an empty array if no tools are enabled (= no tools sent).\n *\n * @param descriptor - The provider descriptor (used to filter by supported tools)\n * @param settingsTools - Tool enablement from provider settings (optional)\n * @param perCallTools - Per-call tool override (optional)\n * @returns The resolved list of tool configs to include in the request\n * @public\n */\nexport function resolveEffectiveTools(\n descriptor: IAiProviderDescriptor,\n settingsTools?: ReadonlyArray<IAiToolEnablement>,\n perCallTools?: ReadonlyArray<AiServerToolConfig>\n): ReadonlyArray<AiServerToolConfig> {\n const supported = new Set(descriptor.supportedTools);\n\n if (perCallTools !== undefined) {\n return perCallTools.filter((t) => supported.has(t.type));\n }\n\n if (settingsTools === undefined) {\n return [];\n }\n\n return settingsTools\n .filter((e) => e.enabled && supported.has(e.type))\n .map((e): AiServerToolConfig => e.config ?? { type: e.type });\n}\n\n// ============================================================================\n// OpenAI / xAI Responses API format\n// ============================================================================\n\n/**\n * Formats a web search tool config for the xAI/OpenAI Responses API.\n * @internal\n */\nfunction webSearchToResponsesApi(config: IAiWebSearchToolConfig): JsonObject {\n const tool: Record<string, unknown> = { type: 'web_search' };\n\n if (config.allowedDomains || config.blockedDomains) {\n const filters: Record<string, unknown> = {};\n if (config.allowedDomains) {\n filters.allowed_domains = [...config.allowedDomains];\n }\n if (config.blockedDomains) {\n filters.excluded_domains = [...config.blockedDomains];\n }\n tool.filters = filters;\n }\n\n if (config.enableImageUnderstanding) {\n tool.enable_image_understanding = true;\n }\n\n return tool as JsonObject;\n}\n\n/**\n * Formats a client tool config for the xAI/OpenAI Responses API.\n * @internal\n */\nfunction clientToolToResponsesApi(config: IAiClientToolConfig): JsonObject {\n return {\n type: 'function',\n name: config.name,\n description: config.description,\n parameters: config.parametersSchema.toJson()\n } as JsonObject;\n}\n\n/**\n * Formats tool configs for the xAI/OpenAI Responses API.\n * @param tools - The resolved tool configs (server-side and/or client-defined)\n * @returns Provider-native tool objects for the `tools` request field\n * @public\n */\nexport function toResponsesApiTools(tools: ReadonlyArray<AiToolConfig>): ReadonlyArray<JsonObject> {\n return tools.map((t) => {\n switch (t.type) {\n case 'web_search':\n return webSearchToResponsesApi(t);\n case 'client_tool':\n return clientToolToResponsesApi(t);\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = t;\n return { type: `unknown:${JSON.stringify(_exhaustive)}` } as JsonObject;\n }\n }\n });\n}\n\n// ============================================================================\n// Anthropic Messages API format\n// ============================================================================\n\n/**\n * Formats a web search tool config for the Anthropic Messages API.\n * @internal\n */\nfunction webSearchToAnthropic(config: IAiWebSearchToolConfig): JsonObject {\n const tool: Record<string, unknown> = {\n type: 'web_search_20250305',\n name: 'web_search'\n };\n\n if (config.maxUses !== undefined) {\n tool.max_uses = config.maxUses;\n }\n if (config.allowedDomains) {\n tool.allowed_domains = [...config.allowedDomains];\n }\n if (config.blockedDomains) {\n tool.blocked_domains = [...config.blockedDomains];\n }\n\n return tool as JsonObject;\n}\n\n/**\n * Formats a client tool config for the Anthropic Messages API.\n * Note: Anthropic client tools have no `type` field (unlike server tools).\n * @internal\n */\nfunction clientToolToAnthropic(config: IAiClientToolConfig): JsonObject {\n return {\n name: config.name,\n description: config.description,\n input_schema: config.parametersSchema.toJson()\n } as JsonObject;\n}\n\n/**\n * Formats tool configs for the Anthropic Messages API.\n * @param tools - The resolved tool configs (server-side and/or client-defined)\n * @returns Provider-native tool objects for the `tools` request field\n * @public\n */\nexport function toAnthropicTools(tools: ReadonlyArray<AiToolConfig>): ReadonlyArray<JsonObject> {\n return tools.map((t) => {\n switch (t.type) {\n case 'web_search':\n return webSearchToAnthropic(t);\n case 'client_tool':\n return clientToolToAnthropic(t);\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = t;\n return { type: `unknown:${JSON.stringify(_exhaustive)}` } as JsonObject;\n }\n }\n });\n}\n\n// ============================================================================\n// Gemini generateContent API format\n// ============================================================================\n\n/**\n * Sanitizes a draft-07 JSON Schema (as emitted by `JsonSchema.object(...).toJson()`)\n * into the OpenAPI 3.0 Schema Object subset that Gemini's `function_declarations[].parameters`\n * accepts.\n *\n * @remarks\n * Gemini's function-declaration schema is **not** full JSON Schema — it is a subset of\n * the OpenAPI 3.0 Schema Object and **rejects** (rather than ignores) draft-07-only\n * keywords. `JsonSchema` objects are strict-by-default, so `.toJson()` emits\n * `additionalProperties: false` on every object node, which 400s the whole request on\n * Gemini. This helper recursively strips the unsupported keywords so any\n * `JsonSchema`-authored client tool works on Gemini without consumer awareness of the\n * dialect difference. Stripping is infallible, so it returns a plain value rather than a\n * `Result`.\n *\n * `additionalProperties` and `$schema` are stripped only where they appear as schema\n * *keywords* (siblings of `type`/`properties`/etc.). Inside a `properties` map the keys\n * are user-defined parameter names, not keywords, so they are preserved verbatim while\n * each property's subschema value is still recursively sanitized — a tool parameter\n * legitimately named `additionalProperties` survives.\n *\n * @internal\n */\nexport function toGeminiParameterSchema(schema: JsonValue): JsonValue {\n if (Array.isArray(schema)) {\n return schema.map(toGeminiParameterSchema);\n }\n if (schema !== null && typeof schema === 'object') {\n const out: JsonObject = {};\n for (const [key, value] of Object.entries(schema)) {\n if (key === 'additionalProperties' || key === '$schema') {\n continue;\n }\n if (key === 'properties' && value !== null && typeof value === 'object' && !Array.isArray(value)) {\n // `properties` maps user-defined parameter names to subschemas: recurse each\n // subschema value but never treat a parameter name as a strippable keyword.\n const properties: JsonObject = {};\n for (const [name, propSchema] of Object.entries(value)) {\n properties[name] = toGeminiParameterSchema(propSchema);\n }\n out[key] = properties;\n } else {\n out[key] = toGeminiParameterSchema(value);\n }\n }\n return out;\n }\n return schema;\n}\n\n/**\n * Formats tool configs for the Gemini generateContent API.\n *\n * @remarks\n * Gemini uses `google_search` for search grounding (no per-tool config).\n * Client-defined tools are accumulated into a single `function_declarations` entry.\n * Each client tool's parameters schema is sanitized to Gemini's OpenAPI-subset\n * dialect via {@link toGeminiParameterSchema} (the raw draft-07 `.toJson()` output\n * carries `additionalProperties`, which Gemini rejects).\n *\n * @param tools - The resolved tool configs (server-side and/or client-defined)\n * @returns Provider-native tool objects for the `tools` request field\n * @public\n */\nexport function toGeminiTools(tools: ReadonlyArray<AiToolConfig>): ReadonlyArray<JsonObject> {\n const result: JsonObject[] = [];\n const functionDeclarations: JsonObject[] = [];\n\n for (const t of tools) {\n switch (t.type) {\n case 'web_search':\n result.push({ google_search: {} } as JsonObject);\n break;\n case 'client_tool':\n functionDeclarations.push({\n name: t.name,\n description: t.description,\n parameters: toGeminiParameterSchema(t.parametersSchema.toJson())\n } as JsonObject);\n break;\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = t;\n result.push({ type: `unknown:${JSON.stringify(_exhaustive)}` } as JsonObject);\n }\n }\n }\n\n if (functionDeclarations.length > 0) {\n result.push({ function_declarations: functionDeclarations } as JsonObject);\n }\n\n return result;\n}\n"]}
|
|
@@ -26,8 +26,9 @@
|
|
|
26
26
|
export * from './model';
|
|
27
27
|
// Constants
|
|
28
28
|
export { AES_256_KEY_SIZE, DEFAULT_ALGORITHM, ENCRYPTED_FILE_FORMAT, GCM_AUTH_TAG_SIZE, GCM_IV_SIZE } from './constants';
|
|
29
|
-
// KeyStore namespace
|
|
30
|
-
|
|
29
|
+
// KeyStore namespace (browser-safe barrel — omits the Node-only
|
|
30
|
+
// EncryptedFilePrivateKeyStorage so the browser entry stays free of node:crypto)
|
|
31
|
+
import * as KeyStore from './keystore/index.browser';
|
|
31
32
|
export { KeyStore };
|
|
32
33
|
// Converters namespace
|
|
33
34
|
import * as Converters from './converters';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.browser.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/index.browser.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AACxE,2DAA2D;AAC3D,EAAE;AACF,iFAAiF;AACjF,kDAAkD;AAClD,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,8EAA8E;AAC9E,yEAAyE;AACzE,gFAAgF;AAChF,gFAAgF;AAChF,YAAY;AAEZ;;;;GAIG;AAEH,iCAAiC;AACjC,cAAc,SAAS,CAAC;AAExB,YAAY;AACZ,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,WAAW,EACZ,MAAM,aAAa,CAAC;AAErB,
|
|
1
|
+
{"version":3,"file":"index.browser.js","sourceRoot":"","sources":["../../../src/packlets/crypto-utils/index.browser.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AACxE,2DAA2D;AAC3D,EAAE;AACF,iFAAiF;AACjF,kDAAkD;AAClD,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,8EAA8E;AAC9E,yEAAyE;AACzE,gFAAgF;AAChF,gFAAgF;AAChF,YAAY;AAEZ;;;;GAIG;AAEH,iCAAiC;AACjC,cAAc,SAAS,CAAC;AAExB,YAAY;AACZ,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,WAAW,EACZ,MAAM,aAAa,CAAC;AAErB,gEAAgE;AAChE,iFAAiF;AACjF,OAAO,KAAK,QAAQ,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,CAAC;AAEpB,uBAAuB;AACvB,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,6BAA6B;AAC7B,OAAO,EAAE,wBAAwB,EAAmC,MAAM,4BAA4B,CAAC;AAEvG,8DAA8D;AAC9D,OAAO,EAA2B,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAE3F,8DAA8D;AAC9D,4DAA4D;AAE5D,yBAAyB;AACzB,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,UAAU,EAEV,QAAQ,EACR,cAAc,EACf,MAAM,iBAAiB,CAAC;AAEzB,yBAAyB;AACzB,OAAO,EACL,8BAA8B,EAC9B,gCAAgC,EAChC,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,eAAe,CAAC;AAEvB,qFAAqF;AACrF,uFAAuF;AACvF,OAAO,EAAE,YAAY,EAAmB,MAAM,gBAAgB,CAAC","sourcesContent":["// Copyright (c) 2024 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Crypto utilities for encrypted file handling and key management (browser version).\n * Note: For browser crypto provider, use \\@fgv/ts-web-extras.\n * @packageDocumentation\n */\n\n// Re-export all types from model\nexport * from './model';\n\n// Constants\nexport {\n AES_256_KEY_SIZE,\n DEFAULT_ALGORITHM,\n ENCRYPTED_FILE_FORMAT,\n GCM_AUTH_TAG_SIZE,\n GCM_IV_SIZE\n} from './constants';\n\n// KeyStore namespace (browser-safe barrel — omits the Node-only\n// EncryptedFilePrivateKeyStorage so the browser entry stays free of node:crypto)\nimport * as KeyStore from './keystore/index.browser';\nexport { KeyStore };\n\n// Converters namespace\nimport * as Converters from './converters';\nexport { Converters };\n\n// Direct encryption provider\nexport { DirectEncryptionProvider, IDirectEncryptionProviderParams } from './directEncryptionProvider';\n\n// WebCrypto parameter table for asymmetric keypair algorithms\nexport { IKeyPairAlgorithmParams, keyPairAlgorithmParams } from './keyPairAlgorithmParams';\n\n// Note: NodeCryptoProvider is NOT exported in browser version\n// Use BrowserCryptoProvider from @fgv/ts-web-extras instead\n\n// Encrypted file helpers\nexport {\n createEncryptedFile,\n decryptFile,\n fromBase64,\n ICreateEncryptedFileParams,\n toBase64,\n tryDecryptFile\n} from './encryptedFile';\n\n// Multibase/SPKI helpers\nexport {\n exportPublicKeyAsMultibaseSpki,\n importPublicKeyFromMultibaseSpki,\n multibaseBase64UrlDecode,\n multibaseBase64UrlEncode\n} from './spkiHelpers';\n\n// HPKE base mode (RFC 9180) — DHKEM(X25519, HKDF-SHA256) + HKDF-SHA256 + AES-256-GCM\n// hpkeProvider.ts has no Node-specific imports and is safe in the browser entry point.\nexport { HpkeProvider, IHpkeSealResult } from './hpkeProvider';\n"]}
|