0.2.0
What's new
MCP
- HTTP / stdio / TCP transports, Bearer auth, namespaced tools, mock servers for tests
- McpServer.from(agent) with explicit tools/listChanged: false capability
- McpRunner standalone main
Typed tools
- tool<Args, Result>(...) with reflection-built JSON Schema
- @generable / @Guide annotations
- Sealed-args boundaries: rejected at the typed tool<> builder (separate untyped path remains)
Runtime hardening
- ForumTranscript deliberation pattern (transcriptCaptain)
- BranchRoute sealed type with onNull / onElse; sealed-completeness validation at construction
- SkillRoute(name, confidence, rationale) structured router output
- Untrusted tool-output wrapping — model can't impersonate framework messages
- Reserved tool names (memory_*) protected from shadowing
- Encapsulated toolMap / skills (read-only Map views; mutation only via DSL)
- Strict typed args — additionalProperties: false, sealed type discriminator must match constructed variant, repaired-args revalidation
Provider integration
- LlmProviderException — provider-boundary errors surface distinctly from output-parse errors
- Inline-tool fallback for Ollama models without native tool support
- Per-instance latch skips redundant native tool attempt after capability error observed
Suspend refactor
- invokeSuspend(input) on Agent + every composition operator
- executeAgentic and selectSkillByLlm are now suspend
- client.chat(...) wrapped in withContext(Dispatchers.IO) so cancellation interrupts HTTP I/O
- Parallel and Forum use coroutineScope for structured concurrency
Fixed
- Ollama provider error envelopes were silently passed through as LlmResponse.Text(rawJson), causing user transformOutput to fail with a misleading
"could not parse" error (#702) - Agent.mcp { } could mutate the tool registry post-construction because registerTool didn't checkNotFrozen() (#708)
- Agentic loop accepted repaired tool args without re-validating them through the typed schema (#658)
- constructFromMap accepted extra keys for plain data classes; sealed variants didn't verify the type discriminator matched (#665, #699)
- Tool name typos in tools(...) silently dropped instead of failing fast at construction (#631)
- Default budget was unbounded — agents could loop indefinitely without an explicit maxTurns (#633)
Migration
Existing code keeps working unchanged. For coroutine-scope callers, the new suspend entry points propagate cancellation cleanly:
runBlocking {
val result = myAgent.invokeSuspend("input") // no nested runBlocking
val out = (a then b).invokeSuspend("input") // suspend composition
val bounded = withTimeoutOrNull(2.seconds) { // works now
slowParallel.invokeSuspend("input")
}
}
No deprecations — the blocking shims are the documented back-compat surface.