@swirls/looms 0.2.0 → 0.3.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 +22 -0
- package/dist/actor/host.js +4 -6
- package/dist/actor/index.d.ts +1 -1
- package/dist/actor/index.js +1 -1
- package/dist/actor/routing.d.ts +5 -0
- package/dist/actor/routing.js +14 -0
- package/dist/agent/agent-session.js +1 -0
- package/dist/agent/debugger/agent-chat.js +45 -11
- package/dist/agent/debugger/summarize.js +2 -0
- package/dist/agent/effects.d.ts +30 -0
- package/dist/agent/events.d.ts +2 -0
- package/dist/agent/events.js +2 -0
- package/dist/agent/llm.js +1 -8
- package/dist/agent/module.d.ts +604 -534
- package/dist/agent/module.js +11 -7
- package/dist/agent/projections.d.ts +5 -0
- package/dist/agent/projections.js +43 -2
- package/dist/agent/scope.d.ts +2 -0
- package/dist/agent/signals.d.ts +5 -0
- package/dist/agent/signals.js +7 -0
- package/dist/agent/threads.js +35 -21
- package/dist/agent/transcript.d.ts +7 -0
- package/dist/agent/transcript.js +19 -0
- package/dist/agent/types.d.ts +10 -0
- package/dist/agent/types.js +4 -0
- package/dist/approval/debugger/approvals-view.js +5 -3
- package/dist/approval/effects.d.ts +12 -0
- package/dist/approval/module.d.ts +24 -0
- package/dist/client/client.d.ts +292 -0
- package/dist/client/client.js +17 -1
- package/dist/cloudflare/router.d.ts +1 -1
- package/dist/cloudflare/router.js +6 -8
- package/dist/core/effects.d.ts +7 -0
- package/dist/core/effects.js +1 -0
- package/dist/core/fold.js +12 -6
- package/dist/core/fork.d.ts +35 -0
- package/dist/core/fork.js +129 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/module-scope.d.ts +1 -0
- package/dist/core/module.d.ts +2 -2
- package/dist/core/projection.js +1 -0
- package/dist/core/protocol.d.ts +10 -1
- package/dist/core/protocol.js +11 -0
- package/dist/core/replay.d.ts +8 -0
- package/dist/core/snapshots.js +3 -17
- package/dist/core/state.d.ts +14 -0
- package/dist/core/state.js +25 -2
- package/dist/core/store.d.ts +1 -0
- package/dist/debugger/app/assets/{index-Qb371t_O.js → index-BevQYa-U.js} +2 -2
- package/dist/debugger/app/assets/index-CgDzWJg7.css +2 -0
- package/dist/debugger/app/assets/routes-B17Om93i.js +47 -0
- package/dist/debugger/app/index.html +2 -2
- package/dist/debugger/components/composer.d.ts +5 -2
- package/dist/debugger/components/composer.js +5 -4
- package/dist/debugger/components/run-tree.js +2 -5
- package/dist/debugger/events/catalog.js +1 -3
- package/dist/debugger/events/protocol-summarize.js +7 -0
- package/dist/debugger/lib/event-counts.d.ts +2 -2
- package/dist/debugger/lib/event-counts.js +5 -9
- package/dist/debugger/shell/debugger-shell.js +1 -1
- package/dist/debugger/shell/run-controls.d.ts +2 -1
- package/dist/debugger/shell/run-controls.js +40 -13
- package/dist/debugger/shell/run-search.js +1 -3
- package/dist/evaluator/effects.d.ts +12 -0
- package/dist/evaluator/module.d.ts +24 -0
- package/dist/projectors/index-model.d.ts +13 -7
- package/dist/projectors/index-model.js +21 -26
- package/dist/projectors/memory.js +19 -11
- package/dist/projectors/postgres.js +20 -19
- package/dist/projectors/schema.js +20 -18
- package/dist/projectors/sqlite.js +32 -27
- package/dist/react/materialize.js +16 -11
- package/dist/react/react.d.ts +6 -2
- package/dist/react/react.js +5 -2
- package/dist/react/tables.d.ts +3 -2
- package/dist/runtime/cancellation.js +14 -27
- package/dist/runtime/errors.d.ts +39 -0
- package/dist/runtime/errors.js +32 -0
- package/dist/runtime/helpers.d.ts +2 -0
- package/dist/runtime/helpers.js +23 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/looms.d.ts +4 -0
- package/dist/runtime/looms.js +1 -0
- package/dist/runtime/run-start.js +1 -3
- package/dist/runtime/runtime.d.ts +1 -1
- package/dist/runtime/runtime.js +45 -18
- package/dist/runtime/server/http.d.ts +2 -0
- package/dist/runtime/server/http.js +17 -2
- package/dist/runtime/server/routes/runs.js +35 -2
- package/dist/runtime/types.d.ts +8 -0
- package/dist/runtime/wake-engine.js +5 -2
- package/dist/s2/snapshot-store.js +2 -6
- package/dist/workflow/effects.d.ts +24 -0
- package/dist/workflow/effects.js +1 -0
- package/dist/workflow/module.d.ts +48 -0
- package/package.json +1 -1
- package/dist/debugger/app/assets/index-B3Ah8WAE.css +0 -2
- package/dist/debugger/app/assets/routes-CjtEHgPQ.js +0 -47
package/dist/agent/module.js
CHANGED
|
@@ -4,7 +4,7 @@ import { createAgentSessionThread } from './agent-session.js';
|
|
|
4
4
|
import { AgentDefinitionsLive } from './definitions-store.js';
|
|
5
5
|
import { callLlmEffect, executeToolEffect } from './effects.js';
|
|
6
6
|
import { llmFromAdapter, LlmTag, StubLlmLive } from './llm.js';
|
|
7
|
-
import { conversation, tokenUsage } from './projections.js';
|
|
7
|
+
import { conversation, tokenUsage, turnActivity } from './projections.js';
|
|
8
8
|
import { agentModule } from './scope.js';
|
|
9
9
|
import { agentThread } from './threads.js';
|
|
10
10
|
export function agent(options = {}) {
|
|
@@ -27,13 +27,17 @@ export function agent(options = {}) {
|
|
|
27
27
|
projections: {
|
|
28
28
|
conversation,
|
|
29
29
|
tokenUsage,
|
|
30
|
+
turnActivity,
|
|
30
31
|
},
|
|
31
32
|
services: () => Layer.merge(llmLayer, AgentDefinitionsLive(agentDefinitions)),
|
|
32
|
-
interruptsOnSignal
|
|
33
|
-
Predicate.isObject(event.payload) &&
|
|
34
|
-
event.payload.interrupt === true &&
|
|
35
|
-
event.threadId
|
|
36
|
-
? [event.threadId]
|
|
37
|
-
: [],
|
|
33
|
+
interruptsOnSignal,
|
|
38
34
|
}));
|
|
39
35
|
}
|
|
36
|
+
/** A stop or an interrupting steer abandons the turn in progress on its thread. */
|
|
37
|
+
function interruptsOnSignal(event) {
|
|
38
|
+
const abandonsTurn = event.type === 'agent.turn.stopped' ||
|
|
39
|
+
(event.type === 'agent.steered' &&
|
|
40
|
+
Predicate.isObject(event.payload) &&
|
|
41
|
+
event.payload.interrupt === true);
|
|
42
|
+
return abandonsTurn && event.threadId ? [event.threadId] : [];
|
|
43
|
+
}
|
|
@@ -11,6 +11,11 @@ export declare const conversation: import("@swirls/looms/core").ProjectionDefini
|
|
|
11
11
|
}[] | undefined;
|
|
12
12
|
}[];
|
|
13
13
|
}>;
|
|
14
|
+
/** Whether the run's root agent or session has a turn in progress that `stopAgentTurn` can end. */
|
|
15
|
+
export declare const turnActivity: import("@swirls/looms/core").ProjectionDefinition<{
|
|
16
|
+
readonly rootThreadId: string | null;
|
|
17
|
+
readonly active: boolean;
|
|
18
|
+
}>;
|
|
14
19
|
export declare const tokenUsage: import("@swirls/looms/core").ProjectionDefinition<{
|
|
15
20
|
readonly input: number;
|
|
16
21
|
readonly output: number;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Predicate } from 'effect';
|
|
2
2
|
import { agentModule } from './scope.js';
|
|
3
|
-
import {
|
|
3
|
+
import { closeOpenToolCalls } from './transcript.js';
|
|
4
|
+
import { ConversationSchema, TokenUsageSchema, TurnActivitySchema, } from './types.js';
|
|
4
5
|
export const conversation = agentModule.projection({
|
|
5
6
|
name: 'conversation',
|
|
6
7
|
shape: ConversationSchema,
|
|
@@ -40,7 +41,8 @@ export const conversation = agentModule.projection({
|
|
|
40
41
|
name: raw.name ?? undefined,
|
|
41
42
|
toolCalls,
|
|
42
43
|
};
|
|
43
|
-
|
|
44
|
+
const interrupted = event.type === 'agent.steered' && event.payload.interrupt === true;
|
|
45
|
+
return { lines: [...(interrupted ? closeOpenToolCalls(state.lines) : state.lines), line] };
|
|
44
46
|
}
|
|
45
47
|
case 'agent.tool.result': {
|
|
46
48
|
const { error, result, toolCallId, name } = event.payload;
|
|
@@ -56,6 +58,45 @@ export const conversation = agentModule.projection({
|
|
|
56
58
|
lines: [...state.lines, toolLine],
|
|
57
59
|
};
|
|
58
60
|
}
|
|
61
|
+
case 'agent.turn.stopped':
|
|
62
|
+
return { lines: closeOpenToolCalls(state.lines) };
|
|
63
|
+
default:
|
|
64
|
+
return state;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
/** Whether the run's root agent or session has a turn in progress that `stopAgentTurn` can end. */
|
|
69
|
+
export const turnActivity = agentModule.projection({
|
|
70
|
+
name: 'turnActivity',
|
|
71
|
+
shape: TurnActivitySchema,
|
|
72
|
+
initialState: { rootThreadId: null, active: false },
|
|
73
|
+
reduce(state, event) {
|
|
74
|
+
if (event.type === 'runtime.run.started') {
|
|
75
|
+
return { ...state, rootThreadId: event.payload.rootThreadId ?? null };
|
|
76
|
+
}
|
|
77
|
+
if (event.threadId === null || event.threadId !== state.rootThreadId) {
|
|
78
|
+
return state;
|
|
79
|
+
}
|
|
80
|
+
switch (event.type) {
|
|
81
|
+
case 'runtime.thread.started':
|
|
82
|
+
return { ...state, active: event.payload.kind === 'agent' };
|
|
83
|
+
case 'agent.message.received':
|
|
84
|
+
case 'agent.tool_call.requested':
|
|
85
|
+
case 'agent.session.turn.started':
|
|
86
|
+
return { ...state, active: true };
|
|
87
|
+
case 'agent.steered':
|
|
88
|
+
return event.payload.interrupt === true ? { ...state, active: true } : state;
|
|
89
|
+
case 'agent.message':
|
|
90
|
+
case 'agent.turn.stopped':
|
|
91
|
+
case 'runtime.thread.completed':
|
|
92
|
+
case 'runtime.thread.failed':
|
|
93
|
+
case 'runtime.thread.cancelled':
|
|
94
|
+
return { ...state, active: false };
|
|
95
|
+
case 'runtime.wait.satisfied':
|
|
96
|
+
return Predicate.isObject(event.payload.tag) &&
|
|
97
|
+
event.payload.tag.kind === 'agent-session-turn'
|
|
98
|
+
? { ...state, active: false }
|
|
99
|
+
: state;
|
|
59
100
|
default:
|
|
60
101
|
return state;
|
|
61
102
|
}
|
package/dist/agent/scope.d.ts
CHANGED
|
@@ -69,6 +69,7 @@ export declare const agentModule: import("@swirls/looms/core").ModuleScope<"agen
|
|
|
69
69
|
}>;
|
|
70
70
|
readonly interrupt: import("effect/Schema").optional<import("effect/Schema").Boolean>;
|
|
71
71
|
}>;
|
|
72
|
+
'turn.stopped': import("effect/Schema").Struct<{}>;
|
|
72
73
|
'session.message.submitted': import("effect/Schema").Struct<{
|
|
73
74
|
readonly messageId: import("effect/Schema").String;
|
|
74
75
|
readonly text: import("effect/Schema").String;
|
|
@@ -231,6 +232,7 @@ export declare const agentModule: import("@swirls/looms/core").ModuleScope<"agen
|
|
|
231
232
|
}>;
|
|
232
233
|
readonly interrupt: import("effect/Schema").optional<import("effect/Schema").Boolean>;
|
|
233
234
|
}>;
|
|
235
|
+
'turn.stopped': import("effect/Schema").Struct<{}>;
|
|
234
236
|
'session.message.submitted': import("effect/Schema").Struct<{
|
|
235
237
|
readonly messageId: import("effect/Schema").String;
|
|
236
238
|
readonly text: import("effect/Schema").String;
|
package/dist/agent/signals.d.ts
CHANGED
|
@@ -16,6 +16,11 @@ export declare function userMessage(content: string, options?: AgentSignalOption
|
|
|
16
16
|
export declare function steer(content: string, options?: AgentSignalOptions & {
|
|
17
17
|
readonly interrupt?: boolean;
|
|
18
18
|
}): EventInput;
|
|
19
|
+
/**
|
|
20
|
+
* Build the `agent.turn.stopped` event. A conversational agent aborts its in-flight turn and
|
|
21
|
+
* waits for the next message; an agent session cancels its active turn and stays open.
|
|
22
|
+
*/
|
|
23
|
+
export declare function stopAgentTurn(options?: AgentSignalOptions): EventInput;
|
|
19
24
|
export interface AgentSessionMessageOptions extends AgentSignalOptions {
|
|
20
25
|
readonly delivery?: AgentMessageDelivery;
|
|
21
26
|
/** Set by the client helper when a steer is aimed at an active child. */
|
package/dist/agent/signals.js
CHANGED
|
@@ -18,6 +18,13 @@ export function steer(content, options = {}) {
|
|
|
18
18
|
message: { role: 'user', content },
|
|
19
19
|
}, { threadId: options.threadId });
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Build the `agent.turn.stopped` event. A conversational agent aborts its in-flight turn and
|
|
23
|
+
* waits for the next message; an agent session cancels its active turn and stays open.
|
|
24
|
+
*/
|
|
25
|
+
export function stopAgentTurn(options = {}) {
|
|
26
|
+
return agentModule.input('turn.stopped', {}, { threadId: options.threadId });
|
|
27
|
+
}
|
|
21
28
|
export function submitAgentMessage(messageId, text, options = {}) {
|
|
22
29
|
return agentModule.input('session.message.submitted', {
|
|
23
30
|
messageId,
|
package/dist/agent/threads.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Predicate } from 'effect';
|
|
2
|
-
import { createWaitId, DEFAULT_DEFINITION_VERSION, emit, invoke, isWithdrawnError, parseEffectId, spawn, wait, waitOutcome, } from '@swirls/looms/core';
|
|
2
|
+
import { cancel, createWaitId, DEFAULT_DEFINITION_VERSION, emit, invoke, isWithdrawnError, parseEffectId, spawn, wait, waitOutcome, } from '@swirls/looms/core';
|
|
3
3
|
import { callLlmEffect, executeToolEffect } from './effects.js';
|
|
4
4
|
import { agentModule } from './scope.js';
|
|
5
|
+
import { closeOpenToolCalls } from './transcript.js';
|
|
5
6
|
function inputToLine(input) {
|
|
6
7
|
if (input === null) {
|
|
7
8
|
return null;
|
|
@@ -26,20 +27,31 @@ function inputToLine(input) {
|
|
|
26
27
|
return { role: 'user', content: JSON.stringify(input) };
|
|
27
28
|
}
|
|
28
29
|
function attachToolCall(lines, toolCall) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
const existing = line.toolCalls ?? [];
|
|
35
|
-
if (existing.some((item) => item.id === toolCall.id)) {
|
|
36
|
-
return [...lines];
|
|
37
|
-
}
|
|
38
|
-
const next = [...lines];
|
|
39
|
-
next[index] = { ...line, toolCalls: [...existing, toolCall] };
|
|
40
|
-
return next;
|
|
30
|
+
const index = lines.findLastIndex((line) => line.role === 'assistant');
|
|
31
|
+
const line = lines[index];
|
|
32
|
+
if (!line || line.toolCalls?.some((item) => item.id === toolCall.id)) {
|
|
33
|
+
return [...lines];
|
|
41
34
|
}
|
|
42
|
-
return [...
|
|
35
|
+
return lines.with(index, { ...line, toolCalls: [...(line.toolCalls ?? []), toolCall] });
|
|
36
|
+
}
|
|
37
|
+
/** Drop the turn in progress: answer its open tool calls and cancel the children they started. */
|
|
38
|
+
function abandonTurn(state) {
|
|
39
|
+
return {
|
|
40
|
+
...state,
|
|
41
|
+
lines: closeOpenToolCalls(state.lines),
|
|
42
|
+
pendingSteer: null,
|
|
43
|
+
pendingToolCalls: [],
|
|
44
|
+
executingToolCalls: [],
|
|
45
|
+
pendingSpawns: [],
|
|
46
|
+
pendingEffects: [],
|
|
47
|
+
pendingEmits: [],
|
|
48
|
+
pendingEffectTools: {},
|
|
49
|
+
needsLlmCall: false,
|
|
50
|
+
abandonedChildThreadIds: [
|
|
51
|
+
...(state.abandonedChildThreadIds ?? []),
|
|
52
|
+
...state.pendingSpawns.map((item) => item.childThreadId),
|
|
53
|
+
],
|
|
54
|
+
};
|
|
43
55
|
}
|
|
44
56
|
export const agentThread = agentModule.thread({
|
|
45
57
|
kind: 'agent',
|
|
@@ -86,6 +98,7 @@ export const agentThread = agentModule.thread({
|
|
|
86
98
|
turn: event.payload.turn,
|
|
87
99
|
needsLlmCall: false,
|
|
88
100
|
pendingSteer: null,
|
|
101
|
+
abandonedChildThreadIds: [],
|
|
89
102
|
};
|
|
90
103
|
}
|
|
91
104
|
case 'agent.message.received': {
|
|
@@ -148,15 +161,11 @@ export const agentThread = agentModule.thread({
|
|
|
148
161
|
? [...state.consumedSteerMessageIds, messageId]
|
|
149
162
|
: state.consumedSteerMessageIds;
|
|
150
163
|
if (interrupt) {
|
|
164
|
+
const abandoned = abandonTurn(state);
|
|
151
165
|
return {
|
|
152
|
-
...
|
|
153
|
-
lines: [...
|
|
166
|
+
...abandoned,
|
|
167
|
+
lines: [...abandoned.lines, message],
|
|
154
168
|
pendingSteer: message,
|
|
155
|
-
pendingToolCalls: [],
|
|
156
|
-
executingToolCalls: [],
|
|
157
|
-
pendingSpawns: [],
|
|
158
|
-
pendingEffects: [],
|
|
159
|
-
pendingEmits: [],
|
|
160
169
|
needsLlmCall: true,
|
|
161
170
|
consumedSteerMessageIds,
|
|
162
171
|
};
|
|
@@ -168,6 +177,8 @@ export const agentThread = agentModule.thread({
|
|
|
168
177
|
consumedSteerMessageIds,
|
|
169
178
|
};
|
|
170
179
|
}
|
|
180
|
+
case 'agent.turn.stopped':
|
|
181
|
+
return abandonTurn(state);
|
|
171
182
|
case 'agent.spawn.requested': {
|
|
172
183
|
const { childThreadId, kind, definitionName, definitionVersion, toolCallId, input } = event.payload;
|
|
173
184
|
return {
|
|
@@ -370,6 +381,9 @@ export const agentThread = agentModule.thread({
|
|
|
370
381
|
for (const emitReq of state.pendingEmits) {
|
|
371
382
|
effects.push(emit(emitReq.event));
|
|
372
383
|
}
|
|
384
|
+
for (const childThreadId of state.abandonedChildThreadIds ?? []) {
|
|
385
|
+
effects.push(cancel(childThreadId));
|
|
386
|
+
}
|
|
373
387
|
return effects;
|
|
374
388
|
},
|
|
375
389
|
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Message } from './types';
|
|
2
|
+
export declare const STOPPED_TOOL_RESULT = "Stopped before the tool returned a result.";
|
|
3
|
+
/**
|
|
4
|
+
* Answer every assistant tool call that has no tool result yet. Model APIs reject a transcript
|
|
5
|
+
* whose tool calls are left unanswered, so a stopped turn closes them before the next turn.
|
|
6
|
+
*/
|
|
7
|
+
export declare function closeOpenToolCalls(lines: readonly Message[]): Message[];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const STOPPED_TOOL_RESULT = 'Stopped before the tool returned a result.';
|
|
2
|
+
/**
|
|
3
|
+
* Answer every assistant tool call that has no tool result yet. Model APIs reject a transcript
|
|
4
|
+
* whose tool calls are left unanswered, so a stopped turn closes them before the next turn.
|
|
5
|
+
*/
|
|
6
|
+
export function closeOpenToolCalls(lines) {
|
|
7
|
+
const answered = new Set(lines.flatMap((line) => (line.toolCallId ? [line.toolCallId] : [])));
|
|
8
|
+
const closing = lines.flatMap((line) => line.role === 'assistant'
|
|
9
|
+
? (line.toolCalls ?? [])
|
|
10
|
+
.filter((call) => !answered.has(call.id))
|
|
11
|
+
.map((call) => ({
|
|
12
|
+
role: 'tool',
|
|
13
|
+
content: STOPPED_TOOL_RESULT,
|
|
14
|
+
toolCallId: call.id,
|
|
15
|
+
name: call.name,
|
|
16
|
+
}))
|
|
17
|
+
: []);
|
|
18
|
+
return closing.length === 0 ? [...lines] : [...lines, ...closing];
|
|
19
|
+
}
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -39,6 +39,11 @@ export declare const TokenUsageSchema: Schema.Struct<{
|
|
|
39
39
|
readonly output: Schema.Finite;
|
|
40
40
|
}>;
|
|
41
41
|
export type TokenUsage = Schema.Schema.Type<typeof TokenUsageSchema>;
|
|
42
|
+
export declare const TurnActivitySchema: Schema.Struct<{
|
|
43
|
+
readonly rootThreadId: Schema.NullOr<Schema.String>;
|
|
44
|
+
readonly active: Schema.Boolean;
|
|
45
|
+
}>;
|
|
46
|
+
export type TurnActivity = Schema.Schema.Type<typeof TurnActivitySchema>;
|
|
42
47
|
export declare const ThreadStartedPayloadSchema: Schema.Struct<{
|
|
43
48
|
readonly definitionName: Schema.optional<Schema.String>;
|
|
44
49
|
readonly definitionVersion: Schema.withDecodingDefaultKey<Schema.String, never>;
|
|
@@ -87,6 +92,11 @@ export interface AgentState {
|
|
|
87
92
|
[causingSeq: string]: PendingEffectTool;
|
|
88
93
|
};
|
|
89
94
|
consumedSteerMessageIds: string[];
|
|
95
|
+
/**
|
|
96
|
+
* Children of an abandoned turn that still need cancelling, cleared when the next turn starts.
|
|
97
|
+
* Optional so snapshots taken before turns could be abandoned still fold.
|
|
98
|
+
*/
|
|
99
|
+
abandonedChildThreadIds?: string[];
|
|
90
100
|
}
|
|
91
101
|
export type AgentMessageDelivery = 'steer' | 'followUp' | 'nextTurn';
|
|
92
102
|
export type AgentSessionTurnStatus = 'completed' | 'failed' | 'cancelled';
|
package/dist/agent/types.js
CHANGED
|
@@ -25,6 +25,10 @@ export const TokenUsageSchema = Schema.Struct({
|
|
|
25
25
|
input: Schema.Finite,
|
|
26
26
|
output: Schema.Finite,
|
|
27
27
|
});
|
|
28
|
+
export const TurnActivitySchema = Schema.Struct({
|
|
29
|
+
rootThreadId: Schema.NullOr(Schema.String),
|
|
30
|
+
active: Schema.Boolean,
|
|
31
|
+
});
|
|
28
32
|
export const ThreadStartedPayloadSchema = Schema.Struct({
|
|
29
33
|
definitionName: Schema.optional(Schema.String),
|
|
30
34
|
definitionVersion: Schema.String.pipe(Schema.withDecodingDefaultKey(Effect.succeed(DEFAULT_DEFINITION_VERSION))),
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Button, StatusBadge, useDebugger } from '@swirls/looms/debugger';
|
|
3
|
-
import { useProjection, useRunStore } from '@swirls/looms/react';
|
|
3
|
+
import { useProjection, useRunStore, useRunSummary } from '@swirls/looms/react';
|
|
4
4
|
import { pendingApprovals } from '../projections.js';
|
|
5
5
|
import { decision } from '../signals.js';
|
|
6
6
|
export function ApprovalsView({ runId }) {
|
|
7
7
|
const { client } = useDebugger();
|
|
8
|
-
const
|
|
8
|
+
const store = useRunStore(runId);
|
|
9
|
+
const state = useProjection(store, pendingApprovals);
|
|
10
|
+
const { finished } = useRunSummary(store);
|
|
9
11
|
if (state.items.length === 0) {
|
|
10
12
|
return _jsx("p", { className: "text-muted-foreground text-xs", children: "No approvals requested." });
|
|
11
13
|
}
|
|
12
14
|
function decide(approvalId, outcome) {
|
|
13
15
|
void client.signal(runId, [decision(approvalId, outcome)]);
|
|
14
16
|
}
|
|
15
|
-
return (_jsx("ul", { className: "grid gap-2", children: state.items.map((item) => (_jsxs("li", { className: "border-border bg-card/60 rounded-lg border p-2.5", children: [_jsxs("div", { className: "flex items-center gap-2 text-xs", children: [_jsx("span", { className: "min-w-0 flex-1 truncate font-medium", children: item.title || item.approvalId }), _jsx(StatusBadge, { status: item.status })] }), item.status === 'pending' ? (_jsxs("div", { className: "mt-2 flex gap-1.5", children: [_jsx(Button, { size: "xs", onClick: () => decide(item.approvalId, 'approve'), children: "Approve" }), _jsx(Button, { size: "xs", variant: "outline", onClick: () => decide(item.approvalId, 'reject'), children: "Reject" })] })) : null] }, item.approvalId))) }));
|
|
17
|
+
return (_jsx("ul", { className: "grid gap-2", children: state.items.map((item) => (_jsxs("li", { className: "border-border bg-card/60 rounded-lg border p-2.5", children: [_jsxs("div", { className: "flex items-center gap-2 text-xs", children: [_jsx("span", { className: "min-w-0 flex-1 truncate font-medium", children: item.title || item.approvalId }), _jsx(StatusBadge, { status: item.status })] }), item.status === 'pending' && !finished ? (_jsxs("div", { className: "mt-2 flex gap-1.5", children: [_jsx(Button, { size: "xs", onClick: () => decide(item.approvalId, 'approve'), children: "Approve" }), _jsx(Button, { size: "xs", variant: "outline", onClick: () => decide(item.approvalId, 'reject'), children: "Reject" })] })) : null] }, item.approvalId))) }));
|
|
16
18
|
}
|
|
@@ -116,6 +116,11 @@ export declare const requestApprovalEffect: NoInfer<import("@swirls/looms/core")
|
|
|
116
116
|
readonly attempt: number;
|
|
117
117
|
readonly deadlineAt: number | null;
|
|
118
118
|
};
|
|
119
|
+
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
120
|
+
readonly type: "runtime.fork.elided";
|
|
121
|
+
readonly payload: {
|
|
122
|
+
readonly type: string;
|
|
123
|
+
};
|
|
119
124
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
120
125
|
readonly type: "runtime.run.cancelled";
|
|
121
126
|
readonly payload: {
|
|
@@ -127,6 +132,12 @@ export declare const requestApprovalEffect: NoInfer<import("@swirls/looms/core")
|
|
|
127
132
|
readonly output: import("effect/Schema").Json;
|
|
128
133
|
readonly error: string | null;
|
|
129
134
|
};
|
|
135
|
+
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
136
|
+
readonly type: "runtime.run.forked";
|
|
137
|
+
readonly payload: {
|
|
138
|
+
readonly sourceRunId: string;
|
|
139
|
+
readonly sourceSeq: number;
|
|
140
|
+
};
|
|
130
141
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
131
142
|
readonly type: "runtime.run.started";
|
|
132
143
|
readonly payload: {
|
|
@@ -159,6 +170,7 @@ export declare const requestApprovalEffect: NoInfer<import("@swirls/looms/core")
|
|
|
159
170
|
readonly payload: {
|
|
160
171
|
readonly threadId: string;
|
|
161
172
|
readonly reason?: string | undefined;
|
|
173
|
+
readonly resumeSeq?: number | undefined;
|
|
162
174
|
};
|
|
163
175
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
164
176
|
readonly type: "runtime.thread.completed";
|
|
@@ -138,6 +138,11 @@ export declare function approval(): import("@swirls/looms/core").RuntimeModule<"
|
|
|
138
138
|
readonly attempt: number;
|
|
139
139
|
readonly deadlineAt: number | null;
|
|
140
140
|
};
|
|
141
|
+
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
142
|
+
readonly type: "runtime.fork.elided";
|
|
143
|
+
readonly payload: {
|
|
144
|
+
readonly type: string;
|
|
145
|
+
};
|
|
141
146
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
142
147
|
readonly type: "runtime.run.cancelled";
|
|
143
148
|
readonly payload: {
|
|
@@ -149,6 +154,12 @@ export declare function approval(): import("@swirls/looms/core").RuntimeModule<"
|
|
|
149
154
|
readonly output: import("effect/Schema").Json;
|
|
150
155
|
readonly error: string | null;
|
|
151
156
|
};
|
|
157
|
+
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
158
|
+
readonly type: "runtime.run.forked";
|
|
159
|
+
readonly payload: {
|
|
160
|
+
readonly sourceRunId: string;
|
|
161
|
+
readonly sourceSeq: number;
|
|
162
|
+
};
|
|
152
163
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
153
164
|
readonly type: "runtime.run.started";
|
|
154
165
|
readonly payload: {
|
|
@@ -181,6 +192,7 @@ export declare function approval(): import("@swirls/looms/core").RuntimeModule<"
|
|
|
181
192
|
readonly payload: {
|
|
182
193
|
readonly threadId: string;
|
|
183
194
|
readonly reason?: string | undefined;
|
|
195
|
+
readonly resumeSeq?: number | undefined;
|
|
184
196
|
};
|
|
185
197
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
186
198
|
readonly type: "runtime.thread.completed";
|
|
@@ -372,6 +384,11 @@ export declare function approval(): import("@swirls/looms/core").RuntimeModule<"
|
|
|
372
384
|
readonly attempt: number;
|
|
373
385
|
readonly deadlineAt: number | null;
|
|
374
386
|
};
|
|
387
|
+
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
388
|
+
readonly type: "runtime.fork.elided";
|
|
389
|
+
readonly payload: {
|
|
390
|
+
readonly type: string;
|
|
391
|
+
};
|
|
375
392
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
376
393
|
readonly type: "runtime.run.cancelled";
|
|
377
394
|
readonly payload: {
|
|
@@ -383,6 +400,12 @@ export declare function approval(): import("@swirls/looms/core").RuntimeModule<"
|
|
|
383
400
|
readonly output: import("effect/Schema").Json;
|
|
384
401
|
readonly error: string | null;
|
|
385
402
|
};
|
|
403
|
+
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
404
|
+
readonly type: "runtime.run.forked";
|
|
405
|
+
readonly payload: {
|
|
406
|
+
readonly sourceRunId: string;
|
|
407
|
+
readonly sourceSeq: number;
|
|
408
|
+
};
|
|
386
409
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
387
410
|
readonly type: "runtime.run.started";
|
|
388
411
|
readonly payload: {
|
|
@@ -415,6 +438,7 @@ export declare function approval(): import("@swirls/looms/core").RuntimeModule<"
|
|
|
415
438
|
readonly payload: {
|
|
416
439
|
readonly threadId: string;
|
|
417
440
|
readonly reason?: string | undefined;
|
|
441
|
+
readonly resumeSeq?: number | undefined;
|
|
418
442
|
};
|
|
419
443
|
}) | (Omit<import("@swirls/looms/core").EventInput, "payload" | "type"> & {
|
|
420
444
|
readonly type: "runtime.thread.completed";
|