sygnal 6.2.0 → 6.3.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/CHANGELOG.md +61 -0
- package/README.md +3 -1
- package/dist/ai.cjs.js +36 -0
- package/dist/ai.cjs.js.map +1 -1
- package/dist/ai.esm.js +1 -1
- package/dist/astro/server.cjs.js +3 -3
- package/dist/astro/server.cjs.js.map +1 -1
- package/dist/astro/server.mjs +3 -3
- package/dist/astro/server.mjs.map +1 -1
- package/dist/diagnostics.cjs.js +164 -3
- package/dist/diagnostics.cjs.js.map +1 -1
- package/dist/diagnostics.esm.js +164 -3
- package/dist/diagnostics.esm.js.map +1 -1
- package/dist/guide/agent.md +7 -1
- package/dist/guide/ai-cards.md +319 -0
- package/dist/guide/ai-chat.md +4 -0
- package/dist/guide/ai-compose.md +881 -0
- package/dist/guide/ai-decisions.md +16 -0
- package/dist/guide/http.md +1 -0
- package/dist/index.cjs.js +5695 -347
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +638 -8
- package/dist/index.esm.js +5685 -347
- package/dist/index.esm.js.map +1 -1
- package/dist/sygnal.min.js +1 -1
- package/dist/sygnal.min.js.map +1 -1
- package/dist/vike/config/package.json +1 -1
- package/dist/vike/onRenderClient.cjs.js +3 -2
- package/dist/vike/onRenderClient.cjs.js.map +1 -1
- package/dist/vike/onRenderClient.mjs +3 -2
- package/dist/vike/onRenderClient.mjs.map +1 -1
- package/llms.txt +6 -4
- package/package.json +2 -1
- package/src/ai.d.ts +642 -7
- package/src/ai.ts +6 -0
- package/src/collection.ts +2 -1
- package/src/core/instance.ts +6 -3
- package/src/core/markers/lazy.ts +7 -3
- package/src/core/markers/portal.ts +5 -2
- package/src/core/markers/suspense.ts +3 -2
- package/src/core/markers/transition.ts +6 -3
- package/src/core/registry.ts +9 -5
- package/src/cycle/dom/IsolateModule.ts +25 -22
- package/src/extra/ai/chat/behavior.ts +354 -81
- package/src/extra/ai/chat/driver.ts +7 -4
- package/src/extra/ai/compose/agent.ts +55 -0
- package/src/extra/ai/compose/ask.ts +147 -0
- package/src/extra/ai/compose/behavior.ts +183 -0
- package/src/extra/ai/compose/catalog.ts +211 -0
- package/src/extra/ai/compose/composed.ts +61 -0
- package/src/extra/ai/compose/decisions.ts +1649 -0
- package/src/extra/ai/compose/diag.ts +33 -0
- package/src/extra/ai/compose/index.ts +23 -0
- package/src/extra/ai/compose/layout.ts +441 -0
- package/src/extra/ai/compose/llm.ts +1120 -0
- package/src/extra/ai/compose/render.ts +159 -0
- package/src/extra/ai/compose/testing.ts +71 -0
- package/src/extra/ai/compose/types.ts +159 -0
- package/src/extra/ai/decide.ts +97 -1
- package/src/extra/ai/index.ts +6 -1
- package/src/extra/diagnostics/checks/next.ts +86 -2
- package/src/extra/diagnostics/codes.ts +54 -0
- package/src/extra/fetchDriver.ts +58 -27
- package/src/extra/lens.ts +15 -0
- package/src/extra/ssr.ts +3 -3
- package/src/extra/testing.ts +2 -0
- package/src/extra/widget.ts +3 -3
- package/src/index.d.ts +41 -0
- package/src/index.ts +8 -0
- package/src/lazy.ts +3 -2
- package/src/portal.ts +5 -2
- package/src/pragma/index.ts +2 -1
- package/src/suspense.ts +5 -2
- package/src/switchable.ts +2 -1
- package/src/transition.ts +5 -2
- package/src/vike/onRenderClient.ts +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { VNode, VNodeData } from 'snabbdom/build/vnode.js';
|
|
|
4
4
|
import { Module } from 'snabbdom/build/modules/module.js';
|
|
5
5
|
import xsDefault, { Stream, MemoryStream } from 'xstream';
|
|
6
6
|
export { MemoryStream, Stream } from 'xstream';
|
|
7
|
-
import { FieldErrors as FieldErrors$1, BehaviorTarget as BehaviorTarget$1, Behavior as Behavior$1, FetchRequest as FetchRequest$1 } from 'sygnal';
|
|
7
|
+
import { FieldErrors as FieldErrors$1, BehaviorTarget as BehaviorTarget$1, Behavior as Behavior$1, RenderResult as RenderResult$1, FetchRequest as FetchRequest$1 } from 'sygnal';
|
|
8
8
|
export { h } from 'snabbdom/build/h.js';
|
|
9
9
|
export { default as debounce } from 'xstream/extra/debounce.js';
|
|
10
10
|
export { default as throttle } from 'xstream/extra/throttle.js';
|
|
@@ -176,7 +176,7 @@ declare function makeDOMDriver(container: string | Element | DocumentFragment, o
|
|
|
176
176
|
type MessagePart =
|
|
177
177
|
| { type: 'text'; text: string }
|
|
178
178
|
| { type: 'reasoning'; text: string; /** provider data to send back with it (an Anthropic thinking signature) */ providerMetadata?: Record<string, Record<string, unknown>> }
|
|
179
|
-
| { type: `tool-${string}`; toolCallId: string; state: string; input?: unknown; output?: unknown; errorText?: string; approval?: { id: string; approved?: boolean; reason?: string; [key: string]: unknown }; providerExecuted?: boolean }
|
|
179
|
+
| { type: `tool-${string}`; toolCallId: string; state: string; input?: unknown; output?: unknown; errorText?: string; approval?: { id: string; approved?: boolean; reason?: string; [key: string]: unknown }; providerExecuted?: boolean; /** PLAN-9 H-2: an `ask_user` call's card */ ui?: ChatCard }
|
|
180
180
|
| { type: 'file'; mediaType: string; url: string; filename?: string }
|
|
181
181
|
| { type: `source-${string}`; [key: string]: unknown }
|
|
182
182
|
| { type: `data-${string}`; id?: string; data: unknown }
|
|
@@ -288,7 +288,7 @@ interface Decision<Q extends Questions = Questions, R = never> {
|
|
|
288
288
|
type FetchRequestObject = Extract<FetchRequest$1, { url: string }>
|
|
289
289
|
|
|
290
290
|
/** What `decide()` / `decide.openai()` take: the decision, plus any `makeFetchDriver` request keys */
|
|
291
|
-
type DecideOptions<Q extends Questions> = Omit<FetchRequestObject, 'url' | 'json' | 'body'> & {
|
|
291
|
+
type DecideOptions<Q extends Questions> = Omit<FetchRequestObject, 'url' | 'json' | 'body' | 'batch' | 'combine' | 'split'> & {
|
|
292
292
|
/** Default '/api/decide' (the app's own route, which holds the API key) */
|
|
293
293
|
url?: string
|
|
294
294
|
/** The decision model, e.g. 'jev-latest' (TypeSafe), 'nimble' (Ollama), 'gpt-6-luna' (OpenAI) */
|
|
@@ -298,6 +298,23 @@ type DecideOptions<Q extends Questions> = Omit<FetchRequestObject, 'url' | 'json
|
|
|
298
298
|
questions: Q
|
|
299
299
|
/** Base64 PNG / JPEG / WebP files shared by every question (models that read images only) */
|
|
300
300
|
images?: readonly string[]
|
|
301
|
+
/**
|
|
302
|
+
* D472: more questions than this go as parallel sub-requests (a fetch-driver `batch`), their
|
|
303
|
+
* replies merged into one (`answers` by name, `usage` summed). Default 64 (Ollama's limit)
|
|
304
|
+
*/
|
|
305
|
+
maxQuestions?: number
|
|
306
|
+
/**
|
|
307
|
+
* D472: split the same way when the estimated prompt of one question (the state plus every
|
|
308
|
+
* question of the request, as Ollama counts it; the estimate runs high) passes this. Default:
|
|
309
|
+
* none; a request a server rejects as too large is halved anyway (`split`)
|
|
310
|
+
*/
|
|
311
|
+
maxPromptTokens?: number
|
|
312
|
+
/**
|
|
313
|
+
* false: one request whatever its size, and no halving on a "too large" rejection. Default: on
|
|
314
|
+
* (a request under the limits is sent as is; a 400 / 413 that names tokens, fields, context, a
|
|
315
|
+
* limit or "too long / many / large" sends it again in halves, at most 3 deep)
|
|
316
|
+
*/
|
|
317
|
+
split?: boolean
|
|
301
318
|
/** As a resource: keep the previous `data` on a new request */
|
|
302
319
|
keepPrevious?: boolean
|
|
303
320
|
/** As a resource: refetch every this many ms */
|
|
@@ -307,10 +324,15 @@ type DecideOptions<Q extends Questions> = Omit<FetchRequestObject, 'url' | 'json
|
|
|
307
324
|
}
|
|
308
325
|
|
|
309
326
|
/** A decision as a `makeFetchDriver` request (POST JSON); its reply is a `Decision<Q, R>` */
|
|
310
|
-
type DecideRequest<Q extends Questions = Questions, R = never> = Omit<DecideOptions<Q>, 'model' | 'state' | 'questions' | 'images' | 'url'> & {
|
|
327
|
+
type DecideRequest<Q extends Questions = Questions, R = never> = Omit<DecideOptions<Q>, 'model' | 'state' | 'questions' | 'images' | 'url' | 'maxQuestions' | 'maxPromptTokens' | 'split'> & {
|
|
311
328
|
url: string
|
|
312
329
|
method: 'POST'
|
|
330
|
+
/** the whole decision (what a test fake answers); over the limits, the parts go in `batch` */
|
|
313
331
|
json: Record<string, unknown>
|
|
332
|
+
/** D472: the parts of a decision over the limits (sent in parallel, merged by `combine`) */
|
|
333
|
+
batch?: ReadonlyArray<{ url: string; method: 'POST'; json: Record<string, unknown>; parse?: (response: Response) => any }>
|
|
334
|
+
combine?: (bodies: any[], requests: any[]) => any
|
|
335
|
+
split?: (request: any, error: Error & { status?: number; body?: any }) => any[] | null
|
|
314
336
|
/** Type only: the reply's shape (`Decision<Q, R>`); never set */
|
|
315
337
|
readonly __decision?: Decision<Q, R>
|
|
316
338
|
}
|
|
@@ -657,6 +679,11 @@ type ChatRequest<OUT = unknown> = {
|
|
|
657
679
|
* `ok` gets the validated `value`, a failure is the `error` reply with `issues`
|
|
658
680
|
*/
|
|
659
681
|
output?: ChatOutputSchema<OUT>;
|
|
682
|
+
/**
|
|
683
|
+
* `false`: the transport still sends `output`'s JSON Schema, but the driver doesn't read the reply:
|
|
684
|
+
* `ok` has the `text` and no `value` (the caller parses it, e.g. leniently; compose.llm() does)
|
|
685
|
+
*/
|
|
686
|
+
parse?: false;
|
|
660
687
|
/** The request's key for `latest` and `abort` (default: `ok`, else `error`) */
|
|
661
688
|
key?: string;
|
|
662
689
|
/** A new request aborts the sender's request under the same key (default true) */
|
|
@@ -689,7 +716,7 @@ type ChatRequest<OUT = unknown> = {
|
|
|
689
716
|
}
|
|
690
717
|
|
|
691
718
|
/** Stops the sender's requests under a key (`{ abort: 'reply' }`, `{ abort: true, key: 'reply' }`), or all of them (`{ abort: true }`) */
|
|
692
|
-
type ChatAbort = { abort: string | true; key?: string }
|
|
719
|
+
type ChatAbort = { abort: string | readonly string[] | true; key?: string }
|
|
693
720
|
|
|
694
721
|
/** `delta` action data: the reply so far */
|
|
695
722
|
type ChatDelta = {
|
|
@@ -900,6 +927,16 @@ interface ChatActions {
|
|
|
900
927
|
DENY: any
|
|
901
928
|
/** The turn is over (a host entry `'assistant.DONE'` runs after the behavior's) */
|
|
902
929
|
DONE: ChatDone
|
|
930
|
+
/**
|
|
931
|
+
* PLAN-9 H-1: answer an open client tool call (`clientTools`, or `ask_user`): an
|
|
932
|
+
* `input-available` client part of the last message (else nothing happens, SYG685). The next
|
|
933
|
+
* request goes once no call is open. The AI SDK's `addToolOutput`
|
|
934
|
+
*/
|
|
935
|
+
TOOL_OUTPUT: { toolCallId: string; output: unknown } | { toolCallId: string; errorText: string }
|
|
936
|
+
/** PLAN-9 H-1: a client tool call opened (a host entry `'assistant.TOOL_CALL'` runs after it, once per call; the AI SDK's `onToolCall`) */
|
|
937
|
+
TOOL_CALL: ChatCall
|
|
938
|
+
/** PLAN-9 H-2: a result part answered a card (`compose.answer(props, value)`, heard through CHILD.select): the call's output is `{ part, answer }` */
|
|
939
|
+
ANSWER: ComposeAnswer
|
|
903
940
|
/** Internal: the prompt field's input */
|
|
904
941
|
PROMPT: string
|
|
905
942
|
}
|
|
@@ -926,8 +963,13 @@ interface ChatOptions {
|
|
|
926
963
|
* user-entered text named; G-631)
|
|
927
964
|
*/
|
|
928
965
|
instructions?: string
|
|
929
|
-
/**
|
|
930
|
-
|
|
966
|
+
/**
|
|
967
|
+
* A model id for the requests (overrides the transport's), or a function of the host's state
|
|
968
|
+
* that returns one, resolved per request: `model: (state) => state.chatModel` lets an app's model
|
|
969
|
+
* picker switch models with one chat behavior. The default card backend (`ask` without
|
|
970
|
+
* `backend`) uses it too
|
|
971
|
+
*/
|
|
972
|
+
model?: string | ((state: any) => string | undefined)
|
|
931
973
|
/**
|
|
932
974
|
* Whose `agent` declarations become tools: by default the host's and its shown descendants'
|
|
933
975
|
* (D249); `false`: none; `[Comp, …]`: only these components' (in the host's subtree)
|
|
@@ -937,6 +979,13 @@ interface ChatOptions {
|
|
|
937
979
|
maxSteps?: number
|
|
938
980
|
/** Extra request keys for the transport */
|
|
939
981
|
transportOptions?: Record<string, unknown>
|
|
982
|
+
/**
|
|
983
|
+
* PLAN-9 H-1: tools the app answers itself: sent with the agent tools (a name in both: the
|
|
984
|
+
* client tool, SYG684); their calls stay `input-available` until `TOOL_OUTPUT` answers them
|
|
985
|
+
*/
|
|
986
|
+
clientTools?: Record<string, ChatClientTool>
|
|
987
|
+
/** PLAN-9 H-2: the `ask_user` tool: the model says what it needs, and the app shows a card built from the catalog */
|
|
988
|
+
ask?: ChatAskOptions
|
|
940
989
|
}
|
|
941
990
|
|
|
942
991
|
/**
|
|
@@ -1388,6 +1437,552 @@ interface McpAppDriverOptions {
|
|
|
1388
1437
|
*/
|
|
1389
1438
|
declare function makeMcpAppDriver(options?: McpAppDriverOptions): (sink$: Stream<McpAppRequest>) => McpAppSource
|
|
1390
1439
|
|
|
1440
|
+
// ---- PLAN-9 compose ------------------------------------------------------------------------------
|
|
1441
|
+
// (worker A: catalogs, layouts, render, the compose behavior, composeWith; B and C add their
|
|
1442
|
+
// sub-sections below)
|
|
1443
|
+
|
|
1444
|
+
/** A record for a record param: `from: (state) => records` (the value becomes the node key `part:value`) */
|
|
1445
|
+
interface CatalogRecord<V extends string | number = string | number> {
|
|
1446
|
+
value: V
|
|
1447
|
+
name?: string
|
|
1448
|
+
aliases?: string[]
|
|
1449
|
+
description?: string
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/** A part's (or container's) param declaration */
|
|
1453
|
+
type CatalogParam =
|
|
1454
|
+
/** an enum: the model picks one option (decisions: a choice, `not_stated` = the default; LLM: an enum) */
|
|
1455
|
+
| { options: Record<string, string>; default?: string; label?: string; ask?: string }
|
|
1456
|
+
/** a number (LLM: a number; decisions: a bin, which names the vague words it covers) */
|
|
1457
|
+
| { type: 'number'; min?: number; max?: number; default?: number; bins?: Record<string | number, string>; label?: string }
|
|
1458
|
+
/** free text: LLM only (a decision model keeps the default; `required` with no default makes the part LLM-only) */
|
|
1459
|
+
| { type: 'text'; maxLength?: number; default?: string; required?: boolean; label?: string }
|
|
1460
|
+
/** a list of short texts: LLM only */
|
|
1461
|
+
| { type: 'list'; items?: { maxLength?: number }; min?: number; max?: number; required?: boolean; default?: readonly string[]; label?: string }
|
|
1462
|
+
/** a record: one node per record (at most one per part) */
|
|
1463
|
+
| { from: (state: any) => ReadonlyArray<CatalogRecord>; label?: string }
|
|
1464
|
+
|
|
1465
|
+
/** A param's value type */
|
|
1466
|
+
type CatalogParamValue<P> =
|
|
1467
|
+
P extends { from: (state: any) => ReadonlyArray<{ value: infer V }> } ? V
|
|
1468
|
+
: P extends { options: infer O } ? keyof O & string
|
|
1469
|
+
: P extends { type: 'number' } ? number
|
|
1470
|
+
: P extends { type: 'text' } ? string
|
|
1471
|
+
: P extends { type: 'list' } ? string[]
|
|
1472
|
+
: unknown
|
|
1473
|
+
|
|
1474
|
+
/** The params of a part or container declaration, as a layout or tree holds them (all optional: defaults are left out) */
|
|
1475
|
+
type CatalogParamsOf<E> = E extends { params: infer PS } ? { [K in keyof PS]?: CatalogParamValue<PS[K]> } : Record<string, never>
|
|
1476
|
+
|
|
1477
|
+
/** A node of a layout */
|
|
1478
|
+
interface LayoutNode {
|
|
1479
|
+
part: string
|
|
1480
|
+
/** only the non-default values */
|
|
1481
|
+
params?: Record<string, unknown>
|
|
1482
|
+
/** a container's slots: node keys in order */
|
|
1483
|
+
slots?: Record<string, string[]>
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
/**
|
|
1487
|
+
* A composition's layout: a node map whose keys are identities (the part id; `part:recordValue`;
|
|
1488
|
+
* repeats `~2`, `~3`; containers by id: `row`, `row~2`). Plain JSON state.
|
|
1489
|
+
*/
|
|
1490
|
+
interface Layout {
|
|
1491
|
+
root: 'page'
|
|
1492
|
+
nodes: Record<string, LayoutNode>
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
/** A nested tree (what a model writes, what tests use), not tied to a catalog */
|
|
1496
|
+
type ComposeTree = Array<{ part: string; params?: Record<string, unknown>; children?: ComposeTree | Record<string, ComposeTree> }>
|
|
1497
|
+
|
|
1498
|
+
type CatalogLens = { get(state: any): any; set?(state: any, value: any): any }
|
|
1499
|
+
|
|
1500
|
+
/** A part declaration */
|
|
1501
|
+
interface CatalogPartDecl<STATE = any> {
|
|
1502
|
+
/** a Sygnal component (a child of the host: CHILD.select, lenses, EVENTS and context work) */
|
|
1503
|
+
component?: any
|
|
1504
|
+
/** or a view function, called inline with the props (and `state` read through the lens) */
|
|
1505
|
+
render?: (props: any) => any
|
|
1506
|
+
/** fixed props (params go over them), or `(params, state) => props` */
|
|
1507
|
+
props?: Record<string, any> | ((params: Record<string, any>, state: STATE) => Record<string, any>)
|
|
1508
|
+
/** all a model sees of it: "Noun (what it shows)" */
|
|
1509
|
+
description: string
|
|
1510
|
+
/** its state: a key of the host's state, a lens, or `(node, key) => lens` (a record part: `byId(…)`) */
|
|
1511
|
+
state?: string | CatalogLens | ((node: LayoutNode & { params: Record<string, any> }, key: string) => string | CatalogLens)
|
|
1512
|
+
/** state kept in the composition (`slice.local[nodeKey]`), starting as this */
|
|
1513
|
+
local?: unknown
|
|
1514
|
+
params?: Record<string, CatalogParam>
|
|
1515
|
+
/** where it may go: `'page'`, `'container'` (any slot) or `'container:slot'` (default `['page']`) */
|
|
1516
|
+
in?: string | readonly string[]
|
|
1517
|
+
/** alternatives: the first part of a group in a layout wins */
|
|
1518
|
+
group?: string
|
|
1519
|
+
/** how often one identity may appear (default 1) */
|
|
1520
|
+
maxUses?: number
|
|
1521
|
+
/** always on the page (added by the finishing step; not offered to a model) */
|
|
1522
|
+
required?: boolean
|
|
1523
|
+
pin?: 'start' | 'end'
|
|
1524
|
+
/** parts added right after it */
|
|
1525
|
+
companions?: readonly string[]
|
|
1526
|
+
category?: string
|
|
1527
|
+
/** a part that answers a card (`compose.answer(props, value)`) */
|
|
1528
|
+
result?: boolean
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
/** What a container's view gets */
|
|
1532
|
+
interface ContainerView {
|
|
1533
|
+
key: string
|
|
1534
|
+
node: LayoutNode
|
|
1535
|
+
/** its params, defaults filled */
|
|
1536
|
+
params: Record<string, any>
|
|
1537
|
+
/** each slot's vnodes */
|
|
1538
|
+
slots: Record<string, any[]>
|
|
1539
|
+
/** every child in order */
|
|
1540
|
+
children: Array<{ key: string; node: LayoutNode; part: CatalogPart | CatalogContainer; slot: string; vnode: any }>
|
|
1541
|
+
/** `slice.ui[key]` */
|
|
1542
|
+
ui: Record<string, any>
|
|
1543
|
+
/** data attributes to spread on an element: a click on it sets `ui[key][name] = value` (the behavior's CONTROL) */
|
|
1544
|
+
control(name: string, value?: unknown): Record<string, string>
|
|
1545
|
+
scope?: string
|
|
1546
|
+
frozen: boolean
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
/** A container declaration: a view function with named slots (the model never chooses one) */
|
|
1550
|
+
interface CatalogContainerDecl {
|
|
1551
|
+
/** slot name → description (default `{ default: null }`) */
|
|
1552
|
+
slots?: Record<string, string | null>
|
|
1553
|
+
/** fewer filled slots: unwrapped */
|
|
1554
|
+
minSlots?: number
|
|
1555
|
+
/** children per slot: fewer than `min` unwraps it, more than `max` overflow after it (a row splits) */
|
|
1556
|
+
min?: number
|
|
1557
|
+
max?: number
|
|
1558
|
+
/** only parts in its slots */
|
|
1559
|
+
accepts?: 'leaves'
|
|
1560
|
+
/** its order is fixed (no rows inside) */
|
|
1561
|
+
arranged?: boolean
|
|
1562
|
+
direction?: 'row' | 'column'
|
|
1563
|
+
description?: string
|
|
1564
|
+
/** where it may go (default `['page']`) */
|
|
1565
|
+
in?: string | readonly string[]
|
|
1566
|
+
params?: Record<string, CatalogParam>
|
|
1567
|
+
/** a view function, never a component (SYG161) */
|
|
1568
|
+
render?: (view: ContainerView) => any
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
/** defineCatalog's declaration */
|
|
1572
|
+
interface CatalogDecl {
|
|
1573
|
+
parts: Record<string, CatalogPartDecl>
|
|
1574
|
+
/** `page` and `row` are built in (override their render; `row: false` opts out, as `rows: false` does) */
|
|
1575
|
+
containers?: Record<string, CatalogContainerDecl | false>
|
|
1576
|
+
/** the page's label */
|
|
1577
|
+
description?: string
|
|
1578
|
+
/** `{ id: description }`, named by parts' `category` (a prefilter for large catalogs) */
|
|
1579
|
+
categories?: Record<string, string>
|
|
1580
|
+
/** false: no built-in row (canonical; `containers: { row: false }` too) */
|
|
1581
|
+
rows?: boolean
|
|
1582
|
+
/** quoted in order questions and the LLM prompt */
|
|
1583
|
+
guidance?: string
|
|
1584
|
+
/**
|
|
1585
|
+
* maxParts (default 12): parts on the page. maxDepth (default 4): how deep a container may sit,
|
|
1586
|
+
* the page's children at depth 1; a deeper one moves to the page
|
|
1587
|
+
*/
|
|
1588
|
+
limits?: { maxParts?: number; maxDepth?: number }
|
|
1589
|
+
/** app-written few-shot cases (LLM) */
|
|
1590
|
+
examples?: readonly unknown[]
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
/** A normalized part */
|
|
1594
|
+
interface CatalogPart {
|
|
1595
|
+
id: string
|
|
1596
|
+
kind: 'part'
|
|
1597
|
+
description: string
|
|
1598
|
+
params: Record<string, CatalogParam & { kind: 'options' | 'number' | 'text' | 'list' | 'record' }>
|
|
1599
|
+
/** the record param's name */
|
|
1600
|
+
record?: string
|
|
1601
|
+
/** 'container:slot' entries */
|
|
1602
|
+
in: string[]
|
|
1603
|
+
group?: string
|
|
1604
|
+
maxUses: number
|
|
1605
|
+
required: boolean
|
|
1606
|
+
pin?: 'start' | 'end'
|
|
1607
|
+
companions: string[]
|
|
1608
|
+
category?: string
|
|
1609
|
+
result: boolean
|
|
1610
|
+
decl: CatalogPartDecl
|
|
1611
|
+
[key: string]: any
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
/** A normalized container */
|
|
1615
|
+
interface CatalogContainer {
|
|
1616
|
+
id: string
|
|
1617
|
+
kind: 'container'
|
|
1618
|
+
slots: Record<string, string | null>
|
|
1619
|
+
slotNames: string[]
|
|
1620
|
+
minSlots?: number
|
|
1621
|
+
min?: number
|
|
1622
|
+
max?: number
|
|
1623
|
+
accepts?: 'leaves'
|
|
1624
|
+
arranged: boolean
|
|
1625
|
+
direction?: 'row' | 'column'
|
|
1626
|
+
description?: string
|
|
1627
|
+
in: string[]
|
|
1628
|
+
params: Record<string, CatalogParam>
|
|
1629
|
+
render: (view: ContainerView) => any
|
|
1630
|
+
decl: CatalogContainerDecl
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
/** One selectable option: a part, or a record part once per record (`part:value`) */
|
|
1634
|
+
interface CatalogOption { option: string; part: string; params?: Record<string, unknown>; description: string }
|
|
1635
|
+
|
|
1636
|
+
type CatalogPartIds<D> = D extends { parts: infer P } ? keyof P & string : string
|
|
1637
|
+
type CatalogContainerIds<D> = (D extends { containers: infer C } ? { [K in keyof C & string]: C[K] extends false ? never : K }[keyof C & string] : never) | 'row'
|
|
1638
|
+
type CatalogContainerOf<D, C> = D extends { containers: infer CS } ? C extends keyof CS ? CS[C] : {} : {}
|
|
1639
|
+
type CatalogSlotsOf<D, C> = CatalogContainerOf<D, C> extends { slots: infer S } ? keyof S & string : 'default'
|
|
1640
|
+
type CatalogPartOf<D, P> = D extends { parts: infer PS } ? P extends keyof PS ? PS[P] : never : never
|
|
1641
|
+
|
|
1642
|
+
/** A tree node for a catalog: a part with its params, or a container with its children */
|
|
1643
|
+
type CatalogTreeNode<D> =
|
|
1644
|
+
| { [P in CatalogPartIds<D>]: { part: P; params?: CatalogParamsOf<CatalogPartOf<D, P>> } }[CatalogPartIds<D>]
|
|
1645
|
+
| { [C in CatalogContainerIds<D>]: { part: C; params?: CatalogParamsOf<CatalogContainerOf<D, C>>; children?: CatalogTreeNode<D>[] | { [S in CatalogSlotsOf<D, C>]?: CatalogTreeNode<D>[] } } }[CatalogContainerIds<D>]
|
|
1646
|
+
|
|
1647
|
+
/** A nested tree for a catalog (part ids, params and slots checked); `ComposeTree` for an untyped one */
|
|
1648
|
+
type CatalogTree<D> = 0 extends (1 & D) ? ComposeTree : CatalogTreeNode<D>[]
|
|
1649
|
+
|
|
1650
|
+
/** catalog.render's options */
|
|
1651
|
+
interface ComposeRenderOptions {
|
|
1652
|
+
/** several compositions in one host (one per chat card): instance keys become `scope/nodeKey`; parts get `scope` */
|
|
1653
|
+
scope?: string
|
|
1654
|
+
/** an answered card: wrapped in `<fieldset disabled>`; parts get `frozen` */
|
|
1655
|
+
frozen?: boolean
|
|
1656
|
+
/** a result part's answer: `answer.value` goes to the part whose key is `answer.node` */
|
|
1657
|
+
answer?: { node: string; value: unknown } | null
|
|
1658
|
+
/** the slice's path in the host state (for `local` parts; default: the host key whose value is the slice) */
|
|
1659
|
+
at?: string | ReadonlyArray<string | number>
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
/** What catalog.render renders: a compose slice, or anything with a layout */
|
|
1663
|
+
type ComposeRenderable = { layout: Layout | null; preview?: Layout | null; ui?: Record<string, Record<string, any>>; local?: Record<string, any> }
|
|
1664
|
+
|
|
1665
|
+
/** A catalog (defineCatalog's result); D is the declaration, for typed trees */
|
|
1666
|
+
interface Catalog<D = CatalogDecl> {
|
|
1667
|
+
/** (type only) the declaration */
|
|
1668
|
+
readonly __decl?: D
|
|
1669
|
+
parts: Record<string, CatalogPart>
|
|
1670
|
+
containers: Record<string, CatalogContainer>
|
|
1671
|
+
get(id: string): CatalogPart | CatalogContainer | undefined
|
|
1672
|
+
/** every selectable option for this state */
|
|
1673
|
+
options(state: any): CatalogOption[]
|
|
1674
|
+
/** a record part's records (validated: SYG252) */
|
|
1675
|
+
records(part: string | CatalogPart, state: any): CatalogRecord[]
|
|
1676
|
+
/** the deterministic finishing step (idempotent) */
|
|
1677
|
+
finish(layout: Layout | null | undefined, state?: any): Layout
|
|
1678
|
+
/**
|
|
1679
|
+
* The composition as vnodes for the host's own view: `slice.preview ?? slice.layout`, each part a
|
|
1680
|
+
* child of the host (keyed by its node key), containers through their view functions.
|
|
1681
|
+
*/
|
|
1682
|
+
render(slice: ComposeRenderable | null | undefined, state: any, options?: ComposeRenderOptions): any
|
|
1683
|
+
description?: string
|
|
1684
|
+
categories: Record<string, string>
|
|
1685
|
+
rows: boolean
|
|
1686
|
+
guidance?: string
|
|
1687
|
+
limits: { maxParts: number; maxDepth: number }
|
|
1688
|
+
examples: unknown[]
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
/**
|
|
1692
|
+
* PLAN-9 K-1: a catalog of prepared parts a model composes from, one declaration for both
|
|
1693
|
+
* backends. `catalog.render(state.page, state)` renders a composition.
|
|
1694
|
+
*/
|
|
1695
|
+
declare function defineCatalog<const D extends CatalogDecl>(decl: D): Catalog<D>
|
|
1696
|
+
|
|
1697
|
+
/** fromTree(catalog, tree, previous?): a tree → a layout, reusing `previous`'s keys (same params, then same identity) */
|
|
1698
|
+
declare function fromTree<D>(catalog: Catalog<D>, tree: CatalogTree<D>, previous?: Layout | null): Layout
|
|
1699
|
+
/** toTree(layout): the nested tree (keys dropped) */
|
|
1700
|
+
declare function toTree(layout: Layout | null | undefined): ComposeTree
|
|
1701
|
+
/** removeNode(layout, key): the layout without that node and its subtree (not finished) */
|
|
1702
|
+
declare function removeNode(layout: Layout, key: string): Layout
|
|
1703
|
+
|
|
1704
|
+
/** The reply action names a backend's requests carry */
|
|
1705
|
+
interface ComposeNames { ok: string; error: string; delta: string; key: string }
|
|
1706
|
+
|
|
1707
|
+
/** A composition backend (`compose.decisions()`, `compose.llm()`, or your own) */
|
|
1708
|
+
interface ComposeBackend {
|
|
1709
|
+
/** the sink its requests go to: 'HTTP' (decisions) or the LLM sink */
|
|
1710
|
+
sink: string
|
|
1711
|
+
start(a: { catalog: Catalog<any>; state: any; prompt: string; previous: Layout | null; names: ComposeNames }): { request: unknown; pending: unknown }
|
|
1712
|
+
/**
|
|
1713
|
+
* a layout (done), `layout: null, unavailable: true` (nothing fits), `request` + `pending` (another
|
|
1714
|
+
* step), or `error`. `keyed: true`: the layout and preview already carry the previous layout's
|
|
1715
|
+
* keys (an edit), so the behavior doesn't re-key them by identity
|
|
1716
|
+
*/
|
|
1717
|
+
reply(a: { catalog: Catalog<any>; state: any; pending: any; reply: any; names: ComposeNames }):
|
|
1718
|
+
{ layout?: Layout | null; unavailable?: true; preview?: Layout; request?: unknown; pending?: unknown; decisions?: unknown; error?: string; keyed?: boolean }
|
|
1719
|
+
/** `keyed` (on reply too): the layout already has the previous layout's keys (an edit applied to it): the behavior doesn't re-key it */
|
|
1720
|
+
delta?(a: { catalog: Catalog<any>; state: any; pending: any; delta: any }): { preview?: Layout; keyed?: boolean }
|
|
1721
|
+
/** the reply body that leads to `target` (composeWith) */
|
|
1722
|
+
fake(a: { catalog: Catalog<any>; state: any; pending: any; target: ComposeTree }): unknown
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
type ComposeStatus = 'idle' | 'composing' | 'preview' | 'done' | 'unavailable' | 'error'
|
|
1726
|
+
|
|
1727
|
+
/** The compose behavior's slice: `state.page` for `uses = { page: compose(...) }` */
|
|
1728
|
+
interface ComposeState {
|
|
1729
|
+
prompt: string
|
|
1730
|
+
status: ComposeStatus
|
|
1731
|
+
/** the last finished layout (kept on an error and when nothing fits) */
|
|
1732
|
+
layout: Layout | null
|
|
1733
|
+
/** the layout being built (rendered instead while set) */
|
|
1734
|
+
preview: Layout | null
|
|
1735
|
+
/** the backend's step (plain JSON) */
|
|
1736
|
+
pending: unknown
|
|
1737
|
+
/** what the backend explains (decisions: its answers; LLM: its plan) */
|
|
1738
|
+
decisions: unknown
|
|
1739
|
+
error: string | null
|
|
1740
|
+
/** container state per node key (CONTROL) */
|
|
1741
|
+
ui: Record<string, Record<string, any>>
|
|
1742
|
+
/** `local` parts' state per node key */
|
|
1743
|
+
local: Record<string, any>
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
/** The compose behavior's actions, as `'<key>.<ACTION>'` on the host */
|
|
1747
|
+
interface ComposeActions {
|
|
1748
|
+
/** compose (an edit of the current layout unless `fresh`): a prompt, `{ prompt, fresh }`, or the form's submit (the slice's prompt) */
|
|
1749
|
+
COMPOSE: string | { prompt: string; fresh?: boolean } | Event | undefined
|
|
1750
|
+
/** set the layout (finished first): restore, undo, the app's own edits; null clears */
|
|
1751
|
+
SET_LAYOUT: Layout | null
|
|
1752
|
+
/** remove a node (by key) and its subtree */
|
|
1753
|
+
REMOVE: string
|
|
1754
|
+
/** a container control: `ui[key][name] = value` */
|
|
1755
|
+
CONTROL: { key: string; name: string; value: unknown }
|
|
1756
|
+
/** a composition finished (a host entry `'page.DONE'` runs after the behavior's) */
|
|
1757
|
+
DONE: Layout
|
|
1758
|
+
/** Internal: the prompt field's input */
|
|
1759
|
+
PROMPT: string
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
interface ComposeOptions {
|
|
1763
|
+
/** `compose.decisions({ … })`, `compose.llm({ … })`, or your own ComposeBackend */
|
|
1764
|
+
backend: ComposeBackend
|
|
1765
|
+
/** the form whose submit composes */
|
|
1766
|
+
form?: BehaviorTarget$1
|
|
1767
|
+
/** the prompt field (its input sets `prompt`) */
|
|
1768
|
+
prompt?: BehaviorTarget$1
|
|
1769
|
+
/** the request lane (default 'compose'): a new prompt aborts the step in flight */
|
|
1770
|
+
key?: string
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
/** A result part's PARENT value (`compose.answer(props, value)`) */
|
|
1774
|
+
interface ComposeAnswer<V = unknown> { scope: string | undefined; node: string | undefined; value: V }
|
|
1775
|
+
|
|
1776
|
+
/**
|
|
1777
|
+
* PLAN-9 C-1: compose a page from a catalog. `uses = { page: compose(catalog, { backend:
|
|
1778
|
+
* compose.decisions({ model }), form: '.ask', prompt: '.prompt' }) }`, rendered with
|
|
1779
|
+
* `catalog.render(state.page, state)`.
|
|
1780
|
+
*/
|
|
1781
|
+
declare const compose: {
|
|
1782
|
+
(catalog: Catalog<any>, options: ComposeOptions): Behavior$1<ComposeState, ComposeActions, {}, ComposeOptions>
|
|
1783
|
+
/** a decision-model backend (decide() on HTTP) */
|
|
1784
|
+
decisions(options?: ComposeDecisionsOptions): ComposeBackend
|
|
1785
|
+
/** a chat-LLM backend (structured output on the LLM sink) */
|
|
1786
|
+
llm(options?: ComposeLlmOptions): ComposeBackend
|
|
1787
|
+
/** a result part's PARENT value: `{ scope, node, value }` */
|
|
1788
|
+
answer<V>(props: { scope?: string; node?: string }, value: V): ComposeAnswer<V>
|
|
1789
|
+
/**
|
|
1790
|
+
* PLAN-9 C-2: the `agent.actions` entry that lets an agent (a chat assistant) compose the page:
|
|
1791
|
+
* `actions: { ...compose.action('page') }` offers `<agent name>_page_compose({ prompt, fresh? })`;
|
|
1792
|
+
* its result waits (`until`) for the composition to finish, so its `state` (the `read`) shows the
|
|
1793
|
+
* new page (`read: (s) => ({ page: compose.summary(s.page) })`). `timeout` default 60 s
|
|
1794
|
+
*/
|
|
1795
|
+
action<K extends string = 'page'>(key?: K, options?: { description?: string; timeout?: number }): Record<`${K}.COMPOSE`, AgentAction<any, { prompt: string; fresh?: boolean }>>
|
|
1796
|
+
/** PLAN-9 C-2: a composition as an agent's `read` shows it: its status, the layout as a tree, the error */
|
|
1797
|
+
summary(slice: ComposeState | null | undefined): { status: ComposeStatus; page: ComposeTree; error?: string } | undefined
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
/**
|
|
1801
|
+
* PLAN-9 T-1: answer the pending composition of `catalog` so that it becomes `tree`, whatever the
|
|
1802
|
+
* backend (each step through the backend's fake reply). `stream: n` streams an LLM reply in n chunks.
|
|
1803
|
+
*/
|
|
1804
|
+
declare function composeWith<D>(t: RenderResult$1<any>, catalog: Catalog<D>, tree: CatalogTree<D>, options?: { stream?: number | boolean }): Promise<void>
|
|
1805
|
+
|
|
1806
|
+
// PLAN-9 B: compose.decisions
|
|
1807
|
+
/** `compose.decisions(options)`: the decision-model backend (`decide()` on the HTTP sink) */
|
|
1808
|
+
interface ComposeDecisionsOptions {
|
|
1809
|
+
/** the decision endpoint (default '/api/decide': the app's own route, which holds the API key) */
|
|
1810
|
+
url?: string
|
|
1811
|
+
/** the decision model ('jev-latest', 'nimble', …); without one: SYG681 (dev) */
|
|
1812
|
+
model?: string
|
|
1813
|
+
/** the request lane (`key` of every `decide()` request; default: the behavior's, 'compose') */
|
|
1814
|
+
key?: string
|
|
1815
|
+
/**
|
|
1816
|
+
* rows: the mean side-by-side probability two groups of parts need to join one row
|
|
1817
|
+
* (average-linkage clustering of the `beside_` answers; default 0.25, measured on Jev; 0.5 suits nimble)
|
|
1818
|
+
*/
|
|
1819
|
+
rowMean?: number
|
|
1820
|
+
/**
|
|
1821
|
+
* ask which part `categories` the request is about first, then only about their parts (one more
|
|
1822
|
+
* call, about half the input tokens; measured on Jev's 50-part ops console: the same accuracy).
|
|
1823
|
+
* 'auto' (default): on when the catalog has categories and more than 60 parts to choose from
|
|
1824
|
+
* (30 with `profile: 'small'`); `true`: always (with categories); `false`: never
|
|
1825
|
+
*/
|
|
1826
|
+
prefilter?: boolean | 'auto'
|
|
1827
|
+
/**
|
|
1828
|
+
* the most options one choice question may have (default 255; 25 when `url` looks like Ollama;
|
|
1829
|
+
* at least 4): every larger choice is split into chunks that repeat its head options
|
|
1830
|
+
*/
|
|
1831
|
+
maxOptions?: number
|
|
1832
|
+
/**
|
|
1833
|
+
* 'small': for a local ~9B decision model such as Ollama's nimble, which favours the first of two
|
|
1834
|
+
* options: pairwise order questions are asked in both orders, and near-ties follow the order in
|
|
1835
|
+
* which the request names the parts (G-755); at most 8 parts per composition (`maxParts`); the
|
|
1836
|
+
* category prefilter from 30 parts
|
|
1837
|
+
*/
|
|
1838
|
+
profile?: 'small'
|
|
1839
|
+
/**
|
|
1840
|
+
* the most parts one composition selects (the most probable kept; required parts and companions
|
|
1841
|
+
* come on top). Default: the catalog's `limits.maxParts` (12); 8 with `profile: 'small'`. The
|
|
1842
|
+
* catalog's limit still caps the page
|
|
1843
|
+
*/
|
|
1844
|
+
maxParts?: number
|
|
1845
|
+
/** passed to every `decide()` request (D472): see `DecideOptions`. Default 64 */
|
|
1846
|
+
maxQuestions?: number
|
|
1847
|
+
/** passed to every `decide()` request (D472): see `DecideOptions`. Default: none */
|
|
1848
|
+
maxPromptTokens?: number
|
|
1849
|
+
/** passed to every `decide()` request (D472): false sends each step as one request, never halved */
|
|
1850
|
+
split?: boolean
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
// PLAN-9 C: compose.llm ------------------------------------------------------------------------
|
|
1854
|
+
|
|
1855
|
+
/**
|
|
1856
|
+
* `compose.llm(options?)`: the GenAI LLM backend of `compose` (one structured-output request on
|
|
1857
|
+
* a makeChatDriver() sink; a streamed preview). The request carries the catalog's JSON Schema
|
|
1858
|
+
* (`asked_for`, then the layout tree), the system prompt (the catalog as text, its `guidance`,
|
|
1859
|
+
* `examples` as few-shot turns) and `delta` when streaming. Other keys go on the request as is
|
|
1860
|
+
* (transport options such as `body: { temperature: 0 }`). Requests carry `parse: false`: the reply
|
|
1861
|
+
* text is read leniently here (prose or a code fence around the JSON), and text with no layout in
|
|
1862
|
+
* it is the behavior's status 'error' (SYG683), not the driver's FAILED.
|
|
1863
|
+
*
|
|
1864
|
+
* B-4: with a current layout, COMPOSE is an edit. The request sends the page (`n1: part params`,
|
|
1865
|
+
* one node per line) and the change; the model returns operations positioned by named places
|
|
1866
|
+
* (`add` / `remove` / `move` / `replace` / `setParams`; `top`, `bottom`, `above n2`, `left of n3`,
|
|
1867
|
+
* …), applied to the current layout itself: every node they don't replace or remove keeps its key
|
|
1868
|
+
* (a param change too; another record is another node), a replacement takes the old node's place,
|
|
1869
|
+
* and the node a place names never moves. No operation: `unavailable`, the layout stays.
|
|
1870
|
+
*
|
|
1871
|
+
* compose(catalog, { backend: compose.llm({ model: 'gpt-5-mini' }) })
|
|
1872
|
+
*/
|
|
1873
|
+
interface ComposeLlmOptions {
|
|
1874
|
+
/** The model id (default: the transport's), or a function of the host's state that returns one, resolved per request */
|
|
1875
|
+
model?: string | ((state: any) => string | undefined)
|
|
1876
|
+
/** The chat driver's sink (default 'LLM') */
|
|
1877
|
+
sink?: string
|
|
1878
|
+
/** The request key (default: the behavior's key) */
|
|
1879
|
+
key?: string
|
|
1880
|
+
/** Stream a preview of the complete parts so far (default true) */
|
|
1881
|
+
stream?: boolean
|
|
1882
|
+
/** Ask for the `asked_for` plan before the tree (default true; false when there are examples) */
|
|
1883
|
+
plan?: boolean
|
|
1884
|
+
/** More instructions after the rules, or a function of the system prompt returning the one to send */
|
|
1885
|
+
instructions?: string | ((prompt: string) => string)
|
|
1886
|
+
/** Few-shot examples (default: the catalog's): `[prompt, tree, asked_for?]` or `{ prompt, tree, asked_for? }` */
|
|
1887
|
+
examples?: ReadonlyArray<readonly [string, ReadonlyArray<ComposeLlmTreeNode>, ReadonlyArray<string>?] | { prompt: string; tree: ReadonlyArray<ComposeLlmTreeNode>; asked_for?: ReadonlyArray<string> }>
|
|
1888
|
+
/** Transport options, sent on the request as is */
|
|
1889
|
+
[option: string]: unknown
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
/** A node of a layout tree as `examples` take it (the contract's Tree) */
|
|
1893
|
+
type ComposeLlmTreeNode = { part: string; params?: Record<string, unknown>; children?: ReadonlyArray<ComposeLlmTreeNode> | Record<string, ReadonlyArray<ComposeLlmTreeNode>> }
|
|
1894
|
+
|
|
1895
|
+
// ---- PLAN-9 H: chat client tools and ask ---------------------------------------------------------
|
|
1896
|
+
|
|
1897
|
+
/** PLAN-9 H-1: a tool the app answers (`chat({ clientTools: { name: tool } })`) */
|
|
1898
|
+
interface ChatClientTool {
|
|
1899
|
+
description: string
|
|
1900
|
+
/** The input's JSON Schema, or a Standard Schema with a JSON Schema form (its input is validated: a failure closes the call with the issues, so the model can repair it) */
|
|
1901
|
+
inputSchema: JsonSchemaObject | AgentSchema<any>
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
/** PLAN-9 H-2: `chat({ ask })` */
|
|
1905
|
+
interface ChatAskOptions {
|
|
1906
|
+
/** The parts a card is built from; parts with `result: true` answer it (none: SYG686) */
|
|
1907
|
+
catalog: Catalog<any>
|
|
1908
|
+
/** What composes the card from the call's `need` and the app state: `compose.llm()` (default, on the chat's sink) or `compose.decisions()` */
|
|
1909
|
+
backend?: ComposeBackend
|
|
1910
|
+
/** More guidance on when and how to ask, added to the `ask_user` tool's description */
|
|
1911
|
+
instructions?: string
|
|
1912
|
+
/** PLAN-9 H-3: the tool's input is the card (the layout schema; LLM only, for providers that enforce tool schemas): no compose round trip */
|
|
1913
|
+
direct?: boolean
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
/** 'composing' (queued, or its backend step is out) | 'open' (answerable) | 'answered' | 'failed' (the call closed with "could not show a card: …") | 'cancelled' (STOP, a new message) */
|
|
1917
|
+
type ChatCardStatus = 'composing' | 'open' | 'answered' | 'failed' | 'cancelled'
|
|
1918
|
+
|
|
1919
|
+
/** PLAN-9 H-2: an `ask_user` call's card, on its tool part (`part.ui`); render it with `askCard()` */
|
|
1920
|
+
interface ChatCard {
|
|
1921
|
+
status: ChatCardStatus
|
|
1922
|
+
/** The card (a decision backend's preview while it composes) */
|
|
1923
|
+
layout: Layout | null
|
|
1924
|
+
/** State of the card's `local` parts, per node key */
|
|
1925
|
+
local: Record<string, any>
|
|
1926
|
+
/** Container state per node key (CONTROL) */
|
|
1927
|
+
ui: Record<string, Record<string, any>>
|
|
1928
|
+
/** The answer: the result part's node, its part id, the value */
|
|
1929
|
+
answer: { node: string; part: string | null; value: unknown } | null
|
|
1930
|
+
/** The backend's step while its request is out */
|
|
1931
|
+
pending?: unknown
|
|
1932
|
+
/**
|
|
1933
|
+
* What the backend explains, as a compose slice's `decisions`: its last reply's (`compose.llm()`:
|
|
1934
|
+
* ComposeLlmDecisions; `compose.decisions()`: the answers per step, see ComposeDecisionsBackend).
|
|
1935
|
+
* Absent until a reply carries some; kept (and persisted) with the card, for an explain panel
|
|
1936
|
+
*/
|
|
1937
|
+
decisions?: unknown
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
/** A tool part of a chat message */
|
|
1941
|
+
type ChatToolPart = Extract<MessagePart, { toolCallId: string }>
|
|
1942
|
+
|
|
1943
|
+
/**
|
|
1944
|
+
* PLAN-9 H-1: the `input-available` tool parts of the last assistant message: the calls waiting for
|
|
1945
|
+
* the app's answer (and agent calls while they run: status 'streaming')
|
|
1946
|
+
*/
|
|
1947
|
+
declare function openToolCalls(state: ChatState): ChatToolPart[]
|
|
1948
|
+
|
|
1949
|
+
/**
|
|
1950
|
+
* PLAN-9 H-2: the card of an `ask_user` tool part, for the host's view: `catalog.render(part.ui,
|
|
1951
|
+
* state, { scope: part.toolCallId, frozen, answer })`, frozen unless the card is open, `local`
|
|
1952
|
+
* written through a lens to the part. `key`: the chat's key in `uses` (default 'assistant'). Null
|
|
1953
|
+
* while the card has no layout.
|
|
1954
|
+
*/
|
|
1955
|
+
declare function askCard(catalog: Catalog<any>, state: any, part: ChatToolPart, options?: { key?: string }): any
|
|
1956
|
+
|
|
1957
|
+
/** PLAN-9 M-1: `<Composed>`'s props */
|
|
1958
|
+
interface ComposedProps {
|
|
1959
|
+
/** the catalog (defineCatalog's result); missing: SYG451, nothing rendered */
|
|
1960
|
+
catalog: Catalog<any>
|
|
1961
|
+
/**
|
|
1962
|
+
* Where the composition is in the host's state: a key (default 'page') or a path
|
|
1963
|
+
* (['boards', 0, 'page']); with `card`, the chat's key (default 'assistant'). Not a composition
|
|
1964
|
+
* (an object with `layout`): SYG451, nothing rendered
|
|
1965
|
+
*/
|
|
1966
|
+
from?: string | ReadonlyArray<string | number>
|
|
1967
|
+
/** an `ask_user` tool part: its card, as askCard() renders it (scope, frozen and answer from the part) */
|
|
1968
|
+
card?: ChatToolPart
|
|
1969
|
+
/** as catalog.render's options (they override the card's) */
|
|
1970
|
+
scope?: string
|
|
1971
|
+
frozen?: boolean
|
|
1972
|
+
answer?: { node: string; value: unknown } | null
|
|
1973
|
+
key?: string | number
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
/**
|
|
1977
|
+
* PLAN-9 M-1 (D466): `<Composed catalog={catalog} from="page" />` renders the composition at `from`
|
|
1978
|
+
* in the host's state, as `{catalog.render(state.page, state)}` in the view does: the parts are the
|
|
1979
|
+
* host's children (same keys, CHILD.select, lenses). Differences: it reads the host's own state (a
|
|
1980
|
+
* composition computed in the view needs render()), and a container view or part `props()` that
|
|
1981
|
+
* throws replaces only the composition with the host's `onError` (SYG408), where render() shows an
|
|
1982
|
+
* empty `.compose-error` element (SYG406).
|
|
1983
|
+
*/
|
|
1984
|
+
declare function Composed(props: ComposedProps): JSX.Element
|
|
1985
|
+
|
|
1391
1986
|
type Reducer$1<T> = (state: T | undefined) => T | undefined;
|
|
1392
1987
|
type Getter<T, R> = (state: T | undefined) => R | undefined;
|
|
1393
1988
|
type Setter<T, R> = (state: T | undefined, childState: R | undefined) => T | undefined;
|
|
@@ -4087,6 +4682,21 @@ type FetchRequest = string | {
|
|
|
4087
4682
|
* schema's (possibly transformed) value. A failure is an error with `issues`
|
|
4088
4683
|
*/
|
|
4089
4684
|
validate?: StandardSchemaLike;
|
|
4685
|
+
/**
|
|
4686
|
+
* D472: send these sub-requests instead, in parallel (each inherits this request's fields:
|
|
4687
|
+
* `url`, `headers`, `init`, ...; its own `json` / `body` / `parse` win), and deliver ONE reply:
|
|
4688
|
+
* `combine(bodies, requests)`. One failure fails the request (once). The test fake
|
|
4689
|
+
* (renderComponent) answers the request as one, by its own `url` / `json`. `decide()` makes these
|
|
4690
|
+
*/
|
|
4691
|
+
batch?: ReadonlyArray<{ url?: string; method?: string; headers?: Record<string, string>; query?: Record<string, unknown>; json?: unknown; body?: BodyInit; parse?: 'auto' | 'json' | 'text' | ((response: Response) => any) }>;
|
|
4692
|
+
/** D472: merges the parsed bodies of `batch` / `split` parts into the reply (default: the array) */
|
|
4693
|
+
combine?: (bodies: any[], requests: any[]) => any;
|
|
4694
|
+
/**
|
|
4695
|
+
* D472: a request (or a `batch` part) that fails with an HTTP error is sent again as the
|
|
4696
|
+
* requests this returns (≥ 2, in parallel, merged by `combine`), at most 3 times deep; null keeps
|
|
4697
|
+
* the error. `decide()` halves its questions on a 400 / 413 that names a size limit
|
|
4698
|
+
*/
|
|
4699
|
+
split?: (request: any, error: Error & { status?: number; body?: any }) => any[] | null | undefined;
|
|
4090
4700
|
/** Your own fields (an id, ...): not sent, returned on the reply's `request` */
|
|
4091
4701
|
[appData: string]: any;
|
|
4092
4702
|
} | {
|
|
@@ -5426,7 +6036,9 @@ declare global {
|
|
|
5426
6036
|
namespace JSX {
|
|
5427
6037
|
interface IntrinsicElements {
|
|
5428
6038
|
[elemName: string]: any;
|
|
6039
|
+
/** @deprecated since 6.3.0, removed in the next major: `import { Collection } from 'sygnal'` and write `<Collection …>` (SYG426) */
|
|
5429
6040
|
collection: CollectionProps<any>;
|
|
6041
|
+
/** @deprecated since 6.3.0, removed in the next major: `import { Switchable } from 'sygnal'` and write `<Switchable …>` (SYG426) */
|
|
5430
6042
|
switchable: SwitchableProps<any>;
|
|
5431
6043
|
slot: SlotProps;
|
|
5432
6044
|
}
|
|
@@ -5439,6 +6051,15 @@ declare global {
|
|
|
5439
6051
|
children: {};
|
|
5440
6052
|
}
|
|
5441
6053
|
|
|
6054
|
+
/**
|
|
6055
|
+
* `key` on any tag (D456): on a component, its identity among its parent's children (before
|
|
6056
|
+
* its `id` prop, then its position): a keyed instance survives a move or a reorder, and a new
|
|
6057
|
+
* key makes a new instance. Never a prop of the component.
|
|
6058
|
+
*/
|
|
6059
|
+
interface IntrinsicAttributes {
|
|
6060
|
+
key?: string | number | null;
|
|
6061
|
+
}
|
|
6062
|
+
|
|
5442
6063
|
/**
|
|
5443
6064
|
* A component's view receives `state: STATE` and `context`, but in JSX the parent passes
|
|
5444
6065
|
* an optional `state` slice name or lens (`<Editor state="editor" />`, `<Panel />`).
|
|
@@ -5447,4 +6068,13 @@ declare global {
|
|
|
5447
6068
|
}
|
|
5448
6069
|
}
|
|
5449
6070
|
|
|
5450
|
-
|
|
6071
|
+
|
|
6072
|
+
/**
|
|
6073
|
+
* PLAN-9 (D463): a `{ get, set }` lens to the element of the array `state[field]` whose `idKey`
|
|
6074
|
+
* (default 'id') is `id`: a record part's state (`state: (node) => byId('projects',
|
|
6075
|
+
* node.params.id)`) or any child's `state={byId('todos', 3)}`. `get` is undefined once the element
|
|
6076
|
+
* is gone; `set` then leaves the state unchanged.
|
|
6077
|
+
*/
|
|
6078
|
+
declare function byId<T = any, S = any>(field: string, id: unknown, idKey?: string): { get(state: S): T | undefined; set(state: S, value: T): S }
|
|
6079
|
+
|
|
6080
|
+
export { ABORT, type ActionCause, type ActionsOf, type ActiveTimer, type AgentAction, type AgentConfirm, type AgentConfirmInfo, type AgentDeclaration, type AgentIssue, type AgentQuery, type AgentQueryResult, type AgentResult, type AgentSchema, type AgentTool, type AgentToolSet, type AgentToolsOptions, type AguiOptions, type AnswerPick, type AnswerPicks, type AnthropicMessagesOptions, type AnyComponentModule, type AnyControl, type AppErrorHook, type AppErrorInfo, type AppErrorPhase, type ArrayKeysOf, type AsyncDriverError, type AsyncDriverFromFunction, type AsyncRequest, type Behavior, type BehaviorDefinition, type BehaviorFactory, type BehaviorHandler, type BehaviorModelEntry, type BehaviorProps, type BehaviorSources, type BehaviorState, type BehaviorTarget, type BrowserCommand, type BrowserFake, type BrowserFakeOptions, type BrowserIntersection, type BrowserPosition, type BrowserResize, type BrowserSource, type BrowserSources, type BrowserSpec, type Catalog, type CatalogContainer, type CatalogContainerDecl, type CatalogDecl, type CatalogOption, type CatalogParam, type CatalogParamValue, type CatalogParamsOf, type CatalogPart, type CatalogPartDecl, type CatalogRecord, type CatalogTree, type CatalogTreeNode, type ChatAbort, type ChatActions, type ChatAskOptions, type ChatCall, type ChatCard, type ChatCardStatus, type ChatClientTool, type ChatCompletionsOptions, type ChatDelta, type ChatDone, type ChatDriverOptions, type ChatError, type ChatEvent, type ChatOk, type ChatOptions, type ChatOutputOf, type ChatOutputSchema, type ChatRequest, type ChatSource, type ChatState, type ChatStatus, type ChatTool, type ChatToolCall, type ChatToolPart, type ChatTransport, type ChatUsage, type ChromePromptOptions, type ChromePromptStatus, type ChromePromptTransport, type ClassesType, Collection, type CollectionFrom, type CollectionProps, type Command, type CommandBarActions, type CommandBarOptions, type CommandBarResult, type CommandBarState, type CommandBarStatus, type CommandBarUnsure, type CommandSource, type Component, type ComposeActions, type ComposeAnswer, type ComposeBackend, type ComposeNames, type ComposeOptions, type ComposeRenderOptions, type ComposeRenderable, type ComposeState, type ComposeStatus, type ComposeTree, Composed, type ComposedProps, type Connections, type ContainerView, type Control, type ControlCommonProps, type ControlDOMSource, type ControlElementOf, type ControlEvent, type ControlH, type ControlPropsOf, type ControlSpec, type ControlSpecObject, type ControlsOf, type ConvertedSchema, type CycleDOMEvent, type CycleDriver, type DOMDriverOptions, type DOMEventShorthand, type DOMEventShorthands, type DOMSource, type DefaultDrivers, type DefineComponentOptions, type DevToolsActionCause, type DevToolsCopyAsTestOptions, type DevToolsSessionRecording, type Diagnostic, type DiagnosticCode, type DiagnosticSeverity, type DiagnosticsMode, type DiagnosticsOptions, type DragDriverCategory, type DragDriverRegistration, type DragDriverSource, type DragSource, type DragStartPayload, type DriverFactories, type DriverFromAsyncOptions, type DriverSpec, type DriverSpecs, type DropPayload, type ElementCommand, type ElementCommandRegistry, type ElementCommands, type ElementProps, type ElementTarget, type EmittedEvent, type EnrichedEventStream, type Event$1 as Event, type EventName, type EventPayload, type EventPayloadFunction, type EventSink, type EventsFnOptions, type EventsSource, type ExactShape, type ExplainedAction, type ExposeWebMcpOptions, type FakeCacheEntry, type FakeChatChunk, type FakeConnection, type FakeConnectionTarget, type FakeReplyOptions, type FetchCacheOptions, type FetchDriverOptions, type FetchError, type FetchFailure, type FetchInit, type FetchInvalidate, type FetchRequest, type FetchResponse, type FetchRetry, type FetchSource, type FieldErrors, type Filter, type FixDrivers, type FormActions, type FormCalculated, type FormData, type FormField, type FormFieldCheck, type FormOptions, type FormSource, type FormState, type FormTool, type FormToolHandle, type FormToolResult, type FromAISDKOptions, type HeadValue, type HotModuleAPI, type HttpTransportOptions, type InspectAction, type InspectActionTrigger, type InspectChild, type InspectCommand, type InspectComponent, type InspectDiagnostic, type InspectFix, type InspectGraph, type InspectRecentAction, type InspectRelatedLocation, type InspectSelector, type InspectTextEdit, type InspectTimer, type InstallPrompt, type IntentSources, type IntrinsicControlProps, type JsonSchemaObject, type Layout, type LayoutNode, type LazyComponent, type LazyOptions, type Lens, type Lense, MainDOMSource, type McpAppDisplayMode, type McpAppDriverOptions, type McpAppError, type McpAppRequest, type McpAppSource, type McpContentBlock, type McpDownloadItem, type McpHostContext, type McpHostInfo, type McpLogLevel, type McpResourceContents, type McpSamplingRequest, type McpToolResult, type MockConfig, MockedDOMSource, type NonStateSinkReturns, type OpenResponsesEvent, type OpenResponsesOptions, type PagerActions, type PagerCalculated, type PagerOptions, type PagerState, type ParamNames, type ParentPayloadOf, type Persist, type PersistOptions, type PersistOptionsFor, type PersistStorage, type PersistedEntry, Portal, type PortalProps, type ProcessFormOptions, type QueryCache, type QueryCacheSnapshot, type QueryCacheSnapshotEntry, type Ref, type Ref$, type RegisteredEvent, type RenderOptions, type RenderResult, type RenderToStringOptions, type RenderableComponent, type ReplyRequest, type Resource, type ResourceRequest, type RootComponent, type Route, type RouteName, type RouteParamsArg, type RouteQuery, type Router, type RouterBlocked, type RouterCommand, type RouterOptions, type RouterSource, type RunOptions, type SchemaOutput, type ScrollToAlign, type SelectedDOMSource, type SelectionActions, type SelectionCalculated, type SelectionOptions, type SelectionState, type ServiceWorkerCommand, type ServiceWorkerOptions, type ServiceWorkerSource, type SimulatedEventInit, Slot, type SlotProps, type SocketActions, type SocketClose, type SocketConnection, type SocketDriverOptions, type SocketError, type SocketEvent, type SocketOpen, type SocketReconnect, type SocketRequest, type SocketSource, type SortFunction, type SortObject, type SortSpec, type SortableActions, type SortableDropped, type SortableOptions, type SortableState, type SseConnection, type StandardSchemaLike, type StateProp, type StrictDialect, type StrictSchemas, Suspense, type SuspenseProps, Switchable, type SwitchableProps, type SygnalApp, type SygnalBodyDOMSource, type SygnalDOMSource, type SygnalDevTools, type SygnalDocumentDOMSource, type SygnalEvents, type SygnalSinks, type TestAction, type Thunk, type ThunkData, type TimerAfter, type TimerFrame, type TimerSpec, type TimerTick, type Timers, Transition, type TransitionProps, type UIMessageStreamOptions, type UidFunction, type UndoBehaviorOptions, type UndoHistory, type UndoOptions, type UsesActions, type UsesState, type ViewProps, VirtualCollection, type VirtualCollectionProps, type WebMcpHandle, type Widget, type WidgetDefinition, type WidgetDispatch, type WidgetElementOf, type WidgetEmit, type WidgetHandle, type WidgetHostProps, type WithinTarget, abort, agentTools, agui, answers, anthropicMessages, askCard, byId, chat, chatCompletions, checkForm, choice, chromePrompt, classes, clearDiagnostics, clipboardSource, commandBar, compose, composeWith, controls, createCommand, createInstallPrompt, createRef, createRef$, decide, defineBehavior, defineCatalog, defineComponent, defineWidget, driverFromAsync, emit, enableHMR, encodeOpenResponses, event, exactState, experimentalExposeWebMcp, fieldName, fieldNames, focusInvalid, focusWithin, form, formErrors, formTool, fromAISDK, fromTree, geolocationSource, getDevTools, getDiagnostics, getField, hasField, intersectionSource, isSelected, jsonSchema, lazy, makeBrowserDriver, makeBrowserDriverWith, makeChatDriver, makeDOMDriver, makeDragDriver, makeFetchDriver, makeHeadDriver, makeMcpAppDriver, makeRouter, makeRouterDriver, makeServiceWorkerDriver, makeSocketDriver, makeTimerDriver, makeViewTransitionDOMDriver, mediaSource, messageText, mockDOMSource, noul, onDiagnostic, onlineSource, onlineStatus$, openResponses, openToolCalls, outputJsonSchema, pager, parseInput, persist, portal, processDrag, processForm, queryCache, removeNode, renderComponent, renderHead, renderToString, replyErrors, resizeSource, run, score, selection, set, setField, sortable, storageSource, strictSchemas, thunk, toJsonSchema, toTree, toggle, uiMessageStream, undo, undoable, visibilitySource, withToolResults, xs };
|