@theokit/agents 0.6.0 → 0.8.0

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.
@@ -9,6 +9,7 @@ import {
9
9
  TOOL_METHODS,
10
10
  Trace,
11
11
  getAgentConfig,
12
+ getCompactionConfig,
12
13
  getContextWindowConfig,
13
14
  getGatewayConfig,
14
15
  getMcpConfig,
@@ -18,7 +19,7 @@ import {
18
19
  getProjectContextConfig,
19
20
  getSkillsConfig,
20
21
  getSubAgents
21
- } from "./chunk-MVEY7HEY.js";
22
+ } from "./chunk-GVPUUKKE.js";
22
23
  import {
23
24
  __name
24
25
  } from "./chunk-7QVYU63E.js";
@@ -205,6 +206,7 @@ function walkAgentMetadata(AgentClass, toolboxClasses = []) {
205
206
  const contextWindow = getContextWindowConfig(AgentClass);
206
207
  const projectContext = getProjectContextConfig(AgentClass);
207
208
  warnUnmappedDecoratorKnobs(AgentClass.name, contextWindow, projectContext);
209
+ const compaction = getCompactionConfig(AgentClass);
208
210
  const result = {
209
211
  agentConfig,
210
212
  mainLoop,
@@ -219,7 +221,8 @@ function walkAgentMetadata(AgentClass, toolboxClasses = []) {
219
221
  skills,
220
222
  contextWindow,
221
223
  projectContext,
222
- mcpServers
224
+ mcpServers,
225
+ compaction
223
226
  };
224
227
  if (toolboxClasses.length === 0) {
225
228
  agentWalkCache.set(AgentClass, result);
@@ -694,16 +697,47 @@ function createSdkAgentStream(compiled, compiledTools, apiKey, envModel) {
694
697
  }
695
698
  __name(createSdkAgentStream, "createSdkAgentStream");
696
699
 
697
- // src/loop/loop-strategy.ts
700
+ // src/loop/compaction-strategy.ts
701
+ import { compactTranscript } from "@theokit/sdk/compaction";
698
702
  import { z } from "zod";
703
+ var DEFAULT_KEEP_TOKENS = 8e3;
704
+ var compactionStrategyConfigSchema = z.object({
705
+ name: z.literal("token-budget"),
706
+ keepTokens: z.number().int().positive()
707
+ });
708
+ function resolveCompactionStrategy(name, config) {
709
+ const cfg = compactionStrategyConfigSchema.parse({
710
+ name,
711
+ keepTokens: config.keepTokens
712
+ });
713
+ return {
714
+ name: cfg.name,
715
+ keepTokens: cfg.keepTokens,
716
+ compact: /* @__PURE__ */ __name((messages, options) => compactTranscript(messages, {
717
+ keepTokens: options?.keepTokens ?? cfg.keepTokens,
718
+ summarize: options?.summarize,
719
+ marker: options?.marker,
720
+ summaryTemplate: options?.summaryTemplate,
721
+ // Default-safe: a thrown summarize keeps the transcript (app opts out via failSafe:false).
722
+ failSafe: options?.failSafe ?? true
723
+ }), "compact")
724
+ };
725
+ }
726
+ __name(resolveCompactionStrategy, "resolveCompactionStrategy");
727
+ var tokenBudgetCompactionStrategy = resolveCompactionStrategy("token-budget", {
728
+ keepTokens: DEFAULT_KEEP_TOKENS
729
+ });
730
+
731
+ // src/loop/loop-strategy.ts
732
+ import { z as z2 } from "zod";
699
733
  var DEFAULT_MAX_ITERATIONS = 8;
700
- var loopStrategyConfigSchema = z.object({
701
- name: z.enum([
734
+ var loopStrategyConfigSchema = z2.object({
735
+ name: z2.enum([
702
736
  "simple-chat",
703
737
  "plan-act-reflect",
704
738
  "react"
705
739
  ]),
706
- maxIterations: z.number().int().min(1)
740
+ maxIterations: z2.number().int().min(1)
707
741
  });
708
742
  function resolveLoopStrategy(strategy, maxIterations = DEFAULT_MAX_ITERATIONS) {
709
743
  const cfg = loopStrategyConfigSchema.parse({
@@ -726,9 +760,9 @@ function resolveLoopStrategy(strategy, maxIterations = DEFAULT_MAX_ITERATIONS) {
726
760
  __name(resolveLoopStrategy, "resolveLoopStrategy");
727
761
 
728
762
  // src/loop/reflection-strategy.ts
729
- import { z as z2 } from "zod";
730
- var reflectionStrategyConfigSchema = z2.object({
731
- name: z2.string().min(1)
763
+ import { z as z3 } from "zod";
764
+ var reflectionStrategyConfigSchema = z3.object({
765
+ name: z3.string().min(1)
732
766
  });
733
767
  var ladderReflectionStrategy = {
734
768
  name: "ladder",
@@ -787,14 +821,68 @@ function asNumber(value, fallback) {
787
821
  return typeof value === "number" ? value : fallback;
788
822
  }
789
823
  __name(asNumber, "asNumber");
824
+ var NO_PROGRESS_THRESHOLD = 2;
825
+ var MAINLOOP_METRIC = "[THEO_AGENT_MAINLOOP_RUNTIME_APPLIED]";
826
+ var TOOL_CALLS = "tool-calls";
827
+ var STEP_LIMIT_HINT = "This is your final round \u2014 do not call any more tools; summarize the work done so far and list any remaining tasks.";
828
+ function stableStringify(value) {
829
+ if (value === void 0) return "undefined";
830
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
831
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
832
+ const obj = value;
833
+ const entries = Object.keys(obj).sort((a, b) => a.localeCompare(b)).map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`);
834
+ return `{${entries.join(",")}}`;
835
+ }
836
+ __name(stableStringify, "stableStringify");
837
+ function roundSignature(toolCalls, text) {
838
+ const calls = toolCalls.map((tc) => `${tc.name}:${stableStringify(tc.input)}`).sort((a, b) => a.localeCompare(b)).join(",");
839
+ return `${calls}|${text}`;
840
+ }
841
+ __name(roundSignature, "roundSignature");
842
+ function terminalReason(reflectionContinue, roundReason, round, maxIterations) {
843
+ if (reflectionContinue && roundReason === TOOL_CALLS && round >= maxIterations) return "step_limit";
844
+ if (roundReason === TOOL_CALLS) return "stop";
845
+ return roundReason;
846
+ }
847
+ __name(terminalReason, "terminalReason");
848
+ function buildPrompt(round, maxIterations, message, feedback) {
849
+ const hint = round === maxIterations ? `${STEP_LIMIT_HINT}
850
+
851
+ ` : "";
852
+ const body = round === 1 || !feedback ? message : `${message}
853
+
854
+ [reflection] ${feedback}`;
855
+ return hint + body;
856
+ }
857
+ __name(buildPrompt, "buildPrompt");
858
+ async function* consumeRoundOrThrow(factory, prompt, sessionId, signal, agentName) {
859
+ try {
860
+ return yield* consumeOneRound(factory, prompt, sessionId, signal);
861
+ } catch (err) {
862
+ if (err instanceof BudgetExceededError || err instanceof DelegationError) throw err;
863
+ throw new DelegationError(agentName, err);
864
+ }
865
+ }
866
+ __name(consumeRoundOrThrow, "consumeRoundOrThrow");
867
+ function finalize(acc, round, reason, strategyName) {
868
+ acc.rounds = round;
869
+ acc.finishReason = reason;
870
+ console.debug(MAINLOOP_METRIC, {
871
+ strategy: strategyName,
872
+ rounds: round,
873
+ terminal: reason
874
+ });
875
+ return acc;
876
+ }
877
+ __name(finalize, "finalize");
790
878
  function deriveFinishReason(signals) {
791
879
  if (signals.sawError) return "error";
792
- if (signals.sawDone && signals.doneFinishReason === "tool-calls") return "tool-calls";
793
- if (signals.sawToolResult) return "tool-calls";
880
+ if (signals.sawDone && signals.doneFinishReason === TOOL_CALLS) return TOOL_CALLS;
881
+ if (signals.sawToolResult) return TOOL_CALLS;
794
882
  return "stop";
795
883
  }
796
884
  __name(deriveFinishReason, "deriveFinishReason");
797
- async function consumeOneRound(factory, prompt, sessionId, signal) {
885
+ async function* consumeOneRound(factory, prompt, sessionId, signal) {
798
886
  const r = {
799
887
  responseText: "",
800
888
  toolCalls: [],
@@ -811,6 +899,7 @@ async function consumeOneRound(factory, prompt, sessionId, signal) {
811
899
  };
812
900
  for await (const event of factory(prompt, sessionId)) {
813
901
  if (signal?.aborted) break;
902
+ yield event;
814
903
  if (event.type === "text_delta" && typeof event.content === "string") {
815
904
  r.responseText += event.content;
816
905
  } else if (event.type === "tool_result") {
@@ -834,7 +923,7 @@ async function consumeOneRound(factory, prompt, sessionId, signal) {
834
923
  return r;
835
924
  }
836
925
  __name(consumeOneRound, "consumeOneRound");
837
- async function runReflectiveLoop(factory, message, sessionId, config) {
926
+ async function* runReflectiveLoopStream(factory, message, sessionId, config) {
838
927
  const { loop, reflection, budget = Number.POSITIVE_INFINITY, signal, agentName = loop.name } = config;
839
928
  const acc = {
840
929
  response: "",
@@ -845,17 +934,11 @@ async function runReflectiveLoop(factory, message, sessionId, config) {
845
934
  };
846
935
  let round = 1;
847
936
  let feedback;
937
+ let prevSig;
938
+ let stuck = 0;
848
939
  while (!signal?.aborted) {
849
- const prompt = round === 1 || !feedback ? message : `${message}
850
-
851
- [reflection] ${feedback}`;
852
- let r;
853
- try {
854
- r = await consumeOneRound(factory, prompt, sessionId, signal);
855
- } catch (err) {
856
- if (err instanceof BudgetExceededError || err instanceof DelegationError) throw err;
857
- throw new DelegationError(agentName, err);
858
- }
940
+ const prompt = buildPrompt(round, loop.maxIterations, message, feedback);
941
+ const r = yield* consumeRoundOrThrow(factory, prompt, sessionId, signal, agentName);
859
942
  acc.response += r.responseText;
860
943
  acc.toolCalls.push(...r.toolCalls);
861
944
  acc.cost += r.cost;
@@ -864,6 +947,12 @@ async function runReflectiveLoop(factory, message, sessionId, config) {
864
947
  if (Number.isFinite(budget) && acc.cost > budget) {
865
948
  throw new BudgetExceededError(agentName, acc.cost, budget);
866
949
  }
950
+ if (r.finishReason === TOOL_CALLS) {
951
+ const sig = roundSignature(r.toolCalls, r.responseText);
952
+ stuck = sig === prevSig ? stuck + 1 : 0;
953
+ if (stuck >= NO_PROGRESS_THRESHOLD) return finalize(acc, round, "no_progress", loop.name);
954
+ prevSig = sig;
955
+ }
867
956
  const outcome = {
868
957
  finishReason: r.finishReason,
869
958
  round,
@@ -872,12 +961,8 @@ async function runReflectiveLoop(factory, message, sessionId, config) {
872
961
  };
873
962
  const reflectionResult = reflection.reflect(outcome);
874
963
  if (!(reflectionResult.continue && loop.shouldContinue(outcome))) {
875
- acc.rounds = round;
876
- console.debug("[THEO_AGENT_MAINLOOP_RUNTIME_APPLIED]", {
877
- strategy: loop.name,
878
- rounds: round
879
- });
880
- return acc;
964
+ const reason = terminalReason(reflectionResult.continue, r.finishReason, round, loop.maxIterations);
965
+ return finalize(acc, round, reason, loop.name);
881
966
  }
882
967
  feedback = reflectionResult.feedback;
883
968
  round += 1;
@@ -885,6 +970,13 @@ async function runReflectiveLoop(factory, message, sessionId, config) {
885
970
  acc.rounds = round - 1;
886
971
  return acc;
887
972
  }
973
+ __name(runReflectiveLoopStream, "runReflectiveLoopStream");
974
+ async function runReflectiveLoop(factory, message, sessionId, config) {
975
+ const gen = runReflectiveLoopStream(factory, message, sessionId, config);
976
+ let res = await gen.next();
977
+ while (!res.done) res = await gen.next();
978
+ return res.value;
979
+ }
888
980
  __name(runReflectiveLoop, "runReflectiveLoop");
889
981
 
890
982
  // src/loop/agent-runner.ts
@@ -894,25 +986,47 @@ var AgentRunner = class {
894
986
  }
895
987
  compiled;
896
988
  agentName;
989
+ /** The resolved terminal-decision strategy (parity with `delegate()`). */
897
990
  loopStrategy;
991
+ /** The resolved between-round reflection (default or `.reflection(custom)` override). */
898
992
  reflectionStrategy;
993
+ /**
994
+ * Recorded streaming preference. The reflective loop currently always streams via
995
+ * the SDK `Run.stream()`; a non-streaming collect mode is future work — the flag is
996
+ * captured + exposed here, not yet branched on (honest per G10: documented, not a
997
+ * silent no-op).
998
+ */
899
999
  streamEnabled;
900
- constructor(compiled, agentName, loopStrategy, reflectionStrategy, streamEnabled) {
901
- this.compiled = compiled;
902
- this.agentName = agentName;
903
- this.loopStrategy = loopStrategy;
904
- this.reflectionStrategy = reflectionStrategy;
905
- this.streamEnabled = streamEnabled;
1000
+ /**
1001
+ * V4-F: the resolved compaction strategy (from `@Compaction` or `.compaction()`),
1002
+ * or `undefined` when neither is declared — compaction is opt-in (EC-4). CALLABLE
1003
+ * by the app (ADR D1: `runner.compaction?.compact(messages, { summarize })`); the
1004
+ * reflective loop does NOT auto-invoke it (the SDK owns per-turn context).
1005
+ */
1006
+ compaction;
1007
+ constructor(state) {
1008
+ this.compiled = state.compiled;
1009
+ this.agentName = state.agentName;
1010
+ this.loopStrategy = state.loopStrategy;
1011
+ this.reflectionStrategy = state.reflectionStrategy;
1012
+ this.streamEnabled = state.streamEnabled;
1013
+ this.compaction = state.compaction;
906
1014
  }
907
1015
  /** Start a fluent builder for `AgentClass`. */
908
1016
  static builder(AgentClass) {
909
1017
  return new AgentRunnerBuilder(AgentClass);
910
1018
  }
911
- /** Run the agent to a terminal result via the shared reflective loop. */
912
- run(message, opts) {
1019
+ /**
1020
+ * V4-D-stream: stream the agent's events LIVE across the reflective loop, returning
1021
+ * the aggregated {@link DelegationResult} as the generator's return value. This is the
1022
+ * on-ramp for streaming-first apps (SSE) — `runReflectiveLoopStream` yields every
1023
+ * round's events before the loop terminates. `streamEnabled` is honored: when the
1024
+ * builder set `.stream(false)`, callers should use {@link run} instead.
1025
+ */
1026
+ stream(message, opts) {
913
1027
  const streamFactory = createSdkAgentStream(this.compiled, this.compiled.tools, opts.apiKey, this.compiled.model);
914
1028
  const sessionId = opts.sessionId ?? `runner-${crypto.randomUUID()}`;
915
- return runReflectiveLoop(streamFactory, message, sessionId, {
1029
+ return runReflectiveLoopStream(streamFactory, message, sessionId, {
916
1030
  loop: this.loopStrategy,
917
1031
  reflection: this.reflectionStrategy,
918
1032
  budget: opts.budget,
@@ -920,6 +1034,13 @@ var AgentRunner = class {
920
1034
  signal: opts.signal
921
1035
  });
922
1036
  }
1037
+ /** Run the agent to a terminal result via the shared reflective loop (collect mode). */
1038
+ async run(message, opts) {
1039
+ const gen = this.stream(message, opts);
1040
+ let res = await gen.next();
1041
+ while (!res.done) res = await gen.next();
1042
+ return res.value;
1043
+ }
923
1044
  };
924
1045
  var AgentRunnerBuilder = class {
925
1046
  static {
@@ -928,6 +1049,7 @@ var AgentRunnerBuilder = class {
928
1049
  AgentClass;
929
1050
  reflectionOverride;
930
1051
  streamEnabled = true;
1052
+ compactionOverride;
931
1053
  constructor(AgentClass) {
932
1054
  this.AgentClass = AgentClass;
933
1055
  }
@@ -941,6 +1063,18 @@ var AgentRunnerBuilder = class {
941
1063
  this.streamEnabled = enabled;
942
1064
  return this;
943
1065
  }
1066
+ /**
1067
+ * V4-F: declare the compaction strategy (e.g. `.compaction('token-budget', { keepTokens: 8000 })`).
1068
+ * Resolved + validated at {@link build} (EC-5 — fail-fast there, not here). This builder
1069
+ * call WINS over a `@Compaction` decorator on the same agent (EC-1 — explicit override).
1070
+ */
1071
+ compaction(name, options = {}) {
1072
+ this.compactionOverride = {
1073
+ name,
1074
+ keepTokens: options.keepTokens
1075
+ };
1076
+ return this;
1077
+ }
944
1078
  /** Walk + compile + resolve strategies — the compile→execute boundary (no I/O). */
945
1079
  build() {
946
1080
  const walk = walkAgentMetadata(this.AgentClass, []);
@@ -951,7 +1085,18 @@ var AgentRunnerBuilder = class {
951
1085
  const compiled = compileAgent(walk, toolboxInstances);
952
1086
  const loopStrategy = resolveLoopStrategy(walk.mainLoop.strategy, walk.mainLoop.maxIterations);
953
1087
  const reflectionStrategy = this.reflectionOverride ?? (walk.mainLoop.strategy === "plan-act-reflect" ? ladderReflectionStrategy : noopReflectionStrategy);
954
- return new AgentRunner(compiled, walk.agentConfig.name, loopStrategy, reflectionStrategy, this.streamEnabled);
1088
+ const compactionDecl = this.compactionOverride ?? walk.compaction;
1089
+ const compaction = compactionDecl ? resolveCompactionStrategy(compactionDecl.name, {
1090
+ keepTokens: compactionDecl.keepTokens
1091
+ }) : void 0;
1092
+ return new AgentRunner({
1093
+ compiled,
1094
+ agentName: walk.agentConfig.name,
1095
+ loopStrategy,
1096
+ reflectionStrategy,
1097
+ streamEnabled: this.streamEnabled,
1098
+ compaction
1099
+ });
955
1100
  }
956
1101
  };
957
1102
 
@@ -1143,6 +1288,10 @@ export {
1143
1288
  generateAgentRoutes,
1144
1289
  translateSdkEvent,
1145
1290
  createSdkAgentStream,
1291
+ DEFAULT_KEEP_TOKENS,
1292
+ compactionStrategyConfigSchema,
1293
+ resolveCompactionStrategy,
1294
+ tokenBudgetCompactionStrategy,
1146
1295
  DEFAULT_MAX_ITERATIONS,
1147
1296
  loopStrategyConfigSchema,
1148
1297
  resolveLoopStrategy,
@@ -1157,4 +1306,4 @@ export {
1157
1306
  generateAgentManifest,
1158
1307
  agentsPlugin
1159
1308
  };
1160
- //# sourceMappingURL=chunk-KTYBQ7HY.js.map
1309
+ //# sourceMappingURL=chunk-BCSRKDP6.js.map