v2.0.23
What's Changed
- fix Windows CRLF doubling on write→edit multiline flow (a94a735)
- ci: bump actions to Node 24-compatible versions (3566ea1)
- fix(write): hash fs_state from disk bytes to match edit/read (1ca7b1e)
- fix(jsonl): only retry Windows file lock on contention errors (5525d12)
- test(bash): use tmp_path for redirection test on Windows (889cd00)
- fix: CRLF handling and Windows path edge cases in file tools (3e8e60d)
- fix: Windows File paths and remaining cross-platform CI failures (d3c9b22)
- test(codegen): use sys.executable for CLI subprocess invocations (8ab2496)
- test: fix py3.11 File instantiation and flaky parallel-params assertion (fa11a69)
- ci: add 'os' input to workflow_dispatch for targeted manual runs (1e7d1ff)
- fix(tracing): make JsonlTracingProvider import on Windows (415883e)
- fix(file-content): always send string filename to OpenAI Responses API
_safe_file_namereturns None for data URLs and anonymous BytesIO files, so for PDFs in those source schemesto_openai_responses_inputwas emitting{"filename": null, ...}— rejected by the OpenAI Responses API with a validation error. Falls back tof"document{source_extension or '.pdf'}"when no display name is known. Deterministic (no UUID per call, preserves cache invariants) and human-readable in OpenAI logs. Adds regression tests for both no-name code paths and tightens test_pdf_valid to actually assert the filename value. (21a56c5) - refactor(file-content): drop dead _display_name property The validator already sets self.name = _safe_file_name(self.file) at construction when name is None, so the property's fallback branch was unreachable in practice — it just recomputed the same None. Removes the property and uses self.name directly at the single call site (PDF branch of to_openai_responses_input). (af3911e)
- feat(file-content): add explicit name field for filename metadata Adds
FileContent.name: str | Noneso the original filename survives the full chat-history round-trip. Previously dump() serialized FileContent.file to a bare URL and the frontend had to guess the display name from the URL — fragile with URL encoding, sanitization, uuid paths, and bytes uploads defaulting to{uuid}.ext. Changes: - FileContent: newnamefield; validator defaults from File metadata without triggering the lazy fetcher (no disk read / network call at construction time). Moves_cached_*to PrivateAttr so they no longer leak into dumps. Fixes a stale_cached_openai_inputtypo. - content_factory: reads/restoresnameon deserialize; old traces without the field still work (defaults from URL basename). - serialization.dump(): explicit shape for FileContent: {"type": "file", "name": "...", "file": "..."}nameis omitted when None. Stops leaking private cache attrs. - EML attachment paths propagateattachment['filename']into the synthesized FileContent. Tests (offline + real-API): - 17 unit tests: name defaulting per source scheme, no I/O at construction, dump shape, round-trip via content_factory, backward compat for pre-existing traces. - 1 offline integration test: Agent + JSONL + session-chain reload using TestModel. - 3 real-API integration tests (gated by @pytest.mark.integration): OpenAI gpt-4o-mini, Anthropic claude-haiku-4-5, Google gemini-2.5-flash-lite — each verifies a real LLM accepts a PNG with display name, JSONL persists the name, and a second turn successfully reloads + re-sends the file. (7ddbdc5) - Add Jira tool tests with optional live integration suite (324966d)
- Register Jira tools and use platform Integration (82a1d85)
- Add Jira tools module (9ffdfd7)
Full Changelog: v2.0.22...v2.0.23