Skip to content
Open
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
542 changes: 542 additions & 0 deletions docs/superpowers/plans/2026-06-07-examples-ag-ui-local.md

Large diffs are not rendered by default.

93 changes: 93 additions & 0 deletions examples/ag-ui/angular/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{
"name": "examples-ag-ui-angular",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "examples/ag-ui/angular/src",
"projectType": "application",
"prefix": "app",
"targets": {
"build": {
"executor": "@angular/build:application",
"outputs": [
"{options.outputPath.base}"
],
"options": {
"outputPath": {
"base": "dist/examples/ag-ui/angular",
"browser": ""
},
"index": "examples/ag-ui/angular/src/index.html",
"browser": "examples/ag-ui/angular/src/main.ts",
"tsConfig": "examples/ag-ui/angular/tsconfig.app.json",
"assets": [
{
"glob": "**/*",
"input": "examples/ag-ui/angular/public"
}
],
"styles": [
"examples/ag-ui/angular/src/styles.css"
]
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1.5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "10kb",
"maximumError": "16kb"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true,
"fileReplacements": [
{
"replace": "examples/ag-ui/angular/src/environments/environment.ts",
"with": "examples/ag-ui/angular/src/environments/environment.development.ts"
}
]
}
},
"defaultConfiguration": "development"
},
"serve": {
"continuous": true,
"executor": "@angular/build:dev-server",
"options": {
"port": 4201,
"proxyConfig": "examples/ag-ui/angular/proxy.conf.mjs"
},
"configurations": {
"production": {
"buildTarget": "examples-ag-ui-angular:build:production"
},
"development": {
"buildTarget": "examples-ag-ui-angular:build:development"
}
},
"defaultConfiguration": "development"
},
"test": {
"executor": "@nx/vitest:test",
"options": {
"configFile": "examples/ag-ui/angular/vite.config.mts"
}
},
"lint": {
"executor": "@nx/eslint:lint"
}
},
"tags": [
"scope:examples",
"scope:examples-ag-ui",
"type:app"
]
}
5 changes: 5 additions & 0 deletions examples/ag-ui/angular/proxy.conf.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// SPDX-License-Identifier: MIT
// Dev only: routes the relative /agent calls to the local uvicorn ag-ui server.
export default {
'/agent': { target: 'http://localhost:8000', secure: false, changeOrigin: true, ws: true },
};
Binary file added examples/ag-ui/angular/public/favicon.ico
Binary file not shown.
20 changes: 20 additions & 0 deletions examples/ag-ui/angular/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
import {
ApplicationConfig,
provideBrowserGlobalErrorListeners,
provideZonelessChangeDetection,
} from '@angular/core';
import { provideThreadplaneTelemetry } from '@threadplane/telemetry/browser';
import { provideChat } from '@threadplane/chat';
import { provideAgent } from '@threadplane/ag-ui';
import { environment } from '../environments/environment';

export const appConfig: ApplicationConfig = {
providers: [
provideBrowserGlobalErrorListeners(),
provideZonelessChangeDetection(),
provideThreadplaneTelemetry(environment.telemetry),
provideAgent({ url: environment.agentUrl }),
provideChat({ license: environment.license }),
],
};
7 changes: 7 additions & 0 deletions examples/ag-ui/angular/src/app/app.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<main class="ag-ui-demo">
<header class="ag-ui-demo__header">
<h1>AG-UI Chat</h1>
<p>The Threadplane chat UI over the AG-UI transport.</p>
</header>
<chat main [agent]="agent" class="ag-ui-demo__chat" />
</main>
15 changes: 15 additions & 0 deletions examples/ag-ui/angular/src/app/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { injectAgent } from '@threadplane/ag-ui';
import { ChatComponent } from '@threadplane/chat';

