@jigs.design/prompt 0.3.0 → 0.3.2
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/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/system-prompt.d.ts +10 -4
- package/dist/system-prompt.js +35 -8
- package/dist/tool-results.d.ts +12 -0
- package/dist/tool-results.js +22 -0
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { askOf, documentOf, withDocument } from "./document.js";
|
|
2
2
|
import { editRepairText, fullDocumentText, needsRepair, repairText } from "./repair.js";
|
|
3
3
|
import { PromptMode, PromptOptions, SystemPromptParts, systemPrompt, systemPromptParts } from "./system-prompt.js";
|
|
4
|
+
import { TOOL_RESULTS, toolResultsSlot } from "./tool-results.js";
|
|
4
5
|
import { typeText } from "./types.js";
|
|
5
|
-
export { type PromptMode, type PromptOptions, type SystemPromptParts, askOf, documentOf, editRepairText, fullDocumentText, needsRepair, repairText, systemPrompt, systemPromptParts, typeText, withDocument };
|
|
6
|
+
export { type PromptMode, type PromptOptions, type SystemPromptParts, TOOL_RESULTS, askOf, documentOf, editRepairText, fullDocumentText, needsRepair, repairText, systemPrompt, systemPromptParts, toolResultsSlot, typeText, withDocument };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { askOf, documentOf, withDocument } from "./document.js";
|
|
2
2
|
import { editRepairText, fullDocumentText, needsRepair, repairText } from "./repair.js";
|
|
3
3
|
import { typeText } from "./types.js";
|
|
4
|
+
import { TOOL_RESULTS, toolResultsSlot } from "./tool-results.js";
|
|
4
5
|
import { systemPrompt, systemPromptParts } from "./system-prompt.js";
|
|
5
|
-
export { askOf, documentOf, editRepairText, fullDocumentText, needsRepair, repairText, systemPrompt, systemPromptParts, typeText, withDocument };
|
|
6
|
+
export { TOOL_RESULTS, askOf, documentOf, editRepairText, fullDocumentText, needsRepair, repairText, systemPrompt, systemPromptParts, toolResultsSlot, typeText, withDocument };
|
package/dist/system-prompt.d.ts
CHANGED
|
@@ -11,6 +11,12 @@ export interface PromptOptions {
|
|
|
11
11
|
instructions?: string;
|
|
12
12
|
/** Default "document". */
|
|
13
13
|
mode?: PromptMode;
|
|
14
|
+
/**
|
|
15
|
+
* The host carries the `toolResults` slot (`toolResultsSlot`): add the
|
|
16
|
+
* rules on reading a tool's results instead of copying them. The slot
|
|
17
|
+
* itself is listed as any provided slot is.
|
|
18
|
+
*/
|
|
19
|
+
toolResults?: boolean;
|
|
14
20
|
}
|
|
15
21
|
/**
|
|
16
22
|
* The system prompt for writing Jigs against `host`. In document mode
|
|
@@ -22,10 +28,10 @@ export interface PromptOptions {
|
|
|
22
28
|
* cache it as a prefix: the output rules, the language, the catalog's
|
|
23
29
|
* types and components, the app's tags, the design guidance and situations.
|
|
24
30
|
* What a turn may change comes last: the app's `instructions`, the
|
|
25
|
-
* procedures' own types, the queries, mutations and actions,
|
|
26
|
-
* procedure enum the catalog already names keeps that name;
|
|
27
|
-
* named among the procedures alone, so changing them never
|
|
28
|
-
* prefix.
|
|
31
|
+
* procedures' own types, the queries, provided data, mutations and actions,
|
|
32
|
+
* and images. A procedure enum the catalog already names keeps that name;
|
|
33
|
+
* the others are named among the procedures alone, so changing them never
|
|
34
|
+
* changes the prefix.
|
|
29
35
|
*/
|
|
30
36
|
export declare function systemPrompt(host: Host, options?: PromptOptions): string;
|
|
31
37
|
/** The system prompt in two parts: what stays the same from turn to turn, and the rest. */
|
package/dist/system-prompt.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { enumKey, enumUses, objectUses, typeText } from "./types.js";
|
|
2
2
|
import { sharedObjects, sharedTypes } from "./shared-types.js";
|
|
3
|
+
import { CHAT_TOOL_RULE, HOOKS_TOOL_RULE } from "./tool-results.js";
|
|
3
4
|
import { jigSignature } from "@jigs.design/compiler";
|
|
4
5
|
import { dataSchema } from "@jigs.design/host";
|
|
5
6
|
//#region src/system-prompt.ts
|
|
@@ -76,7 +77,8 @@ const LANGUAGE = `## Rules
|
|
|
76
77
|
- The body sees only its props, its own \`{@body}\` lines and other components. It does not see the document's state; pass values in as props, with a setter if the component should change them.
|
|
77
78
|
- In a list, give each instance a \`key\` (\`<stat key={item.id}/>\`), on the component inside \`<each>\`, not on \`<each>\`, or repeat items that have an \`id\`, so that state stays put when the list changes.`;
|
|
78
79
|
const NO_PROCEDURES = `## Data and actions
|
|
79
|
-
- This app registered no queries or mutations. Do not call \`useQuery\` or \`useMutation\`; keep everything in state
|
|
80
|
+
- This app registered no queries or mutations. Do not call \`useQuery\` or \`useMutation\`; keep everything in state.
|
|
81
|
+
- Data given in the request itself: write it in \`{@body}\` as literal values and show it. No data given, and the ask is about the user's own records (their accounts, orders, balances): show the UI with placeholders and say what is missing; never invent their numbers, names or records. Content the ask asks you to make, such as a recipe, a quiz, an FAQ or example rows, is yours to write.`;
|
|
80
82
|
const HOOKS = `## Data and actions
|
|
81
83
|
- \`{@body const orders = useQuery("orders", { status: "open" })}\` reads a query listed below while rendering. It returns \`{ status, data, error }\`: status is "pending", "success" or "error"; \`data\` is null until "success"; \`error\` is \`{ code, message }\`. Show each status with \`<if>\`. There is no \`isLoading\` and no \`refetch\`.
|
|
82
84
|
- Calls with the same name and input share one request. Pass submitted values, not live keystrokes: keep a text field in state and copy it into the query's input on Enter or a button.
|
|
@@ -86,7 +88,7 @@ const HOOKS = `## Data and actions
|
|
|
86
88
|
- After a mutation succeeds, the queries listed under "Refreshes" reload by themselves. Write nothing to make that happen.
|
|
87
89
|
- An action listed below is called the same way, with \`useMutation("name")\` and \`mutate(input)\` in a handler. The page handles it instead of the server, for example by sending a message; its handle has the same \`status\`, \`data\` and \`error\`.
|
|
88
90
|
- The first argument is always the name as a string literal. Never write \`useQuery({ queryKey, queryFn })\`.
|
|
89
|
-
-
|
|
91
|
+
- Where a UI's data comes from, in this order. A query or provided slot listed below that covers the ask: read it with \`useQuery\` and show what it returns, and never write its values into the UI yourself, not even as an example. Data given in the request itself that no listed name covers: write it in \`{@body}\` as literal values and show it. Neither, and the ask is about the user's own records (their accounts, orders, balances): show the UI with placeholders and say what is missing; never invent their numbers, names or records. Content the ask asks you to make, such as a recipe, a quiz, an FAQ or example rows, is yours to write.
|
|
90
92
|
- Inputs and data are TypeScript-like types. A \`//\` comment gives a field's meaning and limits; follow them when you build an input.`;
|
|
91
93
|
const COMPONENTS_INTRO = `## Components
|
|
92
94
|
Each prop is \`name: type = default\`, then what it does. Leave a prop out to get its default.
|
|
@@ -203,6 +205,27 @@ function actionSection(name, procedure, names) {
|
|
|
203
205
|
"Handled by the page, not the server. Refreshes nothing."
|
|
204
206
|
].join("\n");
|
|
205
207
|
}
|
|
208
|
+
const PROVIDED_INTRO = `## Provided data
|
|
209
|
+
The app supplies these when it shows the UI. Read one with \`useQuery("name")\`; it takes no input and is never stale on your side.`;
|
|
210
|
+
function slotSection(name, procedure, names) {
|
|
211
|
+
return [
|
|
212
|
+
`### ${name}`,
|
|
213
|
+
procedure.description,
|
|
214
|
+
`Call: useQuery("${name}")`,
|
|
215
|
+
`Data: ${procedure.dataText ?? typeText(procedure.output, "output", names)}`
|
|
216
|
+
].join("\n");
|
|
217
|
+
}
|
|
218
|
+
/** `text` with `line` after its line that starts with `after`. */
|
|
219
|
+
function insertAfter(text, after, line) {
|
|
220
|
+
const lines = text.split("\n");
|
|
221
|
+
const index = lines.findIndex((entry) => entry.startsWith(after));
|
|
222
|
+
if (index === -1) throw new Error(`The prompt has no line starting "${after}"`);
|
|
223
|
+
return [
|
|
224
|
+
...lines.slice(0, index + 1),
|
|
225
|
+
line,
|
|
226
|
+
...lines.slice(index + 1)
|
|
227
|
+
].join("\n");
|
|
228
|
+
}
|
|
206
229
|
const TAGS_INTRO = `## App tags
|
|
207
230
|
Tags this app wrote in Jigs. Use them like any tag, with the props shown; a bare prop is required. They are already defined: never write their <define>. Prefer one over building the same thing from components. When one of them alone answers the ask, the UI is that one tag and nothing else.`;
|
|
208
231
|
function tagSection(entry) {
|
|
@@ -291,10 +314,10 @@ function typesSection(heading, intro, declarations) {
|
|
|
291
314
|
* cache it as a prefix: the output rules, the language, the catalog's
|
|
292
315
|
* types and components, the app's tags, the design guidance and situations.
|
|
293
316
|
* What a turn may change comes last: the app's `instructions`, the
|
|
294
|
-
* procedures' own types, the queries, mutations and actions,
|
|
295
|
-
* procedure enum the catalog already names keeps that name;
|
|
296
|
-
* named among the procedures alone, so changing them never
|
|
297
|
-
* prefix.
|
|
317
|
+
* procedures' own types, the queries, provided data, mutations and actions,
|
|
318
|
+
* and images. A procedure enum the catalog already names keeps that name;
|
|
319
|
+
* the others are named among the procedures alone, so changing them never
|
|
320
|
+
* changes the prefix.
|
|
298
321
|
*/
|
|
299
322
|
function systemPrompt(host, options) {
|
|
300
323
|
const parts = systemPromptParts(host, options);
|
|
@@ -315,10 +338,12 @@ function systemPromptParts(host, options) {
|
|
|
315
338
|
const objectTypes = sharedObjects(procedureObjects(host), enumNames, new Set([...catalogTypes.declarations, ...dataTypes.declarations].map((declaration) => declaration.name)));
|
|
316
339
|
const names = objectTypes.names;
|
|
317
340
|
const mode = options?.mode ?? "document";
|
|
341
|
+
const tools = options?.toolResults === true;
|
|
342
|
+
const hooks = tools ? insertAfter(HOOKS, "- Where a UI's data comes from", HOOKS_TOOL_RULE) : HOOKS;
|
|
318
343
|
const sections = [
|
|
319
|
-
OUTPUT[mode],
|
|
344
|
+
tools && mode === "chat" ? insertAfter(OUTPUT.chat, "- You never see what a query returns", CHAT_TOOL_RULE) : OUTPUT[mode],
|
|
320
345
|
LANGUAGE,
|
|
321
|
-
entries.length === 0 ? NO_PROCEDURES :
|
|
346
|
+
entries.length === 0 ? NO_PROCEDURES : hooks,
|
|
322
347
|
...typesSection("## Types", "Named lists of values, used by the props below and by the data the queries return.", catalogTypes.declarations),
|
|
323
348
|
[COMPONENTS_INTRO, ...componentSections(host.components.components, catalogTypes.names)].join("\n\n")
|
|
324
349
|
];
|
|
@@ -332,6 +357,8 @@ function systemPromptParts(host, options) {
|
|
|
332
357
|
if (instructions !== "") variable.push(`## App instructions\n${instructions}`);
|
|
333
358
|
variable.push(...typesSection("## Data types", "Named lists of values and objects, used by the queries and mutations below.", [...dataTypes.declarations, ...objectTypes.declarations]));
|
|
334
359
|
if (queries.length > 0) variable.push(["## Queries", ...queries.map(([name, procedure]) => procedureSection(name, procedure, names))].join("\n\n"));
|
|
360
|
+
const slots = entries.flatMap(([name, procedure]) => procedure.kind === "data" ? [slotSection(name, procedure, names)] : []);
|
|
361
|
+
if (slots.length > 0) variable.push([PROVIDED_INTRO, ...slots].join("\n\n"));
|
|
335
362
|
if (mutations.length > 0) variable.push(["## Mutations", ...mutations.map(([name, procedure]) => procedureSection(name, procedure, names))].join("\n\n"));
|
|
336
363
|
const actions = entries.flatMap(([name, procedure]) => procedure.kind === "action" ? [actionSection(name, procedure, names)] : []);
|
|
337
364
|
if (actions.length > 0) variable.push(["## Actions", ...actions].join("\n\n"));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/tool-results.d.ts
|
|
3
|
+
/** The provided slot that holds a chat's tool results, by tool name. */
|
|
4
|
+
export declare const TOOL_RESULTS = "toolResults";
|
|
5
|
+
/**
|
|
6
|
+
* The `toolResults` slot as a server with `toolResults: true` adds it: the
|
|
7
|
+
* page passes each block the results of the tools called before it in the
|
|
8
|
+
* conversation, keyed by tool name. Its words are the prompt's, so they
|
|
9
|
+
* live here with the rules that name it.
|
|
10
|
+
*/
|
|
11
|
+
export declare const toolResultsSlot: import("@jigs.design/host").DataDefinition<z.ZodRecord<z.ZodString, z.ZodJSONSchema>>;
|
|
12
|
+
//#endregion
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { data } from "@jigs.design/host";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/tool-results.ts
|
|
4
|
+
/** The provided slot that holds a chat's tool results, by tool name. */
|
|
5
|
+
const TOOL_RESULTS = "toolResults";
|
|
6
|
+
/**
|
|
7
|
+
* The `toolResults` slot as a server with `toolResults: true` adds it: the
|
|
8
|
+
* page passes each block the results of the tools called before it in the
|
|
9
|
+
* conversation, keyed by tool name. Its words are the prompt's, so they
|
|
10
|
+
* live here with the rules that name it.
|
|
11
|
+
*/
|
|
12
|
+
const toolResultsSlot = data({
|
|
13
|
+
dataText: `{ [toolName: string]: the tool's latest result, as you were shown it }. A tool not yet called, or whose call failed or was refused, has no entry. Read one as \`results.data?.["searchFlights"]?.flights\`, with the tool's name as a quoted key and \`?.\` at each step.`,
|
|
14
|
+
description: "The results of the tools called in this conversation, by tool name. A page opened from a block keeps the results it had.",
|
|
15
|
+
schema: z.record(z.string(), z.json())
|
|
16
|
+
});
|
|
17
|
+
/** Added after the chat rule that the model never sees what a query returns. */
|
|
18
|
+
const CHAT_TOOL_RULE = `- You have seen what a tool returned. You may state a figure or a conclusion from it in prose, in a sentence. A UI that shows it reads \`${TOOL_RESULTS}\`, never a copy of its values.`;
|
|
19
|
+
/** Added after the rule on where a UI's data comes from. */
|
|
20
|
+
const HOOKS_TOOL_RULE = `- A listed query that covers the ask comes before \`${TOOL_RESULTS}\`: its data stays live. If you call a tool more than once before a block, the block sees only the last result. To show each result, write its block right after its call, and call again after the block.`;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { CHAT_TOOL_RULE, HOOKS_TOOL_RULE, TOOL_RESULTS, toolResultsSlot };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jigs.design/prompt",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "The system prompt and the repair text, rendered from a host and from diagnostics.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@jigs.design/
|
|
29
|
-
"@jigs.design/
|
|
30
|
-
"@jigs.design/protocol": "0.3.
|
|
28
|
+
"@jigs.design/host": "0.3.2",
|
|
29
|
+
"@jigs.design/compiler": "0.3.2",
|
|
30
|
+
"@jigs.design/protocol": "0.3.2"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"zod": "^4.0.0"
|