juneau 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +104 -10
  2. package/dist/adapters/mockAdapter.d.ts.map +1 -1
  3. package/dist/components/AiChat/AiChat.d.ts +4 -2
  4. package/dist/components/AiChat/AiChat.d.ts.map +1 -1
  5. package/dist/components/AiMessageBubble/AiMessageBubble.d.ts +4 -2
  6. package/dist/components/AiMessageBubble/AiMessageBubble.d.ts.map +1 -1
  7. package/dist/components/AiMessageList/AiMessageList.d.ts +4 -2
  8. package/dist/components/AiMessageList/AiMessageList.d.ts.map +1 -1
  9. package/dist/components/AiSidebar/AiSidebar.d.ts +4 -1
  10. package/dist/components/AiSidebar/AiSidebar.d.ts.map +1 -1
  11. package/dist/components/parts/AiEntityCard.d.ts +9 -0
  12. package/dist/components/parts/AiEntityCard.d.ts.map +1 -0
  13. package/dist/components/parts/AiEntityListPart.d.ts +9 -0
  14. package/dist/components/parts/AiEntityListPart.d.ts.map +1 -0
  15. package/dist/components/parts/AiMessagePartRenderer.d.ts +4 -2
  16. package/dist/components/parts/AiMessagePartRenderer.d.ts.map +1 -1
  17. package/dist/core/types.d.ts +41 -4
  18. package/dist/core/types.d.ts.map +1 -1
  19. package/dist/index.cjs +41 -35
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.ts +3 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +2472 -2346
  24. package/dist/index.js.map +1 -1
  25. package/dist/server/createSkillSet.d.ts.map +1 -1
  26. package/dist/server/index.cjs +16 -9
  27. package/dist/server/index.cjs.map +1 -1
  28. package/dist/server/index.d.ts +4 -3
  29. package/dist/server/index.d.ts.map +1 -1
  30. package/dist/server/index.js +228 -146
  31. package/dist/server/index.js.map +1 -1
  32. package/dist/server/skillIndex.d.ts +20 -4
  33. package/dist/server/skillIndex.d.ts.map +1 -1
  34. package/dist/server/types.d.ts +43 -0
  35. package/dist/server/types.d.ts.map +1 -1
  36. package/dist/server/withSkillDispatch.d.ts +24 -0
  37. package/dist/server/withSkillDispatch.d.ts.map +1 -0
  38. package/dist/style.css +1 -1
  39. package/package.json +1 -1
package/README.md CHANGED
@@ -45,7 +45,7 @@ It receives the conversation history and streams back typed events:
45
45
  ```ts
46
46
  type AiStreamEvent =
47
47
  | { type: 'text'; text: string } // streamed text chunk — append to current bubble
48
- | { type: 'part'; part: AiMessagePart } // rich UI block (table, proposal, activity, error)
48
+ | { type: 'part'; part: AiMessagePart } // rich UI block (table, entity, entity-list, proposal, activity, error)
49
49
  | { type: 'done' } // stream finished cleanly
50
50
  | { type: 'error'; message: string } // stream failed
51
51
  ```
