ai-tool-set 0.1.0-alpha.4 → 1.1.0

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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 Chris
3
+ Copyright (c) 2024 Chris Cook
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # ai-tool-set
4
4
 
5
- <p align="center">AI SDK: Manage tool activation with type-safe, chainable tool sets</p>
5
+ <p align="center">Conditional tool activation for the AI SDK, fully type-safe</p>
6
6
  <p align="center">
7
7
  <a href="https://www.npmjs.com/package/ai-tool-set" alt="ai-tool-set"><img src="https://img.shields.io/npm/dt/ai-tool-set?label=ai-tool-set"></a> <a href="https://github.com/zirkelc/ai-tool-set/actions/workflows/ci.yml" alt="CI"><img src="https://img.shields.io/github/actions/workflow/status/zirkelc/ai-tool-set/ci.yml?branch=main"></a>
8
8
  </p>
@@ -441,6 +441,28 @@ type MyInput = ActivationInput<MyUIMessage, { isAdmin: boolean }>;
441
441
  // { messages?: Array<MyUIMessage>; context?: { isAdmin: boolean } }
442
442
  ```
443
443
 
444
+ ### `ToolSet`
445
+
446
+ Parameter type that accepts both immutable and mutable variants of an existing tool set. Use it for helpers that should work regardless of which flavor the caller is holding:
447
+
448
+ ```ts
449
+ import { createToolSet, type ToolSet } from 'ai-tool-set';
450
+
451
+ const toolSet = createToolSet({ tools }).deactivate(['cancel_order']);
452
+
453
+ type MyToolSet = ToolSet<typeof toolSet>;
454
+
455
+ // Accepts the immutable toolset AND the cloned mutable instance
456
+ function activateTools(toolSet: MyToolSet) {
457
+ toolSet.activate(['cancel_order']);
458
+ }
459
+
460
+ activateTools(toolSet);
461
+
462
+ const mutableToolSet = toolSet.clone({ mutable: true });
463
+ activateTools(mutableToolSet);
464
+ ```
465
+
444
466
  ### `InferToolSet`
445
467
 
446
468
  Extract the raw tool record from a tool record or `ToolSet` instance:
@@ -467,35 +489,35 @@ type MyUIMessage = UIMessage<unknown, any, InferUIToolSet<typeof toolSet>>;
467
489
  // message.parts[0].output // typed as search tool's return type
468
490
  ```
469
491
 
470
- ### `ActiveTools`
492
+ ### `InferActiveTools`
471
493
 
472
494
  Extract the tool names tracked as active from an immutable `ToolSet` instance. Tracks tools from `.activate()` and `.deactivateWhen()`.
473
495
 
474
496
  > [!NOTE]
475
- > `ActiveTools` returns `never` for mutable toolsets, since TypeScript cannot track type changes on the same reference across method calls.
497
+ > `InferActiveTools` returns `never` for mutable toolsets, since TypeScript cannot track type changes on the same reference across method calls.
476
498
 
477
499
  ```ts
478
- import type { ActiveTools } from 'ai-tool-set';
500
+ import type { InferActiveTools } from 'ai-tool-set';
479
501
 
480
502
  const toolSet = createToolSet({ tools }).deactivate(['cancel_order']);
481
503
 
482
- type Active = ActiveTools<typeof toolSet>;
504
+ type Active = InferActiveTools<typeof toolSet>;
483
505
  // 'search' | 'list_orders'
484
506
  ```
485
507
 
486
- ### `InactiveTools`
508
+ ### `InferInactiveTools`
487
509
 
488
510
  Extract the tool names tracked as inactive from an immutable `ToolSet` instance. Tracks tools from `.deactivate()` and `.activateWhen()`.
489
511
 
490
512
  > [!NOTE]
491
- > `InactiveTools` returns `never` for mutable toolsets, since TypeScript cannot track type changes on the same reference across method calls.
513
+ > `InferInactiveTools` returns `never` for mutable toolsets, since TypeScript cannot track type changes on the same reference across method calls.
492
514
 
493
515
  ```ts
494
- import type { InactiveTools } from 'ai-tool-set';
516
+ import type { InferInactiveTools } from 'ai-tool-set';
495
517
 
496
518
  const toolSet = createToolSet({ tools }).deactivate(['cancel_order']);
497
519
 
498
- type Inactive = InactiveTools<typeof toolSet>;
520
+ type Inactive = InferInactiveTools<typeof toolSet>;
499
521
  // 'cancel_order'
500
522
  ```
501
523
 
package/dist/index.d.mts CHANGED
@@ -8,19 +8,19 @@ type MessageType = UIMessage | ModelMessage;
8
8
  /** The fully-typed UIMessage for a given tool record. */
9
9
  type InferUIMessage<TOOLS extends ToolRecord> = UIMessage<unknown, any, InferUIToolSet<TOOLS>>;
10
10
  /** Infer the raw tool record from a ToolRecord or ToolSet instance. */
11
- type InferToolSet<T extends ToolRecord | AnyToolSet> = T extends ImmutableToolSet<infer TOOLS, any, any> ? TOOLS : T extends MutableToolSet<infer TOOLS, any, any> ? TOOLS : T;
11
+ type InferToolSet<TOOLSET extends ToolRecord | AnyToolSet> = TOOLSET extends ImmutableToolSet<infer TOOLS, any, any> ? TOOLS : TOOLSET extends MutableToolSet<infer TOOLS, any, any> ? TOOLS : TOOLSET;
12
12
  /** Infer the UI tool types from a tool record or ToolSet instance. */
