From 2f07e6da281370f0ecd5b1a6c766d14fe2b5504a Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 24 Apr 2026 13:44:15 -0400 Subject: [PATCH 1/6] =?UTF-8?q?docs:=20ChatAgent=20=E2=86=92=20Agent=20ren?= =?UTF-8?q?ame=20design?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scope: contract types strip prefix (Agent, AgentWithHistory). Data types go bare (Message, Role, ToolCall, ContentBlock, Subagent). Collision-prone types prefix with Agent (AgentCustomEvent, AgentInterrupt, AgentStatus, AgentSubmit*, AgentCheckpoint). No backwards-compat aliases, no structural changes. Co-Authored-By: Claude Opus 4.7 --- .../specs/2026-04-24-agent-rename-design.md | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-24-agent-rename-design.md diff --git a/docs/superpowers/specs/2026-04-24-agent-rename-design.md b/docs/superpowers/specs/2026-04-24-agent-rename-design.md new file mode 100644 index 000000000..7ff7e44fc --- /dev/null +++ b/docs/superpowers/specs/2026-04-24-agent-rename-design.md @@ -0,0 +1,141 @@ +# Rename `ChatAgent` → `Agent` Design + +## Goal + +Rename the runtime-neutral contract in `@cacheplane/chat` (and its directly-paired types, factories, and test helpers) from `Chat*` to either bare nouns or `Agent*` prefixes. The contract is already domain-neutral; the name should reflect that. + +## Motivation + +**Naming clarity only.** The contract surface is agent-general: `messages`, `status`, `isLoading`, `toolCalls`, `state`, `submit`, `stop` describe any agent runtime, not specifically chat. Every major agent ecosystem uses `Agent` as the top-level vocabulary: + +- **OpenAI Agents SDK** (`@openai/agents`): `Agent`, `Runner`, `Session` — no `ChatAgent`. Responses API explicitly dropped "Chat" from its name. +- **AG-UI** (`@ag-ui/client`): `AbstractAgent`, `HttpAgent`, `LangGraphAgent`. +- **Mastra, CrewAI, Pydantic AI:** `Agent` as top-level class. +- **Microsoft Agent Framework:** `Agent` base, `ChatAgent` as a narrower subclass (precedent for a future sub-interface if needed). +- **LangChain:** `AgentExecutor` / `create*Agent` — no `Chat` prefix on orchestrators (only on LLM chat-completion models: `BaseChatModel`). + +Keeping `Chat*` names obscures the contract's generality and cognitively pushes users toward "this is only for chat UIs" when it isn't. + +No structural change — this is a rename, not a refactor. No new subclass is introduced. + +## Scope + +### Contract types (strip `Chat`) + +| Old | New | +|---|---| +| `ChatAgent` | `Agent` | +| `ChatAgentWithHistory` | `AgentWithHistory` | + +### Data types (bare — no `Chat`, no `Agent`) + +| Old | New | +|---|---| +| `ChatMessage` | `Message` | +| `ChatRole` | `Role` | +| `ChatToolCall` | `ToolCall` | +| `ChatToolCallStatus` | `ToolCallStatus` | +| `ChatContentBlock` | `ContentBlock` | +| `ChatSubagent` | `Subagent` | +| `ChatSubagentStatus` | `SubagentStatus` | + +Rationale: these align with LangChain/OpenAI/AG-UI vocabulary (which don't prefix message types). `Message` / `ToolCall` / `Role` read naturally in component code. + +### Collision-prone types (prefix `Agent`) + +| Old | New | Why not bare | +|---|---|---| +| `ChatCustomEvent` | `AgentCustomEvent` | DOM `CustomEvent` is a global type | +| `ChatInterrupt` | `AgentInterrupt` | `@langchain/langgraph-sdk` exports `Interrupt` | +| `ChatStatus` | `AgentStatus` | bare `Status` too generic | +| `ChatSubmitInput` | `AgentSubmitInput` | bare `SubmitInput` generic; pairs with `Agent` | +| `ChatSubmitOptions` | `AgentSubmitOptions` | same | +| `ChatCheckpoint` | `AgentCheckpoint` | `@langchain/langgraph-sdk` exports `Checkpoint` | + +### Factories and test helpers + +| Old | New | +|---|---| +| `toChatAgent` (in `@cacheplane/langgraph`) | `toAgent` | +| `mockChatAgent` | `mockAgent` | +| `MockChatAgent` | `MockAgent` | +| `MockChatAgentOptions` | `MockAgentOptions` | +| `runChatAgentConformance` | `runAgentConformance` | +| `runChatAgentWithHistoryConformance` | `runAgentWithHistoryConformance` | + +### Guard helpers (unchanged) + +`isUserMessage`, `isAssistantMessage`, `isToolMessage`, `isSystemMessage` — no `Chat` prefix to strip; keep names. + +## File renames + +**`libs/chat/src/lib/agent/`** +| Old | New | +|---|---| +| `chat-agent.ts` (+ `.spec.ts`) | `agent.ts` (+ `.spec.ts`) | +| `chat-agent-with-history.ts` | `agent-with-history.ts` | +| `chat-message.ts` (+ `.spec.ts`) | `message.ts` (+ `.spec.ts`) | +| `chat-content-block.ts` | `content-block.ts` | +| `chat-tool-call.ts` | `tool-call.ts` | +| `chat-subagent.ts` | `subagent.ts` | +| `chat-status.ts` | `agent-status.ts` | +| `chat-interrupt.ts` | `agent-interrupt.ts` | +| `chat-submit.ts` | `agent-submit.ts` | +| `chat-custom-event.ts` (+ `.spec.ts`) | `agent-custom-event.ts` (+ `.spec.ts`) | +| `chat-checkpoint.ts` | `agent-checkpoint.ts` | + +**`libs/chat/src/lib/testing/`** +| Old | New | +|---|---| +| `mock-chat-agent.ts` (+ `.spec.ts`) | `mock-agent.ts` (+ `.spec.ts`) | +| `chat-agent-conformance.ts` (+ `.spec.ts`) | `agent-conformance.ts` (+ `.spec.ts`) | +| `chat-agent-with-history-conformance.ts` | `agent-with-history-conformance.ts` | + +**`libs/langgraph/src/lib/`** +| Old | New | +|---|---| +| `to-chat-agent.ts` | `to-agent.ts` | +| `to-chat-agent.spec.ts` | `to-agent.spec.ts` | +| `to-chat-agent.conformance.spec.ts` | `to-agent.conformance.spec.ts` | + +Directory `libs/chat/src/lib/agent/` itself does NOT rename — it's already generic. + +## Consumers to update + +- `libs/chat/src/lib/agent/index.ts` — re-exports. +- `libs/chat/src/public-api.ts` — exports + import paths. +- `libs/langgraph/src/public-api.ts` — `toChatAgent` → `toAgent` export. +- Every chat primitive + composition (`libs/chat/src/lib/primitives/**`, `libs/chat/src/lib/compositions/**`) — input types and local imports. +- `libs/chat/src/lib/testing/mock-chat-agent.ts` (moved file) — its own type references. +- Cockpit consumers: `cockpit/chat/**` and `cockpit/langgraph/**` where `toChatAgent` / `mockChatAgent` are imported (~25 files from Phase-1). + +## Out of scope + +- **No backwards-compat aliases.** No `export type ChatAgent = Agent;` shims. Fresh names only. +- **Historical docs** (`docs/superpowers/specs/2026-04-21-*`, `docs/superpowers/plans/2026-04-21-*`) stay as-written. They're artifacts of prior decisions; rewriting them loses the history. +- **No structural changes.** No new subclass. No contract re-shaping. If a `ChatAgent extends Agent` subclass is ever wanted, that's a separate design. +- **Directory rename.** `libs/chat/src/lib/agent/` already uses the neutral name. +- **`@cacheplane/chat` package name.** Stays — the package IS a chat library, even if the contract is agent-general. + +## Migration mechanics + +Mechanical rename. Proceed in this order: + +1. Rename files (via `git mv`) — preserves history. +2. Update type/function names inside each file (find/replace). +3. Update `agent/index.ts` and `public-api.ts` exports. +4. Update all consumer imports. +5. Lint/test/build to catch stragglers. + +No backwards-compat shims, so a missed import surfaces immediately as a build error. + +## Risk + +- **Large blast radius:** ~69 files. Mitigated by mechanical nature (find/replace) and strict build-break signal (no compat shims). +- **Symbol collisions accepted:** we've chosen `Agent*` prefixes for types that would collide with DOM globals (`CustomEvent`) or transitive deps (`@langchain/langgraph-sdk`'s `Interrupt`, `Checkpoint`). +- **Cockpit demo churn:** Phase-1 already updated cockpit apps to use `toChatAgent` / `mockChatAgent` / `ChatAgent` types. This rename re-churns those same ~25 files. One-liners per file. + +## When to revisit + +- If a non-chat UI library is added that consumes the same contract (e.g., a `@cacheplane/task` or `@cacheplane/review` package), the `Agent*`-prefixed submit types feel correct and no re-rename needed. +- If the `ChatAgent extends Agent` subclass pattern becomes wanted (e.g., to add chat-specific fields like typing status or read receipts), revisit this design and reintroduce the subclass. From f598443e456951ba38c14f22d9c6eccf75039562 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 24 Apr 2026 18:52:21 -0400 Subject: [PATCH 2/6] =?UTF-8?q?docs:=20ChatAgent=20=E2=86=92=20Agent=20ren?= =?UTF-8?q?ame=20implementation=20plan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 8 tasks: rename agent/ files, testing/ files, exports, primitives + compositions, langgraph adapter file, cockpit consumers, then verify. git mv preserves history; ordered find/replace avoids partial matches. Co-Authored-By: Claude Opus 4.7 --- .../plans/2026-04-24-agent-rename.md | 504 ++++++++++++++++++ 1 file changed, 504 insertions(+) create mode 100644 docs/superpowers/plans/2026-04-24-agent-rename.md diff --git a/docs/superpowers/plans/2026-04-24-agent-rename.md b/docs/superpowers/plans/2026-04-24-agent-rename.md new file mode 100644 index 000000000..8be2c5880 --- /dev/null +++ b/docs/superpowers/plans/2026-04-24-agent-rename.md @@ -0,0 +1,504 @@ +# Rename `ChatAgent` → `Agent` Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Rename the runtime-neutral contract in `@cacheplane/chat` from `ChatAgent` / `ChatAgentWithHistory` and the paired data/factory/test types per the rename map in the spec, with no backwards-compat aliases. + +**Architecture:** Mechanical rename. `git mv` files to preserve history, then find/replace symbol names across the codebase. No structural changes; the type fields, signal shapes, and adapter behavior are unchanged. + +**Tech Stack:** Angular 21 (signals), RxJS, Nx, Vitest, ng-packagr. + +**Spec:** `docs/superpowers/specs/2026-04-24-agent-rename-design.md` + +--- + +## Rename map (canonical reference) + +### Type renames + +``` +ChatAgent → Agent +ChatAgentWithHistory → AgentWithHistory +ChatMessage → Message +ChatRole → Role +ChatToolCall → ToolCall +ChatToolCallStatus → ToolCallStatus +ChatContentBlock → ContentBlock +ChatSubagent → Subagent +ChatSubagentStatus → SubagentStatus +ChatStatus → AgentStatus +ChatInterrupt → AgentInterrupt +ChatCustomEvent → AgentCustomEvent +ChatSubmitInput → AgentSubmitInput +ChatSubmitOptions → AgentSubmitOptions +ChatCheckpoint → AgentCheckpoint +MockChatAgent → MockAgent +MockChatAgentOptions → MockAgentOptions +``` + +### Function renames + +``` +toChatAgent → toAgent +mockChatAgent → mockAgent +runChatAgentConformance → runAgentConformance +runChatAgentWithHistoryConformance → runAgentWithHistoryConformance +``` + +### File renames (`git mv` preserves history) + +``` +libs/chat/src/lib/agent/chat-agent.ts → agent.ts +libs/chat/src/lib/agent/chat-agent.spec.ts → agent.spec.ts +libs/chat/src/lib/agent/chat-agent-with-history.ts → agent-with-history.ts +libs/chat/src/lib/agent/chat-message.ts → message.ts +libs/chat/src/lib/agent/chat-message.spec.ts → message.spec.ts +libs/chat/src/lib/agent/chat-content-block.ts → content-block.ts +libs/chat/src/lib/agent/chat-tool-call.ts → tool-call.ts +libs/chat/src/lib/agent/chat-subagent.ts → subagent.ts +libs/chat/src/lib/agent/chat-status.ts → agent-status.ts +libs/chat/src/lib/agent/chat-interrupt.ts → agent-interrupt.ts +libs/chat/src/lib/agent/chat-submit.ts → agent-submit.ts +libs/chat/src/lib/agent/chat-custom-event.ts → agent-custom-event.ts +libs/chat/src/lib/agent/chat-custom-event.spec.ts → agent-custom-event.spec.ts +libs/chat/src/lib/agent/chat-checkpoint.ts → agent-checkpoint.ts + +libs/chat/src/lib/testing/mock-chat-agent.ts → mock-agent.ts +libs/chat/src/lib/testing/mock-chat-agent.spec.ts → mock-agent.spec.ts +libs/chat/src/lib/testing/chat-agent-conformance.ts → agent-conformance.ts +libs/chat/src/lib/testing/chat-agent-conformance.spec.ts → agent-conformance.spec.ts +libs/chat/src/lib/testing/chat-agent-with-history-conformance.ts → agent-with-history-conformance.ts + +libs/langgraph/src/lib/to-chat-agent.ts → to-agent.ts +libs/langgraph/src/lib/to-chat-agent.spec.ts → to-agent.spec.ts +libs/langgraph/src/lib/to-chat-agent.conformance.spec.ts → to-agent.conformance.spec.ts +``` + +--- + +## File Structure (no new files; only renames + edits) + +This plan creates no new source files. All work is rename + find/replace. + +--- + +### Task 1: Rename core agent files in `libs/chat/src/lib/agent/` + +**Files:** all under `libs/chat/src/lib/agent/`. + +- [ ] **Step 1: `git mv` each file** + +```bash +cd libs/chat/src/lib/agent +git mv chat-agent.ts agent.ts +git mv chat-agent.spec.ts agent.spec.ts +git mv chat-agent-with-history.ts agent-with-history.ts +git mv chat-message.ts message.ts +git mv chat-message.spec.ts message.spec.ts +git mv chat-content-block.ts content-block.ts +git mv chat-tool-call.ts tool-call.ts +git mv chat-subagent.ts subagent.ts +git mv chat-status.ts agent-status.ts +git mv chat-interrupt.ts agent-interrupt.ts +git mv chat-submit.ts agent-submit.ts +git mv chat-custom-event.ts agent-custom-event.ts +git mv chat-custom-event.spec.ts agent-custom-event.spec.ts +git mv chat-checkpoint.ts agent-checkpoint.ts +cd ../../../../.. +``` + +- [ ] **Step 2: Update each file's symbol declarations and internal imports** + +For every renamed file, apply find/replace based on the rename map. For example, in `agent.ts`: +- Replace `ChatAgent` with `Agent` +- Replace `ChatMessage` with `Message` +- Replace `ChatToolCall` with `ToolCall` +- Replace `ChatStatus` with `AgentStatus` +- Replace `ChatInterrupt` with `AgentInterrupt` +- Replace `ChatSubagent` with `Subagent` +- Replace `ChatCustomEvent` with `AgentCustomEvent` +- Replace `ChatSubmitInput` with `AgentSubmitInput` +- Replace `ChatSubmitOptions` with `AgentSubmitOptions` +- Update `from './chat-message'` → `from './message'` (and similar for every renamed sibling) + +After this step `libs/chat/src/lib/agent/agent.ts` should look like: + +```ts +// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 +import type { Signal } from '@angular/core'; +import type { Observable } from 'rxjs'; +import type { Message } from './message'; +import type { ToolCall } from './tool-call'; +import type { AgentStatus } from './agent-status'; +import type { AgentInterrupt } from './agent-interrupt'; +import type { Subagent } from './subagent'; +import type { AgentCustomEvent } from './agent-custom-event'; +import type { AgentSubmitInput, AgentSubmitOptions } from './agent-submit'; + +export interface Agent { + messages: Signal; + status: Signal; + isLoading: Signal; + error: Signal; + toolCalls: Signal; + state: Signal>; + submit: (input: AgentSubmitInput, opts?: AgentSubmitOptions) => Promise; + stop: () => Promise; + interrupt?: Signal; + subagents?: Signal>; + customEvents$?: Observable; +} +``` + +`agent-with-history.ts`: +```ts +// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 +import type { Signal } from '@angular/core'; +import type { Agent } from './agent'; +import type { AgentCheckpoint } from './agent-checkpoint'; + +export interface AgentWithHistory extends Agent { + history: Signal; +} +``` + +`message.ts`: declares `Message` and `Role` (not `ChatMessage` / `ChatRole`); update guard helpers (`isUserMessage`, etc.) to take `Message`. + +Apply the same find/replace to every file in the directory. + +- [ ] **Step 3: Verify the directory builds in isolation** + +Skip — internal references won't resolve until index.ts and consumers update. Move to Task 2. + +--- + +### Task 2: Rename testing files in `libs/chat/src/lib/testing/` + +- [ ] **Step 1: `git mv` each file** + +```bash +cd libs/chat/src/lib/testing +git mv mock-chat-agent.ts mock-agent.ts +git mv mock-chat-agent.spec.ts mock-agent.spec.ts +git mv chat-agent-conformance.ts agent-conformance.ts +git mv chat-agent-conformance.spec.ts agent-conformance.spec.ts +git mv chat-agent-with-history-conformance.ts agent-with-history-conformance.ts +cd ../../../../.. +``` + +- [ ] **Step 2: Update each file's symbols and imports** + +In `mock-agent.ts`: +- `mockChatAgent` → `mockAgent` +- `MockChatAgent` → `MockAgent` +- `MockChatAgentOptions` → `MockAgentOptions` +- `ChatAgent` → `Agent`, `ChatMessage` → `Message`, `ChatStatus` → `AgentStatus`, etc. per rename map +- Update `from '../agent'` import block to use new type names + +In `agent-conformance.ts`: `runChatAgentConformance` → `runAgentConformance`; update `ChatAgent` → `Agent`. + +In `agent-with-history-conformance.ts`: `runChatAgentWithHistoryConformance` → `runAgentWithHistoryConformance`; `ChatAgentWithHistory` → `AgentWithHistory`; `ChatCheckpoint` → `AgentCheckpoint`. Also update internal call: `runChatAgentConformance(label, ...)` → `runAgentConformance(label, ...)` and the `import` statement: `from './chat-agent-conformance'` → `from './agent-conformance'`. + +Spec files: rename `describe('mockChatAgent ...')` strings to `describe('mockAgent ...')`. Same for the other spec. + +--- + +### Task 3: Update `libs/chat/src/lib/agent/index.ts` + +- [ ] **Step 1: Replace re-exports** + +Final content of `libs/chat/src/lib/agent/index.ts`: + +```ts +// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 +export type { Agent } from './agent'; +export type { Message, Role } from './message'; +export { isUserMessage, isAssistantMessage, isToolMessage, isSystemMessage } from './message'; +export type { ContentBlock } from './content-block'; +export type { ToolCall, ToolCallStatus } from './tool-call'; +export type { AgentStatus } from './agent-status'; +export type { AgentInterrupt } from './agent-interrupt'; +export type { Subagent, SubagentStatus } from './subagent'; +export type { AgentSubmitInput, AgentSubmitOptions } from './agent-submit'; +export type { AgentCustomEvent } from './agent-custom-event'; +export type { AgentCheckpoint } from './agent-checkpoint'; +export type { AgentWithHistory } from './agent-with-history'; +``` + +--- + +### Task 4: Update `libs/chat/src/public-api.ts` + +- [ ] **Step 1: Update the agent exports block** + +Replace the entire `export type { ... } from './lib/agent'` block with: + +```ts +export type { + Agent, + AgentWithHistory, + Message, + Role, + ContentBlock, + ToolCall, + ToolCallStatus, + AgentStatus, + AgentInterrupt, + Subagent, + SubagentStatus, + AgentSubmitInput, + AgentSubmitOptions, + AgentCustomEvent, + AgentCheckpoint, +} from './lib/agent'; +export { + isUserMessage, + isAssistantMessage, + isToolMessage, + isSystemMessage, +} from './lib/agent'; +``` + +- [ ] **Step 2: Update the testing exports block** + +Replace the existing `mockChatAgent` / `MockChatAgent` / `MockChatAgentOptions` / `runChatAgentConformance` / `runChatAgentWithHistoryConformance` entries with their new names. Final testing block: + +```ts +export { mockAgent } from './lib/testing/mock-agent'; +export type { MockAgent, MockAgentOptions } from './lib/testing/mock-agent'; +export { runAgentConformance } from './lib/testing/agent-conformance'; +export { runAgentWithHistoryConformance } from './lib/testing/agent-with-history-conformance'; +``` + +- [ ] **Step 3: Run chat lint + test + build (will fail; that's fine)** + +```bash +npx nx run-many -t lint,test,build -p chat +``` + +Expected: FAIL — chat primitives still reference old names. Move to Task 5. + +--- + +### Task 5: Update chat primitives + compositions + +**Files:** every `.ts` and `.spec.ts` under `libs/chat/src/lib/primitives/**` and `libs/chat/src/lib/compositions/**` that imports `ChatAgent` / `ChatMessage` / etc. or calls `mockChatAgent` / `runChatAgentConformance` / `runChatAgentWithHistoryConformance`. + +- [ ] **Step 1: Find affected files** + +```bash +rg -l "\bChatAgent\b|\bChatAgentWithHistory\b|\bChatMessage\b|\bChatRole\b|\bChatToolCall\b|\bChatToolCallStatus\b|\bChatContentBlock\b|\bChatSubagent\b|\bChatSubagentStatus\b|\bChatStatus\b|\bChatInterrupt\b|\bChatCustomEvent\b|\bChatSubmitInput\b|\bChatSubmitOptions\b|\bChatCheckpoint\b|\bmockChatAgent\b|\bMockChatAgent\b|\bMockChatAgentOptions\b|\brunChatAgentConformance\b|\brunChatAgentWithHistoryConformance\b" libs/chat/src/lib/primitives/ libs/chat/src/lib/compositions/ +``` + +- [ ] **Step 2: Apply the rename map across each file** + +For each file, run find/replace using the canonical rename map at the top of this plan. Whole-word boundaries are essential — `ChatAgent` should not match `ChatAgentWithHistory` in a partial way (it doesn't; `replace_all` on the longer string first, or use whole-word regex). + +Order to avoid partial matches: +1. `ChatAgentWithHistory` → `AgentWithHistory` (longest first) +2. `ChatAgent` → `Agent` +3. `MockChatAgentOptions` → `MockAgentOptions` +4. `MockChatAgent` → `MockAgent` +5. `mockChatAgent` → `mockAgent` +6. `runChatAgentWithHistoryConformance` → `runAgentWithHistoryConformance` +7. `runChatAgentConformance` → `runAgentConformance` +8. `toChatAgent` → `toAgent` +9. `ChatMessage` → `Message` +10. `ChatRole` → `Role` +11. `ChatToolCallStatus` → `ToolCallStatus` +12. `ChatToolCall` → `ToolCall` +13. `ChatContentBlock` → `ContentBlock` +14. `ChatSubagentStatus` → `SubagentStatus` +15. `ChatSubagent` → `Subagent` +16. `ChatStatus` → `AgentStatus` +17. `ChatInterrupt` → `AgentInterrupt` +18. `ChatCustomEvent` → `AgentCustomEvent` +19. `ChatSubmitInput` → `AgentSubmitInput` +20. `ChatSubmitOptions` → `AgentSubmitOptions` +21. `ChatCheckpoint` → `AgentCheckpoint` + +Also update import paths if any file directly imports from `./agent/chat-agent`, `./agent/chat-message`, etc. (most use the `'../agent'` barrel; those need no path edits). + +- [ ] **Step 3: Run chat lint + test + build** + +```bash +npx nx run-many -t lint,test,build -p chat +``` + +Expected: PASS. If any errors remain, they should be missed find/replace targets — fix and re-run. + +- [ ] **Step 4: Commit (intermediate checkpoint)** + +```bash +git add libs/chat/ +git commit -m "refactor(chat): rename ChatAgent → Agent and paired types" +``` + +--- + +### Task 6: Rename `to-chat-agent` files in `libs/langgraph/` + +**Files:** +- Rename: `libs/langgraph/src/lib/to-chat-agent.ts` → `to-agent.ts` +- Rename: `libs/langgraph/src/lib/to-chat-agent.spec.ts` → `to-agent.spec.ts` +- Rename: `libs/langgraph/src/lib/to-chat-agent.conformance.spec.ts` → `to-agent.conformance.spec.ts` +- Modify: `libs/langgraph/src/public-api.ts` + +- [ ] **Step 1: `git mv` files** + +```bash +cd libs/langgraph/src/lib +git mv to-chat-agent.ts to-agent.ts +git mv to-chat-agent.spec.ts to-agent.spec.ts +git mv to-chat-agent.conformance.spec.ts to-agent.conformance.spec.ts +cd ../../../.. +``` + +- [ ] **Step 2: Update each file's symbols and imports** + +In `to-agent.ts`: +- Function name: `toChatAgent` → `toAgent` +- Return type: `ChatAgentWithHistory` → `AgentWithHistory` +- Translation helpers: anywhere `ChatMessage` / `ChatToolCall` / `ChatStatus` / `ChatInterrupt` / `ChatSubagent` / `ChatCustomEvent` / `ChatSubmitInput` / `ChatSubmitOptions` / `ChatCheckpoint` / `ChatRole` / `ChatToolCallStatus` appears, apply rename map. +- Imports from `@cacheplane/chat`: update the type names (the package name stays). + +In both spec files: +- Imports: `toChatAgent` → `toAgent`; types per rename map. +- Function calls: `runChatAgentConformance` → `runAgentConformance`; `runChatAgentWithHistoryConformance` → `runAgentWithHistoryConformance`. +- Stub helpers (`stubAgentRef`, `minimalRef`): no name changes needed (these don't use `Chat*` prefix). + +- [ ] **Step 3: Update `libs/langgraph/src/public-api.ts`** + +Find the line: +```ts +export { toChatAgent } from './lib/to-chat-agent'; +``` + +Replace with: +```ts +export { toAgent } from './lib/to-agent'; +``` + +- [ ] **Step 4: Run langgraph lint + test + build** + +```bash +npx nx run-many -t lint,test,build -p langgraph +``` + +Expected: PASS. + +- [ ] **Step 5: Commit** + +```bash +git add libs/langgraph/ +git commit -m "refactor(langgraph): rename toChatAgent → toAgent" +``` + +--- + +### Task 7: Update cockpit consumers + +**Files:** every `.ts` under `cockpit/` that imports from `@cacheplane/chat` or `@cacheplane/langgraph` and references `toChatAgent`, `mockChatAgent`, `ChatAgent` types, or any of the other renamed symbols. + +- [ ] **Step 1: Find affected files** + +```bash +rg -l "\bChatAgent\b|\bChatAgentWithHistory\b|\bChatMessage\b|\bChatRole\b|\bChatToolCall\b|\bChatToolCallStatus\b|\bChatContentBlock\b|\bChatSubagent\b|\bChatSubagentStatus\b|\bChatStatus\b|\bChatInterrupt\b|\bChatCustomEvent\b|\bChatSubmitInput\b|\bChatSubmitOptions\b|\bChatCheckpoint\b|\bmockChatAgent\b|\bMockChatAgent\b|\bMockChatAgentOptions\b|\brunChatAgentConformance\b|\brunChatAgentWithHistoryConformance\b|\btoChatAgent\b" cockpit/ +``` + +- [ ] **Step 2: Apply rename map to each file** + +Same ordered find/replace as Task 5 Step 2. + +The most common pattern in cockpit demos: +- `import { toChatAgent } from '@cacheplane/langgraph';` → `import { toAgent } from '@cacheplane/langgraph';` +- `protected readonly chatAgent = toChatAgent(this.stream);` → `protected readonly chatAgent = toAgent(this.stream);` (variable name stays — it's local). + +You MAY rename the local variable `chatAgent` → `agent` in cockpit files for consistency with the new vocabulary, but it's optional and a personal-style call. If you do, also update template references (`[agent]="chatAgent"` → `[agent]="agent"`). + +- [ ] **Step 3: Build all affected cockpit apps** + +```bash +npx nx affected -t build --base=origin/main +``` + +Expected: PASS. + +- [ ] **Step 4: Commit** + +```bash +git add cockpit/ +git commit -m "refactor(cockpit): adopt Agent rename across demos" +``` + +--- + +### Task 8: Final verification, push, PR + +- [ ] **Step 1: Verify no stale references remain** + +```bash +rg "\bChatAgent\b|\bChatAgentWithHistory\b|\btoChatAgent\b|\bmockChatAgent\b|\bMockChatAgent\b|\bMockChatAgentOptions\b|\brunChatAgentConformance\b|\brunChatAgentWithHistoryConformance\b" libs/ cockpit/ +``` + +Expected: zero hits in source files (`docs/superpowers/specs/2026-04-21-*` and `docs/superpowers/plans/2026-04-21-*` are intentionally NOT renamed — they're historical). + +```bash +rg "\bChatMessage\b|\bChatRole\b|\bChatToolCall\b|\bChatContentBlock\b|\bChatSubagent\b|\bChatStatus\b|\bChatInterrupt\b|\bChatCustomEvent\b|\bChatSubmit(Input|Options)\b|\bChatCheckpoint\b" libs/ cockpit/ +``` + +Expected: zero hits. + +- [ ] **Step 2: Full lint/test/build** + +```bash +npx nx run-many -t lint,test,build -p chat,langgraph +npx nx affected -t build --base=origin/main +``` + +Expected: all pass. + +- [ ] **Step 3: Push branch** + +```bash +git push -u origin feat/rename-chat-agent-to-agent +``` + +- [ ] **Step 4: Open PR** + +```bash +gh pr create --title "refactor: rename ChatAgent → Agent across the contract surface" --body "$(cat <<'EOF' +## Summary +- Renames `ChatAgent` / `ChatAgentWithHistory` to `Agent` / `AgentWithHistory`. +- Strips `Chat` prefix from message/data types: `Message`, `Role`, `ToolCall`, `ContentBlock`, `Subagent`. +- Prefixes `Agent` on names that would collide otherwise: `AgentCustomEvent` (vs DOM), `AgentInterrupt` / `AgentCheckpoint` (vs `@langchain/langgraph-sdk`), `AgentStatus` (clarity), `AgentSubmitInput` / `AgentSubmitOptions` (clarity). +- Renames `toChatAgent` → `toAgent`, `mockChatAgent` → `mockAgent`, conformance helpers analogously. +- File renames via `git mv` so blame/log preserve. +- No backwards-compat aliases — fresh names only. + +## Motivation +Naming clarity. The contract is agent-general; the `Chat` prefix obscured this and misaligned with industry vocabulary (OpenAI Agents SDK, AG-UI, Mastra, CrewAI, Pydantic AI all use `Agent`). + +## Test Plan +- [x] `nx run-many -t lint,test,build -p chat,langgraph` passes +- [x] `nx affected -t build` passes +- [x] No residual `ChatAgent` / `ChatMessage` / etc. references in `libs/` or `cockpit/` +- [ ] Cockpit demos render correctly in browser + +## Design + plan +- Spec: `docs/superpowers/specs/2026-04-24-agent-rename-design.md` +- Plan: `docs/superpowers/plans/2026-04-24-agent-rename.md` + +🤖 Generated with [Claude Code](https://claude.com/claude-code) +EOF +)" +``` + +--- + +## Out of Scope + +- Backwards-compat aliases (`export type ChatAgent = Agent`). +- Renaming historical docs in `docs/superpowers/specs/2026-04-21-*` and `docs/superpowers/plans/2026-04-21-*`. +- Structural changes (new subclasses, contract reshaping). +- Renaming the `@cacheplane/chat` package itself. From 350efcad28cf7cf1cc9bc029940586085ecc0a07 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 24 Apr 2026 20:36:08 -0400 Subject: [PATCH 3/6] =?UTF-8?q?refactor(chat):=20rename=20ChatAgent=20?= =?UTF-8?q?=E2=86=92=20Agent=20and=20paired=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Strip Chat prefix from contract types (Agent, AgentWithHistory) - Strip Chat prefix from data types (Message, Role, ToolCall, ContentBlock, Subagent) - Prefix Agent on collision-prone types (AgentStatus, AgentInterrupt, AgentCustomEvent, AgentSubmit*, AgentCheckpoint) - Rename mockChatAgent → mockAgent, conformance helpers analogously - File renames via git mv preserve history Co-Authored-By: Claude Opus 4.7 --- ...chat-checkpoint.ts => agent-checkpoint.ts} | 2 +- ...ent.spec.ts => agent-custom-event.spec.ts} | 10 +-- ...-custom-event.ts => agent-custom-event.ts} | 6 +- .../{chat-interrupt.ts => agent-interrupt.ts} | 2 +- .../agent/{chat-status.ts => agent-status.ts} | 2 +- .../agent/{chat-submit.ts => agent-submit.ts} | 8 +-- libs/chat/src/lib/agent/agent-with-history.ts | 15 ++++ .../{chat-agent.spec.ts => agent.spec.ts} | 8 +-- .../src/lib/agent/{chat-agent.ts => agent.ts} | 30 ++++---- .../src/lib/agent/chat-agent-with-history.ts | 15 ---- libs/chat/src/lib/agent/chat-message.ts | 33 --------- ...chat-content-block.ts => content-block.ts} | 2 +- libs/chat/src/lib/agent/index.ts | 24 +++---- .../{chat-message.spec.ts => message.spec.ts} | 8 +-- libs/chat/src/lib/agent/message.ts | 33 +++++++++ .../agent/{chat-subagent.ts => subagent.ts} | 10 +-- .../agent/{chat-tool-call.ts => tool-call.ts} | 6 +- .../chat-debug/chat-debug.component.spec.ts | 14 ++-- .../chat-debug/chat-debug.component.ts | 4 +- .../compositions/chat-debug/debug-utils.ts | 6 +- .../chat-interrupt-panel.component.spec.ts | 18 ++--- .../chat-interrupt-panel.component.ts | 10 +-- .../chat-subagent-card.component.ts | 6 +- .../chat-timeline-slider.component.spec.ts | 8 +-- .../chat-timeline-slider.component.ts | 10 +-- .../compositions/chat/chat.component.spec.ts | 16 ++--- .../lib/compositions/chat/chat.component.ts | 4 +- .../chat-error/chat-error.component.spec.ts | 12 ++-- .../chat-error/chat-error.component.ts | 4 +- .../chat-input/chat-input.component.spec.ts | 18 ++--- .../chat-input/chat-input.component.ts | 6 +- .../chat-interrupt.component.spec.ts | 34 +++++----- .../chat-interrupt.component.ts | 10 +-- .../chat-messages.component.spec.ts | 26 +++---- .../chat-messages/chat-messages.component.ts | 8 +-- .../chat-subagents.component.spec.ts | 24 +++---- .../chat-subagents.component.ts | 10 +-- .../chat-timeline.component.spec.ts | 12 ++-- .../chat-timeline/chat-timeline.component.ts | 10 +-- .../chat-tool-calls.component.spec.ts | 38 +++++------ .../chat-tool-calls.component.ts | 10 +-- .../chat-typing-indicator.component.spec.ts | 24 +++---- .../chat-typing-indicator.component.ts | 6 +- .../src/lib/testing/agent-conformance.spec.ts | 5 ++ ...nt-conformance.ts => agent-conformance.ts} | 10 +-- ...e.ts => agent-with-history-conformance.ts} | 18 ++--- .../testing/chat-agent-conformance.spec.ts | 5 -- ...-chat-agent.spec.ts => mock-agent.spec.ts} | 26 +++---- .../{mock-chat-agent.ts => mock-agent.ts} | 68 +++++++++---------- libs/chat/src/public-api.ts | 40 +++++------ 50 files changed, 367 insertions(+), 367 deletions(-) rename libs/chat/src/lib/agent/{chat-checkpoint.ts => agent-checkpoint.ts} (94%) rename libs/chat/src/lib/agent/{chat-custom-event.spec.ts => agent-custom-event.spec.ts} (75%) rename libs/chat/src/lib/agent/{chat-custom-event.ts => agent-custom-event.ts} (71%) rename libs/chat/src/lib/agent/{chat-interrupt.ts => agent-interrupt.ts} (90%) rename libs/chat/src/lib/agent/{chat-status.ts => agent-status.ts} (50%) rename libs/chat/src/lib/agent/{chat-submit.ts => agent-submit.ts} (67%) create mode 100644 libs/chat/src/lib/agent/agent-with-history.ts rename libs/chat/src/lib/agent/{chat-agent.spec.ts => agent.spec.ts} (86%) rename libs/chat/src/lib/agent/{chat-agent.ts => agent.ts} (51%) delete mode 100644 libs/chat/src/lib/agent/chat-agent-with-history.ts delete mode 100644 libs/chat/src/lib/agent/chat-message.ts rename libs/chat/src/lib/agent/{chat-content-block.ts => content-block.ts} (90%) rename libs/chat/src/lib/agent/{chat-message.spec.ts => message.spec.ts} (56%) create mode 100644 libs/chat/src/lib/agent/message.ts rename libs/chat/src/lib/agent/{chat-subagent.ts => subagent.ts} (54%) rename libs/chat/src/lib/agent/{chat-tool-call.ts => tool-call.ts} (70%) create mode 100644 libs/chat/src/lib/testing/agent-conformance.spec.ts rename libs/chat/src/lib/testing/{chat-agent-conformance.ts => agent-conformance.ts} (89%) rename libs/chat/src/lib/testing/{chat-agent-with-history-conformance.ts => agent-with-history-conformance.ts} (58%) delete mode 100644 libs/chat/src/lib/testing/chat-agent-conformance.spec.ts rename libs/chat/src/lib/testing/{mock-chat-agent.spec.ts => mock-agent.spec.ts} (68%) rename libs/chat/src/lib/testing/{mock-chat-agent.ts => mock-agent.ts} (51%) diff --git a/libs/chat/src/lib/agent/chat-checkpoint.ts b/libs/chat/src/lib/agent/agent-checkpoint.ts similarity index 94% rename from libs/chat/src/lib/agent/chat-checkpoint.ts rename to libs/chat/src/lib/agent/agent-checkpoint.ts index 91e08fcdf..ff6d0ceea 100644 --- a/libs/chat/src/lib/agent/chat-checkpoint.ts +++ b/libs/chat/src/lib/agent/agent-checkpoint.ts @@ -7,7 +7,7 @@ * it back to the parent app on replay/fork, and the parent app dispatches * to the underlying runtime. */ -export interface ChatCheckpoint { +export interface AgentCheckpoint { /** Adapter-opaque checkpoint identifier (e.g. LangGraph checkpoint_id). */ id?: string; /** Human-friendly label for the checkpoint (e.g. next node name). */ diff --git a/libs/chat/src/lib/agent/chat-custom-event.spec.ts b/libs/chat/src/lib/agent/agent-custom-event.spec.ts similarity index 75% rename from libs/chat/src/lib/agent/chat-custom-event.spec.ts rename to libs/chat/src/lib/agent/agent-custom-event.spec.ts index 929ed0b6f..6cff87791 100644 --- a/libs/chat/src/lib/agent/chat-custom-event.spec.ts +++ b/libs/chat/src/lib/agent/agent-custom-event.spec.ts @@ -1,14 +1,14 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -import type { ChatCustomEvent } from './chat-custom-event'; +import type { AgentCustomEvent } from './agent-custom-event'; -describe('ChatCustomEvent', () => { +describe('AgentCustomEvent', () => { it('accepts a minimal { type } event', () => { - const event: ChatCustomEvent = { type: 'state_update' }; + const event: AgentCustomEvent = { type: 'state_update' }; expect(event.type).toBe('state_update'); }); it('accepts arbitrary additional fields via index signature', () => { - const event: ChatCustomEvent = { + const event: AgentCustomEvent = { type: 'a2ui.surface', surfaceId: 'main', payload: { foo: 'bar' }, @@ -19,7 +19,7 @@ describe('ChatCustomEvent', () => { }); it('allows AG-UI-shaped events to pass through without remapping', () => { - const agUiEvent: ChatCustomEvent = { + const agUiEvent: AgentCustomEvent = { type: 'TEXT_MESSAGE_START', messageId: 'msg-1', role: 'assistant', diff --git a/libs/chat/src/lib/agent/chat-custom-event.ts b/libs/chat/src/lib/agent/agent-custom-event.ts similarity index 71% rename from libs/chat/src/lib/agent/chat-custom-event.ts rename to libs/chat/src/lib/agent/agent-custom-event.ts index 1b773d1a2..5632abada 100644 --- a/libs/chat/src/lib/agent/chat-custom-event.ts +++ b/libs/chat/src/lib/agent/agent-custom-event.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 /** - * Runtime-neutral custom event shape flowing through `ChatAgent.customEvents$`. + * Runtime-neutral custom event shape flowing through `Agent.customEvents$`. * * The only required field is `type` — a string discriminator consumers switch * on. All other fields pass through verbatim from the source runtime, which @@ -9,9 +9,9 @@ * without the core contract owning their union. * * Adapters are responsible for normalising their native shape to include a - * `type` field (e.g., `toChatAgent` aliases LangGraph's `name` to `type`). + * `type` field (e.g., `toAgent` aliases LangGraph's `name` to `type`). */ -export interface ChatCustomEvent { +export interface AgentCustomEvent { readonly type: string; readonly [key: string]: unknown; } diff --git a/libs/chat/src/lib/agent/chat-interrupt.ts b/libs/chat/src/lib/agent/agent-interrupt.ts similarity index 90% rename from libs/chat/src/lib/agent/chat-interrupt.ts rename to libs/chat/src/lib/agent/agent-interrupt.ts index 992ab7d24..f95a7a11a 100644 --- a/libs/chat/src/lib/agent/chat-interrupt.ts +++ b/libs/chat/src/lib/agent/agent-interrupt.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -export interface ChatInterrupt { +export interface AgentInterrupt { /** Stable identifier for this interrupt instance. */ id: string; /** Opaque payload the app renders. Runtime-specific shape. */ diff --git a/libs/chat/src/lib/agent/chat-status.ts b/libs/chat/src/lib/agent/agent-status.ts similarity index 50% rename from libs/chat/src/lib/agent/chat-status.ts rename to libs/chat/src/lib/agent/agent-status.ts index 6d0a7adbc..70c4a39d8 100644 --- a/libs/chat/src/lib/agent/chat-status.ts +++ b/libs/chat/src/lib/agent/agent-status.ts @@ -1,3 +1,3 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -export type ChatStatus = 'idle' | 'running' | 'error'; +export type AgentStatus = 'idle' | 'running' | 'error'; diff --git a/libs/chat/src/lib/agent/chat-submit.ts b/libs/chat/src/lib/agent/agent-submit.ts similarity index 67% rename from libs/chat/src/lib/agent/chat-submit.ts rename to libs/chat/src/lib/agent/agent-submit.ts index 75f1b21e7..e9a8a82dc 100644 --- a/libs/chat/src/lib/agent/chat-submit.ts +++ b/libs/chat/src/lib/agent/agent-submit.ts @@ -1,15 +1,15 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -import type { ChatContentBlock } from './chat-content-block'; +import type { ContentBlock } from './content-block'; -export interface ChatSubmitInput { +export interface AgentSubmitInput { /** New user message to append. May be combined with `resume` and/or `state` in the same submit call. */ - message?: string | ChatContentBlock[]; + message?: string | ContentBlock[]; /** Resume payload for an active interrupt. */ resume?: unknown; /** State patch to merge before submitting (runtime-interpreted). */ state?: Record; } -export interface ChatSubmitOptions { +export interface AgentSubmitOptions { signal?: AbortSignal; } diff --git a/libs/chat/src/lib/agent/agent-with-history.ts b/libs/chat/src/lib/agent/agent-with-history.ts new file mode 100644 index 000000000..685b2a567 --- /dev/null +++ b/libs/chat/src/lib/agent/agent-with-history.ts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 +import type { Signal } from '@angular/core'; +import type { Agent } from './agent'; +import type { AgentCheckpoint } from './agent-checkpoint'; + +/** + * Extends Agent with a required `history` signal. + * + * Compositions that need time-travel / checkpoint data (chat-timeline, + * chat-debug) take this richer contract. Adapters that cannot supply + * history should return plain Agent instead of stubbing an empty array. + */ +export interface AgentWithHistory extends Agent { + history: Signal; +} diff --git a/libs/chat/src/lib/agent/chat-agent.spec.ts b/libs/chat/src/lib/agent/agent.spec.ts similarity index 86% rename from libs/chat/src/lib/agent/chat-agent.spec.ts rename to libs/chat/src/lib/agent/agent.spec.ts index 8660522e5..fc58055db 100644 --- a/libs/chat/src/lib/agent/chat-agent.spec.ts +++ b/libs/chat/src/lib/agent/agent.spec.ts @@ -1,10 +1,10 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { signal } from '@angular/core'; -import type { ChatAgent } from './chat-agent'; +import type { Agent } from './agent'; -describe('ChatAgent interface', () => { +describe('Agent interface', () => { it('accepts a minimal implementation without optional capabilities', () => { - const agent: ChatAgent = { + const agent: Agent = { messages: signal([]), status: signal('idle'), isLoading: signal(false), @@ -18,7 +18,7 @@ describe('ChatAgent interface', () => { }); it('accepts an implementation with interrupts and subagents', () => { - const agent: ChatAgent = { + const agent: Agent = { messages: signal([]), status: signal('idle'), isLoading: signal(false), diff --git a/libs/chat/src/lib/agent/chat-agent.ts b/libs/chat/src/lib/agent/agent.ts similarity index 51% rename from libs/chat/src/lib/agent/chat-agent.ts rename to libs/chat/src/lib/agent/agent.ts index 58a5d76f1..4e32b49f5 100644 --- a/libs/chat/src/lib/agent/chat-agent.ts +++ b/libs/chat/src/lib/agent/agent.ts @@ -1,13 +1,13 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import type { Signal } from '@angular/core'; import type { Observable } from 'rxjs'; -import type { ChatMessage } from './chat-message'; -import type { ChatToolCall } from './chat-tool-call'; -import type { ChatStatus } from './chat-status'; -import type { ChatInterrupt } from './chat-interrupt'; -import type { ChatSubagent } from './chat-subagent'; -import type { ChatCustomEvent } from './chat-custom-event'; -import type { ChatSubmitInput, ChatSubmitOptions } from './chat-submit'; +import type { Message } from './message'; +import type { ToolCall } from './tool-call'; +import type { AgentStatus } from './agent-status'; +import type { AgentInterrupt } from './agent-interrupt'; +import type { Subagent } from './subagent'; +import type { AgentCustomEvent } from './agent-custom-event'; +import type { AgentSubmitInput, AgentSubmitOptions } from './agent-submit'; /** * Runtime-neutral contract chat primitives consume. @@ -19,21 +19,21 @@ import type { ChatSubmitInput, ChatSubmitOptions } from './chat-submit'; * do not support these concepts should leave them undefined, and primitives * that need them check presence and render a neutral fallback when absent. */ -export interface ChatAgent { +export interface Agent { // Core state - messages: Signal; - status: Signal; + messages: Signal; + status: Signal; isLoading: Signal; error: Signal; - toolCalls: Signal; + toolCalls: Signal; state: Signal>; // Actions - submit: (input: ChatSubmitInput, opts?: ChatSubmitOptions) => Promise; + submit: (input: AgentSubmitInput, opts?: AgentSubmitOptions) => Promise; stop: () => Promise; // Extended (optional; absent when runtime does not support) - interrupt?: Signal; - subagents?: Signal>; - customEvents$?: Observable; + interrupt?: Signal; + subagents?: Signal>; + customEvents$?: Observable; } diff --git a/libs/chat/src/lib/agent/chat-agent-with-history.ts b/libs/chat/src/lib/agent/chat-agent-with-history.ts deleted file mode 100644 index 715dce97f..000000000 --- a/libs/chat/src/lib/agent/chat-agent-with-history.ts +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -import type { Signal } from '@angular/core'; -import type { ChatAgent } from './chat-agent'; -import type { ChatCheckpoint } from './chat-checkpoint'; - -/** - * Extends ChatAgent with a required `history` signal. - * - * Compositions that need time-travel / checkpoint data (chat-timeline, - * chat-debug) take this richer contract. Adapters that cannot supply - * history should return plain ChatAgent instead of stubbing an empty array. - */ -export interface ChatAgentWithHistory extends ChatAgent { - history: Signal; -} diff --git a/libs/chat/src/lib/agent/chat-message.ts b/libs/chat/src/lib/agent/chat-message.ts deleted file mode 100644 index 445b6f6aa..000000000 --- a/libs/chat/src/lib/agent/chat-message.ts +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -import type { ChatContentBlock } from './chat-content-block'; - -export type ChatRole = 'user' | 'assistant' | 'system' | 'tool'; - -export interface ChatMessage { - id: string; - role: ChatRole; - /** Plain text, or a list of structured content blocks. */ - content: string | ChatContentBlock[]; - /** Present when role === 'tool'. */ - toolCallId?: string; - /** Optional display/author name. */ - name?: string; - /** Runtime-specific extras; do not rely on shape in portable code. */ - extra?: Record; -} - -export function isUserMessage(m: ChatMessage): m is ChatMessage & { role: 'user' } { - return m.role === 'user'; -} - -export function isAssistantMessage(m: ChatMessage): m is ChatMessage & { role: 'assistant' } { - return m.role === 'assistant'; -} - -export function isToolMessage(m: ChatMessage): m is ChatMessage & { role: 'tool' } { - return m.role === 'tool'; -} - -export function isSystemMessage(m: ChatMessage): m is ChatMessage & { role: 'system' } { - return m.role === 'system'; -} diff --git a/libs/chat/src/lib/agent/chat-content-block.ts b/libs/chat/src/lib/agent/content-block.ts similarity index 90% rename from libs/chat/src/lib/agent/chat-content-block.ts rename to libs/chat/src/lib/agent/content-block.ts index 3e82bc292..21ec97441 100644 --- a/libs/chat/src/lib/agent/chat-content-block.ts +++ b/libs/chat/src/lib/agent/content-block.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -export type ChatContentBlock = +export type ContentBlock = | { type: 'text'; text: string } | { type: 'image'; url: string; alt?: string } | { type: 'tool_use'; id: string; name: string; args: unknown } diff --git a/libs/chat/src/lib/agent/index.ts b/libs/chat/src/lib/agent/index.ts index e99bd9827..6c6aebda6 100644 --- a/libs/chat/src/lib/agent/index.ts +++ b/libs/chat/src/lib/agent/index.ts @@ -1,13 +1,13 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -export type { ChatAgent } from './chat-agent'; -export type { ChatMessage, ChatRole } from './chat-message'; -export { isUserMessage, isAssistantMessage, isToolMessage, isSystemMessage } from './chat-message'; -export type { ChatContentBlock } from './chat-content-block'; -export type { ChatToolCall, ChatToolCallStatus } from './chat-tool-call'; -export type { ChatStatus } from './chat-status'; -export type { ChatInterrupt } from './chat-interrupt'; -export type { ChatSubagent, ChatSubagentStatus } from './chat-subagent'; -export type { ChatSubmitInput, ChatSubmitOptions } from './chat-submit'; -export type { ChatCustomEvent } from './chat-custom-event'; -export type { ChatCheckpoint } from './chat-checkpoint'; -export type { ChatAgentWithHistory } from './chat-agent-with-history'; +export type { Agent } from './agent'; +export type { Message, Role } from './message'; +export { isUserMessage, isAssistantMessage, isToolMessage, isSystemMessage } from './message'; +export type { ContentBlock } from './content-block'; +export type { ToolCall, ToolCallStatus } from './tool-call'; +export type { AgentStatus } from './agent-status'; +export type { AgentInterrupt } from './agent-interrupt'; +export type { Subagent, SubagentStatus } from './subagent'; +export type { AgentSubmitInput, AgentSubmitOptions } from './agent-submit'; +export type { AgentCustomEvent } from './agent-custom-event'; +export type { AgentCheckpoint } from './agent-checkpoint'; +export type { AgentWithHistory } from './agent-with-history'; diff --git a/libs/chat/src/lib/agent/chat-message.spec.ts b/libs/chat/src/lib/agent/message.spec.ts similarity index 56% rename from libs/chat/src/lib/agent/chat-message.spec.ts rename to libs/chat/src/lib/agent/message.spec.ts index 3b2f6e411..0c575d6ac 100644 --- a/libs/chat/src/lib/agent/chat-message.spec.ts +++ b/libs/chat/src/lib/agent/message.spec.ts @@ -1,15 +1,15 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -import { isUserMessage, isAssistantMessage, type ChatMessage } from './chat-message'; +import { isUserMessage, isAssistantMessage, type Message } from './message'; -describe('ChatMessage', () => { +describe('Message', () => { it('isUserMessage narrows role', () => { - const msg: ChatMessage = { id: '1', role: 'user', content: 'hi' }; + const msg: Message = { id: '1', role: 'user', content: 'hi' }; expect(isUserMessage(msg)).toBe(true); expect(isAssistantMessage(msg)).toBe(false); }); it('isAssistantMessage narrows role', () => { - const msg: ChatMessage = { id: '2', role: 'assistant', content: 'hello' }; + const msg: Message = { id: '2', role: 'assistant', content: 'hello' }; expect(isAssistantMessage(msg)).toBe(true); expect(isUserMessage(msg)).toBe(false); }); diff --git a/libs/chat/src/lib/agent/message.ts b/libs/chat/src/lib/agent/message.ts new file mode 100644 index 000000000..28e7a74d5 --- /dev/null +++ b/libs/chat/src/lib/agent/message.ts @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 +import type { ContentBlock } from './content-block'; + +export type Role = 'user' | 'assistant' | 'system' | 'tool'; + +export interface Message { + id: string; + role: Role; + /** Plain text, or a list of structured content blocks. */ + content: string | ContentBlock[]; + /** Present when role === 'tool'. */ + toolCallId?: string; + /** Optional display/author name. */ + name?: string; + /** Runtime-specific extras; do not rely on shape in portable code. */ + extra?: Record; +} + +export function isUserMessage(m: Message): m is Message & { role: 'user' } { + return m.role === 'user'; +} + +export function isAssistantMessage(m: Message): m is Message & { role: 'assistant' } { + return m.role === 'assistant'; +} + +export function isToolMessage(m: Message): m is Message & { role: 'tool' } { + return m.role === 'tool'; +} + +export function isSystemMessage(m: Message): m is Message & { role: 'system' } { + return m.role === 'system'; +} diff --git a/libs/chat/src/lib/agent/chat-subagent.ts b/libs/chat/src/lib/agent/subagent.ts similarity index 54% rename from libs/chat/src/lib/agent/chat-subagent.ts rename to libs/chat/src/lib/agent/subagent.ts index a92a2a702..123c01901 100644 --- a/libs/chat/src/lib/agent/chat-subagent.ts +++ b/libs/chat/src/lib/agent/subagent.ts @@ -1,15 +1,15 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import type { Signal } from '@angular/core'; -import type { ChatMessage } from './chat-message'; +import type { Message } from './message'; -export type ChatSubagentStatus = 'pending' | 'running' | 'complete' | 'error'; +export type SubagentStatus = 'pending' | 'running' | 'complete' | 'error'; -export interface ChatSubagent { +export interface Subagent { /** Tool call ID that spawned this subagent. */ toolCallId: string; /** Optional human-readable name. */ name?: string; - status: Signal; - messages: Signal; + status: Signal; + messages: Signal; state: Signal>; } diff --git a/libs/chat/src/lib/agent/chat-tool-call.ts b/libs/chat/src/lib/agent/tool-call.ts similarity index 70% rename from libs/chat/src/lib/agent/chat-tool-call.ts rename to libs/chat/src/lib/agent/tool-call.ts index d61385065..deaf93d01 100644 --- a/libs/chat/src/lib/agent/chat-tool-call.ts +++ b/libs/chat/src/lib/agent/tool-call.ts @@ -1,13 +1,13 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -export type ChatToolCallStatus = 'pending' | 'running' | 'complete' | 'error'; +export type ToolCallStatus = 'pending' | 'running' | 'complete' | 'error'; -export interface ChatToolCall { +export interface ToolCall { id: string; name: string; /** Arguments. May be partial while streaming (`status !== 'complete'`). */ args: unknown; - status: ChatToolCallStatus; + status: ToolCallStatus; /** Present when status === 'complete' or 'error'. */ result?: unknown; /** Optional error payload when status === 'error'. */ diff --git a/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.spec.ts b/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.spec.ts index c7456b72f..bd69ef691 100644 --- a/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.spec.ts +++ b/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.spec.ts @@ -3,7 +3,7 @@ import { describe, it, expect } from 'vitest'; import { computeStateDiff } from './state-diff'; import type { DiffEntry } from './state-diff'; import { toDebugCheckpoint, extractStateValues } from './debug-utils'; -import type { ChatCheckpoint } from '../../agent'; +import type { AgentCheckpoint } from '../../agent'; import { DebugCheckpointCardComponent } from './debug-checkpoint-card.component'; import { DebugControlsComponent } from './debug-controls.component'; import { DebugSummaryComponent } from './debug-summary.component'; @@ -87,20 +87,20 @@ describe('computeStateDiff', () => { describe('toDebugCheckpoint', () => { it('uses label as node name when available', () => { - const cp: ChatCheckpoint = { id: 'cp1', label: 'agent', values: {} }; + const cp: AgentCheckpoint = { id: 'cp1', label: 'agent', values: {} }; const result = toDebugCheckpoint(cp, 0); expect(result.node).toBe('agent'); expect(result.checkpointId).toBe('cp1'); }); it('falls back to Step N when label is absent', () => { - const cp: ChatCheckpoint = { values: {} }; + const cp: AgentCheckpoint = { values: {} }; const result = toDebugCheckpoint(cp, 2); expect(result.node).toBe('Step 3'); }); it('returns undefined checkpointId when id is not present', () => { - const cp: ChatCheckpoint = { label: 'tool', values: {} }; + const cp: AgentCheckpoint = { label: 'tool', values: {} }; const result = toDebugCheckpoint(cp, 0); expect(result.checkpointId).toBeUndefined(); }); @@ -113,13 +113,13 @@ describe('extractStateValues', () => { expect(extractStateValues(undefined)).toEqual({}); }); - it('extracts values from a ChatCheckpoint', () => { - const cp: ChatCheckpoint = { values: { messages: [], count: 5 } }; + it('extracts values from a AgentCheckpoint', () => { + const cp: AgentCheckpoint = { values: { messages: [], count: 5 } }; expect(extractStateValues(cp)).toEqual({ messages: [], count: 5 }); }); it('returns empty object for a checkpoint with empty values', () => { - const cp: ChatCheckpoint = { values: {} }; + const cp: AgentCheckpoint = { values: {} }; expect(extractStateValues(cp)).toEqual({}); }); }); diff --git a/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts b/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts index 831a6576f..5dcdc64e0 100644 --- a/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts +++ b/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts @@ -11,7 +11,7 @@ import { ChangeDetectionStrategy, } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; -import type { ChatAgentWithHistory } from '../../agent'; +import type { AgentWithHistory } from '../../agent'; import { ChatMessagesComponent } from '../../primitives/chat-messages/chat-messages.component'; import { MessageTemplateDirective } from '../../primitives/chat-messages/message-template.directive'; import { ChatInputComponent } from '../../primitives/chat-input/chat-input.component'; @@ -188,7 +188,7 @@ import { toDebugCheckpoint, extractStateValues } from './debug-utils'; export class ChatDebugComponent { private readonly sanitizer = inject(DomSanitizer); - readonly agent = input.required(); + readonly agent = input.required(); readonly debugOpen = signal(true); readonly selectedCheckpointIndex = signal(-1); diff --git a/libs/chat/src/lib/compositions/chat-debug/debug-utils.ts b/libs/chat/src/lib/compositions/chat-debug/debug-utils.ts index 1487d7b14..4bb5df762 100644 --- a/libs/chat/src/lib/compositions/chat-debug/debug-utils.ts +++ b/libs/chat/src/lib/compositions/chat-debug/debug-utils.ts @@ -1,14 +1,14 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -import type { ChatCheckpoint } from '../../agent'; +import type { AgentCheckpoint } from '../../agent'; import type { DebugCheckpoint } from './debug-checkpoint-card.component'; -export function toDebugCheckpoint(cp: ChatCheckpoint, index: number): DebugCheckpoint { +export function toDebugCheckpoint(cp: AgentCheckpoint, index: number): DebugCheckpoint { return { node: cp.label ?? `Step ${index + 1}`, checkpointId: cp.id, }; } -export function extractStateValues(cp: ChatCheckpoint | undefined): Record { +export function extractStateValues(cp: AgentCheckpoint | undefined): Record { return cp?.values ?? {}; } diff --git a/libs/chat/src/lib/compositions/chat-interrupt-panel/chat-interrupt-panel.component.spec.ts b/libs/chat/src/lib/compositions/chat-interrupt-panel/chat-interrupt-panel.component.spec.ts index 4c6d59d20..a62f821ad 100644 --- a/libs/chat/src/lib/compositions/chat-interrupt-panel/chat-interrupt-panel.component.spec.ts +++ b/libs/chat/src/lib/compositions/chat-interrupt-panel/chat-interrupt-panel.component.spec.ts @@ -3,32 +3,32 @@ import { describe, it, expect } from 'vitest'; import { signal, computed } from '@angular/core'; import { getInterruptFromAgent, ChatInterruptPanelComponent } from './chat-interrupt-panel.component'; import type { InterruptAction } from './chat-interrupt-panel.component'; -import { mockChatAgent } from '../../testing/mock-chat-agent'; -import type { ChatInterrupt } from '../../agent/chat-interrupt'; +import { mockAgent } from '../../testing/mock-agent'; +import type { AgentInterrupt } from '../../agent/agent-interrupt'; describe('getInterruptFromAgent()', () => { it('returns undefined when agent has no interrupt property', () => { - const agent = mockChatAgent(); + const agent = mockAgent(); expect(getInterruptFromAgent(agent)).toBeUndefined(); }); it('returns undefined when agent.interrupt signal is undefined', () => { - const agent = mockChatAgent({ withInterrupt: true }); + const agent = mockAgent({ withInterrupt: true }); expect(getInterruptFromAgent(agent)).toBeUndefined(); }); it('returns the interrupt value when present', () => { - const agent = mockChatAgent({ withInterrupt: true }); - const mockInterrupt: ChatInterrupt = { id: 'int-1', value: { question: 'Confirm?' }, resumable: true }; + const agent = mockAgent({ withInterrupt: true }); + const mockInterrupt: AgentInterrupt = { id: 'int-1', value: { question: 'Confirm?' }, resumable: true }; agent.interrupt!.set(mockInterrupt); expect(getInterruptFromAgent(agent)).toBe(mockInterrupt); }); it('updates reactively when interrupt signal changes', () => { - const agent = mockChatAgent({ withInterrupt: true }); - const interrupt1: ChatInterrupt = { id: 'int-1', value: 'first', resumable: true }; - const interrupt2: ChatInterrupt = { id: 'int-2', value: 'second', resumable: false }; + const agent = mockAgent({ withInterrupt: true }); + const interrupt1: AgentInterrupt = { id: 'int-1', value: 'first', resumable: true }; + const interrupt2: AgentInterrupt = { id: 'int-2', value: 'second', resumable: false }; agent.interrupt!.set(interrupt1); expect(getInterruptFromAgent(agent)).toBe(interrupt1); diff --git a/libs/chat/src/lib/compositions/chat-interrupt-panel/chat-interrupt-panel.component.ts b/libs/chat/src/lib/compositions/chat-interrupt-panel/chat-interrupt-panel.component.ts index 2cced4cf1..edce747ba 100644 --- a/libs/chat/src/lib/compositions/chat-interrupt-panel/chat-interrupt-panel.component.ts +++ b/libs/chat/src/lib/compositions/chat-interrupt-panel/chat-interrupt-panel.component.ts @@ -6,17 +6,17 @@ import { output, ChangeDetectionStrategy, } from '@angular/core'; -import type { ChatAgent } from '../../agent'; -import type { ChatInterrupt } from '../../agent/chat-interrupt'; +import type { Agent } from '../../agent'; +import type { AgentInterrupt } from '../../agent/agent-interrupt'; export type InterruptAction = 'accept' | 'edit' | 'respond' | 'ignore'; /** - * Retrieves the current interrupt value from a ChatAgent, or undefined when + * Retrieves the current interrupt value from an Agent, or undefined when * the runtime does not expose interrupts. * Exported for unit testing without DOM rendering. */ -export function getInterruptFromAgent(agent: ChatAgent): ChatInterrupt | undefined { +export function getInterruptFromAgent(agent: Agent): AgentInterrupt | undefined { return agent.interrupt?.(); } @@ -85,7 +85,7 @@ export function getInterruptFromAgent(agent: ChatAgent): ChatInterrupt | undefin `, }) export class ChatInterruptPanelComponent { - readonly agent = input.required(); + readonly agent = input.required(); readonly action = output(); diff --git a/libs/chat/src/lib/compositions/chat-subagent-card/chat-subagent-card.component.ts b/libs/chat/src/lib/compositions/chat-subagent-card/chat-subagent-card.component.ts index feb5fd798..2a8908e5d 100644 --- a/libs/chat/src/lib/compositions/chat-subagent-card/chat-subagent-card.component.ts +++ b/libs/chat/src/lib/compositions/chat-subagent-card/chat-subagent-card.component.ts @@ -6,9 +6,9 @@ import { signal, ChangeDetectionStrategy, } from '@angular/core'; -import type { ChatSubagent, ChatSubagentStatus } from '../../agent/chat-subagent'; +import type { Subagent, SubagentStatus } from '../../agent/subagent'; -function statusColor(status: ChatSubagentStatus): string { +function statusColor(status: SubagentStatus): string { switch (status) { case 'pending': return 'background: var(--chat-bg-alt); color: var(--chat-text-muted);'; case 'running': return 'background: var(--chat-warning-bg); color: var(--chat-warning-text);'; @@ -69,7 +69,7 @@ export { statusColor }; `, }) export class ChatSubagentCardComponent { - readonly subagent = input.required(); + readonly subagent = input.required(); readonly expanded = signal(false); diff --git a/libs/chat/src/lib/compositions/chat-timeline-slider/chat-timeline-slider.component.spec.ts b/libs/chat/src/lib/compositions/chat-timeline-slider/chat-timeline-slider.component.spec.ts index be1ba6059..0f5085326 100644 --- a/libs/chat/src/lib/compositions/chat-timeline-slider/chat-timeline-slider.component.spec.ts +++ b/libs/chat/src/lib/compositions/chat-timeline-slider/chat-timeline-slider.component.spec.ts @@ -2,7 +2,7 @@ import { describe, it, expect, vi } from 'vitest'; import { TestBed } from '@angular/core/testing'; import { ChatTimelineSliderComponent } from './chat-timeline-slider.component'; -import type { ChatCheckpoint } from '../../agent'; +import type { AgentCheckpoint } from '../../agent'; describe('ChatTimelineSliderComponent', () => { it('replay() emits the checkpoint id when id is present', () => { @@ -10,7 +10,7 @@ describe('ChatTimelineSliderComponent', () => { const slider = new ChatTimelineSliderComponent(); const spy = vi.fn(); slider.replayRequested.subscribe(spy); - slider.replay({ id: 'ck1', values: {} } as ChatCheckpoint); + slider.replay({ id: 'ck1', values: {} } as AgentCheckpoint); expect(spy).toHaveBeenCalledWith('ck1'); }); }); @@ -20,7 +20,7 @@ describe('ChatTimelineSliderComponent', () => { const slider = new ChatTimelineSliderComponent(); const spy = vi.fn(); slider.replayRequested.subscribe(spy); - slider.replay({ values: {} } as ChatCheckpoint); + slider.replay({ values: {} } as AgentCheckpoint); expect(spy).not.toHaveBeenCalled(); }); }); @@ -30,7 +30,7 @@ describe('ChatTimelineSliderComponent', () => { const slider = new ChatTimelineSliderComponent(); const spy = vi.fn(); slider.forkRequested.subscribe(spy); - slider.fork({ id: 'ck2', values: {} } as ChatCheckpoint, 3); + slider.fork({ id: 'ck2', values: {} } as AgentCheckpoint, 3); expect(slider.selectedIndex()).toBe(3); expect(spy).toHaveBeenCalledWith('ck2'); }); diff --git a/libs/chat/src/lib/compositions/chat-timeline-slider/chat-timeline-slider.component.ts b/libs/chat/src/lib/compositions/chat-timeline-slider/chat-timeline-slider.component.ts index e1a264175..3d2ca8748 100644 --- a/libs/chat/src/lib/compositions/chat-timeline-slider/chat-timeline-slider.component.ts +++ b/libs/chat/src/lib/compositions/chat-timeline-slider/chat-timeline-slider.component.ts @@ -3,7 +3,7 @@ import { Component, computed, input, output, signal, ChangeDetectionStrategy, } from '@angular/core'; -import type { ChatAgentWithHistory, ChatCheckpoint } from '../../agent'; +import type { AgentWithHistory, AgentCheckpoint } from '../../agent'; @Component({ selector: 'chat-timeline-slider', @@ -61,20 +61,20 @@ import type { ChatAgentWithHistory, ChatCheckpoint } from '../../agent'; `, }) export class ChatTimelineSliderComponent { - readonly agent = input.required(); + readonly agent = input.required(); readonly selectedIndex = signal(-1); - readonly history = computed(() => this.agent().history()); + readonly history = computed(() => this.agent().history()); readonly replayRequested = output(); readonly forkRequested = output(); - replay(cp: ChatCheckpoint): void { + replay(cp: AgentCheckpoint): void { if (cp.id) this.replayRequested.emit(cp.id); } - fork(cp: ChatCheckpoint, index: number): void { + fork(cp: AgentCheckpoint, index: number): void { this.selectedIndex.set(index); if (cp.id) this.forkRequested.emit(cp.id); } diff --git a/libs/chat/src/lib/compositions/chat/chat.component.spec.ts b/libs/chat/src/lib/compositions/chat/chat.component.spec.ts index 83b9321ba..8e02dc44c 100644 --- a/libs/chat/src/lib/compositions/chat/chat.component.spec.ts +++ b/libs/chat/src/lib/compositions/chat/chat.component.spec.ts @@ -8,9 +8,9 @@ import { HumanMessage, AIMessage } from '@langchain/core/messages'; import { ChatComponent } from './chat.component'; import { messageContent } from '../shared/message-utils'; import { createContentClassifier, type ContentClassifier } from '../../streaming/content-classifier'; -import { mockChatAgent } from '../../testing/mock-chat-agent'; +import { mockAgent } from '../../testing/mock-agent'; import { signalStateStore } from '@cacheplane/render'; -import type { ChatCustomEvent } from '../../agent/chat-custom-event'; +import type { AgentCustomEvent } from '../../agent/agent-custom-event'; describe('ChatComponent', () => { it('is defined as a class', () => { @@ -38,10 +38,10 @@ describe('ChatComponent', () => { }); describe('ChatComponent — onA2uiAction', () => { - it('submits the action message as a JSON string via ChatAgent', () => { + it('submits the action message as a JSON string via Agent', () => { TestBed.configureTestingModule({}); TestBed.runInInjectionContext(() => { - const agent = mockChatAgent(); + const agent = mockAgent(); // Instantiate a minimal ChatComponent-like object to test onA2uiAction logic // without a full DOM fixture (the component requires [agent] input which can't @@ -133,9 +133,9 @@ describe('ChatComponent — customEvents$ routing', () => { it('routes state_update customEvents to the resolved render store', () => { TestBed.configureTestingModule({}); TestBed.runInInjectionContext(() => { - const events$ = new Subject(); + const events$ = new Subject(); const store = signalStateStore({}); - const agent = mockChatAgent({ customEvents$: events$.asObservable() }); + const agent = mockAgent({ customEvents$: events$.asObservable() }); const destroyRef = inject(DestroyRef); // Re-implement the exact routing effect from ChatComponent's constructor @@ -168,9 +168,9 @@ describe('ChatComponent — customEvents$ routing', () => { it('ignores non-state_update events and events with non-object data', () => { TestBed.configureTestingModule({}); TestBed.runInInjectionContext(() => { - const events$ = new Subject(); + const events$ = new Subject(); const store = signalStateStore({ initial: true }); - const agent = mockChatAgent({ customEvents$: events$.asObservable() }); + const agent = mockAgent({ customEvents$: events$.asObservable() }); const destroyRef = inject(DestroyRef); const agentSig = signal(agent); diff --git a/libs/chat/src/lib/compositions/chat/chat.component.ts b/libs/chat/src/lib/compositions/chat/chat.component.ts index d888b3ead..636acd1c1 100644 --- a/libs/chat/src/lib/compositions/chat/chat.component.ts +++ b/libs/chat/src/lib/compositions/chat/chat.component.ts @@ -14,7 +14,7 @@ import { inject, } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import type { ChatAgent } from '../../agent'; +import type { Agent } from '../../agent'; import type { ViewRegistry, RenderEvent } from '@cacheplane/render'; import type { A2uiActionMessage } from '@cacheplane/a2ui'; import type { StateStore } from '@json-render/core'; @@ -223,7 +223,7 @@ import { KeyValuePipe } from '@angular/common'; }) export class ChatComponent { - readonly agent = input.required(); + readonly agent = input.required(); readonly views = input(undefined); readonly store = input(undefined); diff --git a/libs/chat/src/lib/primitives/chat-error/chat-error.component.spec.ts b/libs/chat/src/lib/primitives/chat-error/chat-error.component.spec.ts index 9ff0844e0..e2700af31 100644 --- a/libs/chat/src/lib/primitives/chat-error/chat-error.component.spec.ts +++ b/libs/chat/src/lib/primitives/chat-error/chat-error.component.spec.ts @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest'; import { signal, computed } from '@angular/core'; import { extractErrorMessage } from './chat-error.component'; -import { mockChatAgent } from '../../testing/mock-chat-agent'; +import { mockAgent } from '../../testing/mock-agent'; describe('extractErrorMessage()', () => { it('returns null for null error', () => { @@ -28,7 +28,7 @@ describe('extractErrorMessage()', () => { describe('ChatErrorComponent — errorMessage computed', () => { it('errorMessage is null when agent.error is null', () => { - const agent = mockChatAgent({ error: null }); + const agent = mockAgent({ error: null }); const agent$ = signal(agent); const errorMessage = computed(() => extractErrorMessage(agent$().error())); @@ -37,7 +37,7 @@ describe('ChatErrorComponent — errorMessage computed', () => { }); it('errorMessage reflects Error object message', () => { - const agent = mockChatAgent({ status: 'error', error: new Error('boom') }); + const agent = mockAgent({ status: 'error', error: new Error('boom') }); const agent$ = signal(agent); const errorMessage = computed(() => extractErrorMessage(agent$().error())); @@ -46,7 +46,7 @@ describe('ChatErrorComponent — errorMessage computed', () => { }); it('errorMessage reflects string error', () => { - const agent = mockChatAgent({ error: 'timeout' }); + const agent = mockAgent({ error: 'timeout' }); const agent$ = signal(agent); const errorMessage = computed(() => extractErrorMessage(agent$().error())); @@ -55,8 +55,8 @@ describe('ChatErrorComponent — errorMessage computed', () => { }); it('errorMessage updates reactively when agent changes', () => { - const noErrorAgent = mockChatAgent({ error: null }); - const errorAgent = mockChatAgent({ status: 'error', error: new Error('failed') }); + const noErrorAgent = mockAgent({ error: null }); + const errorAgent = mockAgent({ status: 'error', error: new Error('failed') }); const agent$ = signal(noErrorAgent); const errorMessage = computed(() => extractErrorMessage(agent$().error())); diff --git a/libs/chat/src/lib/primitives/chat-error/chat-error.component.ts b/libs/chat/src/lib/primitives/chat-error/chat-error.component.ts index 75c6965d2..71d006960 100644 --- a/libs/chat/src/lib/primitives/chat-error/chat-error.component.ts +++ b/libs/chat/src/lib/primitives/chat-error/chat-error.component.ts @@ -5,7 +5,7 @@ import { input, ChangeDetectionStrategy, } from '@angular/core'; -import type { ChatAgent } from '../../agent'; +import type { Agent } from '../../agent'; export function extractErrorMessage(error: unknown): string | null { if (!error) return null; @@ -29,6 +29,6 @@ export function extractErrorMessage(error: unknown): string | null { `, }) export class ChatErrorComponent { - readonly agent = input.required(); + readonly agent = input.required(); readonly errorMessage = computed(() => extractErrorMessage(this.agent().error())); } diff --git a/libs/chat/src/lib/primitives/chat-input/chat-input.component.spec.ts b/libs/chat/src/lib/primitives/chat-input/chat-input.component.spec.ts index 473a8c3ac..92aefc7a3 100644 --- a/libs/chat/src/lib/primitives/chat-input/chat-input.component.spec.ts +++ b/libs/chat/src/lib/primitives/chat-input/chat-input.component.spec.ts @@ -2,11 +2,11 @@ import { describe, it, expect } from 'vitest'; import { signal, computed } from '@angular/core'; import { submitMessage } from './chat-input.component'; -import { mockChatAgent } from '../../testing/mock-chat-agent'; +import { mockAgent } from '../../testing/mock-agent'; describe('submitMessage()', () => { it('calls agent.submit with { message: trimmed text }', async () => { - const agent = mockChatAgent(); + const agent = mockAgent(); submitMessage(agent, ' hello world '); @@ -17,13 +17,13 @@ describe('submitMessage()', () => { }); it('returns the trimmed text on successful submit', () => { - const agent = mockChatAgent(); + const agent = mockAgent(); const result = submitMessage(agent, ' hello '); expect(result).toBe('hello'); }); it('does not call agent.submit and returns null for whitespace-only text', async () => { - const agent = mockChatAgent(); + const agent = mockAgent(); const result = submitMessage(agent, ' '); @@ -33,7 +33,7 @@ describe('submitMessage()', () => { }); it('does not call agent.submit and returns null for empty string', async () => { - const agent = mockChatAgent(); + const agent = mockAgent(); const result = submitMessage(agent, ''); @@ -45,7 +45,7 @@ describe('submitMessage()', () => { describe('ChatInputComponent — isDisabled computed', () => { it('isDisabled is false when agent.isLoading is false', () => { - const agent = mockChatAgent({ isLoading: false }); + const agent = mockAgent({ isLoading: false }); const agent$ = signal(agent); const isDisabled = computed(() => agent$().isLoading()); @@ -54,7 +54,7 @@ describe('ChatInputComponent — isDisabled computed', () => { }); it('isDisabled is true when agent.isLoading is true', () => { - const agent = mockChatAgent({ isLoading: true }); + const agent = mockAgent({ isLoading: true }); const agent$ = signal(agent); const isDisabled = computed(() => agent$().isLoading()); @@ -63,8 +63,8 @@ describe('ChatInputComponent — isDisabled computed', () => { }); it('isDisabled updates reactively when agent changes', () => { - const idleAgent = mockChatAgent({ isLoading: false }); - const loadingAgent = mockChatAgent({ isLoading: true }); + const idleAgent = mockAgent({ isLoading: false }); + const loadingAgent = mockAgent({ isLoading: true }); const agent$ = signal(idleAgent); const isDisabled = computed(() => agent$().isLoading()); diff --git a/libs/chat/src/lib/primitives/chat-input/chat-input.component.ts b/libs/chat/src/lib/primitives/chat-input/chat-input.component.ts index 300a65453..fb0958e1f 100644 --- a/libs/chat/src/lib/primitives/chat-input/chat-input.component.ts +++ b/libs/chat/src/lib/primitives/chat-input/chat-input.component.ts @@ -10,10 +10,10 @@ import { ChangeDetectionStrategy, } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import type { ChatAgent } from '../../agent'; +import type { Agent } from '../../agent'; export function submitMessage( - agent: ChatAgent, + agent: Agent, text: string, ): string | null { const trimmed = text.trim(); @@ -74,7 +74,7 @@ export function submitMessage( `, }) export class ChatInputComponent { - readonly agent = input.required(); + readonly agent = input.required(); readonly submitOnEnter = input(true); readonly placeholder = input(''); readonly submitted = output(); diff --git a/libs/chat/src/lib/primitives/chat-interrupt/chat-interrupt.component.spec.ts b/libs/chat/src/lib/primitives/chat-interrupt/chat-interrupt.component.spec.ts index 178fe90e5..234b0fc5a 100644 --- a/libs/chat/src/lib/primitives/chat-interrupt/chat-interrupt.component.spec.ts +++ b/libs/chat/src/lib/primitives/chat-interrupt/chat-interrupt.component.spec.ts @@ -2,52 +2,52 @@ import { describe, it, expect } from 'vitest'; import { signal, computed, type WritableSignal } from '@angular/core'; import { getInterrupt } from './chat-interrupt.component'; -import { mockChatAgent } from '../../testing/mock-chat-agent'; -import type { ChatInterrupt } from '../../agent/chat-interrupt'; +import { mockAgent } from '../../testing/mock-agent'; +import type { AgentInterrupt } from '../../agent/agent-interrupt'; describe('getInterrupt()', () => { it('returns undefined when the runtime does not expose interrupt', () => { - const agent = mockChatAgent(); // no withInterrupt → agent.interrupt absent + const agent = mockAgent(); // no withInterrupt → agent.interrupt absent expect(getInterrupt(agent)).toBeUndefined(); }); it('returns undefined when the interrupt signal holds undefined', () => { - const agent = mockChatAgent({ withInterrupt: true }); + const agent = mockAgent({ withInterrupt: true }); expect(getInterrupt(agent)).toBeUndefined(); }); it('returns the interrupt value when the signal holds one', () => { - const ix: ChatInterrupt = { id: 'ix-1', value: { question: 'Confirm?' }, resumable: true }; - const agent = mockChatAgent({ withInterrupt: true }); - (agent.interrupt as WritableSignal).set(ix); + const ix: AgentInterrupt = { id: 'ix-1', value: { question: 'Confirm?' }, resumable: true }; + const agent = mockAgent({ withInterrupt: true }); + (agent.interrupt as WritableSignal).set(ix); expect(getInterrupt(agent)).toBe(ix); }); }); -describe('ChatInterruptComponent — interrupt computed', () => { +describe('AgentInterruptComponent — interrupt computed', () => { it('interrupt is undefined when agent does not expose interrupt', () => { - const agent = mockChatAgent(); + const agent = mockAgent(); const agent$ = signal(agent); const interrupt = computed(() => agent$().interrupt?.()); expect(interrupt()).toBeUndefined(); }); it('interrupt reflects agent.interrupt value when present', () => { - const ix: ChatInterrupt = { id: 'ix-1', value: { step: 'confirm' }, resumable: true }; - const agent = mockChatAgent({ withInterrupt: true }); - (agent.interrupt as WritableSignal).set(ix); + const ix: AgentInterrupt = { id: 'ix-1', value: { step: 'confirm' }, resumable: true }; + const agent = mockAgent({ withInterrupt: true }); + (agent.interrupt as WritableSignal).set(ix); const agent$ = signal(agent); const interrupt = computed(() => agent$().interrupt?.()); expect(interrupt()).toBe(ix); }); it('interrupt updates reactively when agent changes', () => { - const noIx = mockChatAgent({ withInterrupt: true }); - const withIx = mockChatAgent({ withInterrupt: true }); - const ix: ChatInterrupt = { id: 'ix-2', value: { type: 'human_review' }, resumable: true }; - (withIx.interrupt as WritableSignal).set(ix); + const noIx = mockAgent({ withInterrupt: true }); + const withIx = mockAgent({ withInterrupt: true }); + const ix: AgentInterrupt = { id: 'ix-2', value: { type: 'human_review' }, resumable: true }; + (withIx.interrupt as WritableSignal).set(ix); - const agent$ = signal>(noIx); + const agent$ = signal>(noIx); const interrupt = computed(() => agent$().interrupt?.()); expect(interrupt()).toBeUndefined(); diff --git a/libs/chat/src/lib/primitives/chat-interrupt/chat-interrupt.component.ts b/libs/chat/src/lib/primitives/chat-interrupt/chat-interrupt.component.ts index 3b0b2a101..9c2e3f761 100644 --- a/libs/chat/src/lib/primitives/chat-interrupt/chat-interrupt.component.ts +++ b/libs/chat/src/lib/primitives/chat-interrupt/chat-interrupt.component.ts @@ -8,15 +8,15 @@ import { ChangeDetectionStrategy, } from '@angular/core'; import { NgTemplateOutlet } from '@angular/common'; -import type { ChatAgent } from '../../agent'; -import type { ChatInterrupt } from '../../agent/chat-interrupt'; +import type { Agent } from '../../agent'; +import type { AgentInterrupt } from '../../agent/agent-interrupt'; /** - * Retrieves the current interrupt value from a ChatAgent, or undefined when + * Retrieves the current interrupt value from an Agent, or undefined when * the runtime does not expose interrupts. * Exported for unit testing without DOM rendering. */ -export function getInterrupt(agent: ChatAgent): ChatInterrupt | undefined { +export function getInterrupt(agent: Agent): AgentInterrupt | undefined { return agent.interrupt?.(); } @@ -37,7 +37,7 @@ export function getInterrupt(agent: ChatAgent): ChatInterrupt | undefined { `, }) export class ChatInterruptComponent { - readonly agent = input.required(); + readonly agent = input.required(); readonly templateRef = contentChild(TemplateRef); diff --git a/libs/chat/src/lib/primitives/chat-messages/chat-messages.component.spec.ts b/libs/chat/src/lib/primitives/chat-messages/chat-messages.component.spec.ts index 2f9e82ec9..6c8f6ca25 100644 --- a/libs/chat/src/lib/primitives/chat-messages/chat-messages.component.spec.ts +++ b/libs/chat/src/lib/primitives/chat-messages/chat-messages.component.spec.ts @@ -2,43 +2,43 @@ import { describe, it, expect } from 'vitest'; import { signal } from '@angular/core'; import { getMessageType } from './chat-messages.component'; -import { mockChatAgent } from '../../testing/mock-chat-agent'; -import type { ChatMessage } from '../../agent'; +import { mockAgent } from '../../testing/mock-agent'; +import type { Message } from '../../agent'; describe('getMessageType', () => { it('maps user role to "human"', () => { - const msg: ChatMessage = { id: '1', role: 'user', content: 'hello' }; + const msg: Message = { id: '1', role: 'user', content: 'hello' }; expect(getMessageType(msg)).toBe('human'); }); it('maps assistant role to "ai"', () => { - const msg: ChatMessage = { id: '2', role: 'assistant', content: 'response' }; + const msg: Message = { id: '2', role: 'assistant', content: 'response' }; expect(getMessageType(msg)).toBe('ai'); }); it('maps system role to "system"', () => { - const msg: ChatMessage = { id: '3', role: 'system', content: 'system prompt' }; + const msg: Message = { id: '3', role: 'system', content: 'system prompt' }; expect(getMessageType(msg)).toBe('system'); }); it('maps tool role to "tool"', () => { - const msg: ChatMessage = { id: '4', role: 'tool', content: 'result', toolCallId: 'call_1' }; + const msg: Message = { id: '4', role: 'tool', content: 'result', toolCallId: 'call_1' }; expect(getMessageType(msg)).toBe('tool'); }); it('falls back to "ai" for unknown roles', () => { - const msg = { id: '5', role: 'unknown', content: '' } as unknown as ChatMessage; + const msg = { id: '5', role: 'unknown', content: '' } as unknown as Message; expect(getMessageType(msg)).toBe('ai'); }); }); -describe('ChatMessagesComponent — computed messages', () => { +describe('MessagesComponent — computed messages', () => { it('messages() signal reflects the agent messages signal', () => { - const msgs: ChatMessage[] = [ + const msgs: Message[] = [ { id: '1', role: 'user', content: 'hi' }, { id: '2', role: 'assistant', content: 'hello' }, ]; - const agent = mockChatAgent({ messages: msgs }); + const agent = mockAgent({ messages: msgs }); const agent$ = signal(agent); const messages = () => agent$().messages(); @@ -49,13 +49,13 @@ describe('ChatMessagesComponent — computed messages', () => { }); it('messages() updates reactively when agent messages change', () => { - const agent = mockChatAgent({ messages: [] }); + const agent = mockAgent({ messages: [] }); const agent$ = signal(agent); const messages = () => agent$().messages(); expect(messages()).toHaveLength(0); - const updatedAgent = mockChatAgent({ + const updatedAgent = mockAgent({ messages: [{ id: '1', role: 'user', content: 'new message' }], }); agent$.set(updatedAgent); @@ -64,7 +64,7 @@ describe('ChatMessagesComponent — computed messages', () => { }); }); -describe('ChatMessagesComponent — findTemplate logic', () => { +describe('MessagesComponent — findTemplate logic', () => { it('findTemplate returns matching directive by type', () => { const templates = [ { chatMessageTemplate: () => 'human' as const, templateRef: {} }, diff --git a/libs/chat/src/lib/primitives/chat-messages/chat-messages.component.ts b/libs/chat/src/lib/primitives/chat-messages/chat-messages.component.ts index 30beb65e3..fa7fac1ca 100644 --- a/libs/chat/src/lib/primitives/chat-messages/chat-messages.component.ts +++ b/libs/chat/src/lib/primitives/chat-messages/chat-messages.component.ts @@ -7,15 +7,15 @@ import { ChangeDetectionStrategy, } from '@angular/core'; import { NgTemplateOutlet } from '@angular/common'; -import type { ChatAgent, ChatMessage } from '../../agent'; +import type { Agent, Message } from '../../agent'; import { MessageTemplateDirective } from './message-template.directive'; import type { MessageTemplateType } from '../../chat.types'; /** - * Maps a {@link ChatMessage} to a {@link MessageTemplateType}. + * Maps a {@link Message} to a {@link MessageTemplateType}. * Exported as a standalone function so it can be unit-tested without DOM rendering. */ -export function getMessageType(message: ChatMessage): MessageTemplateType { +export function getMessageType(message: Message): MessageTemplateType { switch (message.role) { case 'user': return 'human'; @@ -48,7 +48,7 @@ export function getMessageType(message: ChatMessage): MessageTemplateType { `, }) export class ChatMessagesComponent { - readonly agent = input.required(); + readonly agent = input.required(); readonly messageTemplates = contentChildren(MessageTemplateDirective); diff --git a/libs/chat/src/lib/primitives/chat-subagents/chat-subagents.component.spec.ts b/libs/chat/src/lib/primitives/chat-subagents/chat-subagents.component.spec.ts index 5c13624df..3da1baf07 100644 --- a/libs/chat/src/lib/primitives/chat-subagents/chat-subagents.component.spec.ts +++ b/libs/chat/src/lib/primitives/chat-subagents/chat-subagents.component.spec.ts @@ -2,10 +2,10 @@ import { describe, it, expect } from 'vitest'; import { signal, computed, type WritableSignal } from '@angular/core'; import { activeSubagentsFromAgent } from './chat-subagents.component'; -import { mockChatAgent } from '../../testing/mock-chat-agent'; -import type { ChatSubagent, ChatSubagentStatus } from '../../agent/chat-subagent'; +import { mockAgent } from '../../testing/mock-agent'; +import type { Subagent, SubagentStatus } from '../../agent/subagent'; -function makeSubagent(toolCallId: string, status: ChatSubagentStatus): ChatSubagent { +function makeSubagent(toolCallId: string, status: SubagentStatus): Subagent { return { toolCallId, status: signal(status), @@ -16,20 +16,20 @@ function makeSubagent(toolCallId: string, status: ChatSubagentStatus): ChatSubag describe('activeSubagentsFromAgent()', () => { it('returns an empty array when agent does not expose subagents', () => { - const agent = mockChatAgent(); // no withSubagents + const agent = mockAgent(); // no withSubagents expect(activeSubagentsFromAgent(agent)).toEqual([]); }); it('returns an empty array when the subagents map is empty', () => { - const agent = mockChatAgent({ withSubagents: true }); + const agent = mockAgent({ withSubagents: true }); expect(activeSubagentsFromAgent(agent)).toEqual([]); }); it('includes subagents with status pending or running', () => { - const agent = mockChatAgent({ withSubagents: true }); + const agent = mockAgent({ withSubagents: true }); const pending = makeSubagent('tc-1', 'pending'); const running = makeSubagent('tc-2', 'running'); - (agent.subagents as WritableSignal>).set( + (agent.subagents as WritableSignal>).set( new Map([['tc-1', pending], ['tc-2', running]]), ); const active = activeSubagentsFromAgent(agent); @@ -39,11 +39,11 @@ describe('activeSubagentsFromAgent()', () => { }); it('excludes subagents with status complete or error', () => { - const agent = mockChatAgent({ withSubagents: true }); + const agent = mockAgent({ withSubagents: true }); const complete = makeSubagent('tc-1', 'complete'); const error = makeSubagent('tc-2', 'error'); const running = makeSubagent('tc-3', 'running'); - (agent.subagents as WritableSignal>).set( + (agent.subagents as WritableSignal>).set( new Map([ ['tc-1', complete], ['tc-2', error], @@ -55,10 +55,10 @@ describe('activeSubagentsFromAgent()', () => { }); }); -describe('ChatSubagentsComponent — activeSubagents computed', () => { +describe('SubagentsComponent — activeSubagents computed', () => { it('reflects the agent map and updates reactively', () => { - const agent = mockChatAgent({ withSubagents: true }); - const writable = agent.subagents as WritableSignal>; + const agent = mockAgent({ withSubagents: true }); + const writable = agent.subagents as WritableSignal>; const running = makeSubagent('tc-1', 'running'); const agent$ = signal(agent); diff --git a/libs/chat/src/lib/primitives/chat-subagents/chat-subagents.component.ts b/libs/chat/src/lib/primitives/chat-subagents/chat-subagents.component.ts index 4251a411c..e255f623f 100644 --- a/libs/chat/src/lib/primitives/chat-subagents/chat-subagents.component.ts +++ b/libs/chat/src/lib/primitives/chat-subagents/chat-subagents.component.ts @@ -8,8 +8,8 @@ import { ChangeDetectionStrategy, } from '@angular/core'; import { NgTemplateOutlet } from '@angular/common'; -import type { ChatAgent } from '../../agent'; -import type { ChatSubagent } from '../../agent/chat-subagent'; +import type { Agent } from '../../agent'; +import type { Subagent } from '../../agent/subagent'; /** * Returns the list of currently-active subagents on the agent. "Active" means @@ -17,10 +17,10 @@ import type { ChatSubagent } from '../../agent/chat-subagent'; * when the runtime does not expose a subagents surface. * Exported for unit testing without DOM rendering. */ -export function activeSubagentsFromAgent(agent: ChatAgent): ChatSubagent[] { +export function activeSubagentsFromAgent(agent: Agent): Subagent[] { const map = agent.subagents?.(); if (!map) return []; - const out: ChatSubagent[] = []; + const out: Subagent[] = []; map.forEach((sa) => { const s = sa.status(); if (s !== 'complete' && s !== 'error') out.push(sa); @@ -45,7 +45,7 @@ export function activeSubagentsFromAgent(agent: ChatAgent): ChatSubagent[] { `, }) export class ChatSubagentsComponent { - readonly agent = input.required(); + readonly agent = input.required(); readonly templateRef = contentChild(TemplateRef); diff --git a/libs/chat/src/lib/primitives/chat-timeline/chat-timeline.component.spec.ts b/libs/chat/src/lib/primitives/chat-timeline/chat-timeline.component.spec.ts index 272013f50..056c5db54 100644 --- a/libs/chat/src/lib/primitives/chat-timeline/chat-timeline.component.spec.ts +++ b/libs/chat/src/lib/primitives/chat-timeline/chat-timeline.component.spec.ts @@ -1,21 +1,21 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { describe, it, expect } from 'vitest'; import { signal, computed } from '@angular/core'; -import { mockChatAgent } from '../../testing/mock-chat-agent'; -import type { ChatCheckpoint } from '../../agent'; +import { mockAgent } from '../../testing/mock-agent'; +import type { AgentCheckpoint } from '../../agent'; describe('ChatTimelineComponent', () => { it('renders a template for each checkpoint', () => { - const checkpoints: ChatCheckpoint[] = [ + const checkpoints: AgentCheckpoint[] = [ { id: 'a', label: 'nodeA', values: {} }, { id: 'b', label: 'nodeB', values: {} }, ]; - const agent = mockChatAgent({ history: checkpoints }); + const agent = mockAgent({ history: checkpoints }); // Mirrors the computed inside ChatTimelineComponent: - // history = computed(() => this.agent().history()) + // history = computed(() => this.agent().history()) const agentSig = signal(agent as any); - const history = computed(() => agentSig().history()); + const history = computed(() => agentSig().history()); expect(history()).toHaveLength(2); // Simulate what the @for template renders: index:label diff --git a/libs/chat/src/lib/primitives/chat-timeline/chat-timeline.component.ts b/libs/chat/src/lib/primitives/chat-timeline/chat-timeline.component.ts index 343352ab1..5ee6caf1b 100644 --- a/libs/chat/src/lib/primitives/chat-timeline/chat-timeline.component.ts +++ b/libs/chat/src/lib/primitives/chat-timeline/chat-timeline.component.ts @@ -4,7 +4,7 @@ import { TemplateRef, ChangeDetectionStrategy, } from '@angular/core'; import { NgTemplateOutlet } from '@angular/common'; -import type { ChatAgentWithHistory, ChatCheckpoint } from '../../agent'; +import type { AgentWithHistory, AgentCheckpoint } from '../../agent'; @Component({ selector: 'chat-timeline', @@ -23,15 +23,15 @@ import type { ChatAgentWithHistory, ChatCheckpoint } from '../../agent'; `, }) export class ChatTimelineComponent { - readonly agent = input.required(); + readonly agent = input.required(); - readonly checkpointSelected = output(); + readonly checkpointSelected = output(); readonly templateRef = contentChild(TemplateRef); - readonly history = computed(() => this.agent().history()); + readonly history = computed(() => this.agent().history()); - selectCheckpoint(cp: ChatCheckpoint): void { + selectCheckpoint(cp: AgentCheckpoint): void { this.checkpointSelected.emit(cp); } } diff --git a/libs/chat/src/lib/primitives/chat-tool-calls/chat-tool-calls.component.spec.ts b/libs/chat/src/lib/primitives/chat-tool-calls/chat-tool-calls.component.spec.ts index 3d3dba7ea..db2793f08 100644 --- a/libs/chat/src/lib/primitives/chat-tool-calls/chat-tool-calls.component.spec.ts +++ b/libs/chat/src/lib/primitives/chat-tool-calls/chat-tool-calls.component.spec.ts @@ -1,15 +1,15 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { describe, it, expect } from 'vitest'; import { signal, computed } from '@angular/core'; -import { mockChatAgent } from '../../testing/mock-chat-agent'; -import type { ChatMessage, ChatToolCall } from '../../agent'; +import { mockAgent } from '../../testing/mock-agent'; +import type { Message, ToolCall } from '../../agent'; -describe('ChatToolCallsComponent — toolCalls computed', () => { +describe('ToolCallsComponent — toolCalls computed', () => { it('returns agent.toolCalls() when no message is provided', () => { - const mockToolCalls: ChatToolCall[] = [ + const mockToolCalls: ToolCall[] = [ { id: 'call_1', name: 'get_weather', args: { city: 'NYC' }, status: 'complete', result: 'sunny' }, ]; - const agent = mockChatAgent({ toolCalls: mockToolCalls }); + const agent = mockAgent({ toolCalls: mockToolCalls }); const agent$ = signal(agent); const toolCalls = computed(() => agent$().toolCalls()); @@ -19,13 +19,13 @@ describe('ChatToolCallsComponent — toolCalls computed', () => { }); it('returns agent.toolCalls() when message is a user message (no tool_use blocks)', () => { - const agent = mockChatAgent(); - const msg: ChatMessage = { id: '1', role: 'user', content: 'hello' }; + const agent = mockAgent(); + const msg: Message = { id: '1', role: 'user', content: 'hello' }; const agent$ = signal(agent); - const message$ = signal(msg); + const message$ = signal(msg); - const toolCalls = computed((): ChatToolCall[] => { + const toolCalls = computed((): ToolCall[] => { const m = message$(); if (m && m.role === 'assistant' && Array.isArray(m.content)) { const blocks = m.content.filter((b: any) => b.type === 'tool_use') as Array<{ @@ -34,7 +34,7 @@ describe('ChatToolCallsComponent — toolCalls computed', () => { const all = agent$().toolCalls(); return blocks .map(b => all.find(tc => tc.id === b.id)) - .filter((x): x is ChatToolCall => !!x); + .filter((x): x is ToolCall => !!x); } return agent$().toolCalls(); }); @@ -42,22 +42,22 @@ describe('ChatToolCallsComponent — toolCalls computed', () => { expect(toolCalls()).toHaveLength(0); }); - it('returns matched ChatToolCalls when message has tool_use content blocks', () => { - const mockToolCalls: ChatToolCall[] = [ + it('returns matched ToolCalls when message has tool_use content blocks', () => { + const mockToolCalls: ToolCall[] = [ { id: 'call_2', name: 'search', args: { query: 'test' }, status: 'complete', result: 'results' }, ]; - const agent = mockChatAgent({ toolCalls: mockToolCalls }); + const agent = mockAgent({ toolCalls: mockToolCalls }); - const msg: ChatMessage = { + const msg: Message = { id: '2', role: 'assistant', content: [{ type: 'tool_use', id: 'call_2', name: 'search', args: { query: 'test' } }], }; const agent$ = signal(agent); - const message$ = signal(msg); + const message$ = signal(msg); - const toolCalls = computed((): ChatToolCall[] => { + const toolCalls = computed((): ToolCall[] => { const m = message$(); if (m && m.role === 'assistant' && Array.isArray(m.content)) { const blocks = m.content.filter((b: any) => b.type === 'tool_use') as Array<{ @@ -66,7 +66,7 @@ describe('ChatToolCallsComponent — toolCalls computed', () => { const all = agent$().toolCalls(); return blocks .map(b => all.find(tc => tc.id === b.id)) - .filter((x): x is ChatToolCall => !!x); + .filter((x): x is ToolCall => !!x); } return agent$().toolCalls(); }); @@ -77,8 +77,8 @@ describe('ChatToolCallsComponent — toolCalls computed', () => { }); it('toolCalls updates reactively when agent changes', () => { - const emptyAgent = mockChatAgent(); - const loadedAgent = mockChatAgent({ + const emptyAgent = mockAgent(); + const loadedAgent = mockAgent({ toolCalls: [{ id: 'call_3', name: 'calculator', args: {}, status: 'complete' }], }); diff --git a/libs/chat/src/lib/primitives/chat-tool-calls/chat-tool-calls.component.ts b/libs/chat/src/lib/primitives/chat-tool-calls/chat-tool-calls.component.ts index ed5dff2a9..11494c264 100644 --- a/libs/chat/src/lib/primitives/chat-tool-calls/chat-tool-calls.component.ts +++ b/libs/chat/src/lib/primitives/chat-tool-calls/chat-tool-calls.component.ts @@ -8,7 +8,7 @@ import { ChangeDetectionStrategy, } from '@angular/core'; import { NgTemplateOutlet } from '@angular/common'; -import type { ChatAgent, ChatMessage, ChatToolCall } from '../../agent'; +import type { Agent, Message, ToolCall } from '../../agent'; @Component({ selector: 'chat-tool-calls', @@ -27,19 +27,19 @@ import type { ChatAgent, ChatMessage, ChatToolCall } from '../../agent'; `, }) export class ChatToolCallsComponent { - readonly agent = input.required(); - readonly message = input(undefined); + readonly agent = input.required(); + readonly message = input(undefined); readonly templateRef = contentChild(TemplateRef); - readonly toolCalls = computed((): ChatToolCall[] => { + readonly toolCalls = computed((): ToolCall[] => { const msg = this.message(); if (msg && msg.role === 'assistant' && Array.isArray(msg.content)) { const blocks = msg.content.filter((b) => b.type === 'tool_use'); const all = this.agent().toolCalls(); return blocks .map(b => all.find(tc => tc.id === b.id)) - .filter((x): x is ChatToolCall => !!x); + .filter((x): x is ToolCall => !!x); } return this.agent().toolCalls(); }); diff --git a/libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.spec.ts b/libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.spec.ts index 44f324d26..1daf38df1 100644 --- a/libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.spec.ts +++ b/libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.spec.ts @@ -2,22 +2,22 @@ import { describe, it, expect } from 'vitest'; import { signal, computed } from '@angular/core'; import { isTyping } from './chat-typing-indicator.component'; -import { mockChatAgent } from '../../testing/mock-chat-agent'; -import type { ChatMessage } from '../../agent'; +import { mockAgent } from '../../testing/mock-agent'; +import type { Message } from '../../agent'; describe('isTyping()', () => { it('returns false when agent.isLoading is false', () => { - const agent = mockChatAgent({ isLoading: false }); + const agent = mockAgent({ isLoading: false }); expect(isTyping(agent)).toBe(false); }); it('returns true when agent.isLoading is true and messages is empty', () => { - const agent = mockChatAgent({ isLoading: true, messages: [] }); + const agent = mockAgent({ isLoading: true, messages: [] }); expect(isTyping(agent)).toBe(true); }); it('returns true when loading and last message is user', () => { - const agent = mockChatAgent({ + const agent = mockAgent({ isLoading: true, messages: [{ id: '1', role: 'user', content: 'hi' }], }); @@ -25,7 +25,7 @@ describe('isTyping()', () => { }); it('returns false when loading and last message is non-empty assistant', () => { - const agent = mockChatAgent({ + const agent = mockAgent({ isLoading: true, messages: [ { id: '1', role: 'user', content: 'hi' }, @@ -36,7 +36,7 @@ describe('isTyping()', () => { }); it('returns true when loading and last message is empty-content assistant', () => { - const agent = mockChatAgent({ + const agent = mockAgent({ isLoading: true, messages: [ { id: '1', role: 'user', content: 'hi' }, @@ -47,7 +47,7 @@ describe('isTyping()', () => { }); it('returns true when loading and last assistant message has empty block array', () => { - const agent = mockChatAgent({ + const agent = mockAgent({ isLoading: true, messages: [ { id: '1', role: 'user', content: 'hi' }, @@ -60,7 +60,7 @@ describe('isTyping()', () => { describe('ChatTypingIndicatorComponent — visible computed', () => { it('visible is false when agent.isLoading is false', () => { - const agent = mockChatAgent({ isLoading: false }); + const agent = mockAgent({ isLoading: false }); const agent$ = signal(agent); const visible = computed(() => isTyping(agent$())); @@ -69,7 +69,7 @@ describe('ChatTypingIndicatorComponent — visible computed', () => { }); it('visible is true when agent.isLoading is true and no messages', () => { - const agent = mockChatAgent({ isLoading: true, messages: [] }); + const agent = mockAgent({ isLoading: true, messages: [] }); const agent$ = signal(agent); const visible = computed(() => isTyping(agent$())); @@ -78,8 +78,8 @@ describe('ChatTypingIndicatorComponent — visible computed', () => { }); it('visible updates reactively when agent changes', () => { - const idleAgent = mockChatAgent({ isLoading: false }); - const loadingAgent = mockChatAgent({ + const idleAgent = mockAgent({ isLoading: false }); + const loadingAgent = mockAgent({ isLoading: true, messages: [{ id: '1', role: 'user', content: 'hi' }], }); diff --git a/libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.ts b/libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.ts index 39fea580b..925256bb7 100644 --- a/libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.ts +++ b/libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.ts @@ -5,9 +5,9 @@ import { input, ChangeDetectionStrategy, } from '@angular/core'; -import type { ChatAgent } from '../../agent'; +import type { Agent } from '../../agent'; -export function isTyping(agent: ChatAgent): boolean { +export function isTyping(agent: Agent): boolean { if (!agent.isLoading()) return false; const msgs = agent.messages(); if (msgs.length === 0) return true; @@ -59,6 +59,6 @@ export function isTyping(agent: ChatAgent): boolean { `, }) export class ChatTypingIndicatorComponent { - readonly agent = input.required(); + readonly agent = input.required(); readonly visible = computed(() => isTyping(this.agent())); } diff --git a/libs/chat/src/lib/testing/agent-conformance.spec.ts b/libs/chat/src/lib/testing/agent-conformance.spec.ts new file mode 100644 index 000000000..ae97fbcd9 --- /dev/null +++ b/libs/chat/src/lib/testing/agent-conformance.spec.ts @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 +import { runAgentConformance } from './agent-conformance'; +import { mockAgent } from './mock-agent'; + +runAgentConformance('mockAgent', () => mockAgent()); diff --git a/libs/chat/src/lib/testing/chat-agent-conformance.ts b/libs/chat/src/lib/testing/agent-conformance.ts similarity index 89% rename from libs/chat/src/lib/testing/chat-agent-conformance.ts rename to libs/chat/src/lib/testing/agent-conformance.ts index ddca43d28..53de84e34 100644 --- a/libs/chat/src/lib/testing/chat-agent-conformance.ts +++ b/libs/chat/src/lib/testing/agent-conformance.ts @@ -1,17 +1,17 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { describe, it, expect } from 'vitest'; -import type { ChatAgent } from '../agent'; +import type { Agent } from '../agent'; /** * Runs a suite of contract conformance assertions against a factory that - * produces a fresh ChatAgent. Adapter packages should call this in their + * produces a fresh Agent. Adapter packages should call this in their * own test suites to verify the contract is satisfied. */ -export function runChatAgentConformance( +export function runAgentConformance( label: string, - factory: () => ChatAgent, + factory: () => Agent, ): void { - describe(`${label} — ChatAgent conformance`, () => { + describe(`${label} — Agent conformance`, () => { it('exposes required core signals', () => { const a = factory(); expect(typeof a.messages).toBe('function'); diff --git a/libs/chat/src/lib/testing/chat-agent-with-history-conformance.ts b/libs/chat/src/lib/testing/agent-with-history-conformance.ts similarity index 58% rename from libs/chat/src/lib/testing/chat-agent-with-history-conformance.ts rename to libs/chat/src/lib/testing/agent-with-history-conformance.ts index baafdcb37..b7124f21f 100644 --- a/libs/chat/src/lib/testing/chat-agent-with-history-conformance.ts +++ b/libs/chat/src/lib/testing/agent-with-history-conformance.ts @@ -1,19 +1,19 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { describe, it, expect } from 'vitest'; -import type { ChatAgentWithHistory, ChatCheckpoint } from '../agent'; -import { runChatAgentConformance } from './chat-agent-conformance'; +import type { AgentWithHistory, AgentCheckpoint } from '../agent'; +import { runAgentConformance } from './agent-conformance'; /** - * Conformance suite for ChatAgentWithHistory implementations. + * Conformance suite for AgentWithHistory implementations. * - * Runs the base ChatAgent conformance suite, then verifies the history - * signal is present and returns an array of ChatCheckpoint-shaped entries. + * Runs the base Agent conformance suite, then verifies the history + * signal is present and returns an array of AgentCheckpoint-shaped entries. */ -export function runChatAgentWithHistoryConformance( +export function runAgentWithHistoryConformance( label: string, - factory: (seed?: { history?: ChatCheckpoint[] }) => ChatAgentWithHistory, + factory: (seed?: { history?: AgentCheckpoint[] }) => AgentWithHistory, ): void { - runChatAgentConformance(label, () => factory()); + runAgentConformance(label, () => factory()); describe(`${label} — history`, () => { it('exposes a history signal', () => { @@ -23,7 +23,7 @@ export function runChatAgentWithHistoryConformance( }); it('reflects seeded checkpoints', () => { - const seed: ChatCheckpoint[] = [ + const seed: AgentCheckpoint[] = [ { id: 'c1', label: 'Step 1', values: { foo: 1 } }, { id: 'c2', label: 'Step 2', values: { foo: 2 } }, ]; diff --git a/libs/chat/src/lib/testing/chat-agent-conformance.spec.ts b/libs/chat/src/lib/testing/chat-agent-conformance.spec.ts deleted file mode 100644 index 7e6c70e6b..000000000 --- a/libs/chat/src/lib/testing/chat-agent-conformance.spec.ts +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -import { runChatAgentConformance } from './chat-agent-conformance'; -import { mockChatAgent } from './mock-chat-agent'; - -runChatAgentConformance('mockChatAgent', () => mockChatAgent()); diff --git a/libs/chat/src/lib/testing/mock-chat-agent.spec.ts b/libs/chat/src/lib/testing/mock-agent.spec.ts similarity index 68% rename from libs/chat/src/lib/testing/mock-chat-agent.spec.ts rename to libs/chat/src/lib/testing/mock-agent.spec.ts index 97fd32da5..9775cece4 100644 --- a/libs/chat/src/lib/testing/mock-chat-agent.spec.ts +++ b/libs/chat/src/lib/testing/mock-agent.spec.ts @@ -1,10 +1,10 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -import { mockChatAgent } from './mock-chat-agent'; -import type { ChatAgentWithHistory } from '../agent'; +import { mockAgent } from './mock-agent'; +import type { AgentWithHistory } from '../agent'; -describe('mockChatAgent', () => { +describe('mockAgent', () => { it('starts in idle state with empty messages', () => { - const agent = mockChatAgent(); + const agent = mockAgent(); expect(agent.status()).toBe('idle'); expect(agent.isLoading()).toBe(false); expect(agent.messages()).toEqual([]); @@ -13,19 +13,19 @@ describe('mockChatAgent', () => { }); it('exposes writable signals for test control', () => { - const agent = mockChatAgent(); + const agent = mockAgent(); agent.messages.set([{ id: '1', role: 'user', content: 'hi' }]); expect(agent.messages().length).toBe(1); }); it('records submit calls', async () => { - const agent = mockChatAgent(); + const agent = mockAgent(); await agent.submit({ message: 'hello' }); expect(agent.submitCalls).toEqual([{ input: { message: 'hello' }, opts: undefined }]); }); it('accepts initial state overrides', () => { - const agent = mockChatAgent({ + const agent = mockAgent({ status: 'running', messages: [{ id: '1', role: 'user', content: 'hi' }], }); @@ -34,7 +34,7 @@ describe('mockChatAgent', () => { }); it('provides interrupt and subagents signals when requested', () => { - const agent = mockChatAgent({ withInterrupt: true, withSubagents: true }); + const agent = mockAgent({ withInterrupt: true, withSubagents: true }); expect(agent.interrupt).toBeDefined(); expect(agent.subagents).toBeDefined(); expect(agent.interrupt!()).toBeUndefined(); @@ -42,16 +42,16 @@ describe('mockChatAgent', () => { }); }); -describe('mockChatAgent with history', () => { +describe('mockAgent with history', () => { it('exposes history signal when history option supplied', () => { - const agent = mockChatAgent({ history: [{ id: 'c1', label: 'start', values: {} }] }); - const withHistory = agent as ChatAgentWithHistory; + const agent = mockAgent({ history: [{ id: 'c1', label: 'start', values: {} }] }); + const withHistory = agent as AgentWithHistory; expect(typeof withHistory.history).toBe('function'); expect(withHistory.history()).toEqual([{ id: 'c1', label: 'start', values: {} }]); }); it('omits history when option absent', () => { - const agent = mockChatAgent({}); - expect((agent as Partial).history).toBeUndefined(); + const agent = mockAgent({}); + expect((agent as Partial).history).toBeUndefined(); }); }); diff --git a/libs/chat/src/lib/testing/mock-chat-agent.ts b/libs/chat/src/lib/testing/mock-agent.ts similarity index 51% rename from libs/chat/src/lib/testing/mock-chat-agent.ts rename to libs/chat/src/lib/testing/mock-agent.ts index 75e340a52..68e0f2ac5 100644 --- a/libs/chat/src/lib/testing/mock-chat-agent.ts +++ b/libs/chat/src/lib/testing/mock-agent.ts @@ -2,70 +2,70 @@ import { signal, WritableSignal } from '@angular/core'; import type { Observable } from 'rxjs'; import type { - ChatAgent, - ChatMessage, - ChatStatus, - ChatToolCall, - ChatInterrupt, - ChatSubagent, - ChatSubmitInput, - ChatSubmitOptions, - ChatCheckpoint, + Agent, + Message, + AgentStatus, + ToolCall, + AgentInterrupt, + Subagent, + AgentSubmitInput, + AgentSubmitOptions, + AgentCheckpoint, } from '../agent'; -import type { ChatCustomEvent } from '../agent/chat-custom-event'; +import type { AgentCustomEvent } from '../agent/agent-custom-event'; -export interface MockChatAgent extends ChatAgent { - messages: WritableSignal; - status: WritableSignal; +export interface MockAgent extends Agent { + messages: WritableSignal; + status: WritableSignal; isLoading: WritableSignal; error: WritableSignal; - toolCalls: WritableSignal; + toolCalls: WritableSignal; state: WritableSignal>; - interrupt?: WritableSignal; - subagents?: WritableSignal>; - history?: WritableSignal; - customEvents$?: Observable; + interrupt?: WritableSignal; + subagents?: WritableSignal>; + history?: WritableSignal; + customEvents$?: Observable; /** Captured calls to submit() in order. */ - submitCalls: Array<{ input: ChatSubmitInput; opts?: ChatSubmitOptions }>; + submitCalls: Array<{ input: AgentSubmitInput; opts?: AgentSubmitOptions }>; /** Count of stop() invocations. */ stopCount: number; } -export interface MockChatAgentOptions { - messages?: ChatMessage[]; - status?: ChatStatus; +export interface MockAgentOptions { + messages?: Message[]; + status?: AgentStatus; isLoading?: boolean; error?: unknown; - toolCalls?: ChatToolCall[]; + toolCalls?: ToolCall[]; state?: Record; withInterrupt?: boolean; withSubagents?: boolean; - history?: ChatCheckpoint[]; - customEvents$?: Observable; + history?: AgentCheckpoint[]; + customEvents$?: Observable; } -export function mockChatAgent(opts: MockChatAgentOptions = {}): MockChatAgent { - const messages = signal(opts.messages ?? []); - const status = signal(opts.status ?? 'idle'); +export function mockAgent(opts: MockAgentOptions = {}): MockAgent { + const messages = signal(opts.messages ?? []); + const status = signal(opts.status ?? 'idle'); const isLoading = signal(opts.isLoading ?? false); const error = signal(opts.error ?? null); - const toolCalls = signal(opts.toolCalls ?? []); + const toolCalls = signal(opts.toolCalls ?? []); const state = signal>(opts.state ?? {}); const interrupt = opts.withInterrupt - ? signal(undefined) + ? signal(undefined) : undefined; const subagents = opts.withSubagents - ? signal>(new Map()) + ? signal>(new Map()) : undefined; const history = opts.history - ? signal(opts.history) + ? signal(opts.history) : undefined; - const submitCalls: MockChatAgent['submitCalls'] = []; + const submitCalls: MockAgent['submitCalls'] = []; let stopCount = 0; - const agent: MockChatAgent = { + const agent: MockAgent = { messages, status, isLoading, error, toolCalls, state, ...(interrupt ? { interrupt } : {}), ...(subagents ? { subagents } : {}), diff --git a/libs/chat/src/public-api.ts b/libs/chat/src/public-api.ts index 788c3e19a..ac4df3bd2 100644 --- a/libs/chat/src/public-api.ts +++ b/libs/chat/src/public-api.ts @@ -4,23 +4,23 @@ export type { ChatConfig } from './lib/provide-chat'; export type { MessageTemplateType } from './lib/chat.types'; -// ChatAgent contract (runtime-neutral) +// Agent contract (runtime-neutral) export type { - ChatAgent, - ChatMessage, - ChatRole, - ChatContentBlock, - ChatToolCall, - ChatToolCallStatus, - ChatStatus, - ChatInterrupt, - ChatSubagent, - ChatSubagentStatus, - ChatSubmitInput, - ChatSubmitOptions, - ChatCustomEvent, - ChatCheckpoint, - ChatAgentWithHistory, + Agent, + AgentWithHistory, + Message, + Role, + ContentBlock, + ToolCall, + ToolCallStatus, + AgentStatus, + AgentInterrupt, + Subagent, + SubagentStatus, + AgentSubmitInput, + AgentSubmitOptions, + AgentCustomEvent, + AgentCheckpoint, } from './lib/agent'; export { isUserMessage, @@ -118,7 +118,7 @@ export type { export { isPathRef, isFunctionCall } from '@cacheplane/a2ui'; // Test utilities -export { mockChatAgent } from './lib/testing/mock-chat-agent'; -export type { MockChatAgent, MockChatAgentOptions } from './lib/testing/mock-chat-agent'; -export { runChatAgentConformance } from './lib/testing/chat-agent-conformance'; -export { runChatAgentWithHistoryConformance } from './lib/testing/chat-agent-with-history-conformance'; +export { mockAgent } from './lib/testing/mock-agent'; +export type { MockAgent, MockAgentOptions } from './lib/testing/mock-agent'; +export { runAgentConformance } from './lib/testing/agent-conformance'; +export { runAgentWithHistoryConformance } from './lib/testing/agent-with-history-conformance'; From 0bbc9b8bff31d3aa6383e81933d45b41a3cb0c22 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 24 Apr 2026 20:39:29 -0400 Subject: [PATCH 4/6] =?UTF-8?q?refactor(langgraph):=20rename=20toChatAgent?= =?UTF-8?q?=20=E2=86=92=20toAgent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapter function renamed to match Agent rename in @cacheplane/chat. ChatAgent → Agent, ChatAgentWithHistory → AgentWithHistory in return type and translation helpers. Co-Authored-By: Claude Opus 4.7 --- ...e.spec.ts => to-agent.conformance.spec.ts} | 10 +-- ...to-chat-agent.spec.ts => to-agent.spec.ts} | 48 +++++----- .../src/lib/{to-chat-agent.ts => to-agent.ts} | 88 +++++++++---------- libs/langgraph/src/public-api.ts | 2 +- 4 files changed, 74 insertions(+), 74 deletions(-) rename libs/langgraph/src/lib/{to-chat-agent.conformance.spec.ts => to-agent.conformance.spec.ts} (84%) rename libs/langgraph/src/lib/{to-chat-agent.spec.ts => to-agent.spec.ts} (79%) rename libs/langgraph/src/lib/{to-chat-agent.ts => to-agent.ts} (66%) diff --git a/libs/langgraph/src/lib/to-chat-agent.conformance.spec.ts b/libs/langgraph/src/lib/to-agent.conformance.spec.ts similarity index 84% rename from libs/langgraph/src/lib/to-chat-agent.conformance.spec.ts rename to libs/langgraph/src/lib/to-agent.conformance.spec.ts index c9a9dca60..45d982a5a 100644 --- a/libs/langgraph/src/lib/to-chat-agent.conformance.spec.ts +++ b/libs/langgraph/src/lib/to-agent.conformance.spec.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { TestBed } from '@angular/core/testing'; -import { runChatAgentConformance } from '@cacheplane/chat'; -import { toChatAgent } from './to-chat-agent'; +import { runAgentConformance } from '@cacheplane/chat'; +import { toAgent } from './to-agent'; import { signal } from '@angular/core'; import { ResourceStatus } from './agent.types'; import type { AgentRef } from './agent.types'; @@ -36,10 +36,10 @@ function minimalRef(): AgentRef { } as AgentRef; } -runChatAgentConformance('toChatAgent', () => { - let agent!: ReturnType; +runAgentConformance('toAgent', () => { + let agent!: ReturnType; TestBed.runInInjectionContext(() => { - agent = toChatAgent(minimalRef()); + agent = toAgent(minimalRef()); }); return agent; }); diff --git a/libs/langgraph/src/lib/to-chat-agent.spec.ts b/libs/langgraph/src/lib/to-agent.spec.ts similarity index 79% rename from libs/langgraph/src/lib/to-chat-agent.spec.ts rename to libs/langgraph/src/lib/to-agent.spec.ts index 2957ac52e..c636b56a5 100644 --- a/libs/langgraph/src/lib/to-chat-agent.spec.ts +++ b/libs/langgraph/src/lib/to-agent.spec.ts @@ -2,10 +2,10 @@ import { signal } from '@angular/core'; import { TestBed } from '@angular/core/testing'; import { HumanMessage, AIMessage } from '@langchain/core/messages'; -import type { ChatAgent, ChatCustomEvent } from '@cacheplane/chat'; +import type { Agent, AgentCustomEvent } from '@cacheplane/chat'; import type { AgentRef, CustomStreamEvent } from './agent.types'; import { ResourceStatus } from './agent.types'; -import { toChatAgent } from './to-chat-agent'; +import { toAgent } from './to-agent'; /* eslint-disable @typescript-eslint/no-empty-function */ function stubAgentRef(overrides: Partial> = {}): AgentRef { @@ -38,12 +38,12 @@ function stubAgentRef(overrides: Partial> = {}): AgentRef } as AgentRef; } -describe('toChatAgent (LangGraph adapter)', () => { +describe('toAgent (LangGraph adapter)', () => { it('translates HumanMessage to role: user', () => { TestBed.runInInjectionContext(() => { const ref = stubAgentRef({ messages: signal([new HumanMessage({ content: 'hi', id: 'm1' })]) }); - const chat = toChatAgent(ref); - expect(chat.messages()).toEqual([ + const agent = toAgent(ref); + expect(agent.messages()).toEqual([ { id: 'm1', role: 'user', content: 'hi', extra: expect.any(Object) }, ]); }); @@ -52,28 +52,28 @@ describe('toChatAgent (LangGraph adapter)', () => { it('translates AIMessage to role: assistant', () => { TestBed.runInInjectionContext(() => { const ref = stubAgentRef({ messages: signal([new AIMessage({ content: 'hello', id: 'm2' })]) }); - const chat = toChatAgent(ref); - expect(chat.messages()[0].role).toBe('assistant'); + const agent = toAgent(ref); + expect(agent.messages()[0].role).toBe('assistant'); }); }); - it('maps ResourceStatus.Loading to ChatStatus "running" and sets isLoading', () => { + it('maps ResourceStatus.Loading to AgentStatus "running" and sets isLoading', () => { TestBed.runInInjectionContext(() => { const ref = stubAgentRef({ status: signal(ResourceStatus.Loading), isLoading: signal(true), }); - const chat = toChatAgent(ref); - expect(chat.status()).toBe('running'); - expect(chat.isLoading()).toBe(true); + const agent = toAgent(ref); + expect(agent.status()).toBe('running'); + expect(agent.isLoading()).toBe(true); }); }); - it('maps ResourceStatus.Error to ChatStatus "error"', () => { + it('maps ResourceStatus.Error to AgentStatus "error"', () => { TestBed.runInInjectionContext(() => { const ref = stubAgentRef({ status: signal(ResourceStatus.Error) }); - const chat = toChatAgent(ref); - expect(chat.status()).toBe('error'); + const agent = toAgent(ref); + expect(agent.status()).toBe('error'); }); }); @@ -81,8 +81,8 @@ describe('toChatAgent (LangGraph adapter)', () => { let captured: unknown = null; TestBed.runInInjectionContext(async () => { const ref = stubAgentRef({ submit: async (v) => { captured = v; } }); - const chat = toChatAgent(ref); - await chat.submit({ message: 'hello' }); + const agent = toAgent(ref); + await agent.submit({ message: 'hello' }); expect(captured).toEqual({ messages: [{ role: 'human', content: 'hello' }] }); }); }); @@ -91,13 +91,13 @@ describe('toChatAgent (LangGraph adapter)', () => { let stopped = false; TestBed.runInInjectionContext(async () => { const ref = stubAgentRef({ stop: async () => { stopped = true; } }); - const chat = toChatAgent(ref); - await chat.stop(); + const agent = toAgent(ref); + await agent.stop(); expect(stopped).toBe(true); }); }); - it('translates ThreadState history into ChatCheckpoint[]', () => { + it('translates ThreadState history into AgentCheckpoint[]', () => { TestBed.runInInjectionContext(() => { const ref = stubAgentRef({ history: signal([ @@ -106,8 +106,8 @@ describe('toChatAgent (LangGraph adapter)', () => { { values: { step: 3 }, next: ['nodeC'], checkpoint: undefined }, ] as any), }); - const chat = toChatAgent(ref); - expect(chat.history()).toEqual([ + const agent = toAgent(ref); + expect(agent.history()).toEqual([ { id: 'ck1', label: 'nodeA', values: { step: 1 } }, { id: 'ck2', label: undefined, values: { step: 2 } }, { id: undefined, label: 'nodeC', values: { step: 3 } }, @@ -119,12 +119,12 @@ describe('toChatAgent (LangGraph adapter)', () => { const customSig = signal([]); const ref = stubAgentRef({ customEvents: customSig }); - let adapter!: ChatAgent; + let adapter!: Agent; TestBed.runInInjectionContext(() => { - adapter = toChatAgent(ref); + adapter = toAgent(ref); }); - const received: ChatCustomEvent[] = []; + const received: AgentCustomEvent[] = []; adapter.customEvents$!.subscribe((e) => received.push(e)); customSig.set([{ name: 'state_update', data: { counter: 1 } }]); diff --git a/libs/langgraph/src/lib/to-chat-agent.ts b/libs/langgraph/src/lib/to-agent.ts similarity index 66% rename from libs/langgraph/src/lib/to-chat-agent.ts rename to libs/langgraph/src/lib/to-agent.ts index b6ee57748..caf7d1047 100644 --- a/libs/langgraph/src/lib/to-chat-agent.ts +++ b/libs/langgraph/src/lib/to-agent.ts @@ -4,62 +4,62 @@ import { Subject, type Observable } from 'rxjs'; import type { BaseMessage } from '@langchain/core/messages'; import type { ToolCallWithResult, Interrupt } from '@langchain/langgraph-sdk'; import type { - ChatAgentWithHistory, - ChatCheckpoint, - ChatCustomEvent, - ChatMessage, - ChatRole, - ChatStatus, - ChatToolCall, - ChatToolCallStatus, - ChatInterrupt, - ChatSubagent, - ChatSubmitInput, - ChatSubmitOptions, + AgentWithHistory, + AgentCheckpoint, + AgentCustomEvent, + Message, + Role, + AgentStatus, + ToolCall, + ToolCallStatus, + AgentInterrupt, + Subagent, + AgentSubmitInput, + AgentSubmitOptions, } from '@cacheplane/chat'; import type { AgentRef, CustomStreamEvent, SubagentStreamRef, ThreadState } from './agent.types'; import { ResourceStatus } from './agent.types'; /** - * Adapts a LangGraph AgentRef to the runtime-neutral ChatAgent contract. + * Adapts a LangGraph AgentRef to the runtime-neutral Agent contract. * The returned object is a live view; it reads from the same signals and * writes back via AgentRef.submit / AgentRef.stop. * * Must be called within an Angular injection context (uses `computed` and * `effect`). */ -export function toChatAgent(ref: AgentRef): ChatAgentWithHistory { - const messages = computed(() => - ref.messages().map(toChatMessage), +export function toAgent(ref: AgentRef): AgentWithHistory { + const messages = computed(() => + ref.messages().map(toMessage), ); - const toolCalls = computed(() => - ref.toolCalls().map(toChatToolCall), + const toolCalls = computed(() => + ref.toolCalls().map(toToolCall), ); - const status = computed(() => mapStatus(ref.status())); + const status = computed(() => mapStatus(ref.status())); const state = computed>(() => { const v = ref.value(); return v && typeof v === 'object' ? (v as Record) : {}; }); - const interrupt = computed(() => { + const interrupt = computed(() => { const ix = ref.interrupt(); - return ix ? toChatInterrupt(ix) : undefined; + return ix ? toInterrupt(ix) : undefined; }); - const subagents = computed>(() => { + const subagents = computed>(() => { const src = ref.subagents(); - const out = new Map(); - src.forEach((sa, key) => out.set(key, toChatSubagent(sa))); + const out = new Map(); + src.forEach((sa, key) => out.set(key, toSubagent(sa))); return out; }); const customEvents$ = buildCustomEvents$(ref); - const history = computed(() => - ref.history().map(toChatCheckpoint), + const history = computed(() => + ref.history().map(toCheckpoint), ); return { @@ -73,22 +73,22 @@ export function toChatAgent(ref: AgentRef): ChatAgentWithHistory { subagents, customEvents$, history, - submit: (input: ChatSubmitInput, opts?: ChatSubmitOptions) => + submit: (input: AgentSubmitInput, opts?: AgentSubmitOptions) => ref.submit(buildSubmitPayload(input), opts ? { signal: opts.signal } as never : undefined), stop: () => ref.stop(), }; } /** - * Build an Observable that bridges LangGraph's + * Build an Observable that bridges LangGraph's * `Signal` (append-only array) into a stream of newly * emitted events. Each effect firing compares against a cursor tracking the * previously-seen length and emits only the tail slice. */ function buildCustomEvents$( ref: AgentRef, -): Observable { - const subject = new Subject(); +): Observable { + const subject = new Subject(); let seen = 0; effect(() => { const all = ref.customEvents(); @@ -97,18 +97,18 @@ function buildCustomEvents$( seen = 0; } for (let i = seen; i < all.length; i++) { - subject.next(toChatCustomEvent(all[i])); + subject.next(toCustomEvent(all[i])); } seen = all.length; }); return subject.asObservable(); } -function toChatCustomEvent(e: CustomStreamEvent): ChatCustomEvent { +function toCustomEvent(e: CustomStreamEvent): AgentCustomEvent { return { type: e.name, data: e.data }; } -function mapStatus(s: ResourceStatus): ChatStatus { +function mapStatus(s: ResourceStatus): AgentStatus { switch (s) { case ResourceStatus.Error: return 'error'; case ResourceStatus.Loading: @@ -119,12 +119,12 @@ function mapStatus(s: ResourceStatus): ChatStatus { } } -function toChatMessage(m: BaseMessage): ChatMessage { +function toMessage(m: BaseMessage): Message { const raw = m as unknown as Record; const typeVal = typeof m._getType === 'function' ? m._getType() : (raw['type'] as string | undefined) ?? 'ai'; - const role: ChatRole = + const role: Role = typeVal === 'human' ? 'user' : typeVal === 'tool' ? 'tool' : typeVal === 'system' ? 'system' : @@ -139,13 +139,13 @@ function toChatMessage(m: BaseMessage): ChatMessage { }; } -function toChatToolCall(tc: ToolCallWithResult): ChatToolCall { - const stateMap: Record = { +function toToolCall(tc: ToolCallWithResult): ToolCall { + const stateMap: Record = { pending: 'pending', completed: 'complete', error: 'error', }; - const status: ChatToolCallStatus = stateMap[tc.state] ?? 'running'; + const status: ToolCallStatus = stateMap[tc.state] ?? 'running'; const result = tc.result as (Record | undefined); return { id: tc.id, @@ -157,7 +157,7 @@ function toChatToolCall(tc: ToolCallWithResult): ChatToolCall { }; } -function toChatInterrupt(ix: Interrupt): ChatInterrupt { +function toInterrupt(ix: Interrupt): AgentInterrupt { const raw = ix as unknown as Record; return { id: (raw['id'] as string | undefined) ?? randomId(), @@ -166,21 +166,21 @@ function toChatInterrupt(ix: Interrupt): ChatInterrupt { }; } -function toChatSubagent(sa: SubagentStreamRef): ChatSubagent { +function toSubagent(sa: SubagentStreamRef): Subagent { return { toolCallId: sa.toolCallId, status: sa.status, - messages: computed(() => sa.messages().map(toChatMessage)) as Signal, + messages: computed(() => sa.messages().map(toMessage)) as Signal, state: sa.values as Signal>, }; } -function buildSubmitPayload(input: ChatSubmitInput): unknown { +function buildSubmitPayload(input: AgentSubmitInput): unknown { if (input.resume !== undefined) return { __resume__: input.resume }; if (input.message !== undefined) { const content = typeof input.message === 'string' ? input.message - : input.message.map((b) => (b.type === 'text' ? b.text : JSON.stringify(b))).join(''); + : input.message.map((b: any) => (b.type === 'text' ? b.text : JSON.stringify(b))).join(''); return { messages: [{ role: 'human', content }], ...(input.state ?? {}) }; } return input.state ?? {}; @@ -190,7 +190,7 @@ function randomId(): string { return Math.random().toString(36).slice(2); } -function toChatCheckpoint(state: ThreadState): ChatCheckpoint { +function toCheckpoint(state: ThreadState): AgentCheckpoint { return { id: state.checkpoint?.checkpoint_id ?? undefined, label: state.next?.[0] ?? undefined, diff --git a/libs/langgraph/src/public-api.ts b/libs/langgraph/src/public-api.ts index 7418e7ea4..2a675a1fb 100644 --- a/libs/langgraph/src/public-api.ts +++ b/libs/langgraph/src/public-api.ts @@ -24,7 +24,7 @@ export type { BagTemplate, InferBag, Interrupt, ThreadState, SubmitOptions } export { ResourceStatus } from './lib/agent.types'; // Chat adapter -export { toChatAgent } from './lib/to-chat-agent'; +export { toAgent } from './lib/to-agent'; // Test utilities (always exported — tree-shaken in prod builds) export { MockAgentTransport } from './lib/transport/mock-stream.transport'; From 40fb7b6320f3aa12318fb0b602929df1c6b33dd4 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 24 Apr 2026 20:44:24 -0400 Subject: [PATCH 5/6] refactor(cockpit): adopt Agent rename across demos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updates imports of toChatAgent → toAgent and any direct Type references (ChatAgent, ChatMessage, etc.) to the new bare/Agent- prefixed names. Component class imports (ChatMessagesComponent etc.) are unchanged. Co-Authored-By: Claude Opus 4.7 --- cockpit/chat/a2ui/angular/src/app/a2ui.component.ts | 4 ++-- cockpit/chat/debug/angular/src/app/debug.component.ts | 4 ++-- .../generative-ui/angular/src/app/generative-ui.component.ts | 4 ++-- cockpit/chat/input/angular/src/app/input.component.ts | 4 ++-- .../chat/interrupts/angular/src/app/interrupts.component.ts | 4 ++-- cockpit/chat/messages/angular/src/app/messages.component.ts | 4 ++-- cockpit/chat/subagents/angular/src/app/subagents.component.ts | 4 ++-- cockpit/chat/theming/angular/src/app/theming.component.ts | 4 ++-- cockpit/chat/threads/angular/src/app/threads.component.ts | 4 ++-- cockpit/chat/timeline/angular/src/app/timeline.component.ts | 4 ++-- .../chat/tool-calls/angular/src/app/tool-calls.component.ts | 4 ++-- .../filesystem/angular/src/app/filesystem.component.ts | 4 ++-- .../deep-agents/memory/angular/src/app/memory.component.ts | 4 ++-- .../planning/angular/src/app/planning.component.ts | 4 ++-- .../sandboxes/angular/src/app/sandboxes.component.ts | 4 ++-- .../deep-agents/skills/angular/src/app/skills.component.ts | 4 ++-- .../subagents/angular/src/app/subagents.component.ts | 4 ++-- .../angular/src/app/deployment-runtime.component.ts | 4 ++-- .../angular/src/app/durable-execution.component.ts | 4 ++-- .../interrupts/angular/src/app/interrupts.component.ts | 4 ++-- cockpit/langgraph/memory/angular/src/app/memory.component.ts | 4 ++-- .../persistence/angular/src/app/persistence.component.ts | 4 ++-- .../streaming/angular/src/app/streaming.component.ts | 4 ++-- .../subgraphs/angular/src/app/subgraphs.component.ts | 4 ++-- .../time-travel/angular/src/app/time-travel.component.ts | 4 ++-- 25 files changed, 50 insertions(+), 50 deletions(-) diff --git a/cockpit/chat/a2ui/angular/src/app/a2ui.component.ts b/cockpit/chat/a2ui/angular/src/app/a2ui.component.ts index 8ce334ebc..269046921 100644 --- a/cockpit/chat/a2ui/angular/src/app/a2ui.component.ts +++ b/cockpit/chat/a2ui/angular/src/app/a2ui.component.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { Component } from '@angular/core'; import { ChatComponent, a2uiBasicCatalog } from '@cacheplane/chat'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { environment } from '../environments/environment'; @Component({ @@ -15,6 +15,6 @@ export class A2uiComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.a2uiAssistantId, }); - protected readonly chatAgent = toChatAgent(this.agentRef); + protected readonly chatAgent = toAgent(this.agentRef); protected readonly catalog = a2uiBasicCatalog(); } diff --git a/cockpit/chat/debug/angular/src/app/debug.component.ts b/cockpit/chat/debug/angular/src/app/debug.component.ts index c4f581fc1..3dec822b9 100644 --- a/cockpit/chat/debug/angular/src/app/debug.component.ts +++ b/cockpit/chat/debug/angular/src/app/debug.component.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { Component } from '@angular/core'; import { ChatDebugComponent } from '@cacheplane/chat'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; import { environment } from '../environments/environment'; @@ -25,5 +25,5 @@ export class DebugPageComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); } diff --git a/cockpit/chat/generative-ui/angular/src/app/generative-ui.component.ts b/cockpit/chat/generative-ui/angular/src/app/generative-ui.component.ts index f82b43bf2..85284ef1d 100644 --- a/cockpit/chat/generative-ui/angular/src/app/generative-ui.component.ts +++ b/cockpit/chat/generative-ui/angular/src/app/generative-ui.component.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { Component } from '@angular/core'; import { ChatComponent, views } from '@cacheplane/chat'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; import { environment } from '../environments/environment'; @@ -36,6 +36,6 @@ export class GenerativeUiComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.generativeUiAssistantId, }); - protected readonly chatAgent = toChatAgent(this.agentRef); + protected readonly chatAgent = toAgent(this.agentRef); protected readonly dashboardViews = dashboardViews; } diff --git a/cockpit/chat/input/angular/src/app/input.component.ts b/cockpit/chat/input/angular/src/app/input.component.ts index 7e9952dc8..3b4c5d6db 100644 --- a/cockpit/chat/input/angular/src/app/input.component.ts +++ b/cockpit/chat/input/angular/src/app/input.component.ts @@ -3,7 +3,7 @@ import { Component, computed } from '@angular/core'; import { ChatInputComponent as ChatInputPrimitive } from '@cacheplane/chat'; import { ChatMessagesComponent } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { environment } from '../environments/environment'; /** @@ -56,7 +56,7 @@ export class InputComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); protected readonly streamStatus = computed(() => this.stream.status()); protected readonly isLoading = computed(() => this.stream.isLoading()); diff --git a/cockpit/chat/interrupts/angular/src/app/interrupts.component.ts b/cockpit/chat/interrupts/angular/src/app/interrupts.component.ts index 78db2db6a..875f98cf2 100644 --- a/cockpit/chat/interrupts/angular/src/app/interrupts.component.ts +++ b/cockpit/chat/interrupts/angular/src/app/interrupts.component.ts @@ -3,7 +3,7 @@ import { Component, computed } from '@angular/core'; import { JsonPipe } from '@angular/common'; import { ChatComponent, ChatInterruptPanelComponent } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { environment } from '../environments/environment'; /** @@ -37,7 +37,7 @@ export class InterruptsComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); protected readonly streamStatus = computed(() => this.stream.status()); } diff --git a/cockpit/chat/messages/angular/src/app/messages.component.ts b/cockpit/chat/messages/angular/src/app/messages.component.ts index ef8a82904..1152d5466 100644 --- a/cockpit/chat/messages/angular/src/app/messages.component.ts +++ b/cockpit/chat/messages/angular/src/app/messages.component.ts @@ -6,7 +6,7 @@ import { ChatTypingIndicatorComponent, } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { environment } from '../environments/environment'; /** @@ -51,7 +51,7 @@ export class MessagesComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); submitMessage(content: string) { this.chatAgent.submit({ message: content }); diff --git a/cockpit/chat/subagents/angular/src/app/subagents.component.ts b/cockpit/chat/subagents/angular/src/app/subagents.component.ts index 2eed880bd..ad753d203 100644 --- a/cockpit/chat/subagents/angular/src/app/subagents.component.ts +++ b/cockpit/chat/subagents/angular/src/app/subagents.component.ts @@ -6,7 +6,7 @@ import { ChatSubagentCardComponent, } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { environment } from '../environments/environment'; /** @@ -44,5 +44,5 @@ export class SubagentsComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); } diff --git a/cockpit/chat/theming/angular/src/app/theming.component.ts b/cockpit/chat/theming/angular/src/app/theming.component.ts index 64f21d35d..00b08645d 100644 --- a/cockpit/chat/theming/angular/src/app/theming.component.ts +++ b/cockpit/chat/theming/angular/src/app/theming.component.ts @@ -3,7 +3,7 @@ import { Component, signal } from '@angular/core'; import { TitleCasePipe } from '@angular/common'; import { ChatComponent } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { environment } from '../environments/environment'; const THEMES: Record> = { @@ -88,7 +88,7 @@ export class ThemingComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); protected readonly themeNames = Object.keys(THEMES); protected readonly activeTheme = signal('dark'); diff --git a/cockpit/chat/threads/angular/src/app/threads.component.ts b/cockpit/chat/threads/angular/src/app/threads.component.ts index e338ab3d7..2e0232e37 100644 --- a/cockpit/chat/threads/angular/src/app/threads.component.ts +++ b/cockpit/chat/threads/angular/src/app/threads.component.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { Component, signal } from '@angular/core'; import { ChatComponent, ChatThreadListComponent, type Thread } from '@cacheplane/chat'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; import { environment } from '../environments/environment'; @@ -33,7 +33,7 @@ export class ThreadsComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); protected readonly threads = signal([ { id: 'thread-1', title: 'First Conversation' }, diff --git a/cockpit/chat/timeline/angular/src/app/timeline.component.ts b/cockpit/chat/timeline/angular/src/app/timeline.component.ts index 681f1cfae..891a796cb 100644 --- a/cockpit/chat/timeline/angular/src/app/timeline.component.ts +++ b/cockpit/chat/timeline/angular/src/app/timeline.component.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { ChatComponent, ChatTimelineSliderComponent } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { environment } from '../environments/environment'; /** @@ -38,5 +38,5 @@ export class TimelineComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); } diff --git a/cockpit/chat/tool-calls/angular/src/app/tool-calls.component.ts b/cockpit/chat/tool-calls/angular/src/app/tool-calls.component.ts index be429ee0e..895d8ed22 100644 --- a/cockpit/chat/tool-calls/angular/src/app/tool-calls.component.ts +++ b/cockpit/chat/tool-calls/angular/src/app/tool-calls.component.ts @@ -6,7 +6,7 @@ import { ChatToolCallCardComponent, } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { environment } from '../environments/environment'; /** @@ -42,5 +42,5 @@ export class ToolCallsComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); } diff --git a/cockpit/deep-agents/filesystem/angular/src/app/filesystem.component.ts b/cockpit/deep-agents/filesystem/angular/src/app/filesystem.component.ts index aef80a94f..ab83f6fe1 100644 --- a/cockpit/deep-agents/filesystem/angular/src/app/filesystem.component.ts +++ b/cockpit/deep-agents/filesystem/angular/src/app/filesystem.component.ts @@ -1,7 +1,7 @@ import { Component, computed } from '@angular/core'; import { ChatComponent, views } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { signalStateStore } from '@cacheplane/render'; import { environment } from '../environments/environment'; import { FilePreviewComponent } from './views/file-preview.component'; @@ -74,7 +74,7 @@ export class FilesystemComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); /** * Reactive list of file operations derived from the message history. diff --git a/cockpit/deep-agents/memory/angular/src/app/memory.component.ts b/cockpit/deep-agents/memory/angular/src/app/memory.component.ts index 6d0046930..ea7b451a3 100644 --- a/cockpit/deep-agents/memory/angular/src/app/memory.component.ts +++ b/cockpit/deep-agents/memory/angular/src/app/memory.component.ts @@ -1,7 +1,7 @@ import { Component, computed } from '@angular/core'; import { ChatComponent } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { environment } from '../environments/environment'; /** @@ -55,7 +55,7 @@ export class MemoryComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); /** * Reactive list of [key, value] memory entries derived from the graph state. diff --git a/cockpit/deep-agents/planning/angular/src/app/planning.component.ts b/cockpit/deep-agents/planning/angular/src/app/planning.component.ts index fa682195e..d667133f0 100644 --- a/cockpit/deep-agents/planning/angular/src/app/planning.component.ts +++ b/cockpit/deep-agents/planning/angular/src/app/planning.component.ts @@ -1,7 +1,7 @@ import { Component, computed } from '@angular/core'; import { ChatComponent, views } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { signalStateStore } from '@cacheplane/render'; import { environment } from '../environments/environment'; import { PlanChecklistComponent } from './views/plan-checklist.component'; @@ -74,7 +74,7 @@ export class PlanningComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); /** * Reactive list of plan steps derived from the graph state. diff --git a/cockpit/deep-agents/sandboxes/angular/src/app/sandboxes.component.ts b/cockpit/deep-agents/sandboxes/angular/src/app/sandboxes.component.ts index 7a88b9ab5..42d13d12f 100644 --- a/cockpit/deep-agents/sandboxes/angular/src/app/sandboxes.component.ts +++ b/cockpit/deep-agents/sandboxes/angular/src/app/sandboxes.component.ts @@ -1,7 +1,7 @@ import { Component, computed } from '@angular/core'; import { ChatComponent, views } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { signalStateStore } from '@cacheplane/render'; import { environment } from '../environments/environment'; import { CodeExecutionComponent } from './views/code-execution.component'; @@ -68,7 +68,7 @@ export class SandboxesComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); /** * Derived signal: extracts code executions from the message stream. diff --git a/cockpit/deep-agents/skills/angular/src/app/skills.component.ts b/cockpit/deep-agents/skills/angular/src/app/skills.component.ts index 876e0b8a9..acc90860a 100644 --- a/cockpit/deep-agents/skills/angular/src/app/skills.component.ts +++ b/cockpit/deep-agents/skills/angular/src/app/skills.component.ts @@ -1,7 +1,7 @@ import { Component, computed } from '@angular/core'; import { ChatComponent, views } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { signalStateStore } from '@cacheplane/render'; import { environment } from '../environments/environment'; import { CalculatorResultComponent } from './views/calculator-result.component'; @@ -75,7 +75,7 @@ export class SkillsComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); private readonly SKILL_NAMES = new Set(['calculator', 'word_count', 'summarize']); diff --git a/cockpit/deep-agents/subagents/angular/src/app/subagents.component.ts b/cockpit/deep-agents/subagents/angular/src/app/subagents.component.ts index 4e2e34660..23370e5c1 100644 --- a/cockpit/deep-agents/subagents/angular/src/app/subagents.component.ts +++ b/cockpit/deep-agents/subagents/angular/src/app/subagents.component.ts @@ -1,7 +1,7 @@ import { Component, computed } from '@angular/core'; import { ChatComponent } from '@cacheplane/chat'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { environment } from '../environments/environment'; /** @@ -59,7 +59,7 @@ export class SubagentsComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); /** * Reactive delegation list derived from messages. diff --git a/cockpit/langgraph/deployment-runtime/angular/src/app/deployment-runtime.component.ts b/cockpit/langgraph/deployment-runtime/angular/src/app/deployment-runtime.component.ts index 1f5f0e260..6b89531ad 100644 --- a/cockpit/langgraph/deployment-runtime/angular/src/app/deployment-runtime.component.ts +++ b/cockpit/langgraph/deployment-runtime/angular/src/app/deployment-runtime.component.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { Component } from '@angular/core'; import { ChatComponent } from '@cacheplane/chat'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; import { environment } from '../environments/environment'; @@ -26,5 +26,5 @@ export class DeploymentRuntimeComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.deploymentRuntimeAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); } diff --git a/cockpit/langgraph/durable-execution/angular/src/app/durable-execution.component.ts b/cockpit/langgraph/durable-execution/angular/src/app/durable-execution.component.ts index 39a323909..4f7e64f91 100644 --- a/cockpit/langgraph/durable-execution/angular/src/app/durable-execution.component.ts +++ b/cockpit/langgraph/durable-execution/angular/src/app/durable-execution.component.ts @@ -1,6 +1,6 @@ import { Component, computed } from '@angular/core'; import { ChatComponent, views } from '@cacheplane/chat'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { signalStateStore } from '@cacheplane/render'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; import { environment } from '../environments/environment'; @@ -102,7 +102,7 @@ export class DurableExecutionComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); /** * Derives the 3-step pipeline status from the graph's `state.step` field. diff --git a/cockpit/langgraph/interrupts/angular/src/app/interrupts.component.ts b/cockpit/langgraph/interrupts/angular/src/app/interrupts.component.ts index fcd053da0..dbfe94329 100644 --- a/cockpit/langgraph/interrupts/angular/src/app/interrupts.component.ts +++ b/cockpit/langgraph/interrupts/angular/src/app/interrupts.component.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { Component } from '@angular/core'; import { ChatComponent, ChatInterruptPanelComponent, views, type InterruptAction } from '@cacheplane/chat'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; import { signalStateStore } from '@cacheplane/render'; import { environment } from '../environments/environment'; @@ -50,7 +50,7 @@ export class InterruptsComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); /** * Handle an interrupt action from the panel. diff --git a/cockpit/langgraph/memory/angular/src/app/memory.component.ts b/cockpit/langgraph/memory/angular/src/app/memory.component.ts index a24992ec6..fda65d53f 100644 --- a/cockpit/langgraph/memory/angular/src/app/memory.component.ts +++ b/cockpit/langgraph/memory/angular/src/app/memory.component.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { Component, computed } from '@angular/core'; import { ChatComponent } from '@cacheplane/chat'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; import { environment } from '../environments/environment'; @@ -52,7 +52,7 @@ export class MemoryComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); /** * Reactive list of [key, value] memory entries derived from the graph state. diff --git a/cockpit/langgraph/persistence/angular/src/app/persistence.component.ts b/cockpit/langgraph/persistence/angular/src/app/persistence.component.ts index fabfd30ac..b88226559 100644 --- a/cockpit/langgraph/persistence/angular/src/app/persistence.component.ts +++ b/cockpit/langgraph/persistence/angular/src/app/persistence.component.ts @@ -1,6 +1,6 @@ import { Component, signal } from '@angular/core'; import { ChatComponent } from '@cacheplane/chat'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; import { environment } from '../environments/environment'; @@ -98,7 +98,7 @@ export class PersistenceComponent { } }, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); /** Switch to an existing thread by ID. */ switchThread(id: string): void { diff --git a/cockpit/langgraph/streaming/angular/src/app/streaming.component.ts b/cockpit/langgraph/streaming/angular/src/app/streaming.component.ts index aa24c2469..c6370953e 100644 --- a/cockpit/langgraph/streaming/angular/src/app/streaming.component.ts +++ b/cockpit/langgraph/streaming/angular/src/app/streaming.component.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { Component } from '@angular/core'; import { ChatComponent } from '@cacheplane/chat'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; import { environment } from '../environments/environment'; @@ -27,5 +27,5 @@ export class StreamingComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); } diff --git a/cockpit/langgraph/subgraphs/angular/src/app/subgraphs.component.ts b/cockpit/langgraph/subgraphs/angular/src/app/subgraphs.component.ts index 7313794a3..9a4279ce1 100644 --- a/cockpit/langgraph/subgraphs/angular/src/app/subgraphs.component.ts +++ b/cockpit/langgraph/subgraphs/angular/src/app/subgraphs.component.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { Component, computed } from '@angular/core'; import { ChatComponent } from '@cacheplane/chat'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; import { environment } from '../environments/environment'; @@ -55,7 +55,7 @@ export class SubgraphsComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); /** * Derived signal: converts the subagents Map to an array for template iteration. diff --git a/cockpit/langgraph/time-travel/angular/src/app/time-travel.component.ts b/cockpit/langgraph/time-travel/angular/src/app/time-travel.component.ts index 274e976b5..2b5b1e483 100644 --- a/cockpit/langgraph/time-travel/angular/src/app/time-travel.component.ts +++ b/cockpit/langgraph/time-travel/angular/src/app/time-travel.component.ts @@ -1,6 +1,6 @@ import { Component, computed, signal } from '@angular/core'; import { ChatComponent } from '@cacheplane/chat'; -import { agent, toChatAgent } from '@cacheplane/langgraph'; +import { agent, toAgent } from '@cacheplane/langgraph'; import type { ThreadState } from '@cacheplane/langgraph'; import { ExampleChatLayoutComponent } from '@cacheplane/example-layouts'; import { environment } from '../environments/environment'; @@ -107,7 +107,7 @@ export class TimeTravelComponent { apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - protected readonly chatAgent = toChatAgent(this.stream); + protected readonly chatAgent = toAgent(this.stream); /** Index of the currently selected checkpoint in the sidebar. */ protected readonly selectedIndex = signal(-1); From 2a0e532a44bc1d265932539c3e4fc7d1f7531ff5 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 24 Apr 2026 20:45:49 -0400 Subject: [PATCH 6/6] docs(chat): update README to reference Agent contract Co-Authored-By: Claude Opus 4.7 --- libs/chat/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/chat/README.md b/libs/chat/README.md index 6fb0aa4c5..8e7ce32b9 100644 --- a/libs/chat/README.md +++ b/libs/chat/README.md @@ -4,11 +4,11 @@ This library was generated with [Nx](https://nx.dev). ## Runtime adapters -Chat primitives consume a runtime-neutral `ChatAgent` contract. Two adapters ship today: +Chat primitives consume a runtime-neutral `Agent` contract. Two adapters ship today: - **`@cacheplane/langgraph`** — for LangGraph / LangGraph Platform backends. - **`@cacheplane/ag-ui`** — for any AG-UI-compatible backend (LangGraph, CrewAI, Mastra, Microsoft Agent Framework, AG2, Pydantic AI, AWS Strands, CopilotKit runtime). -Custom backends can implement `ChatAgent` directly with no library dependency. +Custom backends can implement `Agent` directly with no library dependency. See the capability matrix in the docs site for which primitives require which runtime capabilities.