@fevex/core 0.1.0-alpha.6 → 0.1.0-alpha.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 +47 -0
- package/dist/agents/index.d.mts +2 -2
- package/dist/artifacts/index.d.mts +1 -1
- package/dist/channels/index.d.mts +1 -1
- package/dist/evals/index.d.mts +4 -4
- package/dist/{fevex-B4QY5Z6e.d.mts → fevex-DB0-k1fb.d.mts} +14 -10
- package/dist/http/index.d.mts +4 -4
- package/dist/{index-CzAi2Y_Z.d.mts → index-B8molngu.d.mts} +92 -3
- package/dist/{index-BgKFd9yw.d.mts → index-BfYzemR8.d.mts} +1 -1
- package/dist/{index-CbACw6xZ.d.mts → index-Bl0hR7EC.d.mts} +2 -2
- package/dist/index-CAyAoOW0.d.mts +116 -0
- package/dist/{index-Df84VWmN.d.mts → index-CL7mu_x9.d.mts} +1 -1
- package/dist/{index-1cHr7KB_.d.mts → index-CODYPevS.d.mts} +3 -3
- package/dist/{index-CpLDt6Rw.d.mts → index-CecXoEbs.d.mts} +3 -3
- package/dist/{index-DVw0zOc_.d.mts → index-CuaetTLQ.d.mts} +3 -3
- package/dist/{index-5p3q2yIp.d.mts → index-DtMxzCqj.d.mts} +2 -2
- package/dist/{index-CseuTR-F.d.mts → index-RKE3-CKs.d.mts} +2 -2
- package/dist/index.d.mts +13 -13
- package/dist/index.mjs +311 -24
- package/dist/knowledge/index.d.mts +2 -2
- package/dist/knowledge/index.mjs +236 -36
- package/dist/models/index.d.mts +1 -1
- package/dist/observability/index.d.mts +1 -1
- package/dist/policies/index.d.mts +1 -1
- package/dist/runtime/index.d.mts +2 -2
- package/dist/runtime/index.mjs +105 -1
- package/dist/sandbox/index.d.mts +1 -1
- package/dist/teams/index.d.mts +1 -1
- package/dist/testing/index.d.mts +6 -6
- package/dist/tools/index.d.mts +2 -2
- package/dist/{types-B8laW1hM.d.mts → types-CckDlhYo.d.mts} +15 -1
- package/dist/workflows/index.d.mts +1 -1
- package/package.json +1 -1
- package/dist/index-BJktlD4E.d.mts +0 -70
package/dist/index.mjs
CHANGED
|
@@ -2,9 +2,9 @@ import { defineAgent } from "./agents/index.mjs";
|
|
|
2
2
|
import { a as CatalogedArtifactStore, c as assertArtifactId, i as FileSystemArtifactStore, n as InMemoryArtifactStore, o as ArtifactError, r as InMemoryArtifactCatalog, s as artifactTenantId, t as S3ArtifactStore } from "./artifacts-gUzemET7.mjs";
|
|
3
3
|
import { n as RunPausedError, t as FevexRunError } from "./run-error-Cr17wPGH.mjs";
|
|
4
4
|
import { ChannelError, deliverChannelRun, handleChannelInput } from "./channels/index.mjs";
|
|
5
|
-
import { InMemoryMemoryStore, createMemoryContextProvider, defineContextProvider, defineSkill } from "./knowledge/index.mjs";
|
|
5
|
+
import { InMemoryMemoryStore, createAgentsMdContextProvider, createMemoryContextProvider, defineContextProvider, defineSkill, isProgressiveSkillProvider, loadSkillFile, loadSkillFiles } from "./knowledge/index.mjs";
|
|
6
6
|
import { n as teamAsWorkflow, t as defineTeam } from "./teams-Ctz676G4.mjs";
|
|
7
|
-
import { InMemoryRunStore, isDurableRunStore, isRetainableRunStore, validateListEventsOptions, validatePurgeRunsOptions } from "./runtime/index.mjs";
|
|
7
|
+
import { InMemoryRunStore, createDigestContextCompactor, estimateContextTokens, isDurableRunStore, isRetainableRunStore, resolveContextBudget, validateListEventsOptions, validatePurgeRunsOptions } from "./runtime/index.mjs";
|
|
8
8
|
import { FEVEX_JSON_SCHEMA_PROFILE_VERSION, IntegrationError, compileFevexJsonSchema, defineConnection, defineTool, toToolSpec, validateFevexJsonSchemaProfile } from "./tools/index.mjs";
|
|
9
9
|
import { _ as serializeValue, a as assertTokenBudget, c as eventUsage, d as remainingDeadlineMs, f as remainingOutputTokens, g as serializeJsonValue, h as toErrorMessage, i as assertContinuationBudget, l as isTimeoutError, m as runSignal, n as abortable, o as cancellationReason, p as resumeDeadlineSignal, r as addUsage, s as deadlineAtFromMs, u as minDeadline, v as toJsonValue } from "./run-support-CmZ6Xo6H.mjs";
|
|
10
10
|
import { t as readModelStream } from "./model-stream-JQdHDDcj.mjs";
|
|
@@ -300,6 +300,16 @@ function createComposition(config) {
|
|
|
300
300
|
assertConfiguration(config.tools === void 0 || Array.isArray(config.tools), "INVALID_CONFIG", "Fevex config \"tools\" must be an array");
|
|
301
301
|
assertConfiguration(config.connections === void 0 || Array.isArray(config.connections), "INVALID_CONFIG", "Fevex config \"connections\" must be an array");
|
|
302
302
|
assertConfiguration(config.contextProviders === void 0 || Array.isArray(config.contextProviders), "INVALID_CONFIG", "Fevex config \"contextProviders\" must be an array");
|
|
303
|
+
if (config.contextBudget !== void 0) try {
|
|
304
|
+
resolveContextBudget(config.contextBudget, "Fevex config \"contextBudget\"");
|
|
305
|
+
} catch (error) {
|
|
306
|
+
throw configurationError("INVALID_CONFIG", error.message);
|
|
307
|
+
}
|
|
308
|
+
if (config.compaction !== void 0) {
|
|
309
|
+
assertConfiguration(typeof config.compaction === "object" && config.compaction !== null && !Array.isArray(config.compaction), "INVALID_CONFIG", "Fevex config \"compaction\" must be an object");
|
|
310
|
+
assertConfiguration(config.compaction.compactor === void 0 || isRecord(config.compaction.compactor) && typeof config.compaction.compactor.compact === "function", "INVALID_CONFIG", "Fevex config \"compaction.compactor\" must implement compact");
|
|
311
|
+
assertConfiguration(config.compaction.estimateTokens === void 0 || typeof config.compaction.estimateTokens === "function", "INVALID_CONFIG", "Fevex config \"compaction.estimateTokens\" must be a function");
|
|
312
|
+
}
|
|
303
313
|
assertConfiguration(config.memoryStore === void 0 || isMemoryStore(config.memoryStore), "INVALID_CONFIG", "Fevex config \"memoryStore\" must implement MemoryStore");
|
|
304
314
|
assertConfiguration(config.onEvent === void 0 || typeof config.onEvent === "function", "INVALID_CONFIG", "Fevex config \"onEvent\" must be a function");
|
|
305
315
|
assertConfiguration(config.runStore === void 0 || isRunStore(config.runStore), "INVALID_CONFIG", "Fevex config \"runStore\" must implement RunStore");
|
|
@@ -475,6 +485,11 @@ function createComposition(config) {
|
|
|
475
485
|
assertConfiguration(definition.approvalMode === void 0 || definition.approvalMode === "pause" || definition.approvalMode === "deny", "INVALID_AGENT", `Agent "${name}" approvalMode is invalid`);
|
|
476
486
|
assertConfiguration(definition.toolChoice === void 0 || definition.toolChoice === "auto" || definition.toolChoice === "required" || definition.toolChoice === "none" || isRecord(definition.toolChoice) && typeof definition.toolChoice.name === "string" && Boolean(definition.toolChoice.name.trim()), "INVALID_AGENT", `Agent "${name}" toolChoice is invalid`);
|
|
477
487
|
assertConfiguration(definition.limits === void 0 || isRecord(definition.limits), "INVALID_AGENT", `Agent "${name}" limits must be an object`);
|
|
488
|
+
if (definition.contextBudget !== void 0) try {
|
|
489
|
+
resolveContextBudget(definition.contextBudget, `Agent "${name}" contextBudget`);
|
|
490
|
+
} catch (error) {
|
|
491
|
+
throw configurationError("INVALID_AGENT", error.message);
|
|
492
|
+
}
|
|
478
493
|
if (definition.outputSchema !== void 0) assertConfiguration(isStandardSchema(definition.outputSchema), "INVALID_AGENT", `Output schema for agent "${name}" must implement Standard Schema`);
|
|
479
494
|
const rawLimits = definition.limits;
|
|
480
495
|
assertLimit(rawLimits?.maxSteps, "maxSteps", 1, name);
|
|
@@ -498,6 +513,7 @@ function createComposition(config) {
|
|
|
498
513
|
...definition.toolChoice === void 0 ? {} : { toolChoice: typeof definition.toolChoice === "string" ? definition.toolChoice : { name: definition.toolChoice.name } },
|
|
499
514
|
...definition.elicitation === void 0 ? {} : { elicitation: definition.elicitation },
|
|
500
515
|
...definition.approvalMode === void 0 ? {} : { approvalMode: definition.approvalMode },
|
|
516
|
+
...definition.contextBudget === void 0 ? {} : { contextBudget: { ...definition.contextBudget } },
|
|
501
517
|
...definition.inputSchema === void 0 ? {} : { inputSchema: definition.inputSchema },
|
|
502
518
|
...definition.outputSchema === void 0 ? {} : { outputSchema: definition.outputSchema },
|
|
503
519
|
...rawLimits === void 0 ? {} : { limits: {
|
|
@@ -621,6 +637,11 @@ function createComposition(config) {
|
|
|
621
637
|
teams,
|
|
622
638
|
tools,
|
|
623
639
|
contextProviders,
|
|
640
|
+
contextBudget: config.contextBudget === void 0 ? void 0 : { ...config.contextBudget },
|
|
641
|
+
compaction: {
|
|
642
|
+
compactor: config.compaction?.compactor ?? createDigestContextCompactor(),
|
|
643
|
+
estimateTokens: config.compaction?.estimateTokens ?? estimateContextTokens
|
|
644
|
+
},
|
|
624
645
|
memoryStore: config.memoryStore ?? (usesMemory ? new InMemoryMemoryStore() : void 0),
|
|
625
646
|
runStore: config.runStore ?? new InMemoryRunStore(),
|
|
626
647
|
credentialStore: config.credentialStore,
|
|
@@ -649,6 +670,8 @@ const LEASE_MS = 3e4;
|
|
|
649
670
|
const LEASE_RENEW_MS = 1e4;
|
|
650
671
|
/** Reserved name of the internal elicitation tool exposed to the model. */
|
|
651
672
|
const ELICIT_TOOL_NAME = "fevex__elicit";
|
|
673
|
+
/** Reserved name of the internal progressive skill loader exposed to the model. */
|
|
674
|
+
const LOAD_SKILL_TOOL_NAME = "fevex__load_skill";
|
|
652
675
|
//#endregion
|
|
653
676
|
//#region src/internal/run-helpers.ts
|
|
654
677
|
function redact(message, secrets) {
|
|
@@ -776,6 +799,103 @@ const runErrorPayload = (error) => {
|
|
|
776
799
|
};
|
|
777
800
|
};
|
|
778
801
|
//#endregion
|
|
802
|
+
//#region src/internal/context-compaction.ts
|
|
803
|
+
/** Maximum summary characters copied into the context.compacted event. */
|
|
804
|
+
const MAX_COMPACTION_EVENT_SUMMARY_CHARS = 4e3;
|
|
805
|
+
async function compactContext(input) {
|
|
806
|
+
const estimateWith = (messages, includeTools) => {
|
|
807
|
+
const value = input.estimateTokens({
|
|
808
|
+
messages,
|
|
809
|
+
...includeTools ? { tools: input.tools } : {}
|
|
810
|
+
});
|
|
811
|
+
if (!Number.isFinite(value) || value < 0) throw new TypeError("Context token estimator must return a non-negative finite number");
|
|
812
|
+
return Math.ceil(value * input.contextBudget.safetyFactor);
|
|
813
|
+
};
|
|
814
|
+
const estimate = (messages) => estimateWith(messages, true);
|
|
815
|
+
const estimated = estimate(input.messages);
|
|
816
|
+
const usable = input.contextBudget.contextWindow - input.contextBudget.reserveOutputTokens;
|
|
817
|
+
const threshold = Math.floor(usable * input.contextBudget.compactAt);
|
|
818
|
+
if (input.allowCompaction === false || estimated <= threshold) {
|
|
819
|
+
if (estimated > usable) throw new FevexRunError("CONTEXT_BUDGET_EXCEEDED", `Agent "${input.agentName}" context budget exceeded: ${estimated} tokens > ${usable} usable${input.allowCompaction === false ? " after compaction" : ""}.`, input.runId);
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
const split = splitContextForCompaction(input.messages);
|
|
823
|
+
if (split === void 0 || split.compactable.length === 0) {
|
|
824
|
+
if (estimated > usable) throw new FevexRunError("CONTEXT_BUDGET_EXCEEDED", `Agent "${input.agentName}" context budget exceeded: ${estimated} tokens > ${usable} usable. The preserved system prefix and current turn cannot be compacted further.`, input.runId);
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
const preservedTokens = estimate([...split.prefix, ...split.currentTurn]);
|
|
828
|
+
const available = Math.max(1, Math.min(input.contextBudget.targetTokens, usable - 1) - preservedTokens);
|
|
829
|
+
const compactedMessages = validateCompactedMessages(await abortable(() => input.compactor.compact({
|
|
830
|
+
agentName: input.agentName,
|
|
831
|
+
sessionId: input.sessionId,
|
|
832
|
+
messages: split.compactable,
|
|
833
|
+
tools: input.tools,
|
|
834
|
+
estimatedTokens: estimated,
|
|
835
|
+
targetTokens: available,
|
|
836
|
+
contextWindow: input.contextBudget.contextWindow,
|
|
837
|
+
step: input.step,
|
|
838
|
+
...input.context === void 0 ? {} : { context: input.context },
|
|
839
|
+
signal: input.signal,
|
|
840
|
+
estimateTokens: (messages) => estimateWith(messages, false)
|
|
841
|
+
}), input.signal));
|
|
842
|
+
const messages = [
|
|
843
|
+
...split.prefix,
|
|
844
|
+
...compactedMessages,
|
|
845
|
+
...split.currentTurn
|
|
846
|
+
];
|
|
847
|
+
const compactedTokens = estimate(messages);
|
|
848
|
+
if (compactedTokens > usable) throw new FevexRunError("CONTEXT_BUDGET_EXCEEDED", `Agent "${input.agentName}" context budget exceeded after compaction: ${compactedTokens} tokens > ${usable} usable. The preserved system prefix and current turn cannot be compacted further.`, input.runId);
|
|
849
|
+
return {
|
|
850
|
+
messages,
|
|
851
|
+
removedMessages: split.compactable.length,
|
|
852
|
+
estimatedTokens: estimated,
|
|
853
|
+
compactedTokens,
|
|
854
|
+
summary: compactedMessages.map((message) => message.content).join("\n\n")
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
function splitContextForCompaction(messages) {
|
|
858
|
+
let lastUser = -1;
|
|
859
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) if (messages[index].role === "user") {
|
|
860
|
+
lastUser = index;
|
|
861
|
+
break;
|
|
862
|
+
}
|
|
863
|
+
if (lastUser < 0) return void 0;
|
|
864
|
+
let lastToolBatch = -1;
|
|
865
|
+
for (let index = messages.length - 1; index > lastUser; index -= 1) {
|
|
866
|
+
const message = messages[index];
|
|
867
|
+
if (message.role === "assistant" && (message.toolCalls?.length ?? 0) > 0) {
|
|
868
|
+
lastToolBatch = index;
|
|
869
|
+
break;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
const prefix = messages.filter((message) => message.role === "system");
|
|
873
|
+
const currentTurn = (lastToolBatch === -1 ? messages.slice(lastUser) : [messages[lastUser], ...messages.slice(lastToolBatch)]).filter((message) => message.role !== "system");
|
|
874
|
+
const preserved = /* @__PURE__ */ new Set([...prefix, ...currentTurn]);
|
|
875
|
+
return {
|
|
876
|
+
prefix,
|
|
877
|
+
currentTurn,
|
|
878
|
+
compactable: messages.filter((message) => message.role !== "system" && !preserved.has(message))
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
function validateCompactedMessages(value) {
|
|
882
|
+
if (!Array.isArray(value) || value.length === 0) throw new TypeError("Context compactor must return at least one message");
|
|
883
|
+
const roles = /* @__PURE__ */ new Set([
|
|
884
|
+
"system",
|
|
885
|
+
"user",
|
|
886
|
+
"assistant",
|
|
887
|
+
"tool"
|
|
888
|
+
]);
|
|
889
|
+
for (const [index, message] of value.entries()) {
|
|
890
|
+
if (typeof message !== "object" || message === null || Array.isArray(message)) throw new TypeError(`Context compactor message at index ${index} must be an object`);
|
|
891
|
+
const record = message;
|
|
892
|
+
if (typeof record.role !== "string" || !roles.has(record.role)) throw new TypeError(`Context compactor message at index ${index} has an invalid role`);
|
|
893
|
+
if (typeof record.content !== "string") throw new TypeError(`Context compactor message at index ${index} must have string content`);
|
|
894
|
+
if (record.toolCalls !== void 0 && !Array.isArray(record.toolCalls)) throw new TypeError(`Context compactor message at index ${index} has invalid toolCalls`);
|
|
895
|
+
}
|
|
896
|
+
return value;
|
|
897
|
+
}
|
|
898
|
+
//#endregion
|
|
779
899
|
//#region src/internal/definition-hash.ts
|
|
780
900
|
function canonicalize(value) {
|
|
781
901
|
if (Array.isArray(value)) return value.map(canonicalize);
|
|
@@ -802,7 +922,7 @@ async function sha256(value) {
|
|
|
802
922
|
const digest = await crypto.subtle.digest("SHA-256", encoded);
|
|
803
923
|
return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
804
924
|
}
|
|
805
|
-
async function definitionHash(name, modelName, agent, tools) {
|
|
925
|
+
async function definitionHash(name, modelName, agent, tools, contextBudget) {
|
|
806
926
|
const toolDefinitions = await Promise.all((agent.tools ?? []).map((toolName) => transportableTool(tools.get(toolName))));
|
|
807
927
|
return sha256({
|
|
808
928
|
name,
|
|
@@ -818,6 +938,7 @@ async function definitionHash(name, modelName, agent, tools) {
|
|
|
818
938
|
elicitation: agent.elicitation,
|
|
819
939
|
approvalMode: agent.approvalMode,
|
|
820
940
|
limits: agent.limits,
|
|
941
|
+
contextBudget,
|
|
821
942
|
inputSchema: agent.inputSchema === void 0 ? void 0 : toTransportableSchema(agent.inputSchema, "input", `Input schema for agent "${name}" is not transportable`),
|
|
822
943
|
outputSchema: agent.outputSchema === void 0 ? void 0 : toTransportableSchema(agent.outputSchema, "output", `Output schema for agent "${name}" is not transportable`)
|
|
823
944
|
});
|
|
@@ -902,12 +1023,13 @@ function addWorkflowBudget(first, second) {
|
|
|
902
1023
|
* engine — that direction is what keeps the two separable.
|
|
903
1024
|
*/
|
|
904
1025
|
function createAgentEngine(composition, core) {
|
|
905
|
-
const { models, agents, tools, contextProviders, memoryStore, runStore, credentialStore, sandbox, artifacts, policies } = composition;
|
|
1026
|
+
const { models, agents, tools, contextProviders, contextBudget: defaultContextBudget, compaction, memoryStore, runStore, credentialStore, sandbox, artifacts, policies } = composition;
|
|
906
1027
|
const { activeRuns, activeSessions, runtimeOwner, isClosed, admitStart, markInternalRun, resolveModel, resolveCheckpointModel, notifyObserver, createEvent, emitEvent, releaseExecution, commit, startLease, cancelExecution, authorize } = core;
|
|
907
1028
|
const prepareExecutionBody = async (name, request, internal = false, correlation = {}) => {
|
|
908
1029
|
if (!internal && isClosed()) throw new FevexRunError("RUNTIME_CLOSED", "Runtime is not accepting new runs");
|
|
909
1030
|
const agent = agents.get(name);
|
|
910
1031
|
if (!agent) throw new FevexRunError("AGENT_NOT_FOUND", `Agent "${name}" is not registered`);
|
|
1032
|
+
const contextBudget = resolveContextBudget(request.contextBudget ?? agent.contextBudget ?? defaultContextBudget, `Agent "${name}" contextBudget`);
|
|
911
1033
|
const { modelName, model } = resolveModel(agent, request.model);
|
|
912
1034
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
913
1035
|
let session;
|
|
@@ -965,7 +1087,7 @@ function createAgentEngine(composition, core) {
|
|
|
965
1087
|
content: agent.instructions
|
|
966
1088
|
},
|
|
967
1089
|
...knowledge.skills,
|
|
968
|
-
...session
|
|
1090
|
+
...sessionHistoryMessages(session),
|
|
969
1091
|
...knowledge.context,
|
|
970
1092
|
...knowledge.memory,
|
|
971
1093
|
{
|
|
@@ -978,8 +1100,9 @@ function createAgentEngine(composition, core) {
|
|
|
978
1100
|
runId: run.id,
|
|
979
1101
|
...request.model !== void 0 || typeof agent.model === "string" ? { modelName } : {},
|
|
980
1102
|
...request.reasoning === void 0 ? {} : { reasoning: request.reasoning },
|
|
981
|
-
definitionHash: await definitionHash(name, modelName, agent, tools),
|
|
1103
|
+
definitionHash: await definitionHash(name, modelName, agent, tools, contextBudget),
|
|
982
1104
|
limits: combineLimits(agent.limits, request.limits),
|
|
1105
|
+
...contextBudget === void 0 ? {} : { contextBudget },
|
|
983
1106
|
messages,
|
|
984
1107
|
inputContent,
|
|
985
1108
|
context: request.context,
|
|
@@ -1037,6 +1160,7 @@ function createAgentEngine(composition, core) {
|
|
|
1037
1160
|
const durableCheckpoint = async (state, model, modelName, messages, inputContent, usage, providerState, step, toolCallCount, seenToolCallIds, pendingTools, pendingIndex) => {
|
|
1038
1161
|
const agent = agents.get(state.run.agentName);
|
|
1039
1162
|
if (agent.model !== void 0 && typeof agent.model !== "string") throw new FevexRunError("RUN_NOT_RESUMABLE", "Durable continuation requires a named model", state.run.id);
|
|
1163
|
+
const contextBudget = resolveContextBudget(state.checkpoint?.contextBudget ?? state.request.contextBudget ?? agent.contextBudget ?? defaultContextBudget, `Agent "${state.run.agentName}" contextBudget`);
|
|
1040
1164
|
let serializedState;
|
|
1041
1165
|
if (providerState !== void 0) {
|
|
1042
1166
|
if (!model.stateCodec) throw new FevexRunError("RUN_NOT_RESUMABLE", "ModelGateway must provide stateCodec for durable continuation", state.run.id);
|
|
@@ -1047,8 +1171,9 @@ function createAgentEngine(composition, core) {
|
|
|
1047
1171
|
runId: state.run.id,
|
|
1048
1172
|
modelName,
|
|
1049
1173
|
...state.request.reasoning === void 0 ? {} : { reasoning: state.request.reasoning },
|
|
1050
|
-
definitionHash: await definitionHash(state.run.agentName, modelName, agent, tools),
|
|
1174
|
+
definitionHash: await definitionHash(state.run.agentName, modelName, agent, tools, contextBudget),
|
|
1051
1175
|
limits: state.checkpoint?.limits ?? combineLimits(agent.limits, state.request.limits),
|
|
1176
|
+
...contextBudget === void 0 ? {} : { contextBudget },
|
|
1052
1177
|
messages: structuredClone(messages),
|
|
1053
1178
|
inputContent,
|
|
1054
1179
|
context: state.request.context,
|
|
@@ -1107,6 +1232,7 @@ function createAgentEngine(composition, core) {
|
|
|
1107
1232
|
const { request } = state;
|
|
1108
1233
|
const agent = agents.get(name);
|
|
1109
1234
|
const { modelName, model } = resolveModel(agent, state.checkpoint?.modelName ?? request.model);
|
|
1235
|
+
const contextBudget = resolveContextBudget(state.checkpoint?.contextBudget ?? request.contextBudget ?? agent.contextBudget ?? defaultContextBudget, `Agent "${name}" contextBudget`);
|
|
1110
1236
|
const events = [...state.initialEvents ?? []];
|
|
1111
1237
|
const firstEvents = state.initialEvents ?? [];
|
|
1112
1238
|
state.initialEvents = void 0;
|
|
@@ -1124,12 +1250,13 @@ function createAgentEngine(composition, core) {
|
|
|
1124
1250
|
let seenToolCallIds;
|
|
1125
1251
|
let pendingTools;
|
|
1126
1252
|
let pendingIndex;
|
|
1253
|
+
let compactionApplied = false;
|
|
1127
1254
|
try {
|
|
1128
1255
|
for (const event of firstEvents) yield event;
|
|
1129
1256
|
if (state.checkpoint) {
|
|
1130
1257
|
const checkpoint = state.checkpoint;
|
|
1131
1258
|
if (checkpoint.version !== 2) throw new FevexRunError("CHECKPOINT_UNSUPPORTED", `Checkpoint for run "${state.run.id}" is unsupported`, state.run.id);
|
|
1132
|
-
const hash = await definitionHash(name, modelName, agent, tools);
|
|
1259
|
+
const hash = await definitionHash(name, modelName, agent, tools, contextBudget);
|
|
1133
1260
|
if (checkpoint.definitionHash !== hash) throw new FevexRunError("RUN_DEFINITION_CHANGED", `Definition for agent "${name}" changed`, state.run.id);
|
|
1134
1261
|
inputContent = checkpoint.inputContent;
|
|
1135
1262
|
messages = checkpoint.messages;
|
|
@@ -1151,7 +1278,7 @@ function createAgentEngine(composition, core) {
|
|
|
1151
1278
|
content: agent.instructions
|
|
1152
1279
|
},
|
|
1153
1280
|
...knowledge.skills,
|
|
1154
|
-
...state.session
|
|
1281
|
+
...sessionHistoryMessages(state.session),
|
|
1155
1282
|
...knowledge.context,
|
|
1156
1283
|
...knowledge.memory,
|
|
1157
1284
|
{
|
|
@@ -1179,26 +1306,50 @@ function createAgentEngine(composition, core) {
|
|
|
1179
1306
|
description: remote.description
|
|
1180
1307
|
} : tool, inputSchema);
|
|
1181
1308
|
}));
|
|
1182
|
-
const
|
|
1183
|
-
|
|
1184
|
-
|
|
1309
|
+
const progressiveSkills = (agent.skills ?? []).map((skillName) => contextProviders.get(skillName)).filter((provider) => provider !== void 0 && isProgressiveSkillProvider(provider));
|
|
1310
|
+
const skillTool = progressiveSkills.length === 0 ? void 0 : {
|
|
1311
|
+
name: LOAD_SKILL_TOOL_NAME,
|
|
1312
|
+
description: `Load the full instructions for one of this agent's skills. Available skills: ${progressiveSkills.map((skill) => skill.name).join(", ")}. Pass a resource path from the loaded skill to read one resource.`,
|
|
1185
1313
|
inputSchema: {
|
|
1186
1314
|
type: "object",
|
|
1187
1315
|
properties: {
|
|
1188
|
-
|
|
1316
|
+
name: {
|
|
1189
1317
|
type: "string",
|
|
1190
|
-
|
|
1191
|
-
},
|
|
1192
|
-
responseSchema: {
|
|
1193
|
-
type: "object",
|
|
1194
|
-
description: "JSON Schema for the expected response. Each property should include a short title for the form label and may include a description for field help."
|
|
1318
|
+
enum: progressiveSkills.map((skill) => skill.name)
|
|
1195
1319
|
},
|
|
1196
|
-
|
|
1320
|
+
resource: {
|
|
1321
|
+
type: "string",
|
|
1322
|
+
description: "Optional resource path returned by a previous load."
|
|
1323
|
+
}
|
|
1197
1324
|
},
|
|
1198
|
-
required: ["
|
|
1325
|
+
required: ["name"],
|
|
1199
1326
|
additionalProperties: false
|
|
1200
1327
|
}
|
|
1201
|
-
}
|
|
1328
|
+
};
|
|
1329
|
+
const allTools = [
|
|
1330
|
+
...agentTools,
|
|
1331
|
+
...skillTool === void 0 ? [] : [skillTool],
|
|
1332
|
+
...currentElicitationMode === "pause" ? [{
|
|
1333
|
+
name: ELICIT_TOOL_NAME,
|
|
1334
|
+
description: "Request external information required to continue this run. Use prompt for explanatory text shown outside the form. Put short field labels in responseSchema property titles and optional field help in property descriptions.",
|
|
1335
|
+
inputSchema: {
|
|
1336
|
+
type: "object",
|
|
1337
|
+
properties: {
|
|
1338
|
+
prompt: {
|
|
1339
|
+
type: "string",
|
|
1340
|
+
description: "Explanatory text for the user; do not duplicate field labels here."
|
|
1341
|
+
},
|
|
1342
|
+
responseSchema: {
|
|
1343
|
+
type: "object",
|
|
1344
|
+
description: "JSON Schema for the expected response. Each property should include a short title for the form label and may include a description for field help."
|
|
1345
|
+
},
|
|
1346
|
+
expiresAt: { type: "string" }
|
|
1347
|
+
},
|
|
1348
|
+
required: ["prompt", "responseSchema"],
|
|
1349
|
+
additionalProperties: false
|
|
1350
|
+
}
|
|
1351
|
+
}] : []
|
|
1352
|
+
];
|
|
1202
1353
|
const effectiveLimits = state.checkpoint?.limits ?? combineLimits(agent.limits, request.limits);
|
|
1203
1354
|
const maxSteps = effectiveLimits?.maxSteps ?? 8;
|
|
1204
1355
|
const maxToolCalls = effectiveLimits?.maxToolCalls ?? 16;
|
|
@@ -1206,6 +1357,59 @@ function createAgentEngine(composition, core) {
|
|
|
1206
1357
|
while (step <= maxSteps) {
|
|
1207
1358
|
request.signal.throwIfAborted();
|
|
1208
1359
|
if (pendingTools.length === 0) {
|
|
1360
|
+
if (contextBudget !== void 0) {
|
|
1361
|
+
const compacted = await compactContext({
|
|
1362
|
+
runId: state.run.id,
|
|
1363
|
+
agentName: name,
|
|
1364
|
+
sessionId: state.session.id,
|
|
1365
|
+
messages,
|
|
1366
|
+
tools: allTools,
|
|
1367
|
+
contextBudget,
|
|
1368
|
+
compactor: compaction.compactor,
|
|
1369
|
+
estimateTokens: compaction.estimateTokens,
|
|
1370
|
+
step,
|
|
1371
|
+
...request.context === void 0 ? {} : { context: request.context },
|
|
1372
|
+
signal: request.signal,
|
|
1373
|
+
allowCompaction: !compactionApplied
|
|
1374
|
+
});
|
|
1375
|
+
if (compacted !== void 0) {
|
|
1376
|
+
messages = compacted.messages;
|
|
1377
|
+
compactionApplied = true;
|
|
1378
|
+
const previous = state.session.compaction;
|
|
1379
|
+
const combined = previous === void 0 ? compacted.summary : `${previous.summary}\n\n${compacted.summary}`;
|
|
1380
|
+
const maxSummaryChars = Math.max(200, contextBudget.targetTokens * 4);
|
|
1381
|
+
state.session.compaction = {
|
|
1382
|
+
summary: combined.length > maxSummaryChars ? `…${combined.slice(combined.length - maxSummaryChars + 1)}` : combined,
|
|
1383
|
+
coveredMessages: state.session.history.length,
|
|
1384
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1385
|
+
};
|
|
1386
|
+
const summaryTruncated = compacted.summary.length > MAX_COMPACTION_EVENT_SUMMARY_CHARS;
|
|
1387
|
+
const event = createEvent(state, "context.compacted", {
|
|
1388
|
+
step,
|
|
1389
|
+
removedMessages: compacted.removedMessages,
|
|
1390
|
+
estimatedTokens: compacted.estimatedTokens,
|
|
1391
|
+
compactedTokens: compacted.compactedTokens,
|
|
1392
|
+
targetTokens: contextBudget.targetTokens,
|
|
1393
|
+
contextWindow: contextBudget.contextWindow,
|
|
1394
|
+
summary: summaryTruncated ? `${compacted.summary.slice(0, MAX_COMPACTION_EVENT_SUMMARY_CHARS - 1)}…` : compacted.summary,
|
|
1395
|
+
...summaryTruncated ? { summaryTruncated: true } : {}
|
|
1396
|
+
});
|
|
1397
|
+
if (isDurableRunStore(runStore)) {
|
|
1398
|
+
const checkpoint = await durableCheckpoint(state, model, modelName, messages, inputContent, usage, providerState, step, toolCallCount, seenToolCallIds, pendingTools, pendingIndex);
|
|
1399
|
+
await commit(state, {
|
|
1400
|
+
checkpoint,
|
|
1401
|
+
session: state.session,
|
|
1402
|
+
events: [event]
|
|
1403
|
+
});
|
|
1404
|
+
state.checkpoint = checkpoint;
|
|
1405
|
+
} else {
|
|
1406
|
+
await runStore.appendEvent(event);
|
|
1407
|
+
notifyObserver(event);
|
|
1408
|
+
}
|
|
1409
|
+
events.push(event);
|
|
1410
|
+
yield event;
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1209
1413
|
const hasToolBudget = step < maxSteps && toolCallCount < maxToolCalls;
|
|
1210
1414
|
const modelToolChoice = hasToolBudget && allTools.length ? currentToolChoice === "auto" ? void 0 : currentToolChoice : void 0;
|
|
1211
1415
|
yield await emit("model.started", { step });
|
|
@@ -1287,6 +1491,57 @@ function createAgentEngine(composition, core) {
|
|
|
1287
1491
|
assertContinuationBudget(name, "maxInputTokens", "inputTokens", effectiveLimits?.maxInputTokens, usage);
|
|
1288
1492
|
assertContinuationBudget(name, "maxOutputTokens", "outputTokens", effectiveLimits?.maxOutputTokens, usage);
|
|
1289
1493
|
if (result.toolCalls.length > maxToolCalls - toolCallCount) throw new Error(`Agent "${name}" exceeded maxToolCalls limit of ${maxToolCalls}`);
|
|
1494
|
+
const loadSkillCall = progressiveSkills.length === 0 ? void 0 : result.toolCalls.find((call) => call.name === LOAD_SKILL_TOOL_NAME);
|
|
1495
|
+
if (loadSkillCall) {
|
|
1496
|
+
if (result.toolCalls.length !== 1) throw new Error(`${LOAD_SKILL_TOOL_NAME} must be the only tool call in a model turn`);
|
|
1497
|
+
if (!loadSkillCall.id?.trim()) throw new Error("Tool call id cannot be empty");
|
|
1498
|
+
if (seenToolCallIds.has(loadSkillCall.id)) throw new Error(`Tool call id "${loadSkillCall.id}" is duplicated in run "${state.run.id}"`);
|
|
1499
|
+
if (toolCallCount + 1 > maxToolCalls) throw new Error(`Agent "${name}" exceeded maxToolCalls limit of ${maxToolCalls}`);
|
|
1500
|
+
const rawInput = toJsonValue(loadSkillCall.input, `Input for tool "${LOAD_SKILL_TOOL_NAME}" must be JSON-serializable`);
|
|
1501
|
+
const skillInput = readSkillInput(rawInput);
|
|
1502
|
+
const skill = progressiveSkills.find((item) => item.name === skillInput.name);
|
|
1503
|
+
if (!skill) throw new Error(`Skill "${skillInput.name}" is not available to agent "${name}"`);
|
|
1504
|
+
seenToolCallIds.add(loadSkillCall.id);
|
|
1505
|
+
messages.push({
|
|
1506
|
+
role: "assistant",
|
|
1507
|
+
content: result.output === void 0 ? "" : serializeValue(result.output, `Model output for agent "${name}" must be serializable`),
|
|
1508
|
+
toolCalls: [{
|
|
1509
|
+
...loadSkillCall,
|
|
1510
|
+
input: rawInput
|
|
1511
|
+
}]
|
|
1512
|
+
});
|
|
1513
|
+
yield await emit("tool.started", {
|
|
1514
|
+
step,
|
|
1515
|
+
toolCallId: loadSkillCall.id,
|
|
1516
|
+
toolName: LOAD_SKILL_TOOL_NAME
|
|
1517
|
+
});
|
|
1518
|
+
let blocks;
|
|
1519
|
+
try {
|
|
1520
|
+
blocks = await abortable(() => skill.load(knowledgeContext(state, inputContent), skillInput.resource), request.signal);
|
|
1521
|
+
} catch (error) {
|
|
1522
|
+
yield await emit("tool.failed", {
|
|
1523
|
+
step,
|
|
1524
|
+
toolCallId: loadSkillCall.id,
|
|
1525
|
+
toolName: LOAD_SKILL_TOOL_NAME,
|
|
1526
|
+
error: toErrorMessage(error)
|
|
1527
|
+
});
|
|
1528
|
+
throw new Error(`Skill provider "${skill.name}" failed: ${toErrorMessage(error)}`, { cause: error });
|
|
1529
|
+
}
|
|
1530
|
+
messages.push({
|
|
1531
|
+
role: "tool",
|
|
1532
|
+
name: LOAD_SKILL_TOOL_NAME,
|
|
1533
|
+
toolCallId: loadSkillCall.id,
|
|
1534
|
+
content: blocks.filter((block) => block.content.trim()).map((block) => `[Skill: ${skill.name}/${block.id}]\n${block.content}`).join("\n\n")
|
|
1535
|
+
});
|
|
1536
|
+
yield await emit("tool.completed", {
|
|
1537
|
+
step,
|
|
1538
|
+
toolCallId: loadSkillCall.id,
|
|
1539
|
+
toolName: LOAD_SKILL_TOOL_NAME
|
|
1540
|
+
});
|
|
1541
|
+
toolCallCount += 1;
|
|
1542
|
+
step += 1;
|
|
1543
|
+
continue;
|
|
1544
|
+
}
|
|
1290
1545
|
const elicitationCall = result.toolCalls.find(isElicitationToolCall);
|
|
1291
1546
|
if (elicitationCall) {
|
|
1292
1547
|
if (!isDurableRunStore(runStore)) throw new FevexRunError("DURABLE_STORE_REQUIRED", "Elicitation requires a DurableRunStore", state.run.id);
|
|
@@ -2036,6 +2291,26 @@ function createAgentEngine(composition, core) {
|
|
|
2036
2291
|
cancelStoredAgent
|
|
2037
2292
|
};
|
|
2038
2293
|
}
|
|
2294
|
+
function sessionHistoryMessages(session) {
|
|
2295
|
+
const compaction = session.compaction;
|
|
2296
|
+
if (compaction === void 0 || compaction.coveredMessages <= 0 || compaction.coveredMessages > session.history.length) return session.history;
|
|
2297
|
+
return [{
|
|
2298
|
+
role: "system",
|
|
2299
|
+
content: `[Compacted conversation]\n${compaction.summary}`
|
|
2300
|
+
}, ...session.history.slice(compaction.coveredMessages)];
|
|
2301
|
+
}
|
|
2302
|
+
function readSkillInput(input) {
|
|
2303
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) throw new TypeError(`${LOAD_SKILL_TOOL_NAME} input must be an object`);
|
|
2304
|
+
const record = input;
|
|
2305
|
+
const name = record.name;
|
|
2306
|
+
const resource = record.resource;
|
|
2307
|
+
if (typeof name !== "string" || !name.trim()) throw new TypeError(`${LOAD_SKILL_TOOL_NAME} name must be a non-empty string`);
|
|
2308
|
+
if (resource !== void 0 && (typeof resource !== "string" || !resource.trim())) throw new TypeError(`${LOAD_SKILL_TOOL_NAME} resource must be a non-empty string`);
|
|
2309
|
+
return {
|
|
2310
|
+
name: name.trim(),
|
|
2311
|
+
...resource === void 0 ? {} : { resource: resource.trim() }
|
|
2312
|
+
};
|
|
2313
|
+
}
|
|
2039
2314
|
function scopedArtifacts(store, options) {
|
|
2040
2315
|
const scopedContext = (value) => {
|
|
2041
2316
|
const contextTenant = options.request.context?.attributes?.tenantId;
|
|
@@ -2195,6 +2470,17 @@ function annotation(event) {
|
|
|
2195
2470
|
delayMs: event.payload.delayMs
|
|
2196
2471
|
}
|
|
2197
2472
|
};
|
|
2473
|
+
case "context.compacted": return {
|
|
2474
|
+
name: event.type,
|
|
2475
|
+
timestamp: event.timestamp,
|
|
2476
|
+
attributes: {
|
|
2477
|
+
removedMessages: event.payload.removedMessages,
|
|
2478
|
+
estimatedTokens: event.payload.estimatedTokens,
|
|
2479
|
+
compactedTokens: event.payload.compactedTokens,
|
|
2480
|
+
targetTokens: event.payload.targetTokens,
|
|
2481
|
+
contextWindow: event.payload.contextWindow
|
|
2482
|
+
}
|
|
2483
|
+
};
|
|
2198
2484
|
case "tool.execution_unknown": return {
|
|
2199
2485
|
name: event.type,
|
|
2200
2486
|
timestamp: event.timestamp,
|
|
@@ -2793,12 +3079,12 @@ function createRunCore({ models, agents, tools, runStore, policies, onEvent, obs
|
|
|
2793
3079
|
};
|
|
2794
3080
|
const resolveCheckpointModel = async (agentName, agent, checkpoint) => {
|
|
2795
3081
|
const preferred = resolveModel(agent, checkpoint.modelName);
|
|
2796
|
-
if (checkpoint.definitionHash === await definitionHash(agentName, preferred.modelName, agent, tools)) return preferred;
|
|
3082
|
+
if (checkpoint.definitionHash === await definitionHash(agentName, preferred.modelName, agent, tools, checkpoint.contextBudget)) return preferred;
|
|
2797
3083
|
if (checkpoint.modelName !== void 0) return void 0;
|
|
2798
3084
|
for (const candidateName of models.keys()) {
|
|
2799
3085
|
if (candidateName === preferred.modelName) continue;
|
|
2800
3086
|
const candidate = resolveModel(agent, candidateName);
|
|
2801
|
-
if (checkpoint.definitionHash === await definitionHash(agentName, candidate.modelName, agent, tools)) return candidate;
|
|
3087
|
+
if (checkpoint.definitionHash === await definitionHash(agentName, candidate.modelName, agent, tools, checkpoint.contextBudget)) return candidate;
|
|
2802
3088
|
}
|
|
2803
3089
|
};
|
|
2804
3090
|
const scheduleTraceExport = (event) => {
|
|
@@ -4319,6 +4605,7 @@ function createRuntime(composition) {
|
|
|
4319
4605
|
role: "system",
|
|
4320
4606
|
content: summary
|
|
4321
4607
|
}];
|
|
4608
|
+
session.compaction = void 0;
|
|
4322
4609
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4323
4610
|
await runStore.saveSession(session);
|
|
4324
4611
|
return structuredClone(session);
|
|
@@ -4344,4 +4631,4 @@ function createFevex(config) {
|
|
|
4344
4631
|
return createRuntime(createComposition(config));
|
|
4345
4632
|
}
|
|
4346
4633
|
//#endregion
|
|
4347
|
-
export { ArtifactError, CatalogedArtifactStore, ChannelError, FEVEX_JSON_SCHEMA_PROFILE_VERSION, FevexConfigurationError, FevexRunError, FileSystemArtifactStore, InMemoryArtifactCatalog, InMemoryArtifactStore, InMemoryMemoryStore, InMemoryRunStore, IntegrationError, PROVIDER_REASONING_UNSUPPORTED, PROVIDER_SCHEMA_UNSUPPORTED, RunPausedError, S3ArtifactStore, SCHEMA_NOT_TRANSPORTABLE, SandboxError, artifactTenantId, assertArtifactId, compileFevexJsonSchema, createFevex, createLocalSandbox, createMemoryContextProvider, defineAgent, defineConnection, defineContextProvider, definePolicy, defineSkill, defineTeam, defineTool, defineWorkflow, deliverChannelRun, handleChannelInput, isDurableRunStore, isRetainableRunStore, sandboxResultToJson, toToolSpec, validateFevexJsonSchemaProfile, validateListEventsOptions, validatePurgeRunsOptions };
|
|
4634
|
+
export { ArtifactError, CatalogedArtifactStore, ChannelError, FEVEX_JSON_SCHEMA_PROFILE_VERSION, FevexConfigurationError, FevexRunError, FileSystemArtifactStore, InMemoryArtifactCatalog, InMemoryArtifactStore, InMemoryMemoryStore, InMemoryRunStore, IntegrationError, PROVIDER_REASONING_UNSUPPORTED, PROVIDER_SCHEMA_UNSUPPORTED, RunPausedError, S3ArtifactStore, SCHEMA_NOT_TRANSPORTABLE, SandboxError, artifactTenantId, assertArtifactId, compileFevexJsonSchema, createAgentsMdContextProvider, createDigestContextCompactor, createFevex, createLocalSandbox, createMemoryContextProvider, defineAgent, defineConnection, defineContextProvider, definePolicy, defineSkill, defineTeam, defineTool, defineWorkflow, deliverChannelRun, estimateContextTokens, handleChannelInput, isDurableRunStore, isProgressiveSkillProvider, isRetainableRunStore, loadSkillFile, loadSkillFiles, resolveContextBudget, sandboxResultToJson, toToolSpec, validateFevexJsonSchemaProfile, validateListEventsOptions, validatePurgeRunsOptions };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { ContextBlock, ContextProvider, InMemoryMemoryStore, KnowledgeContext, MemoryQuery, MemoryRecord, MemoryStore, MemoryWrite, SkillDefinition, createMemoryContextProvider, defineContextProvider, defineSkill };
|
|
1
|
+
import { _ as defineContextProvider, a as AgentsMdOptions, c as ContextProvider, d as MemoryRecord, f as MemoryStore, g as createMemoryContextProvider, h as SkillDefinition, i as InMemoryMemoryStore, l as KnowledgeContext, m as ProgressiveSkillProvider, n as loadSkillFile, o as createAgentsMdContextProvider, p as MemoryWrite, r as loadSkillFiles, s as ContextBlock, t as LoadSkillFileOptions, u as MemoryQuery, v as defineSkill, y as isProgressiveSkillProvider } from "../index-CAyAoOW0.mjs";
|
|
2
|
+
export { AgentsMdOptions, ContextBlock, ContextProvider, InMemoryMemoryStore, KnowledgeContext, LoadSkillFileOptions, MemoryQuery, MemoryRecord, MemoryStore, MemoryWrite, ProgressiveSkillProvider, SkillDefinition, createAgentsMdContextProvider, createMemoryContextProvider, defineContextProvider, defineSkill, isProgressiveSkillProvider, loadSkillFile, loadSkillFiles };
|