@invergent/agent-chat-react 2.17.8 → 2.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +228 -287
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -3
- package/dist/index.d.ts +37 -3
- package/dist/index.js +230 -287
- package/dist/index.js.map +1 -1
- package/package.json +1 -2
package/dist/index.cjs
CHANGED
|
@@ -23,10 +23,8 @@ var AnsiImport = require('ansi-to-react');
|
|
|
23
23
|
var cmdk = require('cmdk');
|
|
24
24
|
var nanoid = require('nanoid');
|
|
25
25
|
require('tokenlens');
|
|
26
|
-
require('pdfjs-dist/web/pdf_viewer.css');
|
|
27
26
|
var dateFns = require('date-fns');
|
|
28
27
|
|
|
29
|
-
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
30
28
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
31
29
|
|
|
32
30
|
var AnsiImport__default = /*#__PURE__*/_interopDefault(AnsiImport);
|
|
@@ -12606,7 +12604,7 @@ function messageToEntries(msg, isLast, artifactFallbacks) {
|
|
|
12606
12604
|
if (msg.systemKind === "worker" || msg.systemKind === "thread_proposal") {
|
|
12607
12605
|
return [{ kind: "thread_card", key: msg.id, message: msg }];
|
|
12608
12606
|
}
|
|
12609
|
-
if (msg.systemKind === "browser_marker" || msg.systemKind === "browser_marker_warning") {
|
|
12607
|
+
if (msg.systemKind === "browser_marker" || msg.systemKind === "browser_marker_warning" || msg.systemKind === "notice") {
|
|
12610
12608
|
return [{
|
|
12611
12609
|
kind: "browser_marker",
|
|
12612
12610
|
key: msg.id,
|
|
@@ -12817,7 +12815,7 @@ function OrphanSystemMarker({
|
|
|
12817
12815
|
}
|
|
12818
12816
|
);
|
|
12819
12817
|
}
|
|
12820
|
-
if (message.systemKind === "browser_marker" || message.systemKind === "browser_marker_warning") {
|
|
12818
|
+
if (message.systemKind === "browser_marker" || message.systemKind === "browser_marker_warning" || message.systemKind === "notice") {
|
|
12821
12819
|
const warning = message.systemKind === "browser_marker_warning";
|
|
12822
12820
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12823
12821
|
"div",
|
|
@@ -13853,7 +13851,8 @@ var WORKSPACE_MUTATING_TOOLS = /* @__PURE__ */ new Set([
|
|
|
13853
13851
|
"write_file",
|
|
13854
13852
|
"patch",
|
|
13855
13853
|
"execute_code",
|
|
13856
|
-
"browser_screenshot"
|
|
13854
|
+
"browser_screenshot",
|
|
13855
|
+
"office_edit"
|
|
13857
13856
|
]);
|
|
13858
13857
|
var AGENT_CHAT_LISTENED_EVENTS = [
|
|
13859
13858
|
"user.message",
|
|
@@ -13901,7 +13900,10 @@ var AGENT_CHAT_LISTENED_EVENTS = [
|
|
|
13901
13900
|
"worker.spawned",
|
|
13902
13901
|
"worker.complete",
|
|
13903
13902
|
"worker.failed",
|
|
13904
|
-
"thread.proposed"
|
|
13903
|
+
"thread.proposed",
|
|
13904
|
+
"office.conflict",
|
|
13905
|
+
"office.save_failed",
|
|
13906
|
+
"stream.live"
|
|
13905
13907
|
];
|
|
13906
13908
|
var AGENT_CHAT_LISTENED_EVENT_SET = new Set(
|
|
13907
13909
|
AGENT_CHAT_LISTENED_EVENTS
|
|
@@ -14146,7 +14148,10 @@ function createInitialAgentChatState(options = {}) {
|
|
|
14146
14148
|
browserTabs: [],
|
|
14147
14149
|
viewMode: options.viewMode ?? "simple",
|
|
14148
14150
|
researchSources: [],
|
|
14149
|
-
deviceWait: null
|
|
14151
|
+
deviceWait: null,
|
|
14152
|
+
officeEvents: {},
|
|
14153
|
+
live: false,
|
|
14154
|
+
officeAutoOpen: null
|
|
14150
14155
|
};
|
|
14151
14156
|
}
|
|
14152
14157
|
function applyAgentChatEvent(state, event) {
|
|
@@ -14164,6 +14169,9 @@ function applyAgentChatEvent(state, event) {
|
|
|
14164
14169
|
case "user.message":
|
|
14165
14170
|
// A project coordinator's follow-up to its thread: shown as the thread reads it, its header saying whose it is.
|
|
14166
14171
|
case "coordinator.message":
|
|
14172
|
+
if (event.type === "user.message" && PLATFORM_NOTES.has(stringValue2(event.data.synthetic))) {
|
|
14173
|
+
return nextState;
|
|
14174
|
+
}
|
|
14167
14175
|
return withMessages(
|
|
14168
14176
|
{ ...nextState, terminal: false, stopped: false, isRunning: true },
|
|
14169
14177
|
applyUserMessage(nextState.messages, event.eventId, event.data)
|
|
@@ -14306,6 +14314,21 @@ function applyAgentChatEvent(state, event) {
|
|
|
14306
14314
|
};
|
|
14307
14315
|
case "device.resumed":
|
|
14308
14316
|
return { ...nextState, deviceWait: null };
|
|
14317
|
+
case "office.conflict":
|
|
14318
|
+
case "office.save_failed": {
|
|
14319
|
+
const path = stringValue2(event.data.path);
|
|
14320
|
+
if (!path) return nextState;
|
|
14321
|
+
const conflict = event.type === "office.conflict";
|
|
14322
|
+
return {
|
|
14323
|
+
...nextState,
|
|
14324
|
+
officeEvents: {
|
|
14325
|
+
...nextState.officeEvents,
|
|
14326
|
+
[path]: conflict ? { type: event.type, eventId: event.eventId, conflictPath: stringValue2(event.data.conflict_path) } : { type: event.type, eventId: event.eventId }
|
|
14327
|
+
},
|
|
14328
|
+
// The copy the conflicting save landed as shows in the tree.
|
|
14329
|
+
workspaceRefreshKey: nextState.workspaceRefreshKey + (conflict ? 1 : 0)
|
|
14330
|
+
};
|
|
14331
|
+
}
|
|
14309
14332
|
case "worker.spawned":
|
|
14310
14333
|
return withMessages(nextState, applyWorkerSpawned(nextState.messages, event));
|
|
14311
14334
|
case "worker.complete":
|
|
@@ -14319,17 +14342,22 @@ function applyAgentChatEvent(state, event) {
|
|
|
14319
14342
|
return applyLlmResponse(nextState, event);
|
|
14320
14343
|
case "llm.thinking":
|
|
14321
14344
|
return applyLlmThinking(nextState, event);
|
|
14345
|
+
case "stream.live":
|
|
14346
|
+
return { ...nextState, live: true };
|
|
14322
14347
|
case "tool.call":
|
|
14323
14348
|
return applyToolCall(nextState, event);
|
|
14324
14349
|
case "tool.result": {
|
|
14325
14350
|
const toolCallId = stringValue2(event.data.tool_call_id);
|
|
14326
|
-
const toolName = findToolNameById(nextState.messages, toolCallId);
|
|
14327
14351
|
const messages = applyToolResult(nextState.messages, event.data);
|
|
14352
|
+
const call = findToolCallById(messages, toolCallId);
|
|
14353
|
+
const toolName = call?.toolName ?? null;
|
|
14328
14354
|
const mutatesWorkspace = toolName !== null && WORKSPACE_MUTATING_TOOLS.has(toolName);
|
|
14355
|
+
const officePath = nextState.live && call?.toolName === "office_edit" && !toolCallFailed(call) ? officeEditPath(call.args) : null;
|
|
14329
14356
|
const withResult = {
|
|
14330
14357
|
...nextState,
|
|
14331
14358
|
messages,
|
|
14332
|
-
workspaceRefreshKey: mutatesWorkspace ? nextState.workspaceRefreshKey + 1 : nextState.workspaceRefreshKey
|
|
14359
|
+
workspaceRefreshKey: mutatesWorkspace ? nextState.workspaceRefreshKey + 1 : nextState.workspaceRefreshKey,
|
|
14360
|
+
officeAutoOpen: officePath ? { path: officePath, eventId: event.eventId } : nextState.officeAutoOpen
|
|
14333
14361
|
};
|
|
14334
14362
|
return collectResearchSource(withResult, toolName, event.data);
|
|
14335
14363
|
}
|
|
@@ -14466,6 +14494,7 @@ function typedBehindTheClear(messages, answers) {
|
|
|
14466
14494
|
}
|
|
14467
14495
|
return messages.slice(first);
|
|
14468
14496
|
}
|
|
14497
|
+
var PLATFORM_NOTES = /* @__PURE__ */ new Set(["checkin", "checkin_opener", "outreach_opener"]);
|
|
14469
14498
|
function applyUserMessage(messages, eventId, data) {
|
|
14470
14499
|
const content = stringValue2(data.content);
|
|
14471
14500
|
const images = parseUserMessageImages(data.images);
|
|
@@ -14531,6 +14560,22 @@ function parseUserMessageAttachments(raw) {
|
|
|
14531
14560
|
}
|
|
14532
14561
|
return out.length > 0 ? out : void 0;
|
|
14533
14562
|
}
|
|
14563
|
+
function officeEditPath(args) {
|
|
14564
|
+
try {
|
|
14565
|
+
const path = JSON.parse(args)?.path;
|
|
14566
|
+
return typeof path === "string" ? path.replace(/^__WORKSPACE__\//, "") || null : null;
|
|
14567
|
+
} catch {
|
|
14568
|
+
return null;
|
|
14569
|
+
}
|
|
14570
|
+
}
|
|
14571
|
+
function toolCallFailed(call) {
|
|
14572
|
+
if (call.status === "error") return true;
|
|
14573
|
+
try {
|
|
14574
|
+
return JSON.parse(call.result ?? "")?.error != null;
|
|
14575
|
+
} catch {
|
|
14576
|
+
return false;
|
|
14577
|
+
}
|
|
14578
|
+
}
|
|
14534
14579
|
function onComputer(event) {
|
|
14535
14580
|
return event.data.computer === true ? { computer: true } : {};
|
|
14536
14581
|
}
|
|
@@ -14646,6 +14691,21 @@ function applyLlmResponse(state, event) {
|
|
|
14646
14691
|
const messages = [...state.messages];
|
|
14647
14692
|
const message = objectValue(event.data.message);
|
|
14648
14693
|
const responseContent = stringValue2(message?.content) || stringValue2(event.data.content);
|
|
14694
|
+
if (event.data.notice === true) {
|
|
14695
|
+
return {
|
|
14696
|
+
...state,
|
|
14697
|
+
messages: [...messages, {
|
|
14698
|
+
id: `evt-${event.eventId}`,
|
|
14699
|
+
role: "system",
|
|
14700
|
+
systemKind: "notice",
|
|
14701
|
+
content: responseContent,
|
|
14702
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
14703
|
+
status: "complete"
|
|
14704
|
+
}],
|
|
14705
|
+
hadDeltas: false,
|
|
14706
|
+
isRunning: false
|
|
14707
|
+
};
|
|
14708
|
+
}
|
|
14649
14709
|
const toolCalls = Array.isArray(message?.tool_calls) ? message?.tool_calls : [];
|
|
14650
14710
|
const hasToolCalls = toolCalls.length > 0;
|
|
14651
14711
|
const responseToolCallIds = toolCallIdsFromResponse(toolCalls);
|
|
@@ -15370,11 +15430,11 @@ function hasUserAfterIndex(messages, idx) {
|
|
|
15370
15430
|
}
|
|
15371
15431
|
return false;
|
|
15372
15432
|
}
|
|
15373
|
-
function
|
|
15433
|
+
function findToolCallById(messages, toolCallId) {
|
|
15374
15434
|
if (!toolCallId) return null;
|
|
15375
15435
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
15376
15436
|
const tc = messages[i]?.toolCalls?.find((c) => c.id === toolCallId);
|
|
15377
|
-
if (tc) return tc
|
|
15437
|
+
if (tc) return tc;
|
|
15378
15438
|
}
|
|
15379
15439
|
return null;
|
|
15380
15440
|
}
|
|
@@ -15555,7 +15615,7 @@ function useAgentChatRuntime({
|
|
|
15555
15615
|
stream.addEventListener(eventType, (messageEvent) => {
|
|
15556
15616
|
if (streamRef.current !== stream) return;
|
|
15557
15617
|
const data = parseEventData(messageEvent.data);
|
|
15558
|
-
const eventId = messageEvent.lastEventId ? Number(messageEvent.lastEventId) : 0;
|
|
15618
|
+
const eventId = eventType === "stream.live" ? 0 : messageEvent.lastEventId ? Number(messageEvent.lastEventId) : 0;
|
|
15559
15619
|
setState(
|
|
15560
15620
|
(prev) => applyRuntimeEvent(prev, {
|
|
15561
15621
|
type: eventType,
|
|
@@ -19361,12 +19421,42 @@ function chunkPairs(flat) {
|
|
|
19361
19421
|
for (let i = 0; i + 1 < flat.length; i += 2) pairs.push([flat[i], flat[i + 1]]);
|
|
19362
19422
|
return pairs;
|
|
19363
19423
|
}
|
|
19424
|
+
|
|
19425
|
+
// src/lib/office.ts
|
|
19426
|
+
var OFFICE_EXTENSIONS = /* @__PURE__ */ new Set(["docx", "xlsx", "pptx", "pdf", "doc", "odt", "rtf", "xls", "ods", "ppt", "odp"]);
|
|
19427
|
+
function isOfficeDocument(path) {
|
|
19428
|
+
const dot = path.lastIndexOf(".");
|
|
19429
|
+
return dot >= 0 && OFFICE_EXTENSIONS.has(path.slice(dot + 1).toLowerCase());
|
|
19430
|
+
}
|
|
19431
|
+
var loads = /* @__PURE__ */ new Map();
|
|
19432
|
+
var LOAD_TIMEOUT_MS = 3e4;
|
|
19433
|
+
function loadDocsApi(documentServerUrl) {
|
|
19434
|
+
const src = `${documentServerUrl.replace(/\/$/, "")}/web-apps/apps/api/documents/api.js`;
|
|
19435
|
+
let load = loads.get(src);
|
|
19436
|
+
if (!load) {
|
|
19437
|
+
load = new Promise((resolve, reject) => {
|
|
19438
|
+
const script = document.createElement("script");
|
|
19439
|
+
const settle = (loaded) => {
|
|
19440
|
+
clearTimeout(timer);
|
|
19441
|
+
script.onload = script.onerror = null;
|
|
19442
|
+
if (loaded) return resolve();
|
|
19443
|
+
loads.delete(src);
|
|
19444
|
+
script.remove();
|
|
19445
|
+
reject(new Error("The document editor could not be loaded."));
|
|
19446
|
+
};
|
|
19447
|
+
const timer = setTimeout(() => settle(false), LOAD_TIMEOUT_MS);
|
|
19448
|
+
script.src = src;
|
|
19449
|
+
script.async = true;
|
|
19450
|
+
script.onload = () => settle(Boolean(window.DocsAPI));
|
|
19451
|
+
script.onerror = () => settle(false);
|
|
19452
|
+
document.head.appendChild(script);
|
|
19453
|
+
});
|
|
19454
|
+
loads.set(src, load);
|
|
19455
|
+
}
|
|
19456
|
+
return load;
|
|
19457
|
+
}
|
|
19364
19458
|
init_utils();
|
|
19365
19459
|
var SKELETON_WIDTHS = [70, 85, 55, 90, 60, 78, 45, 82, 65, 72];
|
|
19366
|
-
var PDF_WORKER_SRC = new URL(
|
|
19367
|
-
"pdfjs-dist/legacy/build/pdf.worker.mjs",
|
|
19368
|
-
(typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))
|
|
19369
|
-
).toString();
|
|
19370
19460
|
function FileViewer({
|
|
19371
19461
|
file,
|
|
19372
19462
|
loading,
|
|
@@ -19381,8 +19471,8 @@ function FileViewer({
|
|
|
19381
19471
|
if (!visible) return null;
|
|
19382
19472
|
const fileName2 = file?.path.split("/").pop() ?? "File";
|
|
19383
19473
|
const lang = file ? getLanguageHint(file.path) : "";
|
|
19384
|
-
const
|
|
19385
|
-
const
|
|
19474
|
+
const isImage = file?.encoding === "base64" && (file.mime_type?.startsWith("image/") ?? false);
|
|
19475
|
+
const isBinary = file?.encoding === "base64" && !isImage;
|
|
19386
19476
|
const HeaderIcon = isImage ? lucideReact.ImageIcon : lucideReact.FileTextIcon;
|
|
19387
19477
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex min-h-0 flex-1 flex-col border-t border-line", className), children: [
|
|
19388
19478
|
!hideHeader && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-2 border-b border-line px-3 py-2", children: [
|
|
@@ -19430,12 +19520,7 @@ function FileViewer({
|
|
|
19430
19520
|
}
|
|
19431
19521
|
)
|
|
19432
19522
|
] }),
|
|
19433
|
-
|
|
19434
|
-
// PDF has its own scrollable container — bypass ScrollArea so
|
|
19435
|
-
// it can grow with the parent's flex height (Radix Viewport's
|
|
19436
|
-
// internal table wrapper sizes to content and breaks h-full).
|
|
19437
|
-
/* @__PURE__ */ jsxRuntime.jsx(PdfPreview, { file, fileName: fileName2 })
|
|
19438
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs(ScrollArea, { className: "min-h-0 flex-1", children: [
|
|
19523
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ScrollArea, { className: "min-h-0 flex-1", children: [
|
|
19439
19524
|
loading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5 p-3", children: Array.from({ length: 10 }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
19440
19525
|
Skeleton,
|
|
19441
19526
|
{
|
|
@@ -19450,7 +19535,7 @@ function FileViewer({
|
|
|
19450
19535
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
19451
19536
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: error })
|
|
19452
19537
|
] }),
|
|
19453
|
-
file &&
|
|
19538
|
+
file && isBinary && /* @__PURE__ */ jsxRuntime.jsx(FileViewerError, { message: "Preview not available. Download the file to open it." }),
|
|
19454
19539
|
file && isImage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center p-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
19455
19540
|
"img",
|
|
19456
19541
|
{
|
|
@@ -19459,7 +19544,7 @@ function FileViewer({
|
|
|
19459
19544
|
className: "max-h-[60vh] max-w-full rounded object-contain"
|
|
19460
19545
|
}
|
|
19461
19546
|
) }),
|
|
19462
|
-
file && !isImage && !
|
|
19547
|
+
file && !isImage && !isBinary && /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "wrap-break-word whitespace-pre-wrap p-3 text-base leading-relaxed text-foreground", children: /* @__PURE__ */ jsxRuntime.jsx("code", { "data-language": lang, children: file.content }) })
|
|
19463
19548
|
] })
|
|
19464
19549
|
] });
|
|
19465
19550
|
}
|
|
@@ -19469,277 +19554,113 @@ function FileViewerError({ message }) {
|
|
|
19469
19554
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: message })
|
|
19470
19555
|
] });
|
|
19471
19556
|
}
|
|
19472
|
-
function
|
|
19473
|
-
|
|
19474
|
-
|
|
19475
|
-
|
|
19476
|
-
const containerRef = react.useRef(null);
|
|
19477
|
-
const viewerRef = react.useRef(null);
|
|
19478
|
-
const pdfViewerRef = react.useRef(null);
|
|
19479
|
-
const eventBusRef = react.useRef(null);
|
|
19480
|
-
const findControllerRef = react.useRef(null);
|
|
19557
|
+
function OfficeEditorPane({ adapter, sessionId, path, view, officeEvent, onClose }) {
|
|
19558
|
+
const { resolvedTheme } = nextThemes.useTheme();
|
|
19559
|
+
const theme = resolvedTheme === "dark" ? "dark" : "light";
|
|
19560
|
+
const placeholderId = `office-editor-${react.useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
19481
19561
|
const [error, setError] = react.useState(null);
|
|
19482
|
-
const [
|
|
19483
|
-
const [
|
|
19484
|
-
const
|
|
19485
|
-
const [
|
|
19562
|
+
const [loading, setLoading] = react.useState(true);
|
|
19563
|
+
const [openedAfter] = react.useState(() => officeEvent?.eventId ?? 0);
|
|
19564
|
+
const notice = officeEvent && officeEvent.eventId > openedAfter ? officeEvent : null;
|
|
19565
|
+
const [reopenedFor, setReopenedFor] = react.useState(0);
|
|
19566
|
+
if (notice?.type === "office.conflict" && notice.eventId !== reopenedFor) setReopenedFor(notice.eventId);
|
|
19567
|
+
const paneRef = react.useRef(null);
|
|
19568
|
+
const [fullScreen, setFullScreen] = react.useState(false);
|
|
19569
|
+
react.useEffect(() => {
|
|
19570
|
+
const follow = () => setFullScreen(document.fullscreenElement === paneRef.current);
|
|
19571
|
+
document.addEventListener("fullscreenchange", follow);
|
|
19572
|
+
return () => document.removeEventListener("fullscreenchange", follow);
|
|
19573
|
+
}, []);
|
|
19486
19574
|
react.useEffect(() => {
|
|
19487
19575
|
let cancelled = false;
|
|
19488
|
-
let
|
|
19489
|
-
|
|
19490
|
-
|
|
19491
|
-
|
|
19492
|
-
|
|
19493
|
-
|
|
19494
|
-
|
|
19495
|
-
|
|
19496
|
-
|
|
19497
|
-
|
|
19498
|
-
|
|
19499
|
-
|
|
19500
|
-
|
|
19501
|
-
|
|
19502
|
-
|
|
19503
|
-
if (cancelled) return;
|
|
19504
|
-
const eventBus = new pdfViewerModule.EventBus();
|
|
19505
|
-
const linkService = new pdfViewerModule.PDFLinkService({ eventBus });
|
|
19506
|
-
const findController = new pdfViewerModule.PDFFindController({
|
|
19507
|
-
eventBus,
|
|
19508
|
-
linkService
|
|
19509
|
-
});
|
|
19510
|
-
const pdfViewer = new pdfViewerModule.PDFViewer({
|
|
19511
|
-
container,
|
|
19512
|
-
viewer: viewerElement,
|
|
19513
|
-
eventBus,
|
|
19514
|
-
linkService,
|
|
19515
|
-
findController,
|
|
19516
|
-
removePageBorders: true
|
|
19517
|
-
});
|
|
19518
|
-
linkService.setViewer(pdfViewer);
|
|
19519
|
-
linkService.setDocument(pdf);
|
|
19520
|
-
findController.setDocument(pdf);
|
|
19521
|
-
const onPagesInit = () => {
|
|
19522
|
-
pdfViewer.currentScaleValue = "page-width";
|
|
19523
|
-
setScale(pdfViewer.currentScale || 1);
|
|
19524
|
-
setPagesCount(pdfViewer.pagesCount);
|
|
19525
|
-
setPageNumber(pdfViewer.currentPageNumber);
|
|
19526
|
-
};
|
|
19527
|
-
const onPageChanging = (event) => {
|
|
19528
|
-
if (typeof event.pageNumber === "number") {
|
|
19529
|
-
setPageNumber(event.pageNumber);
|
|
19530
|
-
}
|
|
19531
|
-
};
|
|
19532
|
-
const onScaleChanging = (event) => {
|
|
19533
|
-
if (typeof event.scale === "number") {
|
|
19534
|
-
setScale(event.scale);
|
|
19535
|
-
}
|
|
19536
|
-
};
|
|
19537
|
-
eventBus.on("pagesinit", onPagesInit);
|
|
19538
|
-
eventBus.on("pagechanging", onPageChanging);
|
|
19539
|
-
eventBus.on("scalechanging", onScaleChanging);
|
|
19540
|
-
pdfViewerRef.current = pdfViewer;
|
|
19541
|
-
eventBusRef.current = eventBus;
|
|
19542
|
-
findControllerRef.current = findController;
|
|
19543
|
-
setPagesCount(pdf.numPages);
|
|
19544
|
-
pdfViewer.setDocument(pdf);
|
|
19545
|
-
};
|
|
19546
|
-
void renderPdf().catch((nextError) => {
|
|
19547
|
-
if (cancelled) return;
|
|
19548
|
-
if (nextError instanceof Error && nextError.name === "RenderingCancelledException") {
|
|
19549
|
-
return;
|
|
19576
|
+
let editor = null;
|
|
19577
|
+
setError(null);
|
|
19578
|
+
setLoading(true);
|
|
19579
|
+
void (async () => {
|
|
19580
|
+
try {
|
|
19581
|
+
if (!adapter.getWorkspaceEditorConfig) throw new Error("Preview not available. Download the file to open it.");
|
|
19582
|
+
const opened = await adapter.getWorkspaceEditorConfig({ sessionId, path, theme, view });
|
|
19583
|
+
await loadDocsApi(opened.document_server_url);
|
|
19584
|
+
if (cancelled) return;
|
|
19585
|
+
if (!window.DocsAPI) throw new Error("The document editor could not be loaded.");
|
|
19586
|
+
editor = new window.DocsAPI.DocEditor(placeholderId, opened.config);
|
|
19587
|
+
} catch (openError) {
|
|
19588
|
+
if (!cancelled) setError(openError.message);
|
|
19589
|
+
} finally {
|
|
19590
|
+
if (!cancelled) setLoading(false);
|
|
19550
19591
|
}
|
|
19551
|
-
|
|
19552
|
-
});
|
|
19592
|
+
})();
|
|
19553
19593
|
return () => {
|
|
19554
19594
|
cancelled = true;
|
|
19555
|
-
|
|
19556
|
-
pdfDocument?.destroy();
|
|
19557
|
-
pdfViewerRef.current?.cleanup();
|
|
19558
|
-
pdfViewerRef.current = null;
|
|
19559
|
-
eventBusRef.current = null;
|
|
19560
|
-
findControllerRef.current = null;
|
|
19595
|
+
editor?.destroyEditor();
|
|
19561
19596
|
};
|
|
19562
|
-
}, [
|
|
19563
|
-
const
|
|
19564
|
-
|
|
19565
|
-
|
|
19566
|
-
|
|
19567
|
-
|
|
19568
|
-
|
|
19569
|
-
|
|
19570
|
-
|
|
19571
|
-
|
|
19572
|
-
|
|
19573
|
-
|
|
19574
|
-
|
|
19575
|
-
|
|
19576
|
-
|
|
19577
|
-
|
|
19578
|
-
|
|
19579
|
-
|
|
19580
|
-
|
|
19581
|
-
|
|
19582
|
-
|
|
19583
|
-
|
|
19584
|
-
|
|
19585
|
-
|
|
19586
|
-
|
|
19587
|
-
|
|
19588
|
-
|
|
19589
|
-
|
|
19590
|
-
|
|
19591
|
-
|
|
19592
|
-
|
|
19593
|
-
|
|
19594
|
-
|
|
19595
|
-
|
|
19596
|
-
|
|
19597
|
-
|
|
19598
|
-
|
|
19599
|
-
|
|
19600
|
-
|
|
19601
|
-
|
|
19602
|
-
|
|
19603
|
-
|
|
19604
|
-
|
|
19605
|
-
|
|
19606
|
-
|
|
19607
|
-
|
|
19608
|
-
|
|
19609
|
-
|
|
19610
|
-
|
|
19611
|
-
|
|
19612
|
-
{
|
|
19613
|
-
|
|
19614
|
-
|
|
19615
|
-
|
|
19616
|
-
|
|
19617
|
-
|
|
19618
|
-
|
|
19619
|
-
|
|
19620
|
-
|
|
19621
|
-
),
|
|
19622
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
19623
|
-
"/ ",
|
|
19624
|
-
pagesCount || "-"
|
|
19625
|
-
] }),
|
|
19626
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19627
|
-
Button,
|
|
19628
|
-
{
|
|
19629
|
-
type: "button",
|
|
19630
|
-
variant: "ghost",
|
|
19631
|
-
size: "icon-xs",
|
|
19632
|
-
onClick: () => setViewerPage(pageNumber + 1),
|
|
19633
|
-
disabled: pagesCount > 0 && pageNumber >= pagesCount,
|
|
19634
|
-
"aria-label": "Next PDF page",
|
|
19635
|
-
title: "Next page",
|
|
19636
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRightIcon, { className: "size-3.5" })
|
|
19637
|
-
}
|
|
19638
|
-
),
|
|
19639
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-1 h-5 w-px bg-line" }),
|
|
19640
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19641
|
-
Button,
|
|
19642
|
-
{
|
|
19643
|
-
type: "button",
|
|
19644
|
-
variant: "ghost",
|
|
19645
|
-
size: "icon-xs",
|
|
19646
|
-
onClick: () => setViewerScale(scale - 0.1),
|
|
19647
|
-
disabled: scale <= 0.5,
|
|
19648
|
-
"aria-label": "Zoom out PDF",
|
|
19649
|
-
title: "Zoom out",
|
|
19650
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MinusIcon, { className: "size-3.5" })
|
|
19651
|
-
}
|
|
19652
|
-
),
|
|
19653
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
19654
|
-
"button",
|
|
19655
|
-
{
|
|
19656
|
-
type: "button",
|
|
19657
|
-
className: "h-7 min-w-12 px-1 text-xs text-muted-foreground hover:text-foreground",
|
|
19658
|
-
onClick: () => {
|
|
19659
|
-
const viewer = pdfViewerRef.current;
|
|
19660
|
-
if (!viewer) return;
|
|
19661
|
-
viewer.currentScaleValue = "page-width";
|
|
19662
|
-
setScale(viewer.currentScale || 1);
|
|
19663
|
-
},
|
|
19664
|
-
"aria-label": "Fit PDF to width",
|
|
19665
|
-
title: "Fit width",
|
|
19666
|
-
children: [
|
|
19667
|
-
Math.round(scale * 100),
|
|
19668
|
-
"%"
|
|
19669
|
-
]
|
|
19670
|
-
}
|
|
19671
|
-
),
|
|
19672
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19673
|
-
Button,
|
|
19674
|
-
{
|
|
19675
|
-
type: "button",
|
|
19676
|
-
variant: "ghost",
|
|
19677
|
-
size: "icon-xs",
|
|
19678
|
-
onClick: () => setViewerScale(scale + 0.1),
|
|
19679
|
-
disabled: scale >= 3,
|
|
19680
|
-
"aria-label": "Zoom in PDF",
|
|
19681
|
-
title: "Zoom in",
|
|
19682
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PlusIcon, { className: "size-3.5" })
|
|
19683
|
-
}
|
|
19684
|
-
),
|
|
19685
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-1 h-5 w-px bg-line" }),
|
|
19686
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.SearchIcon, { className: "size-3.5 text-muted-foreground" }),
|
|
19687
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19688
|
-
Input,
|
|
19689
|
-
{
|
|
19690
|
-
type: "search",
|
|
19691
|
-
value: query,
|
|
19692
|
-
onChange: (event) => setQuery(event.target.value),
|
|
19693
|
-
onKeyDown: (event) => {
|
|
19694
|
-
if (event.key === "Enter") runFind(event.shiftKey);
|
|
19695
|
-
},
|
|
19696
|
-
placeholder: "Find",
|
|
19697
|
-
"aria-label": "Find in PDF",
|
|
19698
|
-
className: "h-7 w-28 border-input px-1 text-xs"
|
|
19699
|
-
}
|
|
19700
|
-
),
|
|
19701
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19702
|
-
Button,
|
|
19703
|
-
{
|
|
19704
|
-
type: "button",
|
|
19705
|
-
variant: "ghost",
|
|
19706
|
-
size: "xs",
|
|
19707
|
-
onClick: () => runFind(false),
|
|
19708
|
-
disabled: !query.trim(),
|
|
19709
|
-
children: "Find"
|
|
19710
|
-
}
|
|
19711
|
-
)
|
|
19712
|
-
] }),
|
|
19713
|
-
error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-start gap-2 p-3 text-xs text-destructive", children: [
|
|
19714
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
19715
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: error })
|
|
19716
|
-
] }),
|
|
19717
|
-
!error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative min-h-105 flex-1 bg-muted/20", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
19718
|
-
"div",
|
|
19719
|
-
{
|
|
19720
|
-
ref: containerRef,
|
|
19721
|
-
"aria-label": `PDF viewer for ${fileName2}`,
|
|
19722
|
-
className: "absolute inset-0 overflow-auto",
|
|
19723
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: viewerRef, className: "pdfViewer" })
|
|
19724
|
-
}
|
|
19725
|
-
) })
|
|
19726
|
-
] });
|
|
19727
|
-
}
|
|
19728
|
-
function decodeBase64(content) {
|
|
19729
|
-
const binary = globalThis.atob(content);
|
|
19730
|
-
const bytes = new Uint8Array(binary.length);
|
|
19731
|
-
for (let index = 0; index < binary.length; index += 1) {
|
|
19732
|
-
bytes[index] = binary.charCodeAt(index);
|
|
19733
|
-
}
|
|
19734
|
-
return bytes;
|
|
19597
|
+
}, [adapter, sessionId, path, theme, view, placeholderId, reopenedFor]);
|
|
19598
|
+
const fileName2 = path.split("/").pop() ?? path;
|
|
19599
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
19600
|
+
"aside",
|
|
19601
|
+
{
|
|
19602
|
+
ref: paneRef,
|
|
19603
|
+
"data-testid": "file-preview-panel",
|
|
19604
|
+
className: "flex h-full min-h-0 w-full flex-col overflow-hidden border-l border-line bg-card",
|
|
19605
|
+
children: [
|
|
19606
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-2 border-b border-line px-3 py-2", children: [
|
|
19607
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileTextIcon, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
19608
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1 truncate font-medium", children: fileName2 }),
|
|
19609
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19610
|
+
"a",
|
|
19611
|
+
{
|
|
19612
|
+
href: adapter.getWorkspaceDownloadUrl({ sessionId, path }),
|
|
19613
|
+
download: fileName2,
|
|
19614
|
+
"aria-label": `Download ${fileName2}`,
|
|
19615
|
+
title: "Download",
|
|
19616
|
+
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
19617
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.DownloadIcon, { className: "size-4" })
|
|
19618
|
+
}
|
|
19619
|
+
),
|
|
19620
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19621
|
+
"button",
|
|
19622
|
+
{
|
|
19623
|
+
type: "button",
|
|
19624
|
+
onClick: () => void (fullScreen ? document.exitFullscreen() : paneRef.current?.requestFullscreen()),
|
|
19625
|
+
"aria-label": fullScreen ? "Exit full screen" : "Full screen",
|
|
19626
|
+
title: fullScreen ? "Exit full screen" : "Full screen",
|
|
19627
|
+
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
19628
|
+
children: fullScreen ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minimize2Icon, { className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2Icon, { className: "size-4" })
|
|
19629
|
+
}
|
|
19630
|
+
),
|
|
19631
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19632
|
+
"button",
|
|
19633
|
+
{
|
|
19634
|
+
type: "button",
|
|
19635
|
+
onClick: onClose,
|
|
19636
|
+
"aria-label": "Close file",
|
|
19637
|
+
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
19638
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "size-4" })
|
|
19639
|
+
}
|
|
19640
|
+
)
|
|
19641
|
+
] }),
|
|
19642
|
+
error && /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "alert", className: "flex items-start gap-2 p-3 text-xs text-destructive", children: [
|
|
19643
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
19644
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: error })
|
|
19645
|
+
] }),
|
|
19646
|
+
notice && /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", className: "border-b border-line px-3 py-2 text-xs text-muted-foreground", children: notice.type === "office.conflict" ? `This document changed outside the editor. Your edits were saved to ${notice.conflictPath}.` : "Your latest changes could not be saved yet." }),
|
|
19647
|
+
loading && !error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 text-sm text-muted-foreground", children: [
|
|
19648
|
+
"Opening ",
|
|
19649
|
+
fileName2,
|
|
19650
|
+
"\u2026"
|
|
19651
|
+
] }),
|
|
19652
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { id: placeholderId }) })
|
|
19653
|
+
]
|
|
19654
|
+
}
|
|
19655
|
+
);
|
|
19735
19656
|
}
|
|
19736
|
-
function
|
|
19737
|
-
if (
|
|
19738
|
-
return
|
|
19657
|
+
function WorkspaceFileDrawer({ adapter, sessionId, path, view = false, officeEvent, onClose }) {
|
|
19658
|
+
if (isOfficeDocument(path)) {
|
|
19659
|
+
return /* @__PURE__ */ jsxRuntime.jsx(OfficeEditorPane, { adapter, sessionId, path, view, officeEvent, onClose });
|
|
19739
19660
|
}
|
|
19740
|
-
return
|
|
19661
|
+
return /* @__PURE__ */ jsxRuntime.jsx(WorkspaceFilePreview, { adapter, sessionId, path, onClose });
|
|
19741
19662
|
}
|
|
19742
|
-
function
|
|
19663
|
+
function WorkspaceFilePreview({
|
|
19743
19664
|
adapter,
|
|
19744
19665
|
sessionId,
|
|
19745
19666
|
path,
|
|
@@ -20478,10 +20399,16 @@ function isSubAgentSession(session) {
|
|
|
20478
20399
|
if (session.channel && _SUB_AGENT_CHANNELS.has(session.channel)) return true;
|
|
20479
20400
|
return false;
|
|
20480
20401
|
}
|
|
20402
|
+
function isProjectThread(session) {
|
|
20403
|
+
return session?.config?.workstream_role === "thread";
|
|
20404
|
+
}
|
|
20481
20405
|
function readOnlyReasonForSession(session) {
|
|
20482
20406
|
if (isScheduledRunSession(session)) {
|
|
20483
20407
|
return { readOnly: true, reason: "Scheduled run is read-only" };
|
|
20484
20408
|
}
|
|
20409
|
+
if (isProjectThread(session)) {
|
|
20410
|
+
return { readOnly: false };
|
|
20411
|
+
}
|
|
20485
20412
|
if (isSubAgentSession(session)) {
|
|
20486
20413
|
return {
|
|
20487
20414
|
readOnly: true,
|
|
@@ -20551,11 +20478,13 @@ function AgentChat({
|
|
|
20551
20478
|
setOpenPane(null);
|
|
20552
20479
|
setFilesOpen(false);
|
|
20553
20480
|
}, [runtime.viewMode]);
|
|
20481
|
+
const officeAutoOpened = react.useRef(/* @__PURE__ */ new Set());
|
|
20554
20482
|
react.useEffect(() => {
|
|
20555
20483
|
setFilesOpen(false);
|
|
20556
20484
|
setWorkspacePath(null);
|
|
20557
20485
|
setPreviewPath(null);
|
|
20558
20486
|
setOpenPane(null);
|
|
20487
|
+
officeAutoOpened.current.clear();
|
|
20559
20488
|
}, [sessionId]);
|
|
20560
20489
|
const readOnly = readOnlyReasonForSession(runtime.session);
|
|
20561
20490
|
const boardAvailable = whiteboardEnabled && isBoardSession(runtime.session);
|
|
@@ -20638,6 +20567,16 @@ function AgentChat({
|
|
|
20638
20567
|
setOpenPane("file");
|
|
20639
20568
|
setMobileView("file");
|
|
20640
20569
|
}, []);
|
|
20570
|
+
const officeAutoOpen = runtime.state.officeAutoOpen;
|
|
20571
|
+
react.useEffect(() => {
|
|
20572
|
+
if (!officeAutoOpen || !isOfficeDocument(officeAutoOpen.path)) return;
|
|
20573
|
+
if (openPane === "file" && previewPath !== null && previewPath !== officeAutoOpen.path) return;
|
|
20574
|
+
if (officeAutoOpened.current.has(officeAutoOpen.path)) return;
|
|
20575
|
+
officeAutoOpened.current.add(officeAutoOpen.path);
|
|
20576
|
+
setWorkspacePath(officeAutoOpen.path);
|
|
20577
|
+
setPreviewPath(officeAutoOpen.path);
|
|
20578
|
+
setOpenPane("file");
|
|
20579
|
+
}, [officeAutoOpen?.eventId]);
|
|
20641
20580
|
const handleSelectedPathChange = react.useCallback((path) => {
|
|
20642
20581
|
setWorkspacePath(path);
|
|
20643
20582
|
if (path === null) setPreviewPath(null);
|
|
@@ -20867,6 +20806,8 @@ function AgentChat({
|
|
|
20867
20806
|
adapter,
|
|
20868
20807
|
sessionId,
|
|
20869
20808
|
path: previewPath,
|
|
20809
|
+
view: effectiveDisabled,
|
|
20810
|
+
officeEvent: runtime.state.officeEvents[previewPath],
|
|
20870
20811
|
onClose: () => setOpenPane(null)
|
|
20871
20812
|
}
|
|
20872
20813
|
)
|