Skip to content

Move the instruction a coworker actually follows when somebody edits it - #32

Merged
jerelvelarde merged 1 commit into
mainfrom
jerel/edit-runs-here-fix
Sep 2, 2026
Merged

Move the instruction a coworker actually follows when somebody edits it#32
jerelvelarde merged 1 commit into
mainfrom
jerel/edit-runs-here-fix

Conversation

@jerelvelarde

Copy link
Copy Markdown
Owner

The problem

A coworker with no address runs on configuration.systemPrompt and on nothing else.
registeredAgentFromRow gives a built_in agent that column and no standing role message, so
agentProfiles.roleDescription — the field every screen shows and the edit form writes — never
reaches it.

create writes both. update wrote only the profile.

So editing such a coworker's role description changed everything a person can see and nothing the Bot
follows. The edit reports success, the new text is there when you come back, and the coworker goes on
answering from the instruction it was made with, permanently, with nothing anywhere to say so. It is
the same shape as the endpoint bug the comment directly above this code already warns about —
"the screen reported success and the Bot kept answering at the old address" — arriving through the
other field.

This is live, not theoretical. Production has no MANAGED_AGENT_AG_UI_URL, so every coworker
created without an address takes the built_in branch. Since #31
that is most of them: every coworker the bot-creator card makes is endpoint-less by design.

The approach

update carries the role description into configuration.systemPrompt for built_in rows, and only
those.

Only built_in, and the two exclusions are the point. A remote Bot must not acquire a prompt it
never had — its instruction travels as the standing role message built from the profile, so a
systemPrompt in its configuration would be a second source for the same thing, and the one the
runtime prefers if that row's type ever changed. And the tenant package's own Bots, whose
system_prompt is deliberately not their role_description (General Assistant carries "You are a
helpful general assistant…" against a role of "Help with everyday work…"), cannot reach update at
all: requireManageable throws ProtectedAgentError for anything the package owns. I checked that
before writing the condition, because a blanket sync would have overwritten those.

What is not covered

  • Coworkers already edited before this keep the divergence: their profile says one thing and
    their prompt another, and nothing here reconciles the two retrospectively. A person can restore it
    by saving the role description once more, and that now takes effect. Not backfilled, because
    guessing which of the two texts somebody meant is not a migration's decision to make.
  • No screen says which text is live. With the two now kept in step there is nothing to disclose,
    but that is a property of this code being right rather than something the UI would notice if it
    regressed. The tests are what hold it.

Verification

format:check, lint and typecheck clean. 2897 pass, 23 skip, 0 fail across 228 files.

Test What it holds down
an edit moves the instruction a coworker that runs here actually follows Create endpoint-less, edit the role, and assert both configuration.systemPrompt and the profile carry the new text
an edit never gives a coworker at its own address a system prompt Edit a coworker with an endpoint and assert no systemPrompt appears in its configuration

Both are integration tests against a real database rather than unit tests over the merge, because the
bug was in what got written and a test over the object would have agreed with it.

One note on running the suite locally: a database migrated from a branch without the Slack migrations
reports 47 failures in the external-link and external-thread stores that have nothing to do with this
change. They reproduce identically on a clean main. Migrate a database on this branch before
believing a failure in those files.

Merge notes

The same hunk is in CopilotKit/OpenBot#331, which
carries the create half and this update half together for upstream. Nothing else here overlaps, and
there is no migration.

A coworker with no address runs on `configuration.systemPrompt` and on
nothing else: `registeredAgentFromRow` gives a `built_in` agent that
column and no standing role message, so `agentProfiles.roleDescription`
never reaches it. `create` writes both. `update` wrote only the profile.

So editing such a coworker's role description changed every screen and
nothing the Bot follows. The edit reported success, the text was there
when you came back, and the coworker went on answering from the
instruction it was made with — permanently, with nothing anywhere to say
so. It is the same shape as the endpoint bug the comment above this code
already warns about, arriving through the other field.

Live rather than theoretical: production runs with no managed Bot, so
every coworker created without an address takes the `built_in` branch —
which since the bot-creator shipped is most of them, because every
coworker that card makes is endpoint-less.

`update` now carries the role description into the prompt for `built_in`
rows and only those. A remote Bot must not acquire a prompt it never had:
its instruction travels as the standing role message, and a `systemPrompt`
in its configuration would be a second source for the same thing — and
the one the runtime prefers if that row's type ever changed. The tenant
package's own Bots, whose `system_prompt` is deliberately not their
`role_description`, cannot reach `update` at all, because
`requireManageable` throws `ProtectedAgentError` for anything the package
owns.

Verification: 2897 pass, 23 skip, 0 fail across 228 files; format, lint
and typecheck clean. Two integration tests, because the pair can only
drift silently — one that an edit moves the prompt a coworker running
here follows, one that a coworker at its own address never acquires one.
@jerelvelarde
jerelvelarde merged commit 753ca2e into main Sep 2, 2026
13 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.

1 participant