Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions integrations/aws-strands/typescript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,13 +194,11 @@ The adapter advertises an event / feature matrix at GET `/capabilities`
`addCapabilities(app, path, { agent, overrides })` to derive the chunk flags from
a live agent's `emitChunkEvents` rather than pinning them).

Two flags in that matrix need reading with care. `DEFAULT_CAPABILITIES` reports
`events.RAW: false`, which predates the adapter emitting `RAW` at all: the
passthrough described below is live whatever the matrix says, so do not gate a
client on that flag. `events.STATE_DELTA: false` and `features.stateDelta: false`
are not a mistake, and mean what they say about the adapter, which emits no delta
of its own; a `customResultHandler` that emits one is your own addition. Fold an
override in for either if you serve the matrix to something that reads it.
One flag in that matrix needs reading with care. `events.STATE_DELTA: false` and
`features.stateDelta: false` are not a mistake, and mean what they say about the
adapter, which emits no delta of its own; a `customResultHandler` that emits one
is your own addition. Fold an override in if you serve the matrix to something
that reads it.

## Unmapped Strands events reach the client as `RAW`

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { describe, it, expect } from "vitest";
import express from "express";
import type { AddressInfo } from "net";
import { EventType } from "@ag-ui/core";
import type { AgentStreamEvent } from "@strands-agents/sdk";

import {
addCapabilities,
capabilitiesFor,
DEFAULT_CAPABILITIES,
} from "../endpoint";
import { StrandsAgent } from "../agent";
import { collect, scriptedStrandsAgent } from "./helpers";

async function startApp(configure: (app: express.Express) => void): Promise<{
port: number;
Expand Down Expand Up @@ -170,3 +173,61 @@ describe("capabilitiesFor / addCapabilities { agent }", () => {
}
});
});

describe("the advertised matrix against what a run publishes", () => {
// An unmapped provider event: real, carries a payload no mapped AG-UI event
// conveys, and the adapter has no branch for it. Same guardrail redaction
// `raw-fallback.test.ts` uses to pin the fallback itself.
const UNMAPPED_EVENT = {
type: "modelRedactionEvent",
outputRedaction: { text: "[redacted]" },
} as unknown as AgentStreamEvent;

async function runEmitsRaw(): Promise<boolean> {
const events = await collect(scriptedStrandsAgent([UNMAPPED_EVENT]));
return events.some((e) => e.type === EventType.RAW);
}

it("advertises RAW exactly when a run publishes one", async () => {
// Read off a real run rather than hardcoded, so the flag cannot drift away
// from the adapter again: the terminal fallback in `agent.ts` forwards
// every unmapped Strands event as RAW, unconditionally.
const emitsRaw = await runEmitsRaw();
expect(
emitsRaw,
"no RAW event on the wire to compare the flag against",
).toBe(true);

const { port, close } = await startApp((app) =>
addCapabilities(app, "/capabilities"),
);
try {
const res = await fetch(`http://127.0.0.1:${port}/capabilities`);
const body = await res.json();
expect(body.events.RAW).toBe(emitsRaw);
} finally {
await close();
}
});

it("keeps RAW advertised in chunk mode", async () => {
// The fallback is not gated on `emitChunkEvents`, so neither is the flag.
const emitsRaw = await runEmitsRaw();
const agent = new StrandsAgent({
agent: {
model: {},
tools: [],
toolRegistry: {
list: () => [],
add() {},
get: () => undefined,
remove() {},
},
sessionManager: undefined,
} as unknown as import("@strands-agents/sdk").Agent,
name: "cap",
config: { emitChunkEvents: true },
});
expect(capabilitiesFor(agent).events.RAW).toBe(emitsRaw);
});
});
6 changes: 3 additions & 3 deletions integrations/aws-strands/typescript/src/endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,8 +490,8 @@ export function addPing(app: Express, path: string): void {
/**
* Static description of what this adapter actually supports. Every event
* family here can be observed on the wire; anything missing is either not
* emitted by this adapter (e.g. `ACTIVITY_*`, `RAW`) or only emitted in
* specific configurations (the `*_CHUNK` events, gated by
* emitted by this adapter (e.g. `ACTIVITY_*`, `SUBAGENT_*`) or only emitted
* in specific configurations (the `*_CHUNK` events, gated by
* `emitChunkEvents` — use {@link capabilitiesFor} to derive the matrix
* from a concrete agent and pick those flags up automatically).
*
Expand Down Expand Up @@ -596,7 +596,7 @@ export const DEFAULT_CAPABILITIES: StrandsAguiCapabilities = {
CUSTOM: true,
ACTIVITY_SNAPSHOT: false,
ACTIVITY_DELTA: false,
RAW: false,
RAW: true,
},
features: {
interrupts: true,
Expand Down
Loading