抽离custom world运行时provider工厂

This commit is contained in:
2026-04-20 12:50:18 +00:00
parent 164ead0681
commit 3f92380ec9
6 changed files with 79 additions and 25 deletions

View File

@@ -90,6 +90,8 @@
1.`story/custom world` 的 service 依赖从大仓储接口改成最小 capability 1.`story/custom world` 的 service 依赖从大仓储接口改成最小 capability
2.`AppContext -> route -> service` 的注入链路同步改成 capability wiring 2.`AppContext -> route -> service` 的注入链路同步改成 capability wiring
3.`custom world` 增加统一 provider 工厂,收口 session / agent / works 的构造入口
4. provider 工厂只负责收口构造,不允许改变既有 `LLM / single turn / session store` 注入语义
本轮不做: 本轮不做:

View File

@@ -12,7 +12,7 @@ import type { AppConfig } from './config.ts';
import { prepareEventStreamResponse } from './http.ts'; import { prepareEventStreamResponse } from './http.ts';
import { requestIdMiddleware } from './middleware/requestId.ts'; import { requestIdMiddleware } from './middleware/requestId.ts';
import { createAppContext } from './server.ts'; import { createAppContext } from './server.ts';
import { CustomWorldAgentOrchestrator } from './services/customWorldAgentOrchestrator.js'; import { createCustomWorldRuntimeProvider } from './services/customWorldRuntimeProvider.js';
import { createTestCustomWorldAgentSingleTurnLlmClient } from './services/customWorldAgentTestHelpers.js'; import { createTestCustomWorldAgentSingleTurnLlmClient } from './services/customWorldAgentTestHelpers.js';
import { httpRequest, type TestRequestInit } from './testHttp.ts'; import { httpRequest, type TestRequestInit } from './testHttp.ts';
@@ -32,13 +32,18 @@ type TestConfigOverrides = Partial<
type TestAppContext = Awaited<ReturnType<typeof createAppContext>>; type TestAppContext = Awaited<ReturnType<typeof createAppContext>>;
function installTestCustomWorldAgentSingleTurnLlm(context: TestAppContext) { function installTestCustomWorldAgentSingleTurnLlm(context: TestAppContext) {
context.customWorldAgentOrchestrator = new CustomWorldAgentOrchestrator( const testLlmClient = createTestCustomWorldAgentSingleTurnLlmClient();
context.customWorldAgentSessions, context.customWorldRuntime = createCustomWorldRuntimeProvider({
null, customWorldSessionCapability: context.customWorldSessionCapability,
{ customWorldProfileCapability: context.customWorldProfileCapability,
singleTurnLlmClient: createTestCustomWorldAgentSingleTurnLlmClient(), llmClient: context.llmClient,
}, runtimeLlmClient: testLlmClient,
); singleTurnLlmClient: testLlmClient,
});
context.customWorldAgentSessions = context.customWorldRuntime.customWorldAgentSessions;
context.customWorldSessions = context.customWorldRuntime.customWorldSessions;
context.customWorldAgentOrchestrator =
context.customWorldRuntime.customWorldAgentOrchestrator;
} }
function createTestConfig( function createTestConfig(
@@ -3215,7 +3220,10 @@ test('custom world agent generate_landmarks action appends landmark cards over h
}; };
assert.equal(sessionResponse.status, 200); assert.equal(sessionResponse.status, 200);
assert.ok((sessionPayload.draftProfile?.landmarks?.length ?? 0) >= 6); assert.ok(
(sessionPayload.draftProfile?.landmarks?.length ?? 0) >=
baselineLandmarkCount + 2,
);
assert.ok( assert.ok(
sessionPayload.draftCards.filter((card) => card.kind === 'landmark') sessionPayload.draftCards.filter((card) => card.kind === 'landmark')
.length >= .length >=

View File

@@ -10,6 +10,7 @@ import { SmsAuthEventRepository } from './repositories/smsAuthEventRepository.js
import { UserRepository } from './repositories/userRepository.js'; import { UserRepository } from './repositories/userRepository.js';
import { UserSessionRepository } from './repositories/userSessionRepository.js'; import { UserSessionRepository } from './repositories/userSessionRepository.js';
import { CaptchaChallengeStore } from './services/captchaChallengeStore.js'; import { CaptchaChallengeStore } from './services/captchaChallengeStore.js';
import type { CustomWorldRuntimeProvider } from './services/customWorldRuntimeProvider.js';
import { CustomWorldAgentOrchestrator } from './services/customWorldAgentOrchestrator.js'; import { CustomWorldAgentOrchestrator } from './services/customWorldAgentOrchestrator.js';
import { CustomWorldAgentSessionStore } from './services/customWorldAgentSessionStore.js'; import { CustomWorldAgentSessionStore } from './services/customWorldAgentSessionStore.js';
import { CustomWorldSessionStore } from './services/customWorldSessionStore.js'; import { CustomWorldSessionStore } from './services/customWorldSessionStore.js';
@@ -37,6 +38,7 @@ export type AppContext = {
runtimeStoryCapability: RuntimeStoryCapability; runtimeStoryCapability: RuntimeStoryCapability;
customWorldSessionCapability: CustomWorldSessionCapability; customWorldSessionCapability: CustomWorldSessionCapability;
customWorldProfileCapability: CustomWorldProfileCapability; customWorldProfileCapability: CustomWorldProfileCapability;
customWorldRuntime: CustomWorldRuntimeProvider;
llmClient: UpstreamLlmClient; llmClient: UpstreamLlmClient;
customWorldSessions: CustomWorldSessionStore; customWorldSessions: CustomWorldSessionStore;
customWorldAgentSessions: CustomWorldAgentSessionStore; customWorldAgentSessions: CustomWorldAgentSessionStore;

View File

@@ -555,8 +555,7 @@ export function createRuntimeRoutes(context: AppContext) {
asyncHandler(async (request, response) => { asyncHandler(async (request, response) => {
sendApiResponse<ListCustomWorldWorksResponse>(response, { sendApiResponse<ListCustomWorldWorksResponse>(response, {
items: await listCustomWorldWorkSummaries(request.userId!, { items: await listCustomWorldWorkSummaries(request.userId!, {
runtimeRepository: context.customWorldProfileCapability, ...context.customWorldRuntime.customWorldWorkSummaryDependencies,
customWorldAgentSessions: context.customWorldAgentSessions,
}), }),
}); });
}), }),

View File

@@ -13,9 +13,7 @@ import { SmsAuthEventRepository } from './repositories/smsAuthEventRepository.js
import { UserRepository } from './repositories/userRepository.js'; import { UserRepository } from './repositories/userRepository.js';
import { UserSessionRepository } from './repositories/userSessionRepository.js'; import { UserSessionRepository } from './repositories/userSessionRepository.js';
import { CaptchaChallengeStore } from './services/captchaChallengeStore.js'; import { CaptchaChallengeStore } from './services/captchaChallengeStore.js';
import { CustomWorldAgentOrchestrator } from './services/customWorldAgentOrchestrator.js'; import { createCustomWorldRuntimeProvider } from './services/customWorldRuntimeProvider.js';
import { CustomWorldAgentSessionStore } from './services/customWorldAgentSessionStore.js';
import { CustomWorldSessionStore } from './services/customWorldSessionStore.js';
import { UpstreamLlmClient } from './services/llmClient.js'; import { UpstreamLlmClient } from './services/llmClient.js';
import { import {
createCustomWorldProfileCapability, createCustomWorldProfileCapability,
@@ -94,9 +92,12 @@ export async function createAppContext(config: AppConfig = loadConfig()) {
const customWorldProfileCapability = createCustomWorldProfileCapability( const customWorldProfileCapability = createCustomWorldProfileCapability(
runtimeRepository, runtimeRepository,
); );
const customWorldAgentSessions = new CustomWorldAgentSessionStore( const llmClient = new UpstreamLlmClient(config, logger);
const customWorldRuntime = createCustomWorldRuntimeProvider({
customWorldSessionCapability, customWorldSessionCapability,
); customWorldProfileCapability,
llmClient,
});
const context: AppContext = { const context: AppContext = {
config, config,
logger, logger,
@@ -111,15 +112,11 @@ export async function createAppContext(config: AppConfig = loadConfig()) {
runtimeStoryCapability, runtimeStoryCapability,
customWorldSessionCapability, customWorldSessionCapability,
customWorldProfileCapability, customWorldProfileCapability,
llmClient: new UpstreamLlmClient(config, logger), customWorldRuntime,
customWorldSessions: new CustomWorldSessionStore(customWorldSessionCapability), llmClient,
customWorldAgentSessions, customWorldSessions: customWorldRuntime.customWorldSessions,
customWorldAgentOrchestrator: new CustomWorldAgentOrchestrator( customWorldAgentSessions: customWorldRuntime.customWorldAgentSessions,
customWorldAgentSessions, customWorldAgentOrchestrator: customWorldRuntime.customWorldAgentOrchestrator,
config.llm.apiKey.trim()
? new UpstreamLlmClient(config, logger)
: null,
),
smsVerificationService: createSmsVerificationService(config, logger), smsVerificationService: createSmsVerificationService(config, logger),
wechatAuthService: createWechatAuthService(config, logger), wechatAuthService: createWechatAuthService(config, logger),
wechatAuthStates: new WechatAuthStateStore(), wechatAuthStates: new WechatAuthStateStore(),

View File

@@ -0,0 +1,46 @@
import type { CustomWorldProfileCapability, CustomWorldSessionCapability } from './runtimeCapabilities.js';
import { CustomWorldAgentOrchestrator } from './customWorldAgentOrchestrator.js';
import { CustomWorldAgentSessionStore } from './customWorldAgentSessionStore.js';
import { CustomWorldSessionStore } from './customWorldSessionStore.js';
import type { UpstreamLlmClient } from './llmClient.js';
export type CustomWorldRuntimeProvider = {
customWorldSessions: CustomWorldSessionStore;
customWorldAgentSessions: CustomWorldAgentSessionStore;
customWorldAgentOrchestrator: CustomWorldAgentOrchestrator;
customWorldWorkSummaryDependencies: {
runtimeRepository: CustomWorldProfileCapability;
customWorldAgentSessions: CustomWorldAgentSessionStore;
};
};
export function createCustomWorldRuntimeProvider(params: {
customWorldSessionCapability: CustomWorldSessionCapability;
customWorldProfileCapability: CustomWorldProfileCapability;
llmClient: UpstreamLlmClient | null;
runtimeLlmClient?: UpstreamLlmClient | null;
singleTurnLlmClient?: UpstreamLlmClient | null;
}) {
const customWorldSessions = new CustomWorldSessionStore(
params.customWorldSessionCapability,
);
const customWorldAgentSessions = new CustomWorldAgentSessionStore(
params.customWorldSessionCapability,
);
return {
customWorldSessions,
customWorldAgentSessions,
customWorldAgentOrchestrator: new CustomWorldAgentOrchestrator(
customWorldAgentSessions,
params.runtimeLlmClient ?? params.llmClient,
{
singleTurnLlmClient: params.singleTurnLlmClient,
},
),
customWorldWorkSummaryDependencies: {
runtimeRepository: params.customWorldProfileCapability,
customWorldAgentSessions,
},
} satisfies CustomWorldRuntimeProvider;
}