@theokit/agents 0.5.0 → 0.7.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.
@@ -477,7 +477,8 @@ function translateSystemEvent(msg, runId) {
477
477
  __name(translateSystemEvent, "translateSystemEvent");
478
478
  function translateAssistantEvent(msg) {
479
479
  const events = [];
480
- const content = msg.content;
480
+ const message = msg.message;
481
+ const content = message?.content;
481
482
  if (!Array.isArray(content)) return events;
482
483
  for (const block of content) {
483
484
  const b = block;
@@ -501,12 +502,14 @@ function translateAssistantEvent(msg) {
501
502
  __name(translateAssistantEvent, "translateAssistantEvent");
502
503
  function translateToolCallEvent(msg) {
503
504
  const status = msg.status;
505
+ const callId = asString(msg.call_id, `tc-${Date.now()}`);
506
+ const toolName = asString(msg.name, "unknown");
504
507
  if (status === "completed") {
505
508
  return [
506
509
  {
507
510
  type: "tool_result",
508
- callId: asString(msg.id, `tc-${Date.now()}`),
509
- toolName: asString(msg.name, "unknown"),
511
+ callId,
512
+ toolName,
510
513
  output: asString(msg.result, ""),
511
514
  durationMs: 0,
512
515
  isError: false
@@ -517,9 +520,9 @@ function translateToolCallEvent(msg) {
517
520
  return [
518
521
  {
519
522
  type: "tool_result",
520
- callId: asString(msg.id, `tc-${Date.now()}`),
521
- toolName: asString(msg.name, "unknown"),
522
- output: asString(msg.error, "Tool failed"),
523
+ callId,
524
+ toolName,
525
+ output: asString(msg.result, "Tool failed"),
523
526
  durationMs: 0,
524
527
  isError: true
525
528
  }
@@ -530,7 +533,7 @@ function translateToolCallEvent(msg) {
530
533
  __name(translateToolCallEvent, "translateToolCallEvent");
531
534
  function translateStatusEvent(msg) {
532
535
  const s = msg.status;
533
- if (s === "done" || s === "completed") {
536
+ if (s === "FINISHED" || s === "CANCELLED") {
534
537
  return [
535
538
  {
536
539
  type: "done",
@@ -545,12 +548,12 @@ function translateStatusEvent(msg) {
545
548
  }
546
549
  ];
547
550
  }
548
- if (s === "error") {
551
+ if (s === "ERROR" || s === "EXPIRED") {
549
552
  return [
550
553
  {
551
554
  type: "error",
552
555
  code: "AGENT_ERROR",
553
- message: asString(msg.error, "Agent error"),
556
+ message: asString(msg.message, "Agent error"),
554
557
  retryable: false
555
558
  }
556
559
  ];
@@ -570,7 +573,7 @@ function translateSdkEvent(msg, runId) {
570
573
  return [
571
574
  {
572
575
  type: "thinking",
573
- content: asString(msg.content, "")
576
+ content: asString(msg.text, "")
574
577
  }
575
578
  ];
576
579
  case "status":
@@ -656,23 +659,27 @@ function createSdkAgentStream(compiled, compiledTools, apiKey, envModel) {
656
659
  ...m8
657
660
  });
658
661
  const run = await agent.send(message);
662
+ let sawTerminal = false;
659
663
  for await (const sdkEvent of run.stream()) {
660
664
  const translated = translateSdkEvent(sdkEvent, runId);
661
665
  for (const event of translated) {
666
+ if (event.type === "done" || event.type === "error") sawTerminal = true;
662
667
  yield event;
663
668
  }
664
669
  }
665
- yield {
666
- type: "done",
667
- result: "",
668
- usage: {
669
- inputTokens: 0,
670
- outputTokens: 0,
671
- totalTokens: 0
672
- },
673
- durationMs: Date.now() - t0,
674
- cost: 0
675
- };
670
+ if (!sawTerminal) {
671
+ yield {
672
+ type: "done",
673
+ result: "",
674
+ usage: {
675
+ inputTokens: 0,
676
+ outputTokens: 0,
677
+ totalTokens: 0
678
+ },
679
+ durationMs: Date.now() - t0,
680
+ cost: 0
681
+ };
682
+ }
676
683
  await agent.dispose();
677
684
  } catch (err) {
678
685
  yield {
@@ -687,7 +694,66 @@ function createSdkAgentStream(compiled, compiledTools, apiKey, envModel) {
687
694
  }
688
695
  __name(createSdkAgentStream, "createSdkAgentStream");
689
696
 
690
- // src/bridge/agent-orchestrator.ts
697
+ // src/loop/loop-strategy.ts
698
+ import { z } from "zod";
699
+ var DEFAULT_MAX_ITERATIONS = 8;
700
+ var loopStrategyConfigSchema = z.object({
701
+ name: z.enum([
702
+ "simple-chat",
703
+ "plan-act-reflect",
704
+ "react"
705
+ ]),
706
+ maxIterations: z.number().int().min(1)
707
+ });
708
+ function resolveLoopStrategy(strategy, maxIterations = DEFAULT_MAX_ITERATIONS) {
709
+ const cfg = loopStrategyConfigSchema.parse({
710
+ name: strategy,
711
+ maxIterations
712
+ });
713
+ if (cfg.name === "simple-chat") {
714
+ return {
715
+ name: cfg.name,
716
+ maxIterations: cfg.maxIterations,
717
+ shouldContinue: /* @__PURE__ */ __name(() => false, "shouldContinue")
718
+ };
719
+ }
720
+ return {
721
+ name: cfg.name,
722
+ maxIterations: cfg.maxIterations,
723
+ shouldContinue: /* @__PURE__ */ __name((outcome) => outcome.finishReason === "tool-calls" && outcome.round < cfg.maxIterations, "shouldContinue")
724
+ };
725
+ }
726
+ __name(resolveLoopStrategy, "resolveLoopStrategy");
727
+
728
+ // src/loop/reflection-strategy.ts
729
+ import { z as z2 } from "zod";
730
+ var reflectionStrategyConfigSchema = z2.object({
731
+ name: z2.string().min(1)
732
+ });
733
+ var ladderReflectionStrategy = {
734
+ name: "ladder",
735
+ reflect(outcome) {
736
+ if (outcome.finishReason === "tool-calls") {
737
+ return {
738
+ feedback: `Tool results received (round ${outcome.round}). Reflect on whether the goal is met; if not, refine the approach and continue.`,
739
+ continue: true
740
+ };
741
+ }
742
+ return {
743
+ continue: false
744
+ };
745
+ }
746
+ };
747
+ var noopReflectionStrategy = {
748
+ name: "noop",
749
+ reflect() {
750
+ return {
751
+ continue: true
752
+ };
753
+ }
754
+ };
755
+
756
+ // src/bridge/delegation-types.ts
691
757
  var BudgetExceededError = class extends Error {
692
758
  static {
693
759
  __name(this, "BudgetExceededError");
@@ -711,16 +777,235 @@ var DelegationError = class extends Error {
711
777
  this.name = "DelegationError";
712
778
  }
713
779
  };
780
+
781
+ // src/loop/run-reflective-loop.ts
714
782
  function asString2(value, fallback) {
715
- if (typeof value === "string") return value;
716
- return fallback;
783
+ return typeof value === "string" ? value : fallback;
717
784
  }
718
785
  __name(asString2, "asString");
719
786
  function asNumber(value, fallback) {
720
- if (typeof value === "number") return value;
721
- return fallback;
787
+ return typeof value === "number" ? value : fallback;
722
788
  }
723
789
  __name(asNumber, "asNumber");
790
+ var NO_PROGRESS_THRESHOLD = 2;
791
+ var MAINLOOP_METRIC = "[THEO_AGENT_MAINLOOP_RUNTIME_APPLIED]";
792
+ var TOOL_CALLS = "tool-calls";
793
+ 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.";
794
+ function stableStringify(value) {
795
+ if (value === void 0) return "undefined";
796
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
797
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
798
+ const obj = value;
799
+ const entries = Object.keys(obj).sort((a, b) => a.localeCompare(b)).map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`);
800
+ return `{${entries.join(",")}}`;
801
+ }
802
+ __name(stableStringify, "stableStringify");
803
+ function roundSignature(toolCalls, text) {
804
+ const calls = toolCalls.map((tc) => `${tc.name}:${stableStringify(tc.input)}`).sort((a, b) => a.localeCompare(b)).join(",");
805
+ return `${calls}|${text}`;
806
+ }
807
+ __name(roundSignature, "roundSignature");
808
+ function terminalReason(reflectionContinue, roundReason, round, maxIterations) {
809
+ if (reflectionContinue && roundReason === TOOL_CALLS && round >= maxIterations) return "step_limit";
810
+ if (roundReason === TOOL_CALLS) return "stop";
811
+ return roundReason;
812
+ }
813
+ __name(terminalReason, "terminalReason");
814
+ function buildPrompt(round, maxIterations, message, feedback) {
815
+ const hint = round === maxIterations ? `${STEP_LIMIT_HINT}
816
+
817
+ ` : "";
818
+ const body = round === 1 || !feedback ? message : `${message}
819
+
820
+ [reflection] ${feedback}`;
821
+ return hint + body;
822
+ }
823
+ __name(buildPrompt, "buildPrompt");
824
+ async function consumeRoundOrThrow(factory, prompt, sessionId, signal, agentName) {
825
+ try {
826
+ return await consumeOneRound(factory, prompt, sessionId, signal);
827
+ } catch (err) {
828
+ if (err instanceof BudgetExceededError || err instanceof DelegationError) throw err;
829
+ throw new DelegationError(agentName, err);
830
+ }
831
+ }
832
+ __name(consumeRoundOrThrow, "consumeRoundOrThrow");
833
+ function finalize(acc, round, reason, strategyName) {
834
+ acc.rounds = round;
835
+ acc.finishReason = reason;
836
+ console.debug(MAINLOOP_METRIC, {
837
+ strategy: strategyName,
838
+ rounds: round,
839
+ terminal: reason
840
+ });
841
+ return acc;
842
+ }
843
+ __name(finalize, "finalize");
844
+ function deriveFinishReason(signals) {
845
+ if (signals.sawError) return "error";
846
+ if (signals.sawDone && signals.doneFinishReason === TOOL_CALLS) return TOOL_CALLS;
847
+ if (signals.sawToolResult) return TOOL_CALLS;
848
+ return "stop";
849
+ }
850
+ __name(deriveFinishReason, "deriveFinishReason");
851
+ async function consumeOneRound(factory, prompt, sessionId, signal) {
852
+ const r = {
853
+ responseText: "",
854
+ toolCalls: [],
855
+ cost: 0,
856
+ tokens: 0,
857
+ finishReason: "stop",
858
+ errorMessage: ""
859
+ };
860
+ const signals = {
861
+ sawError: false,
862
+ sawDone: false,
863
+ doneFinishReason: "",
864
+ sawToolResult: false
865
+ };
866
+ for await (const event of factory(prompt, sessionId)) {
867
+ if (signal?.aborted) break;
868
+ if (event.type === "text_delta" && typeof event.content === "string") {
869
+ r.responseText += event.content;
870
+ } else if (event.type === "tool_result") {
871
+ signals.sawToolResult = true;
872
+ r.toolCalls.push({
873
+ name: asString2(event.toolName, "unknown"),
874
+ input: event.input ?? {},
875
+ output: asString2(event.output, "")
876
+ });
877
+ } else if (event.type === "done") {
878
+ signals.sawDone = true;
879
+ signals.doneFinishReason = asString2(event.finishReason, "");
880
+ r.cost = asNumber(event.cost, 0);
881
+ r.tokens = event.usage?.totalTokens ?? 0;
882
+ } else if (event.type === "error") {
883
+ signals.sawError = true;
884
+ r.errorMessage = asString2(event.message, "Unknown agent error");
885
+ }
886
+ }
887
+ r.finishReason = deriveFinishReason(signals);
888
+ return r;
889
+ }
890
+ __name(consumeOneRound, "consumeOneRound");
891
+ async function runReflectiveLoop(factory, message, sessionId, config) {
892
+ const { loop, reflection, budget = Number.POSITIVE_INFINITY, signal, agentName = loop.name } = config;
893
+ const acc = {
894
+ response: "",
895
+ toolCalls: [],
896
+ cost: 0,
897
+ tokens: 0,
898
+ rounds: 0
899
+ };
900
+ let round = 1;
901
+ let feedback;
902
+ let prevSig;
903
+ let stuck = 0;
904
+ while (!signal?.aborted) {
905
+ const prompt = buildPrompt(round, loop.maxIterations, message, feedback);
906
+ const r = await consumeRoundOrThrow(factory, prompt, sessionId, signal, agentName);
907
+ acc.response += r.responseText;
908
+ acc.toolCalls.push(...r.toolCalls);
909
+ acc.cost += r.cost;
910
+ acc.tokens += r.tokens;
911
+ if (r.finishReason === "error") throw new DelegationError(agentName, r.errorMessage);
912
+ if (Number.isFinite(budget) && acc.cost > budget) {
913
+ throw new BudgetExceededError(agentName, acc.cost, budget);
914
+ }
915
+ if (r.finishReason === TOOL_CALLS) {
916
+ const sig = roundSignature(r.toolCalls, r.responseText);
917
+ stuck = sig === prevSig ? stuck + 1 : 0;
918
+ if (stuck >= NO_PROGRESS_THRESHOLD) return finalize(acc, round, "no_progress", loop.name);
919
+ prevSig = sig;
920
+ }
921
+ const outcome = {
922
+ finishReason: r.finishReason,
923
+ round,
924
+ toolCalls: r.toolCalls,
925
+ responseText: r.responseText
926
+ };
927
+ const reflectionResult = reflection.reflect(outcome);
928
+ if (!(reflectionResult.continue && loop.shouldContinue(outcome))) {
929
+ const reason = terminalReason(reflectionResult.continue, r.finishReason, round, loop.maxIterations);
930
+ return finalize(acc, round, reason, loop.name);
931
+ }
932
+ feedback = reflectionResult.feedback;
933
+ round += 1;
934
+ }
935
+ acc.rounds = round - 1;
936
+ return acc;
937
+ }
938
+ __name(runReflectiveLoop, "runReflectiveLoop");
939
+
940
+ // src/loop/agent-runner.ts
941
+ var AgentRunner = class {
942
+ static {
943
+ __name(this, "AgentRunner");
944
+ }
945
+ compiled;
946
+ agentName;
947
+ loopStrategy;
948
+ reflectionStrategy;
949
+ streamEnabled;
950
+ constructor(compiled, agentName, loopStrategy, reflectionStrategy, streamEnabled) {
951
+ this.compiled = compiled;
952
+ this.agentName = agentName;
953
+ this.loopStrategy = loopStrategy;
954
+ this.reflectionStrategy = reflectionStrategy;
955
+ this.streamEnabled = streamEnabled;
956
+ }
957
+ /** Start a fluent builder for `AgentClass`. */
958
+ static builder(AgentClass) {
959
+ return new AgentRunnerBuilder(AgentClass);
960
+ }
961
+ /** Run the agent to a terminal result via the shared reflective loop. */
962
+ run(message, opts) {
963
+ const streamFactory = createSdkAgentStream(this.compiled, this.compiled.tools, opts.apiKey, this.compiled.model);
964
+ const sessionId = opts.sessionId ?? `runner-${crypto.randomUUID()}`;
965
+ return runReflectiveLoop(streamFactory, message, sessionId, {
966
+ loop: this.loopStrategy,
967
+ reflection: this.reflectionStrategy,
968
+ budget: opts.budget,
969
+ agentName: this.agentName,
970
+ signal: opts.signal
971
+ });
972
+ }
973
+ };
974
+ var AgentRunnerBuilder = class {
975
+ static {
976
+ __name(this, "AgentRunnerBuilder");
977
+ }
978
+ AgentClass;
979
+ reflectionOverride;
980
+ streamEnabled = true;
981
+ constructor(AgentClass) {
982
+ this.AgentClass = AgentClass;
983
+ }
984
+ /** Override the default reflection strategy (OCP — plan Drawback #2). No arg ⇒ keep default. */
985
+ reflection(strategy) {
986
+ if (strategy) this.reflectionOverride = strategy;
987
+ return this;
988
+ }
989
+ /** Record the streaming preference (see {@link AgentRunner.streamEnabled}). */
990
+ stream(enabled = true) {
991
+ this.streamEnabled = enabled;
992
+ return this;
993
+ }
994
+ /** Walk + compile + resolve strategies — the compile→execute boundary (no I/O). */
995
+ build() {
996
+ const walk = walkAgentMetadata(this.AgentClass, []);
997
+ const toolboxInstances = new Map(walk.toolboxes.map((tb) => [
998
+ tb.class,
999
+ new tb.class()
1000
+ ]));
1001
+ const compiled = compileAgent(walk, toolboxInstances);
1002
+ const loopStrategy = resolveLoopStrategy(walk.mainLoop.strategy, walk.mainLoop.maxIterations);
1003
+ const reflectionStrategy = this.reflectionOverride ?? (walk.mainLoop.strategy === "plan-act-reflect" ? ladderReflectionStrategy : noopReflectionStrategy);
1004
+ return new AgentRunner(compiled, walk.agentConfig.name, loopStrategy, reflectionStrategy, this.streamEnabled);
1005
+ }
1006
+ };
1007
+
1008
+ // src/bridge/agent-orchestrator.ts
724
1009
  function requireApiKey(opts, agentName) {
725
1010
  const apiKey = opts.apiKey ?? "";
726
1011
  if (!apiKey) {
@@ -738,33 +1023,6 @@ function mergeTools(parentTools, subTools) {
738
1023
  ];
739
1024
  }
740
1025
  __name(mergeTools, "mergeTools");
741
- function processStreamEvent(event, acc, budget, agentName) {
742
- if (event.type === "text_delta" && typeof event.content === "string") {
743
- acc.response += event.content;
744
- return;
745
- }
746
- if (event.type === "tool_result") {
747
- acc.toolCalls.push({
748
- name: asString2(event.toolName, "unknown"),
749
- input: event.input ?? {},
750
- output: asString2(event.output, "")
751
- });
752
- return;
753
- }
754
- if (event.type === "done") {
755
- acc.cost = asNumber(event.cost, 0);
756
- const usage = event.usage;
757
- acc.tokens = usage?.totalTokens ?? 0;
758
- if (Number.isFinite(budget) && acc.cost > budget) {
759
- throw new BudgetExceededError(agentName, acc.cost, budget);
760
- }
761
- return;
762
- }
763
- if (event.type === "error") {
764
- throw new DelegationError(agentName, asString2(event.message, "Unknown agent error"));
765
- }
766
- }
767
- __name(processStreamEvent, "processStreamEvent");
768
1026
  async function delegate(SubAgentClass, message, opts = {}) {
769
1027
  const apiKey = requireApiKey(opts, SubAgentClass.name);
770
1028
  const walk = walkAgentMetadata(SubAgentClass, []);
@@ -777,24 +1035,15 @@ async function delegate(SubAgentClass, message, opts = {}) {
777
1035
  const budget = Math.min(opts.budget ?? Infinity, opts.parentBudgetRemaining ?? Infinity);
778
1036
  const streamFactory = createSdkAgentStream(compiled, allTools, apiKey, walk.agentConfig.model);
779
1037
  const sessionId = opts.sessionId ?? `sub-${crypto.randomUUID()}`;
780
- const acc = {
781
- response: "",
782
- toolCalls: [],
783
- cost: 0,
784
- tokens: 0
785
- };
786
- try {
787
- for await (const event of streamFactory(message, sessionId)) {
788
- processStreamEvent(event, acc, budget, SubAgentClass.name);
789
- }
790
- } catch (err) {
791
- if (err instanceof BudgetExceededError || err instanceof DelegationError) throw err;
792
- throw new DelegationError(SubAgentClass.name, err);
793
- }
794
- if (Number.isFinite(budget) && acc.cost > budget) {
795
- throw new BudgetExceededError(SubAgentClass.name, acc.cost, budget);
796
- }
797
- return acc;
1038
+ const loopStrategy = resolveLoopStrategy(walk.mainLoop.strategy, walk.mainLoop.maxIterations);
1039
+ const reflection = loopStrategy.name === "plan-act-reflect" ? ladderReflectionStrategy : noopReflectionStrategy;
1040
+ return runReflectiveLoop(streamFactory, message, sessionId, {
1041
+ loop: loopStrategy,
1042
+ reflection,
1043
+ budget,
1044
+ agentName: SubAgentClass.name,
1045
+ signal: opts.signal
1046
+ });
798
1047
  }
799
1048
  __name(delegate, "delegate");
800
1049
 
@@ -944,10 +1193,18 @@ export {
944
1193
  generateAgentRoutes,
945
1194
  translateSdkEvent,
946
1195
  createSdkAgentStream,
1196
+ DEFAULT_MAX_ITERATIONS,
1197
+ loopStrategyConfigSchema,
1198
+ resolveLoopStrategy,
1199
+ reflectionStrategyConfigSchema,
1200
+ ladderReflectionStrategy,
1201
+ noopReflectionStrategy,
947
1202
  BudgetExceededError,
948
1203
  DelegationError,
1204
+ AgentRunner,
1205
+ AgentRunnerBuilder,
949
1206
  delegate,
950
1207
  generateAgentManifest,
951
1208
  agentsPlugin
952
1209
  };
953
- //# sourceMappingURL=chunk-2MI27XCA.js.map
1210
+ //# sourceMappingURL=chunk-2MYIZ4OT.js.map