plugin-agent-orchestrator 1.0.19 → 1.0.21

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.
Files changed (100) hide show
  1. package/dist/client/hooks/useRunEventStream.d.ts +22 -0
  2. package/dist/client/index.d.ts +1 -0
  3. package/dist/client/index.js +1 -1
  4. package/dist/externalVersion.js +6 -6
  5. package/dist/server/collections/agent-execution-spans.js +24 -0
  6. package/dist/server/collections/agent-loop-runs.js +36 -0
  7. package/dist/server/collections/orchestrator-config.js +14 -0
  8. package/dist/server/migrations/20260601000000-add-token-fields.d.ts +7 -0
  9. package/dist/server/migrations/20260601000000-add-token-fields.js +101 -0
  10. package/dist/server/plugin.js +47 -0
  11. package/dist/server/resources/agent-loop.js +33 -25
  12. package/dist/server/resources/tracing.js +5 -8
  13. package/dist/server/services/AgentHarness.d.ts +2 -0
  14. package/dist/server/services/AgentHarness.js +56 -90
  15. package/dist/server/services/AgentLoopController.d.ts +33 -20
  16. package/dist/server/services/AgentLoopController.js +164 -125
  17. package/dist/server/services/AgentLoopRepository.js +16 -34
  18. package/dist/server/services/AgentLoopService.d.ts +28 -18
  19. package/dist/server/services/AgentLoopService.js +7 -1
  20. package/dist/server/services/AgentPlannerService.js +5 -25
  21. package/dist/server/services/AgentRegistryService.d.ts +8 -0
  22. package/dist/server/services/AgentRegistryService.js +34 -24
  23. package/dist/server/services/CircuitBreaker.d.ts +40 -0
  24. package/dist/server/services/CircuitBreaker.js +120 -0
  25. package/dist/server/services/ContextAggregator.d.ts +45 -0
  26. package/dist/server/services/ContextAggregator.js +201 -0
  27. package/dist/server/services/ExecutionSpanService.js +2 -5
  28. package/dist/server/services/RunEventBus.d.ts +9 -0
  29. package/dist/server/services/RunEventBus.js +73 -0
  30. package/dist/server/services/TokenTracker.d.ts +62 -0
  31. package/dist/server/services/TokenTracker.js +173 -0
  32. package/dist/server/skill-hub/plugin.js +6 -6
  33. package/dist/server/skill-hub/tasks/SkillExecutionTask.js +6 -6
  34. package/dist/server/tools/agent-loop.d.ts +8 -8
  35. package/dist/server/tools/agent-loop.js +30 -63
  36. package/dist/server/tools/delegate-task.js +14 -72
  37. package/dist/server/tools/orchestrator-plan.d.ts +6 -6
  38. package/dist/server/tools/orchestrator-plan.js +10 -47
  39. package/dist/server/types.d.ts +47 -0
  40. package/dist/server/types.js +24 -0
  41. package/dist/server/utils/ctx-utils.d.ts +30 -0
  42. package/dist/server/utils/ctx-utils.js +152 -0
  43. package/dist/server/utils/logging.d.ts +6 -0
  44. package/dist/server/utils/logging.js +86 -0
  45. package/package.json +44 -44
  46. package/src/client/AgentRunsTab.tsx +764 -764
  47. package/src/client/HarnessProfilesTab.tsx +247 -247
  48. package/src/client/OrchestratorSettings.tsx +106 -106
  49. package/src/client/RulesTab.tsx +716 -716
  50. package/src/client/hooks/useRunEventStream.ts +76 -0
  51. package/src/client/index.tsx +2 -1
  52. package/src/client/plugin.tsx +27 -27
  53. package/src/client/skill-hub/components/LoopSettings.tsx +331 -331
  54. package/src/client/skill-hub/index.tsx +51 -51
  55. package/src/client/skill-hub/tools/InteractionSchemasProvider.tsx +99 -99
  56. package/src/client/skill-hub/tools/SkillHubCard.tsx +109 -109
  57. package/src/client/skill-hub/tools/loopTemplates.ts +52 -52
  58. package/src/client/skill-hub/tools/registerSkillLoopCards.ts +58 -58
  59. package/src/client/tools/PlanApprovalCard.tsx +175 -175
  60. package/src/client/tools/registerOrchestratorCards.ts +7 -7
  61. package/src/server/__tests__/agent-loop-controller.test.ts +375 -0
  62. package/src/server/__tests__/circuit-breaker.test.ts +169 -0
  63. package/src/server/__tests__/context-aggregator.test.ts +222 -0
  64. package/src/server/__tests__/parallel-execution.test.ts +318 -0
  65. package/src/server/__tests__/smoke.test.ts +120 -0
  66. package/src/server/collections/agent-execution-spans.ts +24 -0
  67. package/src/server/collections/agent-harness-profiles.ts +59 -59
  68. package/src/server/collections/agent-loop-events.ts +71 -71
  69. package/src/server/collections/agent-loop-runs.ts +38 -1
  70. package/src/server/collections/agent-loop-steps.ts +144 -144
  71. package/src/server/collections/orchestrator-config.ts +14 -0
  72. package/src/server/collections/skill-executions.ts +106 -106
  73. package/src/server/collections/skill-loop-configs.ts +65 -65
  74. package/src/server/migrations/20260524000000-add-agent-loop-fields-to-skill-executions.ts +30 -30
  75. package/src/server/migrations/20260524001000-add-plan-approval-and-harness-profiles.ts +142 -142
  76. package/src/server/migrations/20260601000000-add-token-fields.ts +89 -0
  77. package/src/server/plugin.ts +53 -0
  78. package/src/server/resources/agent-loop.ts +21 -12
  79. package/src/server/resources/tracing.ts +3 -7
  80. package/src/server/services/AgentHarness.ts +78 -116
  81. package/src/server/services/AgentLoopController.ts +197 -122
  82. package/src/server/services/AgentLoopRepository.ts +9 -25
  83. package/src/server/services/AgentLoopService.ts +13 -1
  84. package/src/server/services/AgentPlanValidator.ts +73 -73
  85. package/src/server/services/AgentPlannerService.ts +2 -25
  86. package/src/server/services/AgentRegistryService.ts +40 -31
  87. package/src/server/services/CircuitBreaker.ts +116 -0
  88. package/src/server/services/ContextAggregator.ts +239 -0
  89. package/src/server/services/ExecutionSpanService.ts +2 -4
  90. package/src/server/services/RunEventBus.ts +45 -0
  91. package/src/server/services/TokenTracker.ts +209 -0
  92. package/src/server/skill-hub/plugin.ts +898 -897
  93. package/src/server/skill-hub/tasks/SkillExecutionTask.ts +460 -458
  94. package/src/server/tools/agent-loop.ts +18 -57
  95. package/src/server/tools/delegate-task.ts +11 -93
  96. package/src/server/tools/orchestrator-plan.ts +26 -50
  97. package/src/server/tools/skill-execute.ts +160 -160
  98. package/src/server/types.ts +55 -0
  99. package/src/server/utils/ctx-utils.ts +118 -0
  100. package/src/server/utils/logging.ts +63 -0
