@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
package/README.md CHANGED
@@ -1 +1,194 @@
1
- Placeholder for @deeprelay/mcp. The real deeprelay MCP server is published by CI from deeprelay-dev/deeprelay over OIDC trusted publishing, starting at 0.1.0.
1
+ # deeprelay MCP server
2
+
3
+ This server connects Claude Code, Claude Desktop, Cursor, or any other
4
+ [MCP](https://modelcontextprotocol.io) client straight to the deeprelay
5
+ serverless inference API. The agent can browse models and their prices, run
6
+ chat, embeddings, image and video generation inside a budget you approve, read
7
+ your balance and usage, manage webhook endpoints, lower or clear your spending
8
+ limit, and create checkout or billing links, all without leaving the editor.
9
+
10
+ **29 tools in three tiers: reads are free, writes confirm once, money tools
11
+ quote a price and require explicit confirmation.** The server enforces these
12
+ rules, so they do not depend on the agent behaving well.
13
+
14
+ This is a **local stdio server**. Your client spawns it as a subprocess and
15
+ talks JSON-RPC over stdin/stdout. Nothing is hosted or proxied: your API key
16
+ stays on your machine, and the server calls `https://api.deeprelay.ai/v1`
17
+ directly.
18
+
19
+ Full documentation: **<https://deeprelay.ai/docs/mcp>**
20
+
21
+ ## Requirements
22
+
23
+ - Node 22 or newer
24
+ - A deeprelay API key, created in the dashboard
25
+
26
+ ## Setup
27
+
28
+ The server runs with `npx -y @deeprelay/mcp@latest`. Your client launches it
29
+ for you.
30
+
31
+ ### Claude Code: `.mcp.json`
32
+
33
+ ```json
34
+ {
35
+ "mcpServers": {
36
+ "deeprelay": {
37
+ "type": "stdio",
38
+ "command": "npx",
39
+ "args": ["-y", "@deeprelay/mcp@latest"],
40
+ "env": {
41
+ "DEEPRELAY_API_KEY": "${DEEPRELAY_API_KEY}"
42
+ }
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ Claude Code fills in `${DEEPRELAY_API_KEY}` from your shell when it spawns the
49
+ server, so the key stays out of the file and out of version control.
50
+
51
+ ### Claude Desktop: `claude_desktop_config.json`
52
+
53
+ Claude Desktop does not expand shell variables, so write the value literally:
54
+
55
+ ```json
56
+ {
57
+ "mcpServers": {
58
+ "deeprelay": {
59
+ "command": "npx",
60
+ "args": ["-y", "@deeprelay/mcp@latest"],
61
+ "env": {
62
+ "DEEPRELAY_API_KEY": "deeprelay_live_..."
63
+ }
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ The file is at `~/Library/Application Support/Claude/claude_desktop_config.json`
70
+ on macOS and `%APPDATA%\Claude\claude_desktop_config.json` on Windows. Restart
71
+ the app after editing it.
72
+
73
+ For Cursor and other clients, see <https://deeprelay.ai/docs/mcp>.
74
+
75
+ Restart your client, then ask the agent to run `deeprelay_auth_status`. If the
76
+ key is set up correctly, it returns your balance, spending limit and session
77
+ budget.
78
+
79
+ ## Configuration
80
+
81
+ | Variable | Required | Meaning |
82
+ | --- | --- | --- |
83
+ | `DEEPRELAY_API_KEY` | yes | The API key. Put it in the client's `env` block only; it must never be passed in args/argv, where it would show up in `ps` output and shell history. |
84
+ | `DEEPRELAY_API_BASE` | no | Base URL override, for example `https://api.demo.deeprelay.ai/v1`. Unset means production (`https://api.deeprelay.ai/v1`). |
85
+
86
+ Startup is **offline**. The server checks that the key is present and that the
87
+ base URL is valid, and makes no network call at boot. A bad key surfaces as a
88
+ clear error on the first tool call. The key is never echoed in a result, an
89
+ error or a confirmation prompt.
90
+
91
+ **Use a dedicated key** for agent work, so you can revoke it on its own and see
92
+ its usage separately. A `read_only` key covers all 17 free tools and cannot
93
+ write or spend. Checkout, the billing portal and spending-limit changes also
94
+ need the org-admin role. **No key scope limits how much a key can spend.** Your
95
+ organization's spending limit and the session budget below do.
96
+
97
+ ## The three tiers
98
+
99
+ | Tier | Tools | What happens before it runs |
100
+ | --- | --- | --- |
101
+ | Free, read-only | 17 | Nothing. No confirmation, no charge, no change. |
102
+ | Writes: single confirmation | 8 | One confirmation. The first call describes the change and returns a `confirmation_token`. The second call, with the same arguments plus the token, runs it. |
103
+ | Money tools | 4 | A price. Priced from the catalog, then checked against the per-call ceiling and the session budget. |
104
+
105
+ Tokens are single-use, expire after five minutes, and are bound to the exact
106
+ arguments that were quoted. No argument or instruction can replace a token.
107
+ Where the client supports MCP elicitation, the server asks you directly and
108
+ your answer goes through the same token.
109
+
110
+ ## Money tools: one session budget
111
+
112
+ Chat, embeddings, image and video share **one session budget**, and a session is
113
+ one server process.
114
+
115
+ - The first money call asks you to approve a **$5.00** session budget. The agent
116
+ can propose a different amount with `session_budget_usd` (**$1–$100**).
117
+ Confirming approves the budget and runs the call.
118
+ - Calls inside the budget then run with no further prompt.
119
+ - Any single call estimated above the **$0.50 per-call ceiling** is confirmed on
120
+ its own. The ceiling is checked before the budget. A model with no published
121
+ rate is treated the same way and is never assumed to be free.
122
+ - When the budget is spent, the next call asks for a new budget.
123
+
124
+ Estimates are reserved before each call and replaced by the actual cost
125
+ afterwards. A failed call releases its reservation.
126
+
127
+ **Video is quoted as a floor, not a cap.** `deeprelay_videos_create` reserves
128
+ the floor price. When `deeprelay_videos_get` or `deeprelay_videos_list` sees the
129
+ job completed, the reservation settles at the actual `cost_cents`. Failed,
130
+ cancelled or expired jobs are not billed. If the server exits before the job
131
+ finishes, the reservation is dropped and the real charge appears in
132
+ `deeprelay_usage_get` and `deeprelay_balance_get`.
133
+
134
+ > Do not run a spend-capable agent with the client's own approval prompts
135
+ > disabled. The client could then accept confirmations for you. Set an
136
+ > organization spending limit as the ceiling that lasts across sessions.
137
+
138
+ ## Writes: one confirmation
139
+
140
+ - `deeprelay_webhooks_create` states that deeprelay will **send event data to
141
+ this URL**. The signing secret is returned once and can never be read again.
142
+ - `deeprelay_spending_limit_update` is **lower-only**: a raise is refused before
143
+ any confirmation exists. Raise a limit in the dashboard.
144
+ - `deeprelay_spending_limit_clear` **removes the limit entirely**, after one
145
+ confirmation that names the limit and says inference is then bounded only by
146
+ your balance. With no limit set it reports "nothing to clear" and changes
147
+ nothing. From the agent's side a limit can be lowered or cleared, never
148
+ raised.
149
+ - `deeprelay_subscription_checkout`, `deeprelay_billing_portal` and
150
+ `deeprelay_deposits_create_crypto` **only create links** (or a deposit
151
+ address). They never charge. Nothing is paid until you complete the step
152
+ yourself.
153
+ - `deeprelay_deposits_create_crypto` is listed only on accounts with crypto
154
+ deposits enabled. It stays hidden at startup and appears once the account is
155
+ shown to have the feature.
156
+
157
+ ## Tools
158
+
159
+ **Free, read-only (17):** `deeprelay_auth_status`, `deeprelay_health`,
160
+ `deeprelay_models_list`, `deeprelay_models_get`,
161
+ `deeprelay_inference_preflight`, `deeprelay_usage_get`,
162
+ `deeprelay_balance_get`, `deeprelay_spending_limit_get`,
163
+ `deeprelay_subscription_get`, `deeprelay_deposits_list`,
164
+ `deeprelay_deposits_get`, `deeprelay_referrals_get`,
165
+ `deeprelay_webhooks_list`, `deeprelay_webhooks_get`, `deeprelay_videos_list`,
166
+ `deeprelay_videos_get`, `deeprelay_videos_content`.
167
+
168
+ **Writes: single confirmation (8):** `deeprelay_webhooks_create`,
169
+ `deeprelay_webhooks_delete`, `deeprelay_spending_limit_update`,
170
+ `deeprelay_spending_limit_clear`, `deeprelay_subscription_checkout`, `deeprelay_billing_portal`,
171
+ `deeprelay_deposits_create_crypto`, `deeprelay_videos_cancel`.
172
+
173
+ **Money (4):** `deeprelay_chat_completion`, `deeprelay_embeddings_create`,
174
+ `deeprelay_images_generate`, `deeprelay_videos_create`.
175
+
176
+ `deeprelay_health` calls the unauthenticated liveness endpoint, so it answers
177
+ even when the key is wrong or revoked; the server itself still needs
178
+ `DEEPRELAY_API_KEY` set to start. `deeprelay_usage_get` reports serverless
179
+ inference usage: optional `modality` (`chat`, `image`, `video`, `embedding`),
180
+ `model`, `bucket`, `start` and `end`; with no `modality` or `model` it covers
181
+ all four modalities and returns `total_cost_cents` plus per-modality subtotals.
182
+ `deeprelay_videos_content` saves the MP4
183
+ to a local file (under the system temp directory by default, or an absolute
184
+ `output_path`) instead of returning it inline.
185
+
186
+ Per-tool arguments and the full guide are at <https://deeprelay.ai/docs/mcp>.
187
+
188
+ ## Support
189
+
190
+ See <https://deeprelay.ai/docs>.
191
+
192
+ ## License
193
+
194
+ Apache-2.0
package/dist/auth.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ import { Configuration } from "@deeprelay/sdk";
2
+ import type { Env } from "./tools/types.js";
3
+ export type { Env };
4
+ /** The only source of the API credential. */
5
+ export declare const API_KEY_ENV = "DEEPRELAY_API_KEY";
6
+ /** Optional base-URL override (demo, staging, self-hosted). */
7
+ export declare const API_BASE_ENV = "DEEPRELAY_API_BASE";
8
+ /** The default API base. Must stay production (invariant 3). */
9
+ export declare const PROD_API_BASE = "https://api.deeprelay.ai/v1";
10
+ /** A configuration problem found before any request is made. */
11
+ export declare class StartupConfigError extends Error {
12
+ /** The concrete fix, printed under the problem line. */
13
+ readonly remedy: string;
14
+ constructor(message: string, remedy: string);
15
+ }
16
+ /**
17
+ * Return the API key from the environment, or throw StartupConfigError.
18
+ *
19
+ * Presence only: keys are opaque, so there is no format probe and no network
20
+ * call. The value is returned verbatim and is never logged or interpolated.
21
+ */
22
+ export declare function requireApiKey(env?: Env): string;
23
+ /**
24
+ * Resolve the API base URL.
25
+ *
26
+ * Unset or blank resolves to PROD_API_BASE. An override must parse as an
27
+ * absolute http(s) URL; trailing slashes are trimmed so path joins in the SDK
28
+ * never produce `//`.
29
+ */
30
+ export declare function resolveBaseUrl(env?: Env): string;
31
+ /**
32
+ * Build the single SDK Configuration every tool uses.
33
+ *
34
+ * The SDK owns turning accessToken into the bearer header. The User-Agent set
35
+ * here overrides the SDK's own `deeprelay-sdk-ts/<v>` default, because the
36
+ * SDK merges caller headers over its defaults.
37
+ */
38
+ export declare function buildConfiguration(env?: Env, options?: BuildConfigurationOptions): Configuration;
39
+ export interface BuildConfigurationOptions {
40
+ /**
41
+ * Build a keyless Configuration when DEEPRELAY_API_KEY is unset. Only the
42
+ * unauthenticated liveness probe (deeprelay_health) sets this, so an agent
43
+ * can tell "the API is up" apart from "my key is missing". A set key is
44
+ * still attached, and a bad base URL still throws.
45
+ */
46
+ allowMissingKey?: boolean;
47
+ }
48
+ /**
49
+ * Render a startup failure for stderr: the problem on the first line and the
50
+ * remedy on the second. Always redacted, never a stack trace.
51
+ */
52
+ export declare function describeStartupError(err: unknown, env?: Env): string;
package/dist/auth.js ADDED
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StartupConfigError = exports.PROD_API_BASE = exports.API_BASE_ENV = exports.API_KEY_ENV = void 0;
4
+ exports.requireApiKey = requireApiKey;
5
+ exports.resolveBaseUrl = resolveBaseUrl;
6
+ exports.buildConfiguration = buildConfiguration;
7
+ exports.describeStartupError = describeStartupError;
8
+ // Startup configuration and the one API-client construction site
9
+ // (Phase 104, D-12: authored fresh; D-15: @deeprelay/sdk is the client).
10
+ //
11
+ // Invariants this module owns:
12
+ //
13
+ // 1. Boot performs no I/O. The key is presence-checked and the base URL is
14
+ // parsed, and that is all. A network probe at startup would turn a
15
+ // transient blip into "the server will not start", which an operator
16
+ // cannot tell apart from a bad key. A bad key surfaces instead as a mapped
17
+ // 401 on the first real call (errors.ts).
18
+ // 2. The key is read from the environment only: DEEPRELAY_API_KEY. It is
19
+ // never taken from argv (it would show up in `ps` and shell history) and
20
+ // never read from a credentials file on disk.
21
+ // 3. Unset DEEPRELAY_API_BASE means production. A customer package that
22
+ // quietly defaulted to a non-production stack would appear to work while
23
+ // billing the wrong account.
24
+ // 4. Every tool builds its client through buildConfiguration(). It is the only
25
+ // place in the package that constructs a Configuration, so the
26
+ // `deeprelay-mcp/<version>` User-Agent is stamped package-wide and no tool
27
+ // can go out under the wrapped SDK's own default.
28
+ // 5. Every message this module produces goes through redactSecrets().
29
+ const sdk_1 = require("@deeprelay/sdk");
30
+ const errors_js_1 = require("./errors.js");
31
+ const version_js_1 = require("./version.js");
32
+ /** The only source of the API credential. */
33
+ exports.API_KEY_ENV = "DEEPRELAY_API_KEY";
34
+ /** Optional base-URL override (demo, staging, self-hosted). */
35
+ exports.API_BASE_ENV = "DEEPRELAY_API_BASE";
36
+ /** The default API base. Must stay production (invariant 3). */
37
+ exports.PROD_API_BASE = "https://api.deeprelay.ai/v1";
38
+ /** A configuration problem found before any request is made. */
39
+ class StartupConfigError extends Error {
40
+ /** The concrete fix, printed under the problem line. */
41
+ remedy;
42
+ constructor(message, remedy) {
43
+ super(message);
44
+ this.name = "StartupConfigError";
45
+ this.remedy = remedy;
46
+ }
47
+ }
48
+ exports.StartupConfigError = StartupConfigError;
49
+ const MISSING_KEY_REMEDY = `Set ${exports.API_KEY_ENV} in the "env" block of this server's entry in your MCP client configuration ` +
50
+ `(create a key at deeprelay.ai; a dedicated key for agent use can be revoked on its own).`;
51
+ const BAD_BASE_REMEDY = `Set ${exports.API_BASE_ENV} to an absolute http(s) URL such as https://api.demo.deeprelay.ai/v1, ` +
52
+ `or unset it to use production (${exports.PROD_API_BASE}).`;
53
+ /**
54
+ * Return the API key from the environment, or throw StartupConfigError.
55
+ *
56
+ * Presence only: keys are opaque, so there is no format probe and no network
57
+ * call. The value is returned verbatim and is never logged or interpolated.
58
+ */
59
+ function requireApiKey(env = process.env) {
60
+ const key = env[exports.API_KEY_ENV];
61
+ if (key === undefined || key.trim() === "") {
62
+ throw new StartupConfigError(`${exports.API_KEY_ENV} is not set.`, MISSING_KEY_REMEDY);
63
+ }
64
+ return key;
65
+ }
66
+ /**
67
+ * Resolve the API base URL.
68
+ *
69
+ * Unset or blank resolves to PROD_API_BASE. An override must parse as an
70
+ * absolute http(s) URL; trailing slashes are trimmed so path joins in the SDK
71
+ * never produce `//`.
72
+ */
73
+ function resolveBaseUrl(env = process.env) {
74
+ const raw = env[exports.API_BASE_ENV]?.trim();
75
+ if (raw === undefined || raw === "") {
76
+ return exports.PROD_API_BASE;
77
+ }
78
+ let url;
79
+ try {
80
+ url = new URL(raw);
81
+ }
82
+ catch {
83
+ throw new StartupConfigError(`${exports.API_BASE_ENV} is not a valid absolute URL.`, BAD_BASE_REMEDY);
84
+ }
85
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
86
+ throw new StartupConfigError(`${exports.API_BASE_ENV} must use http or https (got ${url.protocol.replace(/:$/, "")}).`, BAD_BASE_REMEDY);
87
+ }
88
+ return raw.replace(/\/+$/, "");
89
+ }
90
+ /**
91
+ * Build the single SDK Configuration every tool uses.
92
+ *
93
+ * The SDK owns turning accessToken into the bearer header. The User-Agent set
94
+ * here overrides the SDK's own `deeprelay-sdk-ts/<v>` default, because the
95
+ * SDK merges caller headers over its defaults.
96
+ */
97
+ function buildConfiguration(env = process.env, options = {}) {
98
+ const accessToken = options.allowMissingKey === true ? optionalApiKey(env) : requireApiKey(env);
99
+ const basePath = resolveBaseUrl(env);
100
+ return new sdk_1.Configuration({
101
+ ...(accessToken === undefined ? {} : { accessToken }),
102
+ basePath,
103
+ headers: { "User-Agent": `deeprelay-mcp/${(0, version_js_1.readVersion)()}` },
104
+ });
105
+ }
106
+ function optionalApiKey(env) {
107
+ const key = env[exports.API_KEY_ENV];
108
+ return key === undefined || key.trim() === "" ? undefined : key;
109
+ }
110
+ /**
111
+ * Render a startup failure for stderr: the problem on the first line and the
112
+ * remedy on the second. Always redacted, never a stack trace.
113
+ */
114
+ function describeStartupError(err, env = process.env) {
115
+ if (err instanceof StartupConfigError) {
116
+ return (0, errors_js_1.redactSecrets)(`deeprelay-mcp: ${err.message}\n${err.remedy}`, env);
117
+ }
118
+ const message = err instanceof Error ? err.message : String(err);
119
+ return (0, errors_js_1.redactSecrets)(`deeprelay-mcp: failed to start: ${message.replace(/\s+/g, " ").trim()}\n` +
120
+ `Check the ${exports.API_KEY_ENV} and ${exports.API_BASE_ENV} settings in your MCP client configuration.`, env);
121
+ }
122
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ import type { Env } from "./tools/types.js";
2
+ /** What replaces anything credential-shaped. */
3
+ export declare const REDACTED = "[REDACTED]";
4
+ /**
5
+ * Strip credentials out of arbitrary text. Two passes, because either alone
6
+ * leaves a hole:
7
+ *
8
+ * 1. the configured key's literal value, which catches a key of any shape
9
+ * (a placeholder, another vendor's key pasted by mistake);
10
+ * 2. the deeprelay token shape, which catches a DIFFERENT key echoed back by
11
+ * the API, one this process never held and so cannot match by value.
12
+ */
13
+ export declare function redactSecrets(text: string, env?: Env): string;
14
+ /**
15
+ * Field names whose string VALUES are credential material. Both spellings,
16
+ * because SDK models are camelCase and raw bodies are snake_case. Exact match:
17
+ * a substring rule would also swallow ordinary fields such as `secret_rotated_at`
18
+ * style metadata or URLs the user needs.
19
+ *
20
+ * The webhook create tool reveals the new endpoint's signing secret exactly
21
+ * once through an explicit reveal path in tools/result.ts. Nothing else ever
22
+ * bypasses this set.
23
+ */
24
+ export declare const CREDENTIAL_KEYS: ReadonlySet<string>;
25
+ /**
26
+ * Return a copy of `value` with every string under a CREDENTIAL_KEYS field
27
+ * replaced by REDACTED, at any depth and inside arrays. The input is never
28
+ * mutated. Non-string credential values (null, absent) are left alone so the
29
+ * agent is not told a secret exists where none does. Class instances such as
30
+ * Date are returned whole rather than flattened.
31
+ */
32
+ export declare function sanitizeCredentialFields(value: unknown): unknown;
33
+ /**
34
+ * A spend or write tool's quote step refusing to price a request. Throwing is
35
+ * what keeps a guardrail from minting a confirmation token for something that
36
+ * has no quote: no quote, no token, no execution. The mapper keeps this
37
+ * error's own wording.
38
+ */
39
+ export declare class QuoteUnavailableError extends Error {
40
+ constructor(message: string);
41
+ }
42
+ /**
43
+ * The HTTP status of an SDK error, or undefined for anything that never got a
44
+ * response. Duck-typed as a fallback so a bundling or version skew that breaks
45
+ * instanceof cannot change behaviour. Exported so callers can branch on a
46
+ * status (e.g. a 404 spending limit meaning "none configured") consistently
47
+ * with the mapper.
48
+ */
49
+ export declare function httpStatusOf(err: unknown): number | undefined;
50
+ /** The parts of an API error body worth keeping. */
51
+ export interface ErrorEnvelope {
52
+ code?: string;
53
+ message?: string;
54
+ }
55
+ export interface MapErrorOptions {
56
+ env?: Env;
57
+ /** A short summary already lifted from the body (see readErrorEnvelope). */
58
+ details?: string;
59
+ /** The API's stable error code, when known. */
60
+ code?: string;
61
+ }
62
+ /**
63
+ * Turn any thrown value into an agent-legible Error. Synchronous so the
64
+ * mapping is directly testable; tool handlers normally call mapSdkErrorAsync,
65
+ * which reads the response body first.
66
+ *
67
+ * `context` names what was being attempted ("listing models"), so a failure
68
+ * several calls deep stays attributable.
69
+ */
70
+ export declare function mapSdkError(err: unknown, context: string, options?: MapErrorOptions): Error;
71
+ /**
72
+ * Read `{ code, message }` out of an SDK error's response body. Accepts both
73
+ * shapes the API returns: the OpenAI envelope `{ error: { code, message } }`
74
+ * and problem+json `{ code, detail }`. Fails closed: anything that is not
75
+ * recognisably one of those yields an empty envelope, never the raw body.
76
+ * Reads a clone, so the caller's Response is left unconsumed.
77
+ */
78
+ export declare function readErrorEnvelope(err: unknown): Promise<ErrorEnvelope>;
79
+ /**
80
+ * The funnel tool handlers call: read the body once, then map. A 401 never
81
+ * uses the body (see statusSentence).
82
+ */
83
+ export declare function mapSdkErrorAsync(err: unknown, context: string, env?: Env): Promise<Error>;