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
6 changes: 3 additions & 3 deletions apps/website/content/docs/ag-ui/api/api-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -550,11 +550,11 @@
{
"name": "injectAgent",
"kind": "function",
"description": "Injects the Agent from Angular's dependency injection container.\nUse this in components or services that have been provided via provideAgent().",
"signature": "injectAgent(): Agent",
"description": "Injects the AG-UI agent from Angular's dependency injection container.\nUse this in components or services provided via `provideAgent()` (or\n`provideFakeAgent()`).\n\nReturns an `AgUiAgent` — the runtime-neutral `Agent` contract plus the\nAG-UI-specific `customEvents` signal — so `customEvents` is reachable\ndirectly, without casting.",
"signature": "injectAgent(): AgUiAgent",
"params": [],
"returns": {
"type": "Agent",
"type": "AgUiAgent",
"description": ""
},
"examples": []
Expand Down
6 changes: 3 additions & 3 deletions apps/website/content/docs/ag-ui/api/inject-agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ The AG-UI adapter extends the neutral `Agent` contract with one additional signa
|-------|------|-------------|
| `customEvents()` | `CustomStreamEvent[]` | Custom events emitted by the backend during a run. Accumulates per run; resets on each new `submit()`. |

`injectAgent()` is typed as the neutral `Agent` interface; to access `customEvents` you must cast to `AgUiAgent`:
`injectAgent()` returns the `AgUiAgent` type — the neutral `Agent` contract plus `customEvents` — so the signal is reachable directly, no cast required:

```ts
import { injectAgent, type AgUiAgent } from '@threadplane/ag-ui';
import { injectAgent } from '@threadplane/ag-ui';

const chat = injectAgent() as AgUiAgent;
const chat = injectAgent();
chat.customEvents(); // Signal<CustomStreamEvent[]>
```

Expand Down
12 changes: 6 additions & 6 deletions apps/website/content/docs/ag-ui/guides/custom-events.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Custom Events

AG-UI `CUSTOM` events let a backend node push arbitrary data to the Angular client while a run is in progress. The adapter accumulates these events into a `customEvents` signal. That signal lives on the widened `AgUiAgent` type — `injectAgent()` returns the neutral `Agent`, so you cast its result to `AgUiAgent` to reach `customEvents` (shown in [Reading Custom Events](#reading-custom-events-in-angular) below).
AG-UI `CUSTOM` events let a backend node push arbitrary data to the Angular client while a run is in progress. The adapter accumulates these events into a `customEvents` signal on the `AgUiAgent` returned by `injectAgent()` — reachable directly, no cast required (shown in [Reading Custom Events](#reading-custom-events-in-angular) below).

```ts
interface CustomStreamEvent {
Expand Down Expand Up @@ -49,7 +49,7 @@ The adapter JSON-parses `value` when it arrives as a string, so consumers always

## Reading Custom Events in Angular

`injectAgent()` returns the neutral `Agent` type; cast it to `AgUiAgent` (exported from `@threadplane/ag-ui`) to reach the `customEvents` signal.
`injectAgent()` returns an `AgUiAgent`, so the `customEvents` signal is available directly on the injected agent — no cast needed.

### Reactive effect

Expand All @@ -58,7 +58,7 @@ Use an `effect` to react every time new events arrive:
```typescript
import { Component, ChangeDetectionStrategy, effect, signal } from '@angular/core';
import { ChatComponent } from '@threadplane/chat';
import { injectAgent, type AgUiAgent } from '@threadplane/ag-ui';
import { injectAgent } from '@threadplane/ag-ui';

@Component({
standalone: true,
Expand All @@ -72,7 +72,7 @@ import { injectAgent, type AgUiAgent } from '@threadplane/ag-ui';
`,
})
export class AnalysisComponent {
protected readonly agent = injectAgent() as AgUiAgent;
protected readonly agent = injectAgent();
protected readonly progress = signal<number | null>(null);

constructor() {
Expand All @@ -96,7 +96,7 @@ When you only need to derive a value, `computed` is more concise:
```typescript
import { Component, ChangeDetectionStrategy, computed } from '@angular/core';
import { ChatComponent } from '@threadplane/chat';
import { injectAgent, type AgUiAgent } from '@threadplane/ag-ui';
import { injectAgent } from '@threadplane/ag-ui';
import type { CustomStreamEvent } from '@threadplane/ag-ui';

@Component({
Expand All @@ -109,7 +109,7 @@ import type { CustomStreamEvent } from '@threadplane/ag-ui';
`,
})
export class AnalysisComponent {
protected readonly agent = injectAgent() as AgUiAgent;
protected readonly agent = injectAgent();

protected readonly progressEvents = computed(() =>
this.agent.customEvents().filter(
Expand Down
23 changes: 16 additions & 7 deletions libs/ag-ui/src/lib/provide-agent.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
import { InjectionToken, inject, type Provider } from '@angular/core';
import { HttpAgent } from '@ag-ui/client';
import type { Agent, AgentRuntimeTelemetrySink } from '@threadplane/chat';
import { toAgent } from './to-agent';
import type { AgentRuntimeTelemetrySink } from '@threadplane/chat';
import { toAgent, type AgUiAgent } from './to-agent';

/**
* Configuration for the AG-UI agent provider.
Expand All @@ -21,8 +21,12 @@ export interface AgentConfig {
telemetry?: AgentRuntimeTelemetrySink | false;
}

/** @internal — exported for spec access only. Consumers must use injectAgent(). */
export const AGENT = new InjectionToken<Agent>('AGENT');
/**
* @internal — exported for spec access only. Consumers must use injectAgent().
* Both `provideAgent` and `provideFakeAgent` register the result of `toAgent()`,
* which is always an `AgUiAgent`, so the token is typed accordingly.
*/
export const AGENT = new InjectionToken<AgUiAgent>('AGENT');

/**
* Provides an Agent instance wired through HttpAgent and toAgent.
Expand Down Expand Up @@ -59,9 +63,14 @@ export function provideAgent(
}

/**
* Injects the Agent from Angular's dependency injection container.
* Use this in components or services that have been provided via provideAgent().
* Injects the AG-UI agent from Angular's dependency injection container.
* Use this in components or services provided via `provideAgent()` (or
* `provideFakeAgent()`).
*
* Returns an `AgUiAgent` — the runtime-neutral `Agent` contract plus the
* AG-UI-specific `customEvents` signal — so `customEvents` is reachable
* directly, without casting.
*/
export function injectAgent(): Agent {
export function injectAgent(): AgUiAgent {
return inject(AGENT);
}
Loading