@lota-sdk/core 0.4.20 → 0.4.22

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,13 +1,13 @@
1
1
  {
2
2
  "name": "@lota-sdk/core",
3
- "version": "0.4.20",
4
- "type": "module",
5
- "main": "./src/index.ts",
6
- "types": "./src/index.ts",
3
+ "version": "0.4.22",
7
4
  "files": [
8
5
  "src",
9
6
  "infrastructure/schema"
10
7
  ],
8
+ "type": "module",
9
+ "main": "./src/index.ts",
10
+ "types": "./src/index.ts",
11
11
  "exports": {
12
12
  ".": {
13
13
  "bun": "./src/index.ts",
@@ -15,6 +15,10 @@
15
15
  "types": "./src/index.ts"
16
16
  }
17
17
  },
18
+ "publishConfig": {
19
+ "access": "public",
20
+ "registry": "https://registry.npmjs.org/"
21
+ },
18
22
  "scripts": {
19
23
  "lint": "bunx oxlint --fix -c ../oxlint.config.ts src",
20
24
  "format": "bunx oxfmt src",
@@ -22,23 +26,19 @@
22
26
  "test:unit": "bun test --max-concurrency=1 ../tests/unit/core",
23
27
  "test:coverage": "bun test --coverage ../tests/unit/core"
24
28
  },
25
- "publishConfig": {
26
- "access": "public",
27
- "registry": "https://registry.npmjs.org/"
28
- },
29
29
  "dependencies": {
30
- "@ai-sdk/devtools": "^0.0.15",
31
- "@ai-sdk/openai": "^3.0.53",
30
+ "@ai-sdk/devtools": "^0.0.16",
31
+ "@ai-sdk/openai": "^3.0.54",
32
32
  "@chat-adapter/slack": "^4.26.0",
33
33
  "@chat-adapter/state-ioredis": "^4.26.0",
34
- "@lota-sdk/shared": "0.4.20",
35
- "@mendable/firecrawl-js": "^4.18.3",
34
+ "@lota-sdk/shared": "0.4.22",
35
+ "@mendable/firecrawl-js": "^4.20.0",
36
36
  "@surrealdb/node": "^3.0.3",
37
- "ai": "^6.0.168",
38
- "bullmq": "^5.74.2",
37
+ "ai": "^6.0.170",
38
+ "bullmq": "^5.76.4",
39
39
  "chat": "^4.26.0",
40
- "effect": "^4.0.0-beta.52",
41
- "hono": "^4.12.14",
40
+ "effect": "^4.0.0-beta.59",
41
+ "hono": "^4.12.15",
42
42
  "ioredis": "5.9.3",
43
43
  "mammoth": "^1.12.0",
44
44
  "pdf-parse": "^2.4.5",
@@ -721,6 +721,16 @@ function isReasoningEnabled(params: AiGatewayCallOptions): boolean {
721
721
  return typeof openaiOptions.reasoningEffort === 'string' && openaiOptions.reasoningEffort !== 'none'
722
722
  }
723
723
 
724
+ function hasFunctionTools(params: AiGatewayCallOptions): boolean {
725
+ return Array.isArray(params.tools) && params.tools.some((tool) => isRecord(tool) && tool.type === 'function')
726
+ }
727
+
728
+ function isGpt55Model(modelId: string): boolean {
729
+ const normalized = modelId.trim().toLowerCase()
730
+ const modelName = normalized.split('/').at(-1) ?? normalized
731
+ return modelName === 'gpt-5.5' || modelName.startsWith('gpt-5.5-')
732
+ }
733
+
724
734
  function isOpenRouterModel(modelId: string): boolean {
725
735
  return modelId.trim().toLowerCase().startsWith('openrouter/')
726
736
  }
@@ -882,12 +892,91 @@ function addAiGatewayReasoningRawChunks(
882
892
  return { ...params, includeRawChunks: true }
883
893
  }
884
894
 
895
+ const JSON_SCHEMA_PROPERTY_MAP_KEYS = new Set([
896
+ '$defs',
897
+ 'definitions',
898
+ 'dependentSchemas',
899
+ 'patternProperties',
900
+ 'properties',
901
+ ])
902
+
903
+ function stripJsonSchemaFormatKeywords(value: unknown): unknown {
904
+ if (Array.isArray(value)) {
905
+ return value.map((item) => stripJsonSchemaFormatKeywords(item))
906
+ }
907
+
908
+ if (!isRecord(value)) {
909
+ return value
910
+ }
911
+
912
+ let changed = false
913
+ const nextValue: Record<string, unknown> = {}
914
+
915
+ for (const [key, child] of Object.entries(value)) {
916
+ if (key === 'format') {
917
+ changed = true
918
+ continue
919
+ }
920
+
921
+ if (JSON_SCHEMA_PROPERTY_MAP_KEYS.has(key) && isRecord(child)) {
922
+ let mapChanged = false
923
+ const nextMap: Record<string, unknown> = {}
924
+ for (const [propertyName, propertySchema] of Object.entries(child)) {
925
+ const nextPropertySchema = stripJsonSchemaFormatKeywords(propertySchema)
926
+ mapChanged ||= nextPropertySchema !== propertySchema
927
+ nextMap[propertyName] = nextPropertySchema
928
+ }
929
+ changed ||= mapChanged
930
+ nextValue[key] = mapChanged ? nextMap : child
931
+ continue
932
+ }
933
+
934
+ const nextChild = stripJsonSchemaFormatKeywords(child)
935
+ changed ||= nextChild !== child
936
+ nextValue[key] = nextChild
937
+ }
938
+
939
+ return changed ? nextValue : value
940
+ }
941
+
942
+ export function normalizeAiGatewayJsonSchemas(params: AiGatewayCallOptions): AiGatewayCallOptions {
943
+ let nextParams = params
944
+
945
+ if (params.responseFormat?.type === 'json' && params.responseFormat.schema) {
946
+ const nextSchema = stripJsonSchemaFormatKeywords(params.responseFormat.schema)
947
+ if (nextSchema !== params.responseFormat.schema) {
948
+ nextParams = { ...nextParams, responseFormat: { ...params.responseFormat, schema: nextSchema } }
949
+ }
950
+ }
951
+
952
+ const sourceTools = nextParams.tools
953
+ if (!Array.isArray(sourceTools)) {
954
+ return nextParams
955
+ }
956
+
957
+ const nextTools = sourceTools.map((tool) => {
958
+ if (!isRecord(tool) || tool.type !== 'function') {
959
+ return tool
960
+ }
961
+
962
+ const inputSchema = (tool as { inputSchema: unknown }).inputSchema
963
+ const nextInputSchema = stripJsonSchemaFormatKeywords(inputSchema)
964
+ return { ...tool, inputSchema: nextInputSchema }
965
+ })
966
+
967
+ return { ...nextParams, tools: nextTools as AiGatewayCallOptions['tools'] }
968
+ }
969
+
885
970
  function resolveProviderModel(
886
971
  provider: ReturnType<typeof createOpenAI>,
887
972
  modelId: string,
888
973
  providerId: string,
889
974
  ): AiGatewayLanguageModel {
890
- return providerId === OPENAI_CHAT_PROVIDER_ID ? provider.chat(modelId) : provider(modelId)
975
+ if (providerId !== OPENAI_CHAT_PROVIDER_ID) {
976
+ return provider(modelId)
977
+ }
978
+
979
+ return provider.chat(modelId)
891
980
  }
892
981
 
893
982
  export type AiGatewayDeps = {
@@ -927,7 +1016,12 @@ function createAiGatewayLanguageModelMiddleware(
927
1016
  transformParams: ({ params, type }) =>
928
1017
  Promise.resolve(
929
1018
  withDefaultAiGatewayCacheHeaders(
930
- addAiGatewayReasoningRawChunks(normalizeAiGatewayChatProviderOptions(params, modelId), type),
1019
+ addAiGatewayReasoningRawChunks(
1020
+ normalizeAiGatewayJsonSchemas(
1021
+ providerId === OPENAI_CHAT_PROVIDER_ID ? normalizeAiGatewayChatProviderOptions(params, modelId) : params,
1022
+ ),
1023
+ type,
1024
+ ),
931
1025
  ),
932
1026
  ),
933
1027
  wrapGenerate: ({ params }) => {
@@ -972,9 +1066,38 @@ function createAiGatewayLanguageModelMiddleware(
972
1066
 
973
1067
  export function normalizeAiGatewayChatProviderOptions(
974
1068
  params: AiGatewayCallOptions,
975
- _modelId?: string,
1069
+ modelId?: string,
976
1070
  ): AiGatewayCallOptions {
977
- return params
1071
+ if (!modelId || !isGpt55Model(modelId) || !hasFunctionTools(params)) {
1072
+ return params
1073
+ }
1074
+
1075
+ if (!isRecord(params.providerOptions) || !isRecord(params.providerOptions.openai)) {
1076
+ return params
1077
+ }
1078
+
1079
+ const openaiOptions = { ...params.providerOptions.openai }
1080
+ const strippedReasoningOptions =
1081
+ 'forceReasoning' in openaiOptions || 'reasoningEffort' in openaiOptions || 'reasoningSummary' in openaiOptions
1082
+ if (!strippedReasoningOptions) {
1083
+ return params
1084
+ }
1085
+
1086
+ delete openaiOptions.forceReasoning
1087
+ delete openaiOptions.reasoningEffort
1088
+ delete openaiOptions.reasoningSummary
1089
+
1090
+ const providerOptions = { ...params.providerOptions }
1091
+ delete providerOptions.openai
1092
+ const nextProviderOptions =
1093
+ Object.keys(openaiOptions).length === 0 ? providerOptions : { ...providerOptions, openai: openaiOptions }
1094
+
1095
+ if (Object.keys(nextProviderOptions).length === 0) {
1096
+ const { providerOptions: _providerOptions, ...nextParams } = params
1097
+ return nextParams
1098
+ }
1099
+
1100
+ return { ...params, providerOptions: nextProviderOptions as AiGatewayCallOptions['providerOptions'] }
978
1101
  }
979
1102
 
980
1103
  function withAiGatewayDevTools<TModel extends AiGatewayLanguageModel>(model: TModel): TModel {
@@ -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'
@@ -82,15 +82,15 @@ type PromisifiedService<T> = {
82
82
 
83
83
  type HostSvc<T extends { readonly Service: object }> = PromisifiedService<T['Service']>
84
84
 
85
- export type PromisifiedThreadService = HostSvc<typeof ThreadServiceTag>
86
- export type PromisifiedDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag>
85
+ type PromisifiedThreadService = HostSvc<typeof ThreadServiceTag>
86
+ type PromisifiedDocumentChunkService = HostSvc<typeof DocumentChunkServiceTag>
87
87
 
88
- export type ArchiveSdkThread = (
88
+ type ArchiveSdkThread = (
89
89
  threadId: Parameters<Svc<typeof ThreadServiceTag>['updateStatus']>[0],
90
90
  status?: 'archived',
91
91
  ) => ReturnType<Svc<typeof ThreadServiceTag>['updateStatus']>
92
92
 
93
- export type UnarchiveSdkThread = (
93
+ type UnarchiveSdkThread = (
94
94
  threadId: Parameters<Svc<typeof ThreadServiceTag>['updateStatus']>[0],
95
95
  status?: 'active',
96
96
  ) => ReturnType<Svc<typeof ThreadServiceTag>['updateStatus']>
@@ -5,7 +5,7 @@ import { nowEpochMillis } from '../utils/date-time'
5
5
  import { buildCompletionCheckStructuredOutputHints } from './agent-runtime-policy'
6
6
  import { mergeInstructionSections } from './instruction-sections'
7
7
 
8
- export interface PlanTurnUpstreamHandoff {
8
+ interface PlanTurnUpstreamHandoff {
9
9
  nodeId: string
10
10
  label: string
11
11
  ownerRef: string
@@ -16,7 +16,7 @@ import type { LotaRuntimeBackgroundCursor } from '../../runtime/runtime-extensio
16
16
  import type { SocialChatHistoryMessage } from '../../services/social-chat-history.service'
17
17
  import { unsafeDateFrom } from '../../utils/date-time'
18
18
 
19
- export interface ThreadDigestMessage {
19
+ interface ThreadDigestMessage {
20
20
  source: 'thread'
21
21
  sourceId: string
22
22
  role: 'system' | 'user' | 'assistant'
@@ -25,7 +25,7 @@ export interface ThreadDigestMessage {
25
25
  cursor: LotaRuntimeBackgroundCursor
26
26
  }
27
27
 
28
- export type SocialDigestMessage = Pick<
28
+ type SocialDigestMessage = Pick<
29
29
  SocialChatHistoryMessage,
30
30
  'source' | 'sourceId' | 'role' | 'parts' | 'metadata' | 'cursor'
31
31
  >