@runtypelabs/persona 3.9.0 → 3.9.2
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/index.cjs +7 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.global.js +9 -10
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +7 -8
- package/dist/index.js.map +1 -1
- package/dist/theme-editor.cjs +14 -2
- package/dist/theme-editor.js +14 -2
- package/package.json +1 -1
- package/src/client.test.ts +54 -0
- package/src/client.ts +14 -0
- package/src/components/tool-bubble.ts +1 -1
- package/src/defaults.ts +1 -1
package/dist/theme-editor.cjs
CHANGED
|
@@ -124,7 +124,7 @@ function deepMerge(base, override) {
|
|
|
124
124
|
var DEFAULT_FLOATING_LAUNCHER_WIDTH = "min(440px, calc(100vw - 24px))";
|
|
125
125
|
var DEFAULT_FLOATING_LAUNCHER_MAX_WIDTH = "440px";
|
|
126
126
|
var DEFAULT_WIDGET_CONFIG = {
|
|
127
|
-
apiUrl: "
|
|
127
|
+
apiUrl: "https://api.runtype.com/api/chat/dispatch",
|
|
128
128
|
// Client token mode defaults (optional, only used when clientToken is set)
|
|
129
129
|
clientToken: void 0,
|
|
130
130
|
theme: void 0,
|
|
@@ -4842,6 +4842,18 @@ var AgentWidgetClient = class {
|
|
|
4842
4842
|
if (stepType === "tool" || executionType === "context") {
|
|
4843
4843
|
continue;
|
|
4844
4844
|
}
|
|
4845
|
+
if (didSplitByPartId) {
|
|
4846
|
+
if (assistantMessage !== null) {
|
|
4847
|
+
const msg = assistantMessage;
|
|
4848
|
+
streamParsers.delete(msg.id);
|
|
4849
|
+
rawContentBuffers.delete(msg.id);
|
|
4850
|
+
if (msg.streaming !== false) {
|
|
4851
|
+
msg.streaming = false;
|
|
4852
|
+
emitMessage(msg);
|
|
4853
|
+
}
|
|
4854
|
+
}
|
|
4855
|
+
continue;
|
|
4856
|
+
}
|
|
4845
4857
|
const finalContent = (_ja = payload.result) == null ? void 0 : _ja.response;
|
|
4846
4858
|
const assistant = ensureAssistantMessage();
|
|
4847
4859
|
if (finalContent !== void 0 && finalContent !== null) {
|
|
@@ -10170,7 +10182,7 @@ var createToolBubble = (message, config) => {
|
|
|
10170
10182
|
if (toolCallConfig.codeBlockTextColor) {
|
|
10171
10183
|
logsPre.style.color = toolCallConfig.codeBlockTextColor;
|
|
10172
10184
|
}
|
|
10173
|
-
logsPre.textContent = tool.chunks.join("
|
|
10185
|
+
logsPre.textContent = tool.chunks.join("");
|
|
10174
10186
|
logsBlock.append(logsLabel, logsPre);
|
|
10175
10187
|
content.appendChild(logsBlock);
|
|
10176
10188
|
}
|
package/dist/theme-editor.js
CHANGED
|
@@ -19,7 +19,7 @@ function deepMerge(base, override) {
|
|
|
19
19
|
var DEFAULT_FLOATING_LAUNCHER_WIDTH = "min(440px, calc(100vw - 24px))";
|
|
20
20
|
var DEFAULT_FLOATING_LAUNCHER_MAX_WIDTH = "440px";
|
|
21
21
|
var DEFAULT_WIDGET_CONFIG = {
|
|
22
|
-
apiUrl: "
|
|
22
|
+
apiUrl: "https://api.runtype.com/api/chat/dispatch",
|
|
23
23
|
// Client token mode defaults (optional, only used when clientToken is set)
|
|
24
24
|
clientToken: void 0,
|
|
25
25
|
theme: void 0,
|
|
@@ -4737,6 +4737,18 @@ var AgentWidgetClient = class {
|
|
|
4737
4737
|
if (stepType === "tool" || executionType === "context") {
|
|
4738
4738
|
continue;
|
|
4739
4739
|
}
|
|
4740
|
+
if (didSplitByPartId) {
|
|
4741
|
+
if (assistantMessage !== null) {
|
|
4742
|
+
const msg = assistantMessage;
|
|
4743
|
+
streamParsers.delete(msg.id);
|
|
4744
|
+
rawContentBuffers.delete(msg.id);
|
|
4745
|
+
if (msg.streaming !== false) {
|
|
4746
|
+
msg.streaming = false;
|
|
4747
|
+
emitMessage(msg);
|
|
4748
|
+
}
|
|
4749
|
+
}
|
|
4750
|
+
continue;
|
|
4751
|
+
}
|
|
4740
4752
|
const finalContent = (_ja = payload.result) == null ? void 0 : _ja.response;
|
|
4741
4753
|
const assistant = ensureAssistantMessage();
|
|
4742
4754
|
if (finalContent !== void 0 && finalContent !== null) {
|
|
@@ -10065,7 +10077,7 @@ var createToolBubble = (message, config) => {
|
|
|
10065
10077
|
if (toolCallConfig.codeBlockTextColor) {
|
|
10066
10078
|
logsPre.style.color = toolCallConfig.codeBlockTextColor;
|
|
10067
10079
|
}
|
|
10068
|
-
logsPre.textContent = tool.chunks.join("
|
|
10080
|
+
logsPre.textContent = tool.chunks.join("");
|
|
10069
10081
|
logsBlock.append(logsLabel, logsPre);
|
|
10070
10082
|
content.appendChild(logsBlock);
|
|
10071
10083
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runtypelabs/persona",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.2",
|
|
4
4
|
"description": "Themeable, pluggable streaming agent widget for websites, in plain JS with support for voice input and reasoning / tool output.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
package/src/client.test.ts
CHANGED
|
@@ -1784,5 +1784,59 @@ describe('AgentWidgetClient - partId Text/Tool Interleaving', () => {
|
|
|
1784
1784
|
expect(assistantTexts[0].streaming).toBe(false);
|
|
1785
1785
|
expect(assistantTexts[1].streaming).toBe(false);
|
|
1786
1786
|
});
|
|
1787
|
+
|
|
1788
|
+
it('should not duplicate text when step_complete follows text_end', async () => {
|
|
1789
|
+
const events: AgentWidgetEvent[] = [];
|
|
1790
|
+
|
|
1791
|
+
const encoder = new TextEncoder();
|
|
1792
|
+
global.fetch = vi.fn().mockImplementation(async () => {
|
|
1793
|
+
const stream = new ReadableStream({
|
|
1794
|
+
start(controller) {
|
|
1795
|
+
const e = (eventType: string, data: Record<string, unknown>) =>
|
|
1796
|
+
controller.enqueue(encoder.encode(`event: ${eventType}\ndata: ${JSON.stringify({ type: eventType, ...data })}\n\n`));
|
|
1797
|
+
|
|
1798
|
+
e('flow_start', { flowId: 'f1', flowName: 'Test', totalSteps: 1 });
|
|
1799
|
+
// Tools fire first (no text before them)
|
|
1800
|
+
e('tool_start', { toolId: 'tc_1', name: 'test_tool', toolType: 'custom', startedAt: new Date().toISOString() });
|
|
1801
|
+
e('tool_complete', { toolId: 'tc_1', name: 'test_tool', success: true, completedAt: new Date().toISOString(), executionTime: 0 });
|
|
1802
|
+
// Then text segment
|
|
1803
|
+
e('text_start', { partId: 'text_1', messageId: 'msg_s1', seq: 1 });
|
|
1804
|
+
e('step_delta', { id: 's1', text: 'Tool returned a result.', partId: 'text_1', messageId: 'msg_s1', seq: 2 });
|
|
1805
|
+
e('text_end', { partId: 'text_1', messageId: 'msg_s1', seq: 3 });
|
|
1806
|
+
// step_complete with full response (should NOT create a duplicate)
|
|
1807
|
+
e('step_complete', { id: 's1', name: 'Response', stepType: 'prompt', success: true, result: { response: 'Tool returned a result.' }, executionTime: 500 });
|
|
1808
|
+
e('flow_complete', { success: true });
|
|
1809
|
+
controller.close();
|
|
1810
|
+
}
|
|
1811
|
+
});
|
|
1812
|
+
return { ok: true, body: stream };
|
|
1813
|
+
});
|
|
1814
|
+
|
|
1815
|
+
const client = new AgentWidgetClient({ apiUrl: 'http://localhost:8000' });
|
|
1816
|
+
await client.dispatch(
|
|
1817
|
+
{ messages: [{ id: 'usr_1', role: 'user', content: 'Call tool', createdAt: new Date().toISOString() }] },
|
|
1818
|
+
(event) => events.push(event)
|
|
1819
|
+
);
|
|
1820
|
+
|
|
1821
|
+
const messageEvents = events.filter(e => e.type === 'message');
|
|
1822
|
+
const messagesById = new Map<string, AgentWidgetMessage>();
|
|
1823
|
+
for (const event of messageEvents) {
|
|
1824
|
+
if (event.type === 'message') messagesById.set(event.message.id, event.message);
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
const allMessages = Array.from(messagesById.values());
|
|
1828
|
+
const assistantTexts = allMessages
|
|
1829
|
+
.filter(m => m.role === 'assistant' && !m.variant)
|
|
1830
|
+
.sort((a, b) => (a.sequence ?? 0) - (b.sequence ?? 0));
|
|
1831
|
+
const toolMsgs = allMessages.filter(m => m.variant === 'tool');
|
|
1832
|
+
|
|
1833
|
+
// Exactly ONE text message (not duplicated by step_complete)
|
|
1834
|
+
expect(assistantTexts.length).toBe(1);
|
|
1835
|
+
expect(assistantTexts[0].content).toBe('Tool returned a result.');
|
|
1836
|
+
expect(assistantTexts[0].streaming).toBe(false);
|
|
1837
|
+
|
|
1838
|
+
// Tool message exists
|
|
1839
|
+
expect(toolMsgs.length).toBe(1);
|
|
1840
|
+
});
|
|
1787
1841
|
});
|
|
1788
1842
|
|
package/src/client.ts
CHANGED
|
@@ -1757,6 +1757,20 @@ export class AgentWidgetClient {
|
|
|
1757
1757
|
// Skip tool-related completions - they're handled by tool_complete
|
|
1758
1758
|
continue;
|
|
1759
1759
|
}
|
|
1760
|
+
if (didSplitByPartId) {
|
|
1761
|
+
// text_end already sealed the assistant message(s) — don't recreate
|
|
1762
|
+
// one from step_complete's full response (would cause duplication)
|
|
1763
|
+
if (assistantMessage !== null) {
|
|
1764
|
+
const msg: AgentWidgetMessage = assistantMessage;
|
|
1765
|
+
streamParsers.delete(msg.id);
|
|
1766
|
+
rawContentBuffers.delete(msg.id);
|
|
1767
|
+
if (msg.streaming !== false) {
|
|
1768
|
+
msg.streaming = false;
|
|
1769
|
+
emitMessage(msg);
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
continue;
|
|
1773
|
+
}
|
|
1760
1774
|
const finalContent = payload.result?.response;
|
|
1761
1775
|
const assistant = ensureAssistantMessage();
|
|
1762
1776
|
if (finalContent !== undefined && finalContent !== null) {
|
|
@@ -215,7 +215,7 @@ export const createToolBubble = (message: AgentWidgetMessage, config?: AgentWidg
|
|
|
215
215
|
if (toolCallConfig.codeBlockTextColor) {
|
|
216
216
|
logsPre.style.color = toolCallConfig.codeBlockTextColor;
|
|
217
217
|
}
|
|
218
|
-
logsPre.textContent = tool.chunks.join("
|
|
218
|
+
logsPre.textContent = tool.chunks.join("");
|
|
219
219
|
logsBlock.append(logsLabel, logsPre);
|
|
220
220
|
content.appendChild(logsBlock);
|
|
221
221
|
}
|
package/src/defaults.ts
CHANGED
|
@@ -17,7 +17,7 @@ export const DEFAULT_FLOATING_LAUNCHER_MAX_WIDTH = "440px";
|
|
|
17
17
|
* Single source of truth for all default values
|
|
18
18
|
*/
|
|
19
19
|
export const DEFAULT_WIDGET_CONFIG: Partial<AgentWidgetConfig> = {
|
|
20
|
-
apiUrl: "
|
|
20
|
+
apiUrl: "https://api.runtype.com/api/chat/dispatch",
|
|
21
21
|
// Client token mode defaults (optional, only used when clientToken is set)
|
|
22
22
|
clientToken: undefined,
|
|
23
23
|
theme: undefined,
|