13
- type InferUIToolSet<T extends ToolRecord | AnyToolSet> = { [K in keyof InferToolSet<T> & string]: InferUITool<InferToolSet<T>[K]> };
13
+ type InferUIToolSet<TOOLSET extends ToolRecord | AnyToolSet> = { [K in keyof InferToolSet<TOOLSET> & string]: InferUITool<InferToolSet<TOOLSET>[K]> };
14
14
  /**
15
15
  * Extract tool names tracked as active from an ImmutableToolSet instance.
16
16
  * Returns `never` for MutableToolSet (cannot be determined at compile time).
17
17
  */
18
- type ActiveTools<T extends AnyToolSet> = T extends ImmutableToolSet<any, any, any, infer A, any> ? A : never;
18
+ type InferActiveTools<TOOLSET extends AnyToolSet> = TOOLSET extends ImmutableToolSet<any, any, any, infer A, any> ? A : never;
19
19
  /**
20
20
  * Extract tool names tracked as inactive from an ImmutableToolSet instance.
21
21
  * Returns `never` for MutableToolSet (cannot be determined at compile time).
22
22
  */
23
- type InactiveTools<T extends AnyToolSet> = T extends ImmutableToolSet<any, any, any, any, infer D> ? D : never;
23
+ type InferInactiveTools<TOOLSET extends AnyToolSet> = TOOLSET extends ImmutableToolSet<any, any, any, any, infer D> ? D : never;
24
24
  /**
25
25
  * Input passed to activation predicates.
26
26
  * Use `ActivationInput<MyMsg>` to get per-tool narrowing in callbacks.
@@ -41,7 +41,31 @@ type ResolvedToolSet<TOOLS extends ToolRecord> = {
41
41
  activeTools: Array<keyof TOOLS & string>;
42
42
  };
43
43
  /** Union of both toolset classes for type utility constraints. */
44
- type AnyToolSet = ImmutableToolSet<any> | MutableToolSet<any>;
44
+ type AnyToolSet = ImmutableToolSet<any, any, any> | MutableToolSet<any, any, any>;
45
+ /**
46
+ * Derive a parameter type that accepts both immutable and mutable variants of an existing tool set.
47
+ *
48
+ * `createToolSet({ tools })` returns an `ImmutableToolSet`, while `.clone({ mutable: true })`
49
+ * returns a structurally distinct `MutableToolSet`. Helpers written against `typeof baseToolSet`
50
+ * directly cannot accept the cloned mutable instance — `ToolSet<typeof baseToolSet>` resolves
51
+ * to a union of both flavors and infers `TOOLS`, `MESSAGE`, and `CONTEXT` from the source.
52
+ *
53
+ * @example Accept either flavor in a helper function
54
+ * ```ts
55
+ * const baseToolSet = createToolSet({ tools }).deactivate(['cancel_order']);
56
+ *
57
+ * type MyToolSet = ToolSet<typeof baseToolSet>;
58
+ *
59
+ * // Accepts the immutable baseToolSet AND the cloned mutable instance
60
+ * function activateAdminTools(toolSet: MyToolSet) {
61
+ * toolSet.activate(['cancel_order']);
62
+ * }
63
+ *
64
+ * activateAdminTools(baseToolSet);
65
+ * activateAdminTools(baseToolSet.clone({ mutable: true }));
66
+ * ```
67
+ */
68
+ type ToolSet<TOOLSET extends AnyToolSet> = TOOLSET extends ImmutableToolSet<infer TOOLS, infer MESSAGE, infer CONTEXT, infer ACTIVATED, infer DEACTIVATED> ? ImmutableToolSet<TOOLS, MESSAGE, CONTEXT, ACTIVATED, DEACTIVATED> | MutableToolSet<TOOLS, MESSAGE, CONTEXT> : TOOLSET extends MutableToolSet<infer TOOLS, infer MESSAGE, infer CONTEXT> ? ImmutableToolSet<TOOLS, MESSAGE, CONTEXT, any, any> | MutableToolSet<TOOLS, MESSAGE, CONTEXT> : never;
45
69
  /**
46
70
  * Immutable state container for tool activation.
47
71
  *
@@ -152,4 +176,4 @@ declare function createToolSet<const TOOLS extends ToolRecord, MESSAGE extends M
152
176
  mutable?: false;
153
177
  }): ImmutableToolSet<TOOLS, MESSAGE, CONTEXT, keyof TOOLS & string>;
154
178
  //#endregion
155
- export { type ActivationInput, type ActiveTools, type InactiveTools, type InferToolSet, type InferUIToolSet, createToolSet };
179
+ export { type ActivationInput, type InferActiveTools, type InferInactiveTools, type InferToolSet, type InferUIToolSet, type ToolSet, createToolSet };
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "ai-tool-set",
3
- "version": "0.1.0-alpha.4",
4
- "description": "Tool set utilities for the Vercel AI SDK",
5
- "keywords": [],
3
+ "version": "1.1.0",
4
+ "description": "Conditional tool activation for the AI SDK, fully type-safe",
5
+ "keywords": [
6
+ "ai",
7
+ "ai-sdk",
8
+ "tools",
9
+ "toolset"
10
+ ],
6
11
  "license": "MIT",
7
12
  "author": "Chris Cook",
8
13
  "repository": {