Skip to content

Commit b8104ca

Browse files
committed
refactor(api): extract SelfImprovementSessionManager from AgentOS.ts
Centralize all self-improvement session state (skill enable/disable, model options, user preferences, prompt context, tool deps factory) into a dedicated SelfImprovementSessionManager class. The massive ~180-line selfImprovementDeps closure is now assembled by the manager's buildToolDeps() method with lazy runtime accessors.
1 parent 1fd780d commit b8104ca

2 files changed

Lines changed: 444 additions & 284 deletions

File tree

src/api/AgentOS.ts

Lines changed: 28 additions & 284 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,6 @@ import {
115115
import type { IGuardrailService, GuardrailContext } from '../safety/guardrails/IGuardrailService';
116116
import type { EmergentConfig } from '../emergent/types.js';
117117
import type { SelfImprovementToolDeps } from '../emergent/EmergentCapabilityEngine.js';
118-
import { PersonalityMutationStore } from '../emergent/PersonalityMutationStore.js';
119-
import { resolveSelfImprovementSessionKey } from '../emergent/sessionScope.js';
120118
import { GuardrailAction } from '../safety/guardrails/IGuardrailService';
121119
import {
122120
evaluateInputGuardrails,
@@ -154,6 +152,7 @@ import { adaptTools, adaptToolsToMap, type AdaptableToolInput } from './toolAdap
154152
import { createSchemaOnDemandPack } from '../extensions/packs/schema-on-demand-pack.js';
155153
import { WorkflowFacade } from './WorkflowFacade';
156154
import { CapabilityDiscoveryInitializer } from './CapabilityDiscoveryInitializer';
155+
import { SelfImprovementSessionManager } from './SelfImprovementSessionManager';
157156
import type { TurnPlannerConfig } from '../core/orchestration/TurnPlanner';
158157
import type {
159158
CapabilityDescriptor,
@@ -175,19 +174,6 @@ import type {
175174
WorkflowQueryOptions,
176175
WorkflowTaskUpdate,
177176
} from '../planning/workflows/storage/IWorkflowStore';
178-
import {
179-
applySelfImprovementSessionOverrides as applySessionRuntimeOverrides,
180-
buildSelfImprovementSkillPromptContext as buildSessionSkillPromptContext,
181-
buildSelfImprovementSessionRuntimeKey as buildSessionRuntimeKey,
182-
disableSelfImprovementSessionSkill as disableSessionSkill,
183-
enableSelfImprovementSessionSkill as enableSessionSkill,
184-
getSelfImprovementRuntimeParam as getSessionRuntimeParam,
185-
listSelfImprovementDisabledSkillIds as listDisabledSessionSkillIds,
186-
listSelfImprovementSessionSkills as listSessionSkills,
187-
type SelfImprovementSkillDescriptor,
188-
type SelfImprovementSessionRuntimeState,
189-
setSelfImprovementRuntimeParam as setSessionRuntimeParam,
190-
} from './selfImprovementRuntime.js';
191177

192178
type StorageWriteHookContext = {
193179
readonly operation: 'run' | 'batch';
@@ -211,10 +197,6 @@ type StorageWriteHooks = {
211197
) => Promise<void>;
212198
};
213199

214-
type AgentOSConfiguredSkill = NonNullable<CapabilityIndexSources['skills']>[number] & {
215-
id?: string;
216-
};
217-
218200
function wrapStorageAdapterWithWriteHooks(
219201
adapter: StorageAdapter,
220202
hooks: StorageWriteHooks,
@@ -786,7 +768,7 @@ export class AgentOS implements IAgentOS {
786768
private initialized: boolean = false;
787769
private config!: Readonly<AgentOSConfig>;
788770
private managedStandaloneMemoryClosers: Array<() => Promise<void>> = [];
789-
private readonly selfImprovementSessionRuntime = new Map<string, SelfImprovementSessionRuntimeState>();
771+
private selfImprovementManager!: SelfImprovementSessionManager;
790772

791773
private modelProviderManager!: AIModelProviderManager;
792774
private utilityAIService!: IUtilityAI & IPromptEngineUtilityAI;
@@ -819,84 +801,6 @@ export class AgentOS implements IAgentOS {
819801
*/
820802
constructor(private readonly logger: ILogger = createLogger('AgentOS')) {}
821803

822-
private buildSelfImprovementSessionRuntimeKey(sessionId: string): string {
823-
return buildSessionRuntimeKey(sessionId);
824-
}
825-
826-
private getSelfImprovementRuntimeParam(
827-
sessionKey: string,
828-
param: string,
829-
): unknown {
830-
return getSessionRuntimeParam(this.selfImprovementSessionRuntime, sessionKey, param);
831-
}
832-
833-
private setSelfImprovementRuntimeParam(
834-
sessionKey: string,
835-
param: string,
836-
value: unknown,
837-
): void {
838-
setSessionRuntimeParam(this.selfImprovementSessionRuntime, sessionKey, param, value);
839-
}
840-
841-
private applySelfImprovementSessionOverrides(input: AgentOSInput): AgentOSInput {
842-
return applySessionRuntimeOverrides(this.selfImprovementSessionRuntime, input);
843-
}
844-
845-
private getConfiguredDiscoverySkills(): AgentOSConfiguredSkill[] {
846-
try {
847-
const turnPlanningSkills = this.config.turnPlanning?.discovery?.sources?.skills;
848-
if (Array.isArray(turnPlanningSkills)) {
849-
return turnPlanningSkills as AgentOSConfiguredSkill[];
850-
}
851-
852-
const legacySkills = (this.config as any).capabilityDiscovery?.sources?.skills;
853-
if (Array.isArray(legacySkills)) {
854-
return legacySkills as AgentOSConfiguredSkill[];
855-
}
856-
} catch {
857-
// Fall through to empty set.
858-
}
859-
860-
return [];
861-
}
862-
863-
private normalizeConfiguredSkill(
864-
skill: Partial<AgentOSConfiguredSkill>,
865-
fallbackId?: string,
866-
): SelfImprovementSkillDescriptor {
867-
const skillId = String(skill.id ?? skill.name ?? fallbackId ?? 'unknown');
868-
return {
869-
skillId,
870-
name: String(skill.name ?? fallbackId ?? skillId),
871-
category: String(skill.category ?? 'general'),
872-
...(typeof skill.description === 'string' ? { description: skill.description } : {}),
873-
...(typeof skill.content === 'string' ? { content: skill.content } : {}),
874-
...(typeof skill.sourcePath === 'string' ? { sourcePath: skill.sourcePath } : {}),
875-
};
876-
}
877-
878-
private resolveConfiguredSelfImprovementSkill(
879-
skillId: string,
880-
): SelfImprovementSkillDescriptor | undefined {
881-
const configured = this.getConfiguredDiscoverySkills().find(
882-
(skill) => String(skill.id ?? skill.name ?? '') === skillId,
883-
);
884-
return configured ? this.normalizeConfiguredSkill(configured, skillId) : undefined;
885-
}
886-
887-
private listSelfImprovementSessionSkills(sessionKey: string): SelfImprovementSkillDescriptor[] {
888-
return listSessionSkills(this.selfImprovementSessionRuntime, sessionKey);
889-
}
890-
891-
private listSelfImprovementDisabledSkillIds(sessionKey: string): string[] {
892-
return listDisabledSessionSkillIds(this.selfImprovementSessionRuntime, sessionKey);
893-
}
894-
895-
private buildSelfImprovementSkillPromptContext(sessionId: string): string | undefined {
896-
const sessionKey = this.buildSelfImprovementSessionRuntimeKey(sessionId);
897-
return buildSessionSkillPromptContext(this.selfImprovementSessionRuntime, sessionKey);
898-
}
899-
900804
/**
901805
* Initializes the `AgentOS` service and all its core dependencies.
902806
* This method must be called and successfully awaited before any other operations
@@ -933,6 +837,24 @@ export class AgentOS implements IAgentOS {
933837
});
934838
this.configureManagedStandaloneMemory();
935839

840+
// Initialize self-improvement session manager early (before emergent deps are assembled).
841+
this.selfImprovementManager = new SelfImprovementSessionManager(this.logger);
842+
this.selfImprovementManager.setConfiguredSkillsGetter(() => {
843+
try {
844+
const turnPlanningSkills = this.config.turnPlanning?.discovery?.sources?.skills;
845+
if (Array.isArray(turnPlanningSkills)) {
846+
return turnPlanningSkills as any[];
847+
}
848+
const legacySkills = (this.config as any).capabilityDiscovery?.sources?.skills;
849+
if (Array.isArray(legacySkills)) {
850+
return legacySkills as any[];
851+
}
852+
} catch {
853+
// Fall through to empty set.
854+
}
855+
return [];
856+
});
857+
936858
// Observability is opt-in (config + env). Safe no-op if OTEL is not installed by host.
937859
configureAgentOSObservability(this.config.observability);
938860

@@ -1099,190 +1021,12 @@ export class AgentOS implements IAgentOS {
10991021
}
11001022
: undefined,
11011023

1102-
// ---------------------------------------------------------------
1103-
// Self-improvement deps — only assembled when the feature is
1104-
// enabled. All hooks are lazy closures that resolve against the
1105-
// fully initialised runtime at tool-call time (NOT at bootstrap).
1106-
// ---------------------------------------------------------------
11071024
selfImprovementDeps:
11081025
this.config.emergentConfig?.selfImprovement?.enabled
1109-
? ((): SelfImprovementToolDeps => {
1110-
// PersonalityMutationStore reuses the same storage adapter
1111-
// that the EmergentToolRegistry already depends on.
1112-
const mutationStore = storageAdapter
1113-
? new PersonalityMutationStore({
1114-
run: async (sql: string, params?: unknown[]) =>
1115-
storageAdapter.run(sql, params as any),
1116-
get: async (sql: string, params?: unknown[]) =>
1117-
storageAdapter.get(sql, params as any),
1118-
all: async (sql: string, params?: unknown[]) =>
1119-
storageAdapter.all(sql, params as any),
1120-
exec: async (sql: string) => storageAdapter.exec(sql),
1121-
})
1122-
: undefined;
1123-
1124-
return {
1125-
// --- Personality (HEXACO) ---
1126-
// Reads/writes the active GMI's persona personalityTraits map.
1127-
// Falls back to an empty map when no GMI or persona is active.
1128-
getPersonality: (): Record<string, number> => {
1129-
try {
1130-
const gmi = this.gmiManager?.activeGMIs?.values().next().value;
1131-
const traits = gmi?.getPersona()?.personalityTraits;
1132-
if (traits && typeof traits === 'object') {
1133-
const result: Record<string, number> = {};
1134-
for (const [k, v] of Object.entries(traits)) {
1135-
if (typeof v === 'number') result[k] = v;
1136-
}
1137-
return result;
1138-
}
1139-
} catch { /* GMI not ready yet — return empty. */ }
1140-
return {};
1141-
},
1142-
setPersonality: (trait: string, value: number): void => {
1143-
try {
1144-
const gmi = this.gmiManager?.activeGMIs?.values().next().value;
1145-
const persona = gmi?.getPersona();
1146-
if (persona) {
1147-
if (!persona.personalityTraits) {
1148-
persona.personalityTraits = {};
1149-
}
1150-
persona.personalityTraits[trait] = value;
1151-
}
1152-
} catch { /* GMI not ready — ignore. */ }
1153-
},
1154-
mutationStore,
1155-
1156-
// --- Skills ---
1157-
// AgentOS does not own a mutable SkillRegistry here, so
1158-
// skill activation is tracked as session-scoped overlay
1159-
// state keyed by the self-improvement session.
1160-
getActiveSkills: (
1161-
context?: import('../core/tools/ITool.js').ToolExecutionContext,
1162-
): Array<{ skillId: string; name: string; category: string }> => {
1163-
const sessionKey = resolveSelfImprovementSessionKey(context);
1164-
return this.listSelfImprovementSessionSkills(sessionKey).map((skill) => ({
1165-
skillId: skill.skillId,
1166-
name: skill.name,
1167-
category: skill.category,
1168-
}));
1169-
},
1170-
getLockedSkills: (): string[] => [],
1171-
loadSkill: async (
1172-
id: string,
1173-
context?: import('../core/tools/ITool.js').ToolExecutionContext,
1174-
) => {
1175-
const sessionKey = resolveSelfImprovementSessionKey(context);
1176-
const resolvedSkill = this.resolveConfiguredSelfImprovementSkill(id) ?? {
1177-
skillId: id,
1178-
name: id,
1179-
category: 'dynamic',
1180-
};
1181-
enableSessionSkill(
1182-
this.selfImprovementSessionRuntime,
1183-
sessionKey,
1184-
resolvedSkill,
1185-
);
1186-
return {
1187-
skillId: resolvedSkill.skillId,
1188-
name: resolvedSkill.name,
1189-
category: resolvedSkill.category,
1190-
};
1191-
},
1192-
unloadSkill: (
1193-
id: string,
1194-
context?: import('../core/tools/ITool.js').ToolExecutionContext,
1195-
) => {
1196-
const sessionKey = resolveSelfImprovementSessionKey(context);
1197-
const resolvedSkill = this.resolveConfiguredSelfImprovementSkill(id);
1198-
disableSessionSkill(
1199-
this.selfImprovementSessionRuntime,
1200-
sessionKey,
1201-
resolvedSkill?.name ?? id,
1202-
);
1203-
},
1204-
searchSkills: (query: string) => {
1205-
const q = query.toLowerCase();
1206-
return this.getConfiguredDiscoverySkills()
1207-
.filter((skill) =>
1208-
(skill.name ?? '').toLowerCase().includes(q) ||
1209-
(skill.description ?? '').toLowerCase().includes(q)
1210-
)
1211-
.map((skill) => {
1212-
const normalizedSkill = this.normalizeConfiguredSkill(skill);
1213-
return {
1214-
skillId: normalizedSkill.skillId,
1215-
name: normalizedSkill.name,
1216-
category: normalizedSkill.category,
1217-
description: normalizedSkill.description ?? '',
1218-
};
1219-
});
1220-
},
1221-
1222-
// --- Tools ---
1223-
// Wire directly to the ToolOrchestrator. At tool-call
1224-
// time the orchestrator is guaranteed to be initialised.
1225-
executeTool: async (
1226-
name: string,
1227-
args: unknown,
1228-
context?: import('../core/tools/ITool.js').ToolExecutionContext,
1229-
): Promise<unknown> => {
1230-
const tool = await this.toolOrchestrator.getTool(name);
1231-
if (!tool) {
1232-
throw new Error(`Tool "${name}" not found in orchestrator.`);
1233-
}
1234-
const result = await tool.execute(
1235-
(args ?? {}) as Record<string, unknown>,
1236-
context ?? {
1237-
gmiId: 'self-improvement',
1238-
personaId: 'self-improvement',
1239-
userContext: { userId: 'system' } as any,
1240-
},
1241-
);
1242-
if (!result.success) {
1243-
throw new Error(result.error ?? `Tool "${name}" failed.`);
1244-
}
1245-
return result.output;
1246-
},
1247-
listTools: (): string[] => {
1248-
try {
1249-
return (this.toolOrchestrator as any).toolExecutor
1250-
?.listAvailableTools()
1251-
?.map((t: any) => t.name) ?? [];
1252-
} catch { return []; }
1253-
},
1254-
getSessionParam: (param: string, context) => {
1255-
const sessionKey = resolveSelfImprovementSessionKey(context);
1256-
return this.getSelfImprovementRuntimeParam(sessionKey, param);
1257-
},
1258-
setSessionParam: (param: string, value: unknown, context) => {
1259-
const sessionKey = resolveSelfImprovementSessionKey(context);
1260-
this.setSelfImprovementRuntimeParam(sessionKey, param, value);
1261-
},
1262-
1263-
// --- Memory ---
1264-
// Persist self-improvement traces into the first active
1265-
// GMI's cognitive memory when available.
1266-
storeMemory: async (trace): Promise<void> => {
1267-
try {
1268-
const gmi = this.gmiManager?.activeGMIs?.values().next().value;
1269-
const mem = gmi?.getCognitiveMemoryManager?.();
1270-
if (mem) {
1271-
await mem.encode(
1272-
`[self-improvement:${trace.type}] ${trace.content}`,
1273-
{ valence: 0, arousal: 0, dominance: 0.5 },
1274-
'neutral',
1275-
{
1276-
type: 'semantic' as any,
1277-
scope: (trace.scope ?? 'agent') as any,
1278-
tags: trace.tags,
1279-
},
1280-
);
1281-
}
1282-
} catch { /* Memory not available — silently skip. */ }
1283-
},
1284-
};
1285-
})()
1026+
? this.selfImprovementManager.buildToolDeps(storageAdapter, {
1027+
getActiveGMI: () => this.gmiManager?.activeGMIs?.values().next().value,
1028+
getToolOrchestrator: () => this.toolOrchestrator,
1029+
})
12861030
: undefined,
12871031
}
12881032
: undefined;
@@ -1895,14 +1639,14 @@ export class AgentOS implements IAgentOS {
18951639
return;
18961640
}
18971641

1898-
const orchestratorInput: AgentOSInput = this.applySelfImprovementSessionOverrides({
1642+
const orchestratorInput: AgentOSInput = this.selfImprovementManager.applySessionOverrides({
18991643
...guardrailInputOutcome.sanitizedInput,
19001644
selectedPersonaId: effectivePersonaId,
1901-
skillPromptContext: this.buildSelfImprovementSkillPromptContext(
1645+
skillPromptContext: this.selfImprovementManager.buildSkillPromptContext(
19021646
guardrailInputOutcome.sanitizedInput.sessionId,
19031647
),
1904-
disabledSessionSkillIds: this.listSelfImprovementDisabledSkillIds(
1905-
this.buildSelfImprovementSessionRuntimeKey(guardrailInputOutcome.sanitizedInput.sessionId),
1648+
disabledSessionSkillIds: this.selfImprovementManager.listDisabledSkillIds(
1649+
this.selfImprovementManager.buildSessionRuntimeKey(guardrailInputOutcome.sanitizedInput.sessionId),
19061650
),
19071651
});
19081652
// Language negotiation (non-blocking)

0 commit comments

Comments
 (0)