commit-whisper 1.1.3 → 1.1.5

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.
Files changed (2) hide show
  1. package/dist/index.js +38 -3
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3920,7 +3920,21 @@ function resolveModel(config) {
3920
3920
  }
3921
3921
  case "openai-compatible": {
3922
3922
  const baseURL = requireBaseUrl(config);
3923
- return createOpenAICompatible({ name: "openai-compatible", baseURL, apiKey: config.aiKey?.reveal() })(model);
3923
+ return createOpenAICompatible({
3924
+ name: "openai-compatible",
3925
+ baseURL,
3926
+ apiKey: config.aiKey?.reveal(),
3927
+ // Send the bound schema as a real `json_schema` response format. Without
3928
+ // this the SDK silently DROPS the schema (falling back to `json_object`
3929
+ // mode) and the model's unguided output fails `generateObject`'s
3930
+ // validation — exactly the "narrative unavailable" degrade we hit.
3931
+ supportsStructuredOutputs: true,
3932
+ // …but emit it NON-strict: our narration schemas use `min(1)` (⇒
3933
+ // `minLength`/`minItems`), keywords OpenAI's STRICT structured outputs
3934
+ // reject with a 400. Non-strict still hands the model the schema while
3935
+ // tolerating those keywords; `generateObject` re-validates against Zod.
3936
+ transformRequestBody: relaxStructuredOutputsStrictness
3937
+ })(model);
3924
3938
  }
3925
3939
  case "ollama": {
3926
3940
  let base = cleanBaseUrl2(config.llmBaseUrl) ?? OLLAMA_DEFAULT_BASE_URL2;
@@ -3969,6 +3983,26 @@ function cleanBaseUrl2(baseUrl) {
3969
3983
  function assertNeverProvider(provider) {
3970
3984
  throw new NarrationError(`Unsupported provider: ${String(provider)}`);
3971
3985
  }
3986
+ function isJsonSchemaResponseFormat(value) {
3987
+ if (typeof value !== "object" || value === null) {
3988
+ return false;
3989
+ }
3990
+ const candidate = value;
3991
+ return candidate.type === "json_schema" && typeof candidate.json_schema === "object" && candidate.json_schema !== null;
3992
+ }
3993
+ function relaxStructuredOutputsStrictness(body) {
3994
+ const responseFormat = body.response_format;
3995
+ if (!isJsonSchemaResponseFormat(responseFormat)) {
3996
+ return body;
3997
+ }
3998
+ return {
3999
+ ...body,
4000
+ response_format: {
4001
+ ...responseFormat,
4002
+ json_schema: { ...responseFormat.json_schema, strict: false }
4003
+ }
4004
+ };
4005
+ }
3972
4006
 
3973
4007
  // src/narrate/narrate.ts
3974
4008
  function createNarrate(deps = {}) {
@@ -6008,7 +6042,8 @@ function formatNumber3(n) {
6008
6042
  }
6009
6043
  function valueTable(value) {
6010
6044
  const shape = detectShape(value);
6011
- const labelHeader = shape === "timeseries" ? "Period" : shape === "distribution" ? "Item" : "Field";
6045
+ const labelHeaderByShape = { timeseries: "Period", distribution: "Item" };
6046
+ const labelHeader = labelHeaderByShape[shape] ?? "Field";
6012
6047
  const rows = extractSeries(value).map((point) => `| ${escapeCell(point.label)} | ${escapeCell(formatNumber3(point.value))} |`);
6013
6048
  return [`- **Value**`, "", `| ${labelHeader} | Value |`, "| --- | --- |", ...rows].join("\n");
6014
6049
  }
@@ -6515,7 +6550,7 @@ function localName(target) {
6515
6550
  }
6516
6551
 
6517
6552
  // src/cli/version.ts
6518
- var VERSION = "1.1.3";
6553
+ var VERSION = "1.1.5";
6519
6554
 
6520
6555
  // src/cli/write-file.ts
6521
6556
  import { writeFile as fsWriteFile } from "fs/promises";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commit-whisper",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "Deterministic git history analysis with a grounded, BYOK AI narrative — terminal-native CLI.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",