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
18 changes: 9 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,7 @@ jobs:
NODE

ag-ui-demo-deploy:
name: ag-ui demo → Vercel
name: AG-UI demo → Vercel
timeout-minutes: 30 # fail fast instead of blocking the main concurrency group on a hang
needs: [examples-ag-ui-e2e]
runs-on: ubuntu-latest
Expand All @@ -1024,10 +1024,10 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Require ag-ui demo prerequisite jobs
- name: Require AG-UI demo prerequisite jobs
run: |
if [ "${{ needs.examples-ag-ui-e2e.result }}" != "success" ]; then
echo "::error::examples/ag-ui — e2e finished with ${{ needs.examples-ag-ui-e2e.result }}; refusing to deploy the ag-ui demo."
echo "::error::examples/ag-ui — e2e finished with ${{ needs.examples-ag-ui-e2e.result }}; refusing to deploy the AG-UI demo."
exit 1
fi
# Same staleness guard as the other production promotions.
Expand All @@ -1043,11 +1043,11 @@ jobs:
fi
if [ "$tip" != "${{ github.sha }}" ]; then
echo "stale=true" >> "$GITHUB_OUTPUT"
echo "::warning::main has advanced to ${tip} since this run started (${{ github.sha }}); skipping the ag-ui demo promotion."
echo "::warning::main has advanced to ${tip} since this run started (${{ github.sha }}); skipping the AG-UI demo promotion."
else
echo "stale=false" >> "$GITHUB_OUTPUT"
fi
- name: Check if ag-ui demo changed
- name: Check if AG-UI demo changed
id: ag_ui_changed
run: |
base_sha="${{ github.event.before }}"
Expand All @@ -1065,7 +1065,7 @@ jobs:
fi
echo "changed=$ag_ui_changed" >> "$GITHUB_OUTPUT"
if [ "$ag_ui_changed" != "true" ]; then
echo "::notice::No ag-ui demo files changed; skipping ag-ui demo deploy."
echo "::notice::No AG-UI demo files changed; skipping AG-UI demo deploy."
fi
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
if: steps.freshness.outputs.stale != 'true' && steps.ag_ui_changed.outputs.changed == 'true'
Expand All @@ -1079,7 +1079,7 @@ jobs:
python-version: '3.12'
- if: steps.freshness.outputs.stale != 'true' && steps.ag_ui_changed.outputs.changed == 'true'
run: npm ci
- name: Build and assemble ag-ui demo
- name: Build and assemble AG-UI demo
if: steps.freshness.outputs.stale != 'true' && steps.ag_ui_changed.outputs.changed == 'true'
env:
# Baked into the SPA bundle by inject-env at build time. Without the
Expand All @@ -1089,7 +1089,7 @@ jobs:
GOOGLE_MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
GOOGLE_MAPS_MAP_ID: 86d464ea7d5306034fe2a254
run: npx tsx scripts/assemble-ag-ui-demo.ts
- name: Deploy ag-ui demo SPA to Vercel (production)
- name: Deploy AG-UI demo SPA to Vercel (production)
if: steps.freshness.outputs.stale != 'true' && steps.ag_ui_changed.outputs.changed == 'true'
run: |
mkdir -p deploy/ag-ui-demo/.vercel
Expand All @@ -1099,7 +1099,7 @@ jobs:
cd deploy/ag-ui-demo
npx vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
npx vercel deploy --prebuilt --prod --yes --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy ag-ui backend to Railway
- name: Deploy AG-UI backend to Railway
if: steps.freshness.outputs.stale != 'true' && steps.ag_ui_changed.outputs.changed == 'true'
working-directory: examples/ag-ui/python
env:
Expand Down
10 changes: 5 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@

