Skip to content

refactor(rap-protocol)!: type tool-call IDs (ToolCallId, ProviderCallId, ChoiceId) - #116

Open
MingweiSamuel wants to merge 1 commit into
mingwei/strkind2from
mingwei/strkind3
Open

refactor(rap-protocol)!: type tool-call IDs (ToolCallId, ProviderCallId, ChoiceId)#116
MingweiSamuel wants to merge 1 commit into
mingwei/strkind2from
mingwei/strkind3

Conversation

@MingweiSamuel

Copy link
Copy Markdown
Member

Stage 4 of the string-ID to typed-ID migration (#108). The two distinct
call-ID spaces documented in rap_tool.rs are now distinct types, and choice
IDs are a documented alias. Wire formats unchanged (serde transparent; full
suite + web e2e green; zero snapshot changes).

  • rap-protocol: ToolCallId (RAP id; provider-minted or runtime UUID)
    and ProviderCallId (RAP call_id; provider-scoped echo-back) kinds;
    type ChoiceId<T = String> = ToolCallId<T> per refactor: decide whether ChoiceId should be a distinct kind or remain an alias of ToolCallId #109 (choices are keyed
    by the requesting tool call). All callback types' id/call_id/
    tool_call_id fields typed; send_subscription_event takes ToolCallId
  • infinity-protocol: re-exports; UserChoiceRequired.id,
    UserChoiceAnswered/UserChoiceComplete.choice_id are ChoiceId
  • infinity-agent-core: Tool::execute(id: ToolCallId, call_id: Option<ProviderCallId>), execute_synchronous takes the borrowed
    <str> forms; SyntheticKind/TaggedSyntheticKind tool_call_id fields
    • backward-compat bare-string variant typed; OAuth/UserChoice message
      ids; store traits (spawn_thread, get_thread_parent_info,
      subscription add/remove/list, remove_pending_user_choice) take typed
      borrows; ThreadInfo.spawn_tool_call_id, subscription sets,
      UserChoice.id, AgentEvent::UserChoiceDismissed,
      CompletionAction::ExecuteToolCall, PrepareResult::UserChoiceRequired,
      interrupted-call tracking all typed. Conversions live only at the rig
      boundary (rig ToolCall/ToolResult keep String ids; WireStreamItem in
      provider-protocol deliberately stays a rig mirror since
      internal_call_id is rig's own delta-matching nanoid)
  • daemon/lambda/bridges/sandbox/poller/slack/CLI: trait impls + internal
    maps typed (sandbox in-flight + pending-choice maps keyed by ToolCallId,
    github-poller Subscription + subscriptions map, slack sidecar choice
    routing, CLI choice picker queue + answer channel); DSQL binds and
    Dynamo string sets convert at the storage boundary

BREAKING CHANGE: rap-protocol callback types and agent-core Tool trait
signatures use ToolCallId/ProviderCallId instead of String.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 3, 2026

Copy link
Copy Markdown

Deploying infinity with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4aaf963
Status: ✅  Deploy successful!
Preview URL: https://19af7c80.infinity-dc7.pages.dev
Branch Preview URL: https://mingwei-strkind3.infinity-dc7.pages.dev

View logs

MingweiSamuel added a commit that referenced this pull request Sep 3, 2026
…Id, ChoiceId)

Stage 4 of the string-ID to typed-ID migration (#108). The two distinct
call-ID spaces documented in rap_tool.rs are now distinct types, and choice
IDs are a documented alias. Wire formats unchanged (serde transparent; full
suite + web e2e green; zero snapshot changes).

* rap-protocol: `ToolCallId` (RAP `id`; provider-minted or runtime UUID)
  and `ProviderCallId` (RAP `call_id`; provider-scoped echo-back) kinds;
  `type ChoiceId<T = String> = ToolCallId<T>` per #109 (choices are keyed
  by the requesting tool call). All callback types' `id`/`call_id`/
  `tool_call_id` fields typed; `send_subscription_event` takes ToolCallId
