Skip to content

Commit 448503d

Browse files
authored
feat: add signal resource agent proof
Add a private signal resource adapter proof for the chat Agent contract, with conformance coverage and focused adapter behavior tests.\n\nAlso update the M6 plan with the completed proof decisions and harden the chat e2e request-failure helper for benign aborted icon font loads observed in CI.\n\nVerification:\n- NX_DAEMON=false npx nx test chat --skip-nx-cache --outputStyle=static --testFile=src/lib/agent/signal-chat-resource-agent.spec.ts\n- NX_DAEMON=false npx nx test chat --skip-nx-cache --outputStyle=static\n- NX_DAEMON=false npx nx test ag-ui --skip-nx-cache --outputStyle=static\n- NX_DAEMON=false npx nx test langgraph --skip-nx-cache --outputStyle=static\n- NX_DAEMON=false npx nx lint chat --skip-nx-cache --outputStyle=static\n- NX_DAEMON=false npx nx build chat --skip-nx-cache --outputStyle=static\n- NX_DAEMON=false npx nx e2e examples-chat-angular --skip-nx-cache --outputStyle=static -- --grep "streaming markdown table|streaming code fence"\n- NX_DAEMON=false npx nx lint examples-chat-angular --skip-nx-cache --outputStyle=static\n- GitHub required checks green
1 parent 3e5bb0b commit 448503d

4 files changed

Lines changed: 466 additions & 16 deletions

File tree

docs/superpowers/plans/2026-07-08-client-tools-m6-agent-bridge-plan.md

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,17 @@ Discovery result: the inspected provider exposes a stateful chat/resource API pl
112112
**Files:**
113113
- Modify this plan or add contract notes if the decision is made before implementation.
114114

115-
- [ ] **Step 1: Choose package boundary**
115+
- [x] **Step 1: Choose package boundary**
116116

117117
Pick one:
118118

119119
- new published adapter package, if consumers should import it directly;
120120
- private/internal adapter, if this is only a migration bridge;
121121
- no code, if provider APIs are unstable or unavailable.
122122

123-
- [ ] **Step 2: Decide public API shape**
123+
Decision: add a private/internal adapter proof under `libs/chat` first. Do not create a new published package or public export until the package boundary is approved.
124+
125+
- [x] **Step 2: Decide public API shape**
124126

125127
If public, mirror existing adapter ergonomics:
126128

