Skip to content

fix(copilot): cap tool calls per turn and widen the openai pin - #843

Merged
yeasy merged 4 commits into
hyperledger-cello:mainfrom
agamatlab:fix/copilot-review-followups
Oct 22, 2026
Merged

yeasy merged 4 commits into
hyperledger-cello:mainfrom
agamatlab:fix/copilot-review-followups

Conversation

@agamatlab

Copy link
Copy Markdown
Contributor

Follow-ups 2 and 3 from @yeasy's review on #837. Item 4 adds a route so it is
separate, and item 1 is waiting on the question I asked there.

Tool call cap

max_iterations counts model rounds. One round can ask for any number of
tools, so the rounds cap on its own does not bound how much work a turn does.
Eight rounds of five parallel calls is forty REST requests against a cap that
says eight.

CELLO_COPILOT_MAX_TOOL_CALLS bounds the calls themselves, default 16. The
check runs before a call rather than after, so the cap is the number executed.

Hitting it ends the turn with stop_reason: max_tool_calls. That is a new value
in the set the done frame can carry, so I have added it to the contract in
#813. @Pranav-d33 it is additive and the reply text still arrives normally, so
the panel needs no change, but worth knowing it exists.

Ending the turn is deliberate rather than skipping the rest of the round. A
provider rejects a follow-up request whose assistant message contains tool calls
with no reply for each one. Ending means no follow-up request happens, so the
conversation never goes inconsistent.

openai pin

openai==1.99.9 becomes openai>=1.55.3,<2 so dependabot can take minor bumps.

The floor stays and is still load bearing: earlier releases pass proxies= to
httpx.Client, which httpx 0.28 removed, so building a client raises
TypeError.

One thing worth flagging. openai is on 3.x now, so <2 holds us on the 1.x line
rather than just guarding against one future major. I kept it because nobody has
checked the 2.x or 3.x client surface against this code, and a silent major bump
in a dependabot PR is the wrong place to find out. Happy to raise the ceiling in
its own PR if you would rather, since that wants a real test run.

Testing

37 tests pass locally, two of them new: one drives rounds of three parallel
calls against a cap of four and asserts four ran and the turn ended with
max_tool_calls, the other checks a turn under the cap is untouched.

Docker will not start on my machine at the moment, so the endpoint tests ran
against a minimal Django config rather than the real project settings. CI runs
them properly.

I also pinned my local openai to the allowed range before testing, so the run
reflects what CI installs rather than whatever was already there.

Two follow-ups from the review on hyperledger-cello#837.

max_iterations counts model rounds, not work. A single round can ask for any
number of tools, so the rounds cap on its own does not bound how much a turn
does. CELLO_COPILOT_MAX_TOOL_CALLS bounds the calls themselves, defaulting to
16. The check runs before a call rather than after, so the cap is the number
executed. Hitting it ends the turn with stop_reason max_tool_calls, which is a
new value in the set the done frame may carry.

The turn has to end there rather than skip the remaining calls: a provider
rejects a follow-up request whose assistant message has tool calls without a
reply for each one. Ending means no follow-up request is made, so the
conversation stays consistent.

openai was pinned exactly at 1.99.9. Widened to >=1.55.3,<2 so dependabot can
take minor bumps. The floor is unchanged and still load bearing, since earlier
releases pass proxies= to httpx.Client, which httpx 0.28 removed. Worth knowing
that openai is now on 3.x, so the ceiling holds us on the 1.x line until someone
checks the newer client surface against this code.

Signed-off-by: Aghamatlab Akbarzade <icloudakberzade@gmail.com>
@agamatlab
agamatlab requested a review from a team as a code owner September 30, 2026 09:03
@agamatlab

Copy link
Copy Markdown
Contributor Author

build and test are red here, but the cause is on main.

requirements.txt pins cryptography==50.0.0 (dependabot, 30ec468). That
release requires Python 3.9 or newer. src/api-engine/Dockerfile is still
FROM python:3.8, so pip in the image never sees it and stops at 47.0.0, which
is the last release supporting 3.8. This branch does not touch that line.

Any PR that rebuilds api-engine will fail the same way. #842 migrates
api-engine to 3.11 and fixes it at the source, but its checks are still sitting
at action_required. If that needs more time, pinning back to 47.0.0 unblocks
main in the meantime.

@yeasy yeasy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, thanks for following up on #837. The cap is checked before each call, so it bounds what actually runs, and ending the turn there keeps the conversation consistent. The two new tests cover both sides.

One non-blocking note on the openai pin: I don't see a .github/dependabot.yml, so dependabot only opens security updates here. Moving to >=1.55.3,<2 mostly means each image build picks up whatever the latest 1.x is, and builds are no longer reproducible. I'd lean toward keeping an exact pin (bumped to the latest 1.x) and opening a separate issue to evaluate moving to 3.x with a real test run, as you suggested. Happy to take that in a follow-up rather than block this PR.

@yeasy
yeasy merged commit 49918a4 into hyperledger-cello:main Oct 22, 2026
4 checks passed
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.

3 participants