@@ -0,0 +1,201 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var ContextAggregator_exports = {};
28
+ __export(ContextAggregator_exports, {
29
+ ContextAggregator: () => ContextAggregator
30
+ });
31
+ module.exports = __toCommonJS(ContextAggregator_exports);
32
+ function trimText(text, maxLen) {
33
+ if (text.length <= maxLen) return text;
34
+ return text.slice(0, maxLen) + "\n...[truncated]";
35
+ }
36
+ function estimateTokens(text) {
37
+ return Math.ceil(text.length / 4);
38
+ }
39
+ class ContextAggregator {
40
+ constructor(plugin) {
41
+ this.plugin = plugin;
42
+ }
43
+ get db() {
44
+ return this.plugin.db;
45
+ }
46
+ get app() {
47
+ return this.plugin.app;
48
+ }
49
+ /**
50
+ * Build a structured context string from completed steps of a run.
51
+ *
52
+ * @param runId - agentLoopRuns.id
53
+ * @param maxTokens - Maximum tokens for the context output (default 4000)
54
+ * @param options - Strategy options
55
+ */
56
+ async buildStepContext(runId, maxTokens, options) {
57
+ var _a;
58
+ const effectiveMaxTokens = maxTokens || 4e3;
59
+ let steps;
60
+ try {
61
+ const repo = this.db.getRepository("agentLoopSteps");
62
+ if (!repo) return "";
63
+ steps = await repo.find({
64
+ filter: { runId },
65
+ sort: ["index", "createdAt"],
66
+ pageSize: 500
67
+ });
68
+ } catch {
69
+ return "";
70
+ }
71
+ if (!steps || steps.length === 0) return "";
72
+ const completedSteps = steps.filter((s) => s.status === "succeeded" || s.status === "failed");
73
+ if (completedSteps.length === 0) return "";
74
+ const config = {
75
+ strategy: (options == null ? void 0 : options.strategy) || "all",
76
+ includeToolResults: (options == null ? void 0 : options.includeToolResults) ?? false,
77
+ includeStepOutputs: (options == null ? void 0 : options.includeStepOutputs) ?? true
78
+ };
79
+ let candidates = completedSteps;
80
+ if (config.strategy === "last_n") {
81
+ const n = Math.min(10, completedSteps.length);
82
+ candidates = completedSteps.slice(-n);
83
+ }
84
+ const parts = [];
85
+ for (const step of candidates) {
86
+ const key = step.planKey || `step_${step.index || 0}`;
87
+ const type = step.type || "unknown";
88
+ const target = step.target || "";
89
+ const title = step.title || key;
90
+ const status = step.status || "unknown";
91
+ const lines = [];
92
+ lines.push(`<step key="${key}" type="${type}" target="${target}" status="${status}">`);
93
+ lines.push(` <title>${this.escapeXml(title)}</title>`);
94
+ if (step.description) {
95
+ lines.push(` <description>${this.escapeXml(trimText(step.description, 500))}</description>`);
96
+ }
97
+ if (config.includeStepOutputs && step.output) {
98
+ const outputStr = typeof step.output === "string" ? step.output : this.safeStringify(step.output);
99
+ lines.push(` <output>${this.escapeXml(trimText(outputStr, 2e3))}</output>`);
100
+ }
101
+ if (config.includeToolResults && ((_a = step.metadata) == null ? void 0 : _a.toolResults)) {
102
+ const toolStr = this.safeStringify(step.metadata.toolResults);
103
+ lines.push(` <tool_results>${this.escapeXml(trimText(toolStr, 1500))}</tool_results>`);
104
+ }
105
+ if (step.error) {
106
+ lines.push(` <error>${this.escapeXml(trimText(step.error, 1e3))}</error>`);
107
+ }
108
+ lines.push("</step>");
109
+ parts.push(lines.join("\n"));
110
+ }
111
+ let context = `<previous_steps>
112
+ ${parts.join("\n\n")}
113
+ </previous_steps>`;
114
+ if (estimateTokens(context) > effectiveMaxTokens) {
115
+ context = this.truncateToTokenLimit(context, effectiveMaxTokens);
116
+ }
117
+ return context;
118
+ }
119
+ /**
120
+ * Enrich a base system prompt with step context from the run.
121
+ * Fetches the run from DB to access policy settings (maxContextTokens, etc.).
122
+ *
123
+ * @param basePrompt - The original system prompt to enrich
124
+ * @param runId - agentLoopRuns.id
125
+ * @param _stepId - agentLoopSteps.id (reserved for future per-step context)
126
+ */
127
+ async enrichSystemPrompt(basePrompt, runId, _stepId, options) {
128
+ let run;
129
+ try {
130
+ const repo = this.db.getRepository("agentLoopRuns");
131
+ if (!repo) return basePrompt;
132
+ run = await repo.findOne({ filter: { id: runId } });
133
+ if (!run) return basePrompt;
134
+ } catch {
135
+ return basePrompt;
136
+ }
137
+ const policy = run.policy || {};
138
+ const maxCtxTokens = (options == null ? void 0 : options.maxContextTokens) ?? policy.maxContextTokens ?? 4e3;
139
+ const strategy = (options == null ? void 0 : options.contextSummaryStrategy) ?? policy.contextSummaryStrategy ?? "all";
140
+ const includeToolResults = (options == null ? void 0 : options.includeToolResults) ?? policy.includeToolResults ?? false;
141
+ const includeStepOutputs = (options == null ? void 0 : options.includeStepOutputs) ?? policy.includeStepOutputs ?? true;
142
+ const stepContext = await this.buildStepContext(runId, maxCtxTokens, {
143
+ strategy,
144
+ includeToolResults,
145
+ includeStepOutputs
146
+ });
147
+ if (!stepContext) return basePrompt;
148
+ return `${basePrompt}
149
+
150
+ <previous_steps_context>
151
+ ${stepContext}
152
+ </previous_steps_context>`;
153
+ }
154
+ truncateToTokenLimit(text, maxTokens) {
155
+ const outerMatch = text.match(/<previous_steps>\n([\s\S]*)\n<\/previous_steps>/);
156
+ if (!outerMatch) return text;
157
+ const inner = outerMatch[1];
158
+ const stepBlocks = this.splitStepBlocks(inner);
159
+ if (stepBlocks.length <= 2) {
160
+ const maxChars2 = maxTokens * 4;
161
+ if (text.length <= maxChars2) return text;
162
+ return text.slice(0, maxChars2) + "\n...[truncated]\n</previous_steps>";
163
+ }
164
+ const keepFirst = stepBlocks.slice(0, 2);
165
+ const keepLast = stepBlocks.slice(-2);
166
+ const removed = stepBlocks.length - keepFirst.length - keepLast.length;
167
+ const rebuilt = [
168
+ "<previous_steps>",
169
+ ...keepFirst,
170
+ ` <!-- ... ${removed} intermediate step(s) omitted due to context limit ... -->`,
171
+ ...keepLast,
172
+ "</previous_steps>"
173
+ ].join("\n");
174
+ const maxChars = maxTokens * 4;
175
+ if (rebuilt.length <= maxChars) return rebuilt;
176
+ return rebuilt.slice(0, maxChars) + "\n...[truncated]\n</previous_steps>";
177
+ }
178
+ splitStepBlocks(text) {
179
+ const blocks = [];
180
+ const regex = /<step[\s\S]*?<\/step>/g;
181
+ let match;
182
+ while ((match = regex.exec(text)) !== null) {
183
+ blocks.push(match[0]);
184
+ }
185
+ return blocks;
186
+ }
187
+ escapeXml(value) {
188
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
189
+ }
190
+ safeStringify(value) {
191
+ try {
192
+ return JSON.stringify(value, null, 2);
193
+ } catch {
194
+ return String(value);
195
+ }
196
+ }
197
+ }
198
+ // Annotate the CommonJS export names for ESM import in node:
199
+ 0 && (module.exports = {
200
+ ContextAggregator
201
+ });
@@ -32,11 +32,8 @@ __export(ExecutionSpanService_exports, {
32
32
  setOrchestratorTraceContext: () => setOrchestratorTraceContext
33
33
  });
