pub trait WorkspaceBackend:
Send
+ Sync
+ 'static {
type Conversation: ConversationBackend;
// Required methods
fn id(&self) -> WorkspaceId;
fn info(
&self,
) -> impl Future<Output = Result<WorkspaceInfo, KitError>> + Send + '_;
fn new_conversation(
&self,
request: NewConversation,
) -> impl Future<Output = Result<Self::Conversation, KitError>> + Send + '_;
fn list_conversations(
&self,
) -> impl Future<Output = Result<Vec<ConversationInfo>, KitError>> + Send + '_;
fn conversation_info(
&self,
id: ConversationId,
) -> impl Future<Output = Result<ConversationInfo, KitError>> + Send + '_;
fn get_conversation(
&self,
id: ConversationId,
) -> impl Future<Output = Result<Self::Conversation, KitError>> + Send + '_;
fn list_tools(
&self,
) -> impl Future<Output = Result<Vec<ToolInfo>, KitError>> + Send + '_;
fn ingest_knowledge(
&self,
request: IngestKnowledgeRequest,
) -> impl Future<Output = Result<(), KitError>> + Send + '_;
fn close(self) -> impl Future<Output = Result<(), KitError>> + Send
where Self: Sized;
}Expand description
Public implementation contract for one revision-bound portable workspace.
A caller Agent returns its own concrete workspace through
AgentBackend::Workspace. Each workspace owns
its associated Conversation; runtime composition may use
an exhaustive caller enum hierarchy. A stable workspace ID does not refresh a
stale runtime revision. Closing invalidates runtime descendants while preserving
quiescent durable records for direct-ID reopen.
See crate::AgentBackend::new_workspace for creation and
Self::new_conversation for the child lifecycle. The executable caller hierarchy
implements these contracts directly without a provider, process or database.
Required Associated Types§
Sourcetype Conversation: ConversationBackend
type Conversation: ConversationBackend
Concrete conversation implementation produced by this workspace.
Required Methods§
Sourcefn id(&self) -> WorkspaceId
fn id(&self) -> WorkspaceId
Returns the durable portable workspace identity.
This is the durable workspace identity. A handle also carries a runtime revision binding, so a stable id does not make an old handle current.
See Self::new_conversation for the complete child lifecycle and crate::AgentBackend::new_workspace for workspace creation.
Sourcefn info(
&self,
) -> impl Future<Output = Result<WorkspaceInfo, KitError>> + Send + '_
fn info( &self, ) -> impl Future<Output = Result<WorkspaceInfo, KitError>> + Send + '_
Reads the current committed workspace information.
The result contains the complete committed context/defaults and revision. It does not refresh this handle after a concurrent revision change.
§Errors
Returns KitError for a closed parent/workspace, stale revision,
state-read failure, inconsistent durable state, or deadline expiry.
See Self::new_conversation for the complete child lifecycle and crate::AgentBackend::new_workspace for workspace creation.
Sourcefn new_conversation(
&self,
request: NewConversation,
) -> impl Future<Output = Result<Self::Conversation, KitError>> + Send + '_
fn new_conversation( &self, request: NewConversation, ) -> impl Future<Output = Result<Self::Conversation, KitError>> + Send + '_
Creates and publishes one conversation under this workspace.
The returned associated child is published only after resolved defaults, initial knowledge, backend attachment, and durable ownership agree.
§Errors
Returns KitError for closed or stale runtime, busy admission, invalid
input or unsupported policy/integrations, and dependency/deadline failures.
Accepted native setup remains durably attached or recovery-owned on failure.
§Examples
This local Custom agent uses in-memory Lance and sends no network requests.
#![recursion_limit = "256"] // Nested concrete async futures need this on Linux.
use agents_kit::ConversationBackend;
use agents_kit::conversation::NewConversation;
let workspace_id = workspace.id();
let result = async {
let conversation = workspace.new_conversation(NewConversation::new(
Some("Review".into()), None, Vec::new(),
)?).await?;
let id = conversation.id();
let info = conversation.info().await?;
assert_eq!(info.id(), &id);
assert_eq!(info.workspace_id(), &workspace_id);
assert_eq!(info.title(), Some("Review"));
let inventory = workspace.list_conversations().await?;
assert_eq!(inventory.len(), 1);
assert_eq!(inventory[0].id(), &id);
assert_eq!(workspace.conversation_info(id.clone()).await?.id(), &id);
assert!(workspace.list_tools().await?.is_empty());
Ok::<_, agents_kit::KitError>(id)
}.await;
// Parent close settles children and preserves quiescent records for reopen.
let close = workspace.close().await;
let conversation_id = match (result, close) {
(Err(primary), Err(cleanup)) => Err(primary.with_supplementary(cleanup)),
(Err(error), _) | (_, Err(error)) => Err(error),
(Ok(id), Ok(())) => Ok(id),
}?;
let workspace = agent.get_workspace(workspace_id.clone()).await?;
let result = async {
assert_eq!(workspace.id(), workspace_id);
assert_eq!(workspace.info().await?.id(), &workspace_id);
let conversation = workspace.get_conversation(conversation_id.clone()).await?;
let observed = conversation.info().await;
// Explicit child close is terminal; unlike parent close, it ends reopenability.
let close = conversation.close().await;
let info = match (observed, close) {
(Err(primary), Err(cleanup)) => Err(primary.with_supplementary(cleanup)),
(Err(error), _) | (_, Err(error)) => Err(error),
(Ok(info), Ok(())) => Ok(info),
}?;
assert_eq!(info.id(), &conversation_id);
assert_eq!(info.workspace_id(), &workspace_id);
assert_eq!(info.title(), Some("Review"));
assert!(workspace.list_conversations().await?.is_empty());
Ok::<(), agents_kit::KitError>(())
}.await;
let close = workspace.close().await;
match (result, close) {
(Err(primary), Err(cleanup)) => Err(primary.with_supplementary(cleanup)),
(Err(error), _) | (_, Err(error)) => Err(error),
(Ok(()), Ok(())) => Ok(()),
}?;Sourcefn list_conversations(
&self,
) -> impl Future<Output = Result<Vec<ConversationInfo>, KitError>> + Send + '_
fn list_conversations( &self, ) -> impl Future<Output = Result<Vec<ConversationInfo>, KitError>> + Send + '_
Lists live or reopenable conversations in deterministic identity order.
Inventory comes from ownership-valid durable records; it is not limited to handles currently open in this process. Terminally closed conversations are excluded. Listing does not claim live handles.
§Errors
Returns KitError for closed or stale runtime, state/dependency read
failures, inconsistent inventory, or deadline expiry.
See Self::new_conversation for the complete child lifecycle and crate::AgentBackend::new_workspace for workspace creation.
Sourcefn conversation_info(
&self,
id: ConversationId,
) -> impl Future<Output = Result<ConversationInfo, KitError>> + Send + '_
fn conversation_info( &self, id: ConversationId, ) -> impl Future<Output = Result<ConversationInfo, KitError>> + Send + '_
Reads committed information for one conversation identity.
This reads committed metadata without claiming a live child handle. Missing and foreign identities do not reveal a foreign owner.
§Errors
Returns crate::error::ErrorKind::NotFound for an unavailable or foreign
conversation, or the owning closed/stale runtime, state-read, integrity, or
deadline error.
See Self::new_conversation for the complete child lifecycle and crate::AgentBackend::new_workspace for workspace creation.
Sourcefn get_conversation(
&self,
id: ConversationId,
) -> impl Future<Output = Result<Self::Conversation, KitError>> + Send + '_
fn get_conversation( &self, id: ConversationId, ) -> impl Future<Output = Result<Self::Conversation, KitError>> + Send + '_
Opens the current live handle for one conversation identity.
A current conversation has at most one live public handle; repeated lookup is busy until its claim is released. Reopen verifies the current workspace revision, defaults, attachments, tools, knowledge, and recovery state. It does not create a replacement session for a missing identity.
§Errors
Returns KitError for a missing/foreign or terminal conversation, an
existing live claim, closed or stale runtime, incompatible reopen state,
or dependency/deadline failure.
See Self::new_conversation for the complete child lifecycle and crate::AgentBackend::new_workspace for workspace creation.
Sourcefn list_tools(
&self,
) -> impl Future<Output = Result<Vec<ToolInfo>, KitError>> + Send + '_
fn list_tools( &self, ) -> impl Future<Output = Result<Vec<ToolInfo>, KitError>> + Send + '_
Lists agents-kit-managed tools installed for this workspace.
Returns the complete source-neutral catalog the Agent owns and can expose in this workspace, subject to its execution policy. An unavailable source must not be silently omitted from a purportedly complete result.
§Errors
Returns KitError for closed or stale runtime, unsupported or incomplete
catalog exposure, malformed source data, or dependency/deadline failure.
See Self::new_conversation for the complete child lifecycle and crate::AgentBackend::new_workspace for workspace creation.
Sourcefn ingest_knowledge(
&self,
request: IngestKnowledgeRequest,
) -> impl Future<Output = Result<(), KitError>> + Send + '_
fn ingest_knowledge( &self, request: IngestKnowledgeRequest, ) -> impl Future<Output = Result<(), KitError>> + Send + '_
Atomically replaces managed knowledge from this workspace.
An omitted scope selects this Workspace. Explicit Agent or Database scope
is validated under the shared knowledge rules; Conversation scope is not
accepted here. Empty sources are a no-op after scope validation, not deletion.
Updating workspace context/defaults does not move sources. See crate::knowledge
for local ingestion and policy examples.
§Errors
Returns KitError for invalid sources or scope, missing/incompatible
knowledge integrations, closed or stale runtime, busy admission, or
dependency/deadline failure. Unsupported semantics fail explicitly.
Caller implementations need no service. See IngestKnowledgeRequest for request construction and the executable caller hierarchy for direct-trait ingestion.
Sourcefn close(self) -> impl Future<Output = Result<(), KitError>> + Sendwhere
Self: Sized,
fn close(self) -> impl Future<Output = Result<(), KitError>> + Sendwhere
Self: Sized,
Consumes the implementation, seals its runtime, and settles accepted work.
Close cascade-invalidates live descendants after accepted work and interactions settle. Quiescent durable conversations, notifications, and knowledge remain for reopen. This does not terminally close conversations or acknowledge caller events. Drop alone provides no async cleanup guarantee.
§Errors
Returns KitError when an owned cleanup responsibility fails or cannot
settle within the lifecycle deadline. The consumed handle is not restored;
durable recovery owns later reconciliation and supplementary failures do
not replace the primary error.
See Self::new_conversation for the complete child lifecycle and crate::AgentBackend::new_workspace for workspace creation.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".