Skip to content

Offer coordination tools only to a run that may call them - #731

Open
Chebaleomkar wants to merge 1 commit into
CopilotKit:mainfrom
Chebaleomkar:fix/coordination-tools-offered-only-when-callable
Open

Chebaleomkar wants to merge 1 commit into
CopilotKit:mainfrom
Chebaleomkar:fix/coordination-tools-offered-only-when-callable

Conversation

@Chebaleomkar

Copy link
Copy Markdown
Contributor

What this changes

Fixes #716. A group peer turn runs at depth 1 with no handoff claim, so authoriseCoordinationRun refuses every ask_person and message_bot call from it. toolsForRun still offered both, so the Bot was shown tools that always failed and each attempt wrote an mcp.callback_refused row.

toolsForRun now asks the same authoriseRun that call uses and offers nothing when a call would be refused. This is option 2 from the issue, as @kvnloo recommended there. call keeps its own check, so a stale schema is still refused and audited. Because the tool list and the refusal use one function, they can't drift apart.

Where it runs

  • New state that outlives a request? None. toolsForRun now does the same Postgres reads call already did (person, Bot profile, source thread, handoff lease), once when the run's tools are chosen.
  • What happens on the second replica? The same: authority is read from Postgres, not held in process.
  • Anything serialised? No new writes.
  • Anything fanned out to a browser? No.
  • New listener, port, or schedule? None.

Boundary and audit

  • Every acting call still goes through the gateway: resolve, decide, audit, then act. call is unchanged.
  • New refusals and new failures each write a row. There are no new refusals; this removes refusals nobody caused.
  • Nothing new is trusted from the client that the server can resolve itself.

Changelog

  • A line in CHANGELOG.md under Unreleased.

Proof

server/tests/remote-coordination.test.ts adds:

  • a run that may not coordinate is offered no tools;
  • every tool offered to a run is callable by it, checked against the real authoriseCoordinationRun for a leased delivery, a direct run, and a group peer turn (depth 1, no claim). The peer-turn case failed before the change (offered message_bot and ask_person, both refused) and passes after it.

Run locally on Windows with Bun 1.4.2 (CI pins 1.3.14), against pgvector/pgvector:pg17 with migrations applied:

  • bun run format:check, bun run lint, bun run typecheck: pass.
  • bun test --timeout 60000 server/tests: 4096 pass, 5 skip, 7 fail. All 7 are in learning-langgraph, learning-mastra, provider-oauth, tenant-package and production-loader-boundary. The first six fail identically on main (they need the per-Bot installs CI does, or POSIX symlink/inode behaviour). production-loader-boundary hit the 5 s limit once and passed when rerun on both main and this branch.
  • The group-conversation integration tests need --timeout 60000 on this machine: with the 5 s default, 9 of 15 time out on main and on this branch alike. With it, all 15 pass.

A group peer turn runs at depth 1 with no handoff claim, so
authoriseCoordinationRun refuses every ask_person and message_bot
call from it, yet toolsForRun still offered both. toolsForRun now
asks the same authoriseRun first and offers nothing when a call
would be refused. call() keeps its own check for stale schemas.

Fixes CopilotKit#716

This branch has not been deployed

No deployments
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.

Group peer turns are offered ask_person and message_bot, but every call is refused

1 participant