@jini-ai/chat 0.5.6 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/ag-ui/entry.js +2 -0
- package/dist/core/assistant-client/durable-run-subscription.d.ts +4 -1
- package/dist/core/assistant-client/durable-run-subscription.js +13 -4
- package/dist/core/durable-projection.d.ts +3 -1
- package/dist/core/durable-projection.js +40 -7
- package/dist/core/events.d.ts +3 -0
- package/dist/core/history-tool-metadata.d.ts +23 -0
- package/dist/core/history-tool-metadata.js +13 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.js +4 -0
- package/dist/core/persistence/title.d.ts +24 -0
- package/dist/core/persistence/title.js +60 -9
- package/dist/core/run-activity.d.ts +15 -2
- package/dist/core/run-activity.js +6 -4
- package/dist/core/run-events/entry.d.ts +12 -1
- package/dist/core/run-events/entry.js +19 -6
- package/dist/core/tool-call-detail.d.ts +51 -0
- package/dist/core/tool-call-detail.js +67 -0
- package/dist/core/turn-usage.d.ts +50 -0
- package/dist/core/turn-usage.js +114 -0
- package/dist/core/usage-format.d.ts +10 -0
- package/dist/core/usage-format.js +15 -0
- package/dist/embed-widget/browser/lazy-loader.d.ts +34 -0
- package/dist/embed-widget/browser/lazy-loader.js +116 -0
- package/dist/embed-widget/react/dialog.hooks.d.ts +28 -0
- package/dist/embed-widget/react/dialog.hooks.js +54 -0
- package/dist/embed-widget/react/embed.d.ts +1 -0
- package/dist/embed-widget/react/embed.js +5 -3
- package/dist/embed-widget/react/header.d.ts +3 -1
- package/dist/embed-widget/react/header.hooks.d.ts +13 -0
- package/dist/embed-widget/react/header.hooks.js +32 -0
- package/dist/embed-widget/react/header.js +4 -14
- package/dist/embed-widget/vanilla/index.d.ts +63 -0
- package/dist/embed-widget/vanilla/index.js +319 -0
- package/dist/embed-widget/vanilla/state.d.ts +48 -0
- package/dist/embed-widget/vanilla/state.js +120 -0
- package/dist/embed-widget/vanilla/style.css +29 -0
- package/dist/react/chat-pane.d.ts +2 -2
- package/dist/react/chat-pane.js +1 -1
- package/dist/react/components/A2uiSurfaceCard.d.ts +5 -1
- package/dist/react/components/A2uiSurfaceCard.js +9 -9
- package/dist/react/components/AttachmentPreviewModal.hooks.d.ts +7 -0
- package/dist/react/components/AttachmentPreviewModal.hooks.js +1 -1
- package/dist/react/components/ChatFab.d.ts +4 -1
- package/dist/react/components/ChatFab.js +2 -2
- package/dist/react/components/Composer.d.ts +2 -0
- package/dist/react/components/Composer.js +5 -2
- package/dist/react/components/ConversationList.d.ts +8 -1
- package/dist/react/components/ConversationList.hooks.d.ts +18 -0
- package/dist/react/components/ConversationList.hooks.js +25 -0
- package/dist/react/components/ConversationList.js +12 -5
- package/dist/react/components/ConversationList.rules.d.ts +25 -0
- package/dist/react/components/ConversationList.rules.js +19 -0
- package/dist/react/components/Markdown.js +6 -6
- package/dist/react/components/McpUiSurfaceCard.d.ts +1 -1
- package/dist/react/components/McpUiSurfaceCard.js +8 -4
- package/dist/react/components/MessageList.d.ts +8 -13
- package/dist/react/components/MessageList.hooks.d.ts +4 -0
- package/dist/react/components/MessageList.hooks.js +6 -1
- package/dist/react/components/MessageList.js +23 -4
- package/dist/react/components/MessageRow.d.ts +23 -1
- package/dist/react/components/MessageRow.js +61 -36
- package/dist/react/components/MessageRow.usage.d.ts +48 -0
- package/dist/react/components/MessageRow.usage.js +47 -0
- package/dist/react/components/MidRunUserMessage.d.ts +17 -0
- package/dist/react/components/MidRunUserMessage.js +41 -0
- package/dist/react/components/SentAttachment.d.ts +19 -0
- package/dist/react/components/SentAttachment.hooks.d.ts +44 -0
- package/dist/react/components/SentAttachment.hooks.js +56 -0
- package/dist/react/components/SentAttachment.js +14 -0
- package/dist/react/components/ToolCallGroup.d.ts +12 -0
- package/dist/react/components/ToolCallGroup.hooks.d.ts +20 -0
- package/dist/react/components/ToolCallGroup.hooks.js +23 -0
- package/dist/react/components/ToolCallGroup.js +13 -0
- package/dist/react/components/ToolCard.js +41 -22
- package/dist/react/components/mcp-ui-surface-state.d.ts +21 -0
- package/dist/react/components/mcp-ui-surface-state.js +26 -0
- package/dist/react/ext-event-renderer-registry.d.ts +7 -0
- package/dist/react/features/chat-pane/components/ChatPane.d.ts +1 -1
- package/dist/react/features/chat-pane/components/ChatPane.js +20 -7
- package/dist/react/features/chat-pane/create-mid-run-message-poster.d.ts +44 -0
- package/dist/react/features/chat-pane/create-mid-run-message-poster.js +69 -0
- package/dist/react/features/chat-pane/hooks/useChatPane.hooks.d.ts +4 -1
- package/dist/react/features/chat-pane/hooks/useChatPane.hooks.js +65 -10
- package/dist/react/features/chat-pane/hooks/useChatPaneNewTabLinks.hooks.d.ts +25 -0
- package/dist/react/features/chat-pane/hooks/useChatPaneNewTabLinks.hooks.js +70 -0
- package/dist/react/features/chat-pane/hooks/useChatPaneRuntimeInventory.hooks.js +4 -0
- package/dist/react/features/chat-pane/hooks/useChatPaneSuggestion.hooks.d.ts +9 -0
- package/dist/react/features/chat-pane/hooks/useChatPaneSuggestion.hooks.js +11 -0
- package/dist/react/features/chat-pane/hooks/useChatPaneSurface.hooks.d.ts +17 -0
- package/dist/react/features/chat-pane/hooks/useChatPaneSurface.hooks.js +15 -0
- package/dist/react/features/chat-pane/index.d.ts +2 -1
- package/dist/react/features/chat-pane/index.js +1 -0
- package/dist/react/features/chat-pane/rules.d.ts +27 -0
- package/dist/react/features/chat-pane/rules.js +32 -0
- package/dist/react/features/chat-pane/styles.d.ts +1 -1
- package/dist/react/features/chat-pane/styles.js +92 -1
- package/dist/react/features/chat-pane/types.d.ts +39 -1
- package/dist/react/hooks/composer-draft-cache.d.ts +15 -0
- package/dist/react/hooks/composer-draft-cache.js +20 -0
- package/dist/react/hooks/useAnsweredCards.d.ts +20 -0
- package/dist/react/hooks/useAnsweredCards.js +23 -0
- package/dist/react/hooks/useComposer.d.ts +14 -0
- package/dist/react/hooks/useComposer.js +78 -6
- package/dist/react/hooks/useConversation.d.ts +8 -0
- package/dist/react/hooks/useConversation.js +34 -0
- package/dist/react/hooks/useRunActivity.d.ts +5 -3
- package/dist/react/hooks/useRunActivity.js +4 -3
- package/dist/react/index.d.ts +8 -2
- package/dist/react/index.js +6 -1
- package/dist/react/message-blocks.d.ts +22 -3
- package/dist/react/message-blocks.js +25 -3
- package/dist/react/tool-call-display.d.ts +90 -0
- package/dist/react/tool-call-display.js +97 -0
- package/dist/server/durable-runs/recover.js +19 -11
- package/dist/server/run-finalizer/entry.js +2 -1
- package/dist/store/ports.d.ts +25 -2
- package/dist/store/runtime/durable-run-store.js +5 -2
- package/dist/store/runtime/entry.d.ts +1 -0
- package/dist/store/runtime/entry.js +1 -0
- package/dist/store/runtime/history-tools.d.ts +27 -0
- package/dist/store/runtime/history-tools.js +169 -0
- package/dist/store/runtime/run-ledger.js +5 -2
- package/dist/store/sql/store.js +52 -0
- package/dist/testing/index.d.ts +7 -0
- package/dist/testing/index.js +22 -0
- package/package.json +48 -18
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { VanillaChatControllerArgs, VanillaChatState } from './state.js';
|
|
2
|
+
export { createVanillaChatController } from './state.js';
|
|
3
|
+
export type { VanillaChatControllerArgs, VanillaChatState } from './state.js';
|
|
4
|
+
export interface VanillaChatCopy {
|
|
5
|
+
readonly title: string;
|
|
6
|
+
readonly fabLabel: string;
|
|
7
|
+
readonly placeholder: string;
|
|
8
|
+
readonly send: string;
|
|
9
|
+
readonly stop: string;
|
|
10
|
+
readonly close: string;
|
|
11
|
+
readonly reset: string;
|
|
12
|
+
readonly resetQuestion: string;
|
|
13
|
+
readonly confirm: string;
|
|
14
|
+
readonly confirmDraft?: string;
|
|
15
|
+
readonly keep: string;
|
|
16
|
+
readonly proposalGo: string;
|
|
17
|
+
readonly proposalLabel: (args: {
|
|
18
|
+
title: string;
|
|
19
|
+
}) => string;
|
|
20
|
+
readonly thinking: string;
|
|
21
|
+
readonly greeting?: string;
|
|
22
|
+
readonly suggestionsLabel?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface MountVanillaChatArgs extends Omit<VanillaChatControllerArgs, 'onChange'> {
|
|
25
|
+
readonly element: HTMLElement;
|
|
26
|
+
readonly document: Document;
|
|
27
|
+
readonly copy: VanillaChatCopy;
|
|
28
|
+
readonly suggestions?: readonly string[];
|
|
29
|
+
/** Host renderer must escape raw HTML and reject unsafe link protocols. */
|
|
30
|
+
readonly renderMarkdown: (args: {
|
|
31
|
+
content: string;
|
|
32
|
+
element: HTMLElement;
|
|
33
|
+
}) => void;
|
|
34
|
+
readonly scheduleFrame: (args: {
|
|
35
|
+
callback: () => void;
|
|
36
|
+
}) => () => void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Mounts a DOM-only chat panel. Native buttons/forms supply keyboard semantics;
|
|
40
|
+
* explicitly opened dialogs trap focus, restore the bubble on close and announce settled replies.
|
|
41
|
+
* Restored panels leave page focus alone. Streaming markdown is rendered at most once per frame.
|
|
42
|
+
* All listeners, scheduled page effects and runs belong to this mount and are disposed.
|
|
43
|
+
* Markdown is an injected host capability; no framework or icon font enters this graph.
|
|
44
|
+
*/
|
|
45
|
+
export declare function mountVanillaChat(args: MountVanillaChatArgs, options?: {
|
|
46
|
+
initialOpen?: boolean;
|
|
47
|
+
}): {
|
|
48
|
+
controller: {
|
|
49
|
+
getState(_input?: Record<string, never>, _opts?: {}): VanillaChatState;
|
|
50
|
+
setOpen({ open }: {
|
|
51
|
+
open: boolean;
|
|
52
|
+
}, _opts?: {}): void;
|
|
53
|
+
send({ text }: {
|
|
54
|
+
text: string;
|
|
55
|
+
}, _opts?: {}): Promise<boolean>;
|
|
56
|
+
acceptProposal(_input?: Record<string, never>, _opts?: {}): void;
|
|
57
|
+
cancel(_input?: Record<string, never>, _opts?: {}): void;
|
|
58
|
+
reset(_input?: Record<string, never>, _opts?: {}): void;
|
|
59
|
+
dispose(_input?: Record<string, never>, _opts?: {}): void;
|
|
60
|
+
};
|
|
61
|
+
unmount(_input?: Record<string, never>, _opts?: {}): void;
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { CHAT_BUBBLE_STYLE } from '../browser/lazy-loader.js';
|
|
2
|
+
import { createVanillaChatController } from './state.js';
|
|
3
|
+
import { isQueuedPageAction } from '../../core/browser/page-actions.js';
|
|
4
|
+
export { createVanillaChatController } from './state.js';
|
|
5
|
+
function svgIcon({ document, path }) {
|
|
6
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
7
|
+
svg.setAttribute('viewBox', '0 0 24 24');
|
|
8
|
+
svg.setAttribute('aria-hidden', 'true');
|
|
9
|
+
const shape = document.createElementNS(svg.namespaceURI, 'path');
|
|
10
|
+
shape.setAttribute('d', path);
|
|
11
|
+
shape.setAttribute('fill', 'none');
|
|
12
|
+
shape.setAttribute('stroke', 'currentColor');
|
|
13
|
+
shape.setAttribute('stroke-width', '2');
|
|
14
|
+
svg.append(shape);
|
|
15
|
+
return svg;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Mounts a DOM-only chat panel. Native buttons/forms supply keyboard semantics;
|
|
19
|
+
* explicitly opened dialogs trap focus, restore the bubble on close and announce settled replies.
|
|
20
|
+
* Restored panels leave page focus alone. Streaming markdown is rendered at most once per frame.
|
|
21
|
+
* All listeners, scheduled page effects and runs belong to this mount and are disposed.
|
|
22
|
+
* Markdown is an injected host capability; no framework or icon font enters this graph.
|
|
23
|
+
*/
|
|
24
|
+
export function mountVanillaChat(args, options = {}) {
|
|
25
|
+
const { document, element, copy } = args;
|
|
26
|
+
const node = (tag, className, text = '') => {
|
|
27
|
+
const result = document.createElement(tag);
|
|
28
|
+
result.className = className;
|
|
29
|
+
result.textContent = text;
|
|
30
|
+
return result;
|
|
31
|
+
};
|
|
32
|
+
const button = (label) => {
|
|
33
|
+
const result = node('button', 'jini-chat-vanilla__button', label);
|
|
34
|
+
result.type = 'button';
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
const shell = node('div', 'jini-chat-vanilla');
|
|
38
|
+
const fab = button('');
|
|
39
|
+
fab.className = 'jini-chat-bubble';
|
|
40
|
+
fab.setAttribute('aria-label', copy.fabLabel);
|
|
41
|
+
fab.setAttribute('aria-haspopup', 'dialog');
|
|
42
|
+
fab.append(svgIcon({ document, path: 'M4 4h16v12H9l-5 4V4z' }));
|
|
43
|
+
const panel = node('section', 'jini-chat-vanilla__panel');
|
|
44
|
+
panel.id = `jini-chat-${args.ids({})}`;
|
|
45
|
+
fab.setAttribute('aria-controls', panel.id);
|
|
46
|
+
panel.setAttribute('role', 'dialog');
|
|
47
|
+
panel.setAttribute('aria-modal', 'false');
|
|
48
|
+
panel.setAttribute('aria-label', copy.title);
|
|
49
|
+
const header = node('header', 'jini-chat-vanilla__header');
|
|
50
|
+
const title = node('strong', 'jini-chat-vanilla__title', copy.title);
|
|
51
|
+
const reset = button(copy.reset);
|
|
52
|
+
const close = button('');
|
|
53
|
+
close.setAttribute('aria-label', copy.close);
|
|
54
|
+
close.append(svgIcon({ document, path: 'M6 6l12 12M18 6L6 18' }));
|
|
55
|
+
header.append(title, reset, close);
|
|
56
|
+
const confirmation = node('div', 'jini-chat-vanilla__confirmation');
|
|
57
|
+
const confirm = button(copy.confirm);
|
|
58
|
+
confirm.classList.add('jini-chat-vanilla__discard');
|
|
59
|
+
const keep = button(copy.keep);
|
|
60
|
+
confirmation.append(node('span', '', copy.resetQuestion), confirm, keep);
|
|
61
|
+
confirmation.hidden = true;
|
|
62
|
+
const log = node('div', 'jini-chat-vanilla__messages');
|
|
63
|
+
log.setAttribute('role', 'log');
|
|
64
|
+
log.setAttribute('aria-live', 'off');
|
|
65
|
+
log.setAttribute('aria-relevant', 'additions text');
|
|
66
|
+
log.setAttribute('aria-label', copy.title);
|
|
67
|
+
log.tabIndex = 0;
|
|
68
|
+
const status = node('div', 'jini-chat-vanilla__status');
|
|
69
|
+
status.setAttribute('role', 'status');
|
|
70
|
+
const announcements = node('div', 'jini-chat-vanilla__announcements');
|
|
71
|
+
announcements.setAttribute('role', 'log');
|
|
72
|
+
announcements.setAttribute('aria-live', 'polite');
|
|
73
|
+
announcements.setAttribute('aria-relevant', 'additions');
|
|
74
|
+
announcements.setAttribute('aria-atomic', 'false');
|
|
75
|
+
const error = node('div', 'jini-chat-vanilla__error');
|
|
76
|
+
error.setAttribute('role', 'alert');
|
|
77
|
+
const proposal = node('div', 'jini-chat-vanilla__proposal');
|
|
78
|
+
const proposalText = node('span', '');
|
|
79
|
+
const go = button(copy.proposalGo);
|
|
80
|
+
proposal.append(proposalText, go);
|
|
81
|
+
const form = node('form', 'jini-chat-vanilla__composer');
|
|
82
|
+
const input = node('textarea', 'jini-chat-vanilla__input');
|
|
83
|
+
input.placeholder = copy.placeholder;
|
|
84
|
+
input.setAttribute('aria-label', copy.placeholder);
|
|
85
|
+
input.maxLength = 8000;
|
|
86
|
+
input.rows = 2;
|
|
87
|
+
const send = button(copy.send);
|
|
88
|
+
send.type = 'submit';
|
|
89
|
+
send.classList.add('jini-chat-vanilla__send');
|
|
90
|
+
send.setAttribute('aria-label', copy.send);
|
|
91
|
+
send.replaceChildren(svgIcon({ document, path: 'M5 4l15 8-15 8v-6l9-2-9-2V4z' }));
|
|
92
|
+
const stop = button(copy.stop);
|
|
93
|
+
form.append(input, send, stop);
|
|
94
|
+
const greeting = node('p', 'jini-chat-vanilla__greeting', copy.greeting);
|
|
95
|
+
const suggestions = node('div', 'jini-chat-vanilla__suggestions');
|
|
96
|
+
if (copy.suggestionsLabel)
|
|
97
|
+
suggestions.setAttribute('aria-label', copy.suggestionsLabel);
|
|
98
|
+
const suggestionButtons = (args.suggestions ?? []).map(text => button(text));
|
|
99
|
+
suggestions.append(...suggestionButtons);
|
|
100
|
+
log.append(greeting, suggestions);
|
|
101
|
+
panel.append(header, confirmation, log, status, announcements, error, proposal, form);
|
|
102
|
+
const bubbleStyle = node('style', '', CHAT_BUBBLE_STYLE);
|
|
103
|
+
shell.append(bubbleStyle, fab, panel);
|
|
104
|
+
element.replaceChildren(shell);
|
|
105
|
+
const rows = new Map();
|
|
106
|
+
let wasOpen = false;
|
|
107
|
+
let initialized = false;
|
|
108
|
+
const liveReplies = new Set();
|
|
109
|
+
const renderChrome = ({ state }) => {
|
|
110
|
+
panel.hidden = !state.open;
|
|
111
|
+
panel.setAttribute('aria-modal', String(state.open));
|
|
112
|
+
fab.setAttribute('aria-expanded', String(state.open));
|
|
113
|
+
fab.querySelector('path')?.setAttribute('d', state.open ? 'M6 6l12 12M18 6L6 18' : 'M4 4h16v12H9l-5 4V4z');
|
|
114
|
+
greeting.hidden = !copy.greeting || state.messages.length > 0;
|
|
115
|
+
suggestions.hidden = suggestionButtons.length === 0 || state.messages.length > 0;
|
|
116
|
+
suggestionButtons.forEach(button => { button.disabled = state.busy; });
|
|
117
|
+
error.textContent = state.error ?? '';
|
|
118
|
+
error.hidden = !state.error;
|
|
119
|
+
status.textContent = state.busy ? copy.thinking : '';
|
|
120
|
+
send.disabled = state.busy || !input.value.trim();
|
|
121
|
+
input.disabled = state.busy;
|
|
122
|
+
stop.hidden = !state.busy;
|
|
123
|
+
proposal.hidden = state.proposal === null;
|
|
124
|
+
proposalText.textContent = state.proposal ? copy.proposalLabel({ title: state.proposal.navigate.target.title }) : '';
|
|
125
|
+
};
|
|
126
|
+
const renderRows = ({ state }) => {
|
|
127
|
+
const pinned = log.scrollHeight - log.scrollTop - log.clientHeight < 80;
|
|
128
|
+
const ids = new Set(state.messages.map(message => message.id));
|
|
129
|
+
for (const [id, row] of rows)
|
|
130
|
+
if (!ids.has(id)) {
|
|
131
|
+
row.element.remove();
|
|
132
|
+
rows.delete(id);
|
|
133
|
+
}
|
|
134
|
+
for (const message of state.messages) {
|
|
135
|
+
let row = rows.get(message.id);
|
|
136
|
+
if (!row) {
|
|
137
|
+
row = { element: node('div', `jini-chat-vanilla__message jini-chat-vanilla__message--${message.role}`), content: '\0' };
|
|
138
|
+
rows.set(message.id, row);
|
|
139
|
+
log.append(row.element);
|
|
140
|
+
}
|
|
141
|
+
if (row.content !== message.content) {
|
|
142
|
+
if (message.role === 'user')
|
|
143
|
+
row.element.textContent = message.content;
|
|
144
|
+
else
|
|
145
|
+
args.renderMarkdown({ content: message.content, element: row.element });
|
|
146
|
+
row.content = message.content;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// A dedicated additions-only region announces each LIVE settled reply once. Markdown rows
|
|
150
|
+
// may be rebuilt while streaming, but restored transcripts and old text stay silent.
|
|
151
|
+
for (const message of state.messages) {
|
|
152
|
+
if (message.role !== 'assistant' || message.runStatus === 'running' || !liveReplies.delete(message.id))
|
|
153
|
+
continue;
|
|
154
|
+
const text = rows.get(message.id)?.element.textContent;
|
|
155
|
+
if (text) {
|
|
156
|
+
announcements.append(node('span', '', text));
|
|
157
|
+
// Bound the additions-only live region without replaying earlier replies.
|
|
158
|
+
while (announcements.childElementCount > 2)
|
|
159
|
+
announcements.firstElementChild.remove();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (state.messages.length === 0)
|
|
163
|
+
announcements.replaceChildren();
|
|
164
|
+
if (pinned)
|
|
165
|
+
log.scrollTop = log.scrollHeight;
|
|
166
|
+
};
|
|
167
|
+
const renderFocus = ({ state, composerHadFocus, stopHadFocus, panelHadFocus }) => {
|
|
168
|
+
if (state.open && !wasOpen && initialized) {
|
|
169
|
+
if (state.busy)
|
|
170
|
+
close.focus();
|
|
171
|
+
else
|
|
172
|
+
input.focus();
|
|
173
|
+
}
|
|
174
|
+
else if (state.open && state.busy && composerHadFocus)
|
|
175
|
+
stop.focus();
|
|
176
|
+
else if (state.open && !state.busy && stopHadFocus)
|
|
177
|
+
input.focus();
|
|
178
|
+
if (!state.open && wasOpen) {
|
|
179
|
+
confirmation.hidden = true;
|
|
180
|
+
panel.setAttribute('aria-modal', 'false');
|
|
181
|
+
if (panelHadFocus)
|
|
182
|
+
fab.focus();
|
|
183
|
+
}
|
|
184
|
+
wasOpen = state.open;
|
|
185
|
+
};
|
|
186
|
+
let latestState;
|
|
187
|
+
let framePending = false;
|
|
188
|
+
let cancelRenderFrame = () => { };
|
|
189
|
+
const render = ({ state }) => {
|
|
190
|
+
latestState = state;
|
|
191
|
+
const panelHadFocus = panel.contains(document.activeElement);
|
|
192
|
+
const composerHadFocus = document.activeElement === input;
|
|
193
|
+
const stopHadFocus = document.activeElement === stop;
|
|
194
|
+
renderChrome({ state });
|
|
195
|
+
renderFocus({ state, composerHadFocus, stopHadFocus, panelHadFocus });
|
|
196
|
+
if (initialized && state.busy) {
|
|
197
|
+
for (const message of state.messages)
|
|
198
|
+
if (message.role === 'assistant' && message.runStatus === 'running')
|
|
199
|
+
liveReplies.add(message.id);
|
|
200
|
+
if (framePending)
|
|
201
|
+
return;
|
|
202
|
+
framePending = true;
|
|
203
|
+
cancelRenderFrame = args.scheduleFrame({ callback: () => {
|
|
204
|
+
framePending = false;
|
|
205
|
+
renderRows({ state: latestState });
|
|
206
|
+
} });
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
cancelRenderFrame();
|
|
210
|
+
framePending = false;
|
|
211
|
+
renderRows({ state });
|
|
212
|
+
};
|
|
213
|
+
const controller = createVanillaChatController({ ...args, onChange: render });
|
|
214
|
+
const listeners = [];
|
|
215
|
+
const listen = (target, type, handler) => {
|
|
216
|
+
target.addEventListener(type, handler);
|
|
217
|
+
listeners.push(() => target.removeEventListener(type, handler));
|
|
218
|
+
};
|
|
219
|
+
suggestionButtons.forEach(button => listen(button, 'click', () => {
|
|
220
|
+
input.value = button.textContent ?? '';
|
|
221
|
+
renderChrome({ state: controller.getState({}) });
|
|
222
|
+
input.focus();
|
|
223
|
+
}));
|
|
224
|
+
listen(input, 'input', () => renderChrome({ state: controller.getState({}) }));
|
|
225
|
+
listen(fab, 'click', () => controller.setOpen({ open: !controller.getState({}).open }));
|
|
226
|
+
listen(close, 'click', () => controller.setOpen({ open: false }));
|
|
227
|
+
listen(reset, 'click', () => {
|
|
228
|
+
if (controller.getState({}).messages.length === 0 && input.value.length === 0) {
|
|
229
|
+
controller.reset({});
|
|
230
|
+
input.focus();
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
confirm.textContent = controller.getState({}).messages.length === 0 ? copy.confirmDraft ?? copy.confirm : copy.confirm;
|
|
234
|
+
confirmation.hidden = false;
|
|
235
|
+
keep.focus();
|
|
236
|
+
});
|
|
237
|
+
listen(keep, 'click', () => { confirmation.hidden = true; reset.focus(); });
|
|
238
|
+
listen(confirm, 'click', () => { confirmation.hidden = true; input.value = ''; controller.reset({}); input.focus(); });
|
|
239
|
+
listen(go, 'click', () => controller.acceptProposal({}));
|
|
240
|
+
listen(stop, 'click', () => controller.cancel({}));
|
|
241
|
+
listen(form, 'submit', event => {
|
|
242
|
+
event.preventDefault();
|
|
243
|
+
const text = input.value;
|
|
244
|
+
if (!text.trim() || controller.getState({}).busy)
|
|
245
|
+
return;
|
|
246
|
+
input.value = '';
|
|
247
|
+
void controller.send({ text }).then(() => {
|
|
248
|
+
const state = controller.getState({});
|
|
249
|
+
if (state.open && !state.busy && panel.contains(document.activeElement))
|
|
250
|
+
input.focus();
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
listen(input, 'keydown', event => {
|
|
254
|
+
const key = event;
|
|
255
|
+
if (key.key === 'Enter' && !key.shiftKey && !key.isComposing) {
|
|
256
|
+
key.preventDefault();
|
|
257
|
+
form.requestSubmit();
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
listen(document, 'keydown', event => {
|
|
261
|
+
if (!controller.getState({}).open || !panel.contains(document.activeElement))
|
|
262
|
+
return;
|
|
263
|
+
const key = event;
|
|
264
|
+
if (key.key === 'Escape') {
|
|
265
|
+
key.preventDefault();
|
|
266
|
+
if (!confirmation.hidden) {
|
|
267
|
+
confirmation.hidden = true;
|
|
268
|
+
reset.focus();
|
|
269
|
+
}
|
|
270
|
+
else
|
|
271
|
+
controller.setOpen({ open: false });
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (key.key !== 'Tab')
|
|
275
|
+
return;
|
|
276
|
+
const focusable = Array.from(panel.querySelectorAll('button:not(:disabled), textarea:not(:disabled), a[href], [tabindex="0"]'))
|
|
277
|
+
.filter(candidate => !candidate.closest('[hidden]'));
|
|
278
|
+
const first = focusable[0];
|
|
279
|
+
const last = focusable.at(-1);
|
|
280
|
+
if (key.shiftKey && (document.activeElement === first || !panel.contains(document.activeElement))) {
|
|
281
|
+
key.preventDefault();
|
|
282
|
+
last?.focus();
|
|
283
|
+
}
|
|
284
|
+
else if (!key.shiftKey && (document.activeElement === last || !panel.contains(document.activeElement))) {
|
|
285
|
+
key.preventDefault();
|
|
286
|
+
first?.focus();
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
listen(element, 'jini-chat-open', () => {
|
|
290
|
+
controller.setOpen({ open: true });
|
|
291
|
+
if (controller.getState({}).busy)
|
|
292
|
+
close.focus();
|
|
293
|
+
else
|
|
294
|
+
input.focus();
|
|
295
|
+
});
|
|
296
|
+
const queued = { value: args.session.drain({}) };
|
|
297
|
+
let cancelFrame = () => { };
|
|
298
|
+
if (isQueuedPageAction(queued) && queued.value.type !== 'navigate') {
|
|
299
|
+
const action = queued.value;
|
|
300
|
+
cancelFrame = args.scheduleFrame({ callback: () => { args.pageActions.execute({ action }); } });
|
|
301
|
+
}
|
|
302
|
+
controller.setOpen({ open: options.initialOpen ?? controller.getState({}).open });
|
|
303
|
+
initialized = true;
|
|
304
|
+
element.dataset.chatMounted = 'true';
|
|
305
|
+
element.dispatchEvent(new (document.defaultView?.Event ?? Event)('jini-chat-mounted'));
|
|
306
|
+
return {
|
|
307
|
+
controller,
|
|
308
|
+
unmount(_input = {}, _opts = {}) {
|
|
309
|
+
listeners.forEach(dispose => dispose());
|
|
310
|
+
cancelFrame();
|
|
311
|
+
cancelRenderFrame();
|
|
312
|
+
delete element.dataset.chatMounted;
|
|
313
|
+
controller.dispose({});
|
|
314
|
+
args.pageActions.clearHighlight({});
|
|
315
|
+
shell.remove();
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ChatMessage } from '../../core/messages.js';
|
|
2
|
+
import type { ChatTransport } from '../../core/transport.js';
|
|
3
|
+
import type { BrowserSessionStore } from '../browser/session-store.js';
|
|
4
|
+
import type { PageActionPort, NavigateAction, NonNavigateAction } from '../../core/browser/page-actions.js';
|
|
5
|
+
export interface VanillaChatState {
|
|
6
|
+
readonly open: boolean;
|
|
7
|
+
readonly messages: ChatMessage[];
|
|
8
|
+
readonly busy: boolean;
|
|
9
|
+
readonly error: string | null;
|
|
10
|
+
readonly proposal: {
|
|
11
|
+
navigate: NavigateAction;
|
|
12
|
+
bundled: NonNavigateAction | null;
|
|
13
|
+
} | null;
|
|
14
|
+
}
|
|
15
|
+
export interface VanillaChatControllerArgs {
|
|
16
|
+
readonly transport: ChatTransport;
|
|
17
|
+
readonly session: BrowserSessionStore;
|
|
18
|
+
readonly pageActions: PageActionPort;
|
|
19
|
+
readonly directiveEventName: string;
|
|
20
|
+
readonly agentId: string;
|
|
21
|
+
readonly ids: (args: Record<string, never>) => string;
|
|
22
|
+
readonly createAbortController: (args: Record<string, never>) => AbortController;
|
|
23
|
+
readonly onChange: (args: {
|
|
24
|
+
state: VanillaChatState;
|
|
25
|
+
}) => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Framework-free visitor state over the existing transport/session/page-action owners.
|
|
29
|
+
* Restored messages never replay directives. Only a successful live settlement can act;
|
|
30
|
+
* persistence and queued effects finish synchronously before navigation tears down the page.
|
|
31
|
+
* Reset invalidates callbacks before aborting, preventing late chunks from reviving a thread.
|
|
32
|
+
* @complexity O(retained transcript + reply events + reply characters) per update; storage writes
|
|
33
|
+
* occur only on settle/open/reset/navigation, never per streamed chunk. Session bounds persisted bytes.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createVanillaChatController(args: VanillaChatControllerArgs, _options?: {}): {
|
|
36
|
+
getState(_input?: Record<string, never>, _opts?: {}): VanillaChatState;
|
|
37
|
+
setOpen({ open }: {
|
|
38
|
+
open: boolean;
|
|
39
|
+
}, _opts?: {}): void;
|
|
40
|
+
send({ text }: {
|
|
41
|
+
text: string;
|
|
42
|
+
}, _opts?: {}): Promise<boolean>;
|
|
43
|
+
acceptProposal(_input?: Record<string, never>, _opts?: {}): void;
|
|
44
|
+
cancel(_input?: Record<string, never>, _opts?: {}): void;
|
|
45
|
+
reset(_input?: Record<string, never>, _opts?: {}): void;
|
|
46
|
+
dispose(_input?: Record<string, never>, _opts?: {}): void;
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { assistantContentFromEvents } from '../../core/assistant-content.js';
|
|
2
|
+
import { extractPageActions, splitPageActions } from '../../core/browser/page-actions.js';
|
|
3
|
+
/**
|
|
4
|
+
* Framework-free visitor state over the existing transport/session/page-action owners.
|
|
5
|
+
* Restored messages never replay directives. Only a successful live settlement can act;
|
|
6
|
+
* persistence and queued effects finish synchronously before navigation tears down the page.
|
|
7
|
+
* Reset invalidates callbacks before aborting, preventing late chunks from reviving a thread.
|
|
8
|
+
* @complexity O(retained transcript + reply events + reply characters) per update; storage writes
|
|
9
|
+
* occur only on settle/open/reset/navigation, never per streamed chunk. Session bounds persisted bytes.
|
|
10
|
+
*/
|
|
11
|
+
export function createVanillaChatController(args, _options = {}) {
|
|
12
|
+
const initial = args.session.load({});
|
|
13
|
+
let state = { ...initial, busy: false, error: null, proposal: null };
|
|
14
|
+
let generation = 0;
|
|
15
|
+
let active = null;
|
|
16
|
+
const publish = ({ persist = true } = {}) => {
|
|
17
|
+
if (persist)
|
|
18
|
+
args.session.save({ state: { open: state.open, messages: state.messages } });
|
|
19
|
+
args.onChange({ state });
|
|
20
|
+
};
|
|
21
|
+
const go = (proposal) => {
|
|
22
|
+
if (!args.pageActions.allows({ action: proposal.navigate }))
|
|
23
|
+
return;
|
|
24
|
+
if (proposal.bundled && args.pageActions.allows({ action: proposal.bundled }))
|
|
25
|
+
args.session.enqueue({ action: proposal.bundled });
|
|
26
|
+
state = { ...state, proposal: null };
|
|
27
|
+
publish();
|
|
28
|
+
args.pageActions.navigate({ action: proposal.navigate });
|
|
29
|
+
};
|
|
30
|
+
const settleActions = (events) => {
|
|
31
|
+
const actions = extractPageActions({ events, directiveEventName: args.directiveEventName })
|
|
32
|
+
.filter(action => args.pageActions.allows({ action }));
|
|
33
|
+
const { navigate, other } = splitPageActions({ actions });
|
|
34
|
+
if (!navigate) {
|
|
35
|
+
if (other)
|
|
36
|
+
args.pageActions.execute({ action: other });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const proposal = { navigate, bundled: other };
|
|
40
|
+
if (navigate.auto)
|
|
41
|
+
go(proposal);
|
|
42
|
+
else {
|
|
43
|
+
state = { ...state, proposal };
|
|
44
|
+
publish();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
getState(_input = {}, _opts = {}) { return state; },
|
|
49
|
+
setOpen({ open }, _opts = {}) { state = { ...state, open }; publish(); },
|
|
50
|
+
async send({ text }, _opts = {}) {
|
|
51
|
+
const content = text.trim();
|
|
52
|
+
if (!content || state.busy)
|
|
53
|
+
return false;
|
|
54
|
+
const token = ++generation;
|
|
55
|
+
const abort = args.createAbortController({});
|
|
56
|
+
active = abort;
|
|
57
|
+
const history = [...state.messages, { id: args.ids({}), role: 'user', content }];
|
|
58
|
+
const reply = { id: args.ids({}), role: 'assistant', content: '', events: [], runStatus: 'running' };
|
|
59
|
+
state = { ...state, messages: [...history, reply], busy: true, error: null, proposal: null };
|
|
60
|
+
publish({ persist: false });
|
|
61
|
+
let events = [];
|
|
62
|
+
let failed = false;
|
|
63
|
+
let settled = false;
|
|
64
|
+
const current = () => token === generation && !settled;
|
|
65
|
+
const updateReply = (next, { persist = false } = {}) => {
|
|
66
|
+
state = { ...state, messages: state.messages.map(message => message.id === reply.id ? next : message) };
|
|
67
|
+
publish({ persist });
|
|
68
|
+
};
|
|
69
|
+
const fail = (error) => {
|
|
70
|
+
if (!current())
|
|
71
|
+
return;
|
|
72
|
+
failed = true;
|
|
73
|
+
state = { ...state, error: error.message };
|
|
74
|
+
updateReply({ ...reply, content: assistantContentFromEvents({ events }), events: [...events], runStatus: 'failed' });
|
|
75
|
+
};
|
|
76
|
+
const done = (final) => {
|
|
77
|
+
if (!current())
|
|
78
|
+
return;
|
|
79
|
+
settled = true;
|
|
80
|
+
active = null;
|
|
81
|
+
events = final;
|
|
82
|
+
state = { ...state, busy: false };
|
|
83
|
+
updateReply({ ...reply, content: assistantContentFromEvents({ events }), events: [...events],
|
|
84
|
+
runStatus: failed ? 'failed' : abort.signal.aborted ? 'canceled' : 'succeeded' }, { persist: true });
|
|
85
|
+
if (!failed && !abort.signal.aborted)
|
|
86
|
+
settleActions(events);
|
|
87
|
+
};
|
|
88
|
+
try {
|
|
89
|
+
await args.transport.startRun({ history, agentId: args.agentId, assistantMessageId: reply.id, signal: abort.signal }, {
|
|
90
|
+
onEvent(event) {
|
|
91
|
+
if (!current())
|
|
92
|
+
return;
|
|
93
|
+
events = [...events, event];
|
|
94
|
+
updateReply({ ...reply, content: assistantContentFromEvents({ events }), events: [...events], runStatus: failed ? 'failed' : 'running' });
|
|
95
|
+
},
|
|
96
|
+
onError: fail,
|
|
97
|
+
onDone: done,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
fail(error instanceof Error ? error : new Error(String(error)));
|
|
102
|
+
done(events);
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
},
|
|
106
|
+
acceptProposal(_input = {}, _opts = {}) { if (state.proposal)
|
|
107
|
+
go(state.proposal); },
|
|
108
|
+
cancel(_input = {}, _opts = {}) { active?.abort(); },
|
|
109
|
+
reset(_input = {}, _opts = {}) {
|
|
110
|
+
generation += 1;
|
|
111
|
+
active?.abort();
|
|
112
|
+
active = null;
|
|
113
|
+
args.session.clear({});
|
|
114
|
+
state = { open: state.open, messages: [], busy: false, error: null, proposal: null };
|
|
115
|
+
publish();
|
|
116
|
+
},
|
|
117
|
+
dispose(_input = {}, _opts = {}) { generation += 1; active?.abort(); active = null; },
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
.jini-chat-bubble{position:fixed;right:var(--jini-embed-right,24px);bottom:24px;width:56px;height:56px;border:0;border-radius:50%;background:var(--jini-chat-accent,var(--color-primary,#2563eb));color:var(--jini-chat-accent-text,#fff);box-shadow:0 4px 16px #0003;cursor:pointer;z-index:var(--jini-embed-z-index,1000);display:grid;place-items:center}
|
|
2
|
+
.jini-chat-bubble[hidden]{display:none!important}
|
|
3
|
+
.jini-chat-bubble svg{width:24px;height:24px}
|
|
4
|
+
.jini-chat-bubble:focus-visible{outline:3px solid var(--jini-chat-accent,#2563eb);outline-offset:3px}
|
|
5
|
+
@media(max-width:480px){.jini-chat-bubble{right:16px;bottom:16px}}
|
|
6
|
+
.jini-chat-bubble[aria-busy="true"]{cursor:progress;opacity:.65}
|
|
7
|
+
.jini-chat-bubble[data-load-failed="true"]{outline:2px solid var(--jini-chat-error,#b91c1c);outline-offset:3px}
|
|
8
|
+
.jini-chat-vanilla [hidden]{display:none!important}
|
|
9
|
+
.jini-chat-vanilla svg{width:24px;height:24px}
|
|
10
|
+
.jini-chat-vanilla :focus-visible{outline:3px solid var(--jini-chat-accent,#2563eb);outline-offset:3px}
|
|
11
|
+
.jini-chat-vanilla{font:14px/1.5 var(--font-body,system-ui,sans-serif);color:var(--jini-chat-text,var(--color-text,CanvasText))}
|
|
12
|
+
.jini-chat-vanilla__panel{position:fixed;right:var(--jini-embed-right,24px);bottom:88px;width:min(var(--jini-embed-width,440px),calc(100vw - 32px));height:min(var(--jini-embed-height,620px),calc(100dvh - 120px));z-index:var(--jini-embed-z-index,1000);display:flex;flex-direction:column;background:var(--jini-chat-background,var(--color-background,Canvas));border:1px solid var(--jini-chat-border,#767676);border-radius:16px;box-shadow:0 12px 48px #0003;overflow:hidden}
|
|
13
|
+
.jini-chat-vanilla__header,.jini-chat-vanilla__composer,.jini-chat-vanilla__confirmation,.jini-chat-vanilla__proposal{display:flex;align-items:center;gap:8px;padding:12px;border-bottom:1px solid var(--jini-chat-border,#767676)}
|
|
14
|
+
.jini-chat-vanilla__title{flex:1}
|
|
15
|
+
.jini-chat-vanilla__button{font:inherit;color:inherit;background:transparent;border:1px solid var(--jini-chat-border,#767676);border-radius:8px;padding:6px 10px;cursor:pointer}
|
|
16
|
+
.jini-chat-vanilla__button:disabled{opacity:.5;cursor:default}
|
|
17
|
+
.jini-chat-vanilla__messages{flex:1;min-height:0;overflow:auto;overscroll-behavior:contain;padding:16px}
|
|
18
|
+
.jini-chat-vanilla__message{margin-bottom:16px;overflow-wrap:anywhere}
|
|
19
|
+
.jini-chat-vanilla__message--user{white-space:pre-wrap;padding:10px;border-radius:8px;background:var(--jini-chat-user-background,#8882)}
|
|
20
|
+
.jini-chat-vanilla__message p{margin:0 0 8px}
|
|
21
|
+
.jini-chat-vanilla__message pre{overflow:auto;padding:8px;background:#8882;border-radius:8px}
|
|
22
|
+
.jini-chat-vanilla__message a{color:var(--jini-chat-accent,var(--color-primary,#2563eb));text-decoration:underline}
|
|
23
|
+
.jini-chat-vanilla__input{flex:1;min-width:0;resize:none;font:inherit;font-size:16px;color:inherit;background:transparent;border:1px solid var(--jini-chat-border,#767676);border-radius:8px;padding:8px}
|
|
24
|
+
.jini-chat-vanilla__status,.jini-chat-vanilla__error{padding:0 12px}
|
|
25
|
+
.jini-chat-vanilla__error{color:var(--jini-chat-error,#b91c1c)}
|
|
26
|
+
.jini-chat-vanilla__confirmation{flex-wrap:wrap}
|
|
27
|
+
@media(max-width:480px){.jini-chat-vanilla__panel{right:8px;bottom:88px;width:calc(100vw - 16px);height:calc(100dvh - 104px)}}
|
|
28
|
+
|
|
29
|
+
.jini-chat-vanilla__announcements{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
|
|
@@ -16,6 +16,6 @@
|
|
|
16
16
|
* `@deprecated`, so every existing `import { ChatPane } from '@jini-ai/chat/react'` keeps working
|
|
17
17
|
* unchanged. New code should import from this subpath directly.
|
|
18
18
|
*/
|
|
19
|
-
export { AgentRuntimePicker, CHAT_PANE_AGENT_TOOLS, ChatPane, createDaemonAttachmentUploader, createMcpUiToolCaller, createTypedAnswerPoster, defaultChatPaneSelection, orderChatPaneAgents, resolveChatPaneSelection, useChatPane, useChatPaneAgentControl, useChatPaneRuntimeInventory, useChatPaneWorkingDirectory, } from './features/chat-pane/index.js';
|
|
20
|
-
export type { AgentRuntimePickerProps, ByokRuntimeSummary, ChatPaneActivity, ChatPaneAgent, ChatPaneAgentBridgeAccess, ChatPaneAgentControlOptions, ChatPaneAgentOption, ChatPaneAgentSelection, ChatPaneAgentToolAction, ChatPaneAgentToolDef, ChatPaneAgentToolInputSchema, ChatPaneAgentToolRisk, ChatPaneAttachmentUploadOptions, ChatPaneComposerHandle, ChatPaneProps, ChatPaneRunContext, ChatPaneRunContextInput, ChatPaneRuntimeAccess, ChatPaneVariant, ChatPaneWorkingDirectoryAccess, CreateDaemonAttachmentUploaderOptions, CreateMcpUiToolCallerOptions, CreateTypedAnswerPosterOptions, DeliverTypedAnswer, McpUiToolCallRequest, RuntimePickerPlacement, TypedAnswerDelivery, TypedAnswerNotice, UseChatPaneAgentControlOptions, UseChatPaneOptions, UseChatPaneResult, UseChatPaneRuntimeInventoryOptions, UseChatPaneRuntimeInventoryResult, UseChatPaneWorkingDirectoryOptions, UseChatPaneWorkingDirectoryResult, } from './features/chat-pane/index.js';
|
|
19
|
+
export { AgentRuntimePicker, CHAT_PANE_AGENT_TOOLS, ChatPane, createDaemonAttachmentUploader, createMcpUiToolCaller, createMidRunMessagePoster, createTypedAnswerPoster, defaultChatPaneSelection, orderChatPaneAgents, resolveChatPaneSelection, useChatPane, useChatPaneAgentControl, useChatPaneRuntimeInventory, useChatPaneWorkingDirectory, } from './features/chat-pane/index.js';
|
|
20
|
+
export type { AgentRuntimePickerProps, ByokRuntimeSummary, ChatPaneActivity, ChatPaneAgent, ChatPaneAgentBridgeAccess, ChatPaneAgentControlOptions, ChatPaneAgentOption, ChatPaneAgentSelection, ChatPaneAgentToolAction, ChatPaneAgentToolDef, ChatPaneAgentToolInputSchema, ChatPaneAgentToolRisk, ChatPaneAttachmentUploadOptions, ChatPaneComposerHandle, ChatPaneProps, ChatPaneRunContext, ChatPaneRunContextInput, ChatPaneRuntimeAccess, ChatPaneVariant, ChatPaneWorkingDirectoryAccess, CreateDaemonAttachmentUploaderOptions, CreateMcpUiToolCallerOptions, CreateMidRunMessagePosterOptions, CreateTypedAnswerPosterOptions, DeliverMidRunMessage, DeliverTypedAnswer, McpUiToolCallRequest, MidRunMessageDelivery, RuntimePickerPlacement, TypedAnswerDelivery, TypedAnswerNotice, UseChatPaneAgentControlOptions, UseChatPaneOptions, UseChatPaneResult, UseChatPaneRuntimeInventoryOptions, UseChatPaneRuntimeInventoryResult, UseChatPaneWorkingDirectoryOptions, UseChatPaneWorkingDirectoryResult, } from './features/chat-pane/index.js';
|
|
21
21
|
//# sourceMappingURL=chat-pane.d.ts.map
|
package/dist/react/chat-pane.js
CHANGED
|
@@ -16,5 +16,5 @@
|
|
|
16
16
|
* `@deprecated`, so every existing `import { ChatPane } from '@jini-ai/chat/react'` keeps working
|
|
17
17
|
* unchanged. New code should import from this subpath directly.
|
|
18
18
|
*/
|
|
19
|
-
export { AgentRuntimePicker, CHAT_PANE_AGENT_TOOLS, ChatPane, createDaemonAttachmentUploader, createMcpUiToolCaller, createTypedAnswerPoster, defaultChatPaneSelection, orderChatPaneAgents, resolveChatPaneSelection, useChatPane, useChatPaneAgentControl, useChatPaneRuntimeInventory, useChatPaneWorkingDirectory, } from './features/chat-pane/index.js';
|
|
19
|
+
export { AgentRuntimePicker, CHAT_PANE_AGENT_TOOLS, ChatPane, createDaemonAttachmentUploader, createMcpUiToolCaller, createMidRunMessagePoster, createTypedAnswerPoster, defaultChatPaneSelection, orderChatPaneAgents, resolveChatPaneSelection, useChatPane, useChatPaneAgentControl, useChatPaneRuntimeInventory, useChatPaneWorkingDirectory, } from './features/chat-pane/index.js';
|
|
20
20
|
//# sourceMappingURL=chat-pane.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type InteractiveUiRegistry } from '@jini-ai/ui/interactive-ui';
|
|
1
2
|
import type { ExtEventRenderProps } from '../ext-event-renderer-registry.js';
|
|
2
3
|
/**
|
|
3
4
|
* What a host reports back after attempting to deliver an agent-directed action. Returned (not
|
|
@@ -12,6 +13,9 @@ export type A2uiAgentActionOutcome = {
|
|
|
12
13
|
readonly reason: string;
|
|
13
14
|
};
|
|
14
15
|
export interface A2uiSurfaceCardProps extends ExtEventRenderProps {
|
|
16
|
+
/** Host registry used for both wire validation and rendering. Defaults to ui's built-ins.
|
|
17
|
+
* Supply a stable registry for the card's lifetime; remount the card to switch catalogs. */
|
|
18
|
+
registry?: Pick<InteractiveUiRegistry, 'list' | 'resolveById'>;
|
|
15
19
|
/**
|
|
16
20
|
* Called when a rendered surface produces a `message`-shaped action meant for the agent (as
|
|
17
21
|
* opposed to a `local` client-side function call, which this component already resolves and
|
|
@@ -31,5 +35,5 @@ export interface A2uiSurfaceCardProps extends ExtEventRenderProps {
|
|
|
31
35
|
onAgentAction?: (runId: string | undefined, message: unknown) => void | Promise<A2uiAgentActionOutcome>;
|
|
32
36
|
}
|
|
33
37
|
/** Registered against `ext-event-renderer-registry.ts`'s `'a2ui'` name — see module doc. */
|
|
34
|
-
export declare function A2uiSurfaceCard({ events, runId, onAgentAction }: A2uiSurfaceCardProps): import("react").JSX.Element;
|
|
38
|
+
export declare function A2uiSurfaceCard({ events, runId, onAgentAction, registry }: A2uiSurfaceCardProps): import("react").JSX.Element;
|
|
35
39
|
//# sourceMappingURL=A2uiSurfaceCard.d.ts.map
|