@aleph-alpha/chat-kit 5.8.0 → 5.10.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 (26) hide show
  1. package/dist/{CkHistory.vue_vue_type_script_setup_true_lang-DG96wNug.js → CkHistory.vue_vue_type_script_setup_true_lang-CEqJtMuI.js} +61 -40
  2. package/dist/adapters/responses-api.d.ts +1 -3
  3. package/dist/adapters/responses-api.d.ts.map +1 -1
  4. package/dist/adapters/responses-api.js +55 -65
  5. package/dist/chat-kit.css +1 -1
  6. package/dist/components/base/CkConversationLayout/CkConversationLayout.stories.d.ts +7 -0
  7. package/dist/components/base/CkConversationLayout/CkConversationLayout.stories.d.ts.map +1 -1
  8. package/dist/components/base/CkConversationLayout/CkConversationLayout.vue.d.ts +3 -1
  9. package/dist/components/base/CkConversationLayout/CkConversationLayout.vue.d.ts.map +1 -1
  10. package/dist/components/composed/CkConversation/CkConversation.stories.d.ts +23 -3
  11. package/dist/components/composed/CkConversation/CkConversation.stories.d.ts.map +1 -1
  12. package/dist/components/composed/CkConversation/CkConversation.vue.d.ts +17 -2
  13. package/dist/components/composed/CkConversation/CkConversation.vue.d.ts.map +1 -1
  14. package/dist/components/composed/CkHistory/CkHistory.vue.d.ts +1 -1
  15. package/dist/components/index.js +1 -1
  16. package/dist/index.js +1 -1
  17. package/package.json +3 -3
  18. package/src/adapters/arena.spec.ts +12 -18
  19. package/src/adapters/responses-api.spec.ts +6 -3
  20. package/src/adapters/responses-api.ts +80 -86
  21. package/src/components/base/CkConversationLayout/CkConversationLayout.spec.ts +209 -1
  22. package/src/components/base/CkConversationLayout/CkConversationLayout.stories.ts +84 -0
  23. package/src/components/base/CkConversationLayout/CkConversationLayout.vue +59 -21
  24. package/src/components/composed/CkConversation/CkConversation.spec.ts +96 -5
  25. package/src/components/composed/CkConversation/CkConversation.stories.ts +328 -4
  26. package/src/components/composed/CkConversation/CkConversation.vue +38 -8
@@ -15,6 +15,13 @@ export declare const Default: Story;
15
15
  * Use when streaming tokens from an LLM into the last agent message.
16
16
  */
17
17
  export declare const StreamingSimulation: Story;
