@loopman/langchain-sdk 1.0.9
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/LICENSE +374 -0
- package/README.md +594 -0
- package/dist/agents/loopman-agent.d.ts +29 -0
- package/dist/agents/loopman-agent.d.ts.map +1 -0
- package/dist/agents/loopman-agent.js +441 -0
- package/dist/agents/loopman-agent.js.map +1 -0
- package/dist/client/loopman-api.d.ts +123 -0
- package/dist/client/loopman-api.d.ts.map +1 -0
- package/dist/client/loopman-api.js +407 -0
- package/dist/client/loopman-api.js.map +1 -0
- package/dist/helpers/prompt-orchestrator.d.ts +12 -0
- package/dist/helpers/prompt-orchestrator.d.ts.map +1 -0
- package/dist/helpers/prompt-orchestrator.js +133 -0
- package/dist/helpers/prompt-orchestrator.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/loopman-agent-wrapper.d.ts +70 -0
- package/dist/loopman-agent-wrapper.d.ts.map +1 -0
- package/dist/loopman-agent-wrapper.js +157 -0
- package/dist/loopman-agent-wrapper.js.map +1 -0
- package/dist/loopman-middleware.d.ts +78 -0
- package/dist/loopman-middleware.d.ts.map +1 -0
- package/dist/loopman-middleware.js +367 -0
- package/dist/loopman-middleware.js.map +1 -0
- package/dist/mcp/loopman-mcp-client.d.ts +17 -0
- package/dist/mcp/loopman-mcp-client.d.ts.map +1 -0
- package/dist/mcp/loopman-mcp-client.js +76 -0
- package/dist/mcp/loopman-mcp-client.js.map +1 -0
- package/dist/mcp/tool-registry.d.ts +29 -0
- package/dist/mcp/tool-registry.d.ts.map +1 -0
- package/dist/mcp/tool-registry.js +143 -0
- package/dist/mcp/tool-registry.js.map +1 -0
- package/dist/services/index.d.ts +12 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +9 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/logger.service.d.ts +107 -0
- package/dist/services/logger.service.d.ts.map +1 -0
- package/dist/services/logger.service.js +173 -0
- package/dist/services/logger.service.js.map +1 -0
- package/dist/services/loopman.service.d.ts +72 -0
- package/dist/services/loopman.service.d.ts.map +1 -0
- package/dist/services/loopman.service.js +271 -0
- package/dist/services/loopman.service.js.map +1 -0
- package/dist/services/polling.service.d.ts +136 -0
- package/dist/services/polling.service.d.ts.map +1 -0
- package/dist/services/polling.service.js +428 -0
- package/dist/services/polling.service.js.map +1 -0
- package/dist/types.d.ts +242 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +35 -0
- package/dist/types.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import { createAgent } from "langchain";
|
|
2
|
+
import { buildLoopmanSystemPrompt, extractConfidence, extractTaskId, } from "../helpers/prompt-orchestrator";
|
|
3
|
+
import { loopmanMiddleware } from "../loopman-middleware";
|
|
4
|
+
import { LoopmanMcpClient } from "../mcp/loopman-mcp-client";
|
|
5
|
+
import { LoopmanToolRegistry } from "../mcp/tool-registry";
|
|
6
|
+
import { LoopmanService } from "../services/loopman.service";
|
|
7
|
+
export class LoopmanAgent {
|
|
8
|
+
config;
|
|
9
|
+
hasFixedExecutionId;
|
|
10
|
+
baseExecutionId;
|
|
11
|
+
maxRetries;
|
|
12
|
+
debug;
|
|
13
|
+
additionalTools;
|
|
14
|
+
agent = null;
|
|
15
|
+
mcpClient;
|
|
16
|
+
toolRegistry;
|
|
17
|
+
loopmanService;
|
|
18
|
+
cachedTools = null;
|
|
19
|
+
middlewareConfig = null; // Store middleware config reference
|
|
20
|
+
constructor(config) {
|
|
21
|
+
this.config = config;
|
|
22
|
+
// If executionId is provided, use it for all invocations (shared context)
|
|
23
|
+
// If not provided, generate a unique executionId per processWithHumanValidation call
|
|
24
|
+
this.hasFixedExecutionId = !!config.executionId;
|
|
25
|
+
this.baseExecutionId = config.executionId;
|
|
26
|
+
this.maxRetries = config.maxRetries ?? 3;
|
|
27
|
+
this.debug = config.debug ?? false;
|
|
28
|
+
this.additionalTools = config.additionalTools ?? [];
|
|
29
|
+
this.mcpClient = new LoopmanMcpClient({
|
|
30
|
+
apiKey: config.apiKey,
|
|
31
|
+
serverUrl: config.mcp?.serverUrl,
|
|
32
|
+
timeoutMs: config.mcp?.timeoutMs,
|
|
33
|
+
});
|
|
34
|
+
// ToolRegistry and LoopmanService will be created per invocation with the correct executionId
|
|
35
|
+
this.toolRegistry = null; // Will be initialized in processWithHumanValidation
|
|
36
|
+
this.loopmanService = null; // Will be initialized in processWithHumanValidation
|
|
37
|
+
}
|
|
38
|
+
async processWithHumanValidation(input) {
|
|
39
|
+
// Generate executionId: use provided one or generate unique per invocation
|
|
40
|
+
const executionId = this.hasFixedExecutionId
|
|
41
|
+
? this.baseExecutionId
|
|
42
|
+
: `exec-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
43
|
+
// Initialize services with the correct executionId
|
|
44
|
+
this.toolRegistry = new LoopmanToolRegistry({
|
|
45
|
+
workflowId: this.config.workflowId,
|
|
46
|
+
executionId: executionId,
|
|
47
|
+
category: this.config.category,
|
|
48
|
+
channelId: this.config.channelId,
|
|
49
|
+
debug: this.debug,
|
|
50
|
+
});
|
|
51
|
+
this.loopmanService = new LoopmanService({
|
|
52
|
+
apiKey: this.config.apiKey,
|
|
53
|
+
workflowId: this.config.workflowId,
|
|
54
|
+
executionId: executionId,
|
|
55
|
+
channelId: this.config.channelId,
|
|
56
|
+
timeout: this.config.pollingTimeoutMs,
|
|
57
|
+
pollingInterval: this.config.pollingIntervalMs,
|
|
58
|
+
debug: this.debug,
|
|
59
|
+
});
|
|
60
|
+
let attempt = 0;
|
|
61
|
+
let taskId;
|
|
62
|
+
let feedbackFromHuman;
|
|
63
|
+
while (attempt < this.maxRetries) {
|
|
64
|
+
await this.ensureAgent(executionId, taskId);
|
|
65
|
+
const result = await this.agent.invoke({
|
|
66
|
+
messages: this.buildMessages(input, feedbackFromHuman),
|
|
67
|
+
});
|
|
68
|
+
// Store the conversation history for potential execution after approval
|
|
69
|
+
const conversationHistory = result.messages || [];
|
|
70
|
+
if (this.config.debug) {
|
|
71
|
+
console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
72
|
+
console.log("🧠 [AGENT REASONING] - Attempt", attempt + 1);
|
|
73
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
|
|
74
|
+
// Display all messages to see the agent's reasoning
|
|
75
|
+
if (result.messages &&
|
|
76
|
+
Array.isArray(result.messages)) {
|
|
77
|
+
const messages = result.messages;
|
|
78
|
+
messages.forEach((msg, index) => {
|
|
79
|
+
const role = msg._getType ? msg._getType() : msg.role || "unknown";
|
|
80
|
+
const content = this.normalizeMessageContent(msg.content);
|
|
81
|
+
console.log(`📍 Message ${index + 1} [${role.toUpperCase()}]:`);
|
|
82
|
+
if (content) {
|
|
83
|
+
// Truncate very long content for readability
|
|
84
|
+
const displayContent = content.length > 500
|
|
85
|
+
? content.substring(0, 500) + "... (truncated)"
|
|
86
|
+
: content;
|
|
87
|
+
console.log(displayContent);
|
|
88
|
+
}
|
|
89
|
+
// Show tool calls if present
|
|
90
|
+
if (msg.tool_calls && msg.tool_calls.length > 0) {
|
|
91
|
+
console.log("\n🔧 Tool Calls:");
|
|
92
|
+
msg.tool_calls.forEach((tc) => {
|
|
93
|
+
console.log(` - ${tc.name}(${JSON.stringify(tc.args).substring(0, 100)}...)`);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
console.log("");
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
// Also show intermediate steps if available
|
|
100
|
+
if (result.intermediateSteps &&
|
|
101
|
+
result.intermediateSteps.length > 0) {
|
|
102
|
+
console.log("📊 Intermediate Steps:");
|
|
103
|
+
result.intermediateSteps.forEach((step, index) => {
|
|
104
|
+
console.log(` ${index + 1}. Action: ${step.action?.tool || "unknown"}`);
|
|
105
|
+
if (step.observation) {
|
|
106
|
+
const obs = String(step.observation).substring(0, 100);
|
|
107
|
+
console.log(` Observation: ${obs}...`);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
console.log("");
|
|
111
|
+
}
|
|
112
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
|
|
113
|
+
}
|
|
114
|
+
const finalMessage = Array.isArray(result.messages)
|
|
115
|
+
? result.messages[result.messages.length - 1]
|
|
116
|
+
: undefined;
|
|
117
|
+
const agentOutput = this.normalizeMessageContent(finalMessage?.content);
|
|
118
|
+
const toolCalls = finalMessage?.tool_calls ?? finalMessage?.toolCalls;
|
|
119
|
+
if (this.config.debug && toolCalls) {
|
|
120
|
+
console.log("[LoopmanAgent] Tool calls detected:", JSON.stringify(toolCalls, null, 2));
|
|
121
|
+
}
|
|
122
|
+
const parsedTaskId = extractTaskId(agentOutput ?? "");
|
|
123
|
+
const confidence = agentOutput
|
|
124
|
+
? extractConfidence(agentOutput)
|
|
125
|
+
: undefined;
|
|
126
|
+
if (!parsedTaskId) {
|
|
127
|
+
return {
|
|
128
|
+
response: agentOutput ?? "",
|
|
129
|
+
status: "completed",
|
|
130
|
+
confidence,
|
|
131
|
+
retries: attempt,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
taskId = parsedTaskId;
|
|
135
|
+
this.loopmanService.logger.setTaskId(taskId);
|
|
136
|
+
// Update middleware config with the new taskId as parentTaskId for future tool calls
|
|
137
|
+
if (this.middlewareConfig) {
|
|
138
|
+
this.middlewareConfig.parentTaskId = taskId;
|
|
139
|
+
if (this.config.debug) {
|
|
140
|
+
console.log(`[LoopmanAgent] Updated middlewareConfig.parentTaskId to: ${taskId}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const decision = await this.loopmanService.polling.waitForDecision({
|
|
144
|
+
taskId: taskId,
|
|
145
|
+
workflowId: this.config.workflowId,
|
|
146
|
+
executionId: executionId,
|
|
147
|
+
apiKey: this.config.apiKey,
|
|
148
|
+
timeoutMs: this.config.pollingTimeoutMs,
|
|
149
|
+
pollingIntervalMs: this.config.pollingIntervalMs,
|
|
150
|
+
debug: this.debug,
|
|
151
|
+
});
|
|
152
|
+
if (this.config.debug) {
|
|
153
|
+
console.log("[LoopmanAgent] Decision received:", JSON.stringify(decision, null, 2));
|
|
154
|
+
}
|
|
155
|
+
if (decision.status === "VALIDATED") {
|
|
156
|
+
// If manualExecutionMode is enabled, just return the approval status
|
|
157
|
+
if (this.config.manualExecutionMode) {
|
|
158
|
+
this.loopmanService.logger.info("Manual execution mode: returning approval status without executing action", { taskId });
|
|
159
|
+
return {
|
|
160
|
+
response: agentOutput ?? "",
|
|
161
|
+
taskId,
|
|
162
|
+
status: "approved",
|
|
163
|
+
confidence,
|
|
164
|
+
decision: {
|
|
165
|
+
taskId,
|
|
166
|
+
status: decision.status,
|
|
167
|
+
feedback: decision.data?.feedback,
|
|
168
|
+
modifiedData: decision.data?.modified_data,
|
|
169
|
+
},
|
|
170
|
+
retries: attempt,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
// Auto-execution mode: execute the approved action
|
|
174
|
+
this.loopmanService.logger.info("Auto-execution mode: executing approved action", { taskId, feedback: decision.data?.feedback });
|
|
175
|
+
// Re-invoke the agent with the full conversation history + execution instruction
|
|
176
|
+
const executionMessages = this.buildExecutionMessages(conversationHistory, decision.data?.feedback, decision.data?.modified_data);
|
|
177
|
+
const executionResult = await this.agent.invoke({
|
|
178
|
+
messages: executionMessages,
|
|
179
|
+
});
|
|
180
|
+
const executionOutput = this.extractAgentOutput(executionResult);
|
|
181
|
+
this.loopmanService.logger.info("Action executed successfully", {
|
|
182
|
+
taskId,
|
|
183
|
+
output: executionOutput,
|
|
184
|
+
});
|
|
185
|
+
return {
|
|
186
|
+
response: executionOutput ?? agentOutput ?? "",
|
|
187
|
+
taskId,
|
|
188
|
+
status: "approved",
|
|
189
|
+
confidence,
|
|
190
|
+
decision: {
|
|
191
|
+
taskId,
|
|
192
|
+
status: decision.status,
|
|
193
|
+
feedback: decision.data?.feedback,
|
|
194
|
+
modifiedData: decision.data?.modified_data,
|
|
195
|
+
},
|
|
196
|
+
retries: attempt,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
if (decision.status === "REFUSED" ||
|
|
200
|
+
decision.status === "CANCELLED" ||
|
|
201
|
+
decision.status === "EXPIRED") {
|
|
202
|
+
return {
|
|
203
|
+
response: agentOutput ?? "",
|
|
204
|
+
taskId,
|
|
205
|
+
status: decision.status === "REFUSED" ? "rejected" : "error",
|
|
206
|
+
confidence,
|
|
207
|
+
decision: {
|
|
208
|
+
taskId,
|
|
209
|
+
status: decision.status,
|
|
210
|
+
feedback: decision.data?.feedback,
|
|
211
|
+
modifiedData: decision.data?.modified_data,
|
|
212
|
+
},
|
|
213
|
+
retries: attempt,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
if (decision.status === "TIMEOUT" || decision.status === "ABORTED") {
|
|
217
|
+
return {
|
|
218
|
+
response: agentOutput ?? "",
|
|
219
|
+
taskId,
|
|
220
|
+
status: decision.status === "TIMEOUT" ? "timeout" : "aborted",
|
|
221
|
+
confidence,
|
|
222
|
+
decision: {
|
|
223
|
+
taskId,
|
|
224
|
+
status: decision.status,
|
|
225
|
+
feedback: decision.data?.feedback,
|
|
226
|
+
modifiedData: decision.data?.modified_data,
|
|
227
|
+
},
|
|
228
|
+
retries: attempt,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
attempt += 1;
|
|
232
|
+
if (attempt >= this.maxRetries) {
|
|
233
|
+
return {
|
|
234
|
+
response: agentOutput ?? "",
|
|
235
|
+
taskId,
|
|
236
|
+
status: "needs_changes",
|
|
237
|
+
confidence,
|
|
238
|
+
decision: {
|
|
239
|
+
taskId,
|
|
240
|
+
status: decision.status,
|
|
241
|
+
feedback: decision.data?.feedback,
|
|
242
|
+
modifiedData: decision.data?.modified_data,
|
|
243
|
+
},
|
|
244
|
+
retries: attempt,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
// Store feedback for next iteration
|
|
248
|
+
feedbackFromHuman = decision.data?.feedback;
|
|
249
|
+
this.loopmanService.logger.info("Human requested changes, retrying agent execution", {
|
|
250
|
+
attempt,
|
|
251
|
+
taskId,
|
|
252
|
+
feedback: feedbackFromHuman,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
response: "Maximum retries reached without approval",
|
|
257
|
+
taskId,
|
|
258
|
+
status: "needs_changes",
|
|
259
|
+
retries: this.maxRetries,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
async disconnect() {
|
|
263
|
+
await this.mcpClient.disconnect();
|
|
264
|
+
}
|
|
265
|
+
normalizeMessageContent(content) {
|
|
266
|
+
if (content == null) {
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
if (typeof content === "string") {
|
|
270
|
+
return content;
|
|
271
|
+
}
|
|
272
|
+
if (Array.isArray(content)) {
|
|
273
|
+
return content
|
|
274
|
+
.map((part) => typeof part === "string"
|
|
275
|
+
? part
|
|
276
|
+
: typeof part === "object" && part !== null && "text" in part
|
|
277
|
+
? String(part.text)
|
|
278
|
+
: "")
|
|
279
|
+
.join("\n");
|
|
280
|
+
}
|
|
281
|
+
if (typeof content === "object" && "text" in content) {
|
|
282
|
+
return String(content.text);
|
|
283
|
+
}
|
|
284
|
+
return String(content);
|
|
285
|
+
}
|
|
286
|
+
async ensureAgent(executionId, taskId) {
|
|
287
|
+
// Always try to reconnect if not connected
|
|
288
|
+
if (!this.mcpClient.isConnected) {
|
|
289
|
+
if (this.config.debug) {
|
|
290
|
+
console.log("[LoopmanAgent] MCP not connected, attempting connection...");
|
|
291
|
+
}
|
|
292
|
+
await this.mcpClient.connect();
|
|
293
|
+
}
|
|
294
|
+
// Always refresh tools to ensure MCP session is alive
|
|
295
|
+
// If the session is dead, this will throw and we'll reconnect
|
|
296
|
+
try {
|
|
297
|
+
const tools = await this.mcpClient.getTools();
|
|
298
|
+
if (this.config.debug) {
|
|
299
|
+
console.log("[LoopmanAgent] MCP tools received:", tools.map((t) => t.name));
|
|
300
|
+
}
|
|
301
|
+
this.cachedTools = this.toolRegistry.toDynamicTools(tools);
|
|
302
|
+
if (this.config.debug) {
|
|
303
|
+
console.log("[LoopmanAgent] MCP tools registered:", this.cachedTools.map((tool) => tool.name));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
// MCP session might be dead, try to reconnect
|
|
308
|
+
if (this.config.debug) {
|
|
309
|
+
console.log("[LoopmanAgent] MCP tools retrieval failed, attempting reconnection...", error);
|
|
310
|
+
}
|
|
311
|
+
await this.mcpClient.disconnect();
|
|
312
|
+
await this.mcpClient.connect();
|
|
313
|
+
// Retry getting tools after reconnection
|
|
314
|
+
const tools = await this.mcpClient.getTools();
|
|
315
|
+
if (this.config.debug) {
|
|
316
|
+
console.log("[LoopmanAgent] MCP tools received after reconnection:", tools.map((t) => t.name));
|
|
317
|
+
}
|
|
318
|
+
this.cachedTools = this.toolRegistry.toDynamicTools(tools);
|
|
319
|
+
if (this.config.debug) {
|
|
320
|
+
console.log("[LoopmanAgent] MCP tools registered after reconnection:", this.cachedTools.map((tool) => tool.name));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const allTools = [...(this.cachedTools ?? []), ...this.additionalTools];
|
|
324
|
+
const prompt = buildLoopmanSystemPrompt({
|
|
325
|
+
workflowId: this.config.workflowId,
|
|
326
|
+
executionId: executionId,
|
|
327
|
+
taskId,
|
|
328
|
+
category: this.config.category,
|
|
329
|
+
systemPrompt: this.config.systemPrompt,
|
|
330
|
+
language: this.config.language,
|
|
331
|
+
});
|
|
332
|
+
if (this.config.debug) {
|
|
333
|
+
console.log("[LoopmanAgent] Final system prompt:\n", prompt);
|
|
334
|
+
}
|
|
335
|
+
// Build middleware configuration if requireApprovalForTools is configured
|
|
336
|
+
const middleware = [];
|
|
337
|
+
if (this.config.requireApprovalForTools &&
|
|
338
|
+
this.config.requireApprovalForTools.length > 0) {
|
|
339
|
+
if (this.config.debug) {
|
|
340
|
+
console.log("[LoopmanAgent] Tool validation middleware enabled for tools:", this.config.requireApprovalForTools);
|
|
341
|
+
}
|
|
342
|
+
// Build interruptOn configuration from requireApprovalForTools
|
|
343
|
+
const interruptOn = {};
|
|
344
|
+
// Special case: ['*'] means all tools require approval
|
|
345
|
+
if (this.config.requireApprovalForTools.includes("*")) {
|
|
346
|
+
// Mark all additional tools (non-MCP) for approval
|
|
347
|
+
for (const tool of this.additionalTools) {
|
|
348
|
+
interruptOn[tool.name] = true;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
// Mark specific tools for approval
|
|
353
|
+
for (const toolName of this.config.requireApprovalForTools) {
|
|
354
|
+
interruptOn[toolName] = true;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (this.config.debug) {
|
|
358
|
+
console.log("[LoopmanAgent] InterruptOn configuration:", interruptOn);
|
|
359
|
+
}
|
|
360
|
+
// Create middleware config and store reference for dynamic updates
|
|
361
|
+
this.middlewareConfig = {
|
|
362
|
+
apiKey: this.config.apiKey,
|
|
363
|
+
workflowId: this.config.workflowId,
|
|
364
|
+
executionId: executionId,
|
|
365
|
+
channelId: this.config.channelId,
|
|
366
|
+
interruptOn,
|
|
367
|
+
timeout: this.config.pollingTimeoutMs,
|
|
368
|
+
pollingInterval: this.config.pollingIntervalMs,
|
|
369
|
+
debug: this.config.debug,
|
|
370
|
+
parentTaskId: taskId, // Link to the initial reflection/validation task
|
|
371
|
+
};
|
|
372
|
+
middleware.push(loopmanMiddleware(this.middlewareConfig));
|
|
373
|
+
}
|
|
374
|
+
this.agent = await createAgent({
|
|
375
|
+
model: this.config.model,
|
|
376
|
+
tools: allTools,
|
|
377
|
+
systemPrompt: prompt,
|
|
378
|
+
middleware: middleware.length > 0 ? middleware : undefined,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
buildMessages(input, feedbackFromHuman) {
|
|
382
|
+
let userContent = input.context
|
|
383
|
+
? `${input.input}\n\nContext:\n${JSON.stringify(input.context, null, 2)}`
|
|
384
|
+
: input.input;
|
|
385
|
+
// If we have feedback from a previous NEED_CHANGES, include it
|
|
386
|
+
if (feedbackFromHuman) {
|
|
387
|
+
userContent += `\n\n🔄 IMPORTANT - HUMAN FEEDBACK FROM PREVIOUS ATTEMPT:\nThe human reviewer requested changes: "${feedbackFromHuman}"\n\nYou MUST:\n1. Follow the normal workflow (getHumanGuidelines → getDecisionContext)\n2. Analyze the feedback in Step 3\n3. RE-SUBMIT a corrected proposal via submitForHumanReview in Step 4\n\nDo NOT skip Step 4! The human is waiting for your corrected proposal.`;
|
|
388
|
+
}
|
|
389
|
+
return [
|
|
390
|
+
{
|
|
391
|
+
role: "user",
|
|
392
|
+
content: userContent,
|
|
393
|
+
},
|
|
394
|
+
];
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Build execution messages by continuing the conversation history
|
|
398
|
+
* This ensures the agent has full context of what was proposed and approved
|
|
399
|
+
*/
|
|
400
|
+
buildExecutionMessages(conversationHistory, feedback, modifiedData) {
|
|
401
|
+
// Start with the full conversation history (includes all context, guidelines, and the submitForHumanReview call)
|
|
402
|
+
const messages = [...conversationHistory];
|
|
403
|
+
// Add a new user message instructing execution
|
|
404
|
+
let executionInstruction = `✅ HUMAN APPROVED YOUR PROPOSAL!\n\nNow execute the actual action you proposed in submitForHumanReview.`;
|
|
405
|
+
if (feedback) {
|
|
406
|
+
executionInstruction += `\n\n💬 Human feedback: "${feedback}"`;
|
|
407
|
+
}
|
|
408
|
+
if (modifiedData) {
|
|
409
|
+
executionInstruction += `\n\n📝 Modified parameters to use:\n${JSON.stringify(modifiedData, null, 2)}`;
|
|
410
|
+
}
|
|
411
|
+
executionInstruction += `\n\n🚨 IMPORTANT:
|
|
412
|
+
- Do NOT call submitForHumanReview again (already approved)
|
|
413
|
+
- Execute the actual tool directly (e.g., send_email)
|
|
414
|
+
- Use the parameters you proposed earlier${modifiedData ? " with the modifications above" : ""}`;
|
|
415
|
+
messages.push({
|
|
416
|
+
role: "user",
|
|
417
|
+
content: executionInstruction,
|
|
418
|
+
});
|
|
419
|
+
return messages;
|
|
420
|
+
}
|
|
421
|
+
extractAgentOutput(result) {
|
|
422
|
+
const messages = result?.messages || [];
|
|
423
|
+
const lastMessage = messages[messages.length - 1];
|
|
424
|
+
if (!lastMessage) {
|
|
425
|
+
return undefined;
|
|
426
|
+
}
|
|
427
|
+
const content = lastMessage.content || lastMessage.kwargs?.content;
|
|
428
|
+
return this.normalizeMessageContent(content);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
export function createLoopmanAgent(config) {
|
|
432
|
+
const { tools, prompt, additionalTools, ...base } = config;
|
|
433
|
+
const mergedTools = [...(additionalTools ?? []), ...(tools ?? [])];
|
|
434
|
+
const loopmanConfig = {
|
|
435
|
+
...base,
|
|
436
|
+
systemPrompt: config.systemPrompt ?? prompt,
|
|
437
|
+
additionalTools: mergedTools.length > 0 ? mergedTools : undefined,
|
|
438
|
+
};
|
|
439
|
+
return new LoopmanAgent(loopmanConfig);
|
|
440
|
+
}
|
|
441
|
+
//# sourceMappingURL=loopman-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopman-agent.js","sourceRoot":"","sources":["../../src/agents/loopman-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { LoopmanConfig, LoopmanUser } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Loopman client for direct API connection
|
|
4
|
+
* Allows authentication with an API key and direct backoffice calls
|
|
5
|
+
*/
|
|
6
|
+
export declare class LoopmanApiClient {
|
|
7
|
+
private config;
|
|
8
|
+
private authServiceUrl;
|
|
9
|
+
private tokenCache;
|
|
10
|
+
private readonly bufferTimeSeconds;
|
|
11
|
+
constructor(config: LoopmanConfig);
|
|
12
|
+
/**
|
|
13
|
+
* Exchange an API key for JWT tokens with caching
|
|
14
|
+
* @param apiKey The API key to exchange
|
|
15
|
+
* @returns Object containing accessToken and serverUrl
|
|
16
|
+
*/
|
|
17
|
+
getTokenFromApiKey(apiKey: string): Promise<{
|
|
18
|
+
accessToken: string;
|
|
19
|
+
serverUrl: string;
|
|
20
|
+
fromCache: boolean;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Get authorization headers with access token and server URL
|
|
24
|
+
*/
|
|
25
|
+
private getAuthHeaders;
|
|
26
|
+
/**
|
|
27
|
+
* Get current user from backoffice
|
|
28
|
+
* @param apiKey The API key for authentication
|
|
29
|
+
* @returns Current user information
|
|
30
|
+
*/
|
|
31
|
+
getCurrentUser(apiKey: string): Promise<LoopmanUser>;
|
|
32
|
+
/**
|
|
33
|
+
* Generic method to make GET requests to backoffice
|
|
34
|
+
* @param apiKey The API key for authentication
|
|
35
|
+
* @param endpoint The endpoint to call (e.g. '/tasks', '/channels')
|
|
36
|
+
* @returns Response data
|
|
37
|
+
*/
|
|
38
|
+
get<T>(apiKey: string, endpoint: string): Promise<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Generic method to make POST requests to backoffice
|
|
41
|
+
* @param apiKey The API key for authentication
|
|
42
|
+
* @param endpoint The endpoint to call
|
|
43
|
+
* @param data The data to send
|
|
44
|
+
* @returns Response data
|
|
45
|
+
*/
|
|
46
|
+
post<T>(apiKey: string, endpoint: string, data: any): Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* Generic method to make PUT requests to backoffice
|
|
49
|
+
* @param apiKey The API key for authentication
|
|
50
|
+
* @param endpoint The endpoint to call
|
|
51
|
+
* @param data The data to send
|
|
52
|
+
* @returns Response data
|
|
53
|
+
*/
|
|
54
|
+
put<T>(apiKey: string, endpoint: string, data: any): Promise<T>;
|
|
55
|
+
/**
|
|
56
|
+
* Generic method to make PATCH requests to backoffice
|
|
57
|
+
* @param apiKey The API key for authentication
|
|
58
|
+
* @param endpoint The endpoint to call
|
|
59
|
+
* @param data The data to send
|
|
60
|
+
* @returns Response data
|
|
61
|
+
*/
|
|
62
|
+
patch<T>(apiKey: string, endpoint: string, data: any): Promise<T>;
|
|
63
|
+
/**
|
|
64
|
+
* Generic method to make DELETE requests to backoffice
|
|
65
|
+
* @param apiKey The API key for authentication
|
|
66
|
+
* @param endpoint The endpoint to call
|
|
67
|
+
* @returns Response data
|
|
68
|
+
*/
|
|
69
|
+
delete<T>(apiKey: string, endpoint: string): Promise<T>;
|
|
70
|
+
/**
|
|
71
|
+
* Get token from cache if valid, otherwise return null
|
|
72
|
+
*/
|
|
73
|
+
private getCachedToken;
|
|
74
|
+
/**
|
|
75
|
+
* Store token in cache with expiration
|
|
76
|
+
*/
|
|
77
|
+
private setCachedToken;
|
|
78
|
+
/**
|
|
79
|
+
* Remove a token from cache
|
|
80
|
+
*/
|
|
81
|
+
clearCache(apiKey: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Clear all token cache
|
|
84
|
+
*/
|
|
85
|
+
clearAllCache(): void;
|
|
86
|
+
/**
|
|
87
|
+
* Get cache statistics
|
|
88
|
+
*/
|
|
89
|
+
getCacheStats(): {
|
|
90
|
+
size: number;
|
|
91
|
+
entries: Array<{
|
|
92
|
+
apiKey: string;
|
|
93
|
+
serverUrl: string;
|
|
94
|
+
expiresAt: string;
|
|
95
|
+
ttl: number;
|
|
96
|
+
}>;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Check if a token exists and is valid
|
|
100
|
+
*/
|
|
101
|
+
hasValidToken(apiKey: string): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Get remaining TTL for a cached token
|
|
104
|
+
*/
|
|
105
|
+
getTokenTTL(apiKey: string): number;
|
|
106
|
+
/**
|
|
107
|
+
* Clean up expired tokens from cache
|
|
108
|
+
*/
|
|
109
|
+
private cleanupExpiredTokens;
|
|
110
|
+
/**
|
|
111
|
+
* Handle network errors consistently
|
|
112
|
+
*/
|
|
113
|
+
private handleNetworkError;
|
|
114
|
+
/**
|
|
115
|
+
* Mask API key for logs (show only first 8 characters)
|
|
116
|
+
*/
|
|
117
|
+
private maskApiKey;
|
|
118
|
+
/**
|
|
119
|
+
* Get current configuration
|
|
120
|
+
*/
|
|
121
|
+
get configuration(): Readonly<LoopmanConfig>;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=loopman-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopman-api.d.ts","sourceRoot":"","sources":["../../src/client/loopman-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EAEb,WAAW,EAGZ,MAAM,UAAU,CAAC;AAMlB;;;GAGG;AACH,qBAAa,gBAAgB;IAMf,OAAO,CAAC,MAAM;IAL1B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,UAAU,CACN;IACZ,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAM;gBAEpB,MAAM,EAAE,aAAa;IAQzC;;;;OAIG;IACG,kBAAkB,CACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAqD1E;;OAEG;YACW,cAAc;IAU5B;;;;OAIG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IA6C1D;;;;;OAKG;IACG,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IA8B1D;;;;;;OAMG;IACG,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IAmCtE;;;;;;OAMG;IACG,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IAmCrE;;;;;;OAMG;IACG,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IAmCvE;;;;;OAKG;IACG,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IA+B7D;;OAEG;IACH,OAAO,CAAC,cAAc;IAgCtB;;OAEG;IACH,OAAO,CAAC,cAAc;IAkBtB;;OAEG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAShC;;OAEG;IACH,aAAa,IAAI,IAAI;IAMrB;;OAEG;IACH,aAAa,IAAI;QACf,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,KAAK,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;YACf,SAAS,EAAE,MAAM,CAAC;YAClB,SAAS,EAAE,MAAM,CAAC;YAClB,GAAG,EAAE,MAAM,CAAC;SACb,CAAC,CAAC;KACJ;IAiBD;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAWtC;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAQnC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAoC1B;;OAEG;IACH,OAAO,CAAC,UAAU;IAKlB;;OAEG;IACH,IAAI,aAAa,IAAI,QAAQ,CAAC,aAAa,CAAC,CAE3C;CACF"}
|