@rowan-agent/agent 0.9.6 → 0.9.8
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 +6 -0
- package/dist/index.d.ts +621 -497
- package/dist/index.js +364 -65
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1052,6 +1052,178 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
|
|
|
1052
1052
|
};
|
|
1053
1053
|
}
|
|
1054
1054
|
|
|
1055
|
+
// src/runtime/json.ts
|
|
1056
|
+
function isPlainObject(value) {
|
|
1057
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1058
|
+
return prototype === Object.prototype || prototype === null;
|
|
1059
|
+
}
|
|
1060
|
+
function hasOnlyDataProperties(value) {
|
|
1061
|
+
return Reflect.ownKeys(value).every((key) => {
|
|
1062
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
1063
|
+
return Boolean(descriptor && "value" in descriptor);
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
function visit(value, seen) {
|
|
1067
|
+
if (value === null || typeof value === "boolean" || typeof value === "string") return true;
|
|
1068
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
1069
|
+
if (typeof value !== "object" || seen.has(value)) return false;
|
|
1070
|
+
seen.add(value);
|
|
1071
|
+
try {
|
|
1072
|
+
if (Array.isArray(value)) {
|
|
1073
|
+
if (Object.getPrototypeOf(value) !== Array.prototype || !hasOnlyDataProperties(value)) return false;
|
|
1074
|
+
if (Reflect.ownKeys(value).some((key) => key !== "length" && typeof key !== "string")) return false;
|
|
1075
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
1076
|
+
if (!Object.prototype.hasOwnProperty.call(value, index) || !visit(value[index], seen)) return false;
|
|
1077
|
+
}
|
|
1078
|
+
return true;
|
|
1079
|
+
}
|
|
1080
|
+
if (!isPlainObject(value) || !hasOnlyDataProperties(value)) return false;
|
|
1081
|
+
if (Reflect.ownKeys(value).some((key) => typeof key !== "string")) return false;
|
|
1082
|
+
if (Object.prototype.hasOwnProperty.call(value, "toJSON")) return false;
|
|
1083
|
+
return Object.keys(value).every((key) => visit(value[key], seen));
|
|
1084
|
+
} finally {
|
|
1085
|
+
seen.delete(value);
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
function isJsonValue(value) {
|
|
1089
|
+
return visit(value, /* @__PURE__ */ new Set());
|
|
1090
|
+
}
|
|
1091
|
+
function assertJsonValue(value, argument = "value") {
|
|
1092
|
+
if (!isJsonValue(value)) throw new TypeError(`${argument} must be JSON-safe`);
|
|
1093
|
+
}
|
|
1094
|
+
function canonicalJson(value) {
|
|
1095
|
+
assertJsonValue(value);
|
|
1096
|
+
const encode = (candidate) => {
|
|
1097
|
+
if (candidate === null || typeof candidate !== "object") return JSON.stringify(candidate);
|
|
1098
|
+
if (Array.isArray(candidate)) return `[${candidate.map(encode).join(",")}]`;
|
|
1099
|
+
const object = candidate;
|
|
1100
|
+
return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${encode(object[key])}`).join(",")}}`;
|
|
1101
|
+
};
|
|
1102
|
+
return encode(value);
|
|
1103
|
+
}
|
|
1104
|
+
function utf8ByteLength(value) {
|
|
1105
|
+
return new TextEncoder().encode(value).byteLength;
|
|
1106
|
+
}
|
|
1107
|
+
function assertUtf8ByteLimit(value, limit, argument = "value") {
|
|
1108
|
+
if (utf8ByteLength(value) > limit) throw new RangeError(`${argument} exceeds ${limit} UTF-8 bytes`);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// src/harness/phases/interactions.ts
|
|
1112
|
+
var PhaseInteractionCancelledError = class extends Error {
|
|
1113
|
+
code = "phase_interaction_cancelled";
|
|
1114
|
+
constructor() {
|
|
1115
|
+
super("Phase interaction work was cancelled.");
|
|
1116
|
+
this.name = "PhaseInteractionCancelledError";
|
|
1117
|
+
}
|
|
1118
|
+
};
|
|
1119
|
+
var PhaseInteractionBoundary = class extends Error {
|
|
1120
|
+
constructor(state, interactions) {
|
|
1121
|
+
super("Phase interactions require host input.");
|
|
1122
|
+
this.state = state;
|
|
1123
|
+
this.interactions = interactions;
|
|
1124
|
+
this.name = "PhaseInteractionBoundary";
|
|
1125
|
+
}
|
|
1126
|
+
state;
|
|
1127
|
+
interactions;
|
|
1128
|
+
};
|
|
1129
|
+
function createPhaseInteractionDriver(state, phase, signal) {
|
|
1130
|
+
const stored = state.phaseInteractions;
|
|
1131
|
+
const requests = new Map(
|
|
1132
|
+
stored?.requests.map((request) => [request.id, { ...request }]) ?? []
|
|
1133
|
+
);
|
|
1134
|
+
const answers = new Map(Object.entries(stored?.answers ?? {}));
|
|
1135
|
+
const usedRequestIds = /* @__PURE__ */ new Set();
|
|
1136
|
+
let checkpoint = stored?.checkpoint;
|
|
1137
|
+
const snapshot = () => ({
|
|
1138
|
+
requests: [...requests.values()].map((request) => ({
|
|
1139
|
+
...request,
|
|
1140
|
+
status: answers.has(request.id) ? "answered" : request.status
|
|
1141
|
+
})),
|
|
1142
|
+
answers: Object.fromEntries(answers),
|
|
1143
|
+
...checkpoint === void 0 ? {} : { checkpoint }
|
|
1144
|
+
});
|
|
1145
|
+
const sync = () => {
|
|
1146
|
+
state.phaseInteractions = snapshot();
|
|
1147
|
+
};
|
|
1148
|
+
const assertActive = () => {
|
|
1149
|
+
if (signal?.aborted) throw new PhaseInteractionCancelledError();
|
|
1150
|
+
};
|
|
1151
|
+
const matchingStoredRequest = (input) => {
|
|
1152
|
+
const fingerprint = interactionFingerprint(input);
|
|
1153
|
+
return [...requests.values()].find((request) => !usedRequestIds.has(request.id) && interactionFingerprint(request) === fingerprint);
|
|
1154
|
+
};
|
|
1155
|
+
return {
|
|
1156
|
+
signal: signal ?? new AbortController().signal,
|
|
1157
|
+
request(input) {
|
|
1158
|
+
assertActive();
|
|
1159
|
+
if (input.id !== void 0 && input.id.trim().length === 0) {
|
|
1160
|
+
throw new TypeError("Phase interaction id must be non-empty.");
|
|
1161
|
+
}
|
|
1162
|
+
if (input.prompt.trim().length === 0) {
|
|
1163
|
+
throw new TypeError("Phase interaction prompt must be non-empty.");
|
|
1164
|
+
}
|
|
1165
|
+
if (!PHASE_INTERACTION_KINDS.includes(input.kind)) {
|
|
1166
|
+
throw new TypeError(`Unsupported Phase interaction kind: ${String(input.kind)}.`);
|
|
1167
|
+
}
|
|
1168
|
+
if (input.payload !== void 0) assertJsonValue(input.payload, "Phase interaction payload");
|
|
1169
|
+
const matched = input.id === void 0 ? matchingStoredRequest(input) : void 0;
|
|
1170
|
+
const id = input.id ?? matched?.id ?? createId("interaction");
|
|
1171
|
+
const existing = requests.get(id);
|
|
1172
|
+
if (existing) {
|
|
1173
|
+
if (interactionFingerprint(existing) !== interactionFingerprint(input)) {
|
|
1174
|
+
throw new Error(`Phase interaction ${id} was requested with different metadata.`);
|
|
1175
|
+
}
|
|
1176
|
+
usedRequestIds.add(id);
|
|
1177
|
+
return {
|
|
1178
|
+
...existing,
|
|
1179
|
+
status: answers.has(id) ? "answered" : existing.status
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
const request = {
|
|
1183
|
+
id,
|
|
1184
|
+
phase,
|
|
1185
|
+
kind: input.kind,
|
|
1186
|
+
prompt: input.prompt,
|
|
1187
|
+
...input.payload === void 0 ? {} : { payload: input.payload },
|
|
1188
|
+
createdAt: createTimestamp(),
|
|
1189
|
+
status: "pending"
|
|
1190
|
+
};
|
|
1191
|
+
requests.set(id, request);
|
|
1192
|
+
usedRequestIds.add(id);
|
|
1193
|
+
sync();
|
|
1194
|
+
return request;
|
|
1195
|
+
},
|
|
1196
|
+
pending() {
|
|
1197
|
+
return [...requests.values()].filter((request) => request.status === "pending" && !answers.has(request.id)).map((request) => ({ ...request, status: "pending" }));
|
|
1198
|
+
},
|
|
1199
|
+
answers() {
|
|
1200
|
+
return new Map(answers);
|
|
1201
|
+
},
|
|
1202
|
+
suspend(input = {}) {
|
|
1203
|
+
assertActive();
|
|
1204
|
+
const pending = this.pending();
|
|
1205
|
+
if (pending.length === 0) throw new Error("Cannot suspend without pending Phase interactions.");
|
|
1206
|
+
if (input.checkpoint !== void 0) checkpoint = input.checkpoint;
|
|
1207
|
+
state.status = "suspended";
|
|
1208
|
+
sync();
|
|
1209
|
+
throw new PhaseInteractionBoundary(state, pending);
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
var PHASE_INTERACTION_KINDS = [
|
|
1214
|
+
"user_input",
|
|
1215
|
+
"permission",
|
|
1216
|
+
"elicitation",
|
|
1217
|
+
"confirmation"
|
|
1218
|
+
];
|
|
1219
|
+
function interactionFingerprint(value) {
|
|
1220
|
+
return canonicalJson({
|
|
1221
|
+
kind: value.kind,
|
|
1222
|
+
prompt: value.prompt,
|
|
1223
|
+
payload: value.payload ?? null
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1055
1227
|
// src/harness/phases/loader.ts
|
|
1056
1228
|
import { existsSync as existsSync2, statSync as statSync2 } from "fs";
|
|
1057
1229
|
import { readdir as readdir2 } from "fs/promises";
|
|
@@ -1648,6 +1820,7 @@ function buildModelRequest(input, options) {
|
|
|
1648
1820
|
}));
|
|
1649
1821
|
return {
|
|
1650
1822
|
model: options?.model ?? { provider: "", id: "" },
|
|
1823
|
+
...options?.thinkingLevel === void 0 ? {} : { thinkingLevel: options.thinkingLevel },
|
|
1651
1824
|
system: systemText,
|
|
1652
1825
|
messages,
|
|
1653
1826
|
tools: modelTools.length > 0 ? modelTools : void 0
|
|
@@ -2538,7 +2711,9 @@ async function executeToolCalls(input) {
|
|
|
2538
2711
|
return results;
|
|
2539
2712
|
}
|
|
2540
2713
|
function createPhaseExecution(config, state, phase, messageManager, toolExecutionManager, registry) {
|
|
2714
|
+
const interaction = createPhaseInteractionDriver(state, phase.name, config.signal);
|
|
2541
2715
|
return {
|
|
2716
|
+
interaction,
|
|
2542
2717
|
snapshot() {
|
|
2543
2718
|
return {
|
|
2544
2719
|
systemPrompt: config.context.systemPrompt,
|
|
@@ -2566,7 +2741,10 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
|
|
|
2566
2741
|
skills: phaseContext.skills,
|
|
2567
2742
|
promptGuidelines: phaseContext.promptGuidelines,
|
|
2568
2743
|
appendSystemPrompt: phaseContext.appendSystemPrompt
|
|
2569
|
-
}, {
|
|
2744
|
+
}, {
|
|
2745
|
+
model: phase.model ?? config.model,
|
|
2746
|
+
...config.thinkingLevel === void 0 ? {} : { thinkingLevel: config.thinkingLevel }
|
|
2747
|
+
});
|
|
2570
2748
|
if (!request.tools) {
|
|
2571
2749
|
if (phaseContext.tools.length > 0) {
|
|
2572
2750
|
request.tools = phaseContext.tools.map((t) => ({
|
|
@@ -2705,62 +2883,6 @@ async function waitForBackgroundTasks(backgroundTasks) {
|
|
|
2705
2883
|
return successful;
|
|
2706
2884
|
}
|
|
2707
2885
|
|
|
2708
|
-
// src/runtime/json.ts
|
|
2709
|
-
function isPlainObject(value) {
|
|
2710
|
-
const prototype = Object.getPrototypeOf(value);
|
|
2711
|
-
return prototype === Object.prototype || prototype === null;
|
|
2712
|
-
}
|
|
2713
|
-
function hasOnlyDataProperties(value) {
|
|
2714
|
-
return Reflect.ownKeys(value).every((key) => {
|
|
2715
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
2716
|
-
return Boolean(descriptor && "value" in descriptor);
|
|
2717
|
-
});
|
|
2718
|
-
}
|
|
2719
|
-
function visit(value, seen) {
|
|
2720
|
-
if (value === null || typeof value === "boolean" || typeof value === "string") return true;
|
|
2721
|
-
if (typeof value === "number") return Number.isFinite(value);
|
|
2722
|
-
if (typeof value !== "object" || seen.has(value)) return false;
|
|
2723
|
-
seen.add(value);
|
|
2724
|
-
try {
|
|
2725
|
-
if (Array.isArray(value)) {
|
|
2726
|
-
if (Object.getPrototypeOf(value) !== Array.prototype || !hasOnlyDataProperties(value)) return false;
|
|
2727
|
-
if (Reflect.ownKeys(value).some((key) => key !== "length" && typeof key !== "string")) return false;
|
|
2728
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
2729
|
-
if (!Object.prototype.hasOwnProperty.call(value, index) || !visit(value[index], seen)) return false;
|
|
2730
|
-
}
|
|
2731
|
-
return true;
|
|
2732
|
-
}
|
|
2733
|
-
if (!isPlainObject(value) || !hasOnlyDataProperties(value)) return false;
|
|
2734
|
-
if (Reflect.ownKeys(value).some((key) => typeof key !== "string")) return false;
|
|
2735
|
-
if (Object.prototype.hasOwnProperty.call(value, "toJSON")) return false;
|
|
2736
|
-
return Object.keys(value).every((key) => visit(value[key], seen));
|
|
2737
|
-
} finally {
|
|
2738
|
-
seen.delete(value);
|
|
2739
|
-
}
|
|
2740
|
-
}
|
|
2741
|
-
function isJsonValue(value) {
|
|
2742
|
-
return visit(value, /* @__PURE__ */ new Set());
|
|
2743
|
-
}
|
|
2744
|
-
function assertJsonValue(value, argument = "value") {
|
|
2745
|
-
if (!isJsonValue(value)) throw new TypeError(`${argument} must be JSON-safe`);
|
|
2746
|
-
}
|
|
2747
|
-
function canonicalJson(value) {
|
|
2748
|
-
assertJsonValue(value);
|
|
2749
|
-
const encode = (candidate) => {
|
|
2750
|
-
if (candidate === null || typeof candidate !== "object") return JSON.stringify(candidate);
|
|
2751
|
-
if (Array.isArray(candidate)) return `[${candidate.map(encode).join(",")}]`;
|
|
2752
|
-
const object = candidate;
|
|
2753
|
-
return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${encode(object[key])}`).join(",")}}`;
|
|
2754
|
-
};
|
|
2755
|
-
return encode(value);
|
|
2756
|
-
}
|
|
2757
|
-
function utf8ByteLength(value) {
|
|
2758
|
-
return new TextEncoder().encode(value).byteLength;
|
|
2759
|
-
}
|
|
2760
|
-
function assertUtf8ByteLimit(value, limit, argument = "value") {
|
|
2761
|
-
if (utf8ByteLength(value) > limit) throw new RangeError(`${argument} exceeds ${limit} UTF-8 bytes`);
|
|
2762
|
-
}
|
|
2763
|
-
|
|
2764
2886
|
// src/runtime/execution.ts
|
|
2765
2887
|
var EXECUTION_CHECKPOINT_CODEC = "rowan.agent.execution";
|
|
2766
2888
|
var EXECUTION_CHECKPOINT_VERSION = 1;
|
|
@@ -2809,7 +2931,8 @@ function encodeExecutionCheckpoint(state) {
|
|
|
2809
2931
|
currentPhase: state.currentPhase,
|
|
2810
2932
|
attempt: state.attempt,
|
|
2811
2933
|
metrics,
|
|
2812
|
-
...continuation ? { continuation } : {}
|
|
2934
|
+
...continuation ? { continuation } : {},
|
|
2935
|
+
...state.phaseInteractions === void 0 ? {} : { phaseInteractions: state.phaseInteractions }
|
|
2813
2936
|
};
|
|
2814
2937
|
assertJsonValue(data, "execution checkpoint");
|
|
2815
2938
|
return {
|
|
@@ -2840,6 +2963,13 @@ function decodeExecutionCheckpoint(checkpoint) {
|
|
|
2840
2963
|
...checkpoint.data.continuation,
|
|
2841
2964
|
previousResults: checkpoint.data.continuation.previousResults.map((result) => ({ ...result }))
|
|
2842
2965
|
}
|
|
2966
|
+
} : {},
|
|
2967
|
+
...checkpoint.data.phaseInteractions ? {
|
|
2968
|
+
phaseInteractions: {
|
|
2969
|
+
requests: checkpoint.data.phaseInteractions.requests.map((request) => ({ ...request })),
|
|
2970
|
+
answers: { ...checkpoint.data.phaseInteractions.answers },
|
|
2971
|
+
...checkpoint.data.phaseInteractions.checkpoint === void 0 ? {} : { checkpoint: checkpoint.data.phaseInteractions.checkpoint }
|
|
2972
|
+
}
|
|
2843
2973
|
} : {}
|
|
2844
2974
|
};
|
|
2845
2975
|
}
|
|
@@ -2865,10 +2995,21 @@ async function executeOnce(input) {
|
|
|
2865
2995
|
status: "running",
|
|
2866
2996
|
metrics: createMetrics()
|
|
2867
2997
|
};
|
|
2998
|
+
if (input.interactionAnswers) {
|
|
2999
|
+
state.phaseInteractions = {
|
|
3000
|
+
requests: state.phaseInteractions?.requests ?? [],
|
|
3001
|
+
answers: {
|
|
3002
|
+
...state.phaseInteractions?.answers ?? {},
|
|
3003
|
+
...input.interactionAnswers
|
|
3004
|
+
},
|
|
3005
|
+
...state.phaseInteractions?.checkpoint === void 0 ? {} : { checkpoint: state.phaseInteractions.checkpoint }
|
|
3006
|
+
};
|
|
3007
|
+
}
|
|
2868
3008
|
const config = {
|
|
2869
3009
|
context,
|
|
2870
3010
|
execution: input.execution,
|
|
2871
3011
|
model: input.model,
|
|
3012
|
+
...input.thinkingLevel === void 0 ? {} : { thinkingLevel: input.thinkingLevel },
|
|
2872
3013
|
stream: input.stream,
|
|
2873
3014
|
maxAttempts: input.maxAttempts,
|
|
2874
3015
|
signal: input.signal,
|
|
@@ -2899,6 +3040,20 @@ async function executeOnce(input) {
|
|
|
2899
3040
|
return {
|
|
2900
3041
|
type: "input_required",
|
|
2901
3042
|
request: error.request,
|
|
3043
|
+
interactions: [],
|
|
3044
|
+
checkpoint: encodeExecutionCheckpoint(error.state),
|
|
3045
|
+
messages: snapshotMessages(context.messages)
|
|
3046
|
+
};
|
|
3047
|
+
}
|
|
3048
|
+
if (error instanceof PhaseInteractionBoundary) {
|
|
3049
|
+
return {
|
|
3050
|
+
type: "input_required",
|
|
3051
|
+
request: {
|
|
3052
|
+
phase: error.interactions[0]?.phase ?? state.currentPhase,
|
|
3053
|
+
prompt: error.interactions.map((interaction) => interaction.prompt).join("\n"),
|
|
3054
|
+
requestedAt: error.interactions[0]?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
3055
|
+
},
|
|
3056
|
+
interactions: error.interactions,
|
|
2902
3057
|
checkpoint: encodeExecutionCheckpoint(error.state),
|
|
2903
3058
|
messages: snapshotMessages(context.messages)
|
|
2904
3059
|
};
|
|
@@ -2928,8 +3083,15 @@ function isCheckpointData(value) {
|
|
|
2928
3083
|
if (!isRecord2(value) || typeof value.currentPhase !== "string" || !Number.isInteger(value.attempt)) return false;
|
|
2929
3084
|
if (!isMetrics(value.metrics)) return false;
|
|
2930
3085
|
if (value.continuation !== void 0 && !isContinuation(value.continuation)) return false;
|
|
3086
|
+
if (value.phaseInteractions !== void 0 && !isPhaseInteractionState(value.phaseInteractions)) return false;
|
|
2931
3087
|
return true;
|
|
2932
3088
|
}
|
|
3089
|
+
function isPhaseInteractionState(value) {
|
|
3090
|
+
if (!isRecord2(value) || !Array.isArray(value.requests) || !isRecord2(value.answers)) return false;
|
|
3091
|
+
if (!Object.values(value.answers).every((answer) => isJsonValue(answer))) return false;
|
|
3092
|
+
if (value.checkpoint !== void 0 && !isJsonValue(value.checkpoint)) return false;
|
|
3093
|
+
return value.requests.every((request) => isRecord2(request) && typeof request.id === "string" && typeof request.phase === "string" && ["user_input", "permission", "elicitation", "confirmation"].includes(request.kind) && typeof request.prompt === "string" && typeof request.createdAt === "string" && ["pending", "answered", "denied", "cancelled", "expired"].includes(request.status) && (request.payload === void 0 || isJsonValue(request.payload)));
|
|
3094
|
+
}
|
|
2933
3095
|
function isMetrics(value) {
|
|
2934
3096
|
if (!isRecord2(value)) return false;
|
|
2935
3097
|
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));
|
|
@@ -2941,6 +3103,33 @@ function isContinuation(value) {
|
|
|
2941
3103
|
}
|
|
2942
3104
|
|
|
2943
3105
|
// src/runtime/contracts.ts
|
|
3106
|
+
var THINKING_LEVELS = [
|
|
3107
|
+
"off",
|
|
3108
|
+
"minimal",
|
|
3109
|
+
"low",
|
|
3110
|
+
"medium",
|
|
3111
|
+
"high",
|
|
3112
|
+
"xhigh",
|
|
3113
|
+
"max"
|
|
3114
|
+
];
|
|
3115
|
+
function thinkingLevelFromMetadata(metadata) {
|
|
3116
|
+
const record = isRecord3(metadata) ? metadata : void 0;
|
|
3117
|
+
const everyield = record?.everyield;
|
|
3118
|
+
if (!isRecord3(everyield)) return void 0;
|
|
3119
|
+
const level = everyield.thinkingLevel;
|
|
3120
|
+
return typeof level === "string" && THINKING_LEVELS.includes(level) ? level : void 0;
|
|
3121
|
+
}
|
|
3122
|
+
function thinkingLevelFromMessages(messages) {
|
|
3123
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
3124
|
+
const message = messages[index];
|
|
3125
|
+
if (message?.role !== "user") continue;
|
|
3126
|
+
const metadata = message.metadata;
|
|
3127
|
+
const kind = isRecord3(metadata) && typeof metadata.kind === "string" ? metadata.kind : void 0;
|
|
3128
|
+
if (kind === "phase_prompt" || kind === "phase_input") continue;
|
|
3129
|
+
return thinkingLevelFromMetadata(metadata);
|
|
3130
|
+
}
|
|
3131
|
+
return void 0;
|
|
3132
|
+
}
|
|
2944
3133
|
function isAgentConfiguration(config) {
|
|
2945
3134
|
return !("resources" in config);
|
|
2946
3135
|
}
|
|
@@ -5380,6 +5569,15 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
5380
5569
|
await this.owned.answerInput({ runId, requestId: input.requestId, expectedRevision: snapshot.revision, input: input.input });
|
|
5381
5570
|
void this.pump();
|
|
5382
5571
|
}
|
|
5572
|
+
async respondInteraction(runId, input) {
|
|
5573
|
+
this.assertOpen();
|
|
5574
|
+
const snapshot = await this.owned.snapshotRun(runId);
|
|
5575
|
+
if (snapshot.state !== "input_required" || !snapshot.interactions.some((interaction) => interaction.id === input.interactionId)) {
|
|
5576
|
+
throw new RuntimeError("input_request_conflict", { runId, requestId: input.interactionId, reason: "not_found" });
|
|
5577
|
+
}
|
|
5578
|
+
await this.owned.answerInteraction({ runId, interactionId: input.interactionId, expectedRevision: snapshot.revision, input: input.input });
|
|
5579
|
+
void this.pump();
|
|
5580
|
+
}
|
|
5383
5581
|
async cancel(runId, reason) {
|
|
5384
5582
|
this.assertOpen();
|
|
5385
5583
|
const done = this.executionDone.get(runId);
|
|
@@ -5505,9 +5703,11 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
5505
5703
|
...run.metadata === void 0 ? {} : { runMetadata: run.metadata }
|
|
5506
5704
|
},
|
|
5507
5705
|
model,
|
|
5706
|
+
thinkingLevel: thinkingLevelFromMessages(executionContext.messages),
|
|
5508
5707
|
stream,
|
|
5509
5708
|
maxAttempts: config.maxAttempts,
|
|
5510
5709
|
checkpoint: claim.run.checkpoint,
|
|
5710
|
+
interactionAnswers: claim.run.interactionAnswers,
|
|
5511
5711
|
signal: controller.signal,
|
|
5512
5712
|
beforePhase: assembly.beforePhase,
|
|
5513
5713
|
afterPhase: assembly.afterPhase,
|
|
@@ -5577,7 +5777,17 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
5577
5777
|
}
|
|
5578
5778
|
if (result.type === "input_required") {
|
|
5579
5779
|
const prompt = promptMessage(run, result.request.prompt, result.messages.length);
|
|
5580
|
-
await this.owned.commitInputRequired({
|
|
5780
|
+
await this.owned.commitInputRequired({
|
|
5781
|
+
runId: run.id,
|
|
5782
|
+
execution: claim.execution,
|
|
5783
|
+
expectedRevision: executionRevision,
|
|
5784
|
+
requestId: createId("input"),
|
|
5785
|
+
phase: result.request.phase,
|
|
5786
|
+
prompt,
|
|
5787
|
+
checkpoint: result.checkpoint,
|
|
5788
|
+
interactions: result.interactions,
|
|
5789
|
+
interactionAnswers: claim.run.interactionAnswers
|
|
5790
|
+
});
|
|
5581
5791
|
this.transientEvents.clear(run.id, claim.execution.executionId);
|
|
5582
5792
|
return;
|
|
5583
5793
|
}
|
|
@@ -5840,6 +6050,9 @@ var DurableRun = class {
|
|
|
5840
6050
|
respond(input) {
|
|
5841
6051
|
return this.runtime.respond(this.id, input);
|
|
5842
6052
|
}
|
|
6053
|
+
respondInteraction(input) {
|
|
6054
|
+
return this.runtime.respondInteraction(this.id, input);
|
|
6055
|
+
}
|
|
5843
6056
|
cancel(reason) {
|
|
5844
6057
|
return this.runtime.cancel(this.id, reason);
|
|
5845
6058
|
}
|
|
@@ -5866,7 +6079,14 @@ function durableOutcome(outcome) {
|
|
|
5866
6079
|
function boundaryFromSnapshot(snapshot) {
|
|
5867
6080
|
switch (snapshot.state) {
|
|
5868
6081
|
case "input_required":
|
|
5869
|
-
return {
|
|
6082
|
+
return {
|
|
6083
|
+
type: "input_required",
|
|
6084
|
+
requestId: snapshot.request.id,
|
|
6085
|
+
phase: snapshot.request.phase,
|
|
6086
|
+
prompt: snapshot.request.prompt,
|
|
6087
|
+
interactions: snapshot.interactions,
|
|
6088
|
+
answers: snapshot.answers
|
|
6089
|
+
};
|
|
5870
6090
|
case "completed":
|
|
5871
6091
|
return { type: "completed", outcome: snapshot.outcome, ...snapshot.output ? { output: snapshot.output } : {} };
|
|
5872
6092
|
case "failed":
|
|
@@ -6362,7 +6582,8 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6362
6582
|
if (typeof input.phase !== "string" || input.phase.length === 0) throw new TypeError("phase must be non-empty");
|
|
6363
6583
|
const requestId = input.requestId ?? createId("input");
|
|
6364
6584
|
const operationKey = `input_required:${requestId}`;
|
|
6365
|
-
const
|
|
6585
|
+
const interactions = input.interactions ?? [];
|
|
6586
|
+
const operationPayload = canonicalJson([input.runId, input.expectedRevision, input.phase, input.prompt.id, input.checkpoint, interactions, input.interactionAnswers ?? null]);
|
|
6366
6587
|
const replay = this.replayOperation(operationKey, operationPayload);
|
|
6367
6588
|
if (replay) return clone(replay);
|
|
6368
6589
|
const run = this.requireRun(input.runId);
|
|
@@ -6383,12 +6604,19 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6383
6604
|
run.state = "input_required";
|
|
6384
6605
|
run.checkpoint = clone(input.checkpoint);
|
|
6385
6606
|
run.openInputRequest = request;
|
|
6607
|
+
if (interactions.length > 0) {
|
|
6608
|
+
run.openInteractions = clone(interactions);
|
|
6609
|
+
run.interactionAnswers = clone(input.interactionAnswers ?? run.interactionAnswers ?? {});
|
|
6610
|
+
} else {
|
|
6611
|
+
delete run.openInteractions;
|
|
6612
|
+
delete run.interactionAnswers;
|
|
6613
|
+
}
|
|
6386
6614
|
delete run.execution;
|
|
6387
6615
|
run.revision += 1;
|
|
6388
6616
|
run.updatedAt = createTimestamp();
|
|
6389
6617
|
this.appendMessage(run, prompt);
|
|
6390
|
-
this.appendTransition(run, "running", "input_required", request, prompt);
|
|
6391
|
-
const result = { run: clone(run), prompt: clone(prompt), request: clone(request) };
|
|
6618
|
+
this.appendTransition(run, "running", "input_required", request, prompt, void 0, void 0, void 0, interactions, run.interactionAnswers ?? {});
|
|
6619
|
+
const result = { run: clone(run), prompt: clone(prompt), request: clone(request), interactions: clone(interactions) };
|
|
6392
6620
|
this.writeOperationReceipt(operationKey, operationPayload, result);
|
|
6393
6621
|
return result;
|
|
6394
6622
|
}
|
|
@@ -6405,6 +6633,9 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6405
6633
|
if (!run.openInputRequest || run.openInputRequest.id !== input.requestId) {
|
|
6406
6634
|
throw new RuntimeError("input_request_conflict", { runId: run.id, requestId: input.requestId, reason: "not_found" });
|
|
6407
6635
|
}
|
|
6636
|
+
if (run.openInteractions && run.openInteractions.length > 0) {
|
|
6637
|
+
throw new RuntimeError("input_request_conflict", { runId: run.id, requestId: input.requestId, reason: "not_found" });
|
|
6638
|
+
}
|
|
6408
6639
|
const message = {
|
|
6409
6640
|
id: input.messageId ?? createId("msg"),
|
|
6410
6641
|
agentId: run.agentId,
|
|
@@ -6427,6 +6658,50 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6427
6658
|
this.writeOperationReceipt(operationKey, operationPayload, result);
|
|
6428
6659
|
return result;
|
|
6429
6660
|
}
|
|
6661
|
+
answerInteraction(lease, input) {
|
|
6662
|
+
this.assertOwner(lease);
|
|
6663
|
+
if (input.interactionId.trim().length === 0) throw new TypeError("interactionId must be non-empty");
|
|
6664
|
+
const operationKey = `interaction_answer:${input.runId}:${input.interactionId}`;
|
|
6665
|
+
const operationPayload = canonicalJson(input.input);
|
|
6666
|
+
const replay = this.replayOperation(operationKey, operationPayload);
|
|
6667
|
+
if (replay) return clone(replay);
|
|
6668
|
+
const run = this.requireRun(input.runId);
|
|
6669
|
+
this.assertRevision(run, input.expectedRevision);
|
|
6670
|
+
this.assertState(run, ["input_required"]);
|
|
6671
|
+
const openInteractions = run.openInteractions ?? [];
|
|
6672
|
+
if (!openInteractions.some((interaction) => interaction.id === input.interactionId)) {
|
|
6673
|
+
throw new RuntimeError("input_request_conflict", { runId: run.id, requestId: input.interactionId, reason: "not_found" });
|
|
6674
|
+
}
|
|
6675
|
+
const message = {
|
|
6676
|
+
id: createId("msg"),
|
|
6677
|
+
agentId: run.agentId,
|
|
6678
|
+
runId: run.id,
|
|
6679
|
+
role: "user",
|
|
6680
|
+
content: typeof input.input === "string" ? input.input : JSON.stringify(input.input),
|
|
6681
|
+
metadata: { kind: "phase_interaction", interactionId: input.interactionId },
|
|
6682
|
+
sequenceWithinRun: this.nextMessageSequence(run.id),
|
|
6683
|
+
createdAt: createTimestamp()
|
|
6684
|
+
};
|
|
6685
|
+
this.messages.set(message.id, message);
|
|
6686
|
+
run.openInteractions = openInteractions.filter((interaction) => interaction.id !== input.interactionId);
|
|
6687
|
+
run.interactionAnswers = {
|
|
6688
|
+
...run.interactionAnswers ?? {},
|
|
6689
|
+
[input.interactionId]: clone(input.input)
|
|
6690
|
+
};
|
|
6691
|
+
run.revision += 1;
|
|
6692
|
+
run.updatedAt = message.createdAt;
|
|
6693
|
+
this.appendMessage(run, message);
|
|
6694
|
+
if (run.openInteractions.length === 0) {
|
|
6695
|
+
delete run.openInteractions;
|
|
6696
|
+
delete run.openInputRequest;
|
|
6697
|
+
run.readySequence = this.nextReady(run.agentId);
|
|
6698
|
+
run.state = "queued";
|
|
6699
|
+
this.appendTransition(run, "input_required", "queued");
|
|
6700
|
+
}
|
|
6701
|
+
const result = clone(run);
|
|
6702
|
+
this.writeOperationReceipt(operationKey, operationPayload, result);
|
|
6703
|
+
return result;
|
|
6704
|
+
}
|
|
6430
6705
|
reserveToolCall(lease, input) {
|
|
6431
6706
|
const providerToolCallId = input.providerToolCallId ?? (input.toolCallId ? String(input.toolCallId) : createId("provider"));
|
|
6432
6707
|
const result = this.reserveToolCalls(lease, {
|
|
@@ -6621,6 +6896,8 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6621
6896
|
if (input.outcome) run.outcome = clone(input.outcome);
|
|
6622
6897
|
if (input.failure) run.failure = clone(input.failure);
|
|
6623
6898
|
delete run.execution;
|
|
6899
|
+
delete run.openInteractions;
|
|
6900
|
+
delete run.interactionAnswers;
|
|
6624
6901
|
run.revision += 1;
|
|
6625
6902
|
run.updatedAt = createTimestamp();
|
|
6626
6903
|
this.appendTransition(run, "running", nextState, void 0, output, input.outcome, input.failure);
|
|
@@ -6666,6 +6943,8 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6666
6943
|
delete run.cancellationReason;
|
|
6667
6944
|
delete run.execution;
|
|
6668
6945
|
delete run.openInputRequest;
|
|
6946
|
+
delete run.openInteractions;
|
|
6947
|
+
delete run.interactionAnswers;
|
|
6669
6948
|
run.revision += 1;
|
|
6670
6949
|
run.updatedAt = createTimestamp();
|
|
6671
6950
|
this.appendTransition(run, from, "failed", void 0, void 0, void 0, failure);
|
|
@@ -6677,6 +6956,8 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6677
6956
|
run.cancellationReason = input.reason;
|
|
6678
6957
|
delete run.execution;
|
|
6679
6958
|
delete run.openInputRequest;
|
|
6959
|
+
delete run.openInteractions;
|
|
6960
|
+
delete run.interactionAnswers;
|
|
6680
6961
|
run.revision += 1;
|
|
6681
6962
|
run.updatedAt = createTimestamp();
|
|
6682
6963
|
this.appendTransition(run, from, "cancelled", void 0, void 0, void 0, void 0, input.reason);
|
|
@@ -6708,7 +6989,13 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6708
6989
|
const request = run.openInputRequest;
|
|
6709
6990
|
const prompt = request && this.messages.get(request.messageId);
|
|
6710
6991
|
if (!prompt || prompt.role !== "assistant") throw new Error(`Run ${run.id} has an invalid input prompt.`);
|
|
6711
|
-
return {
|
|
6992
|
+
return {
|
|
6993
|
+
...base,
|
|
6994
|
+
state: "input_required",
|
|
6995
|
+
request: { id: request.id, phase: request.phase, prompt: clone(prompt) },
|
|
6996
|
+
interactions: clone(run.openInteractions ?? []),
|
|
6997
|
+
answers: clone(run.interactionAnswers ?? {})
|
|
6998
|
+
};
|
|
6712
6999
|
}
|
|
6713
7000
|
case "completed": {
|
|
6714
7001
|
const output = this.messagesForRun(run.id).filter((message) => message.role === "assistant").at(-1);
|
|
@@ -6930,13 +7217,14 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
6930
7217
|
message
|
|
6931
7218
|
}));
|
|
6932
7219
|
}
|
|
6933
|
-
appendTransition(run, from, to, request, prompt, outcome, failure, reason) {
|
|
7220
|
+
appendTransition(run, from, to, request, prompt, outcome, failure, reason, interactions, answers) {
|
|
6934
7221
|
const transition = {
|
|
6935
7222
|
...this.baseEvent(run),
|
|
6936
7223
|
kind: "run_state_changed",
|
|
6937
7224
|
from,
|
|
6938
7225
|
to,
|
|
6939
7226
|
...to === "input_required" && request && prompt ? { request: { id: request.id, phase: request.phase, prompt } } : {},
|
|
7227
|
+
...to === "input_required" ? { interactions: clone(interactions ?? []), answers: clone(answers ?? {}) } : {},
|
|
6940
7228
|
...to === "completed" && outcome ? { outcome } : {},
|
|
6941
7229
|
...to === "failed" && failure ? { failure } : {},
|
|
6942
7230
|
...to === "cancelled" && reason ? { reason } : {}
|
|
@@ -7014,6 +7302,9 @@ var MemoryOwnedStore = class {
|
|
|
7014
7302
|
async answerInput(input) {
|
|
7015
7303
|
return this.store.answerInput(this.lease, input);
|
|
7016
7304
|
}
|
|
7305
|
+
async answerInteraction(input) {
|
|
7306
|
+
return this.store.answerInteraction(this.lease, input);
|
|
7307
|
+
}
|
|
7017
7308
|
async commitOutcome(input) {
|
|
7018
7309
|
return this.store.commitOutcome(this.lease, input);
|
|
7019
7310
|
}
|
|
@@ -7315,6 +7606,9 @@ var SqliteStore = class {
|
|
|
7315
7606
|
async answerInput(lease, input) {
|
|
7316
7607
|
return this.invoke(lease, (store, current) => store.answerInput(current, input));
|
|
7317
7608
|
}
|
|
7609
|
+
async answerInteraction(lease, input) {
|
|
7610
|
+
return this.invoke(lease, (store, current) => store.answerInteraction(current, input));
|
|
7611
|
+
}
|
|
7318
7612
|
async commitOutcome(lease, input) {
|
|
7319
7613
|
return this.invoke(lease, (store, current) => store.commitOutcome(current, input));
|
|
7320
7614
|
}
|
|
@@ -7632,6 +7926,9 @@ var SqliteOwnedStore = class {
|
|
|
7632
7926
|
answerInput(input) {
|
|
7633
7927
|
return this.store.answerInput(this.lease, input);
|
|
7634
7928
|
}
|
|
7929
|
+
answerInteraction(input) {
|
|
7930
|
+
return this.store.answerInteraction(this.lease, input);
|
|
7931
|
+
}
|
|
7635
7932
|
commitOutcome(input) {
|
|
7636
7933
|
return this.store.commitOutcome(this.lease, input);
|
|
7637
7934
|
}
|
|
@@ -7734,6 +8031,8 @@ export {
|
|
|
7734
8031
|
ExtensionLifetimeError,
|
|
7735
8032
|
InMemoryConfigProvider,
|
|
7736
8033
|
InMemoryStore,
|
|
8034
|
+
PhaseInteractionBoundary,
|
|
8035
|
+
PhaseInteractionCancelledError,
|
|
7737
8036
|
ResourceRegistry,
|
|
7738
8037
|
ResourceRegistryError,
|
|
7739
8038
|
RuntimeBootstrapRegistry,
|