@try-works/dsh-model-as-tool 0.1.1 → 0.1.3

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 (98) hide show
  1. package/README.md +51 -0
  2. package/bin/dsh-tool-mode-mcp-stdio.mjs +80 -0
  3. package/catalog/desert-ant-models.json +77 -13
  4. package/lib/adapters/index.d.ts +19 -6
  5. package/lib/adapters/index.d.ts.map +1 -1
  6. package/lib/adapters/index.js +28 -13
  7. package/lib/adapters/tongue.d.ts +11 -3
  8. package/lib/adapters/tongue.d.ts.map +1 -1
  9. package/lib/adapters/tongue.js +12 -4
  10. package/lib/adapters/types.d.ts +11 -0
  11. package/lib/adapters/types.d.ts.map +1 -1
  12. package/lib/adapters/voz.d.ts +7 -1
  13. package/lib/adapters/voz.d.ts.map +1 -1
  14. package/lib/adapters/voz.js +16 -4
  15. package/lib/asset-acquisition.d.ts +137 -0
  16. package/lib/asset-acquisition.d.ts.map +1 -0
  17. package/lib/asset-acquisition.js +161 -0
  18. package/lib/authority.d.ts +153 -0
  19. package/lib/authority.d.ts.map +1 -0
  20. package/lib/authority.js +194 -0
  21. package/lib/bindings.d.ts +115 -0
  22. package/lib/bindings.d.ts.map +1 -0
  23. package/lib/bindings.js +239 -0
  24. package/lib/catalog.d.ts.map +1 -1
  25. package/lib/catalog.js +57 -0
  26. package/lib/contract-payload.d.ts +47 -0
  27. package/lib/contract-payload.d.ts.map +1 -0
  28. package/lib/contract-payload.js +137 -0
  29. package/lib/deployment-coordinator.d.ts +213 -0
  30. package/lib/deployment-coordinator.d.ts.map +1 -0
  31. package/lib/deployment-coordinator.js +274 -0
  32. package/lib/harness-budgets.d.ts +158 -0
  33. package/lib/harness-budgets.d.ts.map +1 -0
  34. package/lib/harness-budgets.js +152 -0
  35. package/lib/index.d.ts +41 -0
  36. package/lib/index.d.ts.map +1 -1
  37. package/lib/index.js +424 -16
  38. package/lib/licensing.d.ts +221 -0
  39. package/lib/licensing.d.ts.map +1 -0
  40. package/lib/licensing.js +188 -0
  41. package/lib/mcp/host-binding.d.ts +91 -0
  42. package/lib/mcp/host-binding.d.ts.map +1 -0
  43. package/lib/mcp/host-binding.js +133 -0
  44. package/lib/mcp/http.d.ts +130 -0
  45. package/lib/mcp/http.d.ts.map +1 -0
  46. package/lib/mcp/http.js +274 -0
  47. package/lib/mcp/protocol.d.ts +261 -0
  48. package/lib/mcp/protocol.d.ts.map +1 -0
  49. package/lib/mcp/protocol.js +387 -0
  50. package/lib/mcp/server.d.ts +115 -0
  51. package/lib/mcp/server.d.ts.map +1 -0
  52. package/lib/mcp/server.js +200 -0
  53. package/lib/mcp/stdio.d.ts +80 -0
  54. package/lib/mcp/stdio.d.ts.map +1 -0
  55. package/lib/mcp/stdio.js +176 -0
  56. package/lib/mcp/subscriptions.d.ts +135 -0
  57. package/lib/mcp/subscriptions.d.ts.map +1 -0
  58. package/lib/mcp/subscriptions.js +207 -0
  59. package/lib/provider-bridge.d.ts +69 -0
  60. package/lib/provider-bridge.d.ts.map +1 -0
  61. package/lib/provider-bridge.js +218 -0
  62. package/lib/publication.d.ts +160 -0
  63. package/lib/publication.d.ts.map +1 -0
  64. package/lib/publication.js +173 -0
  65. package/lib/receipt.d.ts +208 -0
  66. package/lib/receipt.d.ts.map +1 -0
  67. package/lib/receipt.js +150 -0
  68. package/lib/registrar.d.ts +13 -0
  69. package/lib/registrar.d.ts.map +1 -1
  70. package/lib/registrar.js +20 -3
  71. package/lib/resource-governance.d.ts +204 -0
  72. package/lib/resource-governance.d.ts.map +1 -0
  73. package/lib/resource-governance.js +213 -0
  74. package/lib/server-lifecycle.d.ts +175 -0
  75. package/lib/server-lifecycle.d.ts.map +1 -0
  76. package/lib/server-lifecycle.js +269 -0
  77. package/lib/types.d.ts +21 -0
  78. package/lib/types.d.ts.map +1 -1
  79. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/lang-detect.d.ts +16 -0
  80. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/lang-detect.d.ts.map +1 -0
  81. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/lang-detect.js +85 -0
  82. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/stt-transcribe.d.ts +20 -0
  83. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/stt-transcribe.d.ts.map +1 -0
  84. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/stt-transcribe.js +112 -0
  85. package/node_modules/@try-works/tool-mode-contracts/lib/dsh.d.ts +82 -0
  86. package/node_modules/@try-works/tool-mode-contracts/lib/dsh.d.ts.map +1 -0
  87. package/node_modules/@try-works/tool-mode-contracts/lib/dsh.js +260 -0
  88. package/node_modules/@try-works/tool-mode-contracts/lib/index.d.ts +23 -0
  89. package/node_modules/@try-works/tool-mode-contracts/lib/index.d.ts.map +1 -0
  90. package/node_modules/@try-works/tool-mode-contracts/lib/index.js +24 -0
  91. package/node_modules/@try-works/tool-mode-contracts/lib/meta.d.ts +104 -0
  92. package/node_modules/@try-works/tool-mode-contracts/lib/meta.d.ts.map +1 -0
  93. package/node_modules/@try-works/tool-mode-contracts/lib/meta.js +55 -0
  94. package/node_modules/@try-works/tool-mode-contracts/lib/registry.d.ts +81 -0
  95. package/node_modules/@try-works/tool-mode-contracts/lib/registry.d.ts.map +1 -0
  96. package/node_modules/@try-works/tool-mode-contracts/lib/registry.js +163 -0
  97. package/node_modules/@try-works/tool-mode-contracts/package.json +35 -0
  98. package/package.json +17 -5
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Server and plugin lifecycle (RUN-01, RUN-02, RUN-05, RUN-06, RUN-07).
3
+ *
4
+ * Almost every rule here is about what must NOT happen:
5
+ *
6
+ * - **Do not announce readiness before it is true** (RUN-06). A listener that reports
7
+ * ready before its bind or its initialisation succeeded sends a client to a port
8
+ * that is not answering. Readiness is therefore a STATE derived from both, not a flag
9
+ * set by whoever got there first.
10
+ * - **Do not resolve a port conflict by force or by stealth** (RUN-06). Taking the port
11
+ * from another process, or silently moving to a different one, both break a client
12
+ * that was told where to connect. The conflict is reported.
13
+ * - **Do not let a failed start take the host with it** (RUN-06). The MCP endpoint is
14
+ * one feature of a much larger host; a port clash must leave the rest running.
15
+ * - **Do not kill work you do not own** (RUN-07). A model process serving another
16
+ * still-authorized owner is not this lifecycle's to terminate.
17
+ * - **Do not prepare anything at startup** (RUN-05). Nothing downloads because a plugin
18
+ * loaded or a client listed tools.
19
+ *
20
+ * @module @try-works/dsh-model-as-tool/server-lifecycle
21
+ */
22
+ /** The documented grace period for cleanup (RUN-07). */
23
+ export const DEFAULT_GRACE_MS = 5000;
24
+ /**
25
+ * Manages one MCP listener's lifecycle.
26
+ *
27
+ * Deliberately separate from the DSH plugin's own lifecycle: RUN-01 requires disabling
28
+ * the SERVER to stop its listener and owned work without disabling unrelated DSH tools,
29
+ * so the two must be independently stoppable.
30
+ */
31
+ export class ServerLifecycle {
32
+ #state = 'stopped';
33
+ #port = null;
34
+ #closeListener = null;
35
+ #work = new Map();
36
+ #host;
37
+ #graceMs;
38
+ /** Set once shutdown begins, so new work is refused from that moment. */
39
+ #acceptingWork = true;
40
+ constructor(host, options = {}) {
41
+ this.#host = host;
42
+ this.#graceMs = options.graceMs ?? DEFAULT_GRACE_MS;
43
+ }
44
+ /** The current state. */
45
+ get state() {
46
+ return this.#state;
47
+ }
48
+ /** The bound port, once one exists. */
49
+ get port() {
50
+ return this.#port;
51
+ }
52
+ /**
53
+ * Whether the endpoint is serving (RUN-06).
54
+ *
55
+ * True only after BOTH bind and initialise succeeded. A caller asking "can I connect"
56
+ * gets one answer, and it is not derived from a flag somebody set early.
57
+ */
58
+ get ready() {
59
+ return this.#state === 'ready';
60
+ }
61
+ /** Work currently owned, for diagnostics. */
62
+ get owned() {
63
+ return [...this.#work.values()];
64
+ }
65
+ /**
66
+ * Start the listener.
67
+ *
68
+ * @returns nothing on success, or the failure — never a thrown exception, because
69
+ * RUN-06 requires a failed start not to crash the unrelated host.
70
+ */
71
+ async start() {
72
+ if (this.#state === 'ready' || this.#state === 'starting') {
73
+ return {
74
+ ok: false,
75
+ failure: {
76
+ code: 'ALREADY_STARTED',
77
+ message: `the server is already ${this.#state}`,
78
+ remedy: 'Call stop() before starting again.',
79
+ },
80
+ };
81
+ }
82
+ this.#state = 'starting';
83
+ try {
84
+ const listener = await this.#host.bind();
85
+ this.#port = listener.port;
86
+ this.#closeListener = listener.close;
87
+ }
88
+ catch (error) {
89
+ const code = error.code;
90
+ this.#state = 'failed';
91
+ if (code === 'EADDRINUSE') {
92
+ // Reported, NOT resolved. Taking the port from another process or silently
93
+ // moving to a different one both break a client told where to connect.
94
+ return {
95
+ ok: false,
96
+ failure: {
97
+ code: 'PORT_IN_USE',
98
+ message: `port ${String(error.message)} is already in use`,
99
+ remedy: 'Choose a different port in the configuration, or stop the process holding it. This server will not take it by force or move silently.',
100
+ },
101
+ };
102
+ }
103
+ return {
104
+ ok: false,
105
+ failure: {
106
+ code: 'BIND_FAILED',
107
+ message: error instanceof Error ? error.message : String(error),
108
+ remedy: 'Check that the bind address is a loopback address and that the port is permitted.',
109
+ },
110
+ };
111
+ }
112
+ try {
113
+ await this.#host.initialise();
114
+ }
115
+ catch (error) {
116
+ this.#state = 'failed';
117
+ // The listener bound but cannot serve, so it is CLOSED rather than left open:
118
+ // an open port that answers nothing is worse than no port.
119
+ await this.#closeListener?.().catch(() => undefined);
120
+ this.#closeListener = null;
121
+ this.#port = null;
122
+ return {
123
+ ok: false,
124
+ failure: {
125
+ code: 'INIT_FAILED',
126
+ message: error instanceof Error ? error.message : String(error),
127
+ remedy: 'Check the server diagnostics; the host itself is unaffected.',
128
+ },
129
+ };
130
+ }
131
+ // Only now. Readiness after BOTH succeed, and never before.
132
+ this.#state = 'ready';
133
+ this.#host.onReady(this.#port);
134
+ return { ok: true, port: this.#port };
135
+ }
136
+ /**
137
+ * Register work this lifecycle owns (RUN-07).
138
+ *
139
+ * Refused once shutdown has begun, so a call racing a stop cannot slip into the
140
+ * cleanup window and be left running.
141
+ * @param work - the work to own.
142
+ * @returns whether it was accepted.
143
+ */
144
+ adopt(work) {
145
+ if (!this.#acceptingWork)
146
+ return false;
147
+ this.#work.set(work.id, work);
148
+ return true;
149
+ }
150
+ /** Release work that finished on its own. */
151
+ release(id) {
152
+ this.#work.delete(id);
153
+ }
154
+ /**
155
+ * Stop the listener and everything it owns (RUN-07).
156
+ *
157
+ * The order is the requirement's: refuse new work, cancel owned foreground
158
+ * invocations, wait within the grace period, terminate what remains, close the
159
+ * transport and release the port. Work belonging to another owner is LEFT ALONE.
160
+ * @param options - `ownedBy` selects the owner whose work may be stopped.
161
+ * @returns the report.
162
+ */
163
+ async stop(options = {}) {
164
+ // 1. Refuse new work FIRST, so nothing is adopted during cleanup.
165
+ this.#acceptingWork = false;
166
+ if (this.#state === 'stopped') {
167
+ return { cancelled: [], terminated: [], untouched: [], portReleased: true, withinGrace: true };
168
+ }
169
+ this.#state = 'stopping';
170
+ const mine = [];
171
+ const untouched = [];
172
+ for (const work of this.#work.values()) {
173
+ // RUN-07: never kill a model process serving another still-authorized owner.
174
+ if (options.ownedBy !== undefined && work.owner !== options.ownedBy) {
175
+ untouched.push(work.id);
176
+ continue;
177
+ }
178
+ mine.push(work);
179
+ }
180
+ // 2. Cancel owned foreground invocations, and wait for them WITHIN the grace
181
+ // period. Racing each cancel against one shared deadline is what makes the grace
182
+ // period mean something: a cancel that never resolves must not hold shutdown open
183
+ // forever, and it must not be reported as stopped either.
184
+ const deadline = Date.now() + this.#graceMs;
185
+ const cancelled = [];
186
+ const terminated = [];
187
+ const outcomes = await Promise.all(mine.map(async (work) => {
188
+ const remaining = Math.max(0, deadline - Date.now());
189
+ const settled = await Promise.race([
190
+ Promise.resolve(work.cancel()).then(() => true).catch(() => false),
191
+ new Promise(resolve => setTimeout(() => resolve(false), remaining)),
192
+ ]);
193
+ return { work, settled };
194
+ }));
195
+ for (const { work, settled } of outcomes) {
196
+ if (settled)
197
+ cancelled.push(work.id);
198
+ }
199
+ const withinGrace = outcomes.every(outcome => outcome.settled);
200
+ // 3. Terminate whatever outlived the grace period.
201
+ for (const { work, settled } of outcomes) {
202
+ if (settled)
203
+ continue;
204
+ try {
205
+ work.terminate?.();
206
+ terminated.push(work.id);
207
+ }
208
+ catch {
209
+ // A terminate that throws is logged rather than fatal: shutdown must complete
210
+ // even when one piece of work refuses to die.
211
+ this.#host.log(`work ${work.id} could not be terminated`);
212
+ }
213
+ }
214
+ this.#work.clear();
215
+ // 4. Close the transport and release the port.
216
+ let portReleased = false;
217
+ try {
218
+ await this.#closeListener?.();
219
+ portReleased = true;
220
+ }
221
+ catch {
222
+ this.#host.log('the listener could not be closed cleanly');
223
+ }
224
+ this.#closeListener = null;
225
+ this.#port = null;
226
+ this.#state = 'stopped';
227
+ this.#acceptingWork = true;
228
+ return { cancelled, terminated, untouched, portReleased, withinGrace };
229
+ }
230
+ }
231
+ /** The only startup policy this implementation permits (RUN-05). */
232
+ export const READ_ONLY_STARTUP = {
233
+ preparesModels: false,
234
+ resolvesPackages: false,
235
+ discoveryIsReadOnly: true,
236
+ };
237
+ /**
238
+ * Whether a startup action is permitted (RUN-05).
239
+ *
240
+ * @param action - what the startup wants to do.
241
+ * @returns whether it may.
242
+ */
243
+ export function startupPermits(action) {
244
+ switch (action) {
245
+ // Restoring an explicitly approved activation and inspecting local state are the
246
+ // two things startup MAY do.
247
+ case 'restore-active':
248
+ case 'inspect-assets':
249
+ case 'read-manifests':
250
+ return true;
251
+ // Preparation and resolution are refused, because RUN-05 is explicit that nothing
252
+ // downloads because a plugin loaded or a client listed tools.
253
+ case 'prepare-model':
254
+ case 'resolve-package':
255
+ case 'download-weights':
256
+ return false;
257
+ }
258
+ }
259
+ /**
260
+ * Whether disabling the MCP server must also disable unrelated DSH tools (RUN-01).
261
+ *
262
+ * It must not. The server and the plugin are independently stoppable, which is why the
263
+ * lifecycle is a separate object from the plugin's own registration state.
264
+ * @returns always false.
265
+ */
266
+ export function disablingServerDisablesOtherTools() {
267
+ return false;
268
+ }
269
+ //# sourceMappingURL=server-lifecycle.js.map
package/lib/types.d.ts CHANGED
@@ -65,6 +65,27 @@ export interface ModelCatalogEntry {
65
65
  readonly name: string;
66
66
  readonly summary: string;
67
67
  readonly capability: string;
68
+ /**
69
+ * The standard contract this model implements, or null when none exists yet.
70
+ *
71
+ * This is what makes tool identity independent of model identity (BASE-02): the
72
+ * contract decides the tool name a caller sees, so a second model implementing
73
+ * the same contract joins the existing tool instead of creating a duplicate. A
74
+ * model with no contract keeps a per-model tool under its own name.
75
+ */
76
+ readonly contract: string | null;
77
+ /**
78
+ * The extension package that implements this model (BASE-09).
79
+ *
80
+ * A binding held as DATA, not a switch on the model name. The host loads
81
+ * whatever package this names through the PUBLIC extension API, so a first-party
82
+ * package takes the same route as a third-party one and adding a vendor means
83
+ * publishing a package plus adding this field — with no host change.
84
+ */
85
+ readonly provider?: {
86
+ readonly extension: string;
87
+ readonly modelId: string;
88
+ };
68
89
  readonly input: ModelInput;
69
90
  readonly output: string;
70
91
  readonly languages: number | null;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `text.language_detect` — the language-identification contract (TOOL-03).
3
+ *
4
+ * TOOL-03 requires three things a naive wrapper loses: ambiguity must survive to
5
+ * the caller, empty input has a defined answer rather than an exception, and the
6
+ * score's MEANING is declared. It also forbids a specific mistake worth naming in
7
+ * the schema: a text language detector is not evidence about the language spoken
8
+ * in audio it never processed, so the contract says so instead of leaving a
9
+ * caller to infer capability from a similar-looking tool.
10
+ *
11
+ * @module @try-works/tool-mode-contracts/contracts/lang-detect
12
+ */
13
+ import type { ToolContract } from '../registry.ts';
14
+ /** The `text.language_detect` contract at version 1.0.0. */
15
+ export declare const langDetect: ToolContract;
16
+ //# sourceMappingURL=lang-detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lang-detect.d.ts","sourceRoot":"","sources":["../../src/contracts/lang-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAElD,4DAA4D;AAC5D,eAAO,MAAM,UAAU,EAAE,YA8ExB,CAAA"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * `text.language_detect` — the language-identification contract (TOOL-03).
3
+ *
4
+ * TOOL-03 requires three things a naive wrapper loses: ambiguity must survive to
5
+ * the caller, empty input has a defined answer rather than an exception, and the
6
+ * score's MEANING is declared. It also forbids a specific mistake worth naming in
7
+ * the schema: a text language detector is not evidence about the language spoken
8
+ * in audio it never processed, so the contract says so instead of leaving a
9
+ * caller to infer capability from a similar-looking tool.
10
+ *
11
+ * @module @try-works/tool-mode-contracts/contracts/lang-detect
12
+ */
13
+ import { withMeta } from "../meta.js";
14
+ /** The `text.language_detect` contract at version 1.0.0. */
15
+ export const langDetect = {
16
+ contract: 'text.language_detect',
17
+ version: '1.0.0',
18
+ toolName: 'lang_detect',
19
+ description: 'Identify the language of a short piece of text. Returns the best language, a reliability '
20
+ + 'verdict and ranked alternatives, because short text is often genuinely ambiguous between '
21
+ + 'related languages and collapsing that to one answer would overstate the result.',
22
+ inputSchema: {
23
+ type: 'object',
24
+ additionalProperties: false,
25
+ required: ['text'],
26
+ properties: {
27
+ text: {
28
+ type: 'string',
29
+ minLength: 1,
30
+ maxLength: 4096,
31
+ description: 'The text to identify. Only the leading portion is examined.',
32
+ },
33
+ top: {
34
+ type: 'integer',
35
+ minimum: 1,
36
+ maximum: 20,
37
+ default: 3,
38
+ description: 'How many ranked alternatives to return.',
39
+ },
40
+ },
41
+ },
42
+ outputSchema: withMeta({
43
+ language: { type: ['string', 'null'], description: 'Best candidate, or null when input had no language signal.' },
44
+ reliability: {
45
+ type: 'string',
46
+ enum: ['confident', 'likely', 'tentative', 'unknown'],
47
+ description: 'Vendor-reported verdict. Not a calibrated probability.',
48
+ },
49
+ tooCloseToCall: {
50
+ type: 'boolean',
51
+ description: 'True when the leading candidates are within the implementation\'s declared tie margin.',
52
+ },
53
+ candidates: {
54
+ type: 'array',
55
+ items: {
56
+ type: 'object',
57
+ additionalProperties: false,
58
+ required: ['language', 'probability'],
59
+ properties: {
60
+ language: { type: 'string' },
61
+ probability: { type: 'number', minimum: 0, maximum: 1 },
62
+ },
63
+ },
64
+ },
65
+ }, ['reliability', 'tooCloseToCall', 'candidates']),
66
+ semantics: {
67
+ scoreKind: 'vendor-reported-probability',
68
+ calibrated: false,
69
+ ambiguityPreserved: true,
70
+ emptyInputMeaning: 'null-language-with-empty-candidates',
71
+ appliesTo: 'written-text-only',
72
+ },
73
+ limits: {
74
+ maxInputCharacters: 4096,
75
+ examinedCharacters: 512,
76
+ maxCandidates: 20,
77
+ },
78
+ unsupported: [
79
+ 'Spoken language: this reads written text only. It is not evidence about the language spoken in audio it has not processed (TOOL-03).',
80
+ 'Translation or transliteration.',
81
+ 'Confident single answers for one or two words: those are frequently ambiguous and are reported as such.',
82
+ 'Documents beyond the examined prefix: only the leading characters are considered.',
83
+ ],
84
+ };
85
+ //# sourceMappingURL=lang-detect.js.map
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `stt.transcribe` — the canonical transcription contract (TOOL-01).
3
+ *
4
+ * This contract is model-free on purpose. Any conforming implementation binds to
5
+ * it, so a caller addresses `stt_transcribe` once and the host decides which
6
+ * model runs (BASE-02). Adding a second transcription model must not add a
7
+ * second tool.
8
+ *
9
+ * The semantics block is the part a schema cannot express and the part the spec
10
+ * insists on (DECL-01, TOOL-01): whether this transcribes or translates, what
11
+ * the timestamps mean, and what an empty result means.
12
+ *
13
+ * @module @try-works/tool-mode-contracts/contracts/stt-transcribe
14
+ */
15
+ import type { ToolContract } from '../registry.ts';
16
+ /** Accepted audio container/codec combinations for the bounded decoder. */
17
+ export declare const STT_ADMITTED_FORMATS: readonly ["wav-pcm16"];
18
+ /** The `stt.transcribe` contract at version 1.0.0. */
19
+ export declare const sttTranscribe: ToolContract;
20
+ //# sourceMappingURL=stt-transcribe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stt-transcribe.d.ts","sourceRoot":"","sources":["../../src/contracts/stt-transcribe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAElD,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,wBAAyB,CAAA;AAE1D,sDAAsD;AACtD,eAAO,MAAM,aAAa,EAAE,YAqG3B,CAAA"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * `stt.transcribe` — the canonical transcription contract (TOOL-01).
3
+ *
4
+ * This contract is model-free on purpose. Any conforming implementation binds to
5
+ * it, so a caller addresses `stt_transcribe` once and the host decides which
6
+ * model runs (BASE-02). Adding a second transcription model must not add a
7
+ * second tool.
8
+ *
9
+ * The semantics block is the part a schema cannot express and the part the spec
10
+ * insists on (DECL-01, TOOL-01): whether this transcribes or translates, what
11
+ * the timestamps mean, and what an empty result means.
12
+ *
13
+ * @module @try-works/tool-mode-contracts/contracts/stt-transcribe
14
+ */
15
+ import { withMeta } from "../meta.js";
16
+ /** Accepted audio container/codec combinations for the bounded decoder. */
17
+ export const STT_ADMITTED_FORMATS = ['wav-pcm16'];
18
+ /** The `stt.transcribe` contract at version 1.0.0. */
19
+ export const sttTranscribe = {
20
+ contract: 'stt.transcribe',
21
+ version: '1.0.0',
22
+ toolName: 'stt_transcribe',
23
+ description: 'Transcribe a local audio recording into text with optional word timestamps. '
24
+ + 'Runs on device by default; the caller selects no model. Accepts 16 kHz mono PCM16 WAV '
25
+ + 'directly, and other encodings only through a tested decoder. Reports partial coverage '
26
+ + 'rather than presenting an incomplete clip as fully transcribed.',
27
+ inputSchema: {
28
+ type: 'object',
29
+ additionalProperties: false,
30
+ required: ['audio'],
31
+ properties: {
32
+ audio: {
33
+ type: 'object',
34
+ additionalProperties: false,
35
+ required: ['path'],
36
+ properties: {
37
+ path: { type: 'string', minLength: 1, description: 'Absolute path to the recording.' },
38
+ sampleRateHz: {
39
+ type: 'integer',
40
+ minimum: 8000,
41
+ maximum: 48000,
42
+ description: 'Declared sample rate; inspected against the file header, not trusted.',
43
+ },
44
+ channels: { type: 'integer', minimum: 1, maximum: 2 },
45
+ },
46
+ },
47
+ language: {
48
+ type: 'string',
49
+ minLength: 2,
50
+ description: 'Requested language as a BCP-47/ISO 639 code. An unsupported request is an error, never a silent fallback.',
51
+ },
52
+ timestamps: {
53
+ type: 'string',
54
+ enum: ['none', 'word'],
55
+ default: 'none',
56
+ description: 'Word timestamps when requested; an implementation that cannot supply them must error rather than omit them.',
57
+ },
58
+ },
59
+ },
60
+ outputSchema: withMeta({
61
+ text: { type: 'string' },
62
+ coverage: {
63
+ type: 'object',
64
+ additionalProperties: false,
65
+ required: ['complete', 'transcribedSeconds'],
66
+ properties: {
67
+ complete: { type: 'boolean' },
68
+ transcribedSeconds: { type: 'number', minimum: 0 },
69
+ totalSeconds: { type: ['number', 'null'], minimum: 0 },
70
+ reason: { type: ['string', 'null'] },
71
+ },
72
+ },
73
+ words: {
74
+ type: ['array', 'null'],
75
+ items: {
76
+ type: 'object',
77
+ additionalProperties: false,
78
+ required: ['text', 'start', 'end'],
79
+ properties: {
80
+ text: { type: 'string' },
81
+ start: { type: 'number', minimum: 0, description: 'Seconds from the start of the audio.' },
82
+ end: { type: 'number', minimum: 0 },
83
+ },
84
+ },
85
+ },
86
+ language: { type: ['string', 'null'], description: 'The language actually recognized, when the implementation reports it.' },
87
+ }, ['text', 'coverage']),
88
+ semantics: {
89
+ operation: 'transcription',
90
+ translation: false,
91
+ timestampUnit: 'seconds',
92
+ timestampReference: 'start-of-audio',
93
+ emptyResultMeaning: 'valid-empty-transcript',
94
+ partialResultMeaning: 'coverage.complete is false; the transcript is incomplete, not wrong',
95
+ languageMismatch: 'error',
96
+ unsupportedTimestampRequest: 'error',
97
+ },
98
+ limits: {
99
+ maxAudioSeconds: 3600,
100
+ maxAudioBytes: 512 * 1024 * 1024,
101
+ admittedSampleRateHz: 16000,
102
+ admittedChannels: 1,
103
+ },
104
+ unsupported: [
105
+ 'Encoding without a tested decoder: only wav-pcm16 is admitted directly; assume nothing from the file extension.',
106
+ 'Translation: this contract transcribes, it does not translate.',
107
+ 'Diarization or speaker attribution: separate capability.',
108
+ 'Timestamps when the selected implementation cannot produce them: reported as an error.',
109
+ 'Live/streaming audio: the input is a completed local file.',
110
+ ],
111
+ };
112
+ //# sourceMappingURL=stt-transcribe.js.map
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Projection of a contract into DSH's parameter DSL (DECL-01).
3
+ *
4
+ * DECL-01 requires that DSH registration, MCP projection and Code Mode types all
5
+ * come from one source. The contract's JSON Schema is that source; this module is
6
+ * the DSH-specific projection of it.
7
+ *
8
+ * It replaces the old registrar behaviour that inferred the required input from
9
+ * parameter ORDER (BASE-04). Requiredness now comes from the schema's `required`
10
+ * array, so a contract cannot silently change meaning when a property is
11
+ * reordered.
12
+ *
13
+ * @module @try-works/tool-mode-contracts/dsh
14
+ */
15
+ import type { ToolContract } from './registry.ts';
16
+ /** One DSH parameter property: a JSON-Schema subset plus `required`. */
17
+ type DshProperty = Record<string, unknown> & {
18
+ required?: true;
19
+ };
20
+ /** The implicit-open-object parameter map DSH expects. */
21
+ export type DshParameters = Record<string, DshProperty>;
22
+ /** The result of projecting a contract into DSH's narrower DSL. */
23
+ export interface DshProjection {
24
+ /** What the model-facing parameter schema advertises. */
25
+ readonly parameters: DshParameters;
26
+ /**
27
+ * Contract keywords the parameter schema cannot advertise, in `path.keyword`
28
+ * form. They remain enforced at runtime against the full contract schema.
29
+ */
30
+ readonly runtimeEnforced: readonly string[];
31
+ }
32
+ /** Raised when a contract uses a schema shape the DSH DSL cannot express. */
33
+ export declare class ProjectionError extends Error {
34
+ readonly name = "ProjectionError";
35
+ readonly unsupported: readonly string[];
36
+ constructor(contract: string, unsupported: readonly string[]);
37
+ }
38
+ /**
39
+ * Project a contract's input schema into DSH parameters.
40
+ *
41
+ * DSH's DSL is narrower than JSON Schema — it has no `minLength`, `minimum` or
42
+ * `pattern` at any nesting level — so the projection is deliberately lossy in what
43
+ * it ADVERTISES while remaining complete in what it ENFORCES. BASE-04 forbids
44
+ * silently discarding a constraint, so every keyword left out is returned in
45
+ * {@link DshProjection.runtimeEnforced} and is checked by `assertValidInput`
46
+ * against the untouched contract.
47
+ * @param contract - the contract to project.
48
+ * @returns the parameter map plus the keywords enforced only at runtime.
49
+ */
50
+ export declare function projectToDsh(contract: ToolContract): DshProjection;
51
+ /**
52
+ * Project a contract's input schema into DSH parameters.
53
+ * @param contract - the contract to project.
54
+ * @returns the parameter map.
55
+ * @throws ProjectionError when the schema is internally inconsistent.
56
+ */
57
+ export declare function toDshParameters(contract: ToolContract): DshParameters;
58
+ /**
59
+ * Cross-field constraints the DSH parameter DSL cannot express (BASE-04).
60
+ *
61
+ * Each returns a violation message, or undefined when the arguments are
62
+ * acceptable. They run after schema validation, so each may assume its fields
63
+ * are present and correctly typed.
64
+ */
65
+ export type CrossFieldRule = (args: Record<string, unknown>) => string | undefined;
66
+ /** The cross-field rules that apply to a given contract. */
67
+ export declare function crossFieldRules(contract: ToolContract): CrossFieldRule[];
68
+ /**
69
+ * Project an arbitrary JSON Schema into the subset DSH can advertise (DECL-02).
70
+ *
71
+ * Written for the OUTPUT schema, which needs the same treatment the input schema
72
+ * already gets. Using the contract's raw output schema would crash registration on the
73
+ * first keyword the DSL cannot express — the failure that produced `runtimeEnforced` in
74
+ * the first place — and using an unconstrained `{type: "object", additionalProperties:
75
+ * true}` instead, which is what this replaced, publishes a tool whose result shape is
76
+ * declared to be anything at all.
77
+ * @param schema - the schema to project.
78
+ * @returns the projected schema plus the keywords left to runtime enforcement.
79
+ */
80
+ export declare function projectSchemaToDsh(schema: Readonly<Record<string, unknown>>): DshProjection;
81
+ export {};
82
+ //# sourceMappingURL=dsh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dsh.d.ts","sourceRoot":"","sources":["../src/dsh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,wEAAwE;AACxE,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,QAAQ,CAAC,EAAE,IAAI,CAAA;CAAE,CAAA;AAEhE,0DAA0D;AAC1D,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;AAEvD,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAA;IAClC;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAA;CAC5C;AAED,6EAA6E;AAC7E,qBAAa,eAAgB,SAAQ,KAAK;IACxC,SAAkB,IAAI,qBAAoB;IAC1C,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;gBAC3B,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE;CAO7D;AAyFD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,YAAY,GAAG,aAAa,CAuBlE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,aAAa,CAErE;AAED;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,GAAG,SAAS,CAAA;AAElF,4DAA4D;AAC5D,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,cAAc,EAAE,CAqCxE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,aAAa,CAsB3F"}