@gotza02/seq-thinking 1.1.2 → 1.1.3
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/README.md +42 -4
- package/data/agents/1770106504306-dljh9ef.json +68 -0
- package/data/agents/1770106504310-4oarrst.json +58 -0
- package/data/agents/1770106540588-pvitt55.json +68 -0
- package/data/agents/1770106540595-z2ya871.json +58 -0
- package/data/agents/1770106710890-0e2naq1.json +68 -0
- package/data/agents/1770106710893-r076yxx.json +58 -0
- package/data/agents/1770109212161-4ybd0i7.json +68 -0
- package/data/agents/1770109212166-gkhya8h.json +58 -0
- package/data/sessions/1770100622009-5afiuyv.json +499 -0
- package/data/sessions/1770106504312-75zk750.json +107 -0
- package/data/sessions/1770106540597-z8e8soo.json +150 -0
- package/data/sessions/1770106710894-0kxgy5x.json +150 -0
- package/data/sessions/1770109212169-zpddeb9.json +150 -0
- package/dist/__tests__/sequential-thinking.test.js +21 -21
- package/dist/__tests__/sequential-thinking.test.js.map +1 -1
- package/dist/agents/base-agent.d.ts +1 -0
- package/dist/agents/base-agent.d.ts.map +1 -1
- package/dist/agents/base-agent.js +5 -3
- package/dist/agents/base-agent.js.map +1 -1
- package/dist/agents/meta-reasoning-agent.d.ts +3 -54
- package/dist/agents/meta-reasoning-agent.d.ts.map +1 -1
- package/dist/agents/meta-reasoning-agent.js +35 -328
- package/dist/agents/meta-reasoning-agent.js.map +1 -1
- package/dist/agents/synthesizer-agent.d.ts +3 -17
- package/dist/agents/synthesizer-agent.d.ts.map +1 -1
- package/dist/agents/synthesizer-agent.js +41 -139
- package/dist/agents/synthesizer-agent.js.map +1 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +9 -6
- package/dist/mcp-server.js.map +1 -1
- package/dist/real_world_test.d.ts +2 -0
- package/dist/real_world_test.d.ts.map +1 -0
- package/dist/real_world_test.js +78 -0
- package/dist/real_world_test.js.map +1 -0
- package/dist/sequential-thinking.d.ts +5 -5
- package/dist/sequential-thinking.d.ts.map +1 -1
- package/dist/sequential-thinking.js +68 -32
- package/dist/sequential-thinking.js.map +1 -1
- package/dist/swarm-coordinator.d.ts +1 -1
- package/dist/swarm-coordinator.d.ts.map +1 -1
- package/dist/swarm-coordinator.js +39 -13
- package/dist/swarm-coordinator.js.map +1 -1
- package/dist/utils/llm-adapter.d.ts +2 -2
- package/dist/utils/llm-adapter.d.ts.map +1 -1
- package/dist/utils/llm-adapter.js +57 -33
- package/dist/utils/llm-adapter.js.map +1 -1
- package/dist/utils/logger.d.ts +20 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +49 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/persistence.d.ts.map +1 -1
- package/dist/utils/persistence.js +4 -3
- package/dist/utils/persistence.js.map +1 -1
- package/package.json +1 -1
- package/real_world_test.log +200 -0
- package/real_world_test_dynamic.log +184 -0
- package/real_world_test_real.log +184 -0
- package/src/__tests__/sequential-thinking.test.ts +21 -21
- package/src/agents/base-agent.ts +6 -3
- package/src/agents/meta-reasoning-agent.ts +38 -397
- package/src/agents/synthesizer-agent.ts +48 -165
- package/src/mcp-server.ts +9 -6
- package/src/real_world_test.ts +89 -0
- package/src/sequential-thinking.ts +87 -33
- package/src/swarm-coordinator.ts +41 -13
- package/src/utils/llm-adapter.ts +66 -32
- package/src/utils/logger.ts +56 -0
- package/src/utils/persistence.ts +4 -3
package/src/swarm-coordinator.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
import { BaseAgent } from './agents/base-agent.js';
|
|
24
24
|
|
|
25
25
|
import { PersistenceManager } from './utils/persistence.js';
|
|
26
|
+
import { Logger } from './utils/logger.js';
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Registry to track all agents in the swarm
|
|
@@ -327,8 +328,9 @@ export class TaskAssigner {
|
|
|
327
328
|
|
|
328
329
|
constructor(private registry: AgentRegistry) {}
|
|
329
330
|
|
|
330
|
-
assignTask(task: Task, strategy: string = 'adaptive') {
|
|
331
|
+
assignTask(task: Task, strategy: string = 'adaptive', excludeAgentIds: string[] = []) {
|
|
331
332
|
const availableAgents = this.registry.getAvailableAgents()
|
|
333
|
+
.filter(a => !excludeAgentIds.includes(a.config.id))
|
|
332
334
|
.filter(a => this.hasRequiredCapabilities(a, task.requirements?.requiredCapabilities || task.requiredCapabilities || []));
|
|
333
335
|
|
|
334
336
|
if (availableAgents.length === 0) return null;
|
|
@@ -568,24 +570,44 @@ export class SwarmCoordinator {
|
|
|
568
570
|
}
|
|
569
571
|
|
|
570
572
|
async executeTask(taskId: string, maxRetries: number = 3) {
|
|
571
|
-
let
|
|
573
|
+
let globalRetries = 0;
|
|
572
574
|
let lastError: any = null;
|
|
575
|
+
const maxGlobalRetries = maxRetries * 2; // Allow attempts across multiple agents
|
|
576
|
+
const failedAgents = new Set<string>();
|
|
573
577
|
|
|
574
|
-
while (
|
|
578
|
+
while (globalRetries < maxGlobalRetries) {
|
|
575
579
|
const task = this.taskQueue.getTask(taskId);
|
|
576
580
|
if (!task) throw new Error(`Task not found: ${taskId}`);
|
|
577
581
|
|
|
582
|
+
// Auto-reassignment logic if not assigned
|
|
578
583
|
if (!task.assignedAgentId) {
|
|
579
|
-
|
|
584
|
+
const agent = this.taskAssigner.assignTask(task, 'adaptive', Array.from(failedAgents));
|
|
585
|
+
if (agent) {
|
|
586
|
+
this.taskQueue.assignTask(task.id, agent.config.id);
|
|
587
|
+
this.registry.updateAgentStatus(agent.config.id, AgentStatus.BUSY);
|
|
588
|
+
Logger.info(`Reassigned task ${taskId} to agent ${agent.config.id}`);
|
|
589
|
+
} else {
|
|
590
|
+
// No more agents available
|
|
591
|
+
Logger.warn(`No suitable agent found for task ${taskId} (Agents tried: ${Array.from(failedAgents).join(', ')})`);
|
|
592
|
+
break;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Check assignment validity
|
|
597
|
+
if (!task.assignedAgentId) {
|
|
598
|
+
break; // Should be handled above, but safety check
|
|
580
599
|
}
|
|
581
600
|
|
|
582
601
|
const agentState = this.registry.getAgent(task.assignedAgentId);
|
|
583
602
|
if (!agentState || !agentState.instance) {
|
|
584
|
-
|
|
603
|
+
// Agent gone? Treat as failure
|
|
604
|
+
failedAgents.add(task.assignedAgentId);
|
|
605
|
+
task.assignedAgentId = null;
|
|
606
|
+
globalRetries++;
|
|
607
|
+
continue;
|
|
585
608
|
}
|
|
586
609
|
|
|
587
610
|
this.taskQueue.startTask(taskId);
|
|
588
|
-
const startTime = Date.now();
|
|
589
611
|
|
|
590
612
|
try {
|
|
591
613
|
const result = await agentState.instance.execute(task);
|
|
@@ -595,20 +617,26 @@ export class SwarmCoordinator {
|
|
|
595
617
|
return result;
|
|
596
618
|
} catch (error) {
|
|
597
619
|
lastError = error;
|
|
598
|
-
|
|
599
|
-
|
|
620
|
+
globalRetries++;
|
|
621
|
+
Logger.warn(`Task ${taskId} failed with agent ${task.assignedAgentId} (attempt ${globalRetries}/${maxGlobalRetries})`, { error });
|
|
600
622
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
623
|
+
// Mark agent as failed for this task and unassign
|
|
624
|
+
if (task.assignedAgentId) {
|
|
625
|
+
failedAgents.add(task.assignedAgentId);
|
|
626
|
+
this.registry.updateAgentStatus(task.assignedAgentId, AgentStatus.IDLE);
|
|
627
|
+
task.assignedAgentId = null; // Unassign to trigger reassignment
|
|
606
628
|
}
|
|
629
|
+
|
|
630
|
+
task.status = TaskStatus.PENDING; // Reset status for next attempt
|
|
631
|
+
|
|
632
|
+
// Wait a bit before next loop
|
|
633
|
+
await new Promise(resolve => setTimeout(resolve, 500 * globalRetries));
|
|
607
634
|
}
|
|
608
635
|
}
|
|
609
636
|
|
|
610
637
|
const processingTime = 0;
|
|
611
638
|
this.taskQueue.failTask(taskId, String(lastError));
|
|
639
|
+
// Final cleanup if task is still assigned
|
|
612
640
|
const task = this.taskQueue.getTask(taskId);
|
|
613
641
|
if (task?.assignedAgentId) {
|
|
614
642
|
this.registry.updateAgentStatus(task.assignedAgentId, AgentStatus.IDLE);
|
package/src/utils/llm-adapter.ts
CHANGED
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
* @module utils/llm-adapter
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { exec } from 'child_process';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
import { Logger } from './logger.js';
|
|
9
|
+
|
|
10
|
+
const execAsync = promisify(exec);
|
|
7
11
|
|
|
8
12
|
export interface LLMResponse {
|
|
9
13
|
content: string;
|
|
@@ -12,56 +16,86 @@ export interface LLMResponse {
|
|
|
12
16
|
|
|
13
17
|
export class LLMAdapter {
|
|
14
18
|
/**
|
|
15
|
-
* Main entry point to call an LLM based on provider
|
|
19
|
+
* Main entry point to call an LLM based on provider pool
|
|
16
20
|
*/
|
|
17
|
-
static async call(prompt: string, systemPrompt?: string): Promise<LLMResponse> {
|
|
18
|
-
const
|
|
19
|
-
const
|
|
21
|
+
static async call(prompt: string, systemPrompt?: string, providerOverride?: string): Promise<LLMResponse> {
|
|
22
|
+
const providerEnv = process.env.provider || 'gemini';
|
|
23
|
+
const providers = providerOverride ? [providerOverride] : providerEnv.split(',').map(p => p.trim());
|
|
24
|
+
|
|
25
|
+
let lastError = '';
|
|
20
26
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return { content: `[MOCK RESPONSE from ${provider}] I have analyzed your request: ${prompt.substring(0, 50)}...` };
|
|
24
|
-
}
|
|
27
|
+
for (const provider of providers) {
|
|
28
|
+
const combinedPrompt = systemPrompt ? `${systemPrompt}\n\nUser: ${prompt}` : prompt;
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
// For testing/development: If MOCK_LLM is set, return mock data
|
|
31
|
+
if (process.env.MOCK_LLM === 'true') {
|
|
32
|
+
Logger.debug('LLM Mock Call', { provider, promptLength: prompt.length });
|
|
33
|
+
return { content: `[MOCK RESPONSE from ${provider}] I have analyzed your request: ${prompt.substring(0, 50)}...` };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
Logger.info('LLM Call initiated', { provider });
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
let response: LLMResponse;
|
|
40
|
+
switch (provider.toLowerCase()) {
|
|
41
|
+
case 'gemini':
|
|
42
|
+
response = await this.safeExec(`gemini ask ${this.escapeShell(combinedPrompt)}`);
|
|
43
|
+
break;
|
|
44
|
+
case 'claude':
|
|
45
|
+
response = await this.safeExec(`claude ${this.escapeShell(combinedPrompt)} --non-interactive`);
|
|
46
|
+
break;
|
|
47
|
+
case 'kimi':
|
|
48
|
+
response = await this.safeExec(`kimi chat ${this.escapeShell(combinedPrompt)}`);
|
|
49
|
+
break;
|
|
50
|
+
case 'opencode':
|
|
51
|
+
response = await this.safeExec(`opencode ask ${this.escapeShell(combinedPrompt)}`);
|
|
52
|
+
break;
|
|
53
|
+
default:
|
|
54
|
+
response = { content: '', error: `Unsupported provider: ${provider}` };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (response.content && !response.error) {
|
|
58
|
+
return response; // Success!
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
lastError = response.error || 'Unknown error';
|
|
62
|
+
Logger.warn(`Provider ${provider} failed, trying next...`, { error: lastError });
|
|
63
|
+
|
|
64
|
+
} catch (error: any) {
|
|
65
|
+
lastError = error.message;
|
|
66
|
+
Logger.error(`LLM Adapter Error with ${provider}`, { error: lastError });
|
|
38
67
|
}
|
|
39
|
-
} catch (error: any) {
|
|
40
|
-
console.error(`LLM Call Error (${provider}):`, error.message);
|
|
41
|
-
return { content: '', error: error.message };
|
|
42
68
|
}
|
|
69
|
+
|
|
70
|
+
return { content: '', error: `All providers failed. Last error: ${lastError}` };
|
|
43
71
|
}
|
|
44
72
|
|
|
45
73
|
/**
|
|
46
74
|
* Safely execute CLI command with timeout and existence check
|
|
47
75
|
*/
|
|
48
|
-
private static safeExec(cmd: string): LLMResponse {
|
|
76
|
+
private static async safeExec(cmd: string): Promise<LLMResponse> {
|
|
49
77
|
try {
|
|
50
78
|
// Check if command base exists (first word)
|
|
51
79
|
const baseCmd = cmd.split(' ')[0];
|
|
52
80
|
try {
|
|
53
|
-
|
|
81
|
+
await execAsync(`command -v ${baseCmd}`);
|
|
54
82
|
} catch {
|
|
55
|
-
|
|
83
|
+
const error = `CLI tool '${baseCmd}' not found or not in PATH. Please install and login.`;
|
|
84
|
+
Logger.warn('CLI tool missing', { baseCmd });
|
|
85
|
+
return { content: '', error };
|
|
56
86
|
}
|
|
57
87
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
61
|
-
timeout: 30000 // 30 second timeout
|
|
88
|
+
const { stdout, stderr } = await execAsync(cmd, {
|
|
89
|
+
timeout: 60000 // 60 second timeout
|
|
62
90
|
});
|
|
63
|
-
|
|
91
|
+
|
|
92
|
+
if (stderr && stderr.trim()) {
|
|
93
|
+
Logger.debug('CLI Stderr output', { baseCmd, stderr: stderr.substring(0, 100) });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { content: stdout.trim() };
|
|
64
97
|
} catch (error: any) {
|
|
98
|
+
Logger.error('Execution failed', { command: cmd.substring(0, 50), error: error.message });
|
|
65
99
|
return { content: '', error: error.message };
|
|
66
100
|
}
|
|
67
101
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple Structured Logging Utility
|
|
3
|
+
* @module utils/logger
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export enum LogLevel {
|
|
7
|
+
DEBUG = 0,
|
|
8
|
+
INFO = 1,
|
|
9
|
+
WARN = 2,
|
|
10
|
+
ERROR = 3
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class Logger {
|
|
14
|
+
private static level: LogLevel = LogLevel.INFO;
|
|
15
|
+
|
|
16
|
+
static setLevel(level: LogLevel) {
|
|
17
|
+
this.level = level;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static debug(message: string, context: any = {}) {
|
|
21
|
+
if (this.level <= LogLevel.DEBUG) {
|
|
22
|
+
this.log('DEBUG', message, context);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static info(message: string, context: any = {}) {
|
|
27
|
+
if (this.level <= LogLevel.INFO) {
|
|
28
|
+
this.log('INFO', message, context);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static warn(message: string, context: any = {}) {
|
|
33
|
+
if (this.level <= LogLevel.WARN) {
|
|
34
|
+
this.log('WARN', message, context);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static error(message: string, context: any = {}) {
|
|
39
|
+
if (this.level <= LogLevel.ERROR) {
|
|
40
|
+
this.log('ERROR', message, context);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private static log(level: string, message: string, context: any) {
|
|
45
|
+
const timestamp = new Date().toISOString();
|
|
46
|
+
const logEntry = {
|
|
47
|
+
timestamp,
|
|
48
|
+
level,
|
|
49
|
+
message,
|
|
50
|
+
...context
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Write to stderr to avoid interfering with MCP stdio protocol
|
|
54
|
+
process.stderr.write(JSON.stringify(logEntry) + '\n');
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/utils/persistence.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import * as fs from 'fs/promises';
|
|
7
7
|
import * as path from 'path';
|
|
8
|
+
import { Logger } from './logger.js';
|
|
8
9
|
|
|
9
10
|
export class PersistenceManager {
|
|
10
11
|
private baseDir: string;
|
|
@@ -23,7 +24,7 @@ export class PersistenceManager {
|
|
|
23
24
|
await fs.mkdir(path.join(this.baseDir, dir), { recursive: true });
|
|
24
25
|
}
|
|
25
26
|
} catch (error) {
|
|
26
|
-
|
|
27
|
+
Logger.error('Failed to initialize persistence directory', { error });
|
|
27
28
|
throw error;
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -38,7 +39,7 @@ export class PersistenceManager {
|
|
|
38
39
|
const serializedData = this.serialize(data);
|
|
39
40
|
await fs.writeFile(filePath, JSON.stringify(serializedData, null, 2), 'utf8');
|
|
40
41
|
} catch (error) {
|
|
41
|
-
|
|
42
|
+
Logger.error(`Failed to save ${collection}/${id}`, { error });
|
|
42
43
|
throw error;
|
|
43
44
|
}
|
|
44
45
|
}
|
|
@@ -53,7 +54,7 @@ export class PersistenceManager {
|
|
|
53
54
|
return JSON.parse(content) as T;
|
|
54
55
|
} catch (error: any) {
|
|
55
56
|
if (error.code === 'ENOENT') return null;
|
|
56
|
-
|
|
57
|
+
Logger.error(`Failed to load ${collection}/${id}`, { error });
|
|
57
58
|
throw error;
|
|
58
59
|
}
|
|
59
60
|
}
|