@swirls/looms 0.4.0 → 0.5.0
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/CHANGELOG.md +55 -0
- package/dist/actor/cell.d.ts +21 -2
- package/dist/actor/cell.js +15 -3
- package/dist/actor/host.d.ts +10 -2
- package/dist/actor/host.js +27 -4
- package/dist/actor/index.d.ts +2 -1
- package/dist/actor/index.js +1 -1
- package/dist/actor/routing.d.ts +3 -0
- package/dist/actor/routing.js +13 -2
- package/dist/agent/definitions-store.d.ts +1 -1
- package/dist/agent/definitions-store.js +1 -1
- package/dist/agent/definitions.d.ts +48 -0
- package/dist/agent/definitions.js +44 -0
- package/dist/agent/effects.d.ts +184 -0
- package/dist/agent/effects.js +172 -40
- package/dist/agent/events.d.ts +89 -0
- package/dist/agent/events.js +25 -0
- package/dist/agent/module.d.ts +412 -0
- package/dist/agent/module.js +5 -1
- package/dist/agent/scope.d.ts +88 -0
- package/dist/agent/threads.js +39 -3
- package/dist/agent/types.d.ts +4 -0
- package/dist/approval/effects.d.ts +40 -0
- package/dist/approval/module.d.ts +80 -0
- package/dist/client/client.d.ts +468 -119
- package/dist/client/client.js +214 -21
- package/dist/client/index.d.ts +1 -1
- package/dist/client/sse.d.ts +1 -1
- package/dist/client/sse.js +2 -2
- package/dist/cloudflare/durable-object.d.ts +66 -2
- package/dist/cloudflare/durable-object.js +96 -1
- package/dist/cloudflare/event-store.d.ts +7 -3
- package/dist/cloudflare/event-store.js +16 -3
- package/dist/cloudflare/index.d.ts +7 -1
- package/dist/cloudflare/index.js +7 -1
- package/dist/cloudflare/memory-queue.d.ts +18 -0
- package/dist/cloudflare/memory-queue.js +53 -0
- package/dist/cloudflare/queue-consumer.d.ts +52 -0
- package/dist/cloudflare/queue-consumer.js +102 -0
- package/dist/cloudflare/queue-message.d.ts +31 -0
- package/dist/cloudflare/queue-message.js +33 -0
- package/dist/cloudflare/queue-pull.d.ts +62 -0
- package/dist/cloudflare/queue-pull.js +130 -0
- package/dist/cloudflare/queue-worker.d.ts +39 -0
- package/dist/cloudflare/queue-worker.js +62 -0
- package/dist/cloudflare/r2-blob-store.d.ts +33 -0
- package/dist/cloudflare/r2-blob-store.js +60 -0
- package/dist/cloudflare/router.d.ts +4 -1
- package/dist/cloudflare/router.js +8 -3
- package/dist/cloudflare/websocket.d.ts +27 -0
- package/dist/cloudflare/websocket.js +215 -0
- package/dist/core/blob-offload.d.ts +21 -0
- package/dist/core/blob-offload.js +143 -0
- package/dist/core/blob-store.d.ts +45 -0
- package/dist/core/blob-store.js +164 -0
- package/dist/core/blobs.d.ts +37 -0
- package/dist/core/blobs.js +160 -0
- package/dist/core/definition-resolver.d.ts +40 -0
- package/dist/core/definition-resolver.js +129 -0
- package/dist/core/definition-store.d.ts +6 -0
- package/dist/core/definition-store.js +37 -1
- package/dist/core/effects.d.ts +86 -3
- package/dist/core/effects.js +99 -3
- package/dist/core/envelope.d.ts +9 -0
- package/dist/core/envelope.js +4 -0
- package/dist/core/event-codec.js +3 -0
- package/dist/core/fold.js +83 -1
- package/dist/core/ids.d.ts +2 -0
- package/dist/core/ids.js +4 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/index.js +8 -0
- package/dist/core/launcher.d.ts +97 -0
- package/dist/core/launcher.js +67 -0
- package/dist/core/module-scope.d.ts +7 -3
- package/dist/core/module-scope.js +3 -0
- package/dist/core/module.d.ts +10 -0
- package/dist/core/projection.js +4 -0
- package/dist/core/protocol.d.ts +36 -1
- package/dist/core/protocol.js +35 -0
- package/dist/core/published.d.ts +2 -0
- package/dist/core/published.js +4 -1
- package/dist/core/replay.d.ts +96 -0
- package/dist/core/run-context.d.ts +33 -0
- package/dist/core/run-context.js +23 -0
- package/dist/core/sqlite-store.js +57 -5
- package/dist/core/state.d.ts +60 -0
- package/dist/core/state.js +19 -0
- package/dist/core/store.d.ts +6 -0
- package/dist/core/store.js +7 -0
- package/dist/core/subscription.d.ts +97 -0
- package/dist/core/subscription.js +224 -0
- package/dist/core/thread.d.ts +7 -0
- package/dist/core/thread.js +1 -0
- package/dist/core/trace.d.ts +21 -0
- package/dist/core/trace.js +45 -0
- package/dist/core/worker-callback.d.ts +25 -1
- package/dist/debugger/app/assets/{index-CgDzWJg7.css → index-B7GdT1UA.css} +1 -1
- package/dist/debugger/app/assets/index-C31SnCuN.js +22 -0
- package/dist/debugger/app/assets/routes-DPA3O5AF.js +47 -0
- package/dist/debugger/app/index.html +2 -2
- package/dist/debugger/components/event-inspector.d.ts +3 -1
- package/dist/debugger/components/event-inspector.js +25 -4
- package/dist/debugger/components/event-stream.d.ts +4 -1
- package/dist/debugger/components/event-stream.js +2 -2
- package/dist/debugger/components/run-tree.d.ts +5 -2
- package/dist/debugger/components/run-tree.js +10 -4
- package/dist/debugger/context.d.ts +8 -1
- package/dist/debugger/context.js +15 -3
- package/dist/debugger/events/protocol-summarize.js +18 -3
- package/dist/debugger/index.d.ts +1 -1
- package/dist/debugger/index.js +1 -1
- package/dist/debugger/shell/debugger-shell.js +1 -1
- package/dist/debugger/shell/events-pane.js +4 -3
- package/dist/debugger/styles.css +1 -0
- package/dist/evaluator/definitions-store.d.ts +3 -4
- package/dist/evaluator/definitions-store.js +3 -3
- package/dist/evaluator/definitions.d.ts +4 -1
- package/dist/evaluator/definitions.js +5 -2
- package/dist/evaluator/effects.d.ts +74 -33
- package/dist/evaluator/effects.js +6 -2
- package/dist/evaluator/module.d.ts +150 -66
- package/dist/evaluator/module.js +7 -3
- package/dist/evaluator/threads.d.ts +2 -0
- package/dist/evaluator/threads.js +4 -0
- package/dist/projectors/event-log.d.ts +87 -0
- package/dist/projectors/event-log.js +396 -0
- package/dist/projectors/index-model.d.ts +12 -0
- package/dist/projectors/index-model.js +12 -3
- package/dist/projectors/memory.js +7 -0
- package/dist/projectors/postgres.d.ts +1 -0
- package/dist/projectors/postgres.js +32 -15
- package/dist/projectors/schema.d.ts +5 -0
- package/dist/projectors/schema.js +26 -1
- package/dist/projectors/sqlite.js +47 -19
- package/dist/projectors/with-projectors.d.ts +7 -1
- package/dist/projectors/with-projectors.js +13 -3
- package/dist/react/materialize.js +5 -1
- package/dist/react/react.d.ts +10 -2
- package/dist/react/react.js +43 -19
- package/dist/react/store.d.ts +11 -2
- package/dist/react/store.js +104 -12
- package/dist/react/tables.d.ts +4 -1
- package/dist/runtime/cancellation.d.ts +2 -1
- package/dist/runtime/cancellation.js +35 -2
- package/dist/runtime/child-run.d.ts +10 -0
- package/dist/runtime/child-run.js +58 -0
- package/dist/runtime/deadline-transition-planner.js +11 -2
- package/dist/runtime/dispatch-effect.d.ts +2 -2
- package/dist/runtime/dispatch-effect.js +43 -19
- package/dist/runtime/errors.d.ts +14 -1
- package/dist/runtime/errors.js +10 -0
- package/dist/runtime/filesystem-blob-store.d.ts +6 -0
- package/dist/runtime/filesystem-blob-store.js +59 -0
- package/dist/runtime/helpers.d.ts +15 -6
- package/dist/runtime/helpers.js +46 -6
- package/dist/runtime/index.d.ts +4 -2
- package/dist/runtime/index.js +3 -1
- package/dist/runtime/local-effect-executor.d.ts +11 -2
- package/dist/runtime/local-effect-executor.js +80 -4
- package/dist/runtime/looms.d.ts +38 -4
- package/dist/runtime/looms.js +17 -3
- package/dist/runtime/repository.d.ts +5 -4
- package/dist/runtime/repository.js +5 -2
- package/dist/runtime/retry-policy.d.ts +5 -0
- package/dist/runtime/retry-policy.js +10 -2
- package/dist/runtime/run-start.d.ts +1 -1
- package/dist/runtime/run-start.js +10 -0
- package/dist/runtime/runtime.d.ts +2 -2
- package/dist/runtime/runtime.js +191 -68
- package/dist/runtime/server/auth.d.ts +3 -0
- package/dist/runtime/server/fetch-handler.d.ts +2 -2
- package/dist/runtime/server/fetch-handler.js +35 -4
- package/dist/runtime/server/grant.d.ts +49 -0
- package/dist/runtime/server/grant.js +177 -0
- package/dist/runtime/server/routes/effects.js +47 -5
- package/dist/runtime/server/routes/runs.js +6 -1
- package/dist/runtime/server/run-route.d.ts +18 -0
- package/dist/runtime/server/run-route.js +26 -0
- package/dist/runtime/server.d.ts +3 -1
- package/dist/runtime/server.js +3 -1
- package/dist/runtime/sse.js +26 -4
- package/dist/runtime/subscription.d.ts +8 -0
- package/dist/runtime/subscription.js +23 -0
- package/dist/runtime/types.d.ts +87 -8
- package/dist/runtime/wake-engine.d.ts +4 -2
- package/dist/runtime/wake-engine.js +57 -6
- package/dist/runtime/worker-callbacks.d.ts +12 -2
- package/dist/runtime/worker-callbacks.js +102 -72
- package/dist/runtime/worker-effect-dispatch.d.ts +14 -5
- package/dist/runtime/worker-effect-dispatch.js +84 -18
- package/dist/schedule/debugger/index.d.ts +4 -0
- package/dist/schedule/debugger/index.js +11 -0
- package/dist/schedule/debugger/schedule-view.d.ts +3 -0
- package/dist/schedule/debugger/schedule-view.js +68 -0
- package/dist/schedule/debugger/summarize.d.ts +2 -0
- package/dist/schedule/debugger/summarize.js +43 -0
- package/dist/schedule/definitions-store.d.ts +10 -0
- package/dist/schedule/definitions-store.js +8 -0
- package/dist/schedule/definitions.d.ts +57 -0
- package/dist/schedule/definitions.js +30 -0
- package/dist/schedule/effects.d.ts +756 -0
- package/dist/schedule/effects.js +244 -0
- package/dist/schedule/ensure.d.ts +55 -0
- package/dist/schedule/ensure.js +109 -0
- package/dist/schedule/events.d.ts +116 -0
- package/dist/schedule/events.js +49 -0
- package/dist/schedule/index.d.ts +11 -0
- package/dist/schedule/index.js +11 -0
- package/dist/schedule/module.d.ts +1474 -0
- package/dist/schedule/module.js +22 -0
- package/dist/schedule/projections.d.ts +55 -0
- package/dist/schedule/projections.js +88 -0
- package/dist/schedule/scope.d.ts +121 -0
- package/dist/schedule/scope.js +7 -0
- package/dist/schedule/signals.d.ts +25 -0
- package/dist/schedule/signals.js +33 -0
- package/dist/schedule/specs.d.ts +59 -0
- package/dist/schedule/specs.js +231 -0
- package/dist/schedule/threads.d.ts +25 -0
- package/dist/schedule/threads.js +259 -0
- package/dist/testing/corpus-module.d.ts +34 -0
- package/dist/testing/corpus-module.js +87 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +5 -6
- package/dist/testing/replay-corpus.d.ts +22 -0
- package/dist/testing/replay-corpus.js +50 -0
- package/dist/workflow/definitions-store.d.ts +1 -1
- package/dist/workflow/definitions-store.js +1 -1
- package/dist/workflow/definitions.d.ts +14 -0
- package/dist/workflow/effects.d.ts +122 -0
- package/dist/workflow/effects.js +16 -6
- package/dist/workflow/events.d.ts +42 -0
- package/dist/workflow/events.js +4 -0
- package/dist/workflow/module.d.ts +345 -32
- package/dist/workflow/module.js +7 -3
- package/dist/workflow/scope.d.ts +42 -0
- package/dist/workflow/threads.d.ts +72 -0
- package/dist/workflow/threads.js +106 -38
- package/package.json +10 -1
- package/dist/debugger/app/assets/index-D--9esm9.js +0 -22
- package/dist/debugger/app/assets/routes-Dakrdusf.js +0 -47
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Looms debugger</title>
|
|
7
|
-
<script type="module" crossorigin src="./assets/index-
|
|
7
|
+
<script type="module" crossorigin src="./assets/index-C31SnCuN.js"></script>
|
|
8
8
|
<link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-CbXtAM7H.js">
|
|
9
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-B7GdT1UA.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { OpenRunTarget } from '../context';
|
|
1
2
|
import type { DebuggerEvent, ReplayLoader } from '../contracts';
|
|
2
|
-
export declare function EventInspector({ event, loadReplayStep, onClose, }: {
|
|
3
|
+
export declare function EventInspector({ event, loadReplayStep, onClose, onOpenRun, }: {
|
|
3
4
|
event: DebuggerEvent;
|
|
4
5
|
loadReplayStep?: ReplayLoader;
|
|
5
6
|
onClose?: () => void;
|
|
7
|
+
onOpenRun?: (runId: string, target?: OpenRunTarget) => void;
|
|
6
8
|
}): import("react").JSX.Element;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { X } from 'lucide-react';
|
|
2
|
+
import { ExternalLink, X } from 'lucide-react';
|
|
3
3
|
import { useEffect, useState } from 'react';
|
|
4
|
-
import { asJson } from '@swirls/looms/core';
|
|
4
|
+
import { asJson, readRunLaunchSource } from '@swirls/looms/core';
|
|
5
|
+
import { jsonFields, jsonText } from '../lib/payload.js';
|
|
5
6
|
import { Button } from '../ui/button.js';
|
|
6
7
|
import { ScrollArea } from '../ui/scroll-area.js';
|
|
7
8
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../ui/tabs.js';
|
|
@@ -12,9 +13,29 @@ function Pane({ value, children }) {
|
|
|
12
13
|
function StepJson({ step, pick, }) {
|
|
13
14
|
return step ? (_jsx(JsonTree, { value: pick(step), defaultExpandDepth: 2 })) : (_jsx("p", { className: "text-muted-foreground text-xs", children: "Loading\u2026" }));
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
+
/** The other run a launch event points at: the run it launched, or the run that launched it. */
|
|
17
|
+
function linkedRun(event) {
|
|
18
|
+
const payload = jsonFields(event.payload);
|
|
19
|
+
if (event.type === 'runtime.run.launched') {
|
|
20
|
+
const runId = jsonText(payload.runId);
|
|
21
|
+
return runId ? { label: 'Open launched run', runId } : undefined;
|
|
22
|
+
}
|
|
23
|
+
if (event.type === 'runtime.run.started') {
|
|
24
|
+
const source = readRunLaunchSource(payload.launchedBy);
|
|
25
|
+
return source
|
|
26
|
+
? {
|
|
27
|
+
label: 'Open launching run',
|
|
28
|
+
runId: source.runId,
|
|
29
|
+
target: { seq: source.causationSeq },
|
|
30
|
+
}
|
|
31
|
+
: undefined;
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
export function EventInspector({ event, loadReplayStep, onClose, onOpenRun, }) {
|
|
16
36
|
const [step, setStep] = useState(null);
|
|
17
37
|
const canReplay = loadReplayStep !== undefined;
|
|
38
|
+
const link = onOpenRun ? linkedRun(event) : undefined;
|
|
18
39
|
useEffect(() => {
|
|
19
40
|
if (!loadReplayStep) {
|
|
20
41
|
setStep(null);
|
|
@@ -30,7 +51,7 @@ export function EventInspector({ event, loadReplayStep, onClose, }) {
|
|
|
30
51
|
cancelled = true;
|
|
31
52
|
};
|
|
32
53
|
}, [event.runId, event.seq, loadReplayStep]);
|
|
33
|
-
return (_jsx("div", { className: "border-border bg-sidebar flex h-[45%] min-h-40 shrink-0 flex-col border-t", children: _jsxs(Tabs, { defaultValue: "payload", className: "min-h-0 flex-1 gap-0", children: [_jsxs("div", { className: "flex h-10 shrink-0 items-center gap-2 pr-2 pl-3", children: [_jsxs("span", { className: "text-muted-foreground font-mono text-[11px] tabular-nums", children: ["#", event.seq] }), _jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: event.type }), _jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "payload", children: "Payload" }), _jsx(TabsTrigger, { value: "envelope", children: "Envelope" }), canReplay ? _jsx(TabsTrigger, { value: "state", children: "State" }) : null, canReplay ? _jsx(TabsTrigger, { value: "effects", children: "Effects" }) : null] }), onClose ? (_jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Close inspector", onClick: onClose, children: _jsx(X, {}) })) : null] }), _jsx(Pane, { value: "payload", children: _jsx(JsonTree, { value: event.payload, defaultExpandDepth: 2 }) }), _jsx(Pane, { value: "envelope", children: _jsx(JsonTree, { value: asJson({
|
|
54
|
+
return (_jsx("div", { className: "border-border bg-sidebar flex h-[45%] min-h-40 shrink-0 flex-col border-t", children: _jsxs(Tabs, { defaultValue: "payload", className: "min-h-0 flex-1 gap-0", children: [_jsxs("div", { className: "flex h-10 shrink-0 items-center gap-2 pr-2 pl-3", children: [_jsxs("span", { className: "text-muted-foreground font-mono text-[11px] tabular-nums", children: ["#", event.seq] }), _jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: event.type }), link && onOpenRun ? (_jsxs(Button, { variant: "ghost", size: "sm", title: link.runId, onClick: () => onOpenRun(link.runId, link.target), children: [_jsx(ExternalLink, {}), link.label] })) : null, _jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "payload", children: "Payload" }), _jsx(TabsTrigger, { value: "envelope", children: "Envelope" }), canReplay ? _jsx(TabsTrigger, { value: "state", children: "State" }) : null, canReplay ? _jsx(TabsTrigger, { value: "effects", children: "Effects" }) : null] }), onClose ? (_jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Close inspector", onClick: onClose, children: _jsx(X, {}) })) : null] }), _jsx(Pane, { value: "payload", children: _jsx(JsonTree, { value: event.payload, defaultExpandDepth: 2 }) }), _jsx(Pane, { value: "envelope", children: _jsx(JsonTree, { value: asJson({
|
|
34
55
|
id: event.id,
|
|
35
56
|
runId: event.runId,
|
|
36
57
|
seq: event.seq,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
+
import type { OpenRunTarget } from '../context';
|
|
2
3
|
import type { DebuggerEvent, EventStreamCatalog, ReplayLoader } from '../contracts';
|
|
3
|
-
export declare function EventStream<TEvent extends DebuggerEvent>({ events, startedAt, threadId, threadLabel, onClearThread, selectedSeq, onSelectSeq, catalog, loadReplayStep, renderInspector, }: {
|
|
4
|
+
export declare function EventStream<TEvent extends DebuggerEvent>({ events, startedAt, threadId, threadLabel, onClearThread, selectedSeq, onSelectSeq, catalog, loadReplayStep, renderInspector, onOpenRun, }: {
|
|
4
5
|
events: readonly TEvent[];
|
|
5
6
|
startedAt?: number;
|
|
6
7
|
threadId?: string;
|
|
@@ -11,4 +12,6 @@ export declare function EventStream<TEvent extends DebuggerEvent>({ events, star
|
|
|
11
12
|
catalog?: EventStreamCatalog<TEvent>;
|
|
12
13
|
loadReplayStep?: ReplayLoader;
|
|
13
14
|
renderInspector?: (selected: TEvent) => ReactNode;
|
|
15
|
+
/** Follows launch links from the inspector to another run. */
|
|
16
|
+
onOpenRun?: (runId: string, target?: OpenRunTarget) => void;
|
|
14
17
|
}): import("react").JSX.Element;
|
|
@@ -12,7 +12,7 @@ import { PanelHeader, PanelTitle } from '../ui/panel.js';
|
|
|
12
12
|
import { EventInspector } from './event-inspector.js';
|
|
13
13
|
import { FollowList } from './follow-list.js';
|
|
14
14
|
const ROW_ESTIMATE = 26;
|
|
15
|
-
export function EventStream({ events, startedAt, threadId, threadLabel, onClearThread, selectedSeq, onSelectSeq, catalog, loadReplayStep, renderInspector, }) {
|
|
15
|
+
export function EventStream({ events, startedAt, threadId, threadLabel, onClearThread, selectedSeq, onSelectSeq, catalog, loadReplayStep, renderInspector, onOpenRun, }) {
|
|
16
16
|
const eventCatalog = catalog ?? defaultEventCatalog;
|
|
17
17
|
const [query, setQuery] = useState('');
|
|
18
18
|
const [follow, setFollow] = useState(true);
|
|
@@ -49,7 +49,7 @@ export function EventStream({ events, startedAt, threadId, threadLabel, onClearT
|
|
|
49
49
|
const hiddenFamilyCount = eventCatalog.families.length - families.size;
|
|
50
50
|
const filtered = visible.length !== events.length;
|
|
51
51
|
return (_jsxs("div", { className: "debugger-event-stream flex h-full min-h-0 flex-col", children: [_jsxs(PanelHeader, { className: "gap-1.5 pr-2", children: [_jsx(PanelTitle, { className: "hidden @md:flex", meta: filtered ? `${visible.length}/${events.length}` : events.length, children: "Events" }), _jsxs("div", { className: "relative ml-auto min-w-0 flex-1 @md:max-w-64", children: [_jsx(Search, { "aria-hidden": true, className: "text-muted-foreground pointer-events-none absolute top-1/2 left-2 size-3 -translate-y-1/2" }), _jsx(Input, { value: query, onChange: (event) => setQuery(event.target.value), placeholder: "Search events", "aria-label": "Search events", className: "h-7 w-full pl-7 text-xs" })] }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "icon-sm", className: "relative", "aria-label": "Filter event families", children: [_jsx(SlidersHorizontal, {}), hiddenFamilyCount > 0 ? (_jsx("span", { className: "bg-foreground text-background absolute top-0.5 right-0.5 flex size-3.5 items-center justify-center rounded-full font-mono text-[8px]", children: hiddenFamilyCount })) : null] }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsx(DropdownMenuLabel, { children: "Event families" }), eventCatalog.families.map((family) => (_jsxs(DropdownMenuCheckboxItem, { checked: families.has(family), onCheckedChange: () => toggleFamily(family), onSelect: (event) => event.preventDefault(), className: "font-mono", children: [_jsx("span", { "aria-hidden": true, className: "size-1.5 rounded-full", style: { backgroundColor: eventCatalog.familyColor(family) } }), family] }, family)))] })] }), _jsxs(Button, { variant: "ghost", size: "sm", "aria-pressed": follow, "aria-label": "Follow newest events", onClick: () => setFollow(!follow), className: "aria-pressed:bg-accent aria-pressed:text-foreground px-2", children: [_jsx(ArrowDownToLine, {}), _jsx("span", { className: "hidden @lg:inline", children: "Follow" })] })] }), threadId ? (_jsxs("div", { className: "border-border flex h-8 shrink-0 items-center gap-2 border-b px-3 text-[11px]", children: [_jsx("span", { className: "text-muted-foreground", children: "Thread" }), _jsxs("span", { className: "bg-accent text-foreground inline-flex h-5 min-w-0 items-center gap-1 rounded-sm pr-0.5 pl-1.5 font-mono", children: [_jsx("span", { className: "truncate", title: threadId, children: threadLabel ?? shortId(threadId) }), onClearThread ? (_jsx("button", { type: "button", "aria-label": "Show all threads", onClick: onClearThread, className: "text-muted-foreground hover:text-foreground hover:bg-background/60 flex size-4 items-center justify-center rounded-sm", children: _jsx(X, { className: "size-3" }) })) : null] })] })) : null, _jsx(FollowList, { items: visible, getKey: (event) => event.id, estimateSize: ROW_ESTIMATE, overscan: 16, follow: follow, onFollowChange: setFollow, className: "min-h-32", itemClassName: "px-1.5", empty: _jsx("p", { className: "text-muted-foreground p-6 text-center text-xs", children: events.length === 0 ? 'Waiting for events…' : 'No events match these filters.' }), renderItem: (event) => (_jsx(EventRow, { event: event, catalog: eventCatalog, startedAt: startedAt, selected: selectedSeq === event.seq, onSelectSeq: onSelectSeq })) }), selected
|
|
52
|
-
? (renderInspector?.(selected) ?? (_jsx(EventInspector, { event: selected, loadReplayStep: loadReplayStep, onClose: () => onSelectSeq(undefined) })))
|
|
52
|
+
? (renderInspector?.(selected) ?? (_jsx(EventInspector, { event: selected, loadReplayStep: loadReplayStep, onClose: () => onSelectSeq(undefined), onOpenRun: onOpenRun })))
|
|
53
53
|
: null] }));
|
|
54
54
|
}
|
|
55
55
|
function EventRow({ event, catalog, startedAt, selected, onSelectSeq, }) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ThreadNode } from '@swirls/looms/core';
|
|
2
|
-
export declare function RunTree({ runId, runStatus, tree, eventCounts, totalEventCount, selectedThread, onSelectThread, formatRunLabel, showHeading, }: {
|
|
1
|
+
import type { RunLaunchSource, ThreadNode } from '@swirls/looms/core';
|
|
2
|
+
export declare function RunTree({ runId, runStatus, tree, eventCounts, totalEventCount, selectedThread, onSelectThread, launchedBy, onOpenLauncher, formatRunLabel, showHeading, }: {
|
|
3
3
|
runId: string;
|
|
4
4
|
runStatus: string;
|
|
5
5
|
tree: {
|
|
@@ -9,6 +9,9 @@ export declare function RunTree({ runId, runStatus, tree, eventCounts, totalEven
|
|
|
9
9
|
totalEventCount?: number;
|
|
10
10
|
selectedThread?: string;
|
|
11
11
|
onSelectThread: (threadId: string | undefined) => void;
|
|
12
|
+
/** The effect in another run that launched this one. */
|
|
13
|
+
launchedBy?: RunLaunchSource;
|
|
14
|
+
onOpenLauncher?: (source: RunLaunchSource) => void;
|
|
12
15
|
formatRunLabel?: (runId: string) => string;
|
|
13
16
|
showHeading?: boolean;
|
|
14
17
|
}): import("react").JSX.Element;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
3
|
-
import { ChevronRight } from 'lucide-react';
|
|
3
|
+
import { ChevronRight, CornerLeftUp } from 'lucide-react';
|
|
4
4
|
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
5
5
|
import { cn, shortId } from '../lib/cn.js';
|
|
6
6
|
import { PanelHeader, PanelTitle } from '../ui/panel.js';
|
|
@@ -33,7 +33,13 @@ function NodeRow({ row, selected, count, collapsed, onToggle, onSelect, }) {
|
|
|
33
33
|
const hasChildren = node.children.length > 0;
|
|
34
34
|
return (_jsxs("div", { className: cn('group/row relative flex h-7 items-center rounded-md pr-2 text-xs', selected ? 'bg-accent text-foreground' : 'hover:bg-accent/50'), style: { paddingLeft: 4 + depth * INDENT }, title: `${node.definitionName} · ${node.kind} · ${node.status}`, children: [Array.from({ length: depth }, (_, level) => (_jsx("span", { "aria-hidden": true, className: "bg-border absolute inset-y-0 w-px", style: { left: 12 + level * INDENT } }, level))), hasChildren ? (_jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground hover:bg-background/40 flex size-4 shrink-0 items-center justify-center rounded-sm", onClick: () => onToggle(node.threadId), "aria-label": collapsed ? 'Expand thread' : 'Collapse thread', "aria-expanded": !collapsed, children: _jsx(ChevronRight, { className: cn('ease-snappy size-3 transition-transform duration-100', !collapsed && 'rotate-90') }) })) : (_jsx("span", { className: "size-4 shrink-0" })), _jsxs("button", { type: "button", className: "flex h-full min-w-0 flex-1 items-center gap-2 pl-1 text-left", onClick: () => onSelect(node.threadId), children: [_jsx(StatusDot, { status: node.status }), _jsxs("span", { className: "min-w-0 truncate", children: [_jsx("span", { className: "font-medium", children: node.definitionName }), _jsx("span", { className: "text-muted-foreground ml-1.5 font-mono text-[10px]", children: node.kind })] }), _jsx("span", { className: "text-muted-foreground ml-auto shrink-0 font-mono text-[10px] tabular-nums", children: count })] })] }));
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
function LaunchedByRow({ source, onOpen, }) {
|
|
37
|
+
const label = (_jsxs(_Fragment, { children: [_jsx(CornerLeftUp, { className: "text-muted-foreground size-3.5 shrink-0" }), _jsx("span", { className: "text-muted-foreground shrink-0", children: "Launched by" }), _jsx("span", { className: "min-w-0 truncate font-mono text-[10px]", children: source.runId }), _jsxs("span", { className: "text-muted-foreground ml-auto shrink-0 font-mono text-[10px] tabular-nums", children: ["#", source.causationSeq] })] }));
|
|
38
|
+
const title = `Effect ${source.effectId} on thread ${source.threadId}, requested by event #${source.causationSeq} of ${source.runId}`;
|
|
39
|
+
const className = 'flex h-7 w-full items-center gap-2 rounded-md px-2 text-left text-xs';
|
|
40
|
+
return onOpen ? (_jsx("button", { type: "button", title: title, onClick: () => onOpen(source), className: cn(className, 'hover:bg-accent/50'), children: label })) : (_jsx("div", { title: title, className: className, children: label }));
|
|
41
|
+
}
|
|
42
|
+
export function RunTree({ runId, runStatus, tree, eventCounts, totalEventCount, selectedThread, onSelectThread, launchedBy, onOpenLauncher, formatRunLabel = shortId, showHeading = true, }) {
|
|
37
43
|
const [collapsed, setCollapsed] = useState(() => new Set());
|
|
38
44
|
const runCount = totalEventCount ?? eventCounts.get('run') ?? 0;
|
|
39
45
|
const rows = useMemo(() => flatten(tree.root, collapsed), [tree.root, collapsed]);
|
|
@@ -58,7 +64,7 @@ export function RunTree({ runId, runStatus, tree, eventCounts, totalEventCount,
|
|
|
58
64
|
return next;
|
|
59
65
|
});
|
|
60
66
|
}, []);
|
|
61
|
-
return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [showHeading ? (_jsxs(PanelHeader, { children: [_jsx(PanelTitle, { children: "Run tree" }), _jsx(StatusBadge, { status: runStatus, className: "ml-auto" })] })) : null,
|
|
67
|
+
return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [showHeading ? (_jsxs(PanelHeader, { children: [_jsx(PanelTitle, { children: "Run tree" }), _jsx(StatusBadge, { status: runStatus, className: "ml-auto" })] })) : null, _jsxs("div", { className: "px-2 pt-2", children: [launchedBy ? _jsx(LaunchedByRow, { source: launchedBy, onOpen: onOpenLauncher }) : null, _jsxs("button", { type: "button", onClick: () => onSelectThread(undefined), className: cn('flex h-7 w-full items-center gap-2 rounded-md px-2 text-left text-xs', !selectedThread ? 'bg-accent text-foreground' : 'hover:bg-accent/50'), children: [_jsx("span", { className: "text-muted-foreground", children: "All threads" }), _jsx("span", { className: "text-muted-foreground/70 truncate font-mono text-[10px]", children: formatRunLabel(runId) }), _jsx("span", { className: "text-muted-foreground ml-auto font-mono text-[10px] tabular-nums", children: runCount })] })] }), rows.length === 0 ? (_jsx("p", { className: "text-muted-foreground px-4 py-2 text-xs", children: "Waiting for threads\u2026" })) : (_jsx(ScrollArea, { viewportRef: parentRef, className: "min-h-0 flex-1", children: _jsx("div", { className: "relative mx-2 mb-2", style: { height: virtualizer.getTotalSize() }, children: virtualizer.getVirtualItems().map((item) => {
|
|
62
68
|
const row = rows[item.index];
|
|
63
69
|
if (!row) {
|
|
64
70
|
return null;
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import { type LoomsClient } from '@swirls/looms/client';
|
|
3
3
|
import type { DebuggerPlugin } from './plugin';
|
|
4
|
+
/** Where to land in a run another view links to. */
|
|
5
|
+
export interface OpenRunTarget {
|
|
6
|
+
readonly seq?: number;
|
|
7
|
+
}
|
|
4
8
|
export interface DebuggerContextValue {
|
|
5
9
|
readonly client: LoomsClient;
|
|
6
10
|
readonly plugins: readonly DebuggerPlugin[];
|
|
11
|
+
/** Opens another run, for example the run a schedule fired or the run that launched this one. */
|
|
12
|
+
readonly openRun?: (runId: string, target?: OpenRunTarget) => void;
|
|
7
13
|
}
|
|
8
14
|
/** Supplies one Looms host to both the API client and the run stores. */
|
|
9
|
-
export declare function DebuggerProvider({ endpoint, plugins, children, }: {
|
|
15
|
+
export declare function DebuggerProvider({ endpoint, plugins, openRun, children, }: {
|
|
10
16
|
endpoint?: string;
|
|
11
17
|
plugins: readonly DebuggerPlugin[];
|
|
18
|
+
openRun?: (runId: string, target?: OpenRunTarget) => void;
|
|
12
19
|
children: ReactNode;
|
|
13
20
|
}): import("react").JSX.Element;
|
|
14
21
|
export declare function useDebugger(): DebuggerContextValue;
|
package/dist/debugger/context.js
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { createContext, useContext, useMemo } from 'react';
|
|
2
|
+
import { createContext, useCallback, useContext, useMemo, useRef } from 'react';
|
|
3
3
|
import { createLoomsClient } from '@swirls/looms/client';
|
|
4
4
|
import { LoomsProvider } from '@swirls/looms/react';
|
|
5
5
|
const DebuggerContext = createContext(null);
|
|
6
6
|
/** Supplies one Looms host to both the API client and the run stores. */
|
|
7
|
-
export function DebuggerProvider({ endpoint = '', plugins, children, }) {
|
|
8
|
-
const
|
|
7
|
+
export function DebuggerProvider({ endpoint = '', plugins, openRun, children, }) {
|
|
8
|
+
const openRunRef = useRef(openRun);
|
|
9
|
+
openRunRef.current = openRun;
|
|
10
|
+
const hasOpenRun = openRun !== undefined;
|
|
11
|
+
const stableOpenRun = useCallback((runId, target) => {
|
|
12
|
+
openRunRef.current?.(runId, target);
|
|
13
|
+
}, []);
|
|
14
|
+
const value = useMemo(() => {
|
|
15
|
+
const client = createLoomsClient({ baseUrl: endpoint });
|
|
16
|
+
if (!hasOpenRun) {
|
|
17
|
+
return { client, plugins };
|
|
18
|
+
}
|
|
19
|
+
return { client, plugins, openRun: stableOpenRun };
|
|
20
|
+
}, [endpoint, plugins, hasOpenRun, stableOpenRun]);
|
|
9
21
|
return (_jsx(LoomsProvider, { endpoint: endpoint, children: _jsx(DebuggerContext.Provider, { value: value, children: children }) }));
|
|
10
22
|
}
|
|
11
23
|
export function useDebugger() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isJsonNumber, isJsonString, isProtocolType } from '@swirls/looms/core';
|
|
1
|
+
import { isJsonNumber, isJsonString, isProtocolType, readRunLaunchSource } from '@swirls/looms/core';
|
|
2
2
|
import { compactJson } from '../lib/cn.js';
|
|
3
3
|
import { jsonFields, jsonNumberText, jsonText } from '../lib/payload.js';
|
|
4
4
|
export function summarizeProtocolEvent(event) {
|
|
@@ -7,11 +7,14 @@ export function summarizeProtocolEvent(event) {
|
|
|
7
7
|
}
|
|
8
8
|
const payload = jsonFields(event.payload);
|
|
9
9
|
switch (event.type) {
|
|
10
|
-
case 'runtime.run.started':
|
|
10
|
+
case 'runtime.run.started': {
|
|
11
|
+
const definition = `${jsonText(payload.kind) ?? 'run'}:${jsonText(payload.definitionName) ?? 'unknown'}`;
|
|
12
|
+
const launchedBy = readRunLaunchSource(payload.launchedBy);
|
|
11
13
|
return {
|
|
12
14
|
title: 'run started',
|
|
13
|
-
detail: `${
|
|
15
|
+
detail: launchedBy ? `${definition} · launched by ${launchedBy.runId}` : definition,
|
|
14
16
|
};
|
|
17
|
+
}
|
|
15
18
|
case 'runtime.run.completed':
|
|
16
19
|
return {
|
|
17
20
|
title: jsonText(payload.error) ? 'run failed' : 'run completed',
|
|
@@ -19,6 +22,18 @@ export function summarizeProtocolEvent(event) {
|
|
|
19
22
|
};
|
|
20
23
|
case 'runtime.run.cancelled':
|
|
21
24
|
return { title: 'run cancelled', detail: jsonText(payload.reason) };
|
|
25
|
+
case 'runtime.run.launched':
|
|
26
|
+
return {
|
|
27
|
+
title: 'run launched',
|
|
28
|
+
detail: `${jsonText(payload.kind) ?? 'run'}:${jsonText(payload.definitionName) ?? 'unknown'} · ${jsonText(payload.runId) ?? 'unknown'}`,
|
|
29
|
+
};
|
|
30
|
+
case 'runtime.child.settled':
|
|
31
|
+
return {
|
|
32
|
+
title: 'child settled',
|
|
33
|
+
detail: `${jsonText(payload.status) ?? 'done'} · ${jsonText(payload.runId) ?? ''}`,
|
|
34
|
+
};
|
|
35
|
+
case 'runtime.child.close.requested':
|
|
36
|
+
return { title: 'child close requested', detail: jsonText(payload.policy) };
|
|
22
37
|
case 'runtime.run.forked':
|
|
23
38
|
return {
|
|
24
39
|
title: 'run forked',
|
package/dist/debugger/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type { DebuggerEvent, EventStreamCatalog, EventSummary, ReplayLoader, ReplayStep, RunTreeModel, ThreadTree, } from './contracts';
|
|
2
2
|
export { createEventCatalog, defaultEventCatalog } from './events/catalog';
|
|
3
3
|
export { summarizeProtocolEvent } from './events/protocol-summarize';
|
|
4
|
-
export { DebuggerProvider, useDebugger, type DebuggerContextValue } from './context';
|
|
4
|
+
export { DebuggerProvider, useDebugger, type DebuggerContextValue, type OpenRunTarget, } from './context';
|
|
5
5
|
export { projectionFor, workspaceFor, type DebuggerPlugin, type EventFamilyView, type ProjectionView, type WorkspaceContext, type WorkspaceView, } from './plugin';
|
|
6
6
|
export { DebuggerShell, type DebuggerSelection } from './shell/debugger-shell';
|
|
7
7
|
export { StartForm } from './shell/start-form';
|
package/dist/debugger/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { createEventCatalog, defaultEventCatalog } from './events/catalog.js';
|
|
2
2
|
export { summarizeProtocolEvent } from './events/protocol-summarize.js';
|
|
3
|
-
export { DebuggerProvider, useDebugger } from './context.js';
|
|
3
|
+
export { DebuggerProvider, useDebugger, } from './context.js';
|
|
4
4
|
export { projectionFor, workspaceFor, } from './plugin.js';
|
|
5
5
|
export { DebuggerShell } from './shell/debugger-shell.js';
|
|
6
6
|
export { StartForm } from './shell/start-form.js';
|
|
@@ -39,5 +39,5 @@ function DebuggerFrame({ selection, onSelectionChange, }) {
|
|
|
39
39
|
}) }), _jsxs("div", { className: "ml-auto flex min-w-0 items-center gap-2", children: [error ? (_jsx("p", { className: "text-status-failed truncate text-[11px]", title: error, children: error })) : null, selection.run ? (_jsx(RunControls, { runId: selection.run, onForked: (run) => onSelectionChange({ kind, name, run }) })) : null] })] }), _jsxs(ResizablePanelGroup, { id: "looms-debugger-columns", className: "min-h-0 flex-1", defaultLayout: layout.defaultLayout, onLayoutChanged: layout.onLayoutChanged, children: [_jsx(ResizablePanel, { id: "tree", defaultSize: "17%", minSize: "12rem", maxSize: "30%", className: "bg-sidebar", children: _jsx("section", { "aria-label": "Run tree", className: "h-full min-h-0 overflow-hidden", children: selection.run ? (_jsx(RunTreePane, { runId: selection.run, threadId: selection.thread, onSelectThread: (thread) => onSelectionChange({ ...selection, thread, seq: undefined }) })) : (_jsxs("div", { className: "flex h-full flex-col", children: [_jsx(PanelHeader, { children: _jsx(PanelTitle, { children: "Run tree" }) }), _jsx(EmptyState, { icon: _jsx(ListTree, {}), title: "No run selected", children: "Threads and child runs appear here once a run starts." })] })) }) }), _jsx(ResizableHandle, {}), _jsx(ResizablePanel, { id: "workspace", defaultSize: "29%", minSize: "16rem", children: _jsx("section", { "aria-label": "Workspace", className: "@container h-full min-h-0 overflow-hidden", children: _jsx(Workspace, { definition: selected, runId: selection.run, onStarted: (run) => onSelectionChange({ kind, name, run }) }) }) }), _jsx(ResizableHandle, {}), _jsx(ResizablePanel, { id: "events", defaultSize: "32%", minSize: "16rem", children: _jsx("section", { "aria-label": "Events", className: "h-full min-h-0 overflow-hidden", children: selection.run ? (_jsx(EventsPane, { runId: selection.run, threadId: selection.thread, seq: selection.seq, onSelectSeq: (seq) => onSelectionChange({ ...selection, seq }), onClearThread: () => onSelectionChange({ ...selection, thread: undefined }) })) : (_jsxs("div", { className: "flex h-full flex-col", children: [_jsx(PanelHeader, { children: _jsx(PanelTitle, { children: "Events" }) }), _jsx(EmptyState, { icon: _jsx(Activity, {}), title: "No events yet", children: "Events stream in live once a run starts." })] })) }) }), _jsx(ResizableHandle, {}), _jsx(ResizablePanel, { id: "projections", defaultSize: "22%", minSize: "14rem", className: "bg-sidebar", children: _jsx("section", { "aria-label": "Projections", className: "h-full min-h-0 overflow-hidden", children: _jsx(ProjectionsPanel, { runId: selection.run, names: catalog.projections }) }) })] })] }));
|
|
40
40
|
}
|
|
41
41
|
export function DebuggerShell({ plugins, selection, onSelectionChange, endpoint, }) {
|
|
42
|
-
return (_jsx(DebuggerProvider, { endpoint: endpoint, plugins: plugins, children: _jsx(DebuggerFrame, { selection: selection, onSelectionChange: onSelectionChange }) }));
|
|
42
|
+
return (_jsx(DebuggerProvider, { endpoint: endpoint, plugins: plugins, openRun: (runId, target) => onSelectionChange({ run: runId, seq: target?.seq }), children: _jsx(DebuggerFrame, { selection: selection, onSelectionChange: onSelectionChange }) }));
|
|
43
43
|
}
|
|
@@ -7,19 +7,20 @@ import { RunTree } from '../components/run-tree.js';
|
|
|
7
7
|
import { useDebugger } from '../context.js';
|
|
8
8
|
import { createEventCatalog } from '../events/catalog.js';
|
|
9
9
|
export function EventsPane({ runId, threadId, seq, onSelectSeq, onClearThread, }) {
|
|
10
|
-
const { client, plugins } = useDebugger();
|
|
10
|
+
const { client, plugins, openRun } = useDebugger();
|
|
11
11
|
const catalog = useMemo(() => createEventCatalog(plugins), [plugins]);
|
|
12
12
|
const store = useRunStore(runId);
|
|
13
13
|
const events = useRunEvents(store);
|
|
14
14
|
const summary = useRunSummary(store);
|
|
15
15
|
const tree = useThreadTree(store);
|
|
16
16
|
const loadReplayStep = useCallback(({ runId: replayRunId, seq: replaySeq }) => client.replayTo(replayRunId, replaySeq).then((result) => result.step), [client]);
|
|
17
|
-
return (_jsx(EventStream, { events: events, startedAt: summary.startedAt, threadId: threadId, threadLabel: findThreadName(tree.root, threadId), onClearThread: onClearThread, selectedSeq: seq, onSelectSeq: onSelectSeq, loadReplayStep: loadReplayStep, catalog: catalog }));
|
|
17
|
+
return (_jsx(EventStream, { events: events, startedAt: summary.startedAt, threadId: threadId, threadLabel: findThreadName(tree.root, threadId), onClearThread: onClearThread, selectedSeq: seq, onSelectSeq: onSelectSeq, loadReplayStep: loadReplayStep, catalog: catalog, onOpenRun: openRun }));
|
|
18
18
|
}
|
|
19
19
|
export function RunTreePane({ runId, threadId, onSelectThread, }) {
|
|
20
|
+
const { openRun } = useDebugger();
|
|
20
21
|
const store = useRunStore(runId);
|
|
21
22
|
const summary = useRunSummary(store);
|
|
22
23
|
const tree = useThreadTree(store);
|
|
23
24
|
const counts = useEventCounts(store);
|
|
24
|
-
return (_jsx(RunTree, { runId: runId, runStatus: summary.status, tree: tree, eventCounts: counts, selectedThread: threadId, onSelectThread: onSelectThread }));
|
|
25
|
+
return (_jsx(RunTree, { runId: runId, runStatus: summary.status, tree: tree, eventCounts: counts, selectedThread: threadId, onSelectThread: onSelectThread, launchedBy: summary.launchedBy, onOpenLauncher: openRun ? (source) => openRun(source.runId, { seq: source.causationSeq }) : undefined }));
|
|
25
26
|
}
|
package/dist/debugger/styles.css
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { Context, Layer } from 'effect';
|
|
2
|
+
import { type DefinitionStore } from '@swirls/looms/core';
|
|
2
3
|
import type { EvaluatorDefinition } from './definitions';
|
|
3
|
-
export
|
|
4
|
-
get(name: string): EvaluatorDefinition | undefined;
|
|
5
|
-
}
|
|
4
|
+
export type EvaluatorDefinitionStore = DefinitionStore<EvaluatorDefinition>;
|
|
6
5
|
declare const EvaluatorDefinitionsTag_base: Context.ServiceClass<EvaluatorDefinitionsTag, "looms/EvaluatorDefinitions", EvaluatorDefinitionStore>;
|
|
7
6
|
export declare class EvaluatorDefinitionsTag extends EvaluatorDefinitionsTag_base {
|
|
8
7
|
}
|
|
9
8
|
export declare function makeEvaluatorDefinitionStore(definitions: ReadonlyArray<EvaluatorDefinition>): EvaluatorDefinitionStore;
|
|
10
|
-
export declare const EvaluatorDefinitionsLive: (definitions:
|
|
9
|
+
export declare const EvaluatorDefinitionsLive: (definitions: EvaluatorDefinitionStore) => Layer.Layer<EvaluatorDefinitionsTag, never, never>;
|
|
11
10
|
export {};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Context, Layer } from 'effect';
|
|
2
|
+
import { makeDefinitionStore } from '@swirls/looms/core';
|
|
2
3
|
export class EvaluatorDefinitionsTag extends Context.Service()('looms/EvaluatorDefinitions') {
|
|
3
4
|
}
|
|
4
5
|
export function makeEvaluatorDefinitionStore(definitions) {
|
|
5
|
-
|
|
6
|
-
return { get: (name) => map.get(name) };
|
|
6
|
+
return makeDefinitionStore('evaluator', definitions);
|
|
7
7
|
}
|
|
8
|
-
export const EvaluatorDefinitionsLive = (definitions) => Layer.succeed(EvaluatorDefinitionsTag,
|
|
8
|
+
export const EvaluatorDefinitionsLive = (definitions) => Layer.succeed(EvaluatorDefinitionsTag, definitions);
|
|
@@ -5,6 +5,7 @@ import type { EvaluatorQuestions, EvaluatorRouteArgs, EvaluatorRouteDecision, Ev
|
|
|
5
5
|
export interface EvaluatorDefinition<TName extends string = string, TInput = JsonValue> {
|
|
6
6
|
readonly kind: 'evaluator';
|
|
7
7
|
readonly name: TName;
|
|
8
|
+
readonly version: string;
|
|
8
9
|
readonly description?: string;
|
|
9
10
|
/** Provider model id. Omit it to use the adapter default. */
|
|
10
11
|
readonly model?: string;
|
|
@@ -15,4 +16,6 @@ export interface EvaluatorDefinition<TName extends string = string, TInput = Jso
|
|
|
15
16
|
route?(this: void, args: EvaluatorRouteArgs): EvaluatorRouteDecision;
|
|
16
17
|
}
|
|
17
18
|
export type AnyEvaluatorDefinition = EvaluatorDefinition;
|
|
18
|
-
export declare function defineEvaluator<TName extends string, TInput = JsonValue>(def: Omit<EvaluatorDefinition<TName, TInput>, 'kind'>
|
|
19
|
+
export declare function defineEvaluator<TName extends string, TInput = JsonValue>(def: Omit<EvaluatorDefinition<TName, TInput>, 'kind' | 'version'> & {
|
|
20
|
+
readonly version?: string;
|
|
21
|
+
}): EvaluatorDefinition<TName, TInput>;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { defineKind } from '@swirls/looms/core';
|
|
1
|
+
import { DEFAULT_DEFINITION_VERSION, defineKind } from '@swirls/looms/core';
|
|
2
2
|
export function defineEvaluator(def) {
|
|
3
|
-
return defineKind('evaluator',
|
|
3
|
+
return defineKind('evaluator', {
|
|
4
|
+
...def,
|
|
5
|
+
version: def.version ?? DEFAULT_DEFINITION_VERSION,
|
|
6
|
+
});
|
|
4
7
|
}
|
|
@@ -4,8 +4,55 @@ import { EvaluatorTag } from './evaluator';
|
|
|
4
4
|
export declare const evaluateEffect: NoInfer<import("@swirls/looms/core").EffectDefinition<{
|
|
5
5
|
readonly evaluationId: string;
|
|
6
6
|
readonly definitionName?: string | undefined;
|
|
7
|
+
readonly definitionVersion?: string | undefined;
|
|
7
8
|
readonly input?: Schema.Json | undefined;
|
|
8
9
|
}, EvaluatorDefinitionsTag | EvaluatorTag, (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
10
|
+
readonly type: "evaluator.evaluated";
|
|
11
|
+
readonly payload: {
|
|
12
|
+
readonly evaluationId: string;
|
|
13
|
+
readonly definitionName?: string | undefined;
|
|
14
|
+
readonly answers: {
|
|
15
|
+
readonly [x: string]: {
|
|
16
|
+
readonly type: "boolean";
|
|
17
|
+
readonly value: boolean;
|
|
18
|
+
readonly probability: number;
|
|
19
|
+
} | {
|
|
20
|
+
readonly type: "choice";
|
|
21
|
+
readonly value: string;
|
|
22
|
+
} | {
|
|
23
|
+
readonly type: "score";
|
|
24
|
+
readonly value: number;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
readonly route: string;
|
|
28
|
+
readonly reason: "model" | "skipped" | "unavailable" | "uncertain";
|
|
29
|
+
readonly usage?: {
|
|
30
|
+
readonly input: number;
|
|
31
|
+
readonly output: number;
|
|
32
|
+
} | undefined;
|
|
33
|
+
};
|
|
34
|
+
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
35
|
+
readonly type: "evaluator.requested";
|
|
36
|
+
readonly payload: {
|
|
37
|
+
readonly evaluationId: string;
|
|
38
|
+
readonly definitionName?: string | undefined;
|
|
39
|
+
readonly state: string;
|
|
40
|
+
readonly model?: string | undefined;
|
|
41
|
+
};
|
|
42
|
+
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
43
|
+
readonly type: "runtime.child.close.requested";
|
|
44
|
+
readonly payload: {
|
|
45
|
+
readonly policy: "terminate" | "wait";
|
|
46
|
+
};
|
|
47
|
+
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
48
|
+
readonly type: "runtime.child.settled";
|
|
49
|
+
readonly payload: {
|
|
50
|
+
readonly runId: string;
|
|
51
|
+
readonly status: "cancelled" | "completed" | "failed";
|
|
52
|
+
readonly output: Schema.Json;
|
|
53
|
+
readonly error: string | null;
|
|
54
|
+
};
|
|
55
|
+
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
9
56
|
readonly type: "runtime.effect.ambiguous";
|
|
10
57
|
readonly payload: {
|
|
11
58
|
readonly effectId: string;
|
|
@@ -49,6 +96,8 @@ export declare const evaluateEffect: NoInfer<import("@swirls/looms/core").Effect
|
|
|
49
96
|
readonly payload: {
|
|
50
97
|
readonly effectId: string;
|
|
51
98
|
readonly error: string;
|
|
99
|
+
readonly nonRetryable?: boolean | undefined;
|
|
100
|
+
readonly retryAfterMs?: number | undefined;
|
|
52
101
|
};
|
|
53
102
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
54
103
|
readonly type: "runtime.effect.heartbeat";
|
|
@@ -57,6 +106,7 @@ export declare const evaluateEffect: NoInfer<import("@swirls/looms/core").Effect
|
|
|
57
106
|
readonly attempt: number;
|
|
58
107
|
readonly heartbeatAt: number;
|
|
59
108
|
readonly deadlineAt: number | null;
|
|
109
|
+
readonly details?: Schema.Json | undefined;
|
|
60
110
|
};
|
|
61
111
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
62
112
|
readonly type: "runtime.effect.queued";
|
|
@@ -109,6 +159,16 @@ export declare const evaluateEffect: NoInfer<import("@swirls/looms/core").Effect
|
|
|
109
159
|
readonly sourceRunId: string;
|
|
110
160
|
readonly sourceSeq: number;
|
|
111
161
|
};
|
|
162
|
+
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
163
|
+
readonly type: "runtime.run.launched";
|
|
164
|
+
readonly payload: {
|
|
165
|
+
readonly runId: string;
|
|
166
|
+
readonly kind: string;
|
|
167
|
+
readonly definitionName: string;
|
|
168
|
+
readonly definitionVersion: string;
|
|
169
|
+
readonly effectId: string;
|
|
170
|
+
readonly close: "terminate" | "wait";
|
|
171
|
+
};
|
|
112
172
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
113
173
|
readonly type: "runtime.run.started";
|
|
114
174
|
readonly payload: {
|
|
@@ -118,6 +178,20 @@ export declare const evaluateEffect: NoInfer<import("@swirls/looms/core").Effect
|
|
|
118
178
|
readonly definitionVersion: string;
|
|
119
179
|
readonly input: Schema.Json;
|
|
120
180
|
readonly requestedThreadId?: string | null | undefined;
|
|
181
|
+
readonly launchedBy?: {
|
|
182
|
+
readonly runId: string;
|
|
183
|
+
readonly threadId: string;
|
|
184
|
+
readonly effectId: string;
|
|
185
|
+
readonly causationId: string;
|
|
186
|
+
readonly causationSeq: number;
|
|
187
|
+
} | undefined;
|
|
188
|
+
readonly attributes?: {
|
|
189
|
+
readonly [x: string]: string;
|
|
190
|
+
} | undefined;
|
|
191
|
+
readonly trace?: {
|
|
192
|
+
readonly traceparent: string;
|
|
193
|
+
readonly tracestate?: string | undefined;
|
|
194
|
+
} | undefined;
|
|
121
195
|
};
|
|
122
196
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
123
197
|
readonly type: "runtime.signal.received";
|
|
@@ -202,37 +276,4 @@ export declare const evaluateEffect: NoInfer<import("@swirls/looms/core").Effect
|
|
|
202
276
|
readonly payload: Schema.Json;
|
|
203
277
|
};
|
|
204
278
|
};
|
|
205
|
-
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
206
|
-
readonly type: "evaluator.evaluated";
|
|
207
|
-
readonly payload: {
|
|
208
|
-
readonly evaluationId: string;
|
|
209
|
-
readonly definitionName?: string | undefined;
|
|
210
|
-
readonly answers: {
|
|
211
|
-
readonly [x: string]: {
|
|
212
|
-
readonly type: "boolean";
|
|
213
|
-
readonly value: boolean;
|
|
214
|
-
readonly probability: number;
|
|
215
|
-
} | {
|
|
216
|
-
readonly type: "choice";
|
|
217
|
-
readonly value: string;
|
|
218
|
-
} | {
|
|
219
|
-
readonly type: "score";
|
|
220
|
-
readonly value: number;
|
|
221
|
-
};
|
|
222
|
-
};
|
|
223
|
-
readonly route: string;
|
|
224
|
-
readonly reason: "model" | "skipped" | "unavailable" | "uncertain";
|
|
225
|
-
readonly usage?: {
|
|
226
|
-
readonly input: number;
|
|
227
|
-
readonly output: number;
|
|
228
|
-
} | undefined;
|
|
229
|
-
};
|
|
230
|
-
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
231
|
-
readonly type: "evaluator.requested";
|
|
232
|
-
readonly payload: {
|
|
233
|
-
readonly evaluationId: string;
|
|
234
|
-
readonly definitionName?: string | undefined;
|
|
235
|
-
readonly state: string;
|
|
236
|
-
readonly model?: string | undefined;
|
|
237
|
-
};
|
|
238
279
|
})>>;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Effect, Schema } from 'effect';
|
|
2
|
-
import { stringifyJson, validateInputEffect } from '@swirls/looms/core';
|
|
2
|
+
import { DEFAULT_DEFINITION_VERSION, stringifyJson, validateInputEffect, } from '@swirls/looms/core';
|
|
3
3
|
import { EvaluatorDefinitionsTag } from './definitions-store.js';
|
|
4
4
|
import { EvaluatorTag } from './evaluator.js';
|
|
5
5
|
import { evaluatorModule } from './scope.js';
|
|
6
6
|
const EvaluateInput = Schema.Struct({
|
|
7
7
|
evaluationId: Schema.String,
|
|
8
8
|
definitionName: Schema.optional(Schema.String),
|
|
9
|
+
definitionVersion: Schema.optional(Schema.String),
|
|
9
10
|
input: Schema.optional(Schema.Json),
|
|
10
11
|
});
|
|
11
12
|
function errorMessage(cause) {
|
|
@@ -36,7 +37,10 @@ export const evaluateEffect = evaluatorModule.effect({
|
|
|
36
37
|
const threadId = ctx.threadId;
|
|
37
38
|
const definitions = yield* EvaluatorDefinitionsTag;
|
|
38
39
|
const evaluator = yield* EvaluatorTag;
|
|
39
|
-
const
|
|
40
|
+
const version = input.definitionVersion ?? DEFAULT_DEFINITION_VERSION;
|
|
41
|
+
const definition = input.definitionName
|
|
42
|
+
? yield* definitions.resolve(input.definitionName, version)
|
|
43
|
+
: undefined;
|
|
40
44
|
if (!definition) {
|
|
41
45
|
const name = input.definitionName ?? 'unknown';
|
|
42
46
|
return failed(threadId, `Unknown evaluator definition for ${name}`);
|