### Install and start the Node AG-UI service Source: https://threadplane.ai/docs/runtimes/mastra/quickstart Installs the service's dependencies and starts the Node AG-UI service with required environment variables. The service listens on port 5332 and requires AG_UI_INTERNAL_TOKEN and OPENAI_API_KEY. ```bash cd deployments/ag-ui-mastra npm ci AG_UI_INTERNAL_TOKEN=dev-local-token \ OPENAI_API_KEY=sk-... \ PORT=5332 node server.mjs ``` -------------------------------- ### Verify installation with TestComponent Source: https://threadplane.ai/docs/langgraph/getting-started/installation Create a minimal Angular component to verify the setup. injectAgent() must be called in an injection context (component field initializer or inside inject()). Logs 'idle' status if setup is correct. ```typescript import { Component } from '@angular/core'; import { injectAgent } from '@threadplane/langgraph'; @Component({ selector: 'app-test', template: '' }) export class TestComponent { protected readonly test = injectAgent(); constructor() { console.log(this.test.status()); // 'idle' — setup is correct } } ``` -------------------------------- ### Start the Angular app with serve-example.ts Source: https://threadplane.ai/docs/runtimes/mastra/quickstart Starts the Angular dev server using the serve-example.ts script with the rt-mastra capability. ```bash npx tsx scripts/examples/serve-example.ts --capability=rt-mastra ``` -------------------------------- ### Start both halves with serve-example.ts Source: https://threadplane.ai/docs/runtimes/microsoft-agent-framework/quickstart Starts the Angular dev server and Python backend together. Runs uv sync on the way, so first start takes longer. Two processes appear in output; stopping the script stops both. ```bash npx tsx scripts/examples/serve-example.ts --capability=rt-maf ``` -------------------------------- ### Start the dev server Source: https://threadplane.ai/docs/langgraph/getting-started/introduction Starts the LangGraph dev server from the examples/chat/python directory. The agent runs at http://localhost:2024. ```bash cd examples/chat/python langgraph dev ``` -------------------------------- ### Install @threadplane/a2ui Source: https://threadplane.ai/docs/a2ui/getting-started/quickstart Install the @threadplane/a2ui package. The package has no peer dependencies. ```bash npm install @threadplane/a2ui ``` -------------------------------- ### Video component example Source: https://threadplane.ai/docs/chat/a2ui/catalog Example JSON configuration for the Video component. The url prop defaults to the empty string. ```json { "id": "intro-video", "component": "Video", "url": "https://example.com/intro.mp4" } ``` -------------------------------- ### provideAgent usage example with TripState Source: https://threadplane.ai/docs/ag-ui/api/provide-agent Example showing how to define a typed AgentRef, provide an agent with a static config, and inject it in a component. The example uses a TripState interface and a TRIP ref. ```typescript interface TripState { day: number; places: string[]; } export const TRIP = createAgentRef('trip'); // app.config.ts: providers: [provideAgent(TRIP, { url: 'http://localhost:8000/agent' })] // component: const agent = injectAgent(TRIP); // AgUiAgent ``` -------------------------------- ### Minimal usage example Source: https://threadplane.ai/docs/chat/api/parse-tree-store A minimal example showing how to create a store, push a partial JSON chunk, and read the spec signal. ```typescript const store = createParseTreeStore(parser); store.push('{"type":"Car'); store.spec(); // best-effort Spec | null ``` -------------------------------- ### Start LangGraph dev server Source: https://threadplane.ai/docs/langgraph/getting-started/quickstart Starts the LangGraph development server. Ensure your LangGraph agent is running at the URL configured in provideAgent(). ```bash langgraph dev ``` -------------------------------- ### Install packages for fake agent Source: https://threadplane.ai/docs/chat/getting-started/try-without-a-backend Installs the required packages: the fake agent adapter, chat component, LangChain peers, and `marked` for rendering assistant markdown. `@threadplane/chat` and `@threadplane/langgraph` must be installed, along with the LangChain packages that are peers of the adapter. ```bash npm install @threadplane/chat @threadplane/langgraph @langchain/core @langchain/langgraph-sdk marked ``` -------------------------------- ### Minimal app.config.ts setup Source: https://threadplane.ai/docs/render/getting-started/installation A complete minimal setup for app.config.ts that registers a single Text component. This is part of a minimal app setup that also includes text.component.ts and app.component.ts. ```typescript import { ApplicationConfig } from '@angular/core'; import { provideRender, defineAngularRegistry } from '@threadplane/render'; import { TextComponent } from './text.component'; export const appConfig: ApplicationConfig = { providers: [ provideRender({ registry: defineAngularRegistry({ Text: TextComponent, }), }), ], }; ``` -------------------------------- ### Install packages for AG-UI chat Source: https://threadplane.ai/docs/ag-ui/getting-started/quickstart Install the required packages: @threadplane/chat, @threadplane/ag-ui, @ag-ui/client, @ag-ui/core, and marked. ```bash npm install @threadplane/chat @threadplane/ag-ui @ag-ui/client @ag-ui/core marked ``` -------------------------------- ### Start Angular dev server and Python backend Source: https://threadplane.ai/docs/runtimes/aws-strands/quickstart Starts both the Angular dev server and the Python backend together using npx tsx. The script runs uv sync on first start, so the first start takes longer. Stopping the script stops both processes. ```bash npx tsx scripts/examples/serve-example.ts --capability=rt-strands ``` -------------------------------- ### Install @threadplane/render and dependencies Source: https://threadplane.ai/docs/render/getting-started/installation Installs the @threadplane/render package along with @threadplane/telemetry and @json-render/core. The latter two are peer dependencies that npm installs automatically, but they are pinned explicitly in your package.json. ```bash npm install @threadplane/render @threadplane/telemetry @json-render/core ``` -------------------------------- ### Complete Example: Spec, Store, and Handlers Source: https://threadplane.ai/docs/render/guides/events A complete example of a spec with a counter and increment button, a signal state store, and a handler that increments the count. ```typescript const spec: Spec = { root: 'app', elements: { app: { type: 'Container', props: {}, children: ['counter', 'increment'], }, counter: { type: 'Text', props: { label: { $state: '/count' } }, }, increment: { type: 'Button', props: { label: 'Increment' }, on: { click: { action: 'increment', params: {} }, }, }, }, state: { count: 0 }, }; const store = signalStateStore({ count: 0 }); const handlers = { increment: () => { const current = store.get('/count') as number; store.set('/count', current + 1); }, }; ``` -------------------------------- ### Install LangGraph CLI Source: https://threadplane.ai/docs/langgraph/getting-started/introduction Installs the LangGraph CLI with in-memory storage support using pip. ```bash pip install -U "langgraph-cli[inmem]" ``` -------------------------------- ### Install packages for LangGraph backend Source: https://threadplane.ai/docs/chat/getting-started/installation Install @threadplane/chat, the LangGraph adapter, and required dependencies. Use this when your backend is LangGraph or LangGraph Platform. ```bash # LangGraph backend npm install @threadplane/chat @threadplane/langgraph @langchain/core @langchain/langgraph-sdk marked ``` -------------------------------- ### AudioPlayer component example Source: https://threadplane.ai/docs/chat/a2ui/catalog Example JSON configuration for the AudioPlayer component. The url prop defaults to the empty string; description is optional. ```json { "id": "podcast", "component": "AudioPlayer", "url": "https://example.com/episode.mp3", "description": "Episode 12" } ``` -------------------------------- ### Usage: Render spec with store input Source: https://threadplane.ai/docs/render/api/render-spec-component HTML example showing how to use with a store input, as shown in the Examples section. ```html ``` -------------------------------- ### Start LangGraph dev server Source: https://threadplane.ai/docs/langgraph/getting-started/installation Start the LangGraph dev server with the command 'langgraph dev'. The agent will be available at http://localhost:2024. ```bash # Start LangGraph dev server langgraph dev # Your agent will be available at http://localhost:2024 ``` -------------------------------- ### Typed AgentRef minimal example Source: https://threadplane.ai/docs/langgraph/api/provide-agent A concise example of creating a typed AgentRef and using it with provideAgent and injectAgent to get a fully typed LangGraphAgent. The debugName 'trip' is used in DI error messages. ```typescript export const TRIP = createAgentRef('trip'); // app.config.ts: providers: [provideAgent(TRIP, { assistantId: 'trip-graph' })] // component: const agent = injectAgent(TRIP); // LangGraphAgent ``` -------------------------------- ### Set up environment variables Source: https://threadplane.ai/docs/langgraph/getting-started/introduction Creates a .env file with API keys for OpenAI and LangSmith. ```bash OPENAI_API_KEY=sk-... LANGSMITH_API_KEY=lsv2_... ``` -------------------------------- ### Push to GitHub and deploy via CLI Source: https://threadplane.ai/docs/langgraph/guides/deployment Commands to initialize a Git repository, push to GitHub, install the LangGraph CLI, and deploy. First deployments take 10-15 minutes; subsequent pushes trigger automatic redeployments. ```bash # Initialize and push to GitHub git init && git add . && git commit -m "initial agent" gh repo create my-agent --public --source=. --push # Deploy via CLI (alternative to the LangSmith UI) pip install langgraph-cli langgraph deploy --project my-agent ``` -------------------------------- ### Instantiate a2uiBasicCatalog Source: https://threadplane.ai/docs/chat/a2ui/catalog Instantiate the catalog directly for custom setups. The result can be passed to A2uiSurfaceComponent or used as a starting point for a custom registry. ```typescript const catalog = a2uiBasicCatalog(); ``` -------------------------------- ### Using surface() to get a single surface signal Source: https://threadplane.ai/docs/chat/a2ui/surface-store Example of calling surface() to obtain a signal for a specific surface, which emits undefined until the commit rule is met. ```typescript const dashboard = store.surface('dashboard'); // dashboard() is A2uiSurface | undefined ``` -------------------------------- ### Basic Usage Example Source: https://threadplane.ai/docs/render/api/signal-state-store Illustrates creating a store with an initial state, setting a value at a path, and using lastChange() to observe the change. The lastChange() returns an object with the path and value. ```javascript const store = signalStateStore({ count: 0 }); store.set('/count', 1); store.lastChange?.(); // { path: '/count', value: 1 } ``` -------------------------------- ### Copy backend environment example file Source: https://threadplane.ai/docs/runtimes/aws-strands/quickstart Copies the .env.example file to .env in the Python backend directory. You must fill in a real OPENAI_API_KEY. ```bash cp cockpit/runtimes/aws-strands/python/.env.example \ cockpit/runtimes/aws-strands/python/.env ``` -------------------------------- ### Configure provideAgent in app.config.ts Source: https://threadplane.ai/docs/deep-agents/getting-started/introduction Sets up the Deep Agents agent connection in an Angular application. Requires the LangGraph quickstart setup and uses the assistantId 'agent' registered in langgraph.json. ```TypeScript // app.config.ts import { ApplicationConfig } from '@angular/core'; import { provideAgent } from '@threadplane/langgraph'; export const appConfig: ApplicationConfig = { providers: [ provideAgent({ apiUrl: 'http://localhost:2024', // the key this graph is registered under in langgraph.json assistantId: 'agent', }), ], }; ``` -------------------------------- ### Directly Inject the Agent Token Source: https://threadplane.ai/docs/ag-ui/concepts/architecture You can also inject the token directly using injectAgent() without the full component setup. This is a minimal example showing how to obtain the Agent instance. ```typescript import { inject } from '@angular/core'; import { injectAgent } from '@threadplane/ag-ui'; const agent = injectAgent(); ``` -------------------------------- ### injectAgent() with AgentRef for typed state Source: https://threadplane.ai/docs/ag-ui/api/inject-agent Pass the same ref supplied to provideAgent(ref, …) to carry the state type through DI. The example uses TRIP to get AgUiAgent. ```typescript const agent = injectAgent(TRIP); // AgUiAgent ``` -------------------------------- ### A2UI content example Source: https://threadplane.ai/docs/chat/api/content-classifier A2UI content: when the snapshot starts with the '---a2ui_JSON---' prefix, the classifier parses the remaining lines as JSONL. Read type() (=> 'a2ui') and a2uiSurfaces() for the parsed surfaces. ```typescript const a2uiClassifier = createContentClassifier(); a2uiClassifier.update( '---a2ui_JSON---\n' + '{"version":"v0.9","createSurface":{"surfaceId":"s1","catalogId":"https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json"}}\n' + '{"version":"v0.9","updateComponents":{"surfaceId":"s1","components":[{"id":"root","component":"Text","text":"Hi"}]}}\n', ); a2uiClassifier.type(); // 'a2ui' a2uiClassifier.a2uiSurfaces(); // Map keyed by surface ID a2uiClassifier.dispose(); ``` -------------------------------- ### updateComponents envelope example Source: https://threadplane.ai/docs/a2ui/reference/schema Adds or replaces components for a surface, merged incrementally by id. Exactly one component across the surface must have id "root"; rendering starts once it is defined. ```json { "version": "v0.9", "updateComponents": { "surfaceId": "checkout", "components": [ { "id": "root", "component": "Card", "child": "title" }, { "id": "title", "component": "Text", "text": "Checkout" } ] } } ``` -------------------------------- ### Angular app.config.ts: provideAgent() with subagentToolNames Source: https://threadplane.ai/docs/deep-agents/capabilities/subagents Registers the agent at the application root using `provideAgent()` from `@threadplane/langgraph`. The `subagentToolNames: ['task']` is the default and changes nothing at runtime; it is there to document which tool call means a child started. The example resolves its connection at runtime via `injectCockpitRuntimeConnection()`; your own app should pass `apiUrl` and `assistantId` directly. ```typescript import { injectCockpitRuntimeConnection } from '@threadplane/cockpit-telemetry'; import { ApplicationConfig } from '@angular/core'; import { provideAgent } from '@threadplane/langgraph'; export const appConfig: ApplicationConfig = { providers: [ provideAgent(() => { const connection = injectCockpitRuntimeConnection(); if (connection.adapter !== 'langgraph') { throw new Error('incompatible runtime'); } return { apiUrl: connection.apiUrl, assistantId: connection.assistantId, clientOptions: connection.clientOptions, // `SubAgentMiddleware` dispatches every child through one tool named // `task`, carrying `{description, subagent_type}`. That name is also the // SubagentTracker's default, so this line changes nothing at runtime — // it is here to say out loud which tool call means "a child agent // started". Set it when your dispatch tool is named something else; // overriding it with a name the graph never calls is what turns the // cards back into generic tool chips. subagentToolNames: ['task'], }; }), ], }; ``` -------------------------------- ### Single Agent with Tools - StateGraph setup Source: https://threadplane.ai/docs/langgraph/concepts/agent-architecture Builds a simple agent graph with a model node and a tools node, using conditional edges to decide whether to continue or call tools. Covers most use cases. ```python # Simple, powerful, covers 80% of use cases builder = StateGraph(AgentState) builder.add_node("model", call_model) builder.add_node("tools", ToolNode(tools)) builder.add_edge(START, "model") builder.add_conditional_edges("model", should_continue) builder.add_edge("tools", "model") graph = builder.compile() ``` -------------------------------- ### Prompt for coding agent to add Threadplane to Angular app Source: https://threadplane.ai/docs/chat/getting-started/coding-agents Use this prompt to instruct a coding agent to integrate Threadplane into an Angular application. It starts with provideFakeAgent() to verify the UI without a server or LLM, then explains LangGraph or AG-UI configuration. The agent should read AGENTS.md and the quickstart, inspect the repository, and run lint, test, and build commands. ```text Add Threadplane to this Angular application. 1. Read https://threadplane.ai/AGENTS.md and the current Threadplane quickstart. 2. Inspect this repository's Angular version, application configuration, design system, test runner, and existing agent/backend code. 3. Begin with Threadplane's provideFakeAgent() path so the UI can be verified without a server or LLM. 4. Render the smallest accessible experience using the app's existing layout and styles. 5. Add a focused test for the integration. 6. After the fake path passes, explain the exact configuration needed for either LangGraph or AG-UI. Do not invent credentials, endpoint URLs, or backend capabilities. 7. Run the repository's relevant lint, test, and build commands and report every changed file. ``` -------------------------------- ### Live-model verification with aimock record mode Source: https://threadplane.ai/docs/ag-ui/guides/testing Run each decision in a fresh process with a fresh capture directory. Configure OPENAI_API_KEY in the environment. Use new directories for every verification session. The first command records the approval scenario, the second records the cancellation scenario. Separate processes and unused capture directories prevent the second decision from reusing the first decision's response. ```bash # Use new directories for every verification session. AIMOCK_MODE=record AIMOCK_RECORD_DIR=/tmp/public-docs-approve-recordings \ npx nx e2e cockpit-runtimes-mastra-angular --grep='Approve sends' AIMOCK_MODE=record AIMOCK_RECORD_DIR=/tmp/public-docs-cancel-recordings \ npx nx e2e cockpit-runtimes-mastra-angular --grep='Cancel sends' ``` -------------------------------- ### Complete graph skeleton with client tools Source: https://threadplane.ai/docs/middleware/getting-started/quickstart Full example combining state definition, tool binding, and graph construction. It includes the agent node, server_tools node, and conditional routing. The graph is exported for use in your application. ```typescript import type { StructuredToolInterface } from '@langchain/core/tools'; import { Annotation, END, MessagesAnnotation, StateGraph } from '@langchain/langgraph'; import { ToolNode } from '@langchain/langgraph/prebuilt'; import { ChatOpenAI } from '@langchain/openai'; import { bindClientTools, clientToolsChannel, clientToolsRouter, } from '@threadplane/middleware/langgraph'; const State = Annotation.Root({ ...MessagesAnnotation.spec, ...clientToolsChannel(), }); const baseLlm = new ChatOpenAI({ model: 'gpt-4o-mini' }); const serverTools: StructuredToolInterface[] = []; const serverToolNames = serverTools.map((tool) => tool.name); async function agent(state: typeof State.State) { const llm = bindClientTools(baseLlm, serverTools, state); const response = await llm.invoke(state.messages); return { messages: [response] }; } export const graph = new StateGraph(State) .addNode('agent', agent) .addNode('server_tools', new ToolNode(serverTools)) .addEdge('__start__', 'agent') .addEdge('server_tools', 'agent') .addConditionalEdges( 'agent', (state) => clientToolsRouter(serverToolNames)(state), ['server_tools', END], ) .compile(); ``` -------------------------------- ### Install packages for @threadplane/chat Source: https://threadplane.ai/docs/chat/getting-started/quickstart Install the required packages: @threadplane/chat, @threadplane/langgraph, @langchain/core, @langchain/langgraph-sdk, and marked. @threadplane/langgraph provides the adapter used by the provider snippet, LangChain packages are required peers, and marked is the markdown renderer for assistant messages. ```bash npm install @threadplane/chat @threadplane/langgraph @langchain/core @langchain/langgraph-sdk marked ``` -------------------------------- ### Install threadplane-middleware with pip Source: https://threadplane.ai/docs/middleware/guides/python-langgraph Install the Python package using pip. The package depends on langchain-core>=0.3.0 and langgraph>=0.3.0. Install your model provider package separately, e.g., langchain-openai for ChatOpenAI. ```bash pip install threadplane-middleware ``` -------------------------------- ### Using computed() to derive signals from agent signals Source: https://threadplane.ai/docs/langgraph/concepts/angular-signals Shows how to use Angular's computed() to create derived signals from an agent signal (injectAgent). Each computed updates automatically when dependencies change, such as when new tokens arrive during streaming. The example includes counting messages, getting the last message, filtering assistant messages, tracking active tools, building an error display, and combining signals into a view model. ```typescript import { computed } from '@angular/core'; import { injectAgent } from '@threadplane/langgraph'; protected readonly chat = injectAgent(); // Count all messages in the conversation const messageCount = computed(() => chat.messages().length); // Get the last message (useful for showing the latest response) const lastMessage = computed(() => chat.messages().at(-1)); // Extract just the assistant's messages const assistantMessages = computed(() => chat.messages().filter(m => m.role === 'assistant') ); // Track which tools the agent is actively calling const activeTools = computed(() => chat.toolCalls()); // Build a user-facing error message const errorDisplay = computed(() => { const err = chat.error(); if (!err) return null; if (err.status === 429) return 'Rate limited. Please wait a moment.'; if (err.kind === 'auth') return 'Your credentials were rejected.'; return err.message; }); // Combine multiple signals into a single view model const viewModel = computed(() => ({ messages: chat.messages(), isStreaming: chat.isLoading(), canSend: !chat.isLoading(), messageCount: messageCount(), error: errorDisplay(), })); ```