Atmosphere 4.0.50
Removed
- Pruned dead/unwired internal classes found during a release-readiness audit —
none was documented, advertised, or reachable from a user code path:
McpWebSocketHandler(superseded byMcpHandler's direct WebSocket-frame
handling),AgUiSession(superseded byResourceAgUiStreamingSession),
AiCoalescingBroadcasterCache(a delegate-onlyBroadcasterCachethat the
no-arg reflective cache-wiring path cannot instantiate),AdkArtifactBridge,
AdkCompactionBridge,AtmosphereRequestBridge,AtmosphereResponseBridge,
the channelsAuditLoggingFilter(never registered as a bean, so it never
reached the filter chain), the unwiredGrpcProtocolBridge, and the A2A
ListTaskPushNotificationConfigsResponseDTO (the
ListTaskPushNotificationConfigsmethod returnsERROR_PUSH_NOT_SUPPORTED,
so the response type was never constructed).
Fixed
ToolBridgeUtils.findUnescapedQuoteno longer advances the scan index past
the end of the string when malformed tool-call JSON ends in a lone backslash
— the escaped-character skip is now bounds-checked (boundary safety,
Correctness Invariant #4). Regression test added.
Added
-
Interactions API (
org.atmosphere.interactions, artifactatmosphere-interactions)
— a stateful agent-turn resource layered above theAgentRuntimeSPI, so it
works for every adapter with no per-runtime code. AnInteractioncarries a
stable id, a durablesteps[]event log, and chains turns via
previousInteractionId(the server holds history; the client does not resend
it). Turns run synchronously or in the background (background=true
returns aRUNNINGrecord immediately and is retrievable after a disconnect),
andstore=falsestreams without persisting. The starter exposes the resource
overPOST /api/interactions,POST /api/interactions/{id}/continue,
GET /api/interactions/{id},GET /api/interactions,
POST /api/interactions/{id}/cancel, andDELETE /api/interactions/{id}—
every mutating route is default-deny behindatmosphere.interactions.http-write-enabled
plus an authenticated principal (Correctness Invariant #6). TwoInteractionStore
backends ship:InMemoryInteractionStore(default) andSqliteInteractionStore;
the SPI is pluggable for others.atmosphere.jsgains a typedInteractionsClient
(atmosphere.js/interactions) covering the REST surface pluspollUntilTerminal
/watchhelpers. -
Interactions live streaming — a background interaction now streams its
durablesteps[]to a subscribed browser as they are produced, over the
Atmosphere transport (/atmosphere/interactions-stream?id=<id>, WebSocket/SSE).
On connect the handler replays the steps captured so far (late-joiner catch-up,
deduped client-side by sequence), then pushes each new step live and a terminal
frame on completion; ownership is enforced per-interaction, same scope as the
REST read.InteractionsClient.subscribe(id, handlers)bridges it on the client
and the Atmosphere Console's Interactions tab renders the live step timeline.
AnAtmosphereInterceptorresolves the principal for the stream socket so
ownership holds across all transports (a servlet filter's request attribute does
not survive the WebSocket upgrade). Demonstrated inspring-boot-coding-agent
andspring-boot-multi-agent-startup-team. -
ToolKind+@AiTool(kind = …)— tools declare a behavioural category
(EDIT,READ,EXECUTE,NETWORK,DELETE,OTHER; defaultOTHER).
This makesPermissionMode.ACCEPT_EDITSa real behaviour instead of a
DEFAULTalias: it now auto-approves a tool's own@RequiresApproval
prompt whenkind == EDIT, while every other tool still routes through the
per-tool approval gate. The classification is compile-time author metadata
(not runtime caller-asserted intent), the defaultOTHERkeeps the approval
posture exactly as restrictive as before, and the relaxation never overrides
an operator-configuredToolPermissionPolicyDENY/CONFIRMor aDenyAll
policy.ToolExecutionHelperAcceptEditsTestpins all four cases. -
Code-as-action sandbox (
org.atmosphere.ai.code) — acode_exectool that
lets a model accomplish tasks by writing a block of code (bash / JavaScript /
Python) instead of negotiating many fine-grained tool calls. Each session gets
an isolated, ephemeral container (CodeSandboxSPI,ContainerCodeSandboxover
Docker/Podman) with hardening applied —--network noneby default, non-root,
--cap-drop ALL,--security-opt no-new-privileges, read-only rootfs + a bounded
writable workspace, and memory/cpu/pid caps — provisioned lazily on first use and
torn down on every terminal path via the newStreamingSession.onTerminate(AutoCloseable)
primitive. Default-deny: code execution is off unless
org.atmosphere.ai.code.enabled=trueand a container engine is confirmed present
at runtime (Correctness Invariant #5); the tool is registered into@AiEndpoint
dispatch only then, with the tool-loop ceiling lifted to 25 write→run→observe
rounds. Each round streams anAiEvent.AgentStepplus any screenshots the code
produced, rendered inline in the Console as markdown data-URI images. New
samples/spring-boot-browser-agentdemonstrates it (Cohere-backed, requires
Docker): the agent drives a headless browser with Playwright and you watch the
screenshots arrive live.
Changed
ai-policy-regoandai-policy-cedarnow ship a
META-INF/services/org.atmosphere.ai.governance.PolicyParserregistration,
so Rego and Cedar policy artifacts are auto-discovered byServiceLoader
the same way YAML always has been — no programmatic parser wiring required.
Safe because both parsers have lazy no-arg constructors (theopa/cedar
binary is only touched at evaluation, and parse failure is already
fail-closed). The Kafka/Postgres audit sinks are deliberately left on
programmaticGovernanceDecisionLog.addSink()wiring: they need a live
broker / JDBC connection, so auto-activating them on classpath presence
would advertise capability that cannot run (Runtime-Truth, Correctness
Invariant #5).RegoPolicyParserTest/CedarPolicyParserTestpin the
discovery.- Four new pre-push drift-prevention gates, each closing a class the
.harness/drift-log.mdhad recorded but left un-automated, wired into
scripts/pre-push-validate.shTier-1:
validate-runtime-overlay-coverage.sh(every snapshot runtime must have a
CLI overlay and abom/pom.xmlartifact — drift #59);
validate-dangling-doc-comments.sh(parse-onlyjavac -Xlint:dangling-doc-comments
under a JDK ≥ 23 to catch detached Javadoc locally, not only on the Native
Image lane — drift #80);
validate-doc-version-alignment.sh(third-party dependency versions in
Markdown must match the pinnedpom.xml/package.json— drift #12/#18/#75);
andvalidate-doc-symbols.sh(annotation references in Markdown must resolve
to an in-tree declaration or a curated external allowlist — drift #72). Two of the
gates caught a pre-existing drift on first run:atmosphere-semantic-kernel
was missing frombom/pom.xml(now added), andmodules/langchain4j/README.md
named LangChain4j 1.12.2 while the pom pins 1.15.0 (now corrected). CLI overlay
coverage was also extended to the three native runtimes (anthropic,cohere,
crewai) incli-e2e.ymlpath filters and thetest-cli.shscaffold+compile
matrix.