@buoy-gg/ask-buoy 7.0.40 → 7.0.42
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/README.md +13 -94
- package/lib/commonjs/blocks/AskBlocks.js +1 -338
- package/lib/commonjs/blocks/BlockRenderer.js +1 -262
- package/lib/commonjs/blocks/ChromePrototypes.js +1 -514
- package/lib/commonjs/blocks/DataBlocks.js +1 -781
- package/lib/commonjs/blocks/ExtraBlocks.js +1 -1860
- package/lib/commonjs/blocks/MediaBlocks.js +1 -156
- package/lib/commonjs/blocks/ReceiptBlocks.js +2 -586
- package/lib/commonjs/blocks/blockText.js +1 -60
- package/lib/commonjs/blocks/blockText.test.js +1 -53
- package/lib/commonjs/blocks/context.js +1 -42
- package/lib/commonjs/blocks/icons.js +1 -96
- package/lib/commonjs/blocks/index.js +1 -95
- package/lib/commonjs/blocks/listRow.test.js +1 -55
- package/lib/commonjs/blocks/pageState.js +1 -34
- package/lib/commonjs/blocks/pageState.test.js +1 -57
- package/lib/commonjs/blocks/primitives.js +1 -457
- package/lib/commonjs/blocks/primitivesIndex.js +1 -62
- package/lib/commonjs/blocks/ruleStates.js +1 -0
- package/lib/commonjs/components/ApprovalCard.js +1 -297
- package/lib/commonjs/components/AskBuoyHeader.js +1 -196
- package/lib/commonjs/components/AskBuoyIcon.js +1 -19
- package/lib/commonjs/components/AskBuoyModal.js +2 -478
- package/lib/commonjs/components/AskBuoySettings.js +1 -181
- package/lib/commonjs/components/ChangesBar.js +1 -211
- package/lib/commonjs/components/Composer.js +1 -255
- package/lib/commonjs/components/EmptyState.js +1 -161
- package/lib/commonjs/components/KeyboardPad.js +1 -80
- package/lib/commonjs/components/Markdown.js +1 -310
- package/lib/commonjs/components/MessageList.js +1 -970
- package/lib/commonjs/components/QueuedMessages.js +1 -145
- package/lib/commonjs/components/ThinkingStrip.js +1 -223
- package/lib/commonjs/components/TypingDots.js +1 -63
- package/lib/commonjs/components/markdownParse.js +1 -131
- package/lib/commonjs/components/markdownParse.test.js +1 -99
- package/lib/commonjs/components/useCopyAction.js +1 -50
- package/lib/commonjs/index.js +1 -252
- package/lib/commonjs/preset.js +1 -91
- package/lib/commonjs/store/activityGroups.js +1 -110
- package/lib/commonjs/store/activityGroups.test.js +1 -78
- package/lib/commonjs/store/askBuoySettings.js +1 -72
- package/lib/commonjs/store/askBuoyStore.js +2 -588
- package/lib/commonjs/store/blockPlacement.js +1 -64
- package/lib/commonjs/store/blockPlacement.test.js +1 -123
- package/lib/commonjs/store/queue.test.js +1 -150
- package/lib/commonjs/store/resetConversation.js +1 -77
- package/lib/commonjs/store/restorePending.test.js +1 -63
- package/lib/commonjs/store/restoredIds.test.js +1 -47
- package/lib/commonjs/store/suggestions.js +1 -54
- package/lib/commonjs/store/suggestions.test.js +1 -58
- package/lib/commonjs/store/systemLine.test.js +1 -77
- package/lib/commonjs/store/ticketPrompt.js +1 -17
- package/lib/commonjs/store/traceText.js +1 -81
- package/lib/commonjs/store/traceText.test.js +1 -112
- package/lib/commonjs/store/transcriptPersistence.js +1 -297
- package/lib/commonjs/store/transcriptPersistence.test.js +1 -333
- package/lib/commonjs/store/turnRendering.test.js +1 -151
- package/lib/commonjs/store/useAskBuoy.js +1 -651
- package/lib/commonjs/store/useAskBuoySettings.js +1 -14
- package/lib/commonjs/sync/askBuoySyncAdapter.js +1 -153
- package/lib/commonjs/sync/askBuoySyncAdapter.test.js +1 -141
- package/lib/commonjs/sync/wire.js +1 -58
- package/lib/commonjs/types.js +1 -6
- package/lib/module/blocks/AskBlocks.js +1 -331
- package/lib/module/blocks/BlockRenderer.js +1 -257
- package/lib/module/blocks/ChromePrototypes.js +1 -503
- package/lib/module/blocks/DataBlocks.js +1 -767
- package/lib/module/blocks/ExtraBlocks.js +1 -1833
- package/lib/module/blocks/MediaBlocks.js +1 -151
- package/lib/module/blocks/ReceiptBlocks.js +2 -574
- package/lib/module/blocks/blockText.js +1 -55
- package/lib/module/blocks/blockText.test.js +1 -53
- package/lib/module/blocks/context.js +1 -35
- package/lib/module/blocks/icons.js +1 -91
- package/lib/module/blocks/index.js +1 -8
- package/lib/module/blocks/listRow.test.js +1 -56
- package/lib/module/blocks/pageState.js +1 -30
- package/lib/module/blocks/pageState.test.js +1 -56
- package/lib/module/blocks/primitives.js +1 -445
- package/lib/module/blocks/primitivesIndex.js +1 -5
- package/lib/module/blocks/ruleStates.js +1 -0
- package/lib/module/components/ApprovalCard.js +1 -292
- package/lib/module/components/AskBuoyHeader.js +1 -193
- package/lib/module/components/AskBuoyIcon.js +1 -8
- package/lib/module/components/AskBuoyModal.js +2 -473
- package/lib/module/components/AskBuoySettings.js +1 -176
- package/lib/module/components/ChangesBar.js +1 -206
- package/lib/module/components/Composer.js +1 -250
- package/lib/module/components/EmptyState.js +1 -156
- package/lib/module/components/KeyboardPad.js +1 -75
- package/lib/module/components/Markdown.js +1 -305
- package/lib/module/components/MessageList.js +1 -964
- package/lib/module/components/QueuedMessages.js +1 -140
- package/lib/module/components/ThinkingStrip.js +1 -218
- package/lib/module/components/TypingDots.js +1 -58
- package/lib/module/components/markdownParse.js +1 -125
- package/lib/module/components/markdownParse.test.js +1 -98
- package/lib/module/components/useCopyAction.js +1 -46
- package/lib/module/index.js +1 -34
- package/lib/module/preset.js +1 -74
- package/lib/module/store/activityGroups.js +1 -103
- package/lib/module/store/activityGroups.test.js +1 -77
- package/lib/module/store/askBuoySettings.js +1 -67
- package/lib/module/store/askBuoyStore.js +2 -582
- package/lib/module/store/blockPlacement.js +1 -59
- package/lib/module/store/blockPlacement.test.js +1 -122
- package/lib/module/store/queue.test.js +1 -149
- package/lib/module/store/resetConversation.js +1 -72
- package/lib/module/store/restorePending.test.js +1 -62
- package/lib/module/store/restoredIds.test.js +1 -46
- package/lib/module/store/suggestions.js +1 -49
- package/lib/module/store/suggestions.test.js +1 -57
- package/lib/module/store/systemLine.test.js +1 -76
- package/lib/module/store/ticketPrompt.js +1 -13
- package/lib/module/store/traceText.js +1 -75
- package/lib/module/store/traceText.test.js +1 -111
- package/lib/module/store/transcriptPersistence.js +1 -287
- package/lib/module/store/transcriptPersistence.test.js +1 -332
- package/lib/module/store/turnRendering.test.js +1 -150
- package/lib/module/store/useAskBuoy.js +1 -646
- package/lib/module/store/useAskBuoySettings.js +1 -9
- package/lib/module/sync/askBuoySyncAdapter.js +1 -148
- package/lib/module/sync/askBuoySyncAdapter.test.js +1 -140
- package/lib/module/sync/wire.js +1 -47
- package/lib/module/types.js +1 -4
- package/lib/typescript/blocks/context.d.ts +3 -0
- package/lib/typescript/blocks/ruleStates.d.ts +15 -0
- package/lib/typescript/components/ChangesBar.d.ts +2 -1
- package/lib/typescript/sync/askBuoySyncAdapter.d.ts +2 -2
- package/lib/web/index.mjs +15 -0
- package/package.json +44 -11
- package/lib/commonjs/blocks/AskBlocks.js.map +0 -1
- package/lib/commonjs/blocks/BlockRenderer.js.map +0 -1
- package/lib/commonjs/blocks/ChromePrototypes.js.map +0 -1
- package/lib/commonjs/blocks/DataBlocks.js.map +0 -1
- package/lib/commonjs/blocks/ExtraBlocks.js.map +0 -1
- package/lib/commonjs/blocks/MediaBlocks.js.map +0 -1
- package/lib/commonjs/blocks/ReceiptBlocks.js.map +0 -1
- package/lib/commonjs/blocks/blockText.js.map +0 -1
- package/lib/commonjs/blocks/blockText.test.js.map +0 -1
- package/lib/commonjs/blocks/context.js.map +0 -1
- package/lib/commonjs/blocks/icons.js.map +0 -1
- package/lib/commonjs/blocks/index.js.map +0 -1
- package/lib/commonjs/blocks/listRow.test.js.map +0 -1
- package/lib/commonjs/blocks/pageState.js.map +0 -1
- package/lib/commonjs/blocks/pageState.test.js.map +0 -1
- package/lib/commonjs/blocks/primitives.js.map +0 -1
- package/lib/commonjs/blocks/primitivesIndex.js.map +0 -1
- package/lib/commonjs/components/ApprovalCard.js.map +0 -1
- package/lib/commonjs/components/AskBuoyHeader.js.map +0 -1
- package/lib/commonjs/components/AskBuoyIcon.js.map +0 -1
- package/lib/commonjs/components/AskBuoyModal.js.map +0 -1
- package/lib/commonjs/components/AskBuoySettings.js.map +0 -1
- package/lib/commonjs/components/ChangesBar.js.map +0 -1
- package/lib/commonjs/components/Composer.js.map +0 -1
- package/lib/commonjs/components/EmptyState.js.map +0 -1
- package/lib/commonjs/components/KeyboardPad.js.map +0 -1
- package/lib/commonjs/components/Markdown.js.map +0 -1
- package/lib/commonjs/components/MessageList.js.map +0 -1
- package/lib/commonjs/components/QueuedMessages.js.map +0 -1
- package/lib/commonjs/components/ThinkingStrip.js.map +0 -1
- package/lib/commonjs/components/TypingDots.js.map +0 -1
- package/lib/commonjs/components/markdownParse.js.map +0 -1
- package/lib/commonjs/components/markdownParse.test.js.map +0 -1
- package/lib/commonjs/components/useCopyAction.js.map +0 -1
- package/lib/commonjs/index.js.map +0 -1
- package/lib/commonjs/preset.js.map +0 -1
- package/lib/commonjs/store/activityGroups.js.map +0 -1
- package/lib/commonjs/store/activityGroups.test.js.map +0 -1
- package/lib/commonjs/store/askBuoySettings.js.map +0 -1
- package/lib/commonjs/store/askBuoyStore.js.map +0 -1
- package/lib/commonjs/store/blockPlacement.js.map +0 -1
- package/lib/commonjs/store/blockPlacement.test.js.map +0 -1
- package/lib/commonjs/store/queue.test.js.map +0 -1
- package/lib/commonjs/store/resetConversation.js.map +0 -1
- package/lib/commonjs/store/restorePending.test.js.map +0 -1
- package/lib/commonjs/store/restoredIds.test.js.map +0 -1
- package/lib/commonjs/store/suggestions.js.map +0 -1
- package/lib/commonjs/store/suggestions.test.js.map +0 -1
- package/lib/commonjs/store/systemLine.test.js.map +0 -1
- package/lib/commonjs/store/ticketPrompt.js.map +0 -1
- package/lib/commonjs/store/traceText.js.map +0 -1
- package/lib/commonjs/store/traceText.test.js.map +0 -1
- package/lib/commonjs/store/transcriptPersistence.js.map +0 -1
- package/lib/commonjs/store/transcriptPersistence.test.js.map +0 -1
- package/lib/commonjs/store/turnRendering.test.js.map +0 -1
- package/lib/commonjs/store/useAskBuoy.js.map +0 -1
- package/lib/commonjs/store/useAskBuoySettings.js.map +0 -1
- package/lib/commonjs/sync/askBuoySyncAdapter.js.map +0 -1
- package/lib/commonjs/sync/askBuoySyncAdapter.test.js.map +0 -1
- package/lib/commonjs/sync/wire.js.map +0 -1
- package/lib/commonjs/types.js.map +0 -1
- package/lib/module/blocks/AskBlocks.js.map +0 -1
- package/lib/module/blocks/BlockRenderer.js.map +0 -1
- package/lib/module/blocks/ChromePrototypes.js.map +0 -1
- package/lib/module/blocks/DataBlocks.js.map +0 -1
- package/lib/module/blocks/ExtraBlocks.js.map +0 -1
- package/lib/module/blocks/MediaBlocks.js.map +0 -1
- package/lib/module/blocks/ReceiptBlocks.js.map +0 -1
- package/lib/module/blocks/blockText.js.map +0 -1
- package/lib/module/blocks/blockText.test.js.map +0 -1
- package/lib/module/blocks/context.js.map +0 -1
- package/lib/module/blocks/icons.js.map +0 -1
- package/lib/module/blocks/index.js.map +0 -1
- package/lib/module/blocks/listRow.test.js.map +0 -1
- package/lib/module/blocks/pageState.js.map +0 -1
- package/lib/module/blocks/pageState.test.js.map +0 -1
- package/lib/module/blocks/primitives.js.map +0 -1
- package/lib/module/blocks/primitivesIndex.js.map +0 -1
- package/lib/module/components/ApprovalCard.js.map +0 -1
- package/lib/module/components/AskBuoyHeader.js.map +0 -1
- package/lib/module/components/AskBuoyIcon.js.map +0 -1
- package/lib/module/components/AskBuoyModal.js.map +0 -1
- package/lib/module/components/AskBuoySettings.js.map +0 -1
- package/lib/module/components/ChangesBar.js.map +0 -1
- package/lib/module/components/Composer.js.map +0 -1
- package/lib/module/components/EmptyState.js.map +0 -1
- package/lib/module/components/KeyboardPad.js.map +0 -1
- package/lib/module/components/Markdown.js.map +0 -1
- package/lib/module/components/MessageList.js.map +0 -1
- package/lib/module/components/QueuedMessages.js.map +0 -1
- package/lib/module/components/ThinkingStrip.js.map +0 -1
- package/lib/module/components/TypingDots.js.map +0 -1
- package/lib/module/components/markdownParse.js.map +0 -1
- package/lib/module/components/markdownParse.test.js.map +0 -1
- package/lib/module/components/useCopyAction.js.map +0 -1
- package/lib/module/index.js.map +0 -1
- package/lib/module/preset.js.map +0 -1
- package/lib/module/store/activityGroups.js.map +0 -1
- package/lib/module/store/activityGroups.test.js.map +0 -1
- package/lib/module/store/askBuoySettings.js.map +0 -1
- package/lib/module/store/askBuoyStore.js.map +0 -1
- package/lib/module/store/blockPlacement.js.map +0 -1
- package/lib/module/store/blockPlacement.test.js.map +0 -1
- package/lib/module/store/queue.test.js.map +0 -1
- package/lib/module/store/resetConversation.js.map +0 -1
- package/lib/module/store/restorePending.test.js.map +0 -1
- package/lib/module/store/restoredIds.test.js.map +0 -1
- package/lib/module/store/suggestions.js.map +0 -1
- package/lib/module/store/suggestions.test.js.map +0 -1
- package/lib/module/store/systemLine.test.js.map +0 -1
- package/lib/module/store/ticketPrompt.js.map +0 -1
- package/lib/module/store/traceText.js.map +0 -1
- package/lib/module/store/traceText.test.js.map +0 -1
- package/lib/module/store/transcriptPersistence.js.map +0 -1
- package/lib/module/store/transcriptPersistence.test.js.map +0 -1
- package/lib/module/store/turnRendering.test.js.map +0 -1
- package/lib/module/store/useAskBuoy.js.map +0 -1
- package/lib/module/store/useAskBuoySettings.js.map +0 -1
- package/lib/module/sync/askBuoySyncAdapter.js.map +0 -1
- package/lib/module/sync/askBuoySyncAdapter.test.js.map +0 -1
- package/lib/module/sync/wire.js.map +0 -1
- package/lib/module/types.js.map +0 -1
- package/lib/typescript/blocks/AskBlocks.d.ts.map +0 -1
- package/lib/typescript/blocks/BlockRenderer.d.ts.map +0 -1
- package/lib/typescript/blocks/ChromePrototypes.d.ts.map +0 -1
- package/lib/typescript/blocks/DataBlocks.d.ts.map +0 -1
- package/lib/typescript/blocks/ExtraBlocks.d.ts.map +0 -1
- package/lib/typescript/blocks/MediaBlocks.d.ts.map +0 -1
- package/lib/typescript/blocks/ReceiptBlocks.d.ts.map +0 -1
- package/lib/typescript/blocks/blockText.d.ts.map +0 -1
- package/lib/typescript/blocks/blockText.test.d.ts.map +0 -1
- package/lib/typescript/blocks/context.d.ts.map +0 -1
- package/lib/typescript/blocks/icons.d.ts.map +0 -1
- package/lib/typescript/blocks/index.d.ts.map +0 -1
- package/lib/typescript/blocks/listRow.test.d.ts.map +0 -1
- package/lib/typescript/blocks/pageState.d.ts.map +0 -1
- package/lib/typescript/blocks/pageState.test.d.ts.map +0 -1
- package/lib/typescript/blocks/primitives.d.ts.map +0 -1
- package/lib/typescript/blocks/primitivesIndex.d.ts.map +0 -1
- package/lib/typescript/components/ApprovalCard.d.ts.map +0 -1
- package/lib/typescript/components/AskBuoyHeader.d.ts.map +0 -1
- package/lib/typescript/components/AskBuoyIcon.d.ts.map +0 -1
- package/lib/typescript/components/AskBuoyModal.d.ts.map +0 -1
- package/lib/typescript/components/AskBuoySettings.d.ts.map +0 -1
- package/lib/typescript/components/ChangesBar.d.ts.map +0 -1
- package/lib/typescript/components/Composer.d.ts.map +0 -1
- package/lib/typescript/components/EmptyState.d.ts.map +0 -1
- package/lib/typescript/components/KeyboardPad.d.ts.map +0 -1
- package/lib/typescript/components/Markdown.d.ts.map +0 -1
- package/lib/typescript/components/MessageList.d.ts.map +0 -1
- package/lib/typescript/components/QueuedMessages.d.ts.map +0 -1
- package/lib/typescript/components/ThinkingStrip.d.ts.map +0 -1
- package/lib/typescript/components/TypingDots.d.ts.map +0 -1
- package/lib/typescript/components/markdownParse.d.ts.map +0 -1
- package/lib/typescript/components/markdownParse.test.d.ts.map +0 -1
- package/lib/typescript/components/useCopyAction.d.ts.map +0 -1
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
- package/lib/typescript/store/activityGroups.d.ts.map +0 -1
- package/lib/typescript/store/activityGroups.test.d.ts.map +0 -1
- package/lib/typescript/store/askBuoySettings.d.ts.map +0 -1
- package/lib/typescript/store/askBuoyStore.d.ts.map +0 -1
- package/lib/typescript/store/blockPlacement.d.ts.map +0 -1
- package/lib/typescript/store/blockPlacement.test.d.ts.map +0 -1
- package/lib/typescript/store/queue.test.d.ts.map +0 -1
- package/lib/typescript/store/resetConversation.d.ts.map +0 -1
- package/lib/typescript/store/restorePending.test.d.ts.map +0 -1
- package/lib/typescript/store/restoredIds.test.d.ts.map +0 -1
- package/lib/typescript/store/suggestions.d.ts.map +0 -1
- package/lib/typescript/store/suggestions.test.d.ts.map +0 -1
- package/lib/typescript/store/systemLine.test.d.ts.map +0 -1
- package/lib/typescript/store/ticketPrompt.d.ts.map +0 -1
- package/lib/typescript/store/traceText.d.ts.map +0 -1
- package/lib/typescript/store/traceText.test.d.ts.map +0 -1
- package/lib/typescript/store/transcriptPersistence.d.ts.map +0 -1
- package/lib/typescript/store/transcriptPersistence.test.d.ts.map +0 -1
- package/lib/typescript/store/turnRendering.test.d.ts.map +0 -1
- package/lib/typescript/store/useAskBuoy.d.ts.map +0 -1
- package/lib/typescript/store/useAskBuoySettings.d.ts.map +0 -1
- package/lib/typescript/sync/askBuoySyncAdapter.d.ts.map +0 -1
- package/lib/typescript/sync/askBuoySyncAdapter.test.d.ts.map +0 -1
- package/lib/typescript/sync/wire.d.ts.map +0 -1
- package/lib/typescript/types.d.ts.map +0 -1
|
@@ -1,333 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _vitest = require("vitest");
|
|
4
|
-
var _transcriptPersistence = require("./transcriptPersistence");
|
|
5
|
-
/**
|
|
6
|
-
* What a saved conversation is allowed to contain, and what it looks like on
|
|
7
|
-
* the way back in.
|
|
8
|
-
*
|
|
9
|
-
* The transcript is on disk under a `@react_buoy` key now, which the Storage
|
|
10
|
-
* tool can read and the unauthenticated broker mirrors. Everything below is a
|
|
11
|
-
* property that keeps that trade bounded: no tool-result payloads, no
|
|
12
|
-
* credentials, no unbounded growth, and nothing that comes back claiming to
|
|
13
|
-
* still be running.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
const msg = (over = {}) => ({
|
|
17
|
-
id: "m1",
|
|
18
|
-
role: "assistant",
|
|
19
|
-
text: "ok",
|
|
20
|
-
toolCalls: [],
|
|
21
|
-
blocks: [],
|
|
22
|
-
...over
|
|
23
|
-
});
|
|
24
|
-
const build = (messages, history = []) => (0, _transcriptPersistence.buildPayload)({
|
|
25
|
-
messages,
|
|
26
|
-
history,
|
|
27
|
-
answers: {},
|
|
28
|
-
usage: {
|
|
29
|
-
input: 0,
|
|
30
|
-
output: 0,
|
|
31
|
-
requests: 0
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
(0, _vitest.describe)("what reaches the disk", () => {
|
|
35
|
-
(0, _vitest.it)("never writes a tool result", () => {
|
|
36
|
-
// The payloads are the sensitive half: storage values, response bodies, a
|
|
37
|
-
// customer's record. The ROUND survives so the model can resume; what it
|
|
38
|
-
// saw does not.
|
|
39
|
-
const history = [{
|
|
40
|
-
role: "user",
|
|
41
|
-
text: "what's in the bag?"
|
|
42
|
-
}, {
|
|
43
|
-
role: "assistant",
|
|
44
|
-
text: "",
|
|
45
|
-
toolCalls: [{
|
|
46
|
-
id: "c1",
|
|
47
|
-
name: "buoy_zustand",
|
|
48
|
-
input: {}
|
|
49
|
-
}]
|
|
50
|
-
}, {
|
|
51
|
-
role: "tool-results",
|
|
52
|
-
results: [{
|
|
53
|
-
toolCallId: "c1",
|
|
54
|
-
content: '{"lines":[{"card":"4111111111111111"}]}'
|
|
55
|
-
}]
|
|
56
|
-
}, {
|
|
57
|
-
role: "assistant",
|
|
58
|
-
text: "Five items."
|
|
59
|
-
}];
|
|
60
|
-
const saved = build([msg()], history);
|
|
61
|
-
const json = JSON.stringify(saved);
|
|
62
|
-
(0, _vitest.expect)(json).not.toContain("4111111111111111");
|
|
63
|
-
// The round itself is intact, so the pairing every provider requires holds.
|
|
64
|
-
(0, _vitest.expect)(saved.history.map(m => m.role)).toEqual(["user", "assistant", "tool-results", "assistant"]);
|
|
65
|
-
});
|
|
66
|
-
(0, _vitest.it)("never writes a step's result, even when it writes the step", () => {
|
|
67
|
-
// The step survives so the trace still reads; the payload is the thing the
|
|
68
|
-
// no-tool-results-on-disk promise is about.
|
|
69
|
-
const saved = build([msg({
|
|
70
|
-
toolCalls: [{
|
|
71
|
-
id: "c1",
|
|
72
|
-
toolId: "zustand",
|
|
73
|
-
action: "getStoreState",
|
|
74
|
-
label: "Read the bag",
|
|
75
|
-
status: "ok",
|
|
76
|
-
summary: "Done",
|
|
77
|
-
params: '{"storeName":"bag"}',
|
|
78
|
-
result: '{"card":"4111111111111111"}'
|
|
79
|
-
}]
|
|
80
|
-
})]);
|
|
81
|
-
(0, _vitest.expect)(JSON.stringify(saved)).not.toContain("4111111111111111");
|
|
82
|
-
(0, _vitest.expect)(saved.messages[0].toolCalls[0].result).toBeUndefined();
|
|
83
|
-
(0, _vitest.expect)(saved.messages[0].toolCalls[0].action).toBe("getStoreState");
|
|
84
|
-
});
|
|
85
|
-
(0, _vitest.it)("scrubs credential shapes out of what the agent said", () => {
|
|
86
|
-
const saved = build([msg({
|
|
87
|
-
text: "The header was Bearer abcdefghijklmnop123456"
|
|
88
|
-
})]);
|
|
89
|
-
(0, _vitest.expect)(saved.messages[0].text).not.toContain("abcdefghijklmnop123456");
|
|
90
|
-
});
|
|
91
|
-
(0, _vitest.it)("caps a long session instead of growing a file forever", () => {
|
|
92
|
-
const many = Array.from({
|
|
93
|
-
length: 400
|
|
94
|
-
}, (_, i) => msg({
|
|
95
|
-
id: `m${i}`,
|
|
96
|
-
text: `answer ${i}`
|
|
97
|
-
}));
|
|
98
|
-
const saved = build(many);
|
|
99
|
-
(0, _vitest.expect)(saved.messages.length).toBeLessThanOrEqual(60);
|
|
100
|
-
// Newest kept, oldest dropped — the end of a session is the useful end.
|
|
101
|
-
(0, _vitest.expect)(saved.messages[saved.messages.length - 1].text).toBe("answer 399");
|
|
102
|
-
});
|
|
103
|
-
(0, _vitest.it)("drops from the oldest end until a heavy transcript fits", () => {
|
|
104
|
-
const heavy = Array.from({
|
|
105
|
-
length: 20
|
|
106
|
-
}, (_, i) => msg({
|
|
107
|
-
id: `m${i}`,
|
|
108
|
-
text: "x".repeat(40_000)
|
|
109
|
-
}));
|
|
110
|
-
const saved = (0, _transcriptPersistence.fitToCaps)({
|
|
111
|
-
v: 1,
|
|
112
|
-
savedAt: 0,
|
|
113
|
-
messages: heavy,
|
|
114
|
-
history: [],
|
|
115
|
-
answers: {},
|
|
116
|
-
usage: {
|
|
117
|
-
input: 0,
|
|
118
|
-
output: 0,
|
|
119
|
-
requests: 0
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
(0, _vitest.expect)(JSON.stringify(saved).length).toBeLessThanOrEqual(256_000);
|
|
123
|
-
(0, _vitest.expect)(saved.messages.length).toBeGreaterThan(0);
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
(0, _vitest.describe)("what comes back", () => {
|
|
127
|
-
(0, _vitest.it)("marks a turn the app died in as interrupted rather than blank", () => {
|
|
128
|
-
// The crash case this feature exists for. An empty bubble with no
|
|
129
|
-
// explanation reads as the model having nothing to say.
|
|
130
|
-
const saved = build([msg({
|
|
131
|
-
text: "",
|
|
132
|
-
streaming: true
|
|
133
|
-
})]);
|
|
134
|
-
(0, _vitest.expect)(saved.messages[0].streaming).toBe(false);
|
|
135
|
-
(0, _vitest.expect)(saved.messages[0].error).toMatch(/interrupted/i);
|
|
136
|
-
});
|
|
137
|
-
(0, _vitest.it)("never restores a tool call still claiming to run", () => {
|
|
138
|
-
const saved = build([msg({
|
|
139
|
-
streaming: true,
|
|
140
|
-
toolCalls: [{
|
|
141
|
-
id: "c1",
|
|
142
|
-
toolId: "storage",
|
|
143
|
-
action: "set",
|
|
144
|
-
label: "Write a key",
|
|
145
|
-
status: "running"
|
|
146
|
-
}]
|
|
147
|
-
})]);
|
|
148
|
-
(0, _vitest.expect)(saved.messages[0].toolCalls[0].status).toBe("failed");
|
|
149
|
-
(0, _vitest.expect)(saved.messages[0].toolCalls[0].summary).toBe("Interrupted");
|
|
150
|
-
});
|
|
151
|
-
(0, _vitest.it)("keeps an answer that already finished exactly as it was", () => {
|
|
152
|
-
const saved = build([msg({
|
|
153
|
-
text: "Five items.",
|
|
154
|
-
streaming: false
|
|
155
|
-
})]);
|
|
156
|
-
(0, _vitest.expect)(saved.messages[0].error).toBeUndefined();
|
|
157
|
-
(0, _vitest.expect)(saved.messages[0].text).toBe("Five items.");
|
|
158
|
-
});
|
|
159
|
-
(0, _vitest.it)("treats anything it cannot trust as no transcript at all", () => {
|
|
160
|
-
(0, _vitest.expect)((0, _transcriptPersistence.parsePayload)(null)).toBeNull();
|
|
161
|
-
(0, _vitest.expect)((0, _transcriptPersistence.parsePayload)("not json")).toBeNull();
|
|
162
|
-
// An older shape is dropped, not coerced — a half-read transcript is worse
|
|
163
|
-
// than a missing one.
|
|
164
|
-
(0, _vitest.expect)((0, _transcriptPersistence.parsePayload)(JSON.stringify({
|
|
165
|
-
v: 0,
|
|
166
|
-
messages: [msg()]
|
|
167
|
-
}))).toBeNull();
|
|
168
|
-
(0, _vitest.expect)((0, _transcriptPersistence.parsePayload)(JSON.stringify({
|
|
169
|
-
v: 1,
|
|
170
|
-
messages: []
|
|
171
|
-
}))).toBeNull();
|
|
172
|
-
});
|
|
173
|
-
(0, _vitest.it)("round-trips a real conversation", () => {
|
|
174
|
-
const saved = build([msg({
|
|
175
|
-
role: "user",
|
|
176
|
-
text: "hi"
|
|
177
|
-
}), msg({
|
|
178
|
-
id: "m2",
|
|
179
|
-
text: "hello"
|
|
180
|
-
})]);
|
|
181
|
-
const back = (0, _transcriptPersistence.parsePayload)(JSON.stringify(saved));
|
|
182
|
-
(0, _vitest.expect)(back?.messages.map(m => m.text)).toEqual(["hi", "hello"]);
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* The card the user never answered.
|
|
188
|
-
*
|
|
189
|
-
* An unanswered question that disappears on reload reads as consent nobody
|
|
190
|
-
* gave — nothing was tapped, so as far as the user is concerned the change is
|
|
191
|
-
* still waiting for them.
|
|
192
|
-
*/
|
|
193
|
-
(0, _vitest.describe)("an unanswered approval", () => {
|
|
194
|
-
const pending = {
|
|
195
|
-
id: "c1",
|
|
196
|
-
toolId: "zustand",
|
|
197
|
-
action: "setState",
|
|
198
|
-
label: "Update the Poké Mart bag store",
|
|
199
|
-
description: "Change a live zustand store.",
|
|
200
|
-
reason: "This will change the app's state.",
|
|
201
|
-
params: {
|
|
202
|
-
storeName: "bag",
|
|
203
|
-
data: {
|
|
204
|
-
lines: []
|
|
205
|
-
}
|
|
206
|
-
},
|
|
207
|
-
resolve: () => {}
|
|
208
|
-
};
|
|
209
|
-
const withPending = (over = {}) => (0, _transcriptPersistence.buildPayload)({
|
|
210
|
-
messages: [msg()],
|
|
211
|
-
history: [],
|
|
212
|
-
answers: {},
|
|
213
|
-
usage: {
|
|
214
|
-
input: 0,
|
|
215
|
-
output: 0,
|
|
216
|
-
requests: 0
|
|
217
|
-
},
|
|
218
|
-
pending: {
|
|
219
|
-
...pending,
|
|
220
|
-
...over
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
(0, _vitest.it)("survives the round trip with the exact call it asked about", () => {
|
|
224
|
-
const back = (0, _transcriptPersistence.parsePayload)(JSON.stringify(withPending()));
|
|
225
|
-
// The params are what makes the restored card answerable at all: the turn
|
|
226
|
-
// that asked is gone, so Allow has to re-dispatch this itself.
|
|
227
|
-
(0, _vitest.expect)(back?.pending).toMatchObject({
|
|
228
|
-
toolId: "zustand",
|
|
229
|
-
action: "setState",
|
|
230
|
-
label: "Update the Poké Mart bag store",
|
|
231
|
-
params: {
|
|
232
|
-
storeName: "bag",
|
|
233
|
-
data: {
|
|
234
|
-
lines: []
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
(0, _vitest.it)("is saved again after it has already been restored once", () => {
|
|
240
|
-
// Reloading twice without answering must not be the thing that finally
|
|
241
|
-
// loses the question.
|
|
242
|
-
(0, _vitest.expect)(withPending({
|
|
243
|
-
restored: true
|
|
244
|
-
}).pending).toBeTruthy();
|
|
245
|
-
});
|
|
246
|
-
(0, _vitest.it)("is dropped rather than scrubbed when the call carries a credential", () => {
|
|
247
|
-
// Scrubbing would change the call: a redacted token written back is not
|
|
248
|
-
// the change the user was shown. So the card is lost instead — an action
|
|
249
|
-
// carrying a credential is the one that must not re-run itself unattended.
|
|
250
|
-
const saved = withPending({
|
|
251
|
-
params: {
|
|
252
|
-
key: "auth",
|
|
253
|
-
value: "Bearer abcdefghijklmnop123456"
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
(0, _vitest.expect)(saved.pending).toBeNull();
|
|
257
|
-
(0, _vitest.expect)(JSON.stringify(saved)).not.toContain("abcdefghijklmnop123456");
|
|
258
|
-
});
|
|
259
|
-
(0, _vitest.it)("reads back as absent from a transcript written before it existed", () => {
|
|
260
|
-
const old = build([msg()]);
|
|
261
|
-
(0, _vitest.expect)((0, _transcriptPersistence.parsePayload)(JSON.stringify(old))?.pending).toBeNull();
|
|
262
|
-
});
|
|
263
|
-
(0, _vitest.it)("refuses a malformed one rather than restoring half a question", () => {
|
|
264
|
-
const raw = JSON.stringify({
|
|
265
|
-
...build([msg()]),
|
|
266
|
-
pending: {
|
|
267
|
-
toolId: "zustand"
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
(0, _vitest.expect)((0, _transcriptPersistence.parsePayload)(raw)?.pending).toBeNull();
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* The undo bar, across a restart.
|
|
276
|
-
*
|
|
277
|
-
* The ledger is the ONLY undo surface and it used to die with the JS context:
|
|
278
|
-
* the transcript came back with its "saved" lines and receipt cards intact
|
|
279
|
-
* while the bar vanished and the changes stayed applied.
|
|
280
|
-
*/
|
|
281
|
-
(0, _vitest.describe)("the effect ledger", () => {
|
|
282
|
-
const entry = {
|
|
283
|
-
id: "fx-1-1",
|
|
284
|
-
at: 1,
|
|
285
|
-
toolId: "storage",
|
|
286
|
-
action: "async.setItem",
|
|
287
|
-
effect: {
|
|
288
|
-
kind: "storage-write",
|
|
289
|
-
toolId: "storage",
|
|
290
|
-
action: "async.setItem",
|
|
291
|
-
label: "Save @qa/key",
|
|
292
|
-
key: "@qa/key",
|
|
293
|
-
had: true,
|
|
294
|
-
previous: "old value"
|
|
295
|
-
}
|
|
296
|
-
};
|
|
297
|
-
const withLedger = entries => (0, _transcriptPersistence.buildPayload)({
|
|
298
|
-
messages: [msg()],
|
|
299
|
-
history: [],
|
|
300
|
-
answers: {},
|
|
301
|
-
usage: {
|
|
302
|
-
input: 0,
|
|
303
|
-
output: 0,
|
|
304
|
-
requests: 0
|
|
305
|
-
},
|
|
306
|
-
ledger: entries
|
|
307
|
-
});
|
|
308
|
-
(0, _vitest.it)("survives the round trip with the prior value an undo needs", () => {
|
|
309
|
-
const back = (0, _transcriptPersistence.parsePayload)(JSON.stringify(withLedger([entry])));
|
|
310
|
-
(0, _vitest.expect)(back?.ledger).toHaveLength(1);
|
|
311
|
-
(0, _vitest.expect)(back?.ledger?.[0]).toMatchObject({
|
|
312
|
-
toolId: "storage",
|
|
313
|
-
action: "async.setItem"
|
|
314
|
-
});
|
|
315
|
-
});
|
|
316
|
-
(0, _vitest.it)("drops an entry holding a credential rather than rewriting it", () => {
|
|
317
|
-
// Scrubbing would make the undo restore "[redacted]" over the real value.
|
|
318
|
-
const secret = {
|
|
319
|
-
...entry,
|
|
320
|
-
effect: {
|
|
321
|
-
...entry.effect,
|
|
322
|
-
previous: "Bearer abcdefghijklmnop123456"
|
|
323
|
-
}
|
|
324
|
-
};
|
|
325
|
-
const saved = withLedger([secret]);
|
|
326
|
-
(0, _vitest.expect)(saved.ledger).toBeUndefined();
|
|
327
|
-
(0, _vitest.expect)(JSON.stringify(saved)).not.toContain("abcdefghijklmnop123456");
|
|
328
|
-
});
|
|
329
|
-
(0, _vitest.it)("reads back as absent from a transcript written before it existed", () => {
|
|
330
|
-
(0, _vitest.expect)((0, _transcriptPersistence.parsePayload)(JSON.stringify(build([msg()])))?.ledger).toBeUndefined();
|
|
331
|
-
});
|
|
332
|
-
});
|
|
333
|
-
//# sourceMappingURL=transcriptPersistence.test.js.map
|
|
1
|
+
"use strict";var _vitest=require("vitest");var _transcriptPersistence=require("./transcriptPersistence");const msg=(e={})=>({id:"m1",role:"assistant",text:"ok",toolCalls:[],blocks:[],...e});const build=(e,s=[])=>(0,_transcriptPersistence.buildPayload)({messages:e,history:s,answers:{},usage:{input:0,output:0,requests:0}});(0,_vitest.describe)("what reaches the disk",()=>{(0,_vitest.it)("never writes a tool result",()=>{const e=[{role:"user",text:"what's in the bag?"},{role:"assistant",text:"",toolCalls:[{id:"c1",name:"buoy_zustand",input:{}}]},{role:"tool-results",results:[{toolCallId:"c1",content:'{"lines":[{"card":"4111111111111111"}]}'}]},{role:"assistant",text:"Five items."}];const s=build([msg()],e);const t=JSON.stringify(s);(0,_vitest.expect)(t).not.toContain("4111111111111111");(0,_vitest.expect)(s.history.map(a=>a.role)).toEqual(["user","assistant","tool-results","assistant"])});(0,_vitest.it)("never writes a step's result, even when it writes the step",()=>{const e=build([msg({toolCalls:[{id:"c1",toolId:"zustand",action:"getStoreState",label:"Read the bag",status:"ok",summary:"Done",params:'{"storeName":"bag"}',result:'{"card":"4111111111111111"}'}]})]);(0,_vitest.expect)(JSON.stringify(e)).not.toContain("4111111111111111");(0,_vitest.expect)(e.messages[0].toolCalls[0].result).toBeUndefined();(0,_vitest.expect)(e.messages[0].toolCalls[0].action).toBe("getStoreState")});(0,_vitest.it)("scrubs credential shapes out of what the agent said",()=>{const e=build([msg({text:"The header was Bearer abcdefghijklmnop123456"})]);(0,_vitest.expect)(e.messages[0].text).not.toContain("abcdefghijklmnop123456")});(0,_vitest.it)("caps a long session instead of growing a file forever",()=>{const e=Array.from({length:400},(t,a)=>msg({id:`m${a}`,text:`answer ${a}`}));const s=build(e);(0,_vitest.expect)(s.messages.length).toBeLessThanOrEqual(60);(0,_vitest.expect)(s.messages[s.messages.length-1].text).toBe("answer 399")});(0,_vitest.it)("drops from the oldest end until a heavy transcript fits",()=>{const e=Array.from({length:20},(t,a)=>msg({id:`m${a}`,text:"x".repeat(4e4)}));const s=(0,_transcriptPersistence.fitToCaps)({v:1,savedAt:0,messages:e,history:[],answers:{},usage:{input:0,output:0,requests:0}});(0,_vitest.expect)(JSON.stringify(s).length).toBeLessThanOrEqual(256e3);(0,_vitest.expect)(s.messages.length).toBeGreaterThan(0)})});(0,_vitest.describe)("what comes back",()=>{(0,_vitest.it)("marks a turn the app died in as interrupted rather than blank",()=>{const e=build([msg({text:"",streaming:true})]);(0,_vitest.expect)(e.messages[0].streaming).toBe(false);(0,_vitest.expect)(e.messages[0].error).toMatch(/interrupted/i)});(0,_vitest.it)("never restores a tool call still claiming to run",()=>{const e=build([msg({streaming:true,toolCalls:[{id:"c1",toolId:"storage",action:"set",label:"Write a key",status:"running"}]})]);(0,_vitest.expect)(e.messages[0].toolCalls[0].status).toBe("failed");(0,_vitest.expect)(e.messages[0].toolCalls[0].summary).toBe("Interrupted")});(0,_vitest.it)("keeps an answer that already finished exactly as it was",()=>{const e=build([msg({text:"Five items.",streaming:false})]);(0,_vitest.expect)(e.messages[0].error).toBeUndefined();(0,_vitest.expect)(e.messages[0].text).toBe("Five items.")});(0,_vitest.it)("treats anything it cannot trust as no transcript at all",()=>{(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(null)).toBeNull();(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)("not json")).toBeNull();(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(JSON.stringify({v:0,messages:[msg()]}))).toBeNull();(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(JSON.stringify({v:1,messages:[]}))).toBeNull()});(0,_vitest.it)("round-trips a real conversation",()=>{const e=build([msg({role:"user",text:"hi"}),msg({id:"m2",text:"hello"})]);const s=(0,_transcriptPersistence.parsePayload)(JSON.stringify(e));(0,_vitest.expect)(s?.messages.map(t=>t.text)).toEqual(["hi","hello"])})});(0,_vitest.describe)("an unanswered approval",()=>{const e={id:"c1",toolId:"zustand",action:"setState",label:"Update the Pok\xE9 Mart bag store",description:"Change a live zustand store.",reason:"This will change the app's state.",params:{storeName:"bag",data:{lines:[]}},resolve:()=>{}};const s=(t={})=>(0,_transcriptPersistence.buildPayload)({messages:[msg()],history:[],answers:{},usage:{input:0,output:0,requests:0},pending:{...e,...t}});(0,_vitest.it)("survives the round trip with the exact call it asked about",()=>{const t=(0,_transcriptPersistence.parsePayload)(JSON.stringify(s()));(0,_vitest.expect)(t?.pending).toMatchObject({toolId:"zustand",action:"setState",label:"Update the Pok\xE9 Mart bag store",params:{storeName:"bag",data:{lines:[]}}})});(0,_vitest.it)("is saved again after it has already been restored once",()=>{(0,_vitest.expect)(s({restored:true}).pending).toBeTruthy()});(0,_vitest.it)("is dropped rather than scrubbed when the call carries a credential",()=>{const t=s({params:{key:"auth",value:"Bearer abcdefghijklmnop123456"}});(0,_vitest.expect)(t.pending).toBeNull();(0,_vitest.expect)(JSON.stringify(t)).not.toContain("abcdefghijklmnop123456")});(0,_vitest.it)("reads back as absent from a transcript written before it existed",()=>{const t=build([msg()]);(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(JSON.stringify(t))?.pending).toBeNull()});(0,_vitest.it)("refuses a malformed one rather than restoring half a question",()=>{const t=JSON.stringify({...build([msg()]),pending:{toolId:"zustand"}});(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(t)?.pending).toBeNull()})});(0,_vitest.describe)("the effect ledger",()=>{const e={id:"fx-1-1",at:1,toolId:"storage",action:"async.setItem",effect:{kind:"storage-write",toolId:"storage",action:"async.setItem",label:"Save @qa/key",key:"@qa/key",had:true,previous:"old value"}};const s=t=>(0,_transcriptPersistence.buildPayload)({messages:[msg()],history:[],answers:{},usage:{input:0,output:0,requests:0},ledger:t});(0,_vitest.it)("survives the round trip with the prior value an undo needs",()=>{const t=(0,_transcriptPersistence.parsePayload)(JSON.stringify(s([e])));(0,_vitest.expect)(t?.ledger).toHaveLength(1);(0,_vitest.expect)(t?.ledger?.[0]).toMatchObject({toolId:"storage",action:"async.setItem"})});(0,_vitest.it)("drops an entry holding a credential rather than rewriting it",()=>{const t={...e,effect:{...e.effect,previous:"Bearer abcdefghijklmnop123456"}};const a=s([t]);(0,_vitest.expect)(a.ledger).toBeUndefined();(0,_vitest.expect)(JSON.stringify(a)).not.toContain("abcdefghijklmnop123456")});(0,_vitest.it)("reads back as absent from a transcript written before it existed",()=>{(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(JSON.stringify(build([msg()])))?.ledger).toBeUndefined()})});
|
|
@@ -1,151 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _vitest = require("vitest");
|
|
4
|
-
var _askBuoyStore = require("./askBuoyStore");
|
|
5
|
-
/**
|
|
6
|
-
* How the store folds a turn into one bubble.
|
|
7
|
-
*
|
|
8
|
-
* Both rules here were written from a real transcript: rounds of an answer
|
|
9
|
-
* arriving as separate text events were concatenated into
|
|
10
|
-
* "…resets every launch.Here's the full picture…", and a turn the user
|
|
11
|
-
* stopped was reported as "Couldn't reach your AI endpoint."
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
(0, _vitest.beforeEach)(() => _askBuoyStore.askBuoyStore.reset());
|
|
15
|
-
const lastText = () => _askBuoyStore.askBuoyStore.getState().messages.at(-1)?.text ?? "";
|
|
16
|
-
(0, _vitest.describe)("round boundaries", () => {
|
|
17
|
-
(0, _vitest.it)("opens a paragraph when the engine says a new round began", () => {
|
|
18
|
-
const id = _askBuoyStore.askBuoyStore.startAssistant();
|
|
19
|
-
_askBuoyStore.askBuoyStore.applyEvent(id, {
|
|
20
|
-
type: "text",
|
|
21
|
-
delta: "Wiping storage now."
|
|
22
|
-
});
|
|
23
|
-
_askBuoyStore.askBuoyStore.applyEvent(id, {
|
|
24
|
-
type: "text",
|
|
25
|
-
delta: "No problem — I left it alone.",
|
|
26
|
-
breakBefore: true
|
|
27
|
-
});
|
|
28
|
-
(0, _vitest.expect)(lastText()).toBe("Wiping storage now.\n\nNo problem — I left it alone.");
|
|
29
|
-
});
|
|
30
|
-
(0, _vitest.it)("still streams deltas within one round straight together", () => {
|
|
31
|
-
const id = _askBuoyStore.askBuoyStore.startAssistant();
|
|
32
|
-
_askBuoyStore.askBuoyStore.applyEvent(id, {
|
|
33
|
-
type: "text",
|
|
34
|
-
delta: "Hello"
|
|
35
|
-
});
|
|
36
|
-
_askBuoyStore.askBuoyStore.applyEvent(id, {
|
|
37
|
-
type: "text",
|
|
38
|
-
delta: " there."
|
|
39
|
-
});
|
|
40
|
-
(0, _vitest.expect)(lastText()).toBe("Hello there.");
|
|
41
|
-
});
|
|
42
|
-
(0, _vitest.it)("never opens with a blank line", () => {
|
|
43
|
-
const id = _askBuoyStore.askBuoyStore.startAssistant();
|
|
44
|
-
_askBuoyStore.askBuoyStore.applyEvent(id, {
|
|
45
|
-
type: "text",
|
|
46
|
-
delta: "First words.",
|
|
47
|
-
breakBefore: true
|
|
48
|
-
});
|
|
49
|
-
(0, _vitest.expect)(lastText()).toBe("First words.");
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
(0, _vitest.describe)("a declined call", () => {
|
|
53
|
-
(0, _vitest.it)("keeps its row and reads as declined, not failed", () => {
|
|
54
|
-
const id = _askBuoyStore.askBuoyStore.startAssistant();
|
|
55
|
-
_askBuoyStore.askBuoyStore.applyEvent(id, {
|
|
56
|
-
type: "tool-start",
|
|
57
|
-
id: "c1",
|
|
58
|
-
toolId: "storage",
|
|
59
|
-
action: "clearAll",
|
|
60
|
-
label: "Clear all saved app data",
|
|
61
|
-
description: "Wipe every stored key",
|
|
62
|
-
params: {},
|
|
63
|
-
effect: "destructive"
|
|
64
|
-
});
|
|
65
|
-
_askBuoyStore.askBuoyStore.applyEvent(id, {
|
|
66
|
-
type: "tool-end",
|
|
67
|
-
id: "c1",
|
|
68
|
-
ok: false,
|
|
69
|
-
summary: "declined",
|
|
70
|
-
durationMs: 0
|
|
71
|
-
});
|
|
72
|
-
(0, _vitest.expect)(_askBuoyStore.askBuoyStore.getState().messages.at(-1)?.toolCalls[0]).toMatchObject({
|
|
73
|
-
label: "Clear all saved app data",
|
|
74
|
-
status: "declined"
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
(0, _vitest.describe)("stop", () => {
|
|
79
|
-
(0, _vitest.it)("marks the turn stopped and leaves no error on it", () => {
|
|
80
|
-
const id = _askBuoyStore.askBuoyStore.startAssistant();
|
|
81
|
-
_askBuoyStore.askBuoyStore.applyEvent(id, {
|
|
82
|
-
type: "text",
|
|
83
|
-
delta: "Looking…"
|
|
84
|
-
});
|
|
85
|
-
_askBuoyStore.askBuoyStore.markStopped(id);
|
|
86
|
-
const m = _askBuoyStore.askBuoyStore.getState().messages.at(-1);
|
|
87
|
-
(0, _vitest.expect)(m?.stopped).toBe(true);
|
|
88
|
-
(0, _vitest.expect)(m?.error).toBeUndefined();
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Stop must not launch the messages parked behind it.
|
|
94
|
-
*
|
|
95
|
-
* Ending a turn is exactly what flushes the queue, so Stop used to send the
|
|
96
|
-
* parked message and start a NEW turn — pressing Stop made the agent start
|
|
97
|
-
* talking again. The queue now HOLDS after a stop (see `queuePauseReason`),
|
|
98
|
-
* and the words stay visible as rows rather than being dumped into the
|
|
99
|
-
* composer.
|
|
100
|
-
*/
|
|
101
|
-
(0, _vitest.describe)("stop and the queue", () => {
|
|
102
|
-
(0, _vitest.it)("keeps parked messages parked, and says why", () => {
|
|
103
|
-
_askBuoyStore.askBuoyStore.addUser("first");
|
|
104
|
-
const id = _askBuoyStore.askBuoyStore.startAssistant();
|
|
105
|
-
_askBuoyStore.askBuoyStore.enqueue("do this next");
|
|
106
|
-
_askBuoyStore.askBuoyStore.requestStop();
|
|
107
|
-
_askBuoyStore.askBuoyStore.markStopped(id);
|
|
108
|
-
_askBuoyStore.askBuoyStore.finishAssistant(id);
|
|
109
|
-
const s = _askBuoyStore.askBuoyStore.getState();
|
|
110
|
-
(0, _vitest.expect)(s.queued.map(q => q.text)).toEqual(["do this next"]);
|
|
111
|
-
(0, _vitest.expect)((0, _askBuoyStore.queuePauseReason)(s)).toMatch(/stopped/);
|
|
112
|
-
});
|
|
113
|
-
(0, _vitest.it)("hands one parked message back to the composer to edit", () => {
|
|
114
|
-
const item = _askBuoyStore.askBuoyStore.enqueue("words");
|
|
115
|
-
_askBuoyStore.askBuoyStore.takeQueuedToDraft(item.id);
|
|
116
|
-
(0, _vitest.expect)(_askBuoyStore.askBuoyStore.getState().queued).toEqual([]);
|
|
117
|
-
(0, _vitest.expect)(_askBuoyStore.askBuoyStore.getState().draft).toBe("words");
|
|
118
|
-
_askBuoyStore.askBuoyStore.clearDraft();
|
|
119
|
-
(0, _vitest.expect)(_askBuoyStore.askBuoyStore.getState().draft).toBeNull();
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* A restored bubble is marked, because the MODEL does not remember it the way
|
|
125
|
-
* the screen does — see `ChatMessage.restored`.
|
|
126
|
-
*/
|
|
127
|
-
(0, _vitest.describe)("hydrate", () => {
|
|
128
|
-
(0, _vitest.it)("marks what it puts back", () => {
|
|
129
|
-
_askBuoyStore.askBuoyStore.hydrate({
|
|
130
|
-
messages: [{
|
|
131
|
-
id: "m1",
|
|
132
|
-
role: "assistant",
|
|
133
|
-
text: "hi",
|
|
134
|
-
toolCalls: [],
|
|
135
|
-
blocks: []
|
|
136
|
-
}],
|
|
137
|
-
answers: {},
|
|
138
|
-
usage: {
|
|
139
|
-
input: 0,
|
|
140
|
-
output: 0,
|
|
141
|
-
requests: 0
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
(0, _vitest.expect)(_askBuoyStore.askBuoyStore.getState().messages[0]?.restored).toBe(true);
|
|
145
|
-
});
|
|
146
|
-
(0, _vitest.it)("leaves a live message unmarked", () => {
|
|
147
|
-
_askBuoyStore.askBuoyStore.addUser("live one");
|
|
148
|
-
(0, _vitest.expect)(_askBuoyStore.askBuoyStore.getState().messages[0]?.restored).toBeUndefined();
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
//# sourceMappingURL=turnRendering.test.js.map
|
|
1
|
+
"use strict";var _vitest=require("vitest");var _askBuoyStore=require("./askBuoyStore");(0,_vitest.beforeEach)(()=>_askBuoyStore.askBuoyStore.reset());const lastText=()=>_askBuoyStore.askBuoyStore.getState().messages.at(-1)?.text??"";(0,_vitest.describe)("round boundaries",()=>{(0,_vitest.it)("opens a paragraph when the engine says a new round began",()=>{const e=_askBuoyStore.askBuoyStore.startAssistant();_askBuoyStore.askBuoyStore.applyEvent(e,{type:"text",delta:"Wiping storage now."});_askBuoyStore.askBuoyStore.applyEvent(e,{type:"text",delta:"No problem \u2014 I left it alone.",breakBefore:true});(0,_vitest.expect)(lastText()).toBe("Wiping storage now.\n\nNo problem \u2014 I left it alone.")});(0,_vitest.it)("still streams deltas within one round straight together",()=>{const e=_askBuoyStore.askBuoyStore.startAssistant();_askBuoyStore.askBuoyStore.applyEvent(e,{type:"text",delta:"Hello"});_askBuoyStore.askBuoyStore.applyEvent(e,{type:"text",delta:" there."});(0,_vitest.expect)(lastText()).toBe("Hello there.")});(0,_vitest.it)("never opens with a blank line",()=>{const e=_askBuoyStore.askBuoyStore.startAssistant();_askBuoyStore.askBuoyStore.applyEvent(e,{type:"text",delta:"First words.",breakBefore:true});(0,_vitest.expect)(lastText()).toBe("First words.")})});(0,_vitest.describe)("a declined call",()=>{(0,_vitest.it)("keeps its row and reads as declined, not failed",()=>{const e=_askBuoyStore.askBuoyStore.startAssistant();_askBuoyStore.askBuoyStore.applyEvent(e,{type:"tool-start",id:"c1",toolId:"storage",action:"clearAll",label:"Clear all saved app data",description:"Wipe every stored key",params:{},effect:"destructive"});_askBuoyStore.askBuoyStore.applyEvent(e,{type:"tool-end",id:"c1",ok:false,summary:"declined",durationMs:0});(0,_vitest.expect)(_askBuoyStore.askBuoyStore.getState().messages.at(-1)?.toolCalls[0]).toMatchObject({label:"Clear all saved app data",status:"declined"})})});(0,_vitest.describe)("stop",()=>{(0,_vitest.it)("marks the turn stopped and leaves no error on it",()=>{const e=_askBuoyStore.askBuoyStore.startAssistant();_askBuoyStore.askBuoyStore.applyEvent(e,{type:"text",delta:"Looking\u2026"});_askBuoyStore.askBuoyStore.markStopped(e);const t=_askBuoyStore.askBuoyStore.getState().messages.at(-1);(0,_vitest.expect)(t?.stopped).toBe(true);(0,_vitest.expect)(t?.error).toBeUndefined()})});(0,_vitest.describe)("stop and the queue",()=>{(0,_vitest.it)("keeps parked messages parked, and says why",()=>{_askBuoyStore.askBuoyStore.addUser("first");const e=_askBuoyStore.askBuoyStore.startAssistant();_askBuoyStore.askBuoyStore.enqueue("do this next");_askBuoyStore.askBuoyStore.requestStop();_askBuoyStore.askBuoyStore.markStopped(e);_askBuoyStore.askBuoyStore.finishAssistant(e);const t=_askBuoyStore.askBuoyStore.getState();(0,_vitest.expect)(t.queued.map(s=>s.text)).toEqual(["do this next"]);(0,_vitest.expect)((0,_askBuoyStore.queuePauseReason)(t)).toMatch(/stopped/)});(0,_vitest.it)("hands one parked message back to the composer to edit",()=>{const e=_askBuoyStore.askBuoyStore.enqueue("words");_askBuoyStore.askBuoyStore.takeQueuedToDraft(e.id);(0,_vitest.expect)(_askBuoyStore.askBuoyStore.getState().queued).toEqual([]);(0,_vitest.expect)(_askBuoyStore.askBuoyStore.getState().draft).toBe("words");_askBuoyStore.askBuoyStore.clearDraft();(0,_vitest.expect)(_askBuoyStore.askBuoyStore.getState().draft).toBeNull()})});(0,_vitest.describe)("hydrate",()=>{(0,_vitest.it)("marks what it puts back",()=>{_askBuoyStore.askBuoyStore.hydrate({messages:[{id:"m1",role:"assistant",text:"hi",toolCalls:[],blocks:[]}],answers:{},usage:{input:0,output:0,requests:0}});(0,_vitest.expect)(_askBuoyStore.askBuoyStore.getState().messages[0]?.restored).toBe(true)});(0,_vitest.it)("leaves a live message unmarked",()=>{_askBuoyStore.askBuoyStore.addUser("live one");(0,_vitest.expect)(_askBuoyStore.askBuoyStore.getState().messages[0]?.restored).toBeUndefined()})});
|