33 * Copyright 2025 BrowserOS
44 */
55
6- import { logger } from '@browseros/common'
7- import type { AgentConfig , AgentMetadata } from './types.js'
8- import type { FormattedEvent } from '../utils/EventFormatter.js'
6+ import { logger } from '@browseros/common' ;
7+ import type { AgentConfig , AgentMetadata } from './types.js' ;
8+ import type { FormattedEvent } from '../utils/EventFormatter.js' ;
99
1010/**
1111 * Generic default system prompt for agents
1212 *
1313 * Minimal prompt - agents should override with their own specific prompts
1414 */
15- export const DEFAULT_SYSTEM_PROMPT = `You are a browser automation agent.`
15+ export const DEFAULT_SYSTEM_PROMPT = `You are a browser automation agent.` ;
1616
1717/**
1818 * Generic default configuration values
@@ -24,8 +24,8 @@ export const DEFAULT_CONFIG = {
2424 maxThinkingTokens : 10000 ,
2525 systemPrompt : DEFAULT_SYSTEM_PROMPT ,
2626 mcpServers : { } ,
27- permissionMode : 'bypassPermissions' as const
28- }
27+ permissionMode : 'bypassPermissions' as const ,
28+ } ;
2929
3030/**
3131 * BaseAgent - Abstract base class for all agent implementations
@@ -56,26 +56,40 @@ export const DEFAULT_CONFIG = {
5656 * }
5757 */
5858export abstract class BaseAgent {
59- protected config : Required < AgentConfig >
60- protected metadata : AgentMetadata
61- protected executionStartTime : number = 0
59+ protected config : Required < AgentConfig > ;
60+ protected metadata : AgentMetadata ;
61+ protected executionStartTime : number = 0 ;
62+ protected initialized : boolean = false ;
6263
6364 constructor (
6465 agentType : string ,
6566 config : AgentConfig ,
66- agentDefaults ?: Partial < AgentConfig >
67+ agentDefaults ?: Partial < AgentConfig > ,
6768 ) {
6869 // Merge config with agent-specific defaults, then with base defaults
6970 this . config = {
7071 apiKey : config . apiKey ,
7172 cwd : config . cwd ,
72- maxTurns : config . maxTurns ?? agentDefaults ?. maxTurns ?? DEFAULT_CONFIG . maxTurns ,
73- maxThinkingTokens : config . maxThinkingTokens ?? agentDefaults ?. maxThinkingTokens ?? DEFAULT_CONFIG . maxThinkingTokens ,
74- systemPrompt : config . systemPrompt ?? agentDefaults ?. systemPrompt ?? DEFAULT_CONFIG . systemPrompt ,
75- mcpServers : config . mcpServers ?? agentDefaults ?. mcpServers ?? DEFAULT_CONFIG . mcpServers ,
76- permissionMode : config . permissionMode ?? agentDefaults ?. permissionMode ?? DEFAULT_CONFIG . permissionMode ,
77- customOptions : config . customOptions ?? agentDefaults ?. customOptions ?? { }
78- }
73+ maxTurns :
74+ config . maxTurns ?? agentDefaults ?. maxTurns ?? DEFAULT_CONFIG . maxTurns ,
75+ maxThinkingTokens :
76+ config . maxThinkingTokens ??
77+ agentDefaults ?. maxThinkingTokens ??
78+ DEFAULT_CONFIG . maxThinkingTokens ,
79+ systemPrompt :
80+ config . systemPrompt ??
81+ agentDefaults ?. systemPrompt ??
82+ DEFAULT_CONFIG . systemPrompt ,
83+ mcpServers :
84+ config . mcpServers ??
85+ agentDefaults ?. mcpServers ??
86+ DEFAULT_CONFIG . mcpServers ,
87+ permissionMode :
88+ config . permissionMode ??
89+ agentDefaults ?. permissionMode ??
90+ DEFAULT_CONFIG . permissionMode ,
91+ customOptions : config . customOptions ?? agentDefaults ?. customOptions ?? { } ,
92+ } ;
7993
8094 // Initialize metadata
8195 this . metadata = {
@@ -84,94 +98,112 @@ export abstract class BaseAgent {
8498 totalDuration : 0 ,
8599 lastEventTime : Date . now ( ) ,
86100 toolsExecuted : 0 ,
87- state : 'idle'
88- }
101+ state : 'idle' ,
102+ } ;
89103
90104 logger . debug ( `🤖 ${ agentType } agent created` , {
91105 agentType,
92106 cwd : this . config . cwd ,
93107 maxTurns : this . config . maxTurns ,
94108 maxThinkingTokens : this . config . maxThinkingTokens ,
95109 usingDefaultMcp : ! config . mcpServers ,
96- usingDefaultPrompt : ! config . systemPrompt
97- } )
110+ usingDefaultPrompt : ! config . systemPrompt ,
111+ } ) ;
112+ }
113+
114+ /**
115+ * Async initialization for agents that need it
116+ * Subclasses can override for async setup (e.g., fetching config)
117+ */
118+ async init ( ) : Promise < void > {
119+ this . initialized = true ;
98120 }
99121
100122 /**
101123 * Execute a task and stream events
102124 * Must be implemented by concrete agent classes
103125 */
104- abstract execute ( message : string ) : AsyncGenerator < FormattedEvent >
126+ // FIXME: make it handle init if not initialized
127+ abstract execute ( message : string ) : AsyncGenerator < FormattedEvent > ;
105128
106129 /**
107130 * Cleanup agent resources
108131 * Must be implemented by concrete agent classes
109132 */
110- abstract destroy ( ) : Promise < void >
133+ abstract destroy ( ) : Promise < void > ;
111134
112135 /**
113136 * Get current agent metadata
114137 */
115138 getMetadata ( ) : AgentMetadata {
116- return { ...this . metadata }
139+ return { ...this . metadata } ;
117140 }
118141
119142 /**
120143 * Helper: Start execution tracking
121144 */
122145 protected startExecution ( ) : void {
123- this . metadata . state = 'executing'
124- this . executionStartTime = Date . now ( )
146+ this . metadata . state = 'executing' ;
147+ this . executionStartTime = Date . now ( ) ;
125148 }
126149
127150 /**
128151 * Helper: Complete execution tracking
129152 */
130153 protected completeExecution ( ) : void {
131- this . metadata . state = 'idle'
132- this . metadata . totalDuration += Date . now ( ) - this . executionStartTime
154+ this . metadata . state = 'idle' ;
155+ this . metadata . totalDuration += Date . now ( ) - this . executionStartTime ;
133156 }
134157
135158 /**
136159 * Helper: Mark execution error
137160 */
138161 protected errorExecution ( error : Error | string ) : void {
139- this . metadata . state = 'error'
140- this . metadata . error = error instanceof Error ? error . message : error
162+ this . metadata . state = 'error' ;
163+ this . metadata . error = error instanceof Error ? error . message : error ;
141164 }
142165
143166 /**
144167 * Helper: Update last event time
145168 */
146169 protected updateEventTime ( ) : void {
147- this . metadata . lastEventTime = Date . now ( )
170+ this . metadata . lastEventTime = Date . now ( ) ;
148171 }
149172
150173 /**
151174 * Helper: Increment tool execution count
152175 */
153176 protected updateToolsExecuted ( count : number = 1 ) : void {
154- this . metadata . toolsExecuted += count
177+ this . metadata . toolsExecuted += count ;
155178 }
156179
157180 /**
158181 * Helper: Update turn count
159182 */
160183 protected updateTurns ( turns : number ) : void {
161- this . metadata . turns = turns
184+ this . metadata . turns = turns ;
162185 }
163186
164187 /**
165188 * Helper: Check if agent is destroyed
166189 */
167190 protected isDestroyed ( ) : boolean {
168- return this . metadata . state === 'destroyed'
191+ return this . metadata . state === 'destroyed' ;
169192 }
170193
171194 /**
172195 * Helper: Mark agent as destroyed
173196 */
174197 protected markDestroyed ( ) : void {
175- this . metadata . state = 'destroyed'
198+ this . metadata . state = 'destroyed' ;
199+ }
200+
201+ /**
202+ * Helper: Ensure agent is initialized
203+ */
204+ protected ensureInitialized ( ) : void {
205+ if ( ! this . initialized ) {
206+ throw new Error ( 'Agent not initialized. Call init() before execute()' ) ;
207+ }
176208 }
177209}
0 commit comments