@@ -187,7 +187,7 @@ export const myAdapter: AiBackendAdapter = {
187
187
  If your backend uses ai-sdk, Juneau ships server-side helpers that eliminate the boilerplate of history mapping, activity streaming, and tool failure recovery. Import from the `/server` subpath — zod stays out of the browser bundle.
188
188
 
189
189
  ```ts
190
- import { toSdkMessages, createSkillSet, buildSkillIndex, selectSkills, withToolRecovery } from 'juneau/server';
190
+ import { toSdkMessages, createSkillSet, buildSkillIndex, selectSkills, selectSkillsById, withToolRecovery, withSkillDispatch } from 'juneau/server';
191
191
  ```
192
192
 
193
193
  **Full integration in ~15 lines:**
@@ -240,29 +240,72 @@ execute: async ({ query }, { emit }) => {
240
240
 
241
241
  Emitted parts share the activity buffer and are drained by `streamToWire` at the same points — they appear in the stream in emit order, before the model's text response.
242
242
 
243
- Skill metadata: `title` (human-readable name), `instructions?` (agent workflow text — lazily loaded via `selectSkills`), `readOnly?` (default `true`), `requiresConfirmation?` (default `false`), `tools?` (skill composition — validated at startup, `createSkillSet` throws on a reference to an unknown skill).
243
+ Skill metadata: `title` (human-readable name), `id` (numeric, required — chosen by the consumer, must be unique across the skill map; `createSkillSet` throws at startup on duplicates), `instructions?` (agent workflow text — lazily loaded via `selectSkills` / `selectSkillsById`), `readOnly?` (default `true`), `requiresConfirmation?` (default `false`), `tools?` (skill composition — validated at startup, `createSkillSet` throws on a reference to an unknown skill).
244
244
 
245
- `SkillSet` members: `tools`, `skills`, `calledSkillNames`, `drainActivities()`, `hadFailure`, `failureContext`.
245
+ `SkillSet` members: `tools`, `skills`, `skillsById` (Map<number, SkillDefinition>), `calledSkillNames`, `calledSkillIds`, `drainActivities()`, `hadFailure`, `failureContext`.
246
246
 
247
247
  `SkillSetOptions`: `language?` — selects label variant (`'en'` default). `debug?` — emit `console.debug` logs per skill execution (default: `false`).
248
248
 
249
249
  #### `buildSkillIndex(skillSet)`
250
250
 
251
- Generates a compact one-liner-per-skill index for the system prompt — registry-driven, so the prompt never drifts from the actual skills:
251
+ Generates a compact one-liner-per-skill index for the system prompt — registry-driven, so the prompt never drifts from the actual skills. Each line includes a numeric ID so the model can request skills by ID rather than by name:
252
252
 
253
253
  ```
254
- - invoiceSearch (read): Find invoices by number, supplier, date, or status.
255
- - invoiceApprove (write, requires confirmation): Approve an invoice.
254
+ [1] invoiceSearch (read): Find invoices by number, supplier, date, or status.
255
+ [2] invoiceApprove (write, requires confirmation): Approve an invoice.
256
256
  ```
257
257
 
258
258
  #### `selectSkills(skillSet, skillNames)`
259
259
 
260
- Returns concatenated `instructions` for the given skill names — typically `skillSet.calledSkillNames` after phase 1, injected into phase 3's system prompt. Workflow instructions load lazily, only for skills the model actually used.
260
+ Returns concatenated `instructions` for the given skill names — typically `skillSet.calledSkillNames` after phase 1. Workflow instructions load lazily, only for skills the model actually used.
261
+
262
+ #### `selectSkillsById(skillSet, skillIds)`
263
+
264
+ Same as `selectSkills` but resolves by numeric ID — use with `skillSet.calledSkillIds` to avoid string comparisons entirely. Unknown IDs and skills without instructions are skipped silently.
261
265
 
262
266
  #### `streamToWire(fullStream, skillSet?, options?)`
263
267
 
264
268
  Converts ai-sdk `fullStream` to Juneau wire SSE strings. Handles all ai-sdk v7 text chunk types (`text-delta` and `text`), drains activity buffer at the right moment, emits `done` at the end. Pass `{ debug: true }` to log every chunk received from ai-sdk.
265
269
 
270
+ #### `withSkillDispatch(options)`
271
+
272
+ Deliberate 2-phase skill dispatch — the clean alternative to sending every skill's full instructions on every request.
273
+
274
+ **Phase 1:** stream with `buildSkillIndex` as the system prompt and thin tool definitions. The model picks a skill by calling a tool — `calledSkillIds` is populated as tools fire.
275
+
276
+ **Phase 2:** always runs when at least one skill was called. Receives the full workflow instructions for the called skills (via `selectSkillsById`) and the complete phase 1 message history including tool-call and tool-result turns. The model is called again without tools so it reads the instructions and produces a text response.
277
+
278
+ If no skill was called (model answered directly), the phase 1 text is emitted as-is and the stream ends cleanly — no phase 2 needed.
279
+
280
+ ```ts
281
+ for await (const chunk of withSkillDispatch({
282
+ phase1: () => streamText({
283
+ model,
284
+ system: buildSkillIndex(skillSet), // compact index: [1] search (read): ...
285
+ messages: sdkMessages,
286
+ tools: skillSet.tools,
287
+ maxSteps: 1,
288
+ }),
289
+ phase2: (instructions, history) => streamText({
290
+ model,
291
+ system: instructions, // full workflow text for the chosen skill only
292
+ messages: history, // full phase 1 history incl. tool-call + tool-result
293
+ }),
294
+ skillSet,
295
+ onFinish: ({ text }) => saveAssistantReply(text),
296
+ })) {
297
+ res.write(chunk);
298
+ }
299
+ ```
300
+
301
+ | Option | Type | Description |
302
+ |---|---|---|
303
+ | `phase1` | `() => ToolRecoveryStreamResult` | Phase 1 stream — model picks a skill via tool call |
304
+ | `phase2` | `(instructions, messages) => { fullStream }` | Phase 2 stream — model executes with full instructions |
305
+ | `skillSet` | `SkillSet` | The skill set used in phase 1 |
306
+ | `onFinish` | `({ text }) => void` | Called once before `done` with accumulated text. Not called on error paths. |
307
+ | `debug` | `boolean` | Log phase decisions to `console.debug`. Default: `false`. |
308
+
266
309
  #### `withToolRecovery(options)`
267
310
 
268
311
  Multi-phase pattern for Gemini-style tool calls. Phase 1 streams with tools. Phase 2 triggers only when a tool failed **and** no text was produced — it calls the model without tools and injects the failure context to force a text response. Phase 3 (optional) handles the silent-success case — Gemini 2.5 Flash often treats a successful tool call as its complete response and never writes text. When the tool succeeded but no text was produced, `phase3` receives the full phase 1 message history (resolved from the ai-sdk result's `messages` promise — includes tool-call and tool-result turns, which Gemini requires to accept the history) so a second model call without tools can summarise the result. Errors thrown by phase 2/3 are emitted as wire `error` events instead of a silent `done`. Pass `debug: true` to log phase decisions, the resolved phase 3 history, and the `textProduced` / `hadFailure` state at each decision point.
@@ -283,6 +326,8 @@ yield* withToolRecovery({
283
326
 
284
327
  The wire/message types shared with the client — `AiMessage`, `AiMessageRole`, `AiMessagePart`, `AiTextPart`, `AiSerializedMessage`, `AiStreamEvent`, `JuneauWireEvent` (and its member types) — are also re-exported from `juneau/server`, so backend code never needs to import from the client entry.
285
328
 
329
+ Server-only types: `SkillSet`, `SkillDefinition`, `SkillExecuteContext`, `SkillSetOptions`, `SkillDispatchOptions`, `ToolRecoveryOptions`, `ToolRecoveryStreamResult`, `StreamToWireOptions`, `CoreMessage`.
330
+
286
331
  ---
287
332
 
288
333
  ### Juneau wire protocol — for Juneau-compatible backends
@@ -300,8 +345,10 @@ If your backend is built specifically for Juneau (e.g. Tappeer), stream newline-
300
345
  { "type": "activity", "id": "doc-search", "title": "Searching document", "status": "running" }
301
346
  { "type": "activity", "id": "doc-search", "title": "Document found", "description": "INV-2024-0894", "status": "done" }
302
347
 
303
- // Rich block — table or proposal
348
+ // Rich block — table, entity, entity list, or proposal
304
349
  { "type": "part", "part": { "type": "table", "columns": ["Name", "Amount"], "rows": [...] } }
350
+ { "type": "part", "part": { "type": "entity", "entityType": "invoice", "entity": { "id": "...", "title": "...", "subtitle": "...", "fields": [{ "label": "Status", "value": "Approved", "badge": "success" }] } } }
351
+ { "type": "part", "part": { "type": "entity-list", "title": "3 results", "entities": [...] } }
305
352
  { "type": "part", "part": { "type": "proposal", "proposal": { "id": "...", "title": "..." } } }
306
353
 
307
354
  // Stream finished cleanly
@@ -331,6 +378,7 @@ Shipped for local development. No backend needed — responds to keywords in the
331
378
  |---|---|
332
379
  | `"show"`, `"list"`, `"data"`, `"table"` | A rendered data table |
333
380
  | `"suggest"`, `"recommend"`, `"proposal"` | A proposal card with confirm/cancel |
381
+ | `"entity"`, `"card"`, `"detail"`, `"find"` | An entity list + entity detail card |
334
382
  | `"activity"`, `"progress"`, `"document"` | An activity timeline with running/done states |
335
383
  | `"help"`, `"what can you do"` | Capability overview |
336
384
  | `"error"`, `"fail"` | Simulated error response |
@@ -465,6 +513,8 @@ The sidebar anchors to the bottom-right of the viewport and opens at 60% screen
465
513
  | `height` | `string` | Height when open. Any CSS value. Defaults to `'60vh'`. |
466
514
  | `className` | `string` | Added to the `<aside>` element. |
467
515
  | `style` | `CSSProperties` | Inline styles on the `<aside>`. |
516
+ | `renderPart` | `RenderPartFn` | Custom part renderer — see below. |
517
+ | `onEntityClick` | `(entity, entityType?) => void` | Makes entity cards clickable — e.g. navigate to the record. |
468
518
 
469
519
  ---
470
520
 
@@ -515,6 +565,7 @@ function MyPage() {
515
565
  | `sendIcon` | `ReactNode` | Override send button icon. |
516
566
  | `placeholder` | `string` | Input placeholder text. |
517
567
  | `renderPart` | `RenderPartFn` | Custom part renderer — see below. |
568
+ | `onEntityClick` | `(entity, entityType?) => void` | Makes entity cards clickable — e.g. navigate to the record. |
518
569
 
519
570
  ---
520
571
 
@@ -526,7 +577,7 @@ Both `AiSidebar` and `AiChat` accept a `renderPart` prop — an escape hatch for
526
577
  type RenderPartFn = (part: AiMessagePart) => ReactNode | null | undefined;
527
578
  ```
528
579
 
529
- It is called **before** the built-in renderers for every message part. Return a ReactNode to render it; return `null`/`undefined` to fall through to the built-ins (`text`, `table`, `proposal`, `activity`, `error`).
580
+ It is called **before** the built-in renderers for every message part. Return a ReactNode to render it; return `null`/`undefined` to fall through to the built-ins (`text`, `table`, `entity`, `entity-list`, `proposal`, `activity`, `error`).
530
581
 
531
582
  The backend can stream any custom part through the standard wire protocol:
532
583
 
@@ -686,6 +737,8 @@ Assistant messages are composed of typed **parts**. Text is streamed chunk by ch
686
737
  |---|---|---|
687
738
  | `text` | `{ type: 'text', text: string }` stream events, accumulated | Markdown via `react-markdown` — safe against XSS |
688
739
  | `table` | `{ type: 'part', part: { type: 'table', ... } }` | `AiTablePart` |
740
+ | `entity` | `{ type: 'part', part: { type: 'entity', ... } }` | `AiEntityCard` |
741
+ | `entity-list` | `{ type: 'part', part: { type: 'entity-list', ... } }` | `AiEntityListPart` |
689
742
  | `proposal` | `{ type: 'part', part: { type: 'proposal', ... } }` | `AiProposalCard` |
690
743
  | `activity` | `{ type: 'part', part: { type: 'activity', ... } }` | `AiActivityPart` |
691
744
  | `error` | `{ type: 'error', message: string }` or `{ type: 'part', part: { type: 'error', ... } }` | Inline error in bubble |
@@ -755,6 +808,47 @@ yield {
755
808
  };
756
809
  ```
757
810
 
811
+ **Emitting an entity or entity list:**
812
+
813
+ Entity parts render structured records as cards — a title, optional subtitle, and labelled field rows. Field values can render as badges (`success` / `warning` / `danger` / `neutral`). Pass `onEntityClick` to `AiSidebar` / `AiChat` to make the cards clickable (e.g. navigate to the record); `entityType` and `entity.payload` are forwarded so consumers can route without guessing.
814
+
815
+ ```ts
816
+ // Single entity card
817
+ yield {
818
+ type: 'part',
819
+ part: {
820
+ type: 'entity',
821
+ entityType: 'invoice', // optional kind — forwarded to onEntityClick and custom renderers
822
+ entity: {
823
+ id: 'inv-0894', // forwarded to onEntityClick
824
+ title: 'INV-2024-0894',
825
+ subtitle: 'DataSys a.s.',
826
+ fields: [
827
+ { label: 'Amount', value: 'CZK 390 000' },
828
+ { label: 'Status', value: 'Approved', badge: 'success' },
829
+ ],
830
+ payload: { internalId: 42 }, // anything — not rendered, available in onEntityClick
831
+ },
832
+ },
833
+ };
834
+
835
+ // List of entities with an optional heading
836
+ yield {
837
+ type: 'part',
838
+ part: {
839
+ type: 'entity-list',
840
+ title: '2 results',
841
+ entityType: 'invoice',
842
+ entities: [
843
+ { id: 'inv-1', title: 'INV-2024-0894', fields: [{ label: 'Status', value: 'Approved', badge: 'success' }] },
844
+ { id: 'inv-2', title: 'INV-2024-0895', fields: [{ label: 'Status', value: 'Pending', badge: 'warning' }] },
845
+ ],
846
+ },
847
+ };
848
+ ```
849
+
850
+ For fully custom entity layouts, override the built-in card via `renderPart` — return your own component for `part.type === 'entity'` / `'entity-list'` and it wins over the default renderer.
851
+
758
852
  ---
759
853
 
760
854
  ## Chat history
@@ -1 +1 @@
1
- {"version":3,"file":"mockAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/mockAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAiC,MAAM,eAAe,CAAC;AAErF;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,gBAmBzB,CAAC"}
1
+ {"version":3,"file":"mockAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/mockAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAiC,MAAM,eAAe,CAAC;AAErF;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,gBAqBzB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { CSSProperties, ReactNode } from 'react';
2
- import type { AiMessage } from '../../core/types';
2
+ import type { AiEntity, AiMessage } from '../../core/types';
3
3
  import type { AiInputAction } from '../AiInput/AiInput';
4
4
  import type { RenderPartFn } from '../parts/AiMessagePartRenderer';
5
5
  type Props = {
@@ -14,6 +14,8 @@ type Props = {
14
14
  onStop?: () => void;
15
15
  onProposalConfirm: (proposalId: string, payload: unknown) => void;
16
16
  onProposalCancel: (proposalId: string) => void;
17
+ /** Makes entity cards clickable — receives the entity and its optional entityType. */
18
+ onEntityClick?: (entity: AiEntity, entityType?: string) => void;
17
19
  placeholder?: string;
18
20
  /** Override the assistant avatar icon. Forwarded to every message bubble. */
19
21
  assistantIcon?: ReactNode;
@@ -42,6 +44,6 @@ type Props = {
42
44
  * Used by AiSidebar (inside the sidebar chrome) and directly in dashboard
43
45
  * or any other layout where you want chat without the sidebar wrapper.
44
46
  */
45
- export declare function AiChat({ messages, input, isLoading, isConnecting, error, onInputChange, onSend, onStop, onProposalConfirm, onProposalCancel, placeholder, assistantIcon, actions, sendIcon, renderPart, className, style, }: Props): import("react").JSX.Element;
47
+ export declare function AiChat({ messages, input, isLoading, isConnecting, error, onInputChange, onSend, onStop, onProposalConfirm, onProposalCancel, onEntityClick, placeholder, assistantIcon, actions, sendIcon, renderPart, className, style, }: Props): import("react").JSX.Element;
46
48
  export {};
47
49
  //# sourceMappingURL=AiChat.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AiChat.d.ts","sourceRoot":"","sources":["../../../src/components/AiChat/AiChat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,iGAAiG;IACjG,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAClE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,EACrB,QAAQ,EACR,KAAK,EACL,SAAS,EACT,YAAY,EACZ,KAAK,EACL,aAAa,EACb,MAAM,EACN,MAAM,EACN,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,OAAO,EACP,QAAQ,EACR,UAAU,EACV,SAAS,EACT,KAAK,GACN,EAAE,KAAK,+BA8BP"}
1
+ {"version":3,"file":"AiChat.d.ts","sourceRoot":"","sources":["../../../src/components/AiChat/AiChat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,iGAAiG;IACjG,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAClE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,sFAAsF;IACtF,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,EACrB,QAAQ,EACR,KAAK,EACL,SAAS,EACT,YAAY,EACZ,KAAK,EACL,aAAa,EACb,MAAM,EACN,MAAM,EACN,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,aAAa,EACb,OAAO,EACP,QAAQ,EACR,UAAU,EACV,SAAS,EACT,KAAK,GACN,EAAE,KAAK,+BA+BP"}
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- import type { AiMessage } from '../../core/types';
2
+ import type { AiEntity, AiMessage } from '../../core/types';
3
3
  import type { RenderPartFn } from '../parts/AiMessagePartRenderer';
4
4
  type Props = {
5
5
  message: AiMessage;
@@ -7,9 +7,11 @@ type Props = {
7
7
  onProposalCancel: (proposalId: string) => void;
8
8
  /** Override the assistant avatar icon. Pass any ReactNode — an SVG, img, or component. Defaults to a brain icon. */
9
9
  assistantIcon?: ReactNode;
10
+ /** Makes entity cards clickable — forwarded to every AiMessagePartRenderer. */
11
+ onEntityClick?: (entity: AiEntity, entityType?: string) => void;
10
12
  /** Custom part renderer — forwarded to every AiMessagePartRenderer. */
11
13
  renderPart?: RenderPartFn;
12
14
  };
13
- export declare function AiMessageBubble({ message, onProposalConfirm, onProposalCancel, assistantIcon, renderPart }: Props): import("react").JSX.Element;
15
+ export declare function AiMessageBubble({ message, onProposalConfirm, onProposalCancel, onEntityClick, assistantIcon, renderPart }: Props): import("react").JSX.Element;
14
16
  export {};
15
17
  //# sourceMappingURL=AiMessageBubble.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AiMessageBubble.d.ts","sourceRoot":"","sources":["../../../src/components/AiMessageBubble/AiMessageBubble.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,KAAK,KAAK,GAAG;IACX,OAAO,EAAE,SAAS,CAAC;IACnB,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAClE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,oHAAoH;IACpH,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,uEAAuE;IACvE,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,EAAE,KAAK,+BA4BjH"}
1
+ {"version":3,"file":"AiMessageBubble.d.ts","sourceRoot":"","sources":["../../../src/components/AiMessageBubble/AiMessageBubble.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,KAAK,KAAK,GAAG;IACX,OAAO,EAAE,SAAS,CAAC;IACnB,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAClE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,oHAAoH;IACpH,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,+EAA+E;IAC/E,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,uEAAuE;IACvE,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,EAAE,KAAK,+BA6BhI"}
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- import type { AiMessage } from '../../core/types';
2
+ import type { AiEntity, AiMessage } from '../../core/types';
3
3
  import type { RenderPartFn } from '../parts/AiMessagePartRenderer';
4
4
  type Props = {
5
5
  messages: AiMessage[];
@@ -10,9 +10,11 @@ type Props = {
10
10
  onProposalCancel: (proposalId: string) => void;
11
11
  /** Override the assistant avatar icon. Forwarded to every AiMessageBubble. */
12
12
  assistantIcon?: ReactNode;
13
+ /** Makes entity cards clickable — forwarded to every AiMessageBubble. */
14
+ onEntityClick?: (entity: AiEntity, entityType?: string) => void;
13
15
  /** Custom part renderer — forwarded to every AiMessageBubble. */
14
16
  renderPart?: RenderPartFn;
15
17
  };
16
- export declare function AiMessageList({ messages, isLoading, isConnecting, onProposalConfirm, onProposalCancel, assistantIcon, renderPart }: Props): import("react").JSX.Element;
18
+ export declare function AiMessageList({ messages, isLoading, isConnecting, onProposalConfirm, onProposalCancel, onEntityClick, assistantIcon, renderPart }: Props): import("react").JSX.Element;
17
19
  export {};
18
20
  //# sourceMappingURL=AiMessageList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AiMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/AiMessageList/AiMessageList.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAIlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,uGAAuG;IACvG,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAClE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,8EAA8E;IAC9E,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,iEAAiE;IACjE,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B,CAAC;AAEF,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,EAAE,KAAK,+BAoCzI"}
1
+ {"version":3,"file":"AiMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/AiMessageList/AiMessageList.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAI5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,uGAAuG;IACvG,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAClE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,8EAA8E;IAC9E,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,yEAAyE;IACzE,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,iEAAiE;IACjE,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B,CAAC;AAEF,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,EAAE,KAAK,+BAqCxJ"}
@@ -1,4 +1,5 @@
1
1
  import type { CSSProperties, ReactNode } from 'react';
2
+ import type { AiEntity } from '../../core/types';
2
3
  import type { AiInputAction } from '../AiInput/AiInput';
3
4
  import type { RenderPartFn } from '../parts/AiMessagePartRenderer';
4
5
  type Props = {
@@ -32,7 +33,9 @@ type Props = {
32
33
  * through to the built-ins. Enables custom part types like invoice cards.
33
34
  */
34
35
  renderPart?: RenderPartFn;
36
+ /** Makes entity cards clickable — receives the entity and its optional entityType. */
37
+ onEntityClick?: (entity: AiEntity, entityType?: string) => void;
35
38
  };
36
- export declare function AiSidebar({ title, icon, actions, sendIcon, height, className, style, onReset, renderPart, }: Props): import("react").JSX.Element;
39
+ export declare function AiSidebar({ title, icon, actions, sendIcon, height, className, style, onReset, renderPart, onEntityClick, }: Props): import("react").JSX.Element;
37
40
  export {};
38
41
  //# sourceMappingURL=AiSidebar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AiSidebar.d.ts","sourceRoot":"","sources":["../../../src/components/AiSidebar/AiSidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,KAAK,KAAK,GAAG;IACX,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B,CAAC;AAEF,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,MAAe,EACf,SAAS,EACT,KAAK,EACL,OAAO,EACP,UAAU,GACX,EAAE,KAAK,+BAsDP"}
1
+ {"version":3,"file":"AiSidebar.d.ts","sourceRoot":"","sources":["../../../src/components/AiSidebar/AiSidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,KAAK,KAAK,GAAG;IACX,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,sFAAsF;IACtF,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACjE,CAAC;AAEF,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,MAAe,EACf,SAAS,EACT,KAAK,EACL,OAAO,EACP,UAAU,EACV,aAAa,GACd,EAAE,KAAK,+BAuDP"}
@@ -0,0 +1,9 @@
1
+ import type { AiEntity, AiEntityPart } from '../../core/types';
2
+ type Props = {
3
+ part: AiEntityPart;
4
+ /** Optional click handler — the card becomes interactive when provided */
5
+ onEntityClick?: (entity: AiEntity, entityType?: string) => void;
6
+ };
7
+ export declare function AiEntityCard({ part, onEntityClick }: Props): import("react").JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=AiEntityCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiEntityCard.d.ts","sourceRoot":"","sources":["../../../src/components/parts/AiEntityCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAqB,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGlF,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,YAAY,CAAC;IACnB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACjE,CAAC;AASF,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,KAAK,+BA0C1D"}
@@ -0,0 +1,9 @@
1
+ import type { AiEntity, AiEntityListPart as AiEntityListPartType } from '../../core/types';
2
+ type Props = {
3
+ part: AiEntityListPartType;
4
+ /** Optional click handler — cards become interactive when provided */
5
+ onEntityClick?: (entity: AiEntity, entityType?: string) => void;
6
+ };
7
+ export declare function AiEntityListPart({ part, onEntityClick }: Props): import("react").JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=AiEntityListPart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiEntityListPart.d.ts","sourceRoot":"","sources":["../../../src/components/parts/AiEntityListPart.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAI3F,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,oBAAoB,CAAC;IAC3B,sEAAsE;IACtE,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACjE,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,KAAK,+BAa9D"}
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- import type { AiMessagePart } from '../../core/types';
2
+ import type { AiEntity, AiMessagePart } from '../../core/types';
3
3
  /**
4
4
  * Consumer escape hatch for rendering custom part types (or overriding
5
5
  * built-in ones). Receives the raw part object with no narrowing or
@@ -11,9 +11,11 @@ type Props = {
11
11
  part: AiMessagePart;
12
12
  onProposalConfirm: (proposalId: string, payload: unknown) => void;
13
13
  onProposalCancel: (proposalId: string) => void;
14
+ /** Makes entity cards clickable — receives the entity and its optional entityType. */
15
+ onEntityClick?: (entity: AiEntity, entityType?: string) => void;
14
16
  /** Called before the built-in switch — a non-nullish return value wins. */
15
17
  renderPart?: RenderPartFn;
16
18
  };
17
- export declare function AiMessagePartRenderer({ part, onProposalConfirm, onProposalCancel, renderPart }: Props): import("react").JSX.Element | null;
19
+ export declare function AiMessagePartRenderer({ part, onProposalConfirm, onProposalCancel, onEntityClick, renderPart }: Props): import("react").JSX.Element | null;
18
20
  export {};
19
21
  //# sourceMappingURL=AiMessagePartRenderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AiMessagePartRenderer.d.ts","sourceRoot":"","sources":["../../../src/components/parts/AiMessagePartRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EACV,aAAa,EAMd,MAAM,kBAAkB,CAAC;AAO1B;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,aAAa,KAAK,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;AAEjF,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,aAAa,CAAC;IACpB,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAClE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,2EAA2E;IAC3E,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,UAAU,EAAE,EAAE,KAAK,sCAsDrG"}
1
+ {"version":3,"file":"AiMessagePartRenderer.d.ts","sourceRoot":"","sources":["../../../src/components/parts/AiMessagePartRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EACV,QAAQ,EACR,aAAa,EAQd,MAAM,kBAAkB,CAAC;AAS1B;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,aAAa,KAAK,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;AAEjF,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,aAAa,CAAC;IACpB,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAClE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,sFAAsF;IACtF,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,2EAA2E;IAC3E,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,EAAE,KAAK,sCA0DpH"}
@@ -34,6 +34,43 @@ export type AiErrorPart = {
34
34
  type: 'error';
35
35
  message: string;
36
36
  };
37
+ /** Badge tone for an entity field value */
38
+ export type AiEntityBadgeTone = 'success' | 'warning' | 'danger' | 'neutral';
39
+ /** One labelled field of an entity — rendered as a label/value row */
40
+ export type AiEntityField = {
41
+ label: string;
42
+ value: string;
43
+ /** Render the value as a coloured badge instead of plain text */
44
+ badge?: AiEntityBadgeTone;
45
+ };
46
+ /**
47
+ * A generic structured entity — a domain record (any object with a title
48
+ * and fields). Juneau renders it as a card; consumers can override via
49
+ * `renderPart` for domain-specific layouts.
50
+ */
51
+ export type AiEntity = {
52
+ /** Stable ID — forwarded to `onEntityClick` so consumers can navigate */
53
+ id?: string;
54
+ title: string;
55
+ subtitle?: string;
56
+ fields?: AiEntityField[];
57
+ /** Arbitrary payload — not rendered, available for custom renderers and click handlers */
58
+ payload?: unknown;
59
+ };
60
+ export type AiEntityPart = {
61
+ type: 'entity';
62
+ entity: AiEntity;
63
+ /** Optional entity kind (e.g. "invoice") — available for custom renderers */
64
+ entityType?: string;
65
+ };
66
+ export type AiEntityListPart = {
67
+ type: 'entity-list';
68
+ entities: AiEntity[];
69
+ /** Optional heading above the list */
70
+ title?: string;
71
+ /** Optional entity kind shared by all items — available for custom renderers */
72
+ entityType?: string;
73
+ };
37
74
  export type AiActivityStatus = 'running' | 'done' | 'failed';
38
75
  export type AiActivityPart = {
39
76
  type: 'activity';
@@ -57,7 +94,7 @@ export type AiCustomPart = {
57
94
  type: string;
58
95
  [key: string]: unknown;
59
96
  };
60
- export type AiMessagePart = AiTextPart | AiTablePart | AiProposalPart | AiActivityPart | AiErrorPart | AiCustomPart;
97
+ export type AiMessagePart = AiTextPart | AiTablePart | AiProposalPart | AiActivityPart | AiErrorPart | AiEntityPart | AiEntityListPart | AiCustomPart;
61
98
  export type AiMessage = {
62
99
  id: string;
63
100
  role: AiMessageRole;
@@ -89,7 +126,7 @@ export type AiStreamTextEvent = {
89
126
  };
90
127
  export type AiStreamPartEvent = {
91
128
  type: 'part';
92
- part: AiTablePart | AiProposalPart | AiActivityPart | AiErrorPart | AiCustomPart;
129
+ part: AiTablePart | AiProposalPart | AiActivityPart | AiErrorPart | AiEntityPart | AiEntityListPart | AiCustomPart;
93
130
  };
94
131
  export type AiStreamDoneEvent = {
95
132
  type: 'done';
@@ -127,10 +164,10 @@ export type JuneauWireActivity = {
127
164
  */
128
165
  metadata?: Record<string, unknown>;
129
166
  };
130
- /** Structured rich block — table, proposal, or any consumer-defined custom part */
167
+ /** Structured rich block — table, proposal, entity, entity list, or any consumer-defined custom part */
131
168
  export type JuneauWirePart = {
132
169
  type: 'part';
133
- part: AiTablePart | AiProposalPart | AiCustomPart;
170
+ part: AiTablePart | AiProposalPart | AiEntityPart | AiEntityListPart | AiCustomPart;
134
171
  };
135
172
  /** Stream finished cleanly */
136
173
  export type JuneauWireDone = {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}