Skip to content

0.2.0

Choose a tag to compare

@Skobeltsyn Skobeltsyn released this 03 May 05:47
· 690 commits to main since this release

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.