* infinity-protocol: re-exports; `UserChoiceRequired.id`,
  `UserChoiceAnswered`/`UserChoiceComplete.choice_id` are ChoiceId
* infinity-agent-core: `Tool::execute(id: ToolCallId, call_id:
  Option<ProviderCallId>)`, `execute_synchronous` takes the borrowed
  `<str>` forms; `SyntheticKind`/`TaggedSyntheticKind` tool_call_id fields
  + backward-compat bare-string variant typed; OAuth/UserChoice message
  ids; store traits (`spawn_thread`, `get_thread_parent_info`,
  subscription add/remove/list, `remove_pending_user_choice`) take typed
  borrows; `ThreadInfo.spawn_tool_call_id`, subscription sets,
  `UserChoice.id`, `AgentEvent::UserChoiceDismissed`,
  `CompletionAction::ExecuteToolCall`, `PrepareResult::UserChoiceRequired`,
  interrupted-call tracking all typed. Conversions live only at the rig
  boundary (rig ToolCall/ToolResult keep String ids; `WireStreamItem` in
  provider-protocol deliberately stays a rig mirror since
  `internal_call_id` is rig's own delta-matching nanoid)
* daemon/lambda/bridges/sandbox/poller/slack/CLI: trait impls + internal
  maps typed (sandbox in-flight + pending-choice maps keyed by ToolCallId,
  github-poller Subscription + subscriptions map, slack sidecar choice
  routing, CLI choice picker queue + answer channel); DSQL binds and
  Dynamo string sets convert at the storage boundary

BREAKING CHANGE: rap-protocol callback types and agent-core Tool trait
signatures use ToolCallId/ProviderCallId instead of String.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #116
MingweiSamuel added a commit that referenced this pull request Sep 3, 2026
…Id, ChoiceId)

Stage 4 of the string-ID to typed-ID migration (#108). The two distinct
call-ID spaces documented in rap_tool.rs are now distinct types, and choice
IDs are a documented alias. Wire formats unchanged (serde transparent; full
suite + web e2e green; zero snapshot changes).

* rap-protocol: `ToolCallId` (RAP `id`; provider-minted or runtime UUID)
  and `ProviderCallId` (RAP `call_id`; provider-scoped echo-back) kinds;
  `type ChoiceId<T = String> = ToolCallId<T>` per #109 (choices are keyed
  by the requesting tool call). All callback types' `id`/`call_id`/
  `tool_call_id` fields typed; `send_subscription_event` takes ToolCallId
* infinity-protocol: re-exports; `UserChoiceRequired.id`,
  `UserChoiceAnswered`/`UserChoiceComplete.choice_id` are ChoiceId
* infinity-agent-core: `Tool::execute(id: ToolCallId, call_id:
  Option<ProviderCallId>)`, `execute_synchronous` takes the borrowed
  `<str>` forms; `SyntheticKind`/`TaggedSyntheticKind` tool_call_id fields
  + backward-compat bare-string variant typed; OAuth/UserChoice message
  ids; store traits (`spawn_thread`, `get_thread_parent_info`,
  subscription add/remove/list, `remove_pending_user_choice`) take typed
  borrows; `ThreadInfo.spawn_tool_call_id`, subscription sets,
  `UserChoice.id`, `AgentEvent::UserChoiceDismissed`,
  `CompletionAction::ExecuteToolCall`, `PrepareResult::UserChoiceRequired`,
  interrupted-call tracking all typed. Conversions live only at the rig
  boundary (rig ToolCall/ToolResult keep String ids; `WireStreamItem` in
  provider-protocol deliberately stays a rig mirror since
  `internal_call_id` is rig's own delta-matching nanoid)
* daemon/lambda/bridges/sandbox/poller/slack/CLI: trait impls + internal
  maps typed (sandbox in-flight + pending-choice maps keyed by ToolCallId,
  github-poller Subscription + subscriptions map, slack sidecar choice
  routing, CLI choice picker queue + answer channel); DSQL binds and
  Dynamo string sets convert at the storage boundary

BREAKING CHANGE: rap-protocol callback types and agent-core Tool trait
signatures use ToolCallId/ProviderCallId instead of String.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #116
MingweiSamuel added a commit that referenced this pull request Sep 3, 2026
…Id, ChoiceId)

