@schlenkr/ragents 0.1.19 → 0.1.20
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/apps/server/src/host-api.json +6 -2
- package/apps/server/src/host-api.ts +3 -2
- package/apps/server/src/host-web.ts +3 -0
- package/apps/server/src/plugin-support/actor-programs/contract.ts +0 -3
- package/apps/server/src/plugin-support/removed-layout.ts +94 -0
- package/apps/server/src/ragents/engine.ts +2 -1
- package/apps/server/src/title-compactor.ts +5 -7
- package/apps/web/dist/assets/highlighted-body-KPVGNVTW-k67VKdbw.js +1 -0
- package/apps/web/dist/assets/main-CVjIz7BS.js +674 -0
- package/apps/web/dist/help/guide-clients.html +22 -42
- package/apps/web/dist/help/guide-clients.md +24 -45
- package/apps/web/dist/help/guide-functions.html +1 -1
- package/apps/web/dist/help/guide-functions.md +1 -1
- package/apps/web/dist/help/guide-getting-started.html +14 -22
- package/apps/web/dist/help/guide-getting-started.md +17 -24
- package/apps/web/dist/help/guide-ideas.html +1 -1
- package/apps/web/dist/help/guide-ideas.md +1 -1
- package/apps/web/dist/help/guide-plugins.html +1 -1
- package/apps/web/dist/help/guide-plugins.md +1 -1
- package/apps/web/dist/help/guide-programs.html +1 -1
- package/apps/web/dist/help/guide-programs.md +1 -1
- package/apps/web/dist/help/index.html +12 -79
- package/apps/web/dist/help/mini-app.css +8 -502
- package/apps/web/dist/host-web.json +28 -23
- package/apps/web/dist/index.html +2 -3
- package/apps/web/dist/run-panel.html +3 -4
- package/apps/web/src/Overview.tsx +4 -143
- package/apps/web/src/PluginChat.tsx +22 -116
- package/apps/web/src/PluginRegistry.tsx +4 -9
- package/apps/web/src/RunPreparationChat.tsx +4 -1
- package/apps/web/src/host-modules.ts +2 -0
- package/apps/web/src/main.tsx +23 -3
- package/apps/web/src/panel/RunLine.tsx +5 -2
- package/apps/web/src/panel/RunsPage.tsx +6 -6
- package/apps/web/src/panel/StartPage.tsx +6 -5
- package/apps/web/src/panel/contract.ts +3 -0
- package/apps/web/src/panel/page-props.ts +2 -0
- package/apps/web/src/run-apps.ts +34 -0
- package/apps/web/src/run-overview.ts +0 -27
- package/apps/web/src/run-panel/PanelContributions.tsx +41 -0
- package/apps/web/src/run-panel/RunPanelApp.tsx +172 -91
- package/apps/web/src/run-panel/RunPanelMenu.tsx +4 -3
- package/apps/web/src/run-panel/RunPanelWorkspace.tsx +8 -2
- package/apps/web/src/run-panel/clipboard.ts +17 -14
- package/apps/web/src/run-panel/host-contract.ts +8 -9
- package/apps/web/src/run-panel/host.ts +5 -31
- package/apps/web/src/run-panel/input-bridge.ts +15 -7
- package/bundles/ragents.activity/ragents-bundle.json +2 -2
- package/bundles/ragents.actor-programs/prompt.hbs +4 -5
- package/bundles/ragents.actor-programs/ragents-bundle.json +4 -14
- package/bundles/ragents.actor-programs/server/index.js +2 -14
- package/bundles/ragents.actor-programs/server/index.js.map +2 -2
- package/bundles/ragents.actor-programs/web/classes.json +1 -1
- package/bundles/ragents.actor-programs/web/index.js +1 -3
- package/bundles/ragents.actor-programs/web/index.js.map +4 -4
- package/bundles/ragents.ask/ragents-bundle.json +2 -2
- package/bundles/ragents.browser/ragents-bundle.json +2 -2
- package/bundles/ragents.documents/ragents-bundle.json +2 -2
- package/bundles/ragents.lsp-fsharp/ragents-bundle.json +2 -2
- package/bundles/ragents.lsp-roslyn/ragents-bundle.json +2 -2
- package/bundles/ragents.lsp-typescript/ragents-bundle.json +2 -2
- package/bundles/ragents.model-relay/ragents-bundle.json +2 -2
- package/bundles/ragents.orchestration/ragents-bundle.json +15 -41
- package/bundles/ragents.orchestration/server/index.js +10 -249
- package/bundles/ragents.orchestration/server/index.js.map +4 -4
- package/bundles/ragents.orchestration/web/chunks/chunk-KU7O6MEX.js +2 -0
- package/bundles/ragents.orchestration/web/chunks/chunk-KU7O6MEX.js.map +7 -0
- package/bundles/ragents.orchestration/web/classes.json +1 -1
- package/bundles/ragents.orchestration/web/exports/web/program-slot.js +1 -1
- package/bundles/ragents.orchestration/web/index.js +10 -18
- package/bundles/ragents.orchestration/web/index.js.map +4 -4
- package/bundles/ragents.overseer/ragents-bundle.json +3 -3
- package/bundles/ragents.overseer/server/index.js +0 -1
- package/bundles/ragents.overseer/server/index.js.map +2 -2
- package/bundles/ragents.processes/ragents-bundle.json +2 -2
- package/bundles/ragents.product/ragents-bundle.json +2 -2
- package/bundles/ragents.profile-distribution/ragents-bundle.json +2 -2
- package/bundles/ragents.reference/ragents-bundle.json +3 -3
- package/bundles/ragents.reference/run-scripts/balcony-wizard/RUN.md +1 -1
- package/bundles/ragents.reference/run-scripts/balcony-wizard/src/server.ts +1 -2
- package/bundles/ragents.reference/run-scripts/balcony-wizard/tests/program.test.ts +6 -7
- package/bundles/ragents.reference/run-scripts/conversation-circle/RUN.md +3 -3
- package/bundles/ragents.reference/run-scripts/conversation-circle/src/server.ts +3 -13
- package/bundles/ragents.reference/run-scripts/conversation-circle/tests/helpers.ts +1 -1
- package/bundles/ragents.reference/run-scripts/conversation-circle/tests/program.test.ts +1 -6
- package/bundles/ragents.reference/run-scripts/learning-afternoon/src/server.ts +1 -15
- package/bundles/ragents.reference/run-scripts/learning-afternoon/tests/program.test.ts +1 -1
- package/bundles/ragents.reference/run-scripts/moderated-round/tests/helpers.ts +1 -1
- package/bundles/ragents.reference/run-scripts/quick-note/RUN.md +1 -1
- package/bundles/ragents.reference/run-scripts/quick-note/src/server.ts +1 -2
- package/bundles/ragents.reference/run-scripts/quick-note/tests/program.test.ts +0 -2
- package/bundles/ragents.reference/run-scripts/run-roster/RUN.md +2 -2
- package/bundles/ragents.reference/run-scripts/run-roster/src/server.ts +1 -2
- package/bundles/ragents.reference/run-scripts/run-roster/tests/program.test.ts +0 -2
- package/bundles/ragents.reference/run-scripts/shared-actor-list/src/server.ts +1 -1
- package/bundles/ragents.reference/run-scripts/shared-actor-list/tests/helpers.ts +1 -1
- package/bundles/ragents.reference/run-scripts/word-game/src/contract.ts +1 -1
- package/bundles/ragents.reference/run-scripts/word-game/src/server.ts +0 -1
- package/bundles/ragents.reference/run-scripts/word-game/tests/program.test.ts +1 -2
- package/bundles/ragents.reference/skills/80-actor-text-analysis/SKILL.md +1 -1
- package/bundles/ragents.reference/skills/90-actor-notes/SKILL.md +1 -1
- package/bundles/ragents.todo/ragents-bundle.json +2 -2
- package/bundles/ragents.transcript/ragents-bundle.json +2 -2
- package/bundles/ragents.watch/ragents-bundle.json +2 -2
- package/bundles/ragents.workspace/ragents-bundle.json +2 -2
- package/package.json +8 -8
- package/packages/agent/dist/core/agent-settings.d.ts +1 -1
- package/packages/ai/dist/types.d.ts +2 -1
- package/packages/ragents/src/runtime/journal.ts +4 -0
- package/plugins/ragents.actor-programs/prompt.hbs +4 -5
- package/plugins/ragents.actor-programs/server/access-projections.ts +1 -1
- package/plugins/ragents.actor-programs/server/index.ts +0 -2
- package/plugins/ragents.actor-programs/server/runtime.ts +2 -10
- package/plugins/ragents.actor-programs/web/ActorViewFrame.tsx +5 -20
- package/plugins/ragents.actor-programs/web/AppsPanel.tsx +3 -79
- package/plugins/ragents.actor-programs/web/EmbeddedApps.tsx +0 -9
- package/plugins/ragents.actor-programs/web/api.ts +0 -20
- package/plugins/ragents.actor-programs/web/context.ts +0 -3
- package/plugins/ragents.actor-programs/web/index.tsx +0 -9
- package/plugins/ragents.orchestration/ragents-plugin.json +1 -2
- package/plugins/ragents.orchestration/server/index.ts +1 -11
- package/plugins/ragents.orchestration/web/ActorChat.tsx +1 -1
- package/plugins/ragents.orchestration/web/ActorChatControls.tsx +1 -1
- package/plugins/ragents.orchestration/web/FlowInspector.tsx +2 -4
- package/plugins/ragents.orchestration/web/InspectionPanel.tsx +21 -0
- package/plugins/ragents.orchestration/web/index.tsx +13 -9
- package/plugins/ragents.orchestration/web/program-slot.ts +0 -3
- package/plugins/ragents.orchestration/web/run-panel/AddresseeControl.tsx +15 -36
- package/plugins/ragents.orchestration/web/run-panel/RunPanel.tsx +76 -451
- package/plugins/ragents.orchestration/web/run-panel/run-panel-actors.ts +0 -27
- package/plugins/ragents.orchestration/web/run-panel/run-panel-state.ts +7 -40
- package/plugins/ragents.overseer/server/coordinator-prompt.ts +0 -1
- package/plugins/ragents.reference/examples.ts +1 -2
- package/plugins/ragents.reference/run-scripts/balcony-wizard/RUN.md +1 -1
- package/plugins/ragents.reference/run-scripts/balcony-wizard/src/server.ts +1 -2
- package/plugins/ragents.reference/run-scripts/balcony-wizard/tests/program.test.ts +6 -7
- package/plugins/ragents.reference/run-scripts/conversation-circle/RUN.md +3 -3
- package/plugins/ragents.reference/run-scripts/conversation-circle/src/server.ts +3 -13
- package/plugins/ragents.reference/run-scripts/conversation-circle/tests/helpers.ts +1 -1
- package/plugins/ragents.reference/run-scripts/conversation-circle/tests/program.test.ts +1 -6
- package/plugins/ragents.reference/run-scripts/learning-afternoon/src/server.ts +1 -15
- package/plugins/ragents.reference/run-scripts/learning-afternoon/tests/program.test.ts +1 -1
- package/plugins/ragents.reference/run-scripts/moderated-round/tests/helpers.ts +1 -1
- package/plugins/ragents.reference/run-scripts/quick-note/RUN.md +1 -1
- package/plugins/ragents.reference/run-scripts/quick-note/src/server.ts +1 -2
- package/plugins/ragents.reference/run-scripts/quick-note/tests/program.test.ts +0 -2
- package/plugins/ragents.reference/run-scripts/run-roster/RUN.md +2 -2
- package/plugins/ragents.reference/run-scripts/run-roster/src/server.ts +1 -2
- package/plugins/ragents.reference/run-scripts/run-roster/tests/program.test.ts +0 -2
- package/plugins/ragents.reference/run-scripts/shared-actor-list/src/server.ts +1 -1
- package/plugins/ragents.reference/run-scripts/shared-actor-list/tests/helpers.ts +1 -1
- package/plugins/ragents.reference/run-scripts/word-game/src/contract.ts +1 -1
- package/plugins/ragents.reference/run-scripts/word-game/src/server.ts +0 -1
- package/plugins/ragents.reference/run-scripts/word-game/tests/program.test.ts +1 -2
- package/plugins/ragents.reference/skills/80-actor-text-analysis/SKILL.md +1 -1
- package/plugins/ragents.reference/skills/90-actor-notes/SKILL.md +1 -1
- package/plugins/ragents.reference/walkthroughs.ts +13 -14
- package/apps/web/dist/assets/highlighted-body-KPVGNVTW-BwD4uYEe.js +0 -1
- package/apps/web/dist/assets/main-KBrc5Q77.js +0 -11
- package/apps/web/dist/assets/mermaid-HWGCJPDP-CSCkaArr.js +0 -608
- package/apps/web/dist/assets/runPanel-BjG5NBKm.js +0 -26
- package/apps/web/src/App.tsx +0 -318
- package/apps/web/src/SessionList.tsx +0 -157
- package/apps/web/src/SurfaceShortcuts.tsx +0 -60
- package/apps/web/src/WorkspacePanel.tsx +0 -309
- package/apps/web/src/run-panel.tsx +0 -52
- package/bundles/ragents.orchestration/server/chunks/chunk-QS3WJ3D7.js +0 -11
- package/bundles/ragents.orchestration/server/chunks/chunk-QS3WJ3D7.js.map +0 -7
- package/bundles/ragents.orchestration/server/exports/server/contract.js +0 -9
- package/bundles/ragents.orchestration/server/exports/server/contract.js.map +0 -7
- package/bundles/ragents.orchestration/surface.hbs +0 -39
- package/bundles/ragents.orchestration/web/chunks/chunk-CFMJD5ZI.js +0 -2
- package/bundles/ragents.orchestration/web/chunks/chunk-CFMJD5ZI.js.map +0 -7
- package/bundles/ragents.orchestration/web/chunks/chunk-HOBLI364.js +0 -2
- package/bundles/ragents.orchestration/web/chunks/chunk-HOBLI364.js.map +0 -7
- package/bundles/ragents.orchestration/web/chunks/chunk-UCIMT2R4.js +0 -2
- package/bundles/ragents.orchestration/web/chunks/chunk-UCIMT2R4.js.map +0 -7
- package/bundles/ragents.orchestration/web/chunks/chunk-XGPPQCZR.js +0 -2
- package/bundles/ragents.orchestration/web/chunks/chunk-XGPPQCZR.js.map +0 -7
- package/bundles/ragents.orchestration/web/exports/web/surface-entities.js +0 -2
- package/bundles/ragents.orchestration/web/exports/web/surface-entities.js.map +0 -7
- package/bundles/ragents.orchestration/web/exports/web/tile-docking.js +0 -2
- package/bundles/ragents.orchestration/web/exports/web/tile-docking.js.map +0 -7
- package/plugins/ragents.actor-programs/web/ExpandIcon.tsx +0 -5
- package/plugins/ragents.actor-programs/web/FullscreenHost.tsx +0 -31
- package/plugins/ragents.orchestration/contract.ts +0 -51
- package/plugins/ragents.orchestration/server/contract.ts +0 -14
- package/plugins/ragents.orchestration/server/surface-tool.ts +0 -198
- package/plugins/ragents.orchestration/surface.hbs +0 -39
- package/plugins/ragents.orchestration/tiled-layout.ts +0 -55
- package/plugins/ragents.orchestration/web/ActorChatPreview.tsx +0 -29
- package/plugins/ragents.orchestration/web/ActorShortcut.tsx +0 -74
- package/plugins/ragents.orchestration/web/ActorSurfaceControls.tsx +0 -130
- package/plugins/ragents.orchestration/web/ActorTile.tsx +0 -23
- package/plugins/ragents.orchestration/web/Center.tsx +0 -133
- package/plugins/ragents.orchestration/web/SurfaceTiles.tsx +0 -47
- package/plugins/ragents.orchestration/web/TiledSurface.tsx +0 -280
- package/plugins/ragents.orchestration/web/actor-header-settings.ts +0 -41
- package/plugins/ragents.orchestration/web/run-panel/RunPanelSettings.tsx +0 -50
- package/plugins/ragents.orchestration/web/run-panel/run-panel-settings.ts +0 -47
- package/plugins/ragents.orchestration/web/run-panel/sheet-status.ts +0 -30
- package/plugins/ragents.orchestration/web/surface-entities.ts +0 -21
- package/plugins/ragents.orchestration/web/surface-view-settings.ts +0 -42
- package/plugins/ragents.orchestration/web/tile-docking.ts +0 -105
- package/plugins/ragents.orchestration/web/tiled-view-settings.ts +0 -74
- /package/apps/web/dist/assets/{mermaid-HWGCJPDP-BPn4aV2r.css → main-BPn4aV2r.css} +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useAccess } from "@ragents/web/AccessContext";
|
|
2
|
-
import { ArrowLeftIcon
|
|
2
|
+
import { ArrowLeftIcon } from "lucide-react";
|
|
3
3
|
import { Alert, Badge, Button, cn, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, Spinner } from "@ragents/web/ui";
|
|
4
|
-
import { ToolbarCopy, ToolbarItem, ToolbarLabel, ToolbarText } from "@ragents/web/Toolbar";
|
|
5
4
|
import {
|
|
6
5
|
useCallback,
|
|
7
6
|
useEffect,
|
|
@@ -15,14 +14,10 @@ import { answerQuestion } from "@ragents/plugins/ragents.ask/web/api";
|
|
|
15
14
|
import { QuestionCard } from "@ragents/plugins/ragents.ask/web/QuestionCard";
|
|
16
15
|
import { ACTOR_PROGRAMS_STATE_ID } from "@ragents/host/plugin-support/actor-programs/contract";
|
|
17
16
|
import {
|
|
18
|
-
useSurfaceController,
|
|
19
17
|
type SessionContext,
|
|
20
|
-
type SessionHeaderContext,
|
|
21
18
|
type WorkspaceTabContext,
|
|
22
19
|
} from "@ragents/web/PluginRegistry";
|
|
23
20
|
import { runViewFrom, type RunAction } from "@ragents/web/run-view";
|
|
24
|
-
import { useSurfaceEntities } from "@ragents/plugins/ragents.orchestration/web/surface-entities";
|
|
25
|
-
import { SURFACE_TILE_DRAG_TYPE } from "@ragents/plugins/ragents.orchestration/web/tile-docking";
|
|
26
21
|
import { ProgramSlotContext, type ProgramSlot } from "@ragents/plugins/ragents.orchestration/web/program-slot";
|
|
27
22
|
import {
|
|
28
23
|
type RunApp,
|
|
@@ -34,7 +29,6 @@ import {
|
|
|
34
29
|
import type { JsonValue } from "./bridge";
|
|
35
30
|
import { actorProgramSourceView, ProgramSource } from "./ProgramSource";
|
|
36
31
|
import { FunctionForm } from "./FunctionForm";
|
|
37
|
-
import { ExpandIcon } from "./ExpandIcon";
|
|
38
32
|
import { actorProgramsRevision } from "./state-revision";
|
|
39
33
|
import { actorProgramViews, currentActorListing } from "./program-state";
|
|
40
34
|
import { activeActorInvocations, readActorInvocation } from "./invocations";
|
|
@@ -47,7 +41,6 @@ export const RUN_TOOLS_TAB_ID = "ragents.actor-programs.tools";
|
|
|
47
41
|
const entryIconClass = "flex size-[34px] items-center justify-center rounded-[10px] bg-[color-mix(in_srgb,var(--primary)_12%,var(--background))] text-primary";
|
|
48
42
|
const headClass = "grid flex-none grid-cols-[auto_minmax(0,1fr)] items-center gap-2.5 border-b border-border-soft px-workspace-inset py-[9px]";
|
|
49
43
|
const sectionLabelClass = "mb-2 text-[0.66rem] tracking-[0.075em] text-muted-foreground uppercase";
|
|
50
|
-
const quickIconClass = "grid size-[30px] flex-none place-items-center rounded-lg border border-info/25 bg-glass-app text-info";
|
|
51
44
|
|
|
52
45
|
const ACTIVE_STATUSES = new Set(["queued", "running"]);
|
|
53
46
|
const POLL_INTERVAL = 700;
|
|
@@ -79,18 +72,6 @@ export function ActorProgramsProvider({
|
|
|
79
72
|
const [storedListing, setListing] = useState<ActorProgramsListing>();
|
|
80
73
|
const listing = useMemo(() => currentActorListing(storedListing, session.runView), [storedListing, session.runView]);
|
|
81
74
|
const [error, setError] = useState<string>();
|
|
82
|
-
const [fullscreen, setFullscreen] = useState<{ runId: string; appId: string }>();
|
|
83
|
-
const visibleApps = actorProgramApps(session).filter((app) => app.app.visible !== false);
|
|
84
|
-
const fullscreenAppId = fullscreen?.runId === runId && visibleApps.some((app) => app.id === fullscreen.appId)
|
|
85
|
-
? fullscreen.appId : undefined;
|
|
86
|
-
const closeFullscreen = useCallback(() => setFullscreen(undefined), []);
|
|
87
|
-
const openFullscreen = useCallback((appId: string) => {
|
|
88
|
-
if (!actorProgramApps(session).some((app) => app.id === appId && app.app.visible !== false)) {
|
|
89
|
-
throw new Error("The actor view is not available on the surface.");
|
|
90
|
-
}
|
|
91
|
-
setFullscreen({ runId, appId });
|
|
92
|
-
}, [runId, session]);
|
|
93
|
-
useEffect(() => { if (fullscreen && !fullscreenAppId) setFullscreen(undefined); }, [fullscreen, fullscreenAppId]);
|
|
94
75
|
const loadRevision = useRef(0);
|
|
95
76
|
|
|
96
77
|
const refresh = useCallback(async () => {
|
|
@@ -172,23 +153,15 @@ export function ActorProgramsProvider({
|
|
|
172
153
|
const value = useMemo<ActorProgramsContextValue>(() => ({
|
|
173
154
|
api,
|
|
174
155
|
error,
|
|
175
|
-
fullscreenAppId,
|
|
176
156
|
invoke,
|
|
177
157
|
listing,
|
|
178
|
-
openFullscreen,
|
|
179
|
-
closeFullscreen,
|
|
180
158
|
refresh,
|
|
181
159
|
runId,
|
|
182
|
-
}), [api, error,
|
|
160
|
+
}), [api, error, invoke, listing, refresh, runId]);
|
|
183
161
|
const slot = useMemo<ProgramSlot>(() => ({
|
|
184
162
|
runId,
|
|
185
|
-
needsAnswer: (session, appId) => {
|
|
186
|
-
const app = listing?.apps.find((candidate) => candidate.id === appId);
|
|
187
|
-
return app !== undefined && pendingConfirmationFor(session, app) !== undefined;
|
|
188
|
-
},
|
|
189
|
-
openFullscreen,
|
|
190
163
|
source: (view, actorId) => actorProgramSourceView(api, view, actorId),
|
|
191
|
-
}), [api,
|
|
164
|
+
}), [api, runId]);
|
|
192
165
|
return <ActorProgramsContext.Provider value={value}>
|
|
193
166
|
<ProgramSlotContext.Provider value={slot}>{children}</ProgramSlotContext.Provider>
|
|
194
167
|
</ActorProgramsContext.Provider>;
|
|
@@ -376,55 +349,6 @@ export function ToolsPanel({ active, navigation, selection, session }: Workspace
|
|
|
376
349
|
);
|
|
377
350
|
}
|
|
378
351
|
|
|
379
|
-
/** A click on a mini-app selects its tile on the surface; the surface is the surface controller of the orchestration plugin. */
|
|
380
|
-
export function ActorProgramsHeader({ session }: SessionHeaderContext) {
|
|
381
|
-
const canArrange = useAccess().can("runs.inspect");
|
|
382
|
-
const surface = useSurfaceController();
|
|
383
|
-
const stage = useSurfaceEntities(session.session.id);
|
|
384
|
-
const { closeFullscreen, fullscreenAppId, openFullscreen } = useActorPrograms();
|
|
385
|
-
const apps = actorProgramApps(session).filter((app) => app.app.visible !== false);
|
|
386
|
-
if (apps.length === 0) return null;
|
|
387
|
-
|
|
388
|
-
return (
|
|
389
|
-
<nav aria-label="Actor views" className="flex min-w-0 flex-none items-stretch">
|
|
390
|
-
{apps.map((app) => (
|
|
391
|
-
<div role="group" aria-label={app.title} key={`app:${app.id}`}
|
|
392
|
-
className={cn("relative flex flex-none items-stretch border-r border-border hover:bg-accent focus-within:bg-accent",
|
|
393
|
-
fullscreenAppId === app.id && "bg-primary/12 after:pointer-events-none after:absolute after:inset-x-0 after:bottom-0 after:h-[3px] after:bg-primary after:content-['']")}>
|
|
394
|
-
<ToolbarItem
|
|
395
|
-
as="button"
|
|
396
|
-
className="max-w-[214px] border-r-0 font-bold hover:not-disabled:bg-transparent"
|
|
397
|
-
draggable={canArrange}
|
|
398
|
-
onDragStart={(event) => {
|
|
399
|
-
if (!canArrange) { event.preventDefault(); return; }
|
|
400
|
-
event.dataTransfer.setData(SURFACE_TILE_DRAG_TYPE, `app:${app.id}`);
|
|
401
|
-
event.dataTransfer.effectAllowed = "move";
|
|
402
|
-
closeFullscreen();
|
|
403
|
-
}}
|
|
404
|
-
onClick={() => {
|
|
405
|
-
if (!surface) throw new Error("The app entries need the surface controller of the orchestration plugin.");
|
|
406
|
-
closeFullscreen();
|
|
407
|
-
surface.acceptSelection({ type: "run-app", id: app.id });
|
|
408
|
-
}}
|
|
409
|
-
aria-label={`Mini-app: ${app.title} of @${app.actorHandle}`}
|
|
410
|
-
title={`Mini-app: ${app.title} of @${app.actorHandle}${canArrange ? ". Drag onto a tile to dock." : ""}`}
|
|
411
|
-
type="button"
|
|
412
|
-
>
|
|
413
|
-
<span className={cn(quickIconClass, !stage.has(`app:${app.id}`) && "bg-transparent")}><LayoutGridIcon size={20} /></span>
|
|
414
|
-
<ToolbarCopy><ToolbarLabel>@{app.actorHandle}</ToolbarLabel><ToolbarText>{app.title}</ToolbarText></ToolbarCopy>
|
|
415
|
-
</ToolbarItem>
|
|
416
|
-
<ToolbarItem as="button" aria-expanded={fullscreenAppId === app.id} aria-label={`${app.title} ${fullscreenAppId === app.id ? "close full view" : "open in full view"}`}
|
|
417
|
-
title={`${app.title} ${fullscreenAppId === app.id ? "close full view" : "open in full view"}`}
|
|
418
|
-
className="relative w-[38px] justify-center border-r-0 p-0 hover:not-disabled:bg-transparent before:pointer-events-none before:absolute before:top-1/4 before:bottom-1/4 before:left-0 before:border-l before:border-dashed before:border-border-strong before:content-['']"
|
|
419
|
-
onClick={() => fullscreenAppId === app.id ? closeFullscreen() : openFullscreen(app.id)} type="button">
|
|
420
|
-
<ExpandIcon />
|
|
421
|
-
</ToolbarItem>
|
|
422
|
-
</div>
|
|
423
|
-
))}
|
|
424
|
-
</nav>
|
|
425
|
-
);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
352
|
export function ToolsBadge() {
|
|
429
353
|
const { listing } = useActorPrograms();
|
|
430
354
|
return listing && listing.tools.length > 0
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useAccess } from "@ragents/web/AccessContext";
|
|
2
2
|
import { Spinner } from "@ragents/web/ui";
|
|
3
|
-
import { isRecord } from "@ragents/web/lib/guards";
|
|
4
3
|
import { runActorFrom } from "@ragents/web/run-view";
|
|
5
4
|
import type {
|
|
6
5
|
SurfaceElementContext,
|
|
@@ -33,13 +32,6 @@ export function ActorProgramToolCardSection({ actor, session }: CardSectionConte
|
|
|
33
32
|
|
|
34
33
|
export const actorProgramSurfaceElements = (session: SessionContext): readonly SurfaceElementDefinition[] =>
|
|
35
34
|
actorProgramApps(session).flatMap((module): SurfaceElementDefinition[] => {
|
|
36
|
-
const rawPlacements = module.app.placements;
|
|
37
|
-
const placement = Array.isArray(rawPlacements) ? rawPlacements.find((entry) => isRecord(entry) && entry.kind === "canvas") : undefined;
|
|
38
|
-
const surface = isRecord(placement) ? placement : undefined;
|
|
39
|
-
if (surface && typeof surface.anchorActorId !== "string") {
|
|
40
|
-
throw new Error(`The surface placement of the actor view ${module.title} is invalid`);
|
|
41
|
-
}
|
|
42
|
-
if (surface && surface.anchorActorId !== module.actorId) throw new Error(`The view ${module.title} belongs to @${module.actorHandle}.`);
|
|
43
35
|
return [{
|
|
44
36
|
id: module.id,
|
|
45
37
|
title: module.title,
|
|
@@ -61,7 +53,6 @@ export function ActorProgramSurfaceElement({ definition, session }: SurfaceEleme
|
|
|
61
53
|
app={app}
|
|
62
54
|
invoke={invoke}
|
|
63
55
|
pendingConfirmationInvocationId={confirmation?.parameters.invocationId}
|
|
64
|
-
presentation="tiled"
|
|
65
56
|
runId={runId}
|
|
66
57
|
session={session}
|
|
67
58
|
/>
|
|
@@ -17,8 +17,6 @@ export interface RunAppAction {
|
|
|
17
17
|
confirmation: string | null;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export type RunAppPlacement = { kind: "canvas"; anchorActorId: string };
|
|
21
|
-
|
|
22
20
|
export type RunAppInvocation = {
|
|
23
21
|
id: string;
|
|
24
22
|
actorId: string;
|
|
@@ -45,7 +43,6 @@ export interface RunApp {
|
|
|
45
43
|
description?: string;
|
|
46
44
|
revision: string;
|
|
47
45
|
actions: RunAppAction[];
|
|
48
|
-
placements: RunAppPlacement[];
|
|
49
46
|
state: { version: 1; revision: number; values: JsonValue };
|
|
50
47
|
invocations: RunAppInvocation[];
|
|
51
48
|
}
|
|
@@ -198,23 +195,10 @@ export const runAppInvocationFrom = (value: unknown): RunAppInvocation => {
|
|
|
198
195
|
}
|
|
199
196
|
};
|
|
200
197
|
|
|
201
|
-
const runAppPlacementFrom = (value: unknown): RunAppPlacement => {
|
|
202
|
-
if (!isRecord(value)) throw new Error("An app placement is not an object");
|
|
203
|
-
if (value.kind === "canvas") {
|
|
204
|
-
return {
|
|
205
|
-
kind: "canvas",
|
|
206
|
-
anchorActorId: requiredString(value.anchorActorId, "placement.anchorActorId"),
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
throw new Error("kind of an app placement must be canvas");
|
|
210
|
-
};
|
|
211
|
-
|
|
212
198
|
export const runAppFrom = (value: unknown): RunApp => {
|
|
213
199
|
if (!isRecord(value)) throw new Error("An app is not an object");
|
|
214
200
|
if (!Array.isArray(value.actions)) throw new Error("actions of an app is not a list");
|
|
215
201
|
if (!Array.isArray(value.invocations)) throw new Error("invocations of an app is not a list");
|
|
216
|
-
const rawPlacements = value.placements ?? [];
|
|
217
|
-
if (!Array.isArray(rawPlacements)) throw new Error("placements of an app is not a list");
|
|
218
202
|
if (!isRecord(value.state) || value.state.version !== 1 || !Number.isSafeInteger(value.state.revision) || !isJsonValue(value.state.values)) throw new Error("state of a view does not match the state contract");
|
|
219
203
|
const actions = unique(value.actions.map(runAppActionFrom), (action) => action.id, "actions");
|
|
220
204
|
const invocations = unique(
|
|
@@ -227,12 +211,9 @@ export const runAppFrom = (value: unknown): RunApp => {
|
|
|
227
211
|
throw new Error("An app execution refers to an unknown action");
|
|
228
212
|
}
|
|
229
213
|
if (value.visible !== undefined && typeof value.visible !== "boolean") throw new Error("visible of an app is not a boolean");
|
|
230
|
-
if (rawPlacements.length > 1) throw new Error("placements of an app contains more than one placement");
|
|
231
|
-
const placements = rawPlacements.map(runAppPlacementFrom);
|
|
232
214
|
const id = requiredString(value.id, "view.id");
|
|
233
215
|
if (!VIEW_ID_PATTERN.test(id)) throw new Error("view.id is not a valid identifier");
|
|
234
216
|
const actorId = requiredString(value.actorId, "view.actorId");
|
|
235
|
-
if (placements.some((placement) => placement.anchorActorId !== actorId)) throw new Error("The view must be placed at its own actor");
|
|
236
217
|
return {
|
|
237
218
|
id,
|
|
238
219
|
actorId,
|
|
@@ -244,7 +225,6 @@ export const runAppFrom = (value: unknown): RunApp => {
|
|
|
244
225
|
: {}),
|
|
245
226
|
revision: requiredString(value.revision, "app.revision"),
|
|
246
227
|
actions,
|
|
247
|
-
placements,
|
|
248
228
|
state: { version: 1, revision: value.state.revision as number, values: value.state.values },
|
|
249
229
|
invocations,
|
|
250
230
|
};
|
|
@@ -5,10 +5,7 @@ import type { JsonValue } from "./bridge";
|
|
|
5
5
|
export interface ActorProgramsContextValue {
|
|
6
6
|
api: ActorProgramsApi;
|
|
7
7
|
error: string | undefined;
|
|
8
|
-
fullscreenAppId: string | undefined;
|
|
9
8
|
listing: ActorProgramsListing | undefined;
|
|
10
|
-
openFullscreen: (appId: string) => void;
|
|
11
|
-
closeFullscreen: () => void;
|
|
12
9
|
refresh: () => Promise<void>;
|
|
13
10
|
invoke: (
|
|
14
11
|
appId: string,
|
|
@@ -7,12 +7,10 @@ import {
|
|
|
7
7
|
import { createActorProgramsApi } from "./api";
|
|
8
8
|
import {
|
|
9
9
|
RUN_TOOLS_TAB_ID,
|
|
10
|
-
ActorProgramsHeader,
|
|
11
10
|
ActorProgramsProvider,
|
|
12
11
|
ToolsBadge,
|
|
13
12
|
ToolsPanel,
|
|
14
13
|
} from "./AppsPanel";
|
|
15
|
-
import { FullscreenHost } from "./FullscreenHost";
|
|
16
14
|
import {
|
|
17
15
|
ActorProgramSurfaceElement,
|
|
18
16
|
ActorProgramToolCardSection,
|
|
@@ -38,7 +36,6 @@ const configuredPlugin = (descriptor: WebPluginDescriptor, routePrefix: string):
|
|
|
38
36
|
return (
|
|
39
37
|
<ActorProgramsProvider api={api} session={session}>
|
|
40
38
|
{children}
|
|
41
|
-
<FullscreenHost session={session} />
|
|
42
39
|
</ActorProgramsProvider>
|
|
43
40
|
);
|
|
44
41
|
}
|
|
@@ -47,12 +44,6 @@ const configuredPlugin = (descriptor: WebPluginDescriptor, routePrefix: string):
|
|
|
47
44
|
...descriptor,
|
|
48
45
|
needsRunView: true,
|
|
49
46
|
SessionProvider: Provider,
|
|
50
|
-
sessionHeaders: [{
|
|
51
|
-
id: "ragents.actor-programs.quick-list",
|
|
52
|
-
placement: "surface",
|
|
53
|
-
order: 250,
|
|
54
|
-
Header: ActorProgramsHeader,
|
|
55
|
-
}],
|
|
56
47
|
cardSections: [{
|
|
57
48
|
id: "ragents.actor-programs.tools",
|
|
58
49
|
order: 400,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
actorInputSchema,
|
|
3
|
-
agentTools,
|
|
4
3
|
enqueueActorInput,
|
|
5
4
|
eventResultSchemaOf,
|
|
6
5
|
ScriptDriver,
|
|
@@ -10,17 +9,13 @@ import {
|
|
|
10
9
|
import { runtimeProviderToken } from "@ragents/host/ragents/host-services.js";
|
|
11
10
|
import { pluginAsset } from "@ragents/host/plugin-support/plugin-folder.js";
|
|
12
11
|
import type { PluginModule } from "@ragents/host/plugin-support/plugin-module.js";
|
|
13
|
-
import {
|
|
14
|
-
import { createSurfaceToolContributor, placeOnSurface } from "./surface-tool.js";
|
|
15
|
-
import { surfacePlacementToken } from "./contract.js";
|
|
12
|
+
import { handlebarsPrompt } from "@ragents/host/plugin-support/prompt.js";
|
|
16
13
|
import { createRunStopContributor } from "./run-stop-tool.js";
|
|
17
14
|
import { runManagementToken } from "@ragents/host/ragents/global-chat.js";
|
|
18
15
|
|
|
19
16
|
const orchestrationPlugin: RAgentsPlugin = {
|
|
20
17
|
manifest: { id: "ragents.orchestration" },
|
|
21
18
|
register: (host) => {
|
|
22
|
-
host.functions(createSurfaceToolContributor());
|
|
23
|
-
host.provide(surfacePlacementToken, placeOnSurface(host.service(runtimeProviderToken)));
|
|
24
19
|
host.functions(createRunStopContributor(
|
|
25
20
|
(runId) => host.service(runManagementToken)().stop(runId),
|
|
26
21
|
(error) => console.error("Run stop by the coordinator failed", error),
|
|
@@ -52,11 +47,6 @@ const orchestrationPlugin: RAgentsPlugin = {
|
|
|
52
47
|
});
|
|
53
48
|
host.prompts(
|
|
54
49
|
handlebarsPrompt("ragents.orchestration.prompt", 600, pluginAsset("ragents.orchestration", "orchestration.hbs")),
|
|
55
|
-
boundToTools(
|
|
56
|
-
handlebarsPrompt("ragents.orchestration.surface", 650, pluginAsset("ragents.orchestration", "surface.hbs")),
|
|
57
|
-
"canvas_layout_replace",
|
|
58
|
-
"canvas_layout_place",
|
|
59
|
-
),
|
|
60
50
|
);
|
|
61
51
|
},
|
|
62
52
|
};
|
|
@@ -13,7 +13,7 @@ const emptyMessages: readonly Message[] = [];
|
|
|
13
13
|
export function ActorChat({ actor, view, presentation, display = presentation, primaryMessages = emptyMessages, conversation, historyError, running = false, className, onNavigate, scrollerRef }: {
|
|
14
14
|
actor: RunActor;
|
|
15
15
|
view: RunView;
|
|
16
|
-
presentation: "
|
|
16
|
+
presentation: "panel" | "inspector";
|
|
17
17
|
/** Key of the display surface for the remembered detail level; defaults to the presentation. */
|
|
18
18
|
display?: string;
|
|
19
19
|
primaryMessages?: readonly Message[];
|
|
@@ -16,7 +16,7 @@ export function ActorChatControls({ actor, view, composerVisible = true, present
|
|
|
16
16
|
actor: RunActor;
|
|
17
17
|
view: RunView;
|
|
18
18
|
composerVisible?: boolean;
|
|
19
|
-
presentation?: "
|
|
19
|
+
presentation?: "inspector" | "panel";
|
|
20
20
|
display?: string;
|
|
21
21
|
running?: boolean;
|
|
22
22
|
toolbarLeft?: ReactNode;
|
|
@@ -42,8 +42,6 @@ interface FlowInspectorProps {
|
|
|
42
42
|
actorConversations?: Readonly<Record<string, readonly Message[]>>;
|
|
43
43
|
conversationError?: string;
|
|
44
44
|
primaryRunning: boolean;
|
|
45
|
-
/** Display surface for the remembered detail level; the popout registers separately from the side inspector. */
|
|
46
|
-
chatDisplay?: string;
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
const inspectorClass = "flex h-full min-h-0 flex-col bg-card";
|
|
@@ -549,7 +547,7 @@ function ActorView({ actor, index, ...props }: FlowInspectorProps & { actor: Run
|
|
|
549
547
|
actor={actor}
|
|
550
548
|
view={view}
|
|
551
549
|
presentation="inspector"
|
|
552
|
-
display=
|
|
550
|
+
display="inspector"
|
|
553
551
|
className="min-h-0 flex-1"
|
|
554
552
|
primaryMessages={props.primaryMessages}
|
|
555
553
|
conversation={props.actorConversations?.[actor.id]}
|
|
@@ -557,7 +555,7 @@ function ActorView({ actor, index, ...props }: FlowInspectorProps & { actor: Run
|
|
|
557
555
|
onNavigate={props.onNavigate}
|
|
558
556
|
running={primary ? props.primaryRunning : lifecycle === "running"}
|
|
559
557
|
/>
|
|
560
|
-
<ActorChatControls actor={actor} view={view} composerVisible={props.composerVisible} display=
|
|
558
|
+
<ActorChatControls actor={actor} view={view} composerVisible={props.composerVisible} display="inspector"
|
|
561
559
|
running={primary ? props.primaryRunning : lifecycle === "running"} />
|
|
562
560
|
</SectionTabs>
|
|
563
561
|
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { WorkspaceTabContext } from "@ragents/web/PluginRegistry";
|
|
2
|
+
import { Button } from "@ragents/web/ui";
|
|
3
|
+
import { chatPrimaryId, runViewFrom } from "@ragents/web/run-view";
|
|
4
|
+
import { FlowInspector, type FlowSelection } from "./FlowInspector";
|
|
5
|
+
|
|
6
|
+
export const INSPECTION_TAB_ID = "ragents.orchestration.inspection";
|
|
7
|
+
|
|
8
|
+
export function InspectionPanel({ navigation, selection, session }: WorkspaceTabContext) {
|
|
9
|
+
const view = runViewFrom(session.runView);
|
|
10
|
+
const primary = view && chatPrimaryId(view);
|
|
11
|
+
const selected = (selection ?? undefined) as FlowSelection | undefined;
|
|
12
|
+
return <div className="flex h-full min-h-0 flex-col">
|
|
13
|
+
<nav aria-label="Inspect participants" className="flex flex-none flex-wrap gap-1 border-b border-border p-2">
|
|
14
|
+
{view?.actors.map((actor) => <Button key={actor.id} onClick={() => navigation.openTab(INSPECTION_TAB_ID, { type: "actor", id: actor.id })} size="xs" variant="ghost">@{actor.handle}</Button>)}
|
|
15
|
+
</nav>
|
|
16
|
+
<div className="min-h-0 flex-1"><FlowInspector actorConversations={session.actorConversations} canGoBack={selected !== undefined} composerVisible={false}
|
|
17
|
+
conversationError={session.conversationError} onBack={() => navigation.openTab(INSPECTION_TAB_ID, null)}
|
|
18
|
+
onNavigate={(next) => navigation.openTab(INSPECTION_TAB_ID, next)} primaryMessages={session.messages}
|
|
19
|
+
primaryRunning={session.running} selection={selected ?? (primary ? { type: "actor", id: primary } : undefined)} view={view} /></div>
|
|
20
|
+
</div>;
|
|
21
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import { SearchIcon } from "lucide-react";
|
|
2
|
+
import { INSPECTION_TAB_ID, InspectionPanel } from "./InspectionPanel";
|
|
1
3
|
import { useEffect, useState } from "react";
|
|
2
|
-
import { OrchestrationCenter } from "./Center";
|
|
3
4
|
import { OrchestrationRunPanel } from "./run-panel/RunPanel";
|
|
4
5
|
import { DocumentsSection } from "./DocumentsSection";
|
|
5
|
-
import { RunPanelSettings } from "./run-panel/RunPanelSettings";
|
|
6
|
-
import { ActorShortcuts } from "./ActorSurfaceControls";
|
|
7
6
|
import { JournalStatus } from "./JournalStatus";
|
|
8
7
|
import { StopRunHeader } from "./StopRunButton";
|
|
9
8
|
import { EXECUTIONS_TAB_ID, ExecutionsPanel, IconExecutions } from "./ExecutionsPanel";
|
|
@@ -18,7 +17,7 @@ import {
|
|
|
18
17
|
|
|
19
18
|
export { ORCHESTRATION_PLUGIN_ID } from "./constants";
|
|
20
19
|
|
|
21
|
-
/** The selection on the surface: an artifact opens the documents
|
|
20
|
+
/** The selection on the surface: an artifact opens the documents; actors and mini-apps report the current location. */
|
|
22
21
|
function OrchestrationSessionProvider({ children, navigation, session }: SessionProviderProps) {
|
|
23
22
|
const runView = runViewFrom(session.runView);
|
|
24
23
|
const [selection, setSelection] = useState<EntityReference>();
|
|
@@ -46,12 +45,8 @@ export const webPlugin: WebPlugin = {
|
|
|
46
45
|
sessionStatus: [{ id: "ragents.orchestration.journal", readRight: "runs.inspect", order: 20, Status: JournalStatus }],
|
|
47
46
|
sessionHeaders: [
|
|
48
47
|
{ id: "ragents.orchestration.stop", readRight: "runs.write", order: 100, Header: StopRunHeader },
|
|
49
|
-
{ id: "ragents.orchestration.actors", order: 300, placement: "surface", Header: ActorShortcuts },
|
|
50
48
|
],
|
|
51
|
-
|
|
52
|
-
{ id: "ragents.orchestration.runPanel", category: "appearance", label: "Run panel", Settings: RunPanelSettings },
|
|
53
|
-
],
|
|
54
|
-
surface: { Center: OrchestrationCenter, RunPanel: OrchestrationRunPanel },
|
|
49
|
+
surface: { RunPanel: OrchestrationRunPanel },
|
|
55
50
|
cardSections: [{
|
|
56
51
|
id: "ragents.orchestration.documents",
|
|
57
52
|
order: 300,
|
|
@@ -59,6 +54,15 @@ export const webPlugin: WebPlugin = {
|
|
|
59
54
|
}],
|
|
60
55
|
SessionProvider: OrchestrationSessionProvider,
|
|
61
56
|
workspaceTabs: [{
|
|
57
|
+
id: INSPECTION_TAB_ID,
|
|
58
|
+
readRight: "runs.inspect",
|
|
59
|
+
label: "Inspection",
|
|
60
|
+
order: 100,
|
|
61
|
+
Icon: SearchIcon,
|
|
62
|
+
Panel: InspectionPanel,
|
|
63
|
+
keepMounted: true,
|
|
64
|
+
available: (session) => runViewFrom(session.runView) !== undefined,
|
|
65
|
+
}, {
|
|
62
66
|
id: EXECUTIONS_TAB_ID,
|
|
63
67
|
readRight: "runs.inspect",
|
|
64
68
|
label: "Executions",
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { createContext, useContext, type ReactNode } from "react";
|
|
2
|
-
import type { SessionContext } from "@ragents/web/PluginRegistry";
|
|
3
2
|
import type { RunView } from "@ragents/web/run-view";
|
|
4
3
|
|
|
5
4
|
/** What an actor-program extension adds to the run panel and the inspector; without one both show no programs. */
|
|
6
5
|
export interface ProgramSlot {
|
|
7
6
|
runId: string;
|
|
8
|
-
needsAnswer: (session: SessionContext, appId: string) => boolean;
|
|
9
|
-
openFullscreen: (appId: string) => void;
|
|
10
7
|
source: (view: RunView, actorId: string) => ReactNode;
|
|
11
8
|
}
|
|
12
9
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useCallback, useId, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { ChevronDownIcon } from "lucide-react";
|
|
3
|
-
import { Badge,
|
|
4
|
-
import { ActorHeaderModeControl } from "../ActorSurfaceControls";
|
|
3
|
+
import { Badge, Input, Spinner } from "@ragents/web/ui";
|
|
5
4
|
import { ActorPopout } from "../ActorPopout";
|
|
6
5
|
import type { RunActor, RunView } from "@ragents/web/run-view";
|
|
7
6
|
import { pendingInputCount } from "./run-panel-actors";
|
|
@@ -11,50 +10,38 @@ import { ActorIcon, AddresseeTree } from "./AddresseeTree";
|
|
|
11
10
|
const chipClass = "flex h-7 min-w-[70px] max-w-[220px] flex-[0_1_auto] cursor-pointer items-center gap-1.5 rounded-full border border-border bg-background pr-2 pl-1 text-[0.72rem] font-semibold text-foreground hover:bg-accent aria-expanded:border-primary focus-visible:outline-2 focus-visible:outline-ring/60 focus-visible:outline-offset-1";
|
|
12
11
|
const busyClass = "flex h-7 min-w-0 flex-[0_1_auto] cursor-pointer items-center gap-1.5 rounded-md px-1.5 text-[0.7rem] text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring/60 focus-visible:outline-offset-1";
|
|
13
12
|
|
|
14
|
-
/** The chat's addressee as a chip in the input bar; the pop-out shows the actors as a tree by creator,
|
|
15
|
-
export function AddresseeControl({
|
|
16
|
-
|
|
17
|
-
onOpenChange: (open: boolean) => void;
|
|
18
|
-
onReveal: (actor: RunActor) => void;
|
|
13
|
+
/** The chat's addressee as a chip in the input bar; the pop-out shows the actors as a tree by creator, including stopped actors. */
|
|
14
|
+
export function AddresseeControl({ actors, onSelect, selected, technical, view }: {
|
|
15
|
+
actors: readonly RunActor[];
|
|
19
16
|
onSelect: (actor: RunActor) => void;
|
|
20
|
-
runId: string;
|
|
21
17
|
selected: RunActor;
|
|
22
|
-
shown: readonly RunActor[];
|
|
23
18
|
technical: boolean;
|
|
24
19
|
view: RunView;
|
|
25
20
|
}) {
|
|
26
21
|
const [open, setOpen] = useState(false);
|
|
27
22
|
const [query, setQuery] = useState("");
|
|
28
|
-
const [hiddenListed, setHiddenListed] = useState(false);
|
|
29
23
|
const [toggled, setToggled] = useState<ReadonlySet<string>>(() => new Set());
|
|
30
24
|
const buttonRef = useRef<HTMLButtonElement>(null);
|
|
31
25
|
const panelId = useId();
|
|
32
|
-
const change = useCallback((next: boolean) => {
|
|
33
|
-
setOpen(next);
|
|
34
|
-
onOpenChange(next);
|
|
35
|
-
}, [onOpenChange]);
|
|
36
26
|
const close = useCallback((restoreFocus = false) => {
|
|
37
|
-
|
|
27
|
+
setOpen(false);
|
|
38
28
|
setQuery("");
|
|
39
29
|
if (restoreFocus) buttonRef.current?.focus({ preventScroll: true });
|
|
40
|
-
}, [
|
|
30
|
+
}, []);
|
|
41
31
|
const revealSelected = useCallback((element: HTMLDivElement | null) => {
|
|
42
32
|
element?.querySelector("[aria-current=true]")?.scrollIntoView({ block: "nearest" });
|
|
43
33
|
}, []);
|
|
44
|
-
const working = useMemo(() =>
|
|
34
|
+
const working = useMemo(() => actors.filter((actor) => actor.lifecycle?.kind === "running" && actor.id !== selected.id), [actors, selected.id]);
|
|
45
35
|
const summary = useMemo(() => addresseeSummaries(view), [view]);
|
|
46
36
|
const searching = query.trim() !== "";
|
|
47
|
-
const
|
|
48
|
-
const hiddenMatches = useMemo(() => addresseeMatches(view, hidden, query, summary), [hidden, query, summary, view]);
|
|
49
|
-
const hiddenTree = useMemo(() => addresseeTree(view, hiddenMatches), [hiddenMatches, view]);
|
|
50
|
-
const hiddenOpen = hiddenListed || (searching && hiddenMatches.length > 0);
|
|
37
|
+
const tree = useMemo(() => addresseeTree(view, addresseeMatches(view, actors, query, summary)), [actors, query, summary, view]);
|
|
51
38
|
const toggle = useCallback((key: string) => setToggled((current) => {
|
|
52
39
|
const next = new Set(current);
|
|
53
40
|
if (!next.delete(key)) next.add(key);
|
|
54
41
|
return next;
|
|
55
42
|
}), []);
|
|
56
|
-
const pick = (actor: RunActor
|
|
57
|
-
|
|
43
|
+
const pick = (actor: RunActor) => {
|
|
44
|
+
onSelect(actor);
|
|
58
45
|
close(true);
|
|
59
46
|
};
|
|
60
47
|
const busyTitle = working.map((actor) => `@${actor.handle} is working`).join(", ");
|
|
@@ -63,33 +50,25 @@ export function AddresseeControl({ hidden, onOpenChange, onReveal, onSelect, run
|
|
|
63
50
|
const listClass = "px-1.5 py-1";
|
|
64
51
|
|
|
65
52
|
return <>
|
|
66
|
-
<button aria-controls={open ? panelId : undefined} aria-expanded={open} aria-haspopup="dialog" className={chipClass} onClick={() =>
|
|
53
|
+
<button aria-controls={open ? panelId : undefined} aria-expanded={open} aria-haspopup="dialog" className={chipClass} onClick={() => setOpen(!open)} ref={buttonRef} title={`Addressee: @${selected.handle}. Click to choose another actor`} type="button">
|
|
67
54
|
<ActorIcon actor={selected} className="size-5" view={view} />
|
|
68
55
|
<span className="truncate">@{selected.handle}</span>
|
|
69
56
|
<ChevronDownIcon aria-hidden className="size-3 flex-none text-muted-foreground" />
|
|
70
57
|
</button>
|
|
71
|
-
{working.length > 0 && <button className={busyClass} onClick={() =>
|
|
58
|
+
{working.length > 0 && <button className={busyClass} onClick={() => setOpen(!open)} title={busyTitle} type="button">
|
|
72
59
|
<Spinner aria-hidden className="size-3 flex-none" />
|
|
73
60
|
<span className="truncate in-data-[compact=true]:hidden">@{working[0].handle}</span>
|
|
74
61
|
{busyPending > 0 && <Badge className="h-4 min-w-4 px-1 text-[0.6rem]" variant="secondary">{busyPending}</Badge>}
|
|
75
62
|
{working.length > 1 && <span className="flex-none">+{working.length - 1}</span>}
|
|
76
63
|
</button>}
|
|
77
64
|
{open && <ActorPopout buttonRef={buttonRef} closeLabel="Close addressee" height={460} id={panelId} label="Addressee" onClose={close} open placement="top" role="dialog" width="available">
|
|
78
|
-
{
|
|
65
|
+
{actors.length > ADDRESSEE_SEARCH_ABOVE && <div className="flex-none border-b border-border-soft px-2.5 py-1.5">
|
|
79
66
|
<Input aria-label="Search actors" className="h-7" onChange={(event) => setQuery(event.target.value)} placeholder="Search handle or task ..." type="search" value={query} />
|
|
80
67
|
</div>}
|
|
81
68
|
<div className="min-h-0 flex-1 overflow-auto overscroll-contain" ref={revealSelected}>
|
|
82
|
-
<AddresseeTree className={listClass} nodes={
|
|
83
|
-
{searching &&
|
|
84
|
-
{hidden.length > 0 && (!searching || hiddenMatches.length > 0) && <div className="border-t border-border-soft">
|
|
85
|
-
<button aria-expanded={hiddenOpen} className="flex w-full cursor-pointer items-center justify-between gap-2 px-3.5 py-2 text-left text-muted-foreground hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring/60 focus-visible:-outline-offset-2" onClick={() => setHiddenListed(!hiddenOpen)} type="button">
|
|
86
|
-
<span>{hidden.length} hidden actors</span>
|
|
87
|
-
<ChevronDownIcon aria-hidden className={cn("size-3.5 flex-none transition-transform", hiddenOpen && "rotate-180")} />
|
|
88
|
-
</button>
|
|
89
|
-
{hiddenOpen && <AddresseeTree className={listClass} nodes={hiddenTree} onPick={(actor) => pick(actor, true)} {...treeProps} />}
|
|
90
|
-
</div>}
|
|
69
|
+
<AddresseeTree className={listClass} nodes={tree} onPick={pick} {...treeProps} />
|
|
70
|
+
{searching && tree.length === 0 && <p className="px-3.5 py-2 text-muted-foreground">No actor matches the search.</p>}
|
|
91
71
|
</div>
|
|
92
|
-
<div className="flex flex-none items-stretch border-t border-border-soft"><ActorHeaderModeControl runId={runId} /></div>
|
|
93
72
|
</ActorPopout>}
|
|
94
73
|
</>;
|
|
95
74
|
}
|