@buoy-gg/ask-buoy 7.0.35 → 7.0.38
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 +73 -15
- package/lib/commonjs/blocks/AskBlocks.js +1 -338
- package/lib/commonjs/blocks/BlockRenderer.js +1 -250
- package/lib/commonjs/blocks/ChromePrototypes.js +1 -514
- package/lib/commonjs/blocks/DataBlocks.js +1 -688
- package/lib/commonjs/blocks/ExtraBlocks.js +1 -1854
- package/lib/commonjs/blocks/MediaBlocks.js +1 -140
- package/lib/commonjs/blocks/ReceiptBlocks.js +1 -586
- package/lib/commonjs/blocks/blockText.js +1 -0
- package/lib/commonjs/blocks/blockText.test.js +1 -0
- 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 -401
- package/lib/commonjs/blocks/primitivesIndex.js +1 -62
- package/lib/commonjs/components/ApprovalCard.js +1 -140
- package/lib/commonjs/components/AskBuoyHeader.js +1 -164
- package/lib/commonjs/components/AskBuoyIcon.js +1 -19
- package/lib/commonjs/components/AskBuoyModal.js +1 -353
- package/lib/commonjs/components/AskBuoySettings.js +1 -69
- package/lib/commonjs/components/ChangesBar.js +1 -211
- package/lib/commonjs/components/Composer.js +1 -175
- package/lib/commonjs/components/EmptyState.js +1 -154
- package/lib/commonjs/components/KeyboardPad.js +1 -0
- package/lib/commonjs/components/Markdown.js +1 -252
- package/lib/commonjs/components/MessageList.js +1 -683
- package/lib/commonjs/components/QueuedMessages.js +1 -0
- package/lib/commonjs/components/ThinkingStrip.js +1 -223
- package/lib/commonjs/components/TypingDots.js +1 -63
- package/lib/commonjs/components/markdownParse.js +1 -0
- package/lib/commonjs/components/markdownParse.test.js +1 -0
- package/lib/commonjs/components/useCopyAction.js +1 -50
- package/lib/commonjs/index.js +1 -252
- package/lib/commonjs/preset.js +1 -90
- package/lib/commonjs/store/activityGroups.js +1 -0
- package/lib/commonjs/store/activityGroups.test.js +1 -0
- package/lib/commonjs/store/askBuoySettings.js +1 -67
- package/lib/commonjs/store/askBuoyStore.js +1 -365
- package/lib/commonjs/store/blockPlacement.js +1 -0
- package/lib/commonjs/store/blockPlacement.test.js +1 -0
- package/lib/commonjs/store/queue.test.js +1 -0
- package/lib/commonjs/store/resetConversation.js +1 -0
- package/lib/commonjs/store/restorePending.test.js +1 -0
- package/lib/commonjs/store/restoredIds.test.js +1 -47
- package/lib/commonjs/store/suggestions.js +1 -0
- package/lib/commonjs/store/suggestions.test.js +1 -0
- package/lib/commonjs/store/systemLine.test.js +1 -0
- package/lib/commonjs/store/ticketPrompt.js +1 -0
- package/lib/commonjs/store/traceText.js +1 -81
- package/lib/commonjs/store/traceText.test.js +1 -112
- package/lib/commonjs/store/transcriptPersistence.js +1 -208
- package/lib/commonjs/store/transcriptPersistence.test.js +1 -185
- package/lib/commonjs/store/turnRendering.test.js +1 -0
- package/lib/commonjs/store/useAskBuoy.js +1 -400
- package/lib/commonjs/store/useAskBuoySettings.js +1 -14
- package/lib/commonjs/sync/askBuoySyncAdapter.js +1 -119
- 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 -245
- package/lib/module/blocks/ChromePrototypes.js +1 -503
- package/lib/module/blocks/DataBlocks.js +1 -674
- package/lib/module/blocks/ExtraBlocks.js +1 -1827
- package/lib/module/blocks/MediaBlocks.js +1 -135
- package/lib/module/blocks/ReceiptBlocks.js +1 -574
- package/lib/module/blocks/blockText.js +1 -0
- package/lib/module/blocks/blockText.test.js +1 -0
- 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 -389
- package/lib/module/blocks/primitivesIndex.js +1 -5
- package/lib/module/components/ApprovalCard.js +1 -135
- package/lib/module/components/AskBuoyHeader.js +1 -161
- package/lib/module/components/AskBuoyIcon.js +1 -8
- package/lib/module/components/AskBuoyModal.js +1 -348
- package/lib/module/components/AskBuoySettings.js +1 -64
- package/lib/module/components/ChangesBar.js +1 -206
- package/lib/module/components/Composer.js +1 -170
- package/lib/module/components/EmptyState.js +1 -149
- package/lib/module/components/KeyboardPad.js +1 -0
- package/lib/module/components/Markdown.js +1 -246
- package/lib/module/components/MessageList.js +1 -677
- package/lib/module/components/QueuedMessages.js +1 -0
- package/lib/module/components/ThinkingStrip.js +1 -218
- package/lib/module/components/TypingDots.js +1 -58
- package/lib/module/components/markdownParse.js +1 -0
- package/lib/module/components/markdownParse.test.js +1 -0
- package/lib/module/components/useCopyAction.js +1 -46
- package/lib/module/index.js +1 -34
- package/lib/module/preset.js +1 -73
- package/lib/module/store/activityGroups.js +1 -0
- package/lib/module/store/activityGroups.test.js +1 -0
- package/lib/module/store/askBuoySettings.js +1 -62
- package/lib/module/store/askBuoyStore.js +1 -361
- package/lib/module/store/blockPlacement.js +1 -0
- package/lib/module/store/blockPlacement.test.js +1 -0
- package/lib/module/store/queue.test.js +1 -0
- package/lib/module/store/resetConversation.js +1 -0
- package/lib/module/store/restorePending.test.js +1 -0
- package/lib/module/store/restoredIds.test.js +1 -46
- package/lib/module/store/suggestions.js +1 -0
- package/lib/module/store/suggestions.test.js +1 -0
- package/lib/module/store/systemLine.test.js +1 -0
- package/lib/module/store/ticketPrompt.js +1 -0
- package/lib/module/store/traceText.js +1 -75
- package/lib/module/store/traceText.test.js +1 -111
- package/lib/module/store/transcriptPersistence.js +1 -198
- package/lib/module/store/transcriptPersistence.test.js +1 -184
- package/lib/module/store/turnRendering.test.js +1 -0
- package/lib/module/store/useAskBuoy.js +1 -394
- package/lib/module/store/useAskBuoySettings.js +1 -9
- package/lib/module/sync/askBuoySyncAdapter.js +1 -114
- 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/DataBlocks.d.ts +11 -0
- package/lib/typescript/blocks/ExtraBlocks.d.ts +18 -2
- package/lib/typescript/blocks/blockText.d.ts +14 -0
- package/lib/typescript/blocks/blockText.test.d.ts +2 -0
- package/lib/typescript/blocks/primitives.d.ts +16 -1
- package/lib/typescript/components/ApprovalCard.d.ts +9 -1
- package/lib/typescript/components/AskBuoyHeader.d.ts +31 -1
- package/lib/typescript/components/Composer.d.ts +16 -1
- package/lib/typescript/components/EmptyState.d.ts +5 -1
- package/lib/typescript/components/KeyboardPad.d.ts +33 -0
- package/lib/typescript/components/Markdown.d.ts +0 -10
- package/lib/typescript/components/MessageList.d.ts +7 -2
- package/lib/typescript/components/QueuedMessages.d.ts +10 -0
- package/lib/typescript/components/markdownParse.d.ts +49 -0
- package/lib/typescript/components/markdownParse.test.d.ts +2 -0
- package/lib/typescript/preset.d.ts +4 -2
- package/lib/typescript/store/activityGroups.d.ts +29 -0
- package/lib/typescript/store/activityGroups.test.d.ts +2 -0
- package/lib/typescript/store/askBuoySettings.d.ts +22 -0
- package/lib/typescript/store/askBuoyStore.d.ts +174 -9
- package/lib/typescript/store/blockPlacement.d.ts +30 -0
- package/lib/typescript/store/blockPlacement.test.d.ts +2 -0
- package/lib/typescript/store/queue.test.d.ts +2 -0
- package/lib/typescript/store/resetConversation.d.ts +38 -0
- package/lib/typescript/store/restorePending.test.d.ts +2 -0
- package/lib/typescript/store/suggestions.d.ts +32 -0
- package/lib/typescript/store/suggestions.test.d.ts +2 -0
- package/lib/typescript/store/systemLine.test.d.ts +2 -0
- package/lib/typescript/store/ticketPrompt.d.ts +11 -0
- package/lib/typescript/store/transcriptPersistence.d.ts +41 -2
- package/lib/typescript/store/turnRendering.test.d.ts +2 -0
- package/lib/typescript/store/useAskBuoy.d.ts +26 -3
- package/lib/typescript/sync/askBuoySyncAdapter.d.ts +29 -6
- package/package.json +10 -10
- 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/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/Markdown.js.map +0 -1
- package/lib/commonjs/components/MessageList.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/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/askBuoySettings.js.map +0 -1
- package/lib/commonjs/store/askBuoyStore.js.map +0 -1
- package/lib/commonjs/store/restoredIds.test.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/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/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/Markdown.js.map +0 -1
- package/lib/module/components/MessageList.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/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/askBuoySettings.js.map +0 -1
- package/lib/module/store/askBuoyStore.js.map +0 -1
- package/lib/module/store/restoredIds.test.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/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/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/Markdown.d.ts.map +0 -1
- package/lib/typescript/components/MessageList.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/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/askBuoySettings.d.ts.map +0 -1
- package/lib/typescript/store/askBuoyStore.d.ts.map +0 -1
- package/lib/typescript/store/restoredIds.test.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/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,140 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* What Ask Buoy is allowed to put on the broker wire, and what it refuses to
|
|
5
|
-
* accept from it.
|
|
6
|
-
*
|
|
7
|
-
* Both directions matter. The broker has no authentication, accepts any client
|
|
8
|
-
* that calls itself "Dashboard", and forwards to every connected dashboard — it
|
|
9
|
-
* already broadcasts license keys that way. So: no tool results go out, and no
|
|
10
|
-
* remote client can make the agent say anything.
|
|
11
|
-
*/
|
|
12
|
-
import { beforeEach, describe, expect, it } from "vitest";
|
|
13
|
-
import { EffectLedger } from "@buoy-gg/agent-core";
|
|
14
|
-
import { askBuoySyncAdapter } from "./askBuoySyncAdapter";
|
|
15
|
-
import { redactForWire } from "./wire";
|
|
16
|
-
import { askBuoyStore } from "../store/askBuoyStore";
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
askBuoyStore.reset();
|
|
19
|
-
askBuoyStore.setLedger(null);
|
|
20
|
-
});
|
|
21
|
-
describe("the wire surface", () => {
|
|
22
|
-
it("exposes no action that can make the agent talk", () => {
|
|
23
|
-
// A `send` here would let anyone on the LAN drive a mutating agent on a
|
|
24
|
-
// tester's phone. The conversation starts on-device, by a person.
|
|
25
|
-
const actions = Object.keys(askBuoySyncAdapter.actions);
|
|
26
|
-
expect(actions).not.toContain("send");
|
|
27
|
-
expect(actions).not.toContain("ask");
|
|
28
|
-
expect(actions).not.toContain("prompt");
|
|
29
|
-
expect(actions.sort()).toEqual(["listChanges", "reset", "undoAll"]);
|
|
30
|
-
});
|
|
31
|
-
it("puts the shape of the conversation on the wire, never tool payloads", () => {
|
|
32
|
-
askBuoyStore.addUser("what is in storage");
|
|
33
|
-
const id = askBuoyStore.startAssistant();
|
|
34
|
-
askBuoyStore.applyEvent(id, {
|
|
35
|
-
type: "tool-start",
|
|
36
|
-
id: "c1",
|
|
37
|
-
toolId: "storage",
|
|
38
|
-
action: "async.getItem",
|
|
39
|
-
label: "Read session",
|
|
40
|
-
description: "Read one AsyncStorage key",
|
|
41
|
-
params: {
|
|
42
|
-
key: "session"
|
|
43
|
-
},
|
|
44
|
-
effect: "read"
|
|
45
|
-
});
|
|
46
|
-
askBuoyStore.applyEvent(id, {
|
|
47
|
-
type: "tool-end",
|
|
48
|
-
id: "c1",
|
|
49
|
-
ok: true,
|
|
50
|
-
durationMs: 12,
|
|
51
|
-
summary: "eyJhbGciOiJIUzI1NiJ9.super.secret"
|
|
52
|
-
});
|
|
53
|
-
const snap = askBuoySyncAdapter.getSnapshot();
|
|
54
|
-
const call = snap.messages[1].toolCalls[0];
|
|
55
|
-
expect(call).toEqual({
|
|
56
|
-
toolId: "storage",
|
|
57
|
-
action: "async.getItem",
|
|
58
|
-
status: "ok"
|
|
59
|
-
});
|
|
60
|
-
// The result summary is not on the wire at all — there is no field for it.
|
|
61
|
-
expect(JSON.stringify(snap)).not.toContain("super.secret");
|
|
62
|
-
});
|
|
63
|
-
it("redacts credentials that made it into the assistant's prose", () => {
|
|
64
|
-
askBuoyStore.addUser("show me the auth header");
|
|
65
|
-
const id = askBuoyStore.startAssistant();
|
|
66
|
-
askBuoyStore.applyEvent(id, {
|
|
67
|
-
type: "text",
|
|
68
|
-
delta: "It sends Authorization: Bearer abcdef0123456789ghijkl to the API."
|
|
69
|
-
});
|
|
70
|
-
const snap = askBuoySyncAdapter.getSnapshot();
|
|
71
|
-
expect(JSON.stringify(snap)).not.toContain("abcdef0123456789ghijkl");
|
|
72
|
-
});
|
|
73
|
-
it("reports reversible and permanent changes separately", () => {
|
|
74
|
-
const ledger = new EffectLedger();
|
|
75
|
-
askBuoyStore.setLedger(ledger);
|
|
76
|
-
ledger.record("storage", "async.setItem", {
|
|
77
|
-
kind: "storage-write",
|
|
78
|
-
toolId: "storage",
|
|
79
|
-
action: "async.setItem",
|
|
80
|
-
key: "points",
|
|
81
|
-
before: "240",
|
|
82
|
-
label: "Set points to 1500"
|
|
83
|
-
});
|
|
84
|
-
ledger.record("perf-monitor", "clearAll", {
|
|
85
|
-
kind: "transient",
|
|
86
|
-
label: "Cleared samples"
|
|
87
|
-
});
|
|
88
|
-
// A store write with no captured prior state: recorded, visible, and
|
|
89
|
-
// NOT something Undo can deliver — it must count as permanent.
|
|
90
|
-
ledger.record("zustand", "setState", {
|
|
91
|
-
kind: "state-write",
|
|
92
|
-
toolId: "zustand",
|
|
93
|
-
action: "setState",
|
|
94
|
-
label: "Update the cart store"
|
|
95
|
-
});
|
|
96
|
-
const snap = askBuoySyncAdapter.getSnapshot();
|
|
97
|
-
expect(snap.changes.reversible).toBe(1);
|
|
98
|
-
// The transient is an ACTION, not a change — it must not inflate
|
|
99
|
-
// "permanent" (that read "Changed this app · N permanent" after a
|
|
100
|
-
// read-only tour). It is still reported, in its own count.
|
|
101
|
-
expect(snap.changes.permanent).toBe(1);
|
|
102
|
-
expect(snap.changes.transients).toBe(1);
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
describe("redactForWire", () => {
|
|
106
|
-
it("removes bearer tokens, JWTs, api keys and license keys", () => {
|
|
107
|
-
const cases = ["Authorization: Bearer abcdefghijklmnop123456", "token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9abcdefgh", "key sk-abcdefghijklmnop1234", "license BUOY-ABCD-1234-EFGH", 'the header is "x-api-key": "supersecretvalue"'];
|
|
108
|
-
for (const input of cases) {
|
|
109
|
-
expect(redactForWire(input)).toContain("removed]");
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
it("leaves ordinary prose alone", () => {
|
|
113
|
-
const text = "The /menu call returned 200 with 12 items and the burger was in stock.";
|
|
114
|
-
expect(redactForWire(text)).toBe(text);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
describe("undo from the desktop", () => {
|
|
118
|
-
it("is allowed, because putting things back is the safe direction", async () => {
|
|
119
|
-
const ledger = new EffectLedger();
|
|
120
|
-
askBuoyStore.setLedger(ledger);
|
|
121
|
-
const store = new Map([["points", "1500"]]);
|
|
122
|
-
ledger.record("storage", "async.setItem", {
|
|
123
|
-
kind: "storage-write",
|
|
124
|
-
toolId: "storage",
|
|
125
|
-
action: "async.setItem",
|
|
126
|
-
key: "points",
|
|
127
|
-
before: "240",
|
|
128
|
-
label: "Set points to 1500"
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// The adapter dispatches through the real seam; stub it at the ledger.
|
|
132
|
-
await ledger.revertAll(async (_t, action, params) => {
|
|
133
|
-
const p = params;
|
|
134
|
-
if (action === "async.setItem") store.set(p.key, p.value);
|
|
135
|
-
return undefined;
|
|
136
|
-
});
|
|
137
|
-
expect(store.get("points")).toBe("240");
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
//# sourceMappingURL=askBuoySyncAdapter.test.js.map
|
|
1
|
+
"use strict";import{beforeEach,describe,expect,it}from"vitest";import{EffectLedger}from"@buoy-gg/agent-core";import{askBuoySyncAdapter}from"./askBuoySyncAdapter";import{redactForWire}from"./wire";import{askBuoyStore}from"../store/askBuoyStore";beforeEach(()=>{askBuoyStore.reset(),askBuoyStore.setLedger(null)}),describe("the wire surface",()=>{it("exposes no action that can make the agent talk",()=>{const e=Object.keys(askBuoySyncAdapter.actions);expect(e).not.toContain("send"),expect(e).not.toContain("ask"),expect(e).not.toContain("prompt"),expect(e.sort()).toEqual(["listChanges","reset","undoAll"])}),it("puts the shape of the conversation on the wire, never tool payloads",()=>{askBuoyStore.addUser("what is in storage");const e=askBuoyStore.startAssistant();askBuoyStore.applyEvent(e,{type:"tool-start",id:"c1",toolId:"storage",action:"async.getItem",label:"Read session",description:"Read one AsyncStorage key",params:{key:"session"},effect:"read"}),askBuoyStore.applyEvent(e,{type:"tool-end",id:"c1",ok:!0,durationMs:12,summary:"eyJhbGciOiJIUzI1NiJ9.super.secret"});const t=askBuoySyncAdapter.getSnapshot(),o=t.messages[1].toolCalls[0];expect(o).toEqual({toolId:"storage",action:"async.getItem",status:"ok"}),expect(JSON.stringify(t)).not.toContain("super.secret")}),it("redacts credentials that made it into the assistant's prose",()=>{askBuoyStore.addUser("show me the auth header");const e=askBuoyStore.startAssistant();askBuoyStore.applyEvent(e,{type:"text",delta:"It sends Authorization: Bearer abcdef0123456789ghijkl to the API."});const t=askBuoySyncAdapter.getSnapshot();expect(JSON.stringify(t)).not.toContain("abcdef0123456789ghijkl")}),it("reports reversible and permanent changes separately",()=>{const e=new EffectLedger;askBuoyStore.setLedger(e),e.record("storage","async.setItem",{kind:"storage-write",toolId:"storage",action:"async.setItem",key:"points",before:"240",label:"Set points to 1500"}),e.record("perf-monitor","clearAll",{kind:"transient",label:"Cleared samples"}),e.record("zustand","setState",{kind:"state-write",toolId:"zustand",action:"setState",label:"Update the cart store"});const t=askBuoySyncAdapter.getSnapshot();expect(t.changes.reversible).toBe(1),expect(t.changes.permanent).toBe(1),expect(t.changes.transients).toBe(1)})}),describe("redactForWire",()=>{it("removes bearer tokens, JWTs, api keys and license keys",()=>{const e=["Authorization: Bearer abcdefghijklmnop123456","token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9abcdefgh","key sk-abcdefghijklmnop1234","license BUOY-ABCD-1234-EFGH",'the header is "x-api-key": "supersecretvalue"'];for(const t of e)expect(redactForWire(t)).toContain("removed]")}),it("leaves ordinary prose alone",()=>{const e="The /menu call returned 200 with 12 items and the burger was in stock.";expect(redactForWire(e)).toBe(e)})}),describe("undo from the desktop",()=>{it("is allowed, because putting things back is the safe direction",async()=>{const e=new EffectLedger;askBuoyStore.setLedger(e);const t=new Map([["points","1500"]]);e.record("storage","async.setItem",{kind:"storage-write",toolId:"storage",action:"async.setItem",key:"points",before:"240",label:"Set points to 1500"}),await e.revertAll(async(e,o,s)=>{const a=s;"async.setItem"===o&&t.set(a.key,a.value)}),expect(t.get("points")).toBe("240")})});
|
package/lib/module/sync/wire.js
CHANGED
|
@@ -1,47 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* What the sync adapter is allowed to put on the broker wire.
|
|
5
|
-
*
|
|
6
|
-
* The broker has no authentication, `cors.origin: "*"`, binds every interface,
|
|
7
|
-
* and forwards to every connected dashboard — it already broadcasts each
|
|
8
|
-
* device's license key to every socket. A chat transcript is not a safe thing
|
|
9
|
-
* to add to that channel unfiltered: the agent reads storage values, network
|
|
10
|
-
* response bodies and user records, and any of it can end up quoted in an
|
|
11
|
-
* answer.
|
|
12
|
-
*
|
|
13
|
-
* So text crossing the wire is scrubbed for the shapes that are unambiguously
|
|
14
|
-
* credentials. This is a reduction in blast radius, not a guarantee — the real
|
|
15
|
-
* guarantee is that tool RESULTS never cross at all (see askBuoySyncAdapter).
|
|
16
|
-
*/
|
|
17
|
-
export { dispatchToolAction } from "@buoy-gg/shared-ui";
|
|
18
|
-
const PATTERNS = [{
|
|
19
|
-
re: /\bBearer\s+[A-Za-z0-9._~+/-]{12,}=*/gi,
|
|
20
|
-
label: "[bearer token removed]"
|
|
21
|
-
}, {
|
|
22
|
-
re: /\beyJ[A-Za-z0-9._-]{20,}/g,
|
|
23
|
-
label: "[jwt removed]"
|
|
24
|
-
}, {
|
|
25
|
-
re: /\bsk-[A-Za-z0-9_-]{16,}/g,
|
|
26
|
-
label: "[api key removed]"
|
|
27
|
-
}, {
|
|
28
|
-
re: /\bBUOY-[A-Z0-9-]{8,}/g,
|
|
29
|
-
label: "[license key removed]"
|
|
30
|
-
},
|
|
31
|
-
// Common "key: value" credential shapes in a quoted payload.
|
|
32
|
-
{
|
|
33
|
-
re: /("|')?(authorization|x-api-key|api[_-]?key|password|secret|access_token|refresh_token)\1?\s*[:=]\s*("|')?[^\s"',}]{6,}/gi,
|
|
34
|
-
label: "[credential removed]"
|
|
35
|
-
}];
|
|
36
|
-
export function redactForWire(text) {
|
|
37
|
-
if (!text) return text;
|
|
38
|
-
let out = text;
|
|
39
|
-
for (const {
|
|
40
|
-
re,
|
|
41
|
-
label
|
|
42
|
-
} of PATTERNS) {
|
|
43
|
-
out = out.replace(re, label);
|
|
44
|
-
}
|
|
45
|
-
return out;
|
|
46
|
-
}
|
|
47
|
-
//# sourceMappingURL=wire.js.map
|
|
1
|
+
"use strict";export{dispatchToolAction}from"@buoy-gg/shared-ui";const PATTERNS=[{re:/\bBearer\s+[A-Za-z0-9._~+/-]{12,}=*/gi,label:"[bearer token removed]"},{re:/\beyJ[A-Za-z0-9._-]{20,}/g,label:"[jwt removed]"},{re:/\bsk-[A-Za-z0-9_-]{16,}/g,label:"[api key removed]"},{re:/\bBUOY-[A-Z0-9-]{8,}/g,label:"[license key removed]"},{re:/("|')?(authorization|x-api-key|api[_-]?key|password|secret|access_token|refresh_token)\1?\s*[:=]\s*("|')?[^\s"',}]{6,}/gi,label:"[credential removed]"}];export function redactForWire(e){if(!e)return e;let r=e;for(const{re:e,label:o}of PATTERNS)r=r.replace(e,o);return r}
|
package/lib/module/types.js
CHANGED
|
@@ -34,6 +34,17 @@ export declare function listRowBehaviour(item: Pick<ListBlock["items"][number],
|
|
|
34
34
|
export declare function List({ block }: {
|
|
35
35
|
block: ListBlock;
|
|
36
36
|
}): import("react").JSX.Element;
|
|
37
|
+
/**
|
|
38
|
+
* What a write changed. Folded by default (see `Card`), and drilled into
|
|
39
|
+
* rather than dumped.
|
|
40
|
+
*
|
|
41
|
+
* A changed field is rendered by the same tree diff viewer the Zustand and
|
|
42
|
+
* Storage tools use, with unchanged branches hidden — so editing one line of a
|
|
43
|
+
* bag shows `qty 4 => 14` and not both copies of a fifty-key array serialised
|
|
44
|
+
* to JSON, which is what the reader was given before and could not read. Only
|
|
45
|
+
* a scalar keeps the plain −/+ pair: a tree of one root node says less than
|
|
46
|
+
* the two values side by side.
|
|
47
|
+
*/
|
|
37
48
|
export declare function Diff({ block }: {
|
|
38
49
|
block: DiffBlock;
|
|
39
50
|
}): import("react").JSX.Element;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Second-wave blocks from the survey (plan §11). Prototype-quality on purpose:
|
|
3
|
+
* each one exists so it can be judged on the review page, and the ones that
|
|
4
|
+
* survive get the same care as the first wave.
|
|
5
|
+
*/
|
|
6
|
+
import { type ReactNode } from "react";
|
|
7
|
+
import type { BannerBlock, Block, CardBlock, CardCarouselBlock, CheckpointBlock, ClaimBlock, CompareBlock, DateTimeBlock, DetailsBlock, FileBlock, FormBlock, MultiSelectBlock, PlanBlock, ProposalBlock, ScreenshotBlock, SelectBlock, SliderBlock, SparklineBlock, SuggestionsBlock, TabsBlock, TaskBlock, TimelineBlock, UploadBlock } from "@buoy-gg/agent-core";
|
|
2
8
|
export declare function Suggestions({ block }: {
|
|
3
9
|
block: SuggestionsBlock;
|
|
4
10
|
}): import("react").JSX.Element;
|
|
@@ -37,8 +43,18 @@ export declare function Details({ block }: {
|
|
|
37
43
|
* Keyed by INDEX, not label: two tabs may legitimately share a label, and a
|
|
38
44
|
* duplicate key would collapse them into one.
|
|
39
45
|
*/
|
|
40
|
-
export declare function Tabs({ block }: {
|
|
46
|
+
export declare function Tabs({ block, renderNested, }: {
|
|
41
47
|
block: TabsBlock;
|
|
48
|
+
/**
|
|
49
|
+
* Renders the block inside the active tab.
|
|
50
|
+
*
|
|
51
|
+
* Passed in rather than imported: this is the only place a block renders
|
|
52
|
+
* another block, and importing BlockRenderer here closed a require cycle
|
|
53
|
+
* (BlockRenderer -> ExtraBlocks -> BlockRenderer) that Metro warned about on
|
|
54
|
+
* every launch — the kind that leaves one of the two modules holding
|
|
55
|
+
* uninitialised values depending on which is reached first.
|
|
56
|
+
*/
|
|
57
|
+
renderNested?: (block: Block) => ReactNode;
|
|
42
58
|
}): import("react").JSX.Element;
|
|
43
59
|
export declare function Timeline({ block }: {
|
|
44
60
|
block: TimelineBlock;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blocks as plain text — for Copy, and for the ticket draft's own Copy.
|
|
3
|
+
*
|
|
4
|
+
* `transcriptToText` used to serialise prose and tool rows only, so a
|
|
5
|
+
* conversation whose whole point was the finding card at the end pasted into
|
|
6
|
+
* Jira WITHOUT the finding. Covers the kinds that carry facts a person would
|
|
7
|
+
* paste; everything else becomes one line naming what was on screen, so the
|
|
8
|
+
* paste says a card existed rather than silently skipping it.
|
|
9
|
+
*/
|
|
10
|
+
import type { Block } from "@buoy-gg/agent-core";
|
|
11
|
+
export declare function blockToText(block: Block): string | null;
|
|
12
|
+
/** Several blocks, blank-line separated, skipping the ones with nothing to say. */
|
|
13
|
+
export declare function blocksToText(blocks: Block[]): string[];
|
|
14
|
+
//# sourceMappingURL=blockText.d.ts.map
|
|
@@ -10,12 +10,27 @@ export declare function toneColor(tone?: Tone): string;
|
|
|
10
10
|
export declare function ProvenanceBadge({ source }: {
|
|
11
11
|
source?: Provenance;
|
|
12
12
|
}): import("react").JSX.Element | null;
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* The block card. Optionally folds its body away behind a one-line summary.
|
|
15
|
+
*
|
|
16
|
+
* A card is `collapsible` when its body is reference material rather than the
|
|
17
|
+
* answer — raw JSON, a field-by-field diff, anything a person reads only when
|
|
18
|
+
* they have a reason to. It stays folded until asked, because the chat is what
|
|
19
|
+
* the reader came for and a screen of `promoCode: null` buries it. What must
|
|
20
|
+
* NEVER fold is the part that carries meaning without being read: the title
|
|
21
|
+
* and the provenance badge stay on the face of the card in both states, so
|
|
22
|
+
* "CHANGED BY ASK BUOY" can't be hidden by the same tap that hides the detail.
|
|
23
|
+
*/
|
|
24
|
+
export declare function Card({ title, source, children, testID, tone, collapsible, summary, }: {
|
|
14
25
|
title?: string;
|
|
15
26
|
source?: Provenance;
|
|
16
27
|
children: ReactNode;
|
|
17
28
|
testID?: string;
|
|
18
29
|
tone?: "warning" | "danger" | "info";
|
|
30
|
+
/** Fold `children` away behind `summary`, closed until tapped. */
|
|
31
|
+
collapsible?: boolean;
|
|
32
|
+
/** The one line that stands in for the folded body. Says what is inside it. */
|
|
33
|
+
summary?: string;
|
|
19
34
|
}): import("react").JSX.Element;
|
|
20
35
|
export interface Paged<T> {
|
|
21
36
|
visible: T[];
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import type { ApprovalAnswer } from "@buoy-gg/agent-core";
|
|
1
2
|
import type { PendingApproval } from "../store/askBuoyStore";
|
|
2
3
|
export interface ApprovalCardProps {
|
|
3
4
|
pending: PendingApproval;
|
|
4
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The answer in full. A note typed before "Not now" goes to the model
|
|
7
|
+
* verbatim — "just the second line", not another round of "what would you
|
|
8
|
+
* prefer?". "Allow for this chat" is `trust`: no card for this action again
|
|
9
|
+
* this conversation (the settings sheet lists it and can forget it). Never
|
|
10
|
+
* offered on a restored card: there is no live turn to trust.
|
|
11
|
+
*/
|
|
12
|
+
onAnswer: (answer: ApprovalAnswer) => void;
|
|
5
13
|
}
|
|
6
14
|
export declare function ApprovalCard({ pending, onAnswer }: ApprovalCardProps): import("react").JSX.Element;
|
|
7
15
|
//# sourceMappingURL=ApprovalCard.d.ts.map
|
|
@@ -5,6 +5,30 @@ export interface AskBuoyHeaderProps {
|
|
|
5
5
|
failed?: boolean;
|
|
6
6
|
/** Title of the tool call in flight, if any. */
|
|
7
7
|
activeLabel: string | null;
|
|
8
|
+
/**
|
|
9
|
+
* When the running turn began (the streaming message's `startedAt`), so the
|
|
10
|
+
* subtitle can carry an elapsed clock — "Reading storage · 1m 04s".
|
|
11
|
+
*
|
|
12
|
+
* A turn can run three minutes, and "Thinking…" at four seconds looked
|
|
13
|
+
* identical to "Thinking…" at two minutes forty; then "This is taking too
|
|
14
|
+
* long" arrived from nowhere. The clock is computed from the timestamp on
|
|
15
|
+
* every tick rather than counted, so minimise/resume shows the true number,
|
|
16
|
+
* and it lives in the HEADER only — the transcript does not re-render once
|
|
17
|
+
* a second for it.
|
|
18
|
+
*/
|
|
19
|
+
startedAt?: number | null;
|
|
20
|
+
/** Stop was pressed and the engine is winding down between calls. */
|
|
21
|
+
stopping?: boolean;
|
|
22
|
+
/** The device's Read only toggle is on — said in the subtitle so a shared phone can't hide it. */
|
|
23
|
+
readOnly?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* An approval card is on screen.
|
|
26
|
+
*
|
|
27
|
+
* The turn is technically still open, so `busy` is true and the subtitle
|
|
28
|
+
* read "Thinking…" — while nothing was thinking and the sheet was in fact
|
|
29
|
+
* waiting on the person looking at it.
|
|
30
|
+
*/
|
|
31
|
+
awaitingApproval?: boolean;
|
|
8
32
|
toolCount: number;
|
|
9
33
|
hasMessages: boolean;
|
|
10
34
|
onBack?: () => void;
|
|
@@ -19,6 +43,12 @@ export interface AskBuoyHeaderProps {
|
|
|
19
43
|
getTranscript?: () => string;
|
|
20
44
|
/** Open the settings view. Omitted where there is nowhere to go (demos). */
|
|
21
45
|
onOpenSettings?: () => void;
|
|
46
|
+
/**
|
|
47
|
+
* Ask the agent for a ticket draft — a `finding` card summarising the
|
|
48
|
+
* session. Lives in the header because the moment you want it is after the
|
|
49
|
+
* conversation, not mid-answer; disabled while a turn runs.
|
|
50
|
+
*/
|
|
51
|
+
onTicket?: () => void;
|
|
22
52
|
}
|
|
23
|
-
export declare function AskBuoyHeader({ configured, busy, failed, activeLabel, toolCount, hasMessages, onBack, onReset, getTranscript, onOpenSettings, }: AskBuoyHeaderProps): import("react").JSX.Element;
|
|
53
|
+
export declare function AskBuoyHeader({ configured, busy, failed, activeLabel, awaitingApproval, startedAt, stopping, readOnly, toolCount, hasMessages, onBack, onReset, getTranscript, onOpenSettings, onTicket, }: AskBuoyHeaderProps): import("react").JSX.Element;
|
|
24
54
|
//# sourceMappingURL=AskBuoyHeader.d.ts.map
|
|
@@ -2,8 +2,23 @@ export interface ComposerProps {
|
|
|
2
2
|
onSend: (text: string) => void;
|
|
3
3
|
onStop: () => void;
|
|
4
4
|
busy: boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Text handed back from a stopped turn's queue — see `AskBuoyState.draft`.
|
|
7
|
+
* Restored into the input instead of being sent, so Stop can cancel
|
|
8
|
+
* everything without losing the words the user had already typed.
|
|
9
|
+
*/
|
|
10
|
+
draft?: string | null;
|
|
11
|
+
onDraftTaken?: () => void;
|
|
5
12
|
disabled?: boolean;
|
|
6
13
|
placeholder?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Ask for focus. Each new non-null value focuses the input once — the
|
|
16
|
+
* redirect after Stop ("tell it what to do differently") is only an
|
|
17
|
+
* invitation if the keyboard is up. Ignored while `canFocus` is false: a
|
|
18
|
+
* hidden sheet must never summon the keyboard over the app.
|
|
19
|
+
*/
|
|
20
|
+
focusKey?: string | null;
|
|
21
|
+
canFocus?: boolean;
|
|
7
22
|
}
|
|
8
|
-
export declare function Composer({ onSend, onStop, busy, disabled, placeholder, }: ComposerProps): import("react").JSX.Element;
|
|
23
|
+
export declare function Composer({ onSend, onStop, busy, draft, onDraftTaken, disabled, placeholder, focusKey, canFocus, }: ComposerProps): import("react").JSX.Element;
|
|
9
24
|
//# sourceMappingURL=Composer.d.ts.map
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export interface EmptyStateProps {
|
|
2
2
|
configured: boolean;
|
|
3
3
|
onPick: (text: string) => void;
|
|
4
|
+
/** Tools registered on this device right now — chips needing others are left out. */
|
|
5
|
+
availableToolIds?: string[];
|
|
6
|
+
/** Effective read-only (app or device) — chips that ask for a change are left out. */
|
|
7
|
+
readOnly?: boolean;
|
|
4
8
|
}
|
|
5
|
-
export declare function EmptyState({ configured, onPick }: EmptyStateProps): import("react").JSX.Element;
|
|
9
|
+
export declare function EmptyState({ configured, onPick, availableToolIds, readOnly }: EmptyStateProps): import("react").JSX.Element;
|
|
6
10
|
//# sourceMappingURL=EmptyState.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps the composer above the iOS keyboard.
|
|
3
|
+
*
|
|
4
|
+
* Why not `KeyboardAvoidingView`: it takes its frame from `onLayout`, which
|
|
5
|
+
* is RELATIVE TO ITS PARENT, and compares that to the keyboard's SCREEN
|
|
6
|
+
* position. That only agrees when the view starts at the window's origin.
|
|
7
|
+
* Ask Buoy is a JsModal — an absolutely positioned sheet anchored to the
|
|
8
|
+
* bottom of the app tree — so the view's local bottom (a few hundred points
|
|
9
|
+
* into the sheet) sits well above the keyboard's screen Y, the overlap comes
|
|
10
|
+
* out as zero, and nothing moves. The keyboard drew over the composer with
|
|
11
|
+
* a "working" `KeyboardAvoidingView` around it.
|
|
12
|
+
*
|
|
13
|
+
* This measures the SAME thing in the SAME coordinate space: the wrapper's
|
|
14
|
+
* bottom edge in window coordinates via `measureInWindow`, against the
|
|
15
|
+
* keyboard's `endCoordinates.screenY`. The difference is the overlap, and it
|
|
16
|
+
* becomes bottom padding animated over the keyboard's own duration so the
|
|
17
|
+
* composer rides the keyboard instead of jumping after it.
|
|
18
|
+
*
|
|
19
|
+
* The wrapper is `flex: 1` inside a fixed-height sheet body, so its OUTER
|
|
20
|
+
* bounds never change when its padding does — re-measuring on a later
|
|
21
|
+
* frame-change event (a predictive-text bar appearing, an emoji keyboard)
|
|
22
|
+
* gives the same bottom edge.
|
|
23
|
+
*
|
|
24
|
+
* iOS only. Android's window resizes under the keyboard
|
|
25
|
+
* (`softwareKeyboardLayoutMode: "resize"`, both the Expo and the RN CLI
|
|
26
|
+
* template default) and a bottom-anchored sheet rides up for free; padding
|
|
27
|
+
* there would lift it twice. Web has no keyboard events and no keyboard.
|
|
28
|
+
*/
|
|
29
|
+
import { type ReactNode } from "react";
|
|
30
|
+
export declare function KeyboardPad({ children }: {
|
|
31
|
+
children: ReactNode;
|
|
32
|
+
}): import("react").JSX.Element;
|
|
33
|
+
//# sourceMappingURL=KeyboardPad.d.ts.map
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Just enough Markdown for a chat answer.
|
|
3
|
-
*
|
|
4
|
-
* Models write `**bold**`, bullet lists and `code` whether or not the prompt
|
|
5
|
-
* asks for prose, and the asterisks rendered raw made every answer look like
|
|
6
|
-
* a broken template. This handles the subset a chat actually receives —
|
|
7
|
-
* paragraphs, `-`/`*`/`1.` lists, `#` headings (rendered bold, not huge),
|
|
8
|
-
* bold, italics and inline code — with no dependency and no HTML. Anything it
|
|
9
|
-
* does not understand falls through as plain text, never as a blank.
|
|
10
|
-
*/
|
|
11
1
|
import { type TextStyle } from "react-native";
|
|
12
2
|
/**
|
|
13
3
|
* `**bold**`, `*italic*` / `_italic_`, `` `code` `` → styled spans. Links and
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ChatMessage } from "../store/askBuoyStore";
|
|
2
2
|
/**
|
|
3
3
|
* The whole conversation as plain text — the only thing Copy ever produces,
|
|
4
4
|
* and the only way a session leaves the DEVICE (what it saves to disk for a
|
|
@@ -20,6 +20,11 @@ export interface MessageListProps {
|
|
|
20
20
|
ListFooterComponent?: React.ReactElement | null;
|
|
21
21
|
/** Re-run the last user message. Offered only on the newest failed turn. */
|
|
22
22
|
onRetry?: () => void;
|
|
23
|
+
/**
|
|
24
|
+
* The turn is parked on the user — a pending approval or an unanswered Ask
|
|
25
|
+
* block. Stops the streaming message claiming to be working on it.
|
|
26
|
+
*/
|
|
27
|
+
waitingOnUser?: boolean;
|
|
23
28
|
}
|
|
24
|
-
export declare function MessageList({ messages, ListHeaderComponent, ListEmptyComponent, ListFooterComponent, onRetry, }: MessageListProps): import("react").JSX.Element;
|
|
29
|
+
export declare function MessageList({ messages, ListHeaderComponent, ListEmptyComponent, ListFooterComponent, onRetry, waitingOnUser, }: MessageListProps): import("react").JSX.Element;
|
|
25
30
|
//# sourceMappingURL=MessageList.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { QueuedMessage } from "../store/askBuoyStore";
|
|
2
|
+
export interface QueuedMessagesProps {
|
|
3
|
+
items: QueuedMessage[];
|
|
4
|
+
/** Why nothing is being sent — or null while the queue will deliver. */
|
|
5
|
+
paused: string | null;
|
|
6
|
+
onEdit: (id: string) => void;
|
|
7
|
+
onRemove: (id: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function QueuedMessages({ items, paused, onEdit, onRemove }: QueuedMessagesProps): import("react").JSX.Element | null;
|
|
10
|
+
//# sourceMappingURL=QueuedMessages.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Markdown parser, kept apart from the renderer so it can be unit-tested
|
|
3
|
+
* without React Native.
|
|
4
|
+
*
|
|
5
|
+
* Just enough for a chat answer: paragraphs, `-`/`*`/`1.` lists, `#` headings,
|
|
6
|
+
* pipe tables, and fenced code. Anything it does not understand falls through
|
|
7
|
+
* as plain text, never as a blank.
|
|
8
|
+
*/
|
|
9
|
+
export type MdBlock = {
|
|
10
|
+
kind: "p";
|
|
11
|
+
text: string;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "h";
|
|
14
|
+
text: string;
|
|
15
|
+
} | {
|
|
16
|
+
kind: "li";
|
|
17
|
+
text: string;
|
|
18
|
+
marker: string;
|
|
19
|
+
depth: number;
|
|
20
|
+
} | {
|
|
21
|
+
kind: "table";
|
|
22
|
+
header: string[];
|
|
23
|
+
rows: string[][];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A fenced block. `closed` is false while the stream is still inside it;
|
|
27
|
+
* it renders as code either way — a half-arrived JSON blob shown as code is
|
|
28
|
+
* readable, the same blob shown as a run-on paragraph with its fence
|
|
29
|
+
* markers is not.
|
|
30
|
+
*/
|
|
31
|
+
| {
|
|
32
|
+
kind: "code";
|
|
33
|
+
lang: string;
|
|
34
|
+
text: string;
|
|
35
|
+
closed: boolean;
|
|
36
|
+
};
|
|
37
|
+
export declare function parseBlocks(source: string): MdBlock[];
|
|
38
|
+
/** The preview a table is cut to. Past this it says so and offers the rest. */
|
|
39
|
+
export declare const TABLE_PREVIEW_ROWS = 12;
|
|
40
|
+
export declare const TABLE_PREVIEW_COLS = 4;
|
|
41
|
+
/**
|
|
42
|
+
* What a table preview leaves out, in the user's words — or null when nothing.
|
|
43
|
+
*
|
|
44
|
+
* The renderer used to slice to 4 columns and 12 rows and say nothing, so a
|
|
45
|
+
* 30-line bag read as a 12-line bag and the bug report that followed was
|
|
46
|
+
* "the bag only has 12 items". Evidence that is cut must say it is cut.
|
|
47
|
+
*/
|
|
48
|
+
export declare function tableTruncation(header: string[], rows: string[][]): string | null;
|
|
49
|
+
//# sourceMappingURL=markdownParse.d.ts.map
|
|
@@ -20,8 +20,9 @@ export declare const askBuoyToolPreset: {
|
|
|
20
20
|
description: string;
|
|
21
21
|
slot: "both";
|
|
22
22
|
color: string;
|
|
23
|
-
icon: ({ size,
|
|
23
|
+
icon: ({ size, slot }: {
|
|
24
24
|
size: number;
|
|
25
|
+
slot?: string;
|
|
25
26
|
color?: string;
|
|
26
27
|
}) => import("react").JSX.Element;
|
|
27
28
|
component: typeof AskBuoyModal;
|
|
@@ -53,8 +54,9 @@ export declare function createAskBuoyTool(config: AskBuoyToolConfig): {
|
|
|
53
54
|
id: string;
|
|
54
55
|
slot: "both";
|
|
55
56
|
color: string;
|
|
56
|
-
icon: ({ size,
|
|
57
|
+
icon: ({ size, slot }: {
|
|
57
58
|
size: number;
|
|
59
|
+
slot?: string;
|
|
58
60
|
color?: string;
|
|
59
61
|
}) => import("react").JSX.Element;
|
|
60
62
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ChatToolCall } from "./askBuoyStore";
|
|
2
|
+
export type ActivityItem = {
|
|
3
|
+
kind: "call";
|
|
4
|
+
call: ChatToolCall;
|
|
5
|
+
} | {
|
|
6
|
+
kind: "reads";
|
|
7
|
+
id: string;
|
|
8
|
+
calls: ChatToolCall[];
|
|
9
|
+
label: string;
|
|
10
|
+
count: number;
|
|
11
|
+
};
|
|
12
|
+
export declare function groupCalls(calls: ChatToolCall[]): ActivityItem[];
|
|
13
|
+
/**
|
|
14
|
+
* "48s · 6 actions · 1 declined" — the line under a finished answer.
|
|
15
|
+
*
|
|
16
|
+
* "Actions" is tool calls, not provider rounds: rounds are an implementation
|
|
17
|
+
* detail nobody outside the engine can count. Failed, refused, declined and
|
|
18
|
+
* stopped are listed separately because they are different outcomes — a
|
|
19
|
+
* failed exploratory read the agent recovered from is not a failed task. No
|
|
20
|
+
* duration is invented when the message has no start time (a restored note).
|
|
21
|
+
*/
|
|
22
|
+
export declare function turnFooter(message: {
|
|
23
|
+
startedAt?: number;
|
|
24
|
+
endedAt?: number;
|
|
25
|
+
toolCalls: ChatToolCall[];
|
|
26
|
+
}): string | null;
|
|
27
|
+
/** "4s", "1m 04s", "1h 02m". Compact, for a subtitle or a footer. */
|
|
28
|
+
export declare function formatElapsed(ms: number): string;
|
|
29
|
+
//# sourceMappingURL=activityGroups.d.ts.map
|
|
@@ -10,6 +10,28 @@ export interface AskBuoySettings {
|
|
|
10
10
|
* the clipboard: the reading happens outside the app.
|
|
11
11
|
*/
|
|
12
12
|
showThinking: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Run everything the agent asks for without the "Allow this change?" card.
|
|
15
|
+
*
|
|
16
|
+
* Off by default, and persisted like every other preference here — a person
|
|
17
|
+
* moving fast on their own dev device should not have to re-say it after
|
|
18
|
+
* every reload, and the sheet's own settings row is where they find out it
|
|
19
|
+
* is still on. It waives the approval GATES only: an app's `deny`, `allow`,
|
|
20
|
+
* `readOnly` and the release-build refusals are the app saying no rather
|
|
21
|
+
* than asking, and this must never widen what the agent can reach.
|
|
22
|
+
*/
|
|
23
|
+
bypassApprovals: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Look, don't touch: refuse every write on this device until turned off.
|
|
26
|
+
*
|
|
27
|
+
* For a support person on a shared phone who wants to inspect a customer's
|
|
28
|
+
* state with zero risk. `policy.readOnly` is the app's to set at build
|
|
29
|
+
* time; this is the person holding the phone setting it. Effective policy
|
|
30
|
+
* is app OR device, so this can only narrow what the agent may do — turning
|
|
31
|
+
* it off never switches off an app's own read-only. Persisted like the
|
|
32
|
+
* others, which on a shared device means: check the subtitle.
|
|
33
|
+
*/
|
|
34
|
+
readOnly: boolean;
|
|
13
35
|
}
|
|
14
36
|
export declare const DEFAULT_SETTINGS: AskBuoySettings;
|
|
15
37
|
export declare const askBuoySettings: {
|