Skip to content

Atmosphere 4.0.50

Choose a tag to compare

@github-actions github-actions released this 05 Jun 12:58
Immutable release. Only release title and notes can be modified.

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 by McpHandler's direct WebSocket-frame
    handling), AgUiSession (superseded by ResourceAgUiStreamingSession),
    AiCoalescingBroadcasterCache (a delegate-only BroadcasterCache that the
    no-arg reflective cache-wiring path cannot instantiate), AdkArtifactBridge,
    AdkCompactionBridge, AtmosphereRequestBridge, AtmosphereResponseBridge,
    the channels AuditLoggingFilter (never registered as a bean, so it never
    reached the filter chain), the unwired GrpcProtocolBridge, and the A2A
    ListTaskPushNotificationConfigsResponse DTO (the
    ListTaskPushNotificationConfigs method returns ERROR_PUSH_NOT_SUPPORTED,
    so the response type was never constructed).

Fixed

  • ToolBridgeUtils.findUnescapedQuote no 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, artifact atmosphere-interactions)
    — a stateful agent-turn resource layered above the AgentRuntime SPI, so it
    works for every adapter with no per-runtime code. An Interaction carries a
    stable id, a durable steps[] 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 a RUNNING record immediately and is retrievable after a disconnect),
    and store=false streams without persisting. The starter exposes the resource
    over POST /api/interactions, POST /api/interactions/{id}/continue,
    GET /api/interactions/{id}, GET /api/interactions,
    POST /api/interactions/{id}/cancel, and DELETE /api/interactions/{id}
    every mutating route is default-deny behind atmosphere.interactions.http-write-enabled
    plus an authenticated principal (Correctness Invariant #6). Two InteractionStore
    backends ship: InMemoryInteractionStore (default) and SqliteInteractionStore;
    the SPI is pluggable for others. atmosphere.js gains a typed InteractionsClient
    (atmosphere.js/interactions) covering the REST surface plus pollUntilTerminal
    / watch helpers.

  • Interactions live streaming — a background interaction now streams its
    durable steps[] 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.
    An AtmosphereInterceptor resolves 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 in spring-boot-coding-agent
    and spring-boot-multi-agent-startup-team.

  • ToolKind + @AiTool(kind = …) — tools declare a behavioural category
    (EDIT, READ, EXECUTE, NETWORK, DELETE, OTHER; default OTHER).
    This makes PermissionMode.ACCEPT_EDITS a real behaviour instead of a
    DEFAULT alias: it now auto-approves a tool's own @RequiresApproval
    prompt when kind == 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 default OTHER keeps the approval
    posture exactly as restrictive as before, and the relaxation never overrides
    an operator-configured ToolPermissionPolicy DENY/CONFIRM or a DenyAll
    policy. ToolExecutionHelperAcceptEditsTest pins all four cases.

  • Code-as-action sandbox (org.atmosphere.ai.code) — a code_exec tool 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 (CodeSandbox SPI, ContainerCodeSandbox over
    Docker/Podman) with hardening applied — --network none by 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 new StreamingSession.onTerminate(AutoCloseable)
    primitive. Default-deny: code execution is off unless
    org.atmosphere.ai.code.enabled=true and 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 an AiEvent.AgentStep plus any screenshots the code
    produced, rendered inline in the Console as markdown data-URI images. New
    samples/spring-boot-browser-agent demonstrates it (Cohere-backed, requires
    Docker): the agent drives a headless browser with Playwright and you watch the
    screenshots arrive live.

Changed

  • ai-policy-rego and ai-policy-cedar now ship a
    META-INF/services/org.atmosphere.ai.governance.PolicyParser registration,
    so Rego and Cedar policy artifacts are auto-discovered by ServiceLoader
    the same way YAML always has been — no programmatic parser wiring required.
    Safe because both parsers have lazy no-arg constructors (the opa / cedar
    binary is only touched at evaluation, and parse failure is already
    fail-closed). The Kafka/Postgres audit sinks are deliberately left on
    programmatic GovernanceDecisionLog.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 / CedarPolicyParserTest pin the
    discovery.
  • Four new pre-push drift-prevention gates, each closing a class the
    .harness/drift-log.md had recorded but left un-automated, wired into
    scripts/pre-push-validate.sh Tier-1:
    validate-runtime-overlay-coverage.sh (every snapshot runtime must have a
    CLI overlay and a bom/pom.xml artifact — drift #59);
    validate-dangling-doc-comments.sh (parse-only javac -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 pinned pom.xml/package.json — drift #12/#18/#75);
    and validate-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 from bom/pom.xml (now added), and modules/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) in cli-e2e.yml path filters and the test-cli.sh scaffold+compile
    matrix.