@rowan-agent/agent 0.8.3 → 0.8.5
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 +12 -5
- package/dist/index.d.ts +31 -6
- package/dist/index.js +275 -78
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,8 +21,12 @@ const agentId = await runtime.createAgent({
|
|
|
21
21
|
identity: "example:v1", // Stable config snapshot identity, not the Agent ID
|
|
22
22
|
model: { provider: "openai", id: "gpt-4o" },
|
|
23
23
|
stream,
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
definition: {
|
|
25
|
+
name: "workspace-assistant",
|
|
26
|
+
description: "Assist with the current workspace.",
|
|
27
|
+
content: "You are helpful.",
|
|
28
|
+
},
|
|
29
|
+
resources: {
|
|
26
30
|
tools: createCoreTools({ root: process.cwd() }),
|
|
27
31
|
skills: [],
|
|
28
32
|
},
|
|
@@ -68,7 +72,8 @@ lifecycles, and Owner fencing.
|
|
|
68
72
|
|
|
69
73
|
## Tool lifecycle
|
|
70
74
|
|
|
71
|
-
Tools are supplied
|
|
75
|
+
Tools are supplied as `AgentConfig.resources.tools`, selected by the
|
|
76
|
+
Definition, and persist through:
|
|
72
77
|
|
|
73
78
|
`pending → running → completed | failed | indeterminate`
|
|
74
79
|
|
|
@@ -101,5 +106,7 @@ checkpoints; transient events never enter the Durable Store.
|
|
|
101
106
|
|
|
102
107
|
## Resources
|
|
103
108
|
|
|
104
|
-
`loadSkills()`, `loadPhases()`, and `loadExtensions()` load
|
|
105
|
-
Pass
|
|
109
|
+
`loadSkills()`, `loadPhases()`, and `loadExtensions()` load Resource Candidates.
|
|
110
|
+
Pass them through `AgentConfig.resources`; the Definition's optional name lists
|
|
111
|
+
select from them after Extension assembly. Omitted lists inherit all candidates,
|
|
112
|
+
`[]` selects none, and missing names warn and are skipped.
|
package/dist/index.d.ts
CHANGED
|
@@ -865,6 +865,20 @@ type ToolProgress = Readonly<{
|
|
|
865
865
|
}>;
|
|
866
866
|
type RunEvent = DurableRunEvent | MessageDelta | ToolProgress;
|
|
867
867
|
|
|
868
|
+
type AgentDefinition = Readonly<{
|
|
869
|
+
name: string;
|
|
870
|
+
description: string;
|
|
871
|
+
content: string;
|
|
872
|
+
tools?: readonly string[];
|
|
873
|
+
skills?: readonly string[];
|
|
874
|
+
phases?: readonly string[];
|
|
875
|
+
extensions?: readonly string[];
|
|
876
|
+
entryPhase?: string;
|
|
877
|
+
model?: ModelRef;
|
|
878
|
+
}>;
|
|
879
|
+
/** Parse one Markdown definition using the same frontmatter vocabulary as Phase resources. */
|
|
880
|
+
declare function parseAgentDefinition(raw: string): AgentDefinition;
|
|
881
|
+
|
|
868
882
|
type UserInput = string | Readonly<{
|
|
869
883
|
content: UserContent;
|
|
870
884
|
metadata?: Metadata;
|
|
@@ -903,17 +917,17 @@ type AfterToolCall = (input: Readonly<{
|
|
|
903
917
|
context: ToolInvocationContext;
|
|
904
918
|
signal: AbortSignal;
|
|
905
919
|
}>) => ToolExecutionResult | Promise<ToolExecutionResult>;
|
|
906
|
-
type
|
|
907
|
-
systemPrompt: string;
|
|
920
|
+
type AgentResources = Readonly<{
|
|
908
921
|
tools: readonly Tool[];
|
|
909
922
|
skills: readonly Skill[];
|
|
910
923
|
phases?: PhaseRegistry;
|
|
924
|
+
extensions?: readonly LoadedExtension[];
|
|
911
925
|
}>;
|
|
912
926
|
type AgentConfig = Readonly<{
|
|
913
927
|
identity: string;
|
|
914
|
-
|
|
928
|
+
definition: AgentDefinition;
|
|
929
|
+
resources: AgentResources;
|
|
915
930
|
cwd?: string;
|
|
916
|
-
extensions?: readonly LoadedExtension[];
|
|
917
931
|
maxAttempts?: number;
|
|
918
932
|
beforeToolCall?: BeforeToolCall;
|
|
919
933
|
afterToolCall?: AfterToolCall;
|
|
@@ -1391,7 +1405,7 @@ declare class InMemoryStore implements DurableStore {
|
|
|
1391
1405
|
ownerId: string;
|
|
1392
1406
|
leaseMs: number;
|
|
1393
1407
|
}): Promise<OwnedStore>;
|
|
1394
|
-
assertOwner(lease: OwnerLease): void;
|
|
1408
|
+
assertOwner(lease: OwnerLease, requireLive?: boolean): void;
|
|
1395
1409
|
renewOwner(lease: OwnerLease, leaseMs: number): OwnerLease;
|
|
1396
1410
|
releaseOwner(lease: OwnerLease): void;
|
|
1397
1411
|
reserveAgent(lease: OwnerLease, input: {
|
|
@@ -1806,6 +1820,17 @@ declare function loadExtensionsFromPath(path: string): Promise<{
|
|
|
1806
1820
|
}>;
|
|
1807
1821
|
}>;
|
|
1808
1822
|
|
|
1823
|
+
/** Parsed frontmatter result */
|
|
1824
|
+
interface FrontmatterResult<T = Record<string, unknown>> {
|
|
1825
|
+
frontmatter: T;
|
|
1826
|
+
body: string;
|
|
1827
|
+
}
|
|
1828
|
+
/**
|
|
1829
|
+
* Parse YAML frontmatter from markdown content.
|
|
1830
|
+
* Parse YAML frontmatter and return the markdown body after the closing delimiter.
|
|
1831
|
+
*/
|
|
1832
|
+
declare function parseFrontmatter<T = Record<string, unknown>>(raw: string): FrontmatterResult<T>;
|
|
1833
|
+
|
|
1809
1834
|
declare function createCoreTools(input?: CoreToolContext): Tool[];
|
|
1810
1835
|
|
|
1811
|
-
export { type AfterToolCall, type AgentConfig, type
|
|
1836
|
+
export { type AfterToolCall, type AgentConfig, type AgentDefinition, type AgentId, type AgentListCursor, type AgentRecord, type AgentResources, type AgentRun, AgentRuntime, type AgentRuntimeOptions, type AgentSummary, type AnyRuntimeError, type AssistantContent, type AssistantMessage, type BeforeToolCall, type ConfigProvider, type ConfigPutResult, type ConfigResolution, type ConfigToken, type CoreToolContext, type DurableConsumer, type DurableRunEvent, type DurableStore, type DurableToolResult, type EventCursor, type EventId, type ExecutionCheckpoint, type ExecutionId, type ExecutionToken, type ExtensionAPI, type ExtensionFactory, type FrontmatterResult, type HookEvent, type HookEventType, type HookHandler, InMemoryConfigProvider, InMemoryStore, type InputRequest, type InputRequestId, type InputRequiredCommit, type JsonObject, type JsonPrimitive, type JsonValue, type LoadExtensionsResult, type LoadedExtension, type Message, type MessageBase, type MessageCommitted, type MessageContent, type MessageDelta, type MessageId, type Metadata, type OpaqueId, type Outcome, type OwnerLease, type OwnerToken, type Page, type Phase, type PhaseContext, type PhaseExecutionIdentity, type PhaseInvocation, type PhaseOutput, type PhaseRegistry, type PhaseState, type RunBoundary, type RunClaim, type RunEvent, type RunFailure, type RunId, type RunListCursor, type RunRecord, type RunSnapshot, type RunState, type RunStateChanged, type RunSummary, RuntimeError, type RuntimeErrorCode, type RuntimeErrorDetails, type Skill, SqliteStore, type TextContent, type ThinkingContent, type Tool, type ToolCallId, type ToolCallSnapshot, type ToolCallState, type ToolDefinition, type ToolExecutionResult, type ToolInvocationContext, type ToolMessage, type ToolMessageContent, type ToolProgress, type ToolResultContent, type ToolStateChanged, type ToolUseContent, type UserContent, type UserInput, type UserMessage, brandConfigToken, createCoreTools, isRuntimeError, loadExtensionsFromPath as loadExtensions, loadPhases, loadSkills, parseAgentDefinition, parseFrontmatter };
|
package/dist/index.js
CHANGED
|
@@ -767,6 +767,15 @@ var EmptyResponseError = class extends Error {
|
|
|
767
767
|
this.name = "EmptyResponseError";
|
|
768
768
|
}
|
|
769
769
|
};
|
|
770
|
+
var ModelOutputLimitError = class extends Error {
|
|
771
|
+
constructor(limit) {
|
|
772
|
+
super(`Model output exceeded the ${limit}-character safety limit.`);
|
|
773
|
+
this.limit = limit;
|
|
774
|
+
this.name = "ModelOutputLimitError";
|
|
775
|
+
}
|
|
776
|
+
limit;
|
|
777
|
+
code = "model_output_limit";
|
|
778
|
+
};
|
|
770
779
|
var LoopGuard = {
|
|
771
780
|
/** Returns abort result if signal is aborted */
|
|
772
781
|
checkAbort(signal) {
|
|
@@ -778,6 +787,7 @@ var LoopGuard = {
|
|
|
778
787
|
};
|
|
779
788
|
|
|
780
789
|
// src/loop/stream-collector.ts
|
|
790
|
+
var MAX_STREAMED_OUTPUT_CHARACTERS = 1024 * 1024;
|
|
781
791
|
async function invokeModel(input) {
|
|
782
792
|
const events = input.config.stream(input.request, { signal: input.config.signal });
|
|
783
793
|
const result = await collectStreamResult({
|
|
@@ -811,7 +821,22 @@ async function collectStreamResult(input) {
|
|
|
811
821
|
let lastPartial;
|
|
812
822
|
let stopReason;
|
|
813
823
|
let doneResponse;
|
|
824
|
+
let streamedOutputCharacters = 0;
|
|
825
|
+
const toolCallsWithDeltas = /* @__PURE__ */ new Set();
|
|
814
826
|
for await (const event of input.events) {
|
|
827
|
+
if (event.type === "text_delta") {
|
|
828
|
+
streamedOutputCharacters += event.text.length;
|
|
829
|
+
} else if (event.type === "thinking_delta") {
|
|
830
|
+
streamedOutputCharacters += event.thinking.length;
|
|
831
|
+
} else if (event.type === "tool_call_delta") {
|
|
832
|
+
streamedOutputCharacters += event.arguments.length;
|
|
833
|
+
toolCallsWithDeltas.add(event.id);
|
|
834
|
+
} else if (event.type === "tool_call_end" && !toolCallsWithDeltas.has(event.id)) {
|
|
835
|
+
streamedOutputCharacters += event.arguments.length;
|
|
836
|
+
}
|
|
837
|
+
if (streamedOutputCharacters > MAX_STREAMED_OUTPUT_CHARACTERS) {
|
|
838
|
+
throw new ModelOutputLimitError(MAX_STREAMED_OUTPUT_CHARACTERS);
|
|
839
|
+
}
|
|
815
840
|
const abortResult2 = LoopGuard.checkAbort(input.config.signal);
|
|
816
841
|
if (abortResult2.stopReason !== "none") {
|
|
817
842
|
if (activeMessageId) {
|
|
@@ -990,7 +1015,92 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
|
|
|
990
1015
|
import { existsSync, statSync } from "fs";
|
|
991
1016
|
import { readdir } from "fs/promises";
|
|
992
1017
|
import { dirname as dirname3, join, resolve as resolve3 } from "path";
|
|
1018
|
+
|
|
1019
|
+
// src/harness/definitions.ts
|
|
993
1020
|
import { parseModelRef } from "@rowan-agent/models";
|
|
1021
|
+
function assertAgentDefinition(value) {
|
|
1022
|
+
if (!isRecord(value)) throw new TypeError("config.definition is invalid");
|
|
1023
|
+
requiredString(value.name, "definition.name");
|
|
1024
|
+
requiredString(value.description, "definition.description");
|
|
1025
|
+
requiredString(value.content, "definition.content");
|
|
1026
|
+
optionalStringList(value.tools, "definition.tools");
|
|
1027
|
+
optionalStringList(value.skills, "definition.skills");
|
|
1028
|
+
optionalStringList(value.phases, "definition.phases");
|
|
1029
|
+
optionalStringList(value.extensions, "definition.extensions");
|
|
1030
|
+
optionalString(value.entryPhase, "definition.entryPhase");
|
|
1031
|
+
if (value.model !== void 0) {
|
|
1032
|
+
if (!isRecord(value.model) || typeof value.model.provider !== "string" || value.model.provider.trim() === "" || typeof value.model.id !== "string" || value.model.id.trim() === "") {
|
|
1033
|
+
throw new TypeError("definition.model must be a valid model reference");
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
function parseAgentDefinition(raw) {
|
|
1038
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
1039
|
+
return normalizeAgentDefinition(frontmatter, body);
|
|
1040
|
+
}
|
|
1041
|
+
function normalizeAgentDefinition(frontmatter, content, options = {}) {
|
|
1042
|
+
const name = frontmatter.name === void 0 && options.fallbackName ? options.fallbackName : requiredString(frontmatter.name, "name");
|
|
1043
|
+
const description = requiredString(frontmatter.description, "description");
|
|
1044
|
+
const normalizedContent = requiredString(content, "content");
|
|
1045
|
+
const tools = optionalStringList(frontmatter.tools, "tools");
|
|
1046
|
+
const skills = optionalStringList(frontmatter.skills, "skills");
|
|
1047
|
+
const phases = optionalStringList(frontmatter.phases, "phases");
|
|
1048
|
+
const extensions = optionalStringList(frontmatter.extensions, "extensions");
|
|
1049
|
+
const entryPhase = optionalString(frontmatter.entryPhase, "entryPhase");
|
|
1050
|
+
const model = optionalModel(frontmatter.model);
|
|
1051
|
+
return {
|
|
1052
|
+
name,
|
|
1053
|
+
description,
|
|
1054
|
+
content: normalizedContent,
|
|
1055
|
+
...tools ? { tools } : {},
|
|
1056
|
+
...skills ? { skills } : {},
|
|
1057
|
+
...phases ? { phases } : {},
|
|
1058
|
+
...extensions ? { extensions } : {},
|
|
1059
|
+
...entryPhase ? { entryPhase } : {},
|
|
1060
|
+
...model ? { model } : {}
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
function requiredString(value, field) {
|
|
1064
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
1065
|
+
throw new TypeError(`${field} is required`);
|
|
1066
|
+
}
|
|
1067
|
+
return value.trim();
|
|
1068
|
+
}
|
|
1069
|
+
function optionalString(value, field) {
|
|
1070
|
+
if (value === void 0) return void 0;
|
|
1071
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
1072
|
+
throw new TypeError(`${field} must be a non-empty string`);
|
|
1073
|
+
}
|
|
1074
|
+
return value.trim();
|
|
1075
|
+
}
|
|
1076
|
+
function optionalStringList(value, field) {
|
|
1077
|
+
if (value === void 0) return void 0;
|
|
1078
|
+
if (!Array.isArray(value)) throw new TypeError(`${field} must be an array of strings`);
|
|
1079
|
+
const names = [];
|
|
1080
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1081
|
+
for (const [index, item] of value.entries()) {
|
|
1082
|
+
if (typeof item !== "string" || item.trim() === "") {
|
|
1083
|
+
throw new TypeError(`${field}[${index}] must be a non-empty string`);
|
|
1084
|
+
}
|
|
1085
|
+
const name = item.trim();
|
|
1086
|
+
if (seen.has(name)) continue;
|
|
1087
|
+
seen.add(name);
|
|
1088
|
+
names.push(name);
|
|
1089
|
+
}
|
|
1090
|
+
return names;
|
|
1091
|
+
}
|
|
1092
|
+
function optionalModel(value) {
|
|
1093
|
+
const source = optionalString(value, "model");
|
|
1094
|
+
if (!source) return void 0;
|
|
1095
|
+
const model = parseModelRef(source);
|
|
1096
|
+
if (!model || model.provider.trim() === "" || model.id.trim() === "") {
|
|
1097
|
+
throw new TypeError("model must be a valid model reference");
|
|
1098
|
+
}
|
|
1099
|
+
return model;
|
|
1100
|
+
}
|
|
1101
|
+
function isRecord(value) {
|
|
1102
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1103
|
+
}
|
|
994
1104
|
|
|
995
1105
|
// src/harness/resource-validation.ts
|
|
996
1106
|
var MAX_RESOURCE_ID_LENGTH = 64;
|
|
@@ -1088,8 +1198,16 @@ async function loadPhase(targetPath) {
|
|
|
1088
1198
|
const { frontmatter, body } = loaded;
|
|
1089
1199
|
const metadata = frontmatter;
|
|
1090
1200
|
const frontmatterName = typeof metadata.name === "string" ? metadata.name : void 0;
|
|
1091
|
-
|
|
1092
|
-
|
|
1201
|
+
let definition;
|
|
1202
|
+
try {
|
|
1203
|
+
definition = normalizeAgentDefinition(metadata, body, { fallbackName: directoryName });
|
|
1204
|
+
} catch (error) {
|
|
1205
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1206
|
+
warnResourceDiagnostics("phase", resolved, [message]);
|
|
1207
|
+
throw new ResourceMetadataError("invalid_metadata", message);
|
|
1208
|
+
}
|
|
1209
|
+
const name = definition.name;
|
|
1210
|
+
const description = validateDescription(definition.description);
|
|
1093
1211
|
const diagnostics = validateResourceId(directoryName);
|
|
1094
1212
|
if (frontmatterName && frontmatterName !== directoryName) {
|
|
1095
1213
|
diagnostics.push(...validateResourceName(frontmatterName, directoryName));
|
|
@@ -1098,22 +1216,19 @@ async function loadPhase(targetPath) {
|
|
|
1098
1216
|
diagnostics.push(...validateSkillReferences(metadata.skills));
|
|
1099
1217
|
diagnostics.push(...validatePhaseTarget(metadata.target));
|
|
1100
1218
|
warnResourceDiagnostics("phase", resolved, diagnostics);
|
|
1101
|
-
if (description.missing) {
|
|
1102
|
-
throw new ResourceMetadataError("invalid_metadata", "description is required");
|
|
1103
|
-
}
|
|
1104
1219
|
const baseDir = dirname3(resolved);
|
|
1105
1220
|
const phase = {
|
|
1106
1221
|
name,
|
|
1107
1222
|
description: description.description,
|
|
1108
|
-
tools:
|
|
1109
|
-
skills:
|
|
1223
|
+
tools: definition.tools ? [...definition.tools] : void 0,
|
|
1224
|
+
skills: definition.skills ? [...definition.skills] : void 0,
|
|
1110
1225
|
target: metadata.target,
|
|
1111
1226
|
input: metadata.input,
|
|
1112
1227
|
isolated: metadata.isolated,
|
|
1113
1228
|
filePath: resolved,
|
|
1114
1229
|
baseDir,
|
|
1115
|
-
content:
|
|
1116
|
-
model:
|
|
1230
|
+
content: definition.content,
|
|
1231
|
+
model: definition.model
|
|
1117
1232
|
};
|
|
1118
1233
|
const codePath = await discoverPhaseCode(baseDir);
|
|
1119
1234
|
if (codePath) {
|
|
@@ -1211,6 +1326,31 @@ function createDefaultPhase() {
|
|
|
1211
1326
|
};
|
|
1212
1327
|
}
|
|
1213
1328
|
|
|
1329
|
+
// src/harness/resource-selection.ts
|
|
1330
|
+
function selectNamedResources(candidates, names, kind) {
|
|
1331
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1332
|
+
for (const candidate of candidates) {
|
|
1333
|
+
if (byName.has(candidate.name)) {
|
|
1334
|
+
throw new TypeError(`Duplicate ${kind} candidate "${candidate.name}".`);
|
|
1335
|
+
}
|
|
1336
|
+
byName.set(candidate.name, candidate);
|
|
1337
|
+
}
|
|
1338
|
+
if (names === void 0) return [...candidates];
|
|
1339
|
+
const selected = [];
|
|
1340
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1341
|
+
for (const name of names) {
|
|
1342
|
+
if (seen.has(name)) continue;
|
|
1343
|
+
seen.add(name);
|
|
1344
|
+
const candidate = byName.get(name);
|
|
1345
|
+
if (!candidate) {
|
|
1346
|
+
console.warn(`${kind} "${name}" is not available and will be skipped.`);
|
|
1347
|
+
continue;
|
|
1348
|
+
}
|
|
1349
|
+
selected.push(candidate);
|
|
1350
|
+
}
|
|
1351
|
+
return selected;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1214
1354
|
// src/harness/context/system-prompt.ts
|
|
1215
1355
|
function buildSystemPrompt(options) {
|
|
1216
1356
|
const { systemPrompt, promptGuidelines, appendSystemPrompt, tools, skills } = options;
|
|
@@ -1738,8 +1878,8 @@ async function runPhaseLoop(config, state, registry) {
|
|
|
1738
1878
|
const messageManager = createMessageManager(config.context, config.onMessage, config.onMessageDelta);
|
|
1739
1879
|
const toolExecutionManager = createToolExecutionManager();
|
|
1740
1880
|
const execution = createPhaseExecution(config, state, phase, messageManager, toolExecutionManager, registry);
|
|
1741
|
-
const phaseTools =
|
|
1742
|
-
const phaseSkills =
|
|
1881
|
+
const phaseTools = selectPhaseTools(allTools, phase.tools);
|
|
1882
|
+
const phaseSkills = selectNamedResources(config.context.skills, phase.skills, "Skill");
|
|
1743
1883
|
let phaseContext = {
|
|
1744
1884
|
systemPrompt: config.context.systemPrompt,
|
|
1745
1885
|
messages: messageManager.visible(),
|
|
@@ -2229,8 +2369,8 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
|
|
|
2229
2369
|
async function executeParallelPhase(config, state, registry, phase, payload, context, availablePhases, instanceId, groupId, index, count, sourcePhaseId) {
|
|
2230
2370
|
const messages = [...context];
|
|
2231
2371
|
const allTools = buildToolsWithRouting(config, availablePhases);
|
|
2232
|
-
const phaseTools =
|
|
2233
|
-
const phaseSkills =
|
|
2372
|
+
const phaseTools = selectPhaseTools(allTools, phase.tools);
|
|
2373
|
+
const phaseSkills = selectNamedResources(config.context.skills, phase.skills, "Skill");
|
|
2234
2374
|
const systemPrompt = config.context.systemPrompt;
|
|
2235
2375
|
const phaseContext = {
|
|
2236
2376
|
systemPrompt,
|
|
@@ -2268,6 +2408,11 @@ async function executeParallelPhase(config, state, registry, phase, payload, con
|
|
|
2268
2408
|
const resultPayload = decision?.decision[0]?.payload !== void 0 ? normalizePayload(decision.decision[0].payload) : output.payload;
|
|
2269
2409
|
return { instanceId, phaseId: phase.name, payload: resultPayload, content: output.message };
|
|
2270
2410
|
}
|
|
2411
|
+
function selectPhaseTools(candidates, names) {
|
|
2412
|
+
const routing = candidates.filter(({ name }) => name === PhaseRouteTool);
|
|
2413
|
+
const ordinary = candidates.filter(({ name }) => name !== PhaseRouteTool);
|
|
2414
|
+
return [...selectNamedResources(ordinary, names, "Tool"), ...routing];
|
|
2415
|
+
}
|
|
2271
2416
|
async function waitForBackgroundTasks(backgroundTasks) {
|
|
2272
2417
|
const entries = Array.from(backgroundTasks.entries());
|
|
2273
2418
|
const results = await Promise.allSettled(entries.map(([, t]) => t.promise));
|
|
@@ -2498,29 +2643,29 @@ function createMetrics() {
|
|
|
2498
2643
|
startedAtMs: Date.now()
|
|
2499
2644
|
};
|
|
2500
2645
|
}
|
|
2501
|
-
function
|
|
2646
|
+
function isRecord2(value) {
|
|
2502
2647
|
return value !== null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
2503
2648
|
}
|
|
2504
2649
|
function isCheckpointData(value) {
|
|
2505
|
-
if (!
|
|
2650
|
+
if (!isRecord2(value) || typeof value.currentPhase !== "string" || !Number.isInteger(value.attempt)) return false;
|
|
2506
2651
|
if (!isMetrics(value.metrics)) return false;
|
|
2507
2652
|
if (value.continuation !== void 0 && !isContinuation(value.continuation)) return false;
|
|
2508
2653
|
return true;
|
|
2509
2654
|
}
|
|
2510
2655
|
function isMetrics(value) {
|
|
2511
|
-
if (!
|
|
2512
|
-
return Number.isInteger(value.iterations) && Array.isArray(value.phaseTransitions) && value.phaseTransitions.every((transition) =>
|
|
2656
|
+
if (!isRecord2(value)) return false;
|
|
2657
|
+
return Number.isInteger(value.iterations) && Array.isArray(value.phaseTransitions) && value.phaseTransitions.every((transition) => isRecord2(transition) && typeof transition.from === "string" && typeof transition.to === "string" && typeof transition.ts === "string") && Number.isInteger(value.compactionCount) && Number.isInteger(value.retryCount) && typeof value.startedAt === "string" && Number.isFinite(value.startedAtMs) && (value.endedAt === void 0 || typeof value.endedAt === "string") && (value.durationMs === void 0 || Number.isFinite(value.durationMs));
|
|
2513
2658
|
}
|
|
2514
2659
|
function isContinuation(value) {
|
|
2515
|
-
if (!
|
|
2660
|
+
if (!isRecord2(value) || typeof value.isContinuing !== "boolean" || !Array.isArray(value.previousResults)) return false;
|
|
2516
2661
|
if (value.previousPayload !== void 0 && !isJsonValue(value.previousPayload)) return false;
|
|
2517
|
-
return value.previousResults.every((result) =>
|
|
2662
|
+
return value.previousResults.every((result) => isRecord2(result) && typeof result.name === "string" && (result.output === void 0 || isJsonValue(result.output))) && (value.pendingInstruction === void 0 || typeof value.pendingInstruction === "string") && (value.previousPhaseMessageId === void 0 || typeof value.previousPhaseMessageId === "string");
|
|
2518
2663
|
}
|
|
2519
2664
|
|
|
2520
2665
|
// src/runtime/contracts.ts
|
|
2521
2666
|
var METADATA_LIMIT = 64 * 1024;
|
|
2522
2667
|
var IDENTITY_LIMIT = 256;
|
|
2523
|
-
function
|
|
2668
|
+
function isRecord3(value) {
|
|
2524
2669
|
if (value === null || typeof value !== "object") return false;
|
|
2525
2670
|
const prototype = Object.getPrototypeOf(value);
|
|
2526
2671
|
return prototype === Object.prototype || prototype === null;
|
|
@@ -2529,7 +2674,7 @@ function hasOnlyKeys(value, allowed) {
|
|
|
2529
2674
|
return Reflect.ownKeys(value).every((key) => typeof key === "string" && allowed.includes(key));
|
|
2530
2675
|
}
|
|
2531
2676
|
function isMetadata(value) {
|
|
2532
|
-
if (!
|
|
2677
|
+
if (!isRecord3(value) || !isJsonValue(value)) return false;
|
|
2533
2678
|
try {
|
|
2534
2679
|
assertUtf8ByteLimit(canonicalJson(value), METADATA_LIMIT, "metadata");
|
|
2535
2680
|
return true;
|
|
@@ -2541,23 +2686,23 @@ function assertMetadata(value, argument) {
|
|
|
2541
2686
|
if (!isMetadata(value)) throw new TypeError(`${argument} must be a JSON-safe metadata object`);
|
|
2542
2687
|
}
|
|
2543
2688
|
function isText(value) {
|
|
2544
|
-
return
|
|
2689
|
+
return isRecord3(value) && value.type === "text" && typeof value.text === "string";
|
|
2545
2690
|
}
|
|
2546
2691
|
function isImage(value) {
|
|
2547
|
-
return
|
|
2692
|
+
return isRecord3(value) && value.type === "image" && typeof value.data === "string" && typeof value.mimeType === "string";
|
|
2548
2693
|
}
|
|
2549
2694
|
function isUserContent(value) {
|
|
2550
2695
|
return typeof value === "string" || Array.isArray(value) && value.every((part) => isText(part) || isImage(part));
|
|
2551
2696
|
}
|
|
2552
2697
|
function normalizeUserInput(input) {
|
|
2553
2698
|
const normalized = typeof input === "string" ? { content: input } : input;
|
|
2554
|
-
if (!
|
|
2699
|
+
if (!isRecord3(normalized) || !hasOnlyKeys(normalized, ["content", "metadata"]) || !isUserContent(normalized.content)) throw new TypeError("input must contain only valid UserContent");
|
|
2555
2700
|
if (normalized.metadata !== void 0) assertMetadata(normalized.metadata, "input.metadata");
|
|
2556
2701
|
assertJsonValue(normalized, "input");
|
|
2557
2702
|
return normalized;
|
|
2558
2703
|
}
|
|
2559
2704
|
function isToolResult(value) {
|
|
2560
|
-
if (!
|
|
2705
|
+
if (!isRecord3(value) || !isJsonValue(value.content) || typeof value.ok !== "boolean") return false;
|
|
2561
2706
|
const expected = value.ok ? ["content", "ok"] : ["content", "error", "ok"];
|
|
2562
2707
|
if (JSON.stringify(Object.keys(value).sort()) !== JSON.stringify(expected)) return false;
|
|
2563
2708
|
return value.ok || typeof value.error === "string";
|
|
@@ -2565,8 +2710,11 @@ function isToolResult(value) {
|
|
|
2565
2710
|
function assertAgentConfig(config) {
|
|
2566
2711
|
if (typeof config.identity !== "string" || config.identity.length === 0) throw new TypeError("config.identity must be non-empty");
|
|
2567
2712
|
assertUtf8ByteLimit(config.identity, IDENTITY_LIMIT, "config.identity");
|
|
2568
|
-
|
|
2569
|
-
|
|
2713
|
+
assertAgentDefinition(config.definition);
|
|
2714
|
+
if (!config.resources || !Array.isArray(config.resources.tools) || !Array.isArray(config.resources.skills)) {
|
|
2715
|
+
throw new TypeError("config.resources is invalid");
|
|
2716
|
+
}
|
|
2717
|
+
for (const tool of config.resources.tools) projectToolDefinition(tool);
|
|
2570
2718
|
}
|
|
2571
2719
|
function assertToolExecutionResult(value) {
|
|
2572
2720
|
if (!isToolResult(value)) throw new TypeError("Tool result must be JSON-safe and contain no Runtime identity");
|
|
@@ -2574,7 +2722,7 @@ function assertToolExecutionResult(value) {
|
|
|
2574
2722
|
function projectToolDefinition(tool) {
|
|
2575
2723
|
if (typeof tool.name !== "string" || tool.name.length === 0 || typeof tool.description !== "string") throw new TypeError("Tool definition is invalid");
|
|
2576
2724
|
assertJsonValue(tool.parameters, "tool.parameters");
|
|
2577
|
-
if (!
|
|
2725
|
+
if (!isRecord3(tool.parameters)) throw new TypeError("tool.parameters must be a JSON object");
|
|
2578
2726
|
return { name: tool.name, description: tool.description, parameters: JSON.parse(canonicalJson(tool.parameters)) };
|
|
2579
2727
|
}
|
|
2580
2728
|
|
|
@@ -2641,7 +2789,7 @@ function brandConfigToken(raw) {
|
|
|
2641
2789
|
return raw;
|
|
2642
2790
|
}
|
|
2643
2791
|
function validateConfigResolution(agentId, value) {
|
|
2644
|
-
if (!
|
|
2792
|
+
if (!isRecord4(value) || typeof value.kind !== "string") {
|
|
2645
2793
|
throw new Error(`Config Provider returned an invalid resolution for Agent ${agentId}.`);
|
|
2646
2794
|
}
|
|
2647
2795
|
if (value.kind === "deferred") {
|
|
@@ -2654,18 +2802,26 @@ function validateConfigResolution(agentId, value) {
|
|
|
2654
2802
|
};
|
|
2655
2803
|
}
|
|
2656
2804
|
if (value.kind === "unavailable" && typeof value.reason === "string") return { kind: "unavailable", reason: value.reason };
|
|
2657
|
-
if (value.kind === "available" &&
|
|
2805
|
+
if (value.kind === "available" && isRecord4(value.config) && typeof value.config.identity === "string") {
|
|
2658
2806
|
return { kind: "available", config: value.config };
|
|
2659
2807
|
}
|
|
2660
2808
|
throw new Error(`Config Provider returned an invalid resolution for Agent ${agentId}.`);
|
|
2661
2809
|
}
|
|
2662
2810
|
function snapshotConfig(config) {
|
|
2663
|
-
const
|
|
2664
|
-
...config.
|
|
2665
|
-
tools: Object.freeze([...config.
|
|
2666
|
-
skills: Object.freeze([...config.
|
|
2811
|
+
const definition = Object.freeze({
|
|
2812
|
+
...config.definition,
|
|
2813
|
+
...config.definition.tools ? { tools: Object.freeze([...config.definition.tools]) } : {},
|
|
2814
|
+
...config.definition.skills ? { skills: Object.freeze([...config.definition.skills]) } : {},
|
|
2815
|
+
...config.definition.phases ? { phases: Object.freeze([...config.definition.phases]) } : {},
|
|
2816
|
+
...config.definition.extensions ? { extensions: Object.freeze([...config.definition.extensions]) } : {}
|
|
2817
|
+
});
|
|
2818
|
+
const resources = Object.freeze({
|
|
2819
|
+
...config.resources,
|
|
2820
|
+
tools: Object.freeze([...config.resources.tools]),
|
|
2821
|
+
skills: Object.freeze([...config.resources.skills]),
|
|
2822
|
+
...config.resources.extensions ? { extensions: Object.freeze([...config.resources.extensions]) } : {}
|
|
2667
2823
|
});
|
|
2668
|
-
return Object.freeze({ ...config,
|
|
2824
|
+
return Object.freeze({ ...config, definition, resources });
|
|
2669
2825
|
}
|
|
2670
2826
|
function assertConfigIdentity(identity) {
|
|
2671
2827
|
if (typeof identity !== "string" || identity.length === 0) throw new TypeError("config.identity must be non-empty");
|
|
@@ -2680,7 +2836,7 @@ function throwIfAborted(signal) {
|
|
|
2680
2836
|
error.name = "AbortError";
|
|
2681
2837
|
throw error;
|
|
2682
2838
|
}
|
|
2683
|
-
function
|
|
2839
|
+
function isRecord4(value) {
|
|
2684
2840
|
return value !== null && typeof value === "object";
|
|
2685
2841
|
}
|
|
2686
2842
|
|
|
@@ -3603,12 +3759,19 @@ function createExtensionRunner(options) {
|
|
|
3603
3759
|
|
|
3604
3760
|
// src/runtime/extensions.ts
|
|
3605
3761
|
async function assembleExtensions(config) {
|
|
3606
|
-
|
|
3762
|
+
const selectedExtensions = selectNamedResources(
|
|
3763
|
+
config.resources.extensions ?? [],
|
|
3764
|
+
config.definition.extensions,
|
|
3765
|
+
"Extension"
|
|
3766
|
+
);
|
|
3767
|
+
if (selectedExtensions.length === 0) {
|
|
3768
|
+
return { context: resolveDefinitionContext(config) };
|
|
3769
|
+
}
|
|
3607
3770
|
const runner = createExtensionRunner({ cwd: config.cwd });
|
|
3608
|
-
await runner.loadExtensions(
|
|
3771
|
+
await runner.loadExtensions(selectedExtensions);
|
|
3609
3772
|
runner.bind();
|
|
3610
3773
|
const extensionTools = runner.getAllRegisteredTools().map(adaptExtensionTool);
|
|
3611
|
-
const tools = [...config.
|
|
3774
|
+
const tools = [...config.resources.tools];
|
|
3612
3775
|
const names = new Set(tools.map((tool) => tool.name));
|
|
3613
3776
|
for (const tool of extensionTools) {
|
|
3614
3777
|
if (names.has(tool.name)) throw new TypeError(`Extension Tool collides with Context Tool "${tool.name}"`);
|
|
@@ -3616,9 +3779,10 @@ async function assembleExtensions(config) {
|
|
|
3616
3779
|
tools.push(tool);
|
|
3617
3780
|
}
|
|
3618
3781
|
const extensionPhases = runner.createPhaseRegistry({ entryPhaseId: null });
|
|
3619
|
-
const phases = mergePhases(config.
|
|
3782
|
+
const phases = mergePhases(config.resources.phases, extensionPhases);
|
|
3783
|
+
const context = resolveDefinitionContext(config, { tools, phases });
|
|
3620
3784
|
return {
|
|
3621
|
-
context
|
|
3785
|
+
context,
|
|
3622
3786
|
beforePhase: (phaseId, input) => runner.emitBeforePhase(phaseId, input),
|
|
3623
3787
|
afterPhase: (phaseId, output) => runner.emitAfterPhase(phaseId, output),
|
|
3624
3788
|
beforePrompt: (phaseId, input) => runner.emitBeforePrompt(phaseId, input),
|
|
@@ -3632,11 +3796,41 @@ async function assembleExtensions(config) {
|
|
|
3632
3796
|
const result = await runner.emitAfterToolCall(tool, toLoopResult(input.result, input.context.toolCallId, input.tool.name));
|
|
3633
3797
|
return fromLoopResult(result);
|
|
3634
3798
|
},
|
|
3635
|
-
setContext: (
|
|
3636
|
-
runner.currentContext =
|
|
3799
|
+
setContext: (context2) => {
|
|
3800
|
+
runner.currentContext = context2;
|
|
3637
3801
|
}
|
|
3638
3802
|
};
|
|
3639
3803
|
}
|
|
3804
|
+
function resolveDefinitionContext(config, assembled = {}) {
|
|
3805
|
+
const tools = selectNamedResources(
|
|
3806
|
+
assembled.tools ?? config.resources.tools,
|
|
3807
|
+
config.definition.tools,
|
|
3808
|
+
"Tool"
|
|
3809
|
+
);
|
|
3810
|
+
const skills = selectNamedResources(
|
|
3811
|
+
config.resources.skills,
|
|
3812
|
+
config.definition.skills,
|
|
3813
|
+
"Skill"
|
|
3814
|
+
);
|
|
3815
|
+
const candidateRegistry = assembled.phases ?? config.resources.phases;
|
|
3816
|
+
const selectedPhases = selectNamedResources(
|
|
3817
|
+
[...candidateRegistry?.phases.values() ?? []],
|
|
3818
|
+
config.definition.phases,
|
|
3819
|
+
"Phase"
|
|
3820
|
+
);
|
|
3821
|
+
const phases = new Map(selectedPhases.map((phase) => [phase.name, phase]));
|
|
3822
|
+
const requestedEntry = config.definition.entryPhase ?? candidateRegistry?.entryPhaseId ?? null;
|
|
3823
|
+
const entryPhaseId = requestedEntry === DEFAULT_PHASE_ID ? DEFAULT_PHASE_ID : requestedEntry && phases.has(requestedEntry) ? requestedEntry : null;
|
|
3824
|
+
if (requestedEntry && requestedEntry !== DEFAULT_PHASE_ID && !phases.has(requestedEntry)) {
|
|
3825
|
+
console.warn(`Phase entry "${requestedEntry}" is not available; Rowan will use "default".`);
|
|
3826
|
+
}
|
|
3827
|
+
return {
|
|
3828
|
+
systemPrompt: config.definition.content,
|
|
3829
|
+
tools,
|
|
3830
|
+
skills,
|
|
3831
|
+
phases: { phases, entryPhaseId }
|
|
3832
|
+
};
|
|
3833
|
+
}
|
|
3640
3834
|
function mergePhases(base, extension) {
|
|
3641
3835
|
if (!base && extension.phases.size === 0) return void 0;
|
|
3642
3836
|
const phases = new Map(base?.phases ?? []);
|
|
@@ -3985,29 +4179,28 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
3985
4179
|
}
|
|
3986
4180
|
const executionId = createId("exec");
|
|
3987
4181
|
claim = await this.owned.claimRun({ runId: run.id, expectedRevision: run.revision, executionId, configToken: token });
|
|
4182
|
+
executionRevision = claim.run.revision;
|
|
3988
4183
|
const controller = new AbortController();
|
|
3989
4184
|
this.executions.set(run.id, { controller, executionId });
|
|
3990
4185
|
const config = resolution.config;
|
|
3991
4186
|
const assembly = await assembleExtensions(config);
|
|
3992
|
-
const executionConfig = {
|
|
3993
|
-
...config,
|
|
3994
|
-
context: assembly.context,
|
|
3995
|
-
...assembly.beforeToolCall ? { beforeToolCall: assembly.beforeToolCall } : {},
|
|
3996
|
-
...assembly.afterToolCall ? { afterToolCall: assembly.afterToolCall } : {}
|
|
3997
|
-
};
|
|
3998
|
-
executionRevision = claim.run.revision;
|
|
3999
4187
|
let toolQueue = Promise.resolve();
|
|
4000
4188
|
const model = "stream" in config && config.stream ? config.model : { provider: config.model.provider, id: config.model.id };
|
|
4001
4189
|
const stream = "stream" in config && config.stream ? config.stream : createModelStream(config.model);
|
|
4002
4190
|
const executionContext = projectModelContext({
|
|
4003
4191
|
context: {
|
|
4004
|
-
...
|
|
4005
|
-
phases: normalizePhaseRegistry(
|
|
4192
|
+
...assembly.context,
|
|
4193
|
+
phases: normalizePhaseRegistry(assembly.context.phases)
|
|
4006
4194
|
},
|
|
4007
4195
|
messages: claim.history,
|
|
4008
4196
|
agentId: run.agentId,
|
|
4009
4197
|
runId: run.id
|
|
4010
4198
|
});
|
|
4199
|
+
const executionTools = {
|
|
4200
|
+
tools: assembly.context.tools,
|
|
4201
|
+
beforeToolCall: assembly.beforeToolCall ?? config.beforeToolCall,
|
|
4202
|
+
afterToolCall: assembly.afterToolCall ?? config.afterToolCall
|
|
4203
|
+
};
|
|
4011
4204
|
const result = await executeOnce({
|
|
4012
4205
|
canonicalMessages: executionContext.messages,
|
|
4013
4206
|
context: executionContext,
|
|
@@ -4018,7 +4211,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
4018
4211
|
},
|
|
4019
4212
|
model,
|
|
4020
4213
|
stream,
|
|
4021
|
-
maxAttempts:
|
|
4214
|
+
maxAttempts: config.maxAttempts,
|
|
4022
4215
|
checkpoint: claim.run.checkpoint,
|
|
4023
4216
|
signal: controller.signal,
|
|
4024
4217
|
beforePhase: assembly.beforePhase,
|
|
@@ -4045,7 +4238,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
4045
4238
|
run,
|
|
4046
4239
|
execution: claim.execution,
|
|
4047
4240
|
expectedRevision: executionRevision,
|
|
4048
|
-
|
|
4241
|
+
toolConfig: executionTools,
|
|
4049
4242
|
toolCalls: [toolCall],
|
|
4050
4243
|
signal: controller.signal
|
|
4051
4244
|
});
|
|
@@ -4061,7 +4254,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
4061
4254
|
run,
|
|
4062
4255
|
execution: claim.execution,
|
|
4063
4256
|
expectedRevision: executionRevision,
|
|
4064
|
-
|
|
4257
|
+
toolConfig: executionTools,
|
|
4065
4258
|
toolCalls,
|
|
4066
4259
|
signal: controller.signal
|
|
4067
4260
|
});
|
|
@@ -4140,7 +4333,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
4140
4333
|
return { results, revision };
|
|
4141
4334
|
}
|
|
4142
4335
|
async executeReservedTool(input) {
|
|
4143
|
-
const durableTool = input.
|
|
4336
|
+
const durableTool = input.toolConfig.tools.find((candidate) => candidate.name === input.toolCall.name);
|
|
4144
4337
|
const providerToolCallId = input.toolCall.id;
|
|
4145
4338
|
const toolCallId = input.tool.id;
|
|
4146
4339
|
let revision = input.expectedRevision;
|
|
@@ -4175,8 +4368,8 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
4175
4368
|
}
|
|
4176
4369
|
};
|
|
4177
4370
|
try {
|
|
4178
|
-
if (input.
|
|
4179
|
-
const decision = await input.
|
|
4371
|
+
if (input.toolConfig.beforeToolCall) {
|
|
4372
|
+
const decision = await input.toolConfig.beforeToolCall({ tool: durableTool, args: toJsonValue(input.toolCall.args), context, signal: input.signal });
|
|
4180
4373
|
if (!decision.allow) {
|
|
4181
4374
|
const failed = await this.owned.commitToolResult({ runId: input.run.id, execution: input.execution, expectedRevision: revision, toolCallId, state: "failed", result: { ok: false, content: null, error: decision.reason } });
|
|
4182
4375
|
return { result: protocolFailure(decision.reason), revision: failed.run.revision };
|
|
@@ -4193,7 +4386,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
4193
4386
|
try {
|
|
4194
4387
|
let result = await durableTool.execute(toJsonValue(input.toolCall.args), context, input.signal);
|
|
4195
4388
|
assertToolExecutionResult(result);
|
|
4196
|
-
if (input.
|
|
4389
|
+
if (input.toolConfig.afterToolCall) result = await input.toolConfig.afterToolCall({ tool: durableTool, result, context, signal: input.signal });
|
|
4197
4390
|
assertToolExecutionResult(result);
|
|
4198
4391
|
const committed = await this.owned.commitToolResult({ runId: input.run.id, execution: input.execution, expectedRevision: revision, toolCallId, state: result.ok ? "completed" : "failed", result });
|
|
4199
4392
|
return {
|
|
@@ -4495,17 +4688,17 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
4495
4688
|
};
|
|
4496
4689
|
return new MemoryOwnedStore(this, clone(this.owner));
|
|
4497
4690
|
}
|
|
4498
|
-
assertOwner(lease) {
|
|
4691
|
+
assertOwner(lease, requireLive = true) {
|
|
4499
4692
|
const actual = this.owner;
|
|
4500
4693
|
if (!actual || actual.token !== lease.token || actual.epoch !== lease.epoch || actual.ownerId !== lease.ownerId) {
|
|
4501
4694
|
throw ownershipLost(lease, actual, "epoch_advanced");
|
|
4502
4695
|
}
|
|
4503
|
-
if (Date.parse(actual.expiresAt) <= Date.now()) {
|
|
4696
|
+
if (requireLive && Date.parse(actual.expiresAt) <= Date.now()) {
|
|
4504
4697
|
throw ownershipLost(lease, actual, "expired");
|
|
4505
4698
|
}
|
|
4506
4699
|
}
|
|
4507
4700
|
renewOwner(lease, leaseMs) {
|
|
4508
|
-
this.assertOwner(lease);
|
|
4701
|
+
this.assertOwner(lease, false);
|
|
4509
4702
|
assertLeaseDuration(leaseMs);
|
|
4510
4703
|
this.owner.expiresAt = expiry(leaseMs);
|
|
4511
4704
|
return clone(this.owner);
|
|
@@ -4600,23 +4793,25 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
4600
4793
|
if ([...this.runs.values()].some((candidate) => candidate.agentId === run.agentId && candidate.id !== run.id && ["running", "input_required"].includes(candidate.state))) {
|
|
4601
4794
|
throw new RuntimeError("run_state_conflict", { runId: run.id, expected: ["queued"], actual: run.state });
|
|
4602
4795
|
}
|
|
4603
|
-
const messageId = input.messageId ?? createId("msg");
|
|
4604
4796
|
if (run.pinnedConfigToken && input.configToken && run.pinnedConfigToken !== input.configToken) {
|
|
4605
4797
|
throw new RuntimeError("run_state_conflict", { runId: run.id, expected: ["queued"], actual: run.state });
|
|
4606
4798
|
}
|
|
4607
4799
|
if (!run.pinnedConfigToken && input.configToken) run.pinnedConfigToken = input.configToken;
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4800
|
+
let message;
|
|
4801
|
+
if (!run.checkpoint) {
|
|
4802
|
+
const userInput = normalizeUserInput(run.input);
|
|
4803
|
+
message = {
|
|
4804
|
+
id: input.messageId ?? createId("msg"),
|
|
4805
|
+
agentId: run.agentId,
|
|
4806
|
+
runId: run.id,
|
|
4807
|
+
role: "user",
|
|
4808
|
+
content: userInputContent(userInput),
|
|
4809
|
+
...userInputMetadata(userInput) ? { metadata: clone(userInputMetadata(userInput)) } : {},
|
|
4810
|
+
sequenceWithinRun: this.nextMessageSequence(run.id),
|
|
4811
|
+
createdAt: createTimestamp()
|
|
4812
|
+
};
|
|
4813
|
+
this.messages.set(message.id, message);
|
|
4814
|
+
}
|
|
4620
4815
|
const execution = {
|
|
4621
4816
|
runId: run.id,
|
|
4622
4817
|
ownerEpoch: lease.epoch,
|
|
@@ -4626,7 +4821,7 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
4626
4821
|
run.execution = execution;
|
|
4627
4822
|
run.revision += 1;
|
|
4628
4823
|
run.updatedAt = createTimestamp();
|
|
4629
|
-
this.appendMessage(run, message);
|
|
4824
|
+
if (message) this.appendMessage(run, message);
|
|
4630
4825
|
this.appendTransition(run, "queued", "running");
|
|
4631
4826
|
const result = { run: clone(run), execution: clone(execution), history: this.history(run.agentId, run.agentSequence) };
|
|
4632
4827
|
this.writeOperationReceipt(operationKey, operationPayload, result);
|
|
@@ -5533,7 +5728,7 @@ var SqliteStore = class {
|
|
|
5533
5728
|
this.assertOpen();
|
|
5534
5729
|
assertOwnerInput(lease.ownerId, leaseMs);
|
|
5535
5730
|
return this.immediateTransaction(() => {
|
|
5536
|
-
const row = this.requireMatchingOwner(lease,
|
|
5731
|
+
const row = this.requireMatchingOwner(lease, false);
|
|
5537
5732
|
const expiresAt = Date.now() + leaseMs;
|
|
5538
5733
|
this.writeOwner({ ...row, expires_at: expiresAt });
|
|
5539
5734
|
return { ...lease, expiresAt: new Date(expiresAt).toISOString() };
|
|
@@ -6094,5 +6289,7 @@ export {
|
|
|
6094
6289
|
isRuntimeError,
|
|
6095
6290
|
loadExtensionsFromPath as loadExtensions,
|
|
6096
6291
|
loadPhases,
|
|
6097
|
-
loadSkills
|
|
6292
|
+
loadSkills,
|
|
6293
|
+
parseAgentDefinition,
|
|
6294
|
+
parseFrontmatter
|
|
6098
6295
|
};
|