@try-works/dsh-model-as-tool 0.1.2 → 0.3.6
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/bin/dsh-tool-mode-credentials.mjs +20 -0
- package/bin/dsh-tool-mode.mjs +202 -0
- package/catalog/desert-ant-models.json +693 -693
- package/client/client.model-tools.js +592 -0
- package/client/index.js +1679 -0
- package/lib/adapters/index.d.ts.map +1 -1
- package/lib/adapters/index.js +4 -4
- package/lib/bindings.d.ts.map +1 -1
- package/lib/bindings.js +26 -25
- package/lib/capability.d.ts.map +1 -1
- package/lib/capability.js +17 -0
- package/lib/capture-path.d.ts +97 -0
- package/lib/capture-path.d.ts.map +1 -0
- package/lib/capture-path.js +152 -0
- package/lib/diagnostics.d.ts +166 -0
- package/lib/diagnostics.d.ts.map +1 -0
- package/lib/diagnostics.js +135 -0
- package/lib/extension-dependencies.d.ts +197 -0
- package/lib/extension-dependencies.d.ts.map +1 -0
- package/lib/extension-dependencies.js +369 -0
- package/lib/extension-dispatch.d.ts +117 -0
- package/lib/extension-dispatch.d.ts.map +1 -0
- package/lib/extension-dispatch.js +124 -0
- package/lib/extension-registrar.d.ts +100 -0
- package/lib/extension-registrar.d.ts.map +1 -0
- package/lib/extension-registrar.js +134 -0
- package/lib/extensions-api.d.ts +217 -0
- package/lib/extensions-api.d.ts.map +1 -0
- package/lib/extensions-api.js +17 -0
- package/lib/extensions-remote.d.ts +54 -0
- package/lib/extensions-remote.d.ts.map +1 -0
- package/lib/extensions-remote.js +66 -0
- package/lib/extensions-service.d.ts +334 -0
- package/lib/extensions-service.d.ts.map +1 -0
- package/lib/extensions-service.js +1351 -0
- package/lib/harness-llm.d.ts +138 -0
- package/lib/harness-llm.d.ts.map +1 -0
- package/lib/harness-llm.js +218 -0
- package/lib/harness-serving.d.ts +95 -0
- package/lib/harness-serving.d.ts.map +1 -0
- package/lib/harness-serving.js +157 -0
- package/lib/headless.d.ts +97 -0
- package/lib/headless.d.ts.map +1 -0
- package/lib/headless.js +349 -0
- package/lib/http-acquisition.d.ts +27 -0
- package/lib/http-acquisition.d.ts.map +1 -0
- package/lib/http-acquisition.js +136 -0
- package/lib/index.d.ts +250 -7
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2625 -70
- package/lib/invocation-accounting.d.ts +169 -0
- package/lib/invocation-accounting.d.ts.map +1 -0
- package/lib/invocation-accounting.js +148 -0
- package/lib/legacy-migration.d.ts +95 -0
- package/lib/legacy-migration.d.ts.map +1 -0
- package/lib/legacy-migration.js +429 -0
- package/lib/managed-workers.d.ts +151 -0
- package/lib/managed-workers.d.ts.map +1 -0
- package/lib/managed-workers.js +249 -0
- package/lib/mcp/client-grant.d.ts +74 -0
- package/lib/mcp/client-grant.d.ts.map +1 -0
- package/lib/mcp/client-grant.js +60 -0
- package/lib/mcp/credential-cli.d.ts +38 -0
- package/lib/mcp/credential-cli.d.ts.map +1 -0
- package/lib/mcp/credential-cli.js +148 -0
- package/lib/mcp/credential-store.d.ts +143 -0
- package/lib/mcp/credential-store.d.ts.map +1 -0
- package/lib/mcp/credential-store.js +454 -0
- package/lib/mcp/host-binding.d.ts +25 -0
- package/lib/mcp/host-binding.d.ts.map +1 -1
- package/lib/mcp/host-binding.js +107 -14
- package/lib/mcp/http.d.ts +68 -18
- package/lib/mcp/http.d.ts.map +1 -1
- package/lib/mcp/http.js +390 -62
- package/lib/mcp/oauth.d.ts +149 -0
- package/lib/mcp/oauth.d.ts.map +1 -0
- package/lib/mcp/oauth.js +396 -0
- package/lib/mcp/protocol.d.ts +46 -7
- package/lib/mcp/protocol.d.ts.map +1 -1
- package/lib/mcp/protocol.js +63 -16
- package/lib/mcp/rate-limit.d.ts +68 -0
- package/lib/mcp/rate-limit.d.ts.map +1 -0
- package/lib/mcp/rate-limit.js +114 -0
- package/lib/mcp/sdk-v2.d.ts +17 -0
- package/lib/mcp/sdk-v2.d.ts.map +1 -0
- package/lib/mcp/sdk-v2.js +181 -0
- package/lib/mcp/server.d.ts +11 -1
- package/lib/mcp/server.d.ts.map +1 -1
- package/lib/mcp/server.js +80 -13
- package/lib/mcp/stdio.d.ts.map +1 -1
- package/lib/mcp/stdio.js +9 -1
- package/lib/mcp/subscriptions.d.ts +43 -1
- package/lib/mcp/subscriptions.d.ts.map +1 -1
- package/lib/mcp/subscriptions.js +90 -9
- package/lib/model-qualification.d.ts +192 -0
- package/lib/model-qualification.d.ts.map +1 -0
- package/lib/model-qualification.js +178 -0
- package/lib/planning.d.ts +246 -0
- package/lib/planning.d.ts.map +1 -0
- package/lib/planning.js +457 -0
- package/lib/prepared-assets.d.ts +178 -0
- package/lib/prepared-assets.d.ts.map +1 -0
- package/lib/prepared-assets.js +286 -0
- package/lib/provider-bridge.d.ts +37 -0
- package/lib/provider-bridge.d.ts.map +1 -1
- package/lib/provider-bridge.js +189 -12
- package/lib/ptc-authority.d.ts +140 -0
- package/lib/ptc-authority.d.ts.map +1 -0
- package/lib/ptc-authority.js +216 -0
- package/lib/ptc-runtime.d.ts +156 -0
- package/lib/ptc-runtime.d.ts.map +1 -0
- package/lib/ptc-runtime.js +191 -0
- package/lib/publication.d.ts +2 -1
- package/lib/publication.d.ts.map +1 -1
- package/lib/publication.js +13 -5
- package/lib/receipt.d.ts.map +1 -1
- package/lib/receipt.js +8 -0
- package/lib/title-proposal.d.ts +194 -0
- package/lib/title-proposal.d.ts.map +1 -0
- package/lib/title-proposal.js +244 -0
- package/lib/tool-mode-run.d.ts +235 -0
- package/lib/tool-mode-run.d.ts.map +1 -0
- package/lib/tool-mode-run.js +283 -0
- package/lib/types.d.ts +3 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/update-surface.d.ts +79 -0
- package/lib/update-surface.d.ts.map +1 -0
- package/lib/update-surface.js +224 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/lang-detect.d.ts +16 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/lang-detect.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/lang-detect.js +85 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/standard.d.ts +38 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/standard.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/standard.js +445 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/stt-transcribe.d.ts +20 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/stt-transcribe.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/stt-transcribe.js +112 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-embed.d.ts +14 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-embed.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-embed.js +63 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-rerank.d.ts +14 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-rerank.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-rerank.js +76 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/dsh.d.ts +82 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/dsh.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/dsh.js +274 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/index.d.ts +26 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/index.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/index.js +48 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/meta.d.ts +104 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/meta.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/meta.js +55 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/registry.d.ts +107 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/registry.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/registry.js +246 -0
- package/node_modules/@try-works/tool-mode-contracts/package.json +34 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/bin/dsh-tool-mode.mjs +20 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/cli.d.ts +80 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/cli.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/cli.js +533 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/declarative-recipes.d.ts +83 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/declarative-recipes.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/declarative-recipes.js +125 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/discovery.d.ts +70 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/discovery.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/discovery.js +201 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/errors.d.ts +57 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/errors.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/errors.js +83 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/index.d.ts +31 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/index.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/index.js +31 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/archive.d.ts +86 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/archive.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/archive.js +185 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/dependencies.d.ts +126 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/dependencies.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/dependencies.js +297 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/lifecycle.d.ts +216 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/lifecycle.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/lifecycle.js +800 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/migration.d.ts +210 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/migration.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/migration.js +368 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/runtime-link.d.ts +63 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/runtime-link.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/runtime-link.js +149 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/source-directory.d.ts +35 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/source-directory.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/source-directory.js +179 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/staged.d.ts +179 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/staged.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/staged.js +235 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/store.d.ts +367 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/store.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/store.js +807 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/update-flow.d.ts +185 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/update-flow.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/update-flow.js +504 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/zip-source.d.ts +17 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/zip-source.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/zip-source.js +80 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/load.d.ts +52 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/load.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/load.js +102 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/manifest.d.ts +171 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/manifest.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/manifest.js +271 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/runtime.d.ts +242 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/runtime.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/runtime.js +58 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/state.d.ts +118 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/state.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/state.js +113 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker/worker-child.d.ts +2 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker/worker-child.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker/worker-child.js +351 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker.d.ts +150 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker.js +670 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/package.json +53 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/schema/extension-manifest-1.1.0.schema.json +253 -0
- package/node_modules/@try-works/tool-mode-recipes/bin/tool-mode-recipe.mjs +15 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/broker.d.ts +427 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/broker.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/broker.js +592 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/cli.d.ts +60 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/cli.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/cli.js +936 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/dsh-adapter.d.ts +237 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/dsh-adapter.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/dsh-adapter.js +200 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/fixture-provider.d.ts +85 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/fixture-provider.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/fixture-provider.js +176 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/images.d.ts +105 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/images.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/images.js +129 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/index.d.ts +25 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/index.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/index.js +25 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/recipe-format.d.ts +325 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/recipe-format.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/recipe-format.js +1310 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/templates.d.ts +51 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/templates.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/templates.js +310 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/titles.d.ts +227 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/titles.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/titles.js +407 -0
- package/node_modules/@try-works/tool-mode-recipes/package.json +56 -0
- package/node_modules/@try-works/tool-mode-recipes/recipes/describe-image.json +38 -0
- package/node_modules/@try-works/tool-mode-recipes/recipes/text-title.json +45 -0
- package/node_modules/@try-works/tool-mode-recipes/schema/harness-model-recipe.schema.json +273 -0
- package/package.json +50 -17
- package/remote/spec.mjs +439 -0
- package/remote/typert.host.mjs +14 -0
- package/remote/typert.remote-client.mjs +16 -0
- package/lib/adapters/tongue.d.ts +0 -31
- package/lib/adapters/tongue.d.ts.map +0 -1
- package/lib/adapters/tongue.js +0 -93
- package/lib/adapters/voz.d.ts +0 -28
- package/lib/adapters/voz.d.ts.map +0 -1
- package/lib/adapters/voz.js +0 -102
- /package/{lib → node_modules/@try-works/tool-mode-extension-sdk/lib}/licensing.d.ts +0 -0
- /package/{lib → node_modules/@try-works/tool-mode-extension-sdk/lib}/licensing.d.ts.map +0 -0
- /package/{lib → node_modules/@try-works/tool-mode-extension-sdk/lib}/licensing.js +0 -0
package/lib/mcp/server.js
CHANGED
|
@@ -53,15 +53,44 @@ export async function dispatch(request, host, options = {}) {
|
|
|
53
53
|
negotiateVersion(metadata);
|
|
54
54
|
// Capabilities the CLIENT requires. A requirement this server cannot meet is
|
|
55
55
|
// -32021 rather than a silent partial service.
|
|
56
|
+
const wiring = { subscriptions: options.subscriptions !== undefined };
|
|
56
57
|
const required = requiredCapabilities(metadata.clientCapabilities);
|
|
57
|
-
const unsupported = unsupportedRequiredCapabilities(required);
|
|
58
|
+
const unsupported = unsupportedRequiredCapabilities(required, wiring);
|
|
58
59
|
if (unsupported.length > 0) {
|
|
59
|
-
throw new WireError(ERROR_CODES.unsupportedClientCapability, `the client requires unsupported capability: ${unsupported.join(', ')}`,
|
|
60
|
+
throw new WireError(ERROR_CODES.unsupportedClientCapability, `the client requires unsupported capability: ${unsupported.join(', ')}`,
|
|
61
|
+
/**
|
|
62
|
+
* THE PINNED SCHEMA'S OWN FIELD NAME, and this was WRONG.
|
|
63
|
+
*
|
|
64
|
+
* `MissingRequiredClientCapabilityError` REQUIRES `data.requiredCapabilities`. This
|
|
65
|
+
* sent `{ unsupported: [...] }`, which Ajv rejects against the pinned definition:
|
|
66
|
+
*
|
|
67
|
+
* INVALID -> /error/data must have required property 'requiredCapabilities'
|
|
68
|
+
*
|
|
69
|
+
* It went unnoticed because the GENERIC `JSONRPCErrorResponse` accepts ANY `data`,
|
|
70
|
+
* every fixture took that path, and no fixture covered `-32021` at all — so the
|
|
71
|
+
* conformance suite validated a shape the specific error definition forbids.
|
|
72
|
+
* P26-03 requires `-32021` "and the schema-defined data"; this is that shape.
|
|
73
|
+
*/
|
|
74
|
+
/**
|
|
75
|
+
* A `ClientCapabilities` OBJECT, not an array of names — and this was STILL wrong.
|
|
76
|
+
*
|
|
77
|
+
* The previous correction fixed the FIELD NAME (`unsupported` -> `requiredCapabilities`)
|
|
78
|
+
* and left the VALUE as an array of strings. The pinned definition is precise:
|
|
79
|
+
*
|
|
80
|
+
* requiredCapabilities -> $ref ClientCapabilities (type: object)
|
|
81
|
+
*
|
|
82
|
+
* so the shape is `{ sampling: {} }`, a capabilities object keyed by capability name.
|
|
83
|
+
* Both defects are the same kind — a plausible shape that no fixture covered — and this
|
|
84
|
+
* one survived the first fix because only a LIVE response validated against the pinned
|
|
85
|
+
* definition could distinguish an array from an object. The fixture probe never saw it,
|
|
86
|
+
* and no test asserted the value's TYPE.
|
|
87
|
+
*/
|
|
88
|
+
{ requiredCapabilities: Object.fromEntries(unsupported.map(name => [name, {}])) });
|
|
60
89
|
}
|
|
61
90
|
switch (request.method) {
|
|
62
91
|
case 'server/discover':
|
|
63
92
|
return {
|
|
64
|
-
response: { jsonrpc: '2.0', id, result: successResult(discoverResult(), host.serverInfo) },
|
|
93
|
+
response: { jsonrpc: '2.0', id, result: successResult(discoverResult(wiring), host.serverInfo) },
|
|
65
94
|
httpStatus: 200,
|
|
66
95
|
};
|
|
67
96
|
case 'tools/list':
|
|
@@ -72,7 +101,15 @@ export async function dispatch(request, host, options = {}) {
|
|
|
72
101
|
result: successResult({
|
|
73
102
|
// Deterministic ordering (MCP-06): the caller sees a stable list, so
|
|
74
103
|
// a client diffing two listings does not see spurious changes.
|
|
104
|
+
//
|
|
105
|
+
// SEC-04: an AUTHENTICATED external caller sees only its GRANTED
|
|
106
|
+
// tools — the list is the client's authorized set, not the operator's
|
|
107
|
+
// whole surface. The grant stays the AUTHORITY: calling a
|
|
108
|
+
// non-granted tool still yields the grant refusal, this only
|
|
109
|
+
// narrows what a client is shown. The caller-less path (stdio /
|
|
110
|
+
// native) sees the full surface.
|
|
75
111
|
tools: [...host.listTools()]
|
|
112
|
+
.filter(tool => options.caller === undefined || options.caller.allowedTools.includes(tool.name))
|
|
76
113
|
.sort((left, right) => left.name.localeCompare(right.name))
|
|
77
114
|
.map(toMcpTool),
|
|
78
115
|
// Required by the schema's CacheableResult; omitting them makes the
|
|
@@ -101,7 +138,7 @@ export async function dispatch(request, host, options = {}) {
|
|
|
101
138
|
};
|
|
102
139
|
}
|
|
103
140
|
case 'tools/call':
|
|
104
|
-
return await callTool(request, id, host, options.signal ?? new AbortController().signal);
|
|
141
|
+
return await callTool(request, id, host, options.signal ?? new AbortController().signal, options.caller);
|
|
105
142
|
default:
|
|
106
143
|
throw new WireError(ERROR_CODES.methodNotFound, `unknown method ${JSON.stringify(request.method)}`);
|
|
107
144
|
}
|
|
@@ -114,13 +151,43 @@ export async function dispatch(request, host, options = {}) {
|
|
|
114
151
|
// payload (MCP-10), so it leaves as a JSON-RPC error.
|
|
115
152
|
return {
|
|
116
153
|
response: errorResponse(id, wire),
|
|
117
|
-
|
|
118
|
-
|
|
154
|
+
/**
|
|
155
|
+
* THE PINNED SCHEMA'S OWN `MUST`, read from the schema rather than inferred.
|
|
156
|
+
*
|
|
157
|
+
* Three error definitions state it in as many words — "For HTTP, the response status
|
|
158
|
+
* code MUST be `400 Bad Request`":
|
|
159
|
+
*
|
|
160
|
+
* HeaderMismatchError -> -32020
|
|
161
|
+
* MissingRequiredClientCapabilityError -> -32021
|
|
162
|
+
* UnsupportedProtocolVersionError -> -32022
|
|
163
|
+
*
|
|
164
|
+
* Only the FIRST and `invalidParams` were mapped to 400, so a client requiring an
|
|
165
|
+
* unsupported capability — or presenting an unsupported protocol version — received an
|
|
166
|
+
* error body under a 200 status. The suite stayed green either way, so the status was
|
|
167
|
+
* untested in BOTH directions.
|
|
168
|
+
*
|
|
169
|
+
* Kept as a named SET so the next transport-level rejection is a one-line addition
|
|
170
|
+
* rather than another condition somebody can forget.
|
|
171
|
+
*/
|
|
172
|
+
httpStatus: TRANSPORT_LEVEL_REJECTIONS.has(wire.code) ? 400 : 200,
|
|
119
173
|
};
|
|
120
174
|
}
|
|
121
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* The JSON-RPC codes the pinned schema requires be answered with HTTP 400 as well.
|
|
178
|
+
*
|
|
179
|
+
* Every one of these definitions says, verbatim: "For HTTP, the response status code MUST
|
|
180
|
+
* be `400 Bad Request`." Kept as a named set so the rule lives in ONE place and the next
|
|
181
|
+
* transport-level rejection is an addition rather than another forgotten condition.
|
|
182
|
+
*/
|
|
183
|
+
const TRANSPORT_LEVEL_REJECTIONS = new Set([
|
|
184
|
+
ERROR_CODES.headerMismatch, // -32020
|
|
185
|
+
ERROR_CODES.unsupportedClientCapability, // -32021
|
|
186
|
+
ERROR_CODES.unsupportedProtocolVersion, // -32022
|
|
187
|
+
ERROR_CODES.invalidParams, // -32602, a malformed request shape
|
|
188
|
+
]);
|
|
122
189
|
/** Handle `tools/call`. */
|
|
123
|
-
async function callTool(request, id, host, signal) {
|
|
190
|
+
async function callTool(request, id, host, signal, caller) {
|
|
124
191
|
const name = request.params?.name;
|
|
125
192
|
if (typeof name !== 'string' || name.length === 0) {
|
|
126
193
|
throw new WireError(ERROR_CODES.invalidParams, 'tools/call requires params.name');
|
|
@@ -140,7 +207,7 @@ async function callTool(request, id, host, signal) {
|
|
|
140
207
|
if (definition.importedFromMcp) {
|
|
141
208
|
throw new WireError(ERROR_CODES.invalidParams, `tool ${JSON.stringify(name)} was imported from MCP and is not re-exported`);
|
|
142
209
|
}
|
|
143
|
-
const outcome = await host.callTool(name, (args ?? {}), signal);
|
|
210
|
+
const outcome = await host.callTool(name, (args ?? {}), signal, caller);
|
|
144
211
|
const result = outcome.isError === true
|
|
145
212
|
// An application failure is a tool-error RESULT (P26-04), so the protocol
|
|
146
213
|
// exchange still succeeded.
|
|
@@ -156,13 +223,13 @@ async function callTool(request, id, host, signal) {
|
|
|
156
223
|
};
|
|
157
224
|
}
|
|
158
225
|
/** The `server/discover` result, in the shape the pinned schema requires. */
|
|
159
|
-
function discoverResult() {
|
|
226
|
+
function discoverResult(wiring = {}) {
|
|
160
227
|
return {
|
|
161
228
|
// `supportedVersions` is the field the schema defines; there is no
|
|
162
229
|
// `protocolVersion` on a DiscoverResult, which is the mistake pinning the schema
|
|
163
230
|
// caught. A client learns the versions the server speaks, not one it picked.
|
|
164
231
|
supportedVersions: [...SUPPORTED_PROTOCOL_VERSIONS],
|
|
165
|
-
capabilities: serverCapabilities(),
|
|
232
|
+
capabilities: serverCapabilities(wiring),
|
|
166
233
|
...cacheableResultFields(),
|
|
167
234
|
};
|
|
168
235
|
}
|
|
@@ -174,10 +241,10 @@ function discoverResult() {
|
|
|
174
241
|
* advertised only when it is genuinely implemented.
|
|
175
242
|
* @returns the `ServerCapabilities` object.
|
|
176
243
|
*/
|
|
177
|
-
function serverCapabilities() {
|
|
178
|
-
const implemented = new Set(implementedCapabilities());
|
|
244
|
+
function serverCapabilities(wiring = {}) {
|
|
245
|
+
const implemented = new Set(implementedCapabilities(wiring));
|
|
179
246
|
return {
|
|
180
|
-
...implemented.has('tools') ? { tools: {} } : {},
|
|
247
|
+
...implemented.has('tools') ? { tools: { listChanged: implemented.has('subscriptions/listen') } } : {},
|
|
181
248
|
...implemented.has('prompts') ? { prompts: {} } : {},
|
|
182
249
|
...implemented.has('resources/subscribe') ? { resources: {} } : {},
|
|
183
250
|
...implemented.has('logging') ? { logging: {} } : {},
|
package/lib/mcp/stdio.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/mcp/stdio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAA;AAElE,gEAAgE;AAChE,MAAM,WAAW,QAAQ;IACvB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,2CAA2C;IAC3C,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B;AAED,2CAA2C;AAC3C,MAAM,WAAW,cAAc;IAC7B,0BAA0B;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,CACd,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,KACzF,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAChF;AAED,wBAAwB;AACxB,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACrD,yDAAyD;IACzD,KAAK,IAAI,IAAI,CAAA;IACb,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,kDAAkD;AAClD,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBtF;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,QAAQ,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/mcp/stdio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAA;AAElE,gEAAgE;AAChE,MAAM,WAAW,QAAQ;IACvB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,2CAA2C;IAC3C,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B;AAED,2CAA2C;AAC3C,MAAM,WAAW,cAAc;IAC7B,0BAA0B;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,CACd,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,KACzF,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAChF;AAED,wBAAwB;AACxB,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACrD,yDAAyD;IACzD,KAAK,IAAI,IAAI,CAAA;IACb,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,kDAAkD;AAClD,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBtF;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,QAAQ,GAAG,WAAW,CAiHrF"}
|
package/lib/mcp/stdio.js
CHANGED
|
@@ -73,9 +73,17 @@ export function createStdioBridge(endpoint, io) {
|
|
|
73
73
|
catch {
|
|
74
74
|
// A malformed frame is answered on the PROTOCOL channel, because the client
|
|
75
75
|
// is waiting for a response and a diagnostic would not reach it.
|
|
76
|
+
/**
|
|
77
|
+
* The `id` is OMITTED rather than set to `null`, which is the rule `protocol.ts`
|
|
78
|
+
* documents three hundred lines away and this site contradicted.
|
|
79
|
+
*
|
|
80
|
+
* JSON-RPC 2.0 conventionally allows `id: null` for an undeterminable id, but the
|
|
81
|
+
* pinned revision types `RequestId` as `string | integer` and does not admit null,
|
|
82
|
+
* while `id` itself is OPTIONAL. A frame that failed to parse has no id to echo, so
|
|
83
|
+
* omitting it is the conformant way to say "unknown".
|
|
84
|
+
*/
|
|
76
85
|
return frame({
|
|
77
86
|
jsonrpc: '2.0',
|
|
78
|
-
id: null,
|
|
79
87
|
error: { code: -32700, message: 'the frame is not valid JSON' },
|
|
80
88
|
});
|
|
81
89
|
}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
*
|
|
28
28
|
* @module @try-works/dsh-model-as-tool/mcp/subscriptions
|
|
29
29
|
*/
|
|
30
|
-
import type
|
|
30
|
+
import { type WireRequest } from './protocol.ts';
|
|
31
31
|
/** The notification types the revision defines for catalog changes. */
|
|
32
32
|
export type SubscriptionFilterKey = 'toolsListChanged' | 'promptsListChanged' | 'resourcesListChanged' | 'resourceSubscriptions';
|
|
33
33
|
/** The filter a client requested, or the subset the server acknowledged. */
|
|
@@ -79,6 +79,7 @@ export declare function acknowledgeFilter(requested: SubscriptionFilter): Subscr
|
|
|
79
79
|
/** Manages the active catalog subscriptions. */
|
|
80
80
|
export declare class SubscriptionRegistry {
|
|
81
81
|
#private;
|
|
82
|
+
/** Counter for ids this server issues, so an id is never caller-chosen. */
|
|
82
83
|
/** Active subscriptions, for diagnostics. */
|
|
83
84
|
get active(): readonly Subscription[];
|
|
84
85
|
/**
|
|
@@ -132,4 +133,45 @@ export declare class SubscriptionRegistry {
|
|
|
132
133
|
* @returns the notification.
|
|
133
134
|
*/
|
|
134
135
|
export declare function cancelSubscription(subscriptionId: string): Record<string, unknown>;
|
|
136
|
+
/**
|
|
137
|
+
* The DELIVERY half of P26-09 (task-73): what a streaming transport
|
|
138
|
+
* implements. The registry owns the subscriptions and the filtering; the sink
|
|
139
|
+
* owns the per-client open streams. A production SSE transport provides its
|
|
140
|
+
* writer here; the tests inject a collecting sink that exercises the SAME
|
|
141
|
+
* consumer path end to end.
|
|
142
|
+
*/
|
|
143
|
+
export interface SubscriptionDeliverySink {
|
|
144
|
+
/** Deliver one addressed notification to its client's open stream. */
|
|
145
|
+
deliver(message: SubscriptionMessage): void;
|
|
146
|
+
/** Close every stream belonging to one client (teardown-cancelled first). */
|
|
147
|
+
closeClient(clientId: string, reason: string): void;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Run one catalog-change publication through the delivery consumer: the
|
|
151
|
+
* registry's per-caller filtering decides WHO gets the event, and the sink
|
|
152
|
+
* carries it to each client's stream. Acknowledgement ordering is the
|
|
153
|
+
* registry's own guarantee — an acknowledgement is marked sent before any
|
|
154
|
+
* publish can run, so no event can precede it.
|
|
155
|
+
* @param registry - the subscription state.
|
|
156
|
+
* @param generation - the catalog generation that changed.
|
|
157
|
+
* @param sink - the delivery transport.
|
|
158
|
+
* @returns how many subscribers received the change.
|
|
159
|
+
*/
|
|
160
|
+
export declare function deliverCatalogChange(registry: SubscriptionRegistry, generation: number, sink: SubscriptionDeliverySink): number;
|
|
161
|
+
/**
|
|
162
|
+
* The memory sink: one per-client queue, used by the tests to exercise the
|
|
163
|
+
* consumer and by the host as the transport seam until a streaming endpoint
|
|
164
|
+
* injects its writer. It honours the same contract a real transport must:
|
|
165
|
+
* delivery only to the addressed client, and closeClient stops that client's
|
|
166
|
+
* queue entirely.
|
|
167
|
+
*/
|
|
168
|
+
export declare class MemoryDeliverySink implements SubscriptionDeliverySink {
|
|
169
|
+
#private;
|
|
170
|
+
/** The delivered messages for one client, in delivery order. */
|
|
171
|
+
forClient(clientId: string): readonly SubscriptionMessage[];
|
|
172
|
+
/** Whether the sink closed a client, and why. */
|
|
173
|
+
closeReason(clientId: string): string | undefined;
|
|
174
|
+
deliver(message: SubscriptionMessage): void;
|
|
175
|
+
closeClient(clientId: string, reason: string): void;
|
|
176
|
+
}
|
|
135
177
|
//# sourceMappingURL=subscriptions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../src/mcp/subscriptions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../src/mcp/subscriptions.ts"],"names":[],"mappings":"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"}
|
package/lib/mcp/subscriptions.js
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
*
|
|
28
28
|
* @module @try-works/dsh-model-as-tool/mcp/subscriptions
|
|
29
29
|
*/
|
|
30
|
+
import { ERROR_CODES, WireError } from "./protocol.js";
|
|
30
31
|
/**
|
|
31
32
|
* The notification types this server actually emits.
|
|
32
33
|
*
|
|
@@ -59,7 +60,6 @@ export function acknowledgeFilter(requested) {
|
|
|
59
60
|
export class SubscriptionRegistry {
|
|
60
61
|
#subscriptions = new Map();
|
|
61
62
|
/** Counter for ids this server issues, so an id is never caller-chosen. */
|
|
62
|
-
#issued = 0;
|
|
63
63
|
/** Active subscriptions, for diagnostics. */
|
|
64
64
|
get active() {
|
|
65
65
|
return [...this.#subscriptions.values()];
|
|
@@ -74,13 +74,47 @@ export class SubscriptionRegistry {
|
|
|
74
74
|
* @returns the result envelope, the acknowledgement, and the subscription id.
|
|
75
75
|
*/
|
|
76
76
|
listen(request, clientId) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
/**
|
|
78
|
+
* `notifications` IS REQUIRED, and this used to default it.
|
|
79
|
+
*
|
|
80
|
+
* The pinned schema's `SubscriptionsListenRequestParams` declares
|
|
81
|
+
* `required: ["_meta","notifications"]`. Defaulting an absent filter to `{}` and
|
|
82
|
+
* returning SUCCESS contradicted that AND contradicted this module's own rule that a
|
|
83
|
+
* missing required field is `invalidParams` rather than a defaulted value — a client
|
|
84
|
+
* would receive an acknowledgement for a subscription it never described, and the
|
|
85
|
+
* filter it believed it had sent would be silently empty.
|
|
86
|
+
*/
|
|
87
|
+
const requested = request.params?.notifications;
|
|
88
|
+
if (requested === undefined || requested === null || typeof requested !== 'object' || Array.isArray(requested)) {
|
|
89
|
+
throw new WireError(ERROR_CODES.invalidParams, 'subscriptions/listen requires params.notifications; a missing filter is invalid rather than defaulted');
|
|
90
|
+
}
|
|
91
|
+
const filter = requested;
|
|
92
|
+
const acknowledged = acknowledgeFilter(filter);
|
|
93
|
+
/**
|
|
94
|
+
* THE SUBSCRIPTION IS IDENTIFIED BY THE LISTEN REQUEST'S OWN ID.
|
|
95
|
+
*
|
|
96
|
+
* This used to invent `sub_<time>_<n>`, which was WRONG, and the pinned schema says so
|
|
97
|
+
* in as many words. `CancelledNotification` states that the server's stream-terminating
|
|
98
|
+
* cancellation "references the ID of the `subscriptions/listen` request that opened the
|
|
99
|
+
* stream", and `SubscriptionsListenResultMetaObject` types its required
|
|
100
|
+
* `io.modelcontextprotocol/subscriptionId` as a **`RequestId`** — the same type as a
|
|
101
|
+
* request id — "so the client can correlate it with the originating subscription".
|
|
102
|
+
*
|
|
103
|
+
* A server-invented id that the client never saw cannot be correlated with anything, so
|
|
104
|
+
* a client could neither match the acknowledgement to its request nor recognise the
|
|
105
|
+
* cancellation that ends the stream.
|
|
106
|
+
*
|
|
107
|
+
* The original comment claimed a caller-chosen id would let one client address
|
|
108
|
+
* another's subscription. That concern is real but it is NOT addressed by inventing an
|
|
109
|
+
* id: subscriptions are keyed by this id and BOUND to `clientId`, and the binding is
|
|
110
|
+
* what prevents cross-client addressing.
|
|
111
|
+
*/
|
|
112
|
+
const subscriptionId = request.id;
|
|
113
|
+
if (typeof subscriptionId !== 'string' && typeof subscriptionId !== 'number') {
|
|
114
|
+
throw new WireError(ERROR_CODES.invalidParams, 'subscriptions/listen requires a string or integer request id, which IS the subscription id');
|
|
115
|
+
}
|
|
116
|
+
const subscription = { subscriptionId: String(subscriptionId), clientId, acknowledged, announced: true };
|
|
117
|
+
this.#subscriptions.set(String(subscriptionId), subscription);
|
|
84
118
|
return {
|
|
85
119
|
result: {
|
|
86
120
|
resultType: 'complete',
|
|
@@ -98,7 +132,7 @@ export class SubscriptionRegistry {
|
|
|
98
132
|
_meta: { [SUBSCRIPTION_ID_KEY]: subscriptionId },
|
|
99
133
|
},
|
|
100
134
|
},
|
|
101
|
-
subscriptionId,
|
|
135
|
+
subscriptionId: String(subscriptionId),
|
|
102
136
|
};
|
|
103
137
|
}
|
|
104
138
|
/**
|
|
@@ -204,4 +238,51 @@ export function cancelSubscription(subscriptionId) {
|
|
|
204
238
|
params: { requestId: subscriptionId },
|
|
205
239
|
};
|
|
206
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Run one catalog-change publication through the delivery consumer: the
|
|
243
|
+
* registry's per-caller filtering decides WHO gets the event, and the sink
|
|
244
|
+
* carries it to each client's stream. Acknowledgement ordering is the
|
|
245
|
+
* registry's own guarantee — an acknowledgement is marked sent before any
|
|
246
|
+
* publish can run, so no event can precede it.
|
|
247
|
+
* @param registry - the subscription state.
|
|
248
|
+
* @param generation - the catalog generation that changed.
|
|
249
|
+
* @param sink - the delivery transport.
|
|
250
|
+
* @returns how many subscribers received the change.
|
|
251
|
+
*/
|
|
252
|
+
export function deliverCatalogChange(registry, generation, sink) {
|
|
253
|
+
const messages = registry.publishToolListChanged(generation);
|
|
254
|
+
for (const message of messages)
|
|
255
|
+
sink.deliver(message);
|
|
256
|
+
return messages.length;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* The memory sink: one per-client queue, used by the tests to exercise the
|
|
260
|
+
* consumer and by the host as the transport seam until a streaming endpoint
|
|
261
|
+
* injects its writer. It honours the same contract a real transport must:
|
|
262
|
+
* delivery only to the addressed client, and closeClient stops that client's
|
|
263
|
+
* queue entirely.
|
|
264
|
+
*/
|
|
265
|
+
export class MemoryDeliverySink {
|
|
266
|
+
#queues = new Map();
|
|
267
|
+
#closed = new Map();
|
|
268
|
+
/** The delivered messages for one client, in delivery order. */
|
|
269
|
+
forClient(clientId) {
|
|
270
|
+
return [...(this.#queues.get(clientId) ?? [])];
|
|
271
|
+
}
|
|
272
|
+
/** Whether the sink closed a client, and why. */
|
|
273
|
+
closeReason(clientId) {
|
|
274
|
+
return this.#closed.get(clientId);
|
|
275
|
+
}
|
|
276
|
+
deliver(message) {
|
|
277
|
+
if (this.#closed.has(message.clientId))
|
|
278
|
+
return;
|
|
279
|
+
const queue = this.#queues.get(message.clientId) ?? [];
|
|
280
|
+
queue.push(message);
|
|
281
|
+
this.#queues.set(message.clientId, queue);
|
|
282
|
+
}
|
|
283
|
+
closeClient(clientId, reason) {
|
|
284
|
+
this.#closed.set(clientId, reason);
|
|
285
|
+
this.#queues.delete(clientId);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
207
288
|
//# sourceMappingURL=subscriptions.js.map
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model qualification and capability resolution (MODEL-01, MODEL-04, MODEL-05, MODEL-06).
|
|
3
|
+
*
|
|
4
|
+
* Four rules, each guarding a way of claiming more than is known:
|
|
5
|
+
*
|
|
6
|
+
* - **A platform table is not proof of correct inference** (MODEL-05). A record is
|
|
7
|
+
* qualified only when the exact revision, artifact hash, tokenizer, processor, engine
|
|
8
|
+
* version, ABI and execution provider are all recorded. A missing field is a GAP, and
|
|
9
|
+
* a gap is not a qualification.
|
|
10
|
+
* - **A model's modality list is not an adapter's** (MODEL-05). A model can support
|
|
11
|
+
* video while the selected adapter does not, so what is ADVERTISED is the INTERSECTION
|
|
12
|
+
* of the two, described as such.
|
|
13
|
+
* - **A model name is not a capability test** (MODEL-06). Capability comes from the
|
|
14
|
+
* resolved model, never from recognising a brand.
|
|
15
|
+
* - **Unknown is not unsupported** (MODEL-06). The requirement says to record them
|
|
16
|
+
* separately, because collapsing them lets an unevaluated capability be reported as a
|
|
17
|
+
* known absence — or, worse, the reverse.
|
|
18
|
+
*
|
|
19
|
+
* @module @try-works/dsh-model-as-tool/model-qualification
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* What is known about one capability.
|
|
23
|
+
*
|
|
24
|
+
* Three states rather than two, because MODEL-06 requires unknown and unsupported to be
|
|
25
|
+
* recorded separately.
|
|
26
|
+
*/
|
|
27
|
+
export type CapabilityState =
|
|
28
|
+
/** Evaluated, and it works. */
|
|
29
|
+
'supported'
|
|
30
|
+
/** Evaluated, and it does not. */
|
|
31
|
+
| 'unsupported'
|
|
32
|
+
/** NOT evaluated. Reporting this as either of the others is the defect. */
|
|
33
|
+
| 'unknown';
|
|
34
|
+
/** A capability of a model or an adapter. */
|
|
35
|
+
export type Modality = 'text' | 'code' | 'image' | 'audio' | 'video' | 'embedding';
|
|
36
|
+
/**
|
|
37
|
+
* The exact path a model is executed through (MODEL-05).
|
|
38
|
+
*
|
|
39
|
+
* Every field is required for qualification, because each one has been the difference
|
|
40
|
+
* between "the package imports" and "inference is correct".
|
|
41
|
+
*/
|
|
42
|
+
export interface QualificationRecord {
|
|
43
|
+
/** The model revision, not a branch or floating tag. */
|
|
44
|
+
readonly modelRevision: string;
|
|
45
|
+
/** The SHA of the exported artifact that is actually loaded. */
|
|
46
|
+
readonly artifactSha: string;
|
|
47
|
+
/** The tokenizer identity. */
|
|
48
|
+
readonly tokenizer: string;
|
|
49
|
+
/** The processor or preprocessing recipe identity. */
|
|
50
|
+
readonly processor: string;
|
|
51
|
+
/** The engine or package version. */
|
|
52
|
+
readonly engineVersion: string;
|
|
53
|
+
/** The Node ABI. */
|
|
54
|
+
readonly nodeAbi: string;
|
|
55
|
+
/** The CPU architecture, e.g. `x64`. */
|
|
56
|
+
readonly architecture: string;
|
|
57
|
+
/** The execution provider, e.g. `cpu` or `wasm`. */
|
|
58
|
+
readonly executionProvider: string;
|
|
59
|
+
}
|
|
60
|
+
/** The fields a qualification record must carry. */
|
|
61
|
+
export declare const QUALIFICATION_FIELDS: readonly (keyof QualificationRecord)[];
|
|
62
|
+
/**
|
|
63
|
+
* Report which qualification fields are missing (MODEL-05).
|
|
64
|
+
*
|
|
65
|
+
* A platform table, a successful package import or a runnable base model is not proof of
|
|
66
|
+
* correct inference, so a record with gaps is not a qualification however well it runs.
|
|
67
|
+
* @param record - the partial record.
|
|
68
|
+
* @returns the missing fields.
|
|
69
|
+
*/
|
|
70
|
+
export declare function qualificationGaps(record: Partial<QualificationRecord>): readonly (keyof QualificationRecord)[];
|
|
71
|
+
/**
|
|
72
|
+
* Whether a record qualifies a path (MODEL-05).
|
|
73
|
+
* @param record - the partial record.
|
|
74
|
+
* @returns whether every required field is present.
|
|
75
|
+
*/
|
|
76
|
+
export declare function isQualified(record: Partial<QualificationRecord>): record is QualificationRecord;
|
|
77
|
+
/** What a model supports, and what an adapter supports. */
|
|
78
|
+
export interface ModalityClaim {
|
|
79
|
+
readonly modelSupports: readonly Modality[];
|
|
80
|
+
readonly adapterSupports: readonly Modality[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The capabilities that may be ADVERTISED (MODEL-05).
|
|
84
|
+
*
|
|
85
|
+
* The intersection, because a model can support a modality while the selected adapter
|
|
86
|
+
* does not. Advertising the model's list would promise something the adapter cannot do.
|
|
87
|
+
* @param claim - what each side supports.
|
|
88
|
+
* @returns the advertisable modalities.
|
|
89
|
+
*/
|
|
90
|
+
export declare function advertisableModalities(claim: ModalityClaim): readonly Modality[];
|
|
91
|
+
/**
|
|
92
|
+
* Describe a model's capability as the INTERSECTION (MODEL-05).
|
|
93
|
+
*
|
|
94
|
+
* The description names what is not advertisable and why, so a reader is not left to
|
|
95
|
+
* infer that the model lacks the modality when in fact the adapter does.
|
|
96
|
+
* @param claim - what each side supports.
|
|
97
|
+
* @returns a description that is true of the pairing.
|
|
98
|
+
*/
|
|
99
|
+
export declare function describeCapability(claim: ModalityClaim): string;
|
|
100
|
+
/**
|
|
101
|
+
* Resolve one capability (MODEL-06).
|
|
102
|
+
*
|
|
103
|
+
* A capability is resolved from what was EVALUATED. A model name is never consulted,
|
|
104
|
+
* because a brand is not a capability test, and an unevaluated capability returns
|
|
105
|
+
* `unknown` rather than being inferred from a sibling.
|
|
106
|
+
* @param evidence - the observed result, or undefined when not evaluated.
|
|
107
|
+
* @returns the state.
|
|
108
|
+
*/
|
|
109
|
+
export declare function resolveCapability(evidence: boolean | undefined): CapabilityState;
|
|
110
|
+
/**
|
|
111
|
+
* Whether a model name may be used to infer a capability (MODEL-06).
|
|
112
|
+
*
|
|
113
|
+
* It may not. Returns false so the prohibition is asserted rather than merely intended:
|
|
114
|
+
* a rule that lives only in a comment is one a future branch will not read.
|
|
115
|
+
* @returns always false.
|
|
116
|
+
*/
|
|
117
|
+
export declare function modelNameImpliesCapability(): boolean;
|
|
118
|
+
/** How a candidate implementation executes (MODEL-04). */
|
|
119
|
+
export type ExecutionMode =
|
|
120
|
+
/** Pure JavaScript or WASM usable in plain Node. */
|
|
121
|
+
'js-wasm-node'
|
|
122
|
+
/** Prebuilt ONNX Runtime for Node. */
|
|
123
|
+
| 'onnxruntime-node'
|
|
124
|
+
/** A managed native Windows executable with pinned assets. */
|
|
125
|
+
| 'managed-native-windows'
|
|
126
|
+
/** Requires Python on the end user's machine. */
|
|
127
|
+
| 'python-required'
|
|
128
|
+
/** Requires WSL. */
|
|
129
|
+
| 'wsl-required'
|
|
130
|
+
/** Requires Docker. */
|
|
131
|
+
| 'docker-required'
|
|
132
|
+
/** Requires a GPU. */
|
|
133
|
+
| 'gpu-required'
|
|
134
|
+
/** Only works in a browser. */
|
|
135
|
+
| 'browser-only'
|
|
136
|
+
/** Requires a consumer-side compile step. */
|
|
137
|
+
| 'consumer-compile';
|
|
138
|
+
/** Why a mode was refused. */
|
|
139
|
+
export interface ModeVerdict {
|
|
140
|
+
readonly acceptable: boolean;
|
|
141
|
+
readonly reason?: string;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Whether an execution mode is acceptable for the end user (MODEL-04).
|
|
145
|
+
*
|
|
146
|
+
* Python, WSL, Docker, a GPU and a consumer compile step are all refused: maintainers may
|
|
147
|
+
* use Python to export artifacts, but it MUST NOT be required on an end user's Windows
|
|
148
|
+
* machine. A browser-only API does not establish Node support.
|
|
149
|
+
* @param mode - the mode.
|
|
150
|
+
* @returns the verdict, with a reason when refused.
|
|
151
|
+
*/
|
|
152
|
+
export declare function executionModeVerdict(mode: ExecutionMode): ModeVerdict;
|
|
153
|
+
/** An embedding space identity (MODEL-01, BASE-12). */
|
|
154
|
+
export interface EmbeddingSpace {
|
|
155
|
+
/** The model that produces it. */
|
|
156
|
+
readonly modelId: string;
|
|
157
|
+
/** The dimensionality of the vectors it produces. */
|
|
158
|
+
readonly dimensions: number;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Whether one embedding space may silently stand in for another (BASE-12).
|
|
162
|
+
*
|
|
163
|
+
* Only when the dimensions MATCH. EmbeddingGemma 2 is 768-dimensional and MiniLM is
|
|
164
|
+
* 384-dimensional, so substituting one for the other silently would compare vectors of
|
|
165
|
+
* different widths and produce meaningless similarity.
|
|
166
|
+
* @param from - the space in use.
|
|
167
|
+
* @param to - the proposed replacement.
|
|
168
|
+
* @returns whether the substitution is safe without an explicit migration.
|
|
169
|
+
*/
|
|
170
|
+
export declare function maySubstituteSilently(from: EmbeddingSpace, to: EmbeddingSpace): boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Describe an embedding substitution (BASE-12).
|
|
173
|
+
* @param from - the space in use.
|
|
174
|
+
* @param to - the proposed replacement.
|
|
175
|
+
* @returns a description naming the incompatibility when there is one.
|
|
176
|
+
*/
|
|
177
|
+
export declare function describeSubstitution(from: EmbeddingSpace, to: EmbeddingSpace): string;
|
|
178
|
+
/**
|
|
179
|
+
* The reduced dimensionalities EmbeddingGemma 2 supports (MODEL-01).
|
|
180
|
+
*
|
|
181
|
+
* The model card describes 768 reducible to 512, 256 and 128. Recorded rather than
|
|
182
|
+
* assumed, because a reduction that is not applied consistently produces vectors that
|
|
183
|
+
* cannot be compared with each other.
|
|
184
|
+
*/
|
|
185
|
+
export declare const EMBEDDINGGEMMA2_DIMENSIONS: readonly number[];
|
|
186
|
+
/**
|
|
187
|
+
* Whether a stated dimensionality is one EmbeddingGemma 2 can produce (MODEL-01).
|
|
188
|
+
* @param dimensions - the stated width.
|
|
189
|
+
* @returns whether it is a documented width.
|
|
190
|
+
*/
|
|
191
|
+
export declare function isEmbeddingGemma2Width(dimensions: number): boolean;
|
|
192
|
+
//# sourceMappingURL=model-qualification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-qualification.d.ts","sourceRoot":"","sources":["../src/model-qualification.ts"],"names":[],"mappings":"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"}
|