Skip to content

Commit 0b91fdf

Browse files
authored
Merge pull request #30 from fancyboi999/fix/provider-config-recreate
fix: recreate provider instances on config change
2 parents 1f96a0e + 06a4db7 commit 0b91fdf

3 files changed

Lines changed: 83 additions & 5 deletions

File tree

src-api/src/core/agent/registry.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {
1212
AgentProvider,
1313
IAgent,
1414
} from '@/core/agent/types';
15+
import { isDeepEqualConfig } from '@/shared/utils/config';
1516

1617
// ============================================================================
1718
// Agent Instance State
@@ -165,10 +166,31 @@ class AgentRegistry {
165166
*/
166167
async getInstance(type: string, config?: AgentConfig): Promise<IAgent> {
167168
let instanceData = this.instances.get(type);
169+
const effectiveConfig: AgentConfig = {
170+
...(config ?? {}),
171+
provider: type as AgentProvider,
172+
};
168173

169174
if (instanceData && instanceData.state === 'ready') {
170-
instanceData.lastUsedAt = new Date();
171-
return instanceData.agent;
175+
if (isDeepEqualConfig(instanceData.config, effectiveConfig)) {
176+
instanceData.lastUsedAt = new Date();
177+
return instanceData.agent;
178+
}
179+
try {
180+
const agentWithShutdown = instanceData.agent as {
181+
shutdown?: () => Promise<void>;
182+
};
183+
if (typeof agentWithShutdown.shutdown === 'function') {
184+
await agentWithShutdown.shutdown();
185+
}
186+
} catch (error) {
187+
console.warn(
188+
`[${this.registryName}] Failed to shutdown provider ${type}:`,
189+
error
190+
);
191+
}
192+
this.instances.delete(type);
193+
instanceData = undefined;
172194
}
173195

174196
// If instance exists but is in error state, try to recreate
@@ -181,7 +203,6 @@ class AgentRegistry {
181203
}
182204

183205
// Create new instance
184-
const effectiveConfig = config || { provider: type as AgentProvider };
185206
const agent = this.create(type, effectiveConfig);
186207
instanceData = {
187208
agent,

src-api/src/core/sandbox/registry.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type {
1616
SandboxProviderRegistry,
1717
SandboxProviderType,
1818
} from '@/core/sandbox/types';
19+
import { isDeepEqualConfig } from '@/shared/utils/config';
1920

2021
// ============================================================================
2122
// Sandbox Instance State
@@ -162,8 +163,20 @@ class SandboxRegistry implements SandboxProviderRegistry {
162163
let instanceData = this.instances.get(type);
163164

164165
if (instanceData && instanceData.state === 'ready') {
165-
instanceData.lastUsedAt = new Date();
166-
return instanceData.provider;
166+
if (isDeepEqualConfig(instanceData.config, config)) {
167+
instanceData.lastUsedAt = new Date();
168+
return instanceData.provider;
169+
}
170+
try {
171+
await instanceData.provider.shutdown();
172+
} catch (error) {
173+
console.warn(
174+
`[${this.registryName}] Failed to shutdown provider ${type}:`,
175+
error
176+
);
177+
}
178+
this.instances.delete(type);
179+
instanceData = undefined;
167180
}
168181

169182
// If instance exists but is in error state, try to recreate

src-api/src/shared/utils/config.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Configuration normalization helpers
3+
*
4+
* Provides stable serialization for config comparison.
5+
*/
6+
7+
function normalizeValue(value: unknown): unknown {
8+
if (value === undefined) {
9+
return undefined;
10+
}
11+
if (value === null) {
12+
return null;
13+
}
14+
if (value instanceof Date) {
15+
return value.toISOString();
16+
}
17+
if (typeof value === 'bigint') {
18+
return value.toString();
19+
}
20+
if (Array.isArray(value)) {
21+
return value.map((item) => normalizeValue(item));
22+
}
23+
if (typeof value === 'object') {
24+
const obj = value as Record<string, unknown>;
25+
const keys = Object.keys(obj).sort();
26+
const normalized: Record<string, unknown> = {};
27+
for (const key of keys) {
28+
const normalizedValue = normalizeValue(obj[key]);
29+
if (normalizedValue !== undefined) {
30+
normalized[key] = normalizedValue;
31+
}
32+
}
33+
return normalized;
34+
}
35+
return value;
36+
}
37+
38+
export function stableStringify(value: unknown): string {
39+
return JSON.stringify(normalizeValue(value));
40+
}
41+
42+
export function isDeepEqualConfig(a: unknown, b: unknown): boolean {
43+
return stableStringify(a) === stableStringify(b);
44+
}

0 commit comments

Comments
 (0)