Skip to content

feat: Add agent block#356

Open
ellie wants to merge 5 commits into
mainfrom
claude/ai-agent-acp-block-2CRpr
Open

feat: Add agent block#356
ellie wants to merge 5 commits into
mainfrom
claude/ai-agent-acp-block-2CRpr

Conversation

@ellie
Copy link
Copy Markdown
Member

@ellie ellie commented Jan 19, 2026

Comprehensive spec for a new "agent" block type that supports:

  • External ACP-compatible agents (Claude Code, Gemini, Codex)
  • Internal Atuin agent using existing AI infrastructure
  • Streaming responses with state tracking
  • Tool call approval flow (confirm with always-allow opt-in)
  • Template integration for prompts and output access

Includes Rust structs, execution flow, ACP client implementation,
UI component requirements, and testing strategy.

Comprehensive spec for a new "agent" block type that supports:
- External ACP-compatible agents (Claude Code, Gemini, Codex)
- Internal Atuin agent using existing AI infrastructure
- Streaming responses with state tracking
- Tool call approval flow (confirm with always-allow opt-in)
- Template integration for prompts and output access

Includes Rust structs, execution flow, ACP client implementation,
UI component requirements, and testing strategy.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jan 19, 2026

Greptile Summary

Adds comprehensive spec for internal agent block that invokes Atuin's AI agent with templated prompts. Uses existing AI infrastructure (FSM, session driver, streaming, multi-provider) with new new_for_agent_block() and wait_for_idle() methods. Includes Rust structs, execution flow, TypeScript types, and UI component requirements.

Issues found:

  • Missing TS derive and #[ts(export)] on AgentState, AgentStatus, and TokenUsage structs - TypeScript types won't be auto-generated
  • Missing .await on update_block_state call at line 193
  • Architecture issue: closure passed to ai_agent_execute won't work since it's a Tauri command (uses Channel<String> for frontend IPC, not Rust closures)

Important Files Changed

Filename Overview
docs/specs/agent-block-spec.md Comprehensive spec for internal agent block; missing TS export, await keyword, closure signature issues

After deeper analysis of the codebase, significantly revised the spec:

- Added "Existing Infrastructure to Reuse" section documenting
  FSM, session driver, tool system, streaming, and storage
- Rewrote Internal Agent Implementation to use existing AISession
  instead of building new streaming/tool handling
- Simplified to: create session → send prompt → wait for idle
- Added specific changes needed to existing files (session.rs,
  fsm.rs, commands/ai.rs) rather than new implementations
- Updated Implementation Order with phased approach and effort
  estimates reflecting reduced scope for Phase 1

Key insight: Internal agent is mostly wiring, not building.
- Replaced detailed ACP implementation with interface contract
- ACP section now just documents what execute_acp_agent() must do
- Updated Implementation Order to emphasize "START HERE" for Phase 1
- Marked Phase 2 and 3 as explicitly DEFERRED
- Reorganized Open Questions by phase
- Reduced spec complexity while preserving ACP extensibility

The AgentSource enum ensures ACP slots in cleanly later:
same output structure, same state machine, same streaming pattern.
Removed all ACP/deferred content. Spec is now:
- 462 lines (down from 1273)
- Internal agent only
- Single implementation checklist
- No phases, no deferrals

Ready for implementation handoff.
@ellie ellie changed the title Add agent block specification for ACP integration feat: Add agent block Jan 19, 2026
@ellie
Copy link
Copy Markdown
Member Author

ellie commented Jan 19, 2026

@greptile review the spec again

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, 5 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +105 to +110

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TokenUsage {
pub input_tokens: Option<u64>,
pub output_tokens: Option<u64>,
}
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.

syntax: TokenUsage lacks #[ts(export)] and TS derive, won't be available in TypeScript

Suggested change
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TokenUsage {
pub input_tokens: Option<u64>,
pub output_tokens: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, TS)]
#[ts(export)]
pub struct TokenUsage {
pub input_tokens: Option<u64>,
pub output_tokens: Option<u64>,
}

Comment thread docs/specs/agent-block-spec.md Outdated
.stdout(Some(chunk))
.build()
);
context.update_block_state::<AgentState, _>(|s| {
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.

syntax: Missing .await on update_block_state

Suggested change
context.update_block_state::<AgentState, _>(|s| {
}).await;

Comment thread docs/specs/agent-block-spec.md Outdated
Comment on lines +180 to +196
let result = ai_agent_execute(
context.runbook_id,
prompt,
system_prompt,
self.model,
self.always_allow_tools,
self.timeout_seconds,
|chunk| {
context.send_output(StreamingBlockOutput::builder()
.block_id(block_id)
.stdout(Some(chunk))
.build()
);
context.update_block_state::<AgentState, _>(|s| {
s.status = AgentStatus::Streaming;
});
},
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.

logic: Closure cannot be passed to ai_agent_execute - that's a Tauri command invoked from frontend, not a callable Rust function. Streaming should happen via Tauri event channel

The ai_agent_execute command at line 247 uses Channel<String> for on_chunk, which is for frontend->backend IPC. The closure here won't work. Instead, need to either:

  1. Make this a regular backend function (not Tauri command) that accepts a closure
  2. Or invoke the Tauri command from frontend and receive chunks via the channel

Based on the existing AI infrastructure, this should likely call a backend function directly within the runtime, not a Tauri command

Comment thread docs/specs/agent-block-spec.md Outdated
Comment on lines +86 to +89
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct AgentState {
pub status: AgentStatus,
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.

syntax: AgentState needs TS derive and #[ts(export)] to generate TypeScript types

Suggested change
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct AgentState {
pub status: AgentStatus,
#[derive(Debug, Clone, Serialize, Deserialize, Default, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export)]
pub struct AgentState {

Comment thread docs/specs/agent-block-spec.md Outdated
Comment on lines +93 to +96
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub enum AgentStatus {
#[default]
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.

syntax: AgentStatus needs TS derive and #[ts(export)] to generate TypeScript types

Suggested change
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub enum AgentStatus {
#[default]
#[derive(Debug, Clone, Serialize, Deserialize, Default, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export)]
pub enum AgentStatus {

Fixes:
1. Add TS derive and #[ts(export)] to AgentState, AgentStatus, TokenUsage
2. Add missing .await on async update_block_state calls
3. Fix architectural mismatch: changed from Tauri command with closure
   to regular backend function with mpsc channel for streaming

The execute_agent_block function is now a regular async function
(not a Tauri command) since it runs in the backend block executor
and uses mpsc::Sender<String> instead of Tauri's Channel<T>.
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