@namzu/zen 1.0.0
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 +61 -0
- package/LICENSE.md +110 -0
- package/README.md +142 -0
- package/dist/client.d.ts +30 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +517 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/models.d.ts +29 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +1170 -0
- package/dist/models.js.map +1 -0
- package/dist/options.d.ts +5 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +221 -0
- package/dist/options.js.map +1 -0
- package/dist/prompt.d.ts +9 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +376 -0
- package/dist/prompt.js.map +1 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +80 -0
- package/src/client.ts +585 -0
- package/src/index.ts +36 -0
- package/src/models.ts +1199 -0
- package/src/options.ts +259 -0
- package/src/prompt.ts +456 -0
- package/src/types.ts +29 -0
package/src/prompt.ts
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
import type {
|
|
3
|
+
JSONValue,
|
|
4
|
+
LanguageModelV3Content,
|
|
5
|
+
LanguageModelV3Message,
|
|
6
|
+
LanguageModelV3Prompt,
|
|
7
|
+
LanguageModelV3ToolResultOutput,
|
|
8
|
+
SharedV3ProviderMetadata,
|
|
9
|
+
} from '@ai-sdk/provider'
|
|
10
|
+
import {
|
|
11
|
+
type AssistantMessage,
|
|
12
|
+
type ChatCompletionParams,
|
|
13
|
+
type Message,
|
|
14
|
+
type MessageAttachment,
|
|
15
|
+
ProviderRequestError,
|
|
16
|
+
type ProviderRoute,
|
|
17
|
+
type ReasoningBlock,
|
|
18
|
+
type ToolResultBlock,
|
|
19
|
+
isModelContentOmission,
|
|
20
|
+
} from '@namzu/sdk'
|
|
21
|
+
import type { ZenProtocol, ZenService } from './models.js'
|
|
22
|
+
|
|
23
|
+
type NativePart = Extract<LanguageModelV3Content, { type: 'text' | 'reasoning' | 'tool-call' }>
|
|
24
|
+
type AssistantContent = Extract<LanguageModelV3Message, { role: 'assistant' }>['content']
|
|
25
|
+
type RichOutput = Extract<LanguageModelV3ToolResultOutput, { type: 'content' }>['value']
|
|
26
|
+
|
|
27
|
+
class HistoryConversionError extends Error {}
|
|
28
|
+
|
|
29
|
+
function record(value: unknown): Record<string, unknown> | undefined {
|
|
30
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
31
|
+
? (value as Record<string, unknown>)
|
|
32
|
+
: undefined
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function jsonValue(value: unknown, depth = 0): value is JSONValue {
|
|
36
|
+
if (depth > 40) return false
|
|
37
|
+
if (value === null || typeof value === 'string' || typeof value === 'boolean') return true
|
|
38
|
+
if (typeof value === 'number') return Number.isFinite(value)
|
|
39
|
+
if (Array.isArray(value)) return value.every((item) => jsonValue(item, depth + 1))
|
|
40
|
+
const object = record(value)
|
|
41
|
+
return (
|
|
42
|
+
object !== undefined &&
|
|
43
|
+
(Object.getPrototypeOf(object) === Object.prototype ||
|
|
44
|
+
Object.getPrototypeOf(object) === null) &&
|
|
45
|
+
Object.values(object).every((item) => item === undefined || jsonValue(item, depth + 1))
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function metadata(value: unknown): value is SharedV3ProviderMetadata | undefined {
|
|
50
|
+
const object = record(value)
|
|
51
|
+
return (
|
|
52
|
+
value === undefined ||
|
|
53
|
+
(object !== undefined &&
|
|
54
|
+
jsonValue(value) &&
|
|
55
|
+
Object.values(object).every((namespace) => record(namespace) !== undefined))
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function parseNativeParts(value: unknown): NativePart[] | undefined {
|
|
60
|
+
if (!Array.isArray(value)) return undefined
|
|
61
|
+
const parts: NativePart[] = []
|
|
62
|
+
for (const item of value) {
|
|
63
|
+
const part = record(item)
|
|
64
|
+
if (!part || !metadata(part.providerMetadata)) return undefined
|
|
65
|
+
const providerMetadata = part.providerMetadata
|
|
66
|
+
if (part.type === 'text' || part.type === 'reasoning') {
|
|
67
|
+
if (typeof part.text !== 'string') return undefined
|
|
68
|
+
parts.push({
|
|
69
|
+
type: part.type,
|
|
70
|
+
text: part.text,
|
|
71
|
+
...(providerMetadata && { providerMetadata }),
|
|
72
|
+
})
|
|
73
|
+
} else if (part.type === 'tool-call') {
|
|
74
|
+
if (
|
|
75
|
+
typeof part.toolCallId !== 'string' ||
|
|
76
|
+
typeof part.toolName !== 'string' ||
|
|
77
|
+
typeof part.input !== 'string' ||
|
|
78
|
+
(part.providerExecuted !== undefined && part.providerExecuted !== false)
|
|
79
|
+
) {
|
|
80
|
+
return undefined
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
parsedArguments(part.input)
|
|
84
|
+
} catch {
|
|
85
|
+
return undefined
|
|
86
|
+
}
|
|
87
|
+
parts.push({
|
|
88
|
+
type: 'tool-call',
|
|
89
|
+
toolCallId: part.toolCallId,
|
|
90
|
+
toolName: part.toolName,
|
|
91
|
+
input: part.input,
|
|
92
|
+
...(providerMetadata && { providerMetadata }),
|
|
93
|
+
})
|
|
94
|
+
} else {
|
|
95
|
+
return undefined
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return parts
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function canonical(value: unknown): unknown {
|
|
102
|
+
if (Array.isArray(value)) return value.map(canonical)
|
|
103
|
+
const object = record(value)
|
|
104
|
+
if (!object) return value
|
|
105
|
+
return Object.fromEntries(
|
|
106
|
+
Object.keys(object)
|
|
107
|
+
.sort()
|
|
108
|
+
.filter((key) => object[key] !== undefined)
|
|
109
|
+
.map((key) => [key, canonical(object[key])]),
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function digest(value: unknown): string {
|
|
114
|
+
return createHash('sha256')
|
|
115
|
+
.update(JSON.stringify(canonical(value)))
|
|
116
|
+
.digest('hex')
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function sameRoute(value: unknown, route: ProviderRoute): boolean {
|
|
120
|
+
const candidate = record(value)
|
|
121
|
+
return (
|
|
122
|
+
candidate?.providerId === route.providerId &&
|
|
123
|
+
candidate.model === route.model &&
|
|
124
|
+
candidate.chainIndex === route.chainIndex
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function prefixDigest(messages: readonly Message[]): string {
|
|
129
|
+
return digest(
|
|
130
|
+
messages.map((message) => ({
|
|
131
|
+
...message,
|
|
132
|
+
...(message.role === 'assistant' && {
|
|
133
|
+
source: message.source && {
|
|
134
|
+
type: message.source.type,
|
|
135
|
+
providerId: message.source.providerId,
|
|
136
|
+
model: message.source.model,
|
|
137
|
+
chainIndex: message.source.chainIndex,
|
|
138
|
+
},
|
|
139
|
+
}),
|
|
140
|
+
timestamp: undefined,
|
|
141
|
+
})),
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function metadataString(part: LanguageModelV3Content, key: string): string | undefined {
|
|
146
|
+
for (const namespace of Object.values(part.providerMetadata ?? {})) {
|
|
147
|
+
const value = namespace[key]
|
|
148
|
+
if (typeof value === 'string') return value
|
|
149
|
+
}
|
|
150
|
+
return undefined
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Shared by stream materialization and the durable replay correspondence guard. */
|
|
154
|
+
export function toReasoningBlocks(content: readonly LanguageModelV3Content[]): ReasoningBlock[] {
|
|
155
|
+
return content.flatMap((part): ReasoningBlock[] => {
|
|
156
|
+
if (part.type !== 'reasoning') return []
|
|
157
|
+
const redacted = metadataString(part, 'redactedData')
|
|
158
|
+
const signature = metadataString(part, 'signature') ?? metadataString(part, 'thoughtSignature')
|
|
159
|
+
const encrypted = redacted ?? metadataString(part, 'reasoningEncryptedContent')
|
|
160
|
+
return [
|
|
161
|
+
{
|
|
162
|
+
type: redacted === undefined ? 'thinking' : 'redacted_thinking',
|
|
163
|
+
text: part.text,
|
|
164
|
+
...(signature !== undefined && { signature }),
|
|
165
|
+
...(encrypted !== undefined && { encrypted }),
|
|
166
|
+
},
|
|
167
|
+
]
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function parsedArguments(input: string): unknown {
|
|
172
|
+
try {
|
|
173
|
+
const value: unknown = JSON.parse(input)
|
|
174
|
+
if (!jsonValue(value)) throw new Error('Non-JSON argument value.')
|
|
175
|
+
return value
|
|
176
|
+
} catch {
|
|
177
|
+
throw new HistoryConversionError(
|
|
178
|
+
'Zen history contains a tool call with invalid JSON arguments.',
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function projection(
|
|
184
|
+
message: Pick<AssistantMessage, 'content' | 'toolCalls' | 'reasoning'>,
|
|
185
|
+
): unknown {
|
|
186
|
+
return {
|
|
187
|
+
text: message.content ?? '',
|
|
188
|
+
tools: (message.toolCalls ?? []).map((call) => ({
|
|
189
|
+
id: call.id,
|
|
190
|
+
name: call.function.name,
|
|
191
|
+
input: parsedArguments(call.function.arguments),
|
|
192
|
+
truncated: call.metadata?.inputTruncated === true,
|
|
193
|
+
})),
|
|
194
|
+
reasoning: (message.reasoning ?? []).map((block) => ({
|
|
195
|
+
type: block.type,
|
|
196
|
+
text: block.text ?? '',
|
|
197
|
+
signature: block.signature ?? null,
|
|
198
|
+
encrypted: block.encrypted ?? null,
|
|
199
|
+
})),
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function nativeProjection(content: readonly NativePart[]): unknown {
|
|
204
|
+
return projection({
|
|
205
|
+
content: content
|
|
206
|
+
.filter((part) => part.type === 'text')
|
|
207
|
+
.map((part) => part.text)
|
|
208
|
+
.join(''),
|
|
209
|
+
toolCalls: content.flatMap((part) =>
|
|
210
|
+
part.type === 'tool-call'
|
|
211
|
+
? [
|
|
212
|
+
{
|
|
213
|
+
id: part.toolCallId,
|
|
214
|
+
type: 'function' as const,
|
|
215
|
+
function: { name: part.toolName, arguments: part.input },
|
|
216
|
+
},
|
|
217
|
+
]
|
|
218
|
+
: [],
|
|
219
|
+
),
|
|
220
|
+
reasoning: toReasoningBlocks(content),
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Save completed native parts, bound to their request and durable public projection. */
|
|
225
|
+
export function createReplayState(
|
|
226
|
+
params: ChatCompletionParams,
|
|
227
|
+
route: ProviderRoute,
|
|
228
|
+
service: ZenService,
|
|
229
|
+
protocol: ZenProtocol,
|
|
230
|
+
content: LanguageModelV3Content[],
|
|
231
|
+
): unknown {
|
|
232
|
+
const parts = parseNativeParts(content)
|
|
233
|
+
if (!parts) return undefined
|
|
234
|
+
return JSON.parse(
|
|
235
|
+
JSON.stringify({
|
|
236
|
+
kind: 'namzu.zen.model-content',
|
|
237
|
+
version: 1,
|
|
238
|
+
route,
|
|
239
|
+
model: params.model,
|
|
240
|
+
service,
|
|
241
|
+
protocol,
|
|
242
|
+
prefixDigest: prefixDigest(params.messages),
|
|
243
|
+
projectionDigest: digest(nativeProjection(parts)),
|
|
244
|
+
contentDigest: digest(parts),
|
|
245
|
+
content: parts,
|
|
246
|
+
}),
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function replayContent(
|
|
251
|
+
message: AssistantMessage,
|
|
252
|
+
params: ChatCompletionParams,
|
|
253
|
+
index: number,
|
|
254
|
+
route: ProviderRoute,
|
|
255
|
+
service: ZenService,
|
|
256
|
+
protocol: ZenProtocol,
|
|
257
|
+
): AssistantContent | undefined {
|
|
258
|
+
if (message.source?.type !== 'model' || !sameRoute(message.source, route)) return undefined
|
|
259
|
+
const state = record(message.source.replayState)
|
|
260
|
+
if (
|
|
261
|
+
state?.kind !== 'namzu.zen.model-content' ||
|
|
262
|
+
state.version !== 1 ||
|
|
263
|
+
!sameRoute(state.route, route) ||
|
|
264
|
+
state.model !== params.model ||
|
|
265
|
+
state.service !== service ||
|
|
266
|
+
state.protocol !== protocol ||
|
|
267
|
+
state.prefixDigest !== prefixDigest(params.messages.slice(0, index))
|
|
268
|
+
)
|
|
269
|
+
return undefined
|
|
270
|
+
const content = parseNativeParts(state.content)
|
|
271
|
+
if (
|
|
272
|
+
!content ||
|
|
273
|
+
state.contentDigest !== digest(content) ||
|
|
274
|
+
state.projectionDigest !== digest(nativeProjection(content)) ||
|
|
275
|
+
state.projectionDigest !== digest(projection(message))
|
|
276
|
+
)
|
|
277
|
+
return undefined
|
|
278
|
+
return content.map((part) => {
|
|
279
|
+
const providerOptions =
|
|
280
|
+
part.providerMetadata === undefined
|
|
281
|
+
? undefined
|
|
282
|
+
: (JSON.parse(JSON.stringify(part.providerMetadata)) as SharedV3ProviderMetadata)
|
|
283
|
+
if (part.type === 'tool-call') {
|
|
284
|
+
// The compatible adapter reads Gemini call signatures from the google namespace.
|
|
285
|
+
const thoughtSignature = metadataString(part, 'thoughtSignature')
|
|
286
|
+
if (protocol === 'chat' && providerOptions && thoughtSignature !== undefined) {
|
|
287
|
+
providerOptions.google = { ...providerOptions.google, thoughtSignature }
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
type: 'tool-call',
|
|
291
|
+
toolCallId: part.toolCallId,
|
|
292
|
+
toolName: part.toolName,
|
|
293
|
+
input: parsedArguments(part.input),
|
|
294
|
+
...(providerOptions && { providerOptions }),
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return { type: part.type, text: part.text, ...(providerOptions && { providerOptions }) }
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function attachment(
|
|
302
|
+
attachment: MessageAttachment,
|
|
303
|
+
): Extract<LanguageModelV3Message, { role: 'user' }>['content'] {
|
|
304
|
+
if (attachment.type === 'stored') {
|
|
305
|
+
throw new HistoryConversionError(
|
|
306
|
+
'Zen requires stored attachments to be resolved before model delivery.',
|
|
307
|
+
)
|
|
308
|
+
}
|
|
309
|
+
if (attachment.type === 'document') {
|
|
310
|
+
if (attachment.citations)
|
|
311
|
+
throw new HistoryConversionError('Zen document citations are not supported.')
|
|
312
|
+
return [
|
|
313
|
+
{
|
|
314
|
+
type: 'file',
|
|
315
|
+
data: attachment.data,
|
|
316
|
+
mediaType: attachment.mediaType,
|
|
317
|
+
...(attachment.name && { filename: attachment.name }),
|
|
318
|
+
},
|
|
319
|
+
]
|
|
320
|
+
}
|
|
321
|
+
if (isModelContentOmission(attachment.modelOmission)) return []
|
|
322
|
+
return [{ type: 'file', data: attachment.data, mediaType: attachment.mediaType }]
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function richOutput(blocks: readonly ToolResultBlock[]): RichOutput {
|
|
326
|
+
return blocks.flatMap((block): RichOutput => {
|
|
327
|
+
if (block.type === 'text') return [{ type: 'text', text: block.text }]
|
|
328
|
+
if (block.type === 'image') {
|
|
329
|
+
if (isModelContentOmission(block.modelOmission)) return []
|
|
330
|
+
return [{ type: 'image-data', data: block.data, mediaType: block.mediaType }]
|
|
331
|
+
}
|
|
332
|
+
if (block.citations)
|
|
333
|
+
throw new HistoryConversionError('Zen document citations are not supported.')
|
|
334
|
+
return [
|
|
335
|
+
{
|
|
336
|
+
type: 'file-data',
|
|
337
|
+
data: block.data,
|
|
338
|
+
mediaType: block.mediaType,
|
|
339
|
+
...(block.name && { filename: block.name }),
|
|
340
|
+
},
|
|
341
|
+
]
|
|
342
|
+
})
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function toolOutput(
|
|
346
|
+
message: Extract<Message, { role: 'tool' }>,
|
|
347
|
+
protocol: ZenProtocol,
|
|
348
|
+
): LanguageModelV3ToolResultOutput {
|
|
349
|
+
const textOutput = (text: string): LanguageModelV3ToolResultOutput => ({
|
|
350
|
+
type: message.isError ? 'error-text' : 'text',
|
|
351
|
+
// Only Messages serializes error-text with a native failure flag.
|
|
352
|
+
value: message.isError && protocol !== 'messages' ? `Tool execution failed.\n${text}` : text,
|
|
353
|
+
})
|
|
354
|
+
if (typeof message.content === 'string') {
|
|
355
|
+
return textOutput(message.content)
|
|
356
|
+
}
|
|
357
|
+
const value = richOutput(message.content)
|
|
358
|
+
if (value.every((part) => part.type === 'text')) {
|
|
359
|
+
return textOutput(value.map((part) => part.text).join('\n'))
|
|
360
|
+
}
|
|
361
|
+
if (message.isError)
|
|
362
|
+
throw new HistoryConversionError(
|
|
363
|
+
'Zen cannot preserve both rich tool content and tool failure status.',
|
|
364
|
+
)
|
|
365
|
+
if (protocol === 'chat')
|
|
366
|
+
throw new HistoryConversionError('Zen chat protocol does not support rich tool results.')
|
|
367
|
+
if (
|
|
368
|
+
protocol === 'messages' &&
|
|
369
|
+
value.some((part) => part.type === 'file-data' && part.mediaType !== 'application/pdf')
|
|
370
|
+
) {
|
|
371
|
+
throw new HistoryConversionError(
|
|
372
|
+
'Zen messages protocol supports only PDF documents in rich tool results.',
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
return { type: 'content', value }
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/** Convert public history; native metadata is admitted only by an exact replay match. */
|
|
379
|
+
function buildModelPrompt(
|
|
380
|
+
params: ChatCompletionParams,
|
|
381
|
+
route: ProviderRoute,
|
|
382
|
+
service: ZenService,
|
|
383
|
+
protocol: ZenProtocol,
|
|
384
|
+
): LanguageModelV3Prompt {
|
|
385
|
+
const prompt: LanguageModelV3Prompt = []
|
|
386
|
+
const toolNames = new Map<string, string>()
|
|
387
|
+
for (const [index, message] of params.messages.entries()) {
|
|
388
|
+
switch (message.role) {
|
|
389
|
+
case 'system':
|
|
390
|
+
prompt.push({ role: 'system', content: message.content })
|
|
391
|
+
break
|
|
392
|
+
case 'user':
|
|
393
|
+
prompt.push({
|
|
394
|
+
role: 'user',
|
|
395
|
+
content: [
|
|
396
|
+
{ type: 'text', text: message.content },
|
|
397
|
+
...(message.attachments ?? []).flatMap(attachment),
|
|
398
|
+
],
|
|
399
|
+
})
|
|
400
|
+
break
|
|
401
|
+
case 'assistant': {
|
|
402
|
+
for (const call of message.toolCalls ?? []) toolNames.set(call.id, call.function.name)
|
|
403
|
+
const content = replayContent(message, params, index, route, service, protocol) ?? [
|
|
404
|
+
...(message.content ? [{ type: 'text' as const, text: message.content }] : []),
|
|
405
|
+
...(message.toolCalls ?? []).map((call) => ({
|
|
406
|
+
type: 'tool-call' as const,
|
|
407
|
+
toolCallId: call.id,
|
|
408
|
+
toolName: call.function.name,
|
|
409
|
+
input: parsedArguments(call.function.arguments),
|
|
410
|
+
})),
|
|
411
|
+
]
|
|
412
|
+
// Google and Anthropic reject empty assistant turns after foreign reasoning is removed.
|
|
413
|
+
if (content.length > 0) prompt.push({ role: 'assistant', content })
|
|
414
|
+
break
|
|
415
|
+
}
|
|
416
|
+
case 'tool': {
|
|
417
|
+
const toolName = toolNames.get(message.toolCallId)
|
|
418
|
+
if (!toolName)
|
|
419
|
+
throw new HistoryConversionError('Zen tool history is missing the preceding tool call.')
|
|
420
|
+
prompt.push({
|
|
421
|
+
role: 'tool',
|
|
422
|
+
content: [
|
|
423
|
+
{
|
|
424
|
+
type: 'tool-result',
|
|
425
|
+
toolCallId: message.toolCallId,
|
|
426
|
+
toolName,
|
|
427
|
+
output: toolOutput(message, protocol),
|
|
428
|
+
},
|
|
429
|
+
],
|
|
430
|
+
})
|
|
431
|
+
break
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return prompt
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
export function toModelPrompt(
|
|
439
|
+
params: ChatCompletionParams,
|
|
440
|
+
route: ProviderRoute,
|
|
441
|
+
service: ZenService,
|
|
442
|
+
protocol: ZenProtocol,
|
|
443
|
+
): LanguageModelV3Prompt {
|
|
444
|
+
try {
|
|
445
|
+
return buildModelPrompt(params, route, service, protocol)
|
|
446
|
+
} catch (error) {
|
|
447
|
+
throw new ProviderRequestError({
|
|
448
|
+
providerId: service === 'go' ? 'zen-go' : 'zen',
|
|
449
|
+
kind: 'bad_request',
|
|
450
|
+
detail:
|
|
451
|
+
error instanceof HistoryConversionError
|
|
452
|
+
? error.message
|
|
453
|
+
: 'Zen cannot represent the supplied message history.',
|
|
454
|
+
})
|
|
455
|
+
}
|
|
456
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ZenProtocol } from './models.js'
|
|
2
|
+
|
|
3
|
+
export interface ZenConfig {
|
|
4
|
+
/** Omit for documented free Zen models. The public sentinel also selects anonymous access. */
|
|
5
|
+
apiKey?: string
|
|
6
|
+
/** Stable conversation identity, shared by every turn and auxiliary request. */
|
|
7
|
+
sessionId?: string
|
|
8
|
+
/** Defaults to free Muse Spark 1.3 anonymously, or glm-5.3-flash with an API key. */
|
|
9
|
+
model?: string
|
|
10
|
+
/** Override the service base URL, primarily for a host-owned proxy. */
|
|
11
|
+
baseURL?: string
|
|
12
|
+
/** Whole request timeout in milliseconds. Defaults to 120000. */
|
|
13
|
+
timeout?: number
|
|
14
|
+
/** Explicit wire format for a model absent from the bundled catalogue. */
|
|
15
|
+
protocol?: ZenProtocol
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Go subscriptions require a real API key; anonymous Zen access does not apply. */
|
|
19
|
+
export interface ZenGoConfig extends ZenConfig {
|
|
20
|
+
apiKey: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ZenProviderConfig extends ZenConfig {
|
|
24
|
+
type: 'zen'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ZenGoProviderConfig extends ZenGoConfig {
|
|
28
|
+
type: 'zen-go'
|
|
29
|
+
}
|