@swirls/looms 0.0.1
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/LICENSE +190 -0
- package/README.md +9 -0
- package/dist/actor/cell.d.ts +27 -0
- package/dist/actor/cell.js +41 -0
- package/dist/actor/host.d.ts +27 -0
- package/dist/actor/host.js +82 -0
- package/dist/actor/index.d.ts +3 -0
- package/dist/actor/index.js +3 -0
- package/dist/actor/routing.d.ts +15 -0
- package/dist/actor/routing.js +80 -0
- package/dist/agent/definitions-store.d.ts +11 -0
- package/dist/agent/definitions-store.js +10 -0
- package/dist/agent/definitions.d.ts +152 -0
- package/dist/agent/definitions.js +74 -0
- package/dist/agent/effects.d.ts +425 -0
- package/dist/agent/effects.js +318 -0
- package/dist/agent/events.d.ts +170 -0
- package/dist/agent/events.js +61 -0
- package/dist/agent/index.d.ts +13 -0
- package/dist/agent/index.js +13 -0
- package/dist/agent/llm.d.ts +35 -0
- package/dist/agent/llm.js +48 -0
- package/dist/agent/module.d.ts +1037 -0
- package/dist/agent/module.js +27 -0
- package/dist/agent/projections.d.ts +17 -0
- package/dist/agent/projections.js +81 -0
- package/dist/agent/scope.d.ts +171 -0
- package/dist/agent/scope.js +7 -0
- package/dist/agent/signals.d.ts +17 -0
- package/dist/agent/signals.js +19 -0
- package/dist/agent/stop-when.d.ts +12 -0
- package/dist/agent/stop-when.js +6 -0
- package/dist/agent/threads.d.ts +34 -0
- package/dist/agent/threads.js +407 -0
- package/dist/agent/tool-schema.d.ts +21 -0
- package/dist/agent/tool-schema.js +67 -0
- package/dist/agent/types.d.ts +87 -0
- package/dist/agent/types.js +32 -0
- package/dist/ai-vercel/index.d.ts +2 -0
- package/dist/ai-vercel/index.js +2 -0
- package/dist/ai-vercel/messages.d.ts +9 -0
- package/dist/ai-vercel/messages.js +68 -0
- package/dist/ai-vercel/vercel-llm.d.ts +8 -0
- package/dist/ai-vercel/vercel-llm.js +98 -0
- package/dist/approval/effects.d.ts +133 -0
- package/dist/approval/effects.js +13 -0
- package/dist/approval/events.d.ts +52 -0
- package/dist/approval/events.js +28 -0
- package/dist/approval/index.d.ts +6 -0
- package/dist/approval/index.js +6 -0
- package/dist/approval/module.d.ts +342 -0
- package/dist/approval/module.js +10 -0
- package/dist/approval/projections.d.ts +42 -0
- package/dist/approval/projections.js +57 -0
- package/dist/approval/scope.d.ts +45 -0
- package/dist/approval/scope.js +7 -0
- package/dist/approval/signals.d.ts +19 -0
- package/dist/approval/signals.js +34 -0
- package/dist/cli/cli.d.ts +2 -0
- package/dist/cli/cli.js +6 -0
- package/dist/cli/commands.d.ts +13 -0
- package/dist/cli/commands.js +133 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +1 -0
- package/dist/client/client.d.ts +69 -0
- package/dist/client/client.js +179 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +2 -0
- package/dist/client/sse.d.ts +10 -0
- package/dist/client/sse.js +103 -0
- package/dist/cloudflare/alarm-scheduler.d.ts +9 -0
- package/dist/cloudflare/alarm-scheduler.js +13 -0
- package/dist/cloudflare/durable-object.d.ts +24 -0
- package/dist/cloudflare/durable-object.js +43 -0
- package/dist/cloudflare/event-store.d.ts +10 -0
- package/dist/cloudflare/event-store.js +18 -0
- package/dist/cloudflare/index.d.ts +4 -0
- package/dist/cloudflare/index.js +4 -0
- package/dist/cloudflare/router.d.ts +12 -0
- package/dist/cloudflare/router.js +26 -0
- package/dist/core/bun-sqlite.d.ts +13 -0
- package/dist/core/bun-sqlite.js +19 -0
- package/dist/core/catalog.d.ts +49 -0
- package/dist/core/catalog.js +39 -0
- package/dist/core/coalesce.d.ts +21 -0
- package/dist/core/coalesce.js +178 -0
- package/dist/core/compose.d.ts +59 -0
- package/dist/core/compose.js +97 -0
- package/dist/core/cursor.d.ts +16 -0
- package/dist/core/cursor.js +46 -0
- package/dist/core/effects.d.ts +110 -0
- package/dist/core/effects.js +99 -0
- package/dist/core/envelope.d.ts +79 -0
- package/dist/core/envelope.js +68 -0
- package/dist/core/event-codec.d.ts +8 -0
- package/dist/core/event-codec.js +82 -0
- package/dist/core/event-index.d.ts +28 -0
- package/dist/core/event-index.js +86 -0
- package/dist/core/fold.d.ts +19 -0
- package/dist/core/fold.js +362 -0
- package/dist/core/ids.d.ts +11 -0
- package/dist/core/ids.js +47 -0
- package/dist/core/index.d.ts +26 -0
- package/dist/core/index.js +25 -0
- package/dist/core/match.d.ts +8 -0
- package/dist/core/match.js +58 -0
- package/dist/core/module-scope.d.ts +99 -0
- package/dist/core/module-scope.js +72 -0
- package/dist/core/module.d.ts +74 -0
- package/dist/core/module.js +3 -0
- package/dist/core/projection.d.ts +83 -0
- package/dist/core/projection.js +241 -0
- package/dist/core/protocol.d.ts +99 -0
- package/dist/core/protocol.js +101 -0
- package/dist/core/replay.d.ts +13 -0
- package/dist/core/replay.js +34 -0
- package/dist/core/schema.d.ts +35 -0
- package/dist/core/schema.js +130 -0
- package/dist/core/serialize.d.ts +14 -0
- package/dist/core/serialize.js +42 -0
- package/dist/core/snapshot-store.d.ts +39 -0
- package/dist/core/snapshot-store.js +53 -0
- package/dist/core/snapshots.d.ts +26 -0
- package/dist/core/snapshots.js +100 -0
- package/dist/core/sqlite-store.d.ts +31 -0
- package/dist/core/sqlite-store.js +328 -0
- package/dist/core/state.d.ts +43 -0
- package/dist/core/state.js +31 -0
- package/dist/core/store.d.ts +146 -0
- package/dist/core/store.js +229 -0
- package/dist/core/thread.d.ts +41 -0
- package/dist/core/thread.js +13 -0
- package/dist/core/types.d.ts +27 -0
- package/dist/core/types.js +42 -0
- package/dist/core/validate-event.d.ts +19 -0
- package/dist/core/validate-event.js +42 -0
- package/dist/debugger/components/debugger-split.d.ts +23 -0
- package/dist/debugger/components/debugger-split.js +25 -0
- package/dist/debugger/components/event-inspector.d.ts +5 -0
- package/dist/debugger/components/event-inspector.js +38 -0
- package/dist/debugger/components/event-stream.d.ts +13 -0
- package/dist/debugger/components/event-stream.js +119 -0
- package/dist/debugger/components/json-view.d.ts +5 -0
- package/dist/debugger/components/json-view.js +5 -0
- package/dist/debugger/components/run-tree.d.ts +14 -0
- package/dist/debugger/components/run-tree.js +38 -0
- package/dist/debugger/components/status-dot.d.ts +3 -0
- package/dist/debugger/components/status-dot.js +5 -0
- package/dist/debugger/contracts.d.ts +22 -0
- package/dist/debugger/contracts.js +1 -0
- package/dist/debugger/events/catalog.d.ts +6 -0
- package/dist/debugger/events/catalog.js +27 -0
- package/dist/debugger/events/domain-summarize.d.ts +3 -0
- package/dist/debugger/events/domain-summarize.js +107 -0
- package/dist/debugger/events/family.d.ts +8 -0
- package/dist/debugger/events/family.js +44 -0
- package/dist/debugger/events/protocol-summarize.d.ts +3 -0
- package/dist/debugger/events/protocol-summarize.js +70 -0
- package/dist/debugger/index.d.ts +17 -0
- package/dist/debugger/index.js +16 -0
- package/dist/debugger/lib/cn.d.ts +5 -0
- package/dist/debugger/lib/cn.js +17 -0
- package/dist/debugger/lib/event-counts.d.ts +5 -0
- package/dist/debugger/lib/event-counts.js +23 -0
- package/dist/debugger/lib/event-meta.d.ts +8 -0
- package/dist/debugger/lib/event-meta.js +20 -0
- package/dist/debugger/lib/project-run.d.ts +9 -0
- package/dist/debugger/lib/project-run.js +14 -0
- package/dist/debugger/lib/status.d.ts +3 -0
- package/dist/debugger/lib/status.js +31 -0
- package/dist/debugger/lib/visible-events.d.ts +8 -0
- package/dist/debugger/lib/visible-events.js +21 -0
- package/dist/debugger/styles.css +71 -0
- package/dist/debugger/ui/checkbox.d.ts +4 -0
- package/dist/debugger/ui/checkbox.js +9 -0
- package/dist/debugger/ui/input.d.ts +3 -0
- package/dist/debugger/ui/input.js +7 -0
- package/dist/debugger/ui/scroll-area.d.ts +9 -0
- package/dist/debugger/ui/scroll-area.js +10 -0
- package/dist/debugger/ui/tabs.d.ts +7 -0
- package/dist/debugger/ui/tabs.js +17 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/projectors/index-model.d.ts +56 -0
- package/dist/projectors/index-model.js +117 -0
- package/dist/projectors/index.d.ts +4 -0
- package/dist/projectors/index.js +3 -0
- package/dist/projectors/memory.d.ts +5 -0
- package/dist/projectors/memory.js +77 -0
- package/dist/projectors/postgres.d.ts +9 -0
- package/dist/projectors/postgres.js +108 -0
- package/dist/projectors/projector.d.ts +11 -0
- package/dist/projectors/projector.js +1 -0
- package/dist/projectors/schema.d.ts +5 -0
- package/dist/projectors/schema.js +43 -0
- package/dist/projectors/sqlite.d.ts +9 -0
- package/dist/projectors/sqlite.js +103 -0
- package/dist/projectors/with-projectors.d.ts +17 -0
- package/dist/projectors/with-projectors.js +55 -0
- package/dist/react/derived.d.ts +19 -0
- package/dist/react/derived.js +50 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.js +5 -0
- package/dist/react/materialize.d.ts +3 -0
- package/dist/react/materialize.js +86 -0
- package/dist/react/notify.d.ts +18 -0
- package/dist/react/notify.js +80 -0
- package/dist/react/react.d.ts +61 -0
- package/dist/react/react.js +187 -0
- package/dist/react/register.d.ts +31 -0
- package/dist/react/register.js +1 -0
- package/dist/react/sse.d.ts +1 -0
- package/dist/react/sse.js +1 -0
- package/dist/react/store.d.ts +56 -0
- package/dist/react/store.js +340 -0
- package/dist/react/tables.d.ts +21 -0
- package/dist/react/tables.js +6 -0
- package/dist/runtime/dispatch-effect.d.ts +3 -0
- package/dist/runtime/dispatch-effect.js +113 -0
- package/dist/runtime/events-api.d.ts +4 -0
- package/dist/runtime/events-api.js +84 -0
- package/dist/runtime/index.d.ts +5 -0
- package/dist/runtime/index.js +5 -0
- package/dist/runtime/looms.d.ts +74 -0
- package/dist/runtime/looms.js +109 -0
- package/dist/runtime/runtime-helpers.d.ts +51 -0
- package/dist/runtime/runtime-helpers.js +230 -0
- package/dist/runtime/runtime.d.ts +91 -0
- package/dist/runtime/runtime.js +531 -0
- package/dist/runtime/server.d.ts +17 -0
- package/dist/runtime/server.js +226 -0
- package/dist/runtime/sse.d.ts +15 -0
- package/dist/runtime/sse.js +96 -0
- package/dist/runtime/wake-scheduler.d.ts +8 -0
- package/dist/runtime/wake-scheduler.js +38 -0
- package/dist/s2/config.d.ts +27 -0
- package/dist/s2/config.js +54 -0
- package/dist/s2/index.d.ts +6 -0
- package/dist/s2/index.js +6 -0
- package/dist/s2/lite.d.ts +26 -0
- package/dist/s2/lite.js +150 -0
- package/dist/s2/projector.d.ts +8 -0
- package/dist/s2/projector.js +28 -0
- package/dist/s2/serialize.d.ts +1 -0
- package/dist/s2/serialize.js +1 -0
- package/dist/s2/snapshot-store.d.ts +17 -0
- package/dist/s2/snapshot-store.js +320 -0
- package/dist/s2/store.d.ts +35 -0
- package/dist/s2/store.js +337 -0
- package/dist/testing/index.d.ts +11 -0
- package/dist/testing/index.js +63 -0
- package/dist/workflow/definitions-store.d.ts +11 -0
- package/dist/workflow/definitions-store.js +8 -0
- package/dist/workflow/definitions.d.ts +82 -0
- package/dist/workflow/definitions.js +32 -0
- package/dist/workflow/effects.d.ts +305 -0
- package/dist/workflow/effects.js +208 -0
- package/dist/workflow/events.d.ts +60 -0
- package/dist/workflow/events.js +39 -0
- package/dist/workflow/index.d.ts +8 -0
- package/dist/workflow/index.js +8 -0
- package/dist/workflow/module.d.ts +926 -0
- package/dist/workflow/module.js +19 -0
- package/dist/workflow/projections.d.ts +30 -0
- package/dist/workflow/projections.js +43 -0
- package/dist/workflow/scope.d.ts +61 -0
- package/dist/workflow/scope.js +7 -0
- package/dist/workflow/threads.d.ts +171 -0
- package/dist/workflow/threads.js +287 -0
- package/package.json +183 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { Effect, Predicate, Schema } from 'effect';
|
|
2
|
+
import { createThreadId, validateInput } from '@swirls/looms/core';
|
|
3
|
+
import { normalizeTools } from './definitions.js';
|
|
4
|
+
import { AgentDefinitionsTag } from './definitions-store.js';
|
|
5
|
+
import { LlmTag } from './llm.js';
|
|
6
|
+
import { agentModule } from './scope.js';
|
|
7
|
+
import { toolSpecs } from './tool-schema.js';
|
|
8
|
+
import { MessageSchema, ToolCallSchema } from './types.js';
|
|
9
|
+
const CallLlmInput = Schema.Struct({
|
|
10
|
+
turn: Schema.Number,
|
|
11
|
+
definitionName: Schema.optional(Schema.String),
|
|
12
|
+
messages: Schema.optional(Schema.Array(MessageSchema)),
|
|
13
|
+
input: Schema.optional(Schema.Json),
|
|
14
|
+
});
|
|
15
|
+
const ExecuteToolInput = Schema.Struct({
|
|
16
|
+
turn: Schema.Number,
|
|
17
|
+
definitionName: Schema.optional(Schema.String),
|
|
18
|
+
toolCall: ToolCallSchema,
|
|
19
|
+
});
|
|
20
|
+
function findTool(tools, name) {
|
|
21
|
+
return tools.find((tool) => tool.name === name);
|
|
22
|
+
}
|
|
23
|
+
export const callLlmEffect = agentModule.effect({
|
|
24
|
+
type: 'agent.callLLM',
|
|
25
|
+
input: CallLlmInput,
|
|
26
|
+
execute: (input, ctx) => runCallLlm({
|
|
27
|
+
turn: input.turn,
|
|
28
|
+
definitionName: input.definitionName,
|
|
29
|
+
// SAFETY: message arrays in callLLM input are serialized Message objects.
|
|
30
|
+
messages: input.messages ?? [],
|
|
31
|
+
input: input.input ?? null,
|
|
32
|
+
runId: ctx.runId,
|
|
33
|
+
threadId: ctx.threadId,
|
|
34
|
+
emit: (event) => ctx.emit(event),
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
function runCallLlm(args) {
|
|
38
|
+
return Effect.gen(function* () {
|
|
39
|
+
const { turn, threadId, emit, definitionName, messages, input } = args;
|
|
40
|
+
const agents = yield* AgentDefinitionsTag;
|
|
41
|
+
const llm = yield* LlmTag;
|
|
42
|
+
const definition = definitionName ? agents.get(definitionName) : undefined;
|
|
43
|
+
if (!definition) {
|
|
44
|
+
return [
|
|
45
|
+
{
|
|
46
|
+
type: 'runtime.thread.failed',
|
|
47
|
+
payload: { threadId, error: `Unknown agent definition for ${threadId}` },
|
|
48
|
+
threadId,
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
if (turn > (definition.maxTurns ?? 20)) {
|
|
53
|
+
return [
|
|
54
|
+
{
|
|
55
|
+
type: 'runtime.thread.failed',
|
|
56
|
+
payload: { threadId, error: `Max turns exceeded (${definition.maxTurns ?? 20})` },
|
|
57
|
+
threadId,
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
const tools = normalizeTools(definition.tools);
|
|
62
|
+
const events = [
|
|
63
|
+
{
|
|
64
|
+
type: 'agent.turn.started',
|
|
65
|
+
payload: { turn },
|
|
66
|
+
threadId,
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
const turnCtx = {
|
|
70
|
+
threadId,
|
|
71
|
+
turn,
|
|
72
|
+
messages,
|
|
73
|
+
input,
|
|
74
|
+
tools,
|
|
75
|
+
instructions: definition.instructions,
|
|
76
|
+
};
|
|
77
|
+
const result = definition.runTurn
|
|
78
|
+
? yield* Effect.tryPromise({
|
|
79
|
+
try: () => Promise.resolve(definition.runTurn(turnCtx)),
|
|
80
|
+
catch: (cause) => (cause instanceof Error ? cause : new Error(String(cause))),
|
|
81
|
+
})
|
|
82
|
+
: yield* llm.complete({
|
|
83
|
+
model: definition.model,
|
|
84
|
+
instructions: definition.instructions,
|
|
85
|
+
messages: [{ role: 'system', content: definition.instructions }, ...turnCtx.messages],
|
|
86
|
+
tools,
|
|
87
|
+
toolSpecs: toolSpecs(tools),
|
|
88
|
+
onTextDelta: async (delta) => {
|
|
89
|
+
await emit({
|
|
90
|
+
type: 'agent.turn.text_delta',
|
|
91
|
+
payload: { turn, delta },
|
|
92
|
+
threadId,
|
|
93
|
+
ephemeral: true,
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
const toolCalls = result.toolCalls ?? result.message.toolCalls ?? [];
|
|
98
|
+
const shouldStop = definition.stopWhen?.({
|
|
99
|
+
turn,
|
|
100
|
+
maxTurns: definition.maxTurns ?? 20,
|
|
101
|
+
messages: turnCtx.messages,
|
|
102
|
+
toolCalls,
|
|
103
|
+
result,
|
|
104
|
+
});
|
|
105
|
+
events.push({
|
|
106
|
+
type: 'agent.message',
|
|
107
|
+
payload: {
|
|
108
|
+
turn,
|
|
109
|
+
message: result.message,
|
|
110
|
+
usage: result.usage,
|
|
111
|
+
},
|
|
112
|
+
threadId,
|
|
113
|
+
});
|
|
114
|
+
if (shouldStop) {
|
|
115
|
+
if (!definition.conversational) {
|
|
116
|
+
events.push({
|
|
117
|
+
type: 'runtime.thread.completed',
|
|
118
|
+
payload: { threadId, output: result.output ?? { text: result.message.content } },
|
|
119
|
+
threadId,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return events;
|
|
123
|
+
}
|
|
124
|
+
for (const toolCall of toolCalls) {
|
|
125
|
+
events.push({
|
|
126
|
+
type: 'agent.tool_call.requested',
|
|
127
|
+
payload: { turn, toolCall },
|
|
128
|
+
threadId,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (toolCalls.length === 0 && !definition.conversational) {
|
|
132
|
+
events.push({
|
|
133
|
+
type: 'runtime.thread.completed',
|
|
134
|
+
payload: {
|
|
135
|
+
threadId,
|
|
136
|
+
output: result.output ?? { text: result.message.content },
|
|
137
|
+
},
|
|
138
|
+
threadId,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return events;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
export const executeToolEffect = agentModule.effect({
|
|
145
|
+
type: 'agent.executeTool',
|
|
146
|
+
input: ExecuteToolInput,
|
|
147
|
+
execute: (input, ctx) => Effect.gen(function* () {
|
|
148
|
+
const threadId = ctx.threadId;
|
|
149
|
+
const agents = yield* AgentDefinitionsTag;
|
|
150
|
+
const definition = input.definitionName ? agents.get(input.definitionName) : undefined;
|
|
151
|
+
if (!definition) {
|
|
152
|
+
return [
|
|
153
|
+
{
|
|
154
|
+
type: 'agent.tool.result',
|
|
155
|
+
payload: {
|
|
156
|
+
turn: input.turn,
|
|
157
|
+
toolCallId: input.toolCall.id,
|
|
158
|
+
name: input.toolCall.name,
|
|
159
|
+
result: null,
|
|
160
|
+
error: 'Unknown agent definition',
|
|
161
|
+
},
|
|
162
|
+
threadId,
|
|
163
|
+
},
|
|
164
|
+
];
|
|
165
|
+
}
|
|
166
|
+
const tools = normalizeTools(definition.tools);
|
|
167
|
+
const tool = findTool(tools, input.toolCall.name);
|
|
168
|
+
if (!tool) {
|
|
169
|
+
return [
|
|
170
|
+
{
|
|
171
|
+
type: 'agent.tool.result',
|
|
172
|
+
payload: {
|
|
173
|
+
turn: input.turn,
|
|
174
|
+
toolCallId: input.toolCall.id,
|
|
175
|
+
name: input.toolCall.name,
|
|
176
|
+
result: null,
|
|
177
|
+
error: `Unknown tool: ${input.toolCall.name}`,
|
|
178
|
+
},
|
|
179
|
+
threadId,
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
}
|
|
183
|
+
switch (tool.kind) {
|
|
184
|
+
case 'function': {
|
|
185
|
+
const validated = yield* Effect.tryPromise({
|
|
186
|
+
try: () => validateInput(tool.input, input.toolCall.arguments),
|
|
187
|
+
catch: (cause) => (cause instanceof Error ? cause : new Error(String(cause))),
|
|
188
|
+
}).pipe(Effect.map((value) => ({ ok: true, value })), Effect.catch((err) => Effect.succeed({ ok: false, error: err.message })));
|
|
189
|
+
if (!validated.ok) {
|
|
190
|
+
return [
|
|
191
|
+
{
|
|
192
|
+
type: 'agent.tool.result',
|
|
193
|
+
payload: {
|
|
194
|
+
turn: input.turn,
|
|
195
|
+
toolCallId: input.toolCall.id,
|
|
196
|
+
name: input.toolCall.name,
|
|
197
|
+
result: null,
|
|
198
|
+
error: validated.error,
|
|
199
|
+
},
|
|
200
|
+
threadId,
|
|
201
|
+
},
|
|
202
|
+
];
|
|
203
|
+
}
|
|
204
|
+
const result = yield* Effect.tryPromise({
|
|
205
|
+
try: () => Promise.resolve(tool.handler(validated.value, {
|
|
206
|
+
threadId,
|
|
207
|
+
turn: input.turn,
|
|
208
|
+
})),
|
|
209
|
+
catch: (cause) => (cause instanceof Error ? cause : new Error(String(cause))),
|
|
210
|
+
}).pipe(Effect.map((value) => ({ ok: true, value })), Effect.catch((err) => Effect.succeed({ ok: false, error: err.message })));
|
|
211
|
+
return [
|
|
212
|
+
{
|
|
213
|
+
type: 'agent.tool.result',
|
|
214
|
+
payload: {
|
|
215
|
+
turn: input.turn,
|
|
216
|
+
toolCallId: input.toolCall.id,
|
|
217
|
+
name: input.toolCall.name,
|
|
218
|
+
result: result.ok ? result.value : null,
|
|
219
|
+
error: result.ok ? null : result.error,
|
|
220
|
+
},
|
|
221
|
+
threadId,
|
|
222
|
+
},
|
|
223
|
+
];
|
|
224
|
+
}
|
|
225
|
+
case 'thread': {
|
|
226
|
+
const validated = tool.input
|
|
227
|
+
? yield* Effect.tryPromise({
|
|
228
|
+
try: () => validateInput(tool.input, input.toolCall.arguments),
|
|
229
|
+
catch: (cause) => (cause instanceof Error ? cause : new Error(String(cause))),
|
|
230
|
+
}).pipe(Effect.map((value) => ({ ok: true, value })), Effect.catch((err) => Effect.succeed({ ok: false, error: err.message })))
|
|
231
|
+
: { ok: true, value: input.toolCall.arguments };
|
|
232
|
+
if (!validated.ok) {
|
|
233
|
+
return [
|
|
234
|
+
{
|
|
235
|
+
type: 'agent.tool.result',
|
|
236
|
+
payload: {
|
|
237
|
+
turn: input.turn,
|
|
238
|
+
toolCallId: input.toolCall.id,
|
|
239
|
+
name: input.toolCall.name,
|
|
240
|
+
result: null,
|
|
241
|
+
error: validated.error,
|
|
242
|
+
},
|
|
243
|
+
threadId,
|
|
244
|
+
},
|
|
245
|
+
];
|
|
246
|
+
}
|
|
247
|
+
const childInput = tool.mapInput ? tool.mapInput(validated.value) : validated.value;
|
|
248
|
+
const childThreadId = createThreadId();
|
|
249
|
+
return [
|
|
250
|
+
{
|
|
251
|
+
type: 'agent.spawn.requested',
|
|
252
|
+
payload: {
|
|
253
|
+
childThreadId,
|
|
254
|
+
kind: tool.childKind,
|
|
255
|
+
definitionName: tool.childName,
|
|
256
|
+
input: childInput,
|
|
257
|
+
toolCallId: input.toolCall.id,
|
|
258
|
+
},
|
|
259
|
+
threadId,
|
|
260
|
+
},
|
|
261
|
+
];
|
|
262
|
+
}
|
|
263
|
+
case 'effects': {
|
|
264
|
+
const validated = tool.input
|
|
265
|
+
? yield* Effect.tryPromise({
|
|
266
|
+
try: () => validateInput(tool.input, input.toolCall.arguments),
|
|
267
|
+
catch: (cause) => (cause instanceof Error ? cause : new Error(String(cause))),
|
|
268
|
+
}).pipe(Effect.map((value) => ({ ok: true, value })), Effect.catch((err) => Effect.succeed({ ok: false, error: err.message })))
|
|
269
|
+
: { ok: true, value: input.toolCall.arguments };
|
|
270
|
+
if (!validated.ok) {
|
|
271
|
+
return [
|
|
272
|
+
{
|
|
273
|
+
type: 'agent.tool.result',
|
|
274
|
+
payload: {
|
|
275
|
+
turn: input.turn,
|
|
276
|
+
toolCallId: input.toolCall.id,
|
|
277
|
+
name: input.toolCall.name,
|
|
278
|
+
result: null,
|
|
279
|
+
error: validated.error,
|
|
280
|
+
},
|
|
281
|
+
threadId,
|
|
282
|
+
},
|
|
283
|
+
];
|
|
284
|
+
}
|
|
285
|
+
const effects = tool.effects(validated.value);
|
|
286
|
+
return [
|
|
287
|
+
{
|
|
288
|
+
type: 'agent.effects.requested',
|
|
289
|
+
payload: {
|
|
290
|
+
toolCallId: input.toolCall.id,
|
|
291
|
+
effects,
|
|
292
|
+
waitOn: tool.waitOn
|
|
293
|
+
? {
|
|
294
|
+
type: tool.waitOn.type,
|
|
295
|
+
match: tool.waitOn.match,
|
|
296
|
+
}
|
|
297
|
+
: undefined,
|
|
298
|
+
},
|
|
299
|
+
threadId,
|
|
300
|
+
},
|
|
301
|
+
];
|
|
302
|
+
}
|
|
303
|
+
default: {
|
|
304
|
+
const exhaustiveCheck = tool;
|
|
305
|
+
return exhaustiveCheck;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}),
|
|
309
|
+
});
|
|
310
|
+
export function readToolCall(value) {
|
|
311
|
+
if (!Predicate.isObject(value)) {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
if (!Predicate.isString(value.id) || !Predicate.isString(value.name)) {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
return { id: value.id, name: value.name, arguments: value.arguments ?? null };
|
|
318
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
import { type RuntimeEffect } from '@swirls/looms/core';
|
|
3
|
+
export declare const AgentMessageReceivedPayloadSchema: Schema.Struct<{
|
|
4
|
+
readonly message: Schema.Struct<{
|
|
5
|
+
readonly role: Schema.Union<readonly [Schema.Literal<"system">, Schema.Literal<"user">, Schema.Literal<"assistant">, Schema.Literal<"tool">]>;
|
|
6
|
+
readonly content: Schema.String;
|
|
7
|
+
readonly toolCallId: Schema.optional<Schema.String>;
|
|
8
|
+
readonly name: Schema.optional<Schema.String>;
|
|
9
|
+
readonly toolCalls: Schema.optional<Schema.mutable<Schema.$Array<Schema.Struct<{
|
|
10
|
+
readonly id: Schema.String;
|
|
11
|
+
readonly name: Schema.String;
|
|
12
|
+
readonly arguments: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
13
|
+
}>>>>;
|
|
14
|
+
}>;
|
|
15
|
+
}>;
|
|
16
|
+
export declare const AgentTurnStartedPayloadSchema: Schema.Struct<{
|
|
17
|
+
readonly turn: Schema.Number;
|
|
18
|
+
}>;
|
|
19
|
+
export declare const AgentTurnTextDeltaPayloadSchema: Schema.Struct<{
|
|
20
|
+
readonly turn: Schema.Number;
|
|
21
|
+
readonly delta: Schema.String;
|
|
22
|
+
}>;
|
|
23
|
+
export declare const AgentMessageEventPayloadSchema: Schema.Struct<{
|
|
24
|
+
readonly turn: Schema.Number;
|
|
25
|
+
readonly message: Schema.Struct<{
|
|
26
|
+
readonly role: Schema.Union<readonly [Schema.Literal<"system">, Schema.Literal<"user">, Schema.Literal<"assistant">, Schema.Literal<"tool">]>;
|
|
27
|
+
readonly content: Schema.String;
|
|
28
|
+
readonly toolCallId: Schema.optional<Schema.String>;
|
|
29
|
+
readonly name: Schema.optional<Schema.String>;
|
|
30
|
+
readonly toolCalls: Schema.optional<Schema.mutable<Schema.$Array<Schema.Struct<{
|
|
31
|
+
readonly id: Schema.String;
|
|
32
|
+
readonly name: Schema.String;
|
|
33
|
+
readonly arguments: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
34
|
+
}>>>>;
|
|
35
|
+
}>;
|
|
36
|
+
readonly usage: Schema.optional<Schema.Struct<{
|
|
37
|
+
readonly input: Schema.Number;
|
|
38
|
+
readonly output: Schema.Number;
|
|
39
|
+
}>>;
|
|
40
|
+
}>;
|
|
41
|
+
export declare const AgentToolCallRequestedPayloadSchema: Schema.Struct<{
|
|
42
|
+
readonly turn: Schema.Number;
|
|
43
|
+
readonly toolCall: Schema.Struct<{
|
|
44
|
+
readonly id: Schema.String;
|
|
45
|
+
readonly name: Schema.String;
|
|
46
|
+
readonly arguments: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
47
|
+
}>;
|
|
48
|
+
}>;
|
|
49
|
+
export declare const AgentToolResultPayloadSchema: Schema.Struct<{
|
|
50
|
+
readonly turn: Schema.Number;
|
|
51
|
+
readonly toolCallId: Schema.String;
|
|
52
|
+
readonly name: Schema.String;
|
|
53
|
+
readonly result: Schema.NullOr<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
54
|
+
readonly error: Schema.NullOr<Schema.String>;
|
|
55
|
+
}>;
|
|
56
|
+
export declare const AgentSteeredPayloadSchema: Schema.Struct<{
|
|
57
|
+
readonly turn: Schema.Number;
|
|
58
|
+
readonly message: Schema.Struct<{
|
|
59
|
+
readonly role: Schema.Union<readonly [Schema.Literal<"system">, Schema.Literal<"user">, Schema.Literal<"assistant">, Schema.Literal<"tool">]>;
|
|
60
|
+
readonly content: Schema.String;
|
|
61
|
+
readonly toolCallId: Schema.optional<Schema.String>;
|
|
62
|
+
readonly name: Schema.optional<Schema.String>;
|
|
63
|
+
readonly toolCalls: Schema.optional<Schema.mutable<Schema.$Array<Schema.Struct<{
|
|
64
|
+
readonly id: Schema.String;
|
|
65
|
+
readonly name: Schema.String;
|
|
66
|
+
readonly arguments: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
67
|
+
}>>>>;
|
|
68
|
+
}>;
|
|
69
|
+
readonly interrupt: Schema.optional<Schema.Boolean>;
|
|
70
|
+
}>;
|
|
71
|
+
export declare const AgentSpawnRequestedPayloadSchema: Schema.Struct<{
|
|
72
|
+
readonly childThreadId: Schema.String;
|
|
73
|
+
readonly kind: Schema.String;
|
|
74
|
+
readonly definitionName: Schema.String;
|
|
75
|
+
readonly toolCallId: Schema.String;
|
|
76
|
+
readonly input: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
77
|
+
}>;
|
|
78
|
+
export declare const AgentEffectsRequestedPayloadSchema: Schema.Struct<{
|
|
79
|
+
readonly toolCallId: Schema.String;
|
|
80
|
+
readonly effects: Schema.$Array<Schema.Schema<RuntimeEffect>>;
|
|
81
|
+
readonly waitOn: Schema.optional<Schema.Struct<{
|
|
82
|
+
readonly type: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>;
|
|
83
|
+
readonly match: Schema.optional<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
84
|
+
}>>;
|
|
85
|
+
}>;
|
|
86
|
+
export declare const agentCatalog: import("@swirls/looms/core").EventCatalog<"agent", {
|
|
87
|
+
'message.received': Schema.Struct<{
|
|
88
|
+
readonly message: Schema.Struct<{
|
|
89
|
+
readonly role: Schema.Union<readonly [Schema.Literal<"system">, Schema.Literal<"user">, Schema.Literal<"assistant">, Schema.Literal<"tool">]>;
|
|
90
|
+
readonly content: Schema.String;
|
|
91
|
+
readonly toolCallId: Schema.optional<Schema.String>;
|
|
92
|
+
readonly name: Schema.optional<Schema.String>;
|
|
93
|
+
readonly toolCalls: Schema.optional<Schema.mutable<Schema.$Array<Schema.Struct<{
|
|
94
|
+
readonly id: Schema.String;
|
|
95
|
+
readonly name: Schema.String;
|
|
96
|
+
readonly arguments: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
97
|
+
}>>>>;
|
|
98
|
+
}>;
|
|
99
|
+
}>;
|
|
100
|
+
'turn.started': Schema.Struct<{
|
|
101
|
+
readonly turn: Schema.Number;
|
|
102
|
+
}>;
|
|
103
|
+
'turn.text_delta': Schema.Struct<{
|
|
104
|
+
readonly turn: Schema.Number;
|
|
105
|
+
readonly delta: Schema.String;
|
|
106
|
+
}>;
|
|
107
|
+
message: Schema.Struct<{
|
|
108
|
+
readonly turn: Schema.Number;
|
|
109
|
+
readonly message: Schema.Struct<{
|
|
110
|
+
readonly role: Schema.Union<readonly [Schema.Literal<"system">, Schema.Literal<"user">, Schema.Literal<"assistant">, Schema.Literal<"tool">]>;
|
|
111
|
+
readonly content: Schema.String;
|
|
112
|
+
readonly toolCallId: Schema.optional<Schema.String>;
|
|
113
|
+
readonly name: Schema.optional<Schema.String>;
|
|
114
|
+
readonly toolCalls: Schema.optional<Schema.mutable<Schema.$Array<Schema.Struct<{
|
|
115
|
+
readonly id: Schema.String;
|
|
116
|
+
readonly name: Schema.String;
|
|
117
|
+
readonly arguments: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
118
|
+
}>>>>;
|
|
119
|
+
}>;
|
|
120
|
+
readonly usage: Schema.optional<Schema.Struct<{
|
|
121
|
+
readonly input: Schema.Number;
|
|
122
|
+
readonly output: Schema.Number;
|
|
123
|
+
}>>;
|
|
124
|
+
}>;
|
|
125
|
+
'tool_call.requested': Schema.Struct<{
|
|
126
|
+
readonly turn: Schema.Number;
|
|
127
|
+
readonly toolCall: Schema.Struct<{
|
|
128
|
+
readonly id: Schema.String;
|
|
129
|
+
readonly name: Schema.String;
|
|
130
|
+
readonly arguments: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
131
|
+
}>;
|
|
132
|
+
}>;
|
|
133
|
+
'tool.result': Schema.Struct<{
|
|
134
|
+
readonly turn: Schema.Number;
|
|
135
|
+
readonly toolCallId: Schema.String;
|
|
136
|
+
readonly name: Schema.String;
|
|
137
|
+
readonly result: Schema.NullOr<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
138
|
+
readonly error: Schema.NullOr<Schema.String>;
|
|
139
|
+
}>;
|
|
140
|
+
steered: Schema.Struct<{
|
|
141
|
+
readonly turn: Schema.Number;
|
|
142
|
+
readonly message: Schema.Struct<{
|
|
143
|
+
readonly role: Schema.Union<readonly [Schema.Literal<"system">, Schema.Literal<"user">, Schema.Literal<"assistant">, Schema.Literal<"tool">]>;
|
|
144
|
+
readonly content: Schema.String;
|
|
145
|
+
readonly toolCallId: Schema.optional<Schema.String>;
|
|
146
|
+
readonly name: Schema.optional<Schema.String>;
|
|
147
|
+
readonly toolCalls: Schema.optional<Schema.mutable<Schema.$Array<Schema.Struct<{
|
|
148
|
+
readonly id: Schema.String;
|
|
149
|
+
readonly name: Schema.String;
|
|
150
|
+
readonly arguments: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
151
|
+
}>>>>;
|
|
152
|
+
}>;
|
|
153
|
+
readonly interrupt: Schema.optional<Schema.Boolean>;
|
|
154
|
+
}>;
|
|
155
|
+
'spawn.requested': Schema.Struct<{
|
|
156
|
+
readonly childThreadId: Schema.String;
|
|
157
|
+
readonly kind: Schema.String;
|
|
158
|
+
readonly definitionName: Schema.String;
|
|
159
|
+
readonly toolCallId: Schema.String;
|
|
160
|
+
readonly input: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
161
|
+
}>;
|
|
162
|
+
'effects.requested': Schema.Struct<{
|
|
163
|
+
readonly toolCallId: Schema.String;
|
|
164
|
+
readonly effects: Schema.$Array<Schema.Schema<RuntimeEffect>>;
|
|
165
|
+
readonly waitOn: Schema.optional<Schema.Struct<{
|
|
166
|
+
readonly type: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.String>]>;
|
|
167
|
+
readonly match: Schema.optional<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
168
|
+
}>>;
|
|
169
|
+
}>;
|
|
170
|
+
}>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
import { defineEventCatalog } from '@swirls/looms/core';
|
|
3
|
+
import { MessageSchema, TokenUsageSchema, ToolCallSchema } from './types.js';
|
|
4
|
+
export const AgentMessageReceivedPayloadSchema = Schema.Struct({
|
|
5
|
+
message: MessageSchema,
|
|
6
|
+
});
|
|
7
|
+
export const AgentTurnStartedPayloadSchema = Schema.Struct({
|
|
8
|
+
turn: Schema.Number,
|
|
9
|
+
});
|
|
10
|
+
export const AgentTurnTextDeltaPayloadSchema = Schema.Struct({
|
|
11
|
+
turn: Schema.Number,
|
|
12
|
+
delta: Schema.String,
|
|
13
|
+
});
|
|
14
|
+
export const AgentMessageEventPayloadSchema = Schema.Struct({
|
|
15
|
+
turn: Schema.Number,
|
|
16
|
+
message: MessageSchema,
|
|
17
|
+
usage: Schema.optional(TokenUsageSchema),
|
|
18
|
+
});
|
|
19
|
+
export const AgentToolCallRequestedPayloadSchema = Schema.Struct({
|
|
20
|
+
turn: Schema.Number,
|
|
21
|
+
toolCall: ToolCallSchema,
|
|
22
|
+
});
|
|
23
|
+
export const AgentToolResultPayloadSchema = Schema.Struct({
|
|
24
|
+
turn: Schema.Number,
|
|
25
|
+
toolCallId: Schema.String,
|
|
26
|
+
name: Schema.String,
|
|
27
|
+
result: Schema.NullOr(Schema.Json),
|
|
28
|
+
error: Schema.NullOr(Schema.String),
|
|
29
|
+
});
|
|
30
|
+
export const AgentSteeredPayloadSchema = Schema.Struct({
|
|
31
|
+
turn: Schema.Number,
|
|
32
|
+
message: MessageSchema,
|
|
33
|
+
interrupt: Schema.optional(Schema.Boolean),
|
|
34
|
+
});
|
|
35
|
+
export const AgentSpawnRequestedPayloadSchema = Schema.Struct({
|
|
36
|
+
childThreadId: Schema.String,
|
|
37
|
+
kind: Schema.String,
|
|
38
|
+
definitionName: Schema.String,
|
|
39
|
+
toolCallId: Schema.String,
|
|
40
|
+
input: Schema.Json,
|
|
41
|
+
});
|
|
42
|
+
export const AgentEffectsRequestedPayloadSchema = Schema.Struct({
|
|
43
|
+
toolCallId: Schema.String,
|
|
44
|
+
// SAFETY: RuntimeEffect represents serializable requested effect instructions.
|
|
45
|
+
effects: Schema.Array(Schema.Unknown),
|
|
46
|
+
waitOn: Schema.optional(Schema.Struct({
|
|
47
|
+
type: Schema.Union([Schema.String, Schema.Array(Schema.String)]),
|
|
48
|
+
match: Schema.optional(Schema.Json),
|
|
49
|
+
})),
|
|
50
|
+
});
|
|
51
|
+
export const agentCatalog = defineEventCatalog('agent', {
|
|
52
|
+
'message.received': AgentMessageReceivedPayloadSchema,
|
|
53
|
+
'turn.started': AgentTurnStartedPayloadSchema,
|
|
54
|
+
'turn.text_delta': AgentTurnTextDeltaPayloadSchema,
|
|
55
|
+
message: AgentMessageEventPayloadSchema,
|
|
56
|
+
'tool_call.requested': AgentToolCallRequestedPayloadSchema,
|
|
57
|
+
'tool.result': AgentToolResultPayloadSchema,
|
|
58
|
+
steered: AgentSteeredPayloadSchema,
|
|
59
|
+
'spawn.requested': AgentSpawnRequestedPayloadSchema,
|
|
60
|
+
'effects.requested': AgentEffectsRequestedPayloadSchema,
|
|
61
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from './types';
|
|
2
|
+
export * from './stop-when';
|
|
3
|
+
export * from './definitions';
|
|
4
|
+
export * from './definitions-store';
|
|
5
|
+
export * from './events';
|
|
6
|
+
export * from './scope';
|
|
7
|
+
export * from './threads';
|
|
8
|
+
export * from './effects';
|
|
9
|
+
export * from './projections';
|
|
10
|
+
export * from './signals';
|
|
11
|
+
export * from './llm';
|
|
12
|
+
export * from './tool-schema';
|
|
13
|
+
export * from './module';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export * from './stop-when.js';
|
|
3
|
+
export * from './definitions.js';
|
|
4
|
+
export * from './definitions-store.js';
|
|
5
|
+
export * from './events.js';
|
|
6
|
+
export * from './scope.js';
|
|
7
|
+
export * from './threads.js';
|
|
8
|
+
export * from './effects.js';
|
|
9
|
+
export * from './projections.js';
|
|
10
|
+
export * from './signals.js';
|
|
11
|
+
export * from './llm.js';
|
|
12
|
+
export * from './tool-schema.js';
|
|
13
|
+
export * from './module.js';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from 'effect';
|
|
2
|
+
import type { JsonValue } from '@swirls/looms/core';
|
|
3
|
+
import type { AgentTurnContext, AgentTurnResult, ToolLike } from './definitions';
|
|
4
|
+
import type { Message, ToolCall } from './types';
|
|
5
|
+
export interface LlmToolSpec {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly description: string;
|
|
8
|
+
readonly inputJsonSchema: JsonValue;
|
|
9
|
+
}
|
|
10
|
+
export interface LlmCompleteArgs {
|
|
11
|
+
model?: string;
|
|
12
|
+
instructions: string;
|
|
13
|
+
messages: Message[];
|
|
14
|
+
tools: ToolLike[];
|
|
15
|
+
toolSpecs?: LlmToolSpec[];
|
|
16
|
+
onTextDelta?: (delta: string) => void | Promise<void>;
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
}
|
|
19
|
+
export interface LlmService {
|
|
20
|
+
readonly complete: (args: LlmCompleteArgs) => Effect.Effect<AgentTurnResult, Error>;
|
|
21
|
+
}
|
|
22
|
+
export interface LlmAdapter {
|
|
23
|
+
readonly complete: (args: LlmCompleteArgs) => Promise<AgentTurnResult>;
|
|
24
|
+
}
|
|
25
|
+
export declare function llmFromAdapter(adapter: LlmAdapter): LlmService;
|
|
26
|
+
declare const LlmTag_base: Context.ServiceClass<LlmTag, "looms/Llm", LlmService>;
|
|
27
|
+
export declare class LlmTag extends LlmTag_base {
|
|
28
|
+
}
|
|
29
|
+
export interface StubLlmPolicy {
|
|
30
|
+
toolCallsFor?: (ctx: AgentTurnContext) => ToolCall[] | undefined;
|
|
31
|
+
doneAfterText?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export declare const makeStubLlm: (policy?: StubLlmPolicy) => LlmService;
|
|
34
|
+
export declare const StubLlmLive: (policy?: StubLlmPolicy) => Layer.Layer<LlmTag, never, never>;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Predicate } from 'effect';
|
|
2
|
+
export function llmFromAdapter(adapter) {
|
|
3
|
+
return {
|
|
4
|
+
complete: (args) => Effect.tryPromise({
|
|
5
|
+
try: () => adapter.complete(args),
|
|
6
|
+
catch: (cause) => (cause instanceof Error ? cause : new Error(String(cause))),
|
|
7
|
+
}),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export class LlmTag extends Context.Service()('looms/Llm') {
|
|
11
|
+
}
|
|
12
|
+
export const makeStubLlm = (policy = {}) => ({
|
|
13
|
+
complete: (args) => Effect.sync(() => {
|
|
14
|
+
const ctx = {
|
|
15
|
+
threadId: 'stub',
|
|
16
|
+
turn: 0,
|
|
17
|
+
messages: args.messages,
|
|
18
|
+
input: null,
|
|
19
|
+
tools: args.tools,
|
|
20
|
+
instructions: args.instructions,
|
|
21
|
+
};
|
|
22
|
+
const toolCalls = policy.toolCallsFor?.(ctx);
|
|
23
|
+
if (toolCalls && toolCalls.length > 0) {
|
|
24
|
+
return {
|
|
25
|
+
message: { role: 'assistant', content: '', toolCalls },
|
|
26
|
+
toolCalls,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
let lastUser;
|
|
30
|
+
for (let i = args.messages.length - 1; i >= 0; i--) {
|
|
31
|
+
const item = args.messages[i];
|
|
32
|
+
if (item?.role === 'user') {
|
|
33
|
+
lastUser = item;
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const lastContent = args.messages.at(-1)?.content;
|
|
38
|
+
const content = lastUser?.content ??
|
|
39
|
+
(Predicate.isString(lastContent) ? lastContent : JSON.stringify(lastContent ?? null));
|
|
40
|
+
return {
|
|
41
|
+
message: { role: 'assistant', content },
|
|
42
|
+
done: policy.doneAfterText !== false,
|
|
43
|
+
output: { text: content },
|
|
44
|
+
usage: { input: 0, output: content.length },
|
|
45
|
+
};
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
export const StubLlmLive = (policy) => Layer.succeed(LlmTag, makeStubLlm(policy));
|