@oneshot-agent/mcp-server 0.39.1 → 0.41.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.
@@ -0,0 +1,105 @@
1
+ /**
2
+ * The two Physical Mail steps that a generated route tool cannot carry (#1883): the send,
3
+ * which needs an idempotency key header beside the quote id and the approval id, and the
4
+ * artwork upload, whose body is a raw PDF, PNG or JPEG. Both go through the SDK's
5
+ * `physicalMail` (libs/agent-sdk/src/physical-mail.ts). The other seven routes (validate,
6
+ * preview, quote, approve, recover, order, cancel) are generated from the declaration.
7
+ */
8
+ /** The route's own limit (`uploadArtwork` in services/physical-mail/service.ts): 20 MB. */
9
+ export const PHYSICAL_MAIL_ASSET_LIMIT_BYTES = 20 * 1024 * 1024;
10
+ export const PHYSICAL_MAIL_ASSET_TYPES = ["application/pdf", "image/png", "image/jpeg"];
11
+ export const physicalMailSendTool = {
12
+ name: "oneshot_physical_mail_send",
13
+ description: "Print and post an approved mailpiece. Paid: the quote's total_usdc is charged (see Pricing), and the receipt is on the order. " +
14
+ "Needs the quote_id from oneshot_physical_mail_preview and the approval_id from oneshot_physical_mail_approve. " +
15
+ "Give an idempotency_key you keep: a retry with the same key returns the same order instead of sending twice, and " +
16
+ "oneshot_physical_mail_recover finds the order by it after a timeout. Returns the order (order_id, order_status, " +
17
+ "payment_status, receipt_id). Delivery is a postal observation, never evidence the mail was read.",
18
+ inputSchema: {
19
+ type: "object",
20
+ properties: {
21
+ quote_id: { type: "string", description: "Quote id from oneshot_physical_mail_preview" },
22
+ approval_id: { type: "string", description: "Approval id from oneshot_physical_mail_approve (the quote's own approval)" },
23
+ idempotency_key: {
24
+ type: "string",
25
+ description: "A key you persist for this send (1-255 characters: letters, digits, _ . : -). Reuse it to retry safely.",
26
+ },
27
+ memo: { type: "string", description: "Why this mail is being sent (audit trail, max 1000 characters; optional)" },
28
+ max_cost: { type: "number", description: "Refuse to pay more than this many USDC (optional)" },
29
+ policy_approval_id: {
30
+ type: "string",
31
+ description: "Only when retrying a send the action policy held: the approval_id from the approval_required error, once a human approved it. Not the quote's approval_id.",
32
+ },
33
+ },
34
+ required: ["quote_id", "approval_id", "idempotency_key"],
35
+ },
36
+ };
37
+ export async function handlePhysicalMailSend(agent, args) {
38
+ return agent.physicalMail.send({
39
+ quote_id: args.quote_id,
40
+ approval_id: args.approval_id,
41
+ idempotencyKey: args.idempotency_key,
42
+ memo: args.memo,
43
+ maxCost: args.max_cost,
44
+ approvalId: args.policy_approval_id,
45
+ });
46
+ }
47
+ export const physicalMailUploadTool = {
48
+ name: "oneshot_physical_mail_upload",
49
+ description: "Upload print-ready artwork for a letter or postcard and get the asset id that oneshot_physical_mail_preview takes in " +
50
+ "artwork.file (a letter needs a PDF) or artwork.front and artwork.back (a postcard). Free. The file is sent as base64; " +
51
+ "it must decode to at most 20 MB. An asset is immutable: upload a new one to change the artwork.",
52
+ inputSchema: {
53
+ type: "object",
54
+ properties: {
55
+ content: { type: "string", description: "The file, base64-encoded (standard or URL-safe alphabet, padding optional)" },
56
+ content_type: { type: "string", enum: [...PHYSICAL_MAIL_ASSET_TYPES], description: "The file's media type" },
57
+ },
58
+ required: ["content", "content_type"],
59
+ },
60
+ };
61
+ /** Decodes the base64 `content`, refusing anything that is not base64 or that would exceed the route's limit before any bytes are sent. */
62
+ export function decodeArtwork(args) {
63
+ const mime = args.content_type;
64
+ if (!PHYSICAL_MAIL_ASSET_TYPES.includes(mime)) {
65
+ throw new Error(`oneshot_physical_mail_upload: content_type must be one of ${PHYSICAL_MAIL_ASSET_TYPES.join(", ")}`);
66
+ }
67
+ if (typeof args.content !== "string" || args.content.length === 0)
68
+ throw new Error("oneshot_physical_mail_upload: content is required");
69
+ const text = args.content.replace(/\s+/g, "");
70
+ const size = base64Size(text);
71
+ if (size === null)
72
+ throw new Error("oneshot_physical_mail_upload: content is not base64");
73
+ if (size > PHYSICAL_MAIL_ASSET_LIMIT_BYTES) {
74
+ throw new Error(`oneshot_physical_mail_upload: the file is ${size} bytes; the limit is ${PHYSICAL_MAIL_ASSET_LIMIT_BYTES} bytes (20 MB)`);
75
+ }
76
+ const data = Buffer.from(text, "base64");
77
+ if (data.length === 0)
78
+ throw new Error("oneshot_physical_mail_upload: content decodes to nothing");
79
+ // The decoder is lenient; the structural check above is what bounds the size, and this guards the limit regardless.
80
+ if (data.length > PHYSICAL_MAIL_ASSET_LIMIT_BYTES) {
81
+ throw new Error(`oneshot_physical_mail_upload: the file is ${data.length} bytes; the limit is ${PHYSICAL_MAIL_ASSET_LIMIT_BYTES} bytes (20 MB)`);
82
+ }
83
+ return { data: new Uint8Array(data), mime: mime };
84
+ }
85
+ /**
86
+ * The decoded size of structurally valid base64 (standard or URL-safe alphabet, padding optional), or null.
87
+ * `Buffer.from(text, "base64")` tolerates a length one past a quartet, missing, short and excess padding
88
+ * (`AAAAA`, `AAA==`, `AAAA==`), so counting characters and subtracting the `=`s would undercount such
89
+ * input; the bound has to come from a shape the decoder cannot read differently.
90
+ */
91
+ export function base64Size(text) {
92
+ if (!/^[A-Za-z0-9+/_-]*={0,2}$/.test(text))
93
+ return null;
94
+ const body = text.replace(/=+$/, "");
95
+ const padding = text.length - body.length;
96
+ const rem = body.length % 4;
97
+ // A body is never one character past a quartet, and padding, when given, is exactly what completes the last one.
98
+ if (body.length === 0 || rem === 1 || (padding > 0 && padding !== (4 - rem) % 4))
99
+ return null;
100
+ return Math.floor((body.length * 3) / 4);
101
+ }
102
+ export async function handlePhysicalMailUpload(agent, args) {
103
+ const { data, mime } = decodeArtwork(args);
104
+ return agent.physicalMail.uploadArtwork(data, mime);
105
+ }
@@ -0,0 +1,275 @@
1
+ export declare const predictInputSchema: {
2
+ readonly type: "object";
3
+ readonly properties: {
4
+ readonly model: {
5
+ readonly type: "string";
6
+ readonly enum: readonly ["simulation", "forecast"];
7
+ };
8
+ readonly time_limit_s: {
9
+ readonly type: "integer";
10
+ readonly minimum: 1;
11
+ readonly maximum: 120;
12
+ readonly default: 20;
13
+ };
14
+ readonly simulation: {
15
+ readonly type: "object";
16
+ readonly properties: {
17
+ readonly runs: {
18
+ readonly type: "integer";
19
+ readonly minimum: 100;
20
+ readonly maximum: 100000;
21
+ readonly default: 10000;
22
+ };
23
+ readonly seed: {
24
+ readonly type: "integer";
25
+ readonly minimum: 0;
26
+ readonly maximum: 4294967295;
27
+ };
28
+ readonly percentiles: {
29
+ readonly type: "array";
30
+ readonly items: {
31
+ readonly type: "number";
32
+ readonly minimum: 0;
33
+ readonly maximum: 100;
34
+ };
35
+ readonly minItems: 1;
36
+ readonly maxItems: 20;
37
+ readonly default: readonly [5, 10, 25, 50, 75, 90, 95];
38
+ };
39
+ readonly variables: {
40
+ readonly type: "array";
41
+ readonly items: {
42
+ readonly type: "object";
43
+ readonly properties: {
44
+ readonly id: {
45
+ readonly type: "string";
46
+ readonly minLength: 1;
47
+ readonly maxLength: 64;
48
+ readonly pattern: "^[A-Za-z_][A-Za-z0-9_]*$";
49
+ };
50
+ readonly distribution: {
51
+ readonly anyOf: readonly [{
52
+ readonly type: "object";
53
+ readonly properties: {
54
+ readonly kind: {
55
+ readonly type: "string";
56
+ readonly const: "fixed";
57
+ };
58
+ readonly value: {
59
+ readonly type: "number";
60
+ };
61
+ };
62
+ readonly required: readonly ["kind", "value"];
63
+ readonly additionalProperties: false;
64
+ }, {
65
+ readonly type: "object";
66
+ readonly properties: {
67
+ readonly kind: {
68
+ readonly type: "string";
69
+ readonly const: "uniform";
70
+ };
71
+ readonly min: {
72
+ readonly type: "number";
73
+ };
74
+ readonly max: {
75
+ readonly type: "number";
76
+ };
77
+ };
78
+ readonly required: readonly ["kind", "min", "max"];
79
+ readonly additionalProperties: false;
80
+ }, {
81
+ readonly type: "object";
82
+ readonly properties: {
83
+ readonly kind: {
84
+ readonly type: "string";
85
+ readonly const: "normal";
86
+ };
87
+ readonly mean: {
88
+ readonly type: "number";
89
+ };
90
+ readonly sd: {
91
+ readonly type: "number";
92
+ readonly exclusiveMinimum: 0;
93
+ };
94
+ };
95
+ readonly required: readonly ["kind", "mean", "sd"];
96
+ readonly additionalProperties: false;
97
+ }, {
98
+ readonly type: "object";
99
+ readonly properties: {
100
+ readonly kind: {
101
+ readonly type: "string";
102
+ readonly const: "lognormal";
103
+ };
104
+ readonly log_mean: {
105
+ readonly type: "number";
106
+ };
107
+ readonly log_sd: {
108
+ readonly type: "number";
109
+ readonly exclusiveMinimum: 0;
110
+ };
111
+ };
112
+ readonly required: readonly ["kind", "log_mean", "log_sd"];
113
+ readonly additionalProperties: false;
114
+ }, {
115
+ readonly type: "object";
116
+ readonly properties: {
117
+ readonly kind: {
118
+ readonly type: "string";
119
+ readonly const: "triangular";
120
+ };
121
+ readonly min: {
122
+ readonly type: "number";
123
+ };
124
+ readonly mode: {
125
+ readonly type: "number";
126
+ };
127
+ readonly max: {
128
+ readonly type: "number";
129
+ };
130
+ };
131
+ readonly required: readonly ["kind", "min", "mode", "max"];
132
+ readonly additionalProperties: false;
133
+ }, {
134
+ readonly type: "object";
135
+ readonly properties: {
136
+ readonly kind: {
137
+ readonly type: "string";
138
+ readonly const: "bernoulli";
139
+ };
140
+ readonly p: {
141
+ readonly type: "number";
142
+ readonly minimum: 0;
143
+ readonly maximum: 1;
144
+ };
145
+ };
146
+ readonly required: readonly ["kind", "p"];
147
+ readonly additionalProperties: false;
148
+ }, {
149
+ readonly type: "object";
150
+ readonly properties: {
151
+ readonly kind: {
152
+ readonly type: "string";
153
+ readonly const: "discrete";
154
+ };
155
+ readonly values: {
156
+ readonly type: "array";
157
+ readonly items: {
158
+ readonly type: "number";
159
+ };
160
+ readonly minItems: 1;
161
+ readonly maxItems: 100;
162
+ };
163
+ readonly weights: {
164
+ readonly type: "array";
165
+ readonly items: {
166
+ readonly type: "number";
167
+ readonly minimum: 0;
168
+ };
169
+ readonly minItems: 1;
170
+ readonly maxItems: 100;
171
+ };
172
+ };
173
+ readonly required: readonly ["kind", "values"];
174
+ readonly additionalProperties: false;
175
+ }];
176
+ };
177
+ };
178
+ readonly required: readonly ["id", "distribution"];
179
+ readonly additionalProperties: false;
180
+ };
181
+ readonly minItems: 1;
182
+ readonly maxItems: 50;
183
+ };
184
+ readonly outputs: {
185
+ readonly type: "array";
186
+ readonly items: {
187
+ readonly type: "object";
188
+ readonly properties: {
189
+ readonly id: {
190
+ readonly type: "string";
191
+ readonly minLength: 1;
192
+ readonly maxLength: 64;
193
+ readonly pattern: "^[A-Za-z_][A-Za-z0-9_]*$";
194
+ };
195
+ readonly expression: {
196
+ readonly type: "string";
197
+ readonly minLength: 1;
198
+ readonly maxLength: 1000;
199
+ };
200
+ };
201
+ readonly required: readonly ["id", "expression"];
202
+ readonly additionalProperties: false;
203
+ };
204
+ readonly minItems: 1;
205
+ readonly maxItems: 10;
206
+ };
207
+ };
208
+ readonly required: readonly ["variables", "outputs"];
209
+ readonly additionalProperties: false;
210
+ };
211
+ readonly forecast: {
212
+ readonly type: "object";
213
+ readonly properties: {
214
+ readonly series: {
215
+ readonly type: "array";
216
+ readonly items: {
217
+ readonly type: "object";
218
+ readonly properties: {
219
+ readonly t: {
220
+ readonly anyOf: readonly [{
221
+ readonly type: "string";
222
+ readonly minLength: 1;
223
+ }, {
224
+ readonly type: "integer";
225
+ readonly minimum: -9007199254740991;
226
+ readonly maximum: 9007199254740991;
227
+ }];
228
+ };
229
+ readonly y: {
230
+ readonly type: "number";
231
+ };
232
+ };
233
+ readonly required: readonly ["t", "y"];
234
+ readonly additionalProperties: false;
235
+ };
236
+ readonly minItems: 8;
237
+ readonly maxItems: 10000;
238
+ };
239
+ readonly horizon: {
240
+ readonly type: "integer";
241
+ readonly minimum: 1;
242
+ readonly maximum: 365;
243
+ };
244
+ readonly frequency: {
245
+ readonly type: "string";
246
+ readonly enum: readonly ["hourly", "daily", "weekly", "monthly", "quarterly", "yearly"];
247
+ };
248
+ readonly seasonal_period: {
249
+ readonly type: "integer";
250
+ readonly minimum: 2;
251
+ readonly maximum: 366;
252
+ };
253
+ readonly interval_levels: {
254
+ readonly type: "array";
255
+ readonly items: {
256
+ readonly type: "integer";
257
+ readonly minimum: 50;
258
+ readonly maximum: 99;
259
+ };
260
+ readonly minItems: 1;
261
+ readonly maxItems: 3;
262
+ readonly default: readonly [80, 95];
263
+ };
264
+ readonly floor: {
265
+ readonly type: "number";
266
+ };
267
+ };
268
+ readonly required: readonly ["series", "horizon"];
269
+ readonly additionalProperties: false;
270
+ };
271
+ };
272
+ readonly required: readonly ["model"];
273
+ readonly additionalProperties: false;
274
+ readonly $schema: "http://json-schema.org/draft-07/schema#";
275
+ };