@Component({
selector: 'app-root',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ChatComponent],
templateUrl: './app.html',
})
export class App {
protected readonly agent = injectAgent();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT
export const environment = {
production: false,
agentUrl: '/agent',
telemetry: { enabled: false, sampleRate: 1 },
license: undefined as string | undefined,
};
7 changes: 7 additions & 0 deletions examples/ag-ui/angular/src/environments/environment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT
export const environment = {
production: true,
agentUrl: '/agent',
telemetry: { enabled: false, sampleRate: 1 },
license: undefined as string | undefined,
};
13 changes: 13 additions & 0 deletions examples/ag-ui/angular/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>AG-UI Chat — Threadplane Example</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>
6 changes: 6 additions & 0 deletions examples/ag-ui/angular/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: MIT
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { App } from './app/app';

bootstrapApplication(App, appConfig).catch((err) => console.error(err));
100 changes: 100 additions & 0 deletions examples/ag-ui/angular/src/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
html, body {
margin: 0;
padding: 0;
height: 100%;
font-family: system-ui, -apple-system, sans-serif;
background: var(--demo-page-bg);
color: var(--demo-page-text);
}

/*
* Demo page color scheme — driven by `data-color-scheme` on <html>.
* The pre-bootstrap inline script in index.html sets the attribute
* from persisted state before any stylesheet applies; the runtime
* effect in DemoShell keeps it in sync afterwards. Default (no
* attribute) is dark to match prior behavior.
*/
html {
--demo-page-bg: #0f1116;
--demo-page-text: #e6e9ef;
}
html[data-color-scheme="light"] {
--demo-page-bg: #ffffff;
--demo-page-text: #1c1c1c;
}

/*
* A2UI theme presets — switched at runtime via the palette "Theme"
* dropdown by toggling `data-theme` on the document root. Mirrors the
* preset CSS files shipped from `@threadplane/chat/themes/*.css`; we inline
* them here to avoid the workspace-vs-published-path resolution
* complexity of importing them dynamically. Default ('default-dark')
* uses the lib's :host defaults, so no override block is needed.
*/

html[data-theme='default-light'] {
--a2ui-primary: #4f8df5;
--a2ui-on-primary: #ffffff;
--a2ui-primary-hover: #3b7be3;
--a2ui-secondary: #5b6275;
--a2ui-on-secondary: #ffffff;
--a2ui-surface: #fafafa;
--a2ui-on-surface: #1a1d23;
--a2ui-surface-variant: rgba(0, 0, 0, 0.04);
--a2ui-on-surface-variant: rgba(0, 0, 0, 0.6);
--a2ui-outline: rgba(0, 0, 0, 0.12);
--a2ui-outline-variant: rgba(0, 0, 0, 0.06);
--a2ui-error: #d33533;
--a2ui-on-error: #ffffff;
--a2ui-scrim: rgba(0, 0, 0, 0.4);
--a2ui-elevation-1: 0 1px 2px rgba(0, 0, 0, 0.08);
--a2ui-elevation-2: 0 2px 4px rgba(0, 0, 0, 0.10);
--a2ui-elevation-3: 0 4px 8px rgba(0, 0, 0, 0.12);
--a2ui-elevation-4: 0 8px 16px rgba(0, 0, 0, 0.14);
--a2ui-elevation-5: 0 16px 32px rgba(0, 0, 0, 0.16);
}

html[data-theme='material-dark'] {
--a2ui-primary: #D0BCFF;
--a2ui-on-primary: #381E72;
--a2ui-primary-hover: #B69DF8;
--a2ui-secondary: #CCC2DC;
--a2ui-on-secondary: #332D41;
--a2ui-surface: #1C1B1F;
--a2ui-on-surface: #E6E1E5;
--a2ui-surface-variant: #49454F;
--a2ui-on-surface-variant: #CAC4D0;
--a2ui-outline: #938F99;
--a2ui-outline-variant: #49454F;
--a2ui-error: #F2B8B5;
--a2ui-on-error: #601410;
--a2ui-scrim: rgba(0, 0, 0, 0.6);
}

html[data-theme='material-light'] {
--a2ui-primary: #6750A4;
--a2ui-on-primary: #FFFFFF;
--a2ui-primary-hover: #533F8E;
--a2ui-secondary: #625B71;
--a2ui-on-secondary: #FFFFFF;
--a2ui-surface: #FFFBFE;
--a2ui-on-surface: #1C1B1F;
--a2ui-surface-variant: #E7E0EC;
--a2ui-on-surface-variant: #49454F;
--a2ui-outline: #79747E;
--a2ui-outline-variant: #CAC4D0;
--a2ui-error: #B3261E;
--a2ui-on-error: #FFFFFF;
--a2ui-scrim: rgba(0, 0, 0, 0.4);
--a2ui-elevation-1: 0 1px 2px rgba(0, 0, 0, 0.08);
--a2ui-elevation-2: 0 2px 4px rgba(0, 0, 0, 0.10);
--a2ui-elevation-3: 0 4px 8px rgba(0, 0, 0, 0.12);
--a2ui-elevation-4: 0 8px 16px rgba(0, 0, 0, 0.14);
--a2ui-elevation-5: 0 16px 32px rgba(0, 0, 0, 0.16);
}

.ag-ui-demo { display: flex; flex-direction: column; height: 100dvh; }
.ag-ui-demo__header { padding: 12px 16px; border-bottom: 1px solid var(--tp-border, #e5e7eb); }
.ag-ui-demo__header h1 { margin: 0; font-size: 1.1rem; }
.ag-ui-demo__header p { margin: 2px 0 0; font-size: 0.85rem; opacity: 0.7; }
.ag-ui-demo__chat { flex: 1 1 auto; min-height: 0; }
12 changes: 12 additions & 0 deletions examples/ag-ui/angular/src/test-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
import { getTestBed } from '@angular/core/testing';
import {
BrowserTestingModule,
platformBrowserTesting,
} from '@angular/platform-browser/testing';

getTestBed().initTestEnvironment(
BrowserTestingModule,
platformBrowserTesting(),
{ teardown: { destroyAfterEach: true } },
);
22 changes: 22 additions & 0 deletions examples/ag-ui/angular/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"lib": ["es2022", "dom"],
"types": [],
"emitDeclarationOnly": false
},
"files": ["src/main.ts"],
"include": ["src/**/*.ts"],
"references": [
{
"path": "../../../libs/ag-ui"
},
{
"path": "../../../libs/chat"
},
{
"path": "../../../libs/telemetry/tsconfig.lib.json"
}
]
}
24 changes: 24 additions & 0 deletions examples/ag-ui/angular/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"noPropertyAccessFromIndexSignature": false,
"experimentalDecorators": true,
"module": "preserve",
"emitDeclarationOnly": false,
"composite": false,
"lib": ["es2022", "dom"],
"skipLibCheck": true,
"strict": false
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": false,
"strictInputAccessModifiers": false,
"strictTemplates": false
},
"files": [],
"include": [],
"references": [
{ "path": "./tsconfig.app.json" }
]
}
19 changes: 19 additions & 0 deletions examples/ag-ui/angular/vite.config.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/// <reference types='vitest' />
import { defineConfig } from 'vite';
import angular from '@analogjs/vite-plugin-angular';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';

export default defineConfig({
root: __dirname,
cacheDir: '../../../node_modules/.vite/examples-ag-ui-angular',
plugins: [angular(), nxViteTsPaths()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: ['src/test-setup.ts'],
include: ['src/**/*.spec.ts'],
reporters: ['default'],
pool: 'forks',
passWithNoTests: true,
},
});
21 changes: 21 additions & 0 deletions examples/ag-ui/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "examples-ag-ui",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"sourceRoot": "examples/ag-ui",
"targets": {
"serve": {
"executor": "nx:run-commands",
"options": {
"commands": [
"npx nx run examples-ag-ui-python:serve",
"npx nx run examples-ag-ui-angular:serve"
],
"parallel": true
}
}
},
"tags": [
"scope:examples-ag-ui"
]
}
3 changes: 3 additions & 0 deletions examples/ag-ui/python/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copy to .env and fill in your key. Required for the demo to make
# real LLM calls against the OpenAI API.
OPENAI_API_KEY=sk-...
1 change: 1 addition & 0 deletions examples/ag-ui/python/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
Loading