Skip to content

refactor(adapter): let workers own protocol-specific prompt notes (#186) - #285

Open
Prithvi1994 wants to merge 1 commit into
exoharness:mainfrom
Prithvi1994:fix/186-adapter-prompt-notes
Open

Prithvi1994 wants to merge 1 commit into
exoharness:mainfrom
Prithvi1994:fix/186-adapter-prompt-notes

Conversation

@Prithvi1994

Copy link
Copy Markdown
Contributor

Closes #186

Problem

compose_inbound_wakeup_prompt in the host branched on adapter_type == "slack" and rendered Slack guidance from two metadata keys (dmTarget, isActiveThread) that the Slack worker invents. That put protocol-specific behavior in the host and coupled it to the worker through untyped string keys across a Rust/TypeScript boundary — against the rule in exo/docs/tools-and-adapters.md:

The host owns supervision, routing, durable message records, retries, and conversation wakeups. Protocol-specific behavior stays in each worker.

Fix

metadata is already free-form JSON the worker fully controls, so the guidance travels in it:

  • Host (crates/executor/src/adapter/runtime.rs): the adapter_type == "slack" block is replaced by a generic loop that appends every string in metadata.promptNotes, in array order, and treats all protocol-specific metadata keys as opaque.
  • Slack worker (exo/adapters/slack/worker.ts): emits the same DM-target and active-thread guidance as promptNotes. Wording and order are unchanged, so Slack wakeup prompts are identical to before.
  • Docs (exo/docs/design/adapter-architecture.md): the Worker Protocol section documents the metadata.promptNotes contract.

The worker keeps emitting dmTarget / isActiveThread — they are legitimate facts it owns, and dmTarget still builds the note. Only the host's interpretation of them is removed.

Adding another adapter's guidance is now a worker-only change: no host edit, no new if adapter_type == … arm.

Verification

  • cargo test -p executor: 117 passed, 0 failed
  • cargo fmt --all -- --check and cargo clippy --workspace --all-targets -- -D warnings: clean
  • pnpm check (oxfmt, oxlint, tsgo, vitest): passes

New tests:

  • wakeup_prompt_appends_worker_prompt_notes_in_order
  • wakeup_prompt_ignores_metadata_keys_the_host_does_not_own — regression guard: dmTarget / isActiveThread alone produce no host-authored text
  • wakeup_prompt_ignores_non_string_prompt_notes
  • wakeup_prompt_tolerates_missing_or_non_array_prompt_notes

Note

No TS unit test for the Slack worker: it performs a live slackAuthTest() at module import, so it is not unit-testable without refactoring (unlike Discord's pure helpers). Typecheck/lint cover the change.

Related, not addressed here

crates/executor/src/adapter/tools.rs still has a Slack-specific dm: target validation branch. #186 lists it as an instance of the same pattern but not the subject of the issue.

…oharness#186)

compose_inbound_wakeup_prompt branched on adapter_type == "slack" and
rendered Slack guidance from the worker-invented metadata keys
`dmTarget` and `isActiveThread`, putting protocol-specific behavior in
the host across a Rust/TypeScript boundary.

The host now appends any strings the worker supplies in
`metadata.promptNotes`, in order, and treats protocol metadata keys as
opaque. The Slack worker emits the same guidance it used to trigger, so
Slack wakeup prompts are unchanged while the host no longer knows what
Slack is.

Refs exoharness#186.
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.

Slack-specific prompt logic leaks into the adapter host runtime

1 participant