@ai-sdk/moonshotai 0.0.20 → 0.0.25
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/CHANGELOG.md +51 -0
- package/README.md +40 -12
- package/dist/index.d.mts +62 -18
- package/dist/index.d.ts +62 -18
- package/dist/index.js +767 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +762 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/src/index.ts +3 -0
- package/src/moonshotai-chat-language-model.ts +607 -7
- package/src/moonshotai-chat-metadata-extractor.ts +112 -0
- package/src/moonshotai-chat-options.ts +187 -9
- package/src/moonshotai-provider.ts +17 -0
- package/src/normalize-json-schema-for-mfjs.ts +103 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { MetadataExtractor } from '@ai-sdk/openai-compatible';
|
|
2
|
+
import type { JSONValue } from '@ai-sdk/provider';
|
|
3
|
+
|
|
4
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
5
|
+
return value != null && typeof value === 'object' && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function getFirstChoice(value: Record<string, unknown>) {
|
|
9
|
+
const choices = value.choices;
|
|
10
|
+
return Array.isArray(choices) && isRecord(choices[0])
|
|
11
|
+
? choices[0]
|
|
12
|
+
: undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getToolCallTypes(value: unknown): Array<'function'> | undefined {
|
|
16
|
+
if (!Array.isArray(value)) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return value.flatMap(toolCall =>
|
|
21
|
+
isRecord(toolCall) && toolCall.type === 'function' ? [toolCall.type] : [],
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function extractMetadata(value: unknown): Record<string, JSONValue> {
|
|
26
|
+
if (!isRecord(value)) {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const choice = getFirstChoice(value);
|
|
31
|
+
const message =
|
|
32
|
+
choice != null && isRecord(choice.message) ? choice.message : undefined;
|
|
33
|
+
const toolCallTypes = getToolCallTypes(message?.tool_calls);
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
...(value.object === 'chat.completion' && {
|
|
37
|
+
responseObject: value.object,
|
|
38
|
+
}),
|
|
39
|
+
...(typeof choice?.index === 'number' && {
|
|
40
|
+
choiceIndex: choice.index,
|
|
41
|
+
}),
|
|
42
|
+
...(message?.role === 'assistant' && {
|
|
43
|
+
messageRole: message.role,
|
|
44
|
+
}),
|
|
45
|
+
...(toolCallTypes != null && { toolCallTypes }),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const moonshotAIChatMetadataExtractor: MetadataExtractor = {
|
|
50
|
+
async extractMetadata({ parsedBody }) {
|
|
51
|
+
return { moonshotai: extractMetadata(parsedBody) };
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
createStreamExtractor() {
|
|
55
|
+
let responseObject: 'chat.completion.chunk' | undefined;
|
|
56
|
+
let choiceIndex: number | undefined;
|
|
57
|
+
let messageRole: 'assistant' | undefined;
|
|
58
|
+
const toolCallTypes = new Map<number, 'function'>();
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
processChunk(parsedChunk) {
|
|
62
|
+
if (!isRecord(parsedChunk)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (parsedChunk.object === 'chat.completion.chunk') {
|
|
67
|
+
responseObject = parsedChunk.object;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const choice = getFirstChoice(parsedChunk);
|
|
71
|
+
if (typeof choice?.index === 'number') {
|
|
72
|
+
choiceIndex = choice.index;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const delta =
|
|
76
|
+
choice != null && isRecord(choice.delta) ? choice.delta : undefined;
|
|
77
|
+
if (delta?.role === 'assistant') {
|
|
78
|
+
messageRole = delta.role;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (Array.isArray(delta?.tool_calls)) {
|
|
82
|
+
for (const [fallbackIndex, toolCall] of delta.tool_calls.entries()) {
|
|
83
|
+
if (!isRecord(toolCall) || toolCall.type !== 'function') {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const index =
|
|
88
|
+
typeof toolCall.index === 'number'
|
|
89
|
+
? toolCall.index
|
|
90
|
+
: fallbackIndex;
|
|
91
|
+
toolCallTypes.set(index, toolCall.type);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
buildMetadata() {
|
|
97
|
+
return {
|
|
98
|
+
moonshotai: {
|
|
99
|
+
...(responseObject != null && { responseObject }),
|
|
100
|
+
...(choiceIndex != null && { choiceIndex }),
|
|
101
|
+
...(messageRole != null && { messageRole }),
|
|
102
|
+
...(toolCallTypes.size > 0 && {
|
|
103
|
+
toolCallTypes: [...toolCallTypes.entries()]
|
|
104
|
+
.sort(([left], [right]) => left - right)
|
|
105
|
+
.map(([, type]) => type),
|
|
106
|
+
}),
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
};
|
|
@@ -1,34 +1,212 @@
|
|
|
1
|
+
import type { LanguageModelV2FunctionTool } from '@ai-sdk/provider';
|
|
1
2
|
import { z } from 'zod/v4';
|
|
2
3
|
|
|
3
4
|
export type MoonshotAIChatModelId =
|
|
5
|
+
| 'moonshot-v1-auto'
|
|
4
6
|
| 'moonshot-v1-8k'
|
|
5
7
|
| 'moonshot-v1-32k'
|
|
6
8
|
| 'moonshot-v1-128k'
|
|
7
|
-
| '
|
|
8
|
-
| '
|
|
9
|
-
| '
|
|
10
|
-
| 'kimi-k2-thinking-turbo'
|
|
11
|
-
| 'kimi-k2-turbo'
|
|
9
|
+
| 'moonshot-v1-8k-vision-preview'
|
|
10
|
+
| 'moonshot-v1-32k-vision-preview'
|
|
11
|
+
| 'moonshot-v1-128k-vision-preview'
|
|
12
12
|
| 'kimi-k2.5'
|
|
13
|
+
| 'kimi-k2.6'
|
|
14
|
+
| 'kimi-k2.7-code'
|
|
15
|
+
| 'kimi-k2.7-code-highspeed'
|
|
13
16
|
| 'kimi-k3'
|
|
14
17
|
| (string & {});
|
|
15
18
|
|
|
19
|
+
export type MoonshotAIModelFamily =
|
|
20
|
+
| 'kimi-k2.5'
|
|
21
|
+
| 'kimi-k2.6'
|
|
22
|
+
| 'kimi-k2.7'
|
|
23
|
+
| 'kimi-k3'
|
|
24
|
+
| 'moonshot-v1'
|
|
25
|
+
| 'unknown';
|
|
26
|
+
|
|
27
|
+
export function getMoonshotAIModelFamily(
|
|
28
|
+
modelId: MoonshotAIChatModelId,
|
|
29
|
+
): MoonshotAIModelFamily {
|
|
30
|
+
if (modelId === 'kimi-k2.5') return 'kimi-k2.5';
|
|
31
|
+
if (modelId === 'kimi-k2.6') return 'kimi-k2.6';
|
|
32
|
+
if (modelId === 'kimi-k2.7-code' || modelId === 'kimi-k2.7-code-highspeed') {
|
|
33
|
+
return 'kimi-k2.7';
|
|
34
|
+
}
|
|
35
|
+
if (modelId === 'kimi-k3') return 'kimi-k3';
|
|
36
|
+
if (modelId.startsWith('moonshot-v1-')) return 'moonshot-v1';
|
|
37
|
+
return 'unknown';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function isMoonshotAIKimiModel(modelId: MoonshotAIChatModelId): boolean {
|
|
41
|
+
return getMoonshotAIModelFamily(modelId).startsWith('kimi-');
|
|
42
|
+
}
|
|
43
|
+
|
|
16
44
|
export const moonshotaiProviderOptions = z.object({
|
|
17
45
|
/**
|
|
18
|
-
*
|
|
46
|
+
* Whether to use strict JSON schema validation for structured outputs.
|
|
47
|
+
*
|
|
48
|
+
* @default true
|
|
49
|
+
*/
|
|
50
|
+
strictJsonSchema: z.boolean().optional(),
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Whether to return log probabilities for generated tokens.
|
|
54
|
+
*/
|
|
55
|
+
logprobs: z.boolean().optional(),
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Number of most likely tokens to return at each token position.
|
|
59
|
+
*
|
|
60
|
+
* Setting this option automatically enables `logprobs`.
|
|
61
|
+
*/
|
|
62
|
+
topLogprobs: z.number().int().min(0).max(20).optional(),
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Reasoning effort for Kimi K3. Supports `low`, `high`, and `max`;
|
|
66
|
+
* defaults to `max`.
|
|
67
|
+
*/
|
|
68
|
+
reasoningEffort: z.enum(['low', 'high', 'max']).optional(),
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Static predicted content that can accelerate responses when much of the
|
|
72
|
+
* output is known ahead of time.
|
|
19
73
|
*/
|
|
20
|
-
|
|
74
|
+
prediction: z
|
|
75
|
+
.object({
|
|
76
|
+
type: z.literal('content'),
|
|
77
|
+
content: z.union([
|
|
78
|
+
z.string(),
|
|
79
|
+
z.array(z.object({ type: z.literal('text'), text: z.string() })),
|
|
80
|
+
]),
|
|
81
|
+
})
|
|
82
|
+
.optional(),
|
|
21
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Thinking configuration for Kimi K2.x models. Kimi K2.5 and K2.6 support
|
|
86
|
+
* enabling or disabling thinking. Kimi K2.7 Code always has thinking
|
|
87
|
+
* enabled.
|
|
88
|
+
*/
|
|
22
89
|
thinking: z
|
|
23
90
|
.object({
|
|
24
91
|
type: z.enum(['enabled', 'disabled']).optional(),
|
|
92
|
+
/**
|
|
93
|
+
* @deprecated Moonshot Chat Completions does not support thinking
|
|
94
|
+
* budgets. Accepted for backwards compatibility, then omitted with a
|
|
95
|
+
* warning.
|
|
96
|
+
*/
|
|
25
97
|
budgetTokens: z.number().int().min(1024).optional(),
|
|
26
98
|
})
|
|
27
99
|
.optional(),
|
|
28
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Controls preserved reasoning behavior in multi-turn conversations.
|
|
103
|
+
* `disabled` and `interleaved` are compatibility values that leave the
|
|
104
|
+
* request unchanged. `preserved` maps to `thinking.keep: 'all'` for Kimi
|
|
105
|
+
* K2.6. Kimi K2.7 and K3 preserve reasoning by default.
|
|
106
|
+
*/
|
|
29
107
|
reasoningHistory: z.enum(['disabled', 'interleaved', 'preserved']).optional(),
|
|
30
108
|
});
|
|
31
109
|
|
|
32
|
-
export type MoonshotAIProviderOptions =
|
|
33
|
-
|
|
110
|
+
export type MoonshotAIProviderOptions = {
|
|
111
|
+
/**
|
|
112
|
+
* Whether to use strict JSON schema validation for structured outputs.
|
|
113
|
+
*
|
|
114
|
+
* @default true
|
|
115
|
+
*/
|
|
116
|
+
strictJsonSchema?: boolean;
|
|
117
|
+
|
|
118
|
+
/** Whether to return log probabilities for generated tokens. */
|
|
119
|
+
logprobs?: boolean;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Number of most likely tokens to return at each token position.
|
|
123
|
+
* Setting this option automatically enables `logprobs`.
|
|
124
|
+
*/
|
|
125
|
+
topLogprobs?: number;
|
|
126
|
+
|
|
127
|
+
/** Reasoning effort for Kimi K3. */
|
|
128
|
+
reasoningEffort?: 'low' | 'high' | 'max';
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Static predicted content that can accelerate responses when much of the
|
|
132
|
+
* output is known ahead of time.
|
|
133
|
+
*/
|
|
134
|
+
prediction?: {
|
|
135
|
+
type: 'content';
|
|
136
|
+
content: string | Array<{ type: 'text'; text: string }>;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/** Controls thinking on Kimi K2.5 and K2.6. K2.7 is always enabled. */
|
|
140
|
+
thinking?: {
|
|
141
|
+
type?: 'enabled' | 'disabled';
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @deprecated Moonshot Chat Completions does not support thinking budgets.
|
|
145
|
+
* This value is ignored with a warning.
|
|
146
|
+
*/
|
|
147
|
+
budgetTokens?: number;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Controls preserved reasoning behavior in multi-turn conversations.
|
|
152
|
+
* `disabled` and `interleaved` are compatibility values that leave the
|
|
153
|
+
* request unchanged. `preserved` maps to `thinking.keep: 'all'` for Kimi
|
|
154
|
+
* K2.6. Kimi K2.7 and K3 preserve reasoning by default.
|
|
155
|
+
*/
|
|
156
|
+
reasoningHistory?: 'disabled' | 'interleaved' | 'preserved';
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export const moonshotaiMessageProviderOptions = z.object({
|
|
160
|
+
/**
|
|
161
|
+
* The name of the participant represented by the message.
|
|
162
|
+
*
|
|
163
|
+
* Supported on system, user, and assistant messages.
|
|
164
|
+
*/
|
|
165
|
+
name: z.string().optional(),
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
export type MoonshotAIMessageProviderOptions = z.infer<
|
|
169
|
+
typeof moonshotaiMessageProviderOptions
|
|
170
|
+
>;
|
|
171
|
+
|
|
172
|
+
export const moonshotaiAssistantMessageProviderOptions =
|
|
173
|
+
moonshotaiMessageProviderOptions.extend({
|
|
174
|
+
/**
|
|
175
|
+
* Whether the assistant message content is a partial response that Moonshot
|
|
176
|
+
* should continue. Only supported on the final assistant message and cannot
|
|
177
|
+
* be combined with JSON object response format.
|
|
178
|
+
*/
|
|
179
|
+
partial: z.literal(true).optional(),
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
export type MoonshotAIAssistantMessageProviderOptions = z.infer<
|
|
183
|
+
typeof moonshotaiAssistantMessageProviderOptions
|
|
34
184
|
>;
|
|
185
|
+
|
|
186
|
+
const moonshotaiDynamicToolSchema = z.object({
|
|
187
|
+
type: z.literal('function'),
|
|
188
|
+
name: z.string(),
|
|
189
|
+
description: z.string().optional(),
|
|
190
|
+
inputSchema: z.record(z.string(), z.unknown()),
|
|
191
|
+
strict: z.boolean().optional(),
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
export const moonshotaiAllMessageProviderOptions =
|
|
195
|
+
moonshotaiAssistantMessageProviderOptions.extend({
|
|
196
|
+
/** Function tools to load at this point in a Kimi K3 conversation. */
|
|
197
|
+
tools: z.array(moonshotaiDynamicToolSchema).optional(),
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
export type MoonshotAISystemMessageProviderOptions =
|
|
201
|
+
MoonshotAIMessageProviderOptions & {
|
|
202
|
+
/** Function tools to load at this point in a Kimi K3 conversation. */
|
|
203
|
+
tools?: Array<
|
|
204
|
+
Pick<
|
|
205
|
+
LanguageModelV2FunctionTool,
|
|
206
|
+
'type' | 'name' | 'description' | 'inputSchema'
|
|
207
|
+
> & {
|
|
208
|
+
/** Whether Moonshot should enforce the tool input schema strictly. */
|
|
209
|
+
strict?: boolean;
|
|
210
|
+
}
|
|
211
|
+
>;
|
|
212
|
+
};
|
|
@@ -21,6 +21,7 @@ const moonshotaiErrorSchema = z.object({
|
|
|
21
21
|
error: z.object({
|
|
22
22
|
message: z.string(),
|
|
23
23
|
type: z.string().nullish(),
|
|
24
|
+
code: z.string().nullish(),
|
|
24
25
|
}),
|
|
25
26
|
});
|
|
26
27
|
|
|
@@ -69,6 +70,21 @@ export interface MoonshotAIProvider extends ProviderV2 {
|
|
|
69
70
|
|
|
70
71
|
const defaultBaseURL = 'https://api.moonshot.ai/v1';
|
|
71
72
|
|
|
73
|
+
export function getModelStructuredOutputSupport(
|
|
74
|
+
modelId: MoonshotAIChatModelId,
|
|
75
|
+
): boolean {
|
|
76
|
+
return (
|
|
77
|
+
modelId.startsWith('kimi-k') ||
|
|
78
|
+
modelId === 'moonshot-v1-8k' ||
|
|
79
|
+
modelId === 'moonshot-v1-32k' ||
|
|
80
|
+
modelId === 'moonshot-v1-128k' ||
|
|
81
|
+
modelId === 'moonshot-v1-auto' ||
|
|
82
|
+
modelId === 'moonshot-v1-8k-vision-preview' ||
|
|
83
|
+
modelId === 'moonshot-v1-32k-vision-preview' ||
|
|
84
|
+
modelId === 'moonshot-v1-128k-vision-preview'
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
72
88
|
export function createMoonshotAI(
|
|
73
89
|
options: MoonshotAIProviderSettings = {},
|
|
74
90
|
): MoonshotAIProvider {
|
|
@@ -105,6 +121,7 @@ export function createMoonshotAI(
|
|
|
105
121
|
...getCommonModelConfig('chat'),
|
|
106
122
|
includeUsage: true,
|
|
107
123
|
errorStructure: moonshotaiErrorStructure,
|
|
124
|
+
supportsStructuredOutputs: getModelStructuredOutputSupport(modelId),
|
|
108
125
|
});
|
|
109
126
|
};
|
|
110
127
|
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { UnsupportedFunctionalityError } from '@ai-sdk/provider';
|
|
2
|
+
|
|
3
|
+
const SCHEMA_ARRAY_KEYS = ['allOf', 'anyOf', 'oneOf', 'prefixItems'] as const;
|
|
4
|
+
const SCHEMA_MAP_KEYS = [
|
|
5
|
+
'properties',
|
|
6
|
+
'patternProperties',
|
|
7
|
+
'$defs',
|
|
8
|
+
'dependentSchemas',
|
|
9
|
+
] as const;
|
|
10
|
+
const SCHEMA_SINGLE_KEYS = [
|
|
11
|
+
'additionalProperties',
|
|
12
|
+
'propertyNames',
|
|
13
|
+
'items',
|
|
14
|
+
'contains',
|
|
15
|
+
'not',
|
|
16
|
+
'if',
|
|
17
|
+
'then',
|
|
18
|
+
'else',
|
|
19
|
+
] as const;
|
|
20
|
+
|
|
21
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
22
|
+
return value != null && typeof value === 'object' && !Array.isArray(value);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Normalizes a JSON Schema to the subset Moonshot's MFJS validator accepts:
|
|
27
|
+
* `object` root required, tuple `items` become `prefixItems`, and `type` next
|
|
28
|
+
* to `anyOf` moves into the branches. Everything else passes through. The
|
|
29
|
+
* full original schema is still used for AI SDK result validation.
|
|
30
|
+
*/
|
|
31
|
+
export function normalizeJsonSchemaForMFJS(schema: unknown): unknown {
|
|
32
|
+
return normalizeDefinition(schema, true);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function normalizeDefinition(definition: unknown, isRoot: boolean): unknown {
|
|
36
|
+
if (typeof definition === 'boolean' || !isRecord(definition)) {
|
|
37
|
+
if (isRoot) {
|
|
38
|
+
throw new UnsupportedFunctionalityError({
|
|
39
|
+
functionality:
|
|
40
|
+
'tool parameters must be a JSON Schema object with type "object" for moonshotai (MFJS)',
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return definition;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (isRoot && definition.type !== 'object') {
|
|
47
|
+
throw new UnsupportedFunctionalityError({
|
|
48
|
+
functionality:
|
|
49
|
+
'tool parameters must be a JSON Schema object with type "object" for moonshotai (MFJS)',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const result: Record<string, unknown> = { ...definition };
|
|
54
|
+
|
|
55
|
+
if (Array.isArray(result.items)) {
|
|
56
|
+
const tuple = result.items;
|
|
57
|
+
result.prefixItems = [
|
|
58
|
+
...(Array.isArray(result.prefixItems) ? result.prefixItems : []),
|
|
59
|
+
...tuple.map(item => normalizeDefinition(item, false)),
|
|
60
|
+
];
|
|
61
|
+
delete result.items;
|
|
62
|
+
} else if (isRecord(result.items)) {
|
|
63
|
+
result.items = normalizeDefinition(result.items, false);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (typeof result.type === 'string' && Array.isArray(result.anyOf)) {
|
|
67
|
+
const parentType = result.type;
|
|
68
|
+
delete result.type;
|
|
69
|
+
result.anyOf = result.anyOf.map(branch =>
|
|
70
|
+
isRecord(branch) && branch.type == null
|
|
71
|
+
? { type: parentType, ...branch }
|
|
72
|
+
: branch,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
for (const key of SCHEMA_ARRAY_KEYS) {
|
|
77
|
+
const value = result[key];
|
|
78
|
+
if (Array.isArray(value)) {
|
|
79
|
+
result[key] = value.map(item => normalizeDefinition(item, false));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
for (const key of SCHEMA_MAP_KEYS) {
|
|
84
|
+
const value = result[key];
|
|
85
|
+
if (isRecord(value)) {
|
|
86
|
+
result[key] = Object.fromEntries(
|
|
87
|
+
Object.entries(value).map(([key, item]) => [
|
|
88
|
+
key,
|
|
89
|
+
normalizeDefinition(item, false),
|
|
90
|
+
]),
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const key of SCHEMA_SINGLE_KEYS) {
|
|
96
|
+
const value = result[key];
|
|
97
|
+
if (isRecord(value) || typeof value === 'boolean') {
|
|
98
|
+
result[key] = normalizeDefinition(value, false);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return result;
|
|
103
|
+
}
|