Conversational API
fchat is the conversation orchestration layer for Fiddlesticks.
It sits above fprovider and is responsible for handling chat turns, session history loading/saving, and assembling provider requests from conversational state.
It can also integrate with ftooling for provider tool-call execution loops.
Responsibilities
- Own chat-session and turn request/response types
- Load prior transcript messages from a conversation store
- Build and execute provider requests through
fprovider::ModelProvider - Persist new user/assistant transcript messages
fchat does not:
- Implement model-provider transports (that belongs to
fprovider) - Execute tools (that belongs to
ftooling) - Define memory retrieval/summarization engines (that belongs to
fmemory)
Current implementation scope
The implementation currently supports:
- Non-streaming turn execution via
ChatService::run_turn(...) - Live streaming turn execution via
ChatService::stream_turn(...) - Session-level system prompt injection
- In-memory transcript storage implementation for local use/tests
- Optional tool-call execution loop via
ftooling::ToolRuntime - Provider-call retries via
fprovider::RetryPolicy - Tool round-cap signaling when execution limits are reached
Add dependency
[]
= { = "../fchat" }
= { = "../ftooling" }
= { = "../fprovider", = ["provider-openai"] }
Basic usage
use Arc;
use *;
use ProviderId;
async
High-level builders and defaults
fchat includes an opinionated builder path so you can configure once and keep turn calls lightweight.
ChatService::builder(provider)defaults toInMemoryConversationStoreChatPolicy::default()is applied unless overridden- per-turn values are merged with service defaults (
ChatTurnRequestvalues win) - provider retries default to
RetryPolicy::default()and can be overridden ChatTurnRequest::builder(...)provides turn-level ergonomics for overrides
use Arc;
use *;
For turn-level overrides, use ChatTurnOptions:
use *;
let options = ChatTurnOptions ;
let request = new
.with_options;
Or use the builder for symmetry with ChatService::builder(...):
use *;
let request = builder
.temperature
.max_tokens
.build;
Streaming usage
use Arc;
use StreamExt;
use *;
use ProviderId;
async
Current streaming semantics:
stream_turnmaps provider stream events into chat-layer events.- streaming supports multi-round tool execution when a tool runtime is configured.
- tool lifecycle events are emitted (
ToolExecutionStarted,ToolExecutionFinished). - Transcript persistence still occurs before
TurnCompleteis emitted. - Events are forwarded as they arrive from the provider stream.
- Stream acquisition uses retry policy; once a stream is established, event failures are surfaced immediately.
Tool loop usage (ftooling integration)
When configured, ChatService::run_turn(...) can execute provider tool calls and continue model turns.
use Arc;
use *;
use ProviderId;
use *;
Tool loop semantics:
- Tool execution is only used when both a runtime is configured and
max_tool_round_trips > 0. - Each provider
ToolCallis executed throughftooling::ToolRuntime. - Tool outputs are returned to the provider as
ToolResultvalues for follow-up completions. - Loop stops when no tool calls remain or max round-trips is reached.
- If the max round-trip cap is reached with pending tool calls:
run_turnsetsChatTurnResult.tool_round_limit_reached = truestream_turnalso emitsChatEvent::ToolRoundLimitReached { ... }
Public API overview
ChatService: turn orchestrator over provider + storeChatSession: session metadata (id,provider,model, optionalsystem_prompt)ChatTurnRequest: user input + per-turn model paramsChatTurnResult: assistant text + tool calls + stop reason + usageChatTurnResult: includestool_round_limit_reachedfor cap visibilityChatTurnRequestBuilder: ergonomic builder for per-turn optionsChatEvent: streaming event envelope (TextDelta,ToolCallDelta,ToolExecutionStarted,ToolExecutionFinished,AssistantMessageComplete,ToolRoundLimitReached,TurnComplete)ChatEventStream: stream alias for chat event consumersConversationStore: async conversation history contractInMemoryConversationStore: default in-crate store implementationwith_tool_runtime(...): opt-inftooling::ToolRuntimeintegrationwith_max_tool_round_trips(...): cap recursive tool/model rounds
Error model
ChatErrorKind variants:
InvalidRequestProviderStoreTooling
Provider errors from fprovider are mapped into ChatErrorKind::Provider.
Tool errors from ftooling are mapped into ChatErrorKind::Tooling.
ChatError also exposes:
retryable: normalized retry hint for higher layersphase: where the failure occurred (Provider,Tooling,Storage,Streaming, etc.)source: source error kind (ProviderErrorKindorToolErrorKind)- helper methods:
is_retryable()andis_user_error()
phase values are stable API hints for where the failure happened:
RequestValidationProviderStreamingToolingStorage