@womp/openai-plugin 0.6.0 → 0.8.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.
- package/README.md +28 -11
- package/dist/index.d.ts +33 -61
- package/dist/index.js +98 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,13 +25,15 @@ src/
|
|
|
25
25
|
backend.ts WompBackend: the contract the host implements
|
|
26
26
|
tools/ one file per tool group (scene.ts, commerce.ts); tool.ts: shared helpers
|
|
27
27
|
cards/ one folder per card (design/, quote/, order/); bridge.ts: shared host connection
|
|
28
|
+
printability.ts the print checks finish_scene and checkout_design make
|
|
28
29
|
text.ts what tools and cards say to the model
|
|
29
|
-
prompts/ the workflow the model follows
|
|
30
|
+
prompts/ the workflow the model follows: brief.ts, experience.ts, modelling.ts, hardware.ts, printability.ts; index.ts joins them
|
|
30
31
|
```
|
|
31
32
|
|
|
32
33
|
### Dependency rules
|
|
33
34
|
|
|
34
|
-
- `server` → `tools` → `backend`, `text`, `prompts`, `cards/<card>/data.ts`.
|
|
35
|
+
- `server` → `tools` → `backend`, `printability`, `text`, `prompts`, `cards/<card>/data.ts`.
|
|
36
|
+
- `text` and `printability` → `backend` (types only).
|
|
35
37
|
- `cards/<card>` → its own `data.ts` and `cards/bridge.ts`. A card never imports `tools`, `server` or `backend`.
|
|
36
38
|
- Nothing imports `server` except `index`. Nothing outside this package sees more than the public API.
|
|
37
39
|
|
|
@@ -43,6 +45,7 @@ src/
|
|
|
43
45
|
| `WompBackend` | the contract the host implements |
|
|
44
46
|
| `BackendRefusal` | an error whose message reaches the model as worded |
|
|
45
47
|
| `CheckoutSession`, `CompleteCheckoutArgs` | ChatGPT's payment sheet: the session it takes, and what it hands `complete_checkout` |
|
|
48
|
+
| `LiveView`, `ClaimLink` | what `openScene` and `claimLink` return for the design card's live view and account link |
|
|
46
49
|
|
|
47
50
|
`subject` is the caller as the host established it. `onError` receives every
|
|
48
51
|
error that is not a `BackendRefusal`. `instructions` is appended to the
|
|
@@ -59,15 +62,16 @@ sign-in.
|
|
|
59
62
|
|
|
60
63
|
| Method | Does |
|
|
61
64
|
|---|---|
|
|
62
|
-
| `openScene(subject, { designId?, title? })` | finds the caller's design, or makes one, and opens a **build** of it; returns `{ designId, buildId, title }` |
|
|
65
|
+
| `openScene(subject, { designId?, title? })` | finds the caller's design, or makes one, and opens a **build** of it; returns `{ designId, buildId, title, live? }`, `live` only from a host that can show the design live |
|
|
63
66
|
| `getSceneApi()` | the scene skill, script limits, view names, and `notes` about these designs |
|
|
64
67
|
| `runScript(subject, { designId, code, purpose })` | runs one script on the design; `purpose` becomes the current build's activity, its last screenshot or a fresh render its picture; a failed script returns `ok: false` |
|
|
65
68
|
| `renderScene(subject, { designId, view?, targetId? })` | renders the design; the image also becomes the current build's picture |
|
|
66
|
-
| `
|
|
69
|
+
| `getMaterials(subject)` | the materials on offer to the caller, before any design exists: each with its label, whether it prints in one colour (`colorRequired`) and its finishes, the first the default; and the largest size checkout takes |
|
|
70
|
+
| `analyzePrint(subject, { designId })` | the design as its scene is now, analysed as it prints at its own size and changing nothing, leaving out Areas named `REFERENCE` (bought parts modelled only to show a fit): size, whether it fits the largest size, separate pieces, and the price per piece in each material on offer |
|
|
71
|
+
| `finishScene(subject, { designId, title })` | marks the current build done, with this version's title; called only for a design that passed the print checks |
|
|
67
72
|
| `claimLink?(subject)` | optional: a one-time link to a page that keeps the chat's designs in an account; without it the design card offers no button |
|
|
68
73
|
| `getBuild(subject, { designId, buildId })` | a build's status, activity, title and picture; a build that isn't the caller's reads as empty |
|
|
69
|
-
| `
|
|
70
|
-
| `checkoutDesign(subject, { designId, material, color?, finish?, quantity?, longestSideCm?, shipTo? })` | freezes the design as quoted and returns the quote with its checkout link; with `shipTo`, also the order to that address as a payment-sheet session |
|
|
74
|
+
| `checkoutDesign(subject, { designId, material, color?, finish?, quantity?, shipTo? })` | freezes the design as quoted, at its own size and without its `REFERENCE` Areas, and returns the quote with its checkout link; with `shipTo`, also the order to that address as a payment-sheet session; called only for a design that passed the print checks |
|
|
71
75
|
| `completeCheckout?(subject, payment)` | optional: charges a payment made in ChatGPT's payment sheet and places the session's order; without it `checkout_design` takes no `shipTo` and there is no `complete_checkout` |
|
|
72
76
|
| `getOrderStatus(subject, { orderId? })` | the caller's paid orders, newest first, and the one to show, with no name, address, email or money |
|
|
73
77
|
|
|
@@ -77,11 +81,19 @@ changes an earlier one.
|
|
|
77
81
|
### Plugin → model and cards
|
|
78
82
|
|
|
79
83
|
- **Identity.** Every tool acts as `subject`, the signed-in Womp account. Tool arguments and client `_meta` are never read for identity. Without a subject every tool call fails; with `wwwAuthenticate`, the failure carries that challenge in `_meta["mcp/www_authenticate"]`, so ChatGPT offers to link the account.
|
|
84
|
+
- **Brief and review.** `open_scene` requires a brief (a full one for a new design, an edit brief to reopen one) and `finish_scene` the critic's review. Both stay in the chat: the backend never receives them.
|
|
85
|
+
- **Print checks.** `finish_scene` and `checkout_design` take the material, finish, colour and pieces, analyse the design as it is now (`analyzePrint`) and check it (`printability.ts`): the material and finish are on offer, a material that prints in one colour has it as `#rrggbb`, the size fits, and it prints as the pieces given (1 by default). Only a design that passes is finished (`finishScene`) or quoted (`checkoutDesign`).
|
|
86
|
+
- **Prompts** are five parts, each a template literal in its own tag, after one line on the workflow.
|
|
87
|
+
- `<brief>` (`brief.ts`): what to build: research, size, parts, proportions, silhouette, the material and the pieces.
|
|
88
|
+
- `<experience>` (`experience.ts`): the user, the conversation, the card, the product shot, the order of the tools, the print checks as they reach the user.
|
|
89
|
+
- `<modelling>` (`modelling.ts`): building, inspecting and reviewing the scene, the Womp way and the critic pass.
|
|
90
|
+
- `<hardware>` (`hardware.ts`): cases for real devices: the fit model in `REFERENCE` Areas, the case around it, the build guide and the Womp price.
|
|
91
|
+
- `<printability>` (`printability.ts`): the physical object: one material, real colours, the review before finishing, how each material prints, what finish_scene and checkout_design check, and a guide to minimums while building (walls by size, protrusions and loops, details, moving and separate parts).
|
|
80
92
|
- **Errors.** A `BackendRefusal` message reaches the model as is. Any other error is one generic failure, reported to `onError`.
|
|
81
93
|
- **Tool metadata states facts.** Descriptions, input schemas and server instructions say what a tool does, never how the model should behave. Behaviour lives in `prompts/` and reaches the model in `load_scene_skill`'s result.
|
|
82
94
|
- **Every tool** declares `ui.visibility`, explicit annotation hints, and `securitySchemes: oauth2` with the `mcp:generate` scope. Tools only a card calls are `ui.visibility: ["app"]`.
|
|
83
95
|
- **Card data** is the tool result's `structuredContent`, typed by the card's `data.ts`. Tools map backend types to it; a card never receives backend types. What only the card may see is in the result's `_meta`, typed by the same `data.ts`: a link that is a credential, and a quote or an order, which the model would otherwise draw as a card of its own.
|
|
84
|
-
- **Cards** are MCP Apps resources (`text/html;profile=mcp-app`): one self-contained HTML file each, loading
|
|
96
|
+
- **Cards** are MCP Apps resources (`text/html;profile=mcp-app`): one self-contained HTML file each, loading no script, style or font from outside, with a `ui://` URI that changes with its content. Only the design card frames a page: the live view, on `liveViewOrigin`.
|
|
85
97
|
|
|
86
98
|
### Tools
|
|
87
99
|
|
|
@@ -94,7 +106,6 @@ changes an earlier one.
|
|
|
94
106
|
| `finish_scene` | model | |
|
|
95
107
|
| `get_scene_progress` | `design` card | |
|
|
96
108
|
| `get_claim_link` | `design` card | |
|
|
97
|
-
| `get_print_options` | model | |
|
|
98
109
|
| `checkout_design` | model | shows `quote` |
|
|
99
110
|
| `complete_checkout` | model and ChatGPT's payment sheet, only with `completeCheckout` | |
|
|
100
111
|
| `get_order_status` | model | shows `order` |
|
|
@@ -116,10 +127,16 @@ implementation in the same release.
|
|
|
116
127
|
## Development
|
|
117
128
|
|
|
118
129
|
```bash
|
|
119
|
-
npm run dev
|
|
120
|
-
npm
|
|
121
|
-
npm
|
|
130
|
+
npm run dev # card preview at http://127.0.0.1:5188/preview/, live from source
|
|
131
|
+
npm run dev:chatgpt # this working copy in real ChatGPT on :8787, forwarding the rest to UPSTREAM (default staging)
|
|
132
|
+
npm test # build the cards, run the tests
|
|
133
|
+
npm run check # format, build, typecheck, tests (CI)
|
|
122
134
|
```
|
|
123
135
|
|
|
136
|
+
`dev:chatgpt` serves the instructions, tools, cards and workflow from `src/` and forwards every other call to a
|
|
137
|
+
deployed swan (`UPSTREAM`, default staging), signed in as you: open `http://localhost:8787/login` once; the sign-in is
|
|
138
|
+
kept in `dev/.token`. Expose it with a tunnel (`cloudflared tunnel --url http://localhost:8787`) and add the https URL
|
|
139
|
+
in ChatGPT with no authentication. New backend methods still need a swan deploy.
|
|
140
|
+
|
|
124
141
|
Release: bump the version and tag `vX.Y.Z`; CI publishes to npm. Then bump the
|
|
125
142
|
dependency in swan-backend.
|
package/dist/index.d.ts
CHANGED
|
@@ -40,19 +40,12 @@ interface Build {
|
|
|
40
40
|
title?: string;
|
|
41
41
|
picture: Picture | null;
|
|
42
42
|
}
|
|
43
|
-
/**
|
|
44
|
-
* The design live in 3D, for the card to frame: a page on the host's own origin (the
|
|
45
|
-
* `liveViewOrigin` option) and when its key stops working. The URL carries a credential, so it goes to
|
|
46
|
-
* the card alone, never into text the model reads.
|
|
47
|
-
*/
|
|
43
|
+
/** The design live in 3D, on `liveViewOrigin`, until `expiresAt`. A credential: for the card alone. */
|
|
48
44
|
interface LiveView {
|
|
49
45
|
url: string;
|
|
50
46
|
expiresAt: string;
|
|
51
47
|
}
|
|
52
|
-
/**
|
|
53
|
-
* A one-time link that opens a page for keeping this chat's designs and orders in a Womp account. Like `LiveView`
|
|
54
|
-
* it is a credential: it goes to the card alone, when the user asks for it, and never into text the model reads.
|
|
55
|
-
*/
|
|
48
|
+
/** A one-time link to keep the chat's designs and orders in a Womp account. A credential: for the card alone. */
|
|
56
49
|
interface ClaimLink {
|
|
57
50
|
url: string;
|
|
58
51
|
expiresAt: string;
|
|
@@ -62,34 +55,35 @@ interface Size {
|
|
|
62
55
|
height: number;
|
|
63
56
|
depth: number;
|
|
64
57
|
}
|
|
65
|
-
/**
|
|
58
|
+
/** Below `amount` in items, checkout tops the order up to it (`topUp`) or refuses it. */
|
|
66
59
|
interface MinimumOrder {
|
|
67
60
|
amount: number;
|
|
68
61
|
topUp: boolean;
|
|
69
62
|
}
|
|
70
|
-
/** One material
|
|
71
|
-
interface
|
|
72
|
-
/** The name checkout_design
|
|
63
|
+
/** One material on offer for printing. */
|
|
64
|
+
interface Material {
|
|
65
|
+
/** The name finish_scene and checkout_design take, such as "resin-clear-tinted". */
|
|
73
66
|
material: string;
|
|
74
67
|
/** Such as "Tinted clear". */
|
|
75
68
|
label: string;
|
|
69
|
+
/** The whole print is one dye colour, which the order names. */
|
|
70
|
+
colorRequired: boolean;
|
|
71
|
+
/** The finishes it is made in; the first is the default. */
|
|
72
|
+
finishes: string[];
|
|
73
|
+
}
|
|
74
|
+
/** One material a design can be printed in, priced per piece. */
|
|
75
|
+
interface PrintOption extends Material {
|
|
76
76
|
/** Per piece, before shipping. */
|
|
77
77
|
unitPrice: number;
|
|
78
78
|
/** Business days to make it, once ordered. */
|
|
79
79
|
productionDays: number;
|
|
80
|
-
/** The material is dyed, so an order names a colour. */
|
|
81
|
-
colorRequired: boolean;
|
|
82
|
-
/** The finishes it is made in; the first is the default. */
|
|
83
|
-
finishes: string[];
|
|
84
80
|
}
|
|
85
|
-
/** A design
|
|
86
|
-
interface
|
|
81
|
+
/** A design analysed as it prints, at its own size, and priced in each material on offer. */
|
|
82
|
+
interface PrintAnalysis {
|
|
87
83
|
designId: string;
|
|
88
84
|
title: string;
|
|
89
|
-
/**
|
|
85
|
+
/** In cm. */
|
|
90
86
|
sizeCm: Size;
|
|
91
|
-
/** Scaled to the longest side asked for, rather than at its own size. */
|
|
92
|
-
resized: boolean;
|
|
93
87
|
/** How many separate pieces it prints as. */
|
|
94
88
|
pieces: number;
|
|
95
89
|
/** The largest size checkout takes, in cm, in any orientation. */
|
|
@@ -97,7 +91,6 @@ interface PrintOptions {
|
|
|
97
91
|
/** Whether `sizeCm` fits within `maxSizeCm`. */
|
|
98
92
|
fits: boolean;
|
|
99
93
|
currency: string;
|
|
100
|
-
minimumOrder: MinimumOrder;
|
|
101
94
|
options: PrintOption[];
|
|
102
95
|
}
|
|
103
96
|
/** Where an order paid in ChatGPT's payment sheet ships. */
|
|
@@ -112,10 +105,7 @@ interface ShipTo {
|
|
|
112
105
|
country: string;
|
|
113
106
|
phoneNumber?: string;
|
|
114
107
|
}
|
|
115
|
-
/**
|
|
116
|
-
* The user's own checkout on the web, where they enter an address and pay. Like `ClaimLink` it is a credential: it goes
|
|
117
|
-
* to the card alone, never into text the model reads.
|
|
118
|
-
*/
|
|
108
|
+
/** The user's own checkout on the web. A credential: for the card alone. */
|
|
119
109
|
interface CheckoutLink {
|
|
120
110
|
url: string;
|
|
121
111
|
expiresAt: string;
|
|
@@ -227,10 +217,7 @@ interface OrderSummary {
|
|
|
227
217
|
id: number;
|
|
228
218
|
statusLabel: string;
|
|
229
219
|
}
|
|
230
|
-
/**
|
|
231
|
-
* An order as the chat may show it. A checkout link can be forwarded and its buyer's order is found too, so it carries
|
|
232
|
-
* no name, address, email or money.
|
|
233
|
-
*/
|
|
220
|
+
/** An order as the chat may show it: no name, address, email or money. */
|
|
234
221
|
interface Order extends OrderSummary {
|
|
235
222
|
step: "paid" | "printing" | "shipped" | "delivered" | "canceled";
|
|
236
223
|
/** Only the items made from this user's checkout links. */
|
|
@@ -243,7 +230,7 @@ interface Order extends OrderSummary {
|
|
|
243
230
|
carrier: string;
|
|
244
231
|
trackingNumber: string;
|
|
245
232
|
}[];
|
|
246
|
-
/** When it leaves the factory and
|
|
233
|
+
/** When it leaves the factory and arrives (ISO); null when it can't be dated. */
|
|
247
234
|
timeline: {
|
|
248
235
|
factoryShippingStartedAt: string;
|
|
249
236
|
deliveredAt: string;
|
|
@@ -273,23 +260,25 @@ interface WompBackend {
|
|
|
273
260
|
view?: string;
|
|
274
261
|
targetId?: number;
|
|
275
262
|
}): Promise<Image>;
|
|
263
|
+
/** The materials on offer to this user, and the largest size checkout takes, before any design exists. */
|
|
264
|
+
getMaterials(subject: string): Promise<{
|
|
265
|
+
materials: Material[];
|
|
266
|
+
maxSizeCm: [number, number, number];
|
|
267
|
+
}>;
|
|
268
|
+
/** The design as its scene is now, analysed and priced. Changes nothing. */
|
|
269
|
+
analyzePrint(subject: string, input: {
|
|
270
|
+
designId: string;
|
|
271
|
+
}): Promise<PrintAnalysis>;
|
|
276
272
|
finishScene(subject: string, input: {
|
|
277
273
|
designId: string;
|
|
278
274
|
title: string;
|
|
279
275
|
}): Promise<void>;
|
|
280
|
-
/**
|
|
281
|
-
* Optional: a host that cannot keep a chat's designs in an account leaves it out, and the card shows no button.
|
|
282
|
-
* Returns undefined when it has no link to give right now.
|
|
283
|
-
*/
|
|
276
|
+
/** Optional: without it the card offers no account button. Undefined when no link is available now. */
|
|
284
277
|
claimLink?(subject: string): Promise<ClaimLink | undefined>;
|
|
285
278
|
getBuild(subject: string, input: {
|
|
286
279
|
designId: string;
|
|
287
280
|
buildId: string;
|
|
288
281
|
}): Promise<Build>;
|
|
289
|
-
getPrintOptions(subject: string, input: {
|
|
290
|
-
designId: string;
|
|
291
|
-
longestSideCm?: number;
|
|
292
|
-
}): Promise<PrintOptions>;
|
|
293
282
|
/** Freezes the design as quoted, so its order prints it as it is now. `shipTo` comes only to a host with `completeCheckout`. */
|
|
294
283
|
checkoutDesign(subject: string, input: {
|
|
295
284
|
designId: string;
|
|
@@ -297,14 +286,9 @@ interface WompBackend {
|
|
|
297
286
|
color?: string;
|
|
298
287
|
finish?: string;
|
|
299
288
|
quantity?: number;
|
|
300
|
-
longestSideCm?: number;
|
|
301
289
|
shipTo?: ShipTo;
|
|
302
290
|
}): Promise<Checkout>;
|
|
303
|
-
/**
|
|
304
|
-
* Optional: paying in ChatGPT's payment sheet. It charges the payment the sheet hands over and places the session's
|
|
305
|
-
* order; a refused payment returns the session with an error message. A host that leaves it out takes no address in
|
|
306
|
-
* checkout_design, and checkout is on the web alone.
|
|
307
|
-
*/
|
|
291
|
+
/** Optional: charges a payment from ChatGPT's payment sheet and places the order; without it, checkout is on the web alone. */
|
|
308
292
|
completeCheckout?(subject: string, payment: CompleteCheckoutArgs): Promise<CheckoutSession>;
|
|
309
293
|
/** The user's paid orders, newest first, and the one to show: `orderId` when it is one of theirs, else the newest. */
|
|
310
294
|
getOrderStatus(subject: string, input: {
|
|
@@ -322,23 +306,11 @@ interface ServerOptions {
|
|
|
322
306
|
subject?: string;
|
|
323
307
|
onError?: (tool: string, error: unknown) => void;
|
|
324
308
|
instructions?: string;
|
|
325
|
-
/**
|
|
326
|
-
* The one origin the card may frame for a live view, such as "https://app.womp.com". Without it the
|
|
327
|
-
* card allows no frames and `live` from the backend is ignored; an `http:` origin, a path or anything
|
|
328
|
-
* that is not an origin is the same as none.
|
|
329
|
-
*/
|
|
309
|
+
/** The one https origin the design card may frame for a live view; without it, no live view. */
|
|
330
310
|
liveViewOrigin?: string;
|
|
331
|
-
/**
|
|
332
|
-
* The origins of the web pages the cards open — checkout, an order's status, keeping designs in an account — such as
|
|
333
|
-
* ["https://app.womp.com"]. ChatGPT opens a page on one of them without asking the user first; anything that is not
|
|
334
|
-
* an https origin is left out.
|
|
335
|
-
*/
|
|
311
|
+
/** The https origins of the pages the cards open, which ChatGPT then opens without asking. */
|
|
336
312
|
linkOrigins?: string[];
|
|
337
|
-
/**
|
|
338
|
-
* The host's OAuth challenge, a `WWW-Authenticate` value, for a request whose sign-in is missing or not valid. With
|
|
339
|
-
* it and no subject, every tool call fails with the challenge in `_meta["mcp/www_authenticate"]`, which is what
|
|
340
|
-
* makes ChatGPT offer to link the account.
|
|
341
|
-
*/
|
|
313
|
+
/** The host's `WWW-Authenticate` challenge for a request without a valid sign-in. */
|
|
342
314
|
wwwAuthenticate?: string;
|
|
343
315
|
}
|
|
344
316
|
declare function createServer({ backend, subject, onError, instructions, liveViewOrigin, linkOrigins, wwwAuthenticate }: ServerOptions): McpServer;
|