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
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,15 @@ jobs:
playwright-${{ runner.os }}-
- run: npx playwright install --with-deps chromium
- run: npx nx e2e website --skip-nx-cache
# The public-copy gate reads served output, and `next dev` serves a
# different bundle than production. Run it a second time against a real
# production build so a claim that only appears in the built output — in a
# generated bundle or a response body — cannot reach the site unnoticed.
- name: Public copy boundary (production build)
env:
GROWTH_FORM_POLICY: growth_v1
WEBSITE_E2E_MODE: production
run: npx nx e2e website --skip-nx-cache --grep "public copy boundary|canonical policy surface"
# The production-smoke spec is testIgnore'd outside PRODUCTION_SMOKE mode,
# so a module-load error in it is invisible until the post-merge Production
# smoke job runs against main — too late to gate a PR. Collect it here:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ The parts you will want on day thirty:
- **Generative UI.** When the agent wants to render a richer surface than a tool-call card, `@threadplane/render` lets the backend stream a UI spec and the frontend resolves it against a registry of your approved Angular components.
No arbitrary code, no `eval`, no design-system bypass.
The agent picks from a menu you control.
- **Observability.** `@threadplane/telemetry` ships a PostHog-shaped sink that is *off by default*. Turn it on per-environment, point it at your own analytics, never ship app content to a vendor you did not pick.
- **Observability.** `@threadplane/telemetry` ships a PostHog-shaped sink your application supplies and configures per environment. Point it at your own analytics rather than at a vendor you did not pick.
- **Testing.** Because the contract is signals all the way down, the testing story is "write a signal, the chat re-renders." `@threadplane/ag-ui` ships a `FakeAgent` you can hand-feed events to in a unit test. No SSE harness, no fixture loader, no test-only DI dance.

Each of those is its own post.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ The [AG-UI testing guide](/docs/ag-ui/guides/testing) lays out those layers.

Observe the transitions users feel: run duration, tool failures, interrupt wait time, retries, and thread restore failures.
Keep event properties operational and out of prompt, completion, tool-input, and tool-output content unless your own policy explicitly requires otherwise.
Threadplane's [browser telemetry is opt-in](/docs/telemetry/getting-started/introduction), and an app-owned sink keeps that boundary under your control.
Threadplane's browser instrumentation runs through an app-owned sink, which keeps that boundary under your control.

## What about backend portability?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ Every time.
- Checkpoint history, which is what makes `<chat-timeline>` possible at all.
- Branch trees for time travel, and queued runs via a multitask strategy.
- Rejoining an in-flight stream by run id, plus a configurable retry budget.
- Eight lifecycle signals that reset on thread switch. That is the difference between "we have telemetry" and "we can answer why that run was slow."
- Eight lifecycle signals that reset on thread switch. That is the difference between "we have metrics" and "we can answer why that run was slow."

<ArchFlowDiagram />