Stage 4 of the string-ID to typed-ID migration (#108). The two distinct
call-ID spaces documented in rap_tool.rs are now distinct types, and choice
IDs are a documented alias. Wire formats unchanged (serde transparent; full
suite + web e2e green; zero snapshot changes).

* rap-protocol: `ToolCallId` (RAP `id`; provider-minted or runtime UUID)
  and `ProviderCallId` (RAP `call_id`; provider-scoped echo-back) kinds;
  `type ChoiceId<T = String> = ToolCallId<T>` per #109 (choices are keyed
  by the requesting tool call). All callback types' `id`/`call_id`/
  `tool_call_id` fields typed; `send_subscription_event` takes ToolCallId
* infinity-protocol: re-exports; `UserChoiceRequired.id`,
  `UserChoiceAnswered`/`UserChoiceComplete.choice_id` are ChoiceId
* infinity-agent-core: `Tool::execute(id: ToolCallId, call_id:
  Option<ProviderCallId>)`, `execute_synchronous` takes the borrowed
  `<str>` forms; `SyntheticKind`/`TaggedSyntheticKind` tool_call_id fields
  + backward-compat bare-string variant typed; OAuth/UserChoice message
  ids; store traits (`spawn_thread`, `get_thread_parent_info`,
  subscription add/remove/list, `remove_pending_user_choice`) take typed
  borrows; `ThreadInfo.spawn_tool_call_id`, subscription sets,
  `UserChoice.id`, `AgentEvent::UserChoiceDismissed`,
  `CompletionAction::ExecuteToolCall`, `PrepareResult::UserChoiceRequired`,
  interrupted-call tracking all typed. Conversions live only at the rig
  boundary (rig ToolCall/ToolResult keep String ids; `WireStreamItem` in
  provider-protocol deliberately stays a rig mirror since
  `internal_call_id` is rig's own delta-matching nanoid)
* daemon/lambda/bridges/sandbox/poller/slack/CLI: trait impls + internal
  maps typed (sandbox in-flight + pending-choice maps keyed by ToolCallId,
  github-poller Subscription + subscriptions map, slack sidecar choice
  routing, CLI choice picker queue + answer channel); DSQL binds and
  Dynamo string sets convert at the storage boundary

BREAKING CHANGE: rap-protocol callback types and agent-core Tool trait
signatures use ToolCallId/ProviderCallId instead of String.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #116
@MingweiSamuel
MingweiSamuel marked this pull request as ready for review September 4, 2026 00:49
Copilot AI lite review requested due to automatic review settings September 4, 2026 00:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The change is a broad, breaking, cross-crate API refactor that warrants a final human verification of downstream compile/test results and compatibility boundaries.

Pull request overview

This PR advances the workspace-wide string-ID → typed-ID migration (issue #108, stage 4) by introducing distinct RAP tool-call identifier types (ToolCallId vs ProviderCallId) and formalizing ChoiceId as an alias of ToolCallId, then propagating those types through protocol messages, tool traits, stores, and service integrations while keeping wire formats unchanged via transparent serde.

Changes:

  • Add ToolCallId, ProviderCallId, and ChoiceId (alias) to rap-protocol, and type RAP invocation/callback fields accordingly.
  • Re-export the typed IDs from infinity-protocol and update agent-core tool/store traits plus event/message handling to use typed IDs (with conversion kept at the rig/storage boundaries).
  • Update downstream crates (daemon, lambda, slack bot, github poller, sandbox, CLI, MCP bridge) to use typed IDs in handler signatures, maps/sets, and serialization glue.
File summaries
File Description
crates/sandbox-local/tests/common.rs Test helpers now construct typed RapInvocation.id via .into().
crates/sandbox-core/src/server.rs In-flight cancellation + pending-choice maps keyed by ToolCallId.
crates/rap-protocol/src/lib.rs Introduces ToolCallId/ProviderCallId and ChoiceId alias; types callback fields.
crates/rap-github-event-poller/src/main.rs Converts cancel requests to typed ToolCallId at the boundary.
crates/rap-github-event-poller/src/lib.rs Subscription structs/maps updated to typed tool/call IDs.
crates/rap-client/src/notifier.rs Notifier API now takes &ToolCallId<str>.
crates/infinity-slack-bot/src/sidecar.rs Slack actions use typed ChoiceId for choice button routing/dismissal.
crates/infinity-slack-bot/src/session_store.rs PendingChoice.choice_id becomes typed ChoiceId.
crates/infinity-slack-bot/src/flow.rs Button-click parsing now converts to typed ChoiceId for daemon commands.
crates/infinity-slack-bot/src/daemon_sidecar.rs Sidecar command uses typed ChoiceId.
crates/infinity-slack-bot/src/daemon_client.rs Daemon client answer_choice takes &ChoiceId<str>.
crates/infinity-rap-bridge/src/callback.rs Converts typed RAP callback IDs back to rig String at the boundary.
crates/infinity-protocol/src/lib.rs Re-exports typed ID kinds and types choice fields as ChoiceId.
crates/infinity-mcp-bridge/src/lib.rs MCP tool execute signature uses typed IDs; dedup uses id.as_str().
crates/infinity-daemon/tests/mcp_proxy_callback.rs Test invocation IDs updated to typed .into().
crates/infinity-daemon/src/set_title_tool.rs Tool trait signature updated; tool results convert typed IDs back to String.
crates/infinity-daemon/src/session/tests.rs Session tests updated for typed tool-call/choice IDs and comparisons.
crates/infinity-daemon/src/session/display.rs Subscription display lookups compare against typed ToolCallId via as_str().
crates/infinity-daemon/src/rap_servers.rs Managed RAP tool now implements typed Tool signature.
crates/infinity-daemon/src/memory_store.rs Store APIs updated to typed tool-call IDs for spawn/subscriptions/choices.
crates/infinity-agent-lambda/src/tools/sleep.rs Lambda sleep tools accept typed IDs; dedup uses id.as_str().
crates/infinity-agent-lambda/src/state_store.rs DynamoDB subscription/choice APIs updated to typed IDs with boundary conversion.
crates/infinity-agent-lambda/src/event_handler.rs Lambda output shaping converts typed ChoiceId to String for outbound messages.
crates/infinity-agent-lambda/src/conversation_history.rs DSQL store APIs bind typed tool-call IDs via as_str(); parent info returns typed ID.
crates/infinity-agent-core/src/traits.rs Core store traits updated to typed ToolCallId/ChoiceId signatures.
crates/infinity-agent-core/src/tools/thread.rs Tools updated to accept typed IDs; rig tool results still use String IDs.
crates/infinity-agent-core/src/tools/sleep.rs Agent sleep tools updated to typed IDs + boundary conversions.
crates/infinity-agent-core/src/tools/rap_tool.rs RAP invocation params and tool trait signature now use typed IDs.
crates/infinity-agent-core/src/tools/mod.rs Tool trait + error helper updated to typed IDs and as_str() dedup.
crates/infinity-agent-core/src/tools/cancel_subscription.rs Cancel tool parses tool_call_id into ToolCallId and returns rig String IDs.
crates/infinity-agent-core/src/system/thread.rs Pending-choice dismissal/retention updated to typed ChoiceId interop.
crates/infinity-agent-core/src/system/tests.rs System tests updated for typed IDs and comparisons.
crates/infinity-agent-core/src/system/test_support.rs Test tools updated to typed tool-call/call IDs.
crates/infinity-agent-core/src/system/events.rs UserChoice and AgentEvent::UserChoiceDismissed now use typed ChoiceId.
crates/infinity-agent-core/src/stores.rs In-memory stores now key subscriptions/spawn IDs using typed ToolCallId/ChoiceId.
crates/infinity-agent-core/src/message.rs Runtime message types updated to typed IDs; synthetic kind tool-call IDs typed.
crates/infinity-agent-core/src/event_processor.rs Completion actions + interruption/subscription tracking migrated to typed IDs.
crates/infinity-agent-core/examples/agent_scale.rs Example tool updated for typed IDs with conversion to rig String payloads.
crates/infinity-agent-cli/tests/tui_viewport_snapshots.rs CLI snapshot tests updated to typed ChoiceId.
crates/infinity-agent-cli/tests/tui_flow_snapshots.rs CLI snapshot tests updated to typed ChoiceId for required/complete events.
crates/infinity-agent-cli/tests/common/mod.rs CLI harness channel now carries typed ChoiceId.
crates/infinity-agent-cli/src/terminal.rs CLI pending choice queue + channel types updated to typed ChoiceId.
crates/infinity-agent-cli/src/display.rs CLI display event types updated to typed ChoiceId.
crates/infinity-agent-cli/src/daemon_client.rs CLI internal channels updated to carry typed ChoiceId.
Review details
  • Files reviewed: 44/44 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 546 to +551
if let Some(cid) = choice_id {
let rt = crate::runtime::get();
rt.choice_messages
.lock()
.expect("bug: lock poisoned")
.insert(cid, (channel, msg_ts));
.insert(cid.into_inner(), (channel, msg_ts));
…Id, ChoiceId)

Stage 4 of the string-ID to typed-ID migration (#108). The two distinct
call-ID spaces documented in rap_tool.rs are now distinct types, and choice
IDs are a documented alias. Wire formats unchanged (serde transparent; full
suite + web e2e green; zero snapshot changes).

* rap-protocol: `ToolCallId` (RAP `id`; provider-minted or runtime UUID)
  and `ProviderCallId` (RAP `call_id`; provider-scoped echo-back) kinds;
  `type ChoiceId<T = String> = ToolCallId<T>` per #109 (choices are keyed
  by the requesting tool call). All callback types' `id`/`call_id`/
  `tool_call_id` fields typed; `send_subscription_event` takes ToolCallId
* infinity-protocol: re-exports; `UserChoiceRequired.id`,
  `UserChoiceAnswered`/`UserChoiceComplete.choice_id` are ChoiceId
* infinity-agent-core: `Tool::execute(id: ToolCallId, call_id:
  Option<ProviderCallId>)`, `execute_synchronous` takes the borrowed
  `<str>` forms; `SyntheticKind`/`TaggedSyntheticKind` tool_call_id fields
  + backward-compat bare-string variant typed; OAuth/UserChoice message
  ids; store traits (`spawn_thread`, `get_thread_parent_info`,
  subscription add/remove/list, `remove_pending_user_choice`) take typed
  borrows; `ThreadInfo.spawn_tool_call_id`, subscription sets,
  `UserChoice.id`, `AgentEvent::UserChoiceDismissed`,
  `CompletionAction::ExecuteToolCall`, `PrepareResult::UserChoiceRequired`,
  interrupted-call tracking all typed. Conversions live only at the rig
  boundary (rig ToolCall/ToolResult keep String ids; `WireStreamItem` in
  provider-protocol deliberately stays a rig mirror since
  `internal_call_id` is rig's own delta-matching nanoid)
* daemon/lambda/bridges/sandbox/poller/slack/CLI: trait impls + internal
  maps typed (sandbox in-flight + pending-choice maps keyed by ToolCallId,
  github-poller Subscription + subscriptions map, slack sidecar choice
  routing, CLI choice picker queue + answer channel); DSQL binds and
  Dynamo string sets convert at the storage boundary

BREAKING CHANGE: rap-protocol callback types and agent-core Tool trait
signatures use ToolCallId/ProviderCallId instead of String.

Co-authored-by: Infinity 🤖 <infinity@hydro.run>
PR: #116
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