@jigs.design/server 0.0.0-stage → 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.
- package/LICENSE +21 -0
- package/README.md +62 -2
- package/dist/chat.d.ts +12 -0
- package/dist/chat.js +711 -0
- package/dist/compile.d.ts +3 -0
- package/dist/compile.js +249 -0
- package/dist/confirm.d.ts +16 -0
- package/dist/confirm.js +97 -0
- package/dist/design.d.ts +17 -0
- package/dist/design.js +145 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.js +62 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +6 -0
- package/dist/inputs.js +224 -0
- package/dist/invalidation.js +39 -0
- package/dist/literal.js +258 -0
- package/dist/node.d.ts +19 -0
- package/dist/node.js +91 -0
- package/dist/outputs.js +120 -0
- package/dist/pragma.js +80 -0
- package/dist/rewrite.js +30 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.js +786 -0
- package/dist/session.d.ts +7 -0
- package/dist/session.js +352 -0
- package/dist/types.d.ts +481 -0
- package/dist/usage.d.ts +5 -0
- package/dist/usage.js +13 -0
- package/package.json +40 -3
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
import { Advice, DesignCheckCode, Placement } from "./design.js";
|
|
2
|
+
import { ConfirmationStore } from "./confirm.js";
|
|
3
|
+
import { EditFailureReason } from "@jigs.design/compiler";
|
|
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, Message, PickleErrorData, Program, SessionEvent } from "@jigs.design/runtime";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
//#region src/types.d.ts
|
|
9
|
+
/**
|
|
10
|
+
* Tokens a model call used. The cache counts are part of `inputTokens`,
|
|
11
|
+
* and only there when the provider reports them: input read from its
|
|
12
|
+
* prompt cache, and input written to it.
|
|
13
|
+
*/
|
|
14
|
+
export interface Usage {
|
|
15
|
+
cacheReadTokens?: number;
|
|
16
|
+
cacheWriteTokens?: number;
|
|
17
|
+
inputTokens: number;
|
|
18
|
+
outputTokens: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Why the server calls `model`: a session turn's answer, a repair round in a
|
|
22
|
+
* session, or the repair of a chat block that closed with errors.
|
|
23
|
+
*/
|
|
24
|
+
export type ModelRequestKind = "chat-repair" | "repair" | "session";
|
|
25
|
+
export interface ModelRequest<TContext, TOptions> {
|
|
26
|
+
ctx: TContext;
|
|
27
|
+
kind: ModelRequestKind;
|
|
28
|
+
/** The conversation, with the server's repair turns added. */
|
|
29
|
+
messages: ReadonlyArray<Message>;
|
|
30
|
+
options: TOptions;
|
|
31
|
+
signal: AbortSignal;
|
|
32
|
+
/** The document prompt rendered from the host, with the server's `instructions`. */
|
|
33
|
+
system: string;
|
|
34
|
+
/**
|
|
35
|
+
* The start of `system` that is the same on every turn: the language and
|
|
36
|
+
* the catalog, before the instructions and procedures. Mark it for a
|
|
37
|
+
* provider's prompt cache, as `aiSdkModel` does.
|
|
38
|
+
*/
|
|
39
|
+
systemPrefix: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The product's call to its LLM. Yield text as it arrives. A generator may
|
|
43
|
+
* return `{ usage }`, which reaches `onTurn`.
|
|
44
|
+
*/
|
|
45
|
+
export type ModelFunction<TContext, TOptions> = (request: ModelRequest<TContext, TOptions>) => AsyncIterable<string>;
|
|
46
|
+
/** What became of a reply written as SEARCH/REPLACE edits. */
|
|
47
|
+
export interface TurnEdits {
|
|
48
|
+
/** False when an edit did not apply, so the reply was not used. */
|
|
49
|
+
applied: boolean;
|
|
50
|
+
/** The complete edit blocks in the reply. */
|
|
51
|
+
blocks: number;
|
|
52
|
+
/**
|
|
53
|
+
* Why the first edit that failed did: its SEARCH text is not in the
|
|
54
|
+
* source (`"missing"`) or is there more than once (`"ambiguous"`), the
|
|
55
|
+
* block is broken (`"malformed"`), or the edit left a tag unclosed or
|
|
56
|
+
* closed one twice (`"broken"`).
|
|
57
|
+
*/
|
|
58
|
+
reason?: EditFailureReason;
|
|
59
|
+
}
|
|
60
|
+
/** One reply from `model` in a turn, and what came of it. */
|
|
61
|
+
export interface TurnRound {
|
|
62
|
+
/**
|
|
63
|
+
* The design checks' advice after this round, numbered like
|
|
64
|
+
* `diagnostics`. It never makes the round invalid; empty when an edit
|
|
65
|
+
* failed to apply.
|
|
66
|
+
*/
|
|
67
|
+
advice: ReadonlyArray<Advice>;
|
|
68
|
+
/**
|
|
69
|
+
* The diagnostics after this round, before any later repair, numbered by
|
|
70
|
+
* the lines of the sent source. Empty when an edit failed to apply, since
|
|
71
|
+
* nothing compiled.
|
|
72
|
+
*/
|
|
73
|
+
diagnostics: ReadonlyArray<Diagnostic>;
|
|
74
|
+
/** Set when the reply was SEARCH/REPLACE edits. */
|
|
75
|
+
edits?: TurnEdits;
|
|
76
|
+
/**
|
|
77
|
+
* "answer" for the model's reply to the user, "repair" for each round
|
|
78
|
+
* after it. Every round of a "chat-repair" turn is a repair: the reply
|
|
79
|
+
* that wrote the block was the answer.
|
|
80
|
+
*/
|
|
81
|
+
kind: "answer" | "repair";
|
|
82
|
+
/**
|
|
83
|
+
* Set when the server rewrote the reply instead of asking for a repair.
|
|
84
|
+
* `diagnostics` and `advice` are then those of the rewritten source,
|
|
85
|
+
* which is what the turn stores.
|
|
86
|
+
*/
|
|
87
|
+
rewrites?: ReadonlyArray<TurnRewrite>;
|
|
88
|
+
/** This round's tokens, when `model` returned them; zeros otherwise. */
|
|
89
|
+
usage: Usage;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* A change the server made to the model's source in place of a repair round:
|
|
93
|
+
* `use_before_declare`, markup above the `{@body}` lines whose names it
|
|
94
|
+
* reads, moved those lines to the top. The program is unchanged.
|
|
95
|
+
*/
|
|
96
|
+
export interface TurnRewrite {
|
|
97
|
+
/** The diagnostic the rewrite answered. */
|
|
98
|
+
code: "use_before_declare";
|
|
99
|
+
/**
|
|
100
|
+
* How many of the page's `{@body}` lines moved: to the top from below
|
|
101
|
+
* markup, including from tags such as `<card>`, or within the top.
|
|
102
|
+
*/
|
|
103
|
+
moved: number;
|
|
104
|
+
}
|
|
105
|
+
export interface Turn<TContext, TOptions> {
|
|
106
|
+
/** The design checks' advice on the source sent with `done`; empty when the turn did not finish. */
|
|
107
|
+
advice: ReadonlyArray<Advice>;
|
|
108
|
+
/** False when the turn was stopped or failed before `done`. */
|
|
109
|
+
completed: boolean;
|
|
110
|
+
ctx: TContext;
|
|
111
|
+
/** The diagnostics sent with `done`; empty when the turn did not finish. */
|
|
112
|
+
diagnostics: ReadonlyArray<Diagnostic>;
|
|
113
|
+
/**
|
|
114
|
+
* Milliseconds from the start of the turn to its first `program` event;
|
|
115
|
+
* null when it sent none. A chat repair sends its block once, when it is
|
|
116
|
+
* done, so for one this is the time to the repaired block.
|
|
117
|
+
*/
|
|
118
|
+
firstProgramMs: number | null;
|
|
119
|
+
/** A session turn, or the repair of a chat block, which is a turn of its own. */
|
|
120
|
+
kind: "chat-repair" | "session";
|
|
121
|
+
messages: ReadonlyArray<Message>;
|
|
122
|
+
options: TOptions;
|
|
123
|
+
/**
|
|
124
|
+
* Rounds after the first: repairs of errors, and requests for the whole
|
|
125
|
+
* document after an edit failed. `rounds` tells them apart.
|
|
126
|
+
*/
|
|
127
|
+
repairs: number;
|
|
128
|
+
/**
|
|
129
|
+
* Every reply `model` finished in this turn, in order. A reply cut off by
|
|
130
|
+
* a stop or a failure is not a round.
|
|
131
|
+
*/
|
|
132
|
+
rounds: ReadonlyArray<TurnRound>;
|
|
133
|
+
/** The checked source sent with `done`, with its pragma; null when the turn did not finish. */
|
|
134
|
+
source: string | null;
|
|
135
|
+
usage: Usage;
|
|
136
|
+
}
|
|
137
|
+
export interface CallContext<TContext> {
|
|
138
|
+
ctx: TContext;
|
|
139
|
+
signal: AbortSignal;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* A value as `run` may return it: readonly all the way down, so a frozen or
|
|
143
|
+
* readonly array is fine. The output schema parses it either way.
|
|
144
|
+
*/
|
|
145
|
+
type DeepReadonly<T> = T extends object ? { readonly [K in keyof T]: DeepReadonly<T[K]>; } : T;
|
|
146
|
+
/** What `run` may return for a procedure. */
|
|
147
|
+
type RunOutput<P extends ProcedureDefinition> = DeepReadonly<OutputOf<P>>;
|
|
148
|
+
/**
|
|
149
|
+
* One function per query and mutation. Actions have none: the page handles
|
|
150
|
+
* them, and the server only checks their input.
|
|
151
|
+
*/
|
|
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]>>; };
|
|
153
|
+
export type ContextFunction<TContext> = (request: Request) => TContext | Promise<TContext>;
|
|
154
|
+
/** The names of a host's mutations. */
|
|
155
|
+
type MutationName<TProcedures extends Procedures> = { [K in keyof TProcedures & string]: TProcedures[K] extends MutationDefinition ? K : never; }[keyof TProcedures & string];
|
|
156
|
+
/**
|
|
157
|
+
* A mutation call the server's `policy` option decides on, one member per
|
|
158
|
+
* mutation, so checking `name` narrows `input`.
|
|
159
|
+
*/
|
|
160
|
+
export type PolicyCall<TProcedures extends Procedures, TContext> = { [K in MutationName<TProcedures>]: {
|
|
161
|
+
ctx: TContext;
|
|
162
|
+
/** The input its schema parsed; `undefined` when it takes none. */
|
|
163
|
+
input: InputOf<TProcedures[K]>;
|
|
164
|
+
name: K;
|
|
165
|
+
}; }[MutationName<TProcedures>];
|
|
166
|
+
/**
|
|
167
|
+
* How a call ended, for `onCall`. A confirmed mutation reports twice: once
|
|
168
|
+
* as "requires-action" when the server asks the page, and once as
|
|
169
|
+
* "confirmed" when it ran with the user's approval.
|
|
170
|
+
*/
|
|
171
|
+
export type CallReportOutcome = "confirmed" | "denied" | "error" | "requires-action" | "success";
|
|
172
|
+
/** One call to a query, mutation or action, as `onCall` receives it. */
|
|
173
|
+
export interface CallReport<TContext> {
|
|
174
|
+
ctx: TContext;
|
|
175
|
+
/** From the call's arrival to its outcome, in milliseconds. */
|
|
176
|
+
durationMs: number;
|
|
177
|
+
/** What the browser received, when `outcome` is not "success". */
|
|
178
|
+
error?: PickleErrorData;
|
|
179
|
+
/**
|
|
180
|
+
* The parsed input, or the input as the browser sent it when the call
|
|
181
|
+
* failed before its input parsed.
|
|
182
|
+
*/
|
|
183
|
+
input: unknown;
|
|
184
|
+
/** The kind the call declared. */
|
|
185
|
+
kind: ProcedureDefinition["kind"];
|
|
186
|
+
name: string;
|
|
187
|
+
/**
|
|
188
|
+
* "denied" when a policy or a bad confirmation refused the call, "error"
|
|
189
|
+
* for any other failure, including one `run` threw.
|
|
190
|
+
*/
|
|
191
|
+
outcome: CallReportOutcome;
|
|
192
|
+
}
|
|
193
|
+
export interface ErrorInfo {
|
|
194
|
+
/** The procedure, for a call. */
|
|
195
|
+
name?: string;
|
|
196
|
+
/** The request it came from: a call, a session turn, or a chat turn with its repairs. */
|
|
197
|
+
type: "call" | "chat" | "session";
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* `TContext` is inferred from `context`; `run` only reads it (`NoInfer`), so
|
|
201
|
+
* a mistake in one `run` function is reported at that function.
|
|
202
|
+
*/
|
|
203
|
+
export interface PickleServerOptions<TProcedures extends Procedures, TCatalog extends Catalog, TContext, TOptions, TSpecName extends string = never> {
|
|
204
|
+
/** Origins whose views may call this server and embed its frame. */
|
|
205
|
+
allowedOrigins?: ReadonlyArray<string>;
|
|
206
|
+
/**
|
|
207
|
+
* Where used confirmation tokens are recorded. The default keeps them in
|
|
208
|
+
* this process's memory, so it is only valid for one server process;
|
|
209
|
+
* behind a load balancer, pass a shared store.
|
|
210
|
+
*/
|
|
211
|
+
confirmations?: ConfirmationStore;
|
|
212
|
+
/**
|
|
213
|
+
* Who a confirmation token is for, from `ctx`, such as the user's id. A
|
|
214
|
+
* token only works for the subject it was issued to. Required with
|
|
215
|
+
* `secret`.
|
|
216
|
+
*/
|
|
217
|
+
confirmSubject?: (ctx: NoInfer<TContext>) => string;
|
|
218
|
+
/**
|
|
219
|
+
* What every call and turn receives as `ctx`, from the request: usually
|
|
220
|
+
* the signed-in user. Required; a server with none writes `() => undefined`.
|
|
221
|
+
*/
|
|
222
|
+
context: ContextFunction<TContext>;
|
|
223
|
+
/**
|
|
224
|
+
* Design checks whose advice gets a repair round, as errors do: at most
|
|
225
|
+
* one per turn or chat block, within `maxRepairs`. Default none, since a
|
|
226
|
+
* repair round is a full model call.
|
|
227
|
+
*/
|
|
228
|
+
designRepair?: ReadonlyArray<DesignCheckCode>;
|
|
229
|
+
host: Host<TProcedures, TCatalog>;
|
|
230
|
+
/**
|
|
231
|
+
* The app's own instructions to the model, such as its persona, today's
|
|
232
|
+
* date or its safety rules. Every prompt carries them: document-mode
|
|
233
|
+
* sessions, `prompt("chat")`, and the repairs of both.
|
|
234
|
+
*/
|
|
235
|
+
instructions?: string;
|
|
236
|
+
/** The largest request body accepted, in bytes. Default 1,000,000. */
|
|
237
|
+
maxBodyBytes?: number;
|
|
238
|
+
/** Repair rounds after a turn that ends with errors. Default 1. */
|
|
239
|
+
maxRepairs?: number;
|
|
240
|
+
model?: ModelFunction<TContext, TOptions>;
|
|
241
|
+
/** The clock confirmation tokens expire by, in ms since the epoch. Default `Date.now`. */
|
|
242
|
+
now?: () => number;
|
|
243
|
+
/**
|
|
244
|
+
* Runs after every call to a query, mutation or action, including ones
|
|
245
|
+
* refused before `run`. The response does not wait for it, and a value it
|
|
246
|
+
* throws or rejects with goes to `onError`.
|
|
247
|
+
*/
|
|
248
|
+
onCall?: (call: CallReport<NoInfer<TContext>>) => Promise<void> | void;
|
|
249
|
+
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
|
+
/** This server's origin, when the request URL does not show it (behind a proxy). */
|
|
254
|
+
origin?: string;
|
|
255
|
+
/**
|
|
256
|
+
* Decides a mutation call's policy from its `ctx` and parsed input, after
|
|
257
|
+
* the input parses and before `run`; `undefined` keeps the host's. A
|
|
258
|
+
* value it throws goes to `onError`, and the call is denied.
|
|
259
|
+
*/
|
|
260
|
+
policy?: (call: PolicyCall<NoInfer<TProcedures>, NoInfer<TContext>>) => CallPolicy | undefined;
|
|
261
|
+
/**
|
|
262
|
+
* While a reply streams, the least time between two program updates, in
|
|
263
|
+
* ms. Each update carries the whole program, so a long reply that changed
|
|
264
|
+
* it at every line sent it hundreds of times. The first program goes out
|
|
265
|
+
* at once, a newer one replaces one still waiting, and the reply's last
|
|
266
|
+
* program always goes out. Default 250; 0 sends every change.
|
|
267
|
+
*/
|
|
268
|
+
programIntervalMs?: number;
|
|
269
|
+
run: RunFunctions<NoInfer<TProcedures>, NoInfer<TContext>>;
|
|
270
|
+
/**
|
|
271
|
+
* Signs confirmation tokens, at least 32 characters; keep it out of the
|
|
272
|
+
* browser. Required, with `confirmSubject`, when a mutation's policy is
|
|
273
|
+
* "confirm": the server refuses to start without it.
|
|
274
|
+
*/
|
|
275
|
+
secret?: string;
|
|
276
|
+
/**
|
|
277
|
+
* Stored specs by name, compiled once at startup. A diagnostic worse than
|
|
278
|
+
* info stops the server, as a bad recipe does. Read one with `spec(name)`.
|
|
279
|
+
*/
|
|
280
|
+
specs?: Readonly<Record<TSpecName, string>>;
|
|
281
|
+
}
|
|
282
|
+
export interface CompileOptions {
|
|
283
|
+
/**
|
|
284
|
+
* Where the UI sits, for the design checks: a whole document (default),
|
|
285
|
+
* or a block of a chat reply, which also counts its actions.
|
|
286
|
+
*/
|
|
287
|
+
placement?: Placement;
|
|
288
|
+
/**
|
|
289
|
+
* Throw a `PickleCompileError` when the source has an error or warning
|
|
290
|
+
* diagnostic. Default true; pass false to get the program and the
|
|
291
|
+
* diagnostics instead, as a session turn does.
|
|
292
|
+
*/
|
|
293
|
+
strict?: boolean;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* What one call returns: the parsed output, or an error the browser may see.
|
|
297
|
+
* A mutation's also lists the queries it refreshed (`invalidate`).
|
|
298
|
+
*/
|
|
299
|
+
export type CallOutcome = {
|
|
300
|
+
data: unknown;
|
|
301
|
+
invalidate?: ReadonlyArray<Invalidation>;
|
|
302
|
+
} | {
|
|
303
|
+
error: PickleErrorData;
|
|
304
|
+
} | {
|
|
305
|
+
requiresAction: RequiresAction;
|
|
306
|
+
};
|
|
307
|
+
/**
|
|
308
|
+
* The first answer to a call whose policy is "confirm": the mutation has
|
|
309
|
+
* not run. The page shows `message` and, when the user approves, sends the
|
|
310
|
+
* call again with `token` as `confirmation`.
|
|
311
|
+
*/
|
|
312
|
+
export interface RequiresAction {
|
|
313
|
+
/** What to ask the user, written by the host. */
|
|
314
|
+
message: string;
|
|
315
|
+
/** Single use, bound to this call and subject, valid for five minutes. */
|
|
316
|
+
token: string;
|
|
317
|
+
}
|
|
318
|
+
export interface CallRequest {
|
|
319
|
+
/** The token from a `requiresAction` answer, once the user approved. */
|
|
320
|
+
confirmation?: string;
|
|
321
|
+
/** Plain JSON from the browser; parsed with the procedure's input schema. */
|
|
322
|
+
input?: unknown;
|
|
323
|
+
/**
|
|
324
|
+
* The procedure's kind, as the program's procedure table declares it. A
|
|
325
|
+
* call whose kind is not the host's is refused with `BAD_INPUT`.
|
|
326
|
+
*/
|
|
327
|
+
kind: ProcedureDefinition["kind"];
|
|
328
|
+
name: string;
|
|
329
|
+
}
|
|
330
|
+
export interface SessionRequest {
|
|
331
|
+
/** Plain JSON from the browser; parsed with the messages schema. */
|
|
332
|
+
messages: unknown;
|
|
333
|
+
/** Plain JSON from the browser; parsed with the `options` schema. */
|
|
334
|
+
options?: unknown;
|
|
335
|
+
}
|
|
336
|
+
/** An earlier block of the conversation, as the chat stored it. */
|
|
337
|
+
export interface ChatBlockSource {
|
|
338
|
+
id: string;
|
|
339
|
+
/** Its checked source; with or without the pragma line. */
|
|
340
|
+
source: string;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* One block of a chat reply and what came of it, from `ChatTurn.results`:
|
|
344
|
+
* enough to count first-pass failures, failed edits and repairs.
|
|
345
|
+
*/
|
|
346
|
+
export interface ChatBlockResult {
|
|
347
|
+
/**
|
|
348
|
+
* The design checks' advice on the block as the reply closed it, numbered
|
|
349
|
+
* like `diagnostics`; empty when `diagnostics` is. A repair's rounds
|
|
350
|
+
* carry their own.
|
|
351
|
+
*/
|
|
352
|
+
advice: ReadonlyArray<Advice>;
|
|
353
|
+
/**
|
|
354
|
+
* The block's diagnostics as the reply closed it, before any repair,
|
|
355
|
+
* numbered by the lines of its source. Empty when it has `error` or an
|
|
356
|
+
* edit that did not apply.
|
|
357
|
+
*/
|
|
358
|
+
diagnostics: ReadonlyArray<Diagnostic>;
|
|
359
|
+
/** Set when the block was SEARCH/REPLACE edits to an earlier block. */
|
|
360
|
+
edits?: TurnEdits;
|
|
361
|
+
/**
|
|
362
|
+
* Set when the block is done without a program of its own: an edit to an
|
|
363
|
+
* id the conversation does not have (`NOT_FOUND`), a block past the
|
|
364
|
+
* reply's limit (`RATE_LIMITED`), or an edit or repair that failed
|
|
365
|
+
* (`INTERNAL`). The same error the block carries.
|
|
366
|
+
*/
|
|
367
|
+
error?: PickleErrorData;
|
|
368
|
+
/** False for Pickle the model wrote without a fence. */
|
|
369
|
+
fenced: boolean;
|
|
370
|
+
id: string;
|
|
371
|
+
key: string;
|
|
372
|
+
/**
|
|
373
|
+
* The rounds of the block's repair, the ones its "chat-repair" turn gives
|
|
374
|
+
* `onTurn`; empty when it had none. The last one's diagnostics are the
|
|
375
|
+
* block's own after the repair.
|
|
376
|
+
*/
|
|
377
|
+
repairs: ReadonlyArray<TurnRound>;
|
|
378
|
+
/**
|
|
379
|
+
* Set when the server rewrote the block instead of asking for a repair;
|
|
380
|
+
* `diagnostics` and `advice` are then those of the rewritten source.
|
|
381
|
+
*/
|
|
382
|
+
rewrites?: ReadonlyArray<TurnRewrite>;
|
|
383
|
+
/** "repairing" until its repair settles, then "done". */
|
|
384
|
+
status: Exclude<ChatBlockStatus, "streaming">;
|
|
385
|
+
}
|
|
386
|
+
/** Prose to show as it arrives, or a block that appeared or changed. */
|
|
387
|
+
export type ChatEvent = {
|
|
388
|
+
block: ChatBlock;
|
|
389
|
+
type: "block";
|
|
390
|
+
} | {
|
|
391
|
+
text: string;
|
|
392
|
+
type: "text";
|
|
393
|
+
};
|
|
394
|
+
export interface ChatOptions {
|
|
395
|
+
/**
|
|
396
|
+
* The conversation's earlier blocks, oldest first: edits apply to the
|
|
397
|
+
* latest version of an id, and versions count on from them. Sources from
|
|
398
|
+
* the browser are only compiled, never trusted as programs.
|
|
399
|
+
*/
|
|
400
|
+
blocks?: ReadonlyArray<ChatBlockSource>;
|
|
401
|
+
/** Plain JSON for the `options` schema, which repairs pass to `model`. */
|
|
402
|
+
options?: unknown;
|
|
403
|
+
/**
|
|
404
|
+
* The user's message this reply answers. A repair shows it to the model,
|
|
405
|
+
* so the fixed block still does what was asked.
|
|
406
|
+
*/
|
|
407
|
+
prompt?: string | undefined;
|
|
408
|
+
/** Stops repairs, and `stream`, when the turn is abandoned. */
|
|
409
|
+
signal?: AbortSignal;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* One chat reply. Feed it the model's text: `push` and `end` return prose
|
|
413
|
+
* and blocks as they complete, `repair` fixes a block that closed with
|
|
414
|
+
* errors, and `stream` does all three over an async iterable.
|
|
415
|
+
*/
|
|
416
|
+
export interface ChatTurn {
|
|
417
|
+
/** Closes a block left open when the reply ends. */
|
|
418
|
+
end: () => Array<ChatEvent>;
|
|
419
|
+
/** Any slice of the reply; returns what it completed. */
|
|
420
|
+
push: (delta: string) => Array<ChatEvent>;
|
|
421
|
+
/**
|
|
422
|
+
* For a block with status "repairing": a document-mode session turn on
|
|
423
|
+
* it, through `model`. Yields the block once more, done. Any other block
|
|
424
|
+
* comes back unchanged.
|
|
425
|
+
*/
|
|
426
|
+
repair: (block: ChatBlock) => AsyncIterable<ChatBlock>;
|
|
427
|
+
/**
|
|
428
|
+
* Each block the reply has closed so far, in order, and what came of it.
|
|
429
|
+
* Read it once `stream` ends, or after `end` and every `repair`, to count
|
|
430
|
+
* the reply's failures.
|
|
431
|
+
*/
|
|
432
|
+
results: () => Array<ChatBlockResult>;
|
|
433
|
+
/** `push`, `end` and `repair` together; ends after every repair settles. */
|
|
434
|
+
stream: (reply: AsyncIterable<string>) => AsyncIterable<ChatEvent>;
|
|
435
|
+
/** The chat-mode prompt, `prompt("chat")`, with the server's `instructions`. */
|
|
436
|
+
system: string;
|
|
437
|
+
/** The start of `system` that is the same on every turn, as on `ModelRequest`. */
|
|
438
|
+
systemPrefix: string;
|
|
439
|
+
}
|
|
440
|
+
export interface PickleServer<TContext, TSpecName extends string = never> {
|
|
441
|
+
call: (request: CallRequest, context: CallContext<TContext>) => Promise<CallOutcome>;
|
|
442
|
+
/**
|
|
443
|
+
* Starts a chat reply for `request`. It refuses the request as `handler`
|
|
444
|
+
* would (an `Origin` that may not call this server, or a body that is not
|
|
445
|
+
* JSON), then runs `context` and parses `blocks` and `options`. Each
|
|
446
|
+
* failure rejects with a `PickleError`. See `ChatTurn`.
|
|
447
|
+
*/
|
|
448
|
+
chat: (request: Request, options?: ChatOptions) => Promise<ChatTurn>;
|
|
449
|
+
/** Checks and compiles a source with no model. Strict unless told otherwise. */
|
|
450
|
+
compile: (source: string, options?: CompileOptions) => Promise<{
|
|
451
|
+
/** The design checks' advice, numbered like `diagnostics`. */
|
|
452
|
+
advice: ReadonlyArray<Advice>;
|
|
453
|
+
diagnostics: ReadonlyArray<Diagnostic>;
|
|
454
|
+
program: Program;
|
|
455
|
+
}>;
|
|
456
|
+
/** The sandbox frame document, with its own content security policy. */
|
|
457
|
+
frame: (request?: Request) => Response;
|
|
458
|
+
handler: (request: Request) => Promise<Response>;
|
|
459
|
+
/** The largest request body `handler` accepts, in bytes. */
|
|
460
|
+
maxBodyBytes: number;
|
|
461
|
+
/**
|
|
462
|
+
* The system prompt for this host. "document" (default) is what sessions
|
|
463
|
+
* use: every reply is one UI. "chat" is Markdown with UIs in fenced
|
|
464
|
+
* `pickle` blocks.
|
|
465
|
+
*/
|
|
466
|
+
prompt: (mode?: PromptMode) => string;
|
|
467
|
+
/**
|
|
468
|
+
* The start of `prompt(mode)` that is the same on every turn: the
|
|
469
|
+
* language and the catalog, before the instructions and procedures. Mark
|
|
470
|
+
* it for a provider's prompt cache (`cachedInstructions` in
|
|
471
|
+
* `@jigs.design/ai-sdk`).
|
|
472
|
+
*/
|
|
473
|
+
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
|
+
/** Changes whenever the compiler, the runtime or the host does. */
|
|
478
|
+
version: string;
|
|
479
|
+
}
|
|
480
|
+
//#endregion
|
|
481
|
+
export type { EditFailureReason };
|
package/dist/usage.d.ts
ADDED
package/dist/usage.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/usage.ts
|
|
2
|
+
/** `a` and `b` added up. A cache count is kept when either reports one. */
|
|
3
|
+
function addUsage(a, b) {
|
|
4
|
+
const total = {
|
|
5
|
+
inputTokens: a.inputTokens + b.inputTokens,
|
|
6
|
+
outputTokens: a.outputTokens + b.outputTokens
|
|
7
|
+
};
|
|
8
|
+
if (a.cacheReadTokens !== void 0 || b.cacheReadTokens !== void 0) total.cacheReadTokens = (a.cacheReadTokens ?? 0) + (b.cacheReadTokens ?? 0);
|
|
9
|
+
if (a.cacheWriteTokens !== void 0 || b.cacheWriteTokens !== void 0) total.cacheWriteTokens = (a.cacheWriteTokens ?? 0) + (b.cacheWriteTokens ?? 0);
|
|
10
|
+
return total;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { addUsage };
|
package/package.json
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jigs.design/server",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "createPickleServer: checks and streams programs, runs procedures, and serves the sandbox frame.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/yoamomonstruos/pickle.git",
|
|
9
|
+
"directory": "packages/server"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"sideEffects": false,
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./node": {
|
|
24
|
+
"types": "./dist/node.d.ts",
|
|
25
|
+
"import": "./dist/node.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@jigs.design/prompt": "0.1.1",
|
|
33
|
+
"@jigs.design/runtime": "0.1.1",
|
|
34
|
+
"@jigs.design/host": "0.1.1",
|
|
35
|
+
"@jigs.design/compiler": "0.1.1"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"zod": "^4.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"zod": "4.6.7"
|
|
42
|
+
}
|
|
6
43
|
}
|