Skip to content

feat: reasoning-aware response API - #44

Merged
lmeyerov merged 3 commits into
mainfrom
feat/skills-fastapi-reasoning
Jul 25, 2026
Merged

lmeyerov merged 3 commits into
mainfrom
feat/skills-fastapi-reasoning

Conversation

@lmeyerov

@lmeyerov lmeyerov commented Jul 25, 2026 •

Copy link
Copy Markdown
Contributor

What this adds

Louie streams a run tree: provisional reasoning text, phase/status updates, traces, and a final answer. Today all of that collapses into .text and the element list, so you cannot tell a draft from the answer, or see why a run failed.

This makes the stream addressable — opt-in, and inert by default.

Opting in

include_reasoning is False everywhere. With it off, behaviour is byte-identical to today.

client.add_cell(thread_id, prompt, include_reasoning=False)   # also: create_thread,
                                                              # upload_dataframe/image/binary
lui = louie(g, include_reasoning=True)                        # notebook factory

Reading the result

r = client.add_cell(thread_id, "Which customers churned?", include_reasoning=True)

r.final_text          # str | None   — the answer, and what .text tracks
r.reasoning_text      # str | None   — provisional draft, only when opted in
r.status              # str          — "succeeded" | "failed" | "running" | "unknown"
r.succeeded           # bool | None
r.terminal_error      # str | None   — stream-level failure, distinct from ExceptionElements
r.phases              # list[dict]   — progress steps
r.trace_events        # list         — server-emitted traces (not W3C request tracing)

Plural and element-level forms exist alongside each: final_texts, final_text_elements, final_text_element, final_answer_id, reasoning_texts, reasoning_elements, run_nodes, root_run, run_updates, phase_updates, token_flow, terminals, terminal.

The same surface is on the notebook cursor, so lui.reasoning_text, lui.status, lui.phases work identically.

Why .text is unchanged

.text stays final-answer-oriented. Reasoning is reachable only through the explicit accessors, so turning on include_reasoning cannot leak drafts into the common path:

lui = louie(g, include_reasoning=True)
lui("Analyze churn")

lui.text            # final answer only — same as before
lui.reasoning_text  # the draft, explicitly asked for

Compatibility

Additive. Regression tests cover .text, .df, the callable form, positional constructor args, legacy and concatenated JSONL, and responses with no reasoning at all. Classification is conservative: with include_reasoning=False the parser preserves historical multi-text behaviour rather than guessing which element was "final".

Review focus

  • src/louieai/_client.py — the parser is the substantive change; the accessors are thin views over it.
  • src/louieai/notebook/cursor.py — .text / reasoning separation.
  • src/louieai/notebook/_html.py — escaping and URL validation for server-controlled render content.

Docs

Rendered pages this PR edits (links are current latest, i.e. pre-merge — this project has no RTD PR preview build, so they do not yet show these changes):

To review the new copy before merge, read the docs/ diff, or uv run --locked mkdocs serve.

Validation

CI-equivalent scope, lockfile toolchain (ruff 0.12.5 / mypy 1.17.0):

  • unit: 599 passed, 5 skipped, 87.03% coverage against the 85% gate
  • integration with credentials blanked: 30 passed, 26 skipped, no outbound request
  • ruff check ., ruff format --check ., mypy ., uv lock --check, secret detection, strict MkDocs, doc tests: pass

Notes

  • Rebased onto main after security: make the secret-detection gates actually reject #45; this PR is reasoning-API only.
  • Integration fixtures route through the shared fail-closed real_client, replacing four local fixtures that each re-implemented auth.
  • The deployed reasoning-contract smoke test is credential-gated and skips by default; it has not been run against a live endpoint from CI.
  • Unrelated, worth a follow-up: pyproject.toml advertises https://louieai.readthedocs.io, which 404s. The real site is louie-py.readthedocs.io, so the PyPI "Documentation" link is broken.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MyiG851jxkDkqB5u9gnpox

@lmeyerov
lmeyerov force-pushed the feat/skills-fastapi-reasoning branch from f694728 to 6754c52 Compare July 25, 2026 03:18
@lmeyerov lmeyerov changed the title feat: add agent skills and reasoning stream support feat: add agent skills and reasoning-aware response API Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

drop older ai/prompts/ in favor of these

@lmeyerov
lmeyerov force-pushed the feat/skills-fastapi-reasoning branch from 88181e4 to 229f20a Compare July 25, 2026 21:44
@lmeyerov lmeyerov changed the title feat: add agent skills and reasoning-aware response API feat: reasoning-aware response API Jul 25, 2026
@lmeyerov

Copy link
Copy Markdown
Contributor Author

Follow-up filed: #46 — exposing a streaming/iterator API for reasoning and phase events, plus the accumulator unification it depends on. Out of scope here; this PR's accessors are read after completion.

@lmeyerov
lmeyerov merged commit d0eedbd into main Jul 25, 2026
19 checks passed
@lmeyerov
lmeyerov deleted the feat/skills-fastapi-reasoning branch July 25, 2026 23:17
lmeyerov added a commit that referenced this pull request Jul 26, 2026
Consolidates the two [Unreleased] sections (from #44 and #47) into one version
heading, and adds the security and internal entries for #45, which landed
without a changelog entry.

0.9.0 rather than 0.8.2: the release carries a breaking change to Response.text,
the most-used accessor.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant