@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.
- package/README.md +194 -1
- package/dist/auth.d.ts +52 -0
- package/dist/auth.js +122 -0
- package/dist/auth.js.map +1 -0
- package/dist/errors.d.ts +83 -0
- package/dist/errors.js +307 -0
- package/dist/errors.js.map +1 -0
- package/dist/guardrail/budget.d.ts +95 -0
- package/dist/guardrail/budget.js +225 -0
- package/dist/guardrail/budget.js.map +1 -0
- package/dist/guardrail/elicitation.d.ts +12 -0
- package/dist/guardrail/elicitation.js +79 -0
- package/dist/guardrail/elicitation.js.map +1 -0
- package/dist/guardrail/estimate.d.ts +67 -0
- package/dist/guardrail/estimate.js +171 -0
- package/dist/guardrail/estimate.js.map +1 -0
- package/dist/guardrail/handshake.d.ts +32 -0
- package/dist/guardrail/handshake.js +164 -0
- package/dist/guardrail/handshake.js.map +1 -0
- package/dist/guardrail/types.d.ts +61 -0
- package/dist/guardrail/types.js +10 -0
- package/dist/guardrail/types.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/roster.d.ts +36 -0
- package/dist/roster.js +130 -0
- package/dist/roster.js.map +1 -0
- package/dist/tools/crypto-deposit-gate.d.ts +21 -0
- package/dist/tools/crypto-deposit-gate.js +91 -0
- package/dist/tools/crypto-deposit-gate.js.map +1 -0
- package/dist/tools/index.d.ts +16 -0
- package/dist/tools/index.js +108 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/readonly/define.d.ts +32 -0
- package/dist/tools/readonly/define.js +64 -0
- package/dist/tools/readonly/define.js.map +1 -0
- package/dist/tools/readonly/index.d.ts +7 -0
- package/dist/tools/readonly/index.js +286 -0
- package/dist/tools/readonly/index.js.map +1 -0
- package/dist/tools/readonly/usage.d.ts +29 -0
- package/dist/tools/readonly/usage.js +126 -0
- package/dist/tools/readonly/usage.js.map +1 -0
- package/dist/tools/readonly/video-reads.d.ts +11 -0
- package/dist/tools/readonly/video-reads.js +170 -0
- package/dist/tools/readonly/video-reads.js.map +1 -0
- package/dist/tools/result.d.ts +22 -0
- package/dist/tools/result.js +63 -0
- package/dist/tools/result.js.map +1 -0
- package/dist/tools/spend/define.d.ts +93 -0
- package/dist/tools/spend/define.js +286 -0
- package/dist/tools/spend/define.js.map +1 -0
- package/dist/tools/spend/index.d.ts +11 -0
- package/dist/tools/spend/index.js +163 -0
- package/dist/tools/spend/index.js.map +1 -0
- package/dist/tools/spend/media.d.ts +9 -0
- package/dist/tools/spend/media.js +164 -0
- package/dist/tools/spend/media.js.map +1 -0
- package/dist/tools/spend/pricing.d.ts +17 -0
- package/dist/tools/spend/pricing.js +58 -0
- package/dist/tools/spend/pricing.js.map +1 -0
- package/dist/tools/types.d.ts +45 -0
- package/dist/tools/types.js +3 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/write/define.d.ts +60 -0
- package/dist/tools/write/define.js +110 -0
- package/dist/tools/write/define.js.map +1 -0
- package/dist/tools/write/index.d.ts +12 -0
- package/dist/tools/write/index.js +159 -0
- package/dist/tools/write/index.js.map +1 -0
- package/dist/tools/write/payment-links.d.ts +3 -0
- package/dist/tools/write/payment-links.js +161 -0
- package/dist/tools/write/payment-links.js.map +1 -0
- package/dist/tools/write/spending-limit.d.ts +2 -0
- package/dist/tools/write/spending-limit.js +229 -0
- package/dist/tools/write/spending-limit.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.js +36 -0
- package/dist/version.js.map +1 -0
- package/package.json +39 -3
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mediaSpendTools = exports.spendTools = exports.EMBEDDINGS_MAX_INPUTS = exports.CHAT_MAX_TOKENS_LIMIT = exports.SPEND_TIER_SENTENCE = exports.SPEND_CONFIRMATION_SHAPE = exports.runWithBudget = exports.defineSpendTool = exports.confirmThenExecute = void 0;
|
|
4
|
+
// The spend tier: billable inference (Phase 104, D-02/D-06/D-07/D-08/D-10).
|
|
5
|
+
//
|
|
6
|
+
// Four tools, one session budget. Chat and embeddings are defined here; image
|
|
7
|
+
// generation and video create live in media.ts. Every one is built by
|
|
8
|
+
// defineSpendTool (define.ts), so pricing, the ceiling → approval → wall →
|
|
9
|
+
// headroom order and the confirmation handshake belong to the tier.
|
|
10
|
+
//
|
|
11
|
+
// Chat and embeddings settle synchronously: reserve the estimate, make the
|
|
12
|
+
// call, reconcile at the actual cost from the response's usage, or release the
|
|
13
|
+
// reservation if the call throws. They send no Idempotency-Key: the API does
|
|
14
|
+
// not accept one on these routes (RESEARCH Pitfall 3).
|
|
15
|
+
//
|
|
16
|
+
// The chat schema deliberately has no `tools` / `response_format`: the API
|
|
17
|
+
// passthrough for them has not landed (CONTEXT, Claude's Discretion), and
|
|
18
|
+
// `stream` is not an argument: the tool always sends stream: false, because an
|
|
19
|
+
// MCP tool result is one message.
|
|
20
|
+
const sdk_1 = require("@deeprelay/sdk");
|
|
21
|
+
const zod_1 = require("zod");
|
|
22
|
+
const budget_js_1 = require("../../guardrail/budget.js");
|
|
23
|
+
const estimate_js_1 = require("../../guardrail/estimate.js");
|
|
24
|
+
const define_js_1 = require("./define.js");
|
|
25
|
+
const media_js_1 = require("./media.js");
|
|
26
|
+
Object.defineProperty(exports, "mediaSpendTools", { enumerable: true, get: function () { return media_js_1.mediaSpendTools; } });
|
|
27
|
+
var define_js_2 = require("./define.js");
|
|
28
|
+
Object.defineProperty(exports, "confirmThenExecute", { enumerable: true, get: function () { return define_js_2.confirmThenExecute; } });
|
|
29
|
+
Object.defineProperty(exports, "defineSpendTool", { enumerable: true, get: function () { return define_js_2.defineSpendTool; } });
|
|
30
|
+
Object.defineProperty(exports, "runWithBudget", { enumerable: true, get: function () { return define_js_2.runWithBudget; } });
|
|
31
|
+
Object.defineProperty(exports, "SPEND_CONFIRMATION_SHAPE", { enumerable: true, get: function () { return define_js_2.SPEND_CONFIRMATION_SHAPE; } });
|
|
32
|
+
Object.defineProperty(exports, "SPEND_TIER_SENTENCE", { enumerable: true, get: function () { return define_js_2.SPEND_TIER_SENTENCE; } });
|
|
33
|
+
/** Upper bound on max_tokens for one chat call. */
|
|
34
|
+
exports.CHAT_MAX_TOKENS_LIMIT = 8192;
|
|
35
|
+
const chatCompletion = (0, define_js_1.defineSpendTool)({
|
|
36
|
+
name: "deeprelay_chat_completion",
|
|
37
|
+
title: "Chat completion",
|
|
38
|
+
description: "Run one chat completion on a deeprelay chat model and return the assistant's reply, token usage and cost. " +
|
|
39
|
+
"Priced per token from the model's catalog rates: the quote bounds the cost by max_tokens (default " +
|
|
40
|
+
`${estimate_js_1.DEFAULT_MAX_TOKENS}), and the session budget settles at the actual usage. Use deeprelay_models_list ` +
|
|
41
|
+
"(modality chat) to find a model id. Returns one complete message; streaming is not offered.",
|
|
42
|
+
inputSchema: {
|
|
43
|
+
model: zod_1.z.string().min(1).describe("A chat model id from deeprelay_models_list."),
|
|
44
|
+
messages: zod_1.z
|
|
45
|
+
.array(zod_1.z.strictObject({
|
|
46
|
+
role: zod_1.z.enum(["system", "user", "assistant"]),
|
|
47
|
+
content: zod_1.z.string(),
|
|
48
|
+
}))
|
|
49
|
+
.min(1)
|
|
50
|
+
.describe("The conversation so far, oldest first."),
|
|
51
|
+
max_tokens: zod_1.z
|
|
52
|
+
.number()
|
|
53
|
+
.int()
|
|
54
|
+
.min(1)
|
|
55
|
+
.max(exports.CHAT_MAX_TOKENS_LIMIT)
|
|
56
|
+
.default(estimate_js_1.DEFAULT_MAX_TOKENS)
|
|
57
|
+
.describe(`Upper bound on generated tokens (1–${exports.CHAT_MAX_TOKENS_LIMIT}, default ${estimate_js_1.DEFAULT_MAX_TOKENS}). It also bounds the quote.`),
|
|
58
|
+
temperature: zod_1.z.number().min(0).max(2).optional().describe("Sampling temperature, 0–2."),
|
|
59
|
+
},
|
|
60
|
+
modality: "chat",
|
|
61
|
+
question: "Run this chat completion at the price shown?",
|
|
62
|
+
context: "running a chat completion",
|
|
63
|
+
describe: (a) => `Chat completion on ${a.model}: ${a.messages.length} message(s), up to ${a.max_tokens} output tokens`,
|
|
64
|
+
async execute(a, run) {
|
|
65
|
+
(0, budget_js_1.recordEstimate)(run.callId, run.estimate.microCents);
|
|
66
|
+
let res;
|
|
67
|
+
let actual;
|
|
68
|
+
try {
|
|
69
|
+
res = await new sdk_1.InferenceApi(run.config).createChatCompletion({
|
|
70
|
+
chatCompletionRequest: {
|
|
71
|
+
model: a.model,
|
|
72
|
+
messages: a.messages,
|
|
73
|
+
temperature: a.temperature,
|
|
74
|
+
maxTokens: a.max_tokens,
|
|
75
|
+
stream: false,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
actual = (0, estimate_js_1.actualMicroCents)("chat", res.usage, run.rates, run.estimate.microCents);
|
|
79
|
+
(0, budget_js_1.reconcileActual)(run.callId, actual);
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
(0, budget_js_1.releaseEstimate)(run.callId);
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
const choice = res.choices?.[0];
|
|
86
|
+
return {
|
|
87
|
+
lead: `Chat completion finished (${choice?.finishReason ?? "no finish reason reported"}).`,
|
|
88
|
+
payload: {
|
|
89
|
+
model: res.model,
|
|
90
|
+
finish_reason: choice?.finishReason ?? null,
|
|
91
|
+
message: choice?.message ?? null,
|
|
92
|
+
usage: {
|
|
93
|
+
prompt_tokens: res.usage?.promptTokens,
|
|
94
|
+
completion_tokens: res.usage?.completionTokens,
|
|
95
|
+
total_tokens: res.usage?.totalTokens,
|
|
96
|
+
},
|
|
97
|
+
cost: { estimated_micro_cents: run.estimate.microCents, actual_micro_cents: actual },
|
|
98
|
+
session_budget: (0, budget_js_1.budgetStatus)(),
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
/** Upper bound on the number of inputs in one embeddings call (keeps the response bounded). */
|
|
104
|
+
exports.EMBEDDINGS_MAX_INPUTS = 64;
|
|
105
|
+
const embeddingsCreate = (0, define_js_1.defineSpendTool)({
|
|
106
|
+
name: "deeprelay_embeddings_create",
|
|
107
|
+
title: "Create embeddings",
|
|
108
|
+
description: "Embed one string or a list of up to 64 strings with a deeprelay embedding model and return the vectors, " +
|
|
109
|
+
"token usage and cost. Priced per input token from the model's catalog rate; the session budget settles at " +
|
|
110
|
+
"the actual prompt tokens. Use deeprelay_models_list (modality embedding) to find a model id.",
|
|
111
|
+
inputSchema: {
|
|
112
|
+
model: zod_1.z.string().min(1).describe("An embedding model id from deeprelay_models_list."),
|
|
113
|
+
input: zod_1.z
|
|
114
|
+
.union([
|
|
115
|
+
zod_1.z.string().min(1),
|
|
116
|
+
zod_1.z.array(zod_1.z.string().min(1)).min(1).max(exports.EMBEDDINGS_MAX_INPUTS),
|
|
117
|
+
])
|
|
118
|
+
.describe(`One non-empty string, or 1–${exports.EMBEDDINGS_MAX_INPUTS} non-empty strings.`),
|
|
119
|
+
dimensions: zod_1.z.number().int().positive().optional().describe("Output dimensions, for models that support it."),
|
|
120
|
+
encoding_format: zod_1.z.enum(["float"]).optional().describe("Only float is offered."),
|
|
121
|
+
},
|
|
122
|
+
modality: "embeddings",
|
|
123
|
+
question: "Create these embeddings at the price shown?",
|
|
124
|
+
context: "creating embeddings",
|
|
125
|
+
describe: (a) => `Embeddings on ${a.model}: ${typeof a.input === "string" ? 1 : a.input.length} input(s)`,
|
|
126
|
+
async execute(a, run) {
|
|
127
|
+
(0, budget_js_1.recordEstimate)(run.callId, run.estimate.microCents);
|
|
128
|
+
let res;
|
|
129
|
+
let actual;
|
|
130
|
+
try {
|
|
131
|
+
res = await new sdk_1.InferenceApi(run.config).createEmbeddings({
|
|
132
|
+
embeddingsRequest: {
|
|
133
|
+
model: a.model,
|
|
134
|
+
input: a.input,
|
|
135
|
+
dimensions: a.dimensions,
|
|
136
|
+
encodingFormat: a.encoding_format,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
actual = (0, estimate_js_1.actualMicroCents)("embeddings", res.usage, run.rates, run.estimate.microCents);
|
|
140
|
+
(0, budget_js_1.reconcileActual)(run.callId, actual);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
(0, budget_js_1.releaseEstimate)(run.callId);
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
const data = res.data ?? [];
|
|
147
|
+
return {
|
|
148
|
+
lead: `Created ${data.length} embedding(s).`,
|
|
149
|
+
payload: {
|
|
150
|
+
model: res.model,
|
|
151
|
+
count: data.length,
|
|
152
|
+
dimensions: data[0]?.embedding.length,
|
|
153
|
+
embeddings: data.map((e) => e.embedding),
|
|
154
|
+
usage: { prompt_tokens: res.usage?.promptTokens, total_tokens: res.usage?.totalTokens },
|
|
155
|
+
cost: { estimated_micro_cents: run.estimate.microCents, actual_micro_cents: actual },
|
|
156
|
+
session_budget: (0, budget_js_1.budgetStatus)(),
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
/** The spend tier, in SPEND_TOOLS order. */
|
|
162
|
+
exports.spendTools = [chatCompletion, embeddingsCreate, ...media_js_1.mediaSpendTools];
|
|
163
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/spend/index.ts"],"names":[],"mappings":";;;AAAA,4EAA4E;AAC5E,EAAE;AACF,8EAA8E;AAC9E,sEAAsE;AACtE,2EAA2E;AAC3E,oEAAoE;AACpE,EAAE;AACF,2EAA2E;AAC3E,+EAA+E;AAC/E,6EAA6E;AAC7E,uDAAuD;AACvD,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,+EAA+E;AAC/E,kCAAkC;AAClC,wCAA8C;AAC9C,6BAAwB;AAExB,yDAA2G;AAC3G,6DAAmF;AAEnF,2CAA8C;AAC9C,yCAA6C;AAsJpC,gGAtJA,0BAAe,OAsJA;AApJxB,yCAMqB;AALnB,+GAAA,kBAAkB,OAAA;AAClB,4GAAA,eAAe,OAAA;AACf,0GAAA,aAAa,OAAA;AACb,qHAAA,wBAAwB,OAAA;AACxB,gHAAA,mBAAmB,OAAA;AAIrB,mDAAmD;AACtC,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAE1C,MAAM,cAAc,GAAG,IAAA,2BAAe,EAAC;IACrC,IAAI,EAAE,2BAA2B;IACjC,KAAK,EAAE,iBAAiB;IACxB,WAAW,EACT,4GAA4G;QAC5G,oGAAoG;QACpG,GAAG,gCAAkB,mFAAmF;QACxG,6FAA6F;IAC/F,WAAW,EAAE;QACX,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,6CAA6C,CAAC;QAChF,QAAQ,EAAE,OAAC;aACR,KAAK,CACJ,OAAC,CAAC,YAAY,CAAC;YACb,IAAI,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;YAC7C,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;SACpB,CAAC,CACH;aACA,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,CAAC,wCAAwC,CAAC;QACrD,UAAU,EAAE,OAAC;aACV,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,6BAAqB,CAAC;aAC1B,OAAO,CAAC,gCAAkB,CAAC;aAC3B,QAAQ,CAAC,sCAAsC,6BAAqB,aAAa,gCAAkB,8BAA8B,CAAC;QACrI,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC;KACxF;IACD,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,8CAA8C;IACxD,OAAO,EAAE,2BAA2B;IACpC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CACd,sBAAsB,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,sBAAsB,CAAC,CAAC,UAAU,gBAAgB;IACvG,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG;QAClB,IAAA,0BAAc,EAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,GAAG,CAAC;QACR,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,IAAI,kBAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC;gBAC5D,qBAAqB,EAAE;oBACrB,KAAK,EAAE,CAAC,CAAC,KAAK;oBACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;oBACpB,WAAW,EAAE,CAAC,CAAC,WAAW;oBAC1B,SAAS,EAAE,CAAC,CAAC,UAAU;oBACvB,MAAM,EAAE,KAAK;iBACd;aACF,CAAC,CAAC;YACH,MAAM,GAAG,IAAA,8BAAgB,EAAC,MAAM,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;YACjF,IAAA,2BAAe,EAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAA,2BAAe,EAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC5B,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QAChC,OAAO;YACL,IAAI,EAAE,6BAA6B,MAAM,EAAE,YAAY,IAAI,2BAA2B,IAAI;YAC1F,OAAO,EAAE;gBACP,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,aAAa,EAAE,MAAM,EAAE,YAAY,IAAI,IAAI;gBAC3C,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,IAAI;gBAChC,KAAK,EAAE;oBACL,aAAa,EAAE,GAAG,CAAC,KAAK,EAAE,YAAY;oBACtC,iBAAiB,EAAE,GAAG,CAAC,KAAK,EAAE,gBAAgB;oBAC9C,YAAY,EAAE,GAAG,CAAC,KAAK,EAAE,WAAW;iBACrC;gBACD,IAAI,EAAE,EAAE,qBAAqB,EAAE,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,EAAE,MAAM,EAAE;gBACpF,cAAc,EAAE,IAAA,wBAAY,GAAE;aAC/B;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC;AAEH,+FAA+F;AAClF,QAAA,qBAAqB,GAAG,EAAE,CAAC;AAExC,MAAM,gBAAgB,GAAG,IAAA,2BAAe,EAAC;IACvC,IAAI,EAAE,6BAA6B;IACnC,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EACT,0GAA0G;QAC1G,4GAA4G;QAC5G,8FAA8F;IAChG,WAAW,EAAE;QACX,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mDAAmD,CAAC;QACtF,KAAK,EAAE,OAAC;aACL,KAAK,CAAC;YACL,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YACjB,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,6BAAqB,CAAC;SAC7D,CAAC;aACD,QAAQ,CAAC,8BAA8B,6BAAqB,qBAAqB,CAAC;QACrF,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC;QAC7G,eAAe,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;KACjF;IACD,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,6CAA6C;IACvD,OAAO,EAAE,qBAAqB;IAC9B,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CACd,iBAAiB,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,WAAW;IAC1F,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG;QAClB,IAAA,0BAAc,EAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,GAAG,CAAC;QACR,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,IAAI,kBAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC;gBACxD,iBAAiB,EAAE;oBACjB,KAAK,EAAE,CAAC,CAAC,KAAK;oBACd,KAAK,EAAE,CAAC,CAAC,KAAK;oBACd,UAAU,EAAE,CAAC,CAAC,UAAU;oBACxB,cAAc,EAAE,CAAC,CAAC,eAAe;iBAClC;aACF,CAAC,CAAC;YACH,MAAM,GAAG,IAAA,8BAAgB,EAAC,YAAY,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;YACvF,IAAA,2BAAe,EAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAA,2BAAe,EAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC5B,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;QAC5B,OAAO;YACL,IAAI,EAAE,WAAW,IAAI,CAAC,MAAM,gBAAgB;YAC5C,OAAO,EAAE;gBACP,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,KAAK,EAAE,IAAI,CAAC,MAAM;gBAClB,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM;gBACrC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;gBACxC,KAAK,EAAE,EAAE,aAAa,EAAE,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE;gBACvF,IAAI,EAAE,EAAE,qBAAqB,EAAE,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,EAAE,MAAM,EAAE;gBACpF,cAAc,EAAE,IAAA,wBAAY,GAAE;aAC/B;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC;AAEH,4CAA4C;AAC/B,QAAA,UAAU,GAAqB,CAAC,cAAc,EAAE,gBAAgB,EAAE,GAAG,0BAAe,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ToolDefinition } from "../types.js";
|
|
2
|
+
export declare const IMAGE_MAX_COUNT = 4;
|
|
3
|
+
export declare const VIDEO_MAX_SECONDS = 30;
|
|
4
|
+
/** The floor wording every video quote carries (D-07). */
|
|
5
|
+
export declare const VIDEO_FLOOR_NOTE = "This is a floor, not a cap \u2014 the final charge is known when the job completes.";
|
|
6
|
+
/** The image's MIME type from its base64 signature; PNG when unrecognized. */
|
|
7
|
+
export declare function imageMimeType(b64: string): string;
|
|
8
|
+
/** Image then video, in SPEND_TOOLS order. */
|
|
9
|
+
export declare const mediaSpendTools: ToolDefinition[];
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mediaSpendTools = exports.VIDEO_FLOOR_NOTE = exports.VIDEO_MAX_SECONDS = exports.IMAGE_MAX_COUNT = void 0;
|
|
4
|
+
exports.imageMimeType = imageMimeType;
|
|
5
|
+
// Image generation and video create: the media half of the spend tier
|
|
6
|
+
// (Phase 104, D-02/D-06/D-07). Both go through defineSpendTool, so they share
|
|
7
|
+
// the one session budget, the per-call ceiling and the confirmation handshake
|
|
8
|
+
// with chat and embeddings.
|
|
9
|
+
//
|
|
10
|
+
// Image is synchronous: reserve, generate, settle at the actual image count.
|
|
11
|
+
// Its result is native MCP image content (one block per image) followed by one
|
|
12
|
+
// text block with usage and cost. ok() only builds text, so the execute step
|
|
13
|
+
// returns a prebuilt ToolResult, which the dispatch passes through unchanged;
|
|
14
|
+
// the text block is still built by ok() (sanitized and redacted).
|
|
15
|
+
//
|
|
16
|
+
// Video is asynchronous (RESEARCH Pitfall 2). The create call returns a queued
|
|
17
|
+
// job with no cost, so this handler reserves the catalog from-price (a FLOOR)
|
|
18
|
+
// under the returned job id and does not settle anything itself. The video
|
|
19
|
+
// reads (readonly/video-reads.ts) settle the reservation when they observe the
|
|
20
|
+
// job finished: at cost_cents on completion, released on failed, cancelled or
|
|
21
|
+
// expired.
|
|
22
|
+
//
|
|
23
|
+
// Both media calls send an Idempotency-Key header (RESEARCH Pitfall 3): the
|
|
24
|
+
// confirmation token when the call was confirmed, else the per-call id, so a
|
|
25
|
+
// transport retry cannot charge twice (T-104-29).
|
|
26
|
+
const sdk_1 = require("@deeprelay/sdk");
|
|
27
|
+
const zod_1 = require("zod");
|
|
28
|
+
const budget_js_1 = require("../../guardrail/budget.js");
|
|
29
|
+
const estimate_js_1 = require("../../guardrail/estimate.js");
|
|
30
|
+
const result_js_1 = require("../result.js");
|
|
31
|
+
const define_js_1 = require("./define.js");
|
|
32
|
+
/** "WxH", e.g. 1024x1024. */
|
|
33
|
+
const SIZE_PATTERN = /^\d{2,4}x\d{2,4}$/;
|
|
34
|
+
exports.IMAGE_MAX_COUNT = 4;
|
|
35
|
+
exports.VIDEO_MAX_SECONDS = 30;
|
|
36
|
+
/** The floor wording every video quote carries (D-07). */
|
|
37
|
+
exports.VIDEO_FLOOR_NOTE = "This is a floor, not a cap — the final charge is known when the job completes.";
|
|
38
|
+
/** The image's MIME type from its base64 signature; PNG when unrecognized. */
|
|
39
|
+
function imageMimeType(b64) {
|
|
40
|
+
if (b64.startsWith("/9j/"))
|
|
41
|
+
return "image/jpeg";
|
|
42
|
+
if (b64.startsWith("UklGR"))
|
|
43
|
+
return "image/webp";
|
|
44
|
+
if (b64.startsWith("R0lGOD"))
|
|
45
|
+
return "image/gif";
|
|
46
|
+
return "image/png";
|
|
47
|
+
}
|
|
48
|
+
const imagesGenerate = (0, define_js_1.defineSpendTool)({
|
|
49
|
+
name: "deeprelay_images_generate",
|
|
50
|
+
title: "Generate images",
|
|
51
|
+
description: "Generate 1–4 images from a text prompt with a deeprelay image model and return them as image content, " +
|
|
52
|
+
"with usage and cost. Priced per image, or per megapixel of the requested size, from the model's catalog " +
|
|
53
|
+
"rate; the session budget settles at the number of images actually returned. Use deeprelay_models_list " +
|
|
54
|
+
"(modality image) to find a model id.",
|
|
55
|
+
inputSchema: {
|
|
56
|
+
model: zod_1.z.string().min(1).describe("An image model id from deeprelay_models_list."),
|
|
57
|
+
prompt: zod_1.z.string().min(1).max(4000).describe("What to draw (up to 4000 characters)."),
|
|
58
|
+
n: zod_1.z
|
|
59
|
+
.number()
|
|
60
|
+
.int()
|
|
61
|
+
.min(1)
|
|
62
|
+
.max(exports.IMAGE_MAX_COUNT)
|
|
63
|
+
.default(1)
|
|
64
|
+
.describe(`How many images (1–${exports.IMAGE_MAX_COUNT}, default 1). Each one is billed.`),
|
|
65
|
+
size: zod_1.z
|
|
66
|
+
.string()
|
|
67
|
+
.regex(SIZE_PATTERN)
|
|
68
|
+
.optional()
|
|
69
|
+
.describe("Output size as WIDTHxHEIGHT, e.g. 1024x1024. Per-megapixel models price by it."),
|
|
70
|
+
},
|
|
71
|
+
modality: "image",
|
|
72
|
+
question: "Generate these images at the price shown?",
|
|
73
|
+
context: "generating images",
|
|
74
|
+
describe: (a) => `Generate ${a.n} image(s) on ${a.model}${a.size !== undefined ? ` at ${a.size}` : ""}`,
|
|
75
|
+
async execute(a, run) {
|
|
76
|
+
(0, budget_js_1.recordEstimate)(run.callId, run.estimate.microCents);
|
|
77
|
+
let res;
|
|
78
|
+
let actual;
|
|
79
|
+
try {
|
|
80
|
+
res = await new sdk_1.InferenceApi(run.config).createImage({
|
|
81
|
+
imagesGenerationsRequest: { model: a.model, prompt: a.prompt, n: a.n, size: a.size, responseFormat: "b64_json" },
|
|
82
|
+
idempotencyKey: run.idempotencyKey,
|
|
83
|
+
});
|
|
84
|
+
actual = (0, estimate_js_1.actualMicroCents)("image", res.usage, run.rates, run.estimate.microCents, { size: a.size });
|
|
85
|
+
(0, budget_js_1.reconcileActual)(run.callId, actual);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
(0, budget_js_1.releaseEstimate)(run.callId);
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
const images = (res.data ?? [])
|
|
92
|
+
.filter((d) => typeof d.b64Json === "string" && d.b64Json !== "")
|
|
93
|
+
.map((d) => ({ type: "image", data: d.b64Json, mimeType: imageMimeType(d.b64Json) }));
|
|
94
|
+
const summary = (0, result_js_1.ok)({
|
|
95
|
+
lead: `Generated ${images.length} image(s).`,
|
|
96
|
+
model: a.model,
|
|
97
|
+
count: images.length,
|
|
98
|
+
usage: { image_count: res.usage?.imageCount },
|
|
99
|
+
cost: { estimated_micro_cents: run.estimate.microCents, actual_micro_cents: actual },
|
|
100
|
+
session_budget: (0, budget_js_1.budgetStatus)(),
|
|
101
|
+
}, { env: run.env });
|
|
102
|
+
return { content: [...images, ...summary.content] };
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
// Keep this definition last in the file: a test scans from here to the end
|
|
106
|
+
// and asserts the video path contains no settlement call.
|
|
107
|
+
const videosCreate = (0, define_js_1.defineSpendTool)({
|
|
108
|
+
name: "deeprelay_videos_create",
|
|
109
|
+
title: "Create a video",
|
|
110
|
+
description: "Start an asynchronous text-to-video job on a deeprelay video model. Priced from the catalog's per-clip " +
|
|
111
|
+
"from-price, or per second of the requested length; the quote is a floor, not a cap, and the real charge " +
|
|
112
|
+
"is known only when the job completes. The floor is held against the session budget until " +
|
|
113
|
+
"deeprelay_videos_get or deeprelay_videos_list sees the job finish, which settles it at the actual cost " +
|
|
114
|
+
"(or releases it if the job failed or was cancelled). Download a finished clip with deeprelay_videos_content.",
|
|
115
|
+
inputSchema: {
|
|
116
|
+
model: zod_1.z.string().min(1).describe("A video model id from deeprelay_models_list."),
|
|
117
|
+
prompt: zod_1.z.string().min(1).max(4000).describe("What the clip should show (up to 4000 characters)."),
|
|
118
|
+
seconds: zod_1.z
|
|
119
|
+
.number()
|
|
120
|
+
.int()
|
|
121
|
+
.min(1)
|
|
122
|
+
.max(exports.VIDEO_MAX_SECONDS)
|
|
123
|
+
.optional()
|
|
124
|
+
.describe(`Clip length in seconds (1–${exports.VIDEO_MAX_SECONDS}). Per-second models price by it.`),
|
|
125
|
+
size: zod_1.z.string().regex(SIZE_PATTERN).optional().describe("Output size as WIDTHxHEIGHT, e.g. 1280x720."),
|
|
126
|
+
},
|
|
127
|
+
modality: "video",
|
|
128
|
+
question: "Start this video job at the floor price shown?",
|
|
129
|
+
context: "creating a video job",
|
|
130
|
+
quoteNote: exports.VIDEO_FLOOR_NOTE,
|
|
131
|
+
describe: (a) => `Start a video job on ${a.model}${a.seconds !== undefined ? ` for ${a.seconds}s` : ""}${a.size !== undefined ? ` at ${a.size}` : ""}`,
|
|
132
|
+
async execute(a, run) {
|
|
133
|
+
// Hold the floor while the create call is in flight, so a parallel call
|
|
134
|
+
// cannot spend the same headroom.
|
|
135
|
+
(0, budget_js_1.recordEstimate)(run.callId, run.estimate.microCents);
|
|
136
|
+
let job;
|
|
137
|
+
try {
|
|
138
|
+
job = await new sdk_1.InferenceApi(run.config).createVideo({
|
|
139
|
+
videoCreateRequest: { model: a.model, prompt: a.prompt, seconds: a.seconds, size: a.size },
|
|
140
|
+
idempotencyKey: run.idempotencyKey,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
(0, budget_js_1.releaseEstimate)(run.callId);
|
|
145
|
+
throw err;
|
|
146
|
+
}
|
|
147
|
+
// Keyed by the real job id; a video read settles it.
|
|
148
|
+
(0, budget_js_1.registerPendingVideo)(job.id, run.callId, run.estimate.microCents);
|
|
149
|
+
return {
|
|
150
|
+
lead: `Video job ${job.id} queued. Call deeprelay_videos_get to poll; the session budget settles when it completes.`,
|
|
151
|
+
payload: {
|
|
152
|
+
video_id: job.id,
|
|
153
|
+
status: job.status,
|
|
154
|
+
model: job.model ?? a.model,
|
|
155
|
+
seconds: job.seconds ?? a.seconds ?? null,
|
|
156
|
+
floor_micro_cents: run.estimate.microCents,
|
|
157
|
+
session_budget: (0, budget_js_1.budgetStatus)(),
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
/** Image then video, in SPEND_TOOLS order. */
|
|
163
|
+
exports.mediaSpendTools = [imagesGenerate, videosCreate];
|
|
164
|
+
//# sourceMappingURL=media.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../../src/tools/spend/media.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Configuration, type ModelModalityEnum } from "@deeprelay/sdk";
|
|
2
|
+
import type { PricingLike } from "../../guardrail/estimate.js";
|
|
3
|
+
/** How long one model's rates are reused before the catalog is read again. */
|
|
4
|
+
export declare const RATE_CACHE_TTL_MS: number;
|
|
5
|
+
/** A model's rates plus the two catalog facts the spend tier checks against. */
|
|
6
|
+
export interface ModelRates extends PricingLike {
|
|
7
|
+
modelId: string;
|
|
8
|
+
/** The catalog modality (chat | embedding | image | video), when published. */
|
|
9
|
+
modality?: ModelModalityEnum;
|
|
10
|
+
}
|
|
11
|
+
/** Test-only: forget every cached rate. */
|
|
12
|
+
export declare function resetPricingCacheForTests(): void;
|
|
13
|
+
/**
|
|
14
|
+
* The model's current rates. The cache is keyed by base URL as well as model
|
|
15
|
+
* id, so a demo override and production never share an entry.
|
|
16
|
+
*/
|
|
17
|
+
export declare function ratesFor(config: Configuration, modelId: string, now?: () => number): Promise<ModelRates>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RATE_CACHE_TTL_MS = void 0;
|
|
4
|
+
exports.resetPricingCacheForTests = resetPricingCacheForTests;
|
|
5
|
+
exports.ratesFor = ratesFor;
|
|
6
|
+
// Catalog rates for the spend tier (Phase 104, D-06). Authored fresh (D-12).
|
|
7
|
+
//
|
|
8
|
+
// Every spend quote prices the call from the model's own catalog entry
|
|
9
|
+
// (InferenceApi.getModel), never from a hard-coded table, so a price change on
|
|
10
|
+
// the platform reaches the next quote without a release. The result is cached
|
|
11
|
+
// per process for RATE_CACHE_TTL_MS: a quote followed by its confirming call a
|
|
12
|
+
// few seconds later should not fetch the catalog twice, and a stale rate lasts
|
|
13
|
+
// at most ten minutes.
|
|
14
|
+
//
|
|
15
|
+
// An unknown model is not handled here: the SDK's 404 propagates to the tool's
|
|
16
|
+
// error funnel (errors.ts), which names it as "not found" without a quote and
|
|
17
|
+
// without minting a token.
|
|
18
|
+
const sdk_1 = require("@deeprelay/sdk");
|
|
19
|
+
const budget_js_1 = require("../../guardrail/budget.js");
|
|
20
|
+
/** How long one model's rates are reused before the catalog is read again. */
|
|
21
|
+
exports.RATE_CACHE_TTL_MS = 10 * 60 * 1000;
|
|
22
|
+
const cache = new Map();
|
|
23
|
+
/** Test-only: forget every cached rate. */
|
|
24
|
+
function resetPricingCacheForTests() {
|
|
25
|
+
cache.clear();
|
|
26
|
+
}
|
|
27
|
+
function pick(value) {
|
|
28
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The model's current rates. The cache is keyed by base URL as well as model
|
|
32
|
+
* id, so a demo override and production never share an entry.
|
|
33
|
+
*/
|
|
34
|
+
async function ratesFor(config, modelId, now = Date.now) {
|
|
35
|
+
const key = `${config.basePath}\u0000${modelId}`;
|
|
36
|
+
const hit = cache.get(key);
|
|
37
|
+
if (hit !== undefined && hit.expiresAt > now()) {
|
|
38
|
+
return hit.rates;
|
|
39
|
+
}
|
|
40
|
+
const model = await new sdk_1.InferenceApi(config).getModel({ id: modelId });
|
|
41
|
+
const p = model.pricing ?? {};
|
|
42
|
+
const rates = {
|
|
43
|
+
modelId: model.id ?? modelId,
|
|
44
|
+
modality: model.modality,
|
|
45
|
+
inputPer1mTokensCents: pick(p.inputPer1mTokensCents),
|
|
46
|
+
outputPer1mTokensCents: pick(p.outputPer1mTokensCents),
|
|
47
|
+
cachedInputPer1mTokensMicrocents: pick(p.cachedInputPer1mTokensMicrocents),
|
|
48
|
+
perImageCents: pick(p.perImageCents),
|
|
49
|
+
perImageMicrocents: pick(p.perImageMicrocents),
|
|
50
|
+
perMpxlMicrocents: pick(p.perMpxlMicrocents),
|
|
51
|
+
perVideoMicrocents: pick(p.perVideoMicrocents),
|
|
52
|
+
perVideoSecondMicrocents: pick(p.perVideoSecondMicrocents) ??
|
|
53
|
+
(pick(p.perVideoSecondCents) === undefined ? undefined : p.perVideoSecondCents * budget_js_1.MICRO_CENTS_PER_CENT),
|
|
54
|
+
};
|
|
55
|
+
cache.set(key, { rates, expiresAt: now() + exports.RATE_CACHE_TTL_MS });
|
|
56
|
+
return rates;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=pricing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../../src/tools/spend/pricing.ts"],"names":[],"mappings":";;;AAmCA,8DAEC;AAUD,4BA6BC;AA5ED,6EAA6E;AAC7E,EAAE;AACF,uEAAuE;AACvE,+EAA+E;AAC/E,8EAA8E;AAC9E,+EAA+E;AAC/E,+EAA+E;AAC/E,uBAAuB;AACvB,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,2BAA2B;AAC3B,wCAA0F;AAE1F,yDAAiE;AAGjE,8EAA8E;AACjE,QAAA,iBAAiB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAchD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;AAE5C,2CAA2C;AAC3C,SAAgB,yBAAyB;IACvC,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC;AAED,SAAS,IAAI,CAAC,KAAyB;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACjF,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,QAAQ,CAC5B,MAAqB,EACrB,OAAe,EACf,MAAoB,IAAI,CAAC,GAAG;IAE5B,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,QAAQ,SAAS,OAAO,EAAE,CAAC;IACjD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,SAAS,GAAG,GAAG,EAAE,EAAE,CAAC;QAC/C,OAAO,GAAG,CAAC,KAAK,CAAC;IACnB,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,IAAI,kBAAY,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IACvE,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAe;QACxB,OAAO,EAAE,KAAK,CAAC,EAAE,IAAI,OAAO;QAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,qBAAqB,EAAE,IAAI,CAAC,CAAC,CAAC,qBAAqB,CAAC;QACpD,sBAAsB,EAAE,IAAI,CAAC,CAAC,CAAC,sBAAsB,CAAC;QACtD,gCAAgC,EAAE,IAAI,CAAC,CAAC,CAAC,gCAAgC,CAAC;QAC1E,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC;QACpC,kBAAkB,EAAE,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC;QAC9C,iBAAiB,EAAE,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC;QAC5C,kBAAkB,EAAE,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC;QAC9C,wBAAwB,EACtB,IAAI,CAAC,CAAC,CAAC,wBAAwB,CAAC;YAChC,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,CAAC,mBAA8B,GAAG,gCAAoB,CAAC;KACrH,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,yBAAiB,EAAE,CAAC,CAAC;IAChE,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ZodRawShape } from "zod";
|
|
2
|
+
import type { ElicitationHost } from "../guardrail/types.js";
|
|
3
|
+
import type { ToolName } from "../roster.js";
|
|
4
|
+
/** Process environment view (the DEEPRELAY_API_KEY / base-URL override source). */
|
|
5
|
+
export type Env = Record<string, string | undefined>;
|
|
6
|
+
export type ToolTier = "read" | "write" | "spend";
|
|
7
|
+
export type ToolContent = {
|
|
8
|
+
type: "text";
|
|
9
|
+
text: string;
|
|
10
|
+
} | {
|
|
11
|
+
type: "image";
|
|
12
|
+
data: string;
|
|
13
|
+
mimeType: string;
|
|
14
|
+
};
|
|
15
|
+
/** Compatible with MCP's CallToolResult. */
|
|
16
|
+
export interface ToolResult {
|
|
17
|
+
content: ToolContent[];
|
|
18
|
+
isError?: boolean;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
}
|
|
21
|
+
/** Per-call context the registration door threads into a handler. */
|
|
22
|
+
export interface ToolContext {
|
|
23
|
+
env?: Env;
|
|
24
|
+
/** Present only when the server can reach the client's elicitation surface. */
|
|
25
|
+
elicitation?: ElicitationHost;
|
|
26
|
+
}
|
|
27
|
+
/** MCP ToolAnnotations. All four hints are always set explicitly. */
|
|
28
|
+
export interface ToolAnnotations {
|
|
29
|
+
readOnlyHint: boolean;
|
|
30
|
+
destructiveHint: boolean;
|
|
31
|
+
idempotentHint: boolean;
|
|
32
|
+
openWorldHint: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface ToolDefinition {
|
|
35
|
+
name: ToolName;
|
|
36
|
+
tier: ToolTier;
|
|
37
|
+
title: string;
|
|
38
|
+
/** Hand-authored and written for the agent (Phase 80 D-14 reasoning). */
|
|
39
|
+
description: string;
|
|
40
|
+
inputSchema: ZodRawShape;
|
|
41
|
+
annotations: ToolAnnotations;
|
|
42
|
+
/** See the file header. False for deeprelay_deposits_create_crypto only. */
|
|
43
|
+
enabledAtBoot: boolean;
|
|
44
|
+
handler(args: Record<string, unknown>, ctx?: ToolContext): Promise<ToolResult>;
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Configuration } from "@deeprelay/sdk";
|
|
2
|
+
import { z, type ZodRawShape } from "zod";
|
|
3
|
+
import type { Quote } from "../../guardrail/types.js";
|
|
4
|
+
import type { WriteToolName } from "../../roster.js";
|
|
5
|
+
import type { Env, ToolDefinition } from "../types.js";
|
|
6
|
+
/** Appended to every write description. The tier's contract, stated to the agent. */
|
|
7
|
+
export declare const WRITE_TIER_SENTENCE: string;
|
|
8
|
+
/** The one extra argument every write tool accepts. */
|
|
9
|
+
export declare const CONFIRMATION_TOKEN_SHAPE: {
|
|
10
|
+
confirmation_token: z.ZodOptional<z.ZodString>;
|
|
11
|
+
};
|
|
12
|
+
/** A quote whose resolvedParams are typed for the tool's execute step. */
|
|
13
|
+
export interface WriteQuote<R> extends Omit<Quote, "resolvedParams" | "estimateMicroCents" | "isFloor"> {
|
|
14
|
+
resolvedParams: R;
|
|
15
|
+
}
|
|
16
|
+
/** What a write's execute step returns. */
|
|
17
|
+
export interface WriteExecuted {
|
|
18
|
+
/** One sentence the agent can relay as-is. */
|
|
19
|
+
lead: string;
|
|
20
|
+
/** Sanitized before it reaches the agent. */
|
|
21
|
+
payload: unknown;
|
|
22
|
+
/** One-time reveal, merged AFTER sanitization. Only webhook create sets it. */
|
|
23
|
+
revealOnce?: Record<string, string>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Thrown from a write's quote or execute when the requested change is already
|
|
27
|
+
* true, e.g. clearing a spending limit on an account that has none. The
|
|
28
|
+
* factory returns `executed` as an ordinary result, not an error: the agent
|
|
29
|
+
* should report "nothing to do", not retry or apologise for a failure. Thrown
|
|
30
|
+
* from quote it mints no token, so nothing is left behind to confirm.
|
|
31
|
+
*/
|
|
32
|
+
export declare class WriteNothingToDo extends Error {
|
|
33
|
+
readonly executed: WriteExecuted;
|
|
34
|
+
constructor(executed: WriteExecuted);
|
|
35
|
+
}
|
|
36
|
+
export interface WriteToolSpec<Shape extends ZodRawShape, R extends Record<string, unknown>> {
|
|
37
|
+
name: WriteToolName;
|
|
38
|
+
title: string;
|
|
39
|
+
/** Agent-shaped. The tier sentence is appended automatically. */
|
|
40
|
+
description: string;
|
|
41
|
+
inputSchema: Shape;
|
|
42
|
+
/** True for delete/cancel: the change cannot be undone. */
|
|
43
|
+
destructive: boolean;
|
|
44
|
+
/** Only deeprelay_deposits_create_crypto sets this to false (D-03). */
|
|
45
|
+
enabledAtBoot?: boolean;
|
|
46
|
+
/** The yes/no question put to the user through elicitation. */
|
|
47
|
+
question: string | ((args: z.infer<z.ZodObject<Shape>>) => string);
|
|
48
|
+
/** What was being attempted, for error messages ("creating a webhook endpoint"). */
|
|
49
|
+
context: string;
|
|
50
|
+
/**
|
|
51
|
+
* Describe the change. Throwing (e.g. QuoteUnavailableError) mints no token.
|
|
52
|
+
* resolvedParams are what execute receives, never the second call's raw args.
|
|
53
|
+
*/
|
|
54
|
+
quote(args: z.infer<z.ZodObject<Shape>>, config: Configuration, env: Env): Promise<WriteQuote<R>>;
|
|
55
|
+
execute(resolved: R, config: Configuration, env: Env): Promise<WriteExecuted>;
|
|
56
|
+
/** Tool-specific wording for an HTTP status; undefined falls back to the shared mapper. */
|
|
57
|
+
overrideError?(status: number | undefined, err: unknown): string | undefined;
|
|
58
|
+
}
|
|
59
|
+
/** Wrap a mutation in the write tier's confirm-once handshake. */
|
|
60
|
+
export declare function defineWriteTool<Shape extends ZodRawShape, R extends Record<string, unknown>>(spec: WriteToolSpec<Shape, R>): ToolDefinition;
|