@namzu/zen 2.5.0 → 3.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/src/models.ts CHANGED
@@ -20,7 +20,7 @@ export interface ZenModel {
20
20
  readonly outputPrice: number
21
21
  readonly supportsToolUse: boolean
22
22
  readonly supportsStreaming: boolean
23
- /** True only for documented anonymous Zen models; omission grants no anonymous access. */
23
+ /** True only for verified direct-anonymous Zen models; zero price does not grant access. */
24
24
  readonly supportsAnonymousAccess?: boolean
25
25
  /** Exact advertised selectable effort levels; empty means no effort selector. */
26
26
  readonly effortLevels?: readonly ReasoningEffort[]
@@ -35,7 +35,7 @@ export interface ZenModel {
35
35
  * derived is an edit to src/catalogue/derive.ts. Both survive regeneration; a
36
36
  * hand edit here does not.
37
37
  *
38
- * Refreshed: 2026-09-21
38
+ * Refreshed: 2026-09-28
39
39
  *
40
40
  * This is the BUNDLED snapshot: what the driver knows with no network. A host
41
41
  * can derive a fresher roster at run time from the same sources, by the same
@@ -44,7 +44,8 @@ export interface ZenModel {
44
44
  *
45
45
  * Routes come from each service's own documentation page, as the pair
46
46
  * (endpoint, AI SDK package) that page states per model; both halves must agree
47
- * or the run stops. Prices come from that page's per-1M-token table at the base
47
+ * or the run stops. Three Go ids have narrow reference-client exceptions in
48
+ * src/catalogue/derive.ts. Prices come from the per-1M-token table at the base
48
49
  * tier, and a model with no price row there must be named in the page's
49
50
  * free-model list and is then zero. Limits, tool support, modalities and effort
50
51
  * options come from the matching provider entry in models.dev, where the
@@ -71,9 +72,9 @@ export interface ZenModel {
71
72
  * does not expose those input kinds.
72
73
  *
73
74
  * Promotional free models with documented routes and complete metadata are
74
- * included at their advertised zero price; the service enforces access limits.
75
- * Anonymous admission is explicit rather than inferred from price, and comes
76
- * from the free-model list on the page. OpenCode's own loader uses the public
75
+ * included at their advertised zero price. Direct anonymous admission is a
76
+ * separate, live-verified curation in src/catalogue/derive.ts and still requires
77
+ * an entry in the page's free-model list. OpenCode's own loader uses the public
77
78
  * sentinel when credentials are absent:
78
79
  * https://github.com/anomalyco/opencode/blob/16747470f976aca3d362ad730bcd3fe82ecc2c9a/packages/opencode/src/provider/provider.ts#L185
79
80
  * Unknown IDs have no inferred protocol or limits. MiniMax and Qwen demonstrate
@@ -102,6 +103,32 @@ const ZEN_MODELS = freezeModels([
102
103
  supportsStreaming: true,
103
104
  effortLevels: ['low', 'medium', 'high', 'xhigh', 'max'],
104
105
  },
106
+ {
107
+ id: 'gpt-6-sol',
108
+ name: 'GPT 6 Sol',
109
+ protocol: 'responses',
110
+ contextWindow: 1050000,
111
+ maxOutputTokens: 128000,
112
+ inputModalities: ['text', 'image', 'document'],
113
+ inputPrice: 2.0,
114
+ outputPrice: 10.0,
115
+ supportsToolUse: true,
116
+ supportsStreaming: true,
117
+ effortLevels: ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
118
+ },
119
+ {
120
+ id: 'gpt-6-luna',
121
+ name: 'GPT 6 Luna',
122
+ protocol: 'responses',
123
+ contextWindow: 1050000,
124
+ maxOutputTokens: 128000,
125
+ inputModalities: ['text', 'image', 'document'],
126
+ inputPrice: 0.1,
127
+ outputPrice: 0.5,
128
+ supportsToolUse: true,
129
+ supportsStreaming: true,
130
+ effortLevels: ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
131
+ },
105
132
  {
106
133
  id: 'gpt-5.6-sol',
107
134
  name: 'GPT 5.6 Sol',
@@ -323,6 +350,19 @@ const ZEN_MODELS = freezeModels([
323
350
  supportsStreaming: true,
324
351
  effortLevels: ['low', 'medium', 'high', 'xhigh', 'max'],
325
352
  },
353
+ {
354
+ id: 'claude-opus-5-5',
355
+ name: 'Claude Opus 5.5',
356
+ protocol: 'messages',
357
+ contextWindow: 1000000,
358
+ maxOutputTokens: 128000,
359
+ inputModalities: ['text', 'image', 'document'],
360
+ inputPrice: 4.0,
361
+ outputPrice: 20.0,
362
+ supportsToolUse: true,
363
+ supportsStreaming: true,
364
+ effortLevels: ['low', 'medium', 'high', 'xhigh', 'max'],
365
+ },
326
366
  {
327
367
  id: 'claude-opus-5',
328
368
  name: 'Claude Opus 5',
@@ -596,6 +636,19 @@ const ZEN_MODELS = freezeModels([
596
636
  supportsStreaming: true,
597
637
  effortLevels: ['minimal', 'low', 'medium', 'high', 'xhigh'],
598
638
  },
639
+ {
640
+ id: 'qwen3.8-max',
641
+ name: 'Qwen3.8 Max',
642
+ protocol: 'chat',
643
+ contextWindow: 262144,
644
+ maxOutputTokens: 131072,
645
+ inputModalities: ['text', 'image'],
646
+ inputPrice: 2.0,
647
+ outputPrice: 6.0,
648
+ supportsToolUse: true,
649
+ supportsStreaming: true,
650
+ effortLevels: [],
651
+ },
599
652
  {
600
653
  id: 'qwen3.8-flash',
601
654
  name: 'Qwen3.8 Flash',
@@ -806,7 +859,6 @@ const ZEN_MODELS = freezeModels([
806
859
  },
807
860
  {
808
861
  id: 'big-pickle',
809
- supportsAnonymousAccess: true,
810
862
  name: 'Big Pickle',
811
863
  protocol: 'chat',
812
864
  contextWindow: 200000,
@@ -819,8 +871,34 @@ const ZEN_MODELS = freezeModels([
819
871
  effortLevels: [],
820
872
  },
821
873
  {
822
- id: 'mimo-v2.5-free',
874
+ id: 'space-bunny-free',
823
875
  supportsAnonymousAccess: true,
876
+ name: 'Space Bunny Free',
877
+ protocol: 'chat',
878
+ contextWindow: 1048576,
879
+ maxOutputTokens: 524288,
880
+ inputModalities: ['text', 'image'],
881
+ inputPrice: 0,
882
+ outputPrice: 0,
883
+ supportsToolUse: true,
884
+ supportsStreaming: true,
885
+ effortLevels: ['low', 'medium', 'high', 'xhigh', 'max'],
886
+ },
887
+ {
888
+ id: 'longcat-2.5-preview-free',
889
+ name: 'LongCat 2.5 Preview Free',
890
+ protocol: 'chat',
891
+ contextWindow: 1000000,
892
+ maxOutputTokens: 131072,
893
+ inputModalities: ['text', 'image'],
894
+ inputPrice: 0,
895
+ outputPrice: 0,
896
+ supportsToolUse: true,
897
+ supportsStreaming: true,
898
+ effortLevels: [],
899
+ },
900
+ {
901
+ id: 'mimo-v2.5-free',
824
902
  name: 'MiMo-V2.5 Free',
825
903
  protocol: 'chat',
826
904
  contextWindow: 200000,
@@ -834,7 +912,6 @@ const ZEN_MODELS = freezeModels([
834
912
  },
835
913
  {
836
914
  id: 'ling-3.0-flash-fin-free',
837
- supportsAnonymousAccess: true,
838
915
  name: 'Ling 3.0 Flash Fin Free',
839
916
  protocol: 'chat',
840
917
  contextWindow: 262144,
@@ -848,7 +925,6 @@ const ZEN_MODELS = freezeModels([
848
925
  },
849
926
  {
850
927
  id: 'nemotron-3-ultra-free',
851
- supportsAnonymousAccess: true,
852
928
  name: 'Nemotron 3 Ultra Free',
853
929
  protocol: 'chat',
854
930
  contextWindow: 1000000,
@@ -862,7 +938,6 @@ const ZEN_MODELS = freezeModels([
862
938
  },
863
939
  {
864
940
  id: 'nemotron-3.5-lightning-free',
865
- supportsAnonymousAccess: true,
866
941
  name: 'Nemotron 3.5 Lightning Free',
867
942
  protocol: 'chat',
868
943
  contextWindow: 262144,
@@ -876,7 +951,6 @@ const ZEN_MODELS = freezeModels([
876
951
  },
877
952
  {
878
953
  id: 'muse-spark-1.3-contributor-free',
879
- supportsAnonymousAccess: true,
880
954
  name: 'Muse Spark 1.3 Contributor Free',
881
955
  protocol: 'responses',
882
956
  contextWindow: 1048576,
@@ -917,6 +991,19 @@ const GO_MODELS = freezeModels([
917
991
  supportsStreaming: true,
918
992
  effortLevels: ['low', 'medium', 'high', 'xhigh'],
919
993
  },
994
+ {
995
+ id: 'gpt-6-luna',
996
+ name: 'GPT 6 Luna',
997
+ protocol: 'responses',
998
+ contextWindow: 1050000,
999
+ maxOutputTokens: 128000,
1000
+ inputModalities: ['text', 'image', 'document'],
1001
+ inputPrice: 0.1,
1002
+ outputPrice: 0.5,
1003
+ supportsToolUse: true,
1004
+ supportsStreaming: true,
1005
+ effortLevels: ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
1006
+ },
920
1007
  {
921
1008
  id: 'gpt-5.6-luna',
922
1009
  name: 'GPT 5.6 Luna',
@@ -969,19 +1056,6 @@ const GO_MODELS = freezeModels([
969
1056
  supportsStreaming: true,
970
1057
  effortLevels: ['high', 'max'],
971
1058
  },
972
- {
973
- id: 'glm-5.1',
974
- name: 'GLM-5.1',
975
- protocol: 'chat',
976
- contextWindow: 202752,
977
- maxOutputTokens: 32768,
978
- inputModalities: ['text'],
979
- inputPrice: 1.4,
980
- outputPrice: 4.4,
981
- supportsToolUse: true,
982
- supportsStreaming: true,
983
- effortLevels: [],
984
- },
985
1059
  {
986
1060
  id: 'kimi-k3',
987
1061
  name: 'Kimi K3',
@@ -1034,6 +1108,19 @@ const GO_MODELS = freezeModels([
1034
1108
  supportsStreaming: true,
1035
1109
  effortLevels: [],
1036
1110
  },
1111
+ {
1112
+ id: 'longcat-2.5-preview-free',
1113
+ name: 'LongCat 2.5 Preview Free',
1114
+ protocol: 'chat',
1115
+ contextWindow: 1000000,
1116
+ maxOutputTokens: 131072,
1117
+ inputModalities: ['text', 'image'],
1118
+ inputPrice: 0,
1119
+ outputPrice: 0,
1120
+ supportsToolUse: true,
1121
+ supportsStreaming: true,
1122
+ effortLevels: [],
1123
+ },
1037
1124
  {
1038
1125
  id: 'deepseek-v4.1-flash',
1039
1126
  name: 'DeepSeek V4.1 Flash',
@@ -1063,7 +1150,7 @@ const GO_MODELS = freezeModels([
1063
1150
  {
1064
1151
  id: 'deepseek-v4-flash',
1065
1152
  name: 'DeepSeek V4 Flash',
1066
- protocol: 'chat',
1153
+ protocol: 'responses',
1067
1154
  contextWindow: 1000000,
1068
1155
  maxOutputTokens: 384000,
1069
1156
  inputModalities: ['text'],
@@ -1115,7 +1202,7 @@ const GO_MODELS = freezeModels([
1115
1202
  {
1116
1203
  id: 'minimax-m3',
1117
1204
  name: 'MiniMax M3',
1118
- protocol: 'messages',
1205
+ protocol: 'chat',
1119
1206
  contextWindow: 1000000,
1120
1207
  maxOutputTokens: 131072,
1121
1208
  inputModalities: ['text', 'image'],
@@ -1128,7 +1215,7 @@ const GO_MODELS = freezeModels([
1128
1215
  {
1129
1216
  id: 'minimax-m2.7',
1130
1217
  name: 'MiniMax M2.7',
1131
- protocol: 'messages',
1218
+ protocol: 'chat',
1132
1219
  contextWindow: 204800,
1133
1220
  maxOutputTokens: 131072,
1134
1221
  inputModalities: ['text'],
@@ -1190,19 +1277,6 @@ const GO_MODELS = freezeModels([
1190
1277
  supportsStreaming: true,
1191
1278
  effortLevels: ['low', 'medium', 'xhigh'],
1192
1279
  },
1193
- {
1194
- id: 'qwen3.7-max',
1195
- name: 'Qwen3.7 Max',
1196
- protocol: 'messages',
1197
- contextWindow: 1000000,
1198
- maxOutputTokens: 65536,
1199
- inputModalities: ['text'],
1200
- inputPrice: 2.5,
1201
- outputPrice: 7.5,
1202
- supportsToolUse: true,
1203
- supportsStreaming: true,
1204
- effortLevels: [],
1205
- },
1206
1280
  {
1207
1281
  id: 'qwen3.7-plus',
1208
1282
  name: 'Qwen3.7 Plus',
@@ -1216,19 +1290,6 @@ const GO_MODELS = freezeModels([
1216
1290
  supportsStreaming: true,
1217
1291
  effortLevels: [],
1218
1292
  },
1219
- {
1220
- id: 'qwen3.6-plus',
1221
- name: 'Qwen3.6 Plus',
1222
- protocol: 'messages',
1223
- contextWindow: 1000000,
1224
- maxOutputTokens: 65536,
1225
- inputModalities: ['text', 'image'],
1226
- inputPrice: 0.5,
1227
- outputPrice: 3.0,
1228
- supportsToolUse: true,
1229
- supportsStreaming: true,
1230
- effortLevels: [],
1231
- },
1232
1293
  {
1233
1294
  id: 'hy4-preview',
1234
1295
  name: 'Hy4 preview',
@@ -1255,6 +1316,19 @@ const GO_MODELS = freezeModels([
1255
1316
  supportsStreaming: true,
1256
1317
  effortLevels: ['none', 'low', 'high'],
1257
1318
  },
1319
+ {
1320
+ id: 'space-bunny-free',
1321
+ name: 'Space Bunny Free',
1322
+ protocol: 'chat',
1323
+ contextWindow: 1048576,
1324
+ maxOutputTokens: 524288,
1325
+ inputModalities: ['text', 'image'],
1326
+ inputPrice: 0,
1327
+ outputPrice: 0,
1328
+ supportsToolUse: true,
1329
+ supportsStreaming: true,
1330
+ effortLevels: ['low', 'medium', 'high', 'xhigh', 'max'],
1331
+ },
1258
1332
  ])
1259
1333
 
1260
1334
  /**
@@ -1265,6 +1339,7 @@ const GO_MODELS = freezeModels([
1265
1339
  export const ZEN_OMITTED_MODELS: readonly string[] = Object.freeze([
1266
1340
  'go/deepseek-flash',
1267
1341
  'go/glm-5',
1342
+ 'go/glm-5.1',
1268
1343
  'go/grok-4.5',
1269
1344
  'go/hy3-preview',
1270
1345
  'go/kimi-k2.5',
@@ -1275,6 +1350,8 @@ export const ZEN_OMITTED_MODELS: readonly string[] = Object.freeze([
1275
1350
  'go/minimax-m2.5',
1276
1351
  'go/omen-alpha',
1277
1352
  'go/qwen3.5-plus',
1353
+ 'go/qwen3.6-plus',
1354
+ 'go/qwen3.7-max',
1278
1355
  'zen/claude-sonnet-4',
1279
1356
  'zen/deepseek-v4-flash-free',
1280
1357
  'zen/glm-5',
package/src/options.ts CHANGED
@@ -1,19 +1,33 @@
1
1
  import { getModelCapabilities as getMessagesCapabilities } from '@ai-sdk/anthropic/internal'
2
2
  import type { LanguageModelV3CallOptions, SharedV3ProviderOptions } from '@ai-sdk/provider'
3
3
  import { type ChatCompletionParams, ProviderRequestError, type ProviderRoute } from '@namzu/sdk'
4
- import { type ZenProtocol, type ZenService, findZenModel } from './models.js'
5
- import { toModelPrompt } from './prompt.js'
4
+ import type { ZenModel, ZenProtocol, ZenService } from './models.js'
5
+ import { isMuseSparkResponsesModel, toModelPrompt } from './prompt.js'
6
+
7
+ function goRejectsToolChoice(service: ZenService, model: string): boolean {
8
+ if (service !== 'go') return false
9
+ if (model.startsWith('mimo-')) return true
10
+ if (model === 'deepseek-flash') return true
11
+ return (
12
+ /^deepseek-v4(?:\.\d+)?-(?:flash|pro)(?:$|-)/.test(model) &&
13
+ model !== 'deepseek-v4-flash-vision-exp'
14
+ )
15
+ }
6
16
 
7
17
  export function createCallOptions(
8
18
  params: ChatCompletionParams,
9
19
  route: ProviderRoute,
10
20
  service: ZenService,
11
21
  protocol: ZenProtocol,
22
+ known: ZenModel | undefined,
12
23
  ): LanguageModelV3CallOptions {
13
24
  const refuse = (detail: string): never => {
14
- throw new ProviderRequestError({ providerId: route.providerId, kind: 'bad_request', detail })
25
+ throw new ProviderRequestError({
26
+ providerId: route.providerId,
27
+ kind: 'bad_request',
28
+ detail,
29
+ })
15
30
  }
16
- const known = findZenModel(service, params.model)
17
31
  let maxOutputTokens = params.maxTokens ?? 4096
18
32
  if (!Number.isSafeInteger(maxOutputTokens) || maxOutputTokens <= 0)
19
33
  refuse('maxTokens must be a positive integer.')
@@ -46,7 +60,9 @@ export function createCallOptions(
46
60
  : {}),
47
61
  ...(params.thinking ? { thinking: { type: params.thinking.type } } : {}),
48
62
  ...(params.responseFormat?.type === 'json_schema'
49
- ? { strictJsonSchema: params.responseFormat.json_schema.strict ?? true }
63
+ ? {
64
+ strictJsonSchema: params.responseFormat.json_schema.strict ?? true,
65
+ }
50
66
  : {}),
51
67
  }
52
68
  break
@@ -95,7 +111,10 @@ export function createCallOptions(
95
111
  refuse('This responses model does not support reasoning controls.')
96
112
  options.openai = {
97
113
  store: false,
98
- include: ['reasoning.encrypted_content'],
114
+ // Muse Spark's gateway cannot replay caller-bound encrypted reasoning.
115
+ ...(isMuseSparkResponsesModel(params.model, protocol)
116
+ ? {}
117
+ : { include: ['reasoning.encrypted_content'] }),
99
118
  ...(known?.effortLevels?.length ? { forceReasoning: true } : {}),
100
119
  ...(params.effort !== undefined ? { reasoningEffort: params.effort } : {}),
101
120
  ...(params.thinking?.type === 'disabled' ? { reasoningEffort: 'none' } : {}),
@@ -104,7 +123,9 @@ export function createCallOptions(
104
123
  ? { parallelToolCalls: params.parallelToolCalls }
105
124
  : {}),
106
125
  ...(params.responseFormat?.type === 'json_schema'
107
- ? { strictJsonSchema: params.responseFormat.json_schema.strict ?? true }
126
+ ? {
127
+ strictJsonSchema: params.responseFormat.json_schema.strict ?? true,
128
+ }
108
129
  : {}),
109
130
  }
110
131
  break
@@ -211,7 +232,16 @@ export function createCallOptions(
211
232
  // Some Responses upstreams accept only auto tool choice (observed on Muse).
212
233
  // A no-tools turn can preserve its meaning by exposing no tools at all.
213
234
  // Keep required/named choices explicit; never silently weaken them to auto.
214
- const withoutTools = protocol === 'responses' && params.toolChoice === 'none'
235
+ const rejectsToolChoice = goRejectsToolChoice(service, params.model)
236
+ if (
237
+ rejectsToolChoice &&
238
+ params.toolChoice !== undefined &&
239
+ params.toolChoice !== 'auto' &&
240
+ params.toolChoice !== 'none'
241
+ )
242
+ refuse('This Zen Go model does not support required or named tool choice.')
243
+ const withoutTools =
244
+ (protocol === 'responses' || rejectsToolChoice) && params.toolChoice === 'none'
215
245
  const enforced = new Set(params.enforceToolInputSchema)
216
246
  return {
217
247
  prompt: toModelPrompt(params, route, service, protocol),
@@ -241,7 +271,7 @@ export function createCallOptions(
241
271
  })),
242
272
  }
243
273
  : {}),
244
- ...(params.toolChoice && !withoutTools
274
+ ...(params.toolChoice && !withoutTools && !rejectsToolChoice
245
275
  ? {
246
276
  toolChoice:
247
277
  typeof params.toolChoice === 'string'
package/src/prompt.ts CHANGED
@@ -24,6 +24,20 @@ type NativePart = Extract<LanguageModelV3Content, { type: 'text' | 'reasoning' |
24
24
  type AssistantContent = Extract<LanguageModelV3Message, { role: 'assistant' }>['content']
25
25
  type RichOutput = Extract<LanguageModelV3ToolResultOutput, { type: 'content' }>['value']
26
26
 
27
+ /** Muse Spark's Responses gateway cannot round-trip caller-bound encrypted reasoning. */
28
+ export function isMuseSparkResponsesModel(model: string, protocol: ZenProtocol): boolean {
29
+ return protocol === 'responses' && model.startsWith('muse-spark-')
30
+ }
31
+
32
+ /** Go's DeepSeek V4 Responses lane requires reasoning before each assistant turn. */
33
+ export function isGoDeepSeekV4ResponsesModel(
34
+ service: ZenService,
35
+ model: string,
36
+ protocol: ZenProtocol,
37
+ ): boolean {
38
+ return service === 'go' && protocol === 'responses' && model === 'deepseek-v4-flash'
39
+ }
40
+
27
41
  class HistoryConversionError extends Error {}
28
42
 
29
43
  function record(value: unknown): Record<string, unknown> | undefined {
@@ -137,7 +151,14 @@ function prefixDigest(messages: readonly Message[]): string {
137
151
  chainIndex: message.source.chainIndex,
138
152
  },
139
153
  }),
154
+ // Bookkeeping the kernel stamps, not content the prefix is defined
155
+ // by: `id` names which durable record a message came from, and two
156
+ // requests built from the exact same prefix disagree on it whenever
157
+ // one side is a fresh, never-recorded copy of the other (or a
158
+ // fork's copy, carrying a different session's id for identical
159
+ // content).
140
160
  timestamp: undefined,
161
+ id: undefined,
141
162
  })),
142
163
  )
143
164
  }
@@ -275,7 +296,23 @@ function replayContent(
275
296
  state.projectionDigest !== digest(projection(message))
276
297
  )
277
298
  return undefined
278
- return content.map((part) => {
299
+ // Validate the original completed turn before dropping Muse's reasoning items.
300
+ // Their encrypted content belongs to the gateway's upstream caller and fails
301
+ // when replayed in a later tool round. Text and tool calls still round-trip.
302
+ let replayParts = isMuseSparkResponsesModel(params.model, protocol)
303
+ ? content.filter((part) => part.type !== 'reasoning')
304
+ : content
305
+ if (isGoDeepSeekV4ResponsesModel(service, params.model, protocol)) {
306
+ // The native adapter emits each part in source order. Go rejects an
307
+ // assistant message between a function_call and its output, so group
308
+ // captured reasoning and text before this turn's tool-call batch.
309
+ replayParts = [
310
+ ...replayParts.filter((part) => part.type === 'reasoning'),
311
+ ...replayParts.filter((part) => part.type === 'text'),
312
+ ...replayParts.filter((part) => part.type === 'tool-call'),
313
+ ]
314
+ }
315
+ return replayParts.map((part) => {
279
316
  const providerOptions =
280
317
  part.providerMetadata === undefined
281
318
  ? undefined
@@ -284,7 +321,10 @@ function replayContent(
284
321
  // The compatible adapter reads Gemini call signatures from the google namespace.
285
322
  const thoughtSignature = metadataString(part, 'thoughtSignature')
286
323
  if (protocol === 'chat' && providerOptions && thoughtSignature !== undefined) {
287
- providerOptions.google = { ...providerOptions.google, thoughtSignature }
324
+ providerOptions.google = {
325
+ ...providerOptions.google,
326
+ thoughtSignature,
327
+ }
288
328
  }
289
329
  return {
290
330
  type: 'tool-call',
@@ -294,7 +334,11 @@ function replayContent(
294
334
  ...(providerOptions && { providerOptions }),
295
335
  }
296
336
  }
297
- return { type: part.type, text: part.text, ...(providerOptions && { providerOptions }) }
337
+ return {
338
+ type: part.type,
339
+ text: part.text,
340
+ ...(providerOptions && { providerOptions }),
341
+ }
298
342
  })
299
343
  }
300
344
 
@@ -454,7 +498,9 @@ function isRequestOnlyContext(message: Message): boolean {
454
498
  )
455
499
  }
456
500
 
457
- const BREAKPOINT = { anthropic: { cacheControl: { type: 'ephemeral' } } } as const
501
+ const BREAKPOINT = {
502
+ anthropic: { cacheControl: { type: 'ephemeral' } },
503
+ } as const
458
504
 
459
505
  /**
460
506
  * Messages-protocol cache breakpoints, block-level: after the last static
package/src/types.ts CHANGED
@@ -2,11 +2,11 @@ import type { ZenCatalogue } from './catalogue/catalogue.js'
2
2
  import type { ZenProtocol } from './models.js'
3
3
 
4
4
  export interface ZenConfig {
5
- /** Omit for documented free Zen models. The public sentinel also selects anonymous access. */
5
+ /** Omit for a model admitted to direct anonymous Zen access; `public` selects the same path. */
6
6
  apiKey?: string
7
7
  /** Stable conversation identity, shared by every turn and auxiliary request. */
8
8
  sessionId?: string
9
- /** Defaults to free Muse Spark 1.3 anonymously, or glm-5.3-flash with an API key. */
9
+ /** Defaults to Space Bunny Free anonymously, or glm-5.3-flash with an API key. */
10
10
  model?: string
11
11
  /** Override the service base URL, primarily for a host-owned proxy. */
12
12
  baseURL?: string
@@ -16,11 +16,12 @@ export interface ZenConfig {
16
16
  protocol?: ZenProtocol
17
17
  /**
18
18
  * A runtime catalogue, from `@namzu/zen/catalogue`, consulted before the
19
- * bundled snapshot for every lookup: routing, anonymous admission, listing,
20
- * context windows and effort levels. A function is called at each lookup, so
21
- * a host can swap in a fresher catalogue for providers it already built;
22
- * returning `undefined` means the bundled snapshot alone. Omitted, the
23
- * provider uses the bundled snapshot and nothing is ever fetched for it.
19
+ * bundled snapshot for every lookup: routing, model listing, context windows
20
+ * and effort levels. Anonymous admission also requires the driver's curated
21
+ * direct-access ID; a catalogue cannot add to that set. A function is called
22
+ * at each lookup, so a host can swap in a fresher catalogue for providers it
23
+ * already built. Returning `undefined` means the bundled snapshot alone.
24
+ * Omitted, the provider uses the bundled snapshot and fetches nothing.
24
25
  */
25
26
  catalogue?: ZenCatalogue | (() => ZenCatalogue | undefined)
26
27
  }