@better-agent/core 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/agent/constants.mjs +6 -0
- package/dist/agent/constants.mjs.map +1 -0
- package/dist/agent/define-agent.d.mts +29 -0
- package/dist/agent/define-agent.d.mts.map +1 -0
- package/dist/agent/define-agent.mjs +27 -0
- package/dist/agent/define-agent.mjs.map +1 -0
- package/dist/agent/index.d.mts +2 -0
- package/dist/agent/types.d.mts +216 -0
- package/dist/agent/types.d.mts.map +1 -0
- package/dist/agent/validation.mjs +64 -0
- package/dist/agent/validation.mjs.map +1 -0
- package/dist/api.d.mts +8 -0
- package/dist/api.d.mts.map +1 -0
- package/dist/api.mjs +63 -0
- package/dist/api.mjs.map +1 -0
- package/dist/app/config.mjs +43 -0
- package/dist/app/config.mjs.map +1 -0
- package/dist/app/create-app.d.mts +36 -0
- package/dist/app/create-app.d.mts.map +1 -0
- package/dist/app/create-app.mjs +132 -0
- package/dist/app/create-app.mjs.map +1 -0
- package/dist/app/registry.mjs +43 -0
- package/dist/app/registry.mjs.map +1 -0
- package/dist/app/types.d.mts +142 -0
- package/dist/app/types.d.mts.map +1 -0
- package/dist/events/constants.d.mts +49 -0
- package/dist/events/constants.d.mts.map +1 -0
- package/dist/events/constants.mjs +46 -0
- package/dist/events/constants.mjs.map +1 -0
- package/dist/events/index.d.mts +4 -0
- package/dist/events/index.mjs +3 -0
- package/dist/events/types.d.mts +289 -0
- package/dist/events/types.d.mts.map +1 -0
- package/dist/index.d.mts +23 -0
- package/dist/index.mjs +14 -0
- package/dist/internal/id.mjs +21 -0
- package/dist/internal/id.mjs.map +1 -0
- package/dist/internal/types.d.mts +11 -0
- package/dist/internal/types.d.mts.map +1 -0
- package/dist/mcp/error/mcp-client-error.d.mts +36 -0
- package/dist/mcp/error/mcp-client-error.d.mts.map +1 -0
- package/dist/mcp/error/mcp-client-error.mjs +33 -0
- package/dist/mcp/error/mcp-client-error.mjs.map +1 -0
- package/dist/mcp/index.d.mts +8 -0
- package/dist/mcp/index.mjs +9 -0
- package/dist/mcp/tool/json-rpc-message.d.mts +50 -0
- package/dist/mcp/tool/json-rpc-message.d.mts.map +1 -0
- package/dist/mcp/tool/json-rpc-message.mjs +84 -0
- package/dist/mcp/tool/json-rpc-message.mjs.map +1 -0
- package/dist/mcp/tool/mcp-client.d.mts +71 -0
- package/dist/mcp/tool/mcp-client.d.mts.map +1 -0
- package/dist/mcp/tool/mcp-client.mjs +304 -0
- package/dist/mcp/tool/mcp-client.mjs.map +1 -0
- package/dist/mcp/tool/mcp-http-transport.d.mts +62 -0
- package/dist/mcp/tool/mcp-http-transport.d.mts.map +1 -0
- package/dist/mcp/tool/mcp-http-transport.mjs +307 -0
- package/dist/mcp/tool/mcp-http-transport.mjs.map +1 -0
- package/dist/mcp/tool/mcp-tools.d.mts +20 -0
- package/dist/mcp/tool/mcp-tools.d.mts.map +1 -0
- package/dist/mcp/tool/mcp-tools.mjs +73 -0
- package/dist/mcp/tool/mcp-tools.mjs.map +1 -0
- package/dist/mcp/tool/mcp-transport.d.mts +81 -0
- package/dist/mcp/tool/mcp-transport.d.mts.map +1 -0
- package/dist/mcp/tool/mcp-transport.mjs +11 -0
- package/dist/mcp/tool/mcp-transport.mjs.map +1 -0
- package/dist/mcp/tool/types.d.mts +230 -0
- package/dist/mcp/tool/types.d.mts.map +1 -0
- package/dist/mcp/tool/types.mjs +19 -0
- package/dist/mcp/tool/types.mjs.map +1 -0
- package/dist/persistence/index.d.mts +3 -0
- package/dist/persistence/index.mjs +3 -0
- package/dist/persistence/memory.d.mts +21 -0
- package/dist/persistence/memory.d.mts.map +1 -0
- package/dist/persistence/memory.mjs +107 -0
- package/dist/persistence/memory.mjs.map +1 -0
- package/dist/persistence/types.d.mts +124 -0
- package/dist/persistence/types.d.mts.map +1 -0
- package/dist/plugins/index.d.mts +2 -0
- package/dist/plugins/runtime.d.mts +17 -0
- package/dist/plugins/runtime.d.mts.map +1 -0
- package/dist/plugins/runtime.mjs +456 -0
- package/dist/plugins/runtime.mjs.map +1 -0
- package/dist/plugins/types.d.mts +344 -0
- package/dist/plugins/types.d.mts.map +1 -0
- package/dist/providers/index.d.mts +9 -0
- package/dist/providers/index.mjs +0 -0
- package/dist/providers/types/capabilities.d.mts +153 -0
- package/dist/providers/types/capabilities.d.mts.map +1 -0
- package/dist/providers/types/content.d.mts +125 -0
- package/dist/providers/types/content.d.mts.map +1 -0
- package/dist/providers/types/conversation.d.mts +32 -0
- package/dist/providers/types/conversation.d.mts.map +1 -0
- package/dist/providers/types/index.d.mts +8 -0
- package/dist/providers/types/input.d.mts +74 -0
- package/dist/providers/types/input.d.mts.map +1 -0
- package/dist/providers/types/model.d.mts +68 -0
- package/dist/providers/types/model.d.mts.map +1 -0
- package/dist/providers/types/output.d.mts +29 -0
- package/dist/providers/types/output.d.mts.map +1 -0
- package/dist/providers/types/response.d.mts +35 -0
- package/dist/providers/types/response.d.mts.map +1 -0
- package/dist/providers/types/tool-calls.d.mts +51 -0
- package/dist/providers/types/tool-calls.d.mts.map +1 -0
- package/dist/run/agent-loop.mjs +231 -0
- package/dist/run/agent-loop.mjs.map +1 -0
- package/dist/run/event-queue.mjs +67 -0
- package/dist/run/event-queue.mjs.map +1 -0
- package/dist/run/execute-tool-calls.mjs +550 -0
- package/dist/run/execute-tool-calls.mjs.map +1 -0
- package/dist/run/execution.mjs +93 -0
- package/dist/run/execution.mjs.map +1 -0
- package/dist/run/helpers.mjs +466 -0
- package/dist/run/helpers.mjs.map +1 -0
- package/dist/run/hooks.mjs +124 -0
- package/dist/run/hooks.mjs.map +1 -0
- package/dist/run/index.d.mts +4 -0
- package/dist/run/messages.d.mts +8 -0
- package/dist/run/messages.d.mts.map +1 -0
- package/dist/run/messages.mjs +83 -0
- package/dist/run/messages.mjs.map +1 -0
- package/dist/run/model-strategy.mjs +105 -0
- package/dist/run/model-strategy.mjs.map +1 -0
- package/dist/run/output-errors.d.mts +75 -0
- package/dist/run/output-errors.d.mts.map +1 -0
- package/dist/run/pending-tools.d.mts +1 -0
- package/dist/run/pending-tools.mjs +185 -0
- package/dist/run/pending-tools.mjs.map +1 -0
- package/dist/run/registry.mjs +22 -0
- package/dist/run/registry.mjs.map +1 -0
- package/dist/run/runtime.d.mts +19 -0
- package/dist/run/runtime.d.mts.map +1 -0
- package/dist/run/runtime.mjs +491 -0
- package/dist/run/runtime.mjs.map +1 -0
- package/dist/run/stop-conditions.mjs +41 -0
- package/dist/run/stop-conditions.mjs.map +1 -0
- package/dist/run/types.d.mts +348 -0
- package/dist/run/types.d.mts.map +1 -0
- package/dist/schema/index.d.mts +2 -0
- package/dist/schema/resolve-json-schema.d.mts +12 -0
- package/dist/schema/resolve-json-schema.d.mts.map +1 -0
- package/dist/schema/resolve-json-schema.mjs +167 -0
- package/dist/schema/resolve-json-schema.mjs.map +1 -0
- package/dist/schema/types.d.mts +27 -0
- package/dist/schema/types.d.mts.map +1 -0
- package/dist/server/create-server.d.mts +21 -0
- package/dist/server/create-server.d.mts.map +1 -0
- package/dist/server/create-server.mjs +107 -0
- package/dist/server/create-server.mjs.map +1 -0
- package/dist/server/http.mjs +182 -0
- package/dist/server/http.mjs.map +1 -0
- package/dist/server/index.d.mts +3 -0
- package/dist/server/index.mjs +3 -0
- package/dist/server/routes.mjs +399 -0
- package/dist/server/routes.mjs.map +1 -0
- package/dist/server/types.d.mts +31 -0
- package/dist/server/types.d.mts.map +1 -0
- package/dist/tools/constants.d.mts +12 -0
- package/dist/tools/constants.d.mts.map +1 -0
- package/dist/tools/constants.mjs +13 -0
- package/dist/tools/constants.mjs.map +1 -0
- package/dist/tools/define-tool.d.mts +25 -0
- package/dist/tools/define-tool.d.mts.map +1 -0
- package/dist/tools/define-tool.mjs +76 -0
- package/dist/tools/define-tool.mjs.map +1 -0
- package/dist/tools/index.d.mts +5 -0
- package/dist/tools/lazy-tools.d.mts +49 -0
- package/dist/tools/lazy-tools.d.mts.map +1 -0
- package/dist/tools/lazy-tools.mjs +87 -0
- package/dist/tools/lazy-tools.mjs.map +1 -0
- package/dist/tools/resolve-tools.d.mts +12 -0
- package/dist/tools/resolve-tools.d.mts.map +1 -0
- package/dist/tools/resolve-tools.mjs +86 -0
- package/dist/tools/resolve-tools.mjs.map +1 -0
- package/dist/tools/types.d.mts +318 -0
- package/dist/tools/types.d.mts.map +1 -0
- package/dist/tools/validation.mjs +23 -0
- package/dist/tools/validation.mjs.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
import { resolveToJsonSchema, validateInput } from "../schema/resolve-json-schema.mjs";
|
|
2
|
+
import { getPreflightedOutputSchema } from "../agent/validation.mjs";
|
|
3
|
+
import { createIdGenerator } from "../internal/id.mjs";
|
|
4
|
+
import { normalizeInputToConversationItems, normalizeInputToMessages, projectConversationItemsToInput, pruneInputByCapabilities } from "./messages.mjs";
|
|
5
|
+
import { BetterAgentError } from "@better-agent/shared/errors";
|
|
6
|
+
import { isPlainRecord, safeJsonParse } from "@better-agent/shared/utils";
|
|
7
|
+
|
|
8
|
+
//#region src/run/helpers.ts
|
|
9
|
+
const MAX_OUTPUT_REPAIR_DEPTH = 2;
|
|
10
|
+
const isJsonSchemaRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11
|
+
const normalizeStructuredOutputJsonSchema = (schema) => {
|
|
12
|
+
const normalized = {};
|
|
13
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
normalized[key] = value.map((item) => isJsonSchemaRecord(item) ? normalizeStructuredOutputJsonSchema(item) : item);
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
normalized[key] = isJsonSchemaRecord(value) ? normalizeStructuredOutputJsonSchema(value) : value;
|
|
19
|
+
}
|
|
20
|
+
if ((normalized.type === "object" || isJsonSchemaRecord(normalized.properties) || Array.isArray(normalized.required)) && normalized.additionalProperties === void 0) normalized.additionalProperties = false;
|
|
21
|
+
return normalized;
|
|
22
|
+
};
|
|
23
|
+
/** Creates an emitter that persists stream events. */
|
|
24
|
+
function createStreamPersistenceEmitter(params) {
|
|
25
|
+
const stream = params.stream;
|
|
26
|
+
if (!stream) return;
|
|
27
|
+
let nextSeq = 0;
|
|
28
|
+
return async (event) => {
|
|
29
|
+
const streamEvent = {
|
|
30
|
+
...event,
|
|
31
|
+
seq: nextSeq++,
|
|
32
|
+
timestamp: event.timestamp ?? Date.now()
|
|
33
|
+
};
|
|
34
|
+
try {
|
|
35
|
+
await stream.append(params.streamId, streamEvent);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (error instanceof Error && error.message.includes("not found")) return;
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Converts `onEvent` into an internal emitter. */
|
|
43
|
+
function toEventEmitter(onEvent) {
|
|
44
|
+
if (!onEvent) return async () => {};
|
|
45
|
+
return async (event) => {
|
|
46
|
+
await onEvent(event);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Validates run context against the agent schema. */
|
|
50
|
+
async function validateAgentContext(agent, context) {
|
|
51
|
+
if (!agent.contextSchema) return context;
|
|
52
|
+
const validated = await validateInput(agent.contextSchema, context, { invalidMessage: "The provided data is invalid according to context schema." });
|
|
53
|
+
if (validated.isErr()) throw validated.error.at({ at: "core.run.validateAgentContext" });
|
|
54
|
+
return validated.value;
|
|
55
|
+
}
|
|
56
|
+
const throwInvalidStoredConversationItem = (conversationId, index) => {
|
|
57
|
+
throw BetterAgentError.fromCode("VALIDATION_FAILED", "Loaded conversation items are invalid.", {
|
|
58
|
+
context: {
|
|
59
|
+
conversationId,
|
|
60
|
+
index
|
|
61
|
+
},
|
|
62
|
+
trace: [{ at: "core.run.validateStoredConversationItems" }]
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
const isConversationPart = (part) => {
|
|
66
|
+
if (!isPlainRecord(part) || typeof part.type !== "string") return false;
|
|
67
|
+
switch (part.type) {
|
|
68
|
+
case "text": return typeof part.text === "string";
|
|
69
|
+
case "reasoning": return typeof part.text === "string" && (part.visibility === "summary" || part.visibility === "full") && (part.provider === void 0 || typeof part.provider === "string");
|
|
70
|
+
case "transcript": return typeof part.text === "string" && (part.segments === void 0 || Array.isArray(part.segments) && part.segments.every((segment) => isPlainRecord(segment) && typeof segment.id === "string" && typeof segment.start === "number" && typeof segment.end === "number" && typeof segment.text === "string" && (segment.speaker === void 0 || typeof segment.speaker === "string")));
|
|
71
|
+
case "image":
|
|
72
|
+
case "audio":
|
|
73
|
+
case "video":
|
|
74
|
+
case "file": return isPlainRecord(part.source);
|
|
75
|
+
case "embedding": return Array.isArray(part.embedding);
|
|
76
|
+
default: return false;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const validateStoredConversationItems = (items, conversationId) => {
|
|
80
|
+
for (const [index, item] of items.entries()) {
|
|
81
|
+
if (!isPlainRecord(item) || typeof item.type !== "string") throwInvalidStoredConversationItem(conversationId, index);
|
|
82
|
+
if (item.type === "message") {
|
|
83
|
+
if (typeof item.role !== "string" || !(typeof item.content === "string" || Array.isArray(item.content) && item.content.every((part) => isConversationPart(part)))) throwInvalidStoredConversationItem(conversationId, index);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (item.type === "tool-call") {
|
|
87
|
+
if (typeof item.name !== "string" || typeof item.callId !== "string" || !("result" in item) && typeof item.arguments !== "string") throwInvalidStoredConversationItem(conversationId, index);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (item.type === "provider-tool-result" && typeof item.name === "string" && typeof item.callId === "string") continue;
|
|
91
|
+
throwInvalidStoredConversationItem(conversationId, index);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const throwUnsupportedInputModality = (params) => {
|
|
95
|
+
throw BetterAgentError.fromCode("VALIDATION_FAILED", `Agent '${params.agent.name}' model does not accept ${params.modality} input at ${params.location}.`, {
|
|
96
|
+
context: {
|
|
97
|
+
agentName: params.agent.name,
|
|
98
|
+
modelId: params.agent.model.modelId,
|
|
99
|
+
modality: params.modality,
|
|
100
|
+
location: params.location
|
|
101
|
+
},
|
|
102
|
+
trace: [{ at: params.traceAt }]
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
const validateMessageContentCapabilities = (params) => {
|
|
106
|
+
const caps = params.agent.model.caps;
|
|
107
|
+
if (typeof params.content === "string") {
|
|
108
|
+
if (caps.inputModalities?.text === false) throwUnsupportedInputModality({
|
|
109
|
+
agent: params.agent,
|
|
110
|
+
modality: "text",
|
|
111
|
+
location: `input[${params.itemIndex}].content`,
|
|
112
|
+
traceAt: params.traceAt
|
|
113
|
+
});
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (!Array.isArray(params.content)) return;
|
|
117
|
+
for (const [partIndex, part] of params.content.entries()) {
|
|
118
|
+
if (typeof part !== "object" || part === null || !("type" in part)) continue;
|
|
119
|
+
const partType = part.type;
|
|
120
|
+
if (partType === "text" || partType === "transcript" || partType === "reasoning") {
|
|
121
|
+
if (caps.inputModalities?.text === false) throwUnsupportedInputModality({
|
|
122
|
+
agent: params.agent,
|
|
123
|
+
modality: "text",
|
|
124
|
+
location: `input[${params.itemIndex}].content[${partIndex}]`,
|
|
125
|
+
traceAt: params.traceAt
|
|
126
|
+
});
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (partType === "image" || partType === "audio" || partType === "video" || partType === "file" || partType === "embedding") {
|
|
130
|
+
const modality = partType;
|
|
131
|
+
if (caps.inputModalities?.[modality] !== true) throwUnsupportedInputModality({
|
|
132
|
+
agent: params.agent,
|
|
133
|
+
modality,
|
|
134
|
+
location: `input[${params.itemIndex}].content[${partIndex}]`,
|
|
135
|
+
traceAt: params.traceAt
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const isReplayInputPart = (part) => {
|
|
141
|
+
if (!isPlainRecord(part) || typeof part.type !== "string") return false;
|
|
142
|
+
switch (part.type) {
|
|
143
|
+
case "text": return typeof part.text === "string";
|
|
144
|
+
case "reasoning": return typeof part.text === "string" && (part.visibility === "summary" || part.visibility === "full") && (part.provider === void 0 || typeof part.provider === "string");
|
|
145
|
+
case "transcript": return typeof part.text === "string" && (part.segments === void 0 || Array.isArray(part.segments) && part.segments.every((segment) => isPlainRecord(segment) && typeof segment.id === "string" && typeof segment.start === "number" && typeof segment.end === "number" && typeof segment.text === "string" && (segment.speaker === void 0 || typeof segment.speaker === "string")));
|
|
146
|
+
case "image":
|
|
147
|
+
case "audio":
|
|
148
|
+
case "video":
|
|
149
|
+
case "file": return isPlainRecord(part.source);
|
|
150
|
+
case "embedding": return Array.isArray(part.embedding) && part.embedding.every((value) => typeof value === "number");
|
|
151
|
+
default: return false;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const isReplayInputItem = (item) => {
|
|
155
|
+
if (!isPlainRecord(item) || typeof item.type !== "string") return false;
|
|
156
|
+
if (item.type === "message") {
|
|
157
|
+
if (item.role !== void 0 && typeof item.role !== "string") return false;
|
|
158
|
+
if (typeof item.content === "string") return true;
|
|
159
|
+
return Array.isArray(item.content) && item.content.every(isReplayInputPart);
|
|
160
|
+
}
|
|
161
|
+
if (item.type === "tool-call") return typeof item.name === "string" && typeof item.callId === "string" && "result" in item;
|
|
162
|
+
return item.type === "provider-tool-result" && typeof item.name === "string" && typeof item.callId === "string" && "result" in item;
|
|
163
|
+
};
|
|
164
|
+
const validatePreparedReplayInput = (params) => {
|
|
165
|
+
if (!Array.isArray(params.input) || !params.input.every(isReplayInputItem)) throw BetterAgentError.fromCode("VALIDATION_FAILED", "conversationReplay.prepareInput must return a valid array of model input items.", {
|
|
166
|
+
context: {
|
|
167
|
+
agentName: params.agentName,
|
|
168
|
+
conversationId: params.conversationId
|
|
169
|
+
},
|
|
170
|
+
trace: [{ at: "core.run.prepareConversationReplayInput.validatePreparedInput" }]
|
|
171
|
+
});
|
|
172
|
+
for (const item of params.input) {
|
|
173
|
+
if (item.type !== "message") continue;
|
|
174
|
+
if (params.caps.inputShape === "prompt") {
|
|
175
|
+
if ("role" in item && item.role !== void 0) throw BetterAgentError.fromCode("VALIDATION_FAILED", "conversationReplay.prepareInput returned a role-bearing message for a prompt-shaped model.", {
|
|
176
|
+
context: {
|
|
177
|
+
agentName: params.agentName,
|
|
178
|
+
conversationId: params.conversationId
|
|
179
|
+
},
|
|
180
|
+
trace: [{ at: "core.run.prepareConversationReplayInput.validatePreparedInput.promptRole" }]
|
|
181
|
+
});
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (!("role" in item) || typeof item.role !== "string") throw BetterAgentError.fromCode("VALIDATION_FAILED", "conversationReplay.prepareInput returned a role-less message for a chat-shaped model.", {
|
|
185
|
+
context: {
|
|
186
|
+
agentName: params.agentName,
|
|
187
|
+
conversationId: params.conversationId
|
|
188
|
+
},
|
|
189
|
+
trace: [{ at: "core.run.prepareConversationReplayInput.validatePreparedInput.chatRole" }]
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
return params.input;
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Validates that run input only uses modalities supported by the target model.
|
|
196
|
+
*/
|
|
197
|
+
function validateRunInputCapabilities(params) {
|
|
198
|
+
const caps = params.agent.model.caps;
|
|
199
|
+
if (typeof params.input === "string") {
|
|
200
|
+
if (caps.inputModalities?.text === false) throwUnsupportedInputModality({
|
|
201
|
+
agent: params.agent,
|
|
202
|
+
modality: "text",
|
|
203
|
+
location: "input",
|
|
204
|
+
traceAt: params.traceAt
|
|
205
|
+
});
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
for (const [itemIndex, item] of params.input.entries()) {
|
|
209
|
+
if (item.type !== "message") continue;
|
|
210
|
+
validateMessageContentCapabilities({
|
|
211
|
+
agent: params.agent,
|
|
212
|
+
content: item.content,
|
|
213
|
+
itemIndex,
|
|
214
|
+
traceAt: params.traceAt
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Validates requested output modalities against the target model's capabilities.
|
|
220
|
+
*/
|
|
221
|
+
function validateRunModalities(params) {
|
|
222
|
+
if (!params.modalities || params.modalities.length === 0) return;
|
|
223
|
+
const caps = params.agent.model.caps;
|
|
224
|
+
for (const modality of params.modalities) {
|
|
225
|
+
if (caps.outputModalities?.[modality] !== void 0) continue;
|
|
226
|
+
throw BetterAgentError.fromCode("VALIDATION_FAILED", `Agent '${params.agent.name}' model does not support ${modality} output.`, {
|
|
227
|
+
context: {
|
|
228
|
+
agentName: params.agent.name,
|
|
229
|
+
modelId: params.agent.model.modelId,
|
|
230
|
+
modality
|
|
231
|
+
},
|
|
232
|
+
trace: [{ at: params.traceAt }]
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
if (params.output !== void 0 && !params.modalities.includes("text")) throw BetterAgentError.fromCode("VALIDATION_FAILED", `Structured output requires text output for agent '${params.agent.name}'.`, {
|
|
236
|
+
context: {
|
|
237
|
+
agentName: params.agent.name,
|
|
238
|
+
modelId: params.agent.model.modelId,
|
|
239
|
+
modalities: [...params.modalities]
|
|
240
|
+
},
|
|
241
|
+
trace: [{ at: params.traceAt }]
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Prepares replayable model input from durable conversation items for a run.
|
|
246
|
+
*
|
|
247
|
+
* Stored history is projected losslessly first. The run can then override that
|
|
248
|
+
* projection with `prepareInput`, or fall back to capability-based pruning.
|
|
249
|
+
*/
|
|
250
|
+
function prepareConversationReplayInput(params) {
|
|
251
|
+
const projected = projectConversationItemsToInput(params.items, params.caps);
|
|
252
|
+
const replay = params.conversationReplay;
|
|
253
|
+
if (typeof replay?.prepareInput === "function") return Promise.resolve(replay.prepareInput({
|
|
254
|
+
items: params.items,
|
|
255
|
+
caps: params.caps,
|
|
256
|
+
agentName: params.agentName,
|
|
257
|
+
conversationId: params.conversationId
|
|
258
|
+
})).then((input) => validatePreparedReplayInput({
|
|
259
|
+
input,
|
|
260
|
+
caps: params.caps,
|
|
261
|
+
agentName: params.agentName,
|
|
262
|
+
conversationId: params.conversationId
|
|
263
|
+
}));
|
|
264
|
+
if (replay?.omitUnsupportedParts === false) return projected;
|
|
265
|
+
return pruneInputByCapabilities(projected, params.caps);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Converts a public output schema definition into a provider request.
|
|
269
|
+
*/
|
|
270
|
+
function toStructuredOutputRequest(agent, output) {
|
|
271
|
+
if (output === void 0) return;
|
|
272
|
+
if (!agent.model.caps.structured_output) throw BetterAgentError.fromCode("NOT_IMPLEMENTED", `Model '${agent.model.modelId}' does not support structured output.`, {
|
|
273
|
+
context: {
|
|
274
|
+
agentName: agent.name,
|
|
275
|
+
modelId: agent.model.modelId
|
|
276
|
+
},
|
|
277
|
+
trace: [{ at: "core.run.toStructuredOutputRequest.capability" }]
|
|
278
|
+
});
|
|
279
|
+
const preflightedSchema = output === agent.outputSchema ? getPreflightedOutputSchema(agent) : void 0;
|
|
280
|
+
if (preflightedSchema !== void 0) return {
|
|
281
|
+
name: output.name ?? `${agent.name}_output`,
|
|
282
|
+
schema: normalizeStructuredOutputJsonSchema(preflightedSchema),
|
|
283
|
+
strict: output.strict
|
|
284
|
+
};
|
|
285
|
+
const runtimeResolvedSchema = resolveToJsonSchema(output.schema);
|
|
286
|
+
if (runtimeResolvedSchema.isErr()) throw runtimeResolvedSchema.error.at({ at: "core.run.toStructuredOutputRequest.resolveSchema" });
|
|
287
|
+
return {
|
|
288
|
+
name: output.name ?? `${agent.name}_output`,
|
|
289
|
+
schema: normalizeStructuredOutputJsonSchema(runtimeResolvedSchema.value),
|
|
290
|
+
strict: output.strict
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Parses and validates structured output from a provider response.
|
|
295
|
+
*
|
|
296
|
+
* Structured output currently requires text output.
|
|
297
|
+
*/
|
|
298
|
+
async function finalizeRunResult(result, output, options) {
|
|
299
|
+
if (output === void 0) return result;
|
|
300
|
+
const outputMessages = result.response.output.filter((item) => item.type === "message");
|
|
301
|
+
const resolvedOutputErrorMode = options?.outputErrorMode ?? "throw";
|
|
302
|
+
const getLastStructuredText = () => outputMessages.map((message) => typeof message.content === "string" ? message.content : message.content.filter((part) => part.type === "text").map((part) => part.text).join("")).filter((text) => text.trim().length > 0).at(-1);
|
|
303
|
+
const defaultOutputErrorBehavior = (error) => {
|
|
304
|
+
throw error;
|
|
305
|
+
};
|
|
306
|
+
const validateStructuredValue = async (value, text, repairDepth) => {
|
|
307
|
+
const validated = await validateInput(output.schema, value);
|
|
308
|
+
if (validated.isErr()) return await resolveOutputError({
|
|
309
|
+
errorKind: "validation",
|
|
310
|
+
error: validated.error.at({ at: "core.run.finalizeRunResult.validateSchema" }),
|
|
311
|
+
text,
|
|
312
|
+
value
|
|
313
|
+
}, repairDepth);
|
|
314
|
+
return validated.value;
|
|
315
|
+
};
|
|
316
|
+
const parseStructuredText = async (text, repairDepth) => {
|
|
317
|
+
const parsed = safeJsonParse(text);
|
|
318
|
+
if (parsed.isErr()) return await resolveOutputError({
|
|
319
|
+
errorKind: "parse",
|
|
320
|
+
error: BetterAgentError.wrap({
|
|
321
|
+
err: parsed.error,
|
|
322
|
+
message: "Structured output was requested, but the model returned invalid JSON.",
|
|
323
|
+
opts: {
|
|
324
|
+
code: "VALIDATION_FAILED",
|
|
325
|
+
context: { preview: text.slice(0, 200) },
|
|
326
|
+
trace: [{ at: "core.run.finalizeRunResult.parseJson" }]
|
|
327
|
+
}
|
|
328
|
+
}),
|
|
329
|
+
text
|
|
330
|
+
}, repairDepth);
|
|
331
|
+
return await validateStructuredValue(parsed.value, text, repairDepth);
|
|
332
|
+
};
|
|
333
|
+
const resolveOutputError = async (context, repairDepth) => {
|
|
334
|
+
if (resolvedOutputErrorMode === "throw" || repairDepth >= MAX_OUTPUT_REPAIR_DEPTH) return defaultOutputErrorBehavior(context.error);
|
|
335
|
+
const action = await options?.onOutputError?.(context);
|
|
336
|
+
switch (action?.action) {
|
|
337
|
+
case "repair_text": return await parseStructuredText(action.text, repairDepth + 1);
|
|
338
|
+
case "repair_value": return await validateStructuredValue(action.value, "text" in context ? context.text : "", repairDepth + 1);
|
|
339
|
+
case "throw": throw context.error;
|
|
340
|
+
default: return defaultOutputErrorBehavior(context.error);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
const lastText = getLastStructuredText();
|
|
344
|
+
if (!lastText) {
|
|
345
|
+
const structured = await resolveOutputError({
|
|
346
|
+
errorKind: "missing_text",
|
|
347
|
+
error: BetterAgentError.fromCode("VALIDATION_FAILED", "Structured output was requested, but the model did not return JSON text.", { trace: [{ at: "core.run.finalizeRunResult.noStructuredText" }] })
|
|
348
|
+
}, 0);
|
|
349
|
+
return {
|
|
350
|
+
...result,
|
|
351
|
+
structured
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
const structured = await parseStructuredText(lastText, 0);
|
|
355
|
+
return {
|
|
356
|
+
...result,
|
|
357
|
+
structured
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Shared id generator for runs and messages.
|
|
362
|
+
*/
|
|
363
|
+
const generateId = createIdGenerator({ prefixes: {
|
|
364
|
+
run: "run",
|
|
365
|
+
message: "msg"
|
|
366
|
+
} });
|
|
367
|
+
/**
|
|
368
|
+
* Loads persisted conversation history and returns:
|
|
369
|
+
* - `input`: the model-facing input for this run
|
|
370
|
+
* - `items`: the durable conversation state to mutate and save
|
|
371
|
+
* - `loaded`: the original persisted record for save concurrency
|
|
372
|
+
* - `replayStartIndex`: where the current run's replay window starts in `items`
|
|
373
|
+
*
|
|
374
|
+
* `replayStartIndex` is `loaded.items.length` when older history should be kept in
|
|
375
|
+
* durable state but excluded from per-step replay, otherwise it is `0`.
|
|
376
|
+
*/
|
|
377
|
+
async function loadConversationMessages(params) {
|
|
378
|
+
const inputItems = normalizeInputToMessages(params.input, params.caps ?? { inputShape: "chat" });
|
|
379
|
+
const durableInputItems = normalizeInputToConversationItems(params.input, params.caps ?? { inputShape: "chat" });
|
|
380
|
+
if (!params.conversations || params.conversationId === void 0) return {
|
|
381
|
+
input: params.input,
|
|
382
|
+
items: durableInputItems,
|
|
383
|
+
replayStartIndex: 0,
|
|
384
|
+
conversationReplayActive: false
|
|
385
|
+
};
|
|
386
|
+
if (!params.agentName) throw BetterAgentError.fromCode("INTERNAL", "agentName is required when loading conversation messages.", {
|
|
387
|
+
context: { conversationId: params.conversationId },
|
|
388
|
+
trace: [{ at: "core.run.loadConversationMessages.missingAgentName" }]
|
|
389
|
+
});
|
|
390
|
+
const loaded = await params.conversations.load({
|
|
391
|
+
conversationId: params.conversationId,
|
|
392
|
+
agentName: params.agentName
|
|
393
|
+
});
|
|
394
|
+
if (!loaded) return {
|
|
395
|
+
input: params.input,
|
|
396
|
+
items: durableInputItems,
|
|
397
|
+
replayStartIndex: 0,
|
|
398
|
+
conversationReplayActive: false
|
|
399
|
+
};
|
|
400
|
+
validateStoredConversationItems(loaded.items, params.conversationId);
|
|
401
|
+
if (params.replaceHistory) return {
|
|
402
|
+
input: params.input,
|
|
403
|
+
items: durableInputItems,
|
|
404
|
+
replayStartIndex: 0,
|
|
405
|
+
conversationReplayActive: false,
|
|
406
|
+
loaded
|
|
407
|
+
};
|
|
408
|
+
const caps = params.caps ?? { inputShape: "chat" };
|
|
409
|
+
if ((caps.replayMode ?? (caps.inputShape === "prompt" ? "single_turn_persistent" : "multi_turn")) !== "multi_turn") return {
|
|
410
|
+
input: params.input,
|
|
411
|
+
items: [...loaded.items, ...durableInputItems],
|
|
412
|
+
replayStartIndex: loaded.items.length,
|
|
413
|
+
conversationReplayActive: false,
|
|
414
|
+
loaded
|
|
415
|
+
};
|
|
416
|
+
return {
|
|
417
|
+
input: [...await prepareConversationReplayInput({
|
|
418
|
+
items: loaded.items,
|
|
419
|
+
caps,
|
|
420
|
+
agentName: params.agentName,
|
|
421
|
+
conversationId: params.conversationId,
|
|
422
|
+
conversationReplay: params.conversationReplay
|
|
423
|
+
}), ...inputItems],
|
|
424
|
+
items: [...loaded.items, ...durableInputItems],
|
|
425
|
+
replayStartIndex: 0,
|
|
426
|
+
conversationReplayActive: true,
|
|
427
|
+
loaded
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Saves durable conversation items after a run completes.
|
|
432
|
+
*/
|
|
433
|
+
async function saveConversationMessages(params) {
|
|
434
|
+
if (!params.conversations || params.conversationId === void 0) return;
|
|
435
|
+
if (!params.agentName) throw BetterAgentError.fromCode("INTERNAL", "agentName is required when saving conversation messages.", {
|
|
436
|
+
context: { conversationId: params.conversationId },
|
|
437
|
+
trace: [{ at: "core.run.saveConversationMessages.missingAgentName" }]
|
|
438
|
+
});
|
|
439
|
+
try {
|
|
440
|
+
validateStoredConversationItems(params.result.items, params.conversationId);
|
|
441
|
+
await params.conversations.save({
|
|
442
|
+
conversationId: params.conversationId,
|
|
443
|
+
agentName: params.agentName,
|
|
444
|
+
items: params.result.items,
|
|
445
|
+
...params.loaded?.cursor !== void 0 ? { expectedCursor: params.loaded.cursor } : {}
|
|
446
|
+
});
|
|
447
|
+
} catch (error) {
|
|
448
|
+
throw BetterAgentError.wrap({
|
|
449
|
+
err: error,
|
|
450
|
+
message: "Failed to save conversation messages.",
|
|
451
|
+
opts: {
|
|
452
|
+
code: error instanceof BetterAgentError && error.code !== void 0 ? error.code : typeof error?.code === "string" ? error.code : "INTERNAL",
|
|
453
|
+
...typeof error?.status === "number" ? { status: error.status } : {},
|
|
454
|
+
context: {
|
|
455
|
+
conversationId: params.conversationId,
|
|
456
|
+
agentName: params.agentName
|
|
457
|
+
},
|
|
458
|
+
trace: [{ at: "core.run.saveConversationMessages" }]
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
//#endregion
|
|
465
|
+
export { createStreamPersistenceEmitter, finalizeRunResult, generateId, loadConversationMessages, prepareConversationReplayInput, saveConversationMessages, toEventEmitter, toStructuredOutputRequest, validateAgentContext, validateRunInputCapabilities, validateRunModalities, validateStoredConversationItems };
|
|
466
|
+
//# sourceMappingURL=helpers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.mjs","names":[],"sources":["../../src/run/helpers.ts"],"sourcesContent":["import { BetterAgentError } from \"@better-agent/shared/errors\";\nimport { isPlainRecord, safeJsonParse } from \"@better-agent/shared/utils\";\nimport type { AnyAgentDefinition } from \"../agent\";\nimport { getPreflightedOutputSchema } from \"../agent/validation\";\nimport type { Event } from \"../events\";\nimport { createIdGenerator } from \"../internal/id\";\nimport type { Awaitable } from \"../internal/types\";\nimport type {\n ConversationStore,\n LoadedConversation,\n StreamEvent,\n StreamStore,\n} from \"../persistence\";\nimport type {\n Capabilities,\n ConversationItem,\n GenerativeModelInput,\n GenerativeModelInputItem,\n GenerativeModelInputMessageContent,\n GenerativeModelOutputMessage,\n Modality,\n OutputSchemaDefinition,\n StructuredOutput,\n} from \"../providers\";\nimport { resolveToJsonSchema, validateInput } from \"../schema\";\nimport {\n normalizeInputToConversationItems,\n normalizeInputToMessages,\n projectConversationItemsToInput,\n pruneInputByCapabilities,\n} from \"./messages\";\nimport type { OnOutputError, OutputErrorContext, OutputErrorMode } from \"./output-errors\";\nimport type { ContextBoundAgent, ConversationReplayOptions, RunOptions, RunResult } from \"./types\";\n\nconst MAX_OUTPUT_REPAIR_DEPTH = 2;\ntype NonTextInputModality = Exclude<Modality, \"text\">;\n\nconst isJsonSchemaRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst normalizeStructuredOutputJsonSchema = (\n schema: Record<string, unknown>,\n): Record<string, unknown> => {\n const normalized: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(schema)) {\n if (Array.isArray(value)) {\n normalized[key] = value.map((item) =>\n isJsonSchemaRecord(item) ? normalizeStructuredOutputJsonSchema(item) : item,\n );\n continue;\n }\n\n normalized[key] = isJsonSchemaRecord(value)\n ? normalizeStructuredOutputJsonSchema(value)\n : value;\n }\n\n const objectLike =\n normalized.type === \"object\" ||\n isJsonSchemaRecord(normalized.properties) ||\n Array.isArray(normalized.required);\n\n if (objectLike && normalized.additionalProperties === undefined) {\n normalized.additionalProperties = false;\n }\n\n return normalized;\n};\n\n/** Creates an emitter that persists stream events. */\nexport function createStreamPersistenceEmitter(params: {\n stream?: StreamStore;\n streamId: string;\n}): ((event: Event) => Promise<void>) | undefined {\n const stream = params.stream;\n if (!stream) {\n return undefined;\n }\n\n let nextSeq = 0;\n\n return async (event: Event) => {\n const streamEvent: StreamEvent = {\n ...event,\n seq: nextSeq++,\n timestamp: event.timestamp ?? Date.now(),\n };\n try {\n await stream.append(params.streamId, streamEvent);\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"not found\")) {\n return;\n }\n throw error;\n }\n };\n}\n\n/** Converts `onEvent` into an internal emitter. */\nexport function toEventEmitter(onEvent?: RunOptions[\"onEvent\"]): (event: Event) => Promise<void> {\n if (!onEvent) {\n return async () => {};\n }\n\n return async (event) => {\n await onEvent(event);\n };\n}\n\n/** Validates run context against the agent schema. */\nexport async function validateAgentContext<TContext>(\n agent: ContextBoundAgent<TContext>,\n context: TContext | undefined,\n): Promise<TContext | undefined> {\n if (!agent.contextSchema) {\n return context;\n }\n\n const validated = await validateInput<TContext>(agent.contextSchema, context, {\n invalidMessage: \"The provided data is invalid according to context schema.\",\n });\n if (validated.isErr()) {\n throw validated.error.at({ at: \"core.run.validateAgentContext\" });\n }\n\n return validated.value;\n}\n\n/** Minimal model info for runtime validation. */\ntype AgentModelInfo = {\n name: string;\n model: {\n modelId: string;\n caps: Capabilities;\n };\n};\n\nconst throwInvalidStoredConversationItem = (conversationId: string, index: number): never => {\n throw BetterAgentError.fromCode(\"VALIDATION_FAILED\", \"Loaded conversation items are invalid.\", {\n context: { conversationId, index },\n trace: [{ at: \"core.run.validateStoredConversationItems\" }],\n });\n};\n\nconst isConversationPart = (part: unknown): boolean => {\n if (!isPlainRecord(part) || typeof part.type !== \"string\") {\n return false;\n }\n\n switch (part.type) {\n case \"text\":\n return typeof part.text === \"string\";\n case \"reasoning\":\n return (\n typeof part.text === \"string\" &&\n (part.visibility === \"summary\" || part.visibility === \"full\") &&\n (part.provider === undefined || typeof part.provider === \"string\")\n );\n case \"transcript\":\n return (\n typeof part.text === \"string\" &&\n (part.segments === undefined ||\n (Array.isArray(part.segments) &&\n part.segments.every(\n (segment) =>\n isPlainRecord(segment) &&\n typeof segment.id === \"string\" &&\n typeof segment.start === \"number\" &&\n typeof segment.end === \"number\" &&\n typeof segment.text === \"string\" &&\n (segment.speaker === undefined ||\n typeof segment.speaker === \"string\"),\n )))\n );\n case \"image\":\n case \"audio\":\n case \"video\":\n case \"file\":\n return isPlainRecord(part.source);\n case \"embedding\":\n return Array.isArray(part.embedding);\n default:\n return false;\n }\n};\n\nexport const validateStoredConversationItems = (\n items: ConversationItem[],\n conversationId: string,\n): void => {\n for (const [index, item] of items.entries()) {\n if (!isPlainRecord(item) || typeof item.type !== \"string\") {\n throwInvalidStoredConversationItem(conversationId, index);\n }\n\n if (item.type === \"message\") {\n if (\n typeof item.role !== \"string\" ||\n !(\n typeof item.content === \"string\" ||\n (Array.isArray(item.content) &&\n item.content.every((part) => isConversationPart(part)))\n )\n ) {\n throwInvalidStoredConversationItem(conversationId, index);\n }\n continue;\n }\n\n if (item.type === \"tool-call\") {\n if (\n typeof item.name !== \"string\" ||\n typeof item.callId !== \"string\" ||\n (!(\"result\" in item) && typeof item.arguments !== \"string\")\n ) {\n throwInvalidStoredConversationItem(conversationId, index);\n }\n continue;\n }\n\n if (\n item.type === \"provider-tool-result\" &&\n typeof item.name === \"string\" &&\n typeof item.callId === \"string\"\n ) {\n continue;\n }\n\n throwInvalidStoredConversationItem(conversationId, index);\n }\n};\n\nconst throwUnsupportedInputModality = (params: {\n agent: AgentModelInfo;\n modality: \"text\" | \"image\" | \"audio\" | \"video\" | \"file\" | \"embedding\";\n location: string;\n traceAt: string;\n}): never => {\n throw BetterAgentError.fromCode(\n \"VALIDATION_FAILED\",\n `Agent '${params.agent.name}' model does not accept ${params.modality} input at ${params.location}.`,\n {\n context: {\n agentName: params.agent.name,\n modelId: params.agent.model.modelId,\n modality: params.modality,\n location: params.location,\n },\n trace: [{ at: params.traceAt }],\n },\n );\n};\n\nconst validateMessageContentCapabilities = (params: {\n agent: AgentModelInfo;\n content: GenerativeModelInputMessageContent;\n itemIndex: number;\n traceAt: string;\n}): void => {\n const caps = params.agent.model.caps;\n\n if (typeof params.content === \"string\") {\n if (caps.inputModalities?.text === false) {\n throwUnsupportedInputModality({\n agent: params.agent,\n modality: \"text\",\n location: `input[${params.itemIndex}].content`,\n traceAt: params.traceAt,\n });\n }\n return;\n }\n\n if (!Array.isArray(params.content)) {\n return;\n }\n\n for (const [partIndex, part] of params.content.entries()) {\n if (typeof part !== \"object\" || part === null || !(\"type\" in part)) {\n continue;\n }\n\n const partType = (part as { type: string }).type;\n\n if (partType === \"text\" || partType === \"transcript\" || partType === \"reasoning\") {\n if (caps.inputModalities?.text === false) {\n throwUnsupportedInputModality({\n agent: params.agent,\n modality: \"text\",\n location: `input[${params.itemIndex}].content[${partIndex}]`,\n traceAt: params.traceAt,\n });\n }\n continue;\n }\n\n if (\n partType === \"image\" ||\n partType === \"audio\" ||\n partType === \"video\" ||\n partType === \"file\" ||\n partType === \"embedding\"\n ) {\n const modality = partType as NonTextInputModality;\n if (caps.inputModalities?.[modality] !== true) {\n throwUnsupportedInputModality({\n agent: params.agent,\n modality,\n location: `input[${params.itemIndex}].content[${partIndex}]`,\n traceAt: params.traceAt,\n });\n }\n }\n }\n};\n\nconst isReplayInputPart = (part: unknown): boolean => {\n if (!isPlainRecord(part) || typeof part.type !== \"string\") {\n return false;\n }\n\n switch (part.type) {\n case \"text\":\n return typeof part.text === \"string\";\n case \"reasoning\":\n return (\n typeof part.text === \"string\" &&\n (part.visibility === \"summary\" || part.visibility === \"full\") &&\n (part.provider === undefined || typeof part.provider === \"string\")\n );\n case \"transcript\":\n return (\n typeof part.text === \"string\" &&\n (part.segments === undefined ||\n (Array.isArray(part.segments) &&\n part.segments.every(\n (segment) =>\n isPlainRecord(segment) &&\n typeof segment.id === \"string\" &&\n typeof segment.start === \"number\" &&\n typeof segment.end === \"number\" &&\n typeof segment.text === \"string\" &&\n (segment.speaker === undefined ||\n typeof segment.speaker === \"string\"),\n )))\n );\n case \"image\":\n case \"audio\":\n case \"video\":\n case \"file\":\n return isPlainRecord(part.source);\n case \"embedding\":\n return (\n Array.isArray(part.embedding) &&\n part.embedding.every((value) => typeof value === \"number\")\n );\n default:\n return false;\n }\n};\n\nconst isReplayInputItem = (item: unknown): item is GenerativeModelInputItem => {\n if (!isPlainRecord(item) || typeof item.type !== \"string\") {\n return false;\n }\n\n if (item.type === \"message\") {\n if (item.role !== undefined && typeof item.role !== \"string\") {\n return false;\n }\n\n if (typeof item.content === \"string\") {\n return true;\n }\n\n return Array.isArray(item.content) && item.content.every(isReplayInputPart);\n }\n\n if (item.type === \"tool-call\") {\n return typeof item.name === \"string\" && typeof item.callId === \"string\" && \"result\" in item;\n }\n\n return (\n item.type === \"provider-tool-result\" &&\n typeof item.name === \"string\" &&\n typeof item.callId === \"string\" &&\n \"result\" in item\n );\n};\n\nconst validatePreparedReplayInput = (params: {\n input: unknown;\n caps: Capabilities;\n agentName: string;\n conversationId: string;\n}): GenerativeModelInputItem[] => {\n if (!Array.isArray(params.input) || !params.input.every(isReplayInputItem)) {\n throw BetterAgentError.fromCode(\n \"VALIDATION_FAILED\",\n \"conversationReplay.prepareInput must return a valid array of model input items.\",\n {\n context: {\n agentName: params.agentName,\n conversationId: params.conversationId,\n },\n trace: [{ at: \"core.run.prepareConversationReplayInput.validatePreparedInput\" }],\n },\n );\n }\n\n for (const item of params.input) {\n if (item.type !== \"message\") {\n continue;\n }\n\n if (params.caps.inputShape === \"prompt\") {\n if (\"role\" in item && item.role !== undefined) {\n throw BetterAgentError.fromCode(\n \"VALIDATION_FAILED\",\n \"conversationReplay.prepareInput returned a role-bearing message for a prompt-shaped model.\",\n {\n context: {\n agentName: params.agentName,\n conversationId: params.conversationId,\n },\n trace: [\n {\n at: \"core.run.prepareConversationReplayInput.validatePreparedInput.promptRole\",\n },\n ],\n },\n );\n }\n continue;\n }\n\n if (!(\"role\" in item) || typeof item.role !== \"string\") {\n throw BetterAgentError.fromCode(\n \"VALIDATION_FAILED\",\n \"conversationReplay.prepareInput returned a role-less message for a chat-shaped model.\",\n {\n context: {\n agentName: params.agentName,\n conversationId: params.conversationId,\n },\n trace: [\n {\n at: \"core.run.prepareConversationReplayInput.validatePreparedInput.chatRole\",\n },\n ],\n },\n );\n }\n }\n\n return params.input;\n};\n\n/**\n * Validates that run input only uses modalities supported by the target model.\n */\nexport function validateRunInputCapabilities(params: {\n agent: AgentModelInfo;\n input: GenerativeModelInput;\n traceAt: string;\n}): void {\n const caps = params.agent.model.caps;\n\n if (typeof params.input === \"string\") {\n if (caps.inputModalities?.text === false) {\n throwUnsupportedInputModality({\n agent: params.agent,\n modality: \"text\",\n location: \"input\",\n traceAt: params.traceAt,\n });\n }\n return;\n }\n\n for (const [itemIndex, item] of params.input.entries()) {\n if (item.type !== \"message\") {\n continue;\n }\n\n validateMessageContentCapabilities({\n agent: params.agent,\n content: item.content,\n itemIndex,\n traceAt: params.traceAt,\n });\n }\n}\n\n/**\n * Validates requested output modalities against the target model's capabilities.\n */\nexport function validateRunModalities(params: {\n agent: AgentModelInfo;\n modalities: readonly Modality[] | undefined;\n output: OutputSchemaDefinition | undefined;\n traceAt: string;\n}): void {\n if (!params.modalities || params.modalities.length === 0) {\n return;\n }\n\n const caps = params.agent.model.caps;\n\n for (const modality of params.modalities) {\n if (caps.outputModalities?.[modality] !== undefined) {\n continue;\n }\n\n throw BetterAgentError.fromCode(\n \"VALIDATION_FAILED\",\n `Agent '${params.agent.name}' model does not support ${modality} output.`,\n {\n context: {\n agentName: params.agent.name,\n modelId: params.agent.model.modelId,\n modality,\n },\n trace: [{ at: params.traceAt }],\n },\n );\n }\n\n if (params.output !== undefined && !params.modalities.includes(\"text\")) {\n throw BetterAgentError.fromCode(\n \"VALIDATION_FAILED\",\n `Structured output requires text output for agent '${params.agent.name}'.`,\n {\n context: {\n agentName: params.agent.name,\n modelId: params.agent.model.modelId,\n modalities: [...params.modalities],\n },\n trace: [{ at: params.traceAt }],\n },\n );\n }\n}\n\n/**\n * Prepares replayable model input from durable conversation items for a run.\n *\n * Stored history is projected losslessly first. The run can then override that\n * projection with `prepareInput`, or fall back to capability-based pruning.\n */\nexport function prepareConversationReplayInput(params: {\n items: ConversationItem[];\n caps: Capabilities;\n agentName: string;\n conversationId: string;\n conversationReplay?: ConversationReplayOptions;\n}): Awaitable<GenerativeModelInputItem[]> {\n const projected = projectConversationItemsToInput(params.items, params.caps);\n const replay = params.conversationReplay;\n\n if (typeof replay?.prepareInput === \"function\") {\n return Promise.resolve(\n replay.prepareInput({\n items: params.items,\n caps: params.caps,\n agentName: params.agentName,\n conversationId: params.conversationId,\n }),\n ).then((input) =>\n validatePreparedReplayInput({\n input,\n caps: params.caps,\n agentName: params.agentName,\n conversationId: params.conversationId,\n }),\n );\n }\n\n if (replay?.omitUnsupportedParts === false) {\n return projected;\n }\n\n return pruneInputByCapabilities(projected, params.caps);\n}\n\n/**\n * Converts a public output schema definition into a provider request.\n */\nexport function toStructuredOutputRequest(\n agent: Pick<AnyAgentDefinition, \"model\" | \"name\" | \"outputSchema\">,\n output: OutputSchemaDefinition | undefined,\n): StructuredOutput | undefined {\n if (output === undefined) {\n return undefined;\n }\n\n const modelCaps = agent.model.caps;\n if (!modelCaps.structured_output) {\n throw BetterAgentError.fromCode(\n \"NOT_IMPLEMENTED\",\n `Model '${agent.model.modelId}' does not support structured output.`,\n {\n context: {\n agentName: agent.name,\n modelId: agent.model.modelId,\n },\n trace: [{ at: \"core.run.toStructuredOutputRequest.capability\" }],\n },\n );\n }\n\n const preflightedSchema =\n output === agent.outputSchema ? getPreflightedOutputSchema(agent) : undefined;\n if (preflightedSchema !== undefined) {\n return {\n name: output.name ?? `${agent.name}_output`,\n schema: normalizeStructuredOutputJsonSchema(preflightedSchema),\n strict: output.strict,\n };\n }\n\n const runtimeResolvedSchema = resolveToJsonSchema(output.schema as never);\n if (runtimeResolvedSchema.isErr()) {\n throw runtimeResolvedSchema.error.at({\n at: \"core.run.toStructuredOutputRequest.resolveSchema\",\n });\n }\n\n return {\n name: output.name ?? `${agent.name}_output`,\n schema: normalizeStructuredOutputJsonSchema(runtimeResolvedSchema.value),\n strict: output.strict,\n };\n}\n\n/**\n * Parses and validates structured output from a provider response.\n *\n * Structured output currently requires text output.\n */\nexport async function finalizeRunResult(\n result: RunResult & { items: ConversationItem[] },\n output: OutputSchemaDefinition | undefined,\n options?: {\n outputErrorMode?: OutputErrorMode;\n onOutputError?: OnOutputError;\n },\n): Promise<RunResult & { items: ConversationItem[] }> {\n if (output === undefined) {\n return result;\n }\n\n const outputMessages = result.response.output.filter(\n (item): item is GenerativeModelOutputMessage => item.type === \"message\",\n );\n const resolvedOutputErrorMode = options?.outputErrorMode ?? \"throw\";\n\n const getLastStructuredText = () =>\n outputMessages\n .map((message) =>\n typeof message.content === \"string\"\n ? message.content\n : message.content\n .filter(\n (\n part,\n ): part is Extract<\n (typeof message.content)[number],\n { type: \"text\" }\n > => part.type === \"text\",\n )\n .map((part) => part.text)\n .join(\"\"),\n )\n .filter((text) => text.trim().length > 0)\n .at(-1);\n\n const defaultOutputErrorBehavior = (error: unknown): never => {\n throw error;\n };\n\n const validateStructuredValue = async (\n value: unknown,\n text: string,\n repairDepth: number,\n ): Promise<unknown> => {\n const validated = await validateInput(output.schema, value);\n if (validated.isErr()) {\n return await resolveOutputError(\n {\n errorKind: \"validation\",\n error: validated.error.at({ at: \"core.run.finalizeRunResult.validateSchema\" }),\n text,\n value,\n },\n repairDepth,\n );\n }\n\n return validated.value;\n };\n\n const parseStructuredText = async (text: string, repairDepth: number): Promise<unknown> => {\n const parsed = safeJsonParse(text);\n if (parsed.isErr()) {\n return await resolveOutputError(\n {\n errorKind: \"parse\",\n error: BetterAgentError.wrap({\n err: parsed.error,\n message:\n \"Structured output was requested, but the model returned invalid JSON.\",\n opts: {\n code: \"VALIDATION_FAILED\",\n context: {\n preview: text.slice(0, 200),\n },\n trace: [{ at: \"core.run.finalizeRunResult.parseJson\" }],\n },\n }),\n text,\n },\n repairDepth,\n );\n }\n\n return await validateStructuredValue(parsed.value, text, repairDepth);\n };\n\n const resolveOutputError = async (\n context: OutputErrorContext,\n repairDepth: number,\n ): Promise<unknown> => {\n if (resolvedOutputErrorMode === \"throw\" || repairDepth >= MAX_OUTPUT_REPAIR_DEPTH) {\n return defaultOutputErrorBehavior(context.error);\n }\n\n const action = await options?.onOutputError?.(context);\n\n switch (action?.action) {\n case \"repair_text\":\n return await parseStructuredText(action.text, repairDepth + 1);\n case \"repair_value\":\n return await validateStructuredValue(\n action.value,\n \"text\" in context ? context.text : \"\",\n repairDepth + 1,\n );\n case \"throw\":\n throw context.error;\n default:\n return defaultOutputErrorBehavior(context.error);\n }\n };\n\n const lastText = getLastStructuredText();\n if (!lastText) {\n const missingTextError = BetterAgentError.fromCode(\n \"VALIDATION_FAILED\",\n \"Structured output was requested, but the model did not return JSON text.\",\n {\n trace: [{ at: \"core.run.finalizeRunResult.noStructuredText\" }],\n },\n );\n\n const structured = await resolveOutputError(\n {\n errorKind: \"missing_text\",\n error: missingTextError,\n },\n 0,\n );\n\n return {\n ...result,\n structured,\n };\n }\n\n const structured = await parseStructuredText(lastText, 0);\n\n return {\n ...result,\n structured,\n };\n}\n\n/**\n * Shared id generator for runs and messages.\n */\nexport const generateId = createIdGenerator({\n prefixes: {\n run: \"run\",\n message: \"msg\",\n },\n});\n\n/**\n * Loads persisted conversation history and returns:\n * - `input`: the model-facing input for this run\n * - `items`: the durable conversation state to mutate and save\n * - `loaded`: the original persisted record for save concurrency\n * - `replayStartIndex`: where the current run's replay window starts in `items`\n *\n * `replayStartIndex` is `loaded.items.length` when older history should be kept in\n * durable state but excluded from per-step replay, otherwise it is `0`.\n */\nexport async function loadConversationMessages(params: {\n conversations?: ConversationStore;\n conversationId?: string;\n agentName?: string;\n input: GenerativeModelInput;\n caps?: Capabilities;\n replaceHistory?: boolean;\n conversationReplay?: ConversationReplayOptions;\n}): Promise<{\n input: GenerativeModelInput;\n items: ConversationItem[];\n replayStartIndex: number;\n conversationReplayActive: boolean;\n loaded?: LoadedConversation;\n}> {\n const inputItems = normalizeInputToMessages(\n params.input,\n params.caps ?? { inputShape: \"chat\" },\n );\n const durableInputItems = normalizeInputToConversationItems(\n params.input,\n params.caps ?? { inputShape: \"chat\" },\n );\n\n if (!params.conversations || params.conversationId === undefined) {\n return {\n input: params.input,\n items: durableInputItems,\n replayStartIndex: 0,\n conversationReplayActive: false,\n };\n }\n\n if (!params.agentName) {\n throw BetterAgentError.fromCode(\n \"INTERNAL\",\n \"agentName is required when loading conversation messages.\",\n {\n context: { conversationId: params.conversationId },\n trace: [{ at: \"core.run.loadConversationMessages.missingAgentName\" }],\n },\n );\n }\n\n const loaded = await params.conversations.load({\n conversationId: params.conversationId,\n agentName: params.agentName,\n });\n if (!loaded) {\n return {\n input: params.input,\n items: durableInputItems,\n replayStartIndex: 0,\n conversationReplayActive: false,\n };\n }\n\n validateStoredConversationItems(loaded.items, params.conversationId);\n\n if (params.replaceHistory) {\n return {\n input: params.input,\n items: durableInputItems,\n replayStartIndex: 0,\n conversationReplayActive: false,\n loaded,\n };\n }\n\n const caps = params.caps ?? { inputShape: \"chat\" };\n const replayMode =\n caps.replayMode ?? (caps.inputShape === \"prompt\" ? \"single_turn_persistent\" : \"multi_turn\");\n\n if (replayMode !== \"multi_turn\") {\n return {\n input: params.input,\n items: [...loaded.items, ...durableInputItems],\n replayStartIndex: loaded.items.length,\n conversationReplayActive: false,\n loaded,\n };\n }\n\n const loadedMessages = await prepareConversationReplayInput({\n items: loaded.items,\n caps,\n agentName: params.agentName,\n conversationId: params.conversationId,\n conversationReplay: params.conversationReplay,\n });\n\n return {\n input: [...loadedMessages, ...inputItems],\n items: [...loaded.items, ...durableInputItems],\n replayStartIndex: 0,\n conversationReplayActive: true,\n loaded,\n };\n}\n\n/**\n * Saves durable conversation items after a run completes.\n */\nexport async function saveConversationMessages(params: {\n conversations?: ConversationStore;\n conversationId?: string;\n agentName?: string;\n result: RunResult & { items: ConversationItem[] };\n loaded?: LoadedConversation;\n}): Promise<void> {\n if (!params.conversations || params.conversationId === undefined) {\n return;\n }\n\n if (!params.agentName) {\n throw BetterAgentError.fromCode(\n \"INTERNAL\",\n \"agentName is required when saving conversation messages.\",\n {\n context: { conversationId: params.conversationId },\n trace: [{ at: \"core.run.saveConversationMessages.missingAgentName\" }],\n },\n );\n }\n\n try {\n validateStoredConversationItems(params.result.items, params.conversationId);\n await params.conversations.save({\n conversationId: params.conversationId,\n agentName: params.agentName,\n items: params.result.items,\n ...(params.loaded?.cursor !== undefined\n ? { expectedCursor: params.loaded.cursor }\n : {}),\n });\n } catch (error) {\n throw BetterAgentError.wrap({\n err: error,\n message: \"Failed to save conversation messages.\",\n opts: {\n code:\n error instanceof BetterAgentError && error.code !== undefined\n ? error.code\n : typeof (error as { code?: unknown })?.code === \"string\"\n ? ((error as { code: string }).code as BetterAgentError[\"code\"])\n : \"INTERNAL\",\n ...(typeof (error as { status?: unknown })?.status === \"number\"\n ? { status: (error as { status: number }).status }\n : {}),\n context: {\n conversationId: params.conversationId,\n agentName: params.agentName,\n },\n trace: [{ at: \"core.run.saveConversationMessages\" }],\n },\n });\n }\n}\n"],"mappings":"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"}
|