Skip to content

feat(team): dynamic agent type list + fix warmup race skipping preset_context#208

Merged
zhuqingyv merged 3 commits into
mainfrom
fix/team-agent-type-list-v2
May 11, 2026
Merged

feat(team): dynamic agent type list + fix warmup race skipping preset_context#208
zhuqingyv merged 3 commits into
mainfrom
fix/team-agent-type-list-v2

Conversation

@zhuqingyv

@zhuqingyv zhuqingyv commented May 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Dynamic agent type list for team sessions based on ACP MCP capabilities
  • Add team_capable computed field to AgentMetadata response
  • Fix critical bug: warmup race condition caused preset_context (team guide prompt) to never be injected into the first user message

Bug Fix Detail

PR #207 introduced eager session opening via warmup_session(). When warmup and the first message arrived concurrently, warmup marked the session as opened before ensure_session_and_send() checked is_brand_new, causing it to skip preset_context injection entirely. The solo agent never received the team guide prompt, so it skipped the "recommend lineup → wait for confirmation" flow and directly called aion_create_team.

Fix: Replace the racy is_brand_new check with a dedicated needs_first_message_injection flag on AcpSession that is consumed exactly once by the first real prompt, independent of session open state.

Test plan

  • cargo nextest run --workspace — 5432 passed
  • cargo clippy --workspace -- -D warnings — clean
  • cargo fmt --all -- --check — clean
  • Manual: new solo conversation with Claude → send "创建成员进来吵架" → verify agent proposes lineup before creating team

🤖 Generated with Claude Code

zhuqingyu-netizen and others added 2 commits May 10, 2026 18:45
Align with old TS architecture: hard whitelist (claude/codex/gemini/aionrs/codebuddy)
always passes, non-whitelisted agents dynamically qualify by having MCP capabilities
persisted from ACP handshake. Centralizes TEAM_CAPABLE_BACKENDS in aionui-common,
eliminating 3 duplicated copies and the manual sync requirement.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Expose team eligibility as a boolean on `/api/agents` so the frontend can
filter team-capable agents without hardcoding a whitelist or parsing
agent_capabilities JSON. Computed at hydrate time from hard whitelist +
persisted MCP capability declarations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@zhuqingyv zhuqingyv force-pushed the fix/team-agent-type-list-v2 branch from 9c183f5 to 5c55ff5 Compare May 10, 2026 10:50
…tion

The first-message injection (team guide prompt, skill index) was gated on
`is_brand_new` which checked `session_id.is_none() && !is_opened()`.
When warmup and messages arrived concurrently, warmup could mark the
session as opened before messages checked the flag, causing the preset
context to never be injected into the first user prompt.

Replace the racy check with a dedicated `needs_first_message_injection`
flag on AcpSession that is consumed exactly once by the first real
prompt, independent of session open state. Resumed sessions (restored
session_id from DB) consume the flag at restore time since their prior
conversation history already contains the injected context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@zhuqingyv zhuqingyv changed the title feat(team): dynamic agent type list based on ACP MCP capabilities feat(team): dynamic agent type list + fix warmup race skipping preset_context May 10, 2026
@zhuqingyv zhuqingyv merged commit 2384a23 into main May 11, 2026
5 checks passed
@zhuqingyv zhuqingyv deleted the fix/team-agent-type-list-v2 branch May 11, 2026 02:17
TCP404 added a commit that referenced this pull request May 14, 2026
Replace the `needs_first_message_injection` flag introduced by #208 with a
proper hook-chain dispatcher. The old flag conflated two orthogonal
concerns (session-opened state vs. first-prompt decoration) and required
a reverse-of-intention `take` in `set_session_id` to cancel its
default-true value on resume paths.

Core changes
- New `crate::capability::prompt_pipeline`: `PromptPipeline` + `PreSendHook`
  / `PostRecvHook` traits + `PromptCtx` borrow slice.
- New `crate::manager::acp::hooks`: `SessionNewPreludeHook` and
  `ModelIdentityReminderHook` as thin adapters over existing
  `inject_first_message_prefix` / `render_model_identity_reminder`.
- `AcpSession`: drop `needs_first_message_injection` (default true), add
  `pending_session_new_prelude` (default false) with explicit `mark_*` /
  `take_*`. Flag is set by `open_session_new` on success; resume paths
  never touch it.
