@jigs.design/server 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -13
- package/dist/chat.d.ts +2 -2
- package/dist/chat.js +46 -34
- package/dist/compile-cache.js +60 -0
- package/dist/compile.d.ts +1 -1
- package/dist/compile.js +182 -40
- package/dist/{server.d.ts → core.d.ts} +7 -3
- package/dist/core.js +722 -0
- package/dist/errors.d.ts +2 -2
- package/dist/errors.js +3 -3
- package/dist/events.js +129 -0
- package/dist/handler.d.ts +4 -0
- package/dist/handler.js +344 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +3 -2
- package/dist/inputs.js +16 -1
- package/dist/model-server.js +155 -0
- package/dist/session.d.ts +1 -2
- package/dist/session.js +116 -52
- package/dist/types.d.ts +292 -55
- package/package.json +6 -6
- package/dist/server.js +0 -786
package/dist/types.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { Advice, DesignCheckCode, Placement } from "./design.js";
|
|
|
2
2
|
import { ConfirmationStore } from "./confirm.js";
|
|
3
3
|
import { EditFailureReason } from "@jigs.design/compiler";
|
|
4
4
|
import { PromptMode } from "@jigs.design/prompt";
|
|
5
|
-
import { ActionDefinition, CallPolicy, Catalog, Host, InputOf, MutationDefinition, OutputOf, ProcedureDefinition, Procedures } from "@jigs.design/host";
|
|
6
|
-
import { ChatBlock, ChatBlockStatus, Diagnostic, Invalidation, JigsErrorData, Message, Program, SessionEvent } from "@jigs.design/protocol";
|
|
5
|
+
import { ActionDefinition, CallPolicy, Catalog, DataDefinition, Host, InputOf, JigDefinition, MutationDefinition, OutputOf, PageName, ProcedureDefinition, Procedures, QueryDefinition } from "@jigs.design/host";
|
|
6
|
+
import { ChatBlock, ChatBlockStatus, Diagnostic, Invalidation, JigsErrorData, JsonValue, Message, PageInvalidation, PageProps, PageRef, Program, SessionEvent } from "@jigs.design/protocol";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
//#region src/types.d.ts
|
|
9
9
|
/**
|
|
@@ -25,7 +25,11 @@ export type ModelRequestKind = "chat-repair" | "repair" | "session";
|
|
|
25
25
|
export interface ModelRequest<TContext, TOptions> {
|
|
26
26
|
ctx: TContext;
|
|
27
27
|
kind: ModelRequestKind;
|
|
28
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* The conversation, with the server's repair turns added. In a session
|
|
30
|
+
* about a document, the last user message carries the current UI before
|
|
31
|
+
* the ask (`withDocument`), on every call.
|
|
32
|
+
*/
|
|
29
33
|
messages: ReadonlyArray<Message>;
|
|
30
34
|
options: TOptions;
|
|
31
35
|
signal: AbortSignal;
|
|
@@ -51,9 +55,10 @@ export interface TurnEdits {
|
|
|
51
55
|
blocks: number;
|
|
52
56
|
/**
|
|
53
57
|
* Why the first edit that failed did: its SEARCH text is not in the
|
|
54
|
-
* source (`"missing"`) or is there more than once (`"ambiguous"`),
|
|
55
|
-
*
|
|
56
|
-
*
|
|
58
|
+
* source (`"missing"`) or is there more than once (`"ambiguous"`), an
|
|
59
|
+
* earlier edit of the reply changes some of the same lines
|
|
60
|
+
* (`"overlapping"`), the block is broken (`"malformed"`), or the edit
|
|
61
|
+
* left a tag unclosed or closed one twice (`"broken"`).
|
|
57
62
|
*/
|
|
58
63
|
reason?: EditFailureReason;
|
|
59
64
|
}
|
|
@@ -110,6 +115,12 @@ export interface Turn<TContext, TOptions> {
|
|
|
110
115
|
ctx: TContext;
|
|
111
116
|
/** The diagnostics sent with `done`; empty when the turn did not finish. */
|
|
112
117
|
diagnostics: ReadonlyArray<Diagnostic>;
|
|
118
|
+
/**
|
|
119
|
+
* The source the turn started from, as the request carried it or the
|
|
120
|
+
* page it named resolved to; null when the turn wrote a new UI. A chat
|
|
121
|
+
* repair's is the block it repairs.
|
|
122
|
+
*/
|
|
123
|
+
document: string | null;
|
|
113
124
|
/**
|
|
114
125
|
* Milliseconds from the start of the turn to its first `program` event;
|
|
115
126
|
* null when it sent none. A chat repair sends its block once, when it is
|
|
@@ -118,6 +129,7 @@ export interface Turn<TContext, TOptions> {
|
|
|
118
129
|
firstProgramMs: number | null;
|
|
119
130
|
/** A session turn, or the repair of a chat block, which is a turn of its own. */
|
|
120
131
|
kind: "chat-repair" | "session";
|
|
132
|
+
/** The conversation as the request carried it, without the document. */
|
|
121
133
|
messages: ReadonlyArray<Message>;
|
|
122
134
|
options: TOptions;
|
|
123
135
|
/**
|
|
@@ -147,9 +159,10 @@ type DeepReadonly<T> = T extends object ? { readonly [K in keyof T]: DeepReadonl
|
|
|
147
159
|
type RunOutput<P extends ProcedureDefinition> = DeepReadonly<OutputOf<P>>;
|
|
148
160
|
/**
|
|
149
161
|
* One function per query and mutation. Actions have none: the page handles
|
|
150
|
-
* them, and the server only checks their input.
|
|
162
|
+
* them, and the server only checks their input. Provided data has none
|
|
163
|
+
* either: the page supplies it.
|
|
151
164
|
*/
|
|
152
|
-
export type RunFunctions<TProcedures extends Procedures, TContext> = { readonly [K in keyof TProcedures as TProcedures[K] extends ActionDefinition ? never : K]: (input: InputOf<TProcedures[K]>, call: CallContext<TContext>) => RunOutput<TProcedures[K]> | Promise<RunOutput<TProcedures[K]>>; };
|
|
165
|
+
export type RunFunctions<TProcedures extends Procedures, TContext> = { readonly [K in keyof TProcedures as TProcedures[K] extends ActionDefinition | DataDefinition ? never : K]: (input: InputOf<TProcedures[K]>, call: CallContext<TContext>) => RunOutput<TProcedures[K]> | Promise<RunOutput<TProcedures[K]>>; };
|
|
153
166
|
export type ContextFunction<TContext> = (request: Request) => TContext | Promise<TContext>;
|
|
154
167
|
/** The names of a host's mutations. */
|
|
155
168
|
type MutationName<TProcedures extends Procedures> = { [K in keyof TProcedures & string]: TProcedures[K] extends MutationDefinition ? K : never; }[keyof TProcedures & string];
|
|
@@ -168,39 +181,142 @@ export type PolicyCall<TProcedures extends Procedures, TContext> = { [K in Mutat
|
|
|
168
181
|
* as "requires-action" when the server asks the page, and once as
|
|
169
182
|
* "confirmed" when it ran with the user's approval.
|
|
170
183
|
*/
|
|
171
|
-
export type CallReportOutcome = "confirmed" | "denied" | "error" | "requires-action" | "success";
|
|
172
|
-
/**
|
|
184
|
+
export type CallReportOutcome = "aborted" | "confirmed" | "denied" | "error" | "requires-action" | "success";
|
|
185
|
+
/**
|
|
186
|
+
* One call to a query, mutation or action, or one page request, as
|
|
187
|
+
* `onCall` receives it.
|
|
188
|
+
*/
|
|
173
189
|
export interface CallReport<TContext> {
|
|
174
190
|
ctx: TContext;
|
|
175
191
|
/** From the call's arrival to its outcome, in milliseconds. */
|
|
176
192
|
durationMs: number;
|
|
177
|
-
/** What the browser received, when `outcome` is
|
|
193
|
+
/** What the browser received, when `outcome` is "denied" or "error". */
|
|
178
194
|
error?: JigsErrorData;
|
|
179
195
|
/**
|
|
180
196
|
* The parsed input, or the input as the browser sent it when the call
|
|
181
197
|
* failed before its input parsed.
|
|
182
198
|
*/
|
|
183
199
|
input: unknown;
|
|
184
|
-
/**
|
|
185
|
-
|
|
200
|
+
/**
|
|
201
|
+
* The kind the call declared, or "page" for a page request on the wire,
|
|
202
|
+
* whose `input` is its props.
|
|
203
|
+
*/
|
|
204
|
+
kind: ProcedureDefinition["kind"] | "page";
|
|
186
205
|
name: string;
|
|
187
206
|
/**
|
|
188
|
-
* "denied" when a policy or a bad confirmation refused the call,
|
|
189
|
-
* for any other failure, including one
|
|
207
|
+
* "denied" when a policy or a bad confirmation refused the call, or
|
|
208
|
+
* `pagePolicy` a page; "error" for any other failure, including one
|
|
209
|
+
* `run` threw and a page no list has; "aborted" when `run` rejected
|
|
210
|
+
* after the browser abandoned the call (its `signal` aborted), which
|
|
211
|
+
* does not reach `onError`.
|
|
190
212
|
*/
|
|
191
213
|
outcome: CallReportOutcome;
|
|
192
214
|
}
|
|
215
|
+
/** The names of a host's queries. */
|
|
216
|
+
type QueryName<TProcedures extends Procedures> = { [K in keyof TProcedures & string]: TProcedures[K] extends QueryDefinition ? K : never; }[keyof TProcedures & string];
|
|
217
|
+
/**
|
|
218
|
+
* One query a push event refreshes, by name. `input` is typed against the
|
|
219
|
+
* query's input schema, as a mutation's scopes are, and the views' queries
|
|
220
|
+
* whose input contains it refetch; without it, every input does. It is a
|
|
221
|
+
* match key that every client the event reaches can read, never a record.
|
|
222
|
+
*/
|
|
223
|
+
export type PushInvalidation<TProcedures extends Procedures> = { [K in QueryName<TProcedures>]: {
|
|
224
|
+
input?: TProcedures[K]["input"] extends z.ZodType ? z.input<TProcedures[K]["input"]> : never;
|
|
225
|
+
name: K;
|
|
226
|
+
}; }[QueryName<TProcedures>];
|
|
227
|
+
/** Queries for one client's push stream to refetch. */
|
|
228
|
+
export interface PushInvalidate<TProcedures extends Procedures> {
|
|
229
|
+
invalidate: ReadonlyArray<PushInvalidation<TProcedures>>;
|
|
230
|
+
type: "invalidate";
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* One page a push event refreshes: a page of the host by its name, or, with
|
|
234
|
+
* `saved: true`, any name `resolvePage` may answer. Without `props`, every
|
|
235
|
+
* props of the page refetches; with them, the pages whose props contain
|
|
236
|
+
* them. `saved` stays on the server: the client sees `{ name, props }`.
|
|
237
|
+
*/
|
|
238
|
+
export type PushPage<TPageName extends string> = PageInvalidation<TPageName> | (PageInvalidation & {
|
|
239
|
+
saved: true;
|
|
240
|
+
});
|
|
241
|
+
/** Pages for one client's push stream to refetch, by name. */
|
|
242
|
+
export interface PushInvalidatePages<TPageName extends string> {
|
|
243
|
+
pages: ReadonlyArray<PushPage<TPageName>>;
|
|
244
|
+
type: "invalidate-pages";
|
|
245
|
+
}
|
|
246
|
+
/** What `send` writes to one client's push stream. */
|
|
247
|
+
export type PushSend<TProcedures extends Procedures, TPageName extends string> = PushInvalidate<TProcedures> | PushInvalidatePages<TPageName>;
|
|
248
|
+
/** One client's push stream, as the `events` option receives it. */
|
|
249
|
+
export interface EventSubscriber<TProcedures extends Procedures, TContext, TPageName extends string = string> {
|
|
250
|
+
/**
|
|
251
|
+
* Writes a `close` event and ends the stream, for a platform that caps how
|
|
252
|
+
* long a response may last: the client reconnects and, having been told,
|
|
253
|
+
* refetches nothing.
|
|
254
|
+
*/
|
|
255
|
+
close: () => void;
|
|
256
|
+
/** What `context` returned for the request that opened the stream. */
|
|
257
|
+
ctx: TContext;
|
|
258
|
+
/**
|
|
259
|
+
* Writes one event. `id` is yours (a log offset, a stream id), at most
|
|
260
|
+
* 200 printable characters; it comes back as `since` when the client
|
|
261
|
+
* reconnects. Give ids only if you replay from `since`: a client that
|
|
262
|
+
* resumed refetches nothing on its own. A send after the stream ended is
|
|
263
|
+
* ignored.
|
|
264
|
+
*/
|
|
265
|
+
send: (event: PushSend<TProcedures, TPageName>, options?: {
|
|
266
|
+
id?: string;
|
|
267
|
+
}) => void;
|
|
268
|
+
/** Aborts when the client leaves or the stream ends. */
|
|
269
|
+
signal: AbortSignal;
|
|
270
|
+
/**
|
|
271
|
+
* The `Last-Event-ID` the client reconnected with, or null: none, or one
|
|
272
|
+
* longer than 200 characters or with a character that is not printable.
|
|
273
|
+
*/
|
|
274
|
+
since: string | null;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* The host's push fan-out: subscribe `send` to your own source of changes
|
|
278
|
+
* (an in-process emitter, Postgres `LISTEN`, Redis) and return the
|
|
279
|
+
* unsubscribe, which runs once when the stream ends. Filter by `ctx`: every
|
|
280
|
+
* event you send reaches that client.
|
|
281
|
+
*/
|
|
282
|
+
export type EventsFunction<TProcedures extends Procedures, TContext, TPageName extends string = string> = (subscriber: EventSubscriber<TProcedures, TContext, TPageName>) => (() => void) | Promise<() => void>;
|
|
193
283
|
export interface ErrorInfo {
|
|
194
|
-
/** The procedure, for a call. */
|
|
284
|
+
/** The procedure, for a call; the page, for a page. */
|
|
195
285
|
name?: string;
|
|
196
|
-
/**
|
|
197
|
-
|
|
286
|
+
/**
|
|
287
|
+
* The request it came from: a call, a session turn, a chat turn with its
|
|
288
|
+
* repairs, the push stream, or a page (`jigs.page` or its wire request).
|
|
289
|
+
*/
|
|
290
|
+
type: "call" | "chat" | "events" | "page" | "session";
|
|
291
|
+
}
|
|
292
|
+
/** A page `resolvePage` found: the source as the app stored it. */
|
|
293
|
+
export interface SavedPage {
|
|
294
|
+
/** The source, with its pragma line when the app kept it. */
|
|
295
|
+
source: string;
|
|
198
296
|
}
|
|
297
|
+
/**
|
|
298
|
+
* Finds a page the host does not ship, by name, for the caller `ctx` names.
|
|
299
|
+
* `null` is "no such page for this caller". Runs on every request for the
|
|
300
|
+
* name; cache in it if the store is slow. Throw a `JigsError` to refuse.
|
|
301
|
+
*/
|
|
302
|
+
export type PageResolver<TContext> = (name: string, call: {
|
|
303
|
+
ctx: TContext;
|
|
304
|
+
signal?: AbortSignal;
|
|
305
|
+
}) => Promise<SavedPage | null> | SavedPage | null;
|
|
306
|
+
/**
|
|
307
|
+
* Whether a shipped page may be served on the wire to the caller `ctx`
|
|
308
|
+
* names. Saved pages are scoped by `resolvePage` instead.
|
|
309
|
+
*/
|
|
310
|
+
export type PagePolicy<TContext, TPageName extends string = string> = (page: {
|
|
311
|
+
ctx: TContext;
|
|
312
|
+
name: TPageName;
|
|
313
|
+
props: PageProps;
|
|
314
|
+
}) => "allow" | "deny";
|
|
199
315
|
/**
|
|
200
316
|
* `TContext` is inferred from `context`; `run` only reads it (`NoInfer`), so
|
|
201
317
|
* a mistake in one `run` function is reported at that function.
|
|
202
318
|
*/
|
|
203
|
-
export interface JigsServerOptions<TProcedures extends Procedures, TCatalog extends Catalog, TContext,
|
|
319
|
+
export interface JigsServerOptions<TProcedures extends Procedures, TCatalog extends Catalog, TContext, TJigs extends ReadonlyArray<JigDefinition> = ReadonlyArray<JigDefinition>> {
|
|
204
320
|
/** Origins whose views may call this server and embed its frame. */
|
|
205
321
|
allowedOrigins?: ReadonlyArray<string>;
|
|
206
322
|
/**
|
|
@@ -221,12 +337,12 @@ export interface JigsServerOptions<TProcedures extends Procedures, TCatalog exte
|
|
|
221
337
|
*/
|
|
222
338
|
context: ContextFunction<TContext>;
|
|
223
339
|
/**
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
340
|
+
* Opens the push stream: a `GET` to the handler with `Accept:
|
|
341
|
+
* text/event-stream`, after `context`. Without it, that `GET` answers
|
|
342
|
+
* `204` and the client stops asking. See `EventsFunction`.
|
|
227
343
|
*/
|
|
228
|
-
|
|
229
|
-
host: Host<TProcedures, TCatalog>;
|
|
344
|
+
events?: EventsFunction<NoInfer<TProcedures>, NoInfer<TContext>, NoInfer<PageName<TJigs>>>;
|
|
345
|
+
host: Host<TProcedures, TCatalog, TJigs>;
|
|
230
346
|
/**
|
|
231
347
|
* The app's own instructions to the model, such as its persona, today's
|
|
232
348
|
* date or its safety rules. Every prompt carries them: document-mode
|
|
@@ -235,23 +351,26 @@ export interface JigsServerOptions<TProcedures extends Procedures, TCatalog exte
|
|
|
235
351
|
instructions?: string;
|
|
236
352
|
/** The largest request body accepted, in bytes. Default 1,000,000. */
|
|
237
353
|
maxBodyBytes?: number;
|
|
238
|
-
/** Repair rounds after a turn that ends with errors. Default 1. */
|
|
239
|
-
maxRepairs?: number;
|
|
240
|
-
model?: ModelFunction<TContext, TOptions>;
|
|
241
354
|
/** The clock confirmation tokens expire by, in ms since the epoch. Default `Date.now`. */
|
|
242
355
|
now?: () => number;
|
|
243
356
|
/**
|
|
244
357
|
* Runs after every call to a query, mutation or action, including ones
|
|
245
|
-
* refused before `run
|
|
358
|
+
* refused before `run`, and after every page request on the wire, with
|
|
359
|
+
* `kind: "page"`, so both can be audited and rate-limited by `ctx`. The response does not wait for it, and a value it
|
|
246
360
|
* throws or rejects with goes to `onError`.
|
|
247
361
|
*/
|
|
248
362
|
onCall?: (call: CallReport<NoInfer<TContext>>) => Promise<void> | void;
|
|
249
363
|
onError?: (cause: unknown, info: ErrorInfo) => void;
|
|
250
|
-
onTurn?: (turn: Turn<TContext, TOptions>) => Promise<void> | void;
|
|
251
|
-
/** Schema for the app options sent with each turn. */
|
|
252
|
-
options?: z.ZodType<TOptions>;
|
|
253
364
|
/** This server's origin, when the request URL does not show it (behind a proxy). */
|
|
254
365
|
origin?: string;
|
|
366
|
+
/**
|
|
367
|
+
* Decides whether a shipped page is served on the wire (`POST { type:
|
|
368
|
+
* "page" }`) to this `ctx`, after `context` and before any compile.
|
|
369
|
+
* "deny" answers `NOT_FOUND`, as for a page no list has. Default: every
|
|
370
|
+
* page to everyone `context` admits. A value it throws, or anything but
|
|
371
|
+
* "allow" or "deny", goes to `onError` and the page is denied.
|
|
372
|
+
*/
|
|
373
|
+
pagePolicy?: PagePolicy<NoInfer<TContext>, PageName<TJigs>>;
|
|
255
374
|
/**
|
|
256
375
|
* Decides a mutation call's policy from its `ctx` and parsed input, after
|
|
257
376
|
* the input parses and before `run`; `undefined` keeps the host's. A
|
|
@@ -259,13 +378,12 @@ export interface JigsServerOptions<TProcedures extends Procedures, TCatalog exte
|
|
|
259
378
|
*/
|
|
260
379
|
policy?: (call: PolicyCall<NoInfer<TProcedures>, NoInfer<TContext>>) => CallPolicy | undefined;
|
|
261
380
|
/**
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
* program always goes out. Default 250; 0 sends every change.
|
|
381
|
+
* Answers `page(name, props, { ctx })` and the wire's page requests for a
|
|
382
|
+
* name the host does not have, such as a page a user saved. A name on
|
|
383
|
+
* the host never reaches it. Saved pages compile leniently unless the
|
|
384
|
+
* call says `strict`. See `PageResolver`.
|
|
267
385
|
*/
|
|
268
|
-
|
|
386
|
+
resolvePage?: PageResolver<NoInfer<TContext>>;
|
|
269
387
|
run: RunFunctions<NoInfer<TProcedures>, NoInfer<TContext>>;
|
|
270
388
|
/**
|
|
271
389
|
* Signs confirmation tokens, at least 32 characters; keep it out of the
|
|
@@ -273,11 +391,33 @@ export interface JigsServerOptions<TProcedures extends Procedures, TCatalog exte
|
|
|
273
391
|
* "confirm": the server refuses to start without it.
|
|
274
392
|
*/
|
|
275
393
|
secret?: string;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* What `withModel` takes: everything that exists only because a model does.
|
|
397
|
+
* `TContext` is already the core's, so `ctx` is typed inside `model` and
|
|
398
|
+
* `onTurn` with no inference of its own.
|
|
399
|
+
*/
|
|
400
|
+
export interface ModelOptions<TContext, TOptions> {
|
|
276
401
|
/**
|
|
277
|
-
*
|
|
278
|
-
*
|
|
402
|
+
* Design checks whose advice gets a repair round, as errors do: at most
|
|
403
|
+
* one per turn or chat block, within `maxRepairs`. Default none, since a
|
|
404
|
+
* repair round is a full model call.
|
|
279
405
|
*/
|
|
280
|
-
|
|
406
|
+
designRepair?: ReadonlyArray<DesignCheckCode>;
|
|
407
|
+
/** Repair rounds after a turn that ends with errors. Default 1. */
|
|
408
|
+
maxRepairs?: number;
|
|
409
|
+
model: ModelFunction<TContext, TOptions>;
|
|
410
|
+
onTurn?: (turn: Turn<TContext, TOptions>) => Promise<void> | void;
|
|
411
|
+
/** Schema for the app options sent with each turn. */
|
|
412
|
+
options?: z.ZodType<TOptions>;
|
|
413
|
+
/**
|
|
414
|
+
* While a reply streams, the least time between two program updates, in
|
|
415
|
+
* ms. Each update carries the whole program, so a long reply that changed
|
|
416
|
+
* it at every line sent it hundreds of times. The first program goes out
|
|
417
|
+
* at once, a newer one replaces one still waiting, and the reply's last
|
|
418
|
+
* program always goes out. Default 250; 0 sends every change.
|
|
419
|
+
*/
|
|
420
|
+
programIntervalMs?: number;
|
|
281
421
|
}
|
|
282
422
|
export interface CompileOptions {
|
|
283
423
|
/**
|
|
@@ -328,14 +468,20 @@ export interface CallRequest {
|
|
|
328
468
|
name: string;
|
|
329
469
|
}
|
|
330
470
|
export interface SessionRequest {
|
|
331
|
-
/**
|
|
471
|
+
/**
|
|
472
|
+
* Plain JSON from the browser: `{ source }`, or `{ name, props? }` for a
|
|
473
|
+
* page the server serves, opened as a document. Absent for a new UI.
|
|
474
|
+
*/
|
|
475
|
+
document?: unknown;
|
|
476
|
+
/** Plain JSON from the browser; parsed with the session schema. */
|
|
332
477
|
messages: unknown;
|
|
333
478
|
/** Plain JSON from the browser; parsed with the `options` schema. */
|
|
334
479
|
options?: unknown;
|
|
335
480
|
}
|
|
336
481
|
/** An earlier block of the conversation, as the chat stored it. */
|
|
337
482
|
export interface ChatBlockSource {
|
|
338
|
-
id
|
|
483
|
+
/** The block's name, the fence id. */
|
|
484
|
+
name: string;
|
|
339
485
|
/** Its checked source; with or without the pragma line. */
|
|
340
486
|
source: string;
|
|
341
487
|
}
|
|
@@ -359,16 +505,19 @@ export interface ChatBlockResult {
|
|
|
359
505
|
/** Set when the block was SEARCH/REPLACE edits to an earlier block. */
|
|
360
506
|
edits?: TurnEdits;
|
|
361
507
|
/**
|
|
362
|
-
* Set when the block is done without a program of its own: an edit to
|
|
363
|
-
*
|
|
508
|
+
* Set when the block is done without a program of its own: an edit to a
|
|
509
|
+
* name the conversation does not have (`NOT_FOUND`), a block past the
|
|
364
510
|
* reply's limit (`RATE_LIMITED`), or an edit or repair that failed
|
|
365
511
|
* (`INTERNAL`). The same error the block carries.
|
|
366
512
|
*/
|
|
367
513
|
error?: JigsErrorData;
|
|
368
514
|
/** False for Jigs the model wrote without a fence. */
|
|
369
515
|
fenced: boolean;
|
|
370
|
-
id: string;
|
|
371
516
|
key: string;
|
|
517
|
+
/** The block's name, the fence id. */
|
|
518
|
+
name: string;
|
|
519
|
+
/** Set when the block is one tag naming a page, as on the block. */
|
|
520
|
+
ref?: PageRef;
|
|
372
521
|
/**
|
|
373
522
|
* The rounds of the block's repair, the ones its "chat-repair" turn gives
|
|
374
523
|
* `onTurn`; empty when it had none. The last one's diagnostics are the
|
|
@@ -437,15 +586,58 @@ export interface ChatTurn {
|
|
|
437
586
|
/** The start of `system` that is the same on every turn, as on `ModelRequest`. */
|
|
438
587
|
systemPrefix: string;
|
|
439
588
|
}
|
|
440
|
-
|
|
441
|
-
|
|
589
|
+
/** A page, compiled, and what the checks said about it. */
|
|
590
|
+
export interface ResolvedPage {
|
|
591
|
+
/** The design checks' advice, numbered like `diagnostics`. */
|
|
592
|
+
advice: ReadonlyArray<Advice>;
|
|
442
593
|
/**
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
* failure rejects with a `JigsError`. See `ChatTurn`.
|
|
594
|
+
* Never an error or warning for a shipped page, or a saved one compiled
|
|
595
|
+
* with `strict`. A saved page is lenient by default: these say what
|
|
596
|
+
* broke, beside a program that still runs. Show a notice when one is.
|
|
447
597
|
*/
|
|
448
|
-
|
|
598
|
+
diagnostics: ReadonlyArray<Diagnostic>;
|
|
599
|
+
/** "shipped": a jig listed on the host; "saved": one `resolvePage` found. */
|
|
600
|
+
origin: "saved" | "shipped";
|
|
601
|
+
program: Program;
|
|
602
|
+
/**
|
|
603
|
+
* What was compiled: a document page's source, or a define page's
|
|
604
|
+
* one-tag use, such as `<orders status={"open"}/>`.
|
|
605
|
+
*/
|
|
606
|
+
source: string;
|
|
607
|
+
}
|
|
608
|
+
/** How `page` finds a name the host may not ship: through `resolvePage`, for `ctx`. */
|
|
609
|
+
export interface PageCall<TContext> {
|
|
610
|
+
ctx: TContext;
|
|
611
|
+
signal?: AbortSignal;
|
|
612
|
+
/**
|
|
613
|
+
* Reject with a `JigsCompileError` when a saved page has an error or
|
|
614
|
+
* warning diagnostic, instead of resolving with them. Default false. A
|
|
615
|
+
* shipped page is always strict.
|
|
616
|
+
*/
|
|
617
|
+
strict?: boolean;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* A page by name: a shipped one with only a name and props, or any name
|
|
621
|
+
* with `{ ctx }`, which may ask `resolvePage`.
|
|
622
|
+
*/
|
|
623
|
+
export interface PageFunction<TContext, TPageName extends string> {
|
|
624
|
+
/**
|
|
625
|
+
* A shipped page. Rejects with a `JigsError` whose code is `BAD_INPUT`
|
|
626
|
+
* when the props are not the define's, so a route that takes props from
|
|
627
|
+
* a URL answers 400.
|
|
628
|
+
*/
|
|
629
|
+
(name: TPageName, props?: PageProps, call?: {
|
|
630
|
+
signal?: AbortSignal;
|
|
631
|
+
}): Promise<ResolvedPage>;
|
|
632
|
+
/**
|
|
633
|
+
* Any name: a shipped page wins and never asks `resolvePage`; otherwise
|
|
634
|
+
* `resolvePage` with `ctx`. Null when neither has it. A saved page takes
|
|
635
|
+
* no props (`BAD_INPUT`).
|
|
636
|
+
*/
|
|
637
|
+
(name: string, props: PageProps | undefined, call: PageCall<TContext>): Promise<ResolvedPage | null>;
|
|
638
|
+
}
|
|
639
|
+
export interface JigsServer<TContext, TPageName extends string = never> {
|
|
640
|
+
call: (request: CallRequest, context: CallContext<TContext>) => Promise<CallOutcome>;
|
|
449
641
|
/** Checks and compiles a source with no model. Strict unless told otherwise. */
|
|
450
642
|
compile: (source: string, options?: CompileOptions) => Promise<{
|
|
451
643
|
/** The design checks' advice, numbered like `diagnostics`. */
|
|
@@ -453,11 +645,38 @@ export interface JigsServer<TContext, TSpecName extends string = never> {
|
|
|
453
645
|
diagnostics: ReadonlyArray<Diagnostic>;
|
|
454
646
|
program: Program;
|
|
455
647
|
}>;
|
|
648
|
+
/**
|
|
649
|
+
* `value` parsed with the schema of provided slot `name`, for a page
|
|
650
|
+
* that wants it checked before it passes it to `JigsView` as `data`.
|
|
651
|
+
* Throws `JigsError("BAD_INPUT")` when it does not match, or when `name`
|
|
652
|
+
* is not provided data on this host. The view does not check it: a value
|
|
653
|
+
* that does not match renders as the program reads it.
|
|
654
|
+
*/
|
|
655
|
+
data: (name: string, value: JsonValue) => JsonValue;
|
|
656
|
+
/**
|
|
657
|
+
* The push stream for `request`, whose `ctx` the caller already has: a
|
|
658
|
+
* foreign `Origin` is `403`, a server without `events` answers `204`, and
|
|
659
|
+
* an `events` that throws is `500`. `handler` does this for a `GET` that
|
|
660
|
+
* accepts `text/event-stream`, after `context`.
|
|
661
|
+
*/
|
|
662
|
+
events: (request: Request, context: CallContext<TContext>) => Promise<Response>;
|
|
456
663
|
/** The sandbox frame document, with its own content security policy. */
|
|
457
664
|
frame: (request?: Request) => Response;
|
|
665
|
+
/**
|
|
666
|
+
* Serves the frame, the push stream, calls, pages and session turns. Without `withModel`, a
|
|
667
|
+
* session turn that would ask the model answers `404 NOT_FOUND`; one
|
|
668
|
+
* that carries a document and no ask is still compiled and streamed.
|
|
669
|
+
*/
|
|
458
670
|
handler: (request: Request) => Promise<Response>;
|
|
459
671
|
/** The largest request body `handler` accepts, in bytes. */
|
|
460
672
|
maxBodyBytes: number;
|
|
673
|
+
/**
|
|
674
|
+
* A page, compiled: a jig with `page: true`, by its name, with the props
|
|
675
|
+
* its `<define>` declares, or with `{ ctx }`, a page `resolvePage` finds.
|
|
676
|
+
* Shipped pages that need no props compile at startup, and every shipped
|
|
677
|
+
* page compiles strictly. See `PageFunction`.
|
|
678
|
+
*/
|
|
679
|
+
page: PageFunction<TContext, TPageName>;
|
|
461
680
|
/**
|
|
462
681
|
* The system prompt for this host. "document" (default) is what sessions
|
|
463
682
|
* use: every reply is one UI. "chat" is Markdown with UIs in fenced
|
|
@@ -471,11 +690,29 @@ export interface JigsServer<TContext, TSpecName extends string = never> {
|
|
|
471
690
|
* `@jigs.design/ai-sdk`).
|
|
472
691
|
*/
|
|
473
692
|
promptPrefix: (mode?: PromptMode) => string;
|
|
474
|
-
session: (body: SessionRequest, context: CallContext<TContext>) => AsyncIterable<SessionEvent>;
|
|
475
|
-
/** A spec from `specs`, compiled at startup. */
|
|
476
|
-
spec: (name: TSpecName) => Program;
|
|
477
693
|
/** Changes whenever the compiler, the runtime or the host does. */
|
|
478
694
|
version: string;
|
|
695
|
+
/**
|
|
696
|
+
* This server with a model: the same core, plus `session` and `chat`,
|
|
697
|
+
* and a handler that runs session turns that ask the model.
|
|
698
|
+
*/
|
|
699
|
+
withModel: <TOptions = undefined>(options: ModelOptions<TContext, TOptions>) => JigsModelServer<TContext, TPageName>;
|
|
700
|
+
}
|
|
701
|
+
/** What `withModel` returns: the core, plus the turns that call the model. */
|
|
702
|
+
export interface JigsModelServer<TContext, TPageName extends string = never> extends Omit<JigsServer<TContext, TPageName>, "withModel"> {
|
|
703
|
+
/**
|
|
704
|
+
* Starts a chat reply for `request`. It refuses the request as `handler`
|
|
705
|
+
* would (an `Origin` that may not call this server, or a body that is not
|
|
706
|
+
* JSON), then runs `context` and parses `blocks` and `options`. Each
|
|
707
|
+
* failure rejects with a `JigsError`. See `ChatTurn`.
|
|
708
|
+
*/
|
|
709
|
+
chat: (request: Request, options?: ChatOptions) => Promise<ChatTurn>;
|
|
710
|
+
/**
|
|
711
|
+
* One session turn: a document whose conversation does not end with an
|
|
712
|
+
* ask is compiled again with no model call; otherwise the model answers,
|
|
713
|
+
* editing the document when there is one.
|
|
714
|
+
*/
|
|
715
|
+
session: (body: SessionRequest, context: CallContext<TContext>) => AsyncIterable<SessionEvent>;
|
|
479
716
|
}
|
|
480
717
|
//#endregion
|
|
481
718
|
export type { EditFailureReason };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jigs.design/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "createJigsServer: checks and streams programs, runs procedures, and serves the sandbox frame.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@jigs.design/
|
|
33
|
-
"@jigs.design/
|
|
34
|
-
"@jigs.design/
|
|
35
|
-
"@jigs.design/
|
|
36
|
-
"@jigs.design/
|
|
32
|
+
"@jigs.design/host": "0.3.1",
|
|
33
|
+
"@jigs.design/compiler": "0.3.1",
|
|
34
|
+
"@jigs.design/protocol": "0.3.1",
|
|
35
|
+
"@jigs.design/runtime": "0.3.1",
|
|
36
|
+
"@jigs.design/prompt": "0.3.1"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"zod": "^4.0.0"
|