18
+ /**
19
+ * Programmatic navigation via the exposed `scrollToMessage(index)` method. Enter
20
+ * a zero-based row index and the layout scrolls that message to the top. Index
21
+ * counts all rows regardless of role (a `thread-footer`, when present, is the
22
+ * trailing row); omitting the index scrolls to the last row.
23
+ */
24
+ export declare const ScrollToMessage: Story;
18
25
  /**
19
26
  * Empty state for when there are no messages. Use as an initial state before
20
27
  * the first user turn, or when history has been cleared.
@@ -1 +1 @@
1
- {"version":3,"file":"CkConversationLayout.stories.d.ts","sourceRoot":"","sources":["../../../../src/components/base/CkConversationLayout/CkConversationLayout.stories.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,KAAK,CAAC;AAI3C,QAAA,MAAM,oBAAoB,EACoB,eAAe,CAAC;AAoB9D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,oBAAoB,CAU3C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AA2EnC;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,KAsBrB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAiFjC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,KAenB,CAAC"}
1
+ {"version":3,"file":"CkConversationLayout.stories.d.ts","sourceRoot":"","sources":["../../../../src/components/base/CkConversationLayout/CkConversationLayout.stories.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,KAAK,CAAC;AAI3C,QAAA,MAAM,oBAAoB,EACoB,eAAe,CAAC;AAoB9D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,oBAAoB,CAU3C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AA6GnC;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,KAsBrB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAiFjC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,KA0C7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,KAenB,CAAC"}
@@ -7,7 +7,9 @@ declare const __VLS_export: <T extends {
7
7
  }> & (typeof globalThis extends {
8
8
  __VLS_PROPS_FALLBACK: infer P;
9
9
  } ? P : {});
10
- expose: (exposed: {}) => void;
10
+ expose: (exposed: import("vue").ShallowUnwrapRef<{
11
+ scrollToMessage: (index?: number) => void;
12
+ }>) => void;
11
13
  attrs: any;
12
14
  slots: {
13
15
  'user-message': (props: {
@@ -1 +1 @@
1
- {"version":3,"file":"CkConversationLayout.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/base/CkConversationLayout/CkConversationLayout.vue"],"names":[],"mappings":"AAyRA,QAAA,MAAM,YAAY,GAAK,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC5D,aAAa,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAC9D,YAAY,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAC3G,gBAAgB,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAClE;WAkWO,OAAO,KAAK,EAAE,WAAW,GAAG,mBAAmB;kBA9V3C,CAAC,EAAE;MA8V2D,GAAG,CAAC,OAAO,UAAU,SAAS;QAAE,oBAAoB,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAC1I,CAAC,OAAO,EAAE,EAAE,KAAK,IAAI;WACtB,GAAG;;wBA3VO,CAAC,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC,CAAA;SAAE,KAAK,IAAI;yBAC9B,CAAC,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC,CAAA;SAAE,KAAK,IAAI;QAChD;;;;WAIG;yBACc,MAAM,IAAI;;UAsVtB,EAAE;EAEL,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,WAAW,CAAC,CAAA;CAAI,CAAC;wBACvD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,CAAC,GAAG,EAAE,CAAC"}
1
+ {"version":3,"file":"CkConversationLayout.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/base/CkConversationLayout/CkConversationLayout.vue"],"names":[],"mappings":"AA+TA,QAAA,MAAM,YAAY,GAAK,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC5D,aAAa,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAC9D,YAAY,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAC3G,gBAAgB,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAClE;WAwYO,OAAO,KAAK,EAAE,WAAW,GAAG,mBAAmB;kBApY3C,CAAC,EAAE;MAoY2D,GAAG,CAAC,OAAO,UAAU,SAAS;QAAE,oBAAoB,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAC1I,CAAC,OAAO,EAAE,OAAO,KAAK,EAAE,gBAAgB;kCAjPb,MAAM,KAAG,IAAI;MAiPsB,KAAK,IAAI;WACxE,GAAG;;wBAjYO,CAAC,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC,CAAA;SAAE,KAAK,IAAI;yBAC9B,CAAC,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC,CAAA;SAAE,KAAK,IAAI;QAChD;;;;WAIG;yBACc,MAAM,IAAI;;UA4XtB,EAAE;EAEL,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,WAAW,CAAC,CAAA;CAAI,CAAC;wBACvD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,CAAC,GAAG,EAAE,CAAC"}
@@ -12,6 +12,13 @@ type Story = StoryObj<typeof meta>;
12
12
  * `#agent-message-header-content`.
13
13
  */
14
14
  export declare const Default: Story;
15
+ /**
16
+ * A diagram of how CkConversation's slots nest. Every slot has a default
17
+ * rendering; overriding a parent slot replaces everything nested beneath it,
18
+ * so the child slots below it no longer apply. Collapse a node to see which
19
+ * slots "fold away" when you take over its parent.
20
+ */
21
+ export declare const SlotAnatomy: Story;
15
22
  /**
16
23
  * Uses a remote avatar image (with fallback text). Use when you want a
17
24
  * branded agent identity in each reply.
@@ -70,11 +77,24 @@ export declare const StreamingSimulation: Story;
70
77
  */
71
78
  export declare const WithCustomMarkdownClasses: Story;
72
79
  /**
73
- * Integrates a custom code-block renderer (Shiki, Prism, etc.) via
74
- * `#agent-message-code-block`. Use when you want syntax highlighting or
75
- * inline copy buttons for assistant code.
80
+ * Fenced code blocks in agent markdown render with `UiCodeBlock` out of the
81
+ * box — syntax highlighting, a language label, and a copy button — without any
82
+ * slot wiring.
83
+ */
84
+ export declare const DefaultCodeBlock: Story;
85
+ /**
86
+ * Fenced code blocks render with `UiCodeBlock` (syntax highlighting + copy
87
+ * button) by default. Override that with a custom renderer (Prism, a bespoke
88
+ * theme, etc.) via `#agent-message-code-block`, as shown here.
76
89
  */
