joonecli 0.1.0 → 0.1.1

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 (69) hide show
  1. package/README.md +12 -12
  2. package/dist/__tests__/optimizations.test.js.map +1 -1
  3. package/dist/__tests__/promptBuilder.test.js +14 -20
  4. package/dist/__tests__/promptBuilder.test.js.map +1 -1
  5. package/dist/agents/agentRegistry.d.ts +37 -0
  6. package/dist/agents/agentRegistry.js +58 -0
  7. package/dist/agents/agentRegistry.js.map +1 -0
  8. package/dist/agents/agentSpec.d.ts +54 -0
  9. package/dist/agents/agentSpec.js +9 -0
  10. package/dist/agents/agentSpec.js.map +1 -0
  11. package/dist/agents/builtinAgents.d.ts +20 -0
  12. package/dist/agents/builtinAgents.js +125 -0
  13. package/dist/agents/builtinAgents.js.map +1 -0
  14. package/dist/cli/config.d.ts +4 -0
  15. package/dist/cli/config.js.map +1 -1
  16. package/dist/cli/index.js +25 -1
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/cli/postinstall.d.ts +2 -0
  19. package/dist/cli/postinstall.js +25 -0
  20. package/dist/cli/postinstall.js.map +1 -0
  21. package/dist/commands/builtinCommands.d.ts +21 -0
  22. package/dist/commands/builtinCommands.js +241 -0
  23. package/dist/commands/builtinCommands.js.map +1 -0
  24. package/dist/commands/commandRegistry.d.ts +90 -0
  25. package/dist/commands/commandRegistry.js +128 -0
  26. package/dist/commands/commandRegistry.js.map +1 -0
  27. package/dist/core/agentLoop.d.ts +4 -1
  28. package/dist/core/agentLoop.js +21 -9
  29. package/dist/core/agentLoop.js.map +1 -1
  30. package/dist/core/autoSave.d.ts +41 -0
  31. package/dist/core/autoSave.js +69 -0
  32. package/dist/core/autoSave.js.map +1 -0
  33. package/dist/core/compactor.d.ts +66 -0
  34. package/dist/core/compactor.js +170 -0
  35. package/dist/core/compactor.js.map +1 -0
  36. package/dist/core/contextGuard.d.ts +33 -0
  37. package/dist/core/contextGuard.js +95 -0
  38. package/dist/core/contextGuard.js.map +1 -0
  39. package/dist/core/promptBuilder.d.ts +16 -1
  40. package/dist/core/promptBuilder.js +27 -14
  41. package/dist/core/promptBuilder.js.map +1 -1
  42. package/dist/core/sessionResumer.js +3 -3
  43. package/dist/core/sessionResumer.js.map +1 -1
  44. package/dist/core/subAgent.d.ts +56 -0
  45. package/dist/core/subAgent.js +240 -0
  46. package/dist/core/subAgent.js.map +1 -0
  47. package/dist/debug_google.d.ts +1 -0
  48. package/dist/debug_google.js +23 -0
  49. package/dist/debug_google.js.map +1 -0
  50. package/dist/test_google.d.ts +1 -0
  51. package/dist/test_google.js +32 -89
  52. package/dist/test_google.js.map +1 -0
  53. package/dist/tools/router.js +2 -0
  54. package/dist/tools/router.js.map +1 -1
  55. package/dist/tools/spawnAgent.d.ts +19 -0
  56. package/dist/tools/spawnAgent.js +130 -0
  57. package/dist/tools/spawnAgent.js.map +1 -0
  58. package/dist/ui/App.js +88 -5
  59. package/dist/ui/App.js.map +1 -1
  60. package/package.json +3 -2
  61. package/src/cli/index.ts +12 -0
  62. package/src/cli/postinstall.ts +28 -0
  63. package/src/core/compactor.ts +2 -2
  64. package/src/core/contextGuard.ts +4 -4
  65. package/src/core/sessionStore.ts +2 -1
  66. package/src/core/subAgent.ts +2 -2
  67. package/tests/core/sessionStore.test.ts +2 -2
  68. package/src/test_google.js +0 -40
  69. package/src/test_google.ts +0 -40
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Context Guard
3
+ *
4
+ * Proactively monitors token usage during the agent loop and triggers auto-compaction
5
+ * before the model's context window is exceeded.
6
+ *
7
+ * Thresholds:
8
+ * - 80% (WARN): Triggers standard LLM-powered context compaction
9
+ * - 95% (CRITICAL): Forces emergency truncation if compaction fails
10
+ */
11
+ import { SystemMessage } from "@langchain/core/messages";
12
+ import { CacheOptimizedPromptBuilder } from "./promptBuilder.js";
13
+ import { countMessageTokens } from "./tokenCounter.js";
14
+ import { createHandoffPrompt } from "./compactor.js";
15
+ export class ContextGuard {
16
+ promptBuilder;
17
+ llm;
18
+ maxTokens;
19
+ constructor(llm, maxTokens, promptBuilder = new CacheOptimizedPromptBuilder()) {
20
+ this.llm = llm;
21
+ this.maxTokens = maxTokens;
22
+ this.promptBuilder = promptBuilder;
23
+ }
24
+ /**
25
+ * Checks the token usage of the current state and compacts if necessary.
26
+ * Returns updated state and metrics about the action taken.
27
+ */
28
+ async ensureCapacity(state, warnThreshold = 0.8, criticalThreshold = 0.95) {
29
+ const fullPrompt = this.promptBuilder.buildPrompt(state);
30
+ const tokenCount = countMessageTokens(fullPrompt);
31
+ // 1. Under limit — do nothing
32
+ if (tokenCount < this.maxTokens * warnThreshold) {
33
+ return {
34
+ state,
35
+ metrics: {
36
+ originalTokens: tokenCount,
37
+ newTokens: tokenCount,
38
+ messagesEvicted: 0,
39
+ actionTaken: "none",
40
+ },
41
+ };
42
+ }
43
+ // 2. Over WARN but below CRITICAL — try standard LLM compaction
44
+ if (tokenCount < this.maxTokens * criticalThreshold) {
45
+ const result = await this.promptBuilder.compactHistoryWithLLM(state.conversationHistory, this.llm, 8 // keep last 8 messages
46
+ );
47
+ return {
48
+ state: {
49
+ ...state,
50
+ conversationHistory: result.compactedHistory,
51
+ },
52
+ metrics: {
53
+ originalTokens: tokenCount,
54
+ newTokens: result.tokensAfter,
55
+ messagesEvicted: result.evictedCount,
56
+ actionTaken: "compacted",
57
+ },
58
+ };
59
+ }
60
+ // 3. CRITICAL overflow (or standard compaction didn't free enough space)
61
+ // Emergency truncation: drop everything except the last 4 messages and inject an emergency handoff
62
+ const keepLast = 4;
63
+ // If we're already at or below 4 messages, we literally can't truncate more
64
+ if (state.conversationHistory.length <= keepLast) {
65
+ return {
66
+ state,
67
+ metrics: { originalTokens: tokenCount, newTokens: tokenCount, messagesEvicted: 0, actionTaken: "none" }
68
+ };
69
+ }
70
+ const recentMsgs = state.conversationHistory.slice(-keepLast);
71
+ const evictedCount = state.conversationHistory.length - keepLast;
72
+ const emergencySystemMsg = new SystemMessage(`[EMERGENCY CONTEXT TRUNCATION]\n` +
73
+ `The conversation exceeded the maximum context window (${this.maxTokens} tokens). ` +
74
+ `Older messages were aggressively deleted without summarization to prevent an immediate crash.\n` +
75
+ `You are the same agent. ` + createHandoffPrompt(new Date().toISOString()));
76
+ const newHistory = [emergencySystemMsg, ...recentMsgs];
77
+ const newTokens = countMessageTokens(this.promptBuilder.buildPrompt({
78
+ ...state,
79
+ conversationHistory: newHistory
80
+ }));
81
+ return {
82
+ state: {
83
+ ...state,
84
+ conversationHistory: newHistory,
85
+ },
86
+ metrics: {
87
+ originalTokens: tokenCount,
88
+ newTokens,
89
+ messagesEvicted: evictedCount,
90
+ actionTaken: "emergency_truncated",
91
+ },
92
+ };
93
+ }
94
+ }
95
+ //# sourceMappingURL=contextGuard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contextGuard.js","sourceRoot":"","sources":["../../src/core/contextGuard.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,7 @@
1
1
  import { BaseMessage } from "@langchain/core/messages";
