@burdenoff/fe-libs 2026.906.6 → 2026.907.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/shared/assistant/api.d.ts +18 -0
- package/dist/shared/assistant/api.d.ts.map +1 -1
- package/dist/shared/assistant/api.js +22 -18
- package/dist/shared/assistant/pendingWrite.d.ts +13 -0
- package/dist/shared/assistant/pendingWrite.d.ts.map +1 -1
- package/dist/shared/assistant/pendingWrite.js +48 -42
- package/dist/shared/assistant/quota.d.ts +30 -0
- package/dist/shared/assistant/quota.d.ts.map +1 -1
- package/dist/shared/assistant/quota.js +33 -2
- package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantChatArea.js +260 -228
- package/dist/shared/assistant/ui/AssistantMessageItem.d.ts +4 -0
- package/dist/shared/assistant/ui/AssistantMessageItem.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantMessageItem.js +54 -50
- package/dist/shared/assistant/ui/AssistantMessageList.d.ts +3 -0
- package/dist/shared/assistant/ui/AssistantMessageList.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantMessageList.js +19 -17
- package/dist/shared/assistant/ui/AssistantPendingWriteCard.d.ts +25 -10
- package/dist/shared/assistant/ui/AssistantPendingWriteCard.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantPendingWriteCard.js +53 -39
- package/dist/shared-assistant.js +92 -92
- package/package.json +1 -1
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
2
|
import { Message } from '../conversation';
|
|
3
3
|
interface Props {
|
|
4
|
+
/** Approve a pending write. Absent outside a live conversation. */
|
|
5
|
+
onApprovePendingWrite?: (reference: string) => void;
|
|
6
|
+
/** Reference currently being approved, so only that card shows a spinner. */
|
|
7
|
+
approvingWriteRef?: string | null;
|
|
4
8
|
message: Message;
|
|
5
9
|
isStreaming?: boolean;
|
|
6
10
|
/** This assistant message ended in an error — show the Retry affordance. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantMessageItem.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/AssistantMessageItem.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAqBnD,OAAO,KAAK,EAGV,OAAO,EACR,MAAM,iBAAiB,CAAC;AAIzB,UAAU,KAAK;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAyCD,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"AssistantMessageItem.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/AssistantMessageItem.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAqBnD,OAAO,KAAK,EAGV,OAAO,EACR,MAAM,iBAAiB,CAAC;AAIzB,UAAU,KAAK;IACb,mEAAmE;IACnE,qBAAqB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAyCD,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,KAAK,CAqS1C,CAAC"}
|
|
@@ -31,60 +31,60 @@ function T(e, t, n) {
|
|
|
31
31
|
let a = new Blob([i], { type: n }), o = URL.createObjectURL(a), s = document.createElement("a");
|
|
32
32
|
s.href = o, s.download = t, document.body.appendChild(s), s.click(), document.body.removeChild(s), URL.revokeObjectURL(o);
|
|
33
33
|
}
|
|
34
|
-
var E = ({
|
|
35
|
-
let
|
|
34
|
+
var E = ({ onApprovePendingWrite: w, approvingWriteRef: E = null, message: D, isStreaming: O, isFailed: k, isLastAssistant: A, onRetry: j }) => {
|
|
35
|
+
let M = r(), N = n(), { getAccessToken: P, getWorkspaceToken: F } = e(), I = o(), [L, R] = m(null), [z, B] = m(!1), V = D.role === "user", H = p(() => S(D), [D]), U = p(() => C(H), [H]), { steps: W, text: G } = p(() => V ? {
|
|
36
36
|
steps: [],
|
|
37
|
-
text:
|
|
38
|
-
} : a(
|
|
39
|
-
s(
|
|
40
|
-
e && (
|
|
37
|
+
text: D.content
|
|
38
|
+
} : a(D.content), [V, D.content]), K = () => {
|
|
39
|
+
s(G || D.content).then((e) => {
|
|
40
|
+
e && (B(!0), setTimeout(() => B(!1), 2e3));
|
|
41
41
|
});
|
|
42
|
-
},
|
|
43
|
-
if (!
|
|
42
|
+
}, q = async (e) => {
|
|
43
|
+
if (!H?.sandboxId || !H.sessionId) return;
|
|
44
44
|
let n = new URLSearchParams(window.location.search).get("workspace") ?? "";
|
|
45
45
|
if (n) {
|
|
46
|
-
|
|
46
|
+
R(e.path);
|
|
47
47
|
try {
|
|
48
|
-
let r = await t(
|
|
49
|
-
accessToken:
|
|
50
|
-
workspaceToken:
|
|
48
|
+
let r = await t(H.sandboxId, n, H.sessionId, e.path, {
|
|
49
|
+
accessToken: P(),
|
|
50
|
+
workspaceToken: F()
|
|
51
51
|
});
|
|
52
52
|
T(r.contentBase64, r.filename, r.mimeType);
|
|
53
53
|
} finally {
|
|
54
|
-
|
|
54
|
+
R(null);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
},
|
|
57
|
+
}, J = new Date(D.timestamp).toLocaleTimeString([], {
|
|
58
58
|
hour: "2-digit",
|
|
59
59
|
minute: "2-digit"
|
|
60
60
|
});
|
|
61
|
-
if (
|
|
61
|
+
if (D.role === "system") return /* @__PURE__ */ b("div", {
|
|
62
62
|
className: "flex justify-center px-2 py-1",
|
|
63
63
|
"data-testid": "assistant-message-system",
|
|
64
64
|
children: /* @__PURE__ */ b("p", {
|
|
65
65
|
className: "max-w-[90%] whitespace-pre-wrap break-words rounded-lg border border-border-subtle bg-bg-sunken/60 px-3 py-2 text-center text-xs leading-relaxed text-text-muted",
|
|
66
|
-
children:
|
|
66
|
+
children: D.content
|
|
67
67
|
})
|
|
68
68
|
});
|
|
69
|
-
if (
|
|
70
|
-
let e =
|
|
69
|
+
if (V) {
|
|
70
|
+
let e = D.metadata?.attachments ?? [];
|
|
71
71
|
return /* @__PURE__ */ b("div", {
|
|
72
72
|
className: "flex justify-end",
|
|
73
73
|
"data-testid": "assistant-message-user",
|
|
74
74
|
children: /* @__PURE__ */ x("div", {
|
|
75
75
|
className: "max-w-[85%]",
|
|
76
76
|
children: [
|
|
77
|
-
|
|
77
|
+
D.content && /* @__PURE__ */ b("div", {
|
|
78
78
|
className: "rounded-2xl rounded-br-md bg-action-primary-bg/12 px-3.5 py-2.5 text-[15px] leading-relaxed text-text-primary",
|
|
79
79
|
children: /* @__PURE__ */ b("p", {
|
|
80
80
|
className: "whitespace-pre-wrap",
|
|
81
|
-
children:
|
|
81
|
+
children: D.content
|
|
82
82
|
})
|
|
83
83
|
}),
|
|
84
84
|
/* @__PURE__ */ b(l, { attachments: e }),
|
|
85
85
|
/* @__PURE__ */ b("div", {
|
|
86
86
|
className: "mt-1 pr-1 text-right text-[10px] text-text-muted",
|
|
87
|
-
children:
|
|
87
|
+
children: J
|
|
88
88
|
})
|
|
89
89
|
]
|
|
90
90
|
})
|
|
@@ -99,61 +99,65 @@ var E = ({ message: w, isStreaming: E, isFailed: D, isLastAssistant: O, onRetry:
|
|
|
99
99
|
}), /* @__PURE__ */ x("div", {
|
|
100
100
|
className: "min-w-0 flex-1",
|
|
101
101
|
children: [
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
W.length > 0 && /* @__PURE__ */ b(i, { steps: W }),
|
|
103
|
+
H?.pendingWrite ? /* @__PURE__ */ b(u, {
|
|
104
|
+
pendingWrite: H.pendingWrite,
|
|
105
|
+
onApprove: w,
|
|
106
|
+
approving: E !== null && E === H.pendingWrite.reference
|
|
107
|
+
}) : null,
|
|
108
|
+
G && /* @__PURE__ */ b("div", {
|
|
105
109
|
className: "text-[15px] leading-relaxed text-text-primary",
|
|
106
|
-
children: /* @__PURE__ */ b(c, { content:
|
|
110
|
+
children: /* @__PURE__ */ b(c, { content: G })
|
|
107
111
|
}),
|
|
108
|
-
|
|
112
|
+
O && /* @__PURE__ */ b("span", {
|
|
109
113
|
"aria-hidden": "true",
|
|
110
114
|
className: "ml-0.5 inline-block h-4 w-1.5 rounded-sm bg-text-secondary align-middle motion-safe:animate-pulse"
|
|
111
115
|
}),
|
|
112
|
-
|
|
116
|
+
U.length > 0 && H?.sandboxId && H.sessionId && /* @__PURE__ */ x("div", {
|
|
113
117
|
className: "mt-3 space-y-2 border-t border-border-subtle pt-2",
|
|
114
118
|
children: [/* @__PURE__ */ b("p", {
|
|
115
119
|
className: "text-[10px] font-medium uppercase tracking-wide text-text-muted",
|
|
116
|
-
children:
|
|
120
|
+
children: M("message.downloads", "Downloads")
|
|
117
121
|
}), /* @__PURE__ */ b("div", {
|
|
118
122
|
className: "flex flex-wrap gap-2",
|
|
119
|
-
children:
|
|
123
|
+
children: U.map((e) => {
|
|
120
124
|
let t = `${e.name}${e.type === "directory" ? ".tar.gz" : ""}`;
|
|
121
125
|
return /* @__PURE__ */ b(f, {
|
|
122
126
|
label: t,
|
|
123
|
-
disabled:
|
|
127
|
+
disabled: L === e.path,
|
|
124
128
|
testId: `assistant-artifact-${e.name}`,
|
|
125
129
|
source: {
|
|
126
130
|
kind: "sandbox-artifact",
|
|
127
|
-
sandboxId:
|
|
128
|
-
sessionId:
|
|
131
|
+
sandboxId: H.sandboxId,
|
|
132
|
+
sessionId: H.sessionId,
|
|
129
133
|
path: e.path,
|
|
130
134
|
filename: t
|
|
131
135
|
},
|
|
132
|
-
defaultFolderPath:
|
|
133
|
-
onDownload: () =>
|
|
136
|
+
defaultFolderPath: N.artifacts,
|
|
137
|
+
onDownload: () => q(e)
|
|
134
138
|
}, e.path);
|
|
135
139
|
})
|
|
136
140
|
})]
|
|
137
141
|
}),
|
|
138
|
-
!
|
|
142
|
+
!O && (G || k || A) && /* @__PURE__ */ x("div", {
|
|
139
143
|
className: "mt-1.5 flex items-center gap-1",
|
|
140
144
|
children: [
|
|
141
|
-
|
|
145
|
+
G && /* @__PURE__ */ b("button", {
|
|
142
146
|
type: "button",
|
|
143
|
-
onClick:
|
|
147
|
+
onClick: K,
|
|
144
148
|
className: "flex items-center gap-1 rounded-md px-1.5 py-1 text-[11px] text-text-muted transition-colors hover:bg-bg-elevated hover:text-text-secondary",
|
|
145
|
-
"aria-label":
|
|
149
|
+
"aria-label": M("message.copy", "Copy message"),
|
|
146
150
|
"data-testid": "assistant-message-copy",
|
|
147
|
-
children:
|
|
151
|
+
children: z ? /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b(h, { className: "size-3 text-status-success-text" }), /* @__PURE__ */ b("span", { children: M("message.copied", "Copied") })] }) : /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b(g, { className: "size-3" }), /* @__PURE__ */ b("span", { children: M("message.copy", "Copy") })] })
|
|
148
152
|
}),
|
|
149
|
-
|
|
150
|
-
let e =
|
|
153
|
+
G && I.isSupported && (() => {
|
|
154
|
+
let e = I.blockedFor(D.id) ?? I.disabledReason, t = !!e && !!A, n = t ? `speak-reason-${D.id}` : void 0;
|
|
151
155
|
return /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b(d, {
|
|
152
|
-
isSpeaking:
|
|
156
|
+
isSpeaking: I.isSpeaking(D.id),
|
|
153
157
|
disabled: e !== null,
|
|
154
158
|
disabledReason: e,
|
|
155
159
|
describedById: n,
|
|
156
|
-
onClick: () =>
|
|
160
|
+
onClick: () => I.toggle(D.id, G, H?.lang)
|
|
157
161
|
}), t && /* @__PURE__ */ b("span", {
|
|
158
162
|
id: n,
|
|
159
163
|
className: "text-[11px] text-text-muted",
|
|
@@ -161,21 +165,21 @@ var E = ({ message: w, isStreaming: E, isFailed: D, isLastAssistant: O, onRetry:
|
|
|
161
165
|
children: e
|
|
162
166
|
})] });
|
|
163
167
|
})(),
|
|
164
|
-
(
|
|
168
|
+
(k || A) && j && /* @__PURE__ */ x("button", {
|
|
165
169
|
type: "button",
|
|
166
|
-
onClick:
|
|
167
|
-
className: `flex items-center gap-1 rounded-md px-1.5 py-1 text-[11px] transition-colors hover:bg-bg-elevated ${
|
|
168
|
-
"aria-label":
|
|
170
|
+
onClick: j,
|
|
171
|
+
className: `flex items-center gap-1 rounded-md px-1.5 py-1 text-[11px] transition-colors hover:bg-bg-elevated ${k ? "text-status-error-text" : "text-text-muted hover:text-text-secondary"}`,
|
|
172
|
+
"aria-label": M("message.retry", "Retry"),
|
|
169
173
|
"data-testid": "assistant-message-retry",
|
|
170
|
-
children: [/* @__PURE__ */ b(_, { className: "size-3" }), /* @__PURE__ */ b("span", { children:
|
|
174
|
+
children: [/* @__PURE__ */ b(_, { className: "size-3" }), /* @__PURE__ */ b("span", { children: M("message.retry", "Retry") })]
|
|
171
175
|
})
|
|
172
176
|
]
|
|
173
177
|
}),
|
|
174
178
|
/* @__PURE__ */ x("div", {
|
|
175
179
|
className: "mt-1 text-[10px] text-text-muted",
|
|
176
|
-
children: [
|
|
180
|
+
children: [J, D.tokens && /* @__PURE__ */ x("span", {
|
|
177
181
|
className: "ml-2",
|
|
178
|
-
children: [
|
|
182
|
+
children: [D.tokens.input + D.tokens.output, " tokens"]
|
|
179
183
|
})]
|
|
180
184
|
})
|
|
181
185
|
]
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
2
|
import { Message } from '../conversation';
|
|
3
3
|
interface Props {
|
|
4
|
+
/** Forwarded to each pending-write card; see AssistantPendingWriteCard. */
|
|
5
|
+
onApprovePendingWrite?: (reference: string) => void;
|
|
6
|
+
approvingWriteRef?: string | null;
|
|
4
7
|
messages: Message[];
|
|
5
8
|
streamingMessageId: string | null;
|
|
6
9
|
/** The assistant message (if any) whose turn ended in an error. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantMessageList.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/AssistantMessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAEnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,UAAU,KAAK;IACb,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"AssistantMessageList.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/AssistantMessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAEnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,UAAU,KAAK;IACb,2EAA2E;IAC3E,qBAAqB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,KAAK,CA8E1C,CAAC"}
|
|
@@ -3,34 +3,36 @@ import { AssistantMessageItem as t } from "./AssistantMessageItem.js";
|
|
|
3
3
|
import { useEffect as n, useRef as r } from "react";
|
|
4
4
|
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
5
|
//#region src/shared/assistant/ui/AssistantMessageList.tsx
|
|
6
|
-
var o = ({
|
|
7
|
-
let
|
|
8
|
-
for (let e =
|
|
6
|
+
var o = ({ onApprovePendingWrite: o, approvingWriteRef: s = null, messages: c, streamingMessageId: l, failedMessageId: u, onRetry: d }) => {
|
|
7
|
+
let f = e(), p = (() => {
|
|
8
|
+
for (let e = c.length - 1; e >= 0; --e) if (c[e].role === "assistant") return c[e].id;
|
|
9
9
|
return null;
|
|
10
|
-
})(),
|
|
10
|
+
})(), m = r(null), h = r(null);
|
|
11
11
|
return n(() => {
|
|
12
|
-
let e =
|
|
12
|
+
let e = h.current;
|
|
13
13
|
if (e && e.scrollHeight - e.scrollTop - e.clientHeight < 100) {
|
|
14
14
|
let e = typeof window < "u" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
15
|
-
|
|
15
|
+
m.current?.scrollIntoView({ behavior: e ? "auto" : "smooth" });
|
|
16
16
|
}
|
|
17
|
-
}, [
|
|
18
|
-
|
|
17
|
+
}, [c, l]), n(() => {
|
|
18
|
+
m.current?.scrollIntoView({ behavior: "instant" });
|
|
19
19
|
}, []), /* @__PURE__ */ a("div", {
|
|
20
|
-
ref:
|
|
20
|
+
ref: h,
|
|
21
21
|
className: "flex-1 space-y-4 overflow-y-auto p-3",
|
|
22
22
|
role: "log",
|
|
23
23
|
"aria-live": "polite",
|
|
24
24
|
"aria-relevant": "additions",
|
|
25
|
-
"aria-busy":
|
|
26
|
-
"aria-label":
|
|
27
|
-
children: [
|
|
25
|
+
"aria-busy": l !== null,
|
|
26
|
+
"aria-label": f("messageList.ariaLabel", "Conversation messages"),
|
|
27
|
+
children: [c.map((e) => /* @__PURE__ */ i(t, {
|
|
28
|
+
onApprovePendingWrite: o,
|
|
29
|
+
approvingWriteRef: s,
|
|
28
30
|
message: e,
|
|
29
|
-
isStreaming: e.id ===
|
|
30
|
-
isFailed: e.id ===
|
|
31
|
-
isLastAssistant: e.id ===
|
|
32
|
-
onRetry:
|
|
33
|
-
}, e.id)), /* @__PURE__ */ i("div", { ref:
|
|
31
|
+
isStreaming: e.id === l,
|
|
32
|
+
isFailed: e.id === u,
|
|
33
|
+
isLastAssistant: e.id === p,
|
|
34
|
+
onRetry: d
|
|
35
|
+
}, e.id)), /* @__PURE__ */ i("div", { ref: m })]
|
|
34
36
|
});
|
|
35
37
|
};
|
|
36
38
|
//#endregion
|
|
@@ -2,6 +2,13 @@ import { FC } from 'react';
|
|
|
2
2
|
import { PendingWrite } from '../pendingWrite';
|
|
3
3
|
interface Props {
|
|
4
4
|
pendingWrite: PendingWrite;
|
|
5
|
+
/**
|
|
6
|
+
* Approve this exact pending write. Absent when the conversation is not live
|
|
7
|
+
* (history, export) — the card then reads as a record of what was asked.
|
|
8
|
+
*/
|
|
9
|
+
onApprove?: (reference: string) => void;
|
|
10
|
+
/** True while the approval is in flight, so the button cannot be double-sent. */
|
|
11
|
+
approving?: boolean;
|
|
5
12
|
}
|
|
6
13
|
/**
|
|
7
14
|
* What the assistant is asking permission to change — taken from the request it
|
|
@@ -15,17 +22,25 @@ interface Props {
|
|
|
15
22
|
* delete described as an update, and the approval still counts. This card is the
|
|
16
23
|
* payload.
|
|
17
24
|
*
|
|
18
|
-
*
|
|
19
|
-
* chat message and let the model decide what that authorises — which is the
|
|
20
|
-
* arrangement this card exists to expose, dressed up as a control. The model
|
|
21
|
-
* holds the single-use token; until it does not (see `write-confirmation.ts`,
|
|
22
|
-
* which names the fix as "the UI holding the approval"), a button would promise
|
|
23
|
-
* an authorization boundary the frontend does not have. The user replies in
|
|
24
|
-
* their own words, and the card makes sure they know what they are replying to.
|
|
25
|
+
* ★★ IT NOW HAS AN APPROVE BUTTON, AND THAT IS A CHANGE OF FACT, NOT OF TASTE.
|
|
25
26
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
27
|
+
* This card deliberately had none. A button would have had to send "yes" as a
|
|
28
|
+
* chat message and let the model decide what that authorised — the very
|
|
29
|
+
* arrangement the card existed to expose, dressed up as a control — because the
|
|
30
|
+
* model held the single-use token and could paste it back whenever it liked.
|
|
31
|
+
*
|
|
32
|
+
* That is no longer true. The sandbox no longer puts the token in anything the
|
|
33
|
+
* model can read; the refusal carries a reference that NAMES the pending change
|
|
34
|
+
* and authorises nothing. Approval is an out-of-band call to the sandbox
|
|
35
|
+
* (`/write-confirmations/:reference/approve`) that the model is not part of. So
|
|
36
|
+
* the button now promises a boundary that exists.
|
|
37
|
+
*
|
|
38
|
+
* ★ The reference is not a secret and the token is never rendered — the card
|
|
39
|
+
* still never displays anything that could authorise the write on its own.
|
|
40
|
+
*
|
|
41
|
+
* ★ Without a reference (an older sandbox image) the button is not shown at
|
|
42
|
+
* all, and the card falls back to what it always said: reply in your own words.
|
|
43
|
+
* A control that cannot work is worse than no control.
|
|
29
44
|
*/
|
|
30
45
|
export declare const AssistantPendingWriteCard: FC<Props>;
|
|
31
46
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantPendingWriteCard.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/AssistantPendingWriteCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD,UAAU,KAAK;IACb,YAAY,EAAE,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"AssistantPendingWriteCard.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/AssistantPendingWriteCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD,UAAU,KAAK;IACb,YAAY,EAAE,YAAY,CAAC;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,KAAK,CA2F/C,CAAC"}
|
|
@@ -2,51 +2,65 @@ import { useAssistantTr as e } from "../i18n.js";
|
|
|
2
2
|
import { ShieldAlert as t } from "lucide-react";
|
|
3
3
|
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
4
|
//#region src/shared/assistant/ui/AssistantPendingWriteCard.tsx
|
|
5
|
-
var i = ({ pendingWrite: i }) => {
|
|
6
|
-
let
|
|
5
|
+
var i = ({ pendingWrite: i, onApprove: a, approving: o = !1 }) => {
|
|
6
|
+
let s = e(), c = !!i.reference && !!a;
|
|
7
7
|
return /* @__PURE__ */ r("div", {
|
|
8
8
|
className: "my-2 overflow-hidden rounded-xl border border-status-warning bg-status-warning/10",
|
|
9
9
|
"data-testid": "assistant-pending-write",
|
|
10
10
|
role: "note",
|
|
11
|
-
"aria-label":
|
|
12
|
-
children: [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
"aria-label": s("pendingWrite.aria", "Change awaiting your approval"),
|
|
12
|
+
children: [
|
|
13
|
+
/* @__PURE__ */ r("div", {
|
|
14
|
+
className: "flex items-start gap-2 border-b border-status-warning/40 px-3 py-2",
|
|
15
|
+
children: [/* @__PURE__ */ n(t, {
|
|
16
|
+
className: "mt-0.5 size-4 flex-shrink-0 text-status-warning",
|
|
17
|
+
"aria-hidden": "true"
|
|
18
|
+
}), /* @__PURE__ */ r("div", {
|
|
19
|
+
className: "min-w-0",
|
|
20
|
+
children: [/* @__PURE__ */ n("p", {
|
|
21
|
+
className: "text-xs font-semibold text-text-primary",
|
|
22
|
+
children: s("pendingWrite.title", "Nothing has changed yet")
|
|
23
|
+
}), /* @__PURE__ */ n("p", {
|
|
24
|
+
className: "text-[11px] leading-relaxed text-text-secondary",
|
|
25
|
+
children: s("pendingWrite.subtitle", c ? "The assistant asked to make this change and was stopped. Approve it, or say what to change." : "The assistant asked to make this change and was stopped. Reply to approve or decline.")
|
|
26
|
+
})]
|
|
27
|
+
})]
|
|
28
|
+
}),
|
|
29
|
+
/* @__PURE__ */ r("div", {
|
|
30
|
+
className: "px-3 py-2",
|
|
19
31
|
children: [/* @__PURE__ */ n("p", {
|
|
20
|
-
className: "text-xs
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
className: "font-mono text-xs text-text-primary",
|
|
33
|
+
"data-testid": "assistant-pending-write-operation",
|
|
34
|
+
children: i.operation
|
|
35
|
+
}), i.values && i.values.length > 0 ? /* @__PURE__ */ n("dl", {
|
|
36
|
+
className: "mt-2 grid grid-cols-[minmax(0,auto)_minmax(0,1fr)] gap-x-3 gap-y-1 text-xs",
|
|
37
|
+
children: i.values.map((e) => /* @__PURE__ */ r("div", {
|
|
38
|
+
className: "contents",
|
|
39
|
+
children: [/* @__PURE__ */ n("dt", {
|
|
40
|
+
className: "truncate text-text-muted",
|
|
41
|
+
children: e.key
|
|
42
|
+
}), /* @__PURE__ */ n("dd", {
|
|
43
|
+
className: "min-w-0 break-words font-medium text-text-primary",
|
|
44
|
+
children: e.value
|
|
45
|
+
})]
|
|
46
|
+
}, e.key))
|
|
47
|
+
}) : /* @__PURE__ */ n("p", {
|
|
48
|
+
className: "mt-1 text-[11px] text-text-muted",
|
|
49
|
+
children: s("pendingWrite.noValues", "No field values were included with this request.")
|
|
25
50
|
})]
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
children: e.key
|
|
40
|
-
}), /* @__PURE__ */ n("dd", {
|
|
41
|
-
className: "min-w-0 break-words font-medium text-text-primary",
|
|
42
|
-
children: e.value
|
|
43
|
-
})]
|
|
44
|
-
}, e.key))
|
|
45
|
-
}) : /* @__PURE__ */ n("p", {
|
|
46
|
-
className: "mt-1 text-[11px] text-text-muted",
|
|
47
|
-
children: a("pendingWrite.noValues", "No field values were included with this request.")
|
|
48
|
-
})]
|
|
49
|
-
})]
|
|
51
|
+
}),
|
|
52
|
+
c ? /* @__PURE__ */ n("div", {
|
|
53
|
+
className: "flex justify-end border-t border-status-warning/40 px-3 py-2",
|
|
54
|
+
children: /* @__PURE__ */ n("button", {
|
|
55
|
+
type: "button",
|
|
56
|
+
onClick: () => a?.(i.reference),
|
|
57
|
+
disabled: o,
|
|
58
|
+
className: "rounded-md bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-fg transition-opacity hover:opacity-90 disabled:opacity-60 focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong",
|
|
59
|
+
"data-testid": "assistant-pending-write-approve",
|
|
60
|
+
children: o ? s("pendingWrite.approving", "Approving…") : s("pendingWrite.approve", "Approve this change")
|
|
61
|
+
})
|
|
62
|
+
}) : null
|
|
63
|
+
]
|
|
50
64
|
});
|
|
51
65
|
};
|
|
52
66
|
//#endregion
|