Skip to content

Edit a built-in coworker without sending the managed Bot's address back as a typed endpoint - #579

Open
kevin9327 wants to merge 1 commit into
CopilotKit:mainfrom
kevin9327:edit-built-in-coworker
Open

kevin9327 wants to merge 1 commit into
CopilotKit:mainfrom
kevin9327:edit-built-in-coworker

Conversation

@kevin9327

Copy link
Copy Markdown
Contributor

What this changes

On a deployment with a managed Bot, a coworker created as Built in is stored as remote_ag_ui pointing at that Bot's address (profile-store.ts create). The profile publishes the address, and since builtIn was added it also publishes the flag, so a screen can tell the address was never typed by anyone. The Connection section already uses it: "an internal address they never typed".

The General section does not use it. Each in-place edit (Name, Title, Role, Visibility) calls save, which rebuilds the whole input with endpoint: profile.endpoint ?? "". So for a built-in coworker, PATCH /api/agents/:id receives the managed Bot's address, and parseAgentInput runs it through checkAgentEndpoint exactly as if a person had typed it.

The README's quick start is bash scripts/start.sh, which sets MANAGED_AGENT_AG_UI_URL=http://localhost:4201/ag-ui. Private hosts are closed unless AGENT_COMPUTER_ALLOW_PRIVATE_HOSTS=true, so that check refuses the address. Every edit of every built-in coworker fails, and this appears under the field:

That address is inside this deployment's own network, so an agent may not live there.

The same happens on any deployment whose managed Bot is at a literal private address not named in AGENT_ENDPOINT_ALLOWED_HOSTS. The desktop app is not affected because it opens private hosts. A cluster DNS name is not affected because it passes the static check.

The fix is one line in GeneralSection: a built-in coworker sends an empty endpoint. The route already reads empty as "leave the stored one": parseAgentInput skips "", and store.update spreads previous and overrides endpoint only when one is given. So:

  • the managed address stays exactly where it is stored;
  • the bot.updated row stops naming the managed address as an endpoint on every rename. That field exists because "repointing the endpoint is the dangerous edit and is worth naming".

A coworker somebody hosts still sends its own endpoint. That is what the endpointOf comment in the store needs, so an edit never reverts an external agent to the built-in one, and the second test pins it.

The server's endpoint check is untouched, and so is the design question in #399 about how a built-in coworker is stored.

Where it runs

  • New state that outlives a request? None.
  • What happens on the second replica? The same. This is the body the browser sends.
  • Anything serialised? No.
  • Anything fanned out to a browser? No.
  • New listener, port, or schedule? No.

Boundary and audit

  • Every acting call still goes through the gateway: resolve, decide, audit, then act. Unchanged.
  • New refusals and new failures each write a row. None are added.
  • Nothing new is trusted from the client that the server can resolve itself. The client now sends less. The endpoint check still applies to any endpoint that is sent.

Changelog

  • A line in CHANGELOG.md under Unreleased.

Proof

New app/tests/agent-dialog-built-in-edit.test.tsx. It draws the real AgentDialog and answers fetch with the server's real createAgentRoutes, the way agent-api-path.test.ts mounts them. Private hosts are closed and managedEndpoint is http://localhost:4201/ag-ui, as scripts/start.sh sets it. A fake store records what the route asked it to update. Each test renames the coworker with userEvent: Edit name, type, Save.

On main (only the test file added):

error: expect(received).toBeNull()
Received: "That address is inside this deployment's own network, so an agent may not live there."
(fail) a built-in coworker can be renamed on a deployment whose own Bot lives on localhost

 1 pass
 1 fail

The passing case is the pin: a coworker hosted at https://agents.example.test/ag-ui is renamed and still sends that endpoint.

With the fix:

  • bun test app/tests/agent-dialog-built-in-edit.test.tsx app/tests/agent-api-path.test.ts: 9 pass, 0 fail. The built-in rename reaches store.update with name: "Receipts" and no endpoint, with no alert. The hosted rename still carries its endpoint.
  • bun test app/: 852 pass, 29 fail. On main it is 850 pass with the same 29 failures, all from this Windows machine: serve.test.ts port and websocket cases, Windows path separators, and a relative-time assertion reading a Korean locale.
  • bun run typecheck (app, server, worker): exit 0.
  • bunx biome check on the changed files: clean.

The changed line runs both ways, built-in and hosted, in the two tests.

This PR adds its line at the top of ## Unreleased, the same place other open PRs add theirs, so the changelog may conflict. I'm happy to rebase.

🤖 Generated with Claude Code

…ck as a typed endpoint

A coworker created as Built in on a deployment with a managed Bot is
stored pointing at that Bot's address, and the profile publishes it with
`builtIn` beside it. The Connection section reads the flag and does not
show an address nobody typed. The General section did not. Every
in-place edit (name, title, role, visibility) sent the whole profile
back, endpoint included, and `parseAgentInput` checks an endpoint it is
sent exactly as it checks a person's.

`scripts/start.sh` sets `MANAGED_AGENT_AG_UI_URL` to
`http://localhost:4201/ag-ui`, and with private hosts closed that check
refuses it, so every edit of a built-in coworker failed with "That
address is inside this deployment's own network, so an agent may not
live there."

The General section now sends an empty endpoint for a built-in
coworker. The update route already reads empty as "leave the stored
one", so the managed address stays where it is and the `bot.updated`
row no longer names it as though it had been repointed. A coworker
somebody hosts still sends its own endpoint, so an edit never reverts
it to the built-in one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

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