Expand Down
4 changes: 2 additions & 2 deletions apps/website/content/docs/ag-ui/api/api-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@
{
"name": "telemetry",
"type": "false | AgentRuntimeTelemetrySink",
"description": "Optional app-owned telemetry sink. No telemetry is emitted unless this is provided.",
"description": "Optional app-owned sink. Supply one to receive runtime lifecycle events.",
"optional": true
},
{
Expand Down Expand Up @@ -540,7 +540,7 @@
{
"name": "telemetry",
"type": "false | AgentRuntimeTelemetrySink",
"description": "Optional app-owned telemetry sink. No telemetry is emitted unless this is provided.",
"description": "Optional app-owned sink. Supply one to receive runtime lifecycle events.",
"optional": true
}
],
Expand Down
2 changes: 1 addition & 1 deletion apps/website/content/docs/ag-ui/api/inject-agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ The method throws when the selected index is not an assistant message, when no p
icon="settings"
href="/docs/ag-ui/api/provide-agent"
>
Configure the endpoint URL, headers, and telemetry for the agent provider.
Configure the endpoint URL, headers, and lifecycle sink for the agent provider.
</Card>
<Card
title="Custom Events guide"
Expand Down
2 changes: 1 addition & 1 deletion apps/website/content/docs/ag-ui/api/provide-agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ bootstrapApplication(AppComponent, {
| `agentId` | `string` | Optional agent identifier forwarded to the backend. |
| `threadId` | `string` | Optional thread identifier for session continuity. |
| `headers` | `Record<string, string>` | Optional custom HTTP headers included on every request. |
| `telemetry` | `AgentRuntimeTelemetrySink \| false` | Optional app-owned telemetry sink. No telemetry is emitted unless this is provided. |
| `telemetry` | `AgentRuntimeTelemetrySink \| false` | Optional app-owned sink. Supply one to receive runtime lifecycle events. |

## Static vs factory config

Expand Down
2 changes: 1 addition & 1 deletion apps/website/content/docs/ag-ui/api/to-agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const agent = toAgent(source, { telemetry: myTelemetrySink });

| Option | Type | Description |
|--------|------|-------------|
| `telemetry` | `AgentRuntimeTelemetrySink \| false` | Optional app-owned telemetry sink. No telemetry is emitted unless this is provided. |
| `telemetry` | `AgentRuntimeTelemetrySink \| false` | Optional app-owned sink. Supply one to receive runtime lifecycle events. |

## AgUiAgent

Expand Down
4 changes: 2 additions & 2 deletions apps/website/content/docs/ag-ui/concepts/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,15 @@ provideAgent({
});
```

The config maps to the AG-UI `HttpAgent` options exposed by this package, plus an optional telemetry sink:
The config maps to the AG-UI `HttpAgent` options exposed by this package, plus an optional lifecycle event sink:

| Option | Type | Description |
|---|---|---|
| `url` | `string` | **Required.** AG-UI backend HTTP/SSE endpoint. |
| `agentId` | `string` | Optional. Identifies a specific agent on the backend. |
| `threadId` | `string` | Optional. Resume an existing conversation thread. |
| `headers` | `Record<string, string>` | Optional. Custom request headers (auth, tracing). |
| `telemetry` | `AgentRuntimeTelemetrySink \| false` | Optional. App-owned telemetry sink — opt-in, emits nothing unless supplied. See [`@threadplane/telemetry`](/docs/telemetry/getting-started/introduction). |
| `telemetry` | `AgentRuntimeTelemetrySink \| false` | Optional. App-owned sink for runtime lifecycle events. |

### Factory config for route params and DI

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const appConfig: ApplicationConfig = {
| `agentId` | `string` | Optional. Identifies a specific agent on the backend. |
| `threadId` | `string` | Optional. Resume an existing conversation thread. |
| `headers` | `Record<string, string>` | Optional. Custom request headers (auth, tracing). |
| `telemetry` | `AgentRuntimeTelemetrySink \| false` | Optional. App-owned telemetry sink — opt-in, emits nothing unless supplied. See [`@threadplane/telemetry`](/docs/telemetry/getting-started/introduction). |
| `telemetry` | `AgentRuntimeTelemetrySink \| false` | Optional. App-owned sink for runtime lifecycle events. |

## Use in a component

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ For every other custom event name, it emits:
{ type: 'custom', name, data: value }
```

Use `state` for durable UI state. Use `events$` for transient events, telemetry hooks, or UI side effects that should not be stored as conversation state.
Use `state` for durable UI state. Use `events$` for transient events, observability hooks, or UI side effects that should not be stored as conversation state.

Every non-`on_interrupt` `CUSTOM` event is fanned out to **two** surfaces, not one. Alongside the `events$` emission above, the reducer also appends `{ name, data }` to the AG-UI-specific `customEvents()` signal documented on [`injectAgent()`](/docs/ag-ui/api/inject-agent#ag-ui-specific-surface) and [`toAgent()`](/docs/ag-ui/api/to-agent). Reach for the signal when you want an accumulated per-run snapshot for reactive rendering (for example, `a2ui-partial` generative UI); reach for `events$` when you want a transient stream for side-effects or telemetry.

Expand Down
2 changes: 1 addition & 1 deletion apps/website/content/docs/chat/guides/error-handling.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class AgentError extends Error {
readonly kind: AgentErrorKind; // 'connection' | 'auth' | 'server' | 'interrupted' | 'aborted'
readonly retryable: boolean; // could retrying the same request plausibly succeed?
readonly status?: number; // HTTP status, when the failure came from a response
readonly cause: unknown; // the original raw error, preserved for debugging/telemetry
readonly cause: unknown; // the original raw error, preserved for debugging and diagnostics
}
```

Expand Down
4 changes: 0 additions & 4 deletions apps/website/content/docs/chat/guides/lifecycle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,3 @@ export class MyComponent {
| `firstMessageSent` | **no (sticky for life of `<chat>`)** |
| `messageCount` | yes (to 0) |
| `inputSubmittedAt` | yes (to null) |

## Privacy

These signals contain no message content, no user input, no PII. They are timestamps and counts only. The trust contract at [libs/telemetry/README.md](https://github.com/cacheplane/angular-agent-framework/blob/main/libs/telemetry/README.md) applies: **no app telemetry by default.** Subscribing to `CHAT_LIFECYCLE` in your code does not fire any telemetry; what you do with the signal values is your choice.
2 changes: 1 addition & 1 deletion apps/website/content/docs/chat/guides/thread-routing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,6 @@ The AG-UI protocol is event-stream-only — it does not define a server-side thr
icon="activity"
href="/docs/chat/guides/lifecycle"
>
Per-instance signals for debugging and telemetry.
Per-instance signals for debugging and observability.
</Card>
</CardGroup>
4 changes: 2 additions & 2 deletions apps/website/content/docs/langgraph/api/api-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -919,7 +919,7 @@
{
"name": "telemetry",
"type": "false | AgentRuntimeTelemetrySink",
"description": "Optional app-owned telemetry sink. No telemetry is emitted unless this is provided.",
"description": "Optional app-owned sink. Supply one to receive runtime lifecycle events.",
"optional": true
},
{
Expand Down Expand Up @@ -1061,7 +1061,7 @@
{
"name": "telemetry",
"type": "false | AgentRuntimeTelemetrySink",
"description": "Optional app-owned telemetry sink. No telemetry is emitted unless this is provided.",
"description": "Optional app-owned sink. Supply one to receive runtime lifecycle events.",
"optional": true
},
{
Expand Down
2 changes: 1 addition & 1 deletion apps/website/content/docs/langgraph/api/provide-agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ bootstrapApplication(AppComponent, {
| `toMessage` | `(msg: unknown) => BaseMessage` | Custom message deserializer for non-standard message formats. |
| `transport` | `AgentTransport` | Optional transport instance. Defaults to `FetchStreamTransport` when omitted. |
| `clientOptions` | `LangGraphClientOptions` | LangGraph SDK client tuning (e.g. `maxRetries`). See [Client tuning](#client-tuning-retry-budget) below. |
| `telemetry` | `AgentRuntimeTelemetrySink \| false` | Optional app-owned telemetry sink. No telemetry is emitted unless this is provided. |
| `telemetry` | `AgentRuntimeTelemetrySink \| false` | Optional app-owned sink. Supply one to receive runtime lifecycle events. |
| `subagentToolNames` | `string[]` | Tool names that indicate a subagent invocation. |
| `transcriptNodeNames` | `string[]` | LangGraph node names whose `messages-tuple` chunks should stream into the main chat transcript. Omit to accept all top-level chunks. |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ Everything `injectAgent()` gives you out of the box — click any to learn more:

<FeatureChips />

That same agent also exposes `injectAgent().lifecycle` — eight read-only signals that capture key transitions (first chunk, first interrupt, tool start/complete, errors) for debugging and telemetry. See [Lifecycle Signals](/docs/langgraph/guides/lifecycle).
That same agent also exposes `injectAgent().lifecycle` — eight read-only signals that capture key transitions (first chunk, first interrupt, tool start/complete, errors) for debugging and observability. See [Lifecycle Signals](/docs/langgraph/guides/lifecycle).

## Deploy to Production

Expand Down Expand Up @@ -333,7 +333,7 @@ Your Angular app is a stateless client. All agent state — threads, checkpoints
Deterministic testing with MockAgentTransport
</Card>
<Card title="Lifecycle Signals" href="/docs/langgraph/guides/lifecycle">
Read per-agent lifecycle signals for debugging and telemetry
Read per-agent lifecycle signals for debugging and observability
</Card>
<Card title="Angular Signals" href="/docs/langgraph/concepts/angular-signals">
Deep dive into how Signals power agent
Expand Down
4 changes: 0 additions & 4 deletions apps/website/content/docs/langgraph/guides/lifecycle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,3 @@ The exported `AGENT_LIFECYCLE` token is a low-level token for custom integration
## Reset semantics

All eight signals reset on `switchThread()`. This keeps lifecycle observations scoped to the current thread.

## Privacy

These signals contain no message content, no model output, no PII. They are timestamps, counts, and short classification strings only. The trust contract at [libs/telemetry/README.md](https://github.com/cacheplane/angular-agent-framework/blob/main/libs/telemetry/README.md) applies: **no app telemetry by default.** Reading lifecycle signals or providing `AgentLifecycleRegistry` does not fire any telemetry; what you do with the signal values is your choice.
4 changes: 0 additions & 4 deletions apps/website/content/docs/render/guides/lifecycle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,3 @@ export class MyComponent {
## Reset semantics

`firstMountAt` is sticky for the life of the render context — once set, it does not reset. The remaining four signals update on every relevant event.

## Privacy

These signals contain no spec content, no state values, no handler parameters. They are timestamps, counts, and short discriminants (`spec` / `element`, action names from the registered handler bindings) only. The trust contract at [libs/telemetry/README.md](https://github.com/cacheplane/angular-agent-framework/blob/main/libs/telemetry/README.md) applies: **no app telemetry by default.** Subscribing to `RENDER_LIFECYCLE` in your code does not fire any telemetry; what you do with the signal values is your choice.
Loading
Loading