@athenaintel/react 0.22.0 → 0.22.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/README.md +16 -8
- package/dist/packages/agent-runtime/src/use-deep-agent-edit-submit.cjs +79 -28
- package/dist/packages/agent-runtime/src/use-deep-agent-edit-submit.cjs.map +1 -1
- package/dist/packages/agent-runtime/src/use-deep-agent-edit-submit.js +81 -30
- package/dist/packages/agent-runtime/src/use-deep-agent-edit-submit.js.map +1 -1
- package/dist/packages/react/package.json.cjs +1 -1
- package/dist/packages/react/package.json.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/voice/use-athena-voice-session.cjs +1 -1
- package/dist/voice/use-athena-voice-session.cjs.map +1 -1
- package/dist/voice/use-athena-voice-session.d.ts +30 -31
- package/dist/voice/use-athena-voice-session.js +1 -1
- package/dist/voice/use-athena-voice-session.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -160,13 +160,13 @@ unless a collab agent supplies one.
|
|
|
160
160
|
## Voice Sessions (`@athenaintel/react/voice`)
|
|
161
161
|
|
|
162
162
|
`useAthenaVoiceSession` runs a real-time voice conversation with an Athena
|
|
163
|
-
voice agent
|
|
164
|
-
|
|
163
|
+
voice agent and streams the transcript into React state. It owns the whole
|
|
164
|
+
browser side — session creation, room connect, mic,
|
|
165
165
|
agent audio, live/interim transcript turns, reconnects, StrictMode-safe
|
|
166
166
|
teardown — so an app is a `start()` button and a transcript list.
|
|
167
167
|
|
|
168
168
|
```bash
|
|
169
|
-
bun add @athenaintel/react livekit-client #
|
|
169
|
+
bun add @athenaintel/react livekit-client # optional peer dep, only needed for voice
|
|
170
170
|
```
|
|
171
171
|
|
|
172
172
|
```tsx
|
|
@@ -191,15 +191,15 @@ const voice = useAthenaVoiceSession({
|
|
|
191
191
|
|
|
192
192
|
**Voice tools.** `enabled_tools` takes voice tool names (`AthenaVoiceToolId`),
|
|
193
193
|
not the chat `Toolkits` ids — `'web_search_browse_toolkit'` is not a voice tool,
|
|
194
|
-
`'web_search'` is. Available: `web_search` (
|
|
194
|
+
`'web_search'` is. Available: `web_search` (`search_web` is a legacy alias),
|
|
195
195
|
`browse` (read a URL), `search_knowledge_base` and `search_knowledge_base_lr`
|
|
196
196
|
(the workspace knowledge base; `_lr` is the thorough long-running retrieval),
|
|
197
197
|
`read_full_asset` and `search_assets` (as the viewer), `ask_agent` (hand a
|
|
198
198
|
question to the general agent), `save_note`, `get_current_time_est`. Tools that
|
|
199
|
-
call back into the client over
|
|
199
|
+
call back into the client over room RPC (`write_to_clipboard`, the desktop and
|
|
200
200
|
mobile tools) are not part of the hook's contract. Omit the field for the
|
|
201
|
-
server's default set; pass `[]` for pure conversation.
|
|
202
|
-
names with a 422
|
|
201
|
+
server's default set; pass `[]` for pure conversation. The server refuses
|
|
202
|
+
unknown names with a 422.
|
|
203
203
|
|
|
204
204
|
**Authentication.** Served from a Marathon computer-asset URL, the hook is
|
|
205
205
|
zero-config: it takes the viewer bearer from `useParentBridge()` and creates
|
|
@@ -234,6 +234,14 @@ Both use the same bearer / API key as session creation. The full recipe
|
|
|
234
234
|
template skill `voice-session-guide.md`. `createAthenaVoiceSession` is also
|
|
235
235
|
exported if you hold the bridge state yourself.
|
|
236
236
|
|
|
237
|
+
## What's new in 0.22.2
|
|
238
|
+
|
|
239
|
+
Public voice docs, JSDoc/`.d.ts` and the session-creation error message now use product-neutral wording (no internal service or transport names). No API changes.
|
|
240
|
+
|
|
241
|
+
## What's new in 0.22.1
|
|
242
|
+
|
|
243
|
+
Tailwind Typography colors now follow theme tokens inside SDK roots; `userBubbleForeground` / `assistantForeground` apply to message text, headings, bold, inline code and blockquotes.
|
|
244
|
+
|
|
237
245
|
## What's new in 0.22.0
|
|
238
246
|
|
|
239
247
|
0.22.0 adds a read-only **workspace presence** feed to `@athenaintel/react/collab`:
|
|
@@ -247,7 +255,7 @@ carries into titles. Admin-only. See
|
|
|
247
255
|
## What's new in 0.21.0
|
|
248
256
|
|
|
249
257
|
0.21.0 adds the `@athenaintel/react/voice` entry: `useAthenaVoiceSession`
|
|
250
|
-
(
|
|
258
|
+
(room lifecycle, mic, agent audio, live transcript turns, reconnect,
|
|
251
259
|
StrictMode-safe) and `createAthenaVoiceSession`. On Marathon it is
|
|
252
260
|
zero-config and attributes the session to the viewer (workspace members and
|
|
253
261
|
external SSO viewers); elsewhere pass `createSession`. See
|
|
@@ -5,39 +5,90 @@ const react = require("react");
|
|
|
5
5
|
const editCommand = require("./edit-command.cjs");
|
|
6
6
|
function useDeepAgentMessageEditSubmit() {
|
|
7
7
|
const aui = store.useAui();
|
|
8
|
+
const alive = react.useRef(true);
|
|
9
|
+
const submitting = react.useRef(false);
|
|
10
|
+
react.useEffect(() => {
|
|
11
|
+
alive.current = true;
|
|
12
|
+
return () => {
|
|
13
|
+
alive.current = false;
|
|
14
|
+
};
|
|
15
|
+
}, []);
|
|
8
16
|
return react.useCallback(async () => {
|
|
9
|
-
var _a, _b;
|
|
17
|
+
var _a, _b, _c;
|
|
18
|
+
if (submitting.current) return false;
|
|
10
19
|
const composer = aui.message().composer();
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
const draft = composer.getState();
|
|
21
|
+
const text = draft.text.trim();
|
|
22
|
+
if (!text && draft.attachments.length === 0) return false;
|
|
23
|
+
const files = [];
|
|
24
|
+
const texts = text ? [text] : [];
|
|
25
|
+
for (const attachment of draft.attachments) {
|
|
26
|
+
if (attachment.status.type !== "complete")
|
|
27
|
+
throw new Error("Wait for attachments to finish before sending your edit.");
|
|
28
|
+
for (const part of attachment.content ?? []) {
|
|
29
|
+
if (part.type === "text") texts.push(part.text);
|
|
30
|
+
else if (part.type === "image")
|
|
31
|
+
files.push({ type: "file", mediaType: "image/*", url: part.image });
|
|
32
|
+
else if (part.type === "file")
|
|
33
|
+
files.push({
|
|
34
|
+
type: "file",
|
|
35
|
+
mediaType: part.mimeType,
|
|
36
|
+
url: part.data,
|
|
37
|
+
...part.filename && { filename: part.filename }
|
|
38
|
+
});
|
|
39
|
+
else throw new Error("This attachment cannot be edited here.");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
submitting.current = true;
|
|
43
|
+
try {
|
|
44
|
+
const sourceId = aui.message().getState().id;
|
|
45
|
+
const readExtras = () => alive.current ? editCommand.readDeepAgentStatewireExtras(aui.thread().getState().extras) : null;
|
|
46
|
+
const extras = readExtras();
|
|
47
|
+
if (extras) {
|
|
48
|
+
const preparedMetadata = (_a = extras.prepareMessageMetadata) == null ? void 0 : _a.call(extras);
|
|
49
|
+
try {
|
|
50
|
+
const command = await editCommand.resolveDeepAgentEditCommand({
|
|
51
|
+
readExtras,
|
|
52
|
+
sourceId,
|
|
53
|
+
text
|
|
54
|
+
});
|
|
55
|
+
if (!alive.current || !composer.getState().isEditing) {
|
|
56
|
+
if (preparedMetadata) (_b = extras.discardPreparedMessageMetadata) == null ? void 0 : _b.call(extras, preparedMetadata);
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (command) {
|
|
60
|
+
void Promise.resolve(
|
|
61
|
+
extras.sendCommand(
|
|
62
|
+
{
|
|
63
|
+
...command,
|
|
64
|
+
message: {
|
|
65
|
+
...command.message,
|
|
66
|
+
parts: [
|
|
67
|
+
...files,
|
|
68
|
+
...texts.length ? [{ type: "text", text: texts.join("\n\n") }] : []
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
preparedMetadata === void 0 ? void 0 : { preparedMetadata }
|
|
73
|
+
)
|
|
74
|
+
).catch(() => void 0);
|
|
75
|
+
composer.cancel();
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
if (preparedMetadata && extras.sendPreparedEdit) {
|
|
79
|
+
extras.sendPreparedEdit(sourceId, preparedMetadata);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
} catch (error) {
|
|
83
|
+
if (preparedMetadata) (_c = extras.discardPreparedMessageMetadata) == null ? void 0 : _c.call(extras, preparedMetadata);
|
|
84
|
+
throw error;
|
|
33
85
|
}
|
|
34
|
-
} catch (error) {
|
|
35
|
-
if (preparedMetadata) (_b = extras.discardPreparedMessageMetadata) == null ? void 0 : _b.call(extras, preparedMetadata);
|
|
36
|
-
throw error;
|
|
37
86
|
}
|
|
87
|
+
composer.send();
|
|
88
|
+
return true;
|
|
89
|
+
} finally {
|
|
90
|
+
submitting.current = false;
|
|
38
91
|
}
|
|
39
|
-
composer.send();
|
|
40
|
-
return true;
|
|
41
92
|
}, [aui]);
|
|
42
93
|
}
|
|
43
94
|
exports.useDeepAgentMessageEditSubmit = useDeepAgentMessageEditSubmit;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-deep-agent-edit-submit.cjs","sources":["../../../../../agent-runtime/src/use-deep-agent-edit-submit.ts"],"sourcesContent":["import { useAui } from '@assistant-ui/store';\nimport { useCallback } from 'react';\nimport { readDeepAgentStatewireExtras, resolveDeepAgentEditCommand } from './edit-command';\n\n/**\n * The submit handler of a message's edit composer on a deep-agent thread: the\n * edited text leaves as a `run/edit` anchored on the host's own parent of the\n * message (see `edit-command.ts`) — on a windowed wire the lane's\n * `anchorBefore` at the window edge, and older pages loaded first for a\n * message below the loaded range — instead of the library's converted-message\n * anchor, which the host rejects `wrong-anchor` after a chunked assistant turn\n * and at the window edge.\n *\n * Read inside the message scope (`aui.message()`): the library's optimistic\n * fold shows the edited bubble and rewinds the visible history the moment the\n * command is dispatched, so the edit composer closes right away. Falls back\n * to the composer's own `send()` when the thread is not a statewire thread or\n * the host has not settled the message yet. Resolves `false`
|
|
1
|
+
{"version":3,"file":"use-deep-agent-edit-submit.cjs","sources":["../../../../../agent-runtime/src/use-deep-agent-edit-submit.ts"],"sourcesContent":["import { useAui } from '@assistant-ui/store';\nimport type { StatewireThread } from '@assistant-ui/react-statewire';\nimport { useCallback, useEffect, useRef } from 'react';\nimport { readDeepAgentStatewireExtras, resolveDeepAgentEditCommand } from './edit-command';\n\n/**\n * The submit handler of a message's edit composer on a deep-agent thread: the\n * edited text leaves as a `run/edit` anchored on the host's own parent of the\n * message (see `edit-command.ts`) — on a windowed wire the lane's\n * `anchorBefore` at the window edge, and older pages loaded first for a\n * message below the loaded range — instead of the library's converted-message\n * anchor, which the host rejects `wrong-anchor` after a chunked assistant turn\n * and at the window edge.\n *\n * Read inside the message scope (`aui.message()`): the library's optimistic\n * fold shows the edited bubble and rewinds the visible history the moment the\n * command is dispatched, so the edit composer closes right away. Falls back\n * to the composer's own `send()` when the thread is not a statewire thread or\n * the host has not settled the message yet. Resolves `false` for an empty\n * draft, a duplicate submission, or an edit cancelled during preparation.\n */\nexport function useDeepAgentMessageEditSubmit(): () => Promise<boolean> {\n const aui = useAui();\n const alive = useRef(true);\n const submitting = useRef(false);\n useEffect(() => {\n alive.current = true;\n return () => {\n alive.current = false;\n };\n }, []);\n return useCallback(async () => {\n if (submitting.current) return false;\n const composer = aui.message().composer();\n const draft = composer.getState();\n const text = draft.text.trim();\n if (!text && draft.attachments.length === 0) return false;\n const files: StatewireThread.FilePart[] = [];\n const texts = text ? [text] : [];\n // beginEdit lifts original inline images/files into completed composer\n // attachments. The anchored command must carry those too: a text-only\n // reconstruction silently deleted them when editing a cross-device turn.\n for (const attachment of draft.attachments) {\n if (attachment.status.type !== 'complete')\n throw new Error('Wait for attachments to finish before sending your edit.');\n for (const part of attachment.content ?? []) {\n if (part.type === 'text') texts.push(part.text);\n else if (part.type === 'image')\n files.push({ type: 'file', mediaType: 'image/*', url: part.image });\n else if (part.type === 'file')\n files.push({\n type: 'file',\n mediaType: part.mimeType,\n url: part.data,\n ...(part.filename && { filename: part.filename }),\n });\n else throw new Error('This attachment cannot be edited here.');\n }\n }\n submitting.current = true;\n try {\n const sourceId = aui.message().getState().id;\n const readExtras = () =>\n alive.current ? readDeepAgentStatewireExtras(aui.thread().getState().extras) : null;\n const extras = readExtras();\n if (extras) {\n const preparedMetadata = extras.prepareMessageMetadata?.();\n try {\n const command = await resolveDeepAgentEditCommand({\n readExtras,\n sourceId,\n text,\n });\n if (!alive.current || !composer.getState().isEditing) {\n if (preparedMetadata) extras.discardPreparedMessageMetadata?.(preparedMetadata);\n return false;\n }\n if (command) {\n void Promise.resolve(\n extras.sendCommand(\n {\n ...command,\n message: {\n ...command.message,\n parts: [\n ...files,\n ...(texts.length\n ? [{ type: 'text' as const, text: texts.join('\\n\\n') }]\n : []),\n ],\n },\n },\n preparedMetadata === undefined ? undefined : { preparedMetadata },\n ),\n ).catch(() => undefined);\n composer.cancel();\n return true;\n }\n if (preparedMetadata && extras.sendPreparedEdit) {\n extras.sendPreparedEdit(sourceId, preparedMetadata);\n return true;\n }\n } catch (error) {\n if (preparedMetadata) extras.discardPreparedMessageMetadata?.(preparedMetadata);\n throw error;\n }\n }\n composer.send();\n return true;\n } finally {\n submitting.current = false;\n }\n }, [aui]);\n}\n"],"names":["useAui","useRef","useEffect","useCallback","readDeepAgentStatewireExtras","resolveDeepAgentEditCommand"],"mappings":";;;;;AAqBO,SAAS,gCAAwD;AACtE,QAAM,MAAMA,MAAAA,OAAA;AACZ,QAAM,QAAQC,MAAAA,OAAO,IAAI;AACzB,QAAM,aAAaA,MAAAA,OAAO,KAAK;AAC/BC,QAAAA,UAAU,MAAM;AACd,UAAM,UAAU;AAChB,WAAO,MAAM;AACX,YAAM,UAAU;AAAA,IAClB;AAAA,EACF,GAAG,CAAA,CAAE;AACL,SAAOC,MAAAA,YAAY,YAAY;;AAC7B,QAAI,WAAW,QAAS,QAAO;AAC/B,UAAM,WAAW,IAAI,QAAA,EAAU,SAAA;AAC/B,UAAM,QAAQ,SAAS,SAAA;AACvB,UAAM,OAAO,MAAM,KAAK,KAAA;AACxB,QAAI,CAAC,QAAQ,MAAM,YAAY,WAAW,EAAG,QAAO;AACpD,UAAM,QAAoC,CAAA;AAC1C,UAAM,QAAQ,OAAO,CAAC,IAAI,IAAI,CAAA;AAI9B,eAAW,cAAc,MAAM,aAAa;AAC1C,UAAI,WAAW,OAAO,SAAS;AAC7B,cAAM,IAAI,MAAM,0DAA0D;AAC5E,iBAAW,QAAQ,WAAW,WAAW,CAAA,GAAI;AAC3C,YAAI,KAAK,SAAS,OAAQ,OAAM,KAAK,KAAK,IAAI;AAAA,iBACrC,KAAK,SAAS;AACrB,gBAAM,KAAK,EAAE,MAAM,QAAQ,WAAW,WAAW,KAAK,KAAK,OAAO;AAAA,iBAC3D,KAAK,SAAS;AACrB,gBAAM,KAAK;AAAA,YACT,MAAM;AAAA,YACN,WAAW,KAAK;AAAA,YAChB,KAAK,KAAK;AAAA,YACV,GAAI,KAAK,YAAY,EAAE,UAAU,KAAK,SAAA;AAAA,UAAS,CAChD;AAAA,YACE,OAAM,IAAI,MAAM,wCAAwC;AAAA,MAC/D;AAAA,IACF;AACA,eAAW,UAAU;AACrB,QAAI;AACF,YAAM,WAAW,IAAI,QAAA,EAAU,WAAW;AAC1C,YAAM,aAAa,MACjB,MAAM,UAAUC,YAAAA,6BAA6B,IAAI,SAAS,WAAW,MAAM,IAAI;AACjF,YAAM,SAAS,WAAA;AACf,UAAI,QAAQ;AACV,cAAM,oBAAmB,YAAO,2BAAP;AACzB,YAAI;AACF,gBAAM,UAAU,MAAMC,wCAA4B;AAAA,YAChD;AAAA,YACA;AAAA,YACA;AAAA,UAAA,CACD;AACD,cAAI,CAAC,MAAM,WAAW,CAAC,SAAS,SAAA,EAAW,WAAW;AACpD,gBAAI,iBAAkB,cAAO,mCAAP,gCAAwC;AAC9D,mBAAO;AAAA,UACT;AACA,cAAI,SAAS;AACX,iBAAK,QAAQ;AAAA,cACX,OAAO;AAAA,gBACL;AAAA,kBACE,GAAG;AAAA,kBACH,SAAS;AAAA,oBACP,GAAG,QAAQ;AAAA,oBACX,OAAO;AAAA,sBACL,GAAG;AAAA,sBACH,GAAI,MAAM,SACN,CAAC,EAAE,MAAM,QAAiB,MAAM,MAAM,KAAK,MAAM,EAAA,CAAG,IACpD,CAAA;AAAA,oBAAC;AAAA,kBACP;AAAA,gBACF;AAAA,gBAEF,qBAAqB,SAAY,SAAY,EAAE,iBAAA;AAAA,cAAiB;AAAA,YAClE,EACA,MAAM,MAAM,MAAS;AACvB,qBAAS,OAAA;AACT,mBAAO;AAAA,UACT;AACA,cAAI,oBAAoB,OAAO,kBAAkB;AAC/C,mBAAO,iBAAiB,UAAU,gBAAgB;AAClD,mBAAO;AAAA,UACT;AAAA,QACF,SAAS,OAAO;AACd,cAAI,iBAAkB,cAAO,mCAAP,gCAAwC;AAC9D,gBAAM;AAAA,QACR;AAAA,MACF;AACA,eAAS,KAAA;AACT,aAAO;AAAA,IACT,UAAA;AACE,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AACV;;"}
|
|
@@ -1,41 +1,92 @@
|
|
|
1
1
|
import { useAui } from "@assistant-ui/store";
|
|
2
|
-
import { useCallback } from "react";
|
|
3
|
-
import {
|
|
2
|
+
import { useRef, useEffect, useCallback } from "react";
|
|
3
|
+
import { readDeepAgentStatewireExtras, resolveDeepAgentEditCommand } from "./edit-command.js";
|
|
4
4
|
function useDeepAgentMessageEditSubmit() {
|
|
5
5
|
const aui = useAui();
|
|
6
|
+
const alive = useRef(true);
|
|
7
|
+
const submitting = useRef(false);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
alive.current = true;
|
|
10
|
+
return () => {
|
|
11
|
+
alive.current = false;
|
|
12
|
+
};
|
|
13
|
+
}, []);
|
|
6
14
|
return useCallback(async () => {
|
|
7
|
-
var _a, _b;
|
|
15
|
+
var _a, _b, _c;
|
|
16
|
+
if (submitting.current) return false;
|
|
8
17
|
const composer = aui.message().composer();
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
18
|
+
const draft = composer.getState();
|
|
19
|
+
const text = draft.text.trim();
|
|
20
|
+
if (!text && draft.attachments.length === 0) return false;
|
|
21
|
+
const files = [];
|
|
22
|
+
const texts = text ? [text] : [];
|
|
23
|
+
for (const attachment of draft.attachments) {
|
|
24
|
+
if (attachment.status.type !== "complete")
|
|
25
|
+
throw new Error("Wait for attachments to finish before sending your edit.");
|
|
26
|
+
for (const part of attachment.content ?? []) {
|
|
27
|
+
if (part.type === "text") texts.push(part.text);
|
|
28
|
+
else if (part.type === "image")
|
|
29
|
+
files.push({ type: "file", mediaType: "image/*", url: part.image });
|
|
30
|
+
else if (part.type === "file")
|
|
31
|
+
files.push({
|
|
32
|
+
type: "file",
|
|
33
|
+
mediaType: part.mimeType,
|
|
34
|
+
url: part.data,
|
|
35
|
+
...part.filename && { filename: part.filename }
|
|
36
|
+
});
|
|
37
|
+
else throw new Error("This attachment cannot be edited here.");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
submitting.current = true;
|
|
41
|
+
try {
|
|
42
|
+
const sourceId = aui.message().getState().id;
|
|
43
|
+
const readExtras = () => alive.current ? readDeepAgentStatewireExtras(aui.thread().getState().extras) : null;
|
|
44
|
+
const extras = readExtras();
|
|
45
|
+
if (extras) {
|
|
46
|
+
const preparedMetadata = (_a = extras.prepareMessageMetadata) == null ? void 0 : _a.call(extras);
|
|
47
|
+
try {
|
|
48
|
+
const command = await resolveDeepAgentEditCommand({
|
|
49
|
+
readExtras,
|
|
50
|
+
sourceId,
|
|
51
|
+
text
|
|
52
|
+
});
|
|
53
|
+
if (!alive.current || !composer.getState().isEditing) {
|
|
54
|
+
if (preparedMetadata) (_b = extras.discardPreparedMessageMetadata) == null ? void 0 : _b.call(extras, preparedMetadata);
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
if (command) {
|
|
58
|
+
void Promise.resolve(
|
|
59
|
+
extras.sendCommand(
|
|
60
|
+
{
|
|
61
|
+
...command,
|
|
62
|
+
message: {
|
|
63
|
+
...command.message,
|
|
64
|
+
parts: [
|
|
65
|
+
...files,
|
|
66
|
+
...texts.length ? [{ type: "text", text: texts.join("\n\n") }] : []
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
preparedMetadata === void 0 ? void 0 : { preparedMetadata }
|
|
71
|
+
)
|
|
72
|
+
).catch(() => void 0);
|
|
73
|
+
composer.cancel();
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (preparedMetadata && extras.sendPreparedEdit) {
|
|
77
|
+
extras.sendPreparedEdit(sourceId, preparedMetadata);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (preparedMetadata) (_c = extras.discardPreparedMessageMetadata) == null ? void 0 : _c.call(extras, preparedMetadata);
|
|
82
|
+
throw error;
|
|
31
83
|
}
|
|
32
|
-
} catch (error) {
|
|
33
|
-
if (preparedMetadata) (_b = extras.discardPreparedMessageMetadata) == null ? void 0 : _b.call(extras, preparedMetadata);
|
|
34
|
-
throw error;
|
|
35
84
|
}
|
|
85
|
+
composer.send();
|
|
86
|
+
return true;
|
|
87
|
+
} finally {
|
|
88
|
+
submitting.current = false;
|
|
36
89
|
}
|
|
37
|
-
composer.send();
|
|
38
|
-
return true;
|
|
39
90
|
}, [aui]);
|
|
40
91
|
}
|
|
41
92
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-deep-agent-edit-submit.js","sources":["../../../../../agent-runtime/src/use-deep-agent-edit-submit.ts"],"sourcesContent":["import { useAui } from '@assistant-ui/store';\nimport { useCallback } from 'react';\nimport { readDeepAgentStatewireExtras, resolveDeepAgentEditCommand } from './edit-command';\n\n/**\n * The submit handler of a message's edit composer on a deep-agent thread: the\n * edited text leaves as a `run/edit` anchored on the host's own parent of the\n * message (see `edit-command.ts`) — on a windowed wire the lane's\n * `anchorBefore` at the window edge, and older pages loaded first for a\n * message below the loaded range — instead of the library's converted-message\n * anchor, which the host rejects `wrong-anchor` after a chunked assistant turn\n * and at the window edge.\n *\n * Read inside the message scope (`aui.message()`): the library's optimistic\n * fold shows the edited bubble and rewinds the visible history the moment the\n * command is dispatched, so the edit composer closes right away. Falls back\n * to the composer's own `send()` when the thread is not a statewire thread or\n * the host has not settled the message yet. Resolves `false`
|
|
1
|
+
{"version":3,"file":"use-deep-agent-edit-submit.js","sources":["../../../../../agent-runtime/src/use-deep-agent-edit-submit.ts"],"sourcesContent":["import { useAui } from '@assistant-ui/store';\nimport type { StatewireThread } from '@assistant-ui/react-statewire';\nimport { useCallback, useEffect, useRef } from 'react';\nimport { readDeepAgentStatewireExtras, resolveDeepAgentEditCommand } from './edit-command';\n\n/**\n * The submit handler of a message's edit composer on a deep-agent thread: the\n * edited text leaves as a `run/edit` anchored on the host's own parent of the\n * message (see `edit-command.ts`) — on a windowed wire the lane's\n * `anchorBefore` at the window edge, and older pages loaded first for a\n * message below the loaded range — instead of the library's converted-message\n * anchor, which the host rejects `wrong-anchor` after a chunked assistant turn\n * and at the window edge.\n *\n * Read inside the message scope (`aui.message()`): the library's optimistic\n * fold shows the edited bubble and rewinds the visible history the moment the\n * command is dispatched, so the edit composer closes right away. Falls back\n * to the composer's own `send()` when the thread is not a statewire thread or\n * the host has not settled the message yet. Resolves `false` for an empty\n * draft, a duplicate submission, or an edit cancelled during preparation.\n */\nexport function useDeepAgentMessageEditSubmit(): () => Promise<boolean> {\n const aui = useAui();\n const alive = useRef(true);\n const submitting = useRef(false);\n useEffect(() => {\n alive.current = true;\n return () => {\n alive.current = false;\n };\n }, []);\n return useCallback(async () => {\n if (submitting.current) return false;\n const composer = aui.message().composer();\n const draft = composer.getState();\n const text = draft.text.trim();\n if (!text && draft.attachments.length === 0) return false;\n const files: StatewireThread.FilePart[] = [];\n const texts = text ? [text] : [];\n // beginEdit lifts original inline images/files into completed composer\n // attachments. The anchored command must carry those too: a text-only\n // reconstruction silently deleted them when editing a cross-device turn.\n for (const attachment of draft.attachments) {\n if (attachment.status.type !== 'complete')\n throw new Error('Wait for attachments to finish before sending your edit.');\n for (const part of attachment.content ?? []) {\n if (part.type === 'text') texts.push(part.text);\n else if (part.type === 'image')\n files.push({ type: 'file', mediaType: 'image/*', url: part.image });\n else if (part.type === 'file')\n files.push({\n type: 'file',\n mediaType: part.mimeType,\n url: part.data,\n ...(part.filename && { filename: part.filename }),\n });\n else throw new Error('This attachment cannot be edited here.');\n }\n }\n submitting.current = true;\n try {\n const sourceId = aui.message().getState().id;\n const readExtras = () =>\n alive.current ? readDeepAgentStatewireExtras(aui.thread().getState().extras) : null;\n const extras = readExtras();\n if (extras) {\n const preparedMetadata = extras.prepareMessageMetadata?.();\n try {\n const command = await resolveDeepAgentEditCommand({\n readExtras,\n sourceId,\n text,\n });\n if (!alive.current || !composer.getState().isEditing) {\n if (preparedMetadata) extras.discardPreparedMessageMetadata?.(preparedMetadata);\n return false;\n }\n if (command) {\n void Promise.resolve(\n extras.sendCommand(\n {\n ...command,\n message: {\n ...command.message,\n parts: [\n ...files,\n ...(texts.length\n ? [{ type: 'text' as const, text: texts.join('\\n\\n') }]\n : []),\n ],\n },\n },\n preparedMetadata === undefined ? undefined : { preparedMetadata },\n ),\n ).catch(() => undefined);\n composer.cancel();\n return true;\n }\n if (preparedMetadata && extras.sendPreparedEdit) {\n extras.sendPreparedEdit(sourceId, preparedMetadata);\n return true;\n }\n } catch (error) {\n if (preparedMetadata) extras.discardPreparedMessageMetadata?.(preparedMetadata);\n throw error;\n }\n }\n composer.send();\n return true;\n } finally {\n submitting.current = false;\n }\n }, [aui]);\n}\n"],"names":[],"mappings":";;;AAqBO,SAAS,gCAAwD;AACtE,QAAM,MAAM,OAAA;AACZ,QAAM,QAAQ,OAAO,IAAI;AACzB,QAAM,aAAa,OAAO,KAAK;AAC/B,YAAU,MAAM;AACd,UAAM,UAAU;AAChB,WAAO,MAAM;AACX,YAAM,UAAU;AAAA,IAClB;AAAA,EACF,GAAG,CAAA,CAAE;AACL,SAAO,YAAY,YAAY;;AAC7B,QAAI,WAAW,QAAS,QAAO;AAC/B,UAAM,WAAW,IAAI,QAAA,EAAU,SAAA;AAC/B,UAAM,QAAQ,SAAS,SAAA;AACvB,UAAM,OAAO,MAAM,KAAK,KAAA;AACxB,QAAI,CAAC,QAAQ,MAAM,YAAY,WAAW,EAAG,QAAO;AACpD,UAAM,QAAoC,CAAA;AAC1C,UAAM,QAAQ,OAAO,CAAC,IAAI,IAAI,CAAA;AAI9B,eAAW,cAAc,MAAM,aAAa;AAC1C,UAAI,WAAW,OAAO,SAAS;AAC7B,cAAM,IAAI,MAAM,0DAA0D;AAC5E,iBAAW,QAAQ,WAAW,WAAW,CAAA,GAAI;AAC3C,YAAI,KAAK,SAAS,OAAQ,OAAM,KAAK,KAAK,IAAI;AAAA,iBACrC,KAAK,SAAS;AACrB,gBAAM,KAAK,EAAE,MAAM,QAAQ,WAAW,WAAW,KAAK,KAAK,OAAO;AAAA,iBAC3D,KAAK,SAAS;AACrB,gBAAM,KAAK;AAAA,YACT,MAAM;AAAA,YACN,WAAW,KAAK;AAAA,YAChB,KAAK,KAAK;AAAA,YACV,GAAI,KAAK,YAAY,EAAE,UAAU,KAAK,SAAA;AAAA,UAAS,CAChD;AAAA,YACE,OAAM,IAAI,MAAM,wCAAwC;AAAA,MAC/D;AAAA,IACF;AACA,eAAW,UAAU;AACrB,QAAI;AACF,YAAM,WAAW,IAAI,QAAA,EAAU,WAAW;AAC1C,YAAM,aAAa,MACjB,MAAM,UAAU,6BAA6B,IAAI,SAAS,WAAW,MAAM,IAAI;AACjF,YAAM,SAAS,WAAA;AACf,UAAI,QAAQ;AACV,cAAM,oBAAmB,YAAO,2BAAP;AACzB,YAAI;AACF,gBAAM,UAAU,MAAM,4BAA4B;AAAA,YAChD;AAAA,YACA;AAAA,YACA;AAAA,UAAA,CACD;AACD,cAAI,CAAC,MAAM,WAAW,CAAC,SAAS,SAAA,EAAW,WAAW;AACpD,gBAAI,iBAAkB,cAAO,mCAAP,gCAAwC;AAC9D,mBAAO;AAAA,UACT;AACA,cAAI,SAAS;AACX,iBAAK,QAAQ;AAAA,cACX,OAAO;AAAA,gBACL;AAAA,kBACE,GAAG;AAAA,kBACH,SAAS;AAAA,oBACP,GAAG,QAAQ;AAAA,oBACX,OAAO;AAAA,sBACL,GAAG;AAAA,sBACH,GAAI,MAAM,SACN,CAAC,EAAE,MAAM,QAAiB,MAAM,MAAM,KAAK,MAAM,EAAA,CAAG,IACpD,CAAA;AAAA,oBAAC;AAAA,kBACP;AAAA,gBACF;AAAA,gBAEF,qBAAqB,SAAY,SAAY,EAAE,iBAAA;AAAA,cAAiB;AAAA,YAClE,EACA,MAAM,MAAM,MAAS;AACvB,qBAAS,OAAA;AACT,mBAAO;AAAA,UACT;AACA,cAAI,oBAAoB,OAAO,kBAAkB;AAC/C,mBAAO,iBAAiB,UAAU,gBAAgB;AAClD,mBAAO;AAAA,UACT;AAAA,QACF,SAAS,OAAO;AACd,cAAI,iBAAkB,cAAO,mCAAP,gCAAwC;AAC9D,gBAAM;AAAA,QACR;AAAA,MACF;AACA,eAAS,KAAA;AACT,aAAO;AAAA,IACT,UAAA;AACE,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AACV;"}
|