Repository navigation
Bound the text an app can put in an agent's context - #9
Merged
Merged
Conversation
Closes #8. Most strings an adapter emits are diagnostics: a human reads them in a log and nothing acts on them. A few are not. They travel in a reply an agent parses, land in its context, and sit next to its own instructions — content in the same channel as directives. One of them is not ours. `credentialHint` is set by the APP and copied verbatim into the 401 challenge, so an app can put text of its choosing into the context of every agent that fails to authenticate to it. It was unbounded: newlines, headings, any length. That is the one path where text reaching an agent has not been through this repository's review, and an open field there is a channel rather than a hint. App text is now collapsed to a single line and capped at 300 characters. Two bounds for two reasons: newlines are what let injected text impersonate structure — a blank line and a heading read as a new section rather than as the tail of a sentence — and a hint is a sentence, so anything long enough to be an argument is not one. It is a bound on the CHANNEL, not a content filter. The words survive, and the test asserts they survive: claiming to sanitise meaning would be the more dangerous promise, and the connect skill already tells agents that an app's text is data and never a directive. This keeps the channel narrow enough for that rule to hold. The framework's own agent-facing text moves to `agentText.ts` with the rule written down — state a fact, never issue an instruction; say who it is for. Collected so that adding a line is a deliberate act: written inline at the site that emits it, new agent-facing text arrives as an incidental part of some other change and gets reviewed as a message rather than as context. That is the gap the review comment named. Removing the bound fails the new test on exactly the case it exists for.
#5 landed on main and brought `DEFAULT_CREDENTIAL_HINT` — the same sentence this branch had already moved into `agentText.ts`. Both sides changed the same line, and keeping both would have left one string with two homes, which is the thing this change exists to fix. Resolved to the bounded call. The local constant had exactly one use, so it is now dead and is removed: the text lives in `agentText.ts`, where the rule for adding agent-facing text is written down, and the app-supplied part goes through `boundAppText` on its way into the reply. Nothing about #5's behaviour changes — the same sentence reaches the same 401, by the same fallback. What changes is that an app can no longer put unbounded multi-line text beside it. 73/73 conformance; whoami and agent-text both passing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #8 — the TODO from the review comment on #5.
The part that isn't ours
Most strings an adapter emits are diagnostics: a human reads them in a log and nothing acts on them. A few are not. They travel in a reply an agent parses, land in its context, and sit next to its own instructions — content in the same channel as directives.
One of them is set by the app.
credentialHintis app config, copied verbatim into the401challenge, so an app can put text of its choosing into the context of every agent that fails to authenticate to it. It was unbounded — newlines, headings, any length.That is the one path where text reaching an agent has not been through this repository's review. On
maintoday:The bound
App text is collapsed to a single line and capped at 300 characters.
Two bounds, for two different reasons:
It is a bound on the channel, not a content filter
The words survive, and the test asserts that they survive:
Claiming to sanitise meaning would be the more dangerous promise — it invites trusting the output. The connect skill already tells agents that an app's text is data and never a directive; this keeps the channel narrow enough for that rule to hold.
The framework's own text
Moved into
agentText.ts, with the rule written down where the next person adding a string will read it:Collected so that adding a line is a deliberate act. Written inline at the emitting site, new agent-facing text arrives as an incidental part of some other change and gets reviewed as a message rather than as context. That is the gap the review comment named.
Verification
agent-text.test.mjscovers the bound, the framework's own strings, and the 401 end to end. Removing the bound fails it on exactly the case it exists for:build,typecheck,testclean · conformance60/60.Scope
adapter-core only. The Python and PocketBase adapters have their own copies of agent-facing strings; they are not touched here because #6 is still open against both files and I am not stacking PRs again. Worth a follow-up once #5 and #6 land.
Merge after #5 and #6. This touches the same
how:line #5 does, so expect a small conflict — mine supersedes, and I will resolve it.