@dudko.dev/agent-web 0.0.1 → 0.0.3
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 +41 -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 +38 -7
- package/dist/index.d.ts +38 -7
- 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 +56 -15
package/dist/index.js
CHANGED
|
@@ -94,7 +94,9 @@ var compressHistory = async (messages, model, opts = {}) => {
|
|
|
94
94
|
const result = await generate(model, {
|
|
95
95
|
system: "Summarize the following conversation into a compact set of durable facts and decisions. Output plain text only.",
|
|
96
96
|
prompt: transcript,
|
|
97
|
-
maxOutputTokens: 400
|
|
97
|
+
maxOutputTokens: 400,
|
|
98
|
+
timeoutMs: opts.timeoutMs,
|
|
99
|
+
abortSignal: opts.abortSignal
|
|
98
100
|
});
|
|
99
101
|
const clean = (result.text || "").trim();
|
|
100
102
|
if (!clean) return messages;
|
|
@@ -302,9 +304,19 @@ var stateBlock = (state) => state && state.trim() ? `
|
|
|
302
304
|
|
|
303
305
|
STATE:
|
|
304
306
|
${state}` : "";
|
|
307
|
+
var clip = (s, max) => s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
|
|
308
|
+
var historyBlock = (history) => {
|
|
309
|
+
if (!history || history.length === 0) return "";
|
|
310
|
+
const lines = history.slice(-8).map((m) => `${m.role}: ${clip(m.content, 400)}`);
|
|
311
|
+
return `
|
|
312
|
+
|
|
313
|
+
CONVERSATION SO FAR:
|
|
314
|
+
${lines.join("\n")}`;
|
|
315
|
+
};
|
|
305
316
|
var PLANNER_NATIVE = `You are the PLANNER of a tool-using agent that changes a workspace step by step.
|
|
306
317
|
Produce a brief "thought" and an ordered "steps" list (1\u20136 DISTINCT, self-contained steps) grounded in the current STATE and the available TOOLS.
|
|
307
318
|
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".
|
|
319
|
+
If a CONVERSATION SO FAR section is present, use it to resolve references to earlier turns.
|
|
308
320
|
Never repeat or pad steps.`;
|
|
309
321
|
var PLANNER_PROMPTED = `You are the PLANNER of a tool-using agent that changes a workspace step by step.
|
|
310
322
|
|
|
@@ -312,7 +324,8 @@ Reply with a single JSON object, nothing else:
|
|
|
312
324
|
{ "reply": string, "plan": string[] }
|
|
313
325
|
- 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".
|
|
314
326
|
- For a real goal: "reply" is one short sentence; "plan" is 1\u20136 DISTINCT, self-contained steps. Never repeat or pad steps.
|
|
315
|
-
- Plan realistic steps the available TOOLS can perform, grounded in the current STATE
|
|
327
|
+
- Plan realistic steps the available TOOLS can perform, grounded in the current STATE.
|
|
328
|
+
- If a CONVERSATION SO FAR section is present, use it to resolve references to earlier turns.`;
|
|
316
329
|
var EXECUTOR_NATIVE = `You are the EXECUTOR of a tool-using agent. Carry out ONLY the current step by calling the provided tools.
|
|
317
330
|
Build on the current STATE \u2014 do not repeat work that is already there.
|
|
318
331
|
When the step is done, reply with one short human sentence describing what you did (no JSON).
|
|
@@ -340,7 +353,7 @@ var SYNTHESIZER_SYSTEM = `You are the SYNTHESIZER. In 1\u20133 short, friendly s
|
|
|
340
353
|
var defaultPrompts = {
|
|
341
354
|
planner: (ctx) => ({
|
|
342
355
|
system: ctx.mode === "prompted" ? PLANNER_PROMPTED : PLANNER_NATIVE,
|
|
343
|
-
prompt: `GOAL: ${ctx.goal}${stateBlock(ctx.state)}
|
|
356
|
+
prompt: `GOAL: ${ctx.goal}${historyBlock(ctx.history)}${stateBlock(ctx.state)}
|
|
344
357
|
|
|
345
358
|
TOOLS:
|
|
346
359
|
${ctx.toolCatalog}`
|
|
@@ -385,11 +398,12 @@ var withSystem = (base, extra) => extra && extra.trim() ? `${extra.trim()}
|
|
|
385
398
|
${base}` : base;
|
|
386
399
|
|
|
387
400
|
// src/tools/mode.ts
|
|
388
|
-
var modelProviderId = (model) => typeof model === "string" ? model : model.provider ?? "";
|
|
389
401
|
var LOCAL_RE = /web-?llm|mlc|browser-ai|transformers|nano|built-?in/i;
|
|
390
402
|
var selectToolMode = (model, mode = "auto") => {
|
|
391
403
|
if (mode === "native" || mode === "prompted") return mode;
|
|
392
|
-
|
|
404
|
+
if (typeof model === "string") return "native";
|
|
405
|
+
const provider = model.provider ?? "";
|
|
406
|
+
return LOCAL_RE.test(provider) ? "prompted" : "native";
|
|
393
407
|
};
|
|
394
408
|
|
|
395
409
|
// src/tools/types.ts
|
|
@@ -514,24 +528,35 @@ var normalizeSteps = (arr, cap = 12) => {
|
|
|
514
528
|
}
|
|
515
529
|
return out;
|
|
516
530
|
};
|
|
531
|
+
var decodeJsonString = (body) => {
|
|
532
|
+
const v = tryParse(`"${body}"`);
|
|
533
|
+
return typeof v === "string" ? v : body;
|
|
534
|
+
};
|
|
517
535
|
var salvageStringArray = (text, field) => {
|
|
518
|
-
const
|
|
519
|
-
if (
|
|
520
|
-
const region = text.slice(at);
|
|
536
|
+
const m = new RegExp(`"${field}"\\s*:\\s*\\[`).exec(text);
|
|
537
|
+
if (!m) return [];
|
|
521
538
|
const out = [];
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
539
|
+
let i = m.index + m[0].length;
|
|
540
|
+
while (i < text.length && text[i] !== "]") {
|
|
541
|
+
if (text[i] !== '"') {
|
|
542
|
+
i += 1;
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
let j = i + 1;
|
|
546
|
+
let esc = false;
|
|
547
|
+
while (j < text.length && (esc || text[j] !== '"')) {
|
|
548
|
+
esc = !esc && text[j] === "\\";
|
|
549
|
+
j += 1;
|
|
550
|
+
}
|
|
551
|
+
if (j >= text.length) break;
|
|
552
|
+
out.push(decodeJsonString(text.slice(i + 1, j)));
|
|
553
|
+
i = j + 1;
|
|
529
554
|
}
|
|
530
555
|
return out;
|
|
531
556
|
};
|
|
532
557
|
var salvageString = (text, field) => {
|
|
533
558
|
const m = text.match(new RegExp(`"${field}"\\s*:\\s*"((?:[^"\\\\]|\\\\.)*)"`));
|
|
534
|
-
return m ? m[1].trim() : "";
|
|
559
|
+
return m ? decodeJsonString(m[1]).trim() : "";
|
|
535
560
|
};
|
|
536
561
|
var parsePlannerResponse = (raw) => {
|
|
537
562
|
const text = stripFences(raw);
|
|
@@ -654,12 +679,14 @@ var runPrompted = async (model, opts) => {
|
|
|
654
679
|
temperature: opts.temperature,
|
|
655
680
|
abortSignal: timeoutSignal(opts.abortSignal, opts.timeoutMs)
|
|
656
681
|
});
|
|
657
|
-
if (result.text) opts.callbacks?.onTextDelta?.(result.text);
|
|
658
682
|
const parsed = parseExecutorResponse(result.text);
|
|
683
|
+
if (parsed.reply) opts.callbacks?.onTextDelta?.(parsed.reply);
|
|
684
|
+
const active = opts.activeTools;
|
|
685
|
+
const tools = active ? Object.fromEntries(Object.entries(opts.tools).filter(([name]) => active.includes(name))) : opts.tools;
|
|
659
686
|
const toolCalls = [];
|
|
660
687
|
for (const action of parsed.actions) {
|
|
661
688
|
opts.callbacks?.onToolCall?.(action.tool, action.args);
|
|
662
|
-
const rec = await dispatch(action,
|
|
689
|
+
const rec = await dispatch(action, tools, { abortSignal: opts.abortSignal });
|
|
663
690
|
toolCalls.push(rec);
|
|
664
691
|
opts.callbacks?.onToolResult?.(rec.name, rec.output, rec.ok);
|
|
665
692
|
}
|
|
@@ -688,13 +715,15 @@ var summaryOf = (text, toolCallCount) => {
|
|
|
688
715
|
};
|
|
689
716
|
var executeStep = async (ctx, goal, step, index, total, done) => {
|
|
690
717
|
const state = await ctx.state();
|
|
718
|
+
const active = activeToolNames(ctx, step);
|
|
719
|
+
const toolCatalog = active === void 0 ? ctx.toolCatalog : renderCatalog(Object.fromEntries(active.map((name) => [name, ctx.tools[name]])));
|
|
691
720
|
const parts = ctx.prompts.executor({
|
|
692
721
|
goal,
|
|
693
722
|
state,
|
|
694
723
|
step: step.description,
|
|
695
724
|
index,
|
|
696
725
|
total,
|
|
697
|
-
toolCatalog
|
|
726
|
+
toolCatalog,
|
|
698
727
|
done,
|
|
699
728
|
mode: ctx.executorMode
|
|
700
729
|
});
|
|
@@ -703,7 +732,7 @@ var executeStep = async (ctx, goal, step, index, total, done) => {
|
|
|
703
732
|
system: systemFor(ctx, parts.system),
|
|
704
733
|
prompt: parts.prompt,
|
|
705
734
|
tools: ctx.tools,
|
|
706
|
-
activeTools:
|
|
735
|
+
activeTools: active,
|
|
707
736
|
maxSteps: ctx.config.maxStepsPerTask,
|
|
708
737
|
maxOutputTokens: ctx.config.budgets.executor,
|
|
709
738
|
temperature: ctx.config.temperature,
|
|
@@ -764,24 +793,26 @@ var toSteps = (raw) => raw.filter((s) => s.description && s.description.trim()).
|
|
|
764
793
|
}));
|
|
765
794
|
var createPlan = async (ctx, goal) => {
|
|
766
795
|
const state = await ctx.state();
|
|
767
|
-
const
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
796
|
+
const commonFor = (mode) => {
|
|
797
|
+
const parts = ctx.prompts.planner({
|
|
798
|
+
goal,
|
|
799
|
+
state,
|
|
800
|
+
toolCatalog: ctx.toolCatalog,
|
|
801
|
+
mode,
|
|
802
|
+
history: ctx.history
|
|
803
|
+
});
|
|
804
|
+
return {
|
|
805
|
+
system: systemFor(ctx, parts.system),
|
|
806
|
+
prompt: parts.prompt,
|
|
807
|
+
maxOutputTokens: ctx.config.budgets.planner,
|
|
808
|
+
temperature: ctx.config.temperature,
|
|
809
|
+
abortSignal: ctx.signal,
|
|
810
|
+
timeoutMs: ctx.config.chatTimeoutMs
|
|
811
|
+
};
|
|
781
812
|
};
|
|
782
813
|
if (ctx.plannerMode === "native") {
|
|
783
814
|
try {
|
|
784
|
-
const result2 = await generateStructured(ctx.plannerModel, PlanSchema,
|
|
815
|
+
const result2 = await generateStructured(ctx.plannerModel, PlanSchema, commonFor("native"));
|
|
785
816
|
return {
|
|
786
817
|
plan: { thought: result2.object.thought, steps: toSteps(result2.object.steps) },
|
|
787
818
|
usage: normalizeUsage(result2.usage)
|
|
@@ -790,14 +821,14 @@ var createPlan = async (ctx, goal) => {
|
|
|
790
821
|
ctx.emit({ type: "retry", phase: "plan", attempt: 1, error: asMessage(err) });
|
|
791
822
|
}
|
|
792
823
|
}
|
|
793
|
-
const result = await generate(ctx.plannerModel,
|
|
824
|
+
const result = await generate(ctx.plannerModel, commonFor("prompted"));
|
|
794
825
|
const parsed = parsePlannerResponse(result.text);
|
|
795
826
|
return {
|
|
796
827
|
plan: {
|
|
797
828
|
thought: parsed.reply,
|
|
798
829
|
steps: toSteps(parsed.plan.map((description) => ({ description })))
|
|
799
830
|
},
|
|
800
|
-
usage:
|
|
831
|
+
usage: normalizeUsage(result.usage)
|
|
801
832
|
};
|
|
802
833
|
};
|
|
803
834
|
var asMessage = (err) => err instanceof Error ? err.message : String(err);
|
|
@@ -805,26 +836,31 @@ var asMessage = (err) => err instanceof Error ? err.message : String(err);
|
|
|
805
836
|
// src/agent/replanner.ts
|
|
806
837
|
var decideReplan = async (ctx, goal, done, remaining) => {
|
|
807
838
|
const state = await ctx.state();
|
|
808
|
-
const
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
839
|
+
const commonFor = (mode) => {
|
|
840
|
+
const parts = ctx.prompts.replanner({ goal, state, done, remaining, mode });
|
|
841
|
+
return {
|
|
842
|
+
system: systemFor(ctx, parts.system),
|
|
843
|
+
prompt: parts.prompt,
|
|
844
|
+
maxOutputTokens: ctx.config.budgets.replanner,
|
|
845
|
+
temperature: ctx.config.temperature,
|
|
846
|
+
abortSignal: ctx.signal,
|
|
847
|
+
timeoutMs: ctx.config.chatTimeoutMs
|
|
848
|
+
};
|
|
816
849
|
};
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
const
|
|
850
|
+
if (ctx.plannerMode === "native") {
|
|
851
|
+
try {
|
|
852
|
+
const result = await generateStructured(ctx.plannerModel, ReplanSchema, commonFor("native"));
|
|
820
853
|
return {
|
|
821
|
-
decision:
|
|
822
|
-
reason:
|
|
823
|
-
plan:
|
|
824
|
-
usage: normalizeUsage(
|
|
854
|
+
decision: result.object.decision,
|
|
855
|
+
reason: result.object.reason,
|
|
856
|
+
plan: result.object.plan ?? [],
|
|
857
|
+
usage: normalizeUsage(result.usage)
|
|
825
858
|
};
|
|
859
|
+
} catch {
|
|
826
860
|
}
|
|
827
|
-
|
|
861
|
+
}
|
|
862
|
+
try {
|
|
863
|
+
const result = await generate(ctx.plannerModel, commonFor("prompted"));
|
|
828
864
|
const parsed = parseReplannerResponse(result.text);
|
|
829
865
|
return {
|
|
830
866
|
decision: parsed.decision,
|
|
@@ -841,7 +877,7 @@ var decideReplan = async (ctx, goal, done, remaining) => {
|
|
|
841
877
|
var synthesizeAnswer = async (ctx, goal, done) => {
|
|
842
878
|
const state = await ctx.state();
|
|
843
879
|
const parts = ctx.prompts.synthesizer({ goal, state, done });
|
|
844
|
-
const result =
|
|
880
|
+
const result = stream(ctx.synthesizerModel, {
|
|
845
881
|
system: systemFor(ctx, parts.system),
|
|
846
882
|
prompt: parts.prompt,
|
|
847
883
|
maxOutputTokens: ctx.config.budgets.synthesizer,
|
|
@@ -849,37 +885,54 @@ var synthesizeAnswer = async (ctx, goal, done) => {
|
|
|
849
885
|
abortSignal: ctx.signal,
|
|
850
886
|
timeoutMs: ctx.config.chatTimeoutMs
|
|
851
887
|
});
|
|
852
|
-
|
|
888
|
+
let text = "";
|
|
889
|
+
let verdict = "unknown";
|
|
890
|
+
for await (const delta of result.textStream) {
|
|
891
|
+
text += delta;
|
|
892
|
+
if (verdict === "unknown") {
|
|
893
|
+
const lead = text.trimStart();
|
|
894
|
+
if (!lead) continue;
|
|
895
|
+
verdict = looksLikeJson(lead) ? "suppress" : "emit";
|
|
896
|
+
if (verdict === "emit") ctx.emit({ type: "final.text-delta", delta: text });
|
|
897
|
+
} else if (verdict === "emit") {
|
|
898
|
+
ctx.emit({ type: "final.text-delta", delta });
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
const clean = parsePlainText(text);
|
|
853
902
|
return {
|
|
854
903
|
text: clean || "Done \u2014 the changes have been applied.",
|
|
855
|
-
usage: normalizeUsage(result.usage)
|
|
904
|
+
usage: normalizeUsage(await result.usage)
|
|
856
905
|
};
|
|
857
906
|
};
|
|
858
907
|
|
|
859
908
|
// src/agent/runner.ts
|
|
860
909
|
var errMessage = (err) => err instanceof Error ? err.message : String(err);
|
|
910
|
+
var filterTools = (all, available, excluded) => {
|
|
911
|
+
let entries = Object.entries(all);
|
|
912
|
+
if (available && available.length > 0) entries = entries.filter(([n]) => available.includes(n));
|
|
913
|
+
if (excluded && excluded.length > 0) entries = entries.filter(([n]) => !excluded.includes(n));
|
|
914
|
+
return Object.fromEntries(entries);
|
|
915
|
+
};
|
|
861
916
|
var createAgent = async (config) => {
|
|
862
917
|
const cfg = resolveConfig(config);
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
),
|
|
874
|
-
buildModelFromStage(
|
|
875
|
-
resolveStage(config.model, config.synthesizer, "synthesizer"),
|
|
876
|
-
config.credentials,
|
|
877
|
-
cfg.clientName
|
|
878
|
-
)
|
|
918
|
+
const buildStage = (override, stageName) => buildModelFromStage(
|
|
919
|
+
resolveStage(config.model, override, stageName),
|
|
920
|
+
config.credentials,
|
|
921
|
+
cfg.clientName
|
|
922
|
+
);
|
|
923
|
+
const executorP = buildStage(void 0, "executor");
|
|
924
|
+
const [executorModel, plannerModel, synthesizerModel] = await Promise.all([
|
|
925
|
+
executorP,
|
|
926
|
+
config.planner === void 0 ? executorP : buildStage(config.planner, "planner"),
|
|
927
|
+
config.synthesizer === void 0 ? executorP : buildStage(config.synthesizer, "synthesizer")
|
|
879
928
|
]);
|
|
880
929
|
const plannerMode = selectToolMode(plannerModel, cfg.toolMode);
|
|
881
930
|
const executorMode = selectToolMode(executorModel, cfg.toolMode);
|
|
882
|
-
const tools =
|
|
931
|
+
const tools = filterTools(
|
|
932
|
+
config.tools ?? {},
|
|
933
|
+
config.availableTools,
|
|
934
|
+
config.excludedTools
|
|
935
|
+
);
|
|
883
936
|
const toolCatalog = renderCatalog(tools);
|
|
884
937
|
const prompts = { ...defaultPrompts, ...config.prompts };
|
|
885
938
|
const run = async (goal, opts = {}) => {
|
|
@@ -904,21 +957,6 @@ var createAgent = async (config) => {
|
|
|
904
957
|
};
|
|
905
958
|
if (!text) return result;
|
|
906
959
|
const state = async () => config.describeState ? config.describeState() : void 0;
|
|
907
|
-
const ctx = {
|
|
908
|
-
config: cfg,
|
|
909
|
-
raw: config,
|
|
910
|
-
plannerModel,
|
|
911
|
-
executorModel,
|
|
912
|
-
synthesizerModel,
|
|
913
|
-
plannerMode,
|
|
914
|
-
executorMode,
|
|
915
|
-
tools,
|
|
916
|
-
toolCatalog,
|
|
917
|
-
prompts,
|
|
918
|
-
emit,
|
|
919
|
-
signal: opts.signal,
|
|
920
|
-
state
|
|
921
|
-
};
|
|
922
960
|
const isAborted = () => opts.signal?.aborted === true;
|
|
923
961
|
const bumpUsage = (u, phase) => {
|
|
924
962
|
usage = addUsage(usage, u);
|
|
@@ -933,6 +971,29 @@ var createAgent = async (config) => {
|
|
|
933
971
|
}
|
|
934
972
|
};
|
|
935
973
|
emit({ type: "run.start", goal: text });
|
|
974
|
+
let history = [];
|
|
975
|
+
if (config.memory) {
|
|
976
|
+
try {
|
|
977
|
+
history = await config.memory.load(sessionId);
|
|
978
|
+
} catch {
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
const ctx = {
|
|
982
|
+
config: cfg,
|
|
983
|
+
raw: config,
|
|
984
|
+
plannerModel,
|
|
985
|
+
executorModel,
|
|
986
|
+
synthesizerModel,
|
|
987
|
+
plannerMode,
|
|
988
|
+
executorMode,
|
|
989
|
+
tools,
|
|
990
|
+
toolCatalog,
|
|
991
|
+
prompts,
|
|
992
|
+
emit,
|
|
993
|
+
signal: opts.signal,
|
|
994
|
+
state,
|
|
995
|
+
history
|
|
996
|
+
};
|
|
936
997
|
await remember({ role: "user", content: text });
|
|
937
998
|
try {
|
|
938
999
|
const planned = await createPlan(ctx, text);
|
|
@@ -973,6 +1034,11 @@ var createAgent = async (config) => {
|
|
|
973
1034
|
bumpUsage(out.usage, "execute");
|
|
974
1035
|
stepResult = out.result;
|
|
975
1036
|
} catch (err) {
|
|
1037
|
+
if (isAborted()) {
|
|
1038
|
+
emit({ type: "stopped" });
|
|
1039
|
+
result.stopped = true;
|
|
1040
|
+
return result;
|
|
1041
|
+
}
|
|
976
1042
|
emit({ type: "error", phase: "execute", error: errMessage(err) });
|
|
977
1043
|
stepResult = { step, summary: errMessage(err), toolCalls: [], blocked: true };
|
|
978
1044
|
}
|
|
@@ -985,7 +1051,7 @@ var createAgent = async (config) => {
|
|
|
985
1051
|
done.push(
|
|
986
1052
|
`${step.description} \u2014 ${applied} applied${failed ? `, ${failed} failed` : ""}${stepResult.blocked ? ", blocked" : ""}`
|
|
987
1053
|
);
|
|
988
|
-
if (cfg.replan &&
|
|
1054
|
+
if (cfg.replan && iter < cfg.maxIterations && revisions < cfg.maxRevisions && !isAborted() && shouldReplan(stepResult)) {
|
|
989
1055
|
const decision = await decideReplan(
|
|
990
1056
|
ctx,
|
|
991
1057
|
text,
|
|
@@ -1025,11 +1091,13 @@ var createAgent = async (config) => {
|
|
|
1025
1091
|
result.final = summary;
|
|
1026
1092
|
if (config.memory && cfg.compressAfterChars > 0) {
|
|
1027
1093
|
try {
|
|
1028
|
-
const
|
|
1029
|
-
const compacted = await compressHistory(
|
|
1030
|
-
maxChars: cfg.compressAfterChars
|
|
1094
|
+
const transcript = await config.memory.load(sessionId);
|
|
1095
|
+
const compacted = await compressHistory(transcript, synthesizerModel, {
|
|
1096
|
+
maxChars: cfg.compressAfterChars,
|
|
1097
|
+
timeoutMs: cfg.chatTimeoutMs,
|
|
1098
|
+
abortSignal: opts.signal
|
|
1031
1099
|
});
|
|
1032
|
-
if (compacted !==
|
|
1100
|
+
if (compacted !== transcript) await config.memory.replace(sessionId, compacted);
|
|
1033
1101
|
} catch {
|
|
1034
1102
|
}
|
|
1035
1103
|
}
|
|
@@ -1078,6 +1146,9 @@ var openAgentWebDB = (opts = {}) => {
|
|
|
1078
1146
|
}
|
|
1079
1147
|
});
|
|
1080
1148
|
cache.set(name, p);
|
|
1149
|
+
p.catch(() => {
|
|
1150
|
+
if (cache.get(name) === p) cache.delete(name);
|
|
1151
|
+
});
|
|
1081
1152
|
}
|
|
1082
1153
|
return p;
|
|
1083
1154
|
};
|
|
@@ -1091,7 +1162,7 @@ var webcrypto = () => {
|
|
|
1091
1162
|
}
|
|
1092
1163
|
return c;
|
|
1093
1164
|
};
|
|
1094
|
-
var
|
|
1165
|
+
var loadOrCreateKey = async (dbName) => {
|
|
1095
1166
|
const db = await openAgentWebDB({ dbName });
|
|
1096
1167
|
const existing = await db.get(KEYS_STORE, KEY_ID);
|
|
1097
1168
|
if (existing) return existing;
|
|
@@ -1101,9 +1172,29 @@ var getOrCreateVaultKey = async (dbName) => {
|
|
|
1101
1172
|
false,
|
|
1102
1173
|
["encrypt", "decrypt"]
|
|
1103
1174
|
);
|
|
1104
|
-
|
|
1175
|
+
const tx = db.transaction(KEYS_STORE, "readwrite");
|
|
1176
|
+
const winner = await tx.store.get(KEY_ID);
|
|
1177
|
+
if (winner) {
|
|
1178
|
+
await tx.done;
|
|
1179
|
+
return winner;
|
|
1180
|
+
}
|
|
1181
|
+
await tx.store.put(key, KEY_ID);
|
|
1182
|
+
await tx.done;
|
|
1105
1183
|
return key;
|
|
1106
1184
|
};
|
|
1185
|
+
var keyCache = /* @__PURE__ */ new Map();
|
|
1186
|
+
var getOrCreateVaultKey = (dbName) => {
|
|
1187
|
+
const cacheKey = dbName ?? "agent-web";
|
|
1188
|
+
let p = keyCache.get(cacheKey);
|
|
1189
|
+
if (!p) {
|
|
1190
|
+
p = loadOrCreateKey(dbName);
|
|
1191
|
+
keyCache.set(cacheKey, p);
|
|
1192
|
+
p.catch(() => {
|
|
1193
|
+
if (keyCache.get(cacheKey) === p) keyCache.delete(cacheKey);
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
return p;
|
|
1197
|
+
};
|
|
1107
1198
|
var textEncoder = new TextEncoder();
|
|
1108
1199
|
var textDecoder = new TextDecoder();
|
|
1109
1200
|
var encryptJSON = async (key, value) => {
|