@redigg/redigg 0.1.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.
- package/LICENSE +21 -0
- package/README.md +145 -0
- package/dist/agent/ResearchAgent.d.ts +35 -0
- package/dist/agent/ResearchAgent.js +818 -0
- package/dist/agent/ResearchAgent.js.map +1 -0
- package/dist/agent/subagent/SubAgent.d.ts +23 -0
- package/dist/agent/subagent/SubAgent.js +87 -0
- package/dist/agent/subagent/SubAgent.js.map +1 -0
- package/dist/agent/subagent/SubAgentManager.d.ts +19 -0
- package/dist/agent/subagent/SubAgentManager.js +40 -0
- package/dist/agent/subagent/SubAgentManager.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +34 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +179 -0
- package/dist/cli.js.map +1 -0
- package/dist/events/EventManager.d.ts +39 -0
- package/dist/events/EventManager.js +20 -0
- package/dist/events/EventManager.js.map +1 -0
- package/dist/gateway/index.d.ts +9 -0
- package/dist/gateway/index.js +474 -0
- package/dist/gateway/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +97 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/LLMClient.d.ts +30 -0
- package/dist/llm/LLMClient.js +21 -0
- package/dist/llm/LLMClient.js.map +1 -0
- package/dist/llm/OpenAIClient.d.ts +16 -0
- package/dist/llm/OpenAIClient.js +58 -0
- package/dist/llm/OpenAIClient.js.map +1 -0
- package/dist/memory/MemoryManager.d.ts +41 -0
- package/dist/memory/MemoryManager.js +221 -0
- package/dist/memory/MemoryManager.js.map +1 -0
- package/dist/memory/evolution/MemoryEvolutionSystem.d.ts +17 -0
- package/dist/memory/evolution/MemoryEvolutionSystem.js +71 -0
- package/dist/memory/evolution/MemoryEvolutionSystem.js.map +1 -0
- package/dist/memory/search/BM25Search.d.ts +22 -0
- package/dist/memory/search/BM25Search.js +61 -0
- package/dist/memory/search/BM25Search.js.map +1 -0
- package/dist/memory/structure/PageIndex.d.ts +26 -0
- package/dist/memory/structure/PageIndex.js +156 -0
- package/dist/memory/structure/PageIndex.js.map +1 -0
- package/dist/quality/QualityManager.d.ts +12 -0
- package/dist/quality/QualityManager.js +61 -0
- package/dist/quality/QualityManager.js.map +1 -0
- package/dist/scheduling/CronManager.d.ts +21 -0
- package/dist/scheduling/CronManager.js +66 -0
- package/dist/scheduling/CronManager.js.map +1 -0
- package/dist/session/SessionManager.d.ts +37 -0
- package/dist/session/SessionManager.js +238 -0
- package/dist/session/SessionManager.js.map +1 -0
- package/dist/skills/SkillManager.d.ts +31 -0
- package/dist/skills/SkillManager.js +254 -0
- package/dist/skills/SkillManager.js.map +1 -0
- package/dist/skills/agent/PACK.md +13 -0
- package/dist/skills/agent/agent-orchestration/SKILL.md +37 -0
- package/dist/skills/agent/agent-orchestration/index.d.ts +9 -0
- package/dist/skills/agent/agent-orchestration/index.js +70 -0
- package/dist/skills/agent/agent-orchestration/index.js.map +1 -0
- package/dist/skills/agent/evolution/SKILL.md +25 -0
- package/dist/skills/agent/evolution/index.d.ts +9 -0
- package/dist/skills/agent/evolution/index.js +57 -0
- package/dist/skills/agent/evolution/index.js.map +1 -0
- package/dist/skills/agent/heartbeat/index.d.ts +8 -0
- package/dist/skills/agent/heartbeat/index.js +44 -0
- package/dist/skills/agent/heartbeat/index.js.map +1 -0
- package/dist/skills/agent/memory-management/SKILL.md +40 -0
- package/dist/skills/agent/memory-management/index.d.ts +8 -0
- package/dist/skills/agent/memory-management/index.js +44 -0
- package/dist/skills/agent/memory-management/index.js.map +1 -0
- package/dist/skills/agent/scheduling/SKILL.md +33 -0
- package/dist/skills/agent/scheduling/index.d.ts +13 -0
- package/dist/skills/agent/scheduling/index.js +80 -0
- package/dist/skills/agent/scheduling/index.js.map +1 -0
- package/dist/skills/agent/session-management/SKILL.md +35 -0
- package/dist/skills/agent/session-management/index.d.ts +11 -0
- package/dist/skills/agent/session-management/index.js +54 -0
- package/dist/skills/agent/session-management/index.js.map +1 -0
- package/dist/skills/agent/skill-management/SKILL.md +31 -0
- package/dist/skills/agent/skill-management/index.d.ts +8 -0
- package/dist/skills/agent/skill-management/index.js +25 -0
- package/dist/skills/agent/skill-management/index.js.map +1 -0
- package/dist/skills/evolution/SkillEvolutionSystem.d.ts +12 -0
- package/dist/skills/evolution/SkillEvolutionSystem.js +157 -0
- package/dist/skills/evolution/SkillEvolutionSystem.js.map +1 -0
- package/dist/skills/lib/ScholarTool.d.ts +14 -0
- package/dist/skills/lib/ScholarTool.js +71 -0
- package/dist/skills/lib/ScholarTool.js.map +1 -0
- package/dist/skills/research/PACK.md +7 -0
- package/dist/skills/research/academic-survey-self-improve/SKILL.md +17 -0
- package/dist/skills/research/academic-survey-self-improve/index.d.ts +10 -0
- package/dist/skills/research/academic-survey-self-improve/index.js +75 -0
- package/dist/skills/research/academic-survey-self-improve/index.js.map +1 -0
- package/dist/skills/research/concept-explainer/SKILL.md +3 -0
- package/dist/skills/research/concept-explainer/index.d.ts +8 -0
- package/dist/skills/research/concept-explainer/index.js +37 -0
- package/dist/skills/research/concept-explainer/index.js.map +1 -0
- package/dist/skills/research/literature-review/SKILL.md +25 -0
- package/dist/skills/research/literature-review/index.d.ts +9 -0
- package/dist/skills/research/literature-review/index.js +132 -0
- package/dist/skills/research/literature-review/index.js.map +1 -0
- package/dist/skills/research/paper-analysis/SKILL.md +3 -0
- package/dist/skills/research/paper-analysis/index.d.ts +9 -0
- package/dist/skills/research/paper-analysis/index.js +64 -0
- package/dist/skills/research/paper-analysis/index.js.map +1 -0
- package/dist/skills/research/pdf-generator/SKILL.md +16 -0
- package/dist/skills/research/pdf-generator/index.d.ts +10 -0
- package/dist/skills/research/pdf-generator/index.js +88 -0
- package/dist/skills/research/pdf-generator/index.js.map +1 -0
- package/dist/skills/system/PACK.md +8 -0
- package/dist/skills/system/code-analysis/SKILL.md +43 -0
- package/dist/skills/system/code-analysis/index.d.ts +12 -0
- package/dist/skills/system/code-analysis/index.js +172 -0
- package/dist/skills/system/code-analysis/index.js.map +1 -0
- package/dist/skills/system/local-file-ops/SKILL.md +55 -0
- package/dist/skills/system/local-file-ops/index.d.ts +9 -0
- package/dist/skills/system/local-file-ops/index.js +111 -0
- package/dist/skills/system/local-file-ops/index.js.map +1 -0
- package/dist/skills/types.d.ts +41 -0
- package/dist/skills/types.js +2 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/skills/vendor/PACK.md +11 -0
- package/dist/skills/vendor/agent-browser/CONTRIBUTING.md +63 -0
- package/dist/skills/vendor/agent-browser/SKILL.md +328 -0
- package/dist/skills/vendor/find-skills/SKILL.md +133 -0
- package/dist/skills/vendor/proactive-agent/SKILL-v2.3-backup.md +554 -0
- package/dist/skills/vendor/proactive-agent/SKILL-v3-draft.md +499 -0
- package/dist/skills/vendor/proactive-agent/SKILL.md +632 -0
- package/dist/skills/vendor/proactive-agent/assets/AGENTS.md +155 -0
- package/dist/skills/vendor/proactive-agent/assets/HEARTBEAT.md +128 -0
- package/dist/skills/vendor/proactive-agent/assets/MEMORY.md +47 -0
- package/dist/skills/vendor/proactive-agent/assets/ONBOARDING.md +103 -0
- package/dist/skills/vendor/proactive-agent/assets/SOUL.md +40 -0
- package/dist/skills/vendor/proactive-agent/assets/TOOLS.md +55 -0
- package/dist/skills/vendor/proactive-agent/assets/USER.md +36 -0
- package/dist/skills/vendor/proactive-agent/references/onboarding-flow.md +158 -0
- package/dist/skills/vendor/proactive-agent/references/security-patterns.md +109 -0
- package/dist/skills/vendor/searxng/CHANGELOG.md +38 -0
- package/dist/skills/vendor/searxng/PUBLISH.md +147 -0
- package/dist/skills/vendor/searxng/PUBLISHING_CHECKLIST.md +111 -0
- package/dist/skills/vendor/searxng/README.md +168 -0
- package/dist/skills/vendor/searxng/SKILL.md +69 -0
- package/dist/skills/vendor/self-improving-agent/.learnings/ERRORS.md +5 -0
- package/dist/skills/vendor/self-improving-agent/.learnings/FEATURE_REQUESTS.md +5 -0
- package/dist/skills/vendor/self-improving-agent/.learnings/LEARNINGS.md +5 -0
- package/dist/skills/vendor/self-improving-agent/SKILL.md +647 -0
- package/dist/skills/vendor/self-improving-agent/assets/LEARNINGS.md +45 -0
- package/dist/skills/vendor/self-improving-agent/assets/SKILL-TEMPLATE.md +177 -0
- package/dist/skills/vendor/self-improving-agent/hooks/openclaw/HOOK.md +23 -0
- package/dist/skills/vendor/self-improving-agent/hooks/openclaw/handler.d.ts +9 -0
- package/dist/skills/vendor/self-improving-agent/hooks/openclaw/handler.js +54 -0
- package/dist/skills/vendor/self-improving-agent/hooks/openclaw/handler.js.map +1 -0
- package/dist/skills/vendor/self-improving-agent/references/examples.md +374 -0
- package/dist/skills/vendor/self-improving-agent/references/hooks-setup.md +223 -0
- package/dist/skills/vendor/self-improving-agent/references/openclaw-integration.md +248 -0
- package/dist/skills/vendor/skill-vetter/SKILL.md +138 -0
- package/dist/src/agent/ResearchAgent.d.ts +35 -0
- package/dist/src/agent/ResearchAgent.js +818 -0
- package/dist/src/agent/ResearchAgent.js.map +1 -0
- package/dist/src/agent/subagent/SubAgent.d.ts +23 -0
- package/dist/src/agent/subagent/SubAgent.js +87 -0
- package/dist/src/agent/subagent/SubAgent.js.map +1 -0
- package/dist/src/agent/subagent/SubAgentManager.d.ts +19 -0
- package/dist/src/agent/subagent/SubAgentManager.js +40 -0
- package/dist/src/agent/subagent/SubAgentManager.js.map +1 -0
- package/dist/src/bin.d.ts +2 -0
- package/dist/src/bin.js +34 -0
- package/dist/src/bin.js.map +1 -0
- package/dist/src/cli.d.ts +1 -0
- package/dist/src/cli.js +179 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/events/EventManager.d.ts +39 -0
- package/dist/src/events/EventManager.js +20 -0
- package/dist/src/events/EventManager.js.map +1 -0
- package/dist/src/gateway/index.d.ts +9 -0
- package/dist/src/gateway/index.js +474 -0
- package/dist/src/gateway/index.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +105 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/llm/LLMClient.d.ts +30 -0
- package/dist/src/llm/LLMClient.js +21 -0
- package/dist/src/llm/LLMClient.js.map +1 -0
- package/dist/src/llm/OpenAIClient.d.ts +16 -0
- package/dist/src/llm/OpenAIClient.js +58 -0
- package/dist/src/llm/OpenAIClient.js.map +1 -0
- package/dist/src/memory/MemoryManager.d.ts +41 -0
- package/dist/src/memory/MemoryManager.js +221 -0
- package/dist/src/memory/MemoryManager.js.map +1 -0
- package/dist/src/memory/evolution/MemoryEvolutionSystem.d.ts +17 -0
- package/dist/src/memory/evolution/MemoryEvolutionSystem.js +71 -0
- package/dist/src/memory/evolution/MemoryEvolutionSystem.js.map +1 -0
- package/dist/src/memory/search/BM25Search.d.ts +22 -0
- package/dist/src/memory/search/BM25Search.js +61 -0
- package/dist/src/memory/search/BM25Search.js.map +1 -0
- package/dist/src/memory/structure/PageIndex.d.ts +26 -0
- package/dist/src/memory/structure/PageIndex.js +156 -0
- package/dist/src/memory/structure/PageIndex.js.map +1 -0
- package/dist/src/quality/QualityManager.d.ts +12 -0
- package/dist/src/quality/QualityManager.js +61 -0
- package/dist/src/quality/QualityManager.js.map +1 -0
- package/dist/src/scheduling/CronManager.d.ts +21 -0
- package/dist/src/scheduling/CronManager.js +66 -0
- package/dist/src/scheduling/CronManager.js.map +1 -0
- package/dist/src/session/SessionManager.d.ts +37 -0
- package/dist/src/session/SessionManager.js +238 -0
- package/dist/src/session/SessionManager.js.map +1 -0
- package/dist/src/skills/SkillManager.d.ts +33 -0
- package/dist/src/skills/SkillManager.js +260 -0
- package/dist/src/skills/SkillManager.js.map +1 -0
- package/dist/src/skills/evolution/SkillEvolutionSystem.d.ts +12 -0
- package/dist/src/skills/evolution/SkillEvolutionSystem.js +157 -0
- package/dist/src/skills/evolution/SkillEvolutionSystem.js.map +1 -0
- package/dist/src/skills/lib/ScholarTool.d.ts +14 -0
- package/dist/src/skills/lib/ScholarTool.js +71 -0
- package/dist/src/skills/lib/ScholarTool.js.map +1 -0
- package/dist/src/skills/types.d.ts +41 -0
- package/dist/src/skills/types.js +2 -0
- package/dist/src/skills/types.js.map +1 -0
- package/dist/src/storage/sqlite.d.ts +8 -0
- package/dist/src/storage/sqlite.js +73 -0
- package/dist/src/storage/sqlite.js.map +1 -0
- package/dist/src/utils/logger.d.ts +12 -0
- package/dist/src/utils/logger.js +53 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/storage/sqlite.d.ts +8 -0
- package/dist/storage/sqlite.js +73 -0
- package/dist/storage/sqlite.js.map +1 -0
- package/dist/utils/logger.d.ts +12 -0
- package/dist/utils/logger.js +53 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +71 -0
- package/skills/agent/PACK.md +13 -0
- package/skills/agent/agent-orchestration/SKILL.md +37 -0
- package/skills/agent/agent-orchestration/index.ts +84 -0
- package/skills/agent/evolution/SKILL.md +25 -0
- package/skills/agent/evolution/index.ts +67 -0
- package/skills/agent/heartbeat/index.ts +48 -0
- package/skills/agent/memory-management/SKILL.md +40 -0
- package/skills/agent/memory-management/index.ts +48 -0
- package/skills/agent/scheduling/SKILL.md +33 -0
- package/skills/agent/scheduling/index.ts +97 -0
- package/skills/agent/session-management/SKILL.md +35 -0
- package/skills/agent/session-management/index.ts +65 -0
- package/skills/agent/skill-management/SKILL.md +31 -0
- package/skills/agent/skill-management/index.ts +32 -0
- package/skills/research/PACK.md +7 -0
- package/skills/research/academic-survey-self-improve/SKILL.md +17 -0
- package/skills/research/academic-survey-self-improve/index.ts +87 -0
- package/skills/research/concept-explainer/SKILL.md +3 -0
- package/skills/research/concept-explainer/index.ts +42 -0
- package/skills/research/literature-review/SKILL.md +25 -0
- package/skills/research/literature-review/index.ts +168 -0
- package/skills/research/paper-analysis/SKILL.md +3 -0
- package/skills/research/paper-analysis/index.ts +73 -0
- package/skills/research/pdf-generator/SKILL.md +16 -0
- package/skills/research/pdf-generator/index.d.ts +10 -0
- package/skills/research/pdf-generator/index.js +114 -0
- package/skills/research/pdf-generator/index.js.map +1 -0
- package/skills/research/pdf-generator/index.ts +97 -0
- package/skills/system/PACK.md +8 -0
- package/skills/system/code-analysis/SKILL.md +43 -0
- package/skills/system/code-analysis/index.ts +180 -0
- package/skills/system/local-file-ops/SKILL.md +55 -0
- package/skills/system/local-file-ops/index.ts +123 -0
- package/skills/vendor/PACK.md +11 -0
- package/skills/vendor/agent-browser/.clawhub/origin.json +7 -0
- package/skills/vendor/agent-browser/CONTRIBUTING.md +63 -0
- package/skills/vendor/agent-browser/SKILL.md +328 -0
- package/skills/vendor/agent-browser/_meta.json +6 -0
- package/skills/vendor/find-skills/.clawhub/origin.json +7 -0
- package/skills/vendor/find-skills/SKILL.md +133 -0
- package/skills/vendor/find-skills/_meta.json +6 -0
- package/skills/vendor/proactive-agent/.clawhub/origin.json +7 -0
- package/skills/vendor/proactive-agent/SKILL-v2.3-backup.md +554 -0
- package/skills/vendor/proactive-agent/SKILL-v3-draft.md +499 -0
- package/skills/vendor/proactive-agent/SKILL.md +632 -0
- package/skills/vendor/proactive-agent/_meta.json +6 -0
- package/skills/vendor/proactive-agent/assets/AGENTS.md +155 -0
- package/skills/vendor/proactive-agent/assets/HEARTBEAT.md +128 -0
- package/skills/vendor/proactive-agent/assets/MEMORY.md +47 -0
- package/skills/vendor/proactive-agent/assets/ONBOARDING.md +103 -0
- package/skills/vendor/proactive-agent/assets/SOUL.md +40 -0
- package/skills/vendor/proactive-agent/assets/TOOLS.md +55 -0
- package/skills/vendor/proactive-agent/assets/USER.md +36 -0
- package/skills/vendor/proactive-agent/references/onboarding-flow.md +158 -0
- package/skills/vendor/proactive-agent/references/security-patterns.md +109 -0
- package/skills/vendor/proactive-agent/scripts/security-audit.sh +149 -0
- package/skills/vendor/searxng/.clawdhub/origin.json +7 -0
- package/skills/vendor/searxng/CHANGELOG.md +38 -0
- package/skills/vendor/searxng/PUBLISH.md +147 -0
- package/skills/vendor/searxng/PUBLISHING_CHECKLIST.md +111 -0
- package/skills/vendor/searxng/README.md +168 -0
- package/skills/vendor/searxng/SKILL.md +69 -0
- package/skills/vendor/searxng/_meta.json +6 -0
- package/skills/vendor/searxng/config/settings.yml +36 -0
- package/skills/vendor/searxng/run-searxng.sh +48 -0
- package/skills/vendor/searxng/scripts/searxng.py +211 -0
- package/skills/vendor/self-improving-agent/.clawhub/origin.json +7 -0
- package/skills/vendor/self-improving-agent/.learnings/ERRORS.md +5 -0
- package/skills/vendor/self-improving-agent/.learnings/FEATURE_REQUESTS.md +5 -0
- package/skills/vendor/self-improving-agent/.learnings/LEARNINGS.md +5 -0
- package/skills/vendor/self-improving-agent/SKILL.md +647 -0
- package/skills/vendor/self-improving-agent/_meta.json +6 -0
- package/skills/vendor/self-improving-agent/assets/LEARNINGS.md +45 -0
- package/skills/vendor/self-improving-agent/assets/SKILL-TEMPLATE.md +177 -0
- package/skills/vendor/self-improving-agent/hooks/openclaw/HOOK.md +23 -0
- package/skills/vendor/self-improving-agent/hooks/openclaw/handler.js +56 -0
- package/skills/vendor/self-improving-agent/hooks/openclaw/handler.ts +62 -0
- package/skills/vendor/self-improving-agent/references/examples.md +374 -0
- package/skills/vendor/self-improving-agent/references/hooks-setup.md +223 -0
- package/skills/vendor/self-improving-agent/references/openclaw-integration.md +248 -0
- package/skills/vendor/self-improving-agent/scripts/activator.sh +20 -0
- package/skills/vendor/self-improving-agent/scripts/error-detector.sh +55 -0
- package/skills/vendor/self-improving-agent/scripts/extract-skill.sh +221 -0
- package/skills/vendor/skill-vetter/.clawhub/origin.json +7 -0
- package/skills/vendor/skill-vetter/SKILL.md +138 -0
- package/skills/vendor/skill-vetter/_meta.json +6 -0
- package/web/README.md +73 -0
- package/web/package.json +65 -0
|
@@ -0,0 +1,818 @@
|
|
|
1
|
+
import { SkillEvolutionSystem } from '../skills/evolution/SkillEvolutionSystem.js';
|
|
2
|
+
import { SkillManager } from '../skills/SkillManager.js';
|
|
3
|
+
import { SessionManager } from '../session/SessionManager.js';
|
|
4
|
+
import { CronManager } from '../scheduling/CronManager.js';
|
|
5
|
+
import { EventManager } from '../events/EventManager.js';
|
|
6
|
+
import { QualityManager } from '../quality/QualityManager.js';
|
|
7
|
+
import { createLogger } from '../utils/logger.js';
|
|
8
|
+
const logger = createLogger('Agent');
|
|
9
|
+
export class ResearchAgent {
|
|
10
|
+
memoryManager;
|
|
11
|
+
memoryEvo;
|
|
12
|
+
skillEvo;
|
|
13
|
+
llm;
|
|
14
|
+
skillManager;
|
|
15
|
+
sessionManager;
|
|
16
|
+
cronManager;
|
|
17
|
+
eventManager;
|
|
18
|
+
qualityManager;
|
|
19
|
+
heartbeatInterval = null;
|
|
20
|
+
constructor(memoryManager, memoryEvo, llm, skillManager) {
|
|
21
|
+
this.memoryManager = memoryManager;
|
|
22
|
+
this.memoryEvo = memoryEvo;
|
|
23
|
+
this.llm = llm;
|
|
24
|
+
this.sessionManager = new SessionManager(memoryManager.storage); // Reuse storage
|
|
25
|
+
this.cronManager = new CronManager();
|
|
26
|
+
this.eventManager = new EventManager();
|
|
27
|
+
this.qualityManager = new QualityManager(llm);
|
|
28
|
+
// Pass managers to SkillManager for injection into SkillContext
|
|
29
|
+
this.skillManager = skillManager || new SkillManager(llm, memoryManager, process.cwd());
|
|
30
|
+
// Inject managers now that they are created
|
|
31
|
+
this.skillManager.setManagers({
|
|
32
|
+
cron: this.cronManager,
|
|
33
|
+
session: this.sessionManager,
|
|
34
|
+
skill: this.skillManager, // Self-reference for skills that need to execute other skills
|
|
35
|
+
event: this.eventManager,
|
|
36
|
+
});
|
|
37
|
+
this.skillEvo = new SkillEvolutionSystem(this.skillManager, llm);
|
|
38
|
+
// Trigger loading from disk (async)
|
|
39
|
+
this.skillManager.loadSkillsFromDisk().catch(err => {
|
|
40
|
+
logger.error('Failed to load skills from disk:', err);
|
|
41
|
+
});
|
|
42
|
+
// Wire up events
|
|
43
|
+
this.setupEventListeners();
|
|
44
|
+
}
|
|
45
|
+
setupEventListeners() {
|
|
46
|
+
// Example: Log all commands
|
|
47
|
+
this.eventManager.on('command:executed', (payload) => {
|
|
48
|
+
logger.info(`[Event] Command Executed: ${payload.command}`);
|
|
49
|
+
});
|
|
50
|
+
// Example: Log memory additions
|
|
51
|
+
this.eventManager.on('memory:added', (payload) => {
|
|
52
|
+
logger.info(`[Event] Memory Added: ${payload.id} (${payload.type})`);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async start() {
|
|
56
|
+
logger.info('Starting heartbeat...');
|
|
57
|
+
this.heartbeatInterval = setInterval(() => this.heartbeat(), 60000); // Every minute
|
|
58
|
+
// Initial check on start
|
|
59
|
+
this.heartbeat().catch(e => logger.error('Initial heartbeat failed:', e));
|
|
60
|
+
}
|
|
61
|
+
stop() {
|
|
62
|
+
if (this.heartbeatInterval) {
|
|
63
|
+
clearInterval(this.heartbeatInterval);
|
|
64
|
+
this.heartbeatInterval = null;
|
|
65
|
+
logger.info('Stopped heartbeat.');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async heartbeat() {
|
|
69
|
+
logger.debug('[Agent] Heartbeat...');
|
|
70
|
+
// Execute Heartbeat Skill
|
|
71
|
+
try {
|
|
72
|
+
// SkillManager loads skills asynchronously, so "heartbeat" might not be ready on first call
|
|
73
|
+
// We should check if it's available or wait/retry, but for now we just catch error
|
|
74
|
+
if (this.skillManager.getSkill('heartbeat')) {
|
|
75
|
+
const result = await this.skillManager.executeSkill('heartbeat', 'system', {});
|
|
76
|
+
// Check for significant updates and notify active session if possible
|
|
77
|
+
const memoryStats = result.memory;
|
|
78
|
+
if (memoryStats && (memoryStats.moved > 0 || memoryStats.promoted > 0 || memoryStats.pruned > 0)) {
|
|
79
|
+
const msg = `[System Heartbeat] Memory Optimization: Moved ${memoryStats.moved} to short-term, Promoted ${memoryStats.promoted} to long-term.`;
|
|
80
|
+
const session = this.sessionManager.getOrCreateActiveSession('web-user');
|
|
81
|
+
if (session) {
|
|
82
|
+
this.sessionManager.addMessage(session.id, 'assistant', msg);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const skillStats = result.skills;
|
|
86
|
+
if (skillStats) {
|
|
87
|
+
// Log stats
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
logger.warn('Heartbeat skill not found (yet). Skipping this beat.');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
logger.error('Heartbeat skill failed:', e);
|
|
96
|
+
}
|
|
97
|
+
// 3. Cron jobs are handled by CronManager independently
|
|
98
|
+
}
|
|
99
|
+
async chat(userId, message, onProgress, sessionId, options) {
|
|
100
|
+
// Helper to log and emit progress
|
|
101
|
+
const log = (content, stats) => {
|
|
102
|
+
const payload = stats ? `${content}__STATS__${JSON.stringify(stats)}` : content;
|
|
103
|
+
onProgress?.('log', payload);
|
|
104
|
+
// Persist log to session history
|
|
105
|
+
this.sessionManager.addMessage(session.id, 'log', payload);
|
|
106
|
+
};
|
|
107
|
+
// Send plan update (UI list)
|
|
108
|
+
const sendPlan = (plan) => {
|
|
109
|
+
onProgress?.('plan', plan);
|
|
110
|
+
};
|
|
111
|
+
// Send todo update (Dynamic List)
|
|
112
|
+
const sendTodo = (todo) => {
|
|
113
|
+
onProgress?.('todo', todo);
|
|
114
|
+
};
|
|
115
|
+
// Get or create session
|
|
116
|
+
let session;
|
|
117
|
+
if (sessionId) {
|
|
118
|
+
const existing = this.sessionManager.getSession(sessionId);
|
|
119
|
+
if (existing && existing.userId === userId) {
|
|
120
|
+
session = existing;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
session = this.sessionManager.createSession(userId);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
session = this.sessionManager.getOrCreateActiveSession(userId);
|
|
128
|
+
}
|
|
129
|
+
// Ensure session is active
|
|
130
|
+
this.sessionManager.activateSession(session.id);
|
|
131
|
+
// Update session title if it's the first user message
|
|
132
|
+
if (session.messages.length === 0) {
|
|
133
|
+
session.title = message.slice(0, 30) + (message.length > 30 ? '...' : '');
|
|
134
|
+
}
|
|
135
|
+
this.sessionManager.addMessage(session.id, 'user', message);
|
|
136
|
+
// 1. Plan
|
|
137
|
+
logger.info(`Creating plan for user ${userId}...`);
|
|
138
|
+
log(`[Agent] Planning response...`);
|
|
139
|
+
// Check if message is simple conversational
|
|
140
|
+
const isConversational = /^(hello|hi|hey|thanks|thank you|bye|goodbye|ok|okay|yes|no|cool|great|wow|who are you|what are you)\b/i.test(message.trim().replace(/[!.?]+$/, ''));
|
|
141
|
+
let plan = { intent: 'single', steps: [] };
|
|
142
|
+
let planningMessage = message;
|
|
143
|
+
// Removed string-based auto mode check in favor of explicit option
|
|
144
|
+
if (!isConversational || options?.autoMode) {
|
|
145
|
+
try {
|
|
146
|
+
// Check for explicit auto-research request
|
|
147
|
+
const forceAuto = options?.autoMode || false;
|
|
148
|
+
plan = await this.createPlan(planningMessage, log, forceAuto);
|
|
149
|
+
if (plan.steps.length > 0) {
|
|
150
|
+
sendPlan({ steps: plan.steps });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch (e) {
|
|
154
|
+
logger.error('Planning failed, falling back to legacy logic', e);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
let reply = '';
|
|
158
|
+
let accumulatedArtifacts = [];
|
|
159
|
+
// 2. Execute Plan or Fallback
|
|
160
|
+
if (plan.intent === 'multi_step' || (plan.intent === 'single' && plan.steps.length > 0)) {
|
|
161
|
+
for (const step of plan.steps) {
|
|
162
|
+
if (this.sessionManager.isSessionStopped(session.id)) {
|
|
163
|
+
log('[Agent] Session stopped by user.');
|
|
164
|
+
return 'Session stopped by user.';
|
|
165
|
+
}
|
|
166
|
+
step.status = 'in_progress';
|
|
167
|
+
sendPlan({ steps: plan.steps });
|
|
168
|
+
let retryCount = 0;
|
|
169
|
+
const maxRetries = 2;
|
|
170
|
+
let success = false;
|
|
171
|
+
const stepStartTime = Date.now();
|
|
172
|
+
while (retryCount <= maxRetries && !success) {
|
|
173
|
+
try {
|
|
174
|
+
if (retryCount > 0) {
|
|
175
|
+
log(`[Agent] Retry ${retryCount}/${maxRetries} for step: ${step.description}`);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
log(`[${step.tool}] ${step.description}`);
|
|
179
|
+
}
|
|
180
|
+
const result = await this.executeStep(step, userId, session, log, onProgress, accumulatedArtifacts);
|
|
181
|
+
// Accumulate artifacts
|
|
182
|
+
if (result.artifacts && result.artifacts.length > 0) {
|
|
183
|
+
accumulatedArtifacts.push(...result.artifacts);
|
|
184
|
+
}
|
|
185
|
+
const duration = Date.now() - stepStartTime;
|
|
186
|
+
// Estimate tokens based on result length if string, or use actual usage
|
|
187
|
+
const tokens = result.usage
|
|
188
|
+
? (result.usage.completionTokens + (result.usage.promptTokens || 0))
|
|
189
|
+
: (typeof result.output === 'string' ? Math.ceil(result.output.length / 4) : 0);
|
|
190
|
+
log(`[${step.tool}] Step completed`, { duration, tokens });
|
|
191
|
+
step.status = 'completed';
|
|
192
|
+
step.result = result.output;
|
|
193
|
+
success = true;
|
|
194
|
+
if (step.tool === 'Chat') {
|
|
195
|
+
reply = result.output;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
retryCount++;
|
|
200
|
+
const errorMsg = String(e);
|
|
201
|
+
const duration = Date.now() - stepStartTime;
|
|
202
|
+
logger.error(`Step failed (Attempt ${retryCount}): ${step.description}`, e);
|
|
203
|
+
if (retryCount > maxRetries) {
|
|
204
|
+
step.status = 'failed';
|
|
205
|
+
step.error = errorMsg;
|
|
206
|
+
log(`[Error] Step failed permanently: ${step.description}`, { duration });
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
log(`[Warning] Step failed, retrying... (${errorMsg})`, { duration });
|
|
210
|
+
// Wait a bit before retry
|
|
211
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
sendPlan({ steps: plan.steps });
|
|
216
|
+
}
|
|
217
|
+
if (!reply) {
|
|
218
|
+
// If no chat step, summarize results
|
|
219
|
+
const completedSteps = plan.steps.filter(s => s.status === 'completed');
|
|
220
|
+
const failedSteps = plan.steps.filter(s => s.status === 'failed');
|
|
221
|
+
let summary = "I have completed the requested tasks.\n\n";
|
|
222
|
+
if (completedSteps.length > 0) {
|
|
223
|
+
summary += "**Completed:**\n" + completedSteps.map(s => `- ${s.description}`).join('\n') + "\n";
|
|
224
|
+
}
|
|
225
|
+
if (failedSteps.length > 0) {
|
|
226
|
+
summary += "\n**Failed:**\n" + failedSteps.map(s => `- ${s.description}: ${s.error}`).join('\n');
|
|
227
|
+
}
|
|
228
|
+
reply = summary;
|
|
229
|
+
const metadata = accumulatedArtifacts.length > 0 ? { attachments: accumulatedArtifacts } : undefined;
|
|
230
|
+
this.sessionManager.addMessage(session.id, 'assistant', reply, metadata);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
// Legacy logic fallback
|
|
235
|
+
reply = await this.executeLegacyLogic(session, userId, message, log, onProgress) || '';
|
|
236
|
+
}
|
|
237
|
+
// If we have a reply from Plan or Legacy, we are done.
|
|
238
|
+
if (reply) {
|
|
239
|
+
// Trigger evolution if needed (Post-processing)
|
|
240
|
+
await this.handlePostProcessing(session, userId, message, reply, log, onProgress);
|
|
241
|
+
}
|
|
242
|
+
return reply || 'I was unable to generate a response.';
|
|
243
|
+
}
|
|
244
|
+
async createPlan(message, log, forceAuto = false) {
|
|
245
|
+
const startTime = Date.now();
|
|
246
|
+
const prompt = `
|
|
247
|
+
You are a planning engine for a research agent.
|
|
248
|
+
User Request: "${message}"
|
|
249
|
+
Force Auto Mode: ${forceAuto}
|
|
250
|
+
|
|
251
|
+
Available Tools:
|
|
252
|
+
- LiteratureReview(topic): Search for papers/web.
|
|
253
|
+
- PaperAnalysis(title): Analyze a specific paper in depth.
|
|
254
|
+
- ConceptExplainer(concept): Explain a scientific concept.
|
|
255
|
+
- PdfGenerator(title, content): Generate a PDF report.
|
|
256
|
+
- CodeAnalysis(path): Analyze project structure/code.
|
|
257
|
+
- MemorySearch(query): Search past memories.
|
|
258
|
+
- FileOps(operation): Organize files.
|
|
259
|
+
- AgentOrchestration(operation): Create/manage sub-agents.
|
|
260
|
+
- Evolution(intent): Create new skills.
|
|
261
|
+
- AutoResearch(topic, iterations): Continuously optimize and improve a research report in a loop.
|
|
262
|
+
- Chat(message): Reply to user (final step).
|
|
263
|
+
|
|
264
|
+
Return a JSON plan:
|
|
265
|
+
{
|
|
266
|
+
"intent": "single" | "multi_step",
|
|
267
|
+
"steps": [
|
|
268
|
+
{
|
|
269
|
+
"id": "1",
|
|
270
|
+
"description": "Concise action description",
|
|
271
|
+
"tool": "ToolName",
|
|
272
|
+
"params": { ... }
|
|
273
|
+
}
|
|
274
|
+
]
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
Rules:
|
|
278
|
+
1. If 'Force Auto Mode' is true, you MUST use the 'AutoResearch' tool as the primary step.
|
|
279
|
+
2. If the user asks for a PDF, ALWAYS include a 'PdfGenerator' step followed by a 'Chat' step.
|
|
280
|
+
3. The 'Chat' step message MUST explicitly mention the generated file and include a placeholder link like '[Title](...)' to indicate where it can be downloaded.
|
|
281
|
+
4. If the user wants to test PDF generation directly or asks for a PDF without confirmation, just generate it.
|
|
282
|
+
`;
|
|
283
|
+
try {
|
|
284
|
+
const response = await this.llm.chat([{ role: 'user', content: prompt }]);
|
|
285
|
+
// Log stats
|
|
286
|
+
const duration = Date.now() - startTime;
|
|
287
|
+
const tokens = response.usage?.completionTokens || Math.ceil(response.content.length / 4);
|
|
288
|
+
if (log) {
|
|
289
|
+
log(`[Agent] Created plan`, { duration, tokens, operation: 'planning' });
|
|
290
|
+
}
|
|
291
|
+
let text = response.content.trim();
|
|
292
|
+
if (text.startsWith('```')) {
|
|
293
|
+
text = text.replace(/^```(json)?/, '').replace(/```$/, '');
|
|
294
|
+
}
|
|
295
|
+
const plan = JSON.parse(text);
|
|
296
|
+
return plan;
|
|
297
|
+
}
|
|
298
|
+
catch (e) {
|
|
299
|
+
logger.error('Planning failed:', e);
|
|
300
|
+
return { intent: 'single', steps: [] };
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
async executeStep(step, userId, session, log, onProgress, accumulatedArtifacts = []) {
|
|
304
|
+
let output = '';
|
|
305
|
+
let artifacts = [];
|
|
306
|
+
let usage;
|
|
307
|
+
switch (step.tool) {
|
|
308
|
+
case 'LiteratureReview':
|
|
309
|
+
output = await this.executeLiteratureReview(session, userId, step.params.topic, log, onProgress);
|
|
310
|
+
break;
|
|
311
|
+
case 'ConceptExplainer':
|
|
312
|
+
const ceResult = await this.skillManager.executeSkill('concept_explainer', userId, { concept: step.params.concept });
|
|
313
|
+
output = ceResult.formatted_output;
|
|
314
|
+
break;
|
|
315
|
+
case 'PdfGenerator':
|
|
316
|
+
const pdfResult = await this.skillManager.executeSkill('pdf_generator', userId, { title: step.params.title, content: step.params.content }, (type, content) => log(`[Skill] ${content}`));
|
|
317
|
+
output = pdfResult.formatted_output;
|
|
318
|
+
if (pdfResult.url && pdfResult.file_path) {
|
|
319
|
+
// Ensure URL is valid (gateway url + relative path)
|
|
320
|
+
const url = pdfResult.url.startsWith('/') ? pdfResult.url : `/${pdfResult.url}`;
|
|
321
|
+
// Use absolute URL if needed, but relative is fine for same origin
|
|
322
|
+
artifacts.push({
|
|
323
|
+
id: `file-${Date.now()}`,
|
|
324
|
+
name: `${step.params.title || 'document'}.pdf`,
|
|
325
|
+
type: 'file',
|
|
326
|
+
url: `http://localhost:4000${url}`,
|
|
327
|
+
path: pdfResult.file_path,
|
|
328
|
+
mimeType: 'application/pdf'
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
break;
|
|
332
|
+
case 'CodeAnalysis':
|
|
333
|
+
const caResult = await this.skillManager.executeSkill('code_analysis', userId, { path: step.params.path || '.', operation: 'structure' });
|
|
334
|
+
output = `Project Structure:\n${caResult.structure}`;
|
|
335
|
+
break;
|
|
336
|
+
case 'MemorySearch':
|
|
337
|
+
const msResult = await this.skillManager.executeSkill('memory_management', userId, { operation: 'search', query: step.params.query });
|
|
338
|
+
output = JSON.stringify(msResult.results);
|
|
339
|
+
break;
|
|
340
|
+
case 'FileOps':
|
|
341
|
+
const foResult = await this.skillManager.executeSkill('local_file_ops', userId, { operation: step.params.operation });
|
|
342
|
+
output = `Moved ${foResult.moved} files.`;
|
|
343
|
+
break;
|
|
344
|
+
case 'AgentOrchestration':
|
|
345
|
+
output = "Agent orchestration not fully implemented in plan yet.";
|
|
346
|
+
break;
|
|
347
|
+
case 'Evolution':
|
|
348
|
+
output = "Evolution not fully implemented in plan yet.";
|
|
349
|
+
break;
|
|
350
|
+
case 'AutoResearch':
|
|
351
|
+
const topic = step.params.topic || 'General Research';
|
|
352
|
+
const iterations = Math.min(step.params.iterations || 3, 5); // Limit to 5
|
|
353
|
+
log(`[AutoResearch] Starting continuous optimization loop for "${topic}" (${iterations} rounds)...`);
|
|
354
|
+
// Notify session that auto mode is active
|
|
355
|
+
// We can use a special log or message that the frontend parses?
|
|
356
|
+
// Or better, we just send logs. Ideally, we'd have a session status.
|
|
357
|
+
// For now, let's just log it clearly.
|
|
358
|
+
let currentContent = `Initial draft for ${topic}.`;
|
|
359
|
+
for (let i = 1; i <= iterations; i++) {
|
|
360
|
+
if (this.sessionManager.isSessionStopped(session.id)) {
|
|
361
|
+
log('[AutoResearch] Session stopped by user.');
|
|
362
|
+
output = `Auto-research stopped by user after ${i - 1} iterations.`;
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
// Check if session is still active/not stopped?
|
|
366
|
+
// Currently we don't have a cancellation token passed down here.
|
|
367
|
+
// But we can check session state if we had it.
|
|
368
|
+
log(`[AutoResearch] Round ${i}/${iterations}: Analyzing and improving...`);
|
|
369
|
+
// 1. Plan Improvement
|
|
370
|
+
const improvePrompt = `
|
|
371
|
+
You are optimizing a research report on "${topic}".
|
|
372
|
+
Current Round: ${i}/${iterations}
|
|
373
|
+
Current Content Length: ${currentContent.length} chars.
|
|
374
|
+
|
|
375
|
+
Goal: Identify ONE specific area to improve (e.g., "Add recent statistics", "Explain concept X better", "Find a case study").
|
|
376
|
+
Return ONLY the improvement task description.
|
|
377
|
+
`;
|
|
378
|
+
const planRes = await this.llm.chat([{ role: 'user', content: improvePrompt }]);
|
|
379
|
+
const improvementTask = planRes.content.trim();
|
|
380
|
+
log(`[AutoResearch] Improvement Task: ${improvementTask}`);
|
|
381
|
+
// 2. Execute Improvement (Simulated via LLM or Skill)
|
|
382
|
+
// For now, we use LLM to expand/refine based on the task
|
|
383
|
+
const refinePrompt = `
|
|
384
|
+
You are an expert researcher.
|
|
385
|
+
Topic: ${topic}
|
|
386
|
+
Current Content:
|
|
387
|
+
${currentContent}
|
|
388
|
+
|
|
389
|
+
Task: ${improvementTask}
|
|
390
|
+
|
|
391
|
+
Action: Perform the task and rewrite the FULL content to include the new information. Make it better, more detailed, and academic.
|
|
392
|
+
`;
|
|
393
|
+
const refineRes = await this.llm.chat([{ role: 'user', content: refinePrompt }]);
|
|
394
|
+
currentContent = refineRes.content;
|
|
395
|
+
// 3. Generate Intermediate PDF
|
|
396
|
+
const title = `${topic} - v${i}`;
|
|
397
|
+
log(`[AutoResearch] Generating PDF version ${i}...`);
|
|
398
|
+
const pdfRes = await this.skillManager.executeSkill('pdf_generator', userId, { title, content: currentContent }, (type, content) => log(`[Skill] ${content}`));
|
|
399
|
+
if (pdfRes.url && pdfRes.file_path) {
|
|
400
|
+
const url = pdfRes.url.startsWith('/') ? pdfRes.url : `/${pdfRes.url}`;
|
|
401
|
+
const artifact = {
|
|
402
|
+
id: `file-${Date.now()}`,
|
|
403
|
+
name: `${title}.pdf`,
|
|
404
|
+
type: 'file',
|
|
405
|
+
url: `http://localhost:4000${url}`,
|
|
406
|
+
path: pdfRes.file_path,
|
|
407
|
+
mimeType: 'application/pdf'
|
|
408
|
+
};
|
|
409
|
+
artifacts.push(artifact);
|
|
410
|
+
accumulatedArtifacts.push(artifact); // Add to global list
|
|
411
|
+
// Send intermediate update to chat
|
|
412
|
+
this.sessionManager.addMessage(session.id, 'assistant', `Round ${i} Complete: I have improved the document based on "${improvementTask}".\n\n[Download ${title}.pdf](${artifact.url})`, { attachments: [artifact] });
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
output = `Auto-research completed after ${iterations} iterations. Final content length: ${currentContent.length}`;
|
|
416
|
+
break;
|
|
417
|
+
case 'Chat': {
|
|
418
|
+
// Use direct LLM call to avoid recursion loop
|
|
419
|
+
// But we need context.
|
|
420
|
+
const context = await this.memoryManager.getFormattedMemories(userId, step.params.message);
|
|
421
|
+
// Include session history
|
|
422
|
+
const history = this.sessionManager.getHistory(session.id, 10);
|
|
423
|
+
const historyText = history.map(m => `${m.role.toUpperCase()}: ${m.content}`).join('\n');
|
|
424
|
+
// Inject artifact info into system prompt so LLM knows what was generated
|
|
425
|
+
let artifactContext = '';
|
|
426
|
+
if (accumulatedArtifacts.length > 0) {
|
|
427
|
+
artifactContext = `
|
|
428
|
+
[SYSTEM NOTICE]
|
|
429
|
+
The following files have been generated and are attached to this response:
|
|
430
|
+
${accumulatedArtifacts.map(a => `- ${a.name} (${a.url})`).join('\n')}
|
|
431
|
+
|
|
432
|
+
IMPORTANT INSTRUCTIONS FOR YOUR REPLY:
|
|
433
|
+
1. You MUST explicitly mention that you have generated these files.
|
|
434
|
+
2. You MUST include a markdown link to the file in your response using the format: [Filename.pdf](URL)
|
|
435
|
+
3. Do not just say "I have attached the file", but provide the clickable link in the text.
|
|
436
|
+
`;
|
|
437
|
+
}
|
|
438
|
+
const response = await this.llm.chat([
|
|
439
|
+
{ role: 'system', content: `You are Redigg. Context: ${context}\n\nSession History:\n${historyText}${artifactContext}` },
|
|
440
|
+
{ role: 'user', content: step.params.message }
|
|
441
|
+
]);
|
|
442
|
+
const reply = response.content;
|
|
443
|
+
usage = response.usage;
|
|
444
|
+
// Attach accumulated artifacts to the final chat message
|
|
445
|
+
// Make sure to attach artifacts to metadata so they are persisted
|
|
446
|
+
const metadata = accumulatedArtifacts.length > 0 ? { attachments: accumulatedArtifacts } : undefined;
|
|
447
|
+
this.sessionManager.addMessage(session.id, 'assistant', reply, metadata);
|
|
448
|
+
output = reply;
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
default:
|
|
452
|
+
throw new Error(`Unknown tool: ${step.tool}`);
|
|
453
|
+
}
|
|
454
|
+
return { output, artifacts, usage };
|
|
455
|
+
}
|
|
456
|
+
async handlePostProcessing(session, userId, message, reply, log, onProgress) {
|
|
457
|
+
// Evolve Memory (Async)
|
|
458
|
+
try {
|
|
459
|
+
const result = await this.memoryEvo.evolve(userId, message, reply, (msg) => log(msg));
|
|
460
|
+
if (result && result.added && result.added.length > 0) {
|
|
461
|
+
// log(`[Evolution] Extracted ${result.added.length} new memories.`); // Redundant as memoryEvo logs it now
|
|
462
|
+
}
|
|
463
|
+
await this.memoryManager.consolidateMemories(userId).catch(e => logger.error('Consolidation failed', e));
|
|
464
|
+
}
|
|
465
|
+
catch (err) {
|
|
466
|
+
logger.error('Memory evolution failed:', err);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
async executeLegacyLogic(session, userId, message, log, onProgress) {
|
|
470
|
+
const lowerMsg = message.toLowerCase();
|
|
471
|
+
// 1. Research Skills / Web Search
|
|
472
|
+
if (lowerMsg.includes('analyze paper') || lowerMsg.includes('summary of paper') || lowerMsg.includes('critique paper')) {
|
|
473
|
+
const title = message.replace(/\b(analyze paper|summary of paper|critique paper|about|on)\b/gi, '').trim();
|
|
474
|
+
if (title.length > 3) {
|
|
475
|
+
log(`[Agent] Analyzing paper: "${title}"`);
|
|
476
|
+
const result = await this.skillManager.executeSkill('paper_analysis', userId, { paper_title: title });
|
|
477
|
+
this.sessionManager.addMessage(session.id, 'assistant', result.formatted_output);
|
|
478
|
+
return result.formatted_output;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (lowerMsg.startsWith('explain') || lowerMsg.includes('what is') || lowerMsg.includes('concept of')) {
|
|
482
|
+
// Simple heuristic: if it looks like a concept question
|
|
483
|
+
// But "what is your name" is conversational.
|
|
484
|
+
if (!lowerMsg.includes('your name') && !lowerMsg.includes('the time')) {
|
|
485
|
+
const concept = message.replace(/\b(explain|what is|concept of|tell me about)\b/gi, '').trim();
|
|
486
|
+
// Let's rely on LLM decision engine usually, but here we can force it if explicitly asked "explain X"
|
|
487
|
+
if (lowerMsg.startsWith('explain')) {
|
|
488
|
+
log(`[Agent] Explaining concept: "${concept}"`);
|
|
489
|
+
const result = await this.skillManager.executeSkill('concept_explainer', userId, { concept });
|
|
490
|
+
this.sessionManager.addMessage(session.id, 'assistant', result.formatted_output);
|
|
491
|
+
return result.formatted_output;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
if (lowerMsg.includes('literature review') || lowerMsg.includes('search papers') || message.includes('[WEB SEARCH REQUEST]')) {
|
|
496
|
+
let topic = message.replace(/\b(do a|perform a|literature review|search papers|about|on)\b/gi, '').trim().replace(/\s+/g, ' ');
|
|
497
|
+
if (message.includes('[WEB SEARCH REQUEST]')) {
|
|
498
|
+
topic = message.replace('[WEB SEARCH REQUEST]', '').split('\n')[0].trim(); // Extract first line as topic usually
|
|
499
|
+
// Clean up the prompt suffix if present
|
|
500
|
+
topic = topic.replace('Please perform a literature review or web search to answer this question.', '').trim();
|
|
501
|
+
}
|
|
502
|
+
if (topic.length > 3) {
|
|
503
|
+
return this.executeLiteratureReview(session, userId, topic, log, onProgress);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
// 2. Infra Skills
|
|
507
|
+
if (lowerMsg.includes('analyze code') || lowerMsg.includes('project structure')) {
|
|
508
|
+
try {
|
|
509
|
+
const targetPath = '.';
|
|
510
|
+
logger.info(`Analyzing code in ${targetPath}...`);
|
|
511
|
+
const startTime = Date.now();
|
|
512
|
+
log(`[Agent] Analyzing code in ${targetPath}...`);
|
|
513
|
+
const result = await this.skillManager.executeSkill('code_analysis', userId, { path: targetPath, operation: 'structure' });
|
|
514
|
+
const duration = Date.now() - startTime;
|
|
515
|
+
const tokens = Math.ceil(result.structure.length / 4);
|
|
516
|
+
log(`[Agent] Completed Code Analysis`, { duration, tokens, operation: 'code_analysis' });
|
|
517
|
+
const response = `Here is the project structure:\n\`\`\`\n${result.structure}\n\`\`\``;
|
|
518
|
+
this.sessionManager.addMessage(session.id, 'assistant', response);
|
|
519
|
+
return response;
|
|
520
|
+
}
|
|
521
|
+
catch (e) {
|
|
522
|
+
logger.error('Skill execution failed:', e);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
if (lowerMsg.includes('organize files') || lowerMsg.includes('move pdfs')) {
|
|
526
|
+
try {
|
|
527
|
+
logger.info('Organizing files...');
|
|
528
|
+
const startTime = Date.now();
|
|
529
|
+
log('[Agent] Organizing files...');
|
|
530
|
+
const result = await this.skillManager.executeSkill('local_file_ops', userId, { operation: 'organize' });
|
|
531
|
+
const duration = Date.now() - startTime;
|
|
532
|
+
log(`[Agent] Completed File Organization`, { duration, tokens: 0, operation: 'file_ops' });
|
|
533
|
+
const response = `I have organized your PDF files into a 'papers' folder. Moved ${result.moved} files.`;
|
|
534
|
+
this.sessionManager.addMessage(session.id, 'assistant', response);
|
|
535
|
+
return response;
|
|
536
|
+
}
|
|
537
|
+
catch (e) {
|
|
538
|
+
logger.error('Skill execution failed:', e);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
// 3. Core Skills (Memory, Agents, Evolution)
|
|
542
|
+
if (lowerMsg.includes('search memories') || lowerMsg.includes('recall')) {
|
|
543
|
+
try {
|
|
544
|
+
const query = message.replace(/\b(search memories|recall|find memory about)\b/gi, '').trim();
|
|
545
|
+
logger.info(`Searching memories for "${query}"...`);
|
|
546
|
+
const startTime = Date.now();
|
|
547
|
+
log(`[Agent] Searching memories for "${query}"...`);
|
|
548
|
+
const result = await this.skillManager.executeSkill('memory_management', userId, {
|
|
549
|
+
operation: 'search',
|
|
550
|
+
query
|
|
551
|
+
});
|
|
552
|
+
const duration = Date.now() - startTime;
|
|
553
|
+
const memories = result.results;
|
|
554
|
+
const tokens = Math.ceil(JSON.stringify(memories).length / 4);
|
|
555
|
+
log(`[Agent] Completed Memory Search`, { duration, tokens, operation: 'memory_search' });
|
|
556
|
+
let response = '';
|
|
557
|
+
if (memories.length === 0) {
|
|
558
|
+
response = `I couldn't find any memories matching "${query}".`;
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
response = `Here are the memories I found:\n\n${memories.map(m => `- [${m.tier}] ${m.content} (${new Date(m.created_at).toLocaleDateString()})`).join('\n')}`;
|
|
562
|
+
}
|
|
563
|
+
this.sessionManager.addMessage(session.id, 'assistant', response);
|
|
564
|
+
return response;
|
|
565
|
+
}
|
|
566
|
+
catch (e) {
|
|
567
|
+
logger.error('Memory search failed:', e);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (lowerMsg.includes('create agent') || lowerMsg.includes('sub-agent') || lowerMsg.includes('delegate') || lowerMsg.includes('list agents')) {
|
|
571
|
+
try {
|
|
572
|
+
if (lowerMsg.includes('create agent')) {
|
|
573
|
+
const nameMatch = message.match(/named\s+["']?(\w+)["']?/i);
|
|
574
|
+
const roleMatch = message.match(/role\s+of\s+["']?([\w\s]+)["']?/i);
|
|
575
|
+
const name = nameMatch ? nameMatch[1] : 'Assistant';
|
|
576
|
+
const role = roleMatch ? roleMatch[1] : 'Generalist';
|
|
577
|
+
const result = await this.skillManager.executeSkill('agent_orchestration', userId, {
|
|
578
|
+
operation: 'create_agent',
|
|
579
|
+
name,
|
|
580
|
+
role
|
|
581
|
+
});
|
|
582
|
+
const response = `Created sub-agent ${result.name} (ID: ${result.agentId})`;
|
|
583
|
+
this.sessionManager.addMessage(session.id, 'assistant', response);
|
|
584
|
+
return response;
|
|
585
|
+
}
|
|
586
|
+
else if (lowerMsg.includes('list agents')) {
|
|
587
|
+
const result = await this.skillManager.executeSkill('agent_orchestration', userId, {
|
|
588
|
+
operation: 'list_agents'
|
|
589
|
+
});
|
|
590
|
+
const agents = result.agents;
|
|
591
|
+
const response = `Active Agents:\n${agents.map(a => `- ${a.name} (${a.role})`).join('\n')}`;
|
|
592
|
+
this.sessionManager.addMessage(session.id, 'assistant', response);
|
|
593
|
+
return response;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
catch (e) {
|
|
597
|
+
logger.error('Orchestration failed:', e);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
if (lowerMsg.includes('can you') || lowerMsg.includes('how do i') || lowerMsg.includes('evolve')) {
|
|
601
|
+
logger.info('Checking if I need to learn a new skill or evolve...');
|
|
602
|
+
log('[Agent] Checking if I need to learn a new skill or evolve...');
|
|
603
|
+
try {
|
|
604
|
+
const intent = message.replace(/\b(can you|how do i|evolve|create a skill to)\b/gi, '').trim();
|
|
605
|
+
if (intent.length > 5) {
|
|
606
|
+
const result = await this.skillManager.executeSkill('evolution', userId, {
|
|
607
|
+
operation: 'create_skill',
|
|
608
|
+
intent
|
|
609
|
+
});
|
|
610
|
+
if (result.success) {
|
|
611
|
+
const response = `I've evolved! ${result.message} (Skill ID: ${result.skillId})`;
|
|
612
|
+
this.sessionManager.addMessage(session.id, 'assistant', response);
|
|
613
|
+
return response;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
catch (e) {
|
|
618
|
+
// Fallback
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
// 4. Intelligent Default: Web Search for Unknown Topics
|
|
622
|
+
// Check if we have relevant memories. Strict search (no fallback to recent).
|
|
623
|
+
// This implements the "Default to Search" behavior for new topics.
|
|
624
|
+
const strictMemories = await this.memoryManager.searchMemories(userId, message, { limit: 1 });
|
|
625
|
+
const hasContext = strictMemories.length > 0;
|
|
626
|
+
const isConversational = /^(hello|hi|hey|thanks|thank you|bye|goodbye|ok|okay|yes|no|cool|great|wow|who are you|what are you)\b/i.test(message.trim().replace(/[!.?]+$/, ''));
|
|
627
|
+
if (!hasContext && !isConversational) {
|
|
628
|
+
log('[Agent] No local knowledge found. Checking if web search is needed...');
|
|
629
|
+
const decision = await this.shouldSearch(message, log);
|
|
630
|
+
if (decision.shouldSearch) {
|
|
631
|
+
logger.info(`Implicit intent: Web Search on "${decision.topic}"`);
|
|
632
|
+
log(`[Agent] Decided to search web for: "${decision.topic}"`);
|
|
633
|
+
return this.executeLiteratureReview(session, userId, decision.topic, log, onProgress);
|
|
634
|
+
}
|
|
635
|
+
else {
|
|
636
|
+
log('[Agent] Decided not to search web. Generating response...');
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
// 5. Fallback: LLM Chat
|
|
640
|
+
logger.info(`Retrieving context for user ${userId}...`);
|
|
641
|
+
log(`[Agent] Retrieving context for user ${userId}...`);
|
|
642
|
+
const context = await this.memoryManager.getFormattedMemories(userId, message);
|
|
643
|
+
// Retrieve Session History
|
|
644
|
+
const history = this.sessionManager.getHistory(session.id, 5); // Last 5 messages
|
|
645
|
+
const historyText = history.map(m => `${m.role.toUpperCase()}: ${m.content}`).join('\n');
|
|
646
|
+
// Build Prompt
|
|
647
|
+
const systemPrompt = `
|
|
648
|
+
You are Redigg, an autonomous research agent.
|
|
649
|
+
Your goal is to assist researchers by providing accurate, insightful, and personalized responses.
|
|
650
|
+
|
|
651
|
+
User Context & Preferences:
|
|
652
|
+
${context || 'No prior context available.'}
|
|
653
|
+
|
|
654
|
+
Session History:
|
|
655
|
+
${historyText}
|
|
656
|
+
|
|
657
|
+
Instructions:
|
|
658
|
+
- Use the provided context to tailor your response.
|
|
659
|
+
- Be concise and scientific.
|
|
660
|
+
- If you don't know something, admit it.
|
|
661
|
+
`.trim();
|
|
662
|
+
// Generate Response
|
|
663
|
+
logger.info(`Generating response...`);
|
|
664
|
+
log(`[Agent] Generating response...`);
|
|
665
|
+
let reply = '';
|
|
666
|
+
if (this.llm.chatStream && onProgress) {
|
|
667
|
+
await this.llm.chatStream([
|
|
668
|
+
{ role: 'system', content: systemPrompt },
|
|
669
|
+
{ role: 'user', content: message }
|
|
670
|
+
], {
|
|
671
|
+
onToken: (token) => {
|
|
672
|
+
reply += token;
|
|
673
|
+
onProgress('token', token);
|
|
674
|
+
},
|
|
675
|
+
onError: (err) => logger.error(String(err))
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
const response = await this.llm.chat([
|
|
680
|
+
{ role: 'system', content: systemPrompt },
|
|
681
|
+
{ role: 'user', content: message }
|
|
682
|
+
]);
|
|
683
|
+
reply = response.content;
|
|
684
|
+
}
|
|
685
|
+
// Save response to session
|
|
686
|
+
this.sessionManager.addMessage(session.id, 'assistant', reply);
|
|
687
|
+
// Evolve Memory (Async - now awaited to ensure logs are streamed)
|
|
688
|
+
try {
|
|
689
|
+
const result = await this.memoryEvo.evolve(userId, message, reply, (msg) => log(msg));
|
|
690
|
+
if (result && result.added && result.added.length > 0) {
|
|
691
|
+
log(`[Evolution] Extracted ${result.added.length} new memories.`);
|
|
692
|
+
result.added.forEach((m) => {
|
|
693
|
+
log(`[Evolution] New Memory: "${m.content}" (${m.type}/${m.tier})`);
|
|
694
|
+
});
|
|
695
|
+
// Silent execution: no chat message for memory updates
|
|
696
|
+
}
|
|
697
|
+
if (result && result.updated && result.updated.length > 0) {
|
|
698
|
+
log(`[Evolution] Updated ${result.updated.length} memories.`);
|
|
699
|
+
result.updated.forEach((m) => {
|
|
700
|
+
log(`[Evolution] Updated Memory: "${m.content}" (${m.type}/${m.tier})`);
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
// Trigger memory consolidation immediately after new interaction
|
|
704
|
+
await this.memoryManager.consolidateMemories(userId).then(() => {
|
|
705
|
+
// logger.debug('Post-chat consolidation complete');
|
|
706
|
+
}).catch(e => {
|
|
707
|
+
logger.error('Post-chat consolidation failed', e);
|
|
708
|
+
});
|
|
709
|
+
// After response and memory evolution, generate a title for the session if it's still generic
|
|
710
|
+
if (session.messages.length <= 4 && (session.title || '').length > 20) { // Early in convo or long default title
|
|
711
|
+
const title = await this.generateSessionTitle(session, message, reply);
|
|
712
|
+
if (title) {
|
|
713
|
+
session.title = title;
|
|
714
|
+
onProgress?.('token', `[TITLE_GENERATED]${title}`);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
catch (err) {
|
|
719
|
+
logger.error('Memory evolution failed:', err);
|
|
720
|
+
}
|
|
721
|
+
return reply;
|
|
722
|
+
}
|
|
723
|
+
async generateSessionTitle(session, userMsg, agentMsg) {
|
|
724
|
+
try {
|
|
725
|
+
const prompt = `Summarize the following conversation into a short, 3-5 word title. Do not use quotes.
|
|
726
|
+
User: ${userMsg}
|
|
727
|
+
Agent: ${agentMsg}
|
|
728
|
+
Title:`;
|
|
729
|
+
const response = await this.llm.chat([{ role: 'user', content: prompt }]);
|
|
730
|
+
return response.content.trim();
|
|
731
|
+
}
|
|
732
|
+
catch (e) {
|
|
733
|
+
return null;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async executeLiteratureReview(session, userId, topic, log, onProgress) {
|
|
737
|
+
logger.info(`Detected intent: Literature Review on "${topic}"`);
|
|
738
|
+
const startTime = Date.now();
|
|
739
|
+
log(`[Agent] Detected intent: Literature Review (Web Search) on "${topic}"`);
|
|
740
|
+
try {
|
|
741
|
+
const result = await this.skillManager.executeSkill('academic_survey_self_improve', userId, { topic }, {
|
|
742
|
+
onLog: (type, content) => log(`[Skill] ${content}`),
|
|
743
|
+
onProgress: async (progress, description, metadata) => {
|
|
744
|
+
log(`[Skill Progress] ${progress}% - ${description}`, metadata);
|
|
745
|
+
if (metadata && metadata.papers) {
|
|
746
|
+
// Emit todo/progress update for UI
|
|
747
|
+
onProgress?.('todo', {
|
|
748
|
+
id: 'research-progress',
|
|
749
|
+
type: 'research',
|
|
750
|
+
status: 'in_progress',
|
|
751
|
+
content: `Found ${metadata.papers.length} papers`,
|
|
752
|
+
metadata: metadata
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
},
|
|
756
|
+
onTodo: async (content, priority, step) => {
|
|
757
|
+
onProgress?.('todo', {
|
|
758
|
+
id: `skill-todo-${Date.now()}`,
|
|
759
|
+
status: 'pending',
|
|
760
|
+
content,
|
|
761
|
+
priority
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
const duration = Date.now() - startTime;
|
|
766
|
+
const tokens = Math.ceil(result.summary.length / 4); // Estimate
|
|
767
|
+
log(`[Agent] Completed Literature Review`, { duration, tokens, operation: 'literature_review' });
|
|
768
|
+
const response = `Here is a literature review on "${topic}":\n\n${result.summary}\n\n**Sources:**\n${result.papers.map((p) => `- [${p.title}](${p.url || '#'}) (${p.year})`).join('\n')}`;
|
|
769
|
+
// Perform Quality Check
|
|
770
|
+
const quality = await this.qualityManager.evaluateTask(`Literature Review on "${topic}"`, result.summary, { papersCount: result.papers.length });
|
|
771
|
+
if (!quality.passed) {
|
|
772
|
+
log(`[Quality] Warning: Score ${quality.score}/100. ${quality.reasoning}`);
|
|
773
|
+
const warning = `\n\n> ⚠️ **Quality Check**: This review scored ${quality.score}/100. ${quality.suggestions[0] || ''}`;
|
|
774
|
+
this.sessionManager.addMessage(session.id, 'assistant', response + warning);
|
|
775
|
+
return response + warning;
|
|
776
|
+
}
|
|
777
|
+
this.sessionManager.addMessage(session.id, 'assistant', response);
|
|
778
|
+
return response;
|
|
779
|
+
}
|
|
780
|
+
catch (e) {
|
|
781
|
+
logger.error('Skill execution failed:', e);
|
|
782
|
+
const errorMsg = "I encountered an error while searching for papers.";
|
|
783
|
+
this.sessionManager.addMessage(session.id, 'assistant', errorMsg);
|
|
784
|
+
return errorMsg;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
async shouldSearch(message, log) {
|
|
788
|
+
const prompt = `
|
|
789
|
+
You are a decision engine for a research agent.
|
|
790
|
+
The user sent: "${message}"
|
|
791
|
+
We have NO local memory/context about this topic.
|
|
792
|
+
|
|
793
|
+
Should we perform a web search to answer this?
|
|
794
|
+
- YES if it asks for facts, news, definitions, explanations of concepts, or research.
|
|
795
|
+
- NO if it is conversational (greeting, thanks), personal ("who are you"), or asks about "this project" or "code" (which should have been caught by other skills).
|
|
796
|
+
|
|
797
|
+
Reply strictly in this format:
|
|
798
|
+
SEARCH: <topic>
|
|
799
|
+
or
|
|
800
|
+
NO_SEARCH
|
|
801
|
+
`;
|
|
802
|
+
try {
|
|
803
|
+
if (log)
|
|
804
|
+
log('[Agent] Thinking about whether to search the web...');
|
|
805
|
+
const res = await this.llm.chat([{ role: 'user', content: prompt }]);
|
|
806
|
+
console.log('[DEBUG] shouldSearch response:', res);
|
|
807
|
+
const text = res.content.trim();
|
|
808
|
+
if (text.startsWith('SEARCH:')) {
|
|
809
|
+
return { shouldSearch: true, topic: text.replace('SEARCH:', '').trim() };
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
catch (e) {
|
|
813
|
+
logger.error('Decision engine failed:', e);
|
|
814
|
+
}
|
|
815
|
+
return { shouldSearch: false, topic: '' };
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
//# sourceMappingURL=ResearchAgent.js.map
|