@abelxiaoxing/cadence 1.0.11 → 1.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,16 +3,11 @@
3
3
  // markers for proposed new paths. Currency is decided per bound path; no
4
4
  // global workspace revision participates.
5
5
  import { createHash } from "node:crypto";
6
- import {
7
- existsSync,
8
- lstatSync,
9
- readdirSync,
10
- readFileSync,
11
- readlinkSync,
12
- statSync,
13
- } from "node:fs";
6
+ import { lstatSync, readdirSync, readFileSync, readlinkSync } from "node:fs";
14
7
  import { join, resolve } from "node:path";
15
8
 
9
+ import { observeSafePath } from "./safe-path.ts";
10
+
16
11
  export interface FileBound {
17
12
  kind: "file";
18
13
  sha256: string;
@@ -37,9 +32,8 @@ function sha256(bytes: Buffer): string {
37
32
 
38
33
  /** Snapshot one existing regular file under root. */
39
34
  export function snapshotFile(root: string, relPath: string): FileBound | null {
35
+ if (observeSafePath(root, relPath).kind !== "file") return null;
40
36
  const abs = resolve(root, relPath);
41
- const st = statSync(abs, { throwIfNoEntry: false });
42
- if (!st?.isFile()) return null;
43
37
  const bytes = readFileSync(abs);
44
38
  return { sha256: sha256(bytes), bytes: bytes.length, kind: "file" };
45
39
  }
@@ -99,9 +93,8 @@ export function snapshotDirManifest(
99
93
  root: string,
100
94
  relDir: string,
101
95
  ): DirBound | null {
96
+ if (observeSafePath(root, relDir).kind !== "directory") return null;
102
97
  const abs = resolve(root, relDir);
103
- const st = statSync(abs, { throwIfNoEntry: false });
104
- if (!st?.isDirectory()) return null;
105
98
  return { manifest: recursiveDirectoryManifest(abs), kind: "dir" };
106
99
  }
107
100
 
@@ -117,8 +110,9 @@ export function snapshotFiles(
117
110
  if (entry) bound[p] = entry;
118
111
  else bound[p] = { kind: "absent", absent: true };
119
112
  }
120
- for (const p of opts.absent ?? [])
113
+ for (const p of opts.absent ?? []) {
121
114
  bound[p] = { kind: "absent", absent: true };
115
+ }
122
116
  return bound;
123
117
  }
124
118
 
@@ -141,12 +135,9 @@ export function isCurrent(root: string, bound: Bound): boolean {
141
135
  if (!now || now.manifest !== expected.manifest) return false;
142
136
  continue;
143
137
  }
144
- const abs = resolve(root, rel);
145
- const exists = existsSync(abs);
138
+ const observation = observeSafePath(root, rel);
146
139
  if (expected.kind === "file") {
147
- if (!exists) return false;
148
- const st = statSync(abs);
149
- if (!st.isFile()) return false;
140
+ if (observation.kind !== "file") return false;
150
141
  const now = snapshotFile(root, rel);
151
142
  if (
152
143
  !now ||
@@ -154,8 +145,8 @@ export function isCurrent(root: string, bound: Bound): boolean {
154
145
  now.bytes !== expected.bytes
155
146
  )
156
147
  return false;
157
- } else if (expected.absent) {
158
- if (exists) return false;
148
+ } else if (expected.absent && observation.kind !== "absent") {
149
+ return false;
159
150
  }
160
151
  }
161
152
  return true;
@@ -0,0 +1,571 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ type ImplementationPhase,
4
+ type ImplementGraphBoundary,
5
+ type ImplementGraphOutput,
6
+ type ImplementGraphReadinessCode,
7
+ type ImplementGraphReadinessDiagnostic,
8
+ type ImplementTaskBoundary,
9
+ type VerificationInputBinding,
10
+ validateImplementGraphBoundary,
11
+ verificationInputPaths,
12
+ } from "./contracts.ts";
13
+ import { isSafeRegularFile } from "./safe-path.ts";
14
+ import { validateVerificationAdapterCapability } from "./verification-capability.ts";
15
+
16
+ function canonicalJson(value: unknown): string {
17
+ if (Array.isArray(value)) {
18
+ return `[${value.map(canonicalJson).join(",")}]`;
19
+ }
20
+ if (value && typeof value === "object") {
21
+ const entries = Object.entries(value as Record<string, unknown>)
22
+ .filter(([, entry]) => entry !== undefined)
23
+ .sort(([left], [right]) => left.localeCompare(right));
24
+ return `{${entries
25
+ .map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`)
26
+ .join(",")}}`;
27
+ }
28
+ return JSON.stringify(value) ?? "null";
29
+ }
30
+
31
+ export function hashImplementGraphBoundary(value: unknown): string {
32
+ return createHash("sha256").update(canonicalJson(value)).digest("hex");
33
+ }
34
+
35
+ export interface ImplementExecutionFacts {
36
+ completedTasks: readonly string[];
37
+ blockedTasks?: readonly string[];
38
+ appliedPhases?: ReadonlyArray<{
39
+ taskId: string;
40
+ phase: ImplementationPhase;
41
+ }>;
42
+ candidate?: { taskId: string; phase: ImplementationPhase };
43
+ dependencyOwner?: string;
44
+ }
45
+
46
+ export interface ImplementPhaseReadiness {
47
+ taskId: string;
48
+ phase: ImplementationPhase;
49
+ ready: boolean;
50
+ completed?: true;
51
+ diagnostics: ImplementGraphReadinessDiagnostic[];
52
+ }
53
+
54
+ export interface ImplementGraphReadiness {
55
+ closure: {
56
+ executable: boolean;
57
+ diagnostics: ImplementGraphReadinessDiagnostic[];
58
+ };
59
+ phases: ImplementPhaseReadiness[];
60
+ outputs: ImplementOutputReadiness[];
61
+ }
62
+
63
+ export interface ImplementOutputReadiness {
64
+ outputId: string;
65
+ producerTaskId: string;
66
+ producerPhase: ImplementationPhase;
67
+ status: "pending" | "available" | "unavailable";
68
+ diagnostic?: ImplementGraphReadinessDiagnostic;
69
+ }
70
+
71
+ const IMPLEMENT_PHASE_INDEX: Record<ImplementationPhase, number> = {
72
+ red: 0,
73
+ green: 1,
74
+ refactor: 2,
75
+ };
76
+
77
+ function graphDiagnostic(
78
+ code: ImplementGraphReadinessCode,
79
+ details: Omit<
80
+ Extract<ImplementGraphReadinessDiagnostic, { kind: "graph-readiness" }>,
81
+ "kind" | "code"
82
+ > = {},
83
+ ): ImplementGraphReadinessDiagnostic {
84
+ return { kind: "graph-readiness", code, ...details };
85
+ }
86
+
87
+ function taskPhases(
88
+ task: ImplementTaskBoundary,
89
+ ): Array<[ImplementationPhase, ImplementTaskBoundary["phases"]["red"]]> {
90
+ return [
91
+ ["red", task.phases.red],
92
+ ["green", task.phases.green],
93
+ ...(task.phases.refactor
94
+ ? ([["refactor", task.phases.refactor]] as Array<
95
+ [ImplementationPhase, ImplementTaskBoundary["phases"]["red"]]
96
+ >)
97
+ : []),
98
+ ];
99
+ }
100
+
101
+ function withinTaskRoots(
102
+ task: ImplementTaskBoundary,
103
+ candidate: string,
104
+ ): boolean {
105
+ return task.roots.some(
106
+ (root) =>
107
+ root === "." || candidate === root || candidate.startsWith(`${root}/`),
108
+ );
109
+ }
110
+
111
+ function dependencyAncestors(
112
+ taskId: string,
113
+ tasks: ReadonlyMap<string, ImplementTaskBoundary>,
114
+ ): Set<string> {
115
+ const ancestors = new Set<string>();
116
+ const pending = [...(tasks.get(taskId)?.dependsOn ?? [])];
117
+ while (pending.length > 0) {
118
+ const dependency = pending.pop() as string;
119
+ if (ancestors.has(dependency)) continue;
120
+ ancestors.add(dependency);
121
+ pending.push(...(tasks.get(dependency)?.dependsOn ?? []));
122
+ }
123
+ return ancestors;
124
+ }
125
+
126
+ function bindingPath(
127
+ binding: VerificationInputBinding,
128
+ outputs: ReadonlyMap<string, ImplementGraphOutput>,
129
+ ): string | undefined {
130
+ return binding.kind === "workspace"
131
+ ? binding.path
132
+ : outputs.get(binding.outputId)?.path;
133
+ }
134
+
135
+ function sameStringSet(
136
+ left: readonly string[],
137
+ right: readonly string[],
138
+ ): boolean {
139
+ return (
140
+ left.length === right.length && left.every((entry) => right.includes(entry))
141
+ );
142
+ }
143
+
144
+ function appendDistinct(
145
+ diagnostics: ImplementGraphReadinessDiagnostic[],
146
+ diagnostic: ImplementGraphReadinessDiagnostic,
147
+ ): void {
148
+ if (
149
+ !diagnostics.some(
150
+ (candidate) => JSON.stringify(candidate) === JSON.stringify(diagnostic),
151
+ )
152
+ ) {
153
+ diagnostics.push(diagnostic);
154
+ }
155
+ }
156
+
157
+ export function assessImplementGraphReadiness(
158
+ root: string,
159
+ value: unknown,
160
+ facts: ImplementExecutionFacts,
161
+ ): ImplementGraphReadiness {
162
+ const validation = validateImplementGraphBoundary(value);
163
+ if (!validation.ok) {
164
+ const diagnostic = graphDiagnostic(validation.diagnostic.code, {
165
+ ...(validation.diagnostic.code === "invalid-output-path" &&
166
+ validation.diagnostic.outputId
167
+ ? { outputId: validation.diagnostic.outputId }
168
+ : {}),
169
+ });
170
+ return {
171
+ closure: { executable: false, diagnostics: [diagnostic] },
172
+ phases: [],
173
+ outputs: [],
174
+ };
175
+ }
176
+
177
+ const graph: ImplementGraphBoundary = validation.value;
178
+ const diagnostics: ImplementGraphReadinessDiagnostic[] = [];
179
+ const tasks = new Map<string, ImplementTaskBoundary>();
180
+ for (const task of graph.tasks) {
181
+ if (tasks.has(task.taskId)) {
182
+ diagnostics.push(
183
+ graphDiagnostic("duplicate-task-id", { taskId: task.taskId }),
184
+ );
185
+ } else {
186
+ tasks.set(task.taskId, task);
187
+ }
188
+ }
189
+
190
+ for (const task of graph.tasks) {
191
+ for (const dependencyTaskId of task.dependsOn) {
192
+ if (!tasks.has(dependencyTaskId) || dependencyTaskId === task.taskId) {
193
+ diagnostics.push(
194
+ graphDiagnostic("unknown-dependency", {
195
+ taskId: task.taskId,
196
+ dependencyTaskId,
197
+ }),
198
+ );
199
+ }
200
+ }
201
+ if (dependencyAncestors(task.taskId, tasks).has(task.taskId)) {
202
+ diagnostics.push(
203
+ graphDiagnostic("dependency-cycle", { taskId: task.taskId }),
204
+ );
205
+ }
206
+ }
207
+
208
+ const outputs = new Map<string, ImplementGraphOutput>();
209
+ const outputPaths = new Map<string, ImplementGraphOutput>();
210
+ for (const output of graph.outputs) {
211
+ if (outputs.has(output.id)) {
212
+ diagnostics.push(
213
+ graphDiagnostic("duplicate-output-id", { outputId: output.id }),
214
+ );
215
+ } else {
216
+ outputs.set(output.id, output);
217
+ }
218
+ const prior = outputPaths.get(output.path);
219
+ if (prior) {
220
+ diagnostics.push(
221
+ graphDiagnostic("multiple-output-producers", {
222
+ outputId: output.id,
223
+ path: output.path,
224
+ producerTaskId: output.producer.taskId,
225
+ producerPhase: output.producer.phase,
226
+ }),
227
+ );
228
+ } else {
229
+ outputPaths.set(output.path, output);
230
+ }
231
+
232
+ const producer = tasks.get(output.producer.taskId);
233
+ const producerPhase = producer?.phases[output.producer.phase];
234
+ if (
235
+ !producer ||
236
+ !producerPhase ||
237
+ !withinTaskRoots(producer, output.path)
238
+ ) {
239
+ diagnostics.push(
240
+ graphDiagnostic("output-producer-invalid", {
241
+ outputId: output.id,
242
+ producerTaskId: output.producer.taskId,
243
+ producerPhase: output.producer.phase,
244
+ }),
245
+ );
246
+ } else if (!producerPhase.write.includes(output.path)) {
247
+ diagnostics.push(
248
+ graphDiagnostic("output-write-not-approved", {
249
+ outputId: output.id,
250
+ producerTaskId: output.producer.taskId,
251
+ producerPhase: output.producer.phase,
252
+ }),
253
+ );
254
+ }
255
+ }
256
+
257
+ const phaseStaticDiagnostics = new Map<
258
+ string,
259
+ ImplementGraphReadinessDiagnostic[]
260
+ >();
261
+ for (const task of graph.tasks) {
262
+ const ancestors = dependencyAncestors(task.taskId, tasks);
263
+ for (const [phase, boundary] of taskPhases(task)) {
264
+ const key = `${task.taskId}\0${phase}`;
265
+ const current: ImplementGraphReadinessDiagnostic[] = [];
266
+ phaseStaticDiagnostics.set(key, current);
267
+ const verificationId = boundary.verification.id;
268
+ const requiredPaths = verificationInputPaths(boundary.verification);
269
+ const boundPaths = boundary.verificationInputs
270
+ .map((binding) => bindingPath(binding, outputs))
271
+ .filter((entry): entry is string => entry !== undefined);
272
+
273
+ for (const binding of boundary.verificationInputs) {
274
+ if (binding.kind === "workspace") {
275
+ const graphOutput = outputPaths.get(binding.path);
276
+ if (graphOutput) {
277
+ appendDistinct(
278
+ current,
279
+ graphDiagnostic("workspace-input-has-producer", {
280
+ taskId: task.taskId,
281
+ phase,
282
+ verificationId,
283
+ outputId: graphOutput.id,
284
+ path: binding.path,
285
+ }),
286
+ );
287
+ }
288
+ if (!isSafeRegularFile(root, binding.path)) {
289
+ appendDistinct(
290
+ current,
291
+ graphDiagnostic("workspace-input-unavailable", {
292
+ taskId: task.taskId,
293
+ phase,
294
+ verificationId,
295
+ path: binding.path,
296
+ }),
297
+ );
298
+ }
299
+ continue;
300
+ }
301
+
302
+ const output = outputs.get(binding.outputId);
303
+ if (!output) {
304
+ appendDistinct(
305
+ current,
306
+ graphDiagnostic("output-not-declared", {
307
+ taskId: task.taskId,
308
+ phase,
309
+ verificationId,
310
+ outputId: binding.outputId,
311
+ }),
312
+ );
313
+ continue;
314
+ }
315
+ if (output.producer.taskId === task.taskId) {
316
+ if (
317
+ IMPLEMENT_PHASE_INDEX[output.producer.phase] >
318
+ IMPLEMENT_PHASE_INDEX[phase]
319
+ ) {
320
+ appendDistinct(
321
+ current,
322
+ graphDiagnostic("producer-phase-after-consumer", {
323
+ taskId: task.taskId,
324
+ phase,
325
+ verificationId,
326
+ outputId: output.id,
327
+ producerTaskId: output.producer.taskId,
328
+ producerPhase: output.producer.phase,
329
+ }),
330
+ );
331
+ }
332
+ } else if (!ancestors.has(output.producer.taskId)) {
333
+ appendDistinct(
334
+ current,
335
+ graphDiagnostic("producer-not-dependency", {
336
+ taskId: task.taskId,
337
+ phase,
338
+ verificationId,
339
+ outputId: output.id,
340
+ producerTaskId: output.producer.taskId,
341
+ producerPhase: output.producer.phase,
342
+ }),
343
+ );
344
+ }
345
+ }
346
+
347
+ if (!sameStringSet(requiredPaths, boundPaths)) {
348
+ appendDistinct(
349
+ current,
350
+ graphDiagnostic("verification-input-binding-mismatch", {
351
+ taskId: task.taskId,
352
+ phase,
353
+ verificationId,
354
+ }),
355
+ );
356
+ }
357
+
358
+ const capability = validateVerificationAdapterCapability(
359
+ root,
360
+ boundary.verification,
361
+ { dependencyOwner: facts.dependencyOwner ?? root },
362
+ );
363
+ if (!capability.ok) {
364
+ const { message: _message, ...diagnostic } = capability.diagnostic;
365
+ appendDistinct(current, {
366
+ ...diagnostic,
367
+ taskId: task.taskId,
368
+ phase,
369
+ });
370
+ }
371
+ diagnostics.push(...current);
372
+ }
373
+ }
374
+
375
+ const closure = {
376
+ executable: diagnostics.length === 0,
377
+ diagnostics,
378
+ };
379
+ const completedTasks = new Set(facts.completedTasks);
380
+ const blockedTasks = new Set(facts.blockedTasks ?? []);
381
+ const appliedPhases = new Set(
382
+ (facts.appliedPhases ?? []).map(
383
+ (entry) => `${entry.taskId}\0${entry.phase}`,
384
+ ),
385
+ );
386
+ const outputReadiness: ImplementOutputReadiness[] = graph.outputs.map(
387
+ (output) => {
388
+ const observed =
389
+ completedTasks.has(output.producer.taskId) ||
390
+ appliedPhases.has(
391
+ `${output.producer.taskId}\0${output.producer.phase}`,
392
+ ) ||
393
+ (facts.candidate?.taskId === output.producer.taskId &&
394
+ facts.candidate.phase === output.producer.phase);
395
+ if (!observed) {
396
+ return {
397
+ outputId: output.id,
398
+ producerTaskId: output.producer.taskId,
399
+ producerPhase: output.producer.phase,
400
+ status: "pending" as const,
401
+ };
402
+ }
403
+ if (isSafeRegularFile(root, output.path)) {
404
+ return {
405
+ outputId: output.id,
406
+ producerTaskId: output.producer.taskId,
407
+ producerPhase: output.producer.phase,
408
+ status: "available" as const,
409
+ };
410
+ }
411
+ return {
412
+ outputId: output.id,
413
+ producerTaskId: output.producer.taskId,
414
+ producerPhase: output.producer.phase,
415
+ status: "unavailable" as const,
416
+ diagnostic: graphDiagnostic("producer-output-unavailable", {
417
+ outputId: output.id,
418
+ producerTaskId: output.producer.taskId,
419
+ producerPhase: output.producer.phase,
420
+ }),
421
+ };
422
+ },
423
+ );
424
+ const outputStatus = new Map(
425
+ outputReadiness.map((entry) => [entry.outputId, entry]),
426
+ );
427
+ const phases: ImplementPhaseReadiness[] = [];
428
+
429
+ for (const task of graph.tasks) {
430
+ for (const [phase, boundary] of taskPhases(task)) {
431
+ const staticDiagnostics = phaseStaticDiagnostics.get(
432
+ `${task.taskId}\0${phase}`,
433
+ ) as ImplementGraphReadinessDiagnostic[];
434
+ if (!closure.executable) {
435
+ phases.push({
436
+ taskId: task.taskId,
437
+ phase,
438
+ ready: false,
439
+ diagnostics:
440
+ staticDiagnostics.length > 0 ? staticDiagnostics : diagnostics,
441
+ });
442
+ continue;
443
+ }
444
+ if (completedTasks.has(task.taskId)) {
445
+ phases.push({
446
+ taskId: task.taskId,
447
+ phase,
448
+ ready: false,
449
+ completed: true,
450
+ diagnostics: [],
451
+ });
452
+ continue;
453
+ }
454
+
455
+ const current: ImplementGraphReadinessDiagnostic[] = [];
456
+ if (blockedTasks.has(task.taskId)) {
457
+ current.push(
458
+ graphDiagnostic("dependency-blocked", {
459
+ taskId: task.taskId,
460
+ phase,
461
+ dependencyTaskId: task.taskId,
462
+ }),
463
+ );
464
+ }
465
+ for (const dependencyTaskId of task.dependsOn) {
466
+ if (!completedTasks.has(dependencyTaskId)) {
467
+ appendDistinct(
468
+ current,
469
+ graphDiagnostic("dependency-blocked", {
470
+ taskId: task.taskId,
471
+ phase,
472
+ dependencyTaskId,
473
+ }),
474
+ );
475
+ }
476
+ }
477
+
478
+ const earlierPhases = taskPhases(task)
479
+ .map(([candidate]) => candidate)
480
+ .filter(
481
+ (candidate) =>
482
+ IMPLEMENT_PHASE_INDEX[candidate] < IMPLEMENT_PHASE_INDEX[phase],
483
+ );
484
+ if (
485
+ earlierPhases.some(
486
+ (candidate) => !appliedPhases.has(`${task.taskId}\0${candidate}`),
487
+ )
488
+ ) {
489
+ appendDistinct(
490
+ current,
491
+ graphDiagnostic("phase-blocked", { taskId: task.taskId, phase }),
492
+ );
493
+ }
494
+
495
+ if (current.length === 0) {
496
+ for (const binding of boundary.verificationInputs) {
497
+ if (binding.kind !== "output") continue;
498
+ const output = outputs.get(binding.outputId);
499
+ if (!output) continue;
500
+ const sameTask = output.producer.taskId === task.taskId;
501
+ const samePhase = sameTask && output.producer.phase === phase;
502
+ const readiness = outputStatus.get(output.id);
503
+ const published =
504
+ !sameTask && completedTasks.has(output.producer.taskId);
505
+ if (readiness?.status === "unavailable") {
506
+ appendDistinct(
507
+ current,
508
+ graphDiagnostic("producer-output-unavailable", {
509
+ taskId: task.taskId,
510
+ phase,
511
+ outputId: output.id,
512
+ producerTaskId: output.producer.taskId,
513
+ producerPhase: output.producer.phase,
514
+ }),
515
+ );
516
+ } else if (
517
+ (!sameTask && !published) ||
518
+ (sameTask && !samePhase && readiness?.status !== "available")
519
+ ) {
520
+ appendDistinct(
521
+ current,
522
+ sameTask
523
+ ? graphDiagnostic("phase-blocked", {
524
+ taskId: task.taskId,
525
+ phase,
526
+ })
527
+ : graphDiagnostic("dependency-blocked", {
528
+ taskId: task.taskId,
529
+ phase,
530
+ dependencyTaskId: output.producer.taskId,
531
+ }),
532
+ );
533
+ }
534
+ }
535
+
536
+ if (
537
+ facts.candidate?.taskId === task.taskId &&
538
+ facts.candidate.phase === phase
539
+ ) {
540
+ for (const output of graph.outputs.filter(
541
+ (entry) =>
542
+ entry.producer.taskId === task.taskId &&
543
+ entry.producer.phase === phase,
544
+ )) {
545
+ if (outputStatus.get(output.id)?.status !== "available") {
546
+ appendDistinct(
547
+ current,
548
+ graphDiagnostic("producer-output-unavailable", {
549
+ taskId: task.taskId,
550
+ phase,
551
+ outputId: output.id,
552
+ producerTaskId: output.producer.taskId,
553
+ producerPhase: output.producer.phase,
554
+ }),
555
+ );
556
+ }
557
+ }
558
+ }
559
+ }
560
+
561
+ phases.push({
562
+ taskId: task.taskId,
563
+ phase,
564
+ ready: current.length === 0,
565
+ diagnostics: current,
566
+ });
567
+ }
568
+ }
569
+
570
+ return { closure, phases, outputs: outputReadiness };
571
+ }
package/src/index.ts CHANGED
@@ -232,6 +232,7 @@ export default function register(pi: ExtensionAPI): void {
232
232
  ? "Run exactly one bounded read-only design-explorer packet. When parallel packets are required, emit every sibling abel_dispatch call together in one assistant response before waiting for any result."
233
233
  : "Private Abel workflow delegation: run bounded read-only evidence or Worker phase requests, apply or discard retained results, apply a parent-only stable AGENTS checkpoint, cancel work, or finish the stage. Inactive unless an eligible Abel stage verified its invocation.",
234
234
  executionMode: "parallel",
235
+ renderShell: "self",
235
236
  parameters: {
236
237
  type: "object",
237
238
  properties: {
@@ -304,16 +305,25 @@ export default function register(pi: ExtensionAPI): void {
304
305
  ...(usage === undefined ? {} : { usage }),
305
306
  };
306
307
  },
307
- renderCall(args: unknown, theme: Theme, _context: unknown) {
308
- return renderActivityCall(args, theme);
308
+ renderCall(args: unknown, theme: Theme, context: unknown) {
309
+ return renderActivityCall(
310
+ args,
311
+ theme,
312
+ context as Parameters<typeof renderActivityCall>[2],
313
+ );
309
314
  },
310
315
  renderResult(
311
316
  result: AgentToolResult<unknown>,
312
317
  options: ToolRenderResultOptions,
313
318
  theme: Theme,
314
- _context: unknown,
319
+ context: unknown,
315
320
  ) {
316
- return renderActivityResult(result, options, theme);
321
+ return renderActivityResult(
322
+ result,
323
+ options,
324
+ theme,
325
+ context as Parameters<typeof renderActivityResult>[3],
326
+ );
317
327
  },
318
328
  } as never);
319
329
  };