- **ci:** never promote a superseded commit to production ([#816](https://github.com/cacheplane/angular-agent-framework/pull/816), [#813](https://github.com/cacheplane/angular-agent-framework/issues/813), [#814](https://github.com/cacheplane/angular-agent-framework/issues/814))
- **deploy:** restore shared-deployment namespace merge broken by src/__init__.py ([#825](https://github.com/cacheplane/angular-agent-framework/pull/825), [#642](https://github.com/cacheplane/angular-agent-framework/issues/642))
- **examples:** raise ag-ui demo initial bundle budget to chat parity ([#821](https://github.com/cacheplane/angular-agent-framework/pull/821))
- **examples:** raise AG-UI demo initial bundle budget to chat parity ([#821](https://github.com/cacheplane/angular-agent-framework/pull/821))
- **langgraph:** reject non-durable client tool flushes ([#809](https://github.com/cacheplane/angular-agent-framework/pull/809))
- **langgraph:** retain client tool results across failed runs ([#810](https://github.com/cacheplane/angular-agent-framework/pull/810))
- **website:** render grouped API entries on middleware helpers page ([#815](https://github.com/cacheplane/angular-agent-framework/pull/815))
Expand Down Expand Up @@ -164,7 +164,7 @@
### 🩹 Fixes

- remove unused fake agent delay variable ([#787](https://github.com/cacheplane/angular-agent-framework/pull/787))
- **ag-ui:** version authoritative snapshot rewrites ([#804](https://github.com/cacheplane/angular-agent-framework/pull/804))
- **AG-UI:** version authoritative snapshot rewrites ([#804](https://github.com/cacheplane/angular-agent-framework/pull/804))
- **chat:** closed drawer sidenav must not intercept clicks on content ([#778](https://github.com/cacheplane/angular-agent-framework/pull/778))
- **chat:** never leave a client tool call unanswered on the server ([#807](https://github.com/cacheplane/angular-agent-framework/pull/807), [#782](https://github.com/cacheplane/angular-agent-framework/issues/782), [#805](https://github.com/cacheplane/angular-agent-framework/issues/805))
- **cockpit-examples:** use CSS sidebar widths ([496db8e8](https://github.com/cacheplane/angular-agent-framework/commit/496db8e8))
Expand Down Expand Up @@ -359,7 +359,7 @@

### Added

- **`Agent.regenerate(index)`** — new method on the `Agent` interface implemented by both LangGraph and ag-ui adapters. Replace-semantics: discards the target assistant message and all subsequent messages, then re-runs against the prior user prompt. (#199)
- **`Agent.regenerate(index)`** — new method on the `Agent` interface implemented by both LangGraph and AG-UI adapters. Replace-semantics: discards the target assistant message and all subsequent messages, then re-runs against the prior user prompt. (#199)
- **`<chat-message-actions>`** — regenerate button is disabled while `agent.isLoading()`. (#199)

### Fixed
Expand Down Expand Up @@ -481,8 +481,8 @@
- relicense to MIT (selective; minting-service stays proprietary) ([#141](https://github.com/cacheplane/angular-agent-framework/pull/141))
- **a2ui:** align validation with v0.9 CheckRule spec ([#97](https://github.com/cacheplane/angular-agent-framework/pull/97))
- **a2ui:** v0.9 action envelope and sendDataModel transport ([#101](https://github.com/cacheplane/angular-agent-framework/pull/101))
- **ag-ui:** @cacheplane/ag-ui adapter wrapping @ag-ui/client ([#139](https://github.com/cacheplane/angular-agent-framework/pull/139))
- **ag-ui:** FakeAgent for offline cockpit demo ([#140](https://github.com/cacheplane/angular-agent-framework/pull/140))
- **AG-UI:** @cacheplane/ag-ui adapter wrapping @ag-ui/client ([#139](https://github.com/cacheplane/angular-agent-framework/pull/139))
- **AG-UI:** FakeAgent for offline cockpit demo ([#140](https://github.com/cacheplane/angular-agent-framework/pull/140))
- **agent:** run license check at provider init ([fd95400f](https://github.com/cacheplane/angular-agent-framework/commit/fd95400f))
- **chat:** Apple-clean UI redesign + streaming example integration ([499ef645](https://github.com/cacheplane/angular-agent-framework/commit/499ef645))
- **chat:** eliminate streaming jank with append-only markdown and frame-synced pipeline ([#107](https://github.com/cacheplane/angular-agent-framework/pull/107))
Expand Down
2 changes: 1 addition & 1 deletion apps/cockpit/ag-ui-agent-url.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const agentBackedCapabilities = capabilities.filter(
(c) => c.product === 'ag-ui' || c.product === 'runtimes'
);

describe('ag-ui agent URL is resolved against <base href>', () => {
describe('AG-UI agent URL is resolved against <base href>', () => {
it('covers every registered agent-backed capability', () => {
expect(agentBackedCapabilities.length).toBeGreaterThan(0);
});
Expand Down
4 changes: 2 additions & 2 deletions apps/cockpit/cockpit-e2e-wiring.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ describe('cockpit e2e wiring', () => {
errors.push(`${wiring.project}: proxy.conf.mjs does not call portsFor('${wiring.project}')`);
}
} else if (existsSync(proxyJson)) {
// Legacy (allowed for ag-ui exception only); not expected for any
// Legacy (allowed for AG-UI exception only); not expected for any
// cap reaching this code path.
const proxy = JSON.parse(readFileSync(proxyJson, 'utf8')) as Record<string, { target?: string }>;
const target = proxy['/api']?.target;
Expand Down Expand Up @@ -293,7 +293,7 @@ describe('cockpit e2e wiring', () => {
const errors: string[] = [];

const capProjects = listProjectJsonFiles(join(repoRoot, 'cockpit'))
.filter((p) => !p.includes('/ag-ui/')) // ag-ui has no python; out of scope
.filter((p) => !p.includes('/ag-ui/')) // AG-UI has no python; out of scope
.filter((p) => p.includes('/angular/') || p.includes('/python/'))
.map((p) => ({
path: p,
Expand Down
8 changes: 4 additions & 4 deletions apps/cockpit/e2e/production-smoke.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ const RENDER_CAPABILITIES = [
] as const;

/**
* Driven off the capability registry so a newly added ag-ui topic is covered
* Driven off the capability registry so a newly added AG-UI topic is covered
* automatically instead of silently going unasserted — the previous two
* hardcoded checks covered interrupts and streaming only.
*
* Scoped to the ag-ui product: `runtimes` capabilities share the Railway
* Scoped to the AG-UI product: `runtimes` capabilities share the Railway
* runtime but are not yet in the examples route table, so they have no
* /ag-ui/<topic>/ URL to assert against.
*/
Expand Down Expand Up @@ -241,7 +241,7 @@ test.describe('Production: canonical demo sends runtime telemetry', () => {
});
});

test.describe('ag-ui Railway runtime', () => {
test.describe('AG-UI Railway runtime', () => {
const RAILWAY_URL = process.env['AG_UI_RAILWAY_URL'] ?? 'https://ag-ui-dev-production.up.railway.app';

test('healthcheck /ok responds 200', async ({ request }) => {
Expand Down Expand Up @@ -327,7 +327,7 @@ test.describe('examples langgraph proxy hardening', () => {
});
});

test.describe('ag-ui demo (ag-ui.threadplane.ai)', () => {
test.describe('AG-UI demo (ag-ui.threadplane.ai)', () => {
const DEMO = process.env['AG_UI_DEMO_URL'] ?? 'https://ag-ui.threadplane.ai';

test('demo SPA is reachable', async ({ page }) => {
Expand Down
6 changes: 3 additions & 3 deletions apps/cockpit/scripts/capability-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ export interface Capability {
/**
* 'runtimes' is the one-capability-many-runtimes axis
* (cockpit/runtimes/<runtime>/): non-LangGraph AG-UI backends measured
* against the same neutral Agent contract. Like 'ag-ui' caps, they are
* against the same neutral Agent contract. Like AG-UI caps, they are
* served by the aggregated deployments/ag-ui-dev FastAPI app.
*/
product: 'langgraph' | 'deep-agents' | 'render' | 'chat' | 'ag-ui' | 'runtimes';
topic: string;
angularProject: string;
port: number;
pythonPort?: number;
/** Optional — ag-ui caps run in-process via FakeAgent and have no Python backend. */
/** Optional — AG-UI caps run in-process via FakeAgent and have no Python backend. */
pythonDir?: string;
/** Optional — see pythonDir. */
graphName?: string;
Expand Down Expand Up @@ -85,7 +85,7 @@ export const capabilities: readonly Capability[] = [
{ id: 'ag-ui-a2ui', product: 'ag-ui', topic: 'a2ui', angularProject: 'cockpit-ag-ui-a2ui-angular', port: 4324, pythonPort: 5324, pythonDir: 'cockpit/ag-ui/a2ui/python' },
{ id: 'ag-ui-subagents', product: 'ag-ui', topic: 'subagents', angularProject: 'cockpit-ag-ui-subagents-angular', port: 4326, pythonPort: 5326, pythonDir: 'cockpit/ag-ui/subagents/python' },
// Runtime-portability examples (one capability, many runtimes; AG-UI-served
// like the ag-ui caps, but the backend is genuinely non-LangGraph)
// like the AG-UI caps, but the backend is genuinely non-LangGraph)
{ id: 'rt-maf', product: 'runtimes', topic: 'microsoft-agent-framework', angularProject: 'cockpit-runtimes-microsoft-agent-framework-angular', port: 4330, pythonPort: 5330, pythonDir: 'cockpit/runtimes/microsoft-agent-framework/python', framework: 'microsoft-agent-framework' },
{ id: 'rt-strands', product: 'runtimes', topic: 'aws-strands', angularProject: 'cockpit-runtimes-aws-strands-angular', port: 4331, pythonPort: 5331, pythonDir: 'cockpit/runtimes/aws-strands/python', framework: 'aws-strands' },
// No pythonDir: the Mastra topic's backend is the hand-written Node
Expand Down
2 changes: 1 addition & 1 deletion apps/cockpit/scripts/generate-combined-langgraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const graphs: Record<string, string> = {};
const dependencies = new Set<string>();
for (const c of capabilities) {
if (!c.pythonDir || !c.graphName) {
continue; // ag-ui (in-process) and other no-Python caps
continue; // AG-UI (in-process) and other no-Python caps
}
graphs[c.graphName] = `./${c.pythonDir}/${normalizeEntrypoint(c.pythonDir, c.graphName)}`;
dependencies.add(`./${c.pythonDir}`);
Expand Down
2 changes: 1 addition & 1 deletion apps/cockpit/scripts/serve-example.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { backendCommand, COCKPIT_RUNTIME_ENV, formatAllModeSummary } from './ser
import { capabilities, findCapability, type Capability } from './capability-registry';

describe('backendCommand', () => {
it('uses uvicorn on the registry pythonPort for ag-ui caps', () => {
it('uses uvicorn on the registry pythonPort for AG-UI caps', () => {
const cap = findCapability('ag-ui-streaming')!;
const cmd = backendCommand(cap)!;
expect(cmd).toContain('cd cockpit/ag-ui/streaming/python');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "Build Fullstack Agentic Angular Apps Using AG-UI"
description: "A practical walkthrough for wiring any AG-UI backend — LangGraph, CrewAI, Mastra, Pydantic AI, and more — to a production Angular chat UI."
date: 2026-05-21
tags: [tutorial, ag-ui, angular, agents, langgraph]
tags: [tutorial, AG-UI, angular, agents, langgraph]
author: brian
featured: true
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "Human-in-the-Loop AG-UI Agents in Angular"
description: "Build a human-in-the-loop AG-UI agent in Angular — the same chat-approval-card composition as the LangGraph version, wired to AG-UI via @threadplane/ag-ui."
date: 2026-06-04
tags: [tutorial, ag-ui, angular, agents, hitl, interrupts]
tags: [tutorial, AG-UI, angular, agents, hitl, interrupts]
author: brian
featured: true
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'Agentic UI in Angular: Production Patterns After the Demo'
description: 'Production patterns for agentic UI in Angular: signals, tool progress, approvals, durable threads, constrained generative UI, and recovery.'
date: 2026-08-09
tags: [opinion, patterns, agentic-ui, ag-ui, angular, production]
tags: [opinion, patterns, agentic-ui, AG-UI, angular, production]
author: brian
draft: false
featured: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'Build an AWS Strands Agent UI in Angular with AG-UI'
description: 'Connect an AWS Strands agent to an Angular chat over AG-UI SSE with Threadplane, then prepare the same server for optional AgentCore deployment.'
date: 2026-08-09
tags: [tutorial, aws-strands, ag-ui, angular, agentic-ui]
tags: [tutorial, aws-strands, AG-UI, angular, agentic-ui]
author: brian
featured: true
draft: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'Angular Chat App Tutorial with AG-UI'
description: 'Build an Angular chat app on AG-UI where the browser owns its own tools — action, view, and ask tools rendering real components inline, plus shared state.'
date: 2026-08-13
tags: [tutorial, ag-ui, angular, client-tools, agentic-ui]
tags: [tutorial, AG-UI, angular, client-tools, agentic-ui]
author: brian
featured: false
draft: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'We Measured the Runtime Swap: Three Non-LangGraph Backends, One Angular Contract'
description: 'Strands, Microsoft Agent Framework, and Mastra against the neutral Agent contract. Messages, tools, and state ported. Both defects we found were ours.'
date: 2026-08-31
tags: [ag-ui, angular, architecture, portability, agentic-ui]
tags: [AG-UI, angular, architecture, portability, agentic-ui]
author: brian
featured: false
draft: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: 'What Changes in Your Angular Code When the Agent Runtime Changes'
description: 'AG-UI and LangGraph land on the same Angular contract. Here is what actually differs — and which differences are the protocol, not the adapter.'
date: 2026-08-31
tags: [ag-ui, langgraph, angular, architecture, agentic-ui]
tags: [AG-UI, langgraph, angular, architecture, agentic-ui]
author: brian
featured: false
draft: false
Expand Down
4 changes: 2 additions & 2 deletions apps/website/content/docs/ag-ui/guides/testing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
`@threadplane/ag-ui` gives you two test doubles, smallest scope first:

- **`provideFakeAgent()`** — a one-call fake backend that runs the real adapter pipeline and streams canned tokens. No server, no LLM.
- **`mockAgent()`** (from `@threadplane/chat`) — a writable-signal mock for component/unit tests. The ag-ui agent _is_ the neutral `Agent` contract, so there is no ag-ui-specific mock — use the neutral one directly.
- **`mockAgent()`** (from `@threadplane/chat`) — a writable-signal mock for component/unit tests. The AG-UI agent _is_ the neutral `Agent` contract, so there is no AG-UI-specific mock — use the neutral one directly.

See [Choosing an adapter → Testing](/docs/choosing-an-adapter#testing) for when to use each test double.

Expand Down Expand Up @@ -89,7 +89,7 @@ describe('chat via provideFakeAgent', () => {

For component and unit tests where you don't need a streaming pipeline at all, use the neutral `mockAgent(initial)` from `@threadplane/chat`. It returns an `Agent` whose state surface is exposed as **writable signals** — set state directly and assert your component reacts. Nothing is real.

The ag-ui adapter exposes exactly the neutral `Agent` contract, so there is no ag-ui-specific mock — `mockAgent()` is the right tool.
The AG-UI adapter exposes exactly the neutral `Agent` contract, so there is no AG-UI-specific mock — `mockAgent()` is the right tool.

```typescript
import { mockAgent } from '@threadplane/chat';
Expand Down
4 changes: 2 additions & 2 deletions apps/website/content/docs/chat/api/api-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -6600,7 +6600,7 @@
{
"name": "Citation",
"kind": "interface",
"description": "Provider-agnostic citation entry. Populated by adapters from message\nmetadata (LangGraph additional_kwargs.citations, ag-ui STATE_DELTA at\n/citations/{messageId}). Pandoc-formatted [^id]: ... defs in message\ncontent remain in the markdown AST sidecar and are merged via\nCitationsResolverService at render time.",
"description": "Provider-agnostic citation entry. Populated by adapters from message\nmetadata (LangGraph additional_kwargs.citations, AG-UI STATE_DELTA at\n/citations/{messageId}). Pandoc-formatted [^id]: ... defs in message\ncontent remain in the markdown AST sidecar and are merged via\nCitationsResolverService at render time.",
"properties": [
{
"name": "extra",
Expand Down Expand Up @@ -7525,7 +7525,7 @@
{
"name": "lifecycle",
"type": "object",
"description": "Minimal lifecycle stub the chat lib's effects subscribe to. We only\nmodel the signals the chat composition currently reads; richer adapter\nlifecycles (langgraph, ag-ui) extend this contract on their own mocks.\nThe public `lifecycle` view is a readonly signal; tests drive the\nvalue via `_internal.streamStartedAt.set(...)` below.",
"description": "Minimal lifecycle stub the chat lib's effects subscribe to. We only\nmodel the signals the chat composition currently reads; richer adapter\nlifecycles (langgraph, AG-UI) extend this contract on their own mocks.\nThe public `lifecycle` view is a readonly signal; tests drive the\nvalue via `_internal.streamStartedAt.set(...)` below.",
"optional": false
},
{
Expand Down
2 changes: 1 addition & 1 deletion apps/website/src/components/docs/LibraryMark.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('LibraryMark', () => {
expect(container.querySelector('svg')).not.toBeNull();
});

it('maps ag-ui and a2ui to their vendor logos', () => {
it('maps AG-UI and a2ui to their vendor logos', () => {
const { container: a } = render(<LibraryMark library="ag-ui" />);
expect(a.querySelector('img')?.getAttribute('src')).toBe('/logos/ag-ui.svg');
const { container: b } = render(<LibraryMark library="a2ui" />);
Expand Down
Loading
Loading