@try-works/dsh-model-as-tool 0.0.0-stage → 0.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.
Files changed (44) hide show
  1. package/README.md +245 -2
  2. package/catalog/desert-ant-models.json +629 -0
  3. package/catalog/playbooks.json +531 -0
  4. package/cordis.patch.yml +39 -0
  5. package/lib/adapters/index.d.ts +48 -0
  6. package/lib/adapters/index.d.ts.map +1 -0
  7. package/lib/adapters/index.js +67 -0
  8. package/lib/adapters/tongue.d.ts +23 -0
  9. package/lib/adapters/tongue.d.ts.map +1 -0
  10. package/lib/adapters/tongue.js +85 -0
  11. package/lib/adapters/types.d.ts +95 -0
  12. package/lib/adapters/types.d.ts.map +1 -0
  13. package/lib/adapters/types.js +85 -0
  14. package/lib/adapters/voz.d.ts +22 -0
  15. package/lib/adapters/voz.d.ts.map +1 -0
  16. package/lib/adapters/voz.js +90 -0
  17. package/lib/capability.d.ts +58 -0
  18. package/lib/capability.d.ts.map +1 -0
  19. package/lib/capability.js +175 -0
  20. package/lib/catalog.d.ts +37 -0
  21. package/lib/catalog.d.ts.map +1 -0
  22. package/lib/catalog.js +217 -0
  23. package/lib/index.d.ts +120 -0
  24. package/lib/index.d.ts.map +1 -0
  25. package/lib/index.js +391 -0
  26. package/lib/playbook.d.ts +42 -0
  27. package/lib/playbook.d.ts.map +1 -0
  28. package/lib/playbook.js +65 -0
  29. package/lib/registrar.d.ts +59 -0
  30. package/lib/registrar.d.ts.map +1 -0
  31. package/lib/registrar.js +136 -0
  32. package/lib/skills.d.ts +25 -0
  33. package/lib/skills.d.ts.map +1 -0
  34. package/lib/skills.js +102 -0
  35. package/lib/state.d.ts +100 -0
  36. package/lib/state.d.ts.map +1 -0
  37. package/lib/state.js +160 -0
  38. package/lib/transport.d.ts +158 -0
  39. package/lib/transport.d.ts.map +1 -0
  40. package/lib/transport.js +332 -0
  41. package/lib/types.d.ts +111 -0
  42. package/lib/types.d.ts.map +1 -0
  43. package/lib/types.js +8 -0
  44. package/package.json +83 -4
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Adapter registry: the one place that maps a catalog model to the code that
3
+ * can invoke it.
4
+ *
5
+ * Two kinds of adapter exist. A **model adapter** is written by hand for a model
6
+ * with a real in-process SDK (Tongue, Voz). A **transport adapter** is generic:
7
+ * it drives any model through the Desert Ant CLI or a user-hosted bridge, using
8
+ * only the catalog's verb and parameter declarations.
9
+ *
10
+ * @module @try-works/dsh-model-as-tool/adapters/index
11
+ */
12
+ import { createTongueAdapter } from "./tongue.js";
13
+ import { createVozAdapter } from "./voz.js";
14
+ import { createCliTransport, createRemoteTransport, } from "../transport.js";
15
+ /**
16
+ * Every hand-written adapter this plugin ships, in priority order.
17
+ *
18
+ * Each factory returns undefined for the entries it does not serve, so the
19
+ * lookup is a linear scan rather than a switch, and a model with no adapter yet
20
+ * simply has no tool.
21
+ */
22
+ export const ADAPTER_FACTORIES = [
23
+ createTongueAdapter,
24
+ createVozAdapter,
25
+ ];
26
+ /**
27
+ * Wrap a command transport as a model adapter.
28
+ *
29
+ * The transport already returns the canonical object, so this is a pure
30
+ * adaptation of shape rather than a second place that knows how to parse a
31
+ * result.
32
+ * @param entry - the catalog entry.
33
+ * @param transport - the CLI or remote transport.
34
+ * @returns the adapter.
35
+ */
36
+ function transportAdapter(entry, transport) {
37
+ return {
38
+ modelId: entry.id,
39
+ invoke: ({ args, signal }) => transport.invoke({ entry, args, signal }),
40
+ };
41
+ }
42
+ /**
43
+ * Create the adapter for one entry.
44
+ *
45
+ * A hand-written adapter always wins for the model it serves: an in-process
46
+ * call is faster and needs no external service. Everything else falls to the
47
+ * transport the capability resolver selected.
48
+ * @param entry - the catalog entry.
49
+ * @param options - the resolved route plus transport settings.
50
+ * @param factories - hand-written adapter factories, defaulting to the shipped set.
51
+ * @returns the adapter, or undefined when no factory or transport serves this model.
52
+ */
53
+ export function createAdapter(entry, options = { route: 'npm-native' }, factories = ADAPTER_FACTORIES) {
54
+ for (const factory of factories) {
55
+ const adapter = factory(entry);
56
+ if (adapter !== undefined)
57
+ return adapter;
58
+ }
59
+ // No hand-written adapter: the model is reachable only through a transport.
60
+ if (options.route === 'cli')
61
+ return transportAdapter(entry, createCliTransport(entry, options));
62
+ if (options.route === 'remote') {
63
+ return transportAdapter(entry, createRemoteTransport(entry, options));
64
+ }
65
+ return undefined;
66
+ }
67
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Tongue adapter — on-device language identification for short text.
3
+ *
4
+ * Tongue is the one Desert Ant model that runs in plain Node on every platform:
5
+ * it is pure JavaScript with no WASM or inference runtime, and its 2 MB model
6
+ * ships inside the npm package. That makes it the reference adapter: the module
7
+ * is imported on first use, the loaded model is cached for the process, and the
8
+ * synchronous `detect()` is wrapped in the async tool contract.
9
+ *
10
+ * @module @try-works/dsh-model-as-tool/adapters/tongue
11
+ */
12
+ import type { ModelCatalogEntry } from '../types.ts';
13
+ import { type ModelAdapter } from './types.ts';
14
+ /**
15
+ * Build the Tongue adapter.
16
+ *
17
+ * The model is loaded once and reused, because `Tongue.load()` parses the
18
+ * bundled 2 MB weight file and detection afterwards is synchronous.
19
+ * @param entry - the catalog entry this adapter serves.
20
+ * @returns the adapter, or undefined if the entry is not Tongue.
21
+ */
22
+ export declare function createTongueAdapter(entry: ModelCatalogEntry): ModelAdapter | undefined;
23
+ //# sourceMappingURL=tongue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tongue.d.ts","sourceRoot":"","sources":["../../src/adapters/tongue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,YAAY,CAAA;AA4BnB;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,GAAG,SAAS,CAwDtF"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Tongue adapter — on-device language identification for short text.
3
+ *
4
+ * Tongue is the one Desert Ant model that runs in plain Node on every platform:
5
+ * it is pure JavaScript with no WASM or inference runtime, and its 2 MB model
6
+ * ships inside the npm package. That makes it the reference adapter: the module
7
+ * is imported on first use, the loaded model is cached for the process, and the
8
+ * synchronous `detect()` is wrapped in the async tool contract.
9
+ *
10
+ * @module @try-works/dsh-model-as-tool/adapters/tongue
11
+ */
12
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
13
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
14
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
15
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
16
+ });
17
+ }
18
+ return path;
19
+ };
20
+ import { optionalInteger, requireString, throwIfAborted, } from "./types.js";
21
+ /** Default number of runner-up candidates reported to the model. */
22
+ const DEFAULT_TOP = 3;
23
+ const MAX_TOP = 20;
24
+ /**
25
+ * Build the Tongue adapter.
26
+ *
27
+ * The model is loaded once and reused, because `Tongue.load()` parses the
28
+ * bundled 2 MB weight file and detection afterwards is synchronous.
29
+ * @param entry - the catalog entry this adapter serves.
30
+ * @returns the adapter, or undefined if the entry is not Tongue.
31
+ */
32
+ export function createTongueAdapter(entry) {
33
+ if (entry.id !== 'tongue')
34
+ return undefined;
35
+ let loaded;
36
+ const load = async () => {
37
+ loaded ??= (async () => {
38
+ try {
39
+ // A dynamic import keyed off a variable keeps this out of the module
40
+ // graph until the tool is actually called: the package is an optional
41
+ // dependency, so a static import would break installs that skip it.
42
+ const specifier = entry.npmPackage;
43
+ const module = await import(__rewriteRelativeImportExtension(specifier));
44
+ return await module.Tongue.load();
45
+ }
46
+ catch (error) {
47
+ // Clear the cache so a transient failure (or a later install) can be
48
+ // retried by the next call rather than poisoning the tool for the life
49
+ // of the plugin.
50
+ loaded = undefined;
51
+ throw new Error(`Tongue could not be loaded: ${error instanceof Error ? error.message : String(error)}`);
52
+ }
53
+ })();
54
+ return loaded;
55
+ };
56
+ return {
57
+ modelId: entry.id,
58
+ async invoke({ args, signal }) {
59
+ throwIfAborted(signal);
60
+ const text = requireString(args, 'text');
61
+ const top = optionalInteger(args, 'top', { min: 1, max: MAX_TOP, fallback: DEFAULT_TOP });
62
+ const tongue = await load();
63
+ throwIfAborted(signal);
64
+ const detection = tongue.detect(text);
65
+ const candidates = (detection.candidates ?? []).slice(0, top);
66
+ return {
67
+ language: detection.language,
68
+ reliability: detection.reliability ?? 'unknown',
69
+ isTooCloseToCall: detection.isTooCloseToCall ?? false,
70
+ candidates: candidates.map(candidate => ({
71
+ language: candidate.language,
72
+ probability: candidate.probability,
73
+ })),
74
+ };
75
+ },
76
+ async dispose() {
77
+ if (loaded === undefined)
78
+ return;
79
+ const instance = await loaded.catch(() => undefined);
80
+ instance?.dispose?.();
81
+ loaded = undefined;
82
+ },
83
+ };
84
+ }
85
+ //# sourceMappingURL=tongue.js.map
@@ -0,0 +1,95 @@
1
+ /**
2
+ * The adapter seam: how one catalog model is actually invoked.
3
+ *
4
+ * An adapter is responsible for exactly two things — loading its model lazily
5
+ * and turning validated tool arguments into the canonical JSON value the tool
6
+ * declares. Everything else (which models exist, whether they may run, what the
7
+ * model sees) belongs to the catalog, the capability resolver, and the
8
+ * registrar.
9
+ *
10
+ * @module @try-works/dsh-model-as-tool/adapters/types
11
+ */
12
+ import type { ModelCatalogEntry } from '../types.ts';
13
+ /** A lossless JSON value, the only thing a tool body may return. */
14
+ export type JsonValue = null | boolean | number | string | JsonValue[] | {
15
+ [key: string]: JsonValue;
16
+ };
17
+ /** One adapter invocation. */
18
+ export interface AdapterInvocation {
19
+ /** Validated tool arguments, already constrained by the registered parameter schema. */
20
+ readonly args: Readonly<Record<string, unknown>>;
21
+ /** Caller cancellation, forwarded by the tool body. */
22
+ readonly signal: AbortSignal;
23
+ }
24
+ /** One model's invocation strategy. */
25
+ export interface ModelAdapter {
26
+ /** The catalog id this adapter serves. */
27
+ readonly modelId: string;
28
+ /**
29
+ * Run the model once and return the canonical value.
30
+ *
31
+ * Every model tool declares an object output schema, so an adapter returns an
32
+ * object rather than an arbitrary JSON root.
33
+ * @param invocation - validated arguments and caller cancellation.
34
+ * @returns the lossless JSON object declared by the tool's output schema.
35
+ */
36
+ invoke(invocation: AdapterInvocation): Promise<Record<string, JsonValue>>;
37
+ /**
38
+ * Release any process-level model resources.
39
+ *
40
+ * Called on plugin dispose. Adapters that cache a loaded model must implement
41
+ * it; adapters that hold nothing may omit it.
42
+ */
43
+ dispose?(): Promise<void>;
44
+ }
45
+ /** Build an adapter for one runnable model, or `undefined` when none exists yet. */
46
+ export type AdapterFactory = (entry: ModelCatalogEntry) => ModelAdapter | undefined;
47
+ /**
48
+ * Reject an aborted call before doing model work.
49
+ * @param signal - caller cancellation.
50
+ * @throws the abort reason when the signal is already aborted.
51
+ */
52
+ export declare function throwIfAborted(signal: AbortSignal): void;
53
+ /**
54
+ * Read a required string argument.
55
+ * @param args - validated arguments.
56
+ * @param key - argument name.
57
+ * @returns the string value.
58
+ * @throws when the value is absent or not a string.
59
+ */
60
+ export declare function requireString(args: Readonly<Record<string, unknown>>, key: string): string;
61
+ /**
62
+ * Read an optional integer argument, clamped to a range.
63
+ * @param args - validated arguments.
64
+ * @param key - argument name.
65
+ * @param options - inclusive bounds and the value to use when absent.
66
+ * @returns the resolved integer.
67
+ * @throws when the value is present but not an integer in range.
68
+ */
69
+ export declare function optionalInteger(args: Readonly<Record<string, unknown>>, key: string, options: {
70
+ readonly min: number;
71
+ readonly max: number;
72
+ readonly fallback: number;
73
+ }): number;
74
+ /**
75
+ * Read an optional number in a range.
76
+ * @param args - validated arguments.
77
+ * @param key - argument name.
78
+ * @param options - inclusive bounds.
79
+ * @returns the resolved number, or undefined when absent.
80
+ * @throws when the value is present but not a finite number in range.
81
+ */
82
+ export declare function optionalNumber(args: Readonly<Record<string, unknown>>, key: string, options: {
83
+ readonly min: number;
84
+ readonly max: number;
85
+ }): number | undefined;
86
+ /**
87
+ * Read a required boolean argument.
88
+ * @param args - validated arguments.
89
+ * @param key - argument name.
90
+ * @param fallback - value used when the argument is absent.
91
+ * @returns the resolved boolean.
92
+ * @throws when the value is present but not a boolean.
93
+ */
94
+ export declare function optionalBoolean(args: Readonly<Record<string, unknown>>, key: string, fallback: boolean): boolean;
95
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEpD,oEAAoE;AACpE,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAA;AAErG,8BAA8B;AAC9B,MAAM,WAAW,iBAAiB;IAChC,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAChD,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAC7B;AAED,uCAAuC;AACvC,MAAM,WAAW,YAAY;IAC3B,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB;;;;;;;OAOG;IACH,MAAM,CAAC,UAAU,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;IACzE;;;;;OAKG;IACH,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1B;AAED,oFAAoF;AACpF,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,iBAAiB,KAAK,YAAY,GAAG,SAAS,CAAA;AAEnF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAExD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAM1F;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACvC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACjF,MAAM,CAOR;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACvC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACtD,MAAM,GAAG,SAAS,CAOpB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACvC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,OAAO,GAChB,OAAO,CAKT"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * The adapter seam: how one catalog model is actually invoked.
3
+ *
4
+ * An adapter is responsible for exactly two things — loading its model lazily
5
+ * and turning validated tool arguments into the canonical JSON value the tool
6
+ * declares. Everything else (which models exist, whether they may run, what the
7
+ * model sees) belongs to the catalog, the capability resolver, and the
8
+ * registrar.
9
+ *
10
+ * @module @try-works/dsh-model-as-tool/adapters/types
11
+ */
12
+ /**
13
+ * Reject an aborted call before doing model work.
14
+ * @param signal - caller cancellation.
15
+ * @throws the abort reason when the signal is already aborted.
16
+ */
17
+ export function throwIfAborted(signal) {
18
+ if (signal.aborted)
19
+ throw signal.reason instanceof Error ? signal.reason : new Error('aborted');
20
+ }
21
+ /**
22
+ * Read a required string argument.
23
+ * @param args - validated arguments.
24
+ * @param key - argument name.
25
+ * @returns the string value.
26
+ * @throws when the value is absent or not a string.
27
+ */
28
+ export function requireString(args, key) {
29
+ const value = args[key];
30
+ if (typeof value !== 'string' || value.length === 0) {
31
+ throw new Error(`argument "${key}" must be a non-empty string`);
32
+ }
33
+ return value;
34
+ }
35
+ /**
36
+ * Read an optional integer argument, clamped to a range.
37
+ * @param args - validated arguments.
38
+ * @param key - argument name.
39
+ * @param options - inclusive bounds and the value to use when absent.
40
+ * @returns the resolved integer.
41
+ * @throws when the value is present but not an integer in range.
42
+ */
43
+ export function optionalInteger(args, key, options) {
44
+ const value = args[key];
45
+ if (value === undefined)
46
+ return options.fallback;
47
+ if (typeof value !== 'number' || !Number.isInteger(value) || value < options.min || value > options.max) {
48
+ throw new Error(`argument "${key}" must be an integer between ${options.min} and ${options.max}`);
49
+ }
50
+ return value;
51
+ }
52
+ /**
53
+ * Read an optional number in a range.
54
+ * @param args - validated arguments.
55
+ * @param key - argument name.
56
+ * @param options - inclusive bounds.
57
+ * @returns the resolved number, or undefined when absent.
58
+ * @throws when the value is present but not a finite number in range.
59
+ */
60
+ export function optionalNumber(args, key, options) {
61
+ const value = args[key];
62
+ if (value === undefined)
63
+ return undefined;
64
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < options.min || value > options.max) {
65
+ throw new Error(`argument "${key}" must be a number between ${options.min} and ${options.max}`);
66
+ }
67
+ return value;
68
+ }
69
+ /**
70
+ * Read a required boolean argument.
71
+ * @param args - validated arguments.
72
+ * @param key - argument name.
73
+ * @param fallback - value used when the argument is absent.
74
+ * @returns the resolved boolean.
75
+ * @throws when the value is present but not a boolean.
76
+ */
77
+ export function optionalBoolean(args, key, fallback) {
78
+ const value = args[key];
79
+ if (value === undefined)
80
+ return fallback;
81
+ if (typeof value !== 'boolean')
82
+ throw new Error(`argument "${key}" must be a boolean`);
83
+ return value;
84
+ }
85
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Voz adapter — on-device speech recognition with word timestamps.
3
+ *
4
+ * Voz has no prebuilt Node core; it runs the same WebAssembly/ONNX Runtime
5
+ * pipeline everywhere and requires the caller to hand it an ONNX Runtime
6
+ * module. `onnxruntime-node` ships win32-x64 binaries, which is what makes Voz
7
+ * the one audio model that works on Windows.
8
+ *
9
+ * Loading is expensive (the weights are ~349 MB and ONNX Runtime compiles three
10
+ * graphs), so the instance is cached for the process and reused.
11
+ *
12
+ * @module @try-works/dsh-model-as-tool/adapters/voz
13
+ */
14
+ import type { ModelCatalogEntry } from '../types.ts';
15
+ import { type ModelAdapter } from './types.ts';
16
+ /**
17
+ * Build the Voz adapter.
18
+ * @param entry - the catalog entry this adapter serves.
19
+ * @returns the adapter, or undefined if the entry is not Voz.
20
+ */
21
+ export declare function createVozAdapter(entry: ModelCatalogEntry): ModelAdapter | undefined;
22
+ //# sourceMappingURL=voz.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voz.d.ts","sourceRoot":"","sources":["../../src/adapters/voz.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,YAAY,CAAA;AAmCnB;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,GAAG,SAAS,CA+DnF"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Voz adapter — on-device speech recognition with word timestamps.
3
+ *
4
+ * Voz has no prebuilt Node core; it runs the same WebAssembly/ONNX Runtime
5
+ * pipeline everywhere and requires the caller to hand it an ONNX Runtime
6
+ * module. `onnxruntime-node` ships win32-x64 binaries, which is what makes Voz
7
+ * the one audio model that works on Windows.
8
+ *
9
+ * Loading is expensive (the weights are ~349 MB and ONNX Runtime compiles three
10
+ * graphs), so the instance is cached for the process and reused.
11
+ *
12
+ * @module @try-works/dsh-model-as-tool/adapters/voz
13
+ */
14
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
15
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
16
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
17
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
18
+ });
19
+ }
20
+ return path;
21
+ };
22
+ import { optionalBoolean, requireString, throwIfAborted, } from "./types.js";
23
+ /** Cap on the words returned inline, so a long recording cannot flood the context. */
24
+ const MAX_WORDS = 2000;
25
+ /**
26
+ * Build the Voz adapter.
27
+ * @param entry - the catalog entry this adapter serves.
28
+ * @returns the adapter, or undefined if the entry is not Voz.
29
+ */
30
+ export function createVozAdapter(entry) {
31
+ if (entry.id !== 'voz')
32
+ return undefined;
33
+ let loaded;
34
+ const load = async () => {
35
+ loaded ??= (async () => {
36
+ try {
37
+ // Both specifiers are variables for the same reason as Tongue: each is
38
+ // an optional dependency that may legitimately be absent.
39
+ const runtimeSpecifier = entry.requiresRuntime[0] ?? 'onnxruntime-node';
40
+ const ort = await import(__rewriteRelativeImportExtension(runtimeSpecifier));
41
+ const module = await import(__rewriteRelativeImportExtension(entry.npmPackage));
42
+ return await module.Voz.load({ ort });
43
+ }
44
+ catch (error) {
45
+ loaded = undefined;
46
+ throw new Error(`Voz could not be loaded: ${error instanceof Error ? error.message : String(error)}. `
47
+ + 'Voz needs onnxruntime-node installed beside the plugin.');
48
+ }
49
+ })();
50
+ return loaded;
51
+ };
52
+ return {
53
+ modelId: entry.id,
54
+ async invoke({ args, signal }) {
55
+ throwIfAborted(signal);
56
+ const audioPath = requireString(args, 'audio_path');
57
+ const includeWords = optionalBoolean(args, 'include_words', true);
58
+ const voz = await load();
59
+ throwIfAborted(signal);
60
+ const result = await voz.transcribe(audioPath);
61
+ throwIfAborted(signal);
62
+ const value = {
63
+ text: result.text,
64
+ wordCount: result.words?.length ?? 0,
65
+ };
66
+ if (typeof result.realtimeFactor === 'number') {
67
+ value.realtimeFactor = result.realtimeFactor;
68
+ }
69
+ if (includeWords) {
70
+ const words = result.words ?? [];
71
+ value.words = words.slice(0, MAX_WORDS).map(word => ({
72
+ text: word.text,
73
+ start: word.start,
74
+ end: word.end,
75
+ }));
76
+ if (words.length > MAX_WORDS)
77
+ value.wordsTruncated = true;
78
+ }
79
+ return value;
80
+ },
81
+ async dispose() {
82
+ if (loaded === undefined)
83
+ return;
84
+ const instance = await loaded.catch(() => undefined);
85
+ instance?.dispose?.();
86
+ loaded = undefined;
87
+ },
88
+ };
89
+ }
90
+ //# sourceMappingURL=voz.js.map
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Capability resolution: decide whether a catalog model can actually run in
3
+ * this DSH process, and by which route.
4
+ *
5
+ * The rule this module enforces is that a model becomes a tool only when an
6
+ * adapter can really invoke it. Every other model stays catalogued and
7
+ * reportable, so `model_tools` can explain what is missing instead of the agent
8
+ * discovering a broken tool at call time.
9
+ *
10
+ * @module @try-works/dsh-model-as-tool/capability
11
+ */
12
+ import type { CapabilityVerdict, ModelCatalogEntry } from './types.ts';
13
+ /**
14
+ * Whether a package specifier resolves from this plugin's installation.
15
+ *
16
+ * Resolution deliberately does not load the module: importing a model package
17
+ * pulls in a WASM or native runtime, and capability probing must stay cheap
18
+ * enough to run at plugin load.
19
+ * @param specifier - package name, optionally with a subpath.
20
+ * @returns whether Node can resolve the specifier.
21
+ */
22
+ export declare function canResolve(specifier: string): boolean;
23
+ /** Join a package and its documented subpath into one specifier. */
24
+ export declare function packageSpecifier(pkg: string, subpath: string | null): string;
25
+ /**
26
+ * Resolve how (and whether) one model can run here.
27
+ *
28
+ * Transport preference is deliberate: an in-process package is fastest and
29
+ * needs no external service, so it wins; the CLI is local but out-of-process;
30
+ * the bridge is last because it depends on another machine. A user who would
31
+ * rather route everything through a bridge can disable the other two.
32
+ * @param entry - the catalog entry to resolve.
33
+ * @param options - overrides for testing; `resolve`, `platform` and the transport switches replace the process facts.
34
+ * @returns the verdict, including the reason for every negative one.
35
+ */
36
+ export declare function resolveCapability(entry: ModelCatalogEntry, options?: {
37
+ readonly resolve?: (specifier: string) => boolean;
38
+ readonly platform?: NodeJS.Platform;
39
+ /** Whether the Desert Ant CLI is on PATH. */
40
+ readonly cliAvailable?: boolean;
41
+ /** Whether a bridge endpoint is configured. */
42
+ readonly remoteEndpoint?: string | undefined;
43
+ /** Turn off in-process npm resolution, to force another transport. */
44
+ readonly allowNpm?: boolean;
45
+ }): CapabilityVerdict;
46
+ /** One model plus its resolved capability verdict. */
47
+ export interface ResolvedModel {
48
+ readonly entry: ModelCatalogEntry;
49
+ readonly verdict: CapabilityVerdict;
50
+ }
51
+ /**
52
+ * Resolve every catalog entry.
53
+ * @param entries - validated catalog entries.
54
+ * @param options - resolution overrides, forwarded to {@link resolveCapability}.
55
+ * @returns one record per entry, in catalog order.
56
+ */
57
+ export declare function resolveCatalog(entries: readonly ModelCatalogEntry[], options?: Parameters<typeof resolveCapability>[1]): ResolvedModel[];
58
+ //# sourceMappingURL=capability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAWtE;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAOrD;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAE5E;AAwBD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,iBAAiB,EACxB,OAAO,GAAE;IACP,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAA;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAA;IACnC,6CAA6C;IAC7C,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAA;IAC/B,+CAA+C;IAC/C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5C,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACvB,GACL,iBAAiB,CA6FnB;AAED,sDAAsD;AACtD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAA;CACpC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,SAAS,iBAAiB,EAAE,EACrC,OAAO,GAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAC,CAAM,GACpD,aAAa,EAAE,CAEjB"}