@swirls/looms 0.0.2 → 0.2.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 +24 -2
- package/dist/actor/cell.d.ts +9 -4
- package/dist/actor/cell.js +7 -11
- package/dist/actor/host.d.ts +7 -3
- package/dist/actor/host.js +57 -33
- package/dist/actor/index.d.ts +1 -1
- package/dist/actor/index.js +1 -1
- package/dist/actor/routing.d.ts +12 -1
- package/dist/actor/routing.js +57 -51
- package/dist/agent/agent-session.d.ts +5 -0
- package/dist/agent/agent-session.js +270 -0
- package/dist/agent/debugger/agent-chat.d.ts +2 -0
- package/dist/agent/debugger/agent-chat.js +176 -0
- package/dist/agent/debugger/index.d.ts +5 -0
- package/dist/agent/debugger/index.js +19 -0
- package/dist/agent/debugger/summarize.d.ts +2 -0
- package/dist/agent/debugger/summarize.js +51 -0
- package/dist/agent/debugger/token-usage.d.ts +3 -0
- package/dist/agent/debugger/token-usage.js +11 -0
- package/dist/agent/definitions-store.d.ts +2 -3
- package/dist/agent/definitions-store.js +2 -4
- package/dist/agent/definitions.d.ts +47 -29
- package/dist/agent/definitions.js +39 -12
- package/dist/agent/effects.d.ts +359 -2
- package/dist/agent/effects.js +60 -34
- package/dist/agent/events.d.ts +175 -19
- package/dist/agent/events.js +45 -10
- package/dist/agent/index.d.ts +1 -0
- package/dist/agent/index.js +1 -0
- package/dist/agent/llm.d.ts +11 -2
- package/dist/agent/llm.js +13 -3
- package/dist/agent/module.d.ts +812 -78
- package/dist/agent/module.js +16 -4
- package/dist/agent/scope.d.ts +174 -18
- package/dist/agent/signals.d.ts +26 -1
- package/dist/agent/signals.js +79 -0
- package/dist/agent/threads.d.ts +3 -33
- package/dist/agent/threads.js +20 -25
- package/dist/agent/tool-schema.d.ts +1 -17
- package/dist/agent/tool-schema.js +3 -43
- package/dist/agent/types.d.ts +49 -4
- package/dist/agent/types.js +5 -5
- package/dist/ai-vercel/index.d.ts +1 -0
- package/dist/ai-vercel/index.js +1 -0
- package/dist/ai-vercel/messages.js +22 -7
- package/dist/ai-vercel/vercel-evaluator.d.ts +36 -0
- package/dist/ai-vercel/vercel-evaluator.js +73 -0
- package/dist/ai-vercel/vercel-llm.js +64 -44
- package/dist/approval/debugger/approvals-view.d.ts +3 -0
- package/dist/approval/debugger/approvals-view.js +16 -0
- package/dist/approval/debugger/index.d.ts +4 -0
- package/dist/approval/debugger/index.js +11 -0
- package/dist/approval/debugger/summarize.d.ts +2 -0
- package/dist/approval/debugger/summarize.js +17 -0
- package/dist/approval/effects.d.ts +89 -0
- package/dist/approval/module.d.ts +179 -29
- package/dist/approval/projections.d.ts +0 -14
- package/dist/approval/projections.js +20 -3
- package/dist/approval/signals.d.ts +2 -0
- package/dist/approval/signals.js +18 -2
- package/dist/cli/cli.js +2 -0
- package/dist/cli/commands.js +12 -16
- package/dist/client/client.d.ts +1213 -18
- package/dist/client/client.js +120 -120
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/sse.d.ts +13 -0
- package/dist/client/sse.js +38 -44
- package/dist/cloudflare/alarm-scheduler.d.ts +12 -2
- package/dist/cloudflare/alarm-scheduler.js +34 -7
- package/dist/cloudflare/durable-object.d.ts +10 -2
- package/dist/cloudflare/durable-object.js +59 -28
- package/dist/cloudflare/event-store.d.ts +7 -2
- package/dist/cloudflare/event-store.js +8 -7
- package/dist/cloudflare/index.d.ts +2 -2
- package/dist/cloudflare/index.js +2 -2
- package/dist/cloudflare/router.d.ts +1 -1
- package/dist/cloudflare/router.js +15 -16
- package/dist/core/catalog.d.ts +3 -3
- package/dist/core/catalog.js +2 -5
- package/dist/core/coalesce.js +5 -3
- package/dist/core/compose.d.ts +2 -1
- package/dist/core/compose.js +19 -2
- package/dist/core/debugger-host.d.ts +16 -0
- package/dist/core/debugger-host.js +1 -0
- package/dist/core/definition-store.d.ts +11 -0
- package/dist/core/definition-store.js +6 -0
- package/dist/core/effects.d.ts +127 -15
- package/dist/core/effects.js +89 -17
- package/dist/core/envelope.d.ts +27 -7
- package/dist/core/envelope.js +20 -6
- package/dist/core/event-codec.d.ts +4 -2
- package/dist/core/event-codec.js +10 -5
- package/dist/core/event-index.js +1 -3
- package/dist/core/fold.d.ts +3 -0
- package/dist/core/fold.js +171 -24
- package/dist/core/ids.d.ts +5 -0
- package/dist/core/ids.js +35 -2
- package/dist/core/index.d.ts +7 -1
- package/dist/core/index.js +6 -1
- package/dist/core/kind.d.ts +22 -0
- package/dist/core/kind.js +17 -0
- package/dist/core/limits.d.ts +34 -0
- package/dist/core/limits.js +46 -0
- package/dist/core/match.d.ts +1 -0
- package/dist/core/match.js +10 -1
- package/dist/core/module-scope.d.ts +22 -20
- package/dist/core/module-scope.js +38 -28
- package/dist/core/module.d.ts +18 -5
- package/dist/core/module.js +4 -0
- package/dist/core/projection.d.ts +13 -13
- package/dist/core/projection.js +9 -5
- package/dist/core/protocol.d.ts +68 -11
- package/dist/core/protocol.js +82 -11
- package/dist/core/published.d.ts +43 -0
- package/dist/core/published.js +44 -0
- package/dist/core/replay.d.ts +312 -3
- package/dist/core/replay.js +11 -1
- package/dist/core/schema.d.ts +11 -20
- package/dist/core/schema.js +63 -80
- package/dist/core/serialize.js +2 -4
- package/dist/core/snapshot-store.d.ts +6 -1
- package/dist/core/snapshot-store.js +15 -2
- package/dist/core/snapshots.d.ts +5 -1
- package/dist/core/snapshots.js +10 -15
- package/dist/core/sqlite-store.js +95 -11
- package/dist/core/state.d.ts +142 -4
- package/dist/core/state.js +78 -0
- package/dist/core/store.d.ts +38 -3
- package/dist/core/store.js +77 -22
- package/dist/core/thread.d.ts +10 -9
- package/dist/core/types.d.ts +5 -8
- package/dist/core/types.js +28 -24
- package/dist/core/validate-event.js +14 -4
- package/dist/core/worker-callback.d.ts +17 -0
- package/dist/core/worker-callback.js +1 -0
- package/dist/debugger/app/assets/index-B3Ah8WAE.css +2 -0
- package/dist/debugger/app/assets/index-Qb371t_O.js +22 -0
- package/dist/debugger/app/assets/rolldown-runtime-CbXtAM7H.js +1 -0
- package/dist/debugger/app/assets/routes-CjtEHgPQ.js +47 -0
- package/dist/debugger/app/index.html +14 -0
- package/dist/debugger/components/composer.d.ts +17 -0
- package/dist/debugger/components/composer.js +25 -0
- package/dist/debugger/components/debugger-split.d.ts +2 -1
- package/dist/debugger/components/debugger-split.js +2 -2
- package/dist/debugger/components/event-inspector.d.ts +2 -1
- package/dist/debugger/components/event-inspector.js +25 -16
- package/dist/debugger/components/event-stream.d.ts +2 -1
- package/dist/debugger/components/event-stream.js +14 -74
- package/dist/debugger/components/follow-list.d.ts +19 -0
- package/dist/debugger/components/follow-list.js +96 -0
- package/dist/debugger/components/json-tree.d.ts +11 -0
- package/dist/debugger/components/json-tree.js +120 -0
- package/dist/debugger/components/json-view.js +2 -2
- package/dist/debugger/components/run-tree.js +53 -20
- package/dist/debugger/components/status-dot.d.ts +4 -0
- package/dist/debugger/components/status-dot.js +6 -2
- package/dist/debugger/context.d.ts +14 -0
- package/dist/debugger/context.js +17 -0
- package/dist/debugger/contracts.d.ts +7 -4
- package/dist/debugger/events/builtin-families.d.ts +3 -0
- package/dist/debugger/events/builtin-families.js +9 -0
- package/dist/debugger/events/catalog.d.ts +3 -4
- package/dist/debugger/events/catalog.js +27 -17
- package/dist/debugger/events/protocol-summarize.d.ts +1 -2
- package/dist/debugger/events/protocol-summarize.js +42 -24
- package/dist/debugger/index.d.ts +20 -6
- package/dist/debugger/index.js +19 -5
- package/dist/debugger/lib/cn.d.ts +1 -0
- package/dist/debugger/lib/cn.js +3 -0
- package/dist/debugger/lib/event-meta.d.ts +2 -3
- package/dist/debugger/lib/event-meta.js +6 -12
- package/dist/debugger/lib/json.d.ts +25 -0
- package/dist/debugger/lib/json.js +87 -0
- package/dist/debugger/lib/payload.d.ts +7 -0
- package/dist/debugger/lib/payload.js +11 -0
- package/dist/debugger/lib/time.d.ts +3 -0
- package/dist/debugger/lib/time.js +24 -0
- package/dist/debugger/plugin.d.ts +36 -0
- package/dist/debugger/plugin.js +14 -0
- package/dist/debugger/server/index.d.ts +14 -0
- package/dist/debugger/server/index.js +114 -0
- package/dist/debugger/shell/debugger-shell.d.ts +15 -0
- package/dist/debugger/shell/debugger-shell.js +43 -0
- package/dist/debugger/shell/definition-key.d.ts +3 -0
- package/dist/debugger/shell/definition-key.js +4 -0
- package/dist/debugger/shell/events-pane.d.ts +12 -0
- package/dist/debugger/shell/events-pane.js +25 -0
- package/dist/debugger/shell/projections-panel.d.ts +4 -0
- package/dist/debugger/shell/projections-panel.js +59 -0
- package/dist/debugger/shell/run-controls.d.ts +4 -0
- package/dist/debugger/shell/run-controls.js +72 -0
- package/dist/debugger/shell/run-search.d.ts +6 -0
- package/dist/debugger/shell/run-search.js +102 -0
- package/dist/debugger/shell/run-type-menu.d.ts +6 -0
- package/dist/debugger/shell/run-type-menu.js +11 -0
- package/dist/debugger/shell/schema-form.d.ts +31 -0
- package/dist/debugger/shell/schema-form.js +117 -0
- package/dist/debugger/shell/start-form.d.ts +3 -0
- package/dist/debugger/shell/start-form.js +75 -0
- package/dist/debugger/shell/use-start-run.d.ts +14 -0
- package/dist/debugger/shell/use-start-run.js +32 -0
- package/dist/debugger/shell/workspace.d.ts +6 -0
- package/dist/debugger/shell/workspace.js +15 -0
- package/dist/debugger/styles.css +111 -27
- package/dist/debugger/ui/button.d.ts +24 -0
- package/dist/debugger/ui/button.js +24 -0
- package/dist/debugger/ui/command.d.ts +9 -0
- package/dist/debugger/ui/command.js +24 -0
- package/dist/debugger/ui/dropdown-menu.d.ts +13 -0
- package/dist/debugger/ui/dropdown-menu.js +37 -0
- package/dist/debugger/ui/panel.d.ts +14 -0
- package/dist/debugger/ui/panel.js +16 -0
- package/dist/debugger/ui/popover.d.ts +7 -0
- package/dist/debugger/ui/popover.js +17 -0
- package/dist/debugger/ui/resizable.d.ts +7 -0
- package/dist/debugger/ui/resizable.js +14 -0
- package/dist/debugger/ui/scroll-area.d.ts +2 -1
- package/dist/debugger/ui/scroll-area.js +5 -3
- package/dist/debugger/ui/select.d.ts +10 -0
- package/dist/debugger/ui/select.js +21 -0
- package/dist/debugger/ui/tabs.js +2 -2
- package/dist/debugger/ui/textarea.d.ts +3 -0
- package/dist/debugger/ui/textarea.js +7 -0
- package/dist/evaluator/definitions-store.d.ts +11 -0
- package/dist/evaluator/definitions-store.js +8 -0
- package/dist/evaluator/definitions.d.ts +18 -0
- package/dist/evaluator/definitions.js +4 -0
- package/dist/evaluator/effects.d.ts +226 -0
- package/dist/evaluator/effects.js +132 -0
- package/dist/evaluator/evaluator.d.ts +24 -0
- package/dist/evaluator/evaluator.js +67 -0
- package/dist/evaluator/events.d.ts +59 -0
- package/dist/evaluator/events.js +21 -0
- package/dist/evaluator/index.d.ts +11 -0
- package/dist/evaluator/index.js +11 -0
- package/dist/evaluator/module.d.ts +606 -0
- package/dist/evaluator/module.js +25 -0
- package/dist/evaluator/projections.d.ts +50 -0
- package/dist/evaluator/projections.js +20 -0
- package/dist/evaluator/scope.d.ts +59 -0
- package/dist/evaluator/scope.js +7 -0
- package/dist/evaluator/signals.d.ts +3 -0
- package/dist/evaluator/signals.js +17 -0
- package/dist/evaluator/threads.d.ts +62 -0
- package/dist/evaluator/threads.js +117 -0
- package/dist/evaluator/types.d.ts +125 -0
- package/dist/evaluator/types.js +51 -0
- package/dist/projectors/delivery.d.ts +83 -0
- package/dist/projectors/delivery.js +182 -0
- package/dist/projectors/index-model.d.ts +1 -1
- package/dist/projectors/index-model.js +4 -6
- package/dist/projectors/index.d.ts +2 -0
- package/dist/projectors/index.js +2 -0
- package/dist/projectors/memory.d.ts +1 -1
- package/dist/projectors/memory.js +10 -8
- package/dist/projectors/postgres.js +44 -58
- package/dist/projectors/projector.d.ts +17 -0
- package/dist/projectors/projector.js +26 -1
- package/dist/projectors/sqlite-delivery.d.ts +4 -0
- package/dist/projectors/sqlite-delivery.js +147 -0
- package/dist/projectors/sqlite.js +23 -23
- package/dist/projectors/with-projectors.d.ts +7 -2
- package/dist/projectors/with-projectors.js +27 -28
- package/dist/react/notify.js +11 -8
- package/dist/react/react.d.ts +2 -3
- package/dist/react/react.js +14 -30
- package/dist/react/sse.d.ts +1 -1
- package/dist/react/sse.js +1 -1
- package/dist/react/store.d.ts +3 -3
- package/dist/react/store.js +109 -119
- package/dist/runtime/cancellation.d.ts +16 -0
- package/dist/runtime/cancellation.js +129 -0
- package/dist/runtime/deadline-transition-planner.d.ts +31 -0
- package/dist/runtime/deadline-transition-planner.js +139 -0
- package/dist/runtime/dispatch-effect.d.ts +3 -2
- package/dist/runtime/dispatch-effect.js +7 -13
- package/dist/runtime/errors.d.ts +51 -0
- package/dist/runtime/errors.js +39 -0
- package/dist/runtime/{runtime-helpers.d.ts → helpers.d.ts} +24 -4
- package/dist/runtime/{runtime-helpers.js → helpers.js} +56 -19
- package/dist/runtime/index.d.ts +3 -3
- package/dist/runtime/index.js +3 -3
- package/dist/runtime/ingress.d.ts +15 -0
- package/dist/runtime/ingress.js +42 -0
- package/dist/runtime/local-effect-executor.d.ts +21 -0
- package/dist/runtime/local-effect-executor.js +137 -0
- package/dist/runtime/looms.d.ts +30 -4
- package/dist/runtime/looms.js +57 -37
- package/dist/runtime/observer.d.ts +45 -0
- package/dist/runtime/observer.js +11 -0
- package/dist/runtime/repository.d.ts +55 -0
- package/dist/runtime/repository.js +293 -0
- package/dist/runtime/retry-policy.d.ts +16 -0
- package/dist/runtime/retry-policy.js +29 -0
- package/dist/runtime/run-execution-context.d.ts +30 -0
- package/dist/runtime/run-execution-context.js +56 -0
- package/dist/runtime/run-start.d.ts +4 -0
- package/dist/runtime/run-start.js +44 -0
- package/dist/runtime/runtime.d.ts +6 -87
- package/dist/runtime/runtime.js +248 -470
- package/dist/runtime/server/auth.d.ts +41 -0
- package/dist/runtime/server/auth.js +45 -0
- package/dist/runtime/server/debugger-host.d.ts +11 -0
- package/dist/runtime/server/debugger-host.js +32 -0
- package/dist/runtime/server/fetch-handler.d.ts +18 -0
- package/dist/runtime/server/fetch-handler.js +62 -0
- package/dist/runtime/server/http.d.ts +38 -0
- package/dist/runtime/server/http.js +66 -0
- package/dist/runtime/server/route-table.d.ts +55 -0
- package/dist/runtime/server/route-table.js +74 -0
- package/dist/runtime/server/routes/definitions.d.ts +3 -0
- package/dist/runtime/server/routes/definitions.js +20 -0
- package/dist/runtime/server/routes/effects.d.ts +3 -0
- package/dist/runtime/server/routes/effects.js +59 -0
- package/dist/runtime/server/routes/operations.d.ts +3 -0
- package/dist/runtime/server/routes/operations.js +14 -0
- package/dist/runtime/server/routes/runs.d.ts +3 -0
- package/dist/runtime/server/routes/runs.js +199 -0
- package/dist/runtime/server.d.ts +4 -8
- package/dist/runtime/server.js +6 -211
- package/dist/runtime/sse.d.ts +2 -1
- package/dist/runtime/sse.js +24 -17
- package/dist/runtime/types.d.ts +117 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/wake-engine.d.ts +20 -0
- package/dist/runtime/wake-engine.js +311 -0
- package/dist/runtime/wake-scheduler.d.ts +3 -4
- package/dist/runtime/wake-scheduler.js +25 -31
- package/dist/runtime/worker-callbacks.d.ts +16 -0
- package/dist/runtime/worker-callbacks.js +167 -0
- package/dist/runtime/worker-effect-dispatch.d.ts +36 -0
- package/dist/runtime/worker-effect-dispatch.js +126 -0
- package/dist/s2/config.d.ts +1 -1
- package/dist/s2/config.js +1 -1
- package/dist/s2/lite.js +70 -82
- package/dist/s2/pagination.d.ts +15 -0
- package/dist/s2/pagination.js +36 -0
- package/dist/s2/projector.js +6 -5
- package/dist/s2/snapshot-store.js +188 -161
- package/dist/s2/store.d.ts +3 -21
- package/dist/s2/store.js +71 -165
- package/dist/testing/index.d.ts +15 -0
- package/dist/testing/index.js +53 -16
- package/dist/workflow/debugger/index.d.ts +4 -0
- package/dist/workflow/debugger/index.js +11 -0
- package/dist/workflow/debugger/nodes-view.d.ts +3 -0
- package/dist/workflow/debugger/nodes-view.js +13 -0
- package/dist/workflow/debugger/summarize.d.ts +2 -0
- package/dist/workflow/debugger/summarize.js +30 -0
- package/dist/workflow/definitions-store.d.ts +2 -3
- package/dist/workflow/definitions-store.js +2 -2
- package/dist/workflow/definitions.d.ts +78 -22
- package/dist/workflow/definitions.js +80 -14
- package/dist/workflow/effects.d.ts +453 -107
- package/dist/workflow/effects.js +214 -115
- package/dist/workflow/events.d.ts +149 -5
- package/dist/workflow/events.js +27 -5
- package/dist/workflow/graph.d.ts +56 -0
- package/dist/workflow/graph.js +207 -0
- package/dist/workflow/index.d.ts +1 -0
- package/dist/workflow/index.js +1 -0
- package/dist/workflow/module.d.ts +1047 -266
- package/dist/workflow/projections.d.ts +14 -12
- package/dist/workflow/projections.js +30 -8
- package/dist/workflow/scope.d.ts +146 -4
- package/dist/workflow/threads.d.ts +383 -155
- package/dist/workflow/threads.js +308 -110
- package/package.json +26 -2
- package/dist/debugger/events/domain-summarize.d.ts +0 -3
- package/dist/debugger/events/domain-summarize.js +0 -107
- package/dist/debugger/events/family.d.ts +0 -8
- package/dist/debugger/events/family.js +0 -44
- package/dist/runtime/events-api.d.ts +0 -4
- package/dist/runtime/events-api.js +0 -84
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { Predicate } from 'effect';
|
|
2
|
+
import { cancel, createWaitId, deterministicThreadId, emit, spawn, wait, } from '@swirls/looms/core';
|
|
3
|
+
import { agentModule } from './scope.js';
|
|
4
|
+
function objectPayload(event) {
|
|
5
|
+
return Predicate.isObject(event.payload) ? event.payload : {};
|
|
6
|
+
}
|
|
7
|
+
function messageFrom(value) {
|
|
8
|
+
const payload = Predicate.isObject(value) ? value : {};
|
|
9
|
+
return Predicate.isString(payload.messageId) && Predicate.isString(payload.text)
|
|
10
|
+
? {
|
|
11
|
+
messageId: payload.messageId,
|
|
12
|
+
text: payload.text,
|
|
13
|
+
delivery: payload.delivery === 'steer' ||
|
|
14
|
+
payload.delivery === 'followUp' ||
|
|
15
|
+
payload.delivery === 'nextTurn'
|
|
16
|
+
? payload.delivery
|
|
17
|
+
: undefined,
|
|
18
|
+
}
|
|
19
|
+
: null;
|
|
20
|
+
}
|
|
21
|
+
function consumedIds(event) {
|
|
22
|
+
const payload = objectPayload(event);
|
|
23
|
+
const embedded = Predicate.isObject(payload.event) ? payload.event : {};
|
|
24
|
+
const embeddedPayload = Predicate.isObject(embedded.payload) ? embedded.payload : {};
|
|
25
|
+
const output = Predicate.isObject(embeddedPayload.output) ? embeddedPayload.output : {};
|
|
26
|
+
const ids = output.consumedSteerMessageIds;
|
|
27
|
+
return Array.isArray(ids) ? ids.filter(Predicate.isString) : [];
|
|
28
|
+
}
|
|
29
|
+
function closureStatus(event) {
|
|
30
|
+
const payload = objectPayload(event);
|
|
31
|
+
const embedded = Predicate.isObject(payload.event) ? payload.event : {};
|
|
32
|
+
const embeddedPayload = Predicate.isObject(embedded.payload) ? embedded.payload : {};
|
|
33
|
+
const status = embedded.type === 'runtime.thread.completed'
|
|
34
|
+
? 'completed'
|
|
35
|
+
: embedded.type === 'runtime.thread.cancelled'
|
|
36
|
+
? 'cancelled'
|
|
37
|
+
: 'failed';
|
|
38
|
+
const error = Predicate.isString(embeddedPayload.error) ? embeddedPayload.error : undefined;
|
|
39
|
+
return { status, error };
|
|
40
|
+
}
|
|
41
|
+
function close(messageId, status, error) {
|
|
42
|
+
return error === undefined ? { messageId, status } : { messageId, status, error };
|
|
43
|
+
}
|
|
44
|
+
export function createAgentSessionThread(definitions) {
|
|
45
|
+
return agentModule.thread({
|
|
46
|
+
kind: 'agent-session',
|
|
47
|
+
initialState: (ctx) => {
|
|
48
|
+
const definition = definitions.get(ctx.definitionName, ctx.definitionVersion);
|
|
49
|
+
return {
|
|
50
|
+
definitionName: ctx.definitionName,
|
|
51
|
+
definitionVersion: ctx.definitionVersion,
|
|
52
|
+
pendingMessages: [],
|
|
53
|
+
nextTurnMessages: [],
|
|
54
|
+
processedMessageIds: [],
|
|
55
|
+
activeTurn: null,
|
|
56
|
+
pendingSteerDeliveries: [],
|
|
57
|
+
pendingClosures: [],
|
|
58
|
+
lastSequence: 0,
|
|
59
|
+
idleTimeoutMs: definition?.idleTimeoutMs ?? 0,
|
|
60
|
+
idleDeadlineAt: null,
|
|
61
|
+
parked: false,
|
|
62
|
+
cancelling: false,
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
step(state, event) {
|
|
66
|
+
switch (event.type) {
|
|
67
|
+
case 'runtime.thread.started': {
|
|
68
|
+
const initial = messageFrom(objectPayload(event).input);
|
|
69
|
+
const idleDeadlineAt = state.idleTimeoutMs > 0 ? event.ts + state.idleTimeoutMs : null;
|
|
70
|
+
if (!initial || state.processedMessageIds.includes(initial.messageId)) {
|
|
71
|
+
return { ...state, idleDeadlineAt };
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
...state,
|
|
75
|
+
pendingMessages: [initial],
|
|
76
|
+
processedMessageIds: [initial.messageId],
|
|
77
|
+
idleDeadlineAt,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
case 'agent.session.message.submitted': {
|
|
81
|
+
const payload = objectPayload(event);
|
|
82
|
+
const message = messageFrom(payload);
|
|
83
|
+
if (!message || state.processedMessageIds.includes(message.messageId)) {
|
|
84
|
+
return state;
|
|
85
|
+
}
|
|
86
|
+
const processedMessageIds = [...state.processedMessageIds, message.messageId];
|
|
87
|
+
const idleDeadlineAt = state.idleTimeoutMs > 0 ? event.ts + state.idleTimeoutMs : null;
|
|
88
|
+
if (message.delivery === 'nextTurn') {
|
|
89
|
+
return {
|
|
90
|
+
...state,
|
|
91
|
+
nextTurnMessages: [...state.nextTurnMessages, message],
|
|
92
|
+
processedMessageIds,
|
|
93
|
+
idleDeadlineAt,
|
|
94
|
+
parked: false,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const queued = message.delivery === 'steer' && state.activeTurn
|
|
98
|
+
? { ...message, steeredIntoMessageId: state.activeTurn.messageId }
|
|
99
|
+
: message;
|
|
100
|
+
return {
|
|
101
|
+
...state,
|
|
102
|
+
pendingMessages: [...state.pendingMessages, queued],
|
|
103
|
+
pendingSteerDeliveries: queued.steeredIntoMessageId &&
|
|
104
|
+
state.activeTurn &&
|
|
105
|
+
payload.activeChildThreadId !== state.activeTurn.childThreadId
|
|
106
|
+
? [...state.pendingSteerDeliveries, queued]
|
|
107
|
+
: state.pendingSteerDeliveries,
|
|
108
|
+
processedMessageIds,
|
|
109
|
+
idleDeadlineAt,
|
|
110
|
+
parked: false,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
case 'agent.session.turn.started': {
|
|
114
|
+
const messageId = event.payload.messageId;
|
|
115
|
+
const admitted = state.pendingMessages.find((message) => message.messageId === messageId);
|
|
116
|
+
const text = [...state.nextTurnMessages, ...(admitted ? [admitted] : [])]
|
|
117
|
+
.map((message) => message.text)
|
|
118
|
+
.join('\n');
|
|
119
|
+
return {
|
|
120
|
+
...state,
|
|
121
|
+
pendingMessages: state.pendingMessages.filter((message) => message.messageId !== messageId),
|
|
122
|
+
activeTurn: {
|
|
123
|
+
messageId,
|
|
124
|
+
childThreadId: event.payload.childThreadId,
|
|
125
|
+
text,
|
|
126
|
+
},
|
|
127
|
+
nextTurnMessages: [],
|
|
128
|
+
lastSequence: state.lastSequence + 1,
|
|
129
|
+
cancelling: false,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
case 'agent.session.steer.delivered':
|
|
133
|
+
return {
|
|
134
|
+
...state,
|
|
135
|
+
pendingSteerDeliveries: state.pendingSteerDeliveries.filter((message) => message.messageId !== event.payload.messageId),
|
|
136
|
+
};
|
|
137
|
+
case 'agent.session.turn.closed':
|
|
138
|
+
return {
|
|
139
|
+
...state,
|
|
140
|
+
pendingClosures: state.pendingClosures.filter((closure) => closure.messageId !== event.payload.messageId),
|
|
141
|
+
};
|
|
142
|
+
case 'agent.session.cancel.requested':
|
|
143
|
+
case 'runtime.thread.cancel.requested':
|
|
144
|
+
return state.activeTurn ? { ...state, cancelling: true } : state;
|
|
145
|
+
case 'runtime.wait.satisfied': {
|
|
146
|
+
const payload = objectPayload(event);
|
|
147
|
+
const tag = Predicate.isObject(payload.tag) ? payload.tag : {};
|
|
148
|
+
if (tag.kind === 'agent-session-idle') {
|
|
149
|
+
if (tag.deadlineAt === state.idleDeadlineAt && state.activeTurn === null) {
|
|
150
|
+
return { ...state, parked: true, idleDeadlineAt: null };
|
|
151
|
+
}
|
|
152
|
+
return state;
|
|
153
|
+
}
|
|
154
|
+
if (tag.kind !== 'agent-session-turn' || !state.activeTurn) {
|
|
155
|
+
return state;
|
|
156
|
+
}
|
|
157
|
+
const active = state.activeTurn;
|
|
158
|
+
const consumed = new Set(consumedIds(event));
|
|
159
|
+
const result = closureStatus(event);
|
|
160
|
+
const pendingClosures = [
|
|
161
|
+
...state.pendingClosures,
|
|
162
|
+
close(active.messageId, result.status, result.error),
|
|
163
|
+
...[...consumed].map((messageId) => close(messageId, result.status, result.error)),
|
|
164
|
+
];
|
|
165
|
+
return {
|
|
166
|
+
...state,
|
|
167
|
+
pendingMessages: state.pendingMessages.flatMap((message) => {
|
|
168
|
+
if (consumed.has(message.messageId)) {
|
|
169
|
+
return [];
|
|
170
|
+
}
|
|
171
|
+
return message.steeredIntoMessageId === active.messageId
|
|
172
|
+
? [{ ...message, steeredIntoMessageId: undefined }]
|
|
173
|
+
: [message];
|
|
174
|
+
}),
|
|
175
|
+
pendingSteerDeliveries: state.pendingSteerDeliveries.filter((message) => !consumed.has(message.messageId) &&
|
|
176
|
+
message.steeredIntoMessageId !== active.messageId),
|
|
177
|
+
pendingClosures,
|
|
178
|
+
activeTurn: null,
|
|
179
|
+
lastSequence: state.lastSequence + 1,
|
|
180
|
+
cancelling: false,
|
|
181
|
+
idleDeadlineAt: state.idleTimeoutMs > 0 ? event.ts + state.idleTimeoutMs : null,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
default:
|
|
185
|
+
return state;
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
effects(state, ctx) {
|
|
189
|
+
const effects = [];
|
|
190
|
+
for (const closure of state.pendingClosures) {
|
|
191
|
+
effects.push(emit(agentModule.input('session.turn.closed', { messageId: closure.messageId, status: closure.status, error: closure.error }, { threadId: ctx.threadId }), `session_close_${closure.messageId}`));
|
|
192
|
+
}
|
|
193
|
+
for (const message of state.pendingSteerDeliveries) {
|
|
194
|
+
if (!state.activeTurn || message.steeredIntoMessageId !== state.activeTurn.messageId) {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
effects.push(emit(agentModule.input('steered', {
|
|
198
|
+
turn: 0,
|
|
199
|
+
messageId: message.messageId,
|
|
200
|
+
message: { role: 'user', content: message.text },
|
|
201
|
+
interrupt: true,
|
|
202
|
+
}, { threadId: state.activeTurn.childThreadId }), `session_steer_${message.messageId}`), emit(agentModule.input('session.steer.delivered', { messageId: message.messageId, activeMessageId: state.activeTurn.messageId }, { threadId: ctx.threadId }), `session_steer_delivered_${message.messageId}`));
|
|
203
|
+
}
|
|
204
|
+
if (state.activeTurn) {
|
|
205
|
+
const { childThreadId: turnThreadId, messageId, text } = state.activeTurn;
|
|
206
|
+
const definition = definitions.get(state.definitionName, state.definitionVersion);
|
|
207
|
+
if (state.cancelling) {
|
|
208
|
+
effects.push(cancel(turnThreadId));
|
|
209
|
+
}
|
|
210
|
+
else if (definition) {
|
|
211
|
+
effects.push(spawn({
|
|
212
|
+
childThreadId: turnThreadId,
|
|
213
|
+
kind: 'agent',
|
|
214
|
+
definitionName: definition.agent.name,
|
|
215
|
+
definitionVersion: definition.agent.version,
|
|
216
|
+
input: { text },
|
|
217
|
+
}));
|
|
218
|
+
}
|
|
219
|
+
// The turn wait must survive cancellation: the child's cancelled event is what closes it.
|
|
220
|
+
effects.push(wait({
|
|
221
|
+
waitId: createWaitId(ctx.threadId, `turn_${messageId}`),
|
|
222
|
+
on: {
|
|
223
|
+
type: [
|
|
224
|
+
'runtime.thread.completed',
|
|
225
|
+
'runtime.thread.failed',
|
|
226
|
+
'runtime.thread.cancelled',
|
|
227
|
+
],
|
|
228
|
+
match: { threadId: turnThreadId },
|
|
229
|
+
},
|
|
230
|
+
tag: { kind: 'agent-session-turn', messageId },
|
|
231
|
+
}));
|
|
232
|
+
return effects;
|
|
233
|
+
}
|
|
234
|
+
const next = state.pendingMessages.find((message) => message.steeredIntoMessageId === undefined);
|
|
235
|
+
if (next) {
|
|
236
|
+
effects.push(emit(agentModule.input('session.turn.started', {
|
|
237
|
+
messageId: next.messageId,
|
|
238
|
+
childThreadId: deterministicThreadId(ctx.threadId, 'turn', next.messageId),
|
|
239
|
+
}, { threadId: ctx.threadId }), `session_admit_${next.messageId}`));
|
|
240
|
+
return effects;
|
|
241
|
+
}
|
|
242
|
+
if (state.parked || state.idleTimeoutMs === 0 || state.idleDeadlineAt === null) {
|
|
243
|
+
effects.push(wait({
|
|
244
|
+
waitId: createWaitId(ctx.threadId, 'mailbox'),
|
|
245
|
+
on: { type: 'agent.session.message.submitted', match: { threadId: ctx.threadId } },
|
|
246
|
+
tag: { kind: 'agent-session-mailbox' },
|
|
247
|
+
}));
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
effects.push(wait({
|
|
251
|
+
waitId: createWaitId(ctx.threadId, `idle_${state.idleDeadlineAt}`),
|
|
252
|
+
on: { timerAt: state.idleDeadlineAt },
|
|
253
|
+
tag: { kind: 'agent-session-idle', deadlineAt: state.idleDeadlineAt },
|
|
254
|
+
}));
|
|
255
|
+
}
|
|
256
|
+
return effects;
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
export function agentSessionSnapshot(state) {
|
|
261
|
+
return {
|
|
262
|
+
activeTurnId: state.activeTurn?.messageId ?? null,
|
|
263
|
+
activeChildThreadId: state.activeTurn?.childThreadId ?? null,
|
|
264
|
+
pendingMessageCount: state.pendingMessages.length,
|
|
265
|
+
nextTurnHeldCount: state.nextTurnMessages.length,
|
|
266
|
+
processedMessageIds: state.processedMessageIds,
|
|
267
|
+
lastSequence: state.lastSequence,
|
|
268
|
+
parked: state.parked,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Bot, CornerDownRight, MessageSquare, Settings2, User, Wrench } from 'lucide-react';
|
|
3
|
+
import { useMemo, useState } from 'react';
|
|
4
|
+
import { createEventId, isJsonObject, isJsonString } from '@swirls/looms/core';
|
|
5
|
+
import { cn, Composer, EmptyState, errorMessage, FollowList, inputForm, JsonTree, messageInput, parseStructuredJson, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, shortId, useDebugger, useStartRun, } from '@swirls/looms/debugger';
|
|
6
|
+
import { createFold, useEventFold, useProjection, useRunStore, useRunSummary } from '@swirls/looms/react';
|
|
7
|
+
import { conversation } from '../projections.js';
|
|
8
|
+
import { agentSessionMessageEvents, userMessage } from '../signals.js';
|
|
9
|
+
/** Child thread of the session turn that is still open, from the events the store already has. */
|
|
10
|
+
function activeSessionChild(events) {
|
|
11
|
+
let child;
|
|
12
|
+
for (const event of events) {
|
|
13
|
+
if (!isJsonObject(event.payload)) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (event.type === 'agent.session.turn.started' && isJsonString(event.payload.childThreadId)) {
|
|
17
|
+
child = event.payload.childThreadId;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const tag = event.payload.tag;
|
|
21
|
+
if (event.type === 'runtime.wait.satisfied' &&
|
|
22
|
+
isJsonObject(tag) &&
|
|
23
|
+
tag.kind === 'agent-session-turn') {
|
|
24
|
+
child = undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return child;
|
|
28
|
+
}
|
|
29
|
+
const streamingFold = createFold({
|
|
30
|
+
name: 'agentStreamingText',
|
|
31
|
+
initialState: { lastMessageSeq: -1, turnStarted: false, parts: [] },
|
|
32
|
+
includeEphemeral: true,
|
|
33
|
+
reduce(state, event) {
|
|
34
|
+
if (event.type === 'agent.message') {
|
|
35
|
+
return { lastMessageSeq: event.seq, turnStarted: false, parts: [] };
|
|
36
|
+
}
|
|
37
|
+
if (event.seq <= state.lastMessageSeq) {
|
|
38
|
+
return state;
|
|
39
|
+
}
|
|
40
|
+
if (event.type === 'agent.turn.started') {
|
|
41
|
+
return { ...state, turnStarted: true };
|
|
42
|
+
}
|
|
43
|
+
if (event.type === 'agent.turn.text_delta' &&
|
|
44
|
+
isJsonObject(event.payload) &&
|
|
45
|
+
isJsonString(event.payload.delta)) {
|
|
46
|
+
return {
|
|
47
|
+
...state,
|
|
48
|
+
turnStarted: true,
|
|
49
|
+
parts: state.parts.concat(event.payload.delta),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return state;
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
const deliveryOptions = [
|
|
56
|
+
{ value: 'followUp', label: 'Follow up', description: 'Queue after the current turn' },
|
|
57
|
+
{ value: 'steer', label: 'Steer', description: 'Redirect the active turn' },
|
|
58
|
+
{ value: 'nextTurn', label: 'Next turn', description: 'Hold until the next turn starts' },
|
|
59
|
+
];
|
|
60
|
+
function RoleLabel({ icon, children }) {
|
|
61
|
+
return (_jsxs("div", { className: "text-muted-foreground mb-1.5 flex items-center gap-1.5 text-[11px] font-medium [&_svg]:size-3", children: [icon, children] }));
|
|
62
|
+
}
|
|
63
|
+
function MessageText({ content, className }) {
|
|
64
|
+
const structured = useMemo(() => parseStructuredJson(content), [content]);
|
|
65
|
+
if (structured !== undefined) {
|
|
66
|
+
return _jsx(JsonTree, { value: structured, defaultExpandDepth: 2 });
|
|
67
|
+
}
|
|
68
|
+
return (_jsx("div", { className: cn('text-[13px] leading-relaxed break-words whitespace-pre-wrap', className), children: content }));
|
|
69
|
+
}
|
|
70
|
+
function ToolCard({ icon, name, meta, children, }) {
|
|
71
|
+
return (_jsxs("div", { className: "border-border bg-card/60 overflow-hidden rounded-lg border", children: [_jsxs("div", { className: "border-border/70 flex h-7 items-center gap-1.5 border-b px-2.5 text-[11px] [&_svg]:size-3", children: [_jsx("span", { className: "text-muted-foreground", children: icon }), _jsx("span", { className: "font-mono font-medium", children: name }), meta ? (_jsx("span", { className: "text-muted-foreground ml-auto truncate font-mono text-[10px]", children: meta })) : null] }), _jsx("div", { className: "px-2.5 py-1.5", children: children })] }));
|
|
72
|
+
}
|
|
73
|
+
function ToolCallCard({ call }) {
|
|
74
|
+
return (_jsx(ToolCard, { icon: _jsx(Wrench, {}), name: call.name, meta: shortId(call.id), children: _jsx(JsonTree, { value: call.arguments, defaultExpandDepth: 2 }) }));
|
|
75
|
+
}
|
|
76
|
+
function MessageItem({ line, toolName }) {
|
|
77
|
+
switch (line.role) {
|
|
78
|
+
case 'user':
|
|
79
|
+
return (_jsxs(_Fragment, { children: [_jsx(RoleLabel, { icon: _jsx(User, {}), children: "User" }), _jsx("div", { className: "bg-secondary w-fit max-w-full rounded-lg px-3 py-2", children: _jsx(MessageText, { content: line.content }) })] }));
|
|
80
|
+
case 'assistant':
|
|
81
|
+
return (_jsxs(_Fragment, { children: [_jsx(RoleLabel, { icon: _jsx(Bot, {}), children: "Assistant" }), _jsxs("div", { className: "grid gap-2", children: [line.content ? _jsx(MessageText, { content: line.content }) : null, line.toolCalls?.map((call) => (_jsx(ToolCallCard, { call: call }, call.id)))] })] }));
|
|
82
|
+
case 'tool':
|
|
83
|
+
return (_jsx(ToolCard, { icon: _jsx(CornerDownRight, {}), name: `${line.name ?? toolName ?? 'tool'} result`, meta: line.toolCallId ? shortId(line.toolCallId) : undefined, children: _jsx(MessageText, { content: line.content }) }));
|
|
84
|
+
case 'system':
|
|
85
|
+
return (_jsxs(_Fragment, { children: [_jsx(RoleLabel, { icon: _jsx(Settings2, {}), children: "System" }), _jsx(MessageText, { content: line.content, className: "text-muted-foreground" })] }));
|
|
86
|
+
default: {
|
|
87
|
+
const exhaustive = line.role;
|
|
88
|
+
return exhaustive;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function StreamingItem({ text }) {
|
|
93
|
+
return (_jsxs(_Fragment, { children: [_jsx(RoleLabel, { icon: _jsx(Bot, {}), children: "Assistant" }), _jsxs("div", { className: "text-[13px] leading-relaxed break-words whitespace-pre-wrap", children: [text, _jsx("span", { "aria-label": "Generating", className: "bg-foreground/70 ml-0.5 inline-block h-3.5 w-1.5 animate-pulse rounded-[1px] align-[-2px]" })] })] }));
|
|
94
|
+
}
|
|
95
|
+
function Transcript({ runId }) {
|
|
96
|
+
const store = useRunStore(runId);
|
|
97
|
+
const convo = useProjection(store, conversation);
|
|
98
|
+
const streaming = useEventFold(store, streamingFold);
|
|
99
|
+
const stream = streaming.turnStarted ? streaming.parts.join('') : null;
|
|
100
|
+
const toolNames = useMemo(() => {
|
|
101
|
+
const names = new Map();
|
|
102
|
+
for (const line of convo.lines) {
|
|
103
|
+
for (const call of line.toolCalls ?? []) {
|
|
104
|
+
names.set(call.id, call.name);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return names;
|
|
108
|
+
}, [convo.lines]);
|
|
109
|
+
const items = useMemo(() => {
|
|
110
|
+
const lines = convo.lines.map((line, index) => ({
|
|
111
|
+
kind: 'line',
|
|
112
|
+
line,
|
|
113
|
+
index,
|
|
114
|
+
}));
|
|
115
|
+
return stream === null ? lines : [...lines, { kind: 'stream', text: stream }];
|
|
116
|
+
}, [convo.lines, stream]);
|
|
117
|
+
return (_jsx(FollowList, { items: items, estimateSize: 96, overscan: 4, paddingStart: 8, paddingEnd: 12, getKey: (item) => (item.kind === 'stream' ? 'stream' : item.index), empty: _jsx("p", { className: "text-muted-foreground p-6 text-center text-xs", children: "Waiting for messages\u2026" }), renderItem: (item) => (_jsx("div", { className: "px-4 py-2", children: item.kind === 'stream' ? (_jsx(StreamingItem, { text: item.text })) : (_jsx(MessageItem, { line: item.line, toolName: item.line.toolCallId ? toolNames.get(item.line.toolCallId) : undefined })) })) }));
|
|
118
|
+
}
|
|
119
|
+
function DeliverySelect({ value, onChange, }) {
|
|
120
|
+
return (_jsxs(Select, { value: value, onValueChange: (next) => {
|
|
121
|
+
const option = deliveryOptions.find((candidate) => candidate.value === next);
|
|
122
|
+
if (option) {
|
|
123
|
+
onChange(option.value);
|
|
124
|
+
}
|
|
125
|
+
}, children: [_jsx(SelectTrigger, { "aria-label": "Delivery", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { align: "start", className: "w-60", children: deliveryOptions.map((option) => (_jsx(SelectItem, { value: option.value, description: option.description, children: option.label }, option.value))) })] }));
|
|
126
|
+
}
|
|
127
|
+
export function AgentChat(context) {
|
|
128
|
+
const { definition, runId } = context;
|
|
129
|
+
const { client } = useDebugger();
|
|
130
|
+
const [draft, setDraft] = useState('');
|
|
131
|
+
const [delivery, setDelivery] = useState('followUp');
|
|
132
|
+
const { start, pending, error } = useStartRun(context);
|
|
133
|
+
const session = definition.kind === 'agent-session';
|
|
134
|
+
const form = inputForm(definition.inputSchema);
|
|
135
|
+
function send() {
|
|
136
|
+
const content = draft.trim();
|
|
137
|
+
const input = session ? null : messageInput(form, content);
|
|
138
|
+
if (!content || input === undefined) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
setDraft('');
|
|
142
|
+
start(input, session
|
|
143
|
+
? (started) => client.signal(started.runId, agentSessionMessageEvents(createEventId(), content, { threadId: started.threadId }))
|
|
144
|
+
: undefined);
|
|
145
|
+
}
|
|
146
|
+
return (_jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [runId ? (_jsx(Transcript, { runId: runId })) : (_jsx("div", { className: "min-h-0 flex-1", children: _jsx(EmptyState, { icon: _jsx(MessageSquare, {}), title: `Talk to ${definition.name}`, children: "Your first message starts a new run." }) })), runId ? (_jsx(FollowUp, { runId: runId, session: session, delivery: delivery, setDelivery: setDelivery, startError: error })) : (_jsx(Composer, { value: draft, onChange: setDraft, onSubmit: send, pending: pending, placeholder: `Message ${definition.name}…`, submitLabel: "Start", error: error }))] }));
|
|
147
|
+
}
|
|
148
|
+
function FollowUp({ runId, session, delivery, setDelivery, startError, }) {
|
|
149
|
+
const store = useRunStore(runId);
|
|
150
|
+
const { rootThreadId } = useRunSummary(store);
|
|
151
|
+
const [draft, setDraft] = useState('');
|
|
152
|
+
const [pending, setPending] = useState(false);
|
|
153
|
+
const [error, setError] = useState(null);
|
|
154
|
+
function send() {
|
|
155
|
+
const content = draft.trim();
|
|
156
|
+
if (!content || !rootThreadId) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
setPending(true);
|
|
160
|
+
setError(null);
|
|
161
|
+
const events = session
|
|
162
|
+
? agentSessionMessageEvents(createEventId(), content, {
|
|
163
|
+
delivery,
|
|
164
|
+
threadId: rootThreadId,
|
|
165
|
+
activeChildThreadId: delivery === 'steer' ? activeSessionChild(store.events()) : undefined,
|
|
166
|
+
})
|
|
167
|
+
: [userMessage(content, { threadId: rootThreadId })];
|
|
168
|
+
const [only] = events;
|
|
169
|
+
const commit = events.length === 1 && only ? store.commit(only) : store.commit(events);
|
|
170
|
+
commit
|
|
171
|
+
.then(() => setDraft(''))
|
|
172
|
+
.catch((cause) => setError(errorMessage(cause)))
|
|
173
|
+
.finally(() => setPending(false));
|
|
174
|
+
}
|
|
175
|
+
return (_jsx(Composer, { value: draft, onChange: setDraft, onSubmit: send, pending: pending, disabled: !rootThreadId, placeholder: "Send a follow-up\u2026", error: error ?? startError, toolbar: session ? _jsx(DeliverySelect, { value: delivery, onChange: setDelivery }) : null }));
|
|
176
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { inputForm, messageInput } from '@swirls/looms/debugger';
|
|
2
|
+
import { tokenUsage } from '../projections.js';
|
|
3
|
+
import { AgentChat } from './agent-chat.js';
|
|
4
|
+
import { summarizeAgentEvent } from './summarize.js';
|
|
5
|
+
import { TokenUsageView } from './token-usage.js';
|
|
6
|
+
function isChat(definition) {
|
|
7
|
+
return messageInput(inputForm(definition.inputSchema), '') !== undefined;
|
|
8
|
+
}
|
|
9
|
+
export const agentDebugger = {
|
|
10
|
+
name: 'agent',
|
|
11
|
+
families: [{ family: 'agent', color: 'oklch(0.74 0.12 240)', summarize: summarizeAgentEvent }],
|
|
12
|
+
workspace: {
|
|
13
|
+
kinds: ['agent', 'agent-session'],
|
|
14
|
+
matches: (definition) => definition.kind === 'agent-session' || isChat(definition),
|
|
15
|
+
component: AgentChat,
|
|
16
|
+
},
|
|
17
|
+
projections: [{ name: tokenUsage.name, component: TokenUsageView }],
|
|
18
|
+
};
|
|
19
|
+
export { AgentChat, TokenUsageView };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { isJsonObject, isJsonString } from '@swirls/looms/core';
|
|
2
|
+
import { compactJson, jsonFields, jsonNumberText, jsonText, } from '@swirls/looms/debugger';
|
|
3
|
+
function messageContent(payload) {
|
|
4
|
+
const message = jsonFields(payload).message;
|
|
5
|
+
return isJsonObject(message) && isJsonString(message.content) ? message.content : undefined;
|
|
6
|
+
}
|
|
7
|
+
function toolCallSummary(payload) {
|
|
8
|
+
const call = jsonFields(payload).toolCall;
|
|
9
|
+
if (!isJsonObject(call)) {
|
|
10
|
+
return { name: 'tool', args: null };
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
name: isJsonString(call.name) ? call.name : 'tool',
|
|
14
|
+
args: call.arguments ?? null,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function summarizeAgentEvent(event) {
|
|
18
|
+
const payload = jsonFields(event.payload);
|
|
19
|
+
switch (event.type) {
|
|
20
|
+
case 'agent.message.received':
|
|
21
|
+
return { title: 'user message', detail: messageContent(event.payload) };
|
|
22
|
+
case 'agent.turn.started':
|
|
23
|
+
return { title: 'turn started', detail: `turn ${jsonNumberText(payload.turn) ?? ''}` };
|
|
24
|
+
case 'agent.turn.text_delta':
|
|
25
|
+
return { title: 'text delta', detail: jsonText(payload.delta) };
|
|
26
|
+
case 'agent.message':
|
|
27
|
+
return { title: 'agent message', detail: messageContent(event.payload) };
|
|
28
|
+
case 'agent.tool_call.requested': {
|
|
29
|
+
const call = toolCallSummary(event.payload);
|
|
30
|
+
return { title: `tool ${call.name}`, detail: compactJson(call.args) };
|
|
31
|
+
}
|
|
32
|
+
case 'agent.tool.result':
|
|
33
|
+
return {
|
|
34
|
+
title: jsonText(payload.error)
|
|
35
|
+
? `tool error ${jsonText(payload.name)}`
|
|
36
|
+
: `tool result ${jsonText(payload.name)}`,
|
|
37
|
+
detail: jsonText(payload.error) ?? compactJson(payload.result ?? null),
|
|
38
|
+
};
|
|
39
|
+
case 'agent.steered':
|
|
40
|
+
return { title: 'steered', detail: messageContent(event.payload) };
|
|
41
|
+
case 'agent.spawn.requested':
|
|
42
|
+
return {
|
|
43
|
+
title: 'agent spawn',
|
|
44
|
+
detail: `${jsonText(payload.kind) ?? 'agent'}:${jsonText(payload.definitionName) ?? 'unknown'}`,
|
|
45
|
+
};
|
|
46
|
+
case 'agent.effects.requested':
|
|
47
|
+
return { title: 'agent effects', detail: jsonText(payload.toolCallId) };
|
|
48
|
+
default:
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useProjection, useRunStore } from '@swirls/looms/react';
|
|
3
|
+
import { tokenUsage } from '../projections.js';
|
|
4
|
+
const format = new Intl.NumberFormat();
|
|
5
|
+
function Stat({ label, value }) {
|
|
6
|
+
return (_jsxs("div", { className: "border-border bg-card/60 rounded-lg border px-2.5 py-2", children: [_jsx("p", { className: "text-muted-foreground text-[11px]", children: label }), _jsx("p", { className: "font-mono text-[13px] font-medium tabular-nums", children: format.format(value) })] }));
|
|
7
|
+
}
|
|
8
|
+
export function TokenUsageView({ runId }) {
|
|
9
|
+
const state = useProjection(useRunStore(runId), tokenUsage);
|
|
10
|
+
return (_jsxs("div", { className: "grid grid-cols-3 gap-2", children: [_jsx(Stat, { label: "Input", value: state.input }), _jsx(Stat, { label: "Output", value: state.output }), _jsx(Stat, { label: "Total", value: state.input + state.output })] }));
|
|
11
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Context, Layer } from 'effect';
|
|
2
|
+
import { type DefinitionStore } from '@swirls/looms/core';
|
|
2
3
|
import type { AgentDefinition } from './definitions';
|
|
3
|
-
export
|
|
4
|
-
get(name: string): AgentDefinition | undefined;
|
|
5
|
-
}
|
|
4
|
+
export type AgentDefinitionStore = DefinitionStore<AgentDefinition>;
|
|
6
5
|
declare const AgentDefinitionsTag_base: Context.ServiceClass<AgentDefinitionsTag, "looms/AgentDefinitions", AgentDefinitionStore>;
|
|
7
6
|
export declare class AgentDefinitionsTag extends AgentDefinitionsTag_base {
|
|
8
7
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { Context, Layer } from 'effect';
|
|
2
|
+
import { makeDefinitionStore } from '@swirls/looms/core';
|
|
2
3
|
export class AgentDefinitionsTag extends Context.Service()('looms/AgentDefinitions') {
|
|
3
4
|
}
|
|
4
5
|
export function makeAgentDefinitionStore(definitions) {
|
|
5
|
-
|
|
6
|
-
return {
|
|
7
|
-
get: (name) => map.get(name),
|
|
8
|
-
};
|
|
6
|
+
return makeDefinitionStore('agent', definitions);
|
|
9
7
|
}
|
|
10
8
|
export const AgentDefinitionsLive = (definitions) => Layer.succeed(AgentDefinitionsTag, makeAgentDefinitionStore(definitions));
|