@@ -132,7 +134,9 @@ injectAgent(ref?)
132134
133135
Use a provider-specific prefix internally if needed to avoid collisions with existing adapter types, but keep the consumer mental model aligned with AG-UI and LangGraph.
134136
135-
- [ ] **Step 3: Decide client-tools mapping**
137+
Decision: no public API in the adapter-proof PR. A future public package should mirror `toAgent(source, options?)` and DI provider ergonomics only after API shape review.
138+
139+
- [x] **Step 3: Decide client-tools mapping**
136140
137141
Confirm whether provider tools are:
138142
@@ -142,13 +146,15 @@ Confirm whether provider tools are:
142146
143147
Only map browser-executed tools into Threadplane `action`/`view`/`ask` when the provider supplies stable pending-call identifiers and a result-return API.
144148
149+
Decision: do not map provider tools into `ClientToolsCapability` in the adapter-proof PR. The inspected source exposes provider-owned tool execution without a stable browser result-return API for Threadplane client tools.
150+
145151
## Task 3: Contract Tests First
146152
147153
**Files:**
148154
- Add: adapter conformance spec path TBD.
149155
- Add: provider fake/test fixture path TBD.
150156
151-
- [ ] **Step 1: Build a scriptable provider fake**
157+
- [x] **Step 1: Build a scriptable provider fake**
152158
153159
Create a test-only fake from the captured event contract. It must support:
154160
@@ -157,7 +163,9 @@ Create a test-only fake from the captured event contract. It must support:
157163
- message/tool history inspection;
158164
- branch-on-tool-result behavior if the provider supports continuation.
159165
160-
- [ ] **Step 2: Write failing `Agent` conformance tests**
166+
Implementation note: the first adapter-proof PR uses a scriptable signal-resource fake scoped to the observed public resource surface, not transport-frame scripts.
167+
168+
- [x] **Step 2: Write failing `Agent` conformance tests**
161169
162170
Cover:
163171
@@ -171,7 +179,7 @@ Cover:
171179
- regenerate trims at the selected assistant message and reruns;
172180
- custom events flow through `events$` or adapter-specific signal if supported.
173181
174-
- [ ] **Step 3: Write client-tools bridge tests only if supported**
182+
- [x] **Step 3: Write client-tools bridge tests only if supported**
175183
176184
If provider has stable browser tool primitives, cover:
177185
@@ -184,16 +192,20 @@ If provider has stable browser tool primitives, cover:
184192
185193
Do not implement client-tools mapping if the provider lacks stable tool-call IDs or result APIs.
186194
195+
Decision: not supported for this proof. The adapter tests cover tool-call projection only; no client-tools bridge tests are added.
196+
187197
## Task 4: Minimal Adapter Implementation
188198
189199
**Files:**
190200
- Add/modify only after Tasks 1-3 pass their decision gates.
191201
192-
- [ ] **Step 1: Implement event reduction**
202+
- [x] **Step 1: Implement event reduction**
193203
194204
Prefer the AG-UI reducer path if compatible. Otherwise implement only the reducer cases proven by fixtures. Unknown events must be ignored or surfaced as neutral custom events; they must not crash the stream.
195205
196-
- [ ] **Step 2: Implement actions**
206+
Implementation note: the proof uses resource-state projection rather than event reduction because the inspected public API exposes resource state, not a public event subscriber.
207+
208+
- [x] **Step 2: Implement actions**
197209
198210
Map:
199211
@@ -204,11 +216,13 @@ Map:
204216
205217
to provider APIs only where semantics match the existing `Agent` contract. Throwing is acceptable for programmer misuse, but normal unsupported provider features should be absent or no-op only if that matches existing adapter precedent.
206218
207-
- [ ] **Step 3: Add Angular provider wiring**
219+
- [x] **Step 3: Add Angular provider wiring**
208220
209221
If public or DI-supported, mirror the existing typed `AgentRef` overloads and factory config pattern from AG-UI/LangGraph.
210222
211-
- [ ] **Step 4: Add public exports and docs only after approval**
223+
Decision: not applicable to the private proof. No DI/provider helper is added.
224+
225+
- [x] **Step 4: Add public exports and docs only after approval**
212226
213227
If the adapter is public:
214228
@@ -218,16 +232,24 @@ npm run generate-api-docs
218232
219233
Expected: generated API docs include the new bridge types. Commit generated docs with the public export.
220234
235+
Decision: not applicable to the private proof. No public export is added, so API docs are unchanged.
236+
221237
## Task 5: Verification
222238
223239
**Files:**
224240
- No additional files.
225241
226-
- [ ] **Step 1: Run focused adapter tests**
242+
- [x] **Step 1: Run focused adapter tests**
227243
228244
Run the new adapter test target or focused Vitest spec.
229245
230-
- [ ] **Step 2: Run affected existing adapter/chat tests**
246+
Verified:
247+
248+
```bash
249+
NX_DAEMON=false npx nx test chat --skip-nx-cache --outputStyle=static --testFile=src/lib/agent/signal-chat-resource-agent.spec.ts
250+
```
251+
252+
- [x] **Step 2: Run affected existing adapter/chat tests**
231253
232254
Run:
233255
@@ -239,18 +261,37 @@ NX_DAEMON=false npx nx test chat --skip-nx-cache --outputStyle=static
239261
240262
Expected: all pass. If the new bridge is in its own project, run its test/lint/build target as well.
241263
242-
- [ ] **Step 3: Lint and build affected projects**
264+
Verified:
265+
266+
```bash
267+
NX_DAEMON=false npx nx test ag-ui --skip-nx-cache --outputStyle=static
268+
NX_DAEMON=false npx nx test langgraph --skip-nx-cache --outputStyle=static
269+
NX_DAEMON=false npx nx test chat --skip-nx-cache --outputStyle=static
270+
```
271+
272+
- [x] **Step 3: Lint and build affected projects**
243273
244274
Run the smallest affected Nx lint/build targets. If API docs changed, verify generated docs are committed.
245275
246-
- [ ] **Step 4: Forbidden-reference scan**
276+
Verified:
277+
278+
```bash
279+
NX_DAEMON=false npx nx lint chat --skip-nx-cache --outputStyle=static
280+
NX_DAEMON=false npx nx build chat --skip-nx-cache --outputStyle=static
281+
```
282+
283+
- [x] **Step 4: Forbidden-reference scan**
247284
248285
Before committing code, run a staged diff scan excluding `docs/superpowers/**` and confirm no forbidden external framework names appear in code, comments, commit text, or PR text.
249286
250-
- [ ] **Step 5: Diff audit**
287+
Verified with a staged diff scan excluding `docs/superpowers/**`; no forbidden references appeared in code or comments.
288+
289+
- [x] **Step 5: Diff audit**
251290
252291
Confirm the diff contains no unrelated refactors, no package dependency changes unless explicitly approved, and no behavior changes to existing AG-UI or LangGraph adapters.
253292
293+
Verified: diff is limited to the private adapter proof, its tests, and this plan status update.
294+
254295
---
255296
256297
## Current Recommendation

examples/chat/angular/e2e/test-helpers.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,19 @@ export function attachBrowserHygiene(page: Page): {
2121
page.on('requestfailed', (request) => {
2222
const failure = request.failure()?.errorText ?? '';
2323
const url = request.url();
24-
if (/runs\/stream/.test(url) && /abort|ERR_ABORTED/i.test(failure)) return;
24+
if (isBenignAbortedRequest(url, failure)) return;
2525
failedRequests.push(`${request.method()} ${url} ${failure}`.trim());
2626
});
2727

2828
return { consoleErrors, failedRequests };
2929
}
3030

31+
function isBenignAbortedRequest(url: string, failure: string): boolean {
32+
if (!/abort|ERR_ABORTED/i.test(failure)) return false;
33+
if (/runs\/stream/.test(url)) return true;
34+
return /fonts\.gstatic\.com\/s\/materialsymbolsoutlined\/.+\.woff2/.test(url);
35+
}
36+
3137
export async function openDemo(page: Page, path = '/embed'): Promise<void> {
3238
await page.goto(path);
3339
await page.evaluate(() => {

0 commit comments

Comments
 (0)