@warmdrift/kgauto-compiler 2.0.0-alpha.64 → 2.0.0-alpha.66

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/dist/index.mjs CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  import {
16
16
  LIBRARY_VERSION,
17
17
  createKeyHealthRoute
18
- } from "./chunk-DGPYLFDG.mjs";
18
+ } from "./chunk-CMB6PZWS.mjs";
19
19
  import {
20
20
  ABSOLUTE_FLOOR,
21
21
  ARCHETYPE_FLOOR_DEFAULT,
@@ -37,10 +37,11 @@ import {
37
37
  isBrainQueryActiveFor,
38
38
  isModelReachable,
39
39
  isProviderReachable,
40
+ isSameModelRetryEnabledFromEnv,
40
41
  loadChainsFromBrain,
41
42
  readBrainReadEnv,
42
43
  resolveProviderKey
43
- } from "./chunk-YZRPNSSQ.mjs";
44
+ } from "./chunk-SBFSYCQG.mjs";
44
45
  import {
45
46
  ALIASES,
46
47
  LATENCY_TIER_MS,
@@ -51,7 +52,7 @@ import {
51
52
  latencyTierOf,
52
53
  profilesByProvider,
53
54
  tryGetProfile
54
- } from "./chunk-QKXTMVCT.mjs";
55
+ } from "./chunk-4UO4CCSP.mjs";
55
56
  import {
56
57
  emitAdvisoryFired,
57
58
  emitCompileDone,
@@ -1102,6 +1103,10 @@ function lower(ir, profile, hints = {}) {
1102
1103
  return lowerOpenAI(ir, profile, hints);
1103
1104
  case "deepseek":
1104
1105
  return lowerDeepSeek(ir, profile);
1106
+ case "zai":
1107
+ return lowerZai(ir, profile, hints);
1108
+ case "moonshot":
1109
+ return lowerMoonshot(ir, profile);
1105
1110
  default:
1106
1111
  throw new Error(`No lowering implementation for provider: ${profile.provider}`);
1107
1112
  }
@@ -1390,6 +1395,68 @@ function lowerDeepSeek(ir, profile) {
1390
1395
  }
1391
1396
  };
1392
1397
  }
