diff options
| author | Adam Malczewski <[email protected]> | 2026-06-04 23:55:29 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-04 23:55:29 +0900 |
| commit | e56b591d56ea3f3007c612da2f0fe2004d696f45 (patch) | |
| tree | 01a3503b5c72cd78971d8dc304d80835d76201cf /packages/kernel/src | |
| parent | 51a88160fbb8e06d93f7507b5e3e4cca80e98902 (diff) | |
| download | dispatch-e56b591d56ea3f3007c612da2f0fe2004d696f45.tar.gz dispatch-e56b591d56ea3f3007c612da2f0fe2004d696f45.zip | |
fix(kernel): expose getProviders/getTools on HostAPI (CR-2) + runTurn uses input tabId/turnId (CR-3); simplify orchestrator wiring (167 tests)
Diffstat (limited to 'packages/kernel/src')
| -rw-r--r-- | packages/kernel/src/contracts/extension.ts | 6 | ||||
| -rw-r--r-- | packages/kernel/src/host/host.test.ts | 50 | ||||
| -rw-r--r-- | packages/kernel/src/host/host.ts | 6 | ||||
| -rw-r--r-- | packages/kernel/src/runtime/run-turn.test.ts | 30 | ||||
| -rw-r--r-- | packages/kernel/src/runtime/run-turn.ts | 4 |
5 files changed, 94 insertions, 2 deletions
diff --git a/packages/kernel/src/contracts/extension.ts b/packages/kernel/src/contracts/extension.ts index ac252b4..7078a9a 100644 --- a/packages/kernel/src/contracts/extension.ts +++ b/packages/kernel/src/contracts/extension.ts @@ -224,6 +224,12 @@ export interface HostAPI { /** Logger — always available, even before other extensions activate. */ readonly logger: Logger; + /** Read-only view of all registered providers. */ + readonly getProviders: () => ReadonlyMap<string, ProviderContract>; + + /** Read-only view of all registered tools. */ + readonly getTools: () => ReadonlyMap<string, ToolContract>; + /** Register a scheduled job with the host's scheduler. */ readonly scheduler: { readonly register: (job: ScheduledJob) => void; diff --git a/packages/kernel/src/host/host.test.ts b/packages/kernel/src/host/host.test.ts index 862854e..f7b7eba 100644 --- a/packages/kernel/src/host/host.test.ts +++ b/packages/kernel/src/host/host.test.ts @@ -584,6 +584,56 @@ describe("createHost", () => { }); }); + describe("HostAPI registry access", () => { + it("getTools returns registered tools via HostAPI", async () => { + const tool = createFakeTool("read-file"); + let capturedTools: ReadonlyMap<string, ToolContract> | undefined; + + const producer = createExtension("tools-fs", { + activate: (host) => { + host.defineTool(tool); + }, + }); + const consumer = createExtension("consumer", { + dependsOn: ["tools-fs"], + activate: (host) => { + capturedTools = host.getTools(); + }, + }); + + const host = createHost([producer, consumer], deps); + await host.activate(); + + expect(capturedTools).toBeDefined(); + expect(capturedTools?.size).toBe(1); + expect(capturedTools?.get("read-file")).toBe(tool); + }); + + it("getProviders returns registered providers via HostAPI", async () => { + const provider = createFakeProvider("anthropic"); + let capturedProviders: ReadonlyMap<string, ProviderContract> | undefined; + + const producer = createExtension("provider-anthropic", { + activate: (host) => { + host.defineProvider(provider); + }, + }); + const consumer = createExtension("consumer", { + dependsOn: ["provider-anthropic"], + activate: (host) => { + capturedProviders = host.getProviders(); + }, + }); + + const host = createHost([producer, consumer], deps); + await host.activate(); + + expect(capturedProviders).toBeDefined(); + expect(capturedProviders?.size).toBe(1); + expect(capturedProviders?.get("anthropic")).toBe(provider); + }); + }); + describe("DAG errors", () => { it("throws on missing dependency", () => { const ext = createExtension("a", { dependsOn: ["missing"] }); diff --git a/packages/kernel/src/host/host.ts b/packages/kernel/src/host/host.ts index 4ffef20..e0ca5d5 100644 --- a/packages/kernel/src/host/host.ts +++ b/packages/kernel/src/host/host.ts @@ -126,6 +126,12 @@ export function createHost(extensions: readonly Extension[], deps: HostDeps): Ho permissions: deps.permissions, events: deps.events, logger: deps.logger, + getProviders() { + return providers; + }, + getTools() { + return tools; + }, scheduler: { register(job: ScheduledJob) { scheduledJobs.push(job); diff --git a/packages/kernel/src/runtime/run-turn.test.ts b/packages/kernel/src/runtime/run-turn.test.ts index f63a0a8..1ea6406 100644 --- a/packages/kernel/src/runtime/run-turn.test.ts +++ b/packages/kernel/src/runtime/run-turn.test.ts @@ -52,6 +52,36 @@ const userMessage: ChatMessage = { }; describe("runTurn", () => { + it("emits events with the tabId and turnId from input", async () => { + const provider = createFakeProvider([ + [ + { type: "text-delta", delta: "hi" }, + { type: "usage", usage: { inputTokens: 1, outputTokens: 1 } }, + { type: "finish", reason: "stop" }, + ], + ]); + + const { events, emit } = createCollectingEmit(); + + await runTurn({ + provider, + messages: [userMessage], + tools: [], + dispatch: { maxConcurrent: 1, eager: false }, + tabId: "conv-42", + turnId: "turn-99", + emit, + }); + + expect(events.length).toBeGreaterThan(0); + for (const event of events) { + expect(event.tabId).toBe("conv-42"); + if (event.type !== "status") { + expect(event.turnId).toBe("turn-99"); + } + } + }); + it("text-only turn emits correct events and returns correct result", async () => { const provider = createFakeProvider([ [ diff --git a/packages/kernel/src/runtime/run-turn.ts b/packages/kernel/src/runtime/run-turn.ts index 46b1465..919491a 100644 --- a/packages/kernel/src/runtime/run-turn.ts +++ b/packages/kernel/src/runtime/run-turn.ts @@ -217,8 +217,8 @@ export async function runTurn(input: RunTurnInput): Promise<RunTurnResult> { toolMap.set(tool.name, tool); } - const tabId = ""; - const turnId = ""; + const tabId = input.tabId; + const turnId = input.turnId; const signal = input.signal ?? new AbortController().signal; for (let step = 0; step < MAX_STEPS; step++) { |
