@relayfx/sdk 0.3.1 → 0.3.3
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/dist/ai.js +67 -37
- package/dist/http-server.js +22 -0
- package/dist/index-25gwk9tj.js +3423 -0
- package/dist/{index-3sv8mmz5.js → index-49fm2rdv.js} +23 -30
- package/dist/{index-c2skef55.js → index-8pa5e2yn.js} +16521 -18783
- package/dist/index-cphmds30.js +2852 -0
- package/dist/index-nb39b5ae.js +17 -0
- package/dist/index.js +315 -844
- package/dist/mysql.js +18 -18
- package/dist/postgres.js +724 -24
- package/dist/sqlite.js +57 -168
- package/dist/types/ai/index.d.ts +2 -1
- package/dist/types/ai/language-model/language-model-registration.d.ts +9 -6
- package/dist/types/relay/adapter-outbox.d.ts +1 -1
- package/dist/types/relay/ai.d.ts +34 -2
- package/dist/types/relay/child-fan-out-admission.d.ts +5 -0
- package/dist/types/relay/child-fan-out-host.d.ts +73 -0
- package/dist/types/relay/client-public.d.ts +481 -0
- package/dist/types/relay/client.d.ts +1 -478
- package/dist/types/relay/database-identity.d.ts +4 -0
- package/dist/types/relay/http-server.d.ts +95 -0
- package/dist/types/relay/index.d.ts +37 -14
- package/dist/types/relay/internal-client.d.ts +22 -0
- package/dist/types/relay/language-model-registration.d.ts +13 -0
- package/dist/types/relay/mysql.d.ts +6 -7
- package/dist/types/relay/operation.d.ts +4 -4
- package/dist/types/relay/postgres.d.ts +10 -7
- package/dist/types/relay/runtime-acquisition-error.d.ts +61 -0
- package/dist/types/relay/runtime-database-adapter.d.ts +8 -5
- package/dist/types/relay/runtime-database-owner.d.ts +13 -0
- package/dist/types/relay/runtime-database-public.d.ts +10 -0
- package/dist/types/relay/runtime.d.ts +77 -72
- package/dist/types/relay/sqlite-runtime.d.ts +5 -18
- package/dist/types/relay/sqlite.d.ts +4 -31
- package/dist/types/relay/state-version-conflict.d.ts +12 -0
- package/dist/types/relay/tool-runtime.d.ts +44 -0
- package/dist/types/relay/tool-worker.d.ts +2 -2
- package/dist/types/relay/workflow-definition-host.d.ts +32 -0
- package/dist/types/runtime/agent/agent-loop-error.d.ts +21 -0
- package/dist/types/runtime/agent/agent-loop-service.d.ts +6 -16
- package/dist/types/runtime/agent/prompt-assembler-service.d.ts +3 -3
- package/dist/types/runtime/cluster/execution-entity.d.ts +3 -3
- package/dist/types/runtime/execution/execution-service.d.ts +3 -0
- package/dist/types/runtime/index.d.ts +1 -0
- package/dist/types/runtime/model/language-model-service.d.ts +5 -12
- package/dist/types/runtime/model/model-hub.d.ts +27 -0
- package/dist/types/runtime/presence/presence-contract.d.ts +24 -0
- package/dist/types/runtime/presence/presence-service.d.ts +6 -24
- package/dist/types/runtime/runner/runner-runtime-service.d.ts +29 -13
- package/dist/types/runtime/session/session-store-service.d.ts +4 -1
- package/dist/types/runtime/tool/tool-runtime-contract.d.ts +121 -0
- package/dist/types/runtime/tool/tool-runtime-service.d.ts +6 -120
- package/dist/types/runtime/workflow/execution-workflow.d.ts +22 -24
- package/dist/types/schema/agent-schema.d.ts +4 -1
- package/dist/types/schema/execution-schema.d.ts +13 -2
- package/dist/types/schema/index.d.ts +1 -0
- package/dist/types/schema/pagination-schema.d.ts +17 -0
- package/dist/types/schema/shared-schema.d.ts +4 -0
- package/dist/types/store-sql/schema/relay-schema.d.ts +12 -12
- package/dist/types/store-sql/session/session-repository.d.ts +54 -11
- package/package.json +17 -14
- package/dist/index-9k4k3wq1.js +0 -2860
- package/dist/index-d3dme13d.js +0 -141
- package/dist/types/relay/database.d.ts +0 -16
|
@@ -0,0 +1,3423 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
__export
|
|
4
|
+
} from "./index-nb39b5ae.js";
|
|
5
|
+
|
|
6
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/turn-policy.js
|
|
7
|
+
var exports_turn_policy = {};
|
|
8
|
+
__export(exports_turn_policy, {
|
|
9
|
+
untilToolCall: () => untilToolCall,
|
|
10
|
+
recurs: () => recurs,
|
|
11
|
+
make: () => make,
|
|
12
|
+
fromLegacy: () => fromLegacy,
|
|
13
|
+
forever: () => forever,
|
|
14
|
+
defaultPolicy: () => defaultPolicy,
|
|
15
|
+
decision: () => decision,
|
|
16
|
+
both: () => both,
|
|
17
|
+
TurnPolicyError: () => TurnPolicyError,
|
|
18
|
+
StopReason: () => StopReason
|
|
19
|
+
});
|
|
20
|
+
import { Effect, Layer, Schema } from "effect";
|
|
21
|
+
import { dual } from "effect/Function";
|
|
22
|
+
import { LanguageModel, Prompt, Response } from "effect/unstable/ai";
|
|
23
|
+
var StopReason = Schema.Union([
|
|
24
|
+
Schema.Struct({ _tag: Schema.tag("TurnLimit"), limit: Schema.Finite }),
|
|
25
|
+
Schema.Struct({ _tag: Schema.tag("GoalSatisfied") }),
|
|
26
|
+
Schema.Struct({ _tag: Schema.tag("BudgetExhausted"), budget: Schema.String }),
|
|
27
|
+
Schema.Struct({ _tag: Schema.tag("Policy"), detail: Schema.String })
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
class TurnPolicyError extends Schema.TaggedErrorClass()("@batonfx/core/TurnPolicyError", {
|
|
31
|
+
message: Schema.String,
|
|
32
|
+
cause: Schema.optionalKey(Schema.Defect())
|
|
33
|
+
}) {
|
|
34
|
+
}
|
|
35
|
+
var decision = {
|
|
36
|
+
continue: (overrides) => ({
|
|
37
|
+
_tag: "Continue",
|
|
38
|
+
...overrides === undefined ? {} : { overrides }
|
|
39
|
+
}),
|
|
40
|
+
stop: (reason) => ({ _tag: "Stop", reason })
|
|
41
|
+
};
|
|
42
|
+
var make = (decide) => ({ decide });
|
|
43
|
+
var fromLegacy = (decide) => make((info) => decide(info).pipe(Effect.map((result) => result._tag === "Stop" ? decision.stop({ _tag: "Policy", detail: "Legacy policy stopped" }) : result)));
|
|
44
|
+
var forever = {
|
|
45
|
+
decide: () => Effect.succeed(decision.continue()),
|
|
46
|
+
snapshot: { _tag: "Forever" }
|
|
47
|
+
};
|
|
48
|
+
var recurs = (n) => ({
|
|
49
|
+
decide: (info) => Effect.succeed(info.turn < n + 1 ? decision.continue() : decision.stop(Number.isFinite(n) ? { _tag: "TurnLimit", limit: n } : { _tag: "Policy", detail: `Non-finite recurrence count stopped: ${String(n)}` })),
|
|
50
|
+
...Number.isFinite(n) ? { snapshot: { _tag: "Recurs", count: n } } : {}
|
|
51
|
+
});
|
|
52
|
+
var untilToolCall = (name) => ({
|
|
53
|
+
decide: (info) => Effect.succeed(info.pendingToolResults.some((result) => result.name === name) ? decision.stop({ _tag: "GoalSatisfied" }) : decision.continue()),
|
|
54
|
+
snapshot: { _tag: "UntilToolCall", name }
|
|
55
|
+
});
|
|
56
|
+
var mergeOverrides = (first, second) => {
|
|
57
|
+
if (first === undefined)
|
|
58
|
+
return second;
|
|
59
|
+
if (second === undefined)
|
|
60
|
+
return first;
|
|
61
|
+
return { ...first, ...second };
|
|
62
|
+
};
|
|
63
|
+
var both = dual(2, (first, second) => ({
|
|
64
|
+
decide: (info) => Effect.gen(function* () {
|
|
65
|
+
const left = yield* first.decide(info);
|
|
66
|
+
if (left._tag === "Stop")
|
|
67
|
+
return left;
|
|
68
|
+
const right = yield* second.decide(info);
|
|
69
|
+
if (right._tag === "Stop")
|
|
70
|
+
return right;
|
|
71
|
+
return decision.continue(mergeOverrides(left.overrides, right.overrides));
|
|
72
|
+
}),
|
|
73
|
+
...first.snapshot === undefined || second.snapshot === undefined ? {} : { snapshot: { _tag: "Both", first: first.snapshot, second: second.snapshot } }
|
|
74
|
+
}));
|
|
75
|
+
var defaultPolicy = forever;
|
|
76
|
+
|
|
77
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/agent-event.js
|
|
78
|
+
var exports_agent_event = {};
|
|
79
|
+
__export(exports_agent_event, {
|
|
80
|
+
addUsage: () => addUsage,
|
|
81
|
+
TurnPolicyStopped: () => TurnPolicyStopped,
|
|
82
|
+
TurnLimitExceeded: () => TurnLimitExceeded,
|
|
83
|
+
ToolOrigin: () => ToolOrigin,
|
|
84
|
+
ToolNameCollision: () => ToolNameCollision,
|
|
85
|
+
ResumeMismatch: () => ResumeMismatch,
|
|
86
|
+
ProgressOverflowError: () => ProgressOverflowError,
|
|
87
|
+
MiddlewareViolation: () => MiddlewareViolation,
|
|
88
|
+
DuplicateToolCallId: () => DuplicateToolCallId,
|
|
89
|
+
AgentSuspended: () => AgentSuspended,
|
|
90
|
+
AgentError: () => AgentError
|
|
91
|
+
});
|
|
92
|
+
import { Function, Schema as Schema2 } from "effect";
|
|
93
|
+
import { Prompt as Prompt2, Response as Response2, Tool } from "effect/unstable/ai";
|
|
94
|
+
var addUsageField = (left, right) => left === undefined && right === undefined ? undefined : (left ?? 0) + (right ?? 0);
|
|
95
|
+
var addUsage = Function.dual(2, (left, right) => Response2.Usage.make({
|
|
96
|
+
inputTokens: {
|
|
97
|
+
uncached: addUsageField(left.inputTokens.uncached, right.inputTokens.uncached),
|
|
98
|
+
total: addUsageField(left.inputTokens.total, right.inputTokens.total),
|
|
99
|
+
cacheRead: addUsageField(left.inputTokens.cacheRead, right.inputTokens.cacheRead),
|
|
100
|
+
cacheWrite: addUsageField(left.inputTokens.cacheWrite, right.inputTokens.cacheWrite)
|
|
101
|
+
},
|
|
102
|
+
outputTokens: {
|
|
103
|
+
total: addUsageField(left.outputTokens.total, right.outputTokens.total),
|
|
104
|
+
text: addUsageField(left.outputTokens.text, right.outputTokens.text),
|
|
105
|
+
reasoning: addUsageField(left.outputTokens.reasoning, right.outputTokens.reasoning)
|
|
106
|
+
}
|
|
107
|
+
}));
|
|
108
|
+
|
|
109
|
+
class AgentError extends Schema2.TaggedErrorClass()("@batonfx/core/AgentError", {
|
|
110
|
+
message: Schema2.String,
|
|
111
|
+
turn: Schema2.Finite,
|
|
112
|
+
cause: Schema2.optionalKey(Schema2.Defect())
|
|
113
|
+
}) {
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
class TurnLimitExceeded extends Schema2.TaggedErrorClass()("@batonfx/core/TurnLimitExceeded", {
|
|
117
|
+
turn: Schema2.Finite,
|
|
118
|
+
limit: Schema2.Finite,
|
|
119
|
+
pending: Schema2.Array(Schema2.Struct({
|
|
120
|
+
tool_call_id: Schema2.String,
|
|
121
|
+
tool_name: Schema2.String
|
|
122
|
+
}))
|
|
123
|
+
}) {
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
class TurnPolicyStopped extends Schema2.TaggedErrorClass()("@batonfx/core/TurnPolicyStopped", {
|
|
127
|
+
turn: Schema2.Finite,
|
|
128
|
+
reason: StopReason,
|
|
129
|
+
pending: Schema2.Array(Schema2.Struct({
|
|
130
|
+
tool_call_id: Schema2.String,
|
|
131
|
+
tool_name: Schema2.String
|
|
132
|
+
}))
|
|
133
|
+
}) {
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
class MiddlewareViolation extends Schema2.TaggedErrorClass()("@batonfx/core/MiddlewareViolation", {
|
|
137
|
+
turn: Schema2.Finite,
|
|
138
|
+
detail: Schema2.String
|
|
139
|
+
}) {
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
class DuplicateToolCallId extends Schema2.TaggedErrorClass()("@batonfx/core/DuplicateToolCallId", {
|
|
143
|
+
id: Schema2.String,
|
|
144
|
+
firstIndex: Schema2.Finite,
|
|
145
|
+
duplicateIndex: Schema2.Finite
|
|
146
|
+
}) {
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
class ProgressOverflowError extends Schema2.TaggedErrorClass()("@batonfx/core/ProgressOverflowError", {
|
|
150
|
+
turn: Schema2.Finite,
|
|
151
|
+
toolCallId: Schema2.String,
|
|
152
|
+
capacity: Schema2.Finite
|
|
153
|
+
}) {
|
|
154
|
+
}
|
|
155
|
+
var ToolOrigin = Schema2.Union([
|
|
156
|
+
Schema2.TaggedStruct("Static", { agent: Schema2.String }),
|
|
157
|
+
Schema2.TaggedStruct("Builtin", { builtin: Schema2.Literal("activate_skill") }),
|
|
158
|
+
Schema2.TaggedStruct("Skill", { skill: Schema2.String }),
|
|
159
|
+
Schema2.TaggedStruct("Handoff", { specialist: Schema2.String })
|
|
160
|
+
]);
|
|
161
|
+
|
|
162
|
+
class ToolNameCollision extends Schema2.TaggedErrorClass()("@batonfx/core/ToolNameCollision", {
|
|
163
|
+
name: Schema2.String,
|
|
164
|
+
origins: Schema2.NonEmptyArray(ToolOrigin)
|
|
165
|
+
}) {
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
class AgentSuspended extends Schema2.TaggedErrorClass()("@batonfx/core/AgentSuspended", {
|
|
169
|
+
token: Schema2.String,
|
|
170
|
+
reason: Schema2.Literals(["tool-wait", "approval"]),
|
|
171
|
+
authorization_stage: Schema2.optional(Schema2.Literals(["permission", "approval"])),
|
|
172
|
+
tool_call_id: Schema2.String,
|
|
173
|
+
tool_name: Schema2.String,
|
|
174
|
+
tool_params: Schema2.Unknown,
|
|
175
|
+
active_tools: Schema2.optional(Schema2.Array(Schema2.String)),
|
|
176
|
+
activated_skills: Schema2.optional(Schema2.Array(Schema2.String))
|
|
177
|
+
}) {
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
class ResumeMismatch extends Schema2.TaggedErrorClass()("@batonfx/core/ResumeMismatch", {
|
|
181
|
+
reason: Schema2.Literals(["checkpoint-not-found", "identity-mismatch"]),
|
|
182
|
+
expected: Schema2.optional(AgentSuspended),
|
|
183
|
+
received: AgentSuspended
|
|
184
|
+
}) {
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/tool-context.js
|
|
188
|
+
var exports_tool_context = {};
|
|
189
|
+
__export(exports_tool_context, {
|
|
190
|
+
testLayer: () => testLayer,
|
|
191
|
+
layerDefault: () => layerDefault,
|
|
192
|
+
ToolContext: () => ToolContext
|
|
193
|
+
});
|
|
194
|
+
import { Context, Effect as Effect2, Layer as Layer2 } from "effect";
|
|
195
|
+
|
|
196
|
+
class ToolContext extends Context.Service()("@batonfx/core/tool-context/ToolContext") {
|
|
197
|
+
}
|
|
198
|
+
var layerDefault = Layer2.sync(ToolContext, () => ToolContext.of({
|
|
199
|
+
signal: new AbortController().signal,
|
|
200
|
+
emit: () => Effect2.void,
|
|
201
|
+
sessionId: "local"
|
|
202
|
+
}));
|
|
203
|
+
var testLayer = (implementation) => Layer2.succeed(ToolContext, ToolContext.of(implementation));
|
|
204
|
+
|
|
205
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/tool-executor.js
|
|
206
|
+
var exports_tool_executor = {};
|
|
207
|
+
__export(exports_tool_executor, {
|
|
208
|
+
testLayer: () => testLayer2,
|
|
209
|
+
sandbox: () => sandbox,
|
|
210
|
+
router: () => router,
|
|
211
|
+
routeToolkit: () => routeToolkit,
|
|
212
|
+
route: () => route,
|
|
213
|
+
remote: () => remote,
|
|
214
|
+
mcp: () => mcp,
|
|
215
|
+
fromToolkit: () => fromToolkit,
|
|
216
|
+
executeToolkit: () => executeToolkit,
|
|
217
|
+
client: () => client,
|
|
218
|
+
ToolExecutor: () => ToolExecutor,
|
|
219
|
+
RemoteRetryError: () => RemoteRetryError,
|
|
220
|
+
FrameworkStage: () => FrameworkStage,
|
|
221
|
+
FrameworkFailure: () => FrameworkFailure
|
|
222
|
+
});
|
|
223
|
+
import { Context as Context2, Effect as Effect3, Layer as Layer3, Option, Schedule, Schema as Schema3, Sink, Stream } from "effect";
|
|
224
|
+
import { AiError, Response as Response3, Tool as Tool2, Toolkit } from "effect/unstable/ai";
|
|
225
|
+
var FrameworkStage = Schema3.Literals([
|
|
226
|
+
"decode-input",
|
|
227
|
+
"handler",
|
|
228
|
+
"encode-success",
|
|
229
|
+
"encode-domain-failure",
|
|
230
|
+
"missing-handler",
|
|
231
|
+
"route",
|
|
232
|
+
"placement",
|
|
233
|
+
"authorization"
|
|
234
|
+
]);
|
|
235
|
+
|
|
236
|
+
class FrameworkFailure extends Schema3.TaggedErrorClass()("@batonfx/core/FrameworkFailure", {
|
|
237
|
+
stage: FrameworkStage,
|
|
238
|
+
tool: Schema3.String,
|
|
239
|
+
message: Schema3.String
|
|
240
|
+
}) {
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
class RemoteRetryError extends Schema3.TaggedErrorClass()("@batonfx/core/RemoteRetryError", {
|
|
244
|
+
reason: Schema3.Literals(["invalid-max-retries", "missing-operation-key", "changed-operation-key"]),
|
|
245
|
+
message: Schema3.String
|
|
246
|
+
}) {
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
class ToolExecutor extends Context2.Service()("@batonfx/core/tool-executor/ToolExecutor") {
|
|
250
|
+
}
|
|
251
|
+
var resultMessage = (result) => {
|
|
252
|
+
if (typeof result === "string")
|
|
253
|
+
return result;
|
|
254
|
+
if (result instanceof Error)
|
|
255
|
+
return `${result.name}: ${result.message}`;
|
|
256
|
+
try {
|
|
257
|
+
const message = JSON.stringify(result);
|
|
258
|
+
return message === undefined ? String(result) : message;
|
|
259
|
+
} catch {
|
|
260
|
+
return String(result);
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
var schemaMessage = (error) => error instanceof Error ? error.message : typeof error === "string" ? error : resultMessage(error);
|
|
264
|
+
var frameworkFailure = (stage, tool, error) => FrameworkFailure.make({ stage, tool, message: schemaMessage(error) });
|
|
265
|
+
var encodeSuccess = (tool, result) => {
|
|
266
|
+
const schema = tool.successSchema;
|
|
267
|
+
return Schema3.encodeUnknownEffect(schema)(result).pipe(Effect3.map((encodedResult) => ({ _tag: "Success", result, encodedResult })), Effect3.mapError((error) => frameworkFailure("encode-success", tool.name, error)));
|
|
268
|
+
};
|
|
269
|
+
var encodeDomainFailure = (tool, failure) => {
|
|
270
|
+
const schema = tool.failureSchema;
|
|
271
|
+
return Schema3.encodeUnknownEffect(schema)(failure).pipe(Effect3.map((encodedFailure) => ({ _tag: "DomainFailure", failure, encodedFailure })), Effect3.mapError((error) => frameworkFailure("encode-domain-failure", tool.name, error)));
|
|
272
|
+
};
|
|
273
|
+
var encodeDomainCandidate = (tool, failure) => !Schema3.is(tool.failureSchema)(failure) ? Effect3.fail(frameworkFailure("handler", tool.name, failure)) : encodeDomainFailure(tool, failure);
|
|
274
|
+
var decodeInput = (tool, input) => {
|
|
275
|
+
const schema = tool.parametersSchema;
|
|
276
|
+
return Schema3.decodeUnknownEffect(schema)(input).pipe(Effect3.asVoid, Effect3.mapError((error) => frameworkFailure("decode-input", tool.name, error)));
|
|
277
|
+
};
|
|
278
|
+
var decodeSuccess = (tool, result) => {
|
|
279
|
+
const schema = tool.successSchema;
|
|
280
|
+
return Schema3.decodeUnknownEffect(schema)(result).pipe(Effect3.mapError((error) => frameworkFailure("encode-success", tool.name, error)), Effect3.flatMap((decoded) => encodeSuccess(tool, decoded)));
|
|
281
|
+
};
|
|
282
|
+
var aiFrameworkFailure = (tool, error) => {
|
|
283
|
+
switch (error.reason._tag) {
|
|
284
|
+
case "ToolParameterValidationError":
|
|
285
|
+
return frameworkFailure("decode-input", tool.name, error);
|
|
286
|
+
case "ToolNotFoundError":
|
|
287
|
+
return frameworkFailure("missing-handler", tool.name, error);
|
|
288
|
+
case "InvalidToolResultError":
|
|
289
|
+
return frameworkFailure("handler", tool.name, error);
|
|
290
|
+
case "ToolResultEncodingError": {
|
|
291
|
+
if (tool.failureMode === "error")
|
|
292
|
+
return frameworkFailure("encode-success", tool.name, error);
|
|
293
|
+
const isSuccess = Schema3.isSchema(tool.successSchema) && Schema3.is(tool.successSchema)(error.reason.toolResult);
|
|
294
|
+
const isDomainFailure = Schema3.isSchema(tool.failureSchema) && Schema3.is(tool.failureSchema)(error.reason.toolResult);
|
|
295
|
+
return frameworkFailure(isSuccess === isDomainFailure ? "handler" : isDomainFailure ? "encode-domain-failure" : "encode-success", tool.name, error);
|
|
296
|
+
}
|
|
297
|
+
default:
|
|
298
|
+
return frameworkFailure("handler", tool.name, error);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
var placementOutcome = (placement, tool, response) => {
|
|
302
|
+
if (typeof response !== "object" || response === null || !("_tag" in response)) {
|
|
303
|
+
return Effect3.fail(frameworkFailure("placement", tool.name, "Placement returned an invalid response"));
|
|
304
|
+
}
|
|
305
|
+
switch (response._tag) {
|
|
306
|
+
case "DomainFailure":
|
|
307
|
+
return "failure" in response ? encodeDomainFailure(tool, response.failure) : Effect3.fail(frameworkFailure("placement", tool.name, "DomainFailure response is missing failure"));
|
|
308
|
+
case "Suspend":
|
|
309
|
+
return "token" in response && typeof response.token === "string" ? Effect3.succeed({ _tag: "Suspend", token: response.token }) : Effect3.fail(frameworkFailure("placement", tool.name, "Suspend response is missing a string token"));
|
|
310
|
+
case "Success":
|
|
311
|
+
return "result" in response ? decodeSuccess(tool, response.result).pipe(Effect3.mapError((error) => FrameworkFailure.make({ ...error, message: `${placement} result: ${error.message}` }))) : Effect3.fail(frameworkFailure("placement", tool.name, "Success response is missing result"));
|
|
312
|
+
default:
|
|
313
|
+
return Effect3.fail(frameworkFailure("placement", tool.name, "Placement returned an unknown response tag"));
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
var findTool = (tools, name) => tools[name];
|
|
317
|
+
var executeWithToolkit = (toolkit, request) => {
|
|
318
|
+
const tool = findTool(toolkit.tools, request.call.name);
|
|
319
|
+
if (tool === undefined) {
|
|
320
|
+
return Effect3.fail(frameworkFailure("missing-handler", request.call.name, `Tool ${request.call.name} is not registered`));
|
|
321
|
+
}
|
|
322
|
+
const handleFailure = (error) => {
|
|
323
|
+
if (Schema3.is(FrameworkFailure)(error))
|
|
324
|
+
return Effect3.fail(error);
|
|
325
|
+
if (AiError.isAiError(error))
|
|
326
|
+
return Effect3.fail(aiFrameworkFailure(tool, error));
|
|
327
|
+
return encodeDomainCandidate(tool, error);
|
|
328
|
+
};
|
|
329
|
+
return toolkit.handle(request.call.name, request.call.params).pipe(Effect3.flatMap((results) => results.pipe(Stream.filter((item) => item.preliminary === false), Stream.run(Sink.last()))), Effect3.flatMap((option) => {
|
|
330
|
+
if (Option.isNone(option)) {
|
|
331
|
+
return Effect3.fail(frameworkFailure("handler", tool.name, "Tool handler did not produce a final result"));
|
|
332
|
+
}
|
|
333
|
+
const result = option.value;
|
|
334
|
+
if (!result.isFailure) {
|
|
335
|
+
return Effect3.succeed({ _tag: "Success", result: result.result, encodedResult: result.encodedResult });
|
|
336
|
+
}
|
|
337
|
+
return AiError.isAiError(result.result) ? Effect3.fail(aiFrameworkFailure(tool, result.result)) : encodeDomainFailure(tool, result.result);
|
|
338
|
+
}), Effect3.catchIf(() => true, handleFailure, handleFailure));
|
|
339
|
+
};
|
|
340
|
+
function executeToolkit(toolkitOrRequest, request) {
|
|
341
|
+
if (request === undefined) {
|
|
342
|
+
let pipeable = function(toolkit2) {
|
|
343
|
+
return "handle" in toolkit2 ? executeWithToolkit(toolkit2, pipeableRequest) : executeToolkit(toolkit2, pipeableRequest);
|
|
344
|
+
};
|
|
345
|
+
const pipeableRequest = toolkitOrRequest;
|
|
346
|
+
return pipeable;
|
|
347
|
+
}
|
|
348
|
+
const toolkit = toolkitOrRequest;
|
|
349
|
+
return ("handle" in toolkit ? Effect3.succeed(toolkit) : toolkit).pipe(Effect3.flatMap((handled) => executeWithToolkit(handled, request)));
|
|
350
|
+
}
|
|
351
|
+
function fromToolkit(toolkit) {
|
|
352
|
+
return Layer3.effect(ToolExecutor, ("handle" in toolkit ? Effect3.succeed(toolkit) : toolkit).pipe(Effect3.map((handled) => ToolExecutor.of({
|
|
353
|
+
execute: (request) => executeWithToolkit(handled, request)
|
|
354
|
+
}))));
|
|
355
|
+
}
|
|
356
|
+
var route = (options) => {
|
|
357
|
+
const routedTools = options.tools ?? [];
|
|
358
|
+
return {
|
|
359
|
+
tools: routedTools,
|
|
360
|
+
matches: (request) => routedTools.includes(request.call.name) || options.matches?.(request) === true,
|
|
361
|
+
execute: options.execute
|
|
362
|
+
};
|
|
363
|
+
};
|
|
364
|
+
var placementRoute = (placement, options) => {
|
|
365
|
+
const routedTools = options.tools ?? Object.keys(options.toolkit.tools);
|
|
366
|
+
return route({
|
|
367
|
+
tools: routedTools,
|
|
368
|
+
execute: (request) => {
|
|
369
|
+
const tool = findTool(options.toolkit.tools, request.call.name);
|
|
370
|
+
if (tool === undefined) {
|
|
371
|
+
return Effect3.fail(frameworkFailure("missing-handler", request.call.name, `Tool ${request.call.name} is not registered`));
|
|
372
|
+
}
|
|
373
|
+
return decodeInput(tool, request.call.params).pipe(Effect3.flatMap(() => {
|
|
374
|
+
const effect = options.execute({ ...request, placement, tool });
|
|
375
|
+
return effect;
|
|
376
|
+
}), Effect3.mapError((error) => Schema3.is(FrameworkFailure)(error) || Schema3.is(RemoteRetryError)(error) ? error : frameworkFailure("placement", request.call.name, error)), Effect3.flatMap((response) => placementOutcome(placement, tool, response)));
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
};
|
|
380
|
+
var remoteRetryError = (reason, message) => RemoteRetryError.make({ reason, message });
|
|
381
|
+
var validateOperationKey = (operationKey) => typeof operationKey !== "string" || operationKey.trim().length === 0 ? Effect3.fail(remoteRetryError("missing-operation-key", "Remote retry operation key must be non-empty")) : Effect3.succeed(operationKey);
|
|
382
|
+
var retryRemote = (options, request) => Effect3.suspend(() => {
|
|
383
|
+
if (!Number.isFinite(options.maxRetries) || !Number.isInteger(options.maxRetries) || options.maxRetries < 0) {
|
|
384
|
+
return Effect3.fail(remoteRetryError("invalid-max-retries", "Remote retry maxRetries must be a non-negative finite integer"));
|
|
385
|
+
}
|
|
386
|
+
const operationKey = typeof options.operationKey === "function" ? options.operationKey(request) : undefined;
|
|
387
|
+
return validateOperationKey(operationKey).pipe(Effect3.flatMap((stableKey) => {
|
|
388
|
+
let attempt = 0;
|
|
389
|
+
const executeAttempt = Effect3.suspend(() => {
|
|
390
|
+
const currentKey = attempt === 0 ? stableKey : options.operationKey(request);
|
|
391
|
+
attempt += 1;
|
|
392
|
+
return validateOperationKey(currentKey).pipe(Effect3.match({
|
|
393
|
+
onFailure: (error) => error,
|
|
394
|
+
onSuccess: (validatedKey) => validatedKey
|
|
395
|
+
}), Effect3.flatMap((validatedKey) => typeof validatedKey !== "string" ? Effect3.succeed(validatedKey) : validatedKey === stableKey ? options.execute({ ...request, operationKey: stableKey }) : Effect3.succeed(remoteRetryError("changed-operation-key", "Remote retry operation key changed between attempts"))));
|
|
396
|
+
});
|
|
397
|
+
return Effect3.retry(executeAttempt, {
|
|
398
|
+
schedule: options.schedule,
|
|
399
|
+
times: options.maxRetries,
|
|
400
|
+
while: (error) => !Schema3.is(AgentError)(error) && !Schema3.is(FrameworkFailure)(error) && !Schema3.is(RemoteRetryError)(error)
|
|
401
|
+
}).pipe(Effect3.flatMap((result) => Schema3.is(RemoteRetryError)(result) ? Effect3.fail(result) : Effect3.succeed(result)));
|
|
402
|
+
}));
|
|
403
|
+
});
|
|
404
|
+
var client = (options) => placementRoute("client", options);
|
|
405
|
+
var remote = (options) => options.retrySafe === true ? placementRoute("remote", {
|
|
406
|
+
toolkit: options.toolkit,
|
|
407
|
+
...options.tools === undefined ? {} : { tools: options.tools },
|
|
408
|
+
execute: (request) => retryRemote(options, request)
|
|
409
|
+
}) : placementRoute("remote", options);
|
|
410
|
+
var mcp = (options) => placementRoute("mcp", options);
|
|
411
|
+
var sandbox = (options) => placementRoute("sandbox", options);
|
|
412
|
+
function routeToolkit(toolkit) {
|
|
413
|
+
const makeRoute = (handled) => route({
|
|
414
|
+
tools: Object.keys(handled.tools),
|
|
415
|
+
execute: (request) => executeWithToolkit(handled, request)
|
|
416
|
+
});
|
|
417
|
+
return "handle" in toolkit ? makeRoute(toolkit) : toolkit.pipe(Effect3.map(makeRoute));
|
|
418
|
+
}
|
|
419
|
+
var routeInputEffect = (input) => Effect3.isEffect(input) ? input : Effect3.succeed(input);
|
|
420
|
+
function router(routes) {
|
|
421
|
+
return Layer3.effect(ToolExecutor, Effect3.all(Array.from(routes, routeInputEffect)).pipe(Effect3.map((resolved) => ToolExecutor.of({
|
|
422
|
+
execute: (request) => {
|
|
423
|
+
const matched = resolved.find((candidate) => candidate.matches(request));
|
|
424
|
+
return matched === undefined ? Effect3.fail(frameworkFailure("route", request.call.name, `Tool ${request.call.name} has no matching route`)) : matched.execute(request);
|
|
425
|
+
}
|
|
426
|
+
}))));
|
|
427
|
+
}
|
|
428
|
+
var testLayer2 = (implementation) => Layer3.succeed(ToolExecutor, ToolExecutor.of(implementation));
|
|
429
|
+
|
|
430
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/approvals.js
|
|
431
|
+
var exports_approvals = {};
|
|
432
|
+
__export(exports_approvals, {
|
|
433
|
+
testLayer: () => testLayer3,
|
|
434
|
+
denyAll: () => denyAll,
|
|
435
|
+
autoApprove: () => autoApprove,
|
|
436
|
+
Approvals: () => Approvals
|
|
437
|
+
});
|
|
438
|
+
import { Context as Context3, Effect as Effect4, Layer as Layer4 } from "effect";
|
|
439
|
+
class Approvals extends Context3.Service()("@batonfx/core/approvals") {
|
|
440
|
+
}
|
|
441
|
+
var autoApprove = Layer4.succeed(Approvals, Approvals.of({ check: () => Effect4.succeed({ _tag: "Approved" }) }));
|
|
442
|
+
var denyAll = Layer4.succeed(Approvals, Approvals.of({ check: () => Effect4.succeed({ _tag: "Denied" }) }));
|
|
443
|
+
var testLayer3 = (implementation) => Layer4.succeed(Approvals, Approvals.of(implementation));
|
|
444
|
+
|
|
445
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/memory.js
|
|
446
|
+
var exports_memory = {};
|
|
447
|
+
__export(exports_memory, {
|
|
448
|
+
testLayer: () => testLayer4,
|
|
449
|
+
replaceRecalledMessage: () => replaceRecalledMessage,
|
|
450
|
+
recalledMessageIdentity: () => recalledMessageIdentity,
|
|
451
|
+
projectTranscript: () => projectTranscript,
|
|
452
|
+
noopLayer: () => noopLayer,
|
|
453
|
+
messageFromRecall: () => messageFromRecall,
|
|
454
|
+
merge: () => merge,
|
|
455
|
+
layerNoop: () => layerNoop,
|
|
456
|
+
itemFromPromptPart: () => itemFromPromptPart,
|
|
457
|
+
isMessageFromRecall: () => isMessageFromRecall,
|
|
458
|
+
MemoryError: () => MemoryError,
|
|
459
|
+
Memory: () => Memory
|
|
460
|
+
});
|
|
461
|
+
import { Context as Context4, Effect as Effect5, Layer as Layer5, Option as Option2, Schema as Schema4 } from "effect";
|
|
462
|
+
import { dual as dual2 } from "effect/Function";
|
|
463
|
+
import { Prompt as Prompt3 } from "effect/unstable/ai";
|
|
464
|
+
var provenanceOption = "@batonfx/core/memory";
|
|
465
|
+
var recallLineage = new WeakMap;
|
|
466
|
+
var itemFromPromptPart = Option2.liftPredicate((part) => part.type === "text" || part.type === "file");
|
|
467
|
+
var isMessageFromRecall = (message) => {
|
|
468
|
+
const provenance = message.options[provenanceOption];
|
|
469
|
+
return typeof provenance === "object" && provenance !== null && !Array.isArray(provenance) && "origin" in provenance && provenance.origin === "memoryRecall";
|
|
470
|
+
};
|
|
471
|
+
var messageFromRecall = (content) => {
|
|
472
|
+
const message = Prompt3.makeMessage("user", {
|
|
473
|
+
content,
|
|
474
|
+
options: { [provenanceOption]: { origin: "memoryRecall" } }
|
|
475
|
+
});
|
|
476
|
+
recallLineage.set(message, message);
|
|
477
|
+
return message;
|
|
478
|
+
};
|
|
479
|
+
var replaceRecalledMessage = dual2(2, (message, content) => {
|
|
480
|
+
const options = isMessageFromRecall(message) ? { ...message.options, [provenanceOption]: { origin: "memoryRecall" } } : { ...message.options };
|
|
481
|
+
const replacement = Prompt3.makeMessage("user", { content, options });
|
|
482
|
+
if (isMessageFromRecall(message))
|
|
483
|
+
recallLineage.set(replacement, recallLineage.get(message) ?? message);
|
|
484
|
+
return replacement;
|
|
485
|
+
});
|
|
486
|
+
var recalledMessageIdentity = (message) => recallLineage.get(message) ?? message;
|
|
487
|
+
var projectTranscript = (transcript) => {
|
|
488
|
+
const content = transcript.content.filter((message) => !isMessageFromRecall(message));
|
|
489
|
+
return content.length === transcript.content.length ? transcript : Prompt3.fromMessages(content);
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
class MemoryError extends Schema4.TaggedErrorClass()("@batonfx/core/MemoryError", {
|
|
493
|
+
message: Schema4.String
|
|
494
|
+
}) {
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
class Memory extends Context4.Service()("@batonfx/core/memory") {
|
|
498
|
+
}
|
|
499
|
+
var noop = {
|
|
500
|
+
recall: () => Effect5.succeed([]),
|
|
501
|
+
remember: () => Effect5.void,
|
|
502
|
+
forget: () => Effect5.void
|
|
503
|
+
};
|
|
504
|
+
var merge = dual2(2, (first, second) => ({
|
|
505
|
+
recall: (input) => Effect5.all([first.recall(input), second.recall(input)]).pipe(Effect5.map(([firstItems, secondItems]) => [...firstItems, ...secondItems])),
|
|
506
|
+
remember: (input) => Effect5.all([first.remember(input), second.remember(input)], { discard: true }),
|
|
507
|
+
forget: (input) => Effect5.all([first.forget(input), second.forget(input)], { discard: true })
|
|
508
|
+
}));
|
|
509
|
+
var layerNoop = Layer5.succeed(Memory, Memory.of(noop));
|
|
510
|
+
var noopLayer = layerNoop;
|
|
511
|
+
var testLayer4 = (implementation) => Layer5.succeed(Memory, Memory.of(implementation));
|
|
512
|
+
|
|
513
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/session.js
|
|
514
|
+
var exports_session = {};
|
|
515
|
+
__export(exports_session, {
|
|
516
|
+
testLayer: () => testLayer5,
|
|
517
|
+
memoryLayer: () => memoryLayer,
|
|
518
|
+
layerMemory: () => layerMemory,
|
|
519
|
+
buildMemoryContext: () => buildMemoryContext,
|
|
520
|
+
buildContext: () => buildContext,
|
|
521
|
+
SessionStoreError: () => SessionStoreError,
|
|
522
|
+
SessionStore: () => SessionStore,
|
|
523
|
+
SessionConflict: () => SessionConflict
|
|
524
|
+
});
|
|
525
|
+
import { Context as Context5, Effect as Effect6, HashMap, Layer as Layer6, Option as Option3, Ref, Schema as Schema5 } from "effect";
|
|
526
|
+
import { Prompt as Prompt4 } from "effect/unstable/ai";
|
|
527
|
+
class SessionStoreError extends Schema5.TaggedErrorClass()("@batonfx/core/SessionStoreError", {
|
|
528
|
+
message: Schema5.String
|
|
529
|
+
}) {
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
class SessionConflict extends Schema5.TaggedErrorClass()("@batonfx/core/SessionConflict", {
|
|
533
|
+
reason: Schema5.Literals(["stale-leaf", "checkpoint-id-reused", "checkpoint-not-on-active-path"]),
|
|
534
|
+
message: Schema5.String
|
|
535
|
+
}) {
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
class SessionStore extends Context5.Service()("@batonfx/core/session/SessionStore") {
|
|
539
|
+
}
|
|
540
|
+
var initialState = {
|
|
541
|
+
entries: HashMap.empty(),
|
|
542
|
+
order: [],
|
|
543
|
+
leaf: null,
|
|
544
|
+
counter: 0
|
|
545
|
+
};
|
|
546
|
+
var success = (value) => ({ _tag: "Success", value });
|
|
547
|
+
var failure = (message) => ({
|
|
548
|
+
_tag: "Failure",
|
|
549
|
+
error: SessionStoreError.make({ message })
|
|
550
|
+
});
|
|
551
|
+
var effectFromResult = (result) => result._tag === "Failure" ? Effect6.fail(result.error) : Effect6.succeed(result.value);
|
|
552
|
+
var effectFromAppendResult = (result) => result._tag === "@batonfx/core/SessionConflict" ? Effect6.fail(result) : effectFromResult(result);
|
|
553
|
+
var entryFromInput = (input, id, parentId) => {
|
|
554
|
+
const base = {
|
|
555
|
+
id,
|
|
556
|
+
parentId,
|
|
557
|
+
...input.metadata === undefined ? {} : { metadata: input.metadata }
|
|
558
|
+
};
|
|
559
|
+
switch (input._tag) {
|
|
560
|
+
case "Message":
|
|
561
|
+
return { ...base, _tag: "Message", message: input.message };
|
|
562
|
+
case "ToolCall":
|
|
563
|
+
return { ...base, _tag: "ToolCall", part: input.part };
|
|
564
|
+
case "ToolResult":
|
|
565
|
+
return { ...base, _tag: "ToolResult", part: input.part };
|
|
566
|
+
case "Memory":
|
|
567
|
+
return { ...base, _tag: "Memory", items: input.items };
|
|
568
|
+
case "Skill":
|
|
569
|
+
return { ...base, _tag: "Skill", name: input.name, body: input.body };
|
|
570
|
+
case "Steering":
|
|
571
|
+
return { ...base, _tag: "Steering", message: input.message };
|
|
572
|
+
case "Handoff":
|
|
573
|
+
return { ...base, _tag: "Handoff", target: input.target, summary: input.summary };
|
|
574
|
+
case "Compaction":
|
|
575
|
+
return { ...base, _tag: "Compaction", summary: input.summary, firstKeptEntryId: input.firstKeptEntryId };
|
|
576
|
+
case "BranchSummary":
|
|
577
|
+
return { ...base, _tag: "BranchSummary", summary: input.summary };
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
var pathFromState = (state, leaf) => {
|
|
581
|
+
const entries = [];
|
|
582
|
+
let cursor = leaf;
|
|
583
|
+
while (cursor !== null) {
|
|
584
|
+
if (entries.length > state.order.length)
|
|
585
|
+
return failure(`Session path for leaf ${leaf} contains a cycle`);
|
|
586
|
+
const entry = HashMap.get(state.entries, cursor);
|
|
587
|
+
if (Option3.isNone(entry))
|
|
588
|
+
return failure(`Session entry ${cursor} does not exist`);
|
|
589
|
+
const value = entry.value;
|
|
590
|
+
entries.push(value);
|
|
591
|
+
cursor = value.parentId;
|
|
592
|
+
}
|
|
593
|
+
return success(entries.toReversed());
|
|
594
|
+
};
|
|
595
|
+
var validateCompaction = (state, input) => {
|
|
596
|
+
if (input._tag !== "Compaction")
|
|
597
|
+
return success(undefined);
|
|
598
|
+
if (state.leaf === null)
|
|
599
|
+
return failure(`Session compaction keeps missing entry ${input.firstKeptEntryId}`);
|
|
600
|
+
const path = pathFromState(state, state.leaf);
|
|
601
|
+
if (path._tag === "Failure")
|
|
602
|
+
return path;
|
|
603
|
+
if (!path.value.some((entry) => entry.id === input.firstKeptEntryId)) {
|
|
604
|
+
return failure(`Session compaction keeps missing entry ${input.firstKeptEntryId}`);
|
|
605
|
+
}
|
|
606
|
+
return success(undefined);
|
|
607
|
+
};
|
|
608
|
+
var appendState = (state, input, options) => {
|
|
609
|
+
if (options?.expectedLeafId !== undefined && options.expectedLeafId !== state.leaf) {
|
|
610
|
+
return [
|
|
611
|
+
SessionConflict.make({
|
|
612
|
+
reason: "stale-leaf",
|
|
613
|
+
message: `Expected Session leaf ${String(options.expectedLeafId)} but found ${String(state.leaf)}`
|
|
614
|
+
}),
|
|
615
|
+
state
|
|
616
|
+
];
|
|
617
|
+
}
|
|
618
|
+
const valid = validateCompaction(state, input);
|
|
619
|
+
if (valid._tag === "Failure")
|
|
620
|
+
return [valid, state];
|
|
621
|
+
const id = String(state.counter);
|
|
622
|
+
const entry = entryFromInput(input, id, state.leaf);
|
|
623
|
+
return [
|
|
624
|
+
success(entry),
|
|
625
|
+
{
|
|
626
|
+
entries: HashMap.set(state.entries, id, entry),
|
|
627
|
+
order: [...state.order, id],
|
|
628
|
+
leaf: id,
|
|
629
|
+
counter: state.counter + 1
|
|
630
|
+
}
|
|
631
|
+
];
|
|
632
|
+
};
|
|
633
|
+
var promptEquivalence = Schema5.toEquivalence(Prompt4.Prompt);
|
|
634
|
+
var checkpointMatches = (entry, prepared) => entry.parentId === prepared.parentId && entry.summary === prepared.summary && promptEquivalence(entry.projectedHistory, prepared.projectedHistory);
|
|
635
|
+
var appendCheckpointState = (state, prepared) => {
|
|
636
|
+
const existing = HashMap.get(state.entries, prepared.id);
|
|
637
|
+
if (Option3.isSome(existing)) {
|
|
638
|
+
const entry = existing.value;
|
|
639
|
+
if (entry._tag !== "Compaction" || entry.version !== 2 || !checkpointMatches(entry, prepared)) {
|
|
640
|
+
return [
|
|
641
|
+
SessionConflict.make({
|
|
642
|
+
reason: "checkpoint-id-reused",
|
|
643
|
+
message: `Session checkpoint id ${prepared.id} was reused with different content`
|
|
644
|
+
}),
|
|
645
|
+
state
|
|
646
|
+
];
|
|
647
|
+
}
|
|
648
|
+
const activePath = state.leaf === null ? success([]) : pathFromState(state, state.leaf);
|
|
649
|
+
if (activePath._tag === "Failure") {
|
|
650
|
+
return [
|
|
651
|
+
SessionConflict.make({ reason: "checkpoint-not-on-active-path", message: activePath.error.message }),
|
|
652
|
+
state
|
|
653
|
+
];
|
|
654
|
+
}
|
|
655
|
+
if (!activePath.value.some((active) => active.id === entry.id)) {
|
|
656
|
+
return [
|
|
657
|
+
SessionConflict.make({
|
|
658
|
+
reason: "checkpoint-not-on-active-path",
|
|
659
|
+
message: `Session checkpoint id ${prepared.id} is not on the active path`
|
|
660
|
+
}),
|
|
661
|
+
state
|
|
662
|
+
];
|
|
663
|
+
}
|
|
664
|
+
return [{ _tag: "AlreadyPresent", checkpoint: entry, leafId: state.leaf ?? entry.id }, state];
|
|
665
|
+
}
|
|
666
|
+
if (state.leaf !== prepared.parentId) {
|
|
667
|
+
return [
|
|
668
|
+
SessionConflict.make({
|
|
669
|
+
reason: "stale-leaf",
|
|
670
|
+
message: `Expected Session leaf ${String(prepared.parentId)} but found ${String(state.leaf)}`
|
|
671
|
+
}),
|
|
672
|
+
state
|
|
673
|
+
];
|
|
674
|
+
}
|
|
675
|
+
const checkpoint = {
|
|
676
|
+
_tag: "Compaction",
|
|
677
|
+
version: 2,
|
|
678
|
+
id: prepared.id,
|
|
679
|
+
parentId: prepared.parentId,
|
|
680
|
+
projectedHistory: prepared.projectedHistory,
|
|
681
|
+
...prepared.summary === undefined ? {} : { summary: prepared.summary }
|
|
682
|
+
};
|
|
683
|
+
return [
|
|
684
|
+
{ _tag: "Appended", checkpoint, leafId: checkpoint.id },
|
|
685
|
+
{
|
|
686
|
+
...state,
|
|
687
|
+
entries: HashMap.set(state.entries, checkpoint.id, checkpoint),
|
|
688
|
+
order: [...state.order, checkpoint.id],
|
|
689
|
+
leaf: checkpoint.id
|
|
690
|
+
}
|
|
691
|
+
];
|
|
692
|
+
};
|
|
693
|
+
var setLeafState = (state, id) => {
|
|
694
|
+
if (id !== null && Option3.isNone(HashMap.get(state.entries, id)))
|
|
695
|
+
return [failure(`Session entry ${id} does not exist`), state];
|
|
696
|
+
return [success(undefined), { ...state, leaf: id }];
|
|
697
|
+
};
|
|
698
|
+
var messageFromText = (role, text) => role === "system" ? Prompt4.makeMessage("system", { content: text }) : Prompt4.makeMessage("user", { content: [Prompt4.makePart("text", { text })] });
|
|
699
|
+
var checkpointMessage = (summary) => messageFromText("user", `<conversation-checkpoint>
|
|
700
|
+
${summary}
|
|
701
|
+
</conversation-checkpoint>`);
|
|
702
|
+
var branchSummaryMessage = (summary) => messageFromText("system", `<abandoned-branch-summary>
|
|
703
|
+
${summary}
|
|
704
|
+
</abandoned-branch-summary>`);
|
|
705
|
+
var attributeValue = (value) => value.replaceAll("&", "&").replaceAll('"', """);
|
|
706
|
+
var memoryMessage = (items) => messageFromText("system", `<memory>
|
|
707
|
+
${items.join(`
|
|
708
|
+
`)}
|
|
709
|
+
</memory>`);
|
|
710
|
+
var skillMessage = (entry) => messageFromText("system", `<skill name="${attributeValue(entry.name)}">
|
|
711
|
+
${entry.body}
|
|
712
|
+
</skill>`);
|
|
713
|
+
var handoffMessage = (entry) => messageFromText("system", `<handoff target="${attributeValue(entry.target)}">
|
|
714
|
+
${entry.summary}
|
|
715
|
+
</handoff>`);
|
|
716
|
+
var projectedMessages = (path) => {
|
|
717
|
+
const compactionIndex = path.findLastIndex((entry) => entry._tag === "Compaction");
|
|
718
|
+
const compaction = compactionIndex === -1 ? undefined : path[compactionIndex];
|
|
719
|
+
const messages = compaction?.version === 2 ? [...compaction.projectedHistory.content] : [];
|
|
720
|
+
const keptIndex = compaction === undefined || compaction.version === 2 ? -1 : path.findIndex((entry) => entry.id === compaction.firstKeptEntryId);
|
|
721
|
+
const entries = compactionIndex === -1 ? path : compaction?.version === 2 ? path.slice(compactionIndex + 1) : path.slice(keptIndex === -1 ? compactionIndex + 1 : keptIndex);
|
|
722
|
+
if (compaction !== undefined && compaction.version !== 2)
|
|
723
|
+
messages.push(checkpointMessage(compaction.summary));
|
|
724
|
+
for (const entry of entries) {
|
|
725
|
+
switch (entry._tag) {
|
|
726
|
+
case "Message":
|
|
727
|
+
messages.push(entry.message);
|
|
728
|
+
break;
|
|
729
|
+
case "ToolCall":
|
|
730
|
+
messages.push(Prompt4.makeMessage("assistant", { content: [entry.part] }));
|
|
731
|
+
break;
|
|
732
|
+
case "ToolResult":
|
|
733
|
+
messages.push(Prompt4.makeMessage("tool", { content: [entry.part] }));
|
|
734
|
+
break;
|
|
735
|
+
case "Memory":
|
|
736
|
+
messages.push(memoryMessage(entry.items));
|
|
737
|
+
break;
|
|
738
|
+
case "Skill":
|
|
739
|
+
messages.push(skillMessage(entry));
|
|
740
|
+
break;
|
|
741
|
+
case "Steering":
|
|
742
|
+
messages.push(entry.message);
|
|
743
|
+
break;
|
|
744
|
+
case "Handoff":
|
|
745
|
+
messages.push(handoffMessage(entry));
|
|
746
|
+
break;
|
|
747
|
+
case "BranchSummary":
|
|
748
|
+
messages.push(branchSummaryMessage(entry.summary));
|
|
749
|
+
break;
|
|
750
|
+
case "Compaction":
|
|
751
|
+
break;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
return messages;
|
|
755
|
+
};
|
|
756
|
+
var buildContext = (path) => Prompt4.fromMessages(projectedMessages(path));
|
|
757
|
+
var buildMemoryContext = (path) => {
|
|
758
|
+
const messages = path.flatMap((entry) => {
|
|
759
|
+
switch (entry._tag) {
|
|
760
|
+
case "Message":
|
|
761
|
+
return [entry.message];
|
|
762
|
+
case "ToolCall":
|
|
763
|
+
return [Prompt4.makeMessage("assistant", { content: [entry.part] })];
|
|
764
|
+
case "ToolResult":
|
|
765
|
+
return [Prompt4.makeMessage("tool", { content: [entry.part] })];
|
|
766
|
+
case "Steering":
|
|
767
|
+
return [entry.message];
|
|
768
|
+
case "Memory":
|
|
769
|
+
case "Skill":
|
|
770
|
+
case "Handoff":
|
|
771
|
+
case "Compaction":
|
|
772
|
+
case "BranchSummary":
|
|
773
|
+
return [];
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
return projectTranscript(Prompt4.fromMessages(messages));
|
|
777
|
+
};
|
|
778
|
+
var layerMemory = Layer6.effect(SessionStore, Ref.make(initialState).pipe(Effect6.map((state) => SessionStore.of({
|
|
779
|
+
reserveEntryId: Ref.modify(state, (current) => [
|
|
780
|
+
String(current.counter),
|
|
781
|
+
{ ...current, counter: current.counter + 1 }
|
|
782
|
+
]),
|
|
783
|
+
append: (entry, options) => Ref.modify(state, (current) => appendState(current, entry, options)).pipe(Effect6.flatMap(effectFromAppendResult)),
|
|
784
|
+
appendCheckpoint: (checkpoint) => Ref.modify(state, (current) => appendCheckpointState(current, checkpoint)).pipe(Effect6.flatMap((result) => result._tag === "@batonfx/core/SessionConflict" ? Effect6.fail(result) : Effect6.succeed(result))),
|
|
785
|
+
path: (leaf) => Ref.get(state).pipe(Effect6.flatMap((current) => leaf === undefined && current.leaf === null ? Effect6.succeed([]) : effectFromResult(pathFromState(current, leaf ?? current.leaf ?? "")))),
|
|
786
|
+
setLeaf: (id) => Ref.modify(state, (current) => setLeafState(current, id)).pipe(Effect6.flatMap(effectFromResult)),
|
|
787
|
+
leaf: Ref.get(state).pipe(Effect6.map((current) => current.leaf))
|
|
788
|
+
}))));
|
|
789
|
+
var memoryLayer = layerMemory;
|
|
790
|
+
var testLayer5 = (implementation) => Layer6.succeed(SessionStore, SessionStore.of(implementation));
|
|
791
|
+
|
|
792
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/tool-output.js
|
|
793
|
+
var exports_tool_output = {};
|
|
794
|
+
__export(exports_tool_output, {
|
|
795
|
+
testLayer: () => testLayer6,
|
|
796
|
+
layerNoop: () => layerNoop2,
|
|
797
|
+
layerMemory: () => layerMemory2,
|
|
798
|
+
bound: () => bound,
|
|
799
|
+
ToolOutputStore: () => ToolOutputStore,
|
|
800
|
+
ToolOutputError: () => ToolOutputError
|
|
801
|
+
});
|
|
802
|
+
import { Cause, Context as Context6, Effect as Effect7, Function as Function2, HashMap as HashMap2, Layer as Layer7, Option as Option4, Ref as Ref2, Schema as Schema6 } from "effect";
|
|
803
|
+
class ToolOutputStore extends Context6.Service()("@batonfx/core/tool-output/ToolOutputStore") {
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
class ToolOutputError extends Schema6.TaggedErrorClass()("@batonfx/core/ToolOutputError", {
|
|
807
|
+
message: Schema6.String
|
|
808
|
+
}) {
|
|
809
|
+
}
|
|
810
|
+
var layerNoop2 = Layer7.succeed(ToolOutputStore, ToolOutputStore.of({ put: () => Effect7.succeed(Option4.none()) }));
|
|
811
|
+
var layerMemory2 = Layer7.effect(ToolOutputStore, Ref2.make({ next: 0, records: HashMap2.empty() }).pipe(Effect7.map((state) => ToolOutputStore.of({
|
|
812
|
+
put: (toolCallId, content) => Ref2.modify(state, ({ next, records }) => {
|
|
813
|
+
const id = `mem:tool-output-${next + 1}`;
|
|
814
|
+
return [Option4.some(id), { next: next + 1, records: HashMap2.set(records, id, { toolCallId, content }) }];
|
|
815
|
+
})
|
|
816
|
+
}))));
|
|
817
|
+
var testLayer6 = (implementation) => Layer7.succeed(ToolOutputStore, ToolOutputStore.of(implementation));
|
|
818
|
+
var encoder = new TextEncoder;
|
|
819
|
+
var decoder = new TextDecoder;
|
|
820
|
+
var serialized = (value) => {
|
|
821
|
+
const json = JSON.stringify(value);
|
|
822
|
+
return json === undefined ? String(value) : json;
|
|
823
|
+
};
|
|
824
|
+
var preview = (value, maxBytes) => {
|
|
825
|
+
const encoded = encoder.encode(value);
|
|
826
|
+
let end = Math.min(encoded.byteLength, Math.floor(maxBytes));
|
|
827
|
+
while (end > 0 && end < encoded.byteLength) {
|
|
828
|
+
const next = encoded[end];
|
|
829
|
+
if (next === undefined || (next & 192) !== 128)
|
|
830
|
+
break;
|
|
831
|
+
end -= 1;
|
|
832
|
+
}
|
|
833
|
+
return decoder.decode(encoded.slice(0, end));
|
|
834
|
+
};
|
|
835
|
+
var isBoundedInline = (value) => typeof value === "object" && value !== null && ("truncated" in value) && value.truncated === true && ("bytes" in value) && typeof value.bytes === "number" && Number.isSafeInteger(value.bytes) && value.bytes >= 0 && ("maxBytes" in value) && typeof value.maxBytes === "number" && Number.isFinite(value.maxBytes) && value.maxBytes >= 0 && ("preview" in value) && typeof value.preview === "string" && encoder.encode(value.preview).byteLength <= value.maxBytes;
|
|
836
|
+
var isToolOutput = (value) => typeof value === "object" && value !== null && ("inline" in value) && isBoundedInline(value.inline) && (!("outputPaths" in value) || Array.isArray(value.outputPaths) && value.outputPaths.every((path) => typeof path === "string"));
|
|
837
|
+
var bounded = (inline, outputPaths) => {
|
|
838
|
+
const output = { inline, outputPaths };
|
|
839
|
+
return { _tag: "Success", result: output, encodedResult: output, outputPaths };
|
|
840
|
+
};
|
|
841
|
+
var boundedFromOriginal = (encoded, bytes, maxBytes, outputPaths) => bounded({ truncated: true, bytes, maxBytes, preview: preview(encoded, maxBytes) }, outputPaths);
|
|
842
|
+
var optionalStore = (store, toolCallId, result) => store.put(toolCallId, { result: result.result, encodedResult: result.encodedResult }).pipe(Effect7.catchCause((cause) => {
|
|
843
|
+
const unrecoverable = cause.reasons.filter((reason) => Cause.isDieReason(reason) || Cause.isInterruptReason(reason));
|
|
844
|
+
return unrecoverable.length === 0 ? Effect7.succeed(Option4.none()) : Effect7.failCause(Cause.fromReasons(unrecoverable));
|
|
845
|
+
}));
|
|
846
|
+
var bound = Function2.dual(2, (result, options) => Effect7.gen(function* () {
|
|
847
|
+
if (isToolOutput(result.encodedResult)) {
|
|
848
|
+
const output = result.encodedResult;
|
|
849
|
+
const outputPaths = output.outputPaths ?? [];
|
|
850
|
+
if (encoder.encode(output.inline.preview).byteLength <= options.maxBytes) {
|
|
851
|
+
return bounded(output.inline, outputPaths);
|
|
852
|
+
}
|
|
853
|
+
return bounded({ ...output.inline, maxBytes: options.maxBytes, preview: preview(output.inline.preview, options.maxBytes) }, outputPaths);
|
|
854
|
+
}
|
|
855
|
+
const encoded = serialized(result.encodedResult);
|
|
856
|
+
const bytes = encoder.encode(encoded).byteLength;
|
|
857
|
+
if (bytes <= options.maxBytes)
|
|
858
|
+
return { ...result, outputPaths: [] };
|
|
859
|
+
const maybeStore = yield* Effect7.serviceOption(ToolOutputStore);
|
|
860
|
+
if (Option4.isNone(maybeStore))
|
|
861
|
+
return boundedFromOriginal(encoded, bytes, options.maxBytes, []);
|
|
862
|
+
const path = yield* optionalStore(maybeStore.value, options.toolCallId, result);
|
|
863
|
+
if (Option4.isNone(path))
|
|
864
|
+
return boundedFromOriginal(encoded, bytes, options.maxBytes, []);
|
|
865
|
+
return boundedFromOriginal(encoded, bytes, options.maxBytes, [path.value]);
|
|
866
|
+
}));
|
|
867
|
+
|
|
868
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/compaction.js
|
|
869
|
+
var exports_compaction = {};
|
|
870
|
+
__export(exports_compaction, {
|
|
871
|
+
truncate: () => truncate,
|
|
872
|
+
toolOutputBound: () => toolOutputBound,
|
|
873
|
+
testLayer: () => testLayer7,
|
|
874
|
+
structuredSummary: () => structuredSummary,
|
|
875
|
+
strategy: () => strategy,
|
|
876
|
+
make: () => make2,
|
|
877
|
+
layer: () => layer,
|
|
878
|
+
keepRecent: () => keepRecent,
|
|
879
|
+
defaultStrategy: () => defaultStrategy,
|
|
880
|
+
SUMMARY_TEMPLATE: () => SUMMARY_TEMPLATE,
|
|
881
|
+
DEFAULT_RESERVE_TOKENS: () => DEFAULT_RESERVE_TOKENS,
|
|
882
|
+
DEFAULT_KEEP_RECENT_TOKENS: () => DEFAULT_KEEP_RECENT_TOKENS,
|
|
883
|
+
CompactionError: () => CompactionError,
|
|
884
|
+
Compaction: () => Compaction,
|
|
885
|
+
AgentSummary: () => AgentSummary
|
|
886
|
+
});
|
|
887
|
+
import { Context as Context7, Effect as Effect8, Function as Function3, Layer as Layer8, Option as Option5, Schema as Schema7 } from "effect";
|
|
888
|
+
import { LanguageModel as LanguageModel2, Prompt as Prompt5, Tokenizer, Toolkit as Toolkit2 } from "effect/unstable/ai";
|
|
889
|
+
var DEFAULT_RESERVE_TOKENS = 16384;
|
|
890
|
+
var DEFAULT_KEEP_RECENT_TOKENS = 20000;
|
|
891
|
+
var SUMMARY_TEMPLATE = `Summarize the conversation so another agent can continue seamlessly.
|
|
892
|
+
|
|
893
|
+
Use Markdown with these sections:
|
|
894
|
+
|
|
895
|
+
## Goal
|
|
896
|
+
## Constraints
|
|
897
|
+
## Progress
|
|
898
|
+
### Done
|
|
899
|
+
### In Progress
|
|
900
|
+
### Blocked
|
|
901
|
+
## Key Decisions
|
|
902
|
+
## Next Steps
|
|
903
|
+
## Critical Context
|
|
904
|
+
|
|
905
|
+
Do not mention that context was compacted.`;
|
|
906
|
+
var AgentSummary = Schema7.Struct({
|
|
907
|
+
goal: Schema7.String,
|
|
908
|
+
facts: Schema7.Array(Schema7.String),
|
|
909
|
+
decisions: Schema7.Array(Schema7.String),
|
|
910
|
+
openQuestions: Schema7.Array(Schema7.String),
|
|
911
|
+
toolFindings: Schema7.Array(Schema7.String)
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
class CompactionError extends Schema7.TaggedErrorClass()("@batonfx/core/CompactionError", {
|
|
915
|
+
message: Schema7.String,
|
|
916
|
+
cause: Schema7.optionalKey(Schema7.Defect())
|
|
917
|
+
}) {
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
class Compaction extends Context7.Service()("@batonfx/core/compaction") {
|
|
921
|
+
}
|
|
922
|
+
var serialized2 = (value) => {
|
|
923
|
+
const json = JSON.stringify(value);
|
|
924
|
+
return json === undefined ? String(value) : json;
|
|
925
|
+
};
|
|
926
|
+
var safeNonNegativeInteger = (name, value) => {
|
|
927
|
+
if (!Number.isSafeInteger(value) || value < 0)
|
|
928
|
+
throw new TypeError(`${name} must be a non-negative safe integer`);
|
|
929
|
+
return value;
|
|
930
|
+
};
|
|
931
|
+
var markdownList = (items) => items.length === 0 ? "- None" : items.map((item) => `- ${item}`).join(`
|
|
932
|
+
`);
|
|
933
|
+
var renderAgentSummary = (summary) => [
|
|
934
|
+
`## Goal
|
|
935
|
+
${summary.goal}`,
|
|
936
|
+
`## Facts
|
|
937
|
+
${markdownList(summary.facts)}`,
|
|
938
|
+
`## Decisions
|
|
939
|
+
${markdownList(summary.decisions)}`,
|
|
940
|
+
`## Open Questions
|
|
941
|
+
${markdownList(summary.openQuestions)}`,
|
|
942
|
+
`## Tool Findings
|
|
943
|
+
${markdownList(summary.toolFindings)}`
|
|
944
|
+
].join(`
|
|
945
|
+
|
|
946
|
+
`);
|
|
947
|
+
var APPROX_CHARS_PER_TOKEN = 4;
|
|
948
|
+
var estimateTokens = (text) => Math.ceil(text.length / APPROX_CHARS_PER_TOKEN);
|
|
949
|
+
var estimateEntryTokens = (entry) => estimateTokens(serialized2(entry));
|
|
950
|
+
var estimatePromptTokens = (prompt) => estimateTokens(serialized2(prompt.content));
|
|
951
|
+
var fits = (history, prompt, usage) => Number.isFinite(usage.contextWindow) && estimatePromptTokens(Prompt5.concat(history, prompt)) <= usage.contextWindow - usage.reserveTokens;
|
|
952
|
+
var isPromptToolResult = (part) => part.type === "tool-result";
|
|
953
|
+
var messageHasToolCall = (message) => typeof message.content !== "string" && message.content.some((part) => part.type === "tool-call");
|
|
954
|
+
var isToolMessage = (entry) => entry?._tag === "Message" && entry.message.role === "tool";
|
|
955
|
+
var isAssistantToolCallEntry = (entry) => entry?._tag === "Message" && entry.message.role === "assistant" && messageHasToolCall(entry.message);
|
|
956
|
+
var compactToolPart = (part, maxBytes) => Effect8.gen(function* () {
|
|
957
|
+
if (part.isFailure)
|
|
958
|
+
return [part, false];
|
|
959
|
+
const success2 = { _tag: "Success", result: part.result, encodedResult: part.result };
|
|
960
|
+
const bounded2 = yield* bound(success2, { toolCallId: part.id, maxBytes });
|
|
961
|
+
if (bounded2.encodedResult === success2.encodedResult)
|
|
962
|
+
return [part, false];
|
|
963
|
+
return [
|
|
964
|
+
Prompt5.makePart("tool-result", {
|
|
965
|
+
id: part.id,
|
|
966
|
+
name: part.name,
|
|
967
|
+
isFailure: false,
|
|
968
|
+
result: bounded2.encodedResult
|
|
969
|
+
}),
|
|
970
|
+
true
|
|
971
|
+
];
|
|
972
|
+
});
|
|
973
|
+
var microcompactPrompt = (prompt, maxBytes) => Effect8.gen(function* () {
|
|
974
|
+
let changed = false;
|
|
975
|
+
const messages = [];
|
|
976
|
+
for (const message of prompt.content) {
|
|
977
|
+
if (typeof message.content === "string") {
|
|
978
|
+
messages.push(message);
|
|
979
|
+
} else {
|
|
980
|
+
let messageChanged = false;
|
|
981
|
+
const content = [];
|
|
982
|
+
for (const part of message.content) {
|
|
983
|
+
if (!isPromptToolResult(part)) {
|
|
984
|
+
content.push(part);
|
|
985
|
+
} else {
|
|
986
|
+
const [compacted, didCompact] = yield* compactToolPart(part, maxBytes);
|
|
987
|
+
changed = changed || didCompact;
|
|
988
|
+
messageChanged = messageChanged || didCompact;
|
|
989
|
+
content.push(compacted);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
messages.push(messageChanged ? { ...message, content } : message);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
return [changed ? Prompt5.fromMessages(messages) : prompt, changed];
|
|
996
|
+
});
|
|
997
|
+
var checkpointMessage2 = (summary) => Prompt5.makeMessage("user", {
|
|
998
|
+
content: [Prompt5.makePart("text", { text: `<conversation-checkpoint>
|
|
999
|
+
${summary}
|
|
1000
|
+
</conversation-checkpoint>` })]
|
|
1001
|
+
});
|
|
1002
|
+
var summaryPrompt = (template, prompt) => Prompt5.make(`${template}
|
|
1003
|
+
|
|
1004
|
+
Conversation to summarize:
|
|
1005
|
+
${serialized2(prompt.content)}`);
|
|
1006
|
+
var systemMessages = (entries) => entries.flatMap((entry) => entry._tag === "Message" && entry.message.role === "system" ? [entry.message] : []);
|
|
1007
|
+
var compactedHistory = (summary, head, recent) => Prompt5.concat(Prompt5.fromMessages([...systemMessages(head), checkpointMessage2(summary)]), recent);
|
|
1008
|
+
var normalizeUsage = (usage, options) => ({
|
|
1009
|
+
contextTokens: Number.isFinite(usage.contextTokens) ? usage.contextTokens : 0,
|
|
1010
|
+
contextWindow: Number.isFinite(usage.contextWindow) ? usage.contextWindow : options.contextWindow ?? Number.POSITIVE_INFINITY,
|
|
1011
|
+
reserveTokens: options.reserveTokens ?? (Number.isFinite(usage.reserveTokens) ? usage.reserveTokens : DEFAULT_RESERVE_TOKENS)
|
|
1012
|
+
});
|
|
1013
|
+
var makeMicrocompact = (history, prompt) => ({
|
|
1014
|
+
_tag: "Microcompact",
|
|
1015
|
+
history,
|
|
1016
|
+
prompt
|
|
1017
|
+
});
|
|
1018
|
+
var safeCutIndex = (entries, keepRecentTokens) => {
|
|
1019
|
+
let total = 0;
|
|
1020
|
+
let index = entries.length;
|
|
1021
|
+
while (index > 0 && total < keepRecentTokens) {
|
|
1022
|
+
index -= 1;
|
|
1023
|
+
total += estimateEntryTokens(entries[index]);
|
|
1024
|
+
}
|
|
1025
|
+
while (index > 0 && (isToolMessage(entries[index]) || isAssistantToolCallEntry(entries[index - 1]))) {
|
|
1026
|
+
index -= 1;
|
|
1027
|
+
}
|
|
1028
|
+
return index;
|
|
1029
|
+
};
|
|
1030
|
+
var defaultStrategy = (options = {}) => ({
|
|
1031
|
+
shouldCompact: (usage) => Number.isFinite(usage.contextWindow) && usage.contextTokens > usage.contextWindow - usage.reserveTokens,
|
|
1032
|
+
cut: (entries, keepRecentTokens) => {
|
|
1033
|
+
const index = safeCutIndex(entries, keepRecentTokens);
|
|
1034
|
+
if (index <= 0 || index >= entries.length)
|
|
1035
|
+
return Option5.none();
|
|
1036
|
+
const recent = entries.slice(index);
|
|
1037
|
+
const first = recent[0];
|
|
1038
|
+
return first === undefined ? Option5.none() : Option5.some({ firstKeptEntryId: first.id, head: entries.slice(0, index), recent });
|
|
1039
|
+
},
|
|
1040
|
+
summarize: (plan, request) => {
|
|
1041
|
+
const effect = Effect8.gen(function* () {
|
|
1042
|
+
const head = buildContext(plan.head);
|
|
1043
|
+
const [compactedHead] = request.toolOutputMaxBytes === undefined ? [head, false] : yield* microcompactPrompt(head, request.toolOutputMaxBytes);
|
|
1044
|
+
const prompt = summaryPrompt(options.summaryPrompt ?? SUMMARY_TEMPLATE, compactedHead);
|
|
1045
|
+
const model = yield* LanguageModel2.LanguageModel;
|
|
1046
|
+
return yield* model.generateText({ prompt, toolkit: Toolkit2.empty, toolChoice: "none" }).pipe(Effect8.map((response) => response.text), Effect8.mapError((error) => CompactionError.make({ message: String(error), cause: error })));
|
|
1047
|
+
});
|
|
1048
|
+
return options.summaryModel === undefined ? effect : Effect8.scoped(Layer8.build(options.summaryModel).pipe(Effect8.flatMap((context) => effect.pipe(Effect8.provide(context)))));
|
|
1049
|
+
}
|
|
1050
|
+
});
|
|
1051
|
+
var strategy = Function3.dual((args) => args.length !== 1 || Array.isArray(args[0]), (parts, base = defaultStrategy()) => parts.reduce((current, part) => ({
|
|
1052
|
+
shouldCompact: part.shouldCompact ?? current.shouldCompact,
|
|
1053
|
+
cut: part.cut ?? current.cut,
|
|
1054
|
+
summarize: part.summarize ?? current.summarize,
|
|
1055
|
+
...part.toolOutputMaxBytes !== undefined ? { toolOutputMaxBytes: part.toolOutputMaxBytes } : current.toolOutputMaxBytes === undefined ? {} : { toolOutputMaxBytes: current.toolOutputMaxBytes },
|
|
1056
|
+
...part.keepRecentTokens !== undefined ? { keepRecentTokens: part.keepRecentTokens } : current.keepRecentTokens === undefined ? {} : { keepRecentTokens: current.keepRecentTokens }
|
|
1057
|
+
}), base));
|
|
1058
|
+
var toolOutputBound = (options) => ({
|
|
1059
|
+
toolOutputMaxBytes: safeNonNegativeInteger("ToolOutputBoundOptions.maxBytes", options.maxBytes)
|
|
1060
|
+
});
|
|
1061
|
+
var keepRecent = (options) => ({
|
|
1062
|
+
keepRecentTokens: safeNonNegativeInteger("KeepRecentOptions.tokens", options.tokens)
|
|
1063
|
+
});
|
|
1064
|
+
var structuredSummary = (options = {}) => ({
|
|
1065
|
+
summarize: (plan, request) => {
|
|
1066
|
+
const effect = Effect8.gen(function* () {
|
|
1067
|
+
const head = buildContext(plan.head);
|
|
1068
|
+
const [compactedHead] = request.toolOutputMaxBytes === undefined ? [head, false] : yield* microcompactPrompt(head, request.toolOutputMaxBytes);
|
|
1069
|
+
const prompt = summaryPrompt(options.summaryPrompt ?? SUMMARY_TEMPLATE, compactedHead);
|
|
1070
|
+
const model = yield* LanguageModel2.LanguageModel;
|
|
1071
|
+
return yield* model.generateObject({
|
|
1072
|
+
prompt,
|
|
1073
|
+
schema: AgentSummary,
|
|
1074
|
+
objectName: options.objectName ?? "AgentSummary",
|
|
1075
|
+
toolChoice: "none"
|
|
1076
|
+
}).pipe(Effect8.map((response) => renderAgentSummary(response.value)), Effect8.mapError((error) => CompactionError.make({ message: String(error), cause: error })));
|
|
1077
|
+
});
|
|
1078
|
+
return options.summaryModel === undefined ? effect : Effect8.scoped(Layer8.build(options.summaryModel).pipe(Effect8.flatMap((context) => effect.pipe(Effect8.provide(context)))));
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1081
|
+
var make2 = Function3.dual((args) => args.length !== 1 || ("shouldCompact" in args[0]), (compactionStrategy, options = {}) => ({
|
|
1082
|
+
maybeCompact: (input) => Effect8.gen(function* () {
|
|
1083
|
+
const usage = normalizeUsage(input.usage, options);
|
|
1084
|
+
const shouldCompact = input.overflow || compactionStrategy.shouldCompact(usage);
|
|
1085
|
+
if (!shouldCompact)
|
|
1086
|
+
return Option5.none();
|
|
1087
|
+
let history = input.history;
|
|
1088
|
+
let prompt = input.prompt;
|
|
1089
|
+
let changed = false;
|
|
1090
|
+
const toolOutputMaxBytes = input.toolOutputMaxBytes ?? compactionStrategy.toolOutputMaxBytes;
|
|
1091
|
+
if (toolOutputMaxBytes !== undefined) {
|
|
1092
|
+
const [compactedHistoryPrompt, historyChanged] = yield* microcompactPrompt(history, toolOutputMaxBytes);
|
|
1093
|
+
const [compactedPrompt, promptChanged] = yield* microcompactPrompt(prompt, toolOutputMaxBytes);
|
|
1094
|
+
history = compactedHistoryPrompt;
|
|
1095
|
+
prompt = compactedPrompt;
|
|
1096
|
+
changed = historyChanged || promptChanged;
|
|
1097
|
+
if (changed && fits(history, prompt, usage))
|
|
1098
|
+
return Option5.some(makeMicrocompact(history, prompt));
|
|
1099
|
+
}
|
|
1100
|
+
const plan = compactionStrategy.cut(input.path ?? [], compactionStrategy.keepRecentTokens ?? options.keepRecentTokens ?? DEFAULT_KEEP_RECENT_TOKENS);
|
|
1101
|
+
if (Option5.isNone(plan))
|
|
1102
|
+
return changed ? Option5.some(makeMicrocompact(history, prompt)) : Option5.none();
|
|
1103
|
+
const summary = yield* compactionStrategy.summarize(plan.value, {
|
|
1104
|
+
...input,
|
|
1105
|
+
history,
|
|
1106
|
+
prompt,
|
|
1107
|
+
usage,
|
|
1108
|
+
...toolOutputMaxBytes === undefined ? {} : { toolOutputMaxBytes }
|
|
1109
|
+
});
|
|
1110
|
+
const recent = buildContext(plan.value.recent);
|
|
1111
|
+
const [compactedRecent] = toolOutputMaxBytes === undefined ? [recent, false] : yield* microcompactPrompt(recent, toolOutputMaxBytes);
|
|
1112
|
+
return Option5.some({
|
|
1113
|
+
_tag: "Summarize",
|
|
1114
|
+
history: compactedHistory(summary, plan.value.head, compactedRecent),
|
|
1115
|
+
prompt,
|
|
1116
|
+
summary,
|
|
1117
|
+
firstKeptEntryId: plan.value.firstKeptEntryId
|
|
1118
|
+
});
|
|
1119
|
+
})
|
|
1120
|
+
}));
|
|
1121
|
+
var layer = Function3.dual((args) => args.length !== 1 || !("shouldCompact" in args[0]), (options = {}, providedStrategy = options.strategy ?? defaultStrategy(options)) => Layer8.succeed(Compaction, Compaction.of(make2(providedStrategy, options))));
|
|
1122
|
+
var truncate = (maxTokens) => ({
|
|
1123
|
+
maybeCompact: (input) => Effect8.gen(function* () {
|
|
1124
|
+
const usage = input.usage;
|
|
1125
|
+
if (!input.overflow && !(Number.isFinite(usage.contextWindow) && usage.contextTokens > usage.contextWindow - usage.reserveTokens)) {
|
|
1126
|
+
return Option5.none();
|
|
1127
|
+
}
|
|
1128
|
+
const tokenizer = yield* Effect8.serviceOption(Tokenizer.Tokenizer);
|
|
1129
|
+
if (Option5.isNone(tokenizer))
|
|
1130
|
+
return Option5.none();
|
|
1131
|
+
const prompt = yield* tokenizer.value.truncate(Prompt5.concat(input.history, input.prompt), maxTokens).pipe(Effect8.mapError((error) => CompactionError.make({ message: String(error), cause: error })));
|
|
1132
|
+
return Option5.some(makeMicrocompact(Prompt5.empty, prompt));
|
|
1133
|
+
})
|
|
1134
|
+
});
|
|
1135
|
+
var testLayer7 = (implementation) => Layer8.succeed(Compaction, Compaction.of(implementation));
|
|
1136
|
+
|
|
1137
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/instructions.js
|
|
1138
|
+
var exports_instructions = {};
|
|
1139
|
+
__export(exports_instructions, {
|
|
1140
|
+
testLayer: () => testLayer8,
|
|
1141
|
+
staticSource: () => staticSource,
|
|
1142
|
+
renderUpdate: () => renderUpdate,
|
|
1143
|
+
openEpoch: () => openEpoch,
|
|
1144
|
+
layer: () => layer2,
|
|
1145
|
+
Instructions: () => Instructions
|
|
1146
|
+
});
|
|
1147
|
+
import { Context as Context8, Effect as Effect9, Layer as Layer9, Option as Option6 } from "effect";
|
|
1148
|
+
import { dual as dual3 } from "effect/Function";
|
|
1149
|
+
class Instructions extends Context8.Service()("@batonfx/core/instructions") {
|
|
1150
|
+
}
|
|
1151
|
+
var staticSource = dual3(2, (id, text) => ({
|
|
1152
|
+
id,
|
|
1153
|
+
cache: "baseline",
|
|
1154
|
+
render: () => Effect9.succeed(text.length === 0 ? Option6.none() : Option6.some(text))
|
|
1155
|
+
}));
|
|
1156
|
+
var openEpoch = dual3(2, (instructions, context) => Effect9.gen(function* () {
|
|
1157
|
+
const baseline = [];
|
|
1158
|
+
const dynamic = [];
|
|
1159
|
+
for (const source of instructions.sources) {
|
|
1160
|
+
if (source.cache === "dynamic") {
|
|
1161
|
+
dynamic.push(source);
|
|
1162
|
+
} else {
|
|
1163
|
+
const rendered = yield* source.render(context);
|
|
1164
|
+
if (Option6.isSome(rendered))
|
|
1165
|
+
baseline.push(rendered.value);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
return { baseline: baseline.join(`
|
|
1169
|
+
|
|
1170
|
+
`), dynamic };
|
|
1171
|
+
}));
|
|
1172
|
+
var renderUpdate = dual3(2, (epoch, context) => Effect9.gen(function* () {
|
|
1173
|
+
const fragments = [];
|
|
1174
|
+
for (const source of epoch.dynamic) {
|
|
1175
|
+
const rendered = yield* source.render(context);
|
|
1176
|
+
if (Option6.isSome(rendered))
|
|
1177
|
+
fragments.push(rendered.value);
|
|
1178
|
+
}
|
|
1179
|
+
return fragments.length === 0 ? Option6.none() : Option6.some(fragments.join(`
|
|
1180
|
+
|
|
1181
|
+
`));
|
|
1182
|
+
}));
|
|
1183
|
+
var layer2 = (sources) => Layer9.succeed(Instructions, Instructions.of({ sources: [...sources] }));
|
|
1184
|
+
var testLayer8 = (implementation) => Layer9.succeed(Instructions, Instructions.of(implementation));
|
|
1185
|
+
|
|
1186
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/model-middleware.js
|
|
1187
|
+
var exports_model_middleware = {};
|
|
1188
|
+
__export(exports_model_middleware, {
|
|
1189
|
+
layerIdentity: () => layerIdentity,
|
|
1190
|
+
layer: () => layer3,
|
|
1191
|
+
identityLayer: () => identityLayer,
|
|
1192
|
+
ModelMiddleware: () => ModelMiddleware
|
|
1193
|
+
});
|
|
1194
|
+
import { Context as Context9, Effect as Effect10, Layer as Layer10, Option as Option7 } from "effect";
|
|
1195
|
+
import { Prompt as Prompt6, Response as Response4 } from "effect/unstable/ai";
|
|
1196
|
+
class ModelMiddleware extends Context9.Service()("@batonfx/core/model-middleware/ModelMiddleware") {
|
|
1197
|
+
}
|
|
1198
|
+
var layerIdentity = Layer10.succeed(ModelMiddleware, []);
|
|
1199
|
+
var identityLayer = layerIdentity;
|
|
1200
|
+
var layer3 = (middleware) => Layer10.succeed(ModelMiddleware, middleware);
|
|
1201
|
+
|
|
1202
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/model-registry.js
|
|
1203
|
+
var exports_model_registry = {};
|
|
1204
|
+
__export(exports_model_registry, {
|
|
1205
|
+
testLayer: () => testLayer9,
|
|
1206
|
+
stream: () => stream,
|
|
1207
|
+
registrations: () => registrations,
|
|
1208
|
+
registrationFromLayer: () => registrationFromLayer,
|
|
1209
|
+
register: () => register,
|
|
1210
|
+
provide: () => provide,
|
|
1211
|
+
operate: () => operate,
|
|
1212
|
+
memoryLayer: () => memoryLayer2,
|
|
1213
|
+
layerMemory: () => layerMemory3,
|
|
1214
|
+
layerFromRegistrationEffects: () => layerFromRegistrationEffects,
|
|
1215
|
+
layer: () => layer4,
|
|
1216
|
+
combine: () => combine,
|
|
1217
|
+
classifyFailure: () => classifyFailure,
|
|
1218
|
+
Service: () => Service,
|
|
1219
|
+
LanguageModelNotRegistered: () => LanguageModelNotRegistered
|
|
1220
|
+
});
|
|
1221
|
+
import { Chunk, Context as Context10, Effect as Effect11, Function as Function4, Layer as Layer11, Option as Option8, Ref as Ref3, Schema as Schema8, Semaphore, Stream as Stream2 } from "effect";
|
|
1222
|
+
import { LanguageModel as LanguageModel3, Model } from "effect/unstable/ai";
|
|
1223
|
+
var FailureClassifierTypeId = Symbol.for("@batonfx/core/model-registry/FailureClassifier");
|
|
1224
|
+
var classifyFailure = Function4.dual(2, (model, error) => model[FailureClassifierTypeId]?.(error) ?? "other");
|
|
1225
|
+
var attachFailureClassifier = (registration, context) => {
|
|
1226
|
+
if (registration.classifyFailure === undefined)
|
|
1227
|
+
return context;
|
|
1228
|
+
const model = Context10.get(context, LanguageModel3.LanguageModel);
|
|
1229
|
+
const classified = {
|
|
1230
|
+
...model,
|
|
1231
|
+
[FailureClassifierTypeId]: registration.classifyFailure
|
|
1232
|
+
};
|
|
1233
|
+
return Context10.add(context, LanguageModel3.LanguageModel, classified);
|
|
1234
|
+
};
|
|
1235
|
+
|
|
1236
|
+
class LanguageModelNotRegistered extends Schema8.TaggedErrorClass()("LanguageModelNotRegistered", {
|
|
1237
|
+
provider: Schema8.String,
|
|
1238
|
+
model: Schema8.String,
|
|
1239
|
+
registration_key: Schema8.optionalKey(Schema8.String)
|
|
1240
|
+
}) {
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
class Service extends Context10.Service()("@batonfx/core/model-registry/Service") {
|
|
1244
|
+
}
|
|
1245
|
+
var registrationVariantKey = (value) => value.registrationKey ?? null;
|
|
1246
|
+
var selectionVariantKey = (selection) => selection.registrationKey ?? null;
|
|
1247
|
+
var registryIdentity = (registration) => JSON.stringify([registration.provider, registration.model, registrationVariantKey(registration)]);
|
|
1248
|
+
var matchesSelection = (selection) => (registration) => registration.provider === selection.provider && registration.model === selection.model && registrationVariantKey(registration) === selectionVariantKey(selection);
|
|
1249
|
+
var upsertRegistration = (registry, registration) => {
|
|
1250
|
+
const key = registryIdentity(registration);
|
|
1251
|
+
const exists = Option8.isSome(Chunk.findFirst(registry, (item) => registryIdentity(item) === key));
|
|
1252
|
+
if (!exists)
|
|
1253
|
+
return Chunk.append(registry, registration);
|
|
1254
|
+
return Chunk.map(registry, (item) => registryIdentity(item) === key ? registration : item);
|
|
1255
|
+
};
|
|
1256
|
+
var findRegistration = (registry, selection) => Chunk.findFirst(registry, matchesSelection(selection)).pipe(Option8.getOrUndefined);
|
|
1257
|
+
var registrationFromLayer = (input) => Model.make(input.provider, input.model, input.layer).captureRequirements.pipe(Effect11.map((layer4) => ({
|
|
1258
|
+
provider: input.provider,
|
|
1259
|
+
model: input.model,
|
|
1260
|
+
layer: layer4,
|
|
1261
|
+
...input.registrationKey === undefined ? {} : { registrationKey: input.registrationKey },
|
|
1262
|
+
...input.metadata === undefined ? {} : { metadata: input.metadata },
|
|
1263
|
+
...input.classifyFailure === undefined ? {} : { classifyFailure: input.classifyFailure }
|
|
1264
|
+
})));
|
|
1265
|
+
var layer4 = Function4.dual((args) => args.length === 0 || args.length > 1 || Array.isArray(args[0]), (initialRegistrations = [], options) => Layer11.effect(Service, Effect11.gen(function* () {
|
|
1266
|
+
const registry = yield* Ref3.make(initialRegistrations.reduce(upsertRegistration, Chunk.empty()));
|
|
1267
|
+
const semaphore = options?.maxConcurrentModelCalls === undefined ? undefined : yield* Semaphore.make(options.maxConcurrentModelCalls);
|
|
1268
|
+
const register = Effect11.fn("ModelRegistry.register")(function* (input) {
|
|
1269
|
+
yield* Ref3.update(registry, (items) => upsertRegistration(items, input.registration));
|
|
1270
|
+
});
|
|
1271
|
+
const registrations = Ref3.get(registry).pipe(Effect11.map(Chunk.toReadonlyArray));
|
|
1272
|
+
const operate = Effect11.fn("ModelRegistry.operate")(function* (selection, effect) {
|
|
1273
|
+
const items = yield* Ref3.get(registry);
|
|
1274
|
+
const registration = findRegistration(items, selection);
|
|
1275
|
+
if (registration === undefined) {
|
|
1276
|
+
return yield* LanguageModelNotRegistered.make({
|
|
1277
|
+
provider: selection.provider,
|
|
1278
|
+
model: selection.model,
|
|
1279
|
+
...selection.registrationKey === undefined ? {} : { registration_key: selection.registrationKey }
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
const provided = Effect11.scoped(Layer11.build(registration.layer).pipe(Effect11.flatMap((context) => effect.pipe(Effect11.provide(attachFailureClassifier(registration, context))))));
|
|
1283
|
+
return yield* semaphore === undefined ? provided : semaphore.withPermits(1)(provided);
|
|
1284
|
+
});
|
|
1285
|
+
const stream = (selection, operation) => Stream2.unwrap(Effect11.gen(function* () {
|
|
1286
|
+
const items = yield* Ref3.get(registry);
|
|
1287
|
+
const registration = findRegistration(items, selection);
|
|
1288
|
+
if (registration === undefined) {
|
|
1289
|
+
return yield* LanguageModelNotRegistered.make({
|
|
1290
|
+
provider: selection.provider,
|
|
1291
|
+
model: selection.model,
|
|
1292
|
+
...selection.registrationKey === undefined ? {} : { registration_key: selection.registrationKey }
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
if (semaphore !== undefined) {
|
|
1296
|
+
yield* Effect11.acquireRelease(semaphore.take(1), () => semaphore.release(1), { interruptible: true });
|
|
1297
|
+
}
|
|
1298
|
+
const context = attachFailureClassifier(registration, yield* Layer11.build(registration.layer));
|
|
1299
|
+
return operation.pipe(Stream2.provideContext(context));
|
|
1300
|
+
}));
|
|
1301
|
+
return Service.of({
|
|
1302
|
+
register,
|
|
1303
|
+
registrations,
|
|
1304
|
+
operate,
|
|
1305
|
+
stream,
|
|
1306
|
+
provide: operate
|
|
1307
|
+
});
|
|
1308
|
+
})));
|
|
1309
|
+
var layerFromRegistrationEffects = Function4.dual((args) => args.length !== 1 || Array.isArray(args[0]), (registrations, options) => Layer11.unwrap(Effect11.all(registrations).pipe(Effect11.map((items) => layer4(items, options)))));
|
|
1310
|
+
var combine = Function4.dual((args) => args.length !== 1 || Array.isArray(args[0]), (registries, options) => Layer11.unwrap(Effect11.forEach(registries, (registry) => Layer11.build(registry).pipe(Effect11.flatMap((context) => Context10.get(context, Service).registrations))).pipe(Effect11.map((groups) => layer4(groups.flat(), options)))));
|
|
1311
|
+
var layerMemory3 = layer4;
|
|
1312
|
+
var memoryLayer2 = layerMemory3;
|
|
1313
|
+
var testLayer9 = (implementation) => Layer11.succeed(Service, Service.of(implementation));
|
|
1314
|
+
var register = Effect11.fn("ModelRegistry.register.call")(function* (input) {
|
|
1315
|
+
const service = yield* Service;
|
|
1316
|
+
return yield* service.register(input);
|
|
1317
|
+
});
|
|
1318
|
+
var registrations = Effect11.fn("ModelRegistry.registrations.call")(function* () {
|
|
1319
|
+
const service = yield* Service;
|
|
1320
|
+
return yield* service.registrations;
|
|
1321
|
+
});
|
|
1322
|
+
var operate = Function4.dual(2, (selection, effect) => Effect11.gen(function* () {
|
|
1323
|
+
const service = yield* Service;
|
|
1324
|
+
return yield* service.operate(selection, effect);
|
|
1325
|
+
}));
|
|
1326
|
+
var stream = Function4.dual(2, (selection, operation) => Stream2.unwrap(Service.pipe(Effect11.map((service) => service.stream(selection, operation)))));
|
|
1327
|
+
var provide = operate;
|
|
1328
|
+
|
|
1329
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/model-resilience.js
|
|
1330
|
+
var exports_model_resilience = {};
|
|
1331
|
+
__export(exports_model_resilience, {
|
|
1332
|
+
testLayer: () => testLayer10,
|
|
1333
|
+
none: () => none,
|
|
1334
|
+
make: () => make3,
|
|
1335
|
+
layer: () => layer5,
|
|
1336
|
+
defaultClassify: () => defaultClassify,
|
|
1337
|
+
apply: () => apply,
|
|
1338
|
+
ModelResilience: () => ModelResilience
|
|
1339
|
+
});
|
|
1340
|
+
import { Cause as Cause2, Context as Context11, Effect as Effect12, Function as Function5, Layer as Layer12, Result, Schedule as Schedule2, Schema as Schema9, Stream as Stream3 } from "effect";
|
|
1341
|
+
import { AiError as AiError2, LanguageModel as LanguageModel4, Response as Response5, Tool as Tool3 } from "effect/unstable/ai";
|
|
1342
|
+
|
|
1343
|
+
class ModelResilience extends Context11.Service()("@batonfx/core/model-resilience/ModelResilience") {
|
|
1344
|
+
}
|
|
1345
|
+
var defaultClassify = (error) => AiError2.isAiError(error) && error.isRetryable ? "transient" : "terminal";
|
|
1346
|
+
var none = { classify: () => "terminal", retrySchedule: Schedule2.recurs(0) };
|
|
1347
|
+
var make3 = (input) => ({
|
|
1348
|
+
classify: input?.classify ?? defaultClassify,
|
|
1349
|
+
retrySchedule: input?.retrySchedule ?? none.retrySchedule
|
|
1350
|
+
});
|
|
1351
|
+
var layer5 = (input) => Layer12.succeed(ModelResilience, ModelResilience.of(make3(input)));
|
|
1352
|
+
var testLayer10 = (implementation) => Layer12.succeed(ModelResilience, ModelResilience.of(implementation));
|
|
1353
|
+
var retryEffect = (effect, resilience) => Effect12.suspend(effect).pipe(Effect12.map((value) => Result.succeed(value)), Effect12.catchCause((cause) => {
|
|
1354
|
+
const reason = cause.reasons.length === 1 ? cause.reasons[0] : undefined;
|
|
1355
|
+
return reason === undefined || !Cause2.isFailReason(reason) ? Effect12.succeed(Result.fail(cause)) : Effect12.fail(reason.error);
|
|
1356
|
+
}), Effect12.retry({
|
|
1357
|
+
schedule: resilience.retrySchedule,
|
|
1358
|
+
while: (error) => resilience.classify(error) === "transient"
|
|
1359
|
+
}), Effect12.flatMap((result) => Result.isFailure(result) ? Effect12.failCause(result.failure) : Effect12.succeed(result.success)));
|
|
1360
|
+
var retryStreamSchedule = (resilience) => resilience.retrySchedule.pipe(Schedule2.while(({ input }) => resilience.classify(input) === "transient"));
|
|
1361
|
+
var retryStream = (stream2, onEmittedFailure, resilience) => Stream3.suspend(() => {
|
|
1362
|
+
let emitted = false;
|
|
1363
|
+
return stream2().pipe(Stream3.map((value) => Result.succeed(value)), Stream3.tap(() => Effect12.sync(() => {
|
|
1364
|
+
emitted = true;
|
|
1365
|
+
})), Stream3.catchCause((cause) => {
|
|
1366
|
+
const reason = cause.reasons.length === 1 ? cause.reasons[0] : undefined;
|
|
1367
|
+
if (reason === undefined || !Cause2.isFailReason(reason))
|
|
1368
|
+
return Stream3.succeed(Result.fail(cause));
|
|
1369
|
+
return emitted ? Stream3.succeed(Result.succeed(onEmittedFailure(reason.error))) : Stream3.fail(reason.error);
|
|
1370
|
+
}));
|
|
1371
|
+
}).pipe(Stream3.retry(retryStreamSchedule(resilience)), Stream3.flatMap((result) => Result.isFailure(result) ? Stream3.failCause(result.failure) : Stream3.succeed(result.success)));
|
|
1372
|
+
var apply = Function5.dual(2, (model, resilience) => ({
|
|
1373
|
+
...model,
|
|
1374
|
+
generateText: (options) => retryEffect(() => model.generateText(options), resilience),
|
|
1375
|
+
generateObject: (options) => {
|
|
1376
|
+
const generate = model.generateObject;
|
|
1377
|
+
return retryEffect(() => generate(options), resilience);
|
|
1378
|
+
},
|
|
1379
|
+
streamText: (options) => retryStream(() => model.streamText(options), (error) => Response5.makePart("error", { error }), resilience)
|
|
1380
|
+
}));
|
|
1381
|
+
|
|
1382
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/permissions.js
|
|
1383
|
+
var exports_permissions = {};
|
|
1384
|
+
__export(exports_permissions, {
|
|
1385
|
+
testLayer: () => testLayer11,
|
|
1386
|
+
ruleStoreTestLayer: () => ruleStoreTestLayer,
|
|
1387
|
+
ruleStoreMemory: () => ruleStoreMemory,
|
|
1388
|
+
matches: () => matches,
|
|
1389
|
+
matchRule: () => matchRule,
|
|
1390
|
+
interactive: () => interactive,
|
|
1391
|
+
fromRuleset: () => fromRuleset,
|
|
1392
|
+
evaluate: () => evaluate,
|
|
1393
|
+
allowAll: () => allowAll,
|
|
1394
|
+
RuleStore: () => RuleStore,
|
|
1395
|
+
Permissions: () => Permissions,
|
|
1396
|
+
PermissionError: () => PermissionError
|
|
1397
|
+
});
|
|
1398
|
+
import { Context as Context12, Effect as Effect13, Layer as Layer13, Option as Option9, Ref as Ref4, Schema as Schema10 } from "effect";
|
|
1399
|
+
import { dual as dual4 } from "effect/Function";
|
|
1400
|
+
|
|
1401
|
+
class PermissionError extends Schema10.TaggedErrorClass()("@batonfx/core/PermissionError", {
|
|
1402
|
+
message: Schema10.String
|
|
1403
|
+
}) {
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
class Permissions extends Context12.Service()("@batonfx/core/permissions") {
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
class RuleStore extends Context12.Service()("@batonfx/core/permissions/RuleStore") {
|
|
1410
|
+
}
|
|
1411
|
+
var escapeRegExp = (value) => value.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
|
1412
|
+
var glob = (pattern) => new RegExp(`^${pattern.split("*").map(escapeRegExp).join(".*")}$`);
|
|
1413
|
+
var isTextLeaf = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint";
|
|
1414
|
+
var collectCandidates = (value, visiting, out) => {
|
|
1415
|
+
if (typeof value === "string") {
|
|
1416
|
+
out.push(value);
|
|
1417
|
+
return true;
|
|
1418
|
+
}
|
|
1419
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
1420
|
+
out.push(String(value));
|
|
1421
|
+
return true;
|
|
1422
|
+
}
|
|
1423
|
+
if (value === null || value === undefined)
|
|
1424
|
+
return true;
|
|
1425
|
+
if (typeof value !== "object")
|
|
1426
|
+
return false;
|
|
1427
|
+
if (visiting.has(value))
|
|
1428
|
+
return false;
|
|
1429
|
+
visiting.add(value);
|
|
1430
|
+
let complete = true;
|
|
1431
|
+
if (Array.isArray(value)) {
|
|
1432
|
+
const joined = value.filter(isTextLeaf).map(String);
|
|
1433
|
+
if (joined.length > 0)
|
|
1434
|
+
out.push(joined.join(" "));
|
|
1435
|
+
for (const element of value) {
|
|
1436
|
+
complete = collectCandidates(element, visiting, out) && complete;
|
|
1437
|
+
}
|
|
1438
|
+
} else {
|
|
1439
|
+
for (const propValue of Object.values(value)) {
|
|
1440
|
+
complete = collectCandidates(propValue, visiting, out) && complete;
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
visiting.delete(value);
|
|
1444
|
+
return complete;
|
|
1445
|
+
};
|
|
1446
|
+
var serializedParams = (params) => {
|
|
1447
|
+
try {
|
|
1448
|
+
const json = JSON.stringify(params);
|
|
1449
|
+
return json === undefined ? String(params) : json;
|
|
1450
|
+
} catch {
|
|
1451
|
+
return String(params);
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
var project = (params) => {
|
|
1455
|
+
const candidates = [];
|
|
1456
|
+
const complete = collectCandidates(params, new Set, candidates);
|
|
1457
|
+
candidates.push(serializedParams(params));
|
|
1458
|
+
return { candidates, complete };
|
|
1459
|
+
};
|
|
1460
|
+
var matchesProjection = (pattern, tool, projection, failClosed) => {
|
|
1461
|
+
const separator = pattern.indexOf(":");
|
|
1462
|
+
if (separator === -1)
|
|
1463
|
+
return glob(pattern).test(tool);
|
|
1464
|
+
const toolPattern = pattern.slice(0, separator);
|
|
1465
|
+
if (!glob(toolPattern).test(tool))
|
|
1466
|
+
return false;
|
|
1467
|
+
if (!projection.complete && failClosed)
|
|
1468
|
+
return true;
|
|
1469
|
+
const paramsPattern = glob(pattern.slice(separator + 1));
|
|
1470
|
+
return projection.candidates.some((candidate) => paramsPattern.test(candidate));
|
|
1471
|
+
};
|
|
1472
|
+
var matches = dual4(3, (pattern, tool, params) => matchesProjection(pattern, tool, project(params), false));
|
|
1473
|
+
var matchingRule = (ruleset, tool, params) => {
|
|
1474
|
+
const projection = project(params);
|
|
1475
|
+
let matched;
|
|
1476
|
+
for (const rule of ruleset.rules) {
|
|
1477
|
+
if (matchesProjection(rule.pattern, tool, projection, rule.level === "deny"))
|
|
1478
|
+
matched = rule;
|
|
1479
|
+
}
|
|
1480
|
+
return matched;
|
|
1481
|
+
};
|
|
1482
|
+
var matchRule = dual4(3, (ruleset, tool, params) => Option9.fromNullishOr(matchingRule(ruleset, tool, params)));
|
|
1483
|
+
var evaluate = dual4(3, (ruleset, tool, params) => matchingRule(ruleset, tool, params)?.level ?? ruleset.fallback ?? "ask");
|
|
1484
|
+
var tokenFor = (request) => `permission:${request.toolCallId ?? `${request.agentName}:${request.turn}:${request.tool}`}`;
|
|
1485
|
+
var decisionFor = (ruleset, request) => {
|
|
1486
|
+
const rule = matchingRule(ruleset, request.tool, request.params);
|
|
1487
|
+
const level = rule?.level ?? ruleset.fallback ?? "ask";
|
|
1488
|
+
switch (level) {
|
|
1489
|
+
case "allow":
|
|
1490
|
+
return { _tag: "Allow" };
|
|
1491
|
+
case "deny":
|
|
1492
|
+
return { _tag: "Deny", ...rule?.reason === undefined ? {} : { reason: rule.reason } };
|
|
1493
|
+
case "ask":
|
|
1494
|
+
return { _tag: "Ask", token: tokenFor(request) };
|
|
1495
|
+
}
|
|
1496
|
+
};
|
|
1497
|
+
var fromRuleset = (ruleset) => Layer13.succeed(Permissions, Permissions.of({
|
|
1498
|
+
evaluate: (request) => Effect13.succeed(decisionFor(ruleset, request)),
|
|
1499
|
+
await: () => Effect13.succeed(Option9.none())
|
|
1500
|
+
}));
|
|
1501
|
+
var allowAll = Layer13.succeed(Permissions, Permissions.of({
|
|
1502
|
+
evaluate: () => Effect13.succeed({ _tag: "Allow" }),
|
|
1503
|
+
await: () => Effect13.succeed(Option9.none())
|
|
1504
|
+
}));
|
|
1505
|
+
var interactive = (options) => Layer13.succeed(Permissions, Permissions.of({
|
|
1506
|
+
evaluate: (request) => Effect13.succeed(decisionFor(options.ruleset, request)),
|
|
1507
|
+
await: (pending) => options.onAsk(pending).pipe(Effect13.map(Option9.some))
|
|
1508
|
+
}));
|
|
1509
|
+
var ruleStoreMemory = (initialRules = []) => Layer13.effect(RuleStore, Ref4.make(initialRules).pipe(Effect13.map((rules) => RuleStore.of({
|
|
1510
|
+
remember: (rule) => Ref4.update(rules, (current) => [...current.filter((existing) => existing.pattern !== rule.pattern), rule]),
|
|
1511
|
+
rules: Ref4.get(rules)
|
|
1512
|
+
}))));
|
|
1513
|
+
var ruleStoreTestLayer = (implementation) => Layer13.succeed(RuleStore, RuleStore.of(implementation));
|
|
1514
|
+
var testLayer11 = (implementation) => Layer13.succeed(Permissions, Permissions.of(implementation));
|
|
1515
|
+
|
|
1516
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/skill-source.js
|
|
1517
|
+
var exports_skill_source = {};
|
|
1518
|
+
__export(exports_skill_source, {
|
|
1519
|
+
testLayer: () => testLayer12,
|
|
1520
|
+
selectListings: () => selectListings,
|
|
1521
|
+
merge: () => merge2,
|
|
1522
|
+
makeListing: () => makeListing,
|
|
1523
|
+
layer: () => layer6,
|
|
1524
|
+
fromSkills: () => fromSkills,
|
|
1525
|
+
empty: () => empty,
|
|
1526
|
+
SkillSourceError: () => SkillSourceError,
|
|
1527
|
+
SkillSource: () => SkillSource,
|
|
1528
|
+
DESCRIPTION_CAP: () => DESCRIPTION_CAP
|
|
1529
|
+
});
|
|
1530
|
+
import { Context as Context13, Effect as Effect14, Function as Function6, Layer as Layer14, Schema as Schema11 } from "effect";
|
|
1531
|
+
import { Tool as Tool4 } from "effect/unstable/ai";
|
|
1532
|
+
|
|
1533
|
+
class SkillSourceError extends Schema11.TaggedErrorClass()("@batonfx/core/SkillSourceError", {
|
|
1534
|
+
source: Schema11.String,
|
|
1535
|
+
message: Schema11.String,
|
|
1536
|
+
cause: Schema11.optionalKey(Schema11.Defect())
|
|
1537
|
+
}) {
|
|
1538
|
+
}
|
|
1539
|
+
var DESCRIPTION_CAP = 1024;
|
|
1540
|
+
|
|
1541
|
+
class SkillSource extends Context13.Service()("@batonfx/core/skill-source/SkillSource") {
|
|
1542
|
+
}
|
|
1543
|
+
var makeListing = Function6.dual((args) => typeof args[0] !== "number", (frontmatter, descriptionCap = DESCRIPTION_CAP) => `- ${frontmatter.name}: ${frontmatter.description.slice(0, Math.max(0, descriptionCap))}`);
|
|
1544
|
+
var fromSkills = (skills) => {
|
|
1545
|
+
const all = [...skills];
|
|
1546
|
+
const byName = new Map(all.map((skill) => [skill.frontmatter.name, skill]));
|
|
1547
|
+
return Layer14.succeed(SkillSource, SkillSource.of({
|
|
1548
|
+
all: Effect14.succeed(all),
|
|
1549
|
+
get: (name) => Effect14.succeed(byName.get(name))
|
|
1550
|
+
}));
|
|
1551
|
+
};
|
|
1552
|
+
var empty = fromSkills([]);
|
|
1553
|
+
var testLayer12 = (implementation) => Layer14.succeed(SkillSource, SkillSource.of(implementation));
|
|
1554
|
+
var merge2 = (sources) => ({
|
|
1555
|
+
all: Effect14.forEach(sources, (source) => source.all).pipe(Effect14.map((groups) => {
|
|
1556
|
+
const byName = new Map;
|
|
1557
|
+
for (const skills of groups) {
|
|
1558
|
+
for (const skill of skills)
|
|
1559
|
+
byName.set(skill.frontmatter.name, skill);
|
|
1560
|
+
}
|
|
1561
|
+
return [...byName.values()];
|
|
1562
|
+
})),
|
|
1563
|
+
get: (name) => Effect14.gen(function* () {
|
|
1564
|
+
for (const source of sources.toReversed()) {
|
|
1565
|
+
const found = yield* source.get(name);
|
|
1566
|
+
if (found !== undefined)
|
|
1567
|
+
return found;
|
|
1568
|
+
}
|
|
1569
|
+
return;
|
|
1570
|
+
})
|
|
1571
|
+
});
|
|
1572
|
+
var layer6 = (sources) => Layer14.effect(SkillSource, Effect14.forEach(sources, (source) => source).pipe(Effect14.map((built) => SkillSource.of(merge2(built)))));
|
|
1573
|
+
var estimatedTokens = (listing) => Math.ceil(listing.length / 4);
|
|
1574
|
+
var usageRank = (skill, recentlyUsed) => {
|
|
1575
|
+
const index = recentlyUsed.indexOf(skill.frontmatter.name);
|
|
1576
|
+
return index === -1 ? -1 : index;
|
|
1577
|
+
};
|
|
1578
|
+
var selectListings = Function6.dual(3, (skills, budgetTokens, recentlyUsed) => {
|
|
1579
|
+
if (budgetTokens <= 0)
|
|
1580
|
+
return [];
|
|
1581
|
+
const selected = skills.filter((skill) => skill.frontmatter.disableModelInvocation !== true && estimatedTokens(skill.listing) <= budgetTokens);
|
|
1582
|
+
let total = selected.reduce((sum, skill) => sum + estimatedTokens(skill.listing), 0);
|
|
1583
|
+
while (total > budgetTokens && selected.length > 0) {
|
|
1584
|
+
let dropIndex = 0;
|
|
1585
|
+
for (let index = 1;index < selected.length; index += 1) {
|
|
1586
|
+
if (usageRank(selected[index], recentlyUsed) < usageRank(selected[dropIndex], recentlyUsed)) {
|
|
1587
|
+
dropIndex = index;
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
const [dropped] = selected.splice(dropIndex, 1);
|
|
1591
|
+
total -= dropped === undefined ? 0 : estimatedTokens(dropped.listing);
|
|
1592
|
+
}
|
|
1593
|
+
return selected;
|
|
1594
|
+
});
|
|
1595
|
+
|
|
1596
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/steering.js
|
|
1597
|
+
var exports_steering = {};
|
|
1598
|
+
__export(exports_steering, {
|
|
1599
|
+
testLayer: () => testLayer13,
|
|
1600
|
+
layer: () => layer7,
|
|
1601
|
+
SteeringQueueFull: () => SteeringQueueFull,
|
|
1602
|
+
Steering: () => Steering
|
|
1603
|
+
});
|
|
1604
|
+
import { Context as Context14, Effect as Effect15, Exit, Layer as Layer15, Queue, Schema as Schema12 } from "effect";
|
|
1605
|
+
import { Prompt as Prompt7 } from "effect/unstable/ai";
|
|
1606
|
+
|
|
1607
|
+
class Steering extends Context14.Service()("@batonfx/core/steering") {
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
class SteeringQueueFull extends Schema12.TaggedErrorClass()("@batonfx/core/SteeringQueueFull", {
|
|
1611
|
+
queue: Schema12.Literals(["steering", "followUp"]),
|
|
1612
|
+
capacity: Schema12.Finite
|
|
1613
|
+
}) {
|
|
1614
|
+
}
|
|
1615
|
+
var resolvePolicy = (policy, mode) => ({
|
|
1616
|
+
mode: policy?.mode ?? mode,
|
|
1617
|
+
...policy?.capacity === undefined ? {} : { capacity: policy.capacity },
|
|
1618
|
+
onFull: policy?.onFull ?? "fail"
|
|
1619
|
+
});
|
|
1620
|
+
var queueStrategy = (strategy2) => {
|
|
1621
|
+
switch (strategy2) {
|
|
1622
|
+
case "drop-oldest":
|
|
1623
|
+
return "sliding";
|
|
1624
|
+
case "drop-newest":
|
|
1625
|
+
case "fail":
|
|
1626
|
+
return "dropping";
|
|
1627
|
+
case "suspend":
|
|
1628
|
+
return "suspend";
|
|
1629
|
+
}
|
|
1630
|
+
};
|
|
1631
|
+
var makeQueue = (name, policy) => (policy.capacity === undefined ? Queue.unbounded() : Queue.make({ capacity: policy.capacity, strategy: queueStrategy(policy.onFull) })).pipe(Effect15.map((queue) => ({ name, queue, policy })));
|
|
1632
|
+
var offer = (runtime, message) => Queue.offer(runtime.queue, message).pipe(Effect15.flatMap((offered) => {
|
|
1633
|
+
if (offered || runtime.policy.capacity === undefined || runtime.policy.onFull !== "fail")
|
|
1634
|
+
return Effect15.void;
|
|
1635
|
+
return SteeringQueueFull.make({ queue: runtime.name, capacity: runtime.policy.capacity });
|
|
1636
|
+
}));
|
|
1637
|
+
var drainOne = (queue) => Effect15.sync(() => {
|
|
1638
|
+
const taken = Queue.takeUnsafe(queue);
|
|
1639
|
+
return taken === undefined || !Exit.isSuccess(taken) ? [] : [taken.value];
|
|
1640
|
+
});
|
|
1641
|
+
var drain = (queue, mode) => mode === "all" ? Queue.clear(queue) : drainOne(queue);
|
|
1642
|
+
var layer7 = (options = {}) => Layer15.effect(Steering, Effect15.gen(function* () {
|
|
1643
|
+
const steeringQueue = yield* makeQueue("steering", resolvePolicy(options.steering, "all"));
|
|
1644
|
+
const followUpQueue = yield* makeQueue("followUp", resolvePolicy(options.followUp, "one-at-a-time"));
|
|
1645
|
+
return Steering.of({
|
|
1646
|
+
steer: (message) => offer(steeringQueue, message),
|
|
1647
|
+
followUp: (message) => offer(followUpQueue, message),
|
|
1648
|
+
takeSteering: drain(steeringQueue.queue, steeringQueue.policy.mode),
|
|
1649
|
+
takeFollowUp: drain(followUpQueue.queue, followUpQueue.policy.mode)
|
|
1650
|
+
});
|
|
1651
|
+
}));
|
|
1652
|
+
var testLayer13 = (implementation) => Layer15.succeed(Steering, Steering.of(implementation));
|
|
1653
|
+
|
|
1654
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/agent.js
|
|
1655
|
+
var exports_agent = {};
|
|
1656
|
+
__export(exports_agent, {
|
|
1657
|
+
streamObject: () => streamObject,
|
|
1658
|
+
stream: () => stream2,
|
|
1659
|
+
provideModel: () => provideModel,
|
|
1660
|
+
persistedObject: () => persistedObject,
|
|
1661
|
+
persisted: () => persisted,
|
|
1662
|
+
make: () => make5,
|
|
1663
|
+
generatePersistedObject: () => generatePersistedObject,
|
|
1664
|
+
generatePersisted: () => generatePersisted,
|
|
1665
|
+
generateObject: () => generateObject,
|
|
1666
|
+
generate: () => generate,
|
|
1667
|
+
defaultObjectPrompt: () => defaultObjectPrompt
|
|
1668
|
+
});
|
|
1669
|
+
import { Cause as Cause4, Channel, Effect as Effect18, Equal, Exit as Exit2, Fiber, HashMap as HashMap4, Layer as Layer17, Option as Option12, Queue as Queue2, Ref as Ref5, Schema as Schema14, Semaphore as Semaphore2, Stream as Stream4, Types } from "effect";
|
|
1670
|
+
import { dual as dual7 } from "effect/Function";
|
|
1671
|
+
import { AiError as AiError3, Chat, LanguageModel as LanguageModel5, Prompt as Prompt9, Response as Response7, Telemetry, Tokenizer as Tokenizer2, Tool as Tool7, Toolkit as Toolkit4 } from "effect/unstable/ai";
|
|
1672
|
+
|
|
1673
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/tool-authorization.js
|
|
1674
|
+
import { Cause as Cause3, Context as Context15, Effect as Effect16, Layer as Layer16, Option as Option10, Schema as Schema13 } from "effect";
|
|
1675
|
+
import { dual as dual5 } from "effect/Function";
|
|
1676
|
+
import { Prompt as Prompt8, Response as Response6, Tool as Tool5 } from "effect/unstable/ai";
|
|
1677
|
+
class PermissionDenied extends Schema13.TaggedErrorClass()("@batonfx/core/PermissionDenied", {
|
|
1678
|
+
message: Schema13.String
|
|
1679
|
+
}) {
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
class AuthorizationError extends Schema13.TaggedErrorClass()("@batonfx/core/AuthorizationError", { message: Schema13.String, cause: Schema13.optional(Schema13.Defect()) }) {
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
class ToolAuthorizerService extends Context15.Service()("@batonfx/core/tool-authorization/ToolAuthorizerService") {
|
|
1686
|
+
}
|
|
1687
|
+
var deny = (message) => ({
|
|
1688
|
+
_tag: "Deny",
|
|
1689
|
+
error: PermissionDenied.make({ message })
|
|
1690
|
+
});
|
|
1691
|
+
var suspension = (request, token, stage) => ({
|
|
1692
|
+
_tag: "Suspend",
|
|
1693
|
+
suspension: AgentSuspended.make({
|
|
1694
|
+
token,
|
|
1695
|
+
reason: "approval",
|
|
1696
|
+
authorization_stage: stage,
|
|
1697
|
+
tool_call_id: request.call.id,
|
|
1698
|
+
tool_name: request.call.name,
|
|
1699
|
+
tool_params: request.call.params,
|
|
1700
|
+
active_tools: request.activeTools,
|
|
1701
|
+
activated_skills: request.activatedSkills
|
|
1702
|
+
})
|
|
1703
|
+
});
|
|
1704
|
+
var authorizationError = (error) => AuthorizationError.make({ message: error.message, cause: error });
|
|
1705
|
+
var approvalRequired = (request) => {
|
|
1706
|
+
const needsApproval = request.tool?.needsApproval;
|
|
1707
|
+
if (needsApproval === undefined)
|
|
1708
|
+
return Effect16.succeed(false);
|
|
1709
|
+
if (typeof needsApproval === "boolean")
|
|
1710
|
+
return Effect16.succeed(needsApproval);
|
|
1711
|
+
return Effect16.suspend(() => {
|
|
1712
|
+
const result = needsApproval(request.call.params, {
|
|
1713
|
+
toolCallId: request.call.id,
|
|
1714
|
+
messages: request.messages
|
|
1715
|
+
});
|
|
1716
|
+
return Effect16.isEffect(result) ? result : Effect16.succeed(result);
|
|
1717
|
+
}).pipe(Effect16.catchCause((cause) => Cause3.hasInterrupts(cause) ? Effect16.interrupt : Effect16.succeed(true)));
|
|
1718
|
+
};
|
|
1719
|
+
var evaluationRequest = (request) => ({
|
|
1720
|
+
tool: request.call.name,
|
|
1721
|
+
params: request.call.params,
|
|
1722
|
+
agentName: request.execution.agentName,
|
|
1723
|
+
turn: request.execution.turn,
|
|
1724
|
+
toolCallId: request.call.id,
|
|
1725
|
+
sessionId: request.execution.sessionId
|
|
1726
|
+
});
|
|
1727
|
+
var rememberedDecision = (request, ruleStore) => ruleStore?.rules === undefined ? Effect16.succeedNone : ruleStore.rules.pipe(Effect16.map((rules) => {
|
|
1728
|
+
if (rules.length === 0)
|
|
1729
|
+
return Option10.none();
|
|
1730
|
+
const matched = matchRule({ rules }, request.call.name, request.call.params);
|
|
1731
|
+
if (Option10.isNone(matched))
|
|
1732
|
+
return Option10.none();
|
|
1733
|
+
switch (matched.value.level) {
|
|
1734
|
+
case "allow":
|
|
1735
|
+
return Option10.some({ _tag: "Allow" });
|
|
1736
|
+
case "deny":
|
|
1737
|
+
return Option10.some({
|
|
1738
|
+
_tag: "Deny",
|
|
1739
|
+
...matched.value.reason === undefined ? {} : { reason: matched.value.reason }
|
|
1740
|
+
});
|
|
1741
|
+
case "ask":
|
|
1742
|
+
return Option10.some({ _tag: "Ask", token: `permission:${request.call.id}` });
|
|
1743
|
+
}
|
|
1744
|
+
}), Effect16.mapError(authorizationError));
|
|
1745
|
+
var resolveRequiredApproval = (request, approvals) => Effect16.gen(function* () {
|
|
1746
|
+
yield* request.onApprovalRequired;
|
|
1747
|
+
if (approvals === undefined)
|
|
1748
|
+
return deny("Approvals service is required for approval-gated tools");
|
|
1749
|
+
const decision2 = yield* approvals.check(request.execution);
|
|
1750
|
+
switch (decision2._tag) {
|
|
1751
|
+
case "Approved":
|
|
1752
|
+
return { _tag: "Execute" };
|
|
1753
|
+
case "Denied":
|
|
1754
|
+
return deny(decision2.reason ?? "Tool call denied");
|
|
1755
|
+
case "Pending":
|
|
1756
|
+
return suspension(request, decision2.token, "approval");
|
|
1757
|
+
}
|
|
1758
|
+
});
|
|
1759
|
+
var finalApproval = (request, approvals) => approvalRequired(request).pipe(Effect16.flatMap((required) => {
|
|
1760
|
+
if (!required)
|
|
1761
|
+
return Effect16.succeed({ _tag: "Execute" });
|
|
1762
|
+
return resolveRequiredApproval(request, approvals);
|
|
1763
|
+
}));
|
|
1764
|
+
var make4 = (options = {}) => ({
|
|
1765
|
+
authorize: (request) => Effect16.gen(function* () {
|
|
1766
|
+
if (!request.active || request.tool === undefined) {
|
|
1767
|
+
return deny(`Tool ${request.call.name} is not active for turn ${request.execution.turn}`);
|
|
1768
|
+
}
|
|
1769
|
+
if (request.authorizationStage === "approval") {
|
|
1770
|
+
return yield* resolveRequiredApproval(request, options.approvals);
|
|
1771
|
+
}
|
|
1772
|
+
const remembered = yield* rememberedDecision(request, options.ruleStore);
|
|
1773
|
+
if (Option10.isSome(remembered) && remembered.value._tag === "Deny") {
|
|
1774
|
+
return deny(remembered.value.reason ?? "Permission denied");
|
|
1775
|
+
}
|
|
1776
|
+
if (request.authorizationStage === "permission") {
|
|
1777
|
+
const token = request.authorizationToken ?? `permission:${request.call.id}`;
|
|
1778
|
+
if (options.permissions !== undefined) {
|
|
1779
|
+
const current2 = yield* options.permissions.evaluate(evaluationRequest(request)).pipe(Effect16.mapError(authorizationError));
|
|
1780
|
+
if (current2._tag === "Deny")
|
|
1781
|
+
return deny(current2.reason ?? "Permission denied");
|
|
1782
|
+
}
|
|
1783
|
+
yield* request.onApprovalRequired;
|
|
1784
|
+
if (options.permissions === undefined)
|
|
1785
|
+
return suspension(request, token, "permission");
|
|
1786
|
+
const answer2 = yield* options.permissions.await({
|
|
1787
|
+
token,
|
|
1788
|
+
tool: request.call.name,
|
|
1789
|
+
params: request.call.params,
|
|
1790
|
+
agentName: request.execution.agentName,
|
|
1791
|
+
turn: request.execution.turn,
|
|
1792
|
+
toolCallId: request.call.id
|
|
1793
|
+
}).pipe(Effect16.mapError(authorizationError));
|
|
1794
|
+
if (Option10.isNone(answer2))
|
|
1795
|
+
return suspension(request, token, "permission");
|
|
1796
|
+
if (answer2.value._tag === "Denied")
|
|
1797
|
+
return deny(answer2.value.reason ?? "Permission denied");
|
|
1798
|
+
if (answer2.value._tag === "Always" && options.ruleStore !== undefined) {
|
|
1799
|
+
yield* options.ruleStore.remember({ pattern: request.call.name, level: "allow" }).pipe(Effect16.mapError(authorizationError));
|
|
1800
|
+
}
|
|
1801
|
+
return yield* finalApproval(request, options.approvals);
|
|
1802
|
+
}
|
|
1803
|
+
if (options.permissions === undefined) {
|
|
1804
|
+
if (Option10.isSome(remembered) && remembered.value._tag === "Ask") {
|
|
1805
|
+
yield* request.onApprovalRequired;
|
|
1806
|
+
return suspension(request, remembered.value.token, "permission");
|
|
1807
|
+
}
|
|
1808
|
+
return yield* finalApproval(request, options.approvals);
|
|
1809
|
+
}
|
|
1810
|
+
const permissions = options.permissions;
|
|
1811
|
+
const current = yield* permissions.evaluate(evaluationRequest(request)).pipe(Effect16.mapError(authorizationError));
|
|
1812
|
+
if (current._tag === "Deny")
|
|
1813
|
+
return deny(current.reason ?? "Permission denied");
|
|
1814
|
+
if (current._tag !== "Ask" || Option10.isSome(remembered) && remembered.value._tag === "Allow") {
|
|
1815
|
+
return yield* finalApproval(request, options.approvals);
|
|
1816
|
+
}
|
|
1817
|
+
const pending = {
|
|
1818
|
+
token: current.token,
|
|
1819
|
+
tool: request.call.name,
|
|
1820
|
+
params: request.call.params,
|
|
1821
|
+
agentName: request.execution.agentName,
|
|
1822
|
+
turn: request.execution.turn,
|
|
1823
|
+
toolCallId: request.call.id
|
|
1824
|
+
};
|
|
1825
|
+
yield* request.onApprovalRequired;
|
|
1826
|
+
const answer = yield* permissions.await(pending).pipe(Effect16.mapError(authorizationError));
|
|
1827
|
+
if (Option10.isNone(answer))
|
|
1828
|
+
return suspension(request, current.token, "permission");
|
|
1829
|
+
switch (answer.value._tag) {
|
|
1830
|
+
case "Denied":
|
|
1831
|
+
return deny(answer.value.reason ?? "Permission denied");
|
|
1832
|
+
case "Always":
|
|
1833
|
+
if (options.ruleStore !== undefined) {
|
|
1834
|
+
yield* options.ruleStore.remember({ pattern: request.call.name, level: "allow" }).pipe(Effect16.mapError(authorizationError));
|
|
1835
|
+
}
|
|
1836
|
+
return yield* finalApproval(request, options.approvals);
|
|
1837
|
+
case "Approved":
|
|
1838
|
+
return yield* finalApproval(request, options.approvals);
|
|
1839
|
+
}
|
|
1840
|
+
})
|
|
1841
|
+
});
|
|
1842
|
+
var fromPermissions = dual5((args) => args.length === 2 || args.length === 1 && ("evaluate" in args[0]), (permissions, options = {}) => make4({ ...options, permissions }));
|
|
1843
|
+
|
|
1844
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/tool-registry.js
|
|
1845
|
+
import { Effect as Effect17, HashMap as HashMap3, Option as Option11 } from "effect";
|
|
1846
|
+
import { dual as dual6 } from "effect/Function";
|
|
1847
|
+
import { Tool as Tool6, Toolkit as Toolkit3 } from "effect/unstable/ai";
|
|
1848
|
+
var makeToolkit = (entries) => {
|
|
1849
|
+
const toolkit = Toolkit3.make(...entries.map((candidate) => candidate.tool));
|
|
1850
|
+
for (const entry of entries) {
|
|
1851
|
+
if (!Object.hasOwn(toolkit.tools, entry.tool.name)) {
|
|
1852
|
+
Object.defineProperty(toolkit.tools, entry.tool.name, {
|
|
1853
|
+
configurable: true,
|
|
1854
|
+
enumerable: true,
|
|
1855
|
+
value: entry.tool,
|
|
1856
|
+
writable: true
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
return toolkit;
|
|
1861
|
+
};
|
|
1862
|
+
var assemble = (candidates) => {
|
|
1863
|
+
const grouped = new Map;
|
|
1864
|
+
for (const candidate of candidates) {
|
|
1865
|
+
const existing = grouped.get(candidate.tool.name);
|
|
1866
|
+
if (existing === undefined)
|
|
1867
|
+
grouped.set(candidate.tool.name, [candidate]);
|
|
1868
|
+
else
|
|
1869
|
+
existing.push(candidate);
|
|
1870
|
+
}
|
|
1871
|
+
for (const candidate of candidates) {
|
|
1872
|
+
const conflicts = grouped.get(candidate.tool.name);
|
|
1873
|
+
if (conflicts !== undefined && conflicts.length > 1) {
|
|
1874
|
+
return Effect17.fail(ToolNameCollision.make({
|
|
1875
|
+
name: candidate.tool.name,
|
|
1876
|
+
origins: [conflicts[0].origin, ...conflicts.slice(1).map((conflict) => conflict.origin)]
|
|
1877
|
+
}));
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
const entries = [...candidates];
|
|
1881
|
+
return Effect17.succeed({
|
|
1882
|
+
entries,
|
|
1883
|
+
byName: HashMap3.fromIterable(entries.map((candidate) => [candidate.tool.name, candidate])),
|
|
1884
|
+
toolkit: makeToolkit(entries)
|
|
1885
|
+
});
|
|
1886
|
+
};
|
|
1887
|
+
var get = dual6(2, (registry, name) => Option11.getOrUndefined(HashMap3.get(registry.byName, name)));
|
|
1888
|
+
var select = dual6(2, (registry, names) => {
|
|
1889
|
+
const entries = registry.entries.filter((entry) => names.includes(entry.tool.name));
|
|
1890
|
+
return {
|
|
1891
|
+
entries,
|
|
1892
|
+
byName: HashMap3.fromIterable(entries.map((candidate) => [candidate.tool.name, candidate])),
|
|
1893
|
+
toolkit: makeToolkit(entries)
|
|
1894
|
+
};
|
|
1895
|
+
});
|
|
1896
|
+
|
|
1897
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/agent.js
|
|
1898
|
+
var AgentTypeId = Symbol.for("@batonfx/core/Agent");
|
|
1899
|
+
var ModelLayerTypeId = Symbol.for("@batonfx/core/Agent/ModelLayer");
|
|
1900
|
+
var classifyOtherFailure = () => "other";
|
|
1901
|
+
function make5(nameOrOptions, options = {}) {
|
|
1902
|
+
if (nameOrOptions === undefined || typeof nameOrOptions !== "string" && !("name" in nameOrOptions)) {
|
|
1903
|
+
const curriedOptions = nameOrOptions ?? {};
|
|
1904
|
+
if ("tools" in curriedOptions && Array.isArray(curriedOptions.tools)) {
|
|
1905
|
+
const tools = curriedOptions.tools;
|
|
1906
|
+
return (name) => make5({
|
|
1907
|
+
name,
|
|
1908
|
+
tools,
|
|
1909
|
+
...curriedOptions.instructions === undefined ? {} : { instructions: curriedOptions.instructions },
|
|
1910
|
+
...curriedOptions.policy === undefined ? {} : { policy: curriedOptions.policy },
|
|
1911
|
+
...curriedOptions.model === undefined ? {} : { model: curriedOptions.model },
|
|
1912
|
+
...curriedOptions.memory === undefined ? {} : { memory: curriedOptions.memory },
|
|
1913
|
+
...curriedOptions.authorization === undefined ? {} : { authorization: curriedOptions.authorization },
|
|
1914
|
+
...curriedOptions.metadata === undefined ? {} : { metadata: curriedOptions.metadata }
|
|
1915
|
+
});
|
|
1916
|
+
}
|
|
1917
|
+
return (name) => make5({
|
|
1918
|
+
name,
|
|
1919
|
+
...curriedOptions.instructions === undefined ? {} : { instructions: curriedOptions.instructions },
|
|
1920
|
+
...curriedOptions.toolkit === undefined ? {} : { toolkit: curriedOptions.toolkit },
|
|
1921
|
+
...curriedOptions.policy === undefined ? {} : { policy: curriedOptions.policy },
|
|
1922
|
+
...curriedOptions.model === undefined ? {} : { model: curriedOptions.model },
|
|
1923
|
+
...curriedOptions.memory === undefined ? {} : { memory: curriedOptions.memory },
|
|
1924
|
+
...curriedOptions.authorization === undefined ? {} : { authorization: curriedOptions.authorization },
|
|
1925
|
+
...curriedOptions.metadata === undefined ? {} : { metadata: curriedOptions.metadata }
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
const resolved = typeof nameOrOptions === "string" ? { ...options, name: nameOrOptions } : nameOrOptions;
|
|
1929
|
+
const declaredTools = "tools" in resolved && Array.isArray(resolved.tools) ? resolved.tools : undefined;
|
|
1930
|
+
const toolkit = declaredTools === undefined ? resolved.toolkit ?? Toolkit4.empty : Toolkit4.make(...declaredTools);
|
|
1931
|
+
if (declaredTools !== undefined) {
|
|
1932
|
+
for (const tool of declaredTools) {
|
|
1933
|
+
if (!Object.hasOwn(toolkit.tools, tool.name)) {
|
|
1934
|
+
Object.defineProperty(toolkit.tools, tool.name, {
|
|
1935
|
+
configurable: true,
|
|
1936
|
+
enumerable: true,
|
|
1937
|
+
value: tool,
|
|
1938
|
+
writable: true
|
|
1939
|
+
});
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
return {
|
|
1944
|
+
[AgentTypeId]: {
|
|
1945
|
+
tools: (value) => value,
|
|
1946
|
+
requirements: (value) => value
|
|
1947
|
+
},
|
|
1948
|
+
name: resolved.name,
|
|
1949
|
+
...resolved.instructions === undefined ? {} : { instructions: resolved.instructions },
|
|
1950
|
+
toolkit,
|
|
1951
|
+
policy: resolved.policy ?? defaultPolicy,
|
|
1952
|
+
...resolved.model === undefined ? {} : { model: resolved.model },
|
|
1953
|
+
...resolved.memory === undefined ? {} : { memory: resolved.memory },
|
|
1954
|
+
...resolved.authorization === undefined ? {} : { authorization: resolved.authorization },
|
|
1955
|
+
...resolved.metadata === undefined ? {} : { metadata: resolved.metadata },
|
|
1956
|
+
toolDeclarations: (declaredTools ?? Object.values(toolkit.tools)).map((tool) => ({
|
|
1957
|
+
tool,
|
|
1958
|
+
origin: { _tag: "Static", agent: resolved.name }
|
|
1959
|
+
}))
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1962
|
+
var defaultProgressOverflowPolicy = { _tag: "Backpressure", capacity: 64 };
|
|
1963
|
+
var progressCapacitySchema = Schema14.Finite.pipe(Schema14.check(Schema14.isInt(), Schema14.isGreaterThan(0)));
|
|
1964
|
+
var progressOverflowPolicySchema = Schema14.Union([
|
|
1965
|
+
Schema14.TaggedStruct("Backpressure", { capacity: progressCapacitySchema }),
|
|
1966
|
+
Schema14.TaggedStruct("Dropping", { capacity: progressCapacitySchema }),
|
|
1967
|
+
Schema14.TaggedStruct("Sliding", { capacity: progressCapacitySchema }),
|
|
1968
|
+
Schema14.TaggedStruct("Fail", { capacity: progressCapacitySchema })
|
|
1969
|
+
]);
|
|
1970
|
+
var defaultObjectPrompt = "Return the final structured output for the task above.";
|
|
1971
|
+
var steeringDrainedEvent = (turn, queue, messages) => ({
|
|
1972
|
+
_tag: "SteeringDrained",
|
|
1973
|
+
turn,
|
|
1974
|
+
queue,
|
|
1975
|
+
count: messages.length
|
|
1976
|
+
});
|
|
1977
|
+
var persistenceLocks = new WeakMap;
|
|
1978
|
+
var reservePersistedChatLock = (persistence, chatId) => {
|
|
1979
|
+
const locks = persistenceLocks.get(persistence) ?? new Map;
|
|
1980
|
+
if (!persistenceLocks.has(persistence))
|
|
1981
|
+
persistenceLocks.set(persistence, locks);
|
|
1982
|
+
const existing = locks.get(chatId);
|
|
1983
|
+
if (existing !== undefined) {
|
|
1984
|
+
existing.users += 1;
|
|
1985
|
+
return existing;
|
|
1986
|
+
}
|
|
1987
|
+
const created = { semaphore: Semaphore2.makeUnsafe(1), users: 1 };
|
|
1988
|
+
locks.set(chatId, created);
|
|
1989
|
+
return created;
|
|
1990
|
+
};
|
|
1991
|
+
var suspensionCheckpointOption = "@batonfx/core/suspension";
|
|
1992
|
+
var suspensionMetadata = Schema14.Struct({
|
|
1993
|
+
token: Schema14.String,
|
|
1994
|
+
reason: Schema14.Literals(["tool-wait", "approval"]),
|
|
1995
|
+
authorization_stage: Schema14.optional(Schema14.Literals(["permission", "approval"])),
|
|
1996
|
+
active_tools: Schema14.optional(Schema14.Array(Schema14.String)),
|
|
1997
|
+
activated_skills: Schema14.optional(Schema14.Array(Schema14.String))
|
|
1998
|
+
});
|
|
1999
|
+
var releasePersistedChatLock = (persistence, chatId, lock) => {
|
|
2000
|
+
lock.users -= 1;
|
|
2001
|
+
if (lock.users !== 0)
|
|
2002
|
+
return;
|
|
2003
|
+
const locks = persistenceLocks.get(persistence);
|
|
2004
|
+
if (locks?.get(chatId) !== lock)
|
|
2005
|
+
return;
|
|
2006
|
+
locks.delete(chatId);
|
|
2007
|
+
if (locks.size === 0)
|
|
2008
|
+
persistenceLocks.delete(persistence);
|
|
2009
|
+
};
|
|
2010
|
+
var unresolvedToolCall = (messages) => {
|
|
2011
|
+
const unpaired = new Map;
|
|
2012
|
+
const ambiguous = new Set;
|
|
2013
|
+
for (const [messageIndex, message] of messages.entries()) {
|
|
2014
|
+
if (typeof message.content === "string")
|
|
2015
|
+
continue;
|
|
2016
|
+
for (const [partIndex, part] of message.content.entries()) {
|
|
2017
|
+
if (part.type === "tool-call") {
|
|
2018
|
+
const occurrences = unpaired.get(part.id) ?? [];
|
|
2019
|
+
if (!part.providerExecuted && occurrences.some(({ call }) => !call.providerExecuted))
|
|
2020
|
+
ambiguous.add(part.id);
|
|
2021
|
+
occurrences.push({ call: part, messageIndex, partIndex });
|
|
2022
|
+
unpaired.set(part.id, occurrences);
|
|
2023
|
+
}
|
|
2024
|
+
if (part.type === "tool-result") {
|
|
2025
|
+
const occurrences = unpaired.get(part.id);
|
|
2026
|
+
if (occurrences === undefined)
|
|
2027
|
+
continue;
|
|
2028
|
+
const matched = occurrences.findLastIndex(({ call }) => call.name === part.name);
|
|
2029
|
+
if (matched !== -1)
|
|
2030
|
+
occurrences.splice(matched, 1);
|
|
2031
|
+
if (occurrences.length === 0) {
|
|
2032
|
+
unpaired.delete(part.id);
|
|
2033
|
+
ambiguous.delete(part.id);
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
const unresolved = [...unpaired.entries()].flatMap(([id, occurrences]) => ambiguous.has(id) ? [] : occurrences.filter(({ call }) => !call.providerExecuted));
|
|
2039
|
+
const pending = unresolved[0];
|
|
2040
|
+
return unresolved.length === 1 && pending !== undefined ? {
|
|
2041
|
+
call: pending.call,
|
|
2042
|
+
messages: messages.slice(0, pending.messageIndex),
|
|
2043
|
+
messageIndex: pending.messageIndex,
|
|
2044
|
+
partIndex: pending.partIndex
|
|
2045
|
+
} : undefined;
|
|
2046
|
+
};
|
|
2047
|
+
var suspensionCheckpoint = (messages) => {
|
|
2048
|
+
const unresolved = unresolvedToolCall(messages);
|
|
2049
|
+
if (unresolved === undefined)
|
|
2050
|
+
return;
|
|
2051
|
+
const metadata = Schema14.decodeUnknownOption(suspensionMetadata)(unresolved.call.options[suspensionCheckpointOption]);
|
|
2052
|
+
if (Option12.isNone(metadata))
|
|
2053
|
+
return;
|
|
2054
|
+
return {
|
|
2055
|
+
call: unresolved.call,
|
|
2056
|
+
messages: unresolved.messages,
|
|
2057
|
+
suspension: AgentSuspended.make({
|
|
2058
|
+
...metadata.value,
|
|
2059
|
+
tool_call_id: unresolved.call.id,
|
|
2060
|
+
tool_name: unresolved.call.name,
|
|
2061
|
+
tool_params: unresolved.call.params
|
|
2062
|
+
})
|
|
2063
|
+
};
|
|
2064
|
+
};
|
|
2065
|
+
var sameSuspension = (left, right) => left.token === right.token && left.reason === right.reason && left.authorization_stage === right.authorization_stage && left.tool_call_id === right.tool_call_id && left.tool_name === right.tool_name && Equal.equals(left.tool_params, right.tool_params) && Equal.equals(left.active_tools, right.active_tools) && Equal.equals(left.activated_skills, right.activated_skills);
|
|
2066
|
+
var skillListingBudgetTokens = 2048;
|
|
2067
|
+
var activateSkillToolName = "activate_skill";
|
|
2068
|
+
var activateSkillParameters = Schema14.Struct({ name: Schema14.String });
|
|
2069
|
+
var activateSkillSuccess = Schema14.Struct({
|
|
2070
|
+
name: Schema14.String,
|
|
2071
|
+
body: Schema14.String,
|
|
2072
|
+
allowedTools: Schema14.Array(Schema14.String)
|
|
2073
|
+
});
|
|
2074
|
+
var activateSkillFailure = Schema14.Struct({
|
|
2075
|
+
reason: Schema14.Literals(["not-found", "not-model-invocable"]),
|
|
2076
|
+
message: Schema14.String
|
|
2077
|
+
});
|
|
2078
|
+
var activateSkillTool = Tool7.make(activateSkillToolName, {
|
|
2079
|
+
description: "Load the full body for one listed Baton skill by name before applying that skill.",
|
|
2080
|
+
parameters: activateSkillParameters,
|
|
2081
|
+
success: activateSkillSuccess,
|
|
2082
|
+
failure: activateSkillFailure,
|
|
2083
|
+
failureMode: "return"
|
|
2084
|
+
});
|
|
2085
|
+
var errorMessage = (error) => error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
2086
|
+
var isToolNameCollision = Schema14.is(ToolNameCollision);
|
|
2087
|
+
var appendInstructionFragment = (base, fragment) => {
|
|
2088
|
+
if (fragment === undefined || fragment.length === 0)
|
|
2089
|
+
return base;
|
|
2090
|
+
if (base === undefined || base.length === 0)
|
|
2091
|
+
return fragment;
|
|
2092
|
+
return `${base}
|
|
2093
|
+
|
|
2094
|
+
${fragment}`;
|
|
2095
|
+
};
|
|
2096
|
+
var isTurnPolicyDecision = (input) => {
|
|
2097
|
+
if (typeof input !== "object" || input === null || !("_tag" in input))
|
|
2098
|
+
return false;
|
|
2099
|
+
if (input._tag === "Continue")
|
|
2100
|
+
return true;
|
|
2101
|
+
return input._tag === "Stop" && "reason" in input && Schema14.is(StopReason)(input.reason);
|
|
2102
|
+
};
|
|
2103
|
+
var successResult = (call, outcome) => Response7.toolResultPart({
|
|
2104
|
+
id: call.id,
|
|
2105
|
+
name: call.name,
|
|
2106
|
+
isFailure: false,
|
|
2107
|
+
result: outcome.result,
|
|
2108
|
+
encodedResult: outcome.encodedResult,
|
|
2109
|
+
providerExecuted: false,
|
|
2110
|
+
preliminary: false
|
|
2111
|
+
});
|
|
2112
|
+
var domainFailureResult = (call, outcome) => Response7.toolResultPart({
|
|
2113
|
+
id: call.id,
|
|
2114
|
+
name: call.name,
|
|
2115
|
+
isFailure: true,
|
|
2116
|
+
result: outcome.failure,
|
|
2117
|
+
encodedResult: outcome.encodedFailure,
|
|
2118
|
+
providerExecuted: false,
|
|
2119
|
+
preliminary: false
|
|
2120
|
+
});
|
|
2121
|
+
var suspended = (call, token, reason) => AgentSuspended.make({
|
|
2122
|
+
token,
|
|
2123
|
+
reason,
|
|
2124
|
+
tool_call_id: call.id,
|
|
2125
|
+
tool_name: call.name,
|
|
2126
|
+
tool_params: call.params
|
|
2127
|
+
});
|
|
2128
|
+
var withSystem = (instructions, prompt) => Prompt9.fromMessages([Prompt9.makeMessage("system", { content: instructions }), ...prompt.content]);
|
|
2129
|
+
var skillListingsInstructions = (listings) => `Available skills:
|
|
2130
|
+
${listings}
|
|
2131
|
+
|
|
2132
|
+
Call ${activateSkillToolName} with a listed skill name to load its full body before using it.`;
|
|
2133
|
+
var recalledMessages = (prompt) => prompt.content.filter(isMessageFromRecall).map(recalledMessageIdentity);
|
|
2134
|
+
var messageJsonStringCodec = Schema14.fromJsonString(Schema14.toCodecJson(Prompt9.Message));
|
|
2135
|
+
var encodeMessage = Schema14.encodeEffect(messageJsonStringCodec);
|
|
2136
|
+
var decodeMessage = Schema14.decodeEffect(messageJsonStringCodec);
|
|
2137
|
+
var detachMessage = (message) => encodeMessage(message).pipe(Effect18.flatMap(decodeMessage), Effect18.map((detached) => isMessageFromRecall(message) && message.role === "user" && detached.role === "user" ? replaceRecalledMessage(message, detached.content) : detached));
|
|
2138
|
+
var detachPrompt = (prompt) => Effect18.forEach(prompt.content, detachMessage).pipe(Effect18.map(Prompt9.fromMessages));
|
|
2139
|
+
var detachEntry = (entry) => entry._tag === "Message" || entry._tag === "Steering" ? detachMessage(entry.message).pipe(Effect18.map((message) => ({ ...entry, message }))) : Effect18.succeed(entry);
|
|
2140
|
+
var preservesRecalledMessages = (allowed, required, transformed) => {
|
|
2141
|
+
const allowedSet = new Set(allowed);
|
|
2142
|
+
const transformedMessages = recalledMessages(transformed);
|
|
2143
|
+
const transformedSet = new Set(transformedMessages);
|
|
2144
|
+
return transformedSet.size === transformedMessages.length && transformedMessages.every((message) => allowedSet.has(message)) && required.every((message) => transformedSet.has(message));
|
|
2145
|
+
};
|
|
2146
|
+
var applyPromptChain = (chain, prompt, context) => Effect18.gen(function* () {
|
|
2147
|
+
let current = prompt;
|
|
2148
|
+
for (const middleware of chain) {
|
|
2149
|
+
if (middleware.transformPrompt !== undefined) {
|
|
2150
|
+
const recalled = recalledMessages(current);
|
|
2151
|
+
const transformed = yield* middleware.transformPrompt(current, context);
|
|
2152
|
+
if (!preservesRecalledMessages(recalled, recalled, transformed)) {
|
|
2153
|
+
return yield* MiddlewareViolation.make({
|
|
2154
|
+
turn: context.turn,
|
|
2155
|
+
detail: "Prompt middleware must preserve recalled-memory message lineage"
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
current = transformed;
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
return current;
|
|
2162
|
+
});
|
|
2163
|
+
var applyPartChain = (chain, part, context) => Effect18.gen(function* () {
|
|
2164
|
+
let current = Option12.some(part);
|
|
2165
|
+
for (const middleware of chain) {
|
|
2166
|
+
if (Option12.isNone(current))
|
|
2167
|
+
break;
|
|
2168
|
+
if (middleware.transformPart !== undefined) {
|
|
2169
|
+
current = yield* middleware.transformPart(current.value, context);
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
return current;
|
|
2173
|
+
});
|
|
2174
|
+
var streamInternal = (agent, options, structured) => Stream4.unwrap(Effect18.gen(function* () {
|
|
2175
|
+
if (options.history !== undefined && options.persistence !== undefined) {
|
|
2176
|
+
return yield* AgentError.make({
|
|
2177
|
+
message: "RunOptions.history and RunOptions.persistence are mutually exclusive",
|
|
2178
|
+
turn: 0
|
|
2179
|
+
});
|
|
2180
|
+
}
|
|
2181
|
+
const persistenceOptions = options.persistence;
|
|
2182
|
+
const resume = options.resume;
|
|
2183
|
+
const persistenceService = yield* Effect18.serviceOption(Chat.Persistence);
|
|
2184
|
+
const compactionService = yield* Effect18.serviceOption(Compaction);
|
|
2185
|
+
const sessionService = yield* Effect18.serviceOption(SessionStore);
|
|
2186
|
+
const persisted = persistenceOptions === undefined ? undefined : yield* Option12.match(persistenceService, {
|
|
2187
|
+
onNone: () => Effect18.fail(AgentError.make({
|
|
2188
|
+
message: "RunOptions.persistence requires Chat.Persistence in context",
|
|
2189
|
+
turn: 0
|
|
2190
|
+
})),
|
|
2191
|
+
onSome: (service) => Effect18.gen(function* () {
|
|
2192
|
+
const lock = yield* Effect18.acquireRelease(Effect18.sync(() => reservePersistedChatLock(service, persistenceOptions.chatId)), (reserved) => Effect18.sync(() => releasePersistedChatLock(service, persistenceOptions.chatId, reserved)));
|
|
2193
|
+
yield* Effect18.acquireRelease(lock.semaphore.take(1), () => lock.semaphore.release(1), {
|
|
2194
|
+
interruptible: true
|
|
2195
|
+
});
|
|
2196
|
+
const getOptions = persistenceOptions.timeToLive === undefined ? undefined : { timeToLive: persistenceOptions.timeToLive };
|
|
2197
|
+
return yield* resume === undefined ? service.getOrCreate(persistenceOptions.chatId, getOptions).pipe(Effect18.mapError((error) => AgentError.make({ message: errorMessage(error), turn: 0, cause: error }))) : service.get(persistenceOptions.chatId, getOptions).pipe(Effect18.mapError((error) => error._tag === "ChatNotFoundError" ? ResumeMismatch.make({
|
|
2198
|
+
reason: "checkpoint-not-found",
|
|
2199
|
+
received: resume.suspension
|
|
2200
|
+
}) : AgentError.make({ message: errorMessage(error), turn: 0, cause: error })));
|
|
2201
|
+
})
|
|
2202
|
+
});
|
|
2203
|
+
let recoveredHistory;
|
|
2204
|
+
if (resume !== undefined && persisted !== undefined && Option12.isSome(compactionService) && Option12.isSome(sessionService)) {
|
|
2205
|
+
yield* Effect18.gen(function* () {
|
|
2206
|
+
const path = yield* sessionService.value.path();
|
|
2207
|
+
const checkpoint = path.at(-1);
|
|
2208
|
+
if (checkpoint?._tag !== "Compaction" || checkpoint.version !== 2)
|
|
2209
|
+
return;
|
|
2210
|
+
const history = yield* Ref5.get(persisted.history);
|
|
2211
|
+
const before = buildContext(path.slice(0, -1));
|
|
2212
|
+
if (!Schema14.toEquivalence(Prompt9.Prompt)(before, history))
|
|
2213
|
+
return;
|
|
2214
|
+
recoveredHistory = buildContext(path);
|
|
2215
|
+
}).pipe(Effect18.mapError((error) => AgentError.make({ message: errorMessage(error), turn: 0, cause: error })));
|
|
2216
|
+
}
|
|
2217
|
+
let resumeChat;
|
|
2218
|
+
let validatedResume;
|
|
2219
|
+
if (resume !== undefined) {
|
|
2220
|
+
resumeChat = persisted ?? (yield* options.history === undefined ? Chat.empty : Chat.fromPrompt(options.history));
|
|
2221
|
+
const received = resume.suspension;
|
|
2222
|
+
const resumeHistory = recoveredHistory ?? (yield* Ref5.get(resumeChat.history));
|
|
2223
|
+
validatedResume = yield* Effect18.succeed(resumeHistory).pipe(Effect18.flatMap((history) => {
|
|
2224
|
+
const expected = suspensionCheckpoint(history.content);
|
|
2225
|
+
if (expected === undefined) {
|
|
2226
|
+
return ResumeMismatch.make({ reason: "checkpoint-not-found", received });
|
|
2227
|
+
}
|
|
2228
|
+
return sameSuspension(expected.suspension, received) ? Effect18.succeed(expected) : ResumeMismatch.make({
|
|
2229
|
+
reason: "identity-mismatch",
|
|
2230
|
+
expected: expected.suspension,
|
|
2231
|
+
received
|
|
2232
|
+
});
|
|
2233
|
+
}));
|
|
2234
|
+
if (recoveredHistory !== undefined && persisted !== undefined) {
|
|
2235
|
+
yield* Ref5.set(persisted.history, recoveredHistory);
|
|
2236
|
+
yield* persisted.save.pipe(Effect18.mapError((error) => AgentError.make({ message: errorMessage(error), turn: 0, cause: error })));
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
const staticCandidates = (agent.toolDeclarations ?? Object.values(agent.toolkit.tools).map((tool) => ({
|
|
2240
|
+
tool,
|
|
2241
|
+
origin: { _tag: "Static", agent: agent.name }
|
|
2242
|
+
}))).map(({ origin, tool }) => ({
|
|
2243
|
+
origin,
|
|
2244
|
+
tool,
|
|
2245
|
+
dispatch: "Static"
|
|
2246
|
+
}));
|
|
2247
|
+
const staticRegistry = yield* assemble(staticCandidates);
|
|
2248
|
+
const staticToolkit = staticRegistry.toolkit;
|
|
2249
|
+
if (agent.toolDeclarations !== undefined && (agent.toolDeclarations.length !== Object.keys(agent.toolkit.tools).length || agent.toolDeclarations.some((declaration) => agent.toolkit.tools[declaration.tool.name] !== declaration.tool))) {
|
|
2250
|
+
return yield* AgentError.make({
|
|
2251
|
+
message: "Agent tool declarations and toolkit must contain the same tool instances",
|
|
2252
|
+
turn: 0
|
|
2253
|
+
});
|
|
2254
|
+
}
|
|
2255
|
+
const executor = yield* Effect18.serviceOption(ToolExecutor);
|
|
2256
|
+
const approvals = yield* Effect18.serviceOption(Approvals);
|
|
2257
|
+
const chain = yield* Effect18.serviceOption(ModelMiddleware).pipe(Effect18.map(Option12.match({ onNone: () => [], onSome: (service) => service })));
|
|
2258
|
+
if (options.toolOutputMaxBytes !== undefined && (!Number.isFinite(options.toolOutputMaxBytes) || options.toolOutputMaxBytes < 0)) {
|
|
2259
|
+
return yield* AgentError.make({
|
|
2260
|
+
message: "RunOptions.toolOutputMaxBytes must be a non-negative finite number",
|
|
2261
|
+
turn: 0
|
|
2262
|
+
});
|
|
2263
|
+
}
|
|
2264
|
+
const decodedProgressPolicy = Schema14.decodeUnknownOption(progressOverflowPolicySchema)(options.toolProgress === undefined ? defaultProgressOverflowPolicy : options.toolProgress);
|
|
2265
|
+
if (Option12.isNone(decodedProgressPolicy)) {
|
|
2266
|
+
return yield* AgentError.make({
|
|
2267
|
+
message: "RunOptions.toolProgress must select a supported policy with a positive safe-integer capacity",
|
|
2268
|
+
turn: 0
|
|
2269
|
+
});
|
|
2270
|
+
}
|
|
2271
|
+
const progressPolicy = decodedProgressPolicy.value;
|
|
2272
|
+
if (options.compaction?.contextWindow !== undefined && (!Number.isFinite(options.compaction.contextWindow) || options.compaction.contextWindow <= 0)) {
|
|
2273
|
+
return yield* AgentError.make({
|
|
2274
|
+
message: "RunOptions.compaction.contextWindow must be a positive finite number",
|
|
2275
|
+
turn: 0
|
|
2276
|
+
});
|
|
2277
|
+
}
|
|
2278
|
+
const sessionId = options.sessionId ?? "local";
|
|
2279
|
+
const instructionsService = yield* Effect18.serviceOption(Instructions);
|
|
2280
|
+
const skillSourceService = yield* Effect18.serviceOption(SkillSource);
|
|
2281
|
+
const skillRuntime = Option12.isNone(skillSourceService) ? undefined : {
|
|
2282
|
+
source: skillSourceService.value,
|
|
2283
|
+
skills: yield* skillSourceService.value.all.pipe(Effect18.mapError((error) => AgentError.make({ message: error.message, turn: 0, cause: error })))
|
|
2284
|
+
};
|
|
2285
|
+
const selectedSkills = skillRuntime === undefined ? [] : selectListings(skillRuntime.skills, skillListingBudgetTokens, []);
|
|
2286
|
+
const skillListings = selectedSkills.map((skill) => skill.listing).join(`
|
|
2287
|
+
`);
|
|
2288
|
+
const hasActivatableSkills = selectedSkills.length > 0;
|
|
2289
|
+
const initialRegistry = yield* assemble([
|
|
2290
|
+
...staticCandidates,
|
|
2291
|
+
...hasActivatableSkills ? [
|
|
2292
|
+
{
|
|
2293
|
+
tool: activateSkillTool,
|
|
2294
|
+
origin: { _tag: "Builtin", builtin: "activate_skill" },
|
|
2295
|
+
dispatch: "Builtin"
|
|
2296
|
+
}
|
|
2297
|
+
] : []
|
|
2298
|
+
]);
|
|
2299
|
+
const instructionsEpoch = options.system === undefined && options.history === undefined && Option12.isSome(instructionsService) ? yield* openEpoch(instructionsService.value, { agentName: agent.name, turn: 0 }) : undefined;
|
|
2300
|
+
const baseSystem = options.system ?? (instructionsEpoch === undefined ? agent.instructions : instructionsEpoch.baseline.length === 0 ? agent.instructions : instructionsEpoch.baseline);
|
|
2301
|
+
const system = appendInstructionFragment(baseSystem, options.history === undefined && skillListings.length > 0 ? skillListingsInstructions(skillListings) : undefined);
|
|
2302
|
+
const resilienceService = yield* Effect18.serviceOption(ModelResilience);
|
|
2303
|
+
const modelRegistryService = yield* Effect18.serviceOption(Service);
|
|
2304
|
+
const permissionsService = yield* Effect18.serviceOption(Permissions);
|
|
2305
|
+
const ruleStoreService = yield* Effect18.serviceOption(RuleStore);
|
|
2306
|
+
const authorizationService = yield* Effect18.serviceOption(ToolAuthorizerService);
|
|
2307
|
+
const steeringService = yield* Effect18.serviceOption(Steering);
|
|
2308
|
+
const memoryService = yield* Effect18.serviceOption(Memory);
|
|
2309
|
+
const tokenizerService = yield* Effect18.serviceOption(Tokenizer2.Tokenizer);
|
|
2310
|
+
const authorizer = agent.authorization ?? Option12.getOrElse(authorizationService, () => make4({
|
|
2311
|
+
...Option12.isNone(permissionsService) ? {} : { permissions: permissionsService.value },
|
|
2312
|
+
...Option12.isNone(approvals) ? {} : { approvals: approvals.value },
|
|
2313
|
+
...Option12.isNone(ruleStoreService) ? {} : { ruleStore: ruleStoreService.value }
|
|
2314
|
+
}));
|
|
2315
|
+
const memoryOptions = options.memory ?? (agent.memory === undefined ? undefined : { key: agent.memory });
|
|
2316
|
+
const agentModel = agent.model;
|
|
2317
|
+
const agentModelRegistry = agentModel === undefined ? undefined : yield* Option12.match(modelRegistryService, {
|
|
2318
|
+
onNone: () => Effect18.fail(AgentError.make({
|
|
2319
|
+
message: "Agent.model requires ModelRegistry in context",
|
|
2320
|
+
turn: 0
|
|
2321
|
+
})),
|
|
2322
|
+
onSome: Effect18.succeed
|
|
2323
|
+
});
|
|
2324
|
+
const memoryRuntime = memoryOptions === undefined ? undefined : {
|
|
2325
|
+
key: memoryOptions.key,
|
|
2326
|
+
service: yield* Option12.match(memoryService, {
|
|
2327
|
+
onNone: () => Effect18.fail(AgentError.make({
|
|
2328
|
+
message: options.memory === undefined ? "Agent.memory requires Memory in context" : "RunOptions.memory requires Memory in context",
|
|
2329
|
+
turn: 0
|
|
2330
|
+
})),
|
|
2331
|
+
onSome: Effect18.succeed
|
|
2332
|
+
})
|
|
2333
|
+
};
|
|
2334
|
+
const seedSystem = persisted !== undefined && system !== undefined && (yield* Ref5.get(persisted.history)).content.length === 0 ? system : undefined;
|
|
2335
|
+
const freshChat = options.history !== undefined ? Chat.fromPrompt(options.history) : system !== undefined ? Chat.fromPrompt([Prompt9.makeMessage("system", { content: system })]) : Chat.empty;
|
|
2336
|
+
const chat = resumeChat ?? persisted ?? (yield* freshChat);
|
|
2337
|
+
const savePersisted = (turn) => persisted === undefined ? Effect18.void : persisted.save.pipe(Effect18.mapError((error) => AgentError.make({ message: errorMessage(error), turn, cause: error })));
|
|
2338
|
+
const appendPending = (turn, pending) => pending.length === 0 ? Ref5.get(chat.history) : Ref5.updateAndGet(chat.history, (history) => Prompt9.concat(history, Prompt9.fromResponseParts(pending))).pipe(Effect18.tap(() => savePersisted(turn)));
|
|
2339
|
+
const checkpointSuspended = (turn, pending, suspension2) => Effect18.gen(function* () {
|
|
2340
|
+
const withPending = yield* appendPending(turn, pending);
|
|
2341
|
+
const unresolved = unresolvedToolCall(withPending.content);
|
|
2342
|
+
if (unresolved === undefined || unresolved.call.id !== suspension2.tool_call_id || unresolved.call.name !== suspension2.tool_name || !Equal.equals(unresolved.call.params, suspension2.tool_params)) {
|
|
2343
|
+
return yield* AgentError.make({
|
|
2344
|
+
message: "Suspension does not match the unresolved checkpoint call",
|
|
2345
|
+
turn
|
|
2346
|
+
});
|
|
2347
|
+
}
|
|
2348
|
+
const metadata = {
|
|
2349
|
+
token: suspension2.token,
|
|
2350
|
+
reason: suspension2.reason,
|
|
2351
|
+
...suspension2.authorization_stage === undefined ? {} : { authorization_stage: suspension2.authorization_stage },
|
|
2352
|
+
...suspension2.active_tools === undefined ? {} : { active_tools: suspension2.active_tools },
|
|
2353
|
+
...suspension2.activated_skills === undefined ? {} : { activated_skills: suspension2.activated_skills }
|
|
2354
|
+
};
|
|
2355
|
+
const messages = withPending.content.map((message, messageIndex) => {
|
|
2356
|
+
if (messageIndex !== unresolved.messageIndex || message.role !== "assistant")
|
|
2357
|
+
return message;
|
|
2358
|
+
return Prompt9.makeMessage("assistant", {
|
|
2359
|
+
content: message.content.map((part, partIndex) => partIndex === unresolved.partIndex && part.type === "tool-call" ? Prompt9.makePart("tool-call", {
|
|
2360
|
+
id: part.id,
|
|
2361
|
+
name: part.name,
|
|
2362
|
+
params: part.params,
|
|
2363
|
+
providerExecuted: part.providerExecuted,
|
|
2364
|
+
options: { ...part.options, [suspensionCheckpointOption]: metadata }
|
|
2365
|
+
}) : part),
|
|
2366
|
+
options: message.options
|
|
2367
|
+
});
|
|
2368
|
+
});
|
|
2369
|
+
const checkpoint = Prompt9.fromMessages(messages);
|
|
2370
|
+
const path = yield* syncSession(turn, withPending);
|
|
2371
|
+
const parentId = path.at(-1)?.id ?? null;
|
|
2372
|
+
yield* applyCompactionResult(turn, { _tag: "Microcompact", history: checkpoint, prompt: Prompt9.empty }, parentId);
|
|
2373
|
+
if (Option12.isNone(activeSession))
|
|
2374
|
+
yield* savePersisted(turn);
|
|
2375
|
+
return yield* Ref5.get(chat.history);
|
|
2376
|
+
});
|
|
2377
|
+
const checkpointPending = (turn, pending) => appendPending(turn, pending).pipe(Effect18.tap((checkpoint) => syncSession(turn, checkpoint)));
|
|
2378
|
+
const failSuspended = (call, token, reason) => Stream4.fail(suspended(call, token, reason));
|
|
2379
|
+
const state = {
|
|
2380
|
+
text: "",
|
|
2381
|
+
turn: 0,
|
|
2382
|
+
pending: [],
|
|
2383
|
+
finish: undefined,
|
|
2384
|
+
usage: undefined
|
|
2385
|
+
};
|
|
2386
|
+
const toolState = yield* Ref5.make({
|
|
2387
|
+
registry: initialRegistry,
|
|
2388
|
+
activatedSkillBodies: new Map
|
|
2389
|
+
});
|
|
2390
|
+
const restoreActivatedSkills = (history) => Effect18.gen(function* () {
|
|
2391
|
+
for (const message of history.content) {
|
|
2392
|
+
if (!Array.isArray(message.content))
|
|
2393
|
+
continue;
|
|
2394
|
+
for (const part of message.content) {
|
|
2395
|
+
if (String(part.type) !== "tool-result" || String(part.name) !== activateSkillToolName || part.isFailure === true)
|
|
2396
|
+
continue;
|
|
2397
|
+
const activation = Schema14.decodeUnknownOption(activateSkillSuccess)(part.result);
|
|
2398
|
+
if (Option12.isNone(activation))
|
|
2399
|
+
continue;
|
|
2400
|
+
if (skillRuntime === undefined) {
|
|
2401
|
+
return yield* AgentError.make({
|
|
2402
|
+
message: "Resuming activated skill tools requires SkillSource in context",
|
|
2403
|
+
turn: 0
|
|
2404
|
+
});
|
|
2405
|
+
}
|
|
2406
|
+
const skill = yield* skillRuntime.source.get(activation.value.name);
|
|
2407
|
+
if (skill === undefined) {
|
|
2408
|
+
return yield* AgentError.make({
|
|
2409
|
+
message: `Skill not found while restoring resume state: ${activation.value.name}`,
|
|
2410
|
+
turn: 0
|
|
2411
|
+
});
|
|
2412
|
+
}
|
|
2413
|
+
const current = yield* Ref5.get(toolState);
|
|
2414
|
+
if (current.activatedSkillBodies.has(skill.frontmatter.name))
|
|
2415
|
+
continue;
|
|
2416
|
+
const registry = yield* assemble([
|
|
2417
|
+
...current.registry.entries,
|
|
2418
|
+
...skill.tools.map((tool) => ({
|
|
2419
|
+
tool,
|
|
2420
|
+
origin: { _tag: "Skill", skill: skill.frontmatter.name },
|
|
2421
|
+
dispatch: "Skill"
|
|
2422
|
+
}))
|
|
2423
|
+
]);
|
|
2424
|
+
const activatedSkillBodies = new Map(current.activatedSkillBodies);
|
|
2425
|
+
activatedSkillBodies.set(skill.frontmatter.name, activation.value.body);
|
|
2426
|
+
yield* Ref5.set(toolState, { registry, activatedSkillBodies });
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
}).pipe(Effect18.mapError((error) => isToolNameCollision(error) ? error : AgentError.make({ message: error.message, turn: 0, cause: error })));
|
|
2430
|
+
if (validatedResume !== undefined)
|
|
2431
|
+
yield* Ref5.get(chat.history).pipe(Effect18.flatMap(restoreActivatedSkills));
|
|
2432
|
+
const activeSession = Option12.isSome(compactionService) ? sessionService : Option12.none();
|
|
2433
|
+
const sessionError = (turn, error) => AgentError.make({ message: error.message, turn, cause: error });
|
|
2434
|
+
const compactionError = (turn, error) => AgentError.make({ message: error.message, turn, cause: error });
|
|
2435
|
+
const memoryError = (turn, error) => AgentError.make({ message: error.message, turn, cause: error });
|
|
2436
|
+
const skillError = (turn, error) => AgentError.make({ message: error.message, turn, cause: error });
|
|
2437
|
+
const isSkillActivationCall = (call, registry) => get(registry, call.name)?.dispatch === "Builtin" && skillRuntime !== undefined;
|
|
2438
|
+
const insertRecalledItems = (prompt, items) => {
|
|
2439
|
+
const content = items.flatMap((item) => item.content);
|
|
2440
|
+
if (content.length === 0)
|
|
2441
|
+
return prompt;
|
|
2442
|
+
const memoryMessage2 = messageFromRecall(content);
|
|
2443
|
+
const [first, ...rest] = prompt.content;
|
|
2444
|
+
return first?.role === "system" ? Prompt9.fromMessages([first, memoryMessage2, ...rest]) : Prompt9.fromMessages([memoryMessage2, ...prompt.content]);
|
|
2445
|
+
};
|
|
2446
|
+
const recallInitialPrompt = (prompt) => memoryRuntime === undefined ? Effect18.succeed(prompt) : memoryRuntime.service.recall({ key: memoryRuntime.key, turn: 0, prompt }).pipe(Effect18.mapError((error) => memoryError(0, error)), Effect18.map((items) => insertRecalledItems(prompt, items)));
|
|
2447
|
+
const rememberTurn = (turn, transcript, terminal, path) => memoryRuntime === undefined ? Effect18.void : memoryRuntime.service.remember({
|
|
2448
|
+
key: memoryRuntime.key,
|
|
2449
|
+
turn,
|
|
2450
|
+
transcript: Option12.isSome(activeSession) ? buildMemoryContext(path) : projectTranscript(transcript),
|
|
2451
|
+
terminal
|
|
2452
|
+
}).pipe(Effect18.mapError((error) => memoryError(turn, error)));
|
|
2453
|
+
const messageEquivalence = Schema14.toEquivalence(Prompt9.Message);
|
|
2454
|
+
const promptEquivalence2 = Schema14.toEquivalence(Prompt9.Prompt);
|
|
2455
|
+
const sessionTranscriptCursor = (projection, transcript) => {
|
|
2456
|
+
if (projection.length === 0)
|
|
2457
|
+
return Option12.some(0);
|
|
2458
|
+
const matches2 = [];
|
|
2459
|
+
for (let start = 0;start <= transcript.length - projection.length; start += 1) {
|
|
2460
|
+
if (transcript.slice(0, start).every((message) => message.role === "system") && projection.every((message, index) => messageEquivalence(message, transcript[start + index]))) {
|
|
2461
|
+
matches2.push(start + projection.length);
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
return matches2.length === 1 ? Option12.some(matches2[0]) : Option12.none();
|
|
2465
|
+
};
|
|
2466
|
+
const syncSession = (turn, transcript) => Option12.match(activeSession, {
|
|
2467
|
+
onNone: () => Effect18.succeed([]),
|
|
2468
|
+
onSome: (session) => Effect18.gen(function* () {
|
|
2469
|
+
let path = yield* session.path();
|
|
2470
|
+
const projection = buildContext(path);
|
|
2471
|
+
const cursor = sessionTranscriptCursor(projection.content, transcript.content);
|
|
2472
|
+
if (Option12.isNone(cursor)) {
|
|
2473
|
+
const checkpoint = path.at(-1);
|
|
2474
|
+
const before = buildContext(path.slice(0, -1));
|
|
2475
|
+
if (checkpoint?._tag === "Compaction" && checkpoint.version === 2 && promptEquivalence2(before, transcript)) {
|
|
2476
|
+
yield* Ref5.set(chat.history, projection);
|
|
2477
|
+
yield* savePersisted(turn);
|
|
2478
|
+
return path;
|
|
2479
|
+
}
|
|
2480
|
+
return yield* AgentError.make({
|
|
2481
|
+
message: "Session projection is not a prefix of authoritative Chat history",
|
|
2482
|
+
turn
|
|
2483
|
+
});
|
|
2484
|
+
}
|
|
2485
|
+
let expectedLeafId = path.at(-1)?.id ?? null;
|
|
2486
|
+
for (const message of transcript.content.slice(cursor.value)) {
|
|
2487
|
+
const appended = yield* session.append({ _tag: "Message", message }, { expectedLeafId });
|
|
2488
|
+
expectedLeafId = appended.id;
|
|
2489
|
+
}
|
|
2490
|
+
if (expectedLeafId !== (path.at(-1)?.id ?? null))
|
|
2491
|
+
path = yield* session.path();
|
|
2492
|
+
return path;
|
|
2493
|
+
}).pipe(Effect18.mapError((error) => Schema14.is(AgentError)(error) ? error : sessionError(turn, error)))
|
|
2494
|
+
});
|
|
2495
|
+
const countTokens = (turn, prompt) => Option12.match(tokenizerService, {
|
|
2496
|
+
onNone: () => Effect18.succeed(Math.ceil(JSON.stringify(prompt.content).length / 4)),
|
|
2497
|
+
onSome: (tokenizer) => tokenizer.tokenize(prompt).pipe(Effect18.map((tokens) => tokens.length), Effect18.mapError((error) => AgentError.make({ message: errorMessage(error), turn, cause: error })))
|
|
2498
|
+
});
|
|
2499
|
+
const compactionUsage = (turn, history, prompt) => countTokens(turn, Prompt9.concat(history, prompt)).pipe(Effect18.map((contextTokens) => ({
|
|
2500
|
+
contextTokens,
|
|
2501
|
+
contextWindow: options.compaction?.contextWindow ?? Number.POSITIVE_INFINITY,
|
|
2502
|
+
reserveTokens: DEFAULT_RESERVE_TOKENS
|
|
2503
|
+
})));
|
|
2504
|
+
const validateCompactionProjection = (turn, result) => {
|
|
2505
|
+
const pending = new Set;
|
|
2506
|
+
const optional = new Set;
|
|
2507
|
+
for (const message of Prompt9.concat(result.history, result.prompt).content) {
|
|
2508
|
+
if (typeof message.content === "string") {
|
|
2509
|
+
if (pending.size > 0) {
|
|
2510
|
+
return Effect18.fail(AgentError.make({ message: "Compaction projection separates a tool call from its result", turn }));
|
|
2511
|
+
}
|
|
2512
|
+
optional.clear();
|
|
2513
|
+
continue;
|
|
2514
|
+
}
|
|
2515
|
+
const hasResult = message.content.some((part) => part.type === "tool-result");
|
|
2516
|
+
if (pending.size > 0 && !hasResult) {
|
|
2517
|
+
return Effect18.fail(AgentError.make({ message: "Compaction projection separates a tool call from its result", turn }));
|
|
2518
|
+
}
|
|
2519
|
+
if (!hasResult)
|
|
2520
|
+
optional.clear();
|
|
2521
|
+
const responseCalls = new Set;
|
|
2522
|
+
for (const part of message.content) {
|
|
2523
|
+
if (part.type === "tool-call") {
|
|
2524
|
+
if (responseCalls.has(part.id)) {
|
|
2525
|
+
return Effect18.fail(AgentError.make({ message: `Compaction projection contains duplicate tool call ${part.id}`, turn }));
|
|
2526
|
+
}
|
|
2527
|
+
responseCalls.add(part.id);
|
|
2528
|
+
if (part.providerExecuted)
|
|
2529
|
+
optional.add(part.id);
|
|
2530
|
+
else
|
|
2531
|
+
pending.add(part.id);
|
|
2532
|
+
}
|
|
2533
|
+
if (part.type === "tool-result") {
|
|
2534
|
+
if (!pending.delete(part.id) && !optional.delete(part.id)) {
|
|
2535
|
+
return Effect18.fail(AgentError.make({ message: `Compaction projection contains orphan tool result ${part.id}`, turn }));
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
return pending.size === 0 ? Effect18.void : Effect18.fail(AgentError.make({ message: "Compaction projection contains an unresolved tool call", turn }));
|
|
2541
|
+
};
|
|
2542
|
+
const applyCompactionResult = (turn, result, parentId) => Option12.match(activeSession, {
|
|
2543
|
+
onNone: () => Ref5.set(chat.history, result.history),
|
|
2544
|
+
onSome: (session) => Effect18.gen(function* () {
|
|
2545
|
+
const id = yield* session.reserveEntryId;
|
|
2546
|
+
yield* Effect18.uninterruptibleMask((restore) => restore(session.appendCheckpoint({
|
|
2547
|
+
id,
|
|
2548
|
+
parentId,
|
|
2549
|
+
projectedHistory: result.history,
|
|
2550
|
+
...result._tag === "Summarize" ? { summary: result.summary } : {}
|
|
2551
|
+
})).pipe(Effect18.flatMap((appended) => restore(session.path(appended.leafId))), Effect18.map(buildContext), Effect18.tap((projection) => Ref5.set(chat.history, projection)), Effect18.andThen(restore(savePersisted(turn)))));
|
|
2552
|
+
}).pipe(Effect18.mapError((error) => Schema14.is(AgentError)(error) ? error : sessionError(turn, error)))
|
|
2553
|
+
});
|
|
2554
|
+
const preparePrompt = (turn, prompt, overflow) => Option12.match(compactionService, {
|
|
2555
|
+
onNone: () => Effect18.succeed({ prompt, changed: false }),
|
|
2556
|
+
onSome: (compaction) => Effect18.gen(function* () {
|
|
2557
|
+
const history = yield* Ref5.get(chat.history);
|
|
2558
|
+
const path = yield* syncSession(turn, history);
|
|
2559
|
+
const usage = yield* compactionUsage(turn, history, prompt);
|
|
2560
|
+
const historyRecalled = recalledMessages(history);
|
|
2561
|
+
const promptRecalled = recalledMessages(prompt);
|
|
2562
|
+
const detachedHistory = yield* detachPrompt(history).pipe(Effect18.mapError((error) => AgentError.make({ message: error.message, turn, cause: error })));
|
|
2563
|
+
const detachedPrompt = yield* detachPrompt(prompt).pipe(Effect18.mapError((error) => AgentError.make({ message: error.message, turn, cause: error })));
|
|
2564
|
+
const originalHistory = yield* detachPrompt(detachedHistory).pipe(Effect18.mapError((error) => AgentError.make({ message: error.message, turn, cause: error })));
|
|
2565
|
+
const originalPrompt = yield* detachPrompt(detachedPrompt).pipe(Effect18.mapError((error) => AgentError.make({ message: error.message, turn, cause: error })));
|
|
2566
|
+
const detachedPath = yield* Effect18.forEach(path, detachEntry).pipe(Effect18.mapError((error) => AgentError.make({ message: error.message, turn, cause: error })));
|
|
2567
|
+
const compacted = yield* compaction.maybeCompact({
|
|
2568
|
+
agentName: agent.name,
|
|
2569
|
+
sessionId,
|
|
2570
|
+
turn,
|
|
2571
|
+
history: detachedHistory,
|
|
2572
|
+
prompt: detachedPrompt,
|
|
2573
|
+
path: detachedPath,
|
|
2574
|
+
usage,
|
|
2575
|
+
overflow,
|
|
2576
|
+
...options.toolOutputMaxBytes === undefined ? {} : { toolOutputMaxBytes: options.toolOutputMaxBytes }
|
|
2577
|
+
}).pipe(Effect18.mapError((error) => compactionError(turn, error)));
|
|
2578
|
+
if (Option12.isNone(compacted))
|
|
2579
|
+
return { prompt, changed: false };
|
|
2580
|
+
const changed = !Equal.equals(originalHistory.content, compacted.value.history.content) || !Equal.equals(originalPrompt.content, compacted.value.prompt.content);
|
|
2581
|
+
if (!changed)
|
|
2582
|
+
return { prompt, changed: false };
|
|
2583
|
+
const allowed = [...historyRecalled, ...promptRecalled];
|
|
2584
|
+
const required = Option12.isSome(activeSession) ? promptRecalled : allowed;
|
|
2585
|
+
if (!preservesRecalledMessages(allowed, required, Prompt9.concat(compacted.value.history, compacted.value.prompt))) {
|
|
2586
|
+
return yield* MiddlewareViolation.make({
|
|
2587
|
+
turn,
|
|
2588
|
+
detail: "Compaction must preserve recalled-memory message lineage outside the lossless Session path"
|
|
2589
|
+
});
|
|
2590
|
+
}
|
|
2591
|
+
yield* validateCompactionProjection(turn, compacted.value);
|
|
2592
|
+
yield* applyCompactionResult(turn, compacted.value, path.at(-1)?.id ?? null);
|
|
2593
|
+
return { prompt: compacted.value.prompt, changed: true };
|
|
2594
|
+
})
|
|
2595
|
+
});
|
|
2596
|
+
const boundedSuccessResult = (call, outcome) => options.toolOutputMaxBytes === undefined ? Effect18.succeed(successResult(call, outcome)) : bound(outcome, { toolCallId: call.id, maxBytes: options.toolOutputMaxBytes }).pipe(Effect18.map((bounded2) => successResult(call, bounded2)));
|
|
2597
|
+
const outcomeEvents = (turn, call, outcome, droppedProgress, registry) => {
|
|
2598
|
+
const metadata = droppedProgress === 0 ? {} : { metadata: { toolProgress: { dropped: droppedProgress } } };
|
|
2599
|
+
switch (outcome._tag) {
|
|
2600
|
+
case "Success":
|
|
2601
|
+
return (isSkillActivationCall(call, registry) ? Effect18.succeed(successResult(call, outcome)) : boundedSuccessResult(call, outcome)).pipe(Effect18.map((result) => {
|
|
2602
|
+
state.pending.push(result);
|
|
2603
|
+
return Stream4.fromIterable([{ _tag: "ToolExecutionCompleted", turn, call, result, ...metadata }]);
|
|
2604
|
+
}));
|
|
2605
|
+
case "DomainFailure": {
|
|
2606
|
+
const result = domainFailureResult(call, outcome);
|
|
2607
|
+
state.pending.push(result);
|
|
2608
|
+
return Effect18.succeed(Stream4.fromIterable([{ _tag: "ToolExecutionCompleted", turn, call, result, ...metadata }]));
|
|
2609
|
+
}
|
|
2610
|
+
case "Suspend":
|
|
2611
|
+
return Effect18.succeed(failSuspended(call, outcome.token, "tool-wait"));
|
|
2612
|
+
}
|
|
2613
|
+
};
|
|
2614
|
+
const defaultExecute = (request, registry) => {
|
|
2615
|
+
const registered = get(registry, request.call.name);
|
|
2616
|
+
if (registered?.dispatch === "Static") {
|
|
2617
|
+
return executeToolkit(staticToolkit, request);
|
|
2618
|
+
}
|
|
2619
|
+
return registered === undefined ? Effect18.fail(FrameworkFailure.make({
|
|
2620
|
+
stage: "missing-handler",
|
|
2621
|
+
tool: request.call.name,
|
|
2622
|
+
message: `Tool ${request.call.name} is not registered`
|
|
2623
|
+
})) : Effect18.fail(FrameworkFailure.make({
|
|
2624
|
+
stage: "missing-handler",
|
|
2625
|
+
tool: request.call.name,
|
|
2626
|
+
message: `Activated skill tool ${request.call.name} requires ToolExecutor`
|
|
2627
|
+
}));
|
|
2628
|
+
};
|
|
2629
|
+
const makeProgressQueue = () => {
|
|
2630
|
+
switch (progressPolicy._tag) {
|
|
2631
|
+
case "Backpressure":
|
|
2632
|
+
return Queue2.bounded(progressPolicy.capacity);
|
|
2633
|
+
case "Dropping":
|
|
2634
|
+
case "Fail":
|
|
2635
|
+
return Queue2.dropping(progressPolicy.capacity);
|
|
2636
|
+
case "Sliding":
|
|
2637
|
+
return Queue2.sliding(progressPolicy.capacity);
|
|
2638
|
+
}
|
|
2639
|
+
};
|
|
2640
|
+
const executeApproved = (turn, call, request, registry) => Stream4.concat(Stream4.fromIterable([{ _tag: "ToolExecutionStarted", turn, call }]), Stream4.unwrap(Effect18.gen(function* () {
|
|
2641
|
+
const progressQueue = yield* Effect18.acquireRelease(makeProgressQueue(), Queue2.shutdown);
|
|
2642
|
+
const droppedProgress = yield* Ref5.make(0);
|
|
2643
|
+
const emitSemaphore = yield* Semaphore2.make(1);
|
|
2644
|
+
const signal = yield* Effect18.abortSignal;
|
|
2645
|
+
const context = ToolContext.of({
|
|
2646
|
+
signal,
|
|
2647
|
+
sessionId,
|
|
2648
|
+
emit: (progress) => {
|
|
2649
|
+
const event = {
|
|
2650
|
+
_tag: "ToolProgress",
|
|
2651
|
+
turn,
|
|
2652
|
+
toolCallId: progress.toolCallId,
|
|
2653
|
+
...progress.message === undefined ? {} : { message: progress.message },
|
|
2654
|
+
...progress.data === undefined ? {} : { data: progress.data }
|
|
2655
|
+
};
|
|
2656
|
+
return emitSemaphore.withPermit(Effect18.gen(function* () {
|
|
2657
|
+
if (progressPolicy._tag === "Sliding") {
|
|
2658
|
+
const dropped = yield* Effect18.sync(() => {
|
|
2659
|
+
const full = Queue2.isFullUnsafe(progressQueue);
|
|
2660
|
+
Queue2.offerUnsafe(progressQueue, event);
|
|
2661
|
+
return full;
|
|
2662
|
+
});
|
|
2663
|
+
if (dropped)
|
|
2664
|
+
yield* Ref5.update(droppedProgress, (count) => count + 1);
|
|
2665
|
+
return;
|
|
2666
|
+
}
|
|
2667
|
+
const offered = yield* Queue2.offer(progressQueue, event);
|
|
2668
|
+
if (progressPolicy._tag === "Dropping" && !offered) {
|
|
2669
|
+
yield* Ref5.update(droppedProgress, (count) => count + 1);
|
|
2670
|
+
} else if (progressPolicy._tag === "Fail" && !offered) {
|
|
2671
|
+
yield* Queue2.fail(progressQueue, ProgressOverflowError.make({ turn, toolCallId: call.id, capacity: progressPolicy.capacity }));
|
|
2672
|
+
}
|
|
2673
|
+
}));
|
|
2674
|
+
}
|
|
2675
|
+
});
|
|
2676
|
+
const execution = isSkillActivationCall(call, registry) ? activateSkillOutcome(turn, call) : Option12.isNone(executor) ? defaultExecute(request, registry) : executor.value.execute(request).pipe(Effect18.mapError((error) => Schema14.is(RemoteRetryError)(error) ? AgentError.make({ message: error.message, turn, cause: error }) : error));
|
|
2677
|
+
const fiber = yield* execution.pipe(Effect18.provideService(ToolContext, context), Effect18.ensuring(Queue2.end(progressQueue).pipe(Effect18.asVoid)), Effect18.forkScoped({ startImmediately: true }));
|
|
2678
|
+
return Stream4.concat(Stream4.fromQueue(progressQueue), Stream4.fromEffect(Fiber.join(fiber)).pipe(Stream4.flatMap((outcome) => Stream4.unwrap(Ref5.get(droppedProgress).pipe(Effect18.flatMap((dropped) => outcomeEvents(turn, call, outcome, dropped, registry)))))));
|
|
2679
|
+
})));
|
|
2680
|
+
const activateSkillOutcome = (turn, call) => Effect18.gen(function* () {
|
|
2681
|
+
if (skillRuntime === undefined) {
|
|
2682
|
+
return yield* FrameworkFailure.make({
|
|
2683
|
+
stage: "missing-handler",
|
|
2684
|
+
tool: call.name,
|
|
2685
|
+
message: "SkillSource is not available"
|
|
2686
|
+
});
|
|
2687
|
+
}
|
|
2688
|
+
const params = Schema14.decodeUnknownOption(activateSkillParameters)(call.params);
|
|
2689
|
+
if (Option12.isNone(params)) {
|
|
2690
|
+
return yield* FrameworkFailure.make({
|
|
2691
|
+
stage: "decode-input",
|
|
2692
|
+
tool: call.name,
|
|
2693
|
+
message: "Skill activation requires a name"
|
|
2694
|
+
});
|
|
2695
|
+
}
|
|
2696
|
+
const skill = yield* skillRuntime.source.get(params.value.name);
|
|
2697
|
+
if (skill === undefined) {
|
|
2698
|
+
const failure2 = { reason: "not-found", message: `Skill not found: ${params.value.name}` };
|
|
2699
|
+
return { _tag: "DomainFailure", failure: failure2, encodedFailure: failure2 };
|
|
2700
|
+
}
|
|
2701
|
+
if (skill.frontmatter.disableModelInvocation === true) {
|
|
2702
|
+
const failure2 = {
|
|
2703
|
+
reason: "not-model-invocable",
|
|
2704
|
+
message: `Skill is not model-invocable: ${params.value.name}`
|
|
2705
|
+
};
|
|
2706
|
+
return { _tag: "DomainFailure", failure: failure2, encodedFailure: failure2 };
|
|
2707
|
+
}
|
|
2708
|
+
const current = yield* Ref5.get(toolState);
|
|
2709
|
+
let body = current.activatedSkillBodies.get(skill.frontmatter.name);
|
|
2710
|
+
if (body === undefined) {
|
|
2711
|
+
const registry = yield* assemble([
|
|
2712
|
+
...current.registry.entries,
|
|
2713
|
+
...skill.tools.map((tool) => ({
|
|
2714
|
+
tool,
|
|
2715
|
+
origin: { _tag: "Skill", skill: skill.frontmatter.name },
|
|
2716
|
+
dispatch: "Skill"
|
|
2717
|
+
}))
|
|
2718
|
+
]);
|
|
2719
|
+
body = yield* skill.body;
|
|
2720
|
+
const activatedSkillBodies = new Map(current.activatedSkillBodies);
|
|
2721
|
+
activatedSkillBodies.set(skill.frontmatter.name, body);
|
|
2722
|
+
yield* Ref5.set(toolState, { registry, activatedSkillBodies });
|
|
2723
|
+
}
|
|
2724
|
+
const output = {
|
|
2725
|
+
name: skill.frontmatter.name,
|
|
2726
|
+
body,
|
|
2727
|
+
allowedTools: [...skill.frontmatter.allowedTools ?? []]
|
|
2728
|
+
};
|
|
2729
|
+
return { _tag: "Success", result: output, encodedResult: output };
|
|
2730
|
+
}).pipe(Effect18.mapError((error) => isToolNameCollision(error) || Schema14.is(FrameworkFailure)(error) ? error : skillError(turn, error)));
|
|
2731
|
+
const authorizationError2 = (turn, error) => AgentError.make({ message: error.message, turn, cause: error });
|
|
2732
|
+
const toolCallEvents = (turn, call, messages, registry, authorizationStage, authorizationToken) => {
|
|
2733
|
+
const request = { call, turn, agentName: agent.name, sessionId };
|
|
2734
|
+
const candidate = get(registry, call.name);
|
|
2735
|
+
if (candidate === undefined)
|
|
2736
|
+
return Stream4.fail(FrameworkFailure.make({
|
|
2737
|
+
stage: "authorization",
|
|
2738
|
+
tool: call.name,
|
|
2739
|
+
message: `Tool ${call.name} is not active for turn ${turn}`
|
|
2740
|
+
}));
|
|
2741
|
+
const activeTools = registry.entries.map((entry) => entry.tool.name);
|
|
2742
|
+
return Stream4.unwrap(Effect18.gen(function* () {
|
|
2743
|
+
const activatedSkills = [...(yield* Ref5.get(toolState)).activatedSkillBodies.keys()];
|
|
2744
|
+
const approvalEvents = yield* Queue2.bounded(1);
|
|
2745
|
+
const fiber = yield* authorizer.authorize({
|
|
2746
|
+
call,
|
|
2747
|
+
tool: candidate.tool,
|
|
2748
|
+
active: true,
|
|
2749
|
+
activeTools,
|
|
2750
|
+
activatedSkills,
|
|
2751
|
+
...authorizationStage === undefined ? {} : { authorizationStage },
|
|
2752
|
+
...authorizationToken === undefined ? {} : { authorizationToken },
|
|
2753
|
+
messages,
|
|
2754
|
+
execution: request,
|
|
2755
|
+
onApprovalRequired: Queue2.offer(approvalEvents, { _tag: "ApprovalRequested", turn, call }).pipe(Effect18.asVoid)
|
|
2756
|
+
}).pipe(Effect18.mapError((error) => authorizationError2(turn, error)), Effect18.ensuring(Queue2.end(approvalEvents).pipe(Effect18.asVoid)), Effect18.forkScoped({ startImmediately: true }));
|
|
2757
|
+
return Stream4.concat(Stream4.fromQueue(approvalEvents), Stream4.fromEffect(Fiber.join(fiber)).pipe(Stream4.flatMap((decision2) => {
|
|
2758
|
+
switch (decision2._tag) {
|
|
2759
|
+
case "Execute":
|
|
2760
|
+
return executeApproved(turn, call, request, registry);
|
|
2761
|
+
case "Deny":
|
|
2762
|
+
return Stream4.fail(FrameworkFailure.make({
|
|
2763
|
+
stage: "authorization",
|
|
2764
|
+
tool: call.name,
|
|
2765
|
+
message: decision2.error.message
|
|
2766
|
+
}));
|
|
2767
|
+
case "Suspend":
|
|
2768
|
+
return Stream4.fail(AgentSuspended.make({
|
|
2769
|
+
token: decision2.suspension.token,
|
|
2770
|
+
reason: "approval",
|
|
2771
|
+
authorization_stage: decision2.suspension.authorization_stage ?? "approval",
|
|
2772
|
+
tool_call_id: call.id,
|
|
2773
|
+
tool_name: call.name,
|
|
2774
|
+
tool_params: call.params,
|
|
2775
|
+
active_tools: activeTools,
|
|
2776
|
+
activated_skills: activatedSkills
|
|
2777
|
+
}));
|
|
2778
|
+
}
|
|
2779
|
+
})));
|
|
2780
|
+
}));
|
|
2781
|
+
};
|
|
2782
|
+
const captureFinishPart = (part) => Effect18.gen(function* () {
|
|
2783
|
+
const span = yield* Effect18.currentSpan;
|
|
2784
|
+
state.finish = {
|
|
2785
|
+
usage: state.finish === undefined ? part.usage : addUsage(state.finish.usage, part.usage),
|
|
2786
|
+
reason: part.reason
|
|
2787
|
+
};
|
|
2788
|
+
state.usage = state.usage === undefined ? part.usage : addUsage(state.usage, part.usage);
|
|
2789
|
+
Telemetry.addGenAIAnnotations(span, {
|
|
2790
|
+
operation: { name: "chat" },
|
|
2791
|
+
usage: {
|
|
2792
|
+
inputTokens: part.usage.inputTokens.total,
|
|
2793
|
+
outputTokens: part.usage.outputTokens.total
|
|
2794
|
+
},
|
|
2795
|
+
response: { finishReasons: [part.reason] }
|
|
2796
|
+
});
|
|
2797
|
+
}).pipe(Effect18.orDie);
|
|
2798
|
+
const captureStructuredUsage = (content) => Effect18.gen(function* () {
|
|
2799
|
+
const span = yield* Effect18.currentSpan;
|
|
2800
|
+
for (const part of content) {
|
|
2801
|
+
if (part.type === "finish") {
|
|
2802
|
+
state.usage = state.usage === undefined ? part.usage : addUsage(state.usage, part.usage);
|
|
2803
|
+
Telemetry.addGenAIAnnotations(span, {
|
|
2804
|
+
operation: { name: "chat" },
|
|
2805
|
+
usage: {
|
|
2806
|
+
inputTokens: part.usage.inputTokens.total,
|
|
2807
|
+
outputTokens: part.usage.outputTokens.total
|
|
2808
|
+
},
|
|
2809
|
+
response: { finishReasons: [part.reason] }
|
|
2810
|
+
});
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
}).pipe(Effect18.orDie);
|
|
2814
|
+
const withModelResilience = (effect) => Option12.match(resilienceService, {
|
|
2815
|
+
onNone: () => effect,
|
|
2816
|
+
onSome: (resilience) => Effect18.flatMap(LanguageModel5.LanguageModel, (model) => effect.pipe(Effect18.provideService(LanguageModel5.LanguageModel, apply(model, {
|
|
2817
|
+
...resilience,
|
|
2818
|
+
classify: (error) => classifyFailure(model, error) === "context-overflow" ? "terminal" : resilience.classify(error)
|
|
2819
|
+
}))))
|
|
2820
|
+
});
|
|
2821
|
+
const withAgentModel = (effect) => agentModelRegistry === undefined || agentModel === undefined ? effect : agentModelRegistry.operate(agentModel, effect);
|
|
2822
|
+
function provideAgentModel(stream2) {
|
|
2823
|
+
return agentModelRegistry === undefined || agentModel === undefined ? stream2 : agentModelRegistry.stream(agentModel, stream2).pipe(Stream4.catchTag("LanguageModelNotRegistered", (error) => Stream4.fail(AgentError.make({ message: errorMessage(error), turn: state.turn, cause: error }))));
|
|
2824
|
+
}
|
|
2825
|
+
const partEvents = (turn, part, messages, registry) => {
|
|
2826
|
+
if (part.type === "error") {
|
|
2827
|
+
if (isToolNameCollision(part.error))
|
|
2828
|
+
return Stream4.fail(part.error);
|
|
2829
|
+
return Stream4.fail(AgentError.make({ message: errorMessage(part.error), turn, cause: part.error }));
|
|
2830
|
+
}
|
|
2831
|
+
const modelPart = Stream4.fromIterable([{ _tag: "ModelPart", turn, part }]);
|
|
2832
|
+
if (part.type === "tool-call") {
|
|
2833
|
+
const call = part;
|
|
2834
|
+
return call.providerExecuted === true ? modelPart : Stream4.concat(modelPart, toolCallEvents(turn, call, messages, registry));
|
|
2835
|
+
}
|
|
2836
|
+
if (part.type === "text-delta") {
|
|
2837
|
+
state.text = `${state.text}${part.delta}`;
|
|
2838
|
+
}
|
|
2839
|
+
if (part.type === "finish") {
|
|
2840
|
+
return modelPart.pipe(Stream4.tap(() => captureFinishPart(part)));
|
|
2841
|
+
}
|
|
2842
|
+
return modelPart;
|
|
2843
|
+
};
|
|
2844
|
+
const transformPart = (turn, part) => applyPartChain(chain, part, { agentName: agent.name, turn }).pipe(Effect18.flatMap(Option12.match({
|
|
2845
|
+
onSome: (transformed) => Effect18.succeed(Option12.some(transformed)),
|
|
2846
|
+
onNone: () => part.type === "tool-call" ? Effect18.fail(MiddlewareViolation.make({
|
|
2847
|
+
turn,
|
|
2848
|
+
detail: "ModelMiddleware dropped a tool-call part"
|
|
2849
|
+
})) : Effect18.succeed(Option12.none())
|
|
2850
|
+
})));
|
|
2851
|
+
const validateToolCallId = (idState, part) => {
|
|
2852
|
+
if (part.type !== "tool-call")
|
|
2853
|
+
return Effect18.void;
|
|
2854
|
+
return Ref5.modify(idState, (current) => {
|
|
2855
|
+
const existingFirstIndex = HashMap4.get(current.firstIndexes, part.id);
|
|
2856
|
+
const duplicate = Option12.map(existingFirstIndex, (index) => DuplicateToolCallId.make({ id: part.id, firstIndex: index, duplicateIndex: current.nextIndex }));
|
|
2857
|
+
return [
|
|
2858
|
+
duplicate,
|
|
2859
|
+
{
|
|
2860
|
+
nextIndex: current.nextIndex + 1,
|
|
2861
|
+
firstIndexes: Option12.isSome(existingFirstIndex) ? current.firstIndexes : HashMap4.set(current.firstIndexes, part.id, current.nextIndex)
|
|
2862
|
+
}
|
|
2863
|
+
];
|
|
2864
|
+
}).pipe(Effect18.flatMap(Option12.match({
|
|
2865
|
+
onNone: () => Effect18.void,
|
|
2866
|
+
onSome: Effect18.fail
|
|
2867
|
+
})));
|
|
2868
|
+
};
|
|
2869
|
+
const modelTurn = (turn, prompt, registry, overrides) => {
|
|
2870
|
+
const activeRegistry = overrides?.activeTools === undefined ? registry : select(registry, overrides.activeTools);
|
|
2871
|
+
const attempt = (activePrompt, retryOverflow, compactOverflow = false, overflowCause) => {
|
|
2872
|
+
let emitted = false;
|
|
2873
|
+
let classifyFailure2 = classifyOtherFailure;
|
|
2874
|
+
const transformedParts = new Array;
|
|
2875
|
+
let preparedState;
|
|
2876
|
+
const singleFailure = (cause) => {
|
|
2877
|
+
const reason = cause.reasons.length === 1 ? cause.reasons[0] : undefined;
|
|
2878
|
+
return reason !== undefined && Cause4.isFailReason(reason) ? Option12.some(reason.error) : Option12.none();
|
|
2879
|
+
};
|
|
2880
|
+
const retryableOverflow = (cause, hasEmitted) => {
|
|
2881
|
+
const failure2 = singleFailure(cause);
|
|
2882
|
+
return retryOverflow && !hasEmitted && Option12.isSome(failure2) && classifyFailure2(failure2.value) === "context-overflow" && Option12.isSome(compactionService);
|
|
2883
|
+
};
|
|
2884
|
+
return Stream4.fromChannel(Channel.acquireUseRelease(Ref5.make({
|
|
2885
|
+
nextIndex: 0,
|
|
2886
|
+
firstIndexes: HashMap4.empty()
|
|
2887
|
+
}), (toolCallIds) => Stream4.unwrap(Effect18.gen(function* () {
|
|
2888
|
+
const activeModel = yield* LanguageModel5.LanguageModel;
|
|
2889
|
+
classifyFailure2 = (error) => classifyFailure(activeModel, error);
|
|
2890
|
+
const prepared = yield* preparePrompt(turn, activePrompt, compactOverflow);
|
|
2891
|
+
if (compactOverflow && !prepared.changed && overflowCause !== undefined) {
|
|
2892
|
+
return yield* Effect18.failCause(overflowCause);
|
|
2893
|
+
}
|
|
2894
|
+
const preparedPrompt = prepared.prompt;
|
|
2895
|
+
const history = yield* Ref5.get(chat.history);
|
|
2896
|
+
preparedState = { history, preparedPrompt };
|
|
2897
|
+
const responsePrompt = Prompt9.concat(history, preparedPrompt);
|
|
2898
|
+
const messages = responsePrompt.content;
|
|
2899
|
+
const rawParts = LanguageModel5.streamText({
|
|
2900
|
+
prompt: responsePrompt,
|
|
2901
|
+
toolkit: activeRegistry.toolkit,
|
|
2902
|
+
disableToolCallResolution: true
|
|
2903
|
+
}).pipe(Stream4.tap(() => Effect18.sync(() => {
|
|
2904
|
+
emitted = true;
|
|
2905
|
+
})), Stream4.catchCause((cause) => {
|
|
2906
|
+
if (Cause4.hasInterrupts(cause) || Cause4.hasDies(cause))
|
|
2907
|
+
return Stream4.failCause(cause);
|
|
2908
|
+
if (retryableOverflow(cause, emitted))
|
|
2909
|
+
return Stream4.failCause(cause);
|
|
2910
|
+
const error = singleFailure(cause);
|
|
2911
|
+
if (Option12.isNone(error))
|
|
2912
|
+
return Stream4.failCause(cause);
|
|
2913
|
+
return Stream4.make(Response7.makePart("error", { error: error.value }));
|
|
2914
|
+
}));
|
|
2915
|
+
return rawParts.pipe(Stream4.mapEffect((part) => transformPart(turn, part)), Stream4.flatMap(Option12.match({ onNone: () => Stream4.empty, onSome: Stream4.make })), Stream4.map((part) => ({
|
|
2916
|
+
part,
|
|
2917
|
+
messages,
|
|
2918
|
+
accept: validateToolCallId(toolCallIds, part).pipe(Effect18.andThen(Effect18.sync(() => {
|
|
2919
|
+
transformedParts.push(part);
|
|
2920
|
+
})))
|
|
2921
|
+
})));
|
|
2922
|
+
})).pipe(Stream4.toChannel), (_, exit) => preparedState === undefined || Exit2.isFailure(exit) && retryableOverflow(exit.cause, emitted) ? Effect18.void : Ref5.set(chat.history, Prompt9.concat(Prompt9.concat(preparedState.history, preparedState.preparedPrompt), Prompt9.fromResponseParts(transformedParts))).pipe(Effect18.andThen(persisted === undefined ? Effect18.void : persisted.save), Effect18.orDie, Effect18.asVoid))).pipe(Stream4.catchCause((cause) => {
|
|
2923
|
+
if (Cause4.hasInterrupts(cause) || Cause4.hasDies(cause))
|
|
2924
|
+
return Stream4.failCause(cause);
|
|
2925
|
+
if (retryableOverflow(cause, emitted)) {
|
|
2926
|
+
return attempt(preparedState?.preparedPrompt ?? activePrompt, false, true, cause);
|
|
2927
|
+
}
|
|
2928
|
+
return Stream4.failCause(cause);
|
|
2929
|
+
}), Stream4.catchCause((cause) => {
|
|
2930
|
+
const failure2 = singleFailure(cause);
|
|
2931
|
+
return Option12.isSome(failure2) && AiError3.isAiError(failure2.value) ? Stream4.fail(AgentError.make({ message: errorMessage(failure2.value), turn, cause: failure2.value })) : Stream4.failCause(cause);
|
|
2932
|
+
}));
|
|
2933
|
+
};
|
|
2934
|
+
const parts = Stream4.unwrap(applyPromptChain(chain, Prompt9.make(prompt), { agentName: agent.name, turn }).pipe(Effect18.map((transformedPrompt) => attempt(transformedPrompt, true).pipe(Stream4.flatMap(({ accept, part, messages }) => Stream4.fromEffect(accept).pipe(Stream4.flatMap(() => partEvents(turn, part, messages, activeRegistry))))))));
|
|
2935
|
+
const resilientParts = Option12.match(resilienceService, {
|
|
2936
|
+
onNone: () => parts,
|
|
2937
|
+
onSome: (resilience) => Stream4.unwrap(LanguageModel5.LanguageModel.pipe(Effect18.map((model) => parts.pipe(Stream4.provideService(LanguageModel5.LanguageModel, apply(model, {
|
|
2938
|
+
...resilience,
|
|
2939
|
+
classify: (error) => classifyFailure(model, error) === "context-overflow" ? "terminal" : resilience.classify(error)
|
|
2940
|
+
}))))))
|
|
2941
|
+
});
|
|
2942
|
+
return overrides?.model === undefined ? provideAgentModel(resilientParts) : resilientParts.pipe(Stream4.provide(overrides.model));
|
|
2943
|
+
};
|
|
2944
|
+
const turnCompletedEvent = (turn, transcript) => ({
|
|
2945
|
+
_tag: "TurnCompleted",
|
|
2946
|
+
turn,
|
|
2947
|
+
transcript,
|
|
2948
|
+
...state.finish === undefined ? {} : { usage: state.finish.usage, finishReason: state.finish.reason }
|
|
2949
|
+
});
|
|
2950
|
+
const terminalCompletedEvent = (turn, transcript) => ({
|
|
2951
|
+
_tag: "Completed",
|
|
2952
|
+
turns: turn + 1,
|
|
2953
|
+
text: state.text,
|
|
2954
|
+
transcript,
|
|
2955
|
+
...state.usage === undefined ? {} : { usage: state.usage }
|
|
2956
|
+
});
|
|
2957
|
+
const structuredFinalEvents = (structuredTurn, config) => Stream4.fromEffect(Effect18.gen(function* () {
|
|
2958
|
+
const transformedPrompt = yield* applyPromptChain(chain, Prompt9.make(config.objectPrompt), {
|
|
2959
|
+
agentName: agent.name,
|
|
2960
|
+
turn: structuredTurn
|
|
2961
|
+
});
|
|
2962
|
+
const history = yield* Ref5.get(chat.history);
|
|
2963
|
+
const response = yield* LanguageModel5.generateObject({
|
|
2964
|
+
prompt: Prompt9.concat(history, transformedPrompt),
|
|
2965
|
+
schema: config.schema,
|
|
2966
|
+
objectName: config.objectName,
|
|
2967
|
+
toolChoice: "none"
|
|
2968
|
+
}).pipe(withModelResilience, withAgentModel, Effect18.catchCause((cause) => {
|
|
2969
|
+
const reason = cause.reasons.length === 1 ? cause.reasons[0] : undefined;
|
|
2970
|
+
return reason !== undefined && Cause4.isFailReason(reason) ? Effect18.fail(AgentError.make({
|
|
2971
|
+
message: errorMessage(reason.error),
|
|
2972
|
+
turn: structuredTurn,
|
|
2973
|
+
cause: reason.error
|
|
2974
|
+
})) : Effect18.failCause(cause);
|
|
2975
|
+
}));
|
|
2976
|
+
yield* captureStructuredUsage(response.content);
|
|
2977
|
+
const transcript = Prompt9.concat(Prompt9.concat(history, transformedPrompt), Prompt9.fromResponseParts(response.content));
|
|
2978
|
+
const path = yield* syncSession(structuredTurn, history);
|
|
2979
|
+
yield* applyCompactionResult(structuredTurn, { _tag: "Microcompact", history: transcript, prompt: Prompt9.empty }, path.at(-1)?.id ?? null);
|
|
2980
|
+
if (Option12.isNone(activeSession))
|
|
2981
|
+
yield* savePersisted(structuredTurn);
|
|
2982
|
+
const structuredOutput = {
|
|
2983
|
+
_tag: "StructuredOutput",
|
|
2984
|
+
turn: structuredTurn,
|
|
2985
|
+
value: response.value,
|
|
2986
|
+
content: response.content
|
|
2987
|
+
};
|
|
2988
|
+
return [structuredOutput, terminalCompletedEvent(structuredTurn, transcript)];
|
|
2989
|
+
})).pipe(Stream4.flatMap((events) => Stream4.fromIterable(events)));
|
|
2990
|
+
const promptFromSteeringMessages = (messages) => messages.reduce((prompt, message) => Prompt9.concat(prompt, message.prompt), Prompt9.empty);
|
|
2991
|
+
const takeSteering = () => Option12.match(steeringService, {
|
|
2992
|
+
onNone: () => Effect18.succeed([]),
|
|
2993
|
+
onSome: (service) => service.takeSteering
|
|
2994
|
+
});
|
|
2995
|
+
const takeFollowUp = () => Option12.match(steeringService, {
|
|
2996
|
+
onNone: () => Effect18.succeed([]),
|
|
2997
|
+
onSome: (service) => service.takeFollowUp
|
|
2998
|
+
});
|
|
2999
|
+
const afterTurn = (turn) => Effect18.gen(function* () {
|
|
3000
|
+
const pending = state.pending;
|
|
3001
|
+
const transcript = yield* checkpointPending(turn, pending);
|
|
3002
|
+
const path = yield* syncSession(turn, transcript);
|
|
3003
|
+
yield* rememberTurn(turn, transcript, pending.length === 0, path);
|
|
3004
|
+
const completed = turnCompletedEvent(turn, transcript);
|
|
3005
|
+
if (pending.length === 0) {
|
|
3006
|
+
const followUp = yield* takeFollowUp();
|
|
3007
|
+
if (followUp.length > 0) {
|
|
3008
|
+
return {
|
|
3009
|
+
events: Stream4.fromIterable([completed, steeringDrainedEvent(turn, "followUp", followUp)]),
|
|
3010
|
+
next: { prompt: promptFromSteeringMessages(followUp) }
|
|
3011
|
+
};
|
|
3012
|
+
}
|
|
3013
|
+
if (structured !== undefined) {
|
|
3014
|
+
return {
|
|
3015
|
+
events: Stream4.fromIterable([completed]),
|
|
3016
|
+
structuredTurn: turn + 1
|
|
3017
|
+
};
|
|
3018
|
+
}
|
|
3019
|
+
yield* savePersisted(turn);
|
|
3020
|
+
return {
|
|
3021
|
+
events: Stream4.fromIterable([completed, terminalCompletedEvent(turn, transcript)])
|
|
3022
|
+
};
|
|
3023
|
+
}
|
|
3024
|
+
const evaluated = yield* agent.policy.decide({
|
|
3025
|
+
turn: turn + 1,
|
|
3026
|
+
history: transcript,
|
|
3027
|
+
pendingToolResults: pending
|
|
3028
|
+
});
|
|
3029
|
+
if (!isTurnPolicyDecision(evaluated)) {
|
|
3030
|
+
return yield* TurnPolicyError.make({
|
|
3031
|
+
message: "TurnPolicy returned an invalid decision; reasonless Stop decisions must be adapted with TurnPolicy.fromLegacy",
|
|
3032
|
+
cause: evaluated
|
|
3033
|
+
});
|
|
3034
|
+
}
|
|
3035
|
+
const decision2 = evaluated;
|
|
3036
|
+
if (decision2._tag === "Stop") {
|
|
3037
|
+
const pendingCalls = pending.map((result) => ({
|
|
3038
|
+
tool_call_id: result.id,
|
|
3039
|
+
tool_name: result.name
|
|
3040
|
+
}));
|
|
3041
|
+
return {
|
|
3042
|
+
events: Stream4.concat(Stream4.fromIterable([completed]), Stream4.fail(decision2.reason._tag === "TurnLimit" ? TurnLimitExceeded.make({
|
|
3043
|
+
turn: turn + 1,
|
|
3044
|
+
limit: decision2.reason.limit,
|
|
3045
|
+
pending: pendingCalls
|
|
3046
|
+
}) : TurnPolicyStopped.make({
|
|
3047
|
+
turn: turn + 1,
|
|
3048
|
+
reason: decision2.reason,
|
|
3049
|
+
pending: pendingCalls
|
|
3050
|
+
})))
|
|
3051
|
+
};
|
|
3052
|
+
}
|
|
3053
|
+
state.pending = [];
|
|
3054
|
+
const steering = yield* takeSteering();
|
|
3055
|
+
const basePrompt = steering.length === 0 ? Prompt9.empty : promptFromSteeringMessages(steering);
|
|
3056
|
+
const prompt = decision2.overrides?.instructions === undefined ? basePrompt : withSystem(decision2.overrides.instructions, basePrompt);
|
|
3057
|
+
return {
|
|
3058
|
+
events: Stream4.fromIterable(steering.length === 0 ? [completed] : [completed, steeringDrainedEvent(turn, "steering", steering)]),
|
|
3059
|
+
next: { prompt, ...decision2.overrides === undefined ? {} : { overrides: decision2.overrides } }
|
|
3060
|
+
};
|
|
3061
|
+
});
|
|
3062
|
+
const resetTurnState = (turn) => Stream4.sync(() => {
|
|
3063
|
+
state.turn = turn;
|
|
3064
|
+
state.finish = undefined;
|
|
3065
|
+
}).pipe(Stream4.drain);
|
|
3066
|
+
const runTurn = (turn, prompt, overrides) => {
|
|
3067
|
+
let next;
|
|
3068
|
+
let structuredTurn;
|
|
3069
|
+
const currentTurn = Stream4.fromIterable([{ _tag: "TurnStarted", turn }]).pipe(Stream4.concat(resetTurnState(turn)), Stream4.concat(Stream4.unwrap(Ref5.get(toolState).pipe(Effect18.map(({ registry }) => modelTurn(turn, prompt, registry, overrides))))), Stream4.concat(Stream4.unwrap(afterTurn(turn).pipe(Effect18.map((result) => {
|
|
3070
|
+
next = result.next;
|
|
3071
|
+
structuredTurn = result.structuredTurn;
|
|
3072
|
+
return result.events;
|
|
3073
|
+
})))), Stream4.withSpan("Baton.Agent.turn", { attributes: { "baton.turn": turn } }));
|
|
3074
|
+
return Stream4.concat(currentTurn, Stream4.suspend(() => {
|
|
3075
|
+
if (structuredTurn !== undefined && structured !== undefined) {
|
|
3076
|
+
return structuredFinalEvents(structuredTurn, structured).pipe(Stream4.withSpan("Baton.Agent.turn", { attributes: { "baton.turn": structuredTurn } }));
|
|
3077
|
+
}
|
|
3078
|
+
return next === undefined ? Stream4.empty : runTurn(turn + 1, next.prompt, next.overrides);
|
|
3079
|
+
}));
|
|
3080
|
+
};
|
|
3081
|
+
const resumeStream = (checkpoint) => {
|
|
3082
|
+
let next;
|
|
3083
|
+
const currentTurn = resetTurnState(0).pipe(Stream4.concat(Stream4.unwrap(Ref5.get(toolState).pipe(Effect18.map((tools) => {
|
|
3084
|
+
const suspension2 = checkpoint.suspension;
|
|
3085
|
+
const registry = suspension2.authorization_stage === undefined && suspension2.active_tools === undefined ? tools.registry : select(tools.registry, suspension2.active_tools ?? []);
|
|
3086
|
+
return toolCallEvents(0, Response7.makePart("tool-call", {
|
|
3087
|
+
id: checkpoint.call.id,
|
|
3088
|
+
name: checkpoint.call.name,
|
|
3089
|
+
params: checkpoint.call.params,
|
|
3090
|
+
providerExecuted: false
|
|
3091
|
+
}), checkpoint.messages, registry, suspension2.authorization_stage, suspension2.token);
|
|
3092
|
+
})))), Stream4.concat(Stream4.unwrap(afterTurn(0).pipe(Effect18.map((result) => {
|
|
3093
|
+
next = result.next;
|
|
3094
|
+
return result.events;
|
|
3095
|
+
})))), Stream4.withSpan("Baton.Agent.turn", { attributes: { "baton.turn": 0 } }));
|
|
3096
|
+
return Stream4.concat(currentTurn, Stream4.suspend(() => next === undefined ? Stream4.empty : runTurn(1, next.prompt, next.overrides)));
|
|
3097
|
+
};
|
|
3098
|
+
const baseInitialPrompt = seedSystem === undefined ? Prompt9.make(options.prompt) : withSystem(seedSystem, Prompt9.make(options.prompt));
|
|
3099
|
+
const initialPrompt = options.resume === undefined ? yield* recallInitialPrompt(baseInitialPrompt) : baseInitialPrompt;
|
|
3100
|
+
const runStream = validatedResume === undefined ? runTurn(0, initialPrompt) : resumeStream(validatedResume);
|
|
3101
|
+
return runStream.pipe(Stream4.catchCause((cause) => {
|
|
3102
|
+
const reason = cause.reasons.length === 1 ? cause.reasons[0] : undefined;
|
|
3103
|
+
if (reason !== undefined && Cause4.isFailReason(reason) && Schema14.is(DuplicateToolCallId)(reason.error)) {
|
|
3104
|
+
return Stream4.unwrap(checkpointPending(state.turn, state.pending).pipe(Effect18.map(() => Stream4.failCause(cause))));
|
|
3105
|
+
}
|
|
3106
|
+
if (reason !== undefined && Cause4.isFailReason(reason) && Schema14.is(AgentSuspended)(reason.error)) {
|
|
3107
|
+
const suspension2 = reason.error;
|
|
3108
|
+
return Stream4.unwrap(Effect18.gen(function* () {
|
|
3109
|
+
const checkpoint = yield* checkpointSuspended(state.turn, state.pending, suspension2);
|
|
3110
|
+
yield* syncSession(state.turn, checkpoint);
|
|
3111
|
+
return Stream4.concat(Stream4.fromIterable([turnCompletedEvent(state.turn, checkpoint)]), Stream4.failCause(cause));
|
|
3112
|
+
}));
|
|
3113
|
+
}
|
|
3114
|
+
return Stream4.failCause(cause);
|
|
3115
|
+
}));
|
|
3116
|
+
})).pipe(Stream4.withSpan("Baton.Agent.run", { attributes: { "baton.agent.name": agent.name } }), (run) => agent[ModelLayerTypeId] === undefined ? run : run.pipe(Stream4.provide(agent[ModelLayerTypeId])));
|
|
3117
|
+
var provideModel = dual7(2, (agent, layer8) => ({
|
|
3118
|
+
...agent,
|
|
3119
|
+
policy: agent.policy,
|
|
3120
|
+
...agent.authorization === undefined ? {} : {
|
|
3121
|
+
authorization: agent.authorization
|
|
3122
|
+
},
|
|
3123
|
+
[AgentTypeId]: {
|
|
3124
|
+
tools: (value) => value,
|
|
3125
|
+
requirements: (value) => value
|
|
3126
|
+
},
|
|
3127
|
+
[ModelLayerTypeId]: layer8
|
|
3128
|
+
}));
|
|
3129
|
+
var stream2 = dual7(2, (agent, options) => streamInternal(agent, options, undefined));
|
|
3130
|
+
var persisted = dual7(2, (agent, options) => streamInternal(agent, options, undefined));
|
|
3131
|
+
var streamObject = dual7(2, (agent, options) => streamInternal(agent, options, {
|
|
3132
|
+
schema: options.schema,
|
|
3133
|
+
objectName: options.objectName ?? "output",
|
|
3134
|
+
objectPrompt: options.objectPrompt ?? defaultObjectPrompt
|
|
3135
|
+
}));
|
|
3136
|
+
var persistedObject = dual7(2, (agent, options) => streamInternal(agent, options, {
|
|
3137
|
+
schema: options.schema,
|
|
3138
|
+
objectName: options.objectName ?? "output",
|
|
3139
|
+
objectPrompt: options.objectPrompt ?? defaultObjectPrompt
|
|
3140
|
+
}));
|
|
3141
|
+
var generate = dual7(2, (agent, options) => Stream4.runLast(stream2(agent, options)).pipe(Effect18.flatMap(Option12.match({
|
|
3142
|
+
onNone: () => Effect18.fail(AgentError.make({ message: "Agent run ended without a Completed event", turn: 0 })),
|
|
3143
|
+
onSome: (event) => event._tag === "Completed" ? Effect18.succeed({ text: event.text, turns: event.turns, transcript: event.transcript }) : Effect18.fail(AgentError.make({ message: "Agent run ended without a Completed event", turn: 0 }))
|
|
3144
|
+
}))));
|
|
3145
|
+
var generatePersisted = dual7(2, (agent, options) => Stream4.runLast(persisted(agent, options)).pipe(Effect18.flatMap(Option12.match({
|
|
3146
|
+
onNone: () => Effect18.fail(AgentError.make({ message: "Agent run ended without a Completed event", turn: 0 })),
|
|
3147
|
+
onSome: (event) => event._tag === "Completed" ? Effect18.succeed({ text: event.text, turns: event.turns, transcript: event.transcript }) : Effect18.fail(AgentError.make({ message: "Agent run ended without a Completed event", turn: 0 }))
|
|
3148
|
+
}))));
|
|
3149
|
+
var generateObject = dual7(2, (agent, options) => Stream4.runFold(streamObject(agent, options), () => ({
|
|
3150
|
+
value: Option12.none(),
|
|
3151
|
+
completed: Option12.none()
|
|
3152
|
+
}), (acc, event) => {
|
|
3153
|
+
if (event._tag === "StructuredOutput") {
|
|
3154
|
+
return { ...acc, value: Option12.some(event.value) };
|
|
3155
|
+
}
|
|
3156
|
+
if (event._tag === "Completed") {
|
|
3157
|
+
return { ...acc, completed: Option12.some(event) };
|
|
3158
|
+
}
|
|
3159
|
+
return acc;
|
|
3160
|
+
}).pipe(Effect18.flatMap(({ value, completed }) => Option12.match(completed, {
|
|
3161
|
+
onNone: () => Effect18.fail(AgentError.make({ message: "Agent object run ended without a Completed event", turn: 0 })),
|
|
3162
|
+
onSome: (event) => Option12.match(value, {
|
|
3163
|
+
onNone: () => Effect18.fail(AgentError.make({
|
|
3164
|
+
message: "Agent object run ended without a StructuredOutput event",
|
|
3165
|
+
turn: 0
|
|
3166
|
+
})),
|
|
3167
|
+
onSome: (typedValue) => Effect18.succeed({
|
|
3168
|
+
text: event.text,
|
|
3169
|
+
turns: event.turns,
|
|
3170
|
+
transcript: event.transcript,
|
|
3171
|
+
value: typedValue
|
|
3172
|
+
})
|
|
3173
|
+
})
|
|
3174
|
+
}))));
|
|
3175
|
+
var generatePersistedObject = dual7(2, (agent, options) => Stream4.runFold(persistedObject(agent, options), () => ({ value: Option12.none(), completed: Option12.none() }), (acc, event) => event._tag === "StructuredOutput" ? { ...acc, value: Option12.some(event.value) } : event._tag === "Completed" ? { ...acc, completed: Option12.some(event) } : acc).pipe(Effect18.flatMap(({ value, completed }) => Option12.match(completed, {
|
|
3176
|
+
onNone: () => Effect18.fail(AgentError.make({ message: "Agent object run ended without a Completed event", turn: 0 })),
|
|
3177
|
+
onSome: (event) => Option12.match(value, {
|
|
3178
|
+
onNone: () => Effect18.fail(AgentError.make({ message: "Agent object run ended without a StructuredOutput event", turn: 0 })),
|
|
3179
|
+
onSome: (typedValue) => Effect18.succeed({
|
|
3180
|
+
text: event.text,
|
|
3181
|
+
turns: event.turns,
|
|
3182
|
+
transcript: event.transcript,
|
|
3183
|
+
value: typedValue
|
|
3184
|
+
})
|
|
3185
|
+
})
|
|
3186
|
+
}))));
|
|
3187
|
+
|
|
3188
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/agent-tool.js
|
|
3189
|
+
var exports_agent_tool = {};
|
|
3190
|
+
__export(exports_agent_tool, {
|
|
3191
|
+
asTool: () => asTool
|
|
3192
|
+
});
|
|
3193
|
+
import { Cause as Cause5, Effect as Effect19, Function as Function7, Schema as Schema15 } from "effect";
|
|
3194
|
+
import { Prompt as Prompt10, Tool as Tool8, Toolkit as Toolkit5 } from "effect/unstable/ai";
|
|
3195
|
+
var defaultParameters = Schema15.Struct({ prompt: Schema15.String });
|
|
3196
|
+
var errorMessage2 = (error) => {
|
|
3197
|
+
if (Schema15.is(AgentSuspended)(error)) {
|
|
3198
|
+
return `suspended on ${error.tool_name}: ${error.reason}`;
|
|
3199
|
+
}
|
|
3200
|
+
if (Schema15.is(AgentError)(error)) {
|
|
3201
|
+
return `failed on turn ${error.turn}: ${error.message}`;
|
|
3202
|
+
}
|
|
3203
|
+
if (Schema15.is(ResumeMismatch)(error)) {
|
|
3204
|
+
return `resume mismatch: ${error.reason}`;
|
|
3205
|
+
}
|
|
3206
|
+
if (Schema15.is(TurnLimitExceeded)(error)) {
|
|
3207
|
+
return `turn limit exceeded at turn ${error.turn}`;
|
|
3208
|
+
}
|
|
3209
|
+
if (Schema15.is(TurnPolicyStopped)(error)) {
|
|
3210
|
+
return `policy stopped at turn ${error.turn}: ${error.reason._tag}`;
|
|
3211
|
+
}
|
|
3212
|
+
if (Schema15.is(TurnPolicyError)(error)) {
|
|
3213
|
+
return `turn policy failed: ${error.message}`;
|
|
3214
|
+
}
|
|
3215
|
+
if (Schema15.is(MiddlewareViolation)(error)) {
|
|
3216
|
+
return `middleware violation on turn ${error.turn}: ${error.detail}`;
|
|
3217
|
+
}
|
|
3218
|
+
if (Schema15.is(DuplicateToolCallId)(error)) {
|
|
3219
|
+
return `duplicate tool-call ID '${error.id}' at position ${error.duplicateIndex} (first at ${error.firstIndex})`;
|
|
3220
|
+
}
|
|
3221
|
+
if (Schema15.is(ToolNameCollision)(error)) {
|
|
3222
|
+
return `tool name collision: ${error.name} (${error.origins.map((origin) => origin._tag === "Static" ? `static:${origin.agent}` : origin._tag === "Builtin" ? `builtin:${origin.builtin}` : origin._tag === "Skill" ? `skill:${origin.skill}` : `handoff:${origin.specialist}`).join(", ")})`;
|
|
3223
|
+
}
|
|
3224
|
+
return error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
3225
|
+
};
|
|
3226
|
+
var causeMessage = (agentName, cause) => `sub-agent '${agentName}' could not complete: ${errorMessage2(Cause5.squash(cause))}`;
|
|
3227
|
+
var lazyHandled = (toolkit, name, handler) => ({
|
|
3228
|
+
tools: toolkit.tools,
|
|
3229
|
+
handle: (toolName, params) => toolkit.toHandlers({
|
|
3230
|
+
[name]: handler
|
|
3231
|
+
}).pipe(Effect19.flatMap((handlers) => toolkit.pipe(Effect19.provide(handlers))), Effect19.flatMap((handled) => handled.handle(toolName, params)))
|
|
3232
|
+
});
|
|
3233
|
+
var asTool = Function7.dual((args) => args.length !== 1 || ("name" in args[0]), (agent, options = {}) => {
|
|
3234
|
+
const name = options.name ?? agent.name;
|
|
3235
|
+
const parameters = options.parameters ?? defaultParameters;
|
|
3236
|
+
const success2 = options.success ?? Schema15.String;
|
|
3237
|
+
const toPrompt = options.toPrompt ?? ((params) => params.prompt);
|
|
3238
|
+
const fromResult = options.fromResult ?? ((result) => result.text);
|
|
3239
|
+
const tool = Tool8.make(name, {
|
|
3240
|
+
...options.description === undefined ? {} : { description: options.description },
|
|
3241
|
+
parameters,
|
|
3242
|
+
success: success2,
|
|
3243
|
+
failure: Schema15.String,
|
|
3244
|
+
failureMode: "return"
|
|
3245
|
+
});
|
|
3246
|
+
const toolkit = Toolkit5.make(tool);
|
|
3247
|
+
const handler = (params) => Effect19.gen(function* () {
|
|
3248
|
+
const prompt = yield* Effect19.try({ try: () => toPrompt(params), catch: errorMessage2 });
|
|
3249
|
+
const result = yield* generate(agent, { prompt }).pipe(Effect19.catchCause((cause) => {
|
|
3250
|
+
if (Cause5.hasInterrupts(cause))
|
|
3251
|
+
return Effect19.interrupt;
|
|
3252
|
+
return Effect19.fail(causeMessage(agent.name, cause));
|
|
3253
|
+
}));
|
|
3254
|
+
return yield* Effect19.try({ try: () => fromResult(result), catch: errorMessage2 });
|
|
3255
|
+
});
|
|
3256
|
+
return lazyHandled(toolkit, name, handler);
|
|
3257
|
+
});
|
|
3258
|
+
|
|
3259
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/guardrail.js
|
|
3260
|
+
var exports_guardrail = {};
|
|
3261
|
+
__export(exports_guardrail, {
|
|
3262
|
+
validateInput: () => validateInput,
|
|
3263
|
+
redactOutput: () => redactOutput,
|
|
3264
|
+
redactInput: () => redactInput,
|
|
3265
|
+
filterOutput: () => filterOutput
|
|
3266
|
+
});
|
|
3267
|
+
import { Effect as Effect20, Option as Option13 } from "effect";
|
|
3268
|
+
import { Prompt as Prompt11, Response as Response8 } from "effect/unstable/ai";
|
|
3269
|
+
var replacement = (options) => options.replacement ?? "[redacted]";
|
|
3270
|
+
var redactText = (text, options) => text.replace(options.pattern, replacement(options));
|
|
3271
|
+
var redactUserPart = (part, options) => part.type === "text" ? Prompt11.makePart("text", { text: redactText(part.text, options), options: part.options }) : part;
|
|
3272
|
+
var redactAssistantPart = (part, options) => {
|
|
3273
|
+
switch (part.type) {
|
|
3274
|
+
case "text":
|
|
3275
|
+
return Prompt11.makePart("text", { text: redactText(part.text, options), options: part.options });
|
|
3276
|
+
case "reasoning":
|
|
3277
|
+
return Prompt11.makePart("reasoning", { text: redactText(part.text, options), options: part.options });
|
|
3278
|
+
default:
|
|
3279
|
+
return part;
|
|
3280
|
+
}
|
|
3281
|
+
};
|
|
3282
|
+
var redactToolPart = (part, options) => {
|
|
3283
|
+
if (part.type !== "tool-approval-response" || part.reason === undefined)
|
|
3284
|
+
return part;
|
|
3285
|
+
return Prompt11.makePart("tool-approval-response", {
|
|
3286
|
+
approvalId: part.approvalId,
|
|
3287
|
+
approved: part.approved,
|
|
3288
|
+
reason: redactText(part.reason, options),
|
|
3289
|
+
options: part.options
|
|
3290
|
+
});
|
|
3291
|
+
};
|
|
3292
|
+
var redactPromptText = (prompt, options) => Prompt11.fromMessages(prompt.content.map((message) => {
|
|
3293
|
+
switch (message.role) {
|
|
3294
|
+
case "system":
|
|
3295
|
+
return Prompt11.makeMessage("system", {
|
|
3296
|
+
content: redactText(message.content, options),
|
|
3297
|
+
options: message.options
|
|
3298
|
+
});
|
|
3299
|
+
case "user":
|
|
3300
|
+
return isMessageFromRecall(message) ? replaceRecalledMessage(message, message.content.map((part) => redactUserPart(part, options))) : Prompt11.makeMessage("user", {
|
|
3301
|
+
content: message.content.map((part) => redactUserPart(part, options)),
|
|
3302
|
+
options: message.options
|
|
3303
|
+
});
|
|
3304
|
+
case "assistant":
|
|
3305
|
+
return Prompt11.makeMessage("assistant", {
|
|
3306
|
+
content: message.content.map((part) => redactAssistantPart(part, options)),
|
|
3307
|
+
options: message.options
|
|
3308
|
+
});
|
|
3309
|
+
case "tool":
|
|
3310
|
+
return Prompt11.makeMessage("tool", {
|
|
3311
|
+
content: message.content.map((part) => redactToolPart(part, options)),
|
|
3312
|
+
options: message.options
|
|
3313
|
+
});
|
|
3314
|
+
}
|
|
3315
|
+
}));
|
|
3316
|
+
var validateInput = (check) => ({
|
|
3317
|
+
transformPrompt: (prompt, context) => check(prompt, context).pipe(Effect20.flatMap(Option13.match({
|
|
3318
|
+
onNone: () => Effect20.succeed(prompt),
|
|
3319
|
+
onSome: (reason) => Effect20.fail(AgentError.make({ message: `Input guardrail blocked: ${reason}`, turn: context.turn }))
|
|
3320
|
+
})))
|
|
3321
|
+
});
|
|
3322
|
+
var redactInput = (options) => ({
|
|
3323
|
+
transformPrompt: (prompt) => Effect20.succeed(redactPromptText(prompt, options))
|
|
3324
|
+
});
|
|
3325
|
+
var redactOutput = (options) => ({
|
|
3326
|
+
transformPart: (part) => {
|
|
3327
|
+
if (part.type !== "text-delta")
|
|
3328
|
+
return Effect20.succeed(Option13.some(part));
|
|
3329
|
+
return Effect20.succeed(Option13.some(Response8.makePart("text-delta", {
|
|
3330
|
+
id: part.id,
|
|
3331
|
+
delta: redactText(part.delta, options),
|
|
3332
|
+
metadata: part.metadata
|
|
3333
|
+
})));
|
|
3334
|
+
}
|
|
3335
|
+
});
|
|
3336
|
+
var filterOutput = (keep) => ({
|
|
3337
|
+
transformPart: (part, context) => Effect20.succeed(part.type === "tool-call" || keep(part, context) ? Option13.some(part) : Option13.none())
|
|
3338
|
+
});
|
|
3339
|
+
|
|
3340
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/handoff.js
|
|
3341
|
+
var exports_handoff = {};
|
|
3342
|
+
__export(exports_handoff, {
|
|
3343
|
+
transferTool: () => transferTool,
|
|
3344
|
+
supervisor: () => supervisor,
|
|
3345
|
+
fanOut: () => fanOut
|
|
3346
|
+
});
|
|
3347
|
+
import { Effect as Effect21, Function as Function8, Schema as Schema16 } from "effect";
|
|
3348
|
+
import { AiError as AiError4, LanguageModel as LanguageModel6, Prompt as Prompt12, Tool as Tool9, Toolkit as Toolkit6 } from "effect/unstable/ai";
|
|
3349
|
+
var defaultTransferParameters = Schema16.Struct({ prompt: Schema16.String });
|
|
3350
|
+
var transferName = (agentName) => `transfer_to_${agentName}`;
|
|
3351
|
+
var positiveConcurrency = (value) => {
|
|
3352
|
+
const concurrency = value ?? 4;
|
|
3353
|
+
return Number.isInteger(concurrency) && concurrency > 0 ? Effect21.succeed(concurrency) : Effect21.fail(AgentError.make({
|
|
3354
|
+
message: "Handoff.fanOut concurrency must be a positive integer",
|
|
3355
|
+
turn: 0
|
|
3356
|
+
}));
|
|
3357
|
+
};
|
|
3358
|
+
var mergeHandled = (toolkits) => {
|
|
3359
|
+
const entries = new Map;
|
|
3360
|
+
for (const toolkit of toolkits) {
|
|
3361
|
+
for (const tool of Object.values(toolkit.tools)) {
|
|
3362
|
+
if (!entries.has(tool.name))
|
|
3363
|
+
entries.set(tool.name, { tool, toolkit });
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
const tools = Object.fromEntries([...entries].map(([name, entry]) => [name, entry.tool]));
|
|
3367
|
+
return {
|
|
3368
|
+
tools,
|
|
3369
|
+
handle: (name, params) => {
|
|
3370
|
+
const entry = entries.get(String(name));
|
|
3371
|
+
return entry === undefined ? Effect21.fail(AiError4.make({
|
|
3372
|
+
module: "Handoff",
|
|
3373
|
+
method: `${String(name)}.handle`,
|
|
3374
|
+
reason: AiError4.ToolNotFoundError.make({
|
|
3375
|
+
toolName: String(name),
|
|
3376
|
+
availableTools: Object.keys(tools)
|
|
3377
|
+
})
|
|
3378
|
+
})) : entry.toolkit.handle(name, params);
|
|
3379
|
+
}
|
|
3380
|
+
};
|
|
3381
|
+
};
|
|
3382
|
+
var toolkitFromHandled = (toolkit) => Toolkit6.make(...Object.values(toolkit.tools));
|
|
3383
|
+
var transferTool = Function8.dual((args) => args.length !== 1 || ("name" in args[0]), (target, options = {}) => asTool(target, {
|
|
3384
|
+
name: options.nameOverride ?? transferName(target.name),
|
|
3385
|
+
description: options.description ?? `Transfer to ${target.name}`,
|
|
3386
|
+
...options.parameters === undefined ? {} : { parameters: options.parameters },
|
|
3387
|
+
...options.success === undefined ? {} : { success: options.success },
|
|
3388
|
+
...options.toPrompt === undefined ? {} : { toPrompt: options.toPrompt },
|
|
3389
|
+
...options.fromResult === undefined ? {} : { fromResult: options.fromResult }
|
|
3390
|
+
}));
|
|
3391
|
+
var fanOut = Function8.dual((args) => args.length !== 1 || Array.isArray(args[0]), (children, options = {}) => positiveConcurrency(options.concurrency).pipe(Effect21.flatMap((concurrency) => Effect21.forEach(children, (child) => {
|
|
3392
|
+
const runOptions = {
|
|
3393
|
+
...child.options,
|
|
3394
|
+
prompt: child.prompt
|
|
3395
|
+
};
|
|
3396
|
+
return generate(child.agent, runOptions);
|
|
3397
|
+
}, { concurrency }))));
|
|
3398
|
+
var supervisor = (options) => {
|
|
3399
|
+
const specialists = options.specialists;
|
|
3400
|
+
const transferTools = specialists.map((specialist) => transferTool(specialist));
|
|
3401
|
+
const toolkit = mergeHandled(transferTools);
|
|
3402
|
+
const agent = make5({
|
|
3403
|
+
name: options.name,
|
|
3404
|
+
...options.instructions === undefined ? {} : { instructions: options.instructions },
|
|
3405
|
+
toolkit: toolkitFromHandled(toolkit),
|
|
3406
|
+
...options.policy === undefined ? {} : { policy: options.policy }
|
|
3407
|
+
});
|
|
3408
|
+
return {
|
|
3409
|
+
agent: {
|
|
3410
|
+
...agent,
|
|
3411
|
+
toolDeclarations: transferTools.flatMap((transfer, index) => Object.values(transfer.tools).map((tool) => ({
|
|
3412
|
+
tool,
|
|
3413
|
+
origin: { _tag: "Handoff", specialist: options.specialists[index].name }
|
|
3414
|
+
})))
|
|
3415
|
+
},
|
|
3416
|
+
toolkit
|
|
3417
|
+
};
|
|
3418
|
+
};
|
|
3419
|
+
|
|
3420
|
+
// ../../node_modules/.bun/@batonfx+core@0.6.1/node_modules/@batonfx/core/dist/index.js
|
|
3421
|
+
import { AiError as AiError5, Chat as Chat2, EmbeddingModel, IdGenerator, LanguageModel as LanguageModel7, Model as Model2, Prompt as Prompt13, Response as Response9, ResponseIdTracker, Telemetry as Telemetry2, Tokenizer as Tokenizer3, Tool as Tool10, Toolkit as Toolkit7 } from "effect/unstable/ai";
|
|
3422
|
+
|
|
3423
|
+
export { exports_turn_policy, exports_agent_event, exports_tool_context, exports_tool_executor, exports_approvals, exports_memory, exports_session, exports_tool_output, exports_compaction, exports_instructions, exports_model_middleware, exports_model_registry, exports_model_resilience, exports_permissions, exports_skill_source, exports_steering, exports_agent, exports_agent_tool, exports_guardrail, exports_handoff, AiError5 as AiError, Chat2 as Chat, EmbeddingModel, IdGenerator, Model2 as Model, Prompt13 as Prompt, Response9 as Response, ResponseIdTracker, Telemetry2 as Telemetry, Tokenizer3 as Tokenizer, Tool10 as Tool, Toolkit7 as Toolkit };
|