@sayknow-cli/ai 0.5.1 → 0.5.2

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.
@@ -45,16 +45,18 @@ export interface ProcessResponsesStreamOptions {
45
45
  }
46
46
  export declare function processResponsesStream<TApi extends Api>(openaiStream: AsyncIterable<OpenAI.Responses.ResponseStreamEvent>, output: AssistantMessage, stream: AssistantMessageEventStream, model: Model<TApi>, options?: ProcessResponsesStreamOptions): Promise<void>;
47
47
  /**
48
- * Mark tool-call blocks left incomplete by a length-truncated response so the
49
- * agent loop rejects them instead of executing a best-effort partial parse.
48
+ * Mark tool-call blocks whose arguments are structurally incomplete when a
49
+ * response stops for length.
50
50
  *
51
- * The universal signal is finalization: a call that never received its terminal
52
- * `output_item.done` (passed in via `isFinalized`) was cut off mid-arguments.
53
- * This covers both JSON function calls and raw-input custom tools without
54
- * mis-flagging a *completed* custom tool whose raw input is not valid JSON. As a
55
- * defensive secondary, a finalized JSON function call whose buffered arguments
56
- * still don't parse (e.g. a misbehaving relay) is flagged too. No-op unless the
57
- * turn stopped for length.
51
+ * A missing `output_item.done` normally means the call was cut off. Responses
52
+ * can also hit the output-token limit after emitting a complete JSON object but
53
+ * before finalizing the item (for example, after a long whitespace tail). A
54
+ * non-finalized JSON call is therefore safe only when its exact buffered text
55
+ * parses as complete JSON. Custom tools carry raw input with no structural
56
+ * completion marker, so they still require finalization.
57
+ *
58
+ * Finalized JSON calls get the same defensive parse check for misbehaving
59
+ * relays. No-op unless the turn stopped for length.
58
60
  *
59
61
  * Shared by both Responses providers (`openai-responses`, `openai-codex-responses`).
60
62
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@sayknow-cli/ai",
4
- "version": "0.5.1",
4
+ "version": "0.5.2",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://sayknow-cli.com",
7
7
  "author": "jaybeyond",
@@ -43,7 +43,7 @@
43
43
  "dependencies": {
44
44
  "@anthropic-ai/sdk": "^0.94.0",
45
45
  "@bufbuild/protobuf": "^2.12.0",
46
- "@sayknow-cli/utils": "0.5.1",
46
+ "@sayknow-cli/utils": "0.5.2",
47
47
  "openai": "^6.36.0",
48
48
  "partial-json": "^0.1.7",
49
49
  "zod": "4.4.3"
@@ -795,16 +795,18 @@ export async function processResponsesStream<TApi extends Api>(
795
795
  }
796
796
 
797
797
  /**
798
- * Mark tool-call blocks left incomplete by a length-truncated response so the
799
- * agent loop rejects them instead of executing a best-effort partial parse.
798
+ * Mark tool-call blocks whose arguments are structurally incomplete when a
799
+ * response stops for length.
800
800
  *
801
- * The universal signal is finalization: a call that never received its terminal
802
- * `output_item.done` (passed in via `isFinalized`) was cut off mid-arguments.
803
- * This covers both JSON function calls and raw-input custom tools without
804
- * mis-flagging a *completed* custom tool whose raw input is not valid JSON. As a
805
- * defensive secondary, a finalized JSON function call whose buffered arguments
806
- * still don't parse (e.g. a misbehaving relay) is flagged too. No-op unless the
807
- * turn stopped for length.
801
+ * A missing `output_item.done` normally means the call was cut off. Responses
802
+ * can also hit the output-token limit after emitting a complete JSON object but
803
+ * before finalizing the item (for example, after a long whitespace tail). A
804
+ * non-finalized JSON call is therefore safe only when its exact buffered text
805
+ * parses as complete JSON. Custom tools carry raw input with no structural
806
+ * completion marker, so they still require finalization.
807
+ *
808
+ * Finalized JSON calls get the same defensive parse check for misbehaving
809
+ * relays. No-op unless the turn stopped for length.
808
810
  *
809
811
  * Shared by both Responses providers (`openai-responses`, `openai-codex-responses`).
810
812
  */
@@ -816,15 +818,17 @@ export function flagTruncatedToolCalls(
816
818
  if (stopReason !== "length") return;
817
819
  for (const block of output.content) {
818
820
  if (block.type !== "toolCall") continue;
821
+ const partial = (block as { partialJson?: string }).partialJson;
819
822
  if (!isFinalized(block)) {
820
- block.incompleteArguments = true;
823
+ if (block.customWireName || partial === undefined || !isCompleteJson(partial)) {
824
+ block.incompleteArguments = true;
825
+ }
821
826
  continue;
822
827
  }
823
- // Finalized: custom tools carry raw (non-JSON) input and are complete once
824
- // finalized; only JSON function calls get the parse double-check.
825
- if (!block.customWireName) {
826
- const partial = (block as { partialJson?: string }).partialJson;
827
- if (partial !== undefined && !isCompleteJson(partial)) block.incompleteArguments = true;
828
+ // Finalized custom tools carry raw (non-JSON) input. Only JSON function
829
+ // calls need the defensive parse check.
830
+ if (!block.customWireName && partial !== undefined && !isCompleteJson(partial)) {
831
+ block.incompleteArguments = true;
828
832
  }
829
833
  }
830
834
  }