1398
+ function buildOpenAICompatibleParts(ir) {
1399
+ const ordered = sortSections(ir.sections);
1400
+ const systemText = ordered.map((s) => s.text).join("\n\n");
1401
+ const messages = systemText ? [{ role: "system", content: systemText }] : [];
1402
+ for (const m of ir.history ?? []) {
1403
+ if (m.role === "system") continue;
1404
+ messages.push({ role: m.role, content: m.parts ?? m.content });
1405
+ }
1406
+ if (ir.currentTurn && ir.currentTurn.role !== "system") {
1407
+ messages.push({
1408
+ role: ir.currentTurn.role,
1409
+ content: ir.currentTurn.parts ?? ir.currentTurn.content
1410
+ });
1411
+ }
1412
+ const history = (ir.history ?? []).filter((m) => m.role !== "system");
1413
+ const histMarkIndex = resolveHistoryMarkIndex(history.length, ir.historyCachePolicy);
1414
+ const historyCacheableTokens = histMarkIndex >= 0 ? sumHistoryTokens(history, histMarkIndex) : 0;
1415
+ return {
1416
+ messages,
1417
+ tools: ir.tools && ir.tools.length > 0 ? toOpenAITools(ir.tools) : void 0,
1418
+ response_format: ir.constraints?.structuredOutput ? { type: "json_object" } : void 0,
1419
+ historyCacheableTokens
1420
+ };
1421
+ }
1422
+ function lowerZai(ir, profile, hints) {
1423
+ const parts = buildOpenAICompatibleParts(ir);
1424
+ return {
1425
+ request: {
1426
+ provider: "zai",
1427
+ model: profile.id,
1428
+ messages: parts.messages,
1429
+ tools: parts.tools,
1430
+ response_format: parts.response_format,
1431
+ // Z.ai thinking defaults to enabled server-side; emit an explicit
1432
+ // disable only when a cliff forced thinking off (the GLM analogue of
1433
+ // Gemini's thinkingBudget=0).
1434
+ thinking: hints.forceThinkingZero ? { type: "disabled" } : void 0
1435
+ },
1436
+ diagnostics: {
1437
+ cacheableTokens: 0,
1438
+ historyCacheableTokens: parts.historyCacheableTokens,
1439
+ estimatedCacheSavingsUsd: 0
1440
+ }
1441
+ };
1442
+ }
1443
+ function lowerMoonshot(ir, profile) {
1444
+ const parts = buildOpenAICompatibleParts(ir);
1445
+ return {
1446
+ request: {
1447
+ provider: "moonshot",
1448
+ model: profile.id,
1449
+ messages: parts.messages,
1450
+ tools: parts.tools,
1451
+ response_format: parts.response_format
1452
+ },
1453
+ diagnostics: {
1454
+ cacheableTokens: 0,
1455
+ historyCacheableTokens: parts.historyCacheableTokens,
1456
+ estimatedCacheSavingsUsd: 0
1457
+ }
1458
+ };
1459
+ }
1393
1460
  function sortSections(sections) {
1394
1461
  return [...sections].sort((a, b) => {
1395
1462
  const wa = a.weight ?? 100;
@@ -3165,6 +3232,9 @@ function buildPayload(input, reg) {
3165
3232
  system_prompt_chars: input.systemPromptChars ?? reg?.systemPromptChars,
3166
3233
  fell_over_from: fellOverFrom,
3167
3234
  fallback_reason: fallbackReason,
3235
+ // alpha.66 — omitted-undefined keeps the key out of the JSON body
3236
+ // entirely for non-retry rows (pre-migration-039 brain safety).
3237
+ retried_same_model: input.retriedSameModel,
3168
3238
  // alpha.29 — translator activity (migration 019). Send NULL when no
3169
3239
  // rewrites fired so the brain's "did the translator do anything?"
3170
3240
  // queries can use `IS NOT NULL` cleanly.
@@ -3732,6 +3802,8 @@ function retryableError(status, code, message, raw) {
3732
3802
  var ANTHROPIC_URL2 = "https://api.anthropic.com/v1/messages";
3733
3803
  var OPENAI_URL = "https://api.openai.com/v1/chat/completions";
3734
3804
  var DEEPSEEK_URL = "https://api.deepseek.com/chat/completions";
3805
+ var ZAI_URL = "https://api.z.ai/api/paas/v4/chat/completions";
3806
+ var MOONSHOT_URL = "https://api.moonshot.ai/v1/chat/completions";
3735
3807
  async function execute(request, opts = {}) {
3736
3808
  const merged = applyOverrides(request, opts.providerOverrides);
3737
3809
  switch (merged.provider) {
@@ -3743,6 +3815,18 @@ async function execute(request, opts = {}) {
3743
3815
  return executeOpenAI(merged, opts);
3744
3816
  case "deepseek":
3745
3817
  return executeDeepSeek(merged, opts);
3818
+ case "zai":
3819
+ return executeOpenAICompatible(
3820
+ merged,
3821
+ opts,
3822
+ { provider: "zai", url: ZAI_URL, missingKeyMessage: "ZAI_API_KEY missing" }
3823
+ );
3824
+ case "moonshot":
3825
+ return executeOpenAICompatible(
3826
+ merged,
3827
+ opts,
3828
+ { provider: "moonshot", url: MOONSHOT_URL, missingKeyMessage: "MOONSHOT_API_KEY missing" }
3829
+ );
3746
3830
  default: {
3747
3831
  const _exhaustive = merged;
3748
3832
  throw new Error(`execute(): no executor for provider: ${JSON.stringify(_exhaustive)}`);
@@ -3892,6 +3976,34 @@ async function executeDeepSeek(request, opts) {
3892
3976
  if (!res.ok) return classifyHttpError2(res.status, json);
3893
3977
  return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
3894
3978
  }
3979
+ async function executeOpenAICompatible(request, opts, spec) {
3980
+ const apiKey = resolveProviderKey(spec.provider, { apiKeys: opts.apiKeys });
3981
+ if (!apiKey) {
3982
+ return terminalError(401, "auth", spec.missingKeyMessage);
3983
+ }
3984
+ if (opts.onChunk) {
3985
+ return streamOpenAILike(spec.url, request, apiKey, spec.provider, {
3986
+ onChunk: opts.onChunk,
3987
+ fetchImpl: opts.fetchImpl
3988
+ });
3989
+ }
3990
+ const { provider: _provider, ...body } = request;
3991
+ const fetchFn = opts.fetchImpl ?? fetch;
3992
+ let res;
3993
+ let json;
3994
+ try {
3995
+ res = await fetchFn(spec.url, {
3996
+ method: "POST",
3997
+ headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
3998
+ body: JSON.stringify(body)
3999
+ });
4000
+ json = await res.json().catch(() => ({}));
4001
+ } catch (err) {
4002
+ return retryableError2(0, "network_error", String(err), null);
4003
+ }
4004
+ if (!res.ok) return classifyHttpError2(res.status, json);
4005
+ return { ok: true, status: res.status, response: normalizeOpenAILike(json) };
4006
+ }
3895
4007
  function normalizeOpenAILike(raw) {
3896
4008
  const r = raw;
3897
4009
  const choice = r.choices?.[0];
@@ -4095,6 +4207,8 @@ async function call(ir, opts = {}) {
4095
4207
  let activeCompile = initial;
4096
4208
  let lastErr;
4097
4209
  const failedProviders = /* @__PURE__ */ new Set();
4210
+ const sameModelRetryEnabled = opts.sameModelRetry ?? isSameModelRetryEnabledFromEnv();
4211
+ let retriedSameModel = false;
4098
4212
  for (let i = 0; i < targetsToTry.length; i++) {
4099
4213
  const targetModel = targetsToTry[i];
4100
4214
  const targetProfile = tryGetProfile(targetModel);
@@ -4132,15 +4246,37 @@ async function call(ir, opts = {}) {
4132
4246
  );
4133
4247
  const targetSupportsStreaming = targetProfile?.streaming === true;
4134
4248
  const streamingOnChunk = opts.onChunk && !opts.noStream && targetSupportsStreaming ? opts.onChunk : void 0;
4135
- const exec = await execute(activeCompile.request, {
4249
+ const execOpts = {
4136
4250
  apiKeys: opts.apiKeys,
4137
4251
  fetchImpl: opts.fetchImpl,
4138
4252
  providerOverrides: opts.providerOverrides,
4139
4253
  onChunk: streamingOnChunk
4140
- });
4141
- const validated = exec.ok ? validateStructuredContract(exec, ir) : exec;
4254
+ };
4255
+ const exec = await execute(activeCompile.request, execOpts);
4256
+ let validated = exec.ok ? validateStructuredContract(exec, ir) : exec;
4257
+ let servedByRetry = false;
4258
+ if (!validated.ok && isStructuredContractViolation(validated.errorCode) && sameModelRetryEnabled && !retriedSameModel) {
4259
+ retriedSameModel = true;
4260
+ attempts.push({
4261
+ model: targetModel,
4262
+ status: validated.errorType,
4263
+ errorCode: validated.errorCode,
4264
+ message: validated.message
4265
+ });
4266
+ const retryRequest = validated.errorCode === "max_tokens_on_structured_output" ? raiseOutputBudget(activeCompile.request, targetProfile) : activeCompile.request;
4267
+ safeEmit(
4268
+ () => emitExecuteAttempt(traceId, ir.appId, { model: targetModel, attemptIndex: i })
4269
+ );
4270
+ const retryExec = await execute(retryRequest, execOpts);
4271
+ validated = retryExec.ok ? validateStructuredContract(retryExec, ir) : retryExec;
4272
+ servedByRetry = true;
4273
+ }
4142
4274
  if (validated.ok) {
4143
- attempts.push({ model: targetModel, status: "success" });
4275
+ attempts.push({
4276
+ model: targetModel,
4277
+ status: "success",
4278
+ ...servedByRetry ? { sameModelRetry: true } : {}
4279
+ });
4144
4280
  const latencyMs2 = Date.now() - start;
4145
4281
  safeEmit(
4146
4282
  () => emitExecuteSuccess(traceId, ir.appId, {
@@ -4177,7 +4313,10 @@ async function call(ir, opts = {}) {
4177
4313
  finishReason: validated.response.finishReason,
4178
4314
  totalMs: latencyMs2,
4179
4315
  fellOverFrom: fellOver ? initial.target : void 0,
4180
- fallbackReason
4316
+ fallbackReason,
4317
+ // alpha.66 — migration 039. Omitted (not false) when no retry fired
4318
+ // so pre-039 brains never see the key.
4319
+ retriedSameModel: retriedSameModel || void 0
4181
4320
  });
4182
4321
  if (fellOver) {
4183
4322
  const firstFailed = attempts.find((a) => a.status !== "success");
@@ -4235,6 +4374,7 @@ async function call(ir, opts = {}) {
4235
4374
  servedBy: targetModel,
4236
4375
  fellOverFrom: fellOver ? initial.target : void 0,
4237
4376
  fallbackReason,
4377
+ retriedSameModel: retriedSameModel || void 0,
4238
4378
  unreachableFiltered,
4239
4379
  policyBlockedFiltered,
4240
4380
  traceId,
@@ -4249,7 +4389,8 @@ async function call(ir, opts = {}) {
4249
4389
  model: targetModel,
4250
4390
  status: validated.errorType,
4251
4391
  errorCode: validated.errorCode,
4252
- message: validated.message
4392
+ message: validated.message,
4393
+ ...servedByRetry ? { sameModelRetry: true } : {}
4253
4394
  });
4254
4395
  lastErr = validated;
4255
4396
  if (validated.errorType === "terminal" || opts.noFallback) {
@@ -4260,15 +4401,20 @@ async function call(ir, opts = {}) {
4260
4401
  break;
4261
4402
  }
4262
4403
  }
4404
+ const lastAttempted = [...attempts].reverse().find(
4405
+ (a) => a.status !== "success" && a.errorCode !== "auth_inferred" && a.errorCode !== "compile_error"
4406
+ );
4263
4407
  const latencyMs = Date.now() - start;
4264
4408
  await record({
4265
4409
  handle: initial.handle,
4266
- tokensIn: 0,
4267
- tokensOut: 0,
4410
+ tokensIn: lastErr?.tokens?.input ?? 0,
4411
+ tokensOut: lastErr?.tokens?.output ?? 0,
4268
4412
  latencyMs,
4269
4413
  success: false,
4270
4414
  errorType: lastErr?.errorCode,
4271
- promptPreview: extractPromptPreview(ir)
4415
+ promptPreview: extractPromptPreview(ir),
4416
+ actualModel: lastAttempted?.model,
4417
+ retriedSameModel: retriedSameModel || void 0
4272
4418
  });
4273
4419
  const filteredNote = unreachableFiltered && unreachableFiltered.length > 0 ? ` (also auto-filtered: [${unreachableFiltered.join(", ")}] \u2014 no API key)` : "";
4274
4420
  const blockedNote = policyBlockedFiltered && policyBlockedFiltered.length > 0 ? ` (also policy-blocked: [${policyBlockedFiltered.join(", ")}])` : "";
@@ -4513,7 +4659,10 @@ function validateStructuredContract(exec, ir) {
4513
4659
  errorType: "retryable",
4514
4660
  errorCode: "max_tokens_on_structured_output",
4515
4661
  message: `Provider returned finishReason="${exec.response.finishReason}" on a structured-output call \u2014 output truncated mid-token, JSON cannot be valid`,
4516
- raw: exec.response.raw
4662
+ raw: exec.response.raw,
4663
+ // alpha.66 — the provider DID serve this call; carry the real usage so
4664
+ // exhausted-chain failure rows aren't stamped tokens_in=0 (PB 05-18 ask 4).
4665
+ tokens: { input: exec.response.tokens.input, output: exec.response.tokens.output }
4517
4666
  };
4518
4667
  }
4519
4668
  if (!exec.response.text) {
@@ -4529,10 +4678,35 @@ function validateStructuredContract(exec, ir) {
4529
4678
  errorType: "retryable",
4530
4679
  errorCode: "structured_output_parse_failed",
4531
4680
  message: err instanceof Error ? err.message : String(err),
4532
- raw: exec.response.raw
4681
+ raw: exec.response.raw,
4682
+ tokens: { input: exec.response.tokens.input, output: exec.response.tokens.output }
4533
4683
  };
4534
4684
  }
4535
4685
  }
4686
+ function isStructuredContractViolation(code) {
4687
+ return code === "max_tokens_on_structured_output" || code === "structured_output_parse_failed";
4688
+ }
4689
+ function raiseOutputBudget(request, profile) {
4690
+ if (!profile) return request;
4691
+ if (request.provider === "anthropic") {
4692
+ if (typeof request.max_tokens === "number" && request.max_tokens < profile.maxOutputTokens) {
4693
+ return { ...request, max_tokens: profile.maxOutputTokens };
4694
+ }
4695
+ return request;
4696
+ }
4697
+ if (request.provider === "google") {
4698
+ const gc = request.generationConfig;
4699
+ const cap = gc?.maxOutputTokens;
4700
+ if (typeof cap === "number" && cap < profile.maxOutputTokens) {
4701
+ return {
4702
+ ...request,
4703
+ generationConfig: { ...gc, maxOutputTokens: profile.maxOutputTokens }
4704
+ };
4705
+ }
4706
+ return request;
4707
+ }
4708
+ return request;
4709
+ }
4536
4710
  function normalizeFallbackReason(attempts) {
4537
4711
  const first = attempts.find((a) => a.status !== "success");
4538
4712
  if (!first) return void 0;
@@ -4565,6 +4739,8 @@ function safeEmit(fn) {
4565
4739
  var _internal = {
4566
4740
  compileAndRegister,
4567
4741
  validateStructuredContract,
4742
+ isStructuredContractViolation,
4743
+ raiseOutputBudget,
4568
4744
  extractPromptPreview,
4569
4745
  normalizeFallbackReason,
4570
4746
  generateTraceId,
@@ -373,7 +373,7 @@ interface PromptIR {
373
373
  */
374
374
  historyCachePolicy?: HistoryCachePolicy;
375
375
  }
376
- type Provider = 'anthropic' | 'google' | 'openai' | 'deepseek' | 'mistral' | 'xai';
376
+ type Provider = 'anthropic' | 'google' | 'openai' | 'deepseek' | 'zai' | 'moonshot' | 'mistral' | 'xai';
377
377
  /**
378
378
  * Mutation IDs that fired during compile. Empty in v1 (no mutation engine
379
379
  * yet). Populated when the brain is online and pushing mutations.
@@ -456,6 +456,33 @@ type CompiledRequest = {
456
456
  content: unknown;
457
457
  }>;
458
458
  tools?: unknown[];
459
+ } | {
460
+ provider: 'zai';
461
+ model: string;
462
+ messages: Array<{
463
+ role: string;
464
+ content: unknown;
465
+ }>;
466
+ tools?: unknown[];
467
+ response_format?: unknown;
468
+ /**
469
+ * alpha.65 — Z.ai thinking knob (docs.z.ai chat-completion reference):
470
+ * `thinking.type` is 'enabled' (default) or 'disabled'. Emitted only
471
+ * when a cliff forces thinking off (`force_thinking_budget_zero`);
472
+ * omitted otherwise so the provider default applies.
473
+ */
474
+ thinking?: {
475
+ type: 'enabled' | 'disabled';
476
+ };
477
+ } | {
478
+ provider: 'moonshot';
479
+ model: string;
480
+ messages: Array<{
481
+ role: string;
482
+ content: unknown;
483
+ }>;
484
+ tools?: unknown[];
485
+ response_format?: unknown;
459
486
  };
460
487
  /**
461
488
  * Best-practice advisory emitted by the compiler at compile time. Non-fatal —
@@ -866,6 +893,8 @@ interface ApiKeys {
866
893
  google?: string;
867
894
  openai?: string;
868
895
  deepseek?: string;
896
+ zai?: string;
897
+ moonshot?: string;
869
898
  }
870
899
  /**
871
900
  * Per-provider override fields shallow-merged into the lowered request before
@@ -877,6 +906,8 @@ interface ProviderOverrides {
877
906
  google?: Record<string, unknown>;
878
907
  openai?: Record<string, unknown>;
879
908
  deepseek?: Record<string, unknown>;
909
+ zai?: Record<string, unknown>;
910
+ moonshot?: Record<string, unknown>;
880
911
  }
881
912
  /**
882
913
  * Full-IR inline shadow-probe config (Shape B, Phase 1 — 2026-05-29 s51).
@@ -1034,12 +1065,40 @@ interface CallOptions {
1034
1065
  * capture never fires.
1035
1066
  */
1036
1067
  goldenCapture?: GoldenCaptureOptions;
1068
+ /**
1069
+ * alpha.66 — one same-model retry on a structured-output contract violation
1070
+ * (`max_tokens_on_structured_output` / `structured_output_parse_failed`)
1071
+ * BEFORE chain-walking to a lower-ranked tier. Filed by playbacksam
1072
+ * 2026-07-18 (`structured-output-truncation-retry-same-model`): on PB's
1073
+ * summarize surface the walk destination is measured quality-inferior
1074
+ * (golden eval run #3), so one more attempt at the leader beats walking.
1075
+ *
1076
+ * Consent posture (matches KGAUTO_AUTO_PROMOTE / KGAUTO_GOLDEN_CAPTURE):
1077
+ * default OFF; `true` wins, explicit `false` beats the env, undefined
1078
+ * falls through to the `KGAUTO_SAME_MODEL_RETRY` env var ('1'/'true').
1079
+ * Default-off because the retry adds one full model round-trip of latency
1080
+ * in the failure class — the consumer decides whether their fallback tier
1081
+ * is bad enough to pay that.
1082
+ *
1083
+ * Bounds: at most ONE retry per call(), on whichever target hits the
1084
+ * contract violation first. Truncation-class retries additionally raise
1085
+ * any explicit wire output cap sitting below the profile's
1086
+ * `maxOutputTokens` (e.g. a terse-clamp or providerOverrides cap);
1087
+ * requests already at the profile ceiling re-roll unchanged.
1088
+ */
1089
+ sameModelRetry?: boolean;
1037
1090
  }
1038
1091
  interface CallAttempt {
1039
1092
  model: string;
1040
1093
  status: 'success' | 'retryable' | 'terminal';
1041
1094
  errorCode?: string;
1042
1095
  message?: string;
1096
+ /**
1097
+ * alpha.66 — true on the attempt row that was the one-shot same-model
1098
+ * retry (CallOptions.sameModelRetry). The preceding row for the same model
1099
+ * carries the contract violation that triggered it.
1100
+ */
1101
+ sameModelRetry?: boolean;
1043
1102
  }
1044
1103
  /**
1045
1104
  * Why fallback fired. Normalized for `CallResult.fallbackReason` (alpha.9).
@@ -1095,6 +1154,14 @@ interface CallResult {
1095
1154
  fellOverFrom?: string;
1096
1155
  /** Set only when fallback fired. Normalized cause. */
1097
1156
  fallbackReason?: FallbackReason;
1157
+ /**
1158
+ * alpha.66 — true when the one-shot same-model retry
1159
+ * (CallOptions.sameModelRetry) fired during this call, regardless of
1160
+ * whether the retry rescued the call or the chain walked afterwards.
1161
+ * Cross-check `attempts[]` (the `sameModelRetry: true` row) and
1162
+ * `fellOverFrom` to distinguish rescued-by-retry from retried-then-walked.
1163
+ */
1164
+ retriedSameModel?: boolean;
1098
1165
  /**
1099
1166
  * alpha.10. Models that auto-filter dropped from the fallback walk because
1100
1167
  * their provider had no reachable API key. Empty when nothing was filtered
@@ -1292,6 +1359,13 @@ interface RecordInput {
1292
1359
  * keep in sync with the wire-contract enum (TraceDetail.fallbackReason).
1293
1360
  */
1294
1361
  fallbackReason?: 'rate_limit' | 'provider_auth_failed' | 'provider_error' | 'cliff' | 'cost_cap' | 'contract_violation';
1362
+ /**
1363
+ * alpha.66 — true when the one-shot same-model retry fired during this
1364
+ * call (migration 039 `retried_same_model`). Powers the offline rollup:
1365
+ * retry rate on the cliff class, and — joined with `fell_over_from` —
1366
+ * how often the retry rescued the call vs the chain walking anyway.
1367
+ */
1368
+ retriedSameModel?: boolean;
1295
1369
  }
1296
1370
  /**
1297
1371
  * alpha.20 Entry 4: kinds of consumer-declared outcomes feeding the quality
@@ -373,7 +373,7 @@ interface PromptIR {
373
373
  */
374
374
  historyCachePolicy?: HistoryCachePolicy;
375
375
  }
376
- type Provider = 'anthropic' | 'google' | 'openai' | 'deepseek' | 'mistral' | 'xai';
376
+ type Provider = 'anthropic' | 'google' | 'openai' | 'deepseek' | 'zai' | 'moonshot' | 'mistral' | 'xai';
377
377
  /**
378
378
  * Mutation IDs that fired during compile. Empty in v1 (no mutation engine
379
379
  * yet). Populated when the brain is online and pushing mutations.
@@ -456,6 +456,33 @@ type CompiledRequest = {
456
456
  content: unknown;
457
457
  }>;
458
458
  tools?: unknown[];
459
+ } | {
460
+ provider: 'zai';
461
+ model: string;
462
+ messages: Array<{
463
+ role: string;
464
+ content: unknown;
465
+ }>;
466
+ tools?: unknown[];
467
+ response_format?: unknown;
468
+ /**
469
+ * alpha.65 — Z.ai thinking knob (docs.z.ai chat-completion reference):
470
+ * `thinking.type` is 'enabled' (default) or 'disabled'. Emitted only
471
+ * when a cliff forces thinking off (`force_thinking_budget_zero`);
472
+ * omitted otherwise so the provider default applies.
473
+ */
474
+ thinking?: {
475
+ type: 'enabled' | 'disabled';
476
+ };
477
+ } | {
478
+ provider: 'moonshot';
479
+ model: string;
480
+ messages: Array<{
481
+ role: string;
482
+ content: unknown;
483
+ }>;
484
+ tools?: unknown[];
485
+ response_format?: unknown;
459
486
  };
460
487
  /**
461
488
  * Best-practice advisory emitted by the compiler at compile time. Non-fatal —
@@ -866,6 +893,8 @@ interface ApiKeys {
866
893
  google?: string;
867
894
  openai?: string;
868
895
  deepseek?: string;
896
+ zai?: string;
897
+ moonshot?: string;
869
898
  }
870
899
  /**
871
900
  * Per-provider override fields shallow-merged into the lowered request before
@@ -877,6 +906,8 @@ interface ProviderOverrides {
877
906
  google?: Record<string, unknown>;
878
907
  openai?: Record<string, unknown>;
879
908
  deepseek?: Record<string, unknown>;
909
+ zai?: Record<string, unknown>;
910
+ moonshot?: Record<string, unknown>;
880
911
  }
881
912
  /**
882
913
  * Full-IR inline shadow-probe config (Shape B, Phase 1 — 2026-05-29 s51).
@@ -1034,12 +1065,40 @@ interface CallOptions {
1034
1065
  * capture never fires.
1035
1066
  */
1036
1067
  goldenCapture?: GoldenCaptureOptions;
1068
+ /**
1069
+ * alpha.66 — one same-model retry on a structured-output contract violation
1070
+ * (`max_tokens_on_structured_output` / `structured_output_parse_failed`)
1071
+ * BEFORE chain-walking to a lower-ranked tier. Filed by playbacksam
1072
+ * 2026-07-18 (`structured-output-truncation-retry-same-model`): on PB's
1073
+ * summarize surface the walk destination is measured quality-inferior
1074
+ * (golden eval run #3), so one more attempt at the leader beats walking.
1075
+ *
1076
+ * Consent posture (matches KGAUTO_AUTO_PROMOTE / KGAUTO_GOLDEN_CAPTURE):
1077
+ * default OFF; `true` wins, explicit `false` beats the env, undefined
1078
+ * falls through to the `KGAUTO_SAME_MODEL_RETRY` env var ('1'/'true').
1079
+ * Default-off because the retry adds one full model round-trip of latency
1080
+ * in the failure class — the consumer decides whether their fallback tier
1081
+ * is bad enough to pay that.
1082
+ *
1083
+ * Bounds: at most ONE retry per call(), on whichever target hits the
1084
+ * contract violation first. Truncation-class retries additionally raise
1085
+ * any explicit wire output cap sitting below the profile's
1086
+ * `maxOutputTokens` (e.g. a terse-clamp or providerOverrides cap);
1087
+ * requests already at the profile ceiling re-roll unchanged.
1088
+ */
1089
+ sameModelRetry?: boolean;
1037
1090
  }
1038
1091
  interface CallAttempt {
1039
1092
  model: string;
1040
1093
  status: 'success' | 'retryable' | 'terminal';
1041
1094
  errorCode?: string;
1042
1095
  message?: string;
1096
+ /**
1097
+ * alpha.66 — true on the attempt row that was the one-shot same-model
1098
+ * retry (CallOptions.sameModelRetry). The preceding row for the same model
1099
+ * carries the contract violation that triggered it.
1100
+ */
1101
+ sameModelRetry?: boolean;
1043
1102
  }
1044
1103
  /**
1045
1104
  * Why fallback fired. Normalized for `CallResult.fallbackReason` (alpha.9).
@@ -1095,6 +1154,14 @@ interface CallResult {
1095
1154
  fellOverFrom?: string;
1096
1155
  /** Set only when fallback fired. Normalized cause. */
1097
1156
  fallbackReason?: FallbackReason;
1157
+ /**
1158
+ * alpha.66 — true when the one-shot same-model retry
1159
+ * (CallOptions.sameModelRetry) fired during this call, regardless of
1160
+ * whether the retry rescued the call or the chain walked afterwards.
1161
+ * Cross-check `attempts[]` (the `sameModelRetry: true` row) and
1162
+ * `fellOverFrom` to distinguish rescued-by-retry from retried-then-walked.
1163
+ */
1164
+ retriedSameModel?: boolean;
1098
1165
  /**
1099
1166
  * alpha.10. Models that auto-filter dropped from the fallback walk because
1100
1167
  * their provider had no reachable API key. Empty when nothing was filtered
@@ -1292,6 +1359,13 @@ interface RecordInput {
1292
1359
  * keep in sync with the wire-contract enum (TraceDetail.fallbackReason).
1293
1360
  */
1294
1361
  fallbackReason?: 'rate_limit' | 'provider_auth_failed' | 'provider_error' | 'cliff' | 'cost_cap' | 'contract_violation';
1362
+ /**
1363
+ * alpha.66 — true when the one-shot same-model retry fired during this
1364
+ * call (migration 039 `retried_same_model`). Powers the offline rollup:
1365
+ * retry rate on the cliff class, and — joined with `fell_over_from` —
1366
+ * how often the retry rescued the call vs the chain walking anyway.
1367
+ */
1368
+ retriedSameModel?: boolean;
1295
1369
  }
1296
1370
  /**
1297
1371
  * alpha.20 Entry 4: kinds of consumer-declared outcomes feeding the quality
@@ -73,7 +73,7 @@
73
73
  * ]
74
74
  * }
75
75
  */
76
- type KeyHealthProvider = 'anthropic' | 'deepseek' | 'google' | 'openai';
76
+ type KeyHealthProvider = 'anthropic' | 'deepseek' | 'google' | 'moonshot' | 'openai';
77
77
  interface KeyHealthConfig {
78
78
  /** Consumer app id echoed as `app_id` in the response (e.g. 'playbacksam'). */
79
79
  appId: string;
@@ -73,7 +73,7 @@
73
73
  * ]
74
74
  * }
75
75
  */
76
- type KeyHealthProvider = 'anthropic' | 'deepseek' | 'google' | 'openai';
76
+ type KeyHealthProvider = 'anthropic' | 'deepseek' | 'google' | 'moonshot' | 'openai';
77
77
  interface KeyHealthConfig {
78
78
  /** Consumer app id echoed as `app_id` in the response (e.g. 'playbacksam'). */
79
79
  appId: string;
@@ -25,7 +25,7 @@ __export(key_health_exports, {
25
25
  module.exports = __toCommonJS(key_health_exports);
26
26
 
27
27
  // src/version.ts
28
- var LIBRARY_VERSION = "2.0.0-alpha.64";
28
+ var LIBRARY_VERSION = "2.0.0-alpha.66";
29
29
 
30
30
  // src/key-health.ts
31
31
  var JSON_HEADERS = { "Content-Type": "application/json" };
@@ -74,6 +74,14 @@ var PROBE_SPECS = [
74
74
  return Number.isFinite(n) ? n : void 0;
75
75
  }
76
76
  },
77
+ {
78
+ provider: "moonshot",
79
+ canonicalEnvName: "MOONSHOT_API_KEY",
80
+ buildRequest: (key) => ({
81
+ url: "https://api.moonshot.ai/v1/models",
82
+ headers: { Authorization: `Bearer ${key}` }
83
+ })
84
+ },
77
85
  {
78
86
  provider: "google",
79
87
  canonicalEnvName: "GEMINI_API_KEY",
@@ -105,6 +113,11 @@ function createKeyHealthRoute(config) {
105
113
  const aiSdk = envKey(env, "GOOGLE_GENERATIVE_AI_API_KEY");
106
114
  key = gemini ?? google ?? aiSdk;
107
115
  envName = gemini ? "GEMINI_API_KEY" : google ? "GOOGLE_API_KEY" : aiSdk ? "GOOGLE_GENERATIVE_AI_API_KEY" : "GEMINI_API_KEY";
116
+ } else if (spec.provider === "moonshot") {
117
+ const moonshot = envKey(env, "MOONSHOT_API_KEY");
118
+ const kimi = envKey(env, "KIMI_API_KEY");
119
+ key = moonshot ?? kimi;
120
+ envName = moonshot ? "MOONSHOT_API_KEY" : kimi ? "KIMI_API_KEY" : "MOONSHOT_API_KEY";
108
121
  } else {
109
122
  key = envKey(env, spec.canonicalEnvName);
110
123
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createKeyHealthRoute
3
- } from "./chunk-DGPYLFDG.mjs";
3
+ } from "./chunk-CMB6PZWS.mjs";
4
4
  export {
5
5
  createKeyHealthRoute
6
6
  };
@@ -1,4 +1,4 @@
1
- import { k as Provider } from './ir-B2dRyJXO.mjs';
1
+ import { k as Provider } from './ir-BTvyl8-w.mjs';
2
2
  import { IntentArchetypeName } from './dialect.mjs';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { k as Provider } from './ir-ClU56aBc.js';
1
+ import { k as Provider } from './ir-Qnw6L265.js';
2
2
  import { IntentArchetypeName } from './dialect.js';
3
3
 
4
4
  /**