@dudko.dev/agent-web 0.0.1 → 0.0.2
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 +35 -1
- package/dist/agent-web.js +177 -0
- package/dist/agent-web.js.map +1 -0
- package/dist/index.cjs +186 -95
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -4
- package/dist/index.d.ts +31 -4
- package/dist/index.js +186 -95
- package/dist/index.js.map +1 -1
- package/dist/mcp.cjs +71 -44
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.d.cts +5 -1
- package/dist/mcp.d.ts +5 -1
- package/dist/mcp.js +71 -44
- package/dist/mcp.js.map +1 -1
- package/package.json +7 -1
package/dist/index.cjs
CHANGED
|
@@ -203,7 +203,9 @@ var compressHistory = async (messages, model, opts = {}) => {
|
|
|
203
203
|
const result = await generate(model, {
|
|
204
204
|
system: "Summarize the following conversation into a compact set of durable facts and decisions. Output plain text only.",
|
|
205
205
|
prompt: transcript,
|
|
206
|
-
maxOutputTokens: 400
|
|
206
|
+
maxOutputTokens: 400,
|
|
207
|
+
timeoutMs: opts.timeoutMs,
|
|
208
|
+
abortSignal: opts.abortSignal
|
|
207
209
|
});
|
|
208
210
|
const clean = (result.text || "").trim();
|
|
209
211
|
if (!clean) return messages;
|
|
@@ -411,9 +413,19 @@ var stateBlock = (state) => state && state.trim() ? `
|
|
|
411
413
|
|
|
412
414
|
STATE:
|
|
413
415
|
${state}` : "";
|
|
416
|
+
var clip = (s, max) => s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
|
|
417
|
+
var historyBlock = (history) => {
|
|
418
|
+
if (!history || history.length === 0) return "";
|
|
419
|
+
const lines = history.slice(-8).map((m) => `${m.role}: ${clip(m.content, 400)}`);
|
|
420
|
+
return `
|
|
421
|
+
|
|
422
|
+
CONVERSATION SO FAR:
|
|
423
|
+
${lines.join("\n")}`;
|
|
424
|
+
};
|
|
414
425
|
var PLANNER_NATIVE = `You are the PLANNER of a tool-using agent that changes a workspace step by step.
|
|
415
426
|
Produce a brief "thought" and an ordered "steps" list (1\u20136 DISTINCT, self-contained steps) grounded in the current STATE and the available TOOLS.
|
|
416
427
|
If the user only greets, thanks, makes small talk, asks a question, or is unclear: return an EMPTY steps list and put a short, friendly answer in "thought".
|
|
428
|
+
If a CONVERSATION SO FAR section is present, use it to resolve references to earlier turns.
|
|
417
429
|
Never repeat or pad steps.`;
|
|
418
430
|
var PLANNER_PROMPTED = `You are the PLANNER of a tool-using agent that changes a workspace step by step.
|
|
419
431
|
|
|
@@ -421,7 +433,8 @@ Reply with a single JSON object, nothing else:
|
|
|
421
433
|
{ "reply": string, "plan": string[] }
|
|
422
434
|
- Only produce a "plan" when the user CLEARLY asks to build, do, or change something. For a greeting, small talk, thanks, a question, or an unclear/empty request: set "plan": [] and put a short, friendly "reply".
|
|
423
435
|
- For a real goal: "reply" is one short sentence; "plan" is 1\u20136 DISTINCT, self-contained steps. Never repeat or pad steps.
|
|
424
|
-
- Plan realistic steps the available TOOLS can perform, grounded in the current STATE
|
|
436
|
+
- Plan realistic steps the available TOOLS can perform, grounded in the current STATE.
|
|
437
|
+
- If a CONVERSATION SO FAR section is present, use it to resolve references to earlier turns.`;
|
|
425
438
|
var EXECUTOR_NATIVE = `You are the EXECUTOR of a tool-using agent. Carry out ONLY the current step by calling the provided tools.
|
|
426
439
|
Build on the current STATE \u2014 do not repeat work that is already there.
|
|
427
440
|
When the step is done, reply with one short human sentence describing what you did (no JSON).
|
|
@@ -449,7 +462,7 @@ var SYNTHESIZER_SYSTEM = `You are the SYNTHESIZER. In 1\u20133 short, friendly s
|
|
|
449
462
|
var defaultPrompts = {
|
|
450
463
|
planner: (ctx) => ({
|
|
451
464
|
system: ctx.mode === "prompted" ? PLANNER_PROMPTED : PLANNER_NATIVE,
|
|
452
|
-
prompt: `GOAL: ${ctx.goal}${stateBlock(ctx.state)}
|
|
465
|
+
prompt: `GOAL: ${ctx.goal}${historyBlock(ctx.history)}${stateBlock(ctx.state)}
|
|
453
466
|
|
|
454
467
|
TOOLS:
|
|
455
468
|
${ctx.toolCatalog}`
|
|
@@ -494,11 +507,12 @@ var withSystem = (base, extra) => extra && extra.trim() ? `${extra.trim()}
|
|
|
494
507
|
${base}` : base;
|
|
495
508
|
|
|
496
509
|
// src/tools/mode.ts
|
|
497
|
-
var modelProviderId = (model) => typeof model === "string" ? model : model.provider ?? "";
|
|
498
510
|
var LOCAL_RE = /web-?llm|mlc|browser-ai|transformers|nano|built-?in/i;
|
|
499
511
|
var selectToolMode = (model, mode = "auto") => {
|
|
500
512
|
if (mode === "native" || mode === "prompted") return mode;
|
|
501
|
-
|
|
513
|
+
if (typeof model === "string") return "native";
|
|
514
|
+
const provider = model.provider ?? "";
|
|
515
|
+
return LOCAL_RE.test(provider) ? "prompted" : "native";
|
|
502
516
|
};
|
|
503
517
|
|
|
504
518
|
// src/tools/types.ts
|
|
@@ -619,24 +633,35 @@ var normalizeSteps = (arr, cap = 12) => {
|
|
|
619
633
|
}
|
|
620
634
|
return out;
|
|
621
635
|
};
|
|
636
|
+
var decodeJsonString = (body) => {
|
|
637
|
+
const v = tryParse(`"${body}"`);
|
|
638
|
+
return typeof v === "string" ? v : body;
|
|
639
|
+
};
|
|
622
640
|
var salvageStringArray = (text, field) => {
|
|
623
|
-
const
|
|
624
|
-
if (
|
|
625
|
-
const region = text.slice(at);
|
|
641
|
+
const m = new RegExp(`"${field}"\\s*:\\s*\\[`).exec(text);
|
|
642
|
+
if (!m) return [];
|
|
626
643
|
const out = [];
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
644
|
+
let i = m.index + m[0].length;
|
|
645
|
+
while (i < text.length && text[i] !== "]") {
|
|
646
|
+
if (text[i] !== '"') {
|
|
647
|
+
i += 1;
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
let j = i + 1;
|
|
651
|
+
let esc = false;
|
|
652
|
+
while (j < text.length && (esc || text[j] !== '"')) {
|
|
653
|
+
esc = !esc && text[j] === "\\";
|
|
654
|
+
j += 1;
|
|
655
|
+
}
|
|
656
|
+
if (j >= text.length) break;
|
|
657
|
+
out.push(decodeJsonString(text.slice(i + 1, j)));
|
|
658
|
+
i = j + 1;
|
|
634
659
|
}
|
|
635
660
|
return out;
|
|
636
661
|
};
|
|
637
662
|
var salvageString = (text, field) => {
|
|
638
663
|
const m = text.match(new RegExp(`"${field}"\\s*:\\s*"((?:[^"\\\\]|\\\\.)*)"`));
|
|
639
|
-
return m ? m[1].trim() : "";
|
|
664
|
+
return m ? decodeJsonString(m[1]).trim() : "";
|
|
640
665
|
};
|
|
641
666
|
var parsePlannerResponse = (raw) => {
|
|
642
667
|
const text = stripFences(raw);
|
|
@@ -759,12 +784,14 @@ var runPrompted = async (model, opts) => {
|
|
|
759
784
|
temperature: opts.temperature,
|
|
760
785
|
abortSignal: timeoutSignal(opts.abortSignal, opts.timeoutMs)
|
|
761
786
|
});
|
|
762
|
-
if (result.text) opts.callbacks?.onTextDelta?.(result.text);
|
|
763
787
|
const parsed = parseExecutorResponse(result.text);
|
|
788
|
+
if (parsed.reply) opts.callbacks?.onTextDelta?.(parsed.reply);
|
|
789
|
+
const active = opts.activeTools;
|
|
790
|
+
const tools = active ? Object.fromEntries(Object.entries(opts.tools).filter(([name]) => active.includes(name))) : opts.tools;
|
|
764
791
|
const toolCalls = [];
|
|
765
792
|
for (const action of parsed.actions) {
|
|
766
793
|
opts.callbacks?.onToolCall?.(action.tool, action.args);
|
|
767
|
-
const rec = await dispatch(action,
|
|
794
|
+
const rec = await dispatch(action, tools, { abortSignal: opts.abortSignal });
|
|
768
795
|
toolCalls.push(rec);
|
|
769
796
|
opts.callbacks?.onToolResult?.(rec.name, rec.output, rec.ok);
|
|
770
797
|
}
|
|
@@ -793,13 +820,15 @@ var summaryOf = (text, toolCallCount) => {
|
|
|
793
820
|
};
|
|
794
821
|
var executeStep = async (ctx, goal, step, index, total, done) => {
|
|
795
822
|
const state = await ctx.state();
|
|
823
|
+
const active = activeToolNames(ctx, step);
|
|
824
|
+
const toolCatalog = active === void 0 ? ctx.toolCatalog : renderCatalog(Object.fromEntries(active.map((name) => [name, ctx.tools[name]])));
|
|
796
825
|
const parts = ctx.prompts.executor({
|
|
797
826
|
goal,
|
|
798
827
|
state,
|
|
799
828
|
step: step.description,
|
|
800
829
|
index,
|
|
801
830
|
total,
|
|
802
|
-
toolCatalog
|
|
831
|
+
toolCatalog,
|
|
803
832
|
done,
|
|
804
833
|
mode: ctx.executorMode
|
|
805
834
|
});
|
|
@@ -808,7 +837,7 @@ var executeStep = async (ctx, goal, step, index, total, done) => {
|
|
|
808
837
|
system: systemFor(ctx, parts.system),
|
|
809
838
|
prompt: parts.prompt,
|
|
810
839
|
tools: ctx.tools,
|
|
811
|
-
activeTools:
|
|
840
|
+
activeTools: active,
|
|
812
841
|
maxSteps: ctx.config.maxStepsPerTask,
|
|
813
842
|
maxOutputTokens: ctx.config.budgets.executor,
|
|
814
843
|
temperature: ctx.config.temperature,
|
|
@@ -869,24 +898,26 @@ var toSteps = (raw) => raw.filter((s) => s.description && s.description.trim()).
|
|
|
869
898
|
}));
|
|
870
899
|
var createPlan = async (ctx, goal) => {
|
|
871
900
|
const state = await ctx.state();
|
|
872
|
-
const
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
901
|
+
const commonFor = (mode) => {
|
|
902
|
+
const parts = ctx.prompts.planner({
|
|
903
|
+
goal,
|
|
904
|
+
state,
|
|
905
|
+
toolCatalog: ctx.toolCatalog,
|
|
906
|
+
mode,
|
|
907
|
+
history: ctx.history
|
|
908
|
+
});
|
|
909
|
+
return {
|
|
910
|
+
system: systemFor(ctx, parts.system),
|
|
911
|
+
prompt: parts.prompt,
|
|
912
|
+
maxOutputTokens: ctx.config.budgets.planner,
|
|
913
|
+
temperature: ctx.config.temperature,
|
|
914
|
+
abortSignal: ctx.signal,
|
|
915
|
+
timeoutMs: ctx.config.chatTimeoutMs
|
|
916
|
+
};
|
|
886
917
|
};
|
|
887
918
|
if (ctx.plannerMode === "native") {
|
|
888
919
|
try {
|
|
889
|
-
const result2 = await generateStructured(ctx.plannerModel, PlanSchema,
|
|
920
|
+
const result2 = await generateStructured(ctx.plannerModel, PlanSchema, commonFor("native"));
|
|
890
921
|
return {
|
|
891
922
|
plan: { thought: result2.object.thought, steps: toSteps(result2.object.steps) },
|
|
892
923
|
usage: normalizeUsage(result2.usage)
|
|
@@ -895,14 +926,14 @@ var createPlan = async (ctx, goal) => {
|
|
|
895
926
|
ctx.emit({ type: "retry", phase: "plan", attempt: 1, error: asMessage(err) });
|
|
896
927
|
}
|
|
897
928
|
}
|
|
898
|
-
const result = await generate(ctx.plannerModel,
|
|
929
|
+
const result = await generate(ctx.plannerModel, commonFor("prompted"));
|
|
899
930
|
const parsed = parsePlannerResponse(result.text);
|
|
900
931
|
return {
|
|
901
932
|
plan: {
|
|
902
933
|
thought: parsed.reply,
|
|
903
934
|
steps: toSteps(parsed.plan.map((description) => ({ description })))
|
|
904
935
|
},
|
|
905
|
-
usage:
|
|
936
|
+
usage: normalizeUsage(result.usage)
|
|
906
937
|
};
|
|
907
938
|
};
|
|
908
939
|
var asMessage = (err) => err instanceof Error ? err.message : String(err);
|
|
@@ -910,26 +941,31 @@ var asMessage = (err) => err instanceof Error ? err.message : String(err);
|
|
|
910
941
|
// src/agent/replanner.ts
|
|
911
942
|
var decideReplan = async (ctx, goal, done, remaining) => {
|
|
912
943
|
const state = await ctx.state();
|
|
913
|
-
const
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
944
|
+
const commonFor = (mode) => {
|
|
945
|
+
const parts = ctx.prompts.replanner({ goal, state, done, remaining, mode });
|
|
946
|
+
return {
|
|
947
|
+
system: systemFor(ctx, parts.system),
|
|
948
|
+
prompt: parts.prompt,
|
|
949
|
+
maxOutputTokens: ctx.config.budgets.replanner,
|
|
950
|
+
temperature: ctx.config.temperature,
|
|
951
|
+
abortSignal: ctx.signal,
|
|
952
|
+
timeoutMs: ctx.config.chatTimeoutMs
|
|
953
|
+
};
|
|
921
954
|
};
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
const
|
|
955
|
+
if (ctx.plannerMode === "native") {
|
|
956
|
+
try {
|
|
957
|
+
const result = await generateStructured(ctx.plannerModel, ReplanSchema, commonFor("native"));
|
|
925
958
|
return {
|
|
926
|
-
decision:
|
|
927
|
-
reason:
|
|
928
|
-
plan:
|
|
929
|
-
usage: normalizeUsage(
|
|
959
|
+
decision: result.object.decision,
|
|
960
|
+
reason: result.object.reason,
|
|
961
|
+
plan: result.object.plan ?? [],
|
|
962
|
+
usage: normalizeUsage(result.usage)
|
|
930
963
|
};
|
|
964
|
+
} catch {
|
|
931
965
|
}
|
|
932
|
-
|
|
966
|
+
}
|
|
967
|
+
try {
|
|
968
|
+
const result = await generate(ctx.plannerModel, commonFor("prompted"));
|
|
933
969
|
const parsed = parseReplannerResponse(result.text);
|
|
934
970
|
return {
|
|
935
971
|
decision: parsed.decision,
|
|
@@ -946,7 +982,7 @@ var decideReplan = async (ctx, goal, done, remaining) => {
|
|
|
946
982
|
var synthesizeAnswer = async (ctx, goal, done) => {
|
|
947
983
|
const state = await ctx.state();
|
|
948
984
|
const parts = ctx.prompts.synthesizer({ goal, state, done });
|
|
949
|
-
const result =
|
|
985
|
+
const result = stream(ctx.synthesizerModel, {
|
|
950
986
|
system: systemFor(ctx, parts.system),
|
|
951
987
|
prompt: parts.prompt,
|
|
952
988
|
maxOutputTokens: ctx.config.budgets.synthesizer,
|
|
@@ -954,37 +990,54 @@ var synthesizeAnswer = async (ctx, goal, done) => {
|
|
|
954
990
|
abortSignal: ctx.signal,
|
|
955
991
|
timeoutMs: ctx.config.chatTimeoutMs
|
|
956
992
|
});
|
|
957
|
-
|
|
993
|
+
let text = "";
|
|
994
|
+
let verdict = "unknown";
|
|
995
|
+
for await (const delta of result.textStream) {
|
|
996
|
+
text += delta;
|
|
997
|
+
if (verdict === "unknown") {
|
|
998
|
+
const lead = text.trimStart();
|
|
999
|
+
if (!lead) continue;
|
|
1000
|
+
verdict = looksLikeJson(lead) ? "suppress" : "emit";
|
|
1001
|
+
if (verdict === "emit") ctx.emit({ type: "final.text-delta", delta: text });
|
|
1002
|
+
} else if (verdict === "emit") {
|
|
1003
|
+
ctx.emit({ type: "final.text-delta", delta });
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
const clean = parsePlainText(text);
|
|
958
1007
|
return {
|
|
959
1008
|
text: clean || "Done \u2014 the changes have been applied.",
|
|
960
|
-
usage: normalizeUsage(result.usage)
|
|
1009
|
+
usage: normalizeUsage(await result.usage)
|
|
961
1010
|
};
|
|
962
1011
|
};
|
|
963
1012
|
|
|
964
1013
|
// src/agent/runner.ts
|
|
965
1014
|
var errMessage = (err) => err instanceof Error ? err.message : String(err);
|
|
1015
|
+
var filterTools = (all, available, excluded) => {
|
|
1016
|
+
let entries = Object.entries(all);
|
|
1017
|
+
if (available && available.length > 0) entries = entries.filter(([n]) => available.includes(n));
|
|
1018
|
+
if (excluded && excluded.length > 0) entries = entries.filter(([n]) => !excluded.includes(n));
|
|
1019
|
+
return Object.fromEntries(entries);
|
|
1020
|
+
};
|
|
966
1021
|
var createAgent = async (config) => {
|
|
967
1022
|
const cfg = resolveConfig(config);
|
|
968
|
-
const
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
),
|
|
979
|
-
buildModelFromStage(
|
|
980
|
-
resolveStage(config.model, config.synthesizer, "synthesizer"),
|
|
981
|
-
config.credentials,
|
|
982
|
-
cfg.clientName
|
|
983
|
-
)
|
|
1023
|
+
const buildStage = (override, stageName) => buildModelFromStage(
|
|
1024
|
+
resolveStage(config.model, override, stageName),
|
|
1025
|
+
config.credentials,
|
|
1026
|
+
cfg.clientName
|
|
1027
|
+
);
|
|
1028
|
+
const executorP = buildStage(void 0, "executor");
|
|
1029
|
+
const [executorModel, plannerModel, synthesizerModel] = await Promise.all([
|
|
1030
|
+
executorP,
|
|
1031
|
+
config.planner === void 0 ? executorP : buildStage(config.planner, "planner"),
|
|
1032
|
+
config.synthesizer === void 0 ? executorP : buildStage(config.synthesizer, "synthesizer")
|
|
984
1033
|
]);
|
|
985
1034
|
const plannerMode = selectToolMode(plannerModel, cfg.toolMode);
|
|
986
1035
|
const executorMode = selectToolMode(executorModel, cfg.toolMode);
|
|
987
|
-
const tools =
|
|
1036
|
+
const tools = filterTools(
|
|
1037
|
+
config.tools ?? {},
|
|
1038
|
+
config.availableTools,
|
|
1039
|
+
config.excludedTools
|
|
1040
|
+
);
|
|
988
1041
|
const toolCatalog = renderCatalog(tools);
|
|
989
1042
|
const prompts = { ...defaultPrompts, ...config.prompts };
|
|
990
1043
|
const run = async (goal, opts = {}) => {
|
|
@@ -1009,21 +1062,6 @@ var createAgent = async (config) => {
|
|
|
1009
1062
|
};
|
|
1010
1063
|
if (!text) return result;
|
|
1011
1064
|
const state = async () => config.describeState ? config.describeState() : void 0;
|
|
1012
|
-
const ctx = {
|
|
1013
|
-
config: cfg,
|
|
1014
|
-
raw: config,
|
|
1015
|
-
plannerModel,
|
|
1016
|
-
executorModel,
|
|
1017
|
-
synthesizerModel,
|
|
1018
|
-
plannerMode,
|
|
1019
|
-
executorMode,
|
|
1020
|
-
tools,
|
|
1021
|
-
toolCatalog,
|
|
1022
|
-
prompts,
|
|
1023
|
-
emit,
|
|
1024
|
-
signal: opts.signal,
|
|
1025
|
-
state
|
|
1026
|
-
};
|
|
1027
1065
|
const isAborted = () => opts.signal?.aborted === true;
|
|
1028
1066
|
const bumpUsage = (u, phase) => {
|
|
1029
1067
|
usage = addUsage(usage, u);
|
|
@@ -1038,6 +1076,29 @@ var createAgent = async (config) => {
|
|
|
1038
1076
|
}
|
|
1039
1077
|
};
|
|
1040
1078
|
emit({ type: "run.start", goal: text });
|
|
1079
|
+
let history = [];
|
|
1080
|
+
if (config.memory) {
|
|
1081
|
+
try {
|
|
1082
|
+
history = await config.memory.load(sessionId);
|
|
1083
|
+
} catch {
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
const ctx = {
|
|
1087
|
+
config: cfg,
|
|
1088
|
+
raw: config,
|
|
1089
|
+
plannerModel,
|
|
1090
|
+
executorModel,
|
|
1091
|
+
synthesizerModel,
|
|
1092
|
+
plannerMode,
|
|
1093
|
+
executorMode,
|
|
1094
|
+
tools,
|
|
1095
|
+
toolCatalog,
|
|
1096
|
+
prompts,
|
|
1097
|
+
emit,
|
|
1098
|
+
signal: opts.signal,
|
|
1099
|
+
state,
|
|
1100
|
+
history
|
|
1101
|
+
};
|
|
1041
1102
|
await remember({ role: "user", content: text });
|
|
1042
1103
|
try {
|
|
1043
1104
|
const planned = await createPlan(ctx, text);
|
|
@@ -1078,6 +1139,11 @@ var createAgent = async (config) => {
|
|
|
1078
1139
|
bumpUsage(out.usage, "execute");
|
|
1079
1140
|
stepResult = out.result;
|
|
1080
1141
|
} catch (err) {
|
|
1142
|
+
if (isAborted()) {
|
|
1143
|
+
emit({ type: "stopped" });
|
|
1144
|
+
result.stopped = true;
|
|
1145
|
+
return result;
|
|
1146
|
+
}
|
|
1081
1147
|
emit({ type: "error", phase: "execute", error: errMessage(err) });
|
|
1082
1148
|
stepResult = { step, summary: errMessage(err), toolCalls: [], blocked: true };
|
|
1083
1149
|
}
|
|
@@ -1090,7 +1156,7 @@ var createAgent = async (config) => {
|
|
|
1090
1156
|
done.push(
|
|
1091
1157
|
`${step.description} \u2014 ${applied} applied${failed ? `, ${failed} failed` : ""}${stepResult.blocked ? ", blocked" : ""}`
|
|
1092
1158
|
);
|
|
1093
|
-
if (cfg.replan &&
|
|
1159
|
+
if (cfg.replan && iter < cfg.maxIterations && revisions < cfg.maxRevisions && !isAborted() && shouldReplan(stepResult)) {
|
|
1094
1160
|
const decision = await decideReplan(
|
|
1095
1161
|
ctx,
|
|
1096
1162
|
text,
|
|
@@ -1130,11 +1196,13 @@ var createAgent = async (config) => {
|
|
|
1130
1196
|
result.final = summary;
|
|
1131
1197
|
if (config.memory && cfg.compressAfterChars > 0) {
|
|
1132
1198
|
try {
|
|
1133
|
-
const
|
|
1134
|
-
const compacted = await compressHistory(
|
|
1135
|
-
maxChars: cfg.compressAfterChars
|
|
1199
|
+
const transcript = await config.memory.load(sessionId);
|
|
1200
|
+
const compacted = await compressHistory(transcript, synthesizerModel, {
|
|
1201
|
+
maxChars: cfg.compressAfterChars,
|
|
1202
|
+
timeoutMs: cfg.chatTimeoutMs,
|
|
1203
|
+
abortSignal: opts.signal
|
|
1136
1204
|
});
|
|
1137
|
-
if (compacted !==
|
|
1205
|
+
if (compacted !== transcript) await config.memory.replace(sessionId, compacted);
|
|
1138
1206
|
} catch {
|
|
1139
1207
|
}
|
|
1140
1208
|
}
|
|
@@ -1186,6 +1254,9 @@ var openAgentWebDB = (opts = {}) => {
|
|
|
1186
1254
|
}
|
|
1187
1255
|
});
|
|
1188
1256
|
cache.set(name, p);
|
|
1257
|
+
p.catch(() => {
|
|
1258
|
+
if (cache.get(name) === p) cache.delete(name);
|
|
1259
|
+
});
|
|
1189
1260
|
}
|
|
1190
1261
|
return p;
|
|
1191
1262
|
};
|
|
@@ -1199,7 +1270,7 @@ var webcrypto = () => {
|
|
|
1199
1270
|
}
|
|
1200
1271
|
return c;
|
|
1201
1272
|
};
|
|
1202
|
-
var
|
|
1273
|
+
var loadOrCreateKey = async (dbName) => {
|
|
1203
1274
|
const db = await openAgentWebDB({ dbName });
|
|
1204
1275
|
const existing = await db.get(KEYS_STORE, KEY_ID);
|
|
1205
1276
|
if (existing) return existing;
|
|
@@ -1209,9 +1280,29 @@ var getOrCreateVaultKey = async (dbName) => {
|
|
|
1209
1280
|
false,
|
|
1210
1281
|
["encrypt", "decrypt"]
|
|
1211
1282
|
);
|
|
1212
|
-
|
|
1283
|
+
const tx = db.transaction(KEYS_STORE, "readwrite");
|
|
1284
|
+
const winner = await tx.store.get(KEY_ID);
|
|
1285
|
+
if (winner) {
|
|
1286
|
+
await tx.done;
|
|
1287
|
+
return winner;
|
|
1288
|
+
}
|
|
1289
|
+
await tx.store.put(key, KEY_ID);
|
|
1290
|
+
await tx.done;
|
|
1213
1291
|
return key;
|
|
1214
1292
|
};
|
|
1293
|
+
var keyCache = /* @__PURE__ */ new Map();
|
|
1294
|
+
var getOrCreateVaultKey = (dbName) => {
|
|
1295
|
+
const cacheKey = dbName ?? "agent-web";
|
|
1296
|
+
let p = keyCache.get(cacheKey);
|
|
1297
|
+
if (!p) {
|
|
1298
|
+
p = loadOrCreateKey(dbName);
|
|
1299
|
+
keyCache.set(cacheKey, p);
|
|
1300
|
+
p.catch(() => {
|
|
1301
|
+
if (keyCache.get(cacheKey) === p) keyCache.delete(cacheKey);
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
return p;
|
|
1305
|
+
};
|
|
1215
1306
|
var textEncoder = new TextEncoder();
|
|
1216
1307
|
var textDecoder = new TextDecoder();
|
|
1217
1308
|
var encryptJSON = async (key, value) => {
|