noukai-sdk 0.2.0__tar.gz

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 (83) hide show
  1. noukai_sdk-0.2.0/.env.example +53 -0
  2. noukai_sdk-0.2.0/.github/CODEOWNERS +6 -0
  3. noukai_sdk-0.2.0/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  4. noukai_sdk-0.2.0/.github/ISSUE_TEMPLATE/feature_request.md +27 -0
  5. noukai_sdk-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +25 -0
  6. noukai_sdk-0.2.0/.github/workflows/ci.yml +61 -0
  7. noukai_sdk-0.2.0/.github/workflows/integration.yml +44 -0
  8. noukai_sdk-0.2.0/.github/workflows/release.yml +64 -0
  9. noukai_sdk-0.2.0/.gitignore +48 -0
  10. noukai_sdk-0.2.0/.python-version +1 -0
  11. noukai_sdk-0.2.0/CHANGELOG.md +114 -0
  12. noukai_sdk-0.2.0/LICENSE +21 -0
  13. noukai_sdk-0.2.0/PKG-INFO +619 -0
  14. noukai_sdk-0.2.0/README.md +577 -0
  15. noukai_sdk-0.2.0/RELEASING.md +119 -0
  16. noukai_sdk-0.2.0/pyproject.toml +85 -0
  17. noukai_sdk-0.2.0/src/noukai_sdk/CONTEXT.md +86 -0
  18. noukai_sdk-0.2.0/src/noukai_sdk/__init__.py +132 -0
  19. noukai_sdk-0.2.0/src/noukai_sdk/_client.py +394 -0
  20. noukai_sdk-0.2.0/src/noukai_sdk/_constants.py +92 -0
  21. noukai_sdk-0.2.0/src/noukai_sdk/_errors.py +149 -0
  22. noukai_sdk-0.2.0/src/noukai_sdk/_flow.py +991 -0
  23. noukai_sdk-0.2.0/src/noukai_sdk/_jobs.py +231 -0
  24. noukai_sdk-0.2.0/src/noukai_sdk/_models/__init__.py +3 -0
  25. noukai_sdk-0.2.0/src/noukai_sdk/_models/_aliases.py +11 -0
  26. noukai_sdk-0.2.0/src/noukai_sdk/_models/events.py +115 -0
  27. noukai_sdk-0.2.0/src/noukai_sdk/_models/requests.py +69 -0
  28. noukai_sdk-0.2.0/src/noukai_sdk/_models/responses.py +166 -0
  29. noukai_sdk-0.2.0/src/noukai_sdk/_models/session.py +97 -0
  30. noukai_sdk-0.2.0/src/noukai_sdk/_models/trace.py +65 -0
  31. noukai_sdk-0.2.0/src/noukai_sdk/_paths.py +155 -0
  32. noukai_sdk-0.2.0/src/noukai_sdk/_run.py +240 -0
  33. noukai_sdk-0.2.0/src/noukai_sdk/_step_iterator.py +679 -0
  34. noukai_sdk-0.2.0/src/noukai_sdk/_streaming.py +176 -0
  35. noukai_sdk-0.2.0/src/noukai_sdk/_tool_calls.py +259 -0
  36. noukai_sdk-0.2.0/src/noukai_sdk/_trace_scope.py +281 -0
  37. noukai_sdk-0.2.0/src/noukai_sdk/_transport.py +555 -0
  38. noukai_sdk-0.2.0/src/noukai_sdk/_transport_shared.py +146 -0
  39. noukai_sdk-0.2.0/src/noukai_sdk/_version.py +1 -0
  40. noukai_sdk-0.2.0/src/noukai_sdk/adapters/__init__.py +0 -0
  41. noukai_sdk-0.2.0/src/noukai_sdk/adapters/fastapi.py +155 -0
  42. noukai_sdk-0.2.0/src/noukai_sdk/adapters/flask.py +124 -0
  43. noukai_sdk-0.2.0/src/noukai_sdk/py.typed +0 -0
  44. noukai_sdk-0.2.0/src/noukai_sdk/replay/__init__.py +0 -0
  45. noukai_sdk-0.2.0/src/noukai_sdk/replay/_state.py +54 -0
  46. noukai_sdk-0.2.0/src/noukai_sdk/replay/fetcher.py +92 -0
  47. noukai_sdk-0.2.0/src/noukai_sdk/replay/matcher.py +459 -0
  48. noukai_sdk-0.2.0/src/noukai_sdk/replay/sse_reconstructor.py +129 -0
  49. noukai_sdk-0.2.0/tests/__init__.py +0 -0
  50. noukai_sdk-0.2.0/tests/conftest.py +1 -0
  51. noukai_sdk-0.2.0/tests/integration/README.md +161 -0
  52. noukai_sdk-0.2.0/tests/integration/__init__.py +3 -0
  53. noukai_sdk-0.2.0/tests/integration/conftest.py +125 -0
  54. noukai_sdk-0.2.0/tests/integration/fixtures/README.md +124 -0
  55. noukai_sdk-0.2.0/tests/integration/fixtures/hello-world.json +11 -0
  56. noukai_sdk-0.2.0/tests/integration/fixtures/tools-enabled.json +27 -0
  57. noukai_sdk-0.2.0/tests/integration/fixtures/two-step.json +12 -0
  58. noukai_sdk-0.2.0/tests/integration/test_errors.py +133 -0
  59. noukai_sdk-0.2.0/tests/integration/test_events.py +158 -0
  60. noukai_sdk-0.2.0/tests/integration/test_execute.py +83 -0
  61. noukai_sdk-0.2.0/tests/integration/test_execute_async.py +71 -0
  62. noukai_sdk-0.2.0/tests/integration/test_replay.py +449 -0
  63. noukai_sdk-0.2.0/tests/integration/test_run_proxy.py +150 -0
  64. noukai_sdk-0.2.0/tests/integration/test_steps.py +75 -0
  65. noukai_sdk-0.2.0/tests/integration/test_tool_calls.py +186 -0
  66. noukai_sdk-0.2.0/tests/unit/__init__.py +0 -0
  67. noukai_sdk-0.2.0/tests/unit/test_adapters_fastapi.py +251 -0
  68. noukai_sdk-0.2.0/tests/unit/test_adapters_flask.py +231 -0
  69. noukai_sdk-0.2.0/tests/unit/test_client_construction.py +193 -0
  70. noukai_sdk-0.2.0/tests/unit/test_execute.py +207 -0
  71. noukai_sdk-0.2.0/tests/unit/test_interfaces.py +118 -0
  72. noukai_sdk-0.2.0/tests/unit/test_jobs.py +332 -0
  73. noukai_sdk-0.2.0/tests/unit/test_models_roundtrip.py +184 -0
  74. noukai_sdk-0.2.0/tests/unit/test_parity.py +44 -0
  75. noukai_sdk-0.2.0/tests/unit/test_replay.py +901 -0
  76. noukai_sdk-0.2.0/tests/unit/test_replay_sync.py +712 -0
  77. noukai_sdk-0.2.0/tests/unit/test_run_proxy.py +200 -0
  78. noukai_sdk-0.2.0/tests/unit/test_sse_parser.py +252 -0
  79. noukai_sdk-0.2.0/tests/unit/test_step_iterator.py +603 -0
  80. noukai_sdk-0.2.0/tests/unit/test_sync_client.py +191 -0
  81. noukai_sdk-0.2.0/tests/unit/test_tool_call_resume.py +289 -0
  82. noukai_sdk-0.2.0/tests/unit/test_transport.py +483 -0
  83. noukai_sdk-0.2.0/uv.lock +1116 -0
