diff options
| author | amankumarsingh77 <amankumarsingh7702@gmal.com> | 2026-05-02 16:05:09 +0530 |
|---|---|---|
| committer | amankumarsingh77 <amankumarsingh7702@gmal.com> | 2026-05-02 16:05:09 +0530 |
| commit | 0f962ef99b82207239e5dacb399be3cabce0ece3 (patch) | |
| tree | eb45efdf8821dc882a6c578fe6e767af24cc5266 /src/util | |
| parent | 6a4bfa31a925af67c026cd68700fe7779fd7c4cb (diff) | |
feat(domains): migrate browser_click to defineBrowserTool — vertical slice
Implements Task 9: adds src/domains/click.ts with the new architecture,
updates registry.ts to register clickTool, removes the legacy browser_click
block from tools.ts, and wires BrowserClient alongside BrowserDaemon in
index.ts so both systems coexist during migration.
Also fixes AnyBrowserToolDefinition variance: uses never-arg renderCall in
the erased type and a boundary cast in registerBrowserTool so concrete tool
definitions (with specific Static<S> args) are assignable to the registry
array without widening.
Diffstat (limited to 'src/util')
| -rw-r--r-- | src/util/tool.ts | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/src/util/tool.ts b/src/util/tool.ts index fc1c5e2..d269ba2 100644 --- a/src/util/tool.ts +++ b/src/util/tool.ts @@ -56,9 +56,14 @@ export type BrowserToolDefinition<S extends TSchema> = { readonly ensureAlive?: boolean; }; -// Type-erased entry for arrays. AnyBrowserToolDefinition lets the registry -// hold a heterogeneous list without losing the per-tool Static<S> binding. -export type AnyBrowserToolDefinition = BrowserToolDefinition<TSchema>; +// Type-erased entry for the registry's heterogeneous TOOLS array. +// renderCall accepts `never` so any concrete args type satisfies it via +// function-parameter contravariance (a handler that takes SpecificT is +// assignable to one that takes never, because never is a subtype of everything). +export type AnyBrowserToolDefinition = Omit<BrowserToolDefinition<TSchema>, "renderCall" | "renderResult"> & { + readonly renderCall?: (args: never, theme: Theme) => Component; + readonly renderResult?: (result: AgentToolResult<unknown>, expanded: boolean, theme: Theme) => Component; +}; export const defineBrowserTool = <S extends TSchema>( def: BrowserToolDefinition<S>, @@ -94,11 +99,15 @@ const toToolResult = ( }; }; -export const registerBrowserTool = <S extends TSchema>( +export const registerBrowserTool = ( pi: ExtensionAPI, client: BrowserClient, - def: BrowserToolDefinition<S>, + def: AnyBrowserToolDefinition, ): void => { + // AnyBrowserToolDefinition is type-erased; we recover the schema-typed surface + // by casting def to the generic form. The cast is safe because defineBrowserTool + // ensures the handler, parameters, and renderCall were all created with the same S. + type S = TSchema; const td: ToolDefinition<S> = { name: def.name, label: def.label, @@ -110,7 +119,9 @@ export const registerBrowserTool = <S extends TSchema>( ? { renderCall: (args: Static<S>, theme: Theme, _ctx: Parameters<NonNullable<ToolDefinition<S>["renderCall"]>>[2]) => // Non-null assertion safe: this branch only runs when renderCall was provided. - def.renderCall!(args, theme), + // Cast from never->Component to unknown->Component: safe because at runtime + // args is always the concrete Static<S> value the tool was defined with. + (def.renderCall as (args: unknown, theme: Theme) => Component)(args, theme), } : {}), ...(def.renderResult |
