Skip to content

[OPIK-5282] [SDK] feat: capture runner job stdout/stderr and stream to backend#5976

Merged
petrotiurin merged 6 commits intomainfrom
petrot/OPIK-5282-fix-signal-handlers-main-thread
Mar 31, 2026
Merged

[OPIK-5282] [SDK] feat: capture runner job stdout/stderr and stream to backend#5976
petrotiurin merged 6 commits intomainfrom
petrot/OPIK-5282-fix-signal-handlers-main-thread

Conversation

@petrotiurin
Copy link
Copy Markdown
Contributor

Details

Python runner was not capturing or sending stdout/stderr from agent job executions to the backend. This adds per-job log capture matching the TypeScript runner behavior.

Uses contextvars.ContextVar to track which job owns each print() call across concurrent executions, and an async LogStreamer task that intercepts stdout/stderr writes, batches log entries per-job, and sends them to the backend via append_job_logs without blocking agent execution.

Key changes:

  • context.py: new ContextVar for per-job ID tracking
  • log_streamer.py: _CaptureStream wraps stdout/stderr to intercept writes; async task batches and sends via run_in_executor
  • in_process_loop.py: sets job context before execution, propagates to executor threads via contextvars.copy_context().run()
  • prefixed_output.py: replace TTY guard with idempotency flag (TTY guard prevented capture in subprocess/CI environments)

Change checklist

  • User facing
  • Documentation update

Issues

  • OPIK-5282

AI-WATERMARK

AI-WATERMARK: yes

  • Tools: Claude Code
  • Model(s): Claude Opus 4.6
  • Scope: full implementation
  • Human verification: code review + e2e testing against local backend

Testing

  • Unit tests: python -m pytest tests/unit/runner/ -xvs (36 passed)
  • E2E tests: python -m pytest tests/e2e/runner/test_runner_e2e.py::test_runner_happy_path -xvs (1 passed — verifies logs appear via get_job_logs API after job completion)
  • Validated with local FastAPI+uvicorn app that the 422: text must not be blank error from whitespace-only writes is filtered out
  • Tested both sync (executor thread) and async agent paths

Documentation

N/A

@github-actions github-actions bot added python Pull requests that update Python code tests Including test files, or tests related like configuration. Python SDK labels Mar 30, 2026
petrotiurin and others added 2 commits March 30, 2026 18:17
…vate_runner

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…o backend

Add per-job log capture for the Python runner, matching TypeScript behavior.
Uses contextvars to track which job owns each print() call, and an async
LogStreamer to send logs to the backend without blocking execution.

- context.py: ContextVar for per-job ID tracking
- log_streamer.py: async task that intercepts stdout/stderr, batches entries,
  and sends via append_job_logs
- in_process_loop.py: propagates context to executor threads via
  contextvars.copy_context().run()
- prefixed_output.py: replace TTY guard with idempotency flag
- e2e + unit tests for log capture pipeline

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@petrotiurin petrotiurin force-pushed the petrot/OPIK-5282-fix-signal-handlers-main-thread branch from f0ffa1e to 9bb6048 Compare March 30, 2026 17:18
Comment thread sdks/python/tests/unit/runner/test_activate.py
Comment thread sdks/python/tests/unit/runner/test_in_process_loop.py
Comment thread sdks/python/src/opik/runner/log_streamer.py
Comment thread sdks/python/src/opik/runner/log_streamer.py
Comment thread sdks/python/src/opik/runner/log_streamer.py
Comment thread sdks/python/src/opik/runner/in_process_loop.py
petrotiurin and others added 2 commits March 30, 2026 18:32
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Graceful LogStreamer shutdown: cancel and await task before closing loop
- Guard _CaptureStream.write against closed event loop
- Restore signal handlers in test_activate fixture

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@petrotiurin petrotiurin marked this pull request as ready for review March 31, 2026 13:12
@petrotiurin petrotiurin requested a review from a team as a code owner March 31, 2026 13:12
Copy link
Copy Markdown
Collaborator

@collincunn collincunn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@petrotiurin petrotiurin merged commit 8ff578f into main Mar 31, 2026
138 checks passed
@petrotiurin petrotiurin deleted the petrot/OPIK-5282-fix-signal-handlers-main-thread branch March 31, 2026 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Python SDK python Pull requests that update Python code tests Including test files, or tests related like configuration.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants