@deeprelay/mcp 0.0.1 → 0.1.1

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 (80) hide show
  1. package/README.md +194 -1
  2. package/dist/auth.d.ts +52 -0
  3. package/dist/auth.js +122 -0
  4. package/dist/auth.js.map +1 -0
  5. package/dist/errors.d.ts +83 -0
  6. package/dist/errors.js +307 -0
  7. package/dist/errors.js.map +1 -0
  8. package/dist/guardrail/budget.d.ts +95 -0
  9. package/dist/guardrail/budget.js +225 -0
  10. package/dist/guardrail/budget.js.map +1 -0
  11. package/dist/guardrail/elicitation.d.ts +12 -0
  12. package/dist/guardrail/elicitation.js +79 -0
  13. package/dist/guardrail/elicitation.js.map +1 -0
  14. package/dist/guardrail/estimate.d.ts +67 -0
  15. package/dist/guardrail/estimate.js +171 -0
  16. package/dist/guardrail/estimate.js.map +1 -0
  17. package/dist/guardrail/handshake.d.ts +32 -0
  18. package/dist/guardrail/handshake.js +164 -0
  19. package/dist/guardrail/handshake.js.map +1 -0
  20. package/dist/guardrail/types.d.ts +61 -0
  21. package/dist/guardrail/types.js +10 -0
  22. package/dist/guardrail/types.js.map +1 -0
  23. package/dist/index.d.ts +18 -0
  24. package/dist/index.js +61 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/roster.d.ts +36 -0
  27. package/dist/roster.js +130 -0
  28. package/dist/roster.js.map +1 -0
  29. package/dist/tools/crypto-deposit-gate.d.ts +21 -0
  30. package/dist/tools/crypto-deposit-gate.js +91 -0
  31. package/dist/tools/crypto-deposit-gate.js.map +1 -0
  32. package/dist/tools/index.d.ts +16 -0
  33. package/dist/tools/index.js +108 -0
  34. package/dist/tools/index.js.map +1 -0
  35. package/dist/tools/readonly/define.d.ts +32 -0
  36. package/dist/tools/readonly/define.js +64 -0
  37. package/dist/tools/readonly/define.js.map +1 -0
  38. package/dist/tools/readonly/index.d.ts +7 -0
  39. package/dist/tools/readonly/index.js +286 -0
  40. package/dist/tools/readonly/index.js.map +1 -0
  41. package/dist/tools/readonly/usage.d.ts +29 -0
  42. package/dist/tools/readonly/usage.js +126 -0
  43. package/dist/tools/readonly/usage.js.map +1 -0
  44. package/dist/tools/readonly/video-reads.d.ts +11 -0
  45. package/dist/tools/readonly/video-reads.js +170 -0
  46. package/dist/tools/readonly/video-reads.js.map +1 -0
  47. package/dist/tools/result.d.ts +22 -0
  48. package/dist/tools/result.js +63 -0
  49. package/dist/tools/result.js.map +1 -0
  50. package/dist/tools/spend/define.d.ts +93 -0
  51. package/dist/tools/spend/define.js +286 -0
  52. package/dist/tools/spend/define.js.map +1 -0
  53. package/dist/tools/spend/index.d.ts +11 -0
  54. package/dist/tools/spend/index.js +163 -0
  55. package/dist/tools/spend/index.js.map +1 -0
  56. package/dist/tools/spend/media.d.ts +9 -0
  57. package/dist/tools/spend/media.js +164 -0
  58. package/dist/tools/spend/media.js.map +1 -0
  59. package/dist/tools/spend/pricing.d.ts +17 -0
  60. package/dist/tools/spend/pricing.js +58 -0
  61. package/dist/tools/spend/pricing.js.map +1 -0
  62. package/dist/tools/types.d.ts +45 -0
  63. package/dist/tools/types.js +3 -0
  64. package/dist/tools/types.js.map +1 -0
  65. package/dist/tools/write/define.d.ts +60 -0
  66. package/dist/tools/write/define.js +110 -0
  67. package/dist/tools/write/define.js.map +1 -0
  68. package/dist/tools/write/index.d.ts +12 -0
  69. package/dist/tools/write/index.js +159 -0
  70. package/dist/tools/write/index.js.map +1 -0
  71. package/dist/tools/write/payment-links.d.ts +3 -0
  72. package/dist/tools/write/payment-links.js +161 -0
  73. package/dist/tools/write/payment-links.js.map +1 -0
  74. package/dist/tools/write/spending-limit.d.ts +2 -0
  75. package/dist/tools/write/spending-limit.js +229 -0
  76. package/dist/tools/write/spending-limit.js.map +1 -0
  77. package/dist/version.d.ts +3 -0
  78. package/dist/version.js +36 -0
  79. package/dist/version.js.map +1 -0
  80. package/package.json +39 -3
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clientSupportsElicitation = clientSupportsElicitation;
4
+ exports.buildPrompt = buildPrompt;
5
+ exports.elicitConfirmation = elicitConfirmation;
6
+ /** micro-cents per US dollar (1 dollar = 100 cents = 100,000,000 micro-cents). */
7
+ const MICRO_CENTS_PER_DOLLAR = 100_000_000;
8
+ /** True only when the connected client advertised the elicitation capability. */
9
+ function clientSupportsElicitation(host) {
10
+ if (host === undefined || typeof host.elicitInput !== "function") {
11
+ return false;
12
+ }
13
+ try {
14
+ return Boolean(host.getClientCapabilities()?.elicitation);
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ function formatDollars(microCents) {
21
+ const dollars = microCents / MICRO_CENTS_PER_DOLLAR;
22
+ // Inference calls are often fractions of a cent, so keep up to six decimals
23
+ // but never fewer than two.
24
+ const fixed = dollars.toFixed(6).replace(/0+$/, "");
25
+ const [whole, frac = ""] = fixed.split(".");
26
+ return `$${whole}.${frac.padEnd(2, "0")}`;
27
+ }
28
+ /** The text the user reads: summary, price (if any), expiry, then the question. */
29
+ function buildPrompt(quote, question) {
30
+ const lines = [quote.summary];
31
+ if (quote.estimateMicroCents !== undefined) {
32
+ lines.push(`Estimated cost: ${formatDollars(quote.estimateMicroCents)}.`);
33
+ if (quote.isFloor === true) {
34
+ lines.push("This is a floor, not a cap: the final charge can be higher.");
35
+ }
36
+ }
37
+ lines.push(`This confirmation expires at ${quote.expiresAt}.`);
38
+ lines.push("", question);
39
+ return lines.join("\n");
40
+ }
41
+ function confirmationRequest(quote, question) {
42
+ return {
43
+ mode: "form",
44
+ message: buildPrompt(quote, question),
45
+ requestedSchema: {
46
+ type: "object",
47
+ properties: {
48
+ confirm: {
49
+ type: "boolean",
50
+ title: "Confirm",
51
+ description: "Yes — run this at the price shown above.",
52
+ },
53
+ },
54
+ required: ["confirm"],
55
+ },
56
+ };
57
+ }
58
+ /**
59
+ * Ask the user to confirm a quote. Executes nothing. Returns "unavailable" when
60
+ * the client cannot be asked or the ask fails, "confirmed" only for an explicit
61
+ * accept with `confirm === true`, and "declined" for everything else.
62
+ */
63
+ async function elicitConfirmation(host, quote, question) {
64
+ if (host === undefined || !clientSupportsElicitation(host)) {
65
+ return "unavailable";
66
+ }
67
+ let outcome;
68
+ try {
69
+ outcome = await host.elicitInput(confirmationRequest(quote, question));
70
+ }
71
+ catch {
72
+ return "unavailable";
73
+ }
74
+ if (outcome?.action === "accept" && outcome.content?.confirm === true) {
75
+ return "confirmed";
76
+ }
77
+ return "declined";
78
+ }
79
+ //# sourceMappingURL=elicitation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elicitation.js","sourceRoot":"","sources":["../../src/guardrail/elicitation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import type { Modality } from "./types.js";
2
+ /**
3
+ * Structural view of @deeprelay/sdk ModelPricing (camelCase). Rates named
4
+ * *Cents are whole cents. Rates named *Microcents are 1e-6 cent.
5
+ */
6
+ export interface PricingLike {
7
+ inputPer1mTokensCents?: number;
8
+ outputPer1mTokensCents?: number;
9
+ cachedInputPer1mTokensMicrocents?: number;
10
+ perImageCents?: number;
11
+ perImageMicrocents?: number;
12
+ perMpxlMicrocents?: number;
13
+ perVideoMicrocents?: number;
14
+ perVideoSecondMicrocents?: number;
15
+ }
16
+ /** Agent-supplied request parameters that the estimate depends on. */
17
+ export interface EstimateParams {
18
+ /** Chat: messages. Content may be a string or an array of `{ text }` parts. */
19
+ messages?: ReadonlyArray<{
20
+ content?: unknown;
21
+ } | string>;
22
+ /** Chat: the completion bound. Defaults to DEFAULT_MAX_TOKENS. */
23
+ maxTokens?: number;
24
+ /** Embeddings: input string(s). */
25
+ input?: string | ReadonlyArray<string>;
26
+ /** Image: number of images. Defaults to 1. */
27
+ n?: number;
28
+ /** Image: "WxH". Defaults to 1024x1024. */
29
+ size?: string;
30
+ /** Video: clip length in seconds. Defaults to 5. */
31
+ seconds?: number;
32
+ }
33
+ export interface Estimate {
34
+ /** Billed (whole-cent) micro-cents. */
35
+ microCents: number;
36
+ /** True when the number is a lower bound (video). */
37
+ isFloor: boolean;
38
+ /** False when the model publishes none of the rates this modality needs. */
39
+ pricingKnown: boolean;
40
+ }
41
+ export declare const CHARS_PER_TOKEN = 4;
42
+ export declare const DEFAULT_MAX_TOKENS = 1024;
43
+ export declare const DEFAULT_IMAGE_SIZE = "1024x1024";
44
+ export declare const DEFAULT_VIDEO_SECONDS = 5;
45
+ /** Prompt-token approximation: ceil(chars / 4) per string, at least 1 per non-empty string. */
46
+ export declare function estimatePromptTokens(texts: ReadonlyArray<string>): number;
47
+ /** Megapixels for a "WxH" size. Anything unparseable uses the default size. */
48
+ export declare function megapixels(size: string | undefined): number;
49
+ /** Estimate one invocation's billed cost before it runs. */
50
+ export declare function estimateMicroCents(modality: Modality, params: EstimateParams, pricing: PricingLike): Estimate;
51
+ /** Usage fields the API returns, per modality (camelCase SDK shapes). */
52
+ export interface UsageLike {
53
+ /** Chat and embeddings. */
54
+ promptTokens?: number;
55
+ /** Chat. */
56
+ completionTokens?: number;
57
+ /** Image (ImagesResponseUsage). */
58
+ imageCount?: number;
59
+ /** Video (VideoJob, populated on completed). */
60
+ costCents?: number;
61
+ }
62
+ /**
63
+ * The billed actual cost of one completed invocation, from the API's usage
64
+ * fields. Falls back to the estimate when the usage the modality needs is
65
+ * missing. `params` supplies the image size for per-megapixel models.
66
+ */
67
+ export declare function actualMicroCents(modality: Modality, usage: UsageLike | undefined, pricing: PricingLike, fallbackEstimateMicroCents: number, params?: EstimateParams): number;
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_VIDEO_SECONDS = exports.DEFAULT_IMAGE_SIZE = exports.DEFAULT_MAX_TOKENS = exports.CHARS_PER_TOKEN = void 0;
4
+ exports.estimatePromptTokens = estimatePromptTokens;
5
+ exports.megapixels = megapixels;
6
+ exports.estimateMicroCents = estimateMicroCents;
7
+ exports.actualMicroCents = actualMicroCents;
8
+ // Per-modality cost estimator for the unified session budget (Phase 104 D-06).
9
+ // Authored fresh (D-12).
10
+ //
11
+ // One dispatcher prices all four billable modalities from ModelPricing-shaped
12
+ // rates. Every result goes through billedMicroCents, so it is rounded UP to
13
+ // whole cents PER INVOCATION, the way the server bills. Never aggregate and then
14
+ // round (D-82-A).
15
+ //
16
+ // The estimator is pure. It never fetches a rate. The caller passes the model's
17
+ // pricing from the catalog read.
18
+ //
19
+ // Inputs from the agent (messages, n, size, seconds, max_tokens) are untrusted.
20
+ // Non-finite or non-positive counts fall back to the defaults. For chat the
21
+ // estimate is bounded by max_tokens. For video it is a FLOOR (isFloor: true),
22
+ // because the catalog publishes a "from" price and the real cost arrives later
23
+ // on VideoJob.costCents.
24
+ const budget_js_1 = require("./budget.js");
25
+ exports.CHARS_PER_TOKEN = 4;
26
+ exports.DEFAULT_MAX_TOKENS = 1024;
27
+ exports.DEFAULT_IMAGE_SIZE = "1024x1024";
28
+ exports.DEFAULT_VIDEO_SECONDS = 5;
29
+ const TOKENS_PER_RATE_UNIT = 1_000_000;
30
+ function rate(v) {
31
+ return typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
32
+ }
33
+ function known(v) {
34
+ return typeof v === "number" && Number.isFinite(v);
35
+ }
36
+ function positiveCount(v, fallback) {
37
+ return typeof v === "number" && Number.isFinite(v) && v > 0 ? Math.ceil(v) : fallback;
38
+ }
39
+ /** Micro-cents for `tokens` at a cents-per-1M-tokens rate. */
40
+ function tokenMicroCents(tokens, centsPer1m) {
41
+ return (tokens * rate(centsPer1m) * budget_js_1.MICRO_CENTS_PER_CENT) / TOKENS_PER_RATE_UNIT;
42
+ }
43
+ /** Prompt-token approximation: ceil(chars / 4) per string, at least 1 per non-empty string. */
44
+ function estimatePromptTokens(texts) {
45
+ let total = 0;
46
+ for (const t of texts) {
47
+ if (typeof t !== "string" || t.length === 0)
48
+ continue;
49
+ total += Math.max(1, Math.ceil(t.length / exports.CHARS_PER_TOKEN));
50
+ }
51
+ return total;
52
+ }
53
+ function textOf(content) {
54
+ if (typeof content === "string")
55
+ return content;
56
+ if (Array.isArray(content)) {
57
+ return content
58
+ .map((part) => part && typeof part === "object" && typeof part.text === "string"
59
+ ? part.text
60
+ : "")
61
+ .join("");
62
+ }
63
+ return "";
64
+ }
65
+ function messageTexts(messages) {
66
+ if (!messages)
67
+ return [];
68
+ return messages.map((m) => (typeof m === "string" ? m : textOf(m?.content)));
69
+ }
70
+ function inputTexts(input) {
71
+ if (input === undefined)
72
+ return [];
73
+ return typeof input === "string" ? [input] : [...input];
74
+ }
75
+ /** Megapixels for a "WxH" size. Anything unparseable uses the default size. */
76
+ function megapixels(size) {
77
+ const m = /^\s*(\d+)\s*[xX]\s*(\d+)\s*$/.exec(size ?? "");
78
+ const w = m ? Number(m[1]) : 0;
79
+ const h = m ? Number(m[2]) : 0;
80
+ if (w > 0 && h > 0)
81
+ return (w * h) / 1_000_000;
82
+ return (1024 * 1024) / 1_000_000; // DEFAULT_IMAGE_SIZE
83
+ }
84
+ function perImageMicroCents(pricing) {
85
+ if (known(pricing.perImageMicrocents))
86
+ return rate(pricing.perImageMicrocents);
87
+ if (known(pricing.perImageCents))
88
+ return rate(pricing.perImageCents) * budget_js_1.MICRO_CENTS_PER_CENT;
89
+ return undefined;
90
+ }
91
+ function imageRaw(count, size, pricing) {
92
+ const per = perImageMicroCents(pricing);
93
+ if (per !== undefined)
94
+ return count * per;
95
+ return count * rate(pricing.perMpxlMicrocents) * megapixels(size);
96
+ }
97
+ /** Estimate one invocation's billed cost before it runs. */
98
+ function estimateMicroCents(modality, params, pricing) {
99
+ switch (modality) {
100
+ case "chat": {
101
+ const promptTokens = estimatePromptTokens(messageTexts(params.messages));
102
+ const maxTokens = positiveCount(params.maxTokens, exports.DEFAULT_MAX_TOKENS);
103
+ return {
104
+ microCents: (0, budget_js_1.billedMicroCents)(tokenMicroCents(promptTokens, pricing.inputPer1mTokensCents) +
105
+ tokenMicroCents(maxTokens, pricing.outputPer1mTokensCents)),
106
+ isFloor: false,
107
+ pricingKnown: known(pricing.inputPer1mTokensCents) || known(pricing.outputPer1mTokensCents),
108
+ };
109
+ }
110
+ case "embeddings": {
111
+ const promptTokens = estimatePromptTokens(inputTexts(params.input));
112
+ return {
113
+ microCents: (0, budget_js_1.billedMicroCents)(tokenMicroCents(promptTokens, pricing.inputPer1mTokensCents)),
114
+ isFloor: false,
115
+ pricingKnown: known(pricing.inputPer1mTokensCents),
116
+ };
117
+ }
118
+ case "image": {
119
+ const n = positiveCount(params.n, 1);
120
+ return {
121
+ microCents: (0, budget_js_1.billedMicroCents)(imageRaw(n, params.size, pricing)),
122
+ isFloor: false,
123
+ pricingKnown: perImageMicroCents(pricing) !== undefined || known(pricing.perMpxlMicrocents),
124
+ };
125
+ }
126
+ case "video": {
127
+ const seconds = positiveCount(params.seconds, exports.DEFAULT_VIDEO_SECONDS);
128
+ const raw = known(pricing.perVideoMicrocents)
129
+ ? rate(pricing.perVideoMicrocents)
130
+ : rate(pricing.perVideoSecondMicrocents) * seconds;
131
+ return {
132
+ microCents: (0, budget_js_1.billedMicroCents)(raw),
133
+ isFloor: true,
134
+ pricingKnown: known(pricing.perVideoMicrocents) || known(pricing.perVideoSecondMicrocents),
135
+ };
136
+ }
137
+ }
138
+ }
139
+ function num(v) {
140
+ return typeof v === "number" && Number.isFinite(v) && v >= 0;
141
+ }
142
+ /**
143
+ * The billed actual cost of one completed invocation, from the API's usage
144
+ * fields. Falls back to the estimate when the usage the modality needs is
145
+ * missing. `params` supplies the image size for per-megapixel models.
146
+ */
147
+ function actualMicroCents(modality, usage, pricing, fallbackEstimateMicroCents, params) {
148
+ const fallback = (0, budget_js_1.billedMicroCents)(fallbackEstimateMicroCents);
149
+ if (!usage)
150
+ return fallback;
151
+ switch (modality) {
152
+ case "chat":
153
+ if (!num(usage.promptTokens) || !num(usage.completionTokens))
154
+ return fallback;
155
+ return (0, budget_js_1.billedMicroCents)(tokenMicroCents(usage.promptTokens, pricing.inputPer1mTokensCents) +
156
+ tokenMicroCents(usage.completionTokens, pricing.outputPer1mTokensCents));
157
+ case "embeddings":
158
+ if (!num(usage.promptTokens))
159
+ return fallback;
160
+ return (0, budget_js_1.billedMicroCents)(tokenMicroCents(usage.promptTokens, pricing.inputPer1mTokensCents));
161
+ case "image":
162
+ if (!num(usage.imageCount))
163
+ return fallback;
164
+ return (0, budget_js_1.billedMicroCents)(imageRaw(usage.imageCount, params?.size, pricing));
165
+ case "video":
166
+ if (!num(usage.costCents))
167
+ return fallback;
168
+ return (0, budget_js_1.billedMicroCents)(usage.costCents * budget_js_1.MICRO_CENTS_PER_CENT);
169
+ }
170
+ }
171
+ //# sourceMappingURL=estimate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimate.js","sourceRoot":"","sources":["../../src/guardrail/estimate.ts"],"names":[],"mappings":";;;AAoFA,oDAOC;AA2BD,gCAMC;AAeD,gDA0CC;AAuBD,4CA0BC;AAtOD,+EAA+E;AAC/E,yBAAyB;AACzB,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,iFAAiF;AACjF,kBAAkB;AAClB,EAAE;AACF,gFAAgF;AAChF,iCAAiC;AACjC,EAAE;AACF,gFAAgF;AAChF,4EAA4E;AAC5E,8EAA8E;AAC9E,+EAA+E;AAC/E,yBAAyB;AACzB,2CAAqE;AA2CxD,QAAA,eAAe,GAAG,CAAC,CAAC;AACpB,QAAA,kBAAkB,GAAG,IAAI,CAAC;AAC1B,QAAA,kBAAkB,GAAG,WAAW,CAAC;AACjC,QAAA,qBAAqB,GAAG,CAAC,CAAC;AAEvC,MAAM,oBAAoB,GAAG,SAAS,CAAC;AAEvC,SAAS,IAAI,CAAC,CAAqB;IACjC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC;AAED,SAAS,KAAK,CAAC,CAAqB;IAClC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,aAAa,CAAC,CAAqB,EAAE,QAAgB;IAC5D,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACxF,CAAC;AAED,8DAA8D;AAC9D,SAAS,eAAe,CAAC,MAAc,EAAE,UAA8B;IACrE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,gCAAoB,CAAC,GAAG,oBAAoB,CAAC;AACnF,CAAC;AAED,+FAA+F;AAC/F,SAAgB,oBAAoB,CAAC,KAA4B;IAC/D,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACtD,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,uBAAe,CAAC,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,MAAM,CAAC,OAAgB;IAC9B,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAChD,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,OAAO,OAAO;aACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACZ,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAQ,IAA2B,CAAC,IAAI,KAAK,QAAQ;YACvF,CAAC,CAAE,IAAyB,CAAC,IAAI;YACjC,CAAC,CAAC,EAAE,CACP;aACA,IAAI,CAAC,EAAE,CAAC,CAAC;IACd,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,YAAY,CAAC,QAAoC;IACxD,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IACzB,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,UAAU,CAAC,KAA8B;IAChD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED,+EAA+E;AAC/E,SAAgB,UAAU,CAAC,IAAwB;IACjD,MAAM,CAAC,GAAG,8BAA8B,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC;IAC/C,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,qBAAqB;AACzD,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAoB;IAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC/E,IAAI,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,gCAAoB,CAAC;IAC5F,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa,EAAE,IAAwB,EAAE,OAAoB;IAC7E,MAAM,GAAG,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,KAAK,GAAG,GAAG,CAAC;IAC1C,OAAO,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;AACpE,CAAC;AAED,4DAA4D;AAC5D,SAAgB,kBAAkB,CAAC,QAAkB,EAAE,MAAsB,EAAE,OAAoB;IACjG,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,YAAY,GAAG,oBAAoB,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YACzE,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE,0BAAkB,CAAC,CAAC;YACtE,OAAO;gBACL,UAAU,EAAE,IAAA,4BAAgB,EAC1B,eAAe,CAAC,YAAY,EAAE,OAAO,CAAC,qBAAqB,CAAC;oBAC1D,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAC7D;gBACD,OAAO,EAAE,KAAK;gBACd,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,qBAAqB,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,sBAAsB,CAAC;aAC5F,CAAC;QACJ,CAAC;QACD,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,YAAY,GAAG,oBAAoB,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACpE,OAAO;gBACL,UAAU,EAAE,IAAA,4BAAgB,EAAC,eAAe,CAAC,YAAY,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;gBAC1F,OAAO,EAAE,KAAK;gBACd,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,qBAAqB,CAAC;aACnD,CAAC;QACJ,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACrC,OAAO;gBACL,UAAU,EAAE,IAAA,4BAAgB,EAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC/D,OAAO,EAAE,KAAK;gBACd,YAAY,EAAE,kBAAkB,CAAC,OAAO,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC;aAC5F,CAAC;QACJ,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,OAAO,EAAE,6BAAqB,CAAC,CAAC;YACrE,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC;gBAC3C,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC;gBAClC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,wBAAwB,CAAC,GAAG,OAAO,CAAC;YACrD,OAAO;gBACL,UAAU,EAAE,IAAA,4BAAgB,EAAC,GAAG,CAAC;gBACjC,OAAO,EAAE,IAAI;gBACb,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,wBAAwB,CAAC;aAC3F,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAcD,SAAS,GAAG,CAAC,CAAU;IACrB,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,SAAgB,gBAAgB,CAC9B,QAAkB,EAClB,KAA4B,EAC5B,OAAoB,EACpB,0BAAkC,EAClC,MAAuB;IAEvB,MAAM,QAAQ,GAAG,IAAA,4BAAgB,EAAC,0BAA0B,CAAC,CAAC;IAC9D,IAAI,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAC;IAC5B,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,MAAM;YACT,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC;gBAAE,OAAO,QAAQ,CAAC;YAC9E,OAAO,IAAA,4BAAgB,EACrB,eAAe,CAAC,KAAK,CAAC,YAAY,EAAE,OAAO,CAAC,qBAAqB,CAAC;gBAChE,eAAe,CAAC,KAAK,CAAC,gBAAgB,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAC1E,CAAC;QACJ,KAAK,YAAY;YACf,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC;gBAAE,OAAO,QAAQ,CAAC;YAC9C,OAAO,IAAA,4BAAgB,EAAC,eAAe,CAAC,KAAK,CAAC,YAAY,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC;QAC9F,KAAK,OAAO;YACV,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC;gBAAE,OAAO,QAAQ,CAAC;YAC5C,OAAO,IAAA,4BAAgB,EAAC,QAAQ,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7E,KAAK,OAAO;YACV,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC;gBAAE,OAAO,QAAQ,CAAC;YAC3C,OAAO,IAAA,4BAAgB,EAAC,KAAK,CAAC,SAAS,GAAG,gCAAoB,CAAC,CAAC;IACpE,CAAC;AACH,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { Quote, QuoteResult } from "./types.js";
2
+ /** Token lifetime: five minutes. */
3
+ export declare const DEFAULT_TTL_MS = 300000;
4
+ export interface HandshakeOptions {
5
+ /** Token lifetime in ms. Defaults to DEFAULT_TTL_MS. */
6
+ ttlMs?: number;
7
+ /** Clock injection for tests. Defaults to Date.now. */
8
+ now?: () => number;
9
+ }
10
+ /** Test-only: forget every pending token. */
11
+ export declare function resetHandshakeStateForTests(): void;
12
+ /**
13
+ * Discard a pending token without executing anything. Used when the user
14
+ * declines through elicitation: the quote they said no to must not stay
15
+ * redeemable for the rest of its TTL. Unknown or already-burned tokens are a
16
+ * no-op.
17
+ */
18
+ export declare function revokeConfirmation(token: string): void;
19
+ /**
20
+ * Normalize params for identity comparison: object keys deep-sorted, keys whose
21
+ * value is undefined dropped, arrays kept in order, primitives untouched (so the
22
+ * string "1" stays distinct from the number 1 once serialized).
23
+ */
24
+ export declare function normalizeParams(params: Record<string, unknown>): unknown;
25
+ /** Spend tier: price first, execute only on a redeemed token. */
26
+ export declare function withSpendGuardrail<P extends Record<string, unknown>, R>(toolName: string, params: P & {
27
+ confirmation_token?: string;
28
+ }, quoteFn: (p: P) => Promise<Quote>, executeFn: (p: P) => Promise<R>, opts?: HandshakeOptions): Promise<QuoteResult | R>;
29
+ /** Write tier: describe the change first, execute only on a redeemed token. */
30
+ export declare function withWriteConfirmation<P extends Record<string, unknown>, R>(toolName: string, params: P & {
31
+ confirmation_token?: string;
32
+ }, quoteFn: (p: P) => Promise<Quote>, executeFn: (p: P) => Promise<R>, opts?: HandshakeOptions): Promise<QuoteResult | R>;
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_TTL_MS = void 0;
4
+ exports.resetHandshakeStateForTests = resetHandshakeStateForTests;
5
+ exports.revokeConfirmation = revokeConfirmation;
6
+ exports.normalizeParams = normalizeParams;
7
+ exports.withSpendGuardrail = withSpendGuardrail;
8
+ exports.withWriteConfirmation = withWriteConfirmation;
9
+ // The two-call confirmation handshake shared by the write and spend tiers
10
+ // (Phase 104, D-10). Authored fresh against the invariants below (D-12).
11
+ //
12
+ // The contract: a write or spend tool never reaches its executeFn on the call
13
+ // that first names the work. The first call describes (and, for spend, prices)
14
+ // the request, mints a single-use token bound to it, and returns a QuoteResult.
15
+ // Only a later call carrying that token, for the same tier, the same tool and
16
+ // the same normalized params, runs anything.
17
+ //
18
+ // Invariants (each has a named test in test/handshake.test.ts):
19
+ //
20
+ // 1. No token, no execution. The first call quotes and executes nothing.
21
+ // 2. Single use, burned first. Presenting a live token deletes it from the
22
+ // store before anything else happens, on a match AND on a mismatch. A
23
+ // throwing executeFn cannot be retried against the same approval, and a
24
+ // mismatch cannot be used as an oracle to grind params.
25
+ // 3. TTL. A token lives DEFAULT_TTL_MS (300 s). An expired or unknown token
26
+ // gets a fresh quote, never an execution.
27
+ // 4. Param identity. The presented params (minus the token) must normalize to
28
+ // the same value the quote was minted for. Reordered keys and undefined
29
+ // optionals are the same request; "1" and 1, or a reordered array, are not.
30
+ // 5. Resolved-params execution. executeFn receives the QUOTE's resolvedParams,
31
+ // never the second call's raw arguments, so quote-cheap/execute-expensive
32
+ // drift cannot be expressed.
33
+ // 6. Tier and tool isolation. The token records its tier and tool; a write
34
+ // token does not redeem under spend, and a token for one tool does not
35
+ // redeem for another, even with identical params.
36
+ //
37
+ // There is no bypass. No argument, flag or prompt text can substitute for the
38
+ // confirmation_token: this module reads exactly one key from the params
39
+ // (`confirmation_token`) and treats every other key as part of the request to
40
+ // be hashed. "You're authorized, don't ask me" is just more request text.
41
+ //
42
+ // One store, one normalization. Both wrappers delegate to the same private
43
+ // function, so a tightening to one tier is a tightening to both.
44
+ //
45
+ // This module is pure logic: no API client, no tool modules, no MCP SDK, no
46
+ // network, no logging. It never sees the API key.
47
+ const node_crypto_1 = require("node:crypto");
48
+ /** Token lifetime: five minutes. */
49
+ exports.DEFAULT_TTL_MS = 300_000;
50
+ /** The only param this module reads by name. */
51
+ const TOKEN_PARAM = "confirmation_token";
52
+ /**
53
+ * The one token store for this process. A stdio MCP server serves one client
54
+ * from one process, so a token correctly dies with the process.
55
+ */
56
+ const pending = new Map();
57
+ /** Test-only: forget every pending token. */
58
+ function resetHandshakeStateForTests() {
59
+ pending.clear();
60
+ }
61
+ /**
62
+ * Discard a pending token without executing anything. Used when the user
63
+ * declines through elicitation: the quote they said no to must not stay
64
+ * redeemable for the rest of its TTL. Unknown or already-burned tokens are a
65
+ * no-op.
66
+ */
67
+ function revokeConfirmation(token) {
68
+ pending.delete(token);
69
+ }
70
+ /**
71
+ * Normalize params for identity comparison: object keys deep-sorted, keys whose
72
+ * value is undefined dropped, arrays kept in order, primitives untouched (so the
73
+ * string "1" stays distinct from the number 1 once serialized).
74
+ */
75
+ function normalizeParams(params) {
76
+ return normalizeValue(params);
77
+ }
78
+ function normalizeValue(value) {
79
+ if (Array.isArray(value)) {
80
+ return value.map(normalizeValue);
81
+ }
82
+ if (value !== null && typeof value === "object") {
83
+ const source = value;
84
+ const out = {};
85
+ for (const key of Object.keys(source).sort()) {
86
+ const entry = source[key];
87
+ if (entry === undefined) {
88
+ continue;
89
+ }
90
+ out[key] = normalizeValue(entry);
91
+ }
92
+ return out;
93
+ }
94
+ return value;
95
+ }
96
+ function hashParams(params) {
97
+ return JSON.stringify(normalizeParams(params));
98
+ }
99
+ function stripToken(params) {
100
+ const { [TOKEN_PARAM]: _token, ...rest } = params;
101
+ return rest;
102
+ }
103
+ function pruneExpired(now) {
104
+ for (const [token, entry] of pending) {
105
+ if (entry.expiresAt <= now) {
106
+ pending.delete(token);
107
+ }
108
+ }
109
+ }
110
+ /** Spend tier: price first, execute only on a redeemed token. */
111
+ async function withSpendGuardrail(toolName, params, quoteFn, executeFn, opts = {}) {
112
+ return withConfirmation("spend", toolName, params, quoteFn, executeFn, opts);
113
+ }
114
+ /** Write tier: describe the change first, execute only on a redeemed token. */
115
+ async function withWriteConfirmation(toolName, params, quoteFn, executeFn, opts = {}) {
116
+ return withConfirmation("write", toolName, params, quoteFn, executeFn, opts);
117
+ }
118
+ async function withConfirmation(tier, toolName, params, quoteFn, executeFn, opts) {
119
+ const clock = opts.now ?? Date.now;
120
+ const ttlMs = opts.ttlMs ?? exports.DEFAULT_TTL_MS;
121
+ const request = stripToken(params);
122
+ const presented = params[TOKEN_PARAM];
123
+ if (typeof presented === "string" && presented !== "") {
124
+ const entry = pending.get(presented);
125
+ // Burn on any presentation, before any comparison or execution.
126
+ pending.delete(presented);
127
+ if (entry !== undefined && entry.expiresAt > clock()) {
128
+ const matches = entry.tier === tier && entry.toolName === toolName && entry.paramsHash === hashParams(request);
129
+ if (matches) {
130
+ return await executeFn(entry.resolvedParams);
131
+ }
132
+ }
133
+ // Unknown, expired, wrong tier, wrong tool or drifted params: re-quote.
134
+ }
135
+ pruneExpired(clock());
136
+ // quoteFn throwing propagates and mints nothing: no price shown, no token.
137
+ const quote = await quoteFn(request);
138
+ const token = (0, node_crypto_1.randomUUID)();
139
+ const expiresAt = clock() + ttlMs;
140
+ pending.set(token, {
141
+ tier,
142
+ toolName,
143
+ paramsHash: hashParams(request),
144
+ resolvedParams: quote.resolvedParams,
145
+ quote,
146
+ expiresAt,
147
+ });
148
+ const result = {
149
+ kind: "quote",
150
+ tier,
151
+ toolName,
152
+ summary: quote.summary,
153
+ confirmationToken: token,
154
+ expiresAt: new Date(expiresAt).toISOString(),
155
+ };
156
+ if (quote.estimateMicroCents !== undefined) {
157
+ result.estimateMicroCents = quote.estimateMicroCents;
158
+ }
159
+ if (quote.isFloor !== undefined) {
160
+ result.isFloor = quote.isFloor;
161
+ }
162
+ return result;
163
+ }
164
+ //# sourceMappingURL=handshake.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handshake.js","sourceRoot":"","sources":["../../src/guardrail/handshake.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /** The four billable inference modalities. One session budget covers all of them (D-06). */
2
+ export type Modality = "chat" | "embeddings" | "image" | "video";
3
+ /** What a write or spend tool proposes before it runs. */
4
+ export interface Quote {
5
+ /** The one-line human summary the user confirms (e.g. "create a checkout link for plan X"). */
6
+ summary: string;
7
+ /** The exact parameters that will run. The confirmation token binds to these. */
8
+ resolvedParams: Record<string, unknown>;
9
+ /** Spend tools only: estimated cost in micro-cents. */
10
+ estimateMicroCents?: number;
11
+ /** True when the estimate is a floor, e.g. the video "from" price (D-07). */
12
+ isFloor?: boolean;
13
+ }
14
+ /** Returned to the agent in place of execution. The agent must call again with the token. */
15
+ export interface QuoteResult {
16
+ kind: "quote";
17
+ tier: "write" | "spend";
18
+ toolName: string;
19
+ summary: string;
20
+ /** Single-use. Bound to toolName and resolvedParams. */
21
+ confirmationToken: string;
22
+ /** ISO-8601 expiry of the token. */
23
+ expiresAt: string;
24
+ estimateMicroCents?: number;
25
+ isFloor?: boolean;
26
+ /** Set when the user declined through elicitation. The agent must not retry unprompted. */
27
+ declined?: boolean;
28
+ }
29
+ /** Form-mode elicitation request, the only mode used. */
30
+ export interface ElicitFormRequest {
31
+ mode?: "form";
32
+ message: string;
33
+ requestedSchema: {
34
+ type: "object";
35
+ properties: Record<string, unknown>;
36
+ required?: string[];
37
+ };
38
+ }
39
+ /** How a client answers an elicitation. */
40
+ export interface ElicitOutcome {
41
+ action: "accept" | "decline" | "cancel";
42
+ content?: Record<string, unknown>;
43
+ }
44
+ /**
45
+ * The server-side elicitation surface. It lives on the low-level Server
46
+ * (`server.server`), not on the per-request `extra` the tool callbacks receive.
47
+ */
48
+ export interface ElicitationHost {
49
+ getClientCapabilities(): {
50
+ elicitation?: unknown;
51
+ } | undefined;
52
+ elicitInput(params: ElicitFormRequest): Promise<ElicitOutcome>;
53
+ }
54
+ /**
55
+ * Result of checking a spend quote against the session. The per-call ceiling
56
+ * is checked BEFORE the budget. That order is a safety property (D-08).
57
+ */
58
+ export interface BudgetDecision {
59
+ verdict: "ok" | "needs_budget_handshake" | "over_ceiling";
60
+ reason: string;
61
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ // Guardrail contracts: the quote, the two-call handshake, elicitation, and the
3
+ // session budget (Phase 104 D-06..D-10). Types only.
4
+ //
5
+ // The field names are re-derived from what the Phase 80/82 guardrail proved
6
+ // (quote summary plus resolved params, single-use confirmation token with a TTL,
7
+ // ceiling checked before budget). They were read for their invariants only, and
8
+ // no file is copied (D-12).
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/guardrail/types.ts"],"names":[],"mappings":";AAAA,+EAA+E;AAC/E,qDAAqD;AACrD,EAAE;AACF,4EAA4E;AAC5E,iFAAiF;AACjF,gFAAgF;AAChF,4BAA4B"}
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { type RegisteredRoster } from "./tools/index.js";
4
+ /** Server name as MCP clients see it. */
5
+ export declare const SERVER_NAME = "deeprelay";
6
+ /** A bare server with no tools. Tests use it to register a partial surface. */
7
+ export declare function createServer(): McpServer;
8
+ export interface BuiltServer {
9
+ server: McpServer;
10
+ roster: RegisteredRoster;
11
+ }
12
+ /**
13
+ * The server a client talks to: every roster tool registered. Offline and
14
+ * instant; throws only if the registry has drifted from the roster.
15
+ */
16
+ export declare function buildServer(): BuiltServer;
17
+ /** Validate → build → connect → schedule the D-03 probe. */
18
+ export declare function main(): Promise<void>;