Skip to content

Commit 7683e5e

Browse files
committed
feat: add agent_sdk package with generic AgentClient interface and Claude bridge
Create a provider-agnostic abstraction layer for AI coding agents. The agent_sdk package defines AgentClient, a sealed AgentResponse hierarchy, conversation/message models, and capability interfaces (ModelConfigurable, Interruptible, etc.). ClaudeAgentClient in claude_sdk bridges ClaudeClient into the generic interface with exhaustive type mappers. This enables vide_core to depend on agent_sdk instead of claude_sdk directly (follow-up PR).
1 parent f9af320 commit 7683e5e

15 files changed

Lines changed: 1441 additions & 2 deletions
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
library agent_sdk;
2+
3+
// Client interface
4+
export 'src/client/agent_client.dart';
5+
export 'src/client/agent_client_capabilities.dart';
6+
7+
// Models
8+
export 'src/models/agent_conversation.dart';
9+
export 'src/models/agent_init_data.dart';
10+
export 'src/models/agent_message.dart';
11+
export 'src/models/agent_response.dart';
12+
export 'src/models/agent_status.dart';
13+
export 'src/models/token_usage.dart';
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import 'dart:async';
2+
3+
import '../models/agent_conversation.dart';
4+
import '../models/agent_init_data.dart';
5+
import '../models/agent_message.dart';
6+
import '../models/agent_response.dart';
7+
import '../models/agent_status.dart';
8+
9+
/// Generic interface for interacting with an AI coding agent.
10+
///
11+
/// This is the common contract that consumers (like vide_core) depend on.
12+
/// Each agent SDK (claude_sdk, codex_sdk) provides a bridge implementation
13+
/// that wraps their SDK-specific client and maps types into this interface.
14+
///
15+
/// Extended capabilities (model switching, permission modes, etc.) are
16+
/// expressed as separate interfaces that the bridge may also implement.
17+
/// Use `if (client is ModelConfigurable)` to check for support.
18+
abstract class AgentClient {
19+
// ── Streams ──────────────────────────────────────────────
20+
21+
/// Stream of conversation state changes.
22+
/// Emits whenever messages are added or updated (including streaming deltas).
23+
Stream<AgentConversation> get conversation;
24+
25+
/// Emits when an agent turn completes (assistant finishes responding).
26+
Stream<void> get onTurnComplete;
27+
28+
/// Stream of processing status updates (thinking, responding, etc.)
29+
Stream<AgentProcessingStatus> get statusStream;
30+
31+
/// Stream of initialization data (model name, tools, etc.)
32+
/// Emits when the agent CLI sends its init message.
33+
Stream<AgentInitData> get initDataStream;
34+
35+
/// Stream of queued message text changes.
36+
/// Emits the queued text, or null when queue is cleared.
37+
Stream<String?> get queuedMessage;
38+
39+
// ── Current state ────────────────────────────────────────
40+
41+
/// The current conversation snapshot.
42+
AgentConversation get currentConversation;
43+
44+
/// The most recent processing status.
45+
AgentProcessingStatus get currentStatus;
46+
47+
/// The most recent initialization data, or null if not yet received.
48+
AgentInitData? get initData;
49+
50+
/// The current queued message text, or null if no message is queued.
51+
String? get currentQueuedMessage;
52+
53+
/// The session ID for this client instance.
54+
String get sessionId;
55+
56+
/// The working directory for this agent.
57+
String get workingDirectory;
58+
59+
/// Future that completes when the client has finished initializing.
60+
Future<void> get initialized;
61+
62+
// ── Actions ──────────────────────────────────────────────
63+
64+
/// Send a message to the agent.
65+
void sendMessage(AgentMessage message);
66+
67+
/// Abort the current operation.
68+
Future<void> abort();
69+
70+
/// Close the client and release all resources.
71+
Future<void> close();
72+
73+
/// Clear the conversation history, starting fresh.
74+
Future<void> clearConversation();
75+
76+
/// Clear any queued message without sending it.
77+
void clearQueuedMessage();
78+
79+
/// Inject a synthetic tool result into the conversation.
80+
/// Used to mark a pending tool invocation as failed (e.g., when
81+
/// permission is denied).
82+
void injectToolResult(AgentToolResultResponse toolResult);
83+
84+
/// Get a registered MCP server by name and type.
85+
/// Returns null if not found.
86+
T? getMcpServer<T>(String name);
87+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/// Extended capability interfaces for agent-specific features.
2+
///
3+
/// Not all agents support the same operations. These interfaces allow
4+
/// consumers to check for specific capabilities using `is` checks:
5+
///
6+
/// ```dart
7+
/// if (client is ModelConfigurable) {
8+
/// await client.setModel('opus');
9+
/// }
10+
/// ```
11+
12+
/// Agent supports changing the model at runtime.
13+
abstract class ModelConfigurable {
14+
Future<void> setModel(String model);
15+
}
16+
17+
/// Agent supports setting a maximum thinking token budget.
18+
abstract class ThinkingConfigurable {
19+
Future<void> setMaxThinkingTokens(int maxTokens);
20+
}
21+
22+
/// Agent supports changing permission mode at runtime.
23+
abstract class PermissionModeConfigurable {
24+
Future<void> setPermissionMode(String mode);
25+
}
26+
27+
/// Agent supports interrupting the current execution
28+
/// (more graceful than abort — marks current message as complete).
29+
abstract class Interruptible {
30+
Future<void> interrupt();
31+
}
32+
33+
/// Agent supports rewinding files to a previous state.
34+
abstract class FileRewindable {
35+
Future<void> rewindFiles(String userMessageId);
36+
}
37+
38+
/// Agent supports dynamic MCP server configuration.
39+
abstract class McpConfigurable {
40+
Future<void> setMcpServers(
41+
List<AgentMcpServerConfig> servers, {
42+
bool replace,
43+
});
44+
Future<AgentMcpStatusInfo> getMcpStatus();
45+
}
46+
47+
/// Configuration for a dynamically-added MCP server.
48+
class AgentMcpServerConfig {
49+
final String name;
50+
final String command;
51+
final List<String> args;
52+
final Map<String, String>? env;
53+
54+
const AgentMcpServerConfig({
55+
required this.name,
56+
required this.command,
57+
this.args = const [],
58+
this.env,
59+
});
60+
}
61+
62+
/// Status information for connected MCP servers.
63+
class AgentMcpStatusInfo {
64+
final List<AgentMcpServerStatus> servers;
65+
66+
const AgentMcpStatusInfo({required this.servers});
67+
}
68+
69+
/// Status of a single MCP server.
70+
class AgentMcpServerStatus {
71+
final String name;
72+
final String status;
73+
final List<String> tools;
74+
75+
const AgentMcpServerStatus({
76+
required this.name,
77+
required this.status,
78+
this.tools = const [],
79+
});
80+
}

0 commit comments

Comments
 (0)