34
34
  module.exports = __toCommonJS(ExecutionSpanService_exports);
35
+ var import_ctx_utils = require("../utils/ctx-utils");
35
36
  const ORCHESTRATOR_TRACE_CONTEXT_KEY = "__orchestratorTraceContext";
36
- function toPlain(record) {
37
- var _a;
38
- return ((_a = record == null ? void 0 : record.toJSON) == null ? void 0 : _a.call(record)) || record;
39
- }
40
37
  class ExecutionSpanService {
41
38
  constructor(plugin) {
42
39
  this.plugin = plugin;
@@ -53,7 +50,7 @@ class ExecutionSpanService {
53
50
  createdAt: /* @__PURE__ */ new Date()
54
51
  }
55
52
  });
56
- return toPlain(record);
53
+ return (0, import_ctx_utils.toPlain)(record);
57
54
  } catch (error) {
58
55
  (_b = (_a = this.plugin.app.log) == null ? void 0 : _a.warn) == null ? void 0 : _b.call(_a, "[AgentOrchestrator] Failed to create execution span", error);
59
56
  return null;
@@ -0,0 +1,9 @@
1
+ type EventCallback = (event: any) => void;
2
+ declare class RunEventBusImpl {
3
+ private listeners;
4
+ subscribe(runId: string | number, callback: EventCallback): () => void;
5
+ emit(runId: string | number, event: any): void;
6
+ listenerCount(runId: string | number): number;
7
+ }
8
+ export declare function getRunEventBus(): RunEventBusImpl;
9
+ export {};
@@ -0,0 +1,73 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var RunEventBus_exports = {};
28
+ __export(RunEventBus_exports, {
29
+ getRunEventBus: () => getRunEventBus
30
+ });
31
+ module.exports = __toCommonJS(RunEventBus_exports);
32
+ class RunEventBusImpl {
33
+ listeners = /* @__PURE__ */ new Map();
34
+ subscribe(runId, callback) {
35
+ let set = this.listeners.get(runId);
36
+ if (!set) {
37
+ set = /* @__PURE__ */ new Set();
38
+ this.listeners.set(runId, set);
39
+ }
40
+ set.add(callback);
41
+ return () => {
42
+ set == null ? void 0 : set.delete(callback);
43
+ if ((set == null ? void 0 : set.size) === 0) {
44
+ this.listeners.delete(runId);
45
+ }
46
+ };
47
+ }
48
+ emit(runId, event) {
49
+ const set = this.listeners.get(runId);
50
+ if (!set) return;
51
+ for (const callback of set) {
52
+ try {
53
+ callback(event);
54
+ } catch {
55
+ }
56
+ }
57
+ }
58
+ listenerCount(runId) {
59
+ var _a;
60
+ return ((_a = this.listeners.get(runId)) == null ? void 0 : _a.size) || 0;
61
+ }
62
+ }
63
+ let instance = null;
64
+ function getRunEventBus() {
65
+ if (!instance) {
66
+ instance = new RunEventBusImpl();
67
+ }
68
+ return instance;
69
+ }
70
+ // Annotate the CommonJS export names for ESM import in node:
71
+ 0 && (module.exports = {
72
+ getRunEventBus
73
+ });
@@ -0,0 +1,62 @@
1
+ export interface TokenUsage {
2
+ inputTokens: number;
3
+ outputTokens: number;
4
+ totalTokens: number;
5
+ cost: number;
6
+ }
7
+ export interface BudgetConfig {
8
+ budgetMaxTokens?: number;
9
+ budgetMaxCost?: number;
10
+ }
11
+ export interface BudgetCheckResult {
12
+ allowed: boolean;
13
+ reason?: string;
14
+ }
15
+ /**
16
+ * Extract usage_metadata from the final state returned by createReactAgent.invoke().
17
+ *
18
+ * LangChain's createReactAgent returns a final state object with a `messages` array.
19
+ * The last AIMessage in that array carries `usage_metadata` populated by the
20
+ * LLM provider after the final generation step. This is the standard LangChain
21
+ * approach — no private API access needed.
22
+ *
23
+ * Expected shape (from @langchain/core/messages/ai):
24
+ * AIMessage.usage_metadata = {
25
+ * input_tokens: number,
26
+ * output_tokens: number,
27
+ * total_tokens: number,
28
+ * }
29
+ */
30
+ export declare function extractTokenUsage(finalState: any): TokenUsage | null;
31
+ /**
32
+ * Service for tracking token consumption across agent runs and spans.
33
+ *
34
+ * Responsibilities:
35
+ * 1. Parse token usage from LangGraph execution results
36
+ * 2. Persist token counts to agentExecutionSpans
37
+ * 3. Accumulate totals at the agentLoopRuns level
38
+ * 4. Enforce budget limits (max tokens / max cost per run)
39
+ */
40
+ export declare class TokenTracker {
41
+ private readonly plugin;
42
+ constructor(plugin: any);
43
+ get db(): any;
44
+ get app(): any;
45
+ /**
46
+ * Track token usage for a single execution span.
47
+ * Updates the span record and accumulates into the parent run.
48
+ *
49
+ * @param spanId - The agentExecutionSpans.id to update
50
+ * @param usage - Parsed token usage from extractTokenUsage()
51
+ * @param runId - Optional agentLoopRuns.id to accumulate totals
52
+ */
53
+ trackSpan(spanId: string | number | undefined, usage: TokenUsage, runId?: string | number): Promise<void>;
54
+ /**
55
+ * Recalculate total token/cost for a run by summing all its spans.
56
+ */
57
+ accumulateToRun(runId: string | number): Promise<void>;
58
+ /**
59
+ * Check if a run has exceeded its budget limits.
60
+ */
61
+ checkBudget(runId: string | number): Promise<BudgetCheckResult>;
62
+ }
@@ -0,0 +1,173 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var TokenTracker_exports = {};
28
+ __export(TokenTracker_exports, {
29
+ TokenTracker: () => TokenTracker,
30
+ extractTokenUsage: () => extractTokenUsage
31
+ });
32
+ module.exports = __toCommonJS(TokenTracker_exports);
33
+ const PRICE_PER_1K_INPUT = Number(process.env.ORCHESTRATOR_PRICE_PER_1K_INPUT || 3e-3);
34
+ const PRICE_PER_1K_OUTPUT = Number(process.env.ORCHESTRATOR_PRICE_PER_1K_OUTPUT || 0.015);
35
+ function estimateCost(inputTokens, outputTokens) {
36
+ return inputTokens / 1e3 * PRICE_PER_1K_INPUT + outputTokens / 1e3 * PRICE_PER_1K_OUTPUT;
37
+ }
38
+ function extractTokenUsage(finalState) {
39
+ if (!(finalState == null ? void 0 : finalState.messages) || !Array.isArray(finalState.messages)) return null;
40
+ let totalInput = 0;
41
+ let totalOutput = 0;
42
+ let totalAll = 0;
43
+ for (const msg of finalState.messages) {
44
+ if (msg == null ? void 0 : msg.usage_metadata) {
45
+ const um = msg.usage_metadata;
46
+ totalInput += um.input_tokens || 0;
47
+ totalOutput += um.output_tokens || 0;
48
+ totalAll += um.total_tokens || 0;
49
+ }
50
+ }
51
+ if (totalAll === 0) return null;
52
+ return {
53
+ inputTokens: totalInput,
54
+ outputTokens: totalOutput,
55
+ totalTokens: totalAll,
56
+ cost: estimateCost(totalInput, totalOutput)
57
+ };
58
+ }
59
+ class TokenTracker {
60
+ constructor(plugin) {
61
+ this.plugin = plugin;
62
+ }
63
+ get db() {
64
+ return this.plugin.db;
65
+ }
66
+ get app() {
67
+ return this.plugin.app;
68
+ }
69
+ /**
70
+ * Track token usage for a single execution span.
71
+ * Updates the span record and accumulates into the parent run.
72
+ *
73
+ * @param spanId - The agentExecutionSpans.id to update
74
+ * @param usage - Parsed token usage from extractTokenUsage()
75
+ * @param runId - Optional agentLoopRuns.id to accumulate totals
76
+ */
77
+ async trackSpan(spanId, usage, runId) {
78
+ var _a, _b;
79
+ if (!spanId) return;
80
+ try {
81
+ const repo = this.db.getRepository("agentExecutionSpans");
82
+ if (!repo) return;
83
+ await repo.update({
84
+ filterByTk: spanId,
85
+ values: {
86
+ inputTokens: usage.inputTokens,
87
+ outputTokens: usage.outputTokens,
88
+ totalTokens: usage.totalTokens,
89
+ cost: usage.cost
90
+ }
91
+ });
92
+ if (runId != null) {
93
+ await this.accumulateToRun(runId);
94
+ }
95
+ } catch (e) {
96
+ (_b = (_a = this.app.log) == null ? void 0 : _a.warn) == null ? void 0 : _b.call(_a, "[TokenTracker] Failed to track span tokens", e);
97
+ }
98
+ }
99
+ /**
100
+ * Recalculate total token/cost for a run by summing all its spans.
101
+ */
102
+ async accumulateToRun(runId) {
103
+ var _a, _b, _c, _d, _e;
104
+ try {
105
+ const spansRepo = this.db.getRepository("agentExecutionSpans");
106
+ if (!spansRepo) return;
107
+ const spans = await spansRepo.find({
108
+ filter: { "metadata.agentLoopRunId": String(runId) }
109
+ });
110
+ let totalInput = 0;
111
+ let totalOutput = 0;
112
+ let totalCost = 0;
113
+ for (const span of spans) {
114
+ totalInput += Number(((_a = span.get) == null ? void 0 : _a.call(span, "inputTokens")) || span.inputTokens || 0);
115
+ totalOutput += Number(((_b = span.get) == null ? void 0 : _b.call(span, "outputTokens")) || span.outputTokens || 0);
116
+ totalCost += Number(((_c = span.get) == null ? void 0 : _c.call(span, "cost")) || span.cost || 0);
117
+ }
118
+ const runsRepo = this.db.getRepository("agentLoopRuns");
119
+ if (!runsRepo) return;
120
+ await runsRepo.update({
121
+ filterByTk: runId,
122
+ values: {
123
+ totalInputTokens: totalInput,
124
+ totalOutputTokens: totalOutput,
125
+ totalTokens: totalInput + totalOutput,
126
+ totalCost
127
+ }
128
+ });
129
+ } catch (e) {
130
+ (_e = (_d = this.app.log) == null ? void 0 : _d.warn) == null ? void 0 : _e.call(_d, "[TokenTracker] Failed to accumulate run totals", e);
131
+ }
132
+ }
133
+ /**
134
+ * Check if a run has exceeded its budget limits.
135
+ */
136
+ async checkBudget(runId) {
137
+ var _a, _b, _c, _d, _e, _f;
138
+ try {
139
+ const repo = this.db.getRepository("agentLoopRuns");
140
+ if (!repo) return { allowed: true };
141
+ const run = await repo.findOne({ filter: { id: runId } });
142
+ if (!run) return { allowed: true };
143
+ const budgetMaxTokens = Number(((_a = run.get) == null ? void 0 : _a.call(run, "budgetMaxTokens")) ?? 0);
144
+ const budgetMaxCost = Number(((_b = run.get) == null ? void 0 : _b.call(run, "budgetMaxCost")) ?? 0);
145
+ if (budgetMaxTokens <= 0 && budgetMaxCost <= 0) return { allowed: true };
146
+ const totalTokens = Number(((_c = run.get) == null ? void 0 : _c.call(run, "totalTokens")) || 0);
147
+ const totalCost = Number(((_d = run.get) == null ? void 0 : _d.call(run, "totalCost")) || 0);
148
+ if (budgetMaxTokens > 0 && totalTokens >= budgetMaxTokens) {
149
+ return {
150
+ allowed: false,
151
+ reason: `Budget exceeded: ${totalTokens}/${budgetMaxTokens} tokens used. Maximum allowed tokens for this run: ${budgetMaxTokens}.`
152
+ };
153
+ }
154
+ if (budgetMaxCost > 0 && totalCost >= budgetMaxCost) {
155
+ return {
156
+ allowed: false,
157
+ reason: `Budget exceeded: $${totalCost.toFixed(4)}/$${budgetMaxCost.toFixed(
158
+ 4
159
+ )} spent. Maximum allowed cost for this run: $${budgetMaxCost}.`
160
+ };
161
+ }
162
+ return { allowed: true };
163
+ } catch (e) {
164
+ (_f = (_e = this.app.log) == null ? void 0 : _e.warn) == null ? void 0 : _f.call(_e, "[TokenTracker] Budget check failed, allowing", e);
165
+ return { allowed: true };
166
+ }
167
+ }
168
+ }
169
+ // Annotate the CommonJS export names for ESM import in node:
170
+ 0 && (module.exports = {
171
+ TokenTracker,
172
+ extractTokenUsage
173
+ });
@@ -170,21 +170,21 @@ class SkillHubSubFeature {
170
170
  return;
171
171
  }
172
172
  const rawStorageId = attachment.get("storageId") || attachment.storageId;
173
+ let matchedKey = null;
173
174
  if (rawStorageId) {
174
175
  const strId = String(rawStorageId);
175
- let matchedKey = null;
176
176
  for (const key of fileManager.storagesCache.keys()) {
177
177
  if (String(key) === strId) {
178
178
  matchedKey = key;
179
179
  break;
180
180
  }
181
181
  }
182
- if (matchedKey !== null) {
183
- attachment.set("storageId", matchedKey);
184
- attachment.storageId = matchedKey;
185
- }
186
182
  }
187
- const streamData = await fileManager.getFileStream(attachment);
183
+ const attachmentObj = typeof attachment.toJSON === "function" ? attachment.toJSON() : { ...attachment };
184
+ if (matchedKey !== null) {
185
+ attachmentObj.storageId = matchedKey;
186
+ }
187
+ const streamData = await fileManager.getFileStream(attachmentObj);
188
188
  if (!streamData || !streamData.stream) {
189
189
  this.app.logger.warn(
190
190
  `[skill-hub] Could not get file stream for attachment ${attachment.get("id")}`
@@ -164,22 +164,22 @@ class SkillExecutionTask {
164
164
  const attachment = await this.app.db.getRepository("attachments").findOne({ filter: { id: fileId } });
165
165
  if (fmPlugin && attachment) {
166
166
  const rawStorageId = attachment.get("storageId") || attachment.storageId;
167
+ let matchedKey = null;
167
168
  if (rawStorageId) {
168
169
  const strId = String(rawStorageId);
169
- let matchedKey = null;
170
170
  for (const key of fmPlugin.storagesCache.keys()) {
171
171
  if (String(key) === strId) {
172
172
  matchedKey = key;
173
173
  break;
174
174
  }
175
175
  }
176
- if (matchedKey !== null) {
177
- attachment.set("storageId", matchedKey);
178
- attachment.storageId = matchedKey;
179
- }
176
+ }
177
+ const attachmentObj = typeof attachment.toJSON === "function" ? attachment.toJSON() : { ...attachment };
178
+ if (matchedKey !== null) {
179
+ attachmentObj.storageId = matchedKey;
180
180
  }
181
181
  try {
182
- const streamData = await fmPlugin.getFileStream(attachment);
182
+ const streamData = await fmPlugin.getFileStream(attachmentObj);
183
183
  if (streamData == null ? void 0 : streamData.stream) {
184
184
  const tempZipPath = require("path").resolve(require("os").tmpdir(), `skill_${Date.now()}_exec.zip`);
185
185
  await new Promise((resolve2, reject) => {
@@ -56,10 +56,10 @@ export declare function createAgentLoopTools(plugin: any, service: AgentLoopServ
56
56
  description?: string;
57
57
  metadata?: any;
58
58
  input?: any;
59
+ id?: string;
59
60
  planKey?: string;
60
61
  target?: string;
61
62
  dependsOn?: string[];
62
- id?: string;
63
63
  parentStepId?: string | number;
64
64
  maxAttempts?: number;
65
65
  }, {
@@ -69,10 +69,10 @@ export declare function createAgentLoopTools(plugin: any, service: AgentLoopServ
69
69
  description?: string;
70
70
  metadata?: any;
71
71
  input?: any;
72
+ id?: string;
72
73
  planKey?: string;
73
74
  target?: string;
74
75
  dependsOn?: string[];
75
- id?: string;
76
76
  parentStepId?: string | number;
77
77
  maxAttempts?: number;
78
78
  }>, "many">>;
@@ -96,10 +96,10 @@ export declare function createAgentLoopTools(plugin: any, service: AgentLoopServ
96
96
  description?: string;
97
97
  metadata?: any;
98
98
  input?: any;
99
+ id?: string;
99
100
  planKey?: string;
100
101
  target?: string;
101
102
  dependsOn?: string[];
102
- id?: string;
103
103
  parentStepId?: string | number;
104
104
  maxAttempts?: number;
105
105
  }[];
@@ -123,10 +123,10 @@ export declare function createAgentLoopTools(plugin: any, service: AgentLoopServ
123
123
  description?: string;
124
124
  metadata?: any;
125
125
  input?: any;
126
+ id?: string;
126
127
  planKey?: string;
127
128
  target?: string;
128
129
  dependsOn?: string[];
129
- id?: string;
130
130
  parentStepId?: string | number;
131
131
  maxAttempts?: number;
132
132
  }[];
@@ -181,20 +181,20 @@ export declare function createAgentLoopTools(plugin: any, service: AgentLoopServ
181
181
  metadata: z.ZodOptional<z.ZodAny>;
182
182
  }, "strip", z.ZodTypeAny, {
183
183
  error?: string;
184
- status?: "running" | "succeeded" | "failed" | "skipped";
184
+ status?: "succeeded" | "failed" | "running" | "skipped";
185
+ reason?: string;
185
186
  metadata?: any;
186
187
  output?: any;
187
188
  skillExecutionId?: string | number;
188
- reason?: string;
189
189
  stepId?: string | number;
190
190
  agentExecutionSpanId?: string | number;
191
191
  }, {
192
192
  error?: string;
193
- status?: "running" | "succeeded" | "failed" | "skipped";
193
+ status?: "succeeded" | "failed" | "running" | "skipped";
194
+ reason?: string;
194
195
  metadata?: any;
195
196
  output?: any;
196
197
  skillExecutionId?: string | number;
197
- reason?: string;
198
198
  stepId?: string | number;
199
199
  agentExecutionSpanId?: string | number;
200
200
  }>;