- `AcpAgentManager`: gains a `pipeline` field constructed with the two
  built-in hooks; `ensure_session_and_send` collapses to a single
  `pipeline.pre_send` call. `set_session_id` no longer drains any flag.
- `agent_session_flow::prompt_existing_session`: drop the inline
  `take_pending_model_notice` + `render_prompt_content` block now that
  `ModelIdentityReminderHook` owns that transformation.

UI plumbing
- New `AgentStreamEvent::AcpPromptHookWarning(Value)` variant and
  `aionui_api_types::AcpPromptHookWarningPayload` struct, so hook
  failures can surface as non-blocking toasts via the existing stream
  channel. `emit_hook_warning` helper is in place; a future refactor
  that surfaces a fallible boundary in `inject_first_message_prefix`
  will wire it up.

Regression tests
- `tests/prompt_pipeline_integration.rs` adds the coverage #207/#208
  should have had: brand-new first prompt injects preset_context;
  second prompt is passthrough; resume path does not inject;
  `set_pending_model_notice` triggers reminder once; both flags at once
  produce `<system-reminder>` outside `[Assistant Rules]`; hook-warning
  end-to-end skeleton is `#[ignore]`'d with unlock condition documented.

Workspace hygiene
- Bump exhaustive match arms for the new event variant in
  `aionui-channel::message_service` and the test helper in
  `acp_agent_integration`.
- Minor pre-existing clippy cleanups surfaced under `-D warnings`
  across the workspace (`assert!(x)` over `assert_eq!(x, true)`,
  `io::Error::other`, targeted `#[allow]` for approx_constant test
  fixtures, etc.).
TCP404 added a commit that referenced this pull request May 14, 2026
…#262)

Replace the `needs_first_message_injection` flag introduced by #208 with a
proper hook-chain dispatcher. The old flag conflated two orthogonal
concerns (session-opened state vs. first-prompt decoration) and required
a reverse-of-intention `take` in `set_session_id` to cancel its
default-true value on resume paths.

Core changes
- New `crate::capability::prompt_pipeline`: `PromptPipeline` + `PreSendHook`
  / `PostRecvHook` traits + `PromptCtx` borrow slice.
- New `crate::manager::acp::hooks`: `SessionNewPreludeHook` and
  `ModelIdentityReminderHook` as thin adapters over existing
  `inject_first_message_prefix` / `render_model_identity_reminder`.
- `AcpSession`: drop `needs_first_message_injection` (default true), add
  `pending_session_new_prelude` (default false) with explicit `mark_*` /
  `take_*`. Flag is set by `open_session_new` on success; resume paths
  never touch it.
- `AcpAgentManager`: gains a `pipeline` field constructed with the two
  built-in hooks; `ensure_session_and_send` collapses to a single
  `pipeline.pre_send` call. `set_session_id` no longer drains any flag.
- `agent_session_flow::prompt_existing_session`: drop the inline
  `take_pending_model_notice` + `render_prompt_content` block now that
  `ModelIdentityReminderHook` owns that transformation.

UI plumbing
- New `AgentStreamEvent::AcpPromptHookWarning(Value)` variant and
  `aionui_api_types::AcpPromptHookWarningPayload` struct, so hook
  failures can surface as non-blocking toasts via the existing stream
  channel. `emit_hook_warning` helper is in place; a future refactor
  that surfaces a fallible boundary in `inject_first_message_prefix`
  will wire it up.

Regression tests
- `tests/prompt_pipeline_integration.rs` adds the coverage #207/#208
  should have had: brand-new first prompt injects preset_context;
  second prompt is passthrough; resume path does not inject;
  `set_pending_model_notice` triggers reminder once; both flags at once
  produce `<system-reminder>` outside `[Assistant Rules]`; hook-warning
  end-to-end skeleton is `#[ignore]`'d with unlock condition documented.

Workspace hygiene
- Bump exhaustive match arms for the new event variant in
  `aionui-channel::message_service` and the test helper in
  `acp_agent_integration`.
- Minor pre-existing clippy cleanups surfaced under `-D warnings`
  across the workspace (`assert!(x)` over `assert_eq!(x, true)`,
  `io::Error::other`, targeted `#[allow]` for approx_constant test
  fixtures, etc.).
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.

2 participants