|
1 | | -# Agents.KT v0.4.1 — Three Providers, Refreshed Deps |
| 1 | +# Agents.KT v0.4.2 — Three Providers + Clean Dependabot |
2 | 2 |
|
3 | 3 | **Release date:** 2026-05-12 |
4 | 4 |
|
5 | | -**0.4.1 is the first Maven Central release of the three-providers feature set.** v0.4.0 was tagged on GitHub but never published; if you grabbed the artifacts manually from the v0.4.0 tag, switch your dependency declaration to `0.4.1` to pick up the security refresh. |
| 5 | +Functionally identical to v0.4.1. The only change is making the BouncyCastle 1.84 pin visible to Dependabot so the four false-positive alerts on `main` clear. |
6 | 6 |
|
7 | | -## What's new (same as the v0.4.0 surface) |
| 7 | +## What changed |
8 | 8 |
|
9 | | -### Three model providers, one `ModelClient` |
| 9 | +### BouncyCastle 1.84 declared explicitly (build-only) |
10 | 10 |
|
11 | | -```kotlin |
12 | | -// Local / cloud Ollama (since 0.1) |
13 | | -model { ollama("qwen2.5:7b"); host = "localhost"; port = 11434 } |
14 | | - |
15 | | -// Anthropic — new |
16 | | -model { claude("claude-opus-4-7"); apiKey = System.getenv("ANTHROPIC_API_KEY") } |
17 | | - |
18 | | -// OpenAI Chat Completions — new |
19 | | -model { openai("gpt-4o"); apiKey = System.getenv("OPENAI_API_KEY") } |
20 | | -``` |
21 | | - |
22 | | -`LlmMessage` / `LlmResponse` are provider-agnostic. Each adapter handles the provider's own conventions internally — Anthropic's structured `tool_use` / `tool_result` content blocks, OpenAI's stringified `function.arguments` and synthesized `tool_call_id`s, Ollama's flat shape with inline-JSON fallback. The agentic loop on top is unchanged. |
23 | | - |
24 | | -Both new adapters share the same boundary contract `OllamaClient` established: top-level provider error envelopes surface as `LlmProviderException`, not garbled text masquerading as model output (`#702`). |
25 | | - |
26 | | -### Fail-fast at REPL startup |
| 11 | +The existing `force(...)` block in `build.gradle.kts` already pins BC to 1.84 — confirmed patched by both OSV and GHSA. The lockfile and `gradle/verification-metadata.xml` both record 1.84 as the resolved version. But Dependabot reads the *requested* dependency graph submitted by `gradle/actions/dependency-submission`, not the *resolved* graph, so it kept alerting on the 1.80 vulnerabilities that don't apply. |
27 | 12 |
|
28 | | -`LiveShowBuilder.precheck: (() -> Unit)?` runs after argument parsing and before the banner / `--once` / REPL prompt. Throw to abort; the runner prints `error: <msg>` and returns exit code 2. No more mid-spinner `java.net.ConnectException` on the first turn. |
| 13 | +The fix: declare BC 1.84 explicitly via `compileOnly(...)` at the project level. `compileOnly` does NOT propagate to consumers — `runtimeClasspath` stays free of BC, same as 0.4.1. The only effect is that Dependabot now sees explicit 1.84 nodes in the graph. |
29 | 14 |
|
30 | 15 | ```kotlin |
31 | | -LiveRunner.serve(captain, args) { |
32 | | - prompt = "fib> " |
33 | | - precheck = OllamaPreflight(host = "localhost", port = 11434)::check |
| 16 | +dependencies { |
| 17 | + compileOnly("org.bouncycastle:bcprov-jdk18on:1.84") |
| 18 | + compileOnly("org.bouncycastle:bcpg-jdk18on:1.84") |
| 19 | + compileOnly("org.bouncycastle:bcpkix-jdk18on:1.84") |
| 20 | + compileOnly("org.bouncycastle:bcutil-jdk18on:1.84") |
34 | 21 | } |
35 | 22 | ``` |
36 | 23 |
|
37 | | -The precheck hook is generic — config validation, environment checks, even a database connection can run before the user types anything (`#1132`). |
38 | | - |
39 | | -### Typed `@Generable` args, live, on every provider |
40 | | - |
41 | | -`TypedArgsLiveIntegrationTest` covers the full round-trip — `@Generable` schema generation → provider envelope (Ollama `parameters`, Anthropic `input_schema`, OpenAI `parameters`) → wire serialization → response parse → `KClass.constructFromMap` → typed executor — against real models. Three tests, one per provider, each gated so a fresh clone without keys stays green (`#1675`). |
42 | | - |
43 | | -### `apiKey` no longer leaks through `toString` |
44 | | - |
45 | | -`ModelConfig.toString()` masks the API key as `apiKey=sk-ant…108chars` instead of dumping the body. `equals`/`hashCode` still consider apiKey (cache keying stays correct); masking is observation-only. `SECURITY.md` gained a "Handling LLM provider credentials" section with the `.secrets/` convention, file perms, the masking contract, and a "if a key is committed → rotate first" runbook (`#1665`). |
46 | | - |
47 | | -## Fixed |
48 | | - |
49 | | -### OllamaClient: assistant tool-call turns wire `content: null` |
| 24 | +Why we don't drop the `force(...)` block: it's still belt-and-suspenders for any transitive request that bypasses `compileClasspath`. |
50 | 25 |
|
51 | | -External bug report: every multi-turn agentic loop against Ollama Cloud `gpt-oss:120b-cloud` / `gpt-oss:20b-cloud` was hitting `500 Internal Server Error`. Root cause: assistant messages with `tool_calls` and no text were serialised as `content: ""`, but the OpenAI / Ollama chat-completions spec says `content` should be `null` (or omitted) when `tool_calls` is present. |
| 26 | +## Inherited from v0.4.1 |
52 | 27 |
|
53 | | -The fix null-coerces only when **all three** hold: role is `assistant`, `tool_calls` is non-empty, and content is blank. Legitimate empty-string assistant turns (no tool_calls) keep their previous shape. Ollama-only patch; the other two adapters were already spec-compliant. Six regression cases cover the truth table from the bug report (`#1694`). |
| 28 | +(See `RELEASE_NOTES.md` in the v0.4.1 tag for the full notes; same content lands in 0.4.2 unchanged.) |
54 | 29 |
|
55 | | -## Security refresh (new in 0.4.1) |
56 | | - |
57 | | -- `kotlinx-coroutines-core` and `kotlinx-coroutines-test` 1.10.2 → 1.11.0 (production + test). |
58 | | -- Gradle wrapper 9.4.1 → 9.5.0 (build). |
59 | | -- Lockfile and `gradle/verification-metadata.xml` regenerated. |
60 | | - |
61 | | -Closes the four dependabot advisories on `main` and supersedes the open dependabot PRs. |
62 | | - |
63 | | -## Binary compatibility |
64 | | - |
65 | | -**Source-compatible** with 0.3.x — every new public API has defaults; existing code compiles unchanged. |
66 | | - |
67 | | -**Wire-shape change for Ollama tool-call messages** (`#1694`) — assistant turns with `tool_calls` and no textual content now serialize as `content: null` on the wire instead of `content: ""`. Pure payload shaping; in-memory `LlmMessage` is unchanged. Local Ollama tolerated both shapes; Ollama Cloud's strict validators only accept the new form, so this is functionally a regression fix for cloud users. |
68 | | - |
69 | | -## Migration |
70 | | - |
71 | | -If you're on 0.3.x and only using Ollama, nothing to do. Bump the version, rebuild, ship. |
72 | | - |
73 | | -If you want to try Claude or OpenAI: |
74 | | - |
75 | | -```kotlin |
76 | | -agent("coder") { |
77 | | - model { |
78 | | - claude("claude-opus-4-7") // or openai("gpt-4o") |
79 | | - apiKey = System.getenv("ANTHROPIC_API_KEY") |
80 | | - temperature = 0.0 |
81 | | - maxTokens = 4096 // required for both cloud providers |
82 | | - } |
83 | | - skills { /* unchanged */ } |
84 | | -} |
85 | | -``` |
| 30 | +- Three model providers — Ollama, Claude, OpenAI (#1644, #1656) |
| 31 | +- LiveRunner precheck hook + `OllamaPreflight` (#1132) |
| 32 | +- Live typed-args integration tests across all three providers (#1675) |
| 33 | +- `ModelConfig.toString()` masks `apiKey` (#1665) |
| 34 | +- Ollama wire-shape fix: `content: null` on assistant tool-call turns (#1694) |
| 35 | +- Dependency refresh: `kotlinx-coroutines` 1.11.0, Gradle 9.5.0 |
86 | 36 |
|
87 | | -Local development convention: keep keys in `<repo-root>/.secrets/anthropic-key` and `<repo-root>/.secrets/openai-key` (gitignored), `chmod 0600`. See `SECURITY.md` for the full handling guidance. |
| 37 | +## Migration from v0.4.1 |
88 | 38 |
|
89 | | -## What's next (Phase 2) |
| 39 | +Nothing to do. Drop-in upgrade. `runtimeClasspath` is byte-for-byte identical. |
90 | 40 |
|
91 | | -- Streaming (`Flow<LlmResponseChunk>`) on every adapter — kills the dead-air spinner. |
92 | | -- Prompt caching headers for Claude — `cache_control: ephemeral` on long system prompts and knowledge blocks. |
93 | | -- KSP compile-time `@Generable` (replaces runtime reflection). |
94 | | -- Google (Gemini) adapter — last on the multi-provider list. |
95 | | -- `Tool<IN, OUT>` base hierarchy + `McpTool<IN, OUT>` subclass, unblocking `grants { }` typed permissions. |
| 41 | +## Migration from 0.3.x |
96 | 42 |
|
97 | | -Full roadmap: [`docs/roadmap.md`](docs/roadmap.md). |
| 43 | +Same as 0.4.1 — see [`RELEASE_NOTES.md`](https://github.com/Deep-CodeAI/Agents.KT/blob/v0.4.1/RELEASE_NOTES.md) at the v0.4.1 tag. |
0 commit comments