Repository navigation
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## trunk #273 +/- ##
============================================
+ Coverage 86.58% 86.86% +0.27%
- Complexity 1383 1429 +46
============================================
Files 69 70 +1
Lines 4449 4574 +125
============================================
+ Hits 3852 3973 +121
- Misses 597 601 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds first-class support in PromptBuilder for (1) appending messages to an existing conversation and (2) automatically resolving model-requested function calls via a bounded multi-round loop, returning loop metadata in the final result’s additional data.
Changes:
- Add
PromptBuilder::withMessages()to append fullMessageinstances (counterpart towithHistory()which prepends). - Introduce
FunctionCallResolverInterfaceand integrate an optional function call resolution loop into text generation, including token-usage aggregation and transcript exposure. - Add comprehensive unit tests plus supporting mocks/helpers for scripted multi-round text generation.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/Builders/PromptBuilder.php |
Adds withMessages(), resolver configuration, and the multi-round function call resolution loop with transcript + token aggregation. |
src/Tools/Contracts/FunctionCallResolverInterface.php |
Defines the resolver extension point (canResolve() + resolve()) used by the loop. |
tests/unit/Builders/PromptBuilderFunctionCallResolutionTest.php |
Covers loop behavior (happy path, transcript ordering, unresolved calls, max iterations, token aggregation, non-text capabilities) and withMessages() ordering. |
tests/traits/MockModelCreationTrait.php |
Adds a scripted text-generation mock model helper to simulate multi-round responses deterministically. |
tests/mocks/MockFunctionCallResolver.php |
Adds a mock resolver that records checked/resolved calls and can be customized via callbacks. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
6fcc530 to
1d0f4df
Compare
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
There was a problem hiding this comment.
🟡 Changes recommended
Thought-token aggregation must preserve unknown usage instead of reporting a misleading partial total.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 11/11 changed files
- Comments generated: 1
- Review effort level: Balanced
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
02b40a5 to
9663ef4
Compare
Fixes #272.
Adds a bounded function call loop to
PromptBuilderandwithMessages()for callers that want to manage the conversation themselves.Use
generateTextResult()to inspect calls when the loop stops early.generateText()throws if the final response has no text.Design
PromptBuilderhandles configuration, model selection, and lifecycle events. An internalFunctionCallRunnerhandles the loop. The public extension point is:canResolve()must have no side effects. The runner checks all calls before executing any. If one is unsupported, none in that round execute. Supported calls run sequentially. Each response must match its call by ID, or by name when no ID is present. Any response name must also match.withMessages()appends complete messages.withHistory()continues to prepend them.Behavior
toolCallsfinish reason and a non-empty name. The default limit allows five tool rounds, plus the initial model request.BeforeGenerateResultEventandAfterGenerateResultEvent. There is no extra event for the aggregate result.functionCallResolutiondata containsrounds,stopReason,resolvedCalls, and the conversation inmessages.Errors and retries
Checking support does not make a batch atomic. A later tool or model request can fail after earlier tools have run.
Exceptions stop the loop and pass to the caller. Completed tools are not rolled back. The SDK does not retry tools or return partial progress after an exception. Retrying the original prompt can repeat actions, so applications that need recovery must record tool outcomes and manage retries. Resolvers can return expected execution errors in a
FunctionResponseso the model can handle them.Provider compatibility
The shared OpenAI-compatible serializer now expands multiple function responses into separate
toolmessages. It rejects malformed JSON arguments instead of turning them intonulland allowing execution.The official OpenAI provider uses the Responses API and needs a separate fix. It must combine parallel output items into one candidate, preserve incomplete response status, emit each call and response as a top-level input item, and reject malformed JSON arguments. That provider change is not included here.
Scope
This supports the WordPress ability resolution work in Trac #64865 and wordpress-develop #12658. WordPress can supply a resolver for registered abilities instead of managing follow-up requests through lifecycle events. Tool execution stays under the caller's control. Persistent execution state and automatic recovery are outside this PR.
Validation
composer test:unit: 1,232 tests and 4,507 assertions passed after rebasing onto trunk.composer phpcs: passed.composer phpstan -- --debug: passed. Debug mode avoids the local sandbox's socket restriction.git diff --check origin/trunk...HEAD: passed.Tests cover multiple calls and rounds, stop conditions, malformed arguments, response matching, exceptions, token usage, event order, builder reuse, model discovery, and message ordering. Scripted test models reject unexpected requests unless repeating is explicitly enabled. No live provider API calls were made.
AI assistance
Claude Code and Codex assisted with implementation, review, tests, documentation, and this description.