@@ -0,0 +1,53 @@
1
+ # noukai-sdk Python — local env for integration tests
2
+ #
3
+ # Setup:
4
+ # cp .env.example .env
5
+ # # fill in real values below
6
+ # uv run pytest tests/integration -v
7
+ #
8
+ # The .env file is loaded automatically by tests/integration/conftest.py
9
+ # via python-dotenv. It is NOT loaded by the SDK at runtime — only by tests.
10
+ # NEVER commit .env (it's in .gitignore).
11
+
12
+ # ----------------------------------------------------------------------------
13
+ # SDK runtime env (read by the SDK itself at Noukai() construction)
14
+ # ----------------------------------------------------------------------------
15
+
16
+ # Deployment target. "dev" → http://localhost:8080/api/v1
17
+ # unset/"production" → https://api.noukai.xyz/api/v1
18
+ NOUKAI_ENV=dev
19
+
20
+ # ----------------------------------------------------------------------------
21
+ # Integration test env (read only by tests/integration/, not the SDK)
22
+ # ----------------------------------------------------------------------------
23
+
24
+ # Real nk_* API key for the integration test account.
25
+ # For local dev: a key minted against your local Noukai server.
26
+ # For staging/prod: a dedicated test-account key (NOT a production user key).
27
+ NOUKAI_INTEGRATION_KEY=nk_replace_me
28
+
29
+ # "org/project" pair holding the fixture flows.
30
+ # Recommended convention: a dedicated "tests-integration" project.
31
+ NOUKAI_INTEGRATION_PROJECT=acme/tests-integration
32
+
33
+ # Slug of a single-step flow that takes `message` and returns a response.
34
+ # Used by test_execute, test_execute_async, test_run_proxy.
35
+ NOUKAI_INTEGRATION_HELLO_SLUG=hello-world
36
+
37
+ # Slug of a two-block flow used to test steps()/events() iteration.
38
+ # Used by test_steps, test_events, test_run_proxy.
39
+ NOUKAI_INTEGRATION_TWO_STEP_SLUG=two-step
40
+
41
+ # Slug of a flow configured with `tools` for tool-call resume testing.
42
+ # Used by test_tool_calls.
43
+ NOUKAI_INTEGRATION_TOOLS_SLUG=tools-enabled
44
+
45
+ # ----------------------------------------------------------------------------
46
+ # Optional: zero-credit org for the InsufficientCreditsError test
47
+ # ----------------------------------------------------------------------------
48
+
49
+ # If you have a separate test account with 0 credits, fill these in to enable
50
+ # the test_zero_credits_raises_insufficient_credits test. Otherwise it skips.
51
+ # NOUKAI_INTEGRATION_ZERO_CREDIT_KEY=nk_zero_credit_account
52
+ # NOUKAI_INTEGRATION_ZERO_CREDIT_PROJECT=acme/integration-zero
53
+ # NOUKAI_INTEGRATION_ZERO_CREDIT_SLUG=hello-world
@@ -0,0 +1,6 @@
1
+ # .github/CODEOWNERS
2
+ # All files: SDK maintainers own everything by default.
3
+ * @noukai/sdk-maintainers
4
+
5
+ # Docs: co-owned by the docs team.
6
+ docs/ @noukai/sdk-maintainers @noukai/docs
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something is not working as expected
4
+ labels: bug
5
+ ---
6
+
7
+ ## Description
8
+
9
+ <!-- A clear, concise description of what the bug is. -->
10
+
11
+ ## Minimal reproducer
12
+
13
+ ```python
14
+ from noukai_sdk import Noukai
15
+
16
+ # Paste the smallest code snippet that triggers the problem.
17
+ ```
18
+
19
+ ## Expected behaviour
20
+
21
+ <!-- What you expected to happen. -->
22
+
23
+ ## Actual behaviour
24
+
25
+ <!-- What actually happened. Include any error messages or tracebacks. -->
26
+
27
+ ## Environment
28
+
29
+ | Field | Value |
30
+ |-------|-------|
31
+ | SDK version | <!-- e.g. 0.1.0 — run: python -c "import noukai_sdk; print(noukai_sdk.__version__)" --> |
32
+ | Python version | <!-- e.g. 3.11.9 --> |
33
+ | OS | <!-- e.g. macOS 14.5, Ubuntu 22.04, Windows 11 --> |
34
+ | Install method | <!-- pip / uv / conda / other --> |
35
+
36
+ ## Additional context
37
+
38
+ <!-- Anything else that might help — logs, related issues, etc. -->
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an improvement or new capability
4
+ labels: enhancement
5
+ ---
6
+
7
+ ## Summary
8
+
9
+ <!-- One sentence: what would you like the SDK to do? -->
10
+
11
+ ## Motivation
12
+
13
+ <!-- Why do you need this? What use case does it unlock? -->
14
+
15
+ ## Proposed API
16
+
17
+ ```python
18
+ # Optional: sketch what the API might look like.
19
+ ```
20
+
21
+ ## Alternatives considered
22
+
23
+ <!-- Have you worked around this another way? Are there existing methods that partially cover the need? -->
24
+
25
+ ## Additional context
26
+
27
+ <!-- Anything else — links to Noukai docs, related issues, etc. -->
@@ -0,0 +1,25 @@
1
+ ## Summary
2
+
3
+ <!-- What does this PR do? One to three bullet points. -->
4
+
5
+ -
6
+
7
+ ## Related issues
8
+
9
+ <!-- Link any issues this PR addresses: "Closes #123" or "Relates to #456". -->
10
+
11
+ ## Test plan
12
+
13
+ - [ ] Existing tests pass (`uv run pytest tests/unit/ -v`)
14
+ - [ ] New tests added for new behaviour (if applicable)
15
+ - [ ] Type-check passes (`uv run mypy`)
16
+ - [ ] Linting passes (`uv run ruff check && uv run ruff format --check`)
17
+ - [ ] Manual verification steps:
18
+
19
+ <!-- Describe any manual steps needed to verify this PR. -->
20
+
21
+ ## Checklist
22
+
23
+ - [ ] CHANGELOG.md updated under `[Unreleased]`
24
+ - [ ] `_version.py` and `pyproject.toml` bumped (if this is a release PR)
25
+ - [ ] Docs updated (if public API changed)
@@ -0,0 +1,61 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ lint-and-type:
11
+ name: Lint & type-check
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - name: Set up uv
17
+ uses: astral-sh/setup-uv@v3
18
+
19
+ - name: Install dev dependencies
20
+ run: uv sync --extra dev
21
+
22
+ - name: Check formatting (ruff)
23
+ run: uv run ruff format --check
24
+
25
+ - name: Lint (ruff)
26
+ run: uv run ruff check
27
+
28
+ - name: Type-check (mypy)
29
+ run: uv run mypy
30
+
31
+ test:
32
+ name: Tests (${{ matrix.os }} / Python ${{ matrix.python-version }})
33
+ runs-on: ${{ matrix.os }}
34
+ strategy:
35
+ fail-fast: false
36
+ matrix:
37
+ os: [ubuntu-latest, macos-latest, windows-latest]
38
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
39
+ steps:
40
+ - uses: actions/checkout@v4
41
+
42
+ - name: Set up uv
43
+ uses: astral-sh/setup-uv@v3
44
+
45
+ - name: Set up Python ${{ matrix.python-version }}
46
+ uses: actions/setup-python@v5
47
+ with:
48
+ python-version: ${{ matrix.python-version }}
49
+
50
+ - name: Install dev dependencies
51
+ run: uv sync --extra dev
52
+
53
+ # Run unit tests with coverage reporting and enforce the floor in
54
+ # the same invocation (one pytest run is sufficient — the second
55
+ # invocation was producing duplicate output and re-running tests).
56
+ - name: Run unit tests with coverage
57
+ run: >
58
+ uv run pytest tests/unit/ -v
59
+ --cov=noukai_sdk
60
+ --cov-report=term-missing
61
+ --cov-fail-under=85
@@ -0,0 +1,44 @@
1
+ name: Integration (Python SDK)
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 6 * * *" # daily 06:00 UTC
6
+ push:
7
+ tags:
8
+ - "v*.*.*"
9
+ workflow_dispatch: # manual trigger
10
+
11
+ jobs:
12
+ integration:
13
+ runs-on: ubuntu-latest
14
+ timeout-minutes: 30
15
+ env:
16
+ NOUKAI_INTEGRATION_KEY: ${{ secrets.NOUKAI_INTEGRATION_KEY }}
17
+ NOUKAI_INTEGRATION_PROJECT: ${{ vars.NOUKAI_INTEGRATION_PROJECT }}
18
+ NOUKAI_INTEGRATION_HELLO_SLUG: ${{ vars.NOUKAI_INTEGRATION_HELLO_SLUG }}
19
+ NOUKAI_INTEGRATION_TWO_STEP_SLUG: ${{ vars.NOUKAI_INTEGRATION_TWO_STEP_SLUG }}
20
+ NOUKAI_INTEGRATION_TOOLS_SLUG: ${{ vars.NOUKAI_INTEGRATION_TOOLS_SLUG }}
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+
24
+ - uses: astral-sh/setup-uv@v3
25
+ with:
26
+ version: "latest"
27
+
28
+ - name: Install dependencies
29
+ run: |
30
+ cd development/noukai/sdk/python
31
+ uv sync --extra dev
32
+
33
+ - name: Run integration tests
34
+ run: |
35
+ cd development/noukai/sdk/python
36
+ uv run pytest tests/integration/ -v --tb=short
37
+
38
+ - name: Upload test results
39
+ if: always()
40
+ uses: actions/upload-artifact@v4
41
+ with:
42
+ name: integration-test-results
43
+ path: development/noukai/sdk/python/.pytest_cache/
44
+ retention-days: 7
@@ -0,0 +1,64 @@
1
+ name: Release
2
+
3
+ # Triggers on semver tags like v0.1.0, v1.2.3, etc.
4
+ on:
5
+ push:
6
+ tags:
7
+ - "v*.*.*"
8
+
9
+ jobs:
10
+ build-and-publish:
11
+ name: Build, publish to PyPI & create GitHub release
12
+ runs-on: ubuntu-latest
13
+ # The "pypi" environment must be created in the GitHub repo settings
14
+ # (Settings → Environments → New environment: pypi) and the PyPI trusted
15
+ # publisher must be configured at:
16
+ # https://pypi.org/manage/account/publishing/
17
+ # pointing at this workflow file path:
18
+ # Workflow: .github/workflows/release.yml
19
+ # Environment: pypi
20
+ environment: pypi
21
+ permissions:
22
+ id-token: write # Required for OIDC trusted publisher (no API token needed)
23
+ contents: write # Required to create the GitHub release
24
+
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+
28
+ - name: Set up uv
29
+ uses: astral-sh/setup-uv@v3
30
+
31
+ - name: Install package (no extras — just needs to be importable for version check)
32
+ run: uv sync
33
+
34
+ # Safety guard: the pushed tag (e.g. v0.1.0) must match the version
35
+ # declared in noukai_sdk._version. Catches "forgot to bump _version.py"
36
+ # before we reach PyPI (uploads there are permanent).
37
+ - name: Verify tag matches package version
38
+ shell: bash
39
+ run: |
40
+ TAG_VER="${GITHUB_REF_NAME#v}"
41
+ FILE_VER=$(uv run python -c "import noukai_sdk; print(noukai_sdk.__version__)")
42
+ echo "Tag version : $TAG_VER"
43
+ echo "Package version: $FILE_VER"
44
+ if [ "$TAG_VER" != "$FILE_VER" ]; then
45
+ echo "ERROR: tag $TAG_VER does not match package version $FILE_VER"
46
+ echo "Update src/noukai_sdk/_version.py and pyproject.toml, then retag."
47
+ exit 1
48
+ fi
49
+
50
+ - name: Build wheel and sdist
51
+ run: uv build
52
+
53
+ # Uses PyPI's OIDC trusted publisher — no API token stored in GitHub secrets.
54
+ # See: https://docs.pypi.org/trusted-publishers/
55
+ - name: Publish to PyPI
56
+ uses: pypa/gh-action-pypi-publish@release/v1
57
+
58
+ # Creates a GitHub release from the tag with auto-generated release notes
59
+ # and attaches the CHANGELOG as the body.
60
+ - name: Create GitHub release
61
+ uses: softprops/action-gh-release@v2
62
+ with:
63
+ generate_release_notes: true
64
+ body_path: CHANGELOG.md
@@ -0,0 +1,48 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.pyo
5
+ *.pyd
6
+ .Python
7
+ *.egg
8
+ *.egg-info/
9
+ dist/
10
+ build/
11
+ .eggs/
12
+
13
+ # Virtual environments
14
+ .venv/
15
+ venv/
16
+ env/
17
+
18
+ # UV
19
+ .uv/
20
+
21
+ # Testing
22
+ .pytest_cache/
23
+ .coverage
24
+ htmlcov/
25
+ .tox/
26
+
27
+ # Type checking
28
+ .mypy_cache/
29
+
30
+ # Linting
31
+ .ruff_cache/
32
+
33
+ # Documentation build output (mkdocs)
34
+ site/
35
+
36
+ # Local env (integration test secrets — never commit)
37
+ .env
38
+ .env.local
39
+ .env.*.local
40
+
41
+ # IDE
42
+ .idea/
43
+ .vscode/
44
+ *.swp
45
+ *.swo
46
+
47
+ # macOS
48
+ .DS_Store
@@ -0,0 +1 @@
1
+ 3.10
@@ -0,0 +1,114 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file. The
4
+ format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.2.0] — 2026-06-06
10
+
11
+ ### Added
12
+
13
+ - `@noukai_sdk.trace` decorator and `trace_scope` / `trace_scope_sync` context
14
+ managers. Wrapping a route (or any callable) in `@trace` groups every Noukai
15
+ SDK call it makes under a single session id so the full execution can be
16
+ replayed later.
17
+ - `current_session_id() -> str | None` — returns the session id of the active
18
+ scope, or `None` when called outside a scope.
19
+ - `session_id=` optional kwarg on `Flow.execute()`, `Flow.steps()`,
20
+ `Flow.events()`, `Flow.execute_async()`, and their `AsyncFlow` counterparts.
21
+ When passed outside a scope the SDK sends `X-Session-Id` on the wire;
22
+ when passed *inside* an active replay scope it triggers a one-shot fetch
23
+ of that explicit session instead of drawing from the scope cassette (see
24
+ Caveats in README).
25
+ - `session_id=` optional kwarg on `Noukai(...)` / `AsyncNoukai(...)` — sets a
26
+ default session id for every call made through that client.
27
+ - `ExecuteResult.session_id` property surfaces the captured or replayed session
28
+ id returned in the `X-Noukai-Session` response header.
29
+ - **Replay mode.** When `NOUKAI_REPLAY_ENABLED=true` and the caller passes
30
+ `X-Noukai-Replay: <session_id>` to the adapter, the SDK fetches the recorded
31
+ session via `GET /seq/sessions/{id}` (idempotent; retried by default transport
32
+ retry logic — see R3 note in README) and serves each `Flow.execute()` /
33
+ `steps()` / `events()` call from the cassette instead of making live calls.
34
+ - **Framework adapters:**
35
+ - `noukai_sdk.adapters.fastapi.NoukaiTraceMiddleware` — ASGI middleware for
36
+ FastAPI / Starlette; reads `X-Noukai-Replay`, opens/closes a trace scope
37
+ around the request, and writes `X-Noukai-Session` to the response.
38
+ - `noukai_sdk.adapters.flask.init_noukai_trace` — Flask before/after-request
39
+ hooks equivalent.
40
+ - **9 replay error classes** (all extend `ReplayError` which extends
41
+ `NoukaiError`):
42
+ - `ReplayError` — base class for all replay errors.
43
+ - `ReplayMissError` — no matching execution found in the cassette for a
44
+ `(slug, position)` lookup.
45
+ - `ReplayLeftoverError` — scope exited with unconsumed executions remaining
46
+ in the cassette.
47
+ - `ReplayForbiddenError` — replay attempted against a session that belongs to
48
+ a different org/project.
49
+ - `ReplaySessionNotFoundError` — the requested session id does not exist on
50
+ the backend.
51
+ - `ReplaySessionExpiredError` — the session exists but its TTL has elapsed and
52
+ snapshots are no longer available.
53
+ - `ReplayInvalidSessionError` — the session payload is structurally invalid or
54
+ cannot be parsed.
55
+ - `ReplayNoSnapshotsError` — the session exists but `trace_capture_mode` was
56
+ `off` so no snapshot data was recorded.
57
+ - `ReplayDisabledError` — replay was requested but `NOUKAI_REPLAY_ENABLED` is
58
+ not set to `true` (raised only when the adapter is used without the guard).
59
+ - Optional package extras: `noukai-sdk[fastapi]` (pulls FastAPI + Starlette)
60
+ and `noukai-sdk[flask]` (pulls `flask>=3.0`).
61
+ - Centralized URL audit registry at `noukai_sdk/_paths.py` — single file
62
+ lists every backend route the SDK calls. Auditing the wire surface is one
63
+ file read.
64
+
65
+ ### Fixed
66
+
67
+ - Replay session fetch now hits `GET /seq/sessions/{id}` (was incorrectly
68
+ `GET /sessions/{id}` — 404 in production).
69
+ - Replay matcher now compares against the BE's bare `flow.slug` (e.g.
70
+ `"grade-3"`), not the synthesized `org/project/slug` that fixtures
71
+ previously used. Replay against the real backend now actually matches
72
+ recorded executions.
73
+ - `SessionExecution` model aligned with BE schema: `status` includes
74
+ `"pending"` and `"cancelled"`; `flow_id`, `slug`, `trigger_type`,
75
+ `trace_capture_mode`, and `error_at_step` are now Optional so the SDK
76
+ does not crash when the underlying flow has been deleted.
77
+ - Reserved-header guard on `extra_headers=`: a misconfigured caller cannot
78
+ overwrite `Authorization`, `X-Noukai-API-Version`, `User-Agent`,
79
+ `X-Request-ID`, `Content-Type`, or `Cookie` via per-request headers.
80
+ - Unified `Flow.execute() / steps() / events()` REPLAY-mode dispatch — all
81
+ three now apply the same rule when an explicit `session_id` matches or
82
+ differs from the scope. Previously `events()` and `steps()` made a live
83
+ call for explicit-sid-matching-scope, asymmetric with `execute()`.
84
+ - Session-id precedence chain uses `is not None` instead of `or`, so an
85
+ explicit empty-string `session_id=""` is no longer silently overridden
86
+ by the next tier.
87
+
88
+ ### Internal
89
+
90
+ - Transport `request()` and `stream()` accept an `extra_headers=` kwarg; used
91
+ by the replay subsystem to inject `X-Session-Id` / `X-Noukai-Replay` without
92
+ touching the public client surface.
93
+ - Log handler receives `scope_open` and `scope_close` events with `mode`
94
+ (`"normal"` | `"capture"` | `"replay"`) and `session_id` fields.
95
+
96
+ ### Requires
97
+
98
+ - Backend session-grouping endpoint per BE design
99
+ `20260605-BE-execution-session-grouping` (`GET /seq/sessions/{id}`,
100
+ `X-Session-Id` header on `/execute` + `/step` routes).
101
+
102
+ ## [0.1.0] — 2026-05-31
103
+
104
+ ### Added
105
+ - Initial release.
106
+ - `Noukai` and `AsyncNoukai` clients (sync + async).
107
+ - `flow.execute()`, `flow.execute_async()`, `flow.steps()`, `flow.events()`.
108
+ - `flow.run(id).trace()`, `step_trace()`, `live_trace()`.
109
+ - Tool-call auto-resume via `tool_handler=`; manual mode via `PausedResult.resume()`.
110
+ - Typed Pydantic event hierarchy for SSE streams.
111
+ - Exception hierarchy mapped to HTTP status; server error codes on `.code`.
112
+
113
+ [Unreleased]: https://github.com/noukai/noukai-python/compare/v0.1.0...HEAD
114
+ [0.1.0]: https://github.com/noukai/noukai-python/releases/tag/v0.1.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 abigcircle
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.