@volter-ai-dev/supercode-ui 0.1.36 → 0.1.37
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 +78 -2
- package/activity.d.ts +2 -0
- package/activity.mjs +941 -0
- package/components.d.ts +4 -0
- package/components.mjs +737 -485
- package/composer.mjs +82 -20
- package/controller.d.ts +4 -0
- package/controller.mjs +19 -0
- package/conversation.mjs +75 -64
- package/core.d.ts +2 -0
- package/core.mjs +85 -2
- package/embed.mjs +338 -149
- package/icon.mjs +1 -1
- package/index.d.ts +66 -2
- package/logo.mjs +11 -6
- package/messenger.mjs +338 -149
- package/package.json +53 -3
- package/react/activity.d.ts +4 -0
- package/react/activity.mjs +941 -0
- package/react/components.mjs +3081 -0
- package/react/composer.d.ts +2 -0
- package/react/composer.mjs +518 -0
- package/react/conversation.d.ts +2 -0
- package/react/conversation.mjs +1330 -0
- package/react/icon.d.ts +2 -0
- package/react/icon.mjs +51 -0
- package/react/index.d.ts +122 -0
- package/react/logo.d.ts +2 -0
- package/react/logo.mjs +92 -0
- package/react/messenger.d.ts +2 -0
- package/react/messenger.mjs +2974 -0
- package/react/sessions.d.ts +2 -0
- package/react/sessions.mjs +429 -0
- package/react/settings.d.ts +2 -0
- package/react/settings.mjs +319 -0
- package/sessions.mjs +48 -28
- package/settings.mjs +170 -69
- package/styles.css +9 -0
package/composer.mjs
CHANGED
|
@@ -32,6 +32,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
32
32
|
mode: "none",
|
|
33
33
|
strategy: null,
|
|
34
34
|
canSend: false,
|
|
35
|
+
canSteer: false,
|
|
35
36
|
canResume: false,
|
|
36
37
|
continuationModes: Object.freeze([]),
|
|
37
38
|
canBranch: false,
|
|
@@ -67,6 +68,16 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
67
68
|
function harnessDisplayName(id) {
|
|
68
69
|
return HARNESS_NAMES[id] ?? id;
|
|
69
70
|
}
|
|
71
|
+
var ACTIVITY_PRIORITY = Object.freeze({
|
|
72
|
+
"needs-input": 70,
|
|
73
|
+
failed: 60,
|
|
74
|
+
working: 50,
|
|
75
|
+
unseen: 40,
|
|
76
|
+
finished: 30,
|
|
77
|
+
running: 20,
|
|
78
|
+
recent: 10,
|
|
79
|
+
idle: 0
|
|
80
|
+
});
|
|
70
81
|
function canContinueHere(state) {
|
|
71
82
|
if (state.mode !== "mirror" || state.canSend) return false;
|
|
72
83
|
const row = state.attached?.key ? state.sessions.find((item) => item.key === state.attached.key) : null;
|
|
@@ -130,7 +141,7 @@ var ICONS = {
|
|
|
130
141
|
function UiIcon({ name, size = 16, class: className = "" }) {
|
|
131
142
|
const Glyph = ICONS[name];
|
|
132
143
|
if (!Glyph) return null;
|
|
133
|
-
return /* @__PURE__ */ jsx("svg", {
|
|
144
|
+
return /* @__PURE__ */ jsx("svg", { className: `scui-icon ${className}`, style: { "--scui-icon-size": `${size}px` }, viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Glyph, {}) });
|
|
134
145
|
}
|
|
135
146
|
|
|
136
147
|
// src/context.jsx
|
|
@@ -204,6 +215,26 @@ function partitionAttachments(value) {
|
|
|
204
215
|
}
|
|
205
216
|
return { context, images };
|
|
206
217
|
}
|
|
218
|
+
function attachmentKey(item) {
|
|
219
|
+
if (item.id) return `id:${item.id}`;
|
|
220
|
+
return "detail" in item ? `context:${item.kind ?? ""}\0${item.label}\0${item.detail}` : `image:${item.url}`;
|
|
221
|
+
}
|
|
222
|
+
function ContextCandidate({ attachment, attached, onAttach }) {
|
|
223
|
+
const image = "url" in attachment;
|
|
224
|
+
return /* @__PURE__ */ jsxs2("button", { type: "button", disabled: attached, "aria-label": `${attached ? "Attached" : "Attach"} ${attachment.label}`, onClick: () => onAttach(attachment), children: [
|
|
225
|
+
image ? /* @__PURE__ */ jsx2("img", { src: attachment.url, alt: "" }) : /* @__PURE__ */ jsx2(UiIcon, { name: "attach", size: 13 }),
|
|
226
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
227
|
+
/* @__PURE__ */ jsx2("strong", { children: attachment.label }),
|
|
228
|
+
/* @__PURE__ */ jsx2("small", { children: image ? "Image" : attachment.kind || "Context" })
|
|
229
|
+
] }),
|
|
230
|
+
attached ? /* @__PURE__ */ jsx2(UiIcon, { name: "check", size: 13 }) : /* @__PURE__ */ jsx2(UiIcon, { name: "plus", size: 13 })
|
|
231
|
+
] });
|
|
232
|
+
}
|
|
233
|
+
function ContextCandidates({ items, context, images, state, adapter, onAttach, component: Candidate = ContextCandidate }) {
|
|
234
|
+
if (!items.length) return null;
|
|
235
|
+
const attached = new Set([...context, ...images].map(attachmentKey));
|
|
236
|
+
return /* @__PURE__ */ jsx2("div", { className: "scui-context-candidates", "aria-label": "Available context", children: items.map((attachment, index) => /* @__PURE__ */ jsx2(Candidate, { value: attachment, attachment, attached: attached.has(attachmentKey(attachment)), state, adapter, onAttach, index }, attachmentKey(attachment))) });
|
|
237
|
+
}
|
|
207
238
|
async function imageAttachmentsFromFiles(value) {
|
|
208
239
|
const files = Array.from(value ?? []).filter((file) => file?.type?.startsWith("image/"));
|
|
209
240
|
if (files.length > MAX_IMAGE_ITEMS) throw new Error(`Attach at most ${MAX_IMAGE_ITEMS} images at a time.`);
|
|
@@ -221,7 +252,7 @@ async function imageAttachmentsFromFiles(value) {
|
|
|
221
252
|
}
|
|
222
253
|
function ContextTray({ items, onRemove }) {
|
|
223
254
|
if (!items.length) return null;
|
|
224
|
-
return /* @__PURE__ */ jsx2("div", {
|
|
255
|
+
return /* @__PURE__ */ jsx2("div", { className: "scui-compose-context", "aria-label": "Attached context", children: items.map((item, index) => /* @__PURE__ */ jsxs2("span", { children: [
|
|
225
256
|
/* @__PURE__ */ jsx2(UiIcon, { name: "attach", size: 12 }),
|
|
226
257
|
/* @__PURE__ */ jsx2("strong", { children: item.label }),
|
|
227
258
|
/* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove context ${item.label}`, onClick: () => onRemove(index), children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 12 }) })
|
|
@@ -229,13 +260,23 @@ function ContextTray({ items, onRemove }) {
|
|
|
229
260
|
}
|
|
230
261
|
function ImageTray({ items, onRemove }) {
|
|
231
262
|
if (!items.length) return null;
|
|
232
|
-
return /* @__PURE__ */ jsx2("div", {
|
|
263
|
+
return /* @__PURE__ */ jsx2("div", { className: "scui-compose-images", "aria-label": "Attached images", children: items.map((item, index) => /* @__PURE__ */ jsxs2("span", { children: [
|
|
233
264
|
/* @__PURE__ */ jsx2("img", { src: item.url, alt: "" }),
|
|
234
265
|
/* @__PURE__ */ jsx2("strong", { children: item.label }),
|
|
235
266
|
onRemove ? /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove image ${item.label}`, onClick: () => onRemove(index), children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 12 }) }) : null
|
|
236
267
|
] }, item.id ?? `${item.label}:${index}`)) });
|
|
237
268
|
}
|
|
238
269
|
|
|
270
|
+
// src/intent.js
|
|
271
|
+
var CONFIRMABLE_ACTIONS = /* @__PURE__ */ new Set(["resume", "join", "branch", "reduce", "export"]);
|
|
272
|
+
async function dispatchConfirmedIntent(adapter, intent) {
|
|
273
|
+
if (CONFIRMABLE_ACTIONS.has(intent.action) && adapter.confirmIntent) {
|
|
274
|
+
const confirmed = await adapter.confirmIntent(intent);
|
|
275
|
+
if (!confirmed) return;
|
|
276
|
+
}
|
|
277
|
+
return adapter.onIntent(intent);
|
|
278
|
+
}
|
|
279
|
+
|
|
239
280
|
// src/textarea.js
|
|
240
281
|
import { useLayoutEffect } from "preact/hooks";
|
|
241
282
|
function useAutosizeTextarea(ref, value) {
|
|
@@ -262,28 +303,29 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
262
303
|
const terminal = resume && state.continuationModes?.includes("terminal");
|
|
263
304
|
const join = state.canAttach;
|
|
264
305
|
const branch = state.canBranch;
|
|
265
|
-
if (!resume && !join && !branch) return /* @__PURE__ */ jsx3("div", {
|
|
306
|
+
if (!resume && !join && !branch) return /* @__PURE__ */ jsx3("div", { className: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
266
307
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
267
308
|
/* @__PURE__ */ jsx3("small", { children: "This session cannot be continued by an available harness." })
|
|
268
309
|
] }) });
|
|
269
|
-
return /* @__PURE__ */ jsxs3("div", {
|
|
310
|
+
return /* @__PURE__ */ jsxs3("div", { className: "scui-continuation", children: [
|
|
270
311
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
271
312
|
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
272
313
|
/* @__PURE__ */ jsx3("small", { children: join ? "Join the proven live runtime without taking it over." : resume ? `Resume this ${harnessDisplayName(state.harness)} session here.` : "Start an independent continuation." })
|
|
273
314
|
] }),
|
|
274
|
-
/* @__PURE__ */ jsxs3("span", {
|
|
275
|
-
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => adapter
|
|
276
|
-
terminal ? /* @__PURE__ */ jsx3("button", { type: "button",
|
|
315
|
+
/* @__PURE__ */ jsxs3("span", { className: "scui-continuation-actions", children: [
|
|
316
|
+
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => dispatchConfirmedIntent(adapter, join ? { action: "join" } : resume ? { action: "resume", mode: "headless" } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere }),
|
|
317
|
+
terminal ? /* @__PURE__ */ jsx3("button", { type: "button", className: "scui-secondary", disabled: Boolean(state.operation), onClick: () => dispatchConfirmedIntent(adapter, { action: "resume", mode: "terminal" }), children: labels.continueWithTerminal ?? DEFAULT_LABELS.continueWithTerminal }) : null
|
|
277
318
|
] })
|
|
278
319
|
] });
|
|
279
320
|
}
|
|
280
|
-
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pendingStatus = null, restoreDraft = null, onPending, onDraftRestored }) {
|
|
321
|
+
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pendingStatus = null, restoreDraft = null, contextCandidates = [], components = {}, onPending, onDraftRestored }) {
|
|
281
322
|
const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, context: [], images: [], queue: [] };
|
|
282
323
|
const [draft, setDraft] = useState2(remembered.draft);
|
|
283
324
|
const [context, setContext] = useState2(remembered.context ?? []);
|
|
284
325
|
const [images, setImages] = useState2(remembered.images ?? []);
|
|
285
326
|
const [queue, setQueue] = useState2((remembered.queue ?? []).map((item) => ({ ...item, context: item.context ?? [], images: item.images ?? [] })));
|
|
286
327
|
const [dispatching, setDispatching] = useState2(false);
|
|
328
|
+
const [steering, setSteering] = useState2(false);
|
|
287
329
|
const [picking, setPicking] = useState2(false);
|
|
288
330
|
const [dragging, setDragging] = useState2(false);
|
|
289
331
|
const [pickerError, setPickerError] = useState2(null);
|
|
@@ -298,8 +340,10 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
298
340
|
remember(draft, context, images, next);
|
|
299
341
|
return next;
|
|
300
342
|
});
|
|
301
|
-
const queueBlocked = state.busy || pendingStatus !== null || dispatching;
|
|
302
|
-
const queuesNewMessage = state.busy || pendingStatus === "sending" || pendingStatus === "failed" || dispatching;
|
|
343
|
+
const queueBlocked = state.busy || pendingStatus !== null || dispatching || steering;
|
|
344
|
+
const queuesNewMessage = state.busy || pendingStatus === "sending" || pendingStatus === "failed" || dispatching || steering;
|
|
345
|
+
const steerAvailable = state.busy && state.canSteer && !steering && pendingStatus === null;
|
|
346
|
+
const canSteerDraft = steerAvailable && Boolean(draft.trim()) && context.length === 0 && images.length === 0;
|
|
303
347
|
useEffect2(() => {
|
|
304
348
|
if (!queueBlocked && state.canSend && queue.length) {
|
|
305
349
|
const [next, ...rest] = queue;
|
|
@@ -351,6 +395,14 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
351
395
|
});
|
|
352
396
|
}).catch((error) => setPickerError(error instanceof Error ? error.message : "Could not attach context.")).finally(() => setPicking(false));
|
|
353
397
|
};
|
|
398
|
+
const attachCandidate = (picked) => {
|
|
399
|
+
const attachments = partitionAttachments(picked);
|
|
400
|
+
const nextContext = mergeContext(context, attachments.context);
|
|
401
|
+
const nextImages = mergeImages(images, attachments.images);
|
|
402
|
+
setContext(nextContext);
|
|
403
|
+
setImages(nextImages);
|
|
404
|
+
remember(draft, nextContext, nextImages, queue);
|
|
405
|
+
};
|
|
354
406
|
const addImageFiles = (value, source) => {
|
|
355
407
|
const allFiles = Array.from(value ?? []);
|
|
356
408
|
if (!allFiles.length) return false;
|
|
@@ -379,9 +431,17 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
379
431
|
setDragging(false);
|
|
380
432
|
if (addImageFiles(event.dataTransfer?.files, "drop")) event.preventDefault();
|
|
381
433
|
};
|
|
382
|
-
const send = () => {
|
|
434
|
+
const send = (forceQueue = false) => {
|
|
383
435
|
const text = draft.trim();
|
|
384
436
|
if (!text && !images.length) return;
|
|
437
|
+
if (canSteerDraft && !forceQueue) {
|
|
438
|
+
setSteering(true);
|
|
439
|
+
Promise.resolve(adapter.onIntent({ action: "steer", text })).then(() => {
|
|
440
|
+
setDraft("");
|
|
441
|
+
remember("", context, images, queue);
|
|
442
|
+
}, (error) => setPickerError(error instanceof Error ? error.message : "Could not steer the active turn.")).finally(() => setSteering(false));
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
385
445
|
const message = { text, context, images };
|
|
386
446
|
if (queuesNewMessage) updateQueue((items) => [...items, message]);
|
|
387
447
|
else if (state.canSend) {
|
|
@@ -394,8 +454,8 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
394
454
|
setImages([]);
|
|
395
455
|
remember("", [], [], queuesNewMessage ? [...queue, message] : queue);
|
|
396
456
|
};
|
|
397
|
-
return /* @__PURE__ */ jsxs3("div", {
|
|
398
|
-
queue.length ? /* @__PURE__ */ jsxs3("div", {
|
|
457
|
+
return /* @__PURE__ */ jsxs3("div", { className: "scui-compose", children: [
|
|
458
|
+
queue.length ? /* @__PURE__ */ jsxs3("div", { className: "scui-queue", children: [
|
|
399
459
|
/* @__PURE__ */ jsxs3("strong", { children: [
|
|
400
460
|
queue.length,
|
|
401
461
|
" queued"
|
|
@@ -411,6 +471,7 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
411
471
|
/* @__PURE__ */ jsx3("button", { type: "button", "aria-label": `Remove queued message ${index + 1}`, onClick: () => updateQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: /* @__PURE__ */ jsx3(UiIcon, { name: "close", size: 13 }) })
|
|
412
472
|
] }, `${index}:${item.text}`))
|
|
413
473
|
] }) : null,
|
|
474
|
+
/* @__PURE__ */ jsx3(ContextCandidates, { items: contextCandidates, context, images, state, adapter, onAttach: attachCandidate, component: components.ContextCandidate }),
|
|
414
475
|
/* @__PURE__ */ jsx3(ImageTray, { items: images, onRemove: (index) => setImages((items) => {
|
|
415
476
|
const next = items.filter((_, itemIndex) => itemIndex !== index);
|
|
416
477
|
remember(draft, context, next, queue);
|
|
@@ -421,8 +482,8 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
421
482
|
remember(draft, next, images, queue);
|
|
422
483
|
return next;
|
|
423
484
|
}) }),
|
|
424
|
-
pickerError ? /* @__PURE__ */ jsx3("small", {
|
|
425
|
-
/* @__PURE__ */ jsxs3("div", {
|
|
485
|
+
pickerError ? /* @__PURE__ */ jsx3("small", { className: "scui-context-error", role: "alert", children: pickerError }) : null,
|
|
486
|
+
/* @__PURE__ */ jsxs3("div", { className: `scui-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
426
487
|
if (Array.from(event.dataTransfer?.types ?? []).includes("Files")) {
|
|
427
488
|
event.preventDefault();
|
|
428
489
|
setDragging(true);
|
|
@@ -432,8 +493,8 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
432
493
|
}, onDragLeave: (event) => {
|
|
433
494
|
if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
|
|
434
495
|
}, onDrop: dropImages, children: [
|
|
435
|
-
adapter.pickContext && state.mode === "control" ? /* @__PURE__ */ jsx3("button", {
|
|
436
|
-
/* @__PURE__ */ jsx3("textarea", { ref: textarea, rows: 1, "aria-label": `Message ${harnessDisplayName(state.harness) || "agent"}`, placeholder: state.startup !== "ready" ? "Connecting\u2026" : pendingStatus === "failed" ? "Retry or edit the unsent message\u2026" : pendingStatus === "editing" ? "Edit and resend\u2026" : queueBlocked ? "Queue a follow-up\u2026" : labels.askAgent, value: draft, disabled: state.mode !== "control" && !state.canSend, onPaste: pasteImages, onInput: (event) => {
|
|
496
|
+
adapter.pickContext && state.mode === "control" ? /* @__PURE__ */ jsx3("button", { className: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS, onClick: pickContext, children: picking ? /* @__PURE__ */ jsx3("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx3(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
497
|
+
/* @__PURE__ */ jsx3("textarea", { ref: textarea, rows: 1, "aria-label": `Message ${harnessDisplayName(state.harness) || "agent"}`, placeholder: state.startup !== "ready" ? "Connecting\u2026" : pendingStatus === "failed" ? "Retry or edit the unsent message\u2026" : pendingStatus === "editing" ? "Edit and resend\u2026" : steerAvailable && context.length === 0 && images.length === 0 ? "Redirect the current turn\u2026" : queueBlocked ? "Queue a follow-up\u2026" : labels.askAgent, value: draft, disabled: state.mode !== "control" && !state.canSend, onPaste: pasteImages, onInput: (event) => {
|
|
437
498
|
const value = event.currentTarget.value;
|
|
438
499
|
setDraft(value);
|
|
439
500
|
remember(value, context, images, queue);
|
|
@@ -444,8 +505,9 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
444
505
|
}
|
|
445
506
|
} }),
|
|
446
507
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
447
|
-
state.busy ? /* @__PURE__ */ jsx3("button", {
|
|
448
|
-
/* @__PURE__ */ jsx3("button", {
|
|
508
|
+
state.busy ? /* @__PURE__ */ jsx3("button", { className: "scui-stop", type: "button", "aria-label": "Stop agent", disabled: !state.canInterrupt, onClick: () => adapter.onIntent({ action: "interrupt" }), children: /* @__PURE__ */ jsx3(UiIcon, { name: "stop", size: 15 }) }) : null,
|
|
509
|
+
canSteerDraft ? /* @__PURE__ */ jsx3("button", { className: "scui-queue-send", type: "button", "aria-label": "Queue follow-up instead", onClick: () => send(true), children: /* @__PURE__ */ jsx3(UiIcon, { name: "plus", size: 15 }) }) : null,
|
|
510
|
+
/* @__PURE__ */ jsx3("button", { className: "scui-send", type: "button", "aria-label": canSteerDraft ? "Steer current turn" : queuesNewMessage ? "Queue message" : "Send message", disabled: steering || !draft.trim() && !images.length || !queuesNewMessage && !state.canSend, onClick: () => send(), children: steering ? /* @__PURE__ */ jsx3("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx3(UiIcon, { name: canSteerDraft ? "send" : queuesNewMessage ? "plus" : "send", size: 17 }) })
|
|
449
511
|
] })
|
|
450
512
|
] })
|
|
451
513
|
] });
|
package/controller.d.ts
CHANGED
|
@@ -115,6 +115,10 @@ export interface ControllerBindingOptions {
|
|
|
115
115
|
onResumeTerminal?: (intent: Extract<SupercodeUiIntent, { action: 'resume' }>) => void | Promise<void>;
|
|
116
116
|
copyText?: UiAdapter['copyText'];
|
|
117
117
|
resolveImage?: UiAdapter['resolveImage'];
|
|
118
|
+
confirmIntent?: UiAdapter['confirmIntent'];
|
|
119
|
+
pickContext?: UiAdapter['pickContext'];
|
|
120
|
+
onClose?: UiAdapter['onClose'];
|
|
121
|
+
onOpen?: UiAdapter['onOpen'];
|
|
118
122
|
}
|
|
119
123
|
|
|
120
124
|
export interface ControllerIntentTarget {
|
package/controller.mjs
CHANGED
|
@@ -470,6 +470,7 @@ function projectClientSnapshotInternal(snapshot, options, imageRegistry) {
|
|
|
470
470
|
mode: snapshot.connection?.mode ?? 'none',
|
|
471
471
|
strategy: snapshot.connection?.strategy ?? null,
|
|
472
472
|
canSend: actions.send === true,
|
|
473
|
+
canSteer: actions.steer === true,
|
|
473
474
|
canResume: actions.resume === true,
|
|
474
475
|
continuationModes: options.continuationModes ?? (actions.resume === true ? ['headless'] : []),
|
|
475
476
|
canBranch: actions.branch === true,
|
|
@@ -508,6 +509,19 @@ function projectClientSnapshotInternal(snapshot, options, imageRegistry) {
|
|
|
508
509
|
installed: harness.installed === true,
|
|
509
510
|
startable: harness.availableActions?.start === true,
|
|
510
511
|
reason: harness.reason ?? null,
|
|
512
|
+
auth: harness.auth,
|
|
513
|
+
runtime: harness.runtime,
|
|
514
|
+
protocol: harness.protocol,
|
|
515
|
+
repair: harness.repair ?? null,
|
|
516
|
+
capabilities: {
|
|
517
|
+
start: harness.availableActions?.start === true,
|
|
518
|
+
resume: harness.availableActions?.resume === true,
|
|
519
|
+
attach: harness.availableActions?.attach === true,
|
|
520
|
+
send: harness.availableActions?.send === true,
|
|
521
|
+
interrupt: harness.availableActions?.interrupt === true,
|
|
522
|
+
steer: harness.availableActions?.steer === true,
|
|
523
|
+
respond: harness.availableActions?.respond === true,
|
|
524
|
+
},
|
|
511
525
|
})),
|
|
512
526
|
history: {
|
|
513
527
|
sessionLimit: options.history?.sessionLimit ?? sessions.length,
|
|
@@ -552,6 +566,7 @@ export async function dispatchControllerIntent(controller, intent, options = {})
|
|
|
552
566
|
if (intent.action === 'mounted') return;
|
|
553
567
|
if (intent.action === 'attach') return controller.dispatch({ type: 'observe', sessionKey: intent.key });
|
|
554
568
|
if (intent.action === 'send') return controller.dispatch({ type: 'send', text: intent.text, ...(intent.context?.length ? { context: intent.context } : {}), ...(intent.images?.length ? { images: intent.images } : {}) });
|
|
569
|
+
if (intent.action === 'steer') return controller.dispatch({ type: 'steer', text: intent.text });
|
|
555
570
|
if (intent.action === 'new') {
|
|
556
571
|
if (intent.mode === 'terminal') {
|
|
557
572
|
return options.onStartTerminal
|
|
@@ -608,6 +623,10 @@ export function createControllerBinding(controller, options = {}) {
|
|
|
608
623
|
},
|
|
609
624
|
...(options.copyText ? { copyText: options.copyText } : {}),
|
|
610
625
|
...(options.resolveImage ? { resolveImage: options.resolveImage } : {}),
|
|
626
|
+
...(options.confirmIntent ? { confirmIntent: options.confirmIntent } : {}),
|
|
627
|
+
...(options.pickContext ? { pickContext: options.pickContext } : {}),
|
|
628
|
+
...(options.onClose ? { onClose: options.onClose } : {}),
|
|
629
|
+
...(options.onOpen ? { onOpen: options.onOpen } : {}),
|
|
611
630
|
};
|
|
612
631
|
return {
|
|
613
632
|
adapter,
|