aboutsummaryrefslogtreecommitdiff
path: root/src/util/tool.ts
diff options
context:
space:
mode:
authoramankumarsingh77 <amankumarsingh7702@gmal.com>2026-05-02 16:05:09 +0530
committeramankumarsingh77 <amankumarsingh7702@gmal.com>2026-05-02 16:05:09 +0530
commit0f962ef99b82207239e5dacb399be3cabce0ece3 (patch)
treeeb45efdf8821dc882a6c578fe6e767af24cc5266 /src/util/tool.ts
parent6a4bfa31a925af67c026cd68700fe7779fd7c4cb (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/tool.ts')
-rw-r--r--src/util/tool.ts23
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