4 Commits

Author SHA1 Message Date
roboomp e26c3034f0 fix(agent): carried terminal content through proxy streams
Made proxy done and error events carry finalized assistant content so provider-only blocks survive event reconstruction.

Covered Anthropic native web-search history restored after live events omitted the opaque blocks.

Fixes #6703
2026-07-26 13:44:14 +00:00
can1357 357c29224d feat: implemented symbol-based streaming state for isolated metadata
- Migrated internal streaming state from string-based properties to symbol-keyed properties for improved data isolation and safety.
- Replaced the deprecated `stripVariant` utility with centralized `clearStreamingPartialJson` and symbol-specific helper methods across all provider implementations.
- Implemented `stripStreamingBlockSymbols` and updated deep equality checks to ensure metadata does not interfere with content comparisons.
- Standardized streaming metadata access through a new `block-symbols` utility module.
2026-06-27 12:07:08 +02:00
oldschoola 2a2aa9fe59 fix(proxy): preserve partialJson on content during streaming, scrub at terminal events
Address review feedback: downstream renderers (event-controller.ts:535)
read content.partialJson during toolcall_delta to pace streaming
previews (bash env assignments, write/edit smooth streaming).

Revised approach:
- toolcall_start: initialize partialJson on content via typed
  ToolCall & { partialJson: string } intersection (not as any)
- toolcall_delta: accumulate in side-channel Map, write onto content
  via typed intersection cast
- toolcall_end: delete partialJson from content + side-channel map
- done/error: scrubPartialJson() cleans any remaining blocks that
  never got toolcall_end (the original leak bug, now fixed for all
  terminal paths)

Added test verifying partialJson IS present during streaming and
IS absent after completion.
2026-06-23 09:40:32 -07:00
oldschoola 9c795f886e fix(proxy): use side-channel Map for partialJson, eliminating as-any casts
streamProxy stored internal partialJson streaming state directly on typed
ToolCall objects via 4 'as any' casts. If toolcall_end was skipped (stream
error, early done), the field leaked into the final AssistantMessage content,
corrupting downstream serialization.

Replace with a side-channel Map<number, string> keyed by contentIndex:
- toolcall_start initializes the map entry
- toolcall_delta accumulates into it
- toolcall_end cleans it up

The typed ToolCall object never carries non-spec fields. All 4 'as any'
casts are eliminated.

Added 4 contract tests covering argument parsing, partialJson isolation on
normal completion, partialJson isolation when toolcall_end is missing, and
multiple concurrent tool calls with interleaved deltas.
2026-06-23 08:17:29 -07:00