文件历史

提交图

6 次代码提交

作者 SHA1 备注 提交日期
Simon Willison 842ab2a93f response.messages is a method, matching .text() / .json() / .tool_calls()
Sync: response.messages() forces execution if not drained, so callers
no longer have to remember to call .text() first. Async: `await
response.messages()` awaits the force.

Internal sync paths (_response_to_dict, _chain_for_tool_results,
_build_full_chain, Response.reply, AsyncResponse.reply) use a new
private _messages_now() helper that assumes the response is already
drained, so they don't have to await on async responses.

Drops the now-obsolete "accessing .messages on un-awaited
AsyncResponse raises" parity test — that constraint goes away with
the method form.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 14:04:35 -07:00
Simon Willison f3a0962162 response.reply() auto-executes pending tool calls
Zero-arg sugar: when a response made tool calls and tool_results= is
not passed, reply() runs self.execute_tool_calls() and threads the
results into the next turn. Pass tool_results= explicitly to skip
the auto-execute path (e.g. for mutated or synthetic results). Also
forwards self.prompt.tools to the next turn so the model can call
the same tools again, mirroring Conversation.prompt's tools-or-self
rule.

AsyncResponse.reply() is now an awaitable coroutine — `await
response.reply(...)` — so the auto-execute path can `await
self.execute_tool_calls()` internally. This is a non-shipped API
break: existing async-reply callers in the test suite updated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 13:51:13 -07:00
Simon Willison de63d8b69e Fixes for ruff 2026-04-22 10:13:39 -07:00
Simon Willison 211e678e07 Cleaned up tests and comments
Removed all mentions of 'phase'
2026-04-22 08:43:33 -07:00
Simon Willison 65b8e37c79 Ran Black 2026-04-21 21:10:13 -07:00
Simon Willison 82b844d7dd Async parity: pin sync/async equivalence for all Phase 1-7 APIs
New tests/test_async_parity.py (18 tests) exercises every new API on
the async path via llm-echo (+ async_mock_model where relevant):

  - AsyncResponse.to_dict() captures chain, output, datetime_utc
  - AsyncResponse.to_dict() raises before await (guard parity)
  - AsyncResponse.from_dict() rehydrates and matches original
  - AsyncResponse.from_dict() + reply() continues correctly
  - model= override on AsyncResponse.from_dict
  - AsyncResponse.from_row fallback (SQLite rehydrate) populates
    response.messages from _chunks so llm -c --async preserves the
    assistant turn
  - load_conversation(async_=True).prompt(...) builds full chain
  - AsyncConversation.chain tool-result turn pre-bakes chain
  - astream_events matches stream_events for text-only output
  - reply chains across 3 async turns
  - Full three-turn save→restore→reply loop under async
  - reply(messages=[...]) kwarg appends to async chain
  - response.messages raises on un-awaited AsyncResponse
  - usage round-trips through async to_dict/from_dict
  - sync/async structurally identical output for same prompts

Plus one test asserting Echo + EchoAsync are both registered.

The tests all passed on first run — Phase 7 async implementation was
already correct. These pin the invariants against future regressions.

620 tests pass (602 before + 18 new).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 09:06:14 -07:00