lynkr 1.0.0 → 2.0.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.
Files changed (41) hide show
  1. package/CITATIONS.bib +6 -0
  2. package/DEPLOYMENT.md +1001 -0
  3. package/README.md +215 -71
  4. package/docs/index.md +55 -2
  5. package/monitor-agents.sh +31 -0
  6. package/package.json +7 -3
  7. package/src/agents/context-manager.js +220 -0
  8. package/src/agents/definitions/loader.js +563 -0
  9. package/src/agents/executor.js +412 -0
  10. package/src/agents/index.js +157 -0
  11. package/src/agents/parallel-coordinator.js +68 -0
  12. package/src/agents/reflector.js +321 -0
  13. package/src/agents/skillbook.js +331 -0
  14. package/src/agents/store.js +244 -0
  15. package/src/api/router.js +55 -0
  16. package/src/clients/databricks.js +214 -17
  17. package/src/clients/routing.js +15 -7
  18. package/src/clients/standard-tools.js +341 -0
  19. package/src/config/index.js +41 -5
  20. package/src/orchestrator/index.js +254 -37
  21. package/src/server.js +2 -0
  22. package/src/tools/agent-task.js +96 -0
  23. package/test/azure-openai-config.test.js +203 -0
  24. package/test/azure-openai-error-resilience.test.js +238 -0
  25. package/test/azure-openai-format-conversion.test.js +354 -0
  26. package/test/azure-openai-integration.test.js +281 -0
  27. package/test/azure-openai-routing.test.js +148 -0
  28. package/test/azure-openai-streaming.test.js +171 -0
  29. package/test/format-conversion.test.js +578 -0
  30. package/test/hybrid-routing-integration.test.js +18 -11
  31. package/test/openrouter-error-resilience.test.js +418 -0
  32. package/test/passthrough-mode.test.js +385 -0
  33. package/test/routing.test.js +9 -3
  34. package/test/web-tools.test.js +3 -0
  35. package/test-agents-simple.js +43 -0
  36. package/test-cli-connection.sh +33 -0
  37. package/test-learning-unit.js +126 -0
  38. package/test-learning.js +112 -0
  39. package/test-parallel-agents.sh +124 -0
  40. package/test-parallel-direct.js +155 -0
  41. package/test-subagents.sh +117 -0