2
+ import { BaseChatModel } from "@langchain/core/language_models/chat_models";
3
+ import { Runnable } from "@langchain/core/runnables";
4
+ import { CompactionResult } from "./compactor.js";
2
5
  export interface ContextState {
3
6
  globalSystemInstructions: string;
4
7
  projectMemory: string;
@@ -29,7 +32,7 @@ export declare class CacheOptimizedPromptBuilder {
29
32
  */
30
33
  injectSystemReminder(history: BaseMessage[], reminder: string): BaseMessage[];
31
34
  /**
32
- * Cache-Safe Compaction
35
+ * Cache-Safe Compaction (string-based fallback)
33
36
  * When history gets too long, we preserve the last N messages (recent context)
34
37
  * and replace older messages with a summary. The static system prefix is untouched.
35
38
  *
@@ -38,6 +41,18 @@ export declare class CacheOptimizedPromptBuilder {
38
41
  * @param keepLastN - Number of recent messages to preserve (default: 6).
39
42
  */
40
43
  compactHistory(history: BaseMessage[], summary: string, keepLastN?: number): BaseMessage[];
44
+ /**
45
+ * LLM-Powered Compaction with Handoff
46
+ * Uses a dedicated LLM call to generate a structured summary, then injects
47
+ * a handoff prompt to orient the agent. Falls back to string-based compaction
48
+ * if the LLM call fails.
49
+ *
50
+ * @param history - The full conversation history.
51
+ * @param llm - The LLM to use for summarization (should be a fast/cheap model).
52
+ * @param keepLastN - Number of recent messages to preserve (default: 8).
53
+ * @returns CompactionResult with the new history and metrics.
54
+ */
55
+ compactHistoryWithLLM(history: BaseMessage[], llm: Runnable | BaseChatModel, keepLastN?: number): Promise<CompactionResult>;
41
56
  /**
42
57
  * Checks if the conversation should be compacted based on token usage.
43
58
  *
@@ -1,5 +1,6 @@
1
1
  import { SystemMessage, HumanMessage, } from "@langchain/core/messages";
2
2
  import { countMessageTokens } from "./tokenCounter.js";
3
+ import { ConversationCompactor } from "./compactor.js";
3
4
  /**
4
5
  * CacheOptimizedPromptBuilder
5
6
  *
@@ -20,18 +21,15 @@ export class CacheOptimizedPromptBuilder {
20
21
  // We use SystemMessages for the static prefix.
21
22
  // In @langchain/anthropic, to use cache_control, we can inject it into the final message of each tier if needed,
22
23
  // but preserving the exact order of the system prompts is the main requirement.
24
+ const unifiedContent = [
25
+ state.globalSystemInstructions,
26
+ `--- Project Context ---\n${state.projectMemory}`,
27
+ `--- Session Rules ---\n${state.sessionContext}`,
28
+ ].join("\n\n");
23
29
  const systemMessages = [
24
30
  new SystemMessage({
25
- content: state.globalSystemInstructions,
26
- name: "global_instructions",
27
- }),
28
- new SystemMessage({
29
- content: `--- Project Context ---\n${state.projectMemory}`,
30
- name: "project_context",
31
- }),
32
- new SystemMessage({
33
- content: `--- Session Rules ---\n${state.sessionContext}`,
34
- name: "session_context",
31
+ content: unifiedContent,
32
+ name: "global_context",
35
33
  }),
36
34
  ];
37
35
  // Combine the static prefix with the dynamic conversation history
@@ -49,7 +47,7 @@ export class CacheOptimizedPromptBuilder {
49
47
  return [...history, reminderMsg];
50
48
  }
51
49
  /**
52
- * Cache-Safe Compaction
50
+ * Cache-Safe Compaction (string-based fallback)
53
51
  * When history gets too long, we preserve the last N messages (recent context)
54
52
  * and replace older messages with a summary. The static system prefix is untouched.
55
53
  *
@@ -61,13 +59,28 @@ export class CacheOptimizedPromptBuilder {
61
59
  if (history.length === 0) {
62
60
  return history;
63
61
  }
64
- // Use SystemMessage (not AIMessage) to avoid breaking user/assistant
65
- // alternation rules enforced by some providers (e.g. Anthropic).
66
- const compactedMessage = new SystemMessage(`[The previous conversation history has been compacted.]\nSummary:\n${summary}`);
62
+ // Use HumanMessage formatted as a system update to avoid breaking Google's validation
63
+ // and maintaining proper user/assistant flow.
64
+ const compactedMessage = new HumanMessage(`<system-update>\n[The previous conversation history has been compacted.]\nSummary:\n${summary}\n</system-update>`);
67
65
  // Preserve recent messages for continuity
68
66
  const recentMessages = history.slice(-keepLastN);
69
67
  return [compactedMessage, ...recentMessages];
70
68
  }
69
+ /**
70
+ * LLM-Powered Compaction with Handoff
71
+ * Uses a dedicated LLM call to generate a structured summary, then injects
72
+ * a handoff prompt to orient the agent. Falls back to string-based compaction
73
+ * if the LLM call fails.
74
+ *
75
+ * @param history - The full conversation history.
76
+ * @param llm - The LLM to use for summarization (should be a fast/cheap model).
77
+ * @param keepLastN - Number of recent messages to preserve (default: 8).
78
+ * @returns CompactionResult with the new history and metrics.
79
+ */
80
+ async compactHistoryWithLLM(history, llm, keepLastN = 8) {
81
+ const compactor = new ConversationCompactor();
82
+ return compactor.compact(history, llm, { keepLastN });
83
+ }
71
84
  /**
72
85
  * Checks if the conversation should be compacted based on token usage.
73
86
  *
@@ -1 +1 @@
1
- {"version":3,"file":"promptBuilder.js","sourceRoot":"","sources":["../../src/core/promptBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EACb,YAAY,GAEb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AASvD;;;;;;;;;;GAUG;AACH,MAAM,OAAO,2BAA2B;IACtC;;;OAGG;IACI,WAAW,CAAC,KAAmB;QACpC,+CAA+C;QAC/C,iHAAiH;QACjH,gFAAgF;QAEhF,MAAM,cAAc,GAAkB;YACpC,IAAI,aAAa,CAAC;gBAChB,OAAO,EAAE,KAAK,CAAC,wBAAwB;gBACvC,IAAI,EAAE,qBAAqB;aAC5B,CAAC;YACF,IAAI,aAAa,CAAC;gBAChB,OAAO,EAAE,4BAA4B,KAAK,CAAC,aAAa,EAAE;gBAC1D,IAAI,EAAE,iBAAiB;aACxB,CAAC;YACF,IAAI,aAAa,CAAC;gBAChB,OAAO,EAAE,0BAA0B,KAAK,CAAC,cAAc,EAAE;gBACzD,IAAI,EAAE,iBAAiB;aACxB,CAAC;SACH,CAAC;QAEF,kEAAkE;QAClE,OAAO,CAAC,GAAG,cAAc,EAAE,GAAG,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAC3D,CAAC;IAED;;;;OAIG;IACI,oBAAoB,CACzB,OAAsB,EACtB,QAAgB;QAEhB,MAAM,WAAW,GAAG,IAAI,YAAY,CAAC;YACnC,OAAO,EAAE,sBAAsB,QAAQ,sBAAsB;SAC9D,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,OAAO,EAAE,WAAW,CAAC,CAAC;IACnC,CAAC;IAED;;;;;;;;OAQG;IACI,cAAc,CACnB,OAAsB,EACtB,OAAe,EACf,SAAS,GAAG,CAAC;QAEb,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,qEAAqE;QACrE,iEAAiE;QACjE,MAAM,gBAAgB,GAAG,IAAI,aAAa,CACxC,sEAAsE,OAAO,EAAE,CAChF,CAAC;QAEF,0CAA0C;QAC1C,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC;QAEjD,OAAO,CAAC,gBAAgB,EAAE,GAAG,cAAc,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;;OAMG;IACI,aAAa,CAClB,KAAmB,EACnB,SAAiB,EACjB,SAAS,GAAG,GAAG;QAEf,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;QAC9C,OAAO,KAAK,IAAI,SAAS,GAAG,SAAS,CAAC;IACxC,CAAC;CACF"}
1
+ {"version":3,"file":"promptBuilder.js","sourceRoot":"","sources":["../../src/core/promptBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EACb,YAAY,GAEb,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAoB,MAAM,gBAAgB,CAAC;AASzE;;;;;;;;;;GAUG;AACH,MAAM,OAAO,2BAA2B;IACtC;;;OAGG;IACI,WAAW,CAAC,KAAmB;QACpC,+CAA+C;QAC/C,iHAAiH;QACjH,gFAAgF;QAEhF,MAAM,cAAc,GAAG;YACrB,KAAK,CAAC,wBAAwB;YAC9B,4BAA4B,KAAK,CAAC,aAAa,EAAE;YACjD,0BAA0B,KAAK,CAAC,cAAc,EAAE;SACjD,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEf,MAAM,cAAc,GAAkB;YACpC,IAAI,aAAa,CAAC;gBAChB,OAAO,EAAE,cAAc;gBACvB,IAAI,EAAE,gBAAgB;aACvB,CAAC;SACH,CAAC;QAEF,kEAAkE;QAClE,OAAO,CAAC,GAAG,cAAc,EAAE,GAAG,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAC3D,CAAC;IAED;;;;OAIG;IACI,oBAAoB,CACzB,OAAsB,EACtB,QAAgB;QAEhB,MAAM,WAAW,GAAG,IAAI,YAAY,CAAC;YACnC,OAAO,EAAE,sBAAsB,QAAQ,sBAAsB;SAC9D,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,OAAO,EAAE,WAAW,CAAC,CAAC;IACnC,CAAC;IAED;;;;;;;;OAQG;IACI,cAAc,CACnB,OAAsB,EACtB,OAAe,EACf,SAAS,GAAG,CAAC;QAEb,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,sFAAsF;QACtF,8CAA8C;QAC9C,MAAM,gBAAgB,GAAG,IAAI,YAAY,CACvC,uFAAuF,OAAO,oBAAoB,CACnH,CAAC;QAEF,0CAA0C;QAC1C,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC;QAEjD,OAAO,CAAC,gBAAgB,EAAE,GAAG,cAAc,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;;;;;;OAUG;IACI,KAAK,CAAC,qBAAqB,CAChC,OAAsB,EACtB,GAA6B,EAC7B,SAAS,GAAG,CAAC;QAEb,MAAM,SAAS,GAAG,IAAI,qBAAqB,EAAE,CAAC;QAC9C,OAAO,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IACxD,CAAC;IAED;;;;;;OAMG;IACI,aAAa,CAClB,KAAmB,EACnB,SAAiB,EACjB,SAAS,GAAG,GAAG;QAEf,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;QAC9C,OAAO,KAAK,IAAI,SAAS,GAAG,SAAS,CAAC;IACxC,CAAC;CACF"}
@@ -1,6 +1,6 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import { AIMessage, SystemMessage } from "@langchain/core/messages";
3
+ import { AIMessage, HumanMessage } from "@langchain/core/messages";
4
4
  export class SessionResumer {
5
5
  workspaceDir;
6
6
  constructor(workspaceDir) {
@@ -29,9 +29,9 @@ export class SessionResumer {
29
29
  else {
30
30
  wakeupPrompt += `- No files in your active context appear to have been edited on the host while you were paused.\n`;
31
31
  }
32
- // Inject as a System Message at the very end of the history
32
+ // Inject as a Human Message at the very end of the history
33
33
  // so it acts as an immediate reminder before the next LLM generation.
34
- state.conversationHistory.push(new SystemMessage(wakeupPrompt));
34
+ state.conversationHistory.push(new HumanMessage(`<system-wakeup>\n${wakeupPrompt}\n</system-wakeup>`));
35
35
  return state;
36
36
  }
37
37
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"sessionResumer.js","sourceRoot":"","sources":["../../src/core/sessionResumer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sessionResumer.js","sourceRoot":"","sources":["../../src/core/sessionResumer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Sub-Agent Manager
3
+ *
4
+ * Spawns and orchestrates isolated sub-agents for scoped tasks.
5
+ * Each sub-agent gets its own ExecutionHarness with a separate conversation
6
+ * history. Only the final SubAgentResult is returned to the main agent,
7
+ * discarding the sub-agent's internal conversation to save context.
8
+ *
9
+ * Supports both synchronous (blocking) and asynchronous (non-blocking) modes.
10
+ *
11
+ * Safety:
12
+ * - Depth limit of 1: sub-agents cannot spawn other sub-agents
13
+ * - maxTurns cap per agent prevents doom-loops
14
+ * - Concurrent async agent cap of 3 prevents resource exhaustion
15
+ * - Per-agent token budget tracking
16
+ */
17
+ import { SubAgentResult } from "../agents/agentSpec.js";
18
+ import { AgentRegistry } from "../agents/agentRegistry.js";
19
+ import { DynamicToolInterface } from "../tools/index.js";
20
+ import { BaseChatModel } from "@langchain/core/language_models/chat_models";
21
+ import { Runnable } from "@langchain/core/runnables";
22
+ export declare class SubAgentManager {
23
+ private registry;
24
+ private allTools;
25
+ private llm;
26
+ private asyncTasks;
27
+ private taskCounter;
28
+ constructor(registry: AgentRegistry, tools: DynamicToolInterface[], llm: Runnable | BaseChatModel);
29
+ /**
30
+ * Synchronous spawn — blocks until the sub-agent finishes.
31
+ */
32
+ spawn(agentName: string, task: string, maxTurnsOverride?: number): Promise<SubAgentResult>;
33
+ /**
34
+ * Asynchronous spawn — returns immediately with a taskId.
35
+ * The main agent can poll with getResult(taskId).
36
+ */
37
+ spawnAsync(agentName: string, task: string, maxTurnsOverride?: number): Promise<string>;
38
+ /**
39
+ * Check the status or get the result of an async task.
40
+ * Returns the result if completed, or a status message if still running.
41
+ */
42
+ getResult(taskId: string): Promise<SubAgentResult | string>;
43
+ /**
44
+ * Core execution loop for a sub-agent.
45
+ * Creates an isolated conversation and runs a multi-turn loop.
46
+ */
47
+ private runAgent;
48
+ /**
49
+ * Creates an error SubAgentResult.
50
+ */
51
+ private makeErrorResult;
52
+ /**
53
+ * Clean up expired async tasks.
54
+ */
55
+ private cleanupExpired;
56
+ }
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Sub-Agent Manager
3
+ *
4
+ * Spawns and orchestrates isolated sub-agents for scoped tasks.
5
+ * Each sub-agent gets its own ExecutionHarness with a separate conversation
6
+ * history. Only the final SubAgentResult is returned to the main agent,
7
+ * discarding the sub-agent's internal conversation to save context.
8
+ *
9
+ * Supports both synchronous (blocking) and asynchronous (non-blocking) modes.
10
+ *
11
+ * Safety:
12
+ * - Depth limit of 1: sub-agents cannot spawn other sub-agents
13
+ * - maxTurns cap per agent prevents doom-loops
14
+ * - Concurrent async agent cap of 3 prevents resource exhaustion
15
+ * - Per-agent token budget tracking
16
+ */
17
+ import { countMessageTokens } from "../core/tokenCounter.js";
18
+ import { HumanMessage, SystemMessage, ToolMessage } from "@langchain/core/messages";
19
+ // ─── Constants ──────────────────────────────────────────────────────────────────
20
+ const DEFAULT_MAX_TURNS = 10;
21
+ const MAX_CONCURRENT_ASYNC = 3;
22
+ const ASYNC_EXPIRY_MS = 5 * 60 * 1000; // 5 minutes
23
+ // ─── SubAgentManager ────────────────────────────────────────────────────────────
24
+ export class SubAgentManager {
25
+ registry;
26
+ allTools;
27
+ llm;
28
+ asyncTasks = new Map();
29
+ taskCounter = 0;
30
+ constructor(registry, tools, llm) {
31
+ this.registry = registry;
32
+ // Filter out spawn_agent and check_agent to prevent recursive nesting (depth-1 limit)
33
+ this.allTools = tools.filter((t) => t.name !== "spawn_agent" && t.name !== "check_agent");
34
+ this.llm = llm;
35
+ }
36
+ /**
37
+ * Synchronous spawn — blocks until the sub-agent finishes.
38
+ */
39
+ async spawn(agentName, task, maxTurnsOverride) {
40
+ const spec = this.registry.get(agentName);
41
+ if (!spec) {
42
+ return this.makeErrorResult(agentName, task, `Unknown agent "${agentName}". Available: ${this.registry.getNames().join(", ")}`);
43
+ }
44
+ return this.runAgent(spec, task, maxTurnsOverride);
45
+ }
46
+ /**
47
+ * Asynchronous spawn — returns immediately with a taskId.
48
+ * The main agent can poll with getResult(taskId).
49
+ */
50
+ async spawnAsync(agentName, task, maxTurnsOverride) {
51
+ // Cap concurrent async agents
52
+ this.cleanupExpired();
53
+ const activeCount = Array.from(this.asyncTasks.values())
54
+ .filter((t) => !t.completed).length;
55
+ if (activeCount >= MAX_CONCURRENT_ASYNC) {
56
+ throw new Error(`Maximum concurrent async agents reached (${MAX_CONCURRENT_ASYNC}). ` +
57
+ `Wait for existing tasks to complete or check them with check_agent.`);
58
+ }
59
+ const spec = this.registry.get(agentName);
60
+ if (!spec) {
61
+ throw new Error(`Unknown agent "${agentName}". Available: ${this.registry.getNames().join(", ")}`);
62
+ }
63
+ const taskId = `task_${++this.taskCounter}_${Date.now()}`;
64
+ const promise = this.runAgent(spec, task, maxTurnsOverride).then((result) => {
65
+ const asyncTask = this.asyncTasks.get(taskId);
66
+ if (asyncTask) {
67
+ asyncTask.result = result;
68
+ asyncTask.completed = true;
69
+ }
70
+ return result;
71
+ });
72
+ this.asyncTasks.set(taskId, {
73
+ taskId,
74
+ agentName,
75
+ taskDescription: task,
76
+ promise,
77
+ startedAt: Date.now(),
78
+ completed: false,
79
+ });
80
+ return taskId;
81
+ }
82
+ /**
83
+ * Check the status or get the result of an async task.
84
+ * Returns the result if completed, or a status message if still running.
85
+ */
86
+ async getResult(taskId) {
87
+ const asyncTask = this.asyncTasks.get(taskId);
88
+ if (!asyncTask) {
89
+ return `Unknown task ID: ${taskId}. No such async task exists.`;
90
+ }
91
+ if (asyncTask.completed && asyncTask.result) {
92
+ // Clean up the task
93
+ this.asyncTasks.delete(taskId);
94
+ return asyncTask.result;
95
+ }
96
+ const elapsed = Math.round((Date.now() - asyncTask.startedAt) / 1000);
97
+ return `Task "${asyncTask.taskDescription}" (agent: ${asyncTask.agentName}) ` +
98
+ `is still running (${elapsed}s elapsed).`;
99
+ }
100
+ /**
101
+ * Core execution loop for a sub-agent.
102
+ * Creates an isolated conversation and runs a multi-turn loop.
103
+ */
104
+ async runAgent(spec, task, maxTurnsOverride) {
105
+ const startTime = Date.now();
106
+ const maxTurns = maxTurnsOverride ?? spec.maxTurns ?? DEFAULT_MAX_TURNS;
107
+ // Resolve available tools for this agent
108
+ const agentTools = spec.tools
109
+ ? this.allTools.filter((t) => spec.tools.includes(t.name))
110
+ : this.allTools;
111
+ // Create isolated conversation history
112
+ const systemPrompt = new SystemMessage(`${spec.systemPrompt}\n\n--- Current Task ---\n${task}`);
113
+ const history = [
114
+ new HumanMessage(task),
115
+ ];
116
+ let promptTokens = 0;
117
+ let completionTokens = 0;
118
+ let toolCallCount = 0;
119
+ let turnsUsed = 0;
120
+ let lastResponse = "";
121
+ const filesModified = new Set();
122
+ // Build LangChain tool declarations for binding
123
+ const toolDeclarations = agentTools.map((t) => ({
124
+ name: t.name,
125
+ description: t.description,
126
+ schema: t.schema,
127
+ }));
128
+ try {
129
+ // Bind tools to the LLM for this sub-agent session
130
+ let boundLlm;
131
+ if ("bindTools" in this.llm && typeof this.llm.bindTools === "function") {
132
+ boundLlm = this.llm.bindTools(toolDeclarations);
133
+ }
134
+ else {
135
+ boundLlm = this.llm;
136
+ }
137
+ for (let turn = 0; turn < maxTurns; turn++) {
138
+ turnsUsed++;
139
+ // Build the full message array
140
+ const messages = [systemPrompt, ...history];
141
+ const stepPromptTokens = countMessageTokens(messages);
142
+ promptTokens += stepPromptTokens;
143
+ // Invoke the LLM
144
+ const response = await boundLlm.invoke(messages);
145
+ const responseTokens = countMessageTokens([response]);
146
+ completionTokens += responseTokens;
147
+ const aiMessage = response;
148
+ history.push(aiMessage);
149
+ // Extract text content
150
+ if (typeof aiMessage.content === "string" && aiMessage.content.length > 0) {
151
+ lastResponse = aiMessage.content;
152
+ }
153
+ // Check for tool calls
154
+ if (!aiMessage.tool_calls || aiMessage.tool_calls.length === 0) {
155
+ // No tool calls — agent is done
156
+ break;
157
+ }
158
+ // Execute tool calls
159
+ for (const call of aiMessage.tool_calls) {
160
+ if (!call.id)
161
+ continue;
162
+ const tool = agentTools.find((t) => t.name === call.name);
163
+ if (!tool) {
164
+ history.push(new ToolMessage({
165
+ content: `Error: Tool "${call.name}" is not available to this sub-agent.`,
166
+ tool_call_id: call.id,
167
+ }));
168
+ continue;
169
+ }
170
+ toolCallCount++;
171
+ try {
172
+ const result = await tool.execute(call.args);
173
+ const output = typeof result === "string" ? result : result.content;
174
+ // Track file modifications
175
+ if (call.name === "write_file" && call.args?.path) {
176
+ filesModified.add(call.args.path);
177
+ }
178
+ history.push(new ToolMessage({
179
+ content: output,
180
+ tool_call_id: call.id,
181
+ }));
182
+ }
183
+ catch (err) {
184
+ history.push(new ToolMessage({
185
+ content: `Tool error: ${err.message}`,
186
+ tool_call_id: call.id,
187
+ }));
188
+ }
189
+ }
190
+ }
191
+ // Determine outcome
192
+ const outcome = turnsUsed >= maxTurns ? "partial" : "success";
193
+ return {
194
+ agentName: spec.name,
195
+ taskDescription: task,
196
+ outcome,
197
+ result: lastResponse || "(Sub-agent produced no text output)",
198
+ filesModified: Array.from(filesModified),
199
+ toolCallCount,
200
+ tokenUsage: { prompt: promptTokens, completion: completionTokens },
201
+ duration: Date.now() - startTime,
202
+ turnsUsed,
203
+ };
204
+ }
205
+ catch (error) {
206
+ return this.makeErrorResult(spec.name, task, `Sub-agent error: ${error.message}`, { promptTokens, completionTokens, toolCallCount, turnsUsed, startTime, filesModified });
207
+ }
208
+ }
209
+ /**
210
+ * Creates an error SubAgentResult.
211
+ */
212
+ makeErrorResult(agentName, task, errorMsg, partial) {
213
+ return {
214
+ agentName,
215
+ taskDescription: task,
216
+ outcome: "failure",
217
+ result: errorMsg,
218
+ filesModified: partial ? Array.from(partial.filesModified) : [],
219
+ toolCallCount: partial?.toolCallCount ?? 0,
220
+ tokenUsage: {
221
+ prompt: partial?.promptTokens ?? 0,
222
+ completion: partial?.completionTokens ?? 0,
223
+ },
224
+ duration: partial ? Date.now() - partial.startTime : 0,
225
+ turnsUsed: partial?.turnsUsed ?? 0,
226
+ };
227
+ }
228
+ /**
229
+ * Clean up expired async tasks.
230
+ */
231
+ cleanupExpired() {
232
+ const now = Date.now();
233
+ for (const [taskId, task] of this.asyncTasks.entries()) {
234
+ if (now - task.startedAt > ASYNC_EXPIRY_MS) {
235
+ this.asyncTasks.delete(taskId);
236
+ }
237
+ }
238
+ }
239
+ }
240
+ //# sourceMappingURL=subAgent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subAgent.js","sourceRoot":"","sources":["../../src/core/subAgent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ import { ExecutionHarness } from "./core/agentLoop.js";
2
+ import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
3
+ import { HumanMessage } from "@langchain/core/messages";
4
+ async function run() {
5
+ const llm = new ChatGoogleGenerativeAI({ apiKey: "dummy-key", modelName: "gemini-1.5-pro" });
6
+ const harness = new ExecutionHarness(llm, [], undefined, undefined, "google", "gemini-1.5-pro");
7
+ const state = {
8
+ globalSystemInstructions: `You are Joone...`,
9
+ projectMemory: "No project context loaded yet.",
10
+ sessionContext: `Environment: test\nCWD: test`,
11
+ conversationHistory: [
12
+ new HumanMessage("Hello Google AI")
13
+ ]
14
+ };
15
+ try {
16
+ await harness.step(state);
17
+ }
18
+ catch (e) {
19
+ console.error("Caught in harness:", e.message);
20
+ }
21
+ }
22
+ run();
23
+ //# sourceMappingURL=debug_google.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug_google.js","sourceRoot":"","sources":["../src/debug_google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,KAAK,UAAU,GAAG;IAChB,MAAM,GAAG,GAAG,IAAI,sBAAsB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAC7F,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IAEhG,MAAM,KAAK,GAAG;QACZ,wBAAwB,EAAE,kBAAkB;QAC5C,aAAa,EAAE,gCAAgC;QAC/C,cAAc,EAAE,8BAA8B;QAC9C,mBAAmB,EAAE;YACnB,IAAI,YAAY,CAAC,iBAAiB,CAAC;SACpC;KACF,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED,GAAG,EAAE,CAAC"}
@@ -0,0 +1 @@
1
+ export {};