77
90
  export declare const WithCustomCodeBlock: Story;
91
+ /**
92
+ * Programmatic navigation via the exposed `scrollToMessage(index)` method. Enter
93
+ * a zero-based row index and the conversation scrolls that message to the top.
94
+ * Index counts all rows regardless of role (a `thread-footer`, when present, is
95
+ * the trailing row); omitting the index scrolls to the last row.
96
+ */
97
+ export declare const ScrollToMessage: Story;
78
98
  /**
79
99
  * Empty state — an initial view before the first turn. Use to show a welcome
80
100
  * screen, quick prompts, or onboarding content above this surface.
@@ -1 +1 @@
1
- {"version":3,"file":"CkConversation.stories.d.ts","sourceRoot":"","sources":["../../../../src/components/composed/CkConversation/CkConversation.stories.ts"],"names":[],"mappings":"AASA,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAwI3D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,cAAc,CAkCrC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AA4SnC;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,EAAE,KAerB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,KAUtB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,KAYtC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,KASpB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,KAe5B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,KAU7B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAmC/B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAiBnC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,KAiBpC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,KA4GjC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,EAAE,KAmBvC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAoDjC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC"}
1
+ {"version":3,"file":"CkConversation.stories.d.ts","sourceRoot":"","sources":["../../../../src/components/composed/CkConversation/CkConversation.stories.ts"],"names":[],"mappings":"AASA,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAwI3D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,cAAc,CAkCrC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AA6WnC;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,EAAE,KAerB,CAAC;AA2HF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,EAAE,KAgCzB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,KAUtB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,KAYtC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,KASpB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,KAe5B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,KAU7B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAmC/B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAiBnC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,KAiBpC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,KA4GjC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,EAAE,KAmBvC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,KA6C9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAoDjC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,KAsC7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC"}
@@ -49,7 +49,11 @@ type __VLS_Slots = {
49
49
  'agent-message-footer': (props: {
50
50
  message: BaseMessage;
51
51
  }) => void;
52
- /** Replace the default code block rendering inside agent markdown */
52
+ /**
53
+ * Replace the default code block rendering inside agent markdown. When not
54
+ * provided, fenced code blocks render with `UiCodeBlock` (syntax highlighting
55
+ * + copy button).
56
+ */
53
57
  'agent-message-code-block': (props: {
54
58
  code: string;
55
59
  language: string;
@@ -61,7 +65,18 @@ type __VLS_Slots = {
61
65
  */
62
66
  'thread-footer': () => void;
63
67
  };
64
- declare const __VLS_base: import("vue").DefineComponent<CkConversationProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<CkConversationProps> & Readonly<{}>, {
68
+ /**
69
+ * Scroll so the message at `index` sits at the top of the viewport. `index` is
70
+ * the zero-based position among the rendered rows (any `thread-footer` counts
71
+ * as the trailing row); when omitted it scrolls to the last row.
72
+ *
73
+ * This only performs the scroll — it does not focus the message. Any
74
+ * accompanying focus handling must be done separately by the caller.
75
+ */
76
+ declare function scrollToMessage(index?: number): void;
77
+ declare const __VLS_base: import("vue").DefineComponent<CkConversationProps, {
78
+ scrollToMessage: typeof scrollToMessage;
79
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<CkConversationProps> & Readonly<{}>, {
65
80
  agentAvatarImage: string;
66
81
  agentAvatarFallback: string;
67
82
  agentLoadingImage: string;
@@ -1 +1 @@
1
- {"version":3,"file":"CkConversation.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/composed/CkConversation/CkConversation.vue"],"names":[],"mappings":"AAuPA,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,gBAAgB,CAAC;AAOtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAkBnD,KAAK,WAAW,GAAG;IACjB,gDAAgD;IAChD,cAAc,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAC1D,yDAAyD;IACzD,sBAAsB,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAClE,iDAAiD;IACjD,eAAe,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3D,oCAAoC;IACpC,oBAAoB,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAChE,8EAA8E;IAC9E,4BAA4B,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IACxE,iFAAiF;IACjF,sBAAsB,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAClE,6EAA6E;IAC7E,8BAA8B,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAC1E;;;;OAIG;IACH,+BAA+B,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3E;;;;OAIG;IACH,uBAAuB,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IACnE,mDAAmD;IACnD,sBAAsB,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAClE,qEAAqE;IACrE,0BAA0B,EAAE,CAAC,KAAK,EAAE;QAClC,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,KAAK,IAAI,CAAC;IACX;;;;OAIG;IACH,eAAe,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC;AAwXF,QAAA,MAAM,UAAU;;;;6EAGd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AAWzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
1
+ {"version":3,"file":"CkConversation.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/composed/CkConversation/CkConversation.vue"],"names":[],"mappings":"AAqRA,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,gBAAgB,CAAC;AAOtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AA0BnD,KAAK,WAAW,GAAG;IACjB,gDAAgD;IAChD,cAAc,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAC1D,yDAAyD;IACzD,sBAAsB,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAClE,iDAAiD;IACjD,eAAe,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3D,oCAAoC;IACpC,oBAAoB,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAChE,8EAA8E;IAC9E,4BAA4B,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IACxE,iFAAiF;IACjF,sBAAsB,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAClE,6EAA6E;IAC7E,8BAA8B,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAC1E;;;;OAIG;IACH,+BAA+B,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3E;;;;OAIG;IACH,uBAAuB,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IACnE,mDAAmD;IACnD,sBAAsB,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAC;IAClE;;;;OAIG;IACH,0BAA0B,EAAE,CAAC,KAAK,EAAE;QAClC,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,KAAK,IAAI,CAAC;IACX;;;;OAIG;IACH,eAAe,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC;AA8DF;;;;;;;GAOG;AACH,iBAAS,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAE7C;AAkVD,QAAA,MAAM,UAAU;;;;;;6EAId,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AAWzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
@@ -40,10 +40,10 @@ declare const __VLS_base: import("vue").DefineComponent<CkHistoryProps, {}, {},
40
40
  }>, {
41
41
  showAction: boolean;
42
42
  showActionOnHover: boolean;
43
+ maxHeight: string;
43
44
  activeId: string;
44
45
  timeFormatter: (updatedAtSeconds: number) => string;
45
46
  collapsedLimit: number;
46
- maxHeight: string;
47
47
  contentClass: string;
48
48
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
49
49
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -1,4 +1,4 @@
1
- import { _, a, C, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z } from "../CkHistory.vue_vue_type_script_setup_true_lang-DG96wNug.js";
1
+ import { _, a, C, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z } from "../CkHistory.vue_vue_type_script_setup_true_lang-CEqJtMuI.js";
2
2
  export {
3
3
  _ as CkAgentMessage,
4
4
  a as CkAgentMessageHeader,
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { u } from "./useMessageHandler-Tellov3w.js";
2
2
  import { C, d, p, u as u2, b } from "./useChatKitLabels-CMOr3Kjq.js";
3
3
  import { S, c, d as d2, f, u as u3, a, b as b2, e } from "./index-Dn4ctxk8.js";
4
- import { _, a as a2, C as C2, b as b3, c as c2, d as d3, e as e2, f as f2, g, h, i, j, k, l, m, n, o, p as p2, q, r, s, t, u as u4, v, w, x, y, z, A } from "./CkHistory.vue_vue_type_script_setup_true_lang-DG96wNug.js";
4
+ import { _, a as a2, C as C2, b as b3, c as c2, d as d3, e as e2, f as f2, g, h, i, j, k, l, m, n, o, p as p2, q, r, s, t, u as u4, v, w, x, y, z, A } from "./CkHistory.vue_vue_type_script_setup_true_lang-CEqJtMuI.js";
5
5
  export {
6
6
  C as CHAT_KIT_LABELS,
7
7
  _ as CkAgentMessage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aleph-alpha/chat-kit",
3
- "version": "5.8.0",
3
+ "version": "5.10.0",
4
4
  "description": "Chat kit package for building chat interfaces with Vue",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -108,8 +108,8 @@
108
108
  "vue-tsc": "^3.2.4",
109
109
  "wait-on": "9.0.3",
110
110
  "@aleph-alpha/eslint-config-frontend": "0.7.0",
111
- "@aleph-alpha/prettier-config-frontend": "2.1.0",
112
- "@aleph-alpha/tsconfig-frontend": "0.7.1"
111
+ "@aleph-alpha/tsconfig-frontend": "0.7.1",
112
+ "@aleph-alpha/prettier-config-frontend": "2.1.0"
113
113
  },
114
114
  "scripts": {
115
115
  "build": "vite build && vue-tsc --project tsconfig.build.json --declaration --emitDeclarationOnly --outDir dist",
@@ -32,7 +32,6 @@ function arenaResponse(
32
32
  matchup_id: matchupId,
33
33
  slot,
34
34
  model_id: modelId,
35
- variant: 'king-of-the-hill',
36
35
  }),
37
36
  },
38
37
  } as StoredResponse;
@@ -54,29 +53,24 @@ describe('responsesToTree arena collapse', () => {
54
53
 
55
54
  const children = root.childrenIds.map((id) => tree.nodes[id]!);
56
55
  expect(children.every((c) => c.role === 'assistant')).toBe(true);
57
- // Model id stamped for lane labels; ordered slot a then b.
56
+ // Ordered slot a then b.
58
57
  const slots = children.map(
59
58
  (c) => (c.metadata.arena as { slot?: string }).slot,
60
59
  );
61
60
  expect(slots).toEqual(['a', 'b']);
61
+ // Blind until the vote: no model label leaks (neither arena.modelId nor
62
+ // metadata.model), so the columns render "Response A/B".
63
+ for (const c of children) {
64
+ expect(
65
+ (c.metadata.arena as { modelId?: string }).modelId,
66
+ ).toBeUndefined();
67
+ expect(c.metadata.model).toBeUndefined();
68
+ }
62
69
  });
63
70
 
64
- it('marks the recorded winner when arenaWinners is supplied', () => {
65
- const tree = responsesToTree(
66
- [
67
- arenaResponse('respA', 'm1', 'a', 'phoenix-latest', 'A'),
68
- arenaResponse('respB', 'm1', 'b', 'kimi-k2.6', 'B'),
69
- ],
70
- { arenaWinners: { m1: 'respB' } },
71
- );
72
- const root = tree.nodes[tree.rootId!]!;
73
- // Winner is respB's assistant node (its wire message id).
74
- expect(root.comparisonWinnerId).toBe('msg-respB');
75
- expect(root.childrenIds[root.activeChildIndex]).toBe('msg-respB');
76
- });
77
-
78
- it('leaves a single surviving response as an ordinary linear turn', () => {
79
- // 7-Discard: after continue, the BE dropped the loser — one response left.
71
+ it('leaves a single (server-collapsed resolved) response as a linear turn', () => {
72
+ // The backend collapses a resolved matchup to its winning branch, so a
73
+ // resolved pair arrives as a lone response — an ordinary linear turn.
80
74
  const tree = responsesToTree([
81
75
  arenaResponse('respA', 'm1', 'a', 'phoenix-latest', 'A'),
82
76
  ]);
@@ -456,9 +456,12 @@ describe('responsesToTree', () => {
456
456
  },
457
457
  ],
458
458
  });
459
- // The assistant turn does not inherit attachments but still carries
460
- // its responseId stamp.
461
- expect(tree.nodes['msg-a1']!.metadata).toEqual({ responseId: 'r1' });
459
+ // The assistant turn does not inherit attachments but still carries its
460
+ // responseId stamp and the response's model id.
461
+ expect(tree.nodes['msg-a1']!.metadata).toEqual({
462
+ responseId: 'r1',
463
+ model: 'pharia-1',
464
+ });
462
465
  });
463
466
 
464
467
  it('skips malformed metadata.attachments without polluting the tree', () => {
@@ -462,6 +462,53 @@ function parseResponseAttachments(
462
462
  return attachments as ResponseAttachment[];
463
463
  }
464
464
 
465
+ // Maps response-level attachments onto the shape stored in node metadata.
466
+ function toMessageAttachments(
467
+ attachments: ResponseAttachment[],
468
+ ): ResponseMessageAttachment[] {
469
+ return attachments.map(
470
+ (a): ResponseMessageAttachment => ({
471
+ name: a.fileName,
472
+ fileId: a.fileId,
473
+ fileName: a.fileName,
474
+ searchStoreId: a.searchStoreId,
475
+ ...(a.documentId ? { documentId: a.documentId } : {}),
476
+ }),
477
+ );
478
+ }
479
+
480
+ // Builds the user node for a single `request_input`, or null when the input is
481
+ // not a user turn / carries no visible content. Attachments bind to the first
482
+ // user node only (`isFirstUserNode`).
483
+ function buildUserNode(
484
+ resp: StoredResponse,
485
+ input: unknown,
486
+ idx: number,
487
+ responseAttachments: ResponseAttachment[] | null,
488
+ isFirstUserNode: boolean,
489
+ ): ResponseMessageNode | null {
490
+ const role = (input as { role?: string }).role;
491
+ const text = extractInputText((input as { content?: unknown }).content);
492
+ const hasContent = text || responseAttachments?.length;
493
+ if (role !== 'user' || !hasContent) return null;
494
+
495
+ const metadata: ResponseTreeMessageMetadata = {
496
+ responseId: resp.id,
497
+ ...(resp.model ? { model: resp.model } : {}),
498
+ };
499
+ if (responseAttachments && isFirstUserNode) {
500
+ metadata.attachments = toMessageAttachments(responseAttachments);
501
+ }
502
+
503
+ return {
504
+ id: `user-${resp.id}-${idx}`,
505
+ role: 'user',
506
+ content: [textPart(text)],
507
+ createdAt: new Date(resp.created_at * 1000),
508
+ metadata,
509
+ };
510
+ }
511
+
465
512
  // Within a single response, the visible messages chain linearly: every user
466
513
  // input is followed by exactly one assistant turn (whose reasoning, tool,
467
514
  // and text outputs are merged into one node). Across responses, branching
@@ -473,40 +520,15 @@ function responseToMessageNodes(resp: StoredResponse): ResponseMessageNode[] {
473
520
  // the user turn that started the response. We bind them to the first
474
521
  // user `request_input` (mirroring the existing wire convention).
475
522
  const responseAttachments = parseResponseAttachments(resp);
476
- let userNodesPushed = 0;
477
- if (resp.request_input) {
478
- for (const [idx, input] of resp.request_input.entries()) {
479
- const role = (input as { role?: string }).role;
480
- const rawContent = (input as { content?: unknown }).content;
481
- const text = extractInputText(rawContent);
482
- const userContent = text || responseAttachments?.length;
483
- if (role !== 'user' || !userContent) continue;
484
-
485
- const metadata: ResponseTreeMessageMetadata = {
486
- responseId: resp.id,
487
- ...(resp.model ? { model: resp.model } : {}),
488
- };
489
- if (responseAttachments && userNodesPushed === 0) {
490
- metadata.attachments = responseAttachments.map(
491
- (a): ResponseMessageAttachment => ({
492
- name: a.fileName,
493
- fileId: a.fileId,
494
- fileName: a.fileName,
495
- searchStoreId: a.searchStoreId,
496
- ...(a.documentId ? { documentId: a.documentId } : {}),
497
- }),
498
- );
499
- }
500
-
501
- nodes.push({
502
- id: `user-${resp.id}-${idx}`,
503
- role: 'user',
504
- content: [textPart(text)],
505
- createdAt: new Date(resp.created_at * 1000),
506
- metadata,
507
- });
508
- userNodesPushed += 1;
509
- }
523
+ for (const [idx, input] of resp.request_input?.entries() ?? []) {
524
+ const userNode = buildUserNode(
525
+ resp,
526
+ input,
527
+ idx,
528
+ responseAttachments,
529
+ nodes.length === 0,
530
+ );
531
+ if (userNode) nodes.push(userNode);
510
532
  }
511
533
 
512
534
  const assistantParts = toAssistantParts(resp);
@@ -516,7 +538,12 @@ function responseToMessageNodes(resp: StoredResponse): ResponseMessageNode[] {
516
538
  role: 'assistant',
517
539
  content: assistantParts,
518
540
  createdAt: new Date((resp.completed_at ?? resp.created_at) * 1000),
519
- metadata: { responseId: resp.id },
541
+ // A stored response carries a single `model` covering both its input and
542
+ // output, so the assistant node gets the same model id as its user node.
543
+ metadata: {
544
+ responseId: resp.id,
545
+ ...(resp.model ? { model: resp.model } : {}),
546
+ },
520
547
  });
521
548
  }
522
549
  return nodes;
@@ -676,7 +703,6 @@ function linkResponse(state: TreeBuildState, resp: StoredResponse): void {
676
703
  */
677
704
  export function responsesToTree(
678
705
  responses: StoredResponse[],
679
- opts?: { arenaWinners?: Record<string, string> },
680
706
  ): ResponseConversationTree {
681
707
  if (responses.length === 0) {
682
708
  return { nodes: {}, rootId: null };
@@ -696,7 +722,6 @@ export function responsesToTree(
696
722
  const rootId = collapseArenaComparisons(
697
723
  state.treeNodes,
698
724
  responses,
699
- opts?.arenaWinners ?? {},
700
725
  state.rootMessageId,
701
726
  state.userMessageByResponse,
702
727
  );
@@ -708,8 +733,6 @@ interface ParsedArena {
708
733
  matchupId: string;
709
734
  modelId?: string;
710
735
  slot?: string;
711
- slotSeed?: string;
712
- variant?: string;
713
736
  }
714
737
 
715
738
  /** Parse a stored response's `metadata.arena` (JSON string or dict). */
@@ -728,16 +751,12 @@ function parseArenaMeta(resp: StoredResponse): ParsedArena | null {
728
751
  matchup_id?: unknown;
729
752
  model_id?: unknown;
730
753
  slot?: unknown;
731
- slot_seed?: unknown;
732
- variant?: unknown;
733
754
  };
734
755
  if (typeof a.matchup_id !== 'string') return null;
735
756
  return {
736
757
  matchupId: a.matchup_id,
737
758
  modelId: typeof a.model_id === 'string' ? a.model_id : undefined,
738
759
  slot: typeof a.slot === 'string' ? a.slot : undefined,
739
- slotSeed: typeof a.slot_seed === 'string' ? a.slot_seed : undefined,
740
- variant: typeof a.variant === 'string' ? a.variant : undefined,
741
760
  };
742
761
  }
743
762
 
@@ -749,18 +768,17 @@ function parseArenaMeta(resp: StoredResponse): ParsedArena | null {
749
768
  * collapses those duplicates so reload matches the live shape (one prompt, N
750
769
  * lanes) that {@link projectActivePath} renders.
751
770
  *
752
- * Only pairs still present as ≥2 responses are folded: once a comparison is
753
- * voted-and-continued the backend drops the loser (Decision 7-Discard), so a
754
- * single surviving response is left as an ordinary linear turn. `arenaWinners`
755
- * (matchup id → winning response id) marks the resolved winner so the reloaded
756
- * comparison renders revealed rather than blind.
771
+ * Only pairs still present as ≥2 responses are folded, which now means only an
772
+ * unresolved (pending) pair: the backend collapses a resolved matchup to its
773
+ * winning branch server-side, so a resolved pair arrives as a single response
774
+ * and is left as an ordinary linear turn. A folded pending pair renders blind
775
+ * (no winner marked) until the user votes.
757
776
  *
758
777
  * Returns the (possibly updated) root id. Best-effort per group.
759
778
  */
760
779
  function collapseArenaComparisons(
761
780
  nodes: Record<string, ResponseTreeMessage>,
762
781
  responses: StoredResponse[],
763
- arenaWinners: Record<string, string>,
764
782
  rootMessageId: string | null,
765
783
  userMessageByResponse: Map<string, string>,
766
784
  ): string | null {
@@ -770,18 +788,12 @@ function collapseArenaComparisons(
770
788
  };
771
789
 
772
790
  let root = rootMessageId;
773
- for (const [matchupId, group] of groupResponsesByMatchup(responses)) {
774
- // Fewer than two survivors is no comparison: a lone response left after a
775
- // vote-and-continue (7-Discard) stays an ordinary linear turn.
791
+ for (const [, group] of groupResponsesByMatchup(responses)) {
792
+ // Fewer than two survivors is no comparison: a resolved matchup is already
793
+ // collapsed to its winner server-side, so it arrives as a lone response.
776
794
  if (group.length < 2) continue;
777
795
  try {
778
- root = foldArenaGroup(
779
- nodes,
780
- group,
781
- arenaWinners[matchupId],
782
- userNodeFor,
783
- root,
784
- );
796
+ root = foldArenaGroup(nodes, group, userNodeFor, root);
785
797
  } catch {
786
798
  // Leave this group as-is on any structural surprise.
787
799
  }
@@ -831,7 +843,12 @@ function stampLaneAssistant(
831
843
  const meta = parseArenaMeta(resp);
832
844
  const assistant = nodes[getAssistantNodeId(resp)];
833
845
  if (assistant && meta) {
834
- assistant.metadata.arena = { modelId: meta.modelId, slot: meta.slot };
846
+ // A folded pair is always still pending (resolved matchups arrive collapsed
847
+ // server-side), so it renders BLIND until the user votes: keep only `slot`
848
+ // for column order and drop any model label so the lane shows "Response
849
+ // A/B", not the model name. The vote response reveals the real names.
850
+ assistant.metadata.arena = { slot: meta.slot };
851
+ delete assistant.metadata.model;
835
852
  }
836
853
  }
837
854
 
@@ -886,23 +903,6 @@ function activateForkNode(
886
903
  return root;
887
904
  }
888
905
 
889
- // Reveal the recorded winner lane: mark it and make it the active child. No-op
890
- // when no winner is recorded or its assistant is not among the lanes.
891
- function applyArenaWinner(
892
- canonicalUser: ResponseTreeMessage,
893
- group: StoredResponse[],
894
- winnerRespId: string | undefined,
895
- ): void {
896
- if (!winnerRespId) return;
897
- const winnerResp = group.find((r) => r.id === winnerRespId);
898
- if (!winnerResp) return;
899
- const winnerAssistantId = getAssistantNodeId(winnerResp);
900
- const idx = canonicalUser.childrenIds.indexOf(winnerAssistantId);
901
- if (idx === -1) return;
902
- canonicalUser.comparisonWinnerId = winnerAssistantId;
903
- canonicalUser.activeChildIndex = idx;
904
- }
905
-
906
906
  // Fold one matchup's sibling responses onto a single comparison node: the first
907
907
  // lane's user turn becomes the shared fork parent, every lane's assistant becomes
908
908
  // a child, and the duplicate echoed-user turns are dropped. The first lane's
@@ -911,7 +911,6 @@ function applyArenaWinner(
911
911
  function foldArenaGroup(
912
912
  nodes: Record<string, ResponseTreeMessage>,
913
913
  group: StoredResponse[],
914
- winnerRespId: string | undefined,
915
914
  userNodeFor: (responseId: string) => ResponseTreeMessage | undefined,
916
915
  root: string | null,
917
916
  ): string | null {
@@ -921,15 +920,11 @@ function foldArenaGroup(
921
920
  if (!canonicalUser) return root;
922
921
  const sharedParentId = canonicalUser.parentId;
923
922
 
924
- // Stamp matchup context on the fork parent so a reloaded comparison can be
925
- // voted on (the host reconstructs the preference payload from here).
923
+ // Stamp the matchup id on the fork parent so a reloaded comparison can be
924
+ // voted on (the host builds the vote payload from `matchup_id`).
926
925
  const forkMeta = parseArenaMeta(first);
927
926
  if (forkMeta) {
928
- canonicalUser.metadata.arena = {
929
- matchupId: forkMeta.matchupId,
930
- slotSeed: forkMeta.slotSeed,
931
- variant: forkMeta.variant,
932
- };
927
+ canonicalUser.metadata.arena = { matchupId: forkMeta.matchupId };
933
928
  }
934
929
 
935
930
  let newRoot = root;
@@ -955,6 +950,5 @@ function foldArenaGroup(
955
950
 
956
951
  canonicalUser.comparing = true;
957
952
  newRoot = activateForkNode(nodes, canonicalUser, sharedParentId, newRoot);
958
- applyArenaWinner(canonicalUser, group, winnerRespId);
959
953
  return newRoot;
960
954
  }