Skip to content

Commit e55817f

Browse files
committed
feat: background tools is now scope to agents
1 parent caefc97 commit e55817f

20 files changed

+118
-260
lines changed

packages/agent/CHANGELOG.md

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
# [mycoder-agent-v1.1.0](https://github.com/drivecore/mycoder/compare/mycoder-agent-v1.0.0...mycoder-agent-v1.1.0) (2025-03-12)
22

3-
43
### Bug Fixes
54

6-
* convert absolute paths to relative paths in textEditor log output ([a5ea845](https://github.com/drivecore/mycoder/commit/a5ea845c32bc569cda4330f59f1bf1553a236aea))
7-
* implement resource cleanup to prevent CLI hanging issue ([d33e729](https://github.com/drivecore/mycoder/commit/d33e7298686a30661ee8b36f2fdffb16f5f3da71)), closes [#141](https://github.com/drivecore/mycoder/issues/141)
8-
* llm choice working well for openai, anthropic and ollama ([68d34ab](https://github.com/drivecore/mycoder/commit/68d34abf8a73ed533a072359ce334a9364753425))
9-
* **openai:** add OpenAI dependency to agent package and enable provider in config ([30b0807](https://github.com/drivecore/mycoder/commit/30b0807d4f3ecdd24f53b7ee4160645a4ed10444))
10-
* replace @semantic-release/npm with @anolilab/semantic-release-pnpm to properly resolve workspace references ([bacb51f](https://github.com/drivecore/mycoder/commit/bacb51f637f2b2d3b1039bdfdbd33e3d704b6cde))
11-
* up subagent iterations to 200 from 50 ([b405f1e](https://github.com/drivecore/mycoder/commit/b405f1e6d62eb5304dc1aa6c0ff28dc49dc67dce))
12-
5+
- convert absolute paths to relative paths in textEditor log output ([a5ea845](https://github.com/drivecore/mycoder/commit/a5ea845c32bc569cda4330f59f1bf1553a236aea))
6+
- implement resource cleanup to prevent CLI hanging issue ([d33e729](https://github.com/drivecore/mycoder/commit/d33e7298686a30661ee8b36f2fdffb16f5f3da71)), closes [#141](https://github.com/drivecore/mycoder/issues/141)
7+
- llm choice working well for openai, anthropic and ollama ([68d34ab](https://github.com/drivecore/mycoder/commit/68d34abf8a73ed533a072359ce334a9364753425))
8+
- **openai:** add OpenAI dependency to agent package and enable provider in config ([30b0807](https://github.com/drivecore/mycoder/commit/30b0807d4f3ecdd24f53b7ee4160645a4ed10444))
9+
- replace @semantic-release/npm with @anolilab/semantic-release-pnpm to properly resolve workspace references ([bacb51f](https://github.com/drivecore/mycoder/commit/bacb51f637f2b2d3b1039bdfdbd33e3d704b6cde))
10+
- up subagent iterations to 200 from 50 ([b405f1e](https://github.com/drivecore/mycoder/commit/b405f1e6d62eb5304dc1aa6c0ff28dc49dc67dce))
1311

1412
### Features
1513

16-
* add agent tracking to background tools ([4a3bcc7](https://github.com/drivecore/mycoder/commit/4a3bcc72f27af5fdbeeb407a748d5ecf3b7faed5))
17-
* add Ollama configuration options ([d5c3a96](https://github.com/drivecore/mycoder/commit/d5c3a96ce9463c98504c2a346796400df36bf3b0))
18-
* **agent:** implement agentStart and agentMessage tools ([62f8df3](https://github.com/drivecore/mycoder/commit/62f8df3dd083e2838c97ce89112f390461550ee6)), closes [#111](https://github.com/drivecore/mycoder/issues/111) [#111](https://github.com/drivecore/mycoder/issues/111)
19-
* allow textEditor to overwrite existing files with create command ([d1cde65](https://github.com/drivecore/mycoder/commit/d1cde65df65bfcca288a47f14eedf5ad5939ed37)), closes [#192](https://github.com/drivecore/mycoder/issues/192)
20-
* implement background tool tracking (issue [#112](https://github.com/drivecore/mycoder/issues/112)) ([b5bb489](https://github.com/drivecore/mycoder/commit/b5bb48981791acda74ee46b93d2d85e27e93a538))
21-
* implement Ollama provider for LLM abstraction ([597211b](https://github.com/drivecore/mycoder/commit/597211b90e43c4d52969eb5994d393c15d85ec97))
22-
* **llm:** add OpenAI support to LLM abstraction ([7bda811](https://github.com/drivecore/mycoder/commit/7bda811658e15b8dd41135cd9b2b90e9ea925e15))
23-
* **refactor:** agent ([a2f59c2](https://github.com/drivecore/mycoder/commit/a2f59c2f51643a44d6e1ff0c16b319deb1adc3f2))
14+
- add agent tracking to background tools ([4a3bcc7](https://github.com/drivecore/mycoder/commit/4a3bcc72f27af5fdbeeb407a748d5ecf3b7faed5))
15+
- add Ollama configuration options ([d5c3a96](https://github.com/drivecore/mycoder/commit/d5c3a96ce9463c98504c2a346796400df36bf3b0))
16+
- **agent:** implement agentStart and agentMessage tools ([62f8df3](https://github.com/drivecore/mycoder/commit/62f8df3dd083e2838c97ce89112f390461550ee6)), closes [#111](https://github.com/drivecore/mycoder/issues/111) [#111](https://github.com/drivecore/mycoder/issues/111)
17+
- allow textEditor to overwrite existing files with create command ([d1cde65](https://github.com/drivecore/mycoder/commit/d1cde65df65bfcca288a47f14eedf5ad5939ed37)), closes [#192](https://github.com/drivecore/mycoder/issues/192)
18+
- implement background tool tracking (issue [#112](https://github.com/drivecore/mycoder/issues/112)) ([b5bb489](https://github.com/drivecore/mycoder/commit/b5bb48981791acda74ee46b93d2d85e27e93a538))
19+
- implement Ollama provider for LLM abstraction ([597211b](https://github.com/drivecore/mycoder/commit/597211b90e43c4d52969eb5994d393c15d85ec97))
20+
- **llm:** add OpenAI support to LLM abstraction ([7bda811](https://github.com/drivecore/mycoder/commit/7bda811658e15b8dd41135cd9b2b90e9ea925e15))
21+
- **refactor:** agent ([a2f59c2](https://github.com/drivecore/mycoder/commit/a2f59c2f51643a44d6e1ff0c16b319deb1adc3f2))
2422

2523
# mycoder-agent-v1.0.0 (2025-03-11)
2624

Lines changed: 13 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { describe, expect, it, vi, beforeEach } from 'vitest';
22

33
import {
4-
backgroundToolRegistry,
4+
BackgroundTools,
55
BackgroundToolStatus,
66
BackgroundToolType,
77
} from './backgroundTools.js';
@@ -12,53 +12,49 @@ vi.mock('uuid', () => ({
1212
}));
1313

1414
describe('BackgroundToolRegistry', () => {
15+
let backgroundTools: BackgroundTools;
1516
beforeEach(() => {
1617
// Clear all registered tools before each test
17-
const registry = backgroundToolRegistry as any;
18-
registry.tools = new Map();
18+
backgroundTools = new BackgroundTools('test');
19+
backgroundTools.tools = new Map();
1920
});
2021

2122
it('should register a shell process', () => {
22-
const id = backgroundToolRegistry.registerShell('agent-1', 'ls -la');
23+
const id = backgroundTools.registerShell('ls -la');
2324

2425
expect(id).toBe('test-id-1');
2526

26-
const tool = backgroundToolRegistry.getToolById(id);
27+
const tool = backgroundTools.getToolById(id);
2728
expect(tool).toBeDefined();
2829
if (tool) {
2930
expect(tool.type).toBe(BackgroundToolType.SHELL);
3031
expect(tool.status).toBe(BackgroundToolStatus.RUNNING);
31-
expect(tool.agentId).toBe('agent-1');
3232
if (tool.type === BackgroundToolType.SHELL) {
3333
expect(tool.metadata.command).toBe('ls -la');
3434
}
3535
}
3636
});
3737

3838
it('should register a browser process', () => {
39-
const id = backgroundToolRegistry.registerBrowser(
40-
'agent-1',
41-
'https://example.com',
42-
);
39+
const id = backgroundTools.registerBrowser('https://example.com');
4340

4441
expect(id).toBe('test-id-1');
4542

46-
const tool = backgroundToolRegistry.getToolById(id);
43+
const tool = backgroundTools.getToolById(id);
4744
expect(tool).toBeDefined();
4845
if (tool) {
4946
expect(tool.type).toBe(BackgroundToolType.BROWSER);
5047
expect(tool.status).toBe(BackgroundToolStatus.RUNNING);
51-
expect(tool.agentId).toBe('agent-1');
5248
if (tool.type === BackgroundToolType.BROWSER) {
5349
expect(tool.metadata.url).toBe('https://example.com');
5450
}
5551
}
5652
});
5753

5854
it('should update tool status', () => {
59-
const id = backgroundToolRegistry.registerShell('agent-1', 'sleep 10');
55+
const id = backgroundTools.registerShell('sleep 10');
6056

61-
const updated = backgroundToolRegistry.updateToolStatus(
57+
const updated = backgroundTools.updateToolStatus(
6258
id,
6359
BackgroundToolStatus.COMPLETED,
6460
{
@@ -68,7 +64,7 @@ describe('BackgroundToolRegistry', () => {
6864

6965
expect(updated).toBe(true);
7066

71-
const tool = backgroundToolRegistry.getToolById(id);
67+
const tool = backgroundTools.getToolById(id);
7268
expect(tool).toBeDefined();
7369
if (tool) {
7470
expect(tool.status).toBe(BackgroundToolStatus.COMPLETED);
@@ -80,57 +76,17 @@ describe('BackgroundToolRegistry', () => {
8076
});
8177

8278
it('should return false when updating non-existent tool', () => {
83-
const updated = backgroundToolRegistry.updateToolStatus(
79+
const updated = backgroundTools.updateToolStatus(
8480
'non-existent-id',
8581
BackgroundToolStatus.COMPLETED,
8682
);
8783

8884
expect(updated).toBe(false);
8985
});
9086

91-
it('should get tools by agent ID', () => {
92-
// For this test, we'll directly manipulate the tools map
93-
const registry = backgroundToolRegistry as any;
94-
registry.tools = new Map();
95-
96-
// Add tools directly to the map with different agent IDs
97-
registry.tools.set('id1', {
98-
id: 'id1',
99-
type: BackgroundToolType.SHELL,
100-
status: BackgroundToolStatus.RUNNING,
101-
startTime: new Date(),
102-
agentId: 'agent-1',
103-
metadata: { command: 'ls -la' },
104-
});
105-
106-
registry.tools.set('id2', {
107-
id: 'id2',
108-
type: BackgroundToolType.BROWSER,
109-
status: BackgroundToolStatus.RUNNING,
110-
startTime: new Date(),
111-
agentId: 'agent-1',
112-
metadata: { url: 'https://example.com' },
113-
});
114-
115-
registry.tools.set('id3', {
116-
id: 'id3',
117-
type: BackgroundToolType.SHELL,
118-
status: BackgroundToolStatus.RUNNING,
119-
startTime: new Date(),
120-
agentId: 'agent-2',
121-
metadata: { command: 'echo hello' },
122-
});
123-
124-
const agent1Tools = backgroundToolRegistry.getToolsByAgent('agent-1');
125-
const agent2Tools = backgroundToolRegistry.getToolsByAgent('agent-2');
126-
127-
expect(agent1Tools.length).toBe(2);
128-
expect(agent2Tools.length).toBe(1);
129-
});
130-
13187
it('should clean up old completed tools', () => {
13288
// Create tools with specific dates
133-
const registry = backgroundToolRegistry as any;
89+
const registry = backgroundTools as any;
13490

13591
// Add a completed tool from 25 hours ago
13692
const oldTool = {
@@ -167,19 +123,5 @@ describe('BackgroundToolRegistry', () => {
167123
registry.tools.set('old-tool', oldTool);
168124
registry.tools.set('recent-tool', recentTool);
169125
registry.tools.set('old-running-tool', oldRunningTool);
170-
171-
// Clean up tools older than 24 hours
172-
backgroundToolRegistry.cleanupOldTools(24);
173-
174-
// Old completed tool should be removed
175-
expect(backgroundToolRegistry.getToolById('old-tool')).toBeUndefined();
176-
177-
// Recent completed tool should remain
178-
expect(backgroundToolRegistry.getToolById('recent-tool')).toBeDefined();
179-
180-
// Old running tool should remain (not completed)
181-
expect(
182-
backgroundToolRegistry.getToolById('old-running-tool'),
183-
).toBeDefined();
184126
});
185127
});

packages/agent/src/core/backgroundTools.ts

Lines changed: 8 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ export interface BackgroundTool {
2222
status: BackgroundToolStatus;
2323
startTime: Date;
2424
endTime?: Date;
25-
agentId: string; // To track which agent created this process
2625
metadata: Record<string, any>; // Additional tool-specific information
2726
}
2827

@@ -61,30 +60,20 @@ export type AnyBackgroundTool =
6160
/**
6261
* Registry to keep track of all background processes
6362
*/
64-
export class BackgroundToolRegistry {
65-
private static instance: BackgroundToolRegistry;
66-
private tools: Map<string, AnyBackgroundTool> = new Map();
63+
export class BackgroundTools {
64+
tools: Map<string, AnyBackgroundTool> = new Map();
6765

6866
// Private constructor for singleton pattern
69-
private constructor() {}
70-
71-
// Get the singleton instance
72-
public static getInstance(): BackgroundToolRegistry {
73-
if (!BackgroundToolRegistry.instance) {
74-
BackgroundToolRegistry.instance = new BackgroundToolRegistry();
75-
}
76-
return BackgroundToolRegistry.instance;
77-
}
67+
constructor(readonly ownerName: string) {}
7868

7969
// Register a new shell process
80-
public registerShell(agentId: string, command: string): string {
70+
public registerShell(command: string): string {
8171
const id = uuidv4();
8272
const tool: ShellBackgroundTool = {
8373
id,
8474
type: BackgroundToolType.SHELL,
8575
status: BackgroundToolStatus.RUNNING,
8676
startTime: new Date(),
87-
agentId,
8877
metadata: {
8978
command,
9079
},
@@ -94,14 +83,13 @@ export class BackgroundToolRegistry {
9483
}
9584

9685
// Register a new browser process
97-
public registerBrowser(agentId: string, url?: string): string {
86+
public registerBrowser(url?: string): string {
9887
const id = uuidv4();
9988
const tool: BrowserBackgroundTool = {
10089
id,
10190
type: BackgroundToolType.BROWSER,
10291
status: BackgroundToolStatus.RUNNING,
10392
startTime: new Date(),
104-
agentId,
10593
metadata: {
10694
url,
10795
},
@@ -111,14 +99,13 @@ export class BackgroundToolRegistry {
11199
}
112100

113101
// Register a new agent process (for future use)
114-
public registerAgent(agentId: string, goal?: string): string {
102+
public registerAgent(goal?: string): string {
115103
const id = uuidv4();
116104
const tool: AgentBackgroundTool = {
117105
id,
118106
type: BackgroundToolType.AGENT,
119107
status: BackgroundToolStatus.RUNNING,
120108
startTime: new Date(),
121-
agentId,
122109
metadata: {
123110
goal,
124111
},
@@ -155,13 +142,10 @@ export class BackgroundToolRegistry {
155142
return true;
156143
}
157144

158-
// Get all processes for a specific agent
159-
public getToolsByAgent(agentId: string): AnyBackgroundTool[] {
145+
public getTools(): AnyBackgroundTool[] {
160146
const result: AnyBackgroundTool[] = [];
161147
for (const tool of this.tools.values()) {
162-
if (tool.agentId === agentId) {
163-
result.push(tool);
164-
}
148+
result.push(tool);
165149
}
166150
return result;
167151
}
@@ -170,25 +154,4 @@ export class BackgroundToolRegistry {
170154
public getToolById(id: string): AnyBackgroundTool | undefined {
171155
return this.tools.get(id);
172156
}
173-
174-
// Clean up completed processes (optional, for maintenance)
175-
public cleanupOldTools(olderThanHours: number = 24): void {
176-
const cutoffTime = new Date(Date.now() - olderThanHours * 60 * 60 * 1000);
177-
178-
for (const [id, tool] of this.tools.entries()) {
179-
// Remove if it's completed/error/terminated AND older than cutoff
180-
if (
181-
tool.endTime &&
182-
tool.endTime < cutoffTime &&
183-
(tool.status === BackgroundToolStatus.COMPLETED ||
184-
tool.status === BackgroundToolStatus.ERROR ||
185-
tool.status === BackgroundToolStatus.TERMINATED)
186-
) {
187-
this.tools.delete(id);
188-
}
189-
}
190-
}
191157
}
192-
193-
// Export singleton instance
194-
export const backgroundToolRegistry = BackgroundToolRegistry.getInstance();

packages/agent/src/core/toolAgent/toolAgentCore.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,15 @@ export const toolAgent = async (
3939

4040
logger.debug('User message:', initialPrompt);
4141

42+
const localContext = {
43+
...context,
44+
};
45+
4246
// Get the system prompt once at the start
43-
const systemPrompt = config.getSystemPrompt(context);
47+
const systemPrompt = config.getSystemPrompt(localContext);
4448

4549
// Create the LLM provider
46-
const provider = createProvider(context.provider, context.model);
50+
const provider = createProvider(localContext.provider, localContext.model);
4751

4852
for (let i = 0; i < config.maxIterations; i++) {
4953
logger.verbose(
@@ -74,8 +78,8 @@ export const toolAgent = async (
7478
const generateOptions = {
7579
messages: messagesWithSystem,
7680
functions: functionDefinitions,
77-
temperature: context.temperature,
78-
maxTokens: context.maxTokens,
81+
temperature: localContext.temperature,
82+
maxTokens: localContext.maxTokens,
7983
};
8084

8185
const { text, toolCalls, tokenUsage } = await generateText(
@@ -123,7 +127,7 @@ export const toolAgent = async (
123127

124128
// Execute the tools and get results
125129
const { sequenceCompleted, completionResult, respawn } =
126-
await executeTools(toolCalls, tools, messages, context);
130+
await executeTools(toolCalls, tools, messages, localContext);
127131

128132
if (respawn) {
129133
logger.info('Respawning agent with new context');

packages/agent/src/core/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { JsonSchema7Type } from 'zod-to-json-schema';
33

44
import { Logger } from '../utils/logger.js';
55

6+
import { BackgroundTools } from './backgroundTools.js';
67
import { TokenTracker } from './tokens.js';
78
import { ModelProvider } from './toolAgent/config.js';
89

@@ -26,6 +27,7 @@ export type ToolContext = {
2627
model: string;
2728
maxTokens: number;
2829
temperature: number;
30+
backgroundTools: BackgroundTools;
2931
};
3032

3133
export type Tool<TParams = Record<string, any>, TReturn = any> = {

0 commit comments

Comments
 (0)