Important: Unstable features are not part of the official ACP specification yet. They may be removed, renamed, or have their behavior changed at any point without notice.Use these features only for experimentation and be prepared to update your code when the protocol evolves.
Unstable Session Methods
The Dart SDK implements several experimental session management methods.
session/list
Lists existing sessions from the agent with optional filtering and pagination.
class MyAgent implements Agent {
@override
Future < ListSessionsResponse > ? unstableListSessions (
ListSessionsRequest params,
) async {
final sessions = await getSessionsForCwd (params.cwd);
return ListSessionsResponse (
sessions : sessions. map ((s) => SessionInfo (
sessionId : s.id,
cwd : s.cwd,
title : s.title,
updatedAt : s.updatedAt,
)). toList (),
nextCursor : sessions.length > 10 ? 'cursor_token' : null ,
);
}
}
Parameters:
cursor (optional): Pagination cursor for retrieving more results
cwd (optional): Filter sessions by working directory
Response:
sessions: List of SessionInfo objects
nextCursor: Token for retrieving the next page (null if no more results)
Advertise this capability by setting sessionCapabilities.list in your initialize response: InitializeResponse (
agentCapabilities : AgentCapabilities (
sessionCapabilities : SessionCapabilities (
list : SessionListCapabilities (),
),
),
)
session/fork
Forks an existing session to create a new independent session with the same history.
@override
Future < ForkSessionResponse > ? unstableForkSession (
ForkSessionRequest params,
) async {
// Load original session
final originalSession = await loadSessionById (params.sessionId);
// Create new session with copied history
final newSessionId = await forkSession (
originalSession,
cwd : params.cwd,
mcpServers : params.mcpServers,
);
return ForkSessionResponse (
sessionId : newSessionId,
modes : originalSession.modes,
models : originalSession.models,
configOptions : originalSession.configOptions,
);
}
Use Cases:
Experiment with different approaches from the same starting point
Create “what-if” scenarios
Branch conversations without losing the original
Capability Advertisement:
sessionCapabilities : SessionCapabilities (
fork : SessionForkCapabilities (),
)
session/resume
Resumes an existing session without replaying the entire message history.
@override
Future < ResumeSessionResponse > ? unstableResumeSession (
ResumeSessionRequest params,
) async {
// Restore session state without replaying history
final session = await restoreSessionState (params.sessionId);
// Reconnect to MCP servers
await connectToMcpServers (params.mcpServers ?? session.mcpServers);
return ResumeSessionResponse (
modes : session.modes,
models : session.models,
configOptions : session.configOptions,
);
}
Difference from session/load:
session/load
Replays entire conversation history
Sends all previous messages via session/update
Slower but provides complete context
session/resume
Skips history replay
Only restores session state
Faster for long conversations
Capability Advertisement:
sessionCapabilities : SessionCapabilities (
resume : SessionResumeCapabilities (),
)
session/set_model
Changes the language model for a given session.
@override
Future < SetSessionModelResponse ?> ? setSessionModel (
SetSessionModelRequest params,
) async {
await updateSessionModel (
sessionId : params.sessionId,
modelId : params.modelId,
);
return SetSessionModelResponse ();
}
Parameters:
sessionId: The session to update
modelId: The new model identifier
Model Selection:
// Advertise available models in session responses
NewSessionResponse (
sessionId : sessionId,
models : SessionModelState (
availableModels : [
ModelInfo (
modelId : 'gpt-4' ,
name : 'GPT-4' ,
description : 'Most capable model' ,
),
ModelInfo (
modelId : 'gpt-3.5-turbo' ,
name : 'GPT-3.5 Turbo' ,
description : 'Fast and efficient' ,
),
],
currentModelId : 'gpt-4' ,
),
)
Clients can use this method to allow users to switch models mid-conversation without creating a new session.
Unstable Session Updates
Additional session update types for enhanced session tracking.
session_info_update
Updates metadata about the session itself.
await connection. sessionUpdate ( SessionNotification (
sessionId : sessionId,
update : SessionInfoUpdate (
title : 'Debug authentication issue' ,
updatedAt : DateTime . now (). toIso8601String (),
),
));
Fields:
title: Human-readable session title
updatedAt: ISO 8601 timestamp of last update
Use Cases:
Auto-generate session titles based on conversation content
Track session activity for UI display
Sync session metadata across clients
usage_update
Provides token usage and cost information.
await connection. sessionUpdate ( SessionNotification (
sessionId : sessionId,
update : UsageUpdate (
size : 100000 , // Total context size
used : 42500 , // Tokens used so far
cost : Cost (
amount : 0.15 ,
currency : 'USD' ,
),
),
));
Fields:
size: Total available context window size
used: Number of tokens used in this session
cost: Estimated cost (optional)
Use Cases:
Display context window usage to users
Warn when approaching token limits
Track API costs per session
Usage updates can be sent periodically during prompt processing to keep the UI synchronized with token consumption.
Implementation Guidelines
Unstable methods are registered in the connection’s request handler: // From lib/src/acp.dart
Future < dynamic > requestHandler ( String method, dynamic params) async {
switch (method) {
case 'session/list' :
return handleOptionalRequest (
method,
params,
ListSessionsRequest .fromJson,
agent.unstableListSessions,
);
// ... other cases
}
}
If your agent doesn’t implement an unstable method, return null and the SDK will respond with Method not found.
Unstable features should be advertised during initialization: @override
Future < InitializeResponse > initialize ( InitializeRequest params) async {
return InitializeResponse (
protocolVersion : 1 ,
agentCapabilities : AgentCapabilities (
sessionCapabilities : SessionCapabilities (
list : SessionListCapabilities (),
fork : SessionForkCapabilities (),
resume : SessionResumeCapabilities (),
),
),
);
}
Clients should check for these capabilities before calling unstable methods.
When unstable features become stable:
Method names may change (e.g., unstableListSessions → listSessions)
Request/response schemas may be refined
Capability advertisement requirements may change
Error handling semantics may be standardized
Always check the ACP changelog for migration guides.
Testing Unstable Features
The SDK includes tests for unstable features to ensure they work as expected:
// Example test structure
test ( 'session/list returns sessions' , () async {
final agent = TestAgent ();
final connection = AgentSideConnection (
(_) => agent,
testStream,
);
final response = await agent. unstableListSessions (
ListSessionsRequest (cwd : '/project' ),
);
expect (response ? .sessions, isNotEmpty);
});
When writing tests for unstable features, clearly mark them as unstable and be prepared to update or remove them when the protocol changes.
Migration Strategy
If you’re using unstable features in production:
Monitor the Protocol: Watch the ACP repository for changes
Version Pin: Consider pinning to a specific SDK version until features stabilize
Feature Flags: Use feature flags to easily disable unstable features
Fallback Logic: Implement graceful degradation when unstable methods fail
// Example: Safe unstable feature usage
Future < List < SessionInfo >> listSessions ( String cwd) async {
try {
final response = await connection. unstableListSessions (
ListSessionsRequest (cwd : cwd),
);
return response.sessions;
} catch (e) {
// Fallback: Use local session cache
return localSessionCache. getSessions (cwd);
}
}
Next: Protocol Extensions Learn how to add custom protocol methods