@@ -0,0 +1,220 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const logger = require("../logger");
4
+
5
+ class ContextManager {
6
+ constructor() {
7
+ this.transcriptsDir = path.join(process.cwd(), "data", "agent-transcripts");
8
+ this.ensureTranscriptsDir();
9
+ }
10
+
11
+ ensureTranscriptsDir() {
12
+ if (!fs.existsSync(this.transcriptsDir)) {
13
+ fs.mkdirSync(this.transcriptsDir, { recursive: true });
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Create fresh context for subagent
19
+ * @param {Object} agentDef - Agent definition
20
+ * @param {string} taskPrompt - Task from main agent
21
+ * @param {Object} mainContext - Minimal context from main agent
22
+ * @returns {Object} - Fresh context for subagent
23
+ */
24
+ createSubagentContext(agentDef, taskPrompt, mainContext = {}) {
25
+ const agentId = this.generateAgentId();
26
+ const transcriptPath = path.join(this.transcriptsDir, `agent-${agentId}.jsonl`);
27
+
28
+ // Initialize transcript file
29
+ fs.writeFileSync(transcriptPath, "");
30
+
31
+ // Build minimal context (NOT full main agent history)
32
+ const messages = [];
33
+
34
+ // System prompt from agent definition
35
+ messages.push({
36
+ role: "system",
37
+ content: agentDef.systemPrompt
38
+ });
39
+
40
+ // Optional: Add minimal context from main agent
41
+ if (mainContext.relevant_context) {
42
+ messages.push({
43
+ role: "system",
44
+ content: `Context from main agent:\n${mainContext.relevant_context}`
45
+ });
46
+ }
47
+
48
+ // Task prompt
49
+ messages.push({
50
+ role: "user",
51
+ content: taskPrompt
52
+ });
53
+
54
+ const context = {
55
+ agentId,
56
+ agentName: agentDef.name,
57
+ transcriptPath,
58
+ messages,
59
+ steps: 0,
60
+ maxSteps: agentDef.maxSteps,
61
+ model: agentDef.model,
62
+ allowedTools: agentDef.allowedTools,
63
+ startTime: Date.now(),
64
+
65
+ // Token tracking
66
+ inputTokens: 0,
67
+ outputTokens: 0,
68
+
69
+ // State
70
+ terminated: false,
71
+ result: null
72
+ };
73
+
74
+ this.writeTranscriptEntry(transcriptPath, {
75
+ type: "agent_start",
76
+ agentId,
77
+ agentName: agentDef.name,
78
+ taskPrompt,
79
+ timestamp: Date.now()
80
+ });
81
+
82
+ logger.info({ agentId, agentName: agentDef.name }, "Created fresh subagent context");
83
+
84
+ return context;
85
+ }
86
+
87
+ /**
88
+ * Add message to subagent context
89
+ */
90
+ addMessage(context, message) {
91
+ context.messages.push(message);
92
+
93
+ this.writeTranscriptEntry(context.transcriptPath, {
94
+ type: "message",
95
+ agentId: context.agentId,
96
+ message,
97
+ timestamp: Date.now()
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Record tool execution in transcript
103
+ */
104
+ recordToolCall(context, toolName, input, output, error = null) {
105
+ this.writeTranscriptEntry(context.transcriptPath, {
106
+ type: "tool_call",
107
+ agentId: context.agentId,
108
+ step: context.steps,
109
+ toolName,
110
+ input,
111
+ output: error ? null : output,
112
+ error: error ? error.message : null,
113
+ timestamp: Date.now()
114
+ });
115
+ }
116
+
117
+ /**
118
+ * Complete subagent execution
119
+ */
120
+ completeExecution(context, result) {
121
+ context.terminated = true;
122
+ context.result = result;
123
+
124
+ this.writeTranscriptEntry(context.transcriptPath, {
125
+ type: "agent_complete",
126
+ agentId: context.agentId,
127
+ result,
128
+ stats: {
129
+ steps: context.steps,
130
+ durationMs: Date.now() - context.startTime,
131
+ inputTokens: context.inputTokens,
132
+ outputTokens: context.outputTokens
133
+ },
134
+ timestamp: Date.now()
135
+ });
136
+
137
+ logger.info({
138
+ agentId: context.agentId,
139
+ steps: context.steps,
140
+ durationMs: Date.now() - context.startTime
141
+ }, "Subagent execution completed");
142
+ }
143
+
144
+ /**
145
+ * Fail subagent execution
146
+ */
147
+ failExecution(context, error) {
148
+ context.terminated = true;
149
+
150
+ this.writeTranscriptEntry(context.transcriptPath, {
151
+ type: "agent_failed",
152
+ agentId: context.agentId,
153
+ error: error.message,
154
+ stats: {
155
+ steps: context.steps,
156
+ durationMs: Date.now() - context.startTime
157
+ },
158
+ timestamp: Date.now()
159
+ });
160
+
161
+ logger.error({
162
+ agentId: context.agentId,
163
+ error: error.message
164
+ }, "Subagent execution failed");
165
+ }
166
+
167
+ /**
168
+ * Write entry to transcript file (JSONL format)
169
+ */
170
+ writeTranscriptEntry(transcriptPath, entry) {
171
+ try {
172
+ fs.appendFileSync(transcriptPath, JSON.stringify(entry) + "\n");
173
+ } catch (error) {
174
+ logger.warn({ error: error.message }, "Failed to write transcript entry");
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Read transcript for debugging
180
+ */
181
+ readTranscript(agentId) {
182
+ const transcriptPath = path.join(this.transcriptsDir, `agent-${agentId}.jsonl`);
183
+
184
+ if (!fs.existsSync(transcriptPath)) {
185
+ return null;
186
+ }
187
+
188
+ const lines = fs.readFileSync(transcriptPath, "utf8").split("\n").filter(l => l.trim());
189
+ return lines.map(line => JSON.parse(line));
190
+ }
191
+
192
+ /**
193
+ * Generate unique agent ID
194
+ */
195
+ generateAgentId() {
196
+ return `${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
197
+ }
198
+
199
+ /**
200
+ * Clean old transcripts (older than 7 days)
201
+ */
202
+ cleanOldTranscripts() {
203
+ const maxAge = 7 * 24 * 60 * 60 * 1000; // 7 days
204
+ const now = Date.now();
205
+
206
+ const files = fs.readdirSync(this.transcriptsDir);
207
+
208
+ for (const file of files) {
209
+ const filePath = path.join(this.transcriptsDir, file);
210
+ const stats = fs.statSync(filePath);
211
+
212
+ if (now - stats.mtimeMs > maxAge) {
213
+ fs.unlinkSync(filePath);
214
+ logger.debug({ file }, "Cleaned old transcript");
215
+ }
216
+ }
217
+ }
218
+ }
219
+
220
+ module.exports = ContextManager;