@lota-sdk/core 0.4.21 → 0.4.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lota-sdk/core",
3
- "version": "0.4.21",
3
+ "version": "0.4.23",
4
4
  "files": [
5
5
  "src",
6
6
  "infrastructure/schema"
@@ -29,9 +29,10 @@
29
29
  "dependencies": {
30
30
  "@ai-sdk/devtools": "^0.0.16",
31
31
  "@ai-sdk/openai": "^3.0.54",
32
+ "@ai-sdk/provider": "^3.0.9",
32
33
  "@chat-adapter/slack": "^4.26.0",
33
34
  "@chat-adapter/state-ioredis": "^4.26.0",
34
- "@lota-sdk/shared": "0.4.21",
35
+ "@lota-sdk/shared": "0.4.23",
35
36
  "@mendable/firecrawl-js": "^4.20.0",
36
37
  "@surrealdb/node": "^3.0.3",
37
38
  "ai": "^6.0.170",
@@ -1,5 +1,6 @@
1
1
  import { devToolsMiddleware } from '@ai-sdk/devtools'
2
2
  import { createOpenAI } from '@ai-sdk/openai'
3
+ import type { JSONSchema7 } from '@ai-sdk/provider'
3
4
  import { wrapEmbeddingModel, wrapLanguageModel } from 'ai'
4
5
  import type { LanguageModelMiddleware } from 'ai'
5
6
  import { Cause, Clock, Context, Duration, Effect, Fiber, Layer, Semaphore } from 'effect'
@@ -16,6 +17,7 @@ type WrapStreamOptions = Parameters<NonNullable<LanguageModelMiddleware['wrapStr
16
17
  type AiGatewayLanguageModel = Parameters<typeof wrapLanguageModel>[0]['model']
17
18
  type AiGatewayEmbeddingModel = Parameters<typeof wrapEmbeddingModel>[0]['model']
18
19
  type AiGatewayCallOptions = WrapStreamOptions['params']
20
+ type AiGatewayFunctionTool = Extract<NonNullable<AiGatewayCallOptions['tools']>[number], { type: 'function' }>
19
21
  type AiGatewayGenerateResult = Awaited<ReturnType<WrapStreamOptions['doGenerate']>>
20
22
  type AiGatewayStreamResult = Awaited<ReturnType<WrapStreamOptions['doStream']>>
21
23
  type AiGatewayGeneratedContent = AiGatewayGenerateResult['content'][number]
@@ -892,6 +894,85 @@ function addAiGatewayReasoningRawChunks(
892
894
  return { ...params, includeRawChunks: true }
893
895
  }
894
896
 
897
+ const JSON_SCHEMA_PROPERTY_MAP_KEYS = new Set([
898
+ '$defs',
899
+ 'definitions',
900
+ 'dependentSchemas',
901
+ 'patternProperties',
902
+ 'properties',
903
+ ])
904
+
905
+ function removeJsonSchemaFormatKeywords(value: unknown): void {
906
+ if (Array.isArray(value)) {
907
+ for (const item of value) {
908
+ removeJsonSchemaFormatKeywords(item)
909
+ }
910
+ return
911
+ }
912
+
913
+ if (!isRecord(value)) {
914
+ return
915
+ }
916
+
917
+ delete value.format
918
+
919
+ for (const [key, child] of Object.entries(value)) {
920
+ if (JSON_SCHEMA_PROPERTY_MAP_KEYS.has(key) && isRecord(child)) {
921
+ for (const propertySchema of Object.values(child)) {
922
+ removeJsonSchemaFormatKeywords(propertySchema)
923
+ }
924
+ continue
925
+ }
926
+
927
+ removeJsonSchemaFormatKeywords(child)
928
+ }
929
+ }
930
+
931
+ function cloneAiGatewayJsonSchema(schema: JSONSchema7): JSONSchema7 {
932
+ // eslint-disable-next-line typescript-eslint/no-unsafe-assignment -- structuredClone preserves the imported JSONSchema7 shape.
933
+ const nextSchema: JSONSchema7 = structuredClone(schema)
934
+ removeJsonSchemaFormatKeywords(nextSchema)
935
+ return nextSchema
936
+ }
937
+
938
+ function isAiGatewayFunctionTool(
939
+ tool: NonNullable<AiGatewayCallOptions['tools']>[number],
940
+ ): tool is AiGatewayFunctionTool {
941
+ return isRecord(tool) && tool.type === 'function'
942
+ }
943
+
944
+ export function normalizeAiGatewayJsonSchemas(params: AiGatewayCallOptions): AiGatewayCallOptions {
945
+ let nextParams = params
946
+
947
+ if (params.responseFormat?.type === 'json' && params.responseFormat.schema) {
948
+ // eslint-disable-next-line typescript-eslint/no-unsafe-assignment -- cloneAiGatewayJsonSchema returns the same JSONSchema7 type.
949
+ const responseSchema: JSONSchema7 = cloneAiGatewayJsonSchema(params.responseFormat.schema)
950
+ nextParams = {
951
+ ...nextParams,
952
+ // eslint-disable-next-line typescript-eslint/no-unsafe-assignment -- responseSchema is JSONSchema7 for responseFormat.schema.
953
+ responseFormat: { ...params.responseFormat, schema: responseSchema },
954
+ }
955
+ }
956
+
957
+ const sourceTools = nextParams.tools
958
+ if (!Array.isArray(sourceTools)) {
959
+ return nextParams
960
+ }
961
+
962
+ const nextTools = sourceTools.map((tool) => {
963
+ if (!isAiGatewayFunctionTool(tool)) {
964
+ return tool
965
+ }
966
+
967
+ // eslint-disable-next-line typescript-eslint/no-unsafe-assignment -- function tool inputSchema is JSONSchema7.
968
+ const inputSchema: JSONSchema7 = cloneAiGatewayJsonSchema(tool.inputSchema)
969
+ // eslint-disable-next-line typescript-eslint/no-unsafe-assignment -- inputSchema is JSONSchema7 for function tool inputSchema.
970
+ return { ...tool, inputSchema }
971
+ })
972
+
973
+ return { ...nextParams, tools: nextTools as AiGatewayCallOptions['tools'] }
974
+ }
975
+
895
976
  function resolveProviderModel(
896
977
  provider: ReturnType<typeof createOpenAI>,
897
978
  modelId: string,
@@ -942,7 +1023,9 @@ function createAiGatewayLanguageModelMiddleware(
942
1023
  Promise.resolve(
943
1024
  withDefaultAiGatewayCacheHeaders(
944
1025
  addAiGatewayReasoningRawChunks(
945
- providerId === OPENAI_CHAT_PROVIDER_ID ? normalizeAiGatewayChatProviderOptions(params, modelId) : params,
1026
+ normalizeAiGatewayJsonSchemas(
1027
+ providerId === OPENAI_CHAT_PROVIDER_ID ? normalizeAiGatewayChatProviderOptions(params, modelId) : params,
1028
+ ),
946
1029
  type,
947
1030
  ),
948
1031
  ),
@@ -14,6 +14,7 @@ export {
14
14
  injectAiGatewayChatReasoningContent,
15
15
  injectAiGatewayChatReasoningStream,
16
16
  normalizeAiGatewayChatProviderOptions,
17
+ normalizeAiGatewayJsonSchemas,
17
18
  normalizeAiGatewayUrl,
18
19
  } from './ai-gateway'
19
20
  export type { AiGatewayDeps, AiGatewayModels, RuntimeBridge } from './ai-gateway'