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.
Files changed (76) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +3 -1
  3. package/dist/ai.cjs.js +36 -0
  4. package/dist/ai.cjs.js.map +1 -1
  5. package/dist/ai.esm.js +1 -1
  6. package/dist/astro/server.cjs.js +3 -3
  7. package/dist/astro/server.cjs.js.map +1 -1
  8. package/dist/astro/server.mjs +3 -3
  9. package/dist/astro/server.mjs.map +1 -1
  10. package/dist/diagnostics.cjs.js +164 -3
  11. package/dist/diagnostics.cjs.js.map +1 -1
  12. package/dist/diagnostics.esm.js +164 -3
  13. package/dist/diagnostics.esm.js.map +1 -1
  14. package/dist/guide/agent.md +7 -1
  15. package/dist/guide/ai-cards.md +319 -0
  16. package/dist/guide/ai-chat.md +4 -0
  17. package/dist/guide/ai-compose.md +881 -0
  18. package/dist/guide/ai-decisions.md +16 -0
  19. package/dist/guide/http.md +1 -0
  20. package/dist/index.cjs.js +5695 -347
  21. package/dist/index.cjs.js.map +1 -1
  22. package/dist/index.d.ts +638 -8
  23. package/dist/index.esm.js +5685 -347
  24. package/dist/index.esm.js.map +1 -1
  25. package/dist/sygnal.min.js +1 -1
  26. package/dist/sygnal.min.js.map +1 -1
  27. package/dist/vike/config/package.json +1 -1
  28. package/dist/vike/onRenderClient.cjs.js +3 -2
  29. package/dist/vike/onRenderClient.cjs.js.map +1 -1
  30. package/dist/vike/onRenderClient.mjs +3 -2
  31. package/dist/vike/onRenderClient.mjs.map +1 -1
  32. package/llms.txt +6 -4
  33. package/package.json +2 -1
  34. package/src/ai.d.ts +642 -7
  35. package/src/ai.ts +6 -0
  36. package/src/collection.ts +2 -1
  37. package/src/core/instance.ts +6 -3
  38. package/src/core/markers/lazy.ts +7 -3
  39. package/src/core/markers/portal.ts +5 -2
  40. package/src/core/markers/suspense.ts +3 -2
  41. package/src/core/markers/transition.ts +6 -3
  42. package/src/core/registry.ts +9 -5
  43. package/src/cycle/dom/IsolateModule.ts +25 -22
  44. package/src/extra/ai/chat/behavior.ts +354 -81
  45. package/src/extra/ai/chat/driver.ts +7 -4
  46. package/src/extra/ai/compose/agent.ts +55 -0
  47. package/src/extra/ai/compose/ask.ts +147 -0
  48. package/src/extra/ai/compose/behavior.ts +183 -0
  49. package/src/extra/ai/compose/catalog.ts +211 -0
  50. package/src/extra/ai/compose/composed.ts +61 -0
  51. package/src/extra/ai/compose/decisions.ts +1649 -0
  52. package/src/extra/ai/compose/diag.ts +33 -0
  53. package/src/extra/ai/compose/index.ts +23 -0
  54. package/src/extra/ai/compose/layout.ts +441 -0
  55. package/src/extra/ai/compose/llm.ts +1120 -0
  56. package/src/extra/ai/compose/render.ts +159 -0
  57. package/src/extra/ai/compose/testing.ts +71 -0
  58. package/src/extra/ai/compose/types.ts +159 -0
  59. package/src/extra/ai/decide.ts +97 -1
  60. package/src/extra/ai/index.ts +6 -1
  61. package/src/extra/diagnostics/checks/next.ts +86 -2
  62. package/src/extra/diagnostics/codes.ts +54 -0
  63. package/src/extra/fetchDriver.ts +58 -27
  64. package/src/extra/lens.ts +15 -0
  65. package/src/extra/ssr.ts +3 -3
  66. package/src/extra/testing.ts +2 -0
  67. package/src/extra/widget.ts +3 -3
  68. package/src/index.d.ts +41 -0
  69. package/src/index.ts +8 -0
  70. package/src/lazy.ts +3 -2
  71. package/src/portal.ts +5 -2
  72. package/src/pragma/index.ts +2 -1
  73. package/src/suspense.ts +5 -2
  74. package/src/switchable.ts +2 -1
  75. package/src/transition.ts +5 -2
  76. 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
- /** A model id for the requests (overrides the transport's) */
930
- model?: string
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
- 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 ChatAbort, type ChatActions, type ChatCall, 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 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 Connections, 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 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, chat, chatCompletions, checkForm, choice, chromePrompt, classes, clearDiagnostics, clipboardSource, commandBar, controls, createCommand, createInstallPrompt, createRef, createRef$, decide, defineBehavior, defineComponent, defineWidget, driverFromAsync, emit, enableHMR, encodeOpenResponses, event, exactState, experimentalExposeWebMcp, fieldName, fieldNames, focusInvalid, focusWithin, form, formErrors, formTool, fromAISDK, 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, outputJsonSchema, pager, parseInput, persist, portal, processDrag, processForm, queryCache, renderComponent, renderHead, renderToString, replyErrors, resizeSource, run, score, selection, set, setField, sortable, storageSource, strictSchemas, thunk, toJsonSchema, toggle, uiMessageStream, undo, undoable, visibilitySource, withToolResults, xs };
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 };