@deeprelay/mcp 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +188 -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 +292 -0
  40. package/dist/tools/readonly/index.js.map +1 -0
  41. package/dist/tools/readonly/video-reads.d.ts +11 -0
  42. package/dist/tools/readonly/video-reads.js +170 -0
  43. package/dist/tools/readonly/video-reads.js.map +1 -0
  44. package/dist/tools/result.d.ts +22 -0
  45. package/dist/tools/result.js +63 -0
  46. package/dist/tools/result.js.map +1 -0
  47. package/dist/tools/spend/define.d.ts +93 -0
  48. package/dist/tools/spend/define.js +286 -0
  49. package/dist/tools/spend/define.js.map +1 -0
  50. package/dist/tools/spend/index.d.ts +11 -0
  51. package/dist/tools/spend/index.js +163 -0
  52. package/dist/tools/spend/index.js.map +1 -0
  53. package/dist/tools/spend/media.d.ts +9 -0
  54. package/dist/tools/spend/media.js +164 -0
  55. package/dist/tools/spend/media.js.map +1 -0
  56. package/dist/tools/spend/pricing.d.ts +17 -0
  57. package/dist/tools/spend/pricing.js +58 -0
  58. package/dist/tools/spend/pricing.js.map +1 -0
  59. package/dist/tools/types.d.ts +45 -0
  60. package/dist/tools/types.js +3 -0
  61. package/dist/tools/types.js.map +1 -0
  62. package/dist/tools/write/define.d.ts +60 -0
  63. package/dist/tools/write/define.js +110 -0
  64. package/dist/tools/write/define.js.map +1 -0
  65. package/dist/tools/write/index.d.ts +12 -0
  66. package/dist/tools/write/index.js +159 -0
  67. package/dist/tools/write/index.js.map +1 -0
  68. package/dist/tools/write/payment-links.d.ts +3 -0
  69. package/dist/tools/write/payment-links.js +161 -0
  70. package/dist/tools/write/payment-links.js.map +1 -0
  71. package/dist/tools/write/spending-limit.d.ts +2 -0
  72. package/dist/tools/write/spending-limit.js +229 -0
  73. package/dist/tools/write/spending-limit.js.map +1 -0
  74. package/dist/version.d.ts +3 -0
  75. package/dist/version.js +36 -0
  76. package/dist/version.js.map +1 -0
  77. package/package.json +39 -3
@@ -0,0 +1,292 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readonlyTools = exports.videoReadTools = exports.VIDEO_TMP_DIR = exports.observeVideoJob = exports.READ_ANNOTATIONS = exports.defineTool = void 0;
4
+ exports.renderSessionBudget = renderSessionBudget;
5
+ // The free read tier (Phase 104, D-03/D-04/D-05/D-10). Authored fresh (D-12).
6
+ //
7
+ // Every tool here is a single GET mapped to one @deeprelay/sdk method (D-05),
8
+ // built with defineTool (define.ts): no confirmation, no quote, no budget
9
+ // accounting, and every result goes through ok(), so credential fields are
10
+ // sanitized and key-shaped text is redacted before the agent sees it.
11
+ //
12
+ // There is no operations tool (D-04). The video reads, which are the only
13
+ // place a pending video reservation settles (D-07), live in video-reads.ts.
14
+ const sdk_1 = require("@deeprelay/sdk");
15
+ const zod_1 = require("zod");
16
+ const auth_js_1 = require("../../auth.js");
17
+ const errors_js_1 = require("../../errors.js");
18
+ const budget_js_1 = require("../../guardrail/budget.js");
19
+ const define_js_1 = require("./define.js");
20
+ const video_reads_js_1 = require("./video-reads.js");
21
+ var define_js_2 = require("./define.js");
22
+ Object.defineProperty(exports, "defineTool", { enumerable: true, get: function () { return define_js_2.defineTool; } });
23
+ Object.defineProperty(exports, "READ_ANNOTATIONS", { enumerable: true, get: function () { return define_js_2.READ_ANNOTATIONS; } });
24
+ var video_reads_js_2 = require("./video-reads.js");
25
+ Object.defineProperty(exports, "observeVideoJob", { enumerable: true, get: function () { return video_reads_js_2.observeVideoJob; } });
26
+ Object.defineProperty(exports, "VIDEO_TMP_DIR", { enumerable: true, get: function () { return video_reads_js_2.VIDEO_TMP_DIR; } });
27
+ Object.defineProperty(exports, "videoReadTools", { enumerable: true, get: function () { return video_reads_js_2.videoReadTools; } });
28
+ /** Render 1e-6-cent units as dollars, for the agent's summary to the user. */
29
+ function dollars(microCents) {
30
+ return `$${(microCents / (budget_js_1.MICRO_CENTS_PER_CENT * 100)).toFixed(2)}`;
31
+ }
32
+ /** Run a read whose 404 is a normal answer ("nothing configured"), not an error. */
33
+ async function orNotFound(call, onNotFound) {
34
+ try {
35
+ return await call();
36
+ }
37
+ catch (err) {
38
+ if ((0, errors_js_1.httpStatusOf)(err) === 404) {
39
+ return onNotFound();
40
+ }
41
+ throw err;
42
+ }
43
+ }
44
+ /** The in-process session budget (D-06/D-08), in dollars, with pending video holds. */
45
+ function renderSessionBudget() {
46
+ const s = (0, budget_js_1.budgetStatus)();
47
+ return {
48
+ approved: s.approved,
49
+ limit: dollars(s.limitCents * budget_js_1.MICRO_CENTS_PER_CENT),
50
+ per_call_ceiling: dollars(s.ceilingMicroCents),
51
+ settled: dollars(s.settledMicroCents),
52
+ reserved: dollars(s.pendingMicroCents),
53
+ remaining: dollars(s.remainingMicroCents),
54
+ pending_video_reservations: (0, budget_js_1.pendingVideoReservations)().map((r) => ({
55
+ video_id: r.videoId,
56
+ reserved: dollars(r.microCents),
57
+ })),
58
+ note: s.approved
59
+ ? "Spend tools draw from this budget. Pending video reservations settle when deeprelay_videos_get or deeprelay_videos_list observes the job finished."
60
+ : `No session budget approved yet. The first spend call asks the user to approve one (default ${dollars(s.limitCents * budget_js_1.MICRO_CENTS_PER_CENT)}).`,
61
+ };
62
+ }
63
+ function balanceView(b) {
64
+ return {
65
+ balance_cents: b.balanceCents,
66
+ balance_dollars: b.balanceDollars,
67
+ auto_pay_enabled: b.autoPayEnabled,
68
+ };
69
+ }
70
+ function spendingLimitView(l) {
71
+ return {
72
+ monthly_limit_cents: l.monthlyLimitCents,
73
+ current_month_spend_cents: l.currentMonthSpendCents,
74
+ percent_used: l.percentUsed,
75
+ daily_limit_cents: l.dailyLimitCents ?? null,
76
+ current_day_spend_cents: l.currentDaySpendCents,
77
+ enforcement: l.enforcement,
78
+ };
79
+ }
80
+ const FREE = "Free: a read-only call with no charge and no confirmation.";
81
+ /** Diagnostics, catalog and usage reads. */
82
+ const coreReadTools = [
83
+ (0, define_js_1.defineTool)({
84
+ name: "deeprelay_auth_status",
85
+ title: "Check deeprelay credentials and session budget",
86
+ description: "Call this FIRST in a session. It confirms the configured deeprelay API key works and reports, in one call: " +
87
+ "the API base in use, the account's monthly/daily spending limit (null when none is configured), the prepaid " +
88
+ "balance, and this session's spend budget (approved or not, settled and reserved spend, remaining headroom, " +
89
+ `and any video jobs whose cost is still pending). ${FREE} It never returns the key itself.`,
90
+ inputSchema: {},
91
+ context: "checking the deeprelay credentials",
92
+ async call(_args, config, env) {
93
+ const billing = new sdk_1.BillingApi(config);
94
+ const limit = await orNotFound(() => billing.getSpendingLimit(), () => null);
95
+ const balance = await billing.getBalance();
96
+ return {
97
+ authenticated: true,
98
+ api_base: (0, auth_js_1.resolveBaseUrl)(env),
99
+ spending_limit: limit === null ? null : spendingLimitView(limit),
100
+ balance: balanceView(balance),
101
+ session_budget: renderSessionBudget(),
102
+ };
103
+ },
104
+ }),
105
+ (0, define_js_1.defineTool)({
106
+ name: "deeprelay_health",
107
+ title: "Check deeprelay API liveness",
108
+ description: "Is the deeprelay API up? Call this when other calls fail with network errors, to tell an outage apart from " +
109
+ `a configuration problem. Works even when no API key is configured. ${FREE}`,
110
+ inputSchema: {},
111
+ context: "checking deeprelay API health",
112
+ keyless: true,
113
+ async call(_args, config, env) {
114
+ const health = await new sdk_1.MetaApi(config).getHealth();
115
+ return { status: health.status ?? "unknown", api_base: (0, auth_js_1.resolveBaseUrl)(env) };
116
+ },
117
+ }),
118
+ (0, define_js_1.defineTool)({
119
+ name: "deeprelay_models_list",
120
+ title: "List deeprelay models",
121
+ description: "List the models deeprelay serves, with their modality (chat, embedding, image, video) and pricing. Call this " +
122
+ "before any inference call to pick a model id and see what it costs; filter with `modality`. " +
123
+ FREE,
124
+ inputSchema: {
125
+ modality: zod_1.z.enum(sdk_1.ListModelsModalityEnum).optional().describe("Only models of this modality."),
126
+ },
127
+ context: "listing models",
128
+ async call(args, config) {
129
+ return new sdk_1.InferenceApi(config).listModels({ modality: args.modality });
130
+ },
131
+ }),
132
+ (0, define_js_1.defineTool)({
133
+ name: "deeprelay_models_get",
134
+ title: "Get one deeprelay model",
135
+ description: "Get one model by id: modality, parameters and pricing. Call this to confirm a model id exists and to read " +
136
+ `its exact rates before quoting a spend call. ${FREE}`,
137
+ inputSchema: {
138
+ id: zod_1.z.string().min(1).describe("Model id, as returned by deeprelay_models_list."),
139
+ },
140
+ context: "getting a model",
141
+ async call(args, config) {
142
+ return new sdk_1.InferenceApi(config).getModel({ id: args.id });
143
+ },
144
+ }),
145
+ (0, define_js_1.defineTool)({
146
+ name: "deeprelay_inference_preflight",
147
+ title: "Preflight an inference call",
148
+ description: "Will a call to this model succeed for this account right now? Returns a verdict (ok, warn or block) with the " +
149
+ "reason and whether the account is funded, subscribed and plan-covered for the model. Call this before a spend " +
150
+ `call when unsure, instead of trying the call and failing. ${FREE}`,
151
+ inputSchema: {
152
+ model: zod_1.z.string().min(1).describe("Model id to check."),
153
+ },
154
+ context: "preflighting an inference call",
155
+ async call(args, config) {
156
+ return new sdk_1.InferenceApi(config).inferencePreflight({ model: args.model });
157
+ },
158
+ }),
159
+ (0, define_js_1.defineTool)({
160
+ name: "deeprelay_usage_get",
161
+ title: "Get deeprelay usage",
162
+ description: "How much has this account used and spent, over time? Returns time-bucketed usage (hour, day, week or month; " +
163
+ "default day, last 31 buckets). Pass `cursor` from `nextCursor` to page. Use this to answer spend questions " +
164
+ `about past days; for this session's spend use deeprelay_auth_status. ${FREE}`,
165
+ inputSchema: {
166
+ bucket: zod_1.z.enum(sdk_1.ListUsageBucketEnum).default("day").describe("Bucket width."),
167
+ start: zod_1.z.iso.datetime({ offset: true }).optional().describe("ISO-8601 start of the window."),
168
+ end: zod_1.z.iso.datetime({ offset: true }).optional().describe("ISO-8601 end of the window."),
169
+ cursor: zod_1.z.string().min(1).optional().describe("Page cursor from a previous result's nextCursor."),
170
+ limit: zod_1.z.number().int().min(1).max(100).default(31).describe("Buckets per page (1-100)."),
171
+ },
172
+ context: "getting usage",
173
+ async call(args, config) {
174
+ return new sdk_1.UsageApi(config).listUsage({
175
+ bucket: args.bucket,
176
+ start: args.start === undefined ? undefined : new Date(args.start),
177
+ end: args.end === undefined ? undefined : new Date(args.end),
178
+ cursor: args.cursor,
179
+ limit: args.limit,
180
+ });
181
+ },
182
+ }),
183
+ ];
184
+ const DEPOSITS_NOTE = "Crypto deposits are visible only on accounts with crypto deposits enabled. If the feature is not enabled the " +
185
+ "result is `{ crypto_deposits_enabled: false }`: that is a final answer, not an error, so do not retry.";
186
+ const NO_SECRET_NOTE = "The endpoint's signing secret is never returned by any read; it is shown once, when the endpoint is created.";
187
+ /** Webhook endpoints without their signing secret, even if the API sent one. */
188
+ function withoutSecret(endpoint) {
189
+ const { secret: _secret, ...rest } = endpoint;
190
+ return rest;
191
+ }
192
+ /** Billing and webhook reads. */
193
+ const billingReadTools = [
194
+ (0, define_js_1.defineTool)({
195
+ name: "deeprelay_balance_get",
196
+ title: "Get deeprelay balance",
197
+ description: "How much prepaid credit does the account have? Returns the balance in cents and dollars and the auto-pay " +
198
+ `settings. Call this before a large spend, or after a 402 insufficient-balance error. ${FREE}`,
199
+ inputSchema: {},
200
+ context: "getting the balance",
201
+ async call(_args, config) {
202
+ return new sdk_1.BillingApi(config).getBalance();
203
+ },
204
+ }),
205
+ (0, define_js_1.defineTool)({
206
+ name: "deeprelay_spending_limit_get",
207
+ title: "Get the deeprelay spending limit",
208
+ description: "What is the account's monthly (and optional daily) spending limit, and how much of it is used? When no limit " +
209
+ "is configured the result is `{ configured: false }`, which is a normal answer. To lower the limit use " +
210
+ `deeprelay_spending_limit_update. ${FREE}`,
211
+ inputSchema: {},
212
+ context: "getting the spending limit",
213
+ async call(_args, config) {
214
+ return orNotFound(async () => ({ configured: true, ...(await new sdk_1.BillingApi(config).getSpendingLimit()) }), () => ({ configured: false }));
215
+ },
216
+ }),
217
+ (0, define_js_1.defineTool)({
218
+ name: "deeprelay_subscription_get",
219
+ title: "Get the deeprelay subscription",
220
+ description: "Is the account subscribed, to which plan, and how much of the plan's quota is used this period? Call this to " +
221
+ `explain a plan-coverage verdict from deeprelay_inference_preflight. ${FREE}`,
222
+ inputSchema: {},
223
+ context: "getting the subscription",
224
+ async call(_args, config) {
225
+ return new sdk_1.BillingApi(config).getSubscription();
226
+ },
227
+ }),
228
+ (0, define_js_1.defineTool)({
229
+ name: "deeprelay_deposits_list",
230
+ title: "List crypto deposits",
231
+ description: `List the account's crypto deposits and the minimum deposit. ${DEPOSITS_NOTE} ${FREE}`,
232
+ inputSchema: {},
233
+ context: "listing crypto deposits",
234
+ async call(_args, config) {
235
+ return orNotFound(async () => ({ crypto_deposits_enabled: true, ...(await new sdk_1.BillingApi(config).listDeposits()) }), () => ({ crypto_deposits_enabled: false }));
236
+ },
237
+ }),
238
+ (0, define_js_1.defineTool)({
239
+ name: "deeprelay_deposits_get",
240
+ title: "Get a crypto deposit",
241
+ description: `Get one crypto deposit by id: status, chain, asset, amount and credited cents. ${DEPOSITS_NOTE} ` +
242
+ FREE,
243
+ inputSchema: {
244
+ id: zod_1.z.string().min(1).describe("Deposit id, as returned by deeprelay_deposits_list."),
245
+ },
246
+ context: "getting a crypto deposit",
247
+ async call(args, config) {
248
+ return orNotFound(async () => ({ crypto_deposits_enabled: true, ...(await new sdk_1.BillingApi(config).getDeposit({ id: args.id })) }), () => ({ crypto_deposits_enabled: false }));
249
+ },
250
+ }),
251
+ (0, define_js_1.defineTool)({
252
+ name: "deeprelay_referrals_get",
253
+ title: "Get the deeprelay referral link",
254
+ description: "Get the account's referral code and invite link, the program terms (reward amounts, qualifying spend, hold " +
255
+ `days) and the referral stats. Call this when the user asks how to invite someone or earn credit. ${FREE}`,
256
+ inputSchema: {},
257
+ context: "getting the referral program",
258
+ async call(_args, config) {
259
+ return new sdk_1.BillingApi(config).getReferral();
260
+ },
261
+ }),
262
+ (0, define_js_1.defineTool)({
263
+ name: "deeprelay_webhooks_list",
264
+ title: "List webhook endpoints",
265
+ description: "List the account's webhook endpoints: id, URL, subscribed event types and whether each is enabled. Pass " +
266
+ `\`cursor\` from \`nextCursor\` to page. ${NO_SECRET_NOTE} ${FREE}`,
267
+ inputSchema: {
268
+ cursor: zod_1.z.string().min(1).optional().describe("Page cursor from a previous result's nextCursor."),
269
+ limit: zod_1.z.number().int().min(1).max(100).optional().describe("Endpoints per page (1-100)."),
270
+ },
271
+ context: "listing webhook endpoints",
272
+ async call(args, config) {
273
+ const page = await new sdk_1.WebhooksApi(config).listWebhookEndpoints({ cursor: args.cursor, limit: args.limit });
274
+ return { ...page, data: page.data.map(withoutSecret) };
275
+ },
276
+ }),
277
+ (0, define_js_1.defineTool)({
278
+ name: "deeprelay_webhooks_get",
279
+ title: "Get a webhook endpoint",
280
+ description: `Get one webhook endpoint by id: URL, event types and enabled flag. ${NO_SECRET_NOTE} ${FREE}`,
281
+ inputSchema: {
282
+ id: zod_1.z.string().min(1).describe("Webhook endpoint id, as returned by deeprelay_webhooks_list."),
283
+ },
284
+ context: "getting a webhook endpoint",
285
+ async call(args, config) {
286
+ return withoutSecret(await new sdk_1.WebhooksApi(config).getWebhookEndpoint({ id: args.id }));
287
+ },
288
+ }),
289
+ ];
290
+ /** The full read tier. Every name in roster READ_TOOLS appears here exactly once. */
291
+ exports.readonlyTools = [...coreReadTools, ...billingReadTools, ...video_reads_js_1.videoReadTools];
292
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/readonly/index.ts"],"names":[],"mappings":";;;AAkDA,kDAiBC;AAnED,8EAA8E;AAC9E,EAAE;AACF,8EAA8E;AAC9E,0EAA0E;AAC1E,2EAA2E;AAC3E,sEAAsE;AACtE,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,wCAUwB;AACxB,6BAAwB;AAExB,2CAA+C;AAC/C,+CAA+C;AAC/C,yDAAyG;AAEzG,2CAAyC;AACzC,qDAAkD;AAElD,yCAA2D;AAAlD,uGAAA,UAAU,OAAA;AAAE,6GAAA,gBAAgB,OAAA;AACrC,mDAAkF;AAAzE,iHAAA,eAAe,OAAA;AAAE,+GAAA,aAAa,OAAA;AAAE,gHAAA,cAAc,OAAA;AAEvD,8EAA8E;AAC9E,SAAS,OAAO,CAAC,UAAkB;IACjC,OAAO,IAAI,CAAC,UAAU,GAAG,CAAC,gCAAoB,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AACtE,CAAC;AAED,oFAAoF;AACpF,KAAK,UAAU,UAAU,CAAO,IAAsB,EAAE,UAAmB;IACzE,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,IAAA,wBAAY,EAAC,GAAG,CAAC,KAAK,GAAG,EAAE,CAAC;YAC9B,OAAO,UAAU,EAAE,CAAC;QACtB,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,SAAgB,mBAAmB;IACjC,MAAM,CAAC,GAAG,IAAA,wBAAY,GAAE,CAAC;IACzB,OAAO;QACL,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,UAAU,GAAG,gCAAoB,CAAC;QACnD,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC;QAC9C,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC;QACrC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC;QACtC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;QACzC,0BAA0B,EAAE,IAAA,oCAAwB,GAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACjE,QAAQ,EAAE,CAAC,CAAC,OAAO;YACnB,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;SAChC,CAAC,CAAC;QACH,IAAI,EAAE,CAAC,CAAC,QAAQ;YACd,CAAC,CAAC,oJAAoJ;YACtJ,CAAC,CAAC,8FAA8F,OAAO,CAAC,CAAC,CAAC,UAAU,GAAG,gCAAoB,CAAC,IAAI;KACnJ,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,CAAU;IAC7B,OAAO;QACL,aAAa,EAAE,CAAC,CAAC,YAAY;QAC7B,eAAe,EAAE,CAAC,CAAC,cAAc;QACjC,gBAAgB,EAAE,CAAC,CAAC,cAAc;KACnC,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,CAAgB;IACzC,OAAO;QACL,mBAAmB,EAAE,CAAC,CAAC,iBAAiB;QACxC,yBAAyB,EAAE,CAAC,CAAC,sBAAsB;QACnD,YAAY,EAAE,CAAC,CAAC,WAAW;QAC3B,iBAAiB,EAAE,CAAC,CAAC,eAAe,IAAI,IAAI;QAC5C,uBAAuB,EAAE,CAAC,CAAC,oBAAoB;QAC/C,WAAW,EAAE,CAAC,CAAC,WAAW;KAC3B,CAAC;AACJ,CAAC;AAED,MAAM,IAAI,GAAG,4DAA4D,CAAC;AAE1E,4CAA4C;AAC5C,MAAM,aAAa,GAAqB;IACtC,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,uBAAuB;QAC7B,KAAK,EAAE,gDAAgD;QACvD,WAAW,EACT,6GAA6G;YAC7G,8GAA8G;YAC9G,6GAA6G;YAC7G,oDAAoD,IAAI,mCAAmC;QAC7F,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,oCAAoC;QAC7C,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG;YAC3B,MAAM,OAAO,GAAG,IAAI,gBAAU,CAAC,MAAM,CAAC,CAAC;YACvC,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YAC7E,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;YAC3C,OAAO;gBACL,aAAa,EAAE,IAAI;gBACnB,QAAQ,EAAE,IAAA,wBAAc,EAAC,GAAG,CAAC;gBAC7B,cAAc,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC;gBAChE,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC;gBAC7B,cAAc,EAAE,mBAAmB,EAAE;aACtC,CAAC;QACJ,CAAC;KACF,CAAC;IACF,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,8BAA8B;QACrC,WAAW,EACT,6GAA6G;YAC7G,sEAAsE,IAAI,EAAE;QAC9E,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,+BAA+B;QACxC,OAAO,EAAE,IAAI;QACb,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG;YAC3B,MAAM,MAAM,GAAG,MAAM,IAAI,aAAO,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,CAAC;YACrD,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,SAAS,EAAE,QAAQ,EAAE,IAAA,wBAAc,EAAC,GAAG,CAAC,EAAE,CAAC;QAC/E,CAAC;KACF,CAAC;IACF,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,uBAAuB;QAC7B,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EACT,+GAA+G;YAC/G,8FAA8F;YAC9F,IAAI;QACN,WAAW,EAAE;YACX,QAAQ,EAAE,OAAC,CAAC,IAAI,CAAC,4BAAsB,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;SAC9F;QACD,OAAO,EAAE,gBAAgB;QACzB,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM;YACrB,OAAO,IAAI,kBAAY,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC1E,CAAC;KACF,CAAC;IACF,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,sBAAsB;QAC5B,KAAK,EAAE,yBAAyB;QAChC,WAAW,EACT,4GAA4G;YAC5G,gDAAgD,IAAI,EAAE;QACxD,WAAW,EAAE;YACX,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,iDAAiD,CAAC;SAClF;QACD,OAAO,EAAE,iBAAiB;QAC1B,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM;YACrB,OAAO,IAAI,kBAAY,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5D,CAAC;KACF,CAAC;IACF,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,+BAA+B;QACrC,KAAK,EAAE,6BAA6B;QACpC,WAAW,EACT,+GAA+G;YAC/G,gHAAgH;YAChH,6DAA6D,IAAI,EAAE;QACrE,WAAW,EAAE;YACX,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,oBAAoB,CAAC;SACxD;QACD,OAAO,EAAE,gCAAgC;QACzC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM;YACrB,OAAO,IAAI,kBAAY,CAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5E,CAAC;KACF,CAAC;IACF,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,qBAAqB;QAC3B,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EACT,8GAA8G;YAC9G,6GAA6G;YAC7G,wEAAwE,IAAI,EAAE;QAChF,WAAW,EAAE;YACX,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,yBAAmB,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC;YAC5E,KAAK,EAAE,OAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;YAC5F,GAAG,EAAE,OAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;YACxF,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kDAAkD,CAAC;YACjG,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,2BAA2B,CAAC;SAC1F;QACD,OAAO,EAAE,eAAe;QACxB,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM;YACrB,OAAO,IAAI,cAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC;gBACpC,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;gBAClE,GAAG,EAAE,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;gBAC5D,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB,CAAC,CAAC;QACL,CAAC;KACF,CAAC;CACH,CAAC;AAEF,MAAM,aAAa,GACjB,+GAA+G;IAC/G,wGAAwG,CAAC;AAE3G,MAAM,cAAc,GAClB,8GAA8G,CAAC;AAEjH,gFAAgF;AAChF,SAAS,aAAa,CAAgC,QAAW;IAC/D,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAC;IAC9C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,iCAAiC;AACjC,MAAM,gBAAgB,GAAqB;IACzC,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,uBAAuB;QAC7B,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EACT,2GAA2G;YAC3G,wFAAwF,IAAI,EAAE;QAChG,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,qBAAqB;QAC9B,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM;YACtB,OAAO,IAAI,gBAAU,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,CAAC;QAC7C,CAAC;KACF,CAAC;IACF,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,8BAA8B;QACpC,KAAK,EAAE,kCAAkC;QACzC,WAAW,EACT,+GAA+G;YAC/G,wGAAwG;YACxG,oCAAoC,IAAI,EAAE;QAC5C,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,4BAA4B;QACrC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM;YACtB,OAAO,UAAU,CACf,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,IAAI,gBAAU,CAAC,MAAM,CAAC,CAAC,gBAAgB,EAAE,CAAC,EAAE,CAAC,EACxF,GAAG,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAC9B,CAAC;QACJ,CAAC;KACF,CAAC;IACF,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,4BAA4B;QAClC,KAAK,EAAE,gCAAgC;QACvC,WAAW,EACT,+GAA+G;YAC/G,uEAAuE,IAAI,EAAE;QAC/E,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,0BAA0B;QACnC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM;YACtB,OAAO,IAAI,gBAAU,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAC;QAClD,CAAC;KACF,CAAC;IACF,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,yBAAyB;QAC/B,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EAAE,+DAA+D,aAAa,IAAI,IAAI,EAAE;QACnG,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,yBAAyB;QAClC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM;YACtB,OAAO,UAAU,CACf,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,uBAAuB,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,IAAI,gBAAU,CAAC,MAAM,CAAC,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,EACjG,GAAG,EAAE,CAAC,CAAC,EAAE,uBAAuB,EAAE,KAAK,EAAE,CAAC,CAC3C,CAAC;QACJ,CAAC;KACF,CAAC;IACF,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,wBAAwB;QAC9B,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EACT,kFAAkF,aAAa,GAAG;YAClG,IAAI;QACN,WAAW,EAAE;YACX,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,qDAAqD,CAAC;SACtF;QACD,OAAO,EAAE,0BAA0B;QACnC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM;YACrB,OAAO,UAAU,CACf,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,uBAAuB,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,IAAI,gBAAU,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAC9G,GAAG,EAAE,CAAC,CAAC,EAAE,uBAAuB,EAAE,KAAK,EAAE,CAAC,CAC3C,CAAC;QACJ,CAAC;KACF,CAAC;IACF,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,yBAAyB;QAC/B,KAAK,EAAE,iCAAiC;QACxC,WAAW,EACT,6GAA6G;YAC7G,oGAAoG,IAAI,EAAE;QAC5G,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,8BAA8B;QACvC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM;YACtB,OAAO,IAAI,gBAAU,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAC9C,CAAC;KACF,CAAC;IACF,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,yBAAyB;QAC/B,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EACT,0GAA0G;YAC1G,2CAA2C,cAAc,IAAI,IAAI,EAAE;QACrE,WAAW,EAAE;YACX,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kDAAkD,CAAC;YACjG,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;SAC3F;QACD,OAAO,EAAE,2BAA2B;QACpC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM;YACrB,MAAM,IAAI,GAAG,MAAM,IAAI,iBAAW,CAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YAC5G,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;QACzD,CAAC;KACF,CAAC;IACF,IAAA,sBAAU,EAAC;QACT,IAAI,EAAE,wBAAwB;QAC9B,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EAAE,sEAAsE,cAAc,IAAI,IAAI,EAAE;QAC3G,WAAW,EAAE;YACX,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,8DAA8D,CAAC;SAC/F;QACD,OAAO,EAAE,4BAA4B;QACrC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM;YACrB,OAAO,aAAa,CAAC,MAAM,IAAI,iBAAW,CAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1F,CAAC;KACF,CAAC;CACH,CAAC;AAEF,qFAAqF;AACxE,QAAA,aAAa,GAAqB,CAAC,GAAG,aAAa,EAAE,GAAG,gBAAgB,EAAE,GAAG,+BAAc,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type VideoJob } from "@deeprelay/sdk";
2
+ import type { ToolDefinition } from "../types.js";
3
+ /** Where deeprelay_videos_content saves when no output_path is given. */
4
+ export declare const VIDEO_TMP_DIR: string;
5
+ export type SessionSettlement = "settled" | "released" | "pending" | "not_tracked";
6
+ /**
7
+ * Settle (or release) this session's reservation for the job, then return the
8
+ * job's public fields plus what happened to the reservation.
9
+ */
10
+ export declare function observeVideoJob(job: VideoJob): Record<string, unknown>;
11
+ export declare const videoReadTools: ToolDefinition[];
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.videoReadTools = exports.VIDEO_TMP_DIR = void 0;
4
+ exports.observeVideoJob = observeVideoJob;
5
+ // Video reads: list, get and content (Phase 104 D-02/D-07). Authored fresh (D-12).
6
+ //
7
+ // Video generation is asynchronous. deeprelay_videos_create reserves a floor
8
+ // estimate against the session budget keyed by the video id, and the actual
9
+ // charge (cost_cents) is only known once the job reaches `completed`. These
10
+ // reads are the only place that reservation resolves: every job they observe
11
+ // goes through observeVideoJob → settleVideo, which
12
+ //
13
+ // completed → settles at cost_cents (the floor if absent)
14
+ // failed | cancelled | expired → releases the hold (never billed)
15
+ // queued | in_progress → leaves it pending
16
+ //
17
+ // settleVideo drops the reservation on first settlement, so observing the same
18
+ // finished job again reports "not_tracked" and never double-counts (T-104-21).
19
+ //
20
+ // Content is delivered as a file on the MCP host, never encoded inline: an MP4
21
+ // can be tens of MB and would flood the agent's context (T-104-20). The stdio
22
+ // server runs as the user, so an agent-chosen path is the user's own
23
+ // filesystem; it must be absolute (T-104-19). The write uses flag "wx", so an
24
+ // existing file is never overwritten: this tool advertises readOnlyHint, and
25
+ // clobbering a file the agent happened to name would contradict that.
26
+ const promises_1 = require("node:fs/promises");
27
+ const node_os_1 = require("node:os");
28
+ const node_path_1 = require("node:path");
29
+ const sdk_1 = require("@deeprelay/sdk");
30
+ const zod_1 = require("zod");
31
+ const budget_js_1 = require("../../guardrail/budget.js");
32
+ const define_js_1 = require("./define.js");
33
+ /** Where deeprelay_videos_content saves when no output_path is given. */
34
+ exports.VIDEO_TMP_DIR = (0, node_path_1.join)((0, node_os_1.tmpdir)(), "deeprelay-mcp");
35
+ const FREE = "Free: a read-only call with no charge and no confirmation.";
36
+ function isTracked(videoId) {
37
+ return (0, budget_js_1.pendingVideoReservations)().some((r) => r.videoId === videoId);
38
+ }
39
+ function iso(unixSeconds) {
40
+ return typeof unixSeconds === "number" && Number.isFinite(unixSeconds)
41
+ ? new Date(unixSeconds * 1000).toISOString()
42
+ : null;
43
+ }
44
+ /**
45
+ * Settle (or release) this session's reservation for the job, then return the
46
+ * job's public fields plus what happened to the reservation.
47
+ */
48
+ function observeVideoJob(job) {
49
+ const tracked = isTracked(job.id);
50
+ const outcome = (0, budget_js_1.settleVideo)(job.id, { status: job.status, costCents: job.costCents });
51
+ let settlement;
52
+ if (!tracked) {
53
+ settlement = "not_tracked";
54
+ }
55
+ else if (!outcome.settled) {
56
+ settlement = "pending";
57
+ }
58
+ else {
59
+ settlement = job.status === "completed" ? "settled" : "released";
60
+ }
61
+ return {
62
+ id: job.id,
63
+ model: job.model,
64
+ status: job.status,
65
+ progress: job.progress,
66
+ size: job.size ?? null,
67
+ seconds: job.seconds ?? null,
68
+ created_at: iso(job.createdAt),
69
+ completed_at: iso(job.completedAt),
70
+ expires_at: iso(job.expiresAt),
71
+ error: job.error ?? null,
72
+ cost_cents: job.costCents ?? null,
73
+ session_settlement: settlement,
74
+ };
75
+ }
76
+ /** A filesystem-safe default file name for a video id. */
77
+ function defaultPath(videoId) {
78
+ const safe = videoId.replace(/[^A-Za-z0-9._-]/g, "_").replace(/^\.+/, "_");
79
+ return (0, node_path_1.join)(exports.VIDEO_TMP_DIR, `${safe || "video"}.mp4`);
80
+ }
81
+ exports.videoReadTools = [
82
+ (0, define_js_1.defineTool)({
83
+ name: "deeprelay_videos_list",
84
+ title: "List video generation jobs",
85
+ description: "List this account's video generation jobs, newest first, with status, progress and cost_cents once finished. " +
86
+ "Page with `after` (the last id seen). Observing a finished job here also settles this session's video " +
87
+ `reservation for it, like deeprelay_videos_get. ${FREE}`,
88
+ inputSchema: {
89
+ after: zod_1.z.string().min(1).optional().describe("Return jobs after this video id (pagination)."),
90
+ limit: zod_1.z.number().int().min(1).max(100).default(20).describe("Jobs per page (1-100)."),
91
+ },
92
+ context: "listing video jobs",
93
+ async call(args, config) {
94
+ const page = await new sdk_1.InferenceApi(config).listVideos({ after: args.after, limit: args.limit });
95
+ return { data: page.data.map((job) => observeVideoJob(job)), has_more: page.hasMore };
96
+ },
97
+ }),
98
+ (0, define_js_1.defineTool)({
99
+ name: "deeprelay_videos_get",
100
+ title: "Get a video generation job",
101
+ description: "Poll one video job: status (queued, in_progress, completed, failed, cancelled, expired), progress, and " +
102
+ "cost_cents once completed. Calling this after the job completes is what settles this session's video " +
103
+ "reservation and reports the actual charge; a failed, cancelled or expired job releases it unbilled. When " +
104
+ `status is completed, download the file with deeprelay_videos_content. ${FREE}`,
105
+ inputSchema: {
106
+ id: zod_1.z.string().min(1).describe("Video job id, as returned by deeprelay_videos_create."),
107
+ },
108
+ context: "getting a video job",
109
+ async call(args, config) {
110
+ return observeVideoJob(await new sdk_1.InferenceApi(config).getVideo({ id: args.id }));
111
+ },
112
+ }),
113
+ (0, define_js_1.defineTool)({
114
+ name: "deeprelay_videos_content",
115
+ title: "Download a generated video",
116
+ description: "Download a completed video's MP4 to a file on this machine and return its path and size (the video is never " +
117
+ "returned inline). Pass `output_path` as an absolute file path, or omit it to save under the system temp " +
118
+ "directory. It never overwrites an existing file: if the path exists the call is refused and you must choose a " +
119
+ "new path. Also settles this session's reservation for the job. Artifacts are kept for 24 hours after " +
120
+ `completion. ${FREE}`,
121
+ inputSchema: {
122
+ id: zod_1.z.string().min(1).describe("Video job id."),
123
+ output_path: zod_1.z
124
+ .string()
125
+ .min(1)
126
+ .refine((p) => (0, node_path_1.isAbsolute)(p), { message: "output_path must be an absolute file path" })
127
+ .optional()
128
+ .describe("Absolute path to write the MP4 to. Default: <system temp>/deeprelay-mcp/<id>.mp4"),
129
+ },
130
+ context: "downloading a video",
131
+ async call(args, config) {
132
+ const api = new sdk_1.InferenceApi(config);
133
+ const job = observeVideoJob(await api.getVideo({ id: args.id }));
134
+ if (job.status !== "completed") {
135
+ return {
136
+ video_id: args.id,
137
+ downloaded: false,
138
+ status: job.status,
139
+ session_settlement: job.session_settlement,
140
+ next: job.status === "queued" || job.status === "in_progress"
141
+ ? "The video is not ready. Poll deeprelay_videos_get until status is completed, then call this again."
142
+ : `The video is ${String(job.status)} and has no downloadable content.`,
143
+ };
144
+ }
145
+ const blob = await api.getVideoContent({ id: args.id });
146
+ const bytes = Buffer.from(await blob.arrayBuffer());
147
+ const target = args.output_path ?? defaultPath(args.id);
148
+ await (0, promises_1.mkdir)((0, node_path_1.dirname)(target), { recursive: true });
149
+ try {
150
+ await (0, promises_1.writeFile)(target, bytes, { mode: 0o600, flag: "wx" });
151
+ }
152
+ catch (err) {
153
+ if (err?.code === "EEXIST") {
154
+ throw new define_js_1.ReadRefusal(`Refused to download video ${args.id}: a file already exists at ${target} and this tool never ` +
155
+ "overwrites files. Call deeprelay_videos_content again with a new absolute output_path.");
156
+ }
157
+ throw err;
158
+ }
159
+ return {
160
+ video_id: args.id,
161
+ saved_to: target,
162
+ bytes: bytes.length,
163
+ mime_type: "video/mp4",
164
+ cost_cents: job.cost_cents,
165
+ session_settlement: job.session_settlement,
166
+ };
167
+ },
168
+ }),
169
+ ];
170
+ //# sourceMappingURL=video-reads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-reads.js","sourceRoot":"","sources":["../../../src/tools/readonly/video-reads.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { QuoteResult } from "../guardrail/types.js";
2
+ import type { Env, ToolResult } from "./types.js";
3
+ export interface OkOptions {
4
+ /** Merged into an object payload after sanitization. One-time reveals only. */
5
+ revealOnce?: Record<string, string>;
6
+ env?: Env;
7
+ }
8
+ /** Serialize a success payload as pretty JSON text, sanitized and redacted. */
9
+ export declare function ok(payload: unknown, options?: OkOptions): ToolResult;
10
+ /** Serialize a failure. The message is redacted again even if already mapped. */
11
+ export declare function fail(err: unknown, env?: Env): ToolResult;
12
+ /**
13
+ * Serialize a quote returned in place of execution. The agent must call the
14
+ * same tool again with `confirmation_token` (after the user agrees) to run it.
15
+ *
16
+ * `extra` carries tier-specific facts the agent needs to relay (the spend
17
+ * tier's `quote_kind` and proposed `session_budget_usd`). It is merged before
18
+ * the fixed fields, so it can never overwrite the token or the summary.
19
+ */
20
+ export declare function quoteResult(q: QuoteResult, env?: Env, extra?: Record<string, unknown>): ToolResult;
21
+ /** True for a guardrail QuoteResult (as opposed to an executed result). */
22
+ export declare function isQuoteResult(v: unknown): v is QuoteResult;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ok = ok;
4
+ exports.fail = fail;
5
+ exports.quoteResult = quoteResult;
6
+ exports.isQuoteResult = isQuoteResult;
7
+ const errors_js_1 = require("../errors.js");
8
+ /** Serialize a success payload as pretty JSON text, sanitized and redacted. */
9
+ function ok(payload, options = {}) {
10
+ let body = (0, errors_js_1.sanitizeCredentialFields)(payload === undefined ? null : payload);
11
+ if (options.revealOnce !== undefined) {
12
+ const base = typeof body === "object" && body !== null && !Array.isArray(body) ? body : { result: body };
13
+ body = { ...base, ...options.revealOnce };
14
+ }
15
+ const text = JSON.stringify(body, null, 2);
16
+ return { content: [{ type: "text", text: (0, errors_js_1.redactSecrets)(text, options.env) }] };
17
+ }
18
+ /** Serialize a failure. The message is redacted again even if already mapped. */
19
+ function fail(err, env) {
20
+ const message = err instanceof Error ? err.message : String(err);
21
+ return { content: [{ type: "text", text: (0, errors_js_1.redactSecrets)(message, env) }], isError: true };
22
+ }
23
+ /**
24
+ * Serialize a quote returned in place of execution. The agent must call the
25
+ * same tool again with `confirmation_token` (after the user agrees) to run it.
26
+ *
27
+ * `extra` carries tier-specific facts the agent needs to relay (the spend
28
+ * tier's `quote_kind` and proposed `session_budget_usd`). It is merged before
29
+ * the fixed fields, so it can never overwrite the token or the summary.
30
+ */
31
+ function quoteResult(q, env, extra) {
32
+ const body = {
33
+ ...(extra ?? {}),
34
+ kind: "quote",
35
+ tier: q.tier,
36
+ tool: q.toolName,
37
+ summary: q.summary,
38
+ confirmation_token: q.confirmationToken,
39
+ expires_at: q.expiresAt,
40
+ };
41
+ if (q.estimateMicroCents !== undefined) {
42
+ body.estimate_micro_cents = q.estimateMicroCents;
43
+ }
44
+ if (q.isFloor !== undefined) {
45
+ body.is_floor = q.isFloor;
46
+ }
47
+ if (q.declined === true) {
48
+ body.declined = true;
49
+ }
50
+ return { content: [{ type: "text", text: (0, errors_js_1.redactSecrets)(JSON.stringify(body, null, 2), env) }] };
51
+ }
52
+ /** True for a guardrail QuoteResult (as opposed to an executed result). */
53
+ function isQuoteResult(v) {
54
+ if (typeof v !== "object" || v === null) {
55
+ return false;
56
+ }
57
+ const candidate = v;
58
+ return (candidate.kind === "quote" &&
59
+ typeof candidate.confirmationToken === "string" &&
60
+ typeof candidate.expiresAt === "string" &&
61
+ typeof candidate.summary === "string");
62
+ }
63
+ //# sourceMappingURL=result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/tools/result.ts"],"names":[],"mappings":"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"}