Files
UHD_Media_Tool/packages/agent/src/runtime/event-channel.ts
T
rootandClaude Fable 5.1 9c881e737f feat(agent): capability registry, Pi AgentRuntimePort, fake model provider and redaction guard (W1-5)
- CapabilityRegistry: descriptor(id/version/schema/scope/risk/idempotent/preview/replay),
  invoke = scope limit -> input schema -> server-side authorize -> idempotency key -> handler
  -> output schema -> audit; capability id <-> tool name mapping (download.submit <-> download__submit)
- PiAgentRuntime (pi-agent-core AgentHarness 0.87.1): whitelist tools + before_tool re-check,
  redacted event stream, JSONL session at sessionDir/<runId>.jsonl, resume/abort/compact,
  tool-call/duration/token/cost budgets -> abort + run_failed(budget)
- AgentSettings -> pi-ai createProvider (anthropic / openai-compatible), compaction mapping
- FakeModelProvider + createFakeRuntime (scripted, transcript-derived, survives crash/resume)
- buildSystemPrompt, redactForModel; 27 tests incl. SIGKILL + resume

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-27 17:55:28 +08:00

41 lines
930 B
TypeScript

/** 追加式事件通道:全部事件保存在内存,支持多个消费者按 seq 回放 + 实时跟随 */
export class EventChannel<T> {
private readonly items: T[] = [];
private waiters: Array<() => void> = [];
private closed = false;
push(item: T): void {
if (this.closed) return;
this.items.push(item);
this.wake();
}
close(): void {
this.closed = true;
this.wake();
}
get size(): number {
return this.items.length;
}
snapshot(): T[] {
return [...this.items];
}
async *iterate(fromIndex = 0): AsyncGenerator<T> {
let i = Math.max(0, fromIndex);
while (true) {
while (i < this.items.length) yield this.items[i++] as T;
if (this.closed) return;
await new Promise<void>((resolve) => this.waiters.push(resolve));
}
}
private wake(): void {
const waiters = this.waiters;
this.waiters = [];
for (const w of waiters) w();
}
}