@ai-agent-forge/agent-forge 0.85.4 → 0.85.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"session-plugin-testkit.d.ts","sourceRoot":"","sources":["../../src/testing/session-plugin-testkit.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Agent } from \"@agent-forge/agent-core\";\nimport {\n\ttype FauxProviderRegistration,\n\ttype FauxResponseStep,\n\tregisterFauxProvider,\n\tstreamSimple,\n} from \"@agent-forge/ai/compat\";\nimport type { AgentSession } from \"../core/agent-session.ts\";\nimport { AuthStorage } from \"../core/auth-storage.ts\";\nimport type { CapabilityPluginFactory, CapabilityPluginHandle } from \"../core/extensions/capability-plugin.ts\";\nimport { type CapabilityRuntime, resolvePluginCapabilityOrder } from \"../core/extensions/capability-runtime.ts\";\nimport type {\n\tAgentCompositionAPI,\n\tCapabilityAPI,\n\tHostCapabilities,\n\tPluginManifest,\n\tRuntimeInspectorSnapshot,\n} from \"../core/extensions/public-api.ts\";\nimport { ModelRuntime } from \"../core/model-runtime.ts\";\nimport { InMemoryCodingAgentModelsStore } from \"../core/models-store.ts\";\nimport { DefaultResourceLoader } from \"../core/resource-loader.ts\";\nimport { createAgentSession } from \"../core/sdk.ts\";\nimport { SessionManager } from \"../core/session-manager.ts\";\nimport { SettingsManager } from \"../core/settings-manager.ts\";\nimport type { ToolDefinition } from \"../core/tools/tool-definition.ts\";\n\nexport interface SessionPluginTestKitPlugin {\n\treadonly manifest: PluginManifest;\n\treadonly factory: CapabilityPluginFactory;\n}\n\nexport interface SessionPluginTestKitOptions {\n\treadonly plugins: readonly SessionPluginTestKitPlugin[];\n\treadonly responses?: readonly FauxResponseStep[];\n\treadonly providerId?: string;\n\treadonly api?: string;\n\treadonly composition?: AgentCompositionAPI;\n\t/** Custom tools registered on the fixture session for gated lifecycle scenarios. */\n\treadonly tools?: readonly ToolDefinition[];\n\t/** Post-run continuation strategy name selected through the public AgentSession config. */\n\treadonly runLoopStrategyName?: string;\n}\n\nexport interface SessionPluginTestKitInspector {\n\treadonly host: HostCapabilities;\n\treadonly plugins: readonly {\n\t\treadonly id: string;\n\t\treadonly version: string;\n\t\treadonly active: boolean;\n\t\treadonly provides: RuntimeInspectorSnapshot[\"plugins\"][number][\"provides\"];\n\t\treadonly requires: RuntimeInspectorSnapshot[\"plugins\"][number][\"requires\"];\n\t}[];\n\treadonly registrations: RuntimeInspectorSnapshot[\"registrations\"];\n\treadonly contributionPoints: readonly {\n\t\treadonly id: string;\n\t\treadonly version: number;\n\t\treadonly lifecycle: string;\n\t\treadonly owner: string;\n\t\treadonly active: boolean;\n\t}[];\n\treadonly contributions: readonly {\n\t\treadonly id: string;\n\t\treadonly pointId: string;\n\t\treadonly version: number;\n\t\treadonly owner: string;\n\t\treadonly lifecycle: string;\n\t}[];\n\treadonly lifecycle: readonly {\n\t\treadonly id: string;\n\t\treadonly version: number;\n\t\treadonly phase: string;\n\t\treadonly schema: string;\n\t\treadonly owner: string;\n\t\treadonly active: boolean;\n\t\treadonly registrations: readonly { readonly id: string; readonly kind: string; readonly owner: string }[];\n\t}[];\n\treadonly lifecycleReports: readonly {\n\t\treadonly eventId: string;\n\t\treadonly type: string;\n\t\treadonly version: number;\n\t\treadonly phase: string;\n\t\treadonly status: string;\n\t\treadonly attempted: number;\n\t\treadonly succeeded: number;\n\t\treadonly queued?: number;\n\t\treadonly failed: number;\n\t\treadonly failures: readonly {\n\t\t\treadonly pluginId: string;\n\t\t\treadonly registrationId: string;\n\t\t\treadonly kind: string;\n\t\t\treadonly error: unknown;\n\t\t}[];\n\t}[];\n\treadonly pluginRejections: RuntimeInspectorSnapshot[\"pluginRejections\"];\n\treadonly subscriptions: RuntimeInspectorSnapshot[\"subscriptions\"];\n\treadonly operations: RuntimeInspectorSnapshot[\"operations\"];\n\treadonly logs: readonly {\n\t\treadonly version: 1;\n\t\treadonly level: string;\n\t\treadonly message: string;\n\t\treadonly fields?: unknown;\n\t\treadonly cause?: unknown;\n\t\treadonly pluginId: string;\n\t\treadonly sessionId?: string;\n\t\treadonly operationId?: string;\n\t\treadonly correlationId?: string;\n\t\treadonly phase?: string;\n\t}[];\n\treadonly spans: readonly {\n\t\treadonly version: 1;\n\t\treadonly traceId: string;\n\t\treadonly spanId: string;\n\t\treadonly parentSpanId?: string;\n\t\treadonly name: string;\n\t\treadonly pluginId: string;\n\t\treadonly sessionId?: string;\n\t\treadonly status: string;\n\t\treadonly attributes: unknown;\n\t\treadonly result?: unknown;\n\t\treadonly cause?: unknown;\n\t\treadonly operationId?: string;\n\t\treadonly correlationId?: string;\n\t\treadonly phase?: string;\n\t}[];\n}\n\nexport interface SessionPluginTestKitTranscript {\n\treadonly version: 1;\n\treadonly sessionId: string;\n\treadonly revision: number;\n\treadonly loadOrder: readonly string[];\n\treadonly fauxCallCount: number;\n\treadonly messages: readonly { readonly role: string; readonly text: string }[];\n\treadonly entries: readonly { readonly type: string; readonly customType?: string; readonly data?: unknown }[];\n\treadonly inspector: SessionPluginTestKitInspector;\n}\n\nexport interface SessionPluginTestKit {\n\treadonly ready: Promise<void>;\n\treadonly session: AgentSession;\n\treadonly agent: Agent;\n\treadonly runtime: CapabilityRuntime;\n\treadonly faux: FauxProviderRegistration;\n\tapi(pluginId: string): CapabilityAPI;\n\trevoke(pluginId: string): void;\n\t/** Throws when a scripted response was not consumed by the fixture. */\n\tassertResponsesConsumed(): void;\n\tinspect(): RuntimeInspectorSnapshot;\n\ttranscript(): SessionPluginTestKitTranscript;\n\tdispose(): Promise<void>;\n}\n\nconst FIXED_SESSION_ID = \"session-plugin-testkit\";\nconst DEFAULT_PROVIDER_ID = \"faux-session-plugin-testkit\";\nconst DEFAULT_API = \"faux:session-plugin-testkit\";\n\nfunction stableText(message: unknown): string {\n\t// v8 ignore next -- 消息对象恒带 content 字段(AgentMessage 类型契约)\n\tif (!message || typeof message !== \"object\" || !(\"content\" in message)) return \"\";\n\tconst content = (message as { content?: unknown }).content;\n\t// v8 ignore next -- 助手消息的 content 恒为分段数组,字符串路径不会被命中\n\tif (typeof content === \"string\") return content;\n\t// v8 ignore next -- 同上:content 恒为数组\n\tif (!Array.isArray(content)) return \"\";\n\treturn content\n\t\t.filter((part): part is { type: \"text\"; text: string } => {\n\t\t\treturn (\n\t\t\t\ttypeof part === \"object\" &&\n\t\t\t\tpart !== null &&\n\t\t\t\t(part as { type?: unknown }).type === \"text\" &&\n\t\t\t\ttypeof (part as { text?: unknown }).text === \"string\"\n\t\t\t);\n\t\t})\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction freezeSnapshot<T>(value: T): T {\n\tconst clone = structuredClone(value);\n\tconst freeze = (candidate: unknown): void => {\n\t\tif (!candidate || typeof candidate !== \"object\" || ArrayBuffer.isView(candidate)) return;\n\t\tfor (const child of Object.values(candidate as Record<string, unknown>)) freeze(child);\n\t\tObject.freeze(candidate);\n\t};\n\tfreeze(clone);\n\treturn clone;\n}\n\nfunction transcriptValue(value: unknown, seen = new WeakSet<object>()): unknown {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") return value;\n\tif (typeof value === \"number\") return Number.isFinite(value) ? value : String(value);\n\tif (typeof value === \"bigint\") return `${value}n`;\n\tif (value === undefined) return null;\n\tif (value instanceof Error) {\n\t\t// v8 ignore next -- 错误经过 structuredClone 落盘,克隆体不可能形成循环引用\n\t\tif (seen.has(value)) return \"[Circular]\";\n\t\tseen.add(value);\n\t\tconst output: Record<string, unknown> = { name: value.name, message: value.message };\n\t\tconst code = (value as Error & { code?: unknown }).code;\n\t\tif (code !== undefined) output.code = transcriptValue(code, seen);\n\t\tconst cause = (value as Error & { cause?: unknown }).cause;\n\t\tif (cause !== undefined) output.cause = transcriptValue(cause, seen);\n\t\tfor (const key of Object.keys(value).sort()) {\n\t\t\tif (key === \"code\" || key === \"cause\") continue;\n\t\t\toutput[key] = transcriptValue((value as unknown as Record<string, unknown>)[key], seen);\n\t\t}\n\t\treturn output;\n\t}\n\t// v8 ignore next -- 值均来自 structuredClone 克隆,函数/符号无法存活\n\tif (typeof value !== \"object\") return String(value);\n\t// v8 ignore next -- 同上:克隆后的对象图无循环引用\n\tif (seen.has(value)) return \"[Circular]\";\n\tseen.add(value);\n\tif (Array.isArray(value)) return value.map((item) => transcriptValue(item, seen));\n\tconst output: Record<string, unknown> = {};\n\tfor (const key of Object.keys(value as Record<string, unknown>).sort()) {\n\t\toutput[key] = transcriptValue((value as Record<string, unknown>)[key], seen);\n\t}\n\treturn output;\n}\n\nfunction canonicalJson(value: unknown): string {\n\tconst serialized = JSON.stringify(transcriptValue(value));\n\t// v8 ignore next -- transcriptValue 已消毒全部值,JSON.stringify 不会返回 undefined\n\tif (serialized === undefined) throw new Error(\"Session plugin testkit transcript is not JSON-serializable\");\n\treturn serialized;\n}\n\n/**\n * The host's agentDir is the fixture's mkdtemp path — environment-specific and\n * random per run, not a behavioral signal. Mask it so repeated-run transcript\n * comparisons stay deterministic (D-075 S4 added agentDir to HostCapabilities).\n */\nfunction normalizeInspectorHost(host: HostCapabilities): HostCapabilities {\n\tif (typeof host.agentDir !== \"string\" || host.agentDir.length === 0) return host;\n\treturn { ...host, agentDir: \"<agentDir>\" };\n}\n\nfunction stableInspector(snapshot: RuntimeInspectorSnapshot): SessionPluginTestKitInspector {\n\treturn {\n\t\thost: normalizeInspectorHost(snapshot.host),\n\t\tplugins: snapshot.plugins.map(({ id, version, active, provides, requires }) => ({\n\t\t\tid,\n\t\t\tversion,\n\t\t\tactive,\n\t\t\tprovides,\n\t\t\trequires,\n\t\t})),\n\t\tregistrations: snapshot.registrations,\n\t\tcontributionPoints: snapshot.contributionPoints.map(({ id, version, lifecycle, owner, active }) => ({\n\t\t\tid,\n\t\t\tversion,\n\t\t\tlifecycle,\n\t\t\towner,\n\t\t\tactive,\n\t\t})),\n\t\tcontributions: snapshot.contributions.map(({ id, pointId, version, owner, lifecycle }) => ({\n\t\t\tid,\n\t\t\tpointId,\n\t\t\tversion,\n\t\t\towner,\n\t\t\tlifecycle,\n\t\t})),\n\t\tlifecycle: snapshot.lifecycle.map(({ id, version, phase, schema, owner, active, registrations }) => ({\n\t\t\tid,\n\t\t\tversion,\n\t\t\tphase,\n\t\t\tschema,\n\t\t\towner,\n\t\t\tactive,\n\t\t\tregistrations,\n\t\t})),\n\t\tlifecycleReports: snapshot.lifecycleReports.map(\n\t\t\t({ eventId, type, version, phase, status, attempted, succeeded, failed, failures }) => ({\n\t\t\t\teventId,\n\t\t\t\ttype,\n\t\t\t\tversion,\n\t\t\t\tphase,\n\t\t\t\tstatus,\n\t\t\t\tattempted,\n\t\t\t\tsucceeded,\n\t\t\t\tfailed,\n\t\t\t\tfailures: failures.map(({ pluginId, registrationId, kind, error }) => ({\n\t\t\t\t\tpluginId,\n\t\t\t\t\tregistrationId,\n\t\t\t\t\tkind,\n\t\t\t\t\terror: transcriptValue(error),\n\t\t\t\t})),\n\t\t\t}),\n\t\t),\n\t\tpluginRejections: snapshot.pluginRejections,\n\t\tsubscriptions: snapshot.subscriptions,\n\t\toperations: snapshot.operations,\n\t\tlogs: snapshot.logs.map(\n\t\t\t({ version, level, message, fields, cause, pluginId, sessionId, operationId, correlationId, phase }) => ({\n\t\t\t\tversion,\n\t\t\t\tlevel,\n\t\t\t\tmessage,\n\t\t\t\t...(fields === undefined ? {} : { fields: transcriptValue(fields) }),\n\t\t\t\t...(cause === undefined ? {} : { cause: transcriptValue(cause) }),\n\t\t\t\tpluginId,\n\t\t\t\t...(sessionId === undefined ? {} : { sessionId }),\n\t\t\t\t...(operationId === undefined ? {} : { operationId }),\n\t\t\t\t...(correlationId === undefined ? {} : { correlationId }),\n\t\t\t\t...(phase === undefined ? {} : { phase }),\n\t\t\t}),\n\t\t),\n\t\tspans: snapshot.spans.map(\n\t\t\t({\n\t\t\t\tversion,\n\t\t\t\ttraceId,\n\t\t\t\tspanId,\n\t\t\t\tparentSpanId,\n\t\t\t\tname,\n\t\t\t\tpluginId,\n\t\t\t\tsessionId,\n\t\t\t\tstatus,\n\t\t\t\tattributes,\n\t\t\t\tresult,\n\t\t\t\tcause,\n\t\t\t\toperationId,\n\t\t\t\tcorrelationId,\n\t\t\t\tphase,\n\t\t\t}) => ({\n\t\t\t\tversion,\n\t\t\t\ttraceId,\n\t\t\t\tspanId,\n\t\t\t\t...(parentSpanId === undefined ? {} : { parentSpanId }),\n\t\t\t\tname,\n\t\t\t\tpluginId,\n\t\t\t\t...(sessionId === undefined ? {} : { sessionId }),\n\t\t\t\tattributes: transcriptValue(attributes),\n\t\t\t\tstatus,\n\t\t\t\t...(result === undefined ? {} : { result: transcriptValue(result) }),\n\t\t\t\t...(cause === undefined ? {} : { cause: transcriptValue(cause) }),\n\t\t\t\t...(operationId === undefined ? {} : { operationId }),\n\t\t\t\t...(correlationId === undefined ? {} : { correlationId }),\n\t\t\t\t...(phase === undefined ? {} : { phase }),\n\t\t\t}),\n\t\t),\n\t};\n}\n\nfunction modelConfig(model: {\n\tid: string;\n\tname: string;\n\tapi: string;\n\tprovider: string;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: readonly (\"text\" | \"image\")[];\n\tcost: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\tcontextWindow: number;\n\tmaxTokens: number;\n}) {\n\treturn {\n\t\tid: model.id,\n\t\tname: model.name,\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tbaseUrl: model.baseUrl,\n\t\treasoning: model.reasoning,\n\t\tinput: [...model.input],\n\t\tcost: model.cost,\n\t\tcontextWindow: model.contextWindow,\n\t\tmaxTokens: model.maxTokens,\n\t};\n}\n\n/** Create a complete deterministic AgentSession fixture and load inline capability plugins. */\nexport async function createSessionPluginTestKit(options: SessionPluginTestKitOptions): Promise<SessionPluginTestKit> {\n\tconst tempDir = await mkdtemp(join(tmpdir(), \"agent-forge-session-plugin-testkit-\"));\n\tconst providerId = options.providerId ?? DEFAULT_PROVIDER_ID;\n\tconst apiName = options.api ?? DEFAULT_API;\n\tlet faux: FauxProviderRegistration | undefined;\n\tlet session: AgentSession | undefined;\n\ttry {\n\t\tfaux = registerFauxProvider({\n\t\t\tapi: apiName,\n\t\t\tprovider: providerId,\n\t\t\tclock: () => 0,\n\t\t\tidFactory: (prefix, sequence) => `${prefix}-${sequence}`,\n\t\t});\n\t\tif (options.responses) faux.setResponses([...options.responses]);\n\t\tconst fauxRegistration = faux;\n\t\tconst model = fauxRegistration.getModel();\n\t\tconst authStorage = AuthStorage.inMemory();\n\t\tawait authStorage.modify(providerId, async () => ({ type: \"api_key\", key: \"faux-key\" }));\n\t\tconst modelRuntime = await ModelRuntime.create({\n\t\t\tcredentials: authStorage,\n\t\t\tmodelsPath: null,\n\t\t\tmodelsStore: new InMemoryCodingAgentModelsStore(),\n\t\t\tallowModelNetwork: false,\n\t\t\trefreshOnCreate: false,\n\t\t});\n\t\tmodelRuntime.registerProvider(providerId, {\n\t\t\tbaseUrl: model.baseUrl,\n\t\t\tapi: apiName,\n\t\t\tapiKey: \"faux-key\",\n\t\t\tmodels: fauxRegistration.models.map(modelConfig),\n\t\t});\n\t\tconst settingsManager = SettingsManager.create(tempDir, tempDir);\n\t\tconst resourceLoader = new DefaultResourceLoader({\n\t\t\tcwd: tempDir,\n\t\t\tagentDir: tempDir,\n\t\t\tsettingsManager,\n\t\t\tnoSkills: true,\n\t\t\tnoPromptTemplates: true,\n\t\t\tnoThemes: true,\n\t\t\tnoContextFiles: true,\n\t\t});\n\t\tawait resourceLoader.reload();\n\t\tconst sessionManager = SessionManager.inMemory(tempDir, { id: FIXED_SESSION_ID });\n\t\tconst created = await createAgentSession({\n\t\t\tagentDir: tempDir,\n\t\t\tnoTools: \"all\",\n\t\t\t// Custom fixture tools must be allowlisted explicitly: noTools=\"all\"\n\t\t\t// clears the allowlist, which would otherwise leave them inactive.\n\t\t\t...(options.tools === undefined\n\t\t\t\t? {}\n\t\t\t\t: { tools: options.tools.map((tool) => tool.name), customTools: [...options.tools] }),\n\t\t\tdiscoverCapabilityPlugins: false,\n\t\t\tenableAgentTasks: false,\n\t\t\t...(options.runLoopStrategyName === undefined ? {} : { runLoopStrategyName: options.runLoopStrategyName }),\n\t\t\tstreamFn: streamSimple,\n\t\t\tmodel,\n\t\t\tmodelRuntime,\n\t\t\tresourceLoader,\n\t\t\tsessionManager,\n\t\t\tsettingsManager,\n\t\t\tcwd: tempDir,\n\t\t\tagentComposition: options.composition,\n\t\t}).then(({ session: createdSession }) => createdSession);\n\t\tsession = created;\n\t\tconst activeSession = session;\n\t\tconst initialRuntime = activeSession.getCapabilityRuntime();\n\t\tconst handles = new Map<string, CapabilityPluginHandle>();\n\t\tconst pluginByManifest = new Map(options.plugins.map((plugin) => [plugin.manifest, plugin]));\n\t\tlet closing = false;\n\t\tlet disposed = false;\n\t\tlet disposePromise: Promise<void> | undefined;\n\t\tconst cleanup = async (): Promise<void> => {\n\t\t\tconst failures: unknown[] = [];\n\t\t\tfor (const handle of [...handles.values()].reverse()) {\n\t\t\t\ttry {\n\t\t\t\t\tawait handle.dispose();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tfailures.push(error);\n\t\t\t\t}\n\t\t\t}\n\t\t\thandles.clear();\n\t\t\ttry {\n\t\t\t\tawait session?.dispose();\n\t\t\t} catch (error) {\n\t\t\t\tfailures.push(error);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tfaux?.unregister();\n\t\t\t\tawait rm(tempDir, { recursive: true, force: true });\n\t\t\t} catch (error) {\n\t\t\t\tfailures.push(error);\n\t\t\t}\n\t\t\tif (failures.length === 1) throw failures[0];\n\t\t\tif (failures.length > 1) throw new AggregateError(failures, \"Session plugin testkit cleanup failed\");\n\t\t};\n\t\tconst ready = (async () => {\n\t\t\ttry {\n\t\t\t\tfor (const manifest of resolvePluginCapabilityOrder(options.plugins.map((plugin) => plugin.manifest))) {\n\t\t\t\t\t// v8 ignore next -- kit 仅在 ready 成功后返回,startup 期间不会调用 dispose\n\t\t\t\t\tif (closing) throw new Error(\"Session plugin testkit was disposed during startup\");\n\t\t\t\t\tconst plugin = pluginByManifest.get(manifest);\n\t\t\t\t\t// v8 ignore next -- plugins 数组同时供给加载顺序与 factory 映射,必可解析\n\t\t\t\t\tif (!plugin) throw new Error(`Session plugin testkit cannot resolve factory: ${manifest.id}`);\n\t\t\t\t\tconst handle = await activeSession.loadCapabilityPlugin(manifest, plugin.factory);\n\t\t\t\t\thandles.set(manifest.id, handle);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tawait cleanup();\n\t\t\t\t} catch (cleanupError) {\n\t\t\t\t\tthrow new AggregateError([error, cleanupError], \"Session plugin testkit startup rollback failed\");\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t})();\n\t\tconst kit: SessionPluginTestKit = {\n\t\t\tready,\n\t\t\tsession: activeSession,\n\t\t\tagent: activeSession.agent,\n\t\t\tget runtime(): CapabilityRuntime {\n\t\t\t\tif (disposed) throw new Error(\"Session plugin testkit runtime is disposed\");\n\t\t\t\treturn activeSession.getCapabilityRuntime();\n\t\t\t},\n\t\t\tfaux: fauxRegistration,\n\t\t\tapi(pluginId) {\n\t\t\t\tif (activeSession.getCapabilityRuntime() !== initialRuntime) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Session plugin testkit plugin API handles expire after session reload; access the current runtime directly\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst handle = handles.get(pluginId);\n\t\t\t\tif (!handle) throw new Error(`Session plugin testkit has no loaded plugin: ${pluginId}`);\n\t\t\t\treturn handle.api;\n\t\t\t},\n\t\t\trevoke(pluginId) {\n\t\t\t\tif (activeSession.getCapabilityRuntime() !== initialRuntime) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Session plugin testkit plugin API handles expire after session reload; access the current runtime directly\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst handle = handles.get(pluginId);\n\t\t\t\tif (!handle) throw new Error(`Session plugin testkit has no loaded plugin: ${pluginId}`);\n\t\t\t\tactiveSession.getCapabilityRuntime().revokeAPI(handle.api);\n\t\t\t},\n\t\t\tassertResponsesConsumed() {\n\t\t\t\tconst pending = fauxRegistration.getPendingResponseCount();\n\t\t\t\tif (pending !== 0) {\n\t\t\t\t\tthrow new Error(`Session plugin testkit has ${pending} unused faux response${pending === 1 ? \"\" : \"s\"}`);\n\t\t\t\t}\n\t\t\t},\n\t\t\tinspect: () => activeSession.getCapabilityRuntime().inspect(),\n\t\t\ttranscript: () => {\n\t\t\t\tconst branch = sessionManager.getBranch();\n\t\t\t\tconst transcript: SessionPluginTestKitTranscript = {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tsessionId: sessionManager.getSessionId(),\n\t\t\t\t\trevision: sessionManager.getRevision().sequence,\n\t\t\t\t\tloadOrder: [...handles.keys()],\n\t\t\t\t\tfauxCallCount: fauxRegistration.state.callCount,\n\t\t\t\t\tmessages: activeSession.agent.state.messages.map((message) => ({\n\t\t\t\t\t\trole: message.role,\n\t\t\t\t\t\ttext: stableText(message),\n\t\t\t\t\t})),\n\t\t\t\t\tentries: branch.map((entry) => ({\n\t\t\t\t\t\ttype: entry.type,\n\t\t\t\t\t\t...(entry.type === \"custom\"\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tcustomType: entry.customType,\n\t\t\t\t\t\t\t\t\t...(entry.data === undefined ? {} : { data: transcriptValue(entry.data) }),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t})),\n\t\t\t\t\tinspector: stableInspector(activeSession.getCapabilityRuntime().inspect()),\n\t\t\t\t};\n\t\t\t\treturn freezeSnapshot(transcript);\n\t\t\t},\n\t\t\tdispose: async () => {\n\t\t\t\tdisposePromise ??= (async () => {\n\t\t\t\t\tclosing = true;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait ready;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Startup rollback already disposed the session and faux provider.\n\t\t\t\t\t\t// v8 ignore next -- ready 已在返回前 await,dispose 中不会进入该 catch\n\t\t\t\t\t\tif (session?.isDisposed) {\n\t\t\t\t\t\t\tdisposed = true;\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait cleanup();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tdisposed = true;\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t\treturn disposePromise;\n\t\t\t},\n\t\t};\n\t\tawait ready;\n\t\treturn kit;\n\t} catch (error) {\n\t\ttry {\n\t\t\tsession && (await session.dispose());\n\t\t} finally {\n\t\t\tfaux?.unregister();\n\t\t\tawait rm(tempDir, { recursive: true, force: true });\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** Runs a session fixture repeatedly and rejects on the first transcript divergence. */\nexport async function repeatSessionPluginTestKit(\n\ttimes: number,\n\trun: () => Promise<SessionPluginTestKitTranscript>,\n): Promise<SessionPluginTestKitTranscript> {\n\tif (!Number.isSafeInteger(times) || times < 1)\n\t\tthrow new Error(\"Session plugin testkit repeat count must be a positive integer\");\n\tlet baseline: SessionPluginTestKitTranscript | undefined;\n\tfor (let index = 0; index < times; index += 1) {\n\t\tconst transcript = await run();\n\t\tif (baseline && canonicalJson(transcript) !== canonicalJson(baseline)) {\n\t\t\tthrow new Error(`Session plugin testkit transcript diverged on run ${index + 1}`);\n\t\t}\n\t\tbaseline = transcript;\n\t}\n\treturn baseline!;\n}\n"]}
1
+ {"version":3,"file":"session-plugin-testkit.d.ts","sourceRoot":"","sources":["../../src/testing/session-plugin-testkit.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EACN,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EAGrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,KAAK,EAAE,uBAAuB,EAA0B,MAAM,yCAAyC,CAAC;AAC/G,OAAO,EAAE,KAAK,iBAAiB,EAAgC,MAAM,0CAA0C,CAAC;AAChH,OAAO,KAAK,EACX,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,wBAAwB,EACxB,MAAM,kCAAkC,CAAC;AAO1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAEvE,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAC;CAC1C;AAED,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,OAAO,EAAE,SAAS,0BAA0B,EAAE,CAAC;IACxD,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACjD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAC3C,oFAAoF;IACpF,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,2FAA2F;IAC3F,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,SAAS;QAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QAC3E,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;KAC3E,EAAE,CAAC;IACJ,QAAQ,CAAC,aAAa,EAAE,wBAAwB,CAAC,eAAe,CAAC,CAAC;IAClE,QAAQ,CAAC,kBAAkB,EAAE,SAAS;QACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;KACzB,EAAE,CAAC;IACJ,QAAQ,CAAC,aAAa,EAAE,SAAS;QAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC3B,EAAE,CAAC;IACJ,QAAQ,CAAC,SAAS,EAAE,SAAS;QAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,aAAa,EAAE,SAAS;YAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;KAC1G,EAAE,CAAC;IACJ,QAAQ,CAAC,gBAAgB,EAAE,SAAS;QACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS;YAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;YAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;YAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;SACxB,EAAE,CAAC;KACJ,EAAE,CAAC;IACJ,QAAQ,CAAC,gBAAgB,EAAE,wBAAwB,CAAC,kBAAkB,CAAC,CAAC;IACxE,QAAQ,CAAC,aAAa,EAAE,wBAAwB,CAAC,eAAe,CAAC,CAAC;IAClE,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC,YAAY,CAAC,CAAC;IAC5D,QAAQ,CAAC,IAAI,EAAE,SAAS;QACvB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;KACxB,EAAE,CAAC;IACJ,QAAQ,CAAC,KAAK,EAAE,SAAS;QACxB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;QAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;KACxB,EAAE,CAAC;CACJ;AAED,MAAM,WAAW,8BAA8B;IAC9C,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC/E,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IAC9G,QAAQ,CAAC,SAAS,EAAE,6BAA6B,CAAC;CAClD;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAAC;IACrC,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,uEAAuE;IACvE,uBAAuB,IAAI,IAAI,CAAC;IAChC,OAAO,IAAI,wBAAwB,CAAC;IACpC,UAAU,IAAI,8BAA8B,CAAC;IAC7C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAkOD,+FAA+F;AAC/F,wBAAsB,0BAA0B,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAiNpH;AAED,wFAAwF;AACxF,wBAAsB,0BAA0B,CAC/C,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,OAAO,CAAC,8BAA8B,CAAC,GAChD,OAAO,CAAC,8BAA8B,CAAC,CAYzC","sourcesContent":["import { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Agent } from \"@agent-forge/agent-core\";\nimport {\n\ttype FauxProviderRegistration,\n\ttype FauxResponseStep,\n\tregisterFauxProvider,\n\tstreamSimple,\n} from \"@agent-forge/ai/compat\";\nimport type { AgentSession } from \"../core/agent-session.ts\";\nimport { AuthStorage } from \"../core/auth-storage.ts\";\nimport type { CapabilityPluginFactory, CapabilityPluginHandle } from \"../core/extensions/capability-plugin.ts\";\nimport { type CapabilityRuntime, resolvePluginCapabilityOrder } from \"../core/extensions/capability-runtime.ts\";\nimport type {\n\tAgentCompositionAPI,\n\tCapabilityAPI,\n\tHostCapabilities,\n\tPluginManifest,\n\tRuntimeInspectorSnapshot,\n} from \"../core/extensions/public-api.ts\";\nimport { ModelRuntime } from \"../core/model-runtime.ts\";\nimport { InMemoryCodingAgentModelsStore } from \"../core/models-store.ts\";\nimport { DefaultResourceLoader } from \"../core/resource-loader.ts\";\nimport { createAgentSession } from \"../core/sdk.ts\";\nimport { SessionManager } from \"../core/session-manager.ts\";\nimport { SettingsManager } from \"../core/settings-manager.ts\";\nimport type { ToolDefinition } from \"../core/tools/tool-definition.ts\";\n\nexport interface SessionPluginTestKitPlugin {\n\treadonly manifest: PluginManifest;\n\treadonly factory: CapabilityPluginFactory;\n}\n\nexport interface SessionPluginTestKitOptions {\n\treadonly plugins: readonly SessionPluginTestKitPlugin[];\n\treadonly responses?: readonly FauxResponseStep[];\n\treadonly providerId?: string;\n\treadonly api?: string;\n\treadonly composition?: AgentCompositionAPI;\n\t/** Custom tools registered on the fixture session for gated lifecycle scenarios. */\n\treadonly tools?: readonly ToolDefinition[];\n\t/** Post-run continuation strategy name selected through the public AgentSession config. */\n\treadonly runLoopStrategyName?: string;\n}\n\nexport interface SessionPluginTestKitInspector {\n\treadonly host: HostCapabilities;\n\treadonly plugins: readonly {\n\t\treadonly id: string;\n\t\treadonly version: string;\n\t\treadonly active: boolean;\n\t\treadonly provides: RuntimeInspectorSnapshot[\"plugins\"][number][\"provides\"];\n\t\treadonly requires: RuntimeInspectorSnapshot[\"plugins\"][number][\"requires\"];\n\t}[];\n\treadonly registrations: RuntimeInspectorSnapshot[\"registrations\"];\n\treadonly contributionPoints: readonly {\n\t\treadonly id: string;\n\t\treadonly version: number;\n\t\treadonly lifecycle: string;\n\t\treadonly owner: string;\n\t\treadonly active: boolean;\n\t}[];\n\treadonly contributions: readonly {\n\t\treadonly id: string;\n\t\treadonly pointId: string;\n\t\treadonly version: number;\n\t\treadonly owner: string;\n\t\treadonly lifecycle: string;\n\t}[];\n\treadonly lifecycle: readonly {\n\t\treadonly id: string;\n\t\treadonly version: number;\n\t\treadonly phase: string;\n\t\treadonly schema: string;\n\t\treadonly owner: string;\n\t\treadonly active: boolean;\n\t\treadonly registrations: readonly { readonly id: string; readonly kind: string; readonly owner: string }[];\n\t}[];\n\treadonly lifecycleReports: readonly {\n\t\treadonly eventId: string;\n\t\treadonly type: string;\n\t\treadonly version: number;\n\t\treadonly phase: string;\n\t\treadonly status: string;\n\t\treadonly attempted: number;\n\t\treadonly succeeded: number;\n\t\treadonly queued?: number;\n\t\treadonly failed: number;\n\t\treadonly failures: readonly {\n\t\t\treadonly pluginId: string;\n\t\t\treadonly registrationId: string;\n\t\t\treadonly kind: string;\n\t\t\treadonly error: unknown;\n\t\t}[];\n\t}[];\n\treadonly pluginRejections: RuntimeInspectorSnapshot[\"pluginRejections\"];\n\treadonly subscriptions: RuntimeInspectorSnapshot[\"subscriptions\"];\n\treadonly operations: RuntimeInspectorSnapshot[\"operations\"];\n\treadonly logs: readonly {\n\t\treadonly version: 1;\n\t\treadonly level: string;\n\t\treadonly message: string;\n\t\treadonly fields?: unknown;\n\t\treadonly cause?: unknown;\n\t\treadonly pluginId: string;\n\t\treadonly sessionId?: string;\n\t\treadonly operationId?: string;\n\t\treadonly correlationId?: string;\n\t\treadonly phase?: string;\n\t}[];\n\treadonly spans: readonly {\n\t\treadonly version: 1;\n\t\treadonly traceId: string;\n\t\treadonly spanId: string;\n\t\treadonly parentSpanId?: string;\n\t\treadonly name: string;\n\t\treadonly pluginId: string;\n\t\treadonly sessionId?: string;\n\t\treadonly status: string;\n\t\treadonly attributes: unknown;\n\t\treadonly result?: unknown;\n\t\treadonly cause?: unknown;\n\t\treadonly operationId?: string;\n\t\treadonly correlationId?: string;\n\t\treadonly phase?: string;\n\t}[];\n}\n\nexport interface SessionPluginTestKitTranscript {\n\treadonly version: 1;\n\treadonly sessionId: string;\n\treadonly revision: number;\n\treadonly loadOrder: readonly string[];\n\treadonly fauxCallCount: number;\n\treadonly messages: readonly { readonly role: string; readonly text: string }[];\n\treadonly entries: readonly { readonly type: string; readonly customType?: string; readonly data?: unknown }[];\n\treadonly inspector: SessionPluginTestKitInspector;\n}\n\nexport interface SessionPluginTestKit {\n\treadonly ready: Promise<void>;\n\treadonly session: AgentSession;\n\treadonly agent: Agent;\n\treadonly runtime: CapabilityRuntime;\n\treadonly faux: FauxProviderRegistration;\n\tapi(pluginId: string): CapabilityAPI;\n\trevoke(pluginId: string): void;\n\t/** Throws when a scripted response was not consumed by the fixture. */\n\tassertResponsesConsumed(): void;\n\tinspect(): RuntimeInspectorSnapshot;\n\ttranscript(): SessionPluginTestKitTranscript;\n\tdispose(): Promise<void>;\n}\n\nconst FIXED_SESSION_ID = \"session-plugin-testkit\";\nconst DEFAULT_PROVIDER_ID = \"faux-session-plugin-testkit\";\nconst DEFAULT_API = \"faux:session-plugin-testkit\";\n\nfunction stableText(message: unknown): string {\n\t// v8 ignore next -- 消息对象恒带 content 字段(AgentMessage 类型契约)\n\tif (!message || typeof message !== \"object\" || !(\"content\" in message)) return \"\";\n\tconst content = (message as { content?: unknown }).content;\n\t// v8 ignore next -- 助手消息的 content 恒为分段数组,字符串路径不会被命中\n\tif (typeof content === \"string\") return content;\n\t// v8 ignore next -- 同上:content 恒为数组\n\tif (!Array.isArray(content)) return \"\";\n\treturn content\n\t\t.filter((part): part is { type: \"text\"; text: string } => {\n\t\t\treturn (\n\t\t\t\ttypeof part === \"object\" &&\n\t\t\t\tpart !== null &&\n\t\t\t\t(part as { type?: unknown }).type === \"text\" &&\n\t\t\t\ttypeof (part as { text?: unknown }).text === \"string\"\n\t\t\t);\n\t\t})\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction freezeSnapshot<T>(value: T): T {\n\tconst clone = structuredClone(value);\n\tconst freeze = (candidate: unknown): void => {\n\t\tif (!candidate || typeof candidate !== \"object\" || ArrayBuffer.isView(candidate)) return;\n\t\tfor (const child of Object.values(candidate as Record<string, unknown>)) freeze(child);\n\t\tObject.freeze(candidate);\n\t};\n\tfreeze(clone);\n\treturn clone;\n}\n\nfunction transcriptValue(value: unknown, seen = new WeakSet<object>()): unknown {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") return value;\n\tif (typeof value === \"number\") return Number.isFinite(value) ? value : String(value);\n\tif (typeof value === \"bigint\") return `${value}n`;\n\tif (value === undefined) return null;\n\tif (value instanceof Error) {\n\t\t// v8 ignore next -- 错误经过 structuredClone 落盘,克隆体不可能形成循环引用\n\t\tif (seen.has(value)) return \"[Circular]\";\n\t\tseen.add(value);\n\t\tconst output: Record<string, unknown> = { name: value.name, message: value.message };\n\t\tconst code = (value as Error & { code?: unknown }).code;\n\t\tif (code !== undefined) output.code = transcriptValue(code, seen);\n\t\tconst cause = (value as Error & { cause?: unknown }).cause;\n\t\tif (cause !== undefined) output.cause = transcriptValue(cause, seen);\n\t\tfor (const key of Object.keys(value).sort()) {\n\t\t\tif (key === \"code\" || key === \"cause\") continue;\n\t\t\toutput[key] = transcriptValue((value as unknown as Record<string, unknown>)[key], seen);\n\t\t}\n\t\treturn output;\n\t}\n\t// v8 ignore next -- 值均来自 structuredClone 克隆,函数/符号无法存活\n\tif (typeof value !== \"object\") return String(value);\n\t// v8 ignore next -- 同上:克隆后的对象图无循环引用\n\tif (seen.has(value)) return \"[Circular]\";\n\tseen.add(value);\n\tif (Array.isArray(value)) return value.map((item) => transcriptValue(item, seen));\n\tconst output: Record<string, unknown> = {};\n\tfor (const key of Object.keys(value as Record<string, unknown>).sort()) {\n\t\toutput[key] = transcriptValue((value as Record<string, unknown>)[key], seen);\n\t}\n\treturn output;\n}\n\nfunction canonicalJson(value: unknown): string {\n\tconst serialized = JSON.stringify(transcriptValue(value));\n\t// v8 ignore next -- transcriptValue 已消毒全部值,JSON.stringify 不会返回 undefined\n\tif (serialized === undefined) throw new Error(\"Session plugin testkit transcript is not JSON-serializable\");\n\treturn serialized;\n}\n\n/**\n * The host's agentDir and workspaceDirectory are the fixture's mkdtemp paths —\n * environment-specific and random per run, not a behavioral signal. Mask them\n * so repeated-run transcript comparisons stay deterministic (D-075 S4 added\n * agentDir to HostCapabilities; workspaceDirectory rides the same channel).\n */\nfunction normalizeInspectorHost(host: HostCapabilities): HostCapabilities {\n\tif (host.agentDir === undefined && host.workspaceDirectory === undefined) return host;\n\treturn {\n\t\t...host,\n\t\t...(typeof host.agentDir === \"string\" && host.agentDir.length > 0 ? { agentDir: \"<agentDir>\" } : {}),\n\t\t...(typeof host.workspaceDirectory === \"string\" && host.workspaceDirectory.length > 0\n\t\t\t? { workspaceDirectory: \"<workspaceDirectory>\" }\n\t\t\t: {}),\n\t};\n}\n\nfunction stableInspector(snapshot: RuntimeInspectorSnapshot): SessionPluginTestKitInspector {\n\treturn {\n\t\thost: normalizeInspectorHost(snapshot.host),\n\t\tplugins: snapshot.plugins.map(({ id, version, active, provides, requires }) => ({\n\t\t\tid,\n\t\t\tversion,\n\t\t\tactive,\n\t\t\tprovides,\n\t\t\trequires,\n\t\t})),\n\t\tregistrations: snapshot.registrations,\n\t\tcontributionPoints: snapshot.contributionPoints.map(({ id, version, lifecycle, owner, active }) => ({\n\t\t\tid,\n\t\t\tversion,\n\t\t\tlifecycle,\n\t\t\towner,\n\t\t\tactive,\n\t\t})),\n\t\tcontributions: snapshot.contributions.map(({ id, pointId, version, owner, lifecycle }) => ({\n\t\t\tid,\n\t\t\tpointId,\n\t\t\tversion,\n\t\t\towner,\n\t\t\tlifecycle,\n\t\t})),\n\t\tlifecycle: snapshot.lifecycle.map(({ id, version, phase, schema, owner, active, registrations }) => ({\n\t\t\tid,\n\t\t\tversion,\n\t\t\tphase,\n\t\t\tschema,\n\t\t\towner,\n\t\t\tactive,\n\t\t\tregistrations,\n\t\t})),\n\t\tlifecycleReports: snapshot.lifecycleReports.map(\n\t\t\t({ eventId, type, version, phase, status, attempted, succeeded, failed, failures }) => ({\n\t\t\t\teventId,\n\t\t\t\ttype,\n\t\t\t\tversion,\n\t\t\t\tphase,\n\t\t\t\tstatus,\n\t\t\t\tattempted,\n\t\t\t\tsucceeded,\n\t\t\t\tfailed,\n\t\t\t\tfailures: failures.map(({ pluginId, registrationId, kind, error }) => ({\n\t\t\t\t\tpluginId,\n\t\t\t\t\tregistrationId,\n\t\t\t\t\tkind,\n\t\t\t\t\terror: transcriptValue(error),\n\t\t\t\t})),\n\t\t\t}),\n\t\t),\n\t\tpluginRejections: snapshot.pluginRejections,\n\t\tsubscriptions: snapshot.subscriptions,\n\t\toperations: snapshot.operations,\n\t\tlogs: snapshot.logs.map(\n\t\t\t({ version, level, message, fields, cause, pluginId, sessionId, operationId, correlationId, phase }) => ({\n\t\t\t\tversion,\n\t\t\t\tlevel,\n\t\t\t\tmessage,\n\t\t\t\t...(fields === undefined ? {} : { fields: transcriptValue(fields) }),\n\t\t\t\t...(cause === undefined ? {} : { cause: transcriptValue(cause) }),\n\t\t\t\tpluginId,\n\t\t\t\t...(sessionId === undefined ? {} : { sessionId }),\n\t\t\t\t...(operationId === undefined ? {} : { operationId }),\n\t\t\t\t...(correlationId === undefined ? {} : { correlationId }),\n\t\t\t\t...(phase === undefined ? {} : { phase }),\n\t\t\t}),\n\t\t),\n\t\tspans: snapshot.spans.map(\n\t\t\t({\n\t\t\t\tversion,\n\t\t\t\ttraceId,\n\t\t\t\tspanId,\n\t\t\t\tparentSpanId,\n\t\t\t\tname,\n\t\t\t\tpluginId,\n\t\t\t\tsessionId,\n\t\t\t\tstatus,\n\t\t\t\tattributes,\n\t\t\t\tresult,\n\t\t\t\tcause,\n\t\t\t\toperationId,\n\t\t\t\tcorrelationId,\n\t\t\t\tphase,\n\t\t\t}) => ({\n\t\t\t\tversion,\n\t\t\t\ttraceId,\n\t\t\t\tspanId,\n\t\t\t\t...(parentSpanId === undefined ? {} : { parentSpanId }),\n\t\t\t\tname,\n\t\t\t\tpluginId,\n\t\t\t\t...(sessionId === undefined ? {} : { sessionId }),\n\t\t\t\tattributes: transcriptValue(attributes),\n\t\t\t\tstatus,\n\t\t\t\t...(result === undefined ? {} : { result: transcriptValue(result) }),\n\t\t\t\t...(cause === undefined ? {} : { cause: transcriptValue(cause) }),\n\t\t\t\t...(operationId === undefined ? {} : { operationId }),\n\t\t\t\t...(correlationId === undefined ? {} : { correlationId }),\n\t\t\t\t...(phase === undefined ? {} : { phase }),\n\t\t\t}),\n\t\t),\n\t};\n}\n\nfunction modelConfig(model: {\n\tid: string;\n\tname: string;\n\tapi: string;\n\tprovider: string;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: readonly (\"text\" | \"image\")[];\n\tcost: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\tcontextWindow: number;\n\tmaxTokens: number;\n}) {\n\treturn {\n\t\tid: model.id,\n\t\tname: model.name,\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tbaseUrl: model.baseUrl,\n\t\treasoning: model.reasoning,\n\t\tinput: [...model.input],\n\t\tcost: model.cost,\n\t\tcontextWindow: model.contextWindow,\n\t\tmaxTokens: model.maxTokens,\n\t};\n}\n\n/** Create a complete deterministic AgentSession fixture and load inline capability plugins. */\nexport async function createSessionPluginTestKit(options: SessionPluginTestKitOptions): Promise<SessionPluginTestKit> {\n\tconst tempDir = await mkdtemp(join(tmpdir(), \"agent-forge-session-plugin-testkit-\"));\n\tconst providerId = options.providerId ?? DEFAULT_PROVIDER_ID;\n\tconst apiName = options.api ?? DEFAULT_API;\n\tlet faux: FauxProviderRegistration | undefined;\n\tlet session: AgentSession | undefined;\n\ttry {\n\t\tfaux = registerFauxProvider({\n\t\t\tapi: apiName,\n\t\t\tprovider: providerId,\n\t\t\tclock: () => 0,\n\t\t\tidFactory: (prefix, sequence) => `${prefix}-${sequence}`,\n\t\t});\n\t\tif (options.responses) faux.setResponses([...options.responses]);\n\t\tconst fauxRegistration = faux;\n\t\tconst model = fauxRegistration.getModel();\n\t\tconst authStorage = AuthStorage.inMemory();\n\t\tawait authStorage.modify(providerId, async () => ({ type: \"api_key\", key: \"faux-key\" }));\n\t\tconst modelRuntime = await ModelRuntime.create({\n\t\t\tcredentials: authStorage,\n\t\t\tmodelsPath: null,\n\t\t\tmodelsStore: new InMemoryCodingAgentModelsStore(),\n\t\t\tallowModelNetwork: false,\n\t\t\trefreshOnCreate: false,\n\t\t});\n\t\tmodelRuntime.registerProvider(providerId, {\n\t\t\tbaseUrl: model.baseUrl,\n\t\t\tapi: apiName,\n\t\t\tapiKey: \"faux-key\",\n\t\t\tmodels: fauxRegistration.models.map(modelConfig),\n\t\t});\n\t\tconst settingsManager = SettingsManager.create(tempDir, tempDir);\n\t\tconst resourceLoader = new DefaultResourceLoader({\n\t\t\tcwd: tempDir,\n\t\t\tagentDir: tempDir,\n\t\t\tsettingsManager,\n\t\t\tnoSkills: true,\n\t\t\tnoPromptTemplates: true,\n\t\t\tnoThemes: true,\n\t\t\tnoContextFiles: true,\n\t\t});\n\t\tawait resourceLoader.reload();\n\t\tconst sessionManager = SessionManager.inMemory(tempDir, { id: FIXED_SESSION_ID });\n\t\tconst created = await createAgentSession({\n\t\t\tagentDir: tempDir,\n\t\t\tnoTools: \"all\",\n\t\t\t// Custom fixture tools must be allowlisted explicitly: noTools=\"all\"\n\t\t\t// clears the allowlist, which would otherwise leave them inactive.\n\t\t\t...(options.tools === undefined\n\t\t\t\t? {}\n\t\t\t\t: { tools: options.tools.map((tool) => tool.name), customTools: [...options.tools] }),\n\t\t\tdiscoverCapabilityPlugins: false,\n\t\t\tenableAgentTasks: false,\n\t\t\t...(options.runLoopStrategyName === undefined ? {} : { runLoopStrategyName: options.runLoopStrategyName }),\n\t\t\tstreamFn: streamSimple,\n\t\t\tmodel,\n\t\t\tmodelRuntime,\n\t\t\tresourceLoader,\n\t\t\tsessionManager,\n\t\t\tsettingsManager,\n\t\t\tcwd: tempDir,\n\t\t\tagentComposition: options.composition,\n\t\t}).then(({ session: createdSession }) => createdSession);\n\t\tsession = created;\n\t\tconst activeSession = session;\n\t\tconst initialRuntime = activeSession.getCapabilityRuntime();\n\t\tconst handles = new Map<string, CapabilityPluginHandle>();\n\t\tconst pluginByManifest = new Map(options.plugins.map((plugin) => [plugin.manifest, plugin]));\n\t\tlet closing = false;\n\t\tlet disposed = false;\n\t\tlet disposePromise: Promise<void> | undefined;\n\t\tconst cleanup = async (): Promise<void> => {\n\t\t\tconst failures: unknown[] = [];\n\t\t\tfor (const handle of [...handles.values()].reverse()) {\n\t\t\t\ttry {\n\t\t\t\t\tawait handle.dispose();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tfailures.push(error);\n\t\t\t\t}\n\t\t\t}\n\t\t\thandles.clear();\n\t\t\ttry {\n\t\t\t\tawait session?.dispose();\n\t\t\t} catch (error) {\n\t\t\t\tfailures.push(error);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tfaux?.unregister();\n\t\t\t\tawait rm(tempDir, { recursive: true, force: true });\n\t\t\t} catch (error) {\n\t\t\t\tfailures.push(error);\n\t\t\t}\n\t\t\tif (failures.length === 1) throw failures[0];\n\t\t\tif (failures.length > 1) throw new AggregateError(failures, \"Session plugin testkit cleanup failed\");\n\t\t};\n\t\tconst ready = (async () => {\n\t\t\ttry {\n\t\t\t\tfor (const manifest of resolvePluginCapabilityOrder(options.plugins.map((plugin) => plugin.manifest))) {\n\t\t\t\t\t// v8 ignore next -- kit 仅在 ready 成功后返回,startup 期间不会调用 dispose\n\t\t\t\t\tif (closing) throw new Error(\"Session plugin testkit was disposed during startup\");\n\t\t\t\t\tconst plugin = pluginByManifest.get(manifest);\n\t\t\t\t\t// v8 ignore next -- plugins 数组同时供给加载顺序与 factory 映射,必可解析\n\t\t\t\t\tif (!plugin) throw new Error(`Session plugin testkit cannot resolve factory: ${manifest.id}`);\n\t\t\t\t\tconst handle = await activeSession.loadCapabilityPlugin(manifest, plugin.factory);\n\t\t\t\t\thandles.set(manifest.id, handle);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tawait cleanup();\n\t\t\t\t} catch (cleanupError) {\n\t\t\t\t\tthrow new AggregateError([error, cleanupError], \"Session plugin testkit startup rollback failed\");\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t})();\n\t\tconst kit: SessionPluginTestKit = {\n\t\t\tready,\n\t\t\tsession: activeSession,\n\t\t\tagent: activeSession.agent,\n\t\t\tget runtime(): CapabilityRuntime {\n\t\t\t\tif (disposed) throw new Error(\"Session plugin testkit runtime is disposed\");\n\t\t\t\treturn activeSession.getCapabilityRuntime();\n\t\t\t},\n\t\t\tfaux: fauxRegistration,\n\t\t\tapi(pluginId) {\n\t\t\t\tif (activeSession.getCapabilityRuntime() !== initialRuntime) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Session plugin testkit plugin API handles expire after session reload; access the current runtime directly\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst handle = handles.get(pluginId);\n\t\t\t\tif (!handle) throw new Error(`Session plugin testkit has no loaded plugin: ${pluginId}`);\n\t\t\t\treturn handle.api;\n\t\t\t},\n\t\t\trevoke(pluginId) {\n\t\t\t\tif (activeSession.getCapabilityRuntime() !== initialRuntime) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Session plugin testkit plugin API handles expire after session reload; access the current runtime directly\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst handle = handles.get(pluginId);\n\t\t\t\tif (!handle) throw new Error(`Session plugin testkit has no loaded plugin: ${pluginId}`);\n\t\t\t\tactiveSession.getCapabilityRuntime().revokeAPI(handle.api);\n\t\t\t},\n\t\t\tassertResponsesConsumed() {\n\t\t\t\tconst pending = fauxRegistration.getPendingResponseCount();\n\t\t\t\tif (pending !== 0) {\n\t\t\t\t\tthrow new Error(`Session plugin testkit has ${pending} unused faux response${pending === 1 ? \"\" : \"s\"}`);\n\t\t\t\t}\n\t\t\t},\n\t\t\tinspect: () => activeSession.getCapabilityRuntime().inspect(),\n\t\t\ttranscript: () => {\n\t\t\t\tconst branch = sessionManager.getBranch();\n\t\t\t\tconst transcript: SessionPluginTestKitTranscript = {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tsessionId: sessionManager.getSessionId(),\n\t\t\t\t\trevision: sessionManager.getRevision().sequence,\n\t\t\t\t\tloadOrder: [...handles.keys()],\n\t\t\t\t\tfauxCallCount: fauxRegistration.state.callCount,\n\t\t\t\t\tmessages: activeSession.agent.state.messages.map((message) => ({\n\t\t\t\t\t\trole: message.role,\n\t\t\t\t\t\ttext: stableText(message),\n\t\t\t\t\t})),\n\t\t\t\t\tentries: branch.map((entry) => ({\n\t\t\t\t\t\ttype: entry.type,\n\t\t\t\t\t\t...(entry.type === \"custom\"\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tcustomType: entry.customType,\n\t\t\t\t\t\t\t\t\t...(entry.data === undefined ? {} : { data: transcriptValue(entry.data) }),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t})),\n\t\t\t\t\tinspector: stableInspector(activeSession.getCapabilityRuntime().inspect()),\n\t\t\t\t};\n\t\t\t\treturn freezeSnapshot(transcript);\n\t\t\t},\n\t\t\tdispose: async () => {\n\t\t\t\tdisposePromise ??= (async () => {\n\t\t\t\t\tclosing = true;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait ready;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Startup rollback already disposed the session and faux provider.\n\t\t\t\t\t\t// v8 ignore next -- ready 已在返回前 await,dispose 中不会进入该 catch\n\t\t\t\t\t\tif (session?.isDisposed) {\n\t\t\t\t\t\t\tdisposed = true;\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait cleanup();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tdisposed = true;\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t\treturn disposePromise;\n\t\t\t},\n\t\t};\n\t\tawait ready;\n\t\treturn kit;\n\t} catch (error) {\n\t\ttry {\n\t\t\tsession && (await session.dispose());\n\t\t} finally {\n\t\t\tfaux?.unregister();\n\t\t\tawait rm(tempDir, { recursive: true, force: true });\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** Runs a session fixture repeatedly and rejects on the first transcript divergence. */\nexport async function repeatSessionPluginTestKit(\n\ttimes: number,\n\trun: () => Promise<SessionPluginTestKitTranscript>,\n): Promise<SessionPluginTestKitTranscript> {\n\tif (!Number.isSafeInteger(times) || times < 1)\n\t\tthrow new Error(\"Session plugin testkit repeat count must be a positive integer\");\n\tlet baseline: SessionPluginTestKitTranscript | undefined;\n\tfor (let index = 0; index < times; index += 1) {\n\t\tconst transcript = await run();\n\t\tif (baseline && canonicalJson(transcript) !== canonicalJson(baseline)) {\n\t\t\tthrow new Error(`Session plugin testkit transcript diverged on run ${index + 1}`);\n\t\t}\n\t\tbaseline = transcript;\n\t}\n\treturn baseline!;\n}\n"]}
@@ -97,14 +97,21 @@ function canonicalJson(value) {
97
97
  return serialized;
98
98
  }
99
99
  /**
100
- * The host's agentDir is the fixture's mkdtemp path — environment-specific and
101
- * random per run, not a behavioral signal. Mask it so repeated-run transcript
102
- * comparisons stay deterministic (D-075 S4 added agentDir to HostCapabilities).
100
+ * The host's agentDir and workspaceDirectory are the fixture's mkdtemp paths —
101
+ * environment-specific and random per run, not a behavioral signal. Mask them
102
+ * so repeated-run transcript comparisons stay deterministic (D-075 S4 added
103
+ * agentDir to HostCapabilities; workspaceDirectory rides the same channel).
103
104
  */
104
105
  function normalizeInspectorHost(host) {
105
- if (typeof host.agentDir !== "string" || host.agentDir.length === 0)
106
+ if (host.agentDir === undefined && host.workspaceDirectory === undefined)
106
107
  return host;
107
- return { ...host, agentDir: "<agentDir>" };
108
+ return {
109
+ ...host,
110
+ ...(typeof host.agentDir === "string" && host.agentDir.length > 0 ? { agentDir: "<agentDir>" } : {}),
111
+ ...(typeof host.workspaceDirectory === "string" && host.workspaceDirectory.length > 0
112
+ ? { workspaceDirectory: "<workspaceDirectory>" }
113
+ : {}),
114
+ };
108
115
  }
109
116
  function stableInspector(snapshot) {
110
117
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"session-plugin-testkit.js","sourceRoot":"","sources":["../../src/testing/session-plugin-testkit.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Agent } from \"@agent-forge/agent-core\";\nimport {\n\ttype FauxProviderRegistration,\n\ttype FauxResponseStep,\n\tregisterFauxProvider,\n\tstreamSimple,\n} from \"@agent-forge/ai/compat\";\nimport type { AgentSession } from \"../core/agent-session.ts\";\nimport { AuthStorage } from \"../core/auth-storage.ts\";\nimport type { CapabilityPluginFactory, CapabilityPluginHandle } from \"../core/extensions/capability-plugin.ts\";\nimport { type CapabilityRuntime, resolvePluginCapabilityOrder } from \"../core/extensions/capability-runtime.ts\";\nimport type {\n\tAgentCompositionAPI,\n\tCapabilityAPI,\n\tHostCapabilities,\n\tPluginManifest,\n\tRuntimeInspectorSnapshot,\n} from \"../core/extensions/public-api.ts\";\nimport { ModelRuntime } from \"../core/model-runtime.ts\";\nimport { InMemoryCodingAgentModelsStore } from \"../core/models-store.ts\";\nimport { DefaultResourceLoader } from \"../core/resource-loader.ts\";\nimport { createAgentSession } from \"../core/sdk.ts\";\nimport { SessionManager } from \"../core/session-manager.ts\";\nimport { SettingsManager } from \"../core/settings-manager.ts\";\nimport type { ToolDefinition } from \"../core/tools/tool-definition.ts\";\n\nexport interface SessionPluginTestKitPlugin {\n\treadonly manifest: PluginManifest;\n\treadonly factory: CapabilityPluginFactory;\n}\n\nexport interface SessionPluginTestKitOptions {\n\treadonly plugins: readonly SessionPluginTestKitPlugin[];\n\treadonly responses?: readonly FauxResponseStep[];\n\treadonly providerId?: string;\n\treadonly api?: string;\n\treadonly composition?: AgentCompositionAPI;\n\t/** Custom tools registered on the fixture session for gated lifecycle scenarios. */\n\treadonly tools?: readonly ToolDefinition[];\n\t/** Post-run continuation strategy name selected through the public AgentSession config. */\n\treadonly runLoopStrategyName?: string;\n}\n\nexport interface SessionPluginTestKitInspector {\n\treadonly host: HostCapabilities;\n\treadonly plugins: readonly {\n\t\treadonly id: string;\n\t\treadonly version: string;\n\t\treadonly active: boolean;\n\t\treadonly provides: RuntimeInspectorSnapshot[\"plugins\"][number][\"provides\"];\n\t\treadonly requires: RuntimeInspectorSnapshot[\"plugins\"][number][\"requires\"];\n\t}[];\n\treadonly registrations: RuntimeInspectorSnapshot[\"registrations\"];\n\treadonly contributionPoints: readonly {\n\t\treadonly id: string;\n\t\treadonly version: number;\n\t\treadonly lifecycle: string;\n\t\treadonly owner: string;\n\t\treadonly active: boolean;\n\t}[];\n\treadonly contributions: readonly {\n\t\treadonly id: string;\n\t\treadonly pointId: string;\n\t\treadonly version: number;\n\t\treadonly owner: string;\n\t\treadonly lifecycle: string;\n\t}[];\n\treadonly lifecycle: readonly {\n\t\treadonly id: string;\n\t\treadonly version: number;\n\t\treadonly phase: string;\n\t\treadonly schema: string;\n\t\treadonly owner: string;\n\t\treadonly active: boolean;\n\t\treadonly registrations: readonly { readonly id: string; readonly kind: string; readonly owner: string }[];\n\t}[];\n\treadonly lifecycleReports: readonly {\n\t\treadonly eventId: string;\n\t\treadonly type: string;\n\t\treadonly version: number;\n\t\treadonly phase: string;\n\t\treadonly status: string;\n\t\treadonly attempted: number;\n\t\treadonly succeeded: number;\n\t\treadonly queued?: number;\n\t\treadonly failed: number;\n\t\treadonly failures: readonly {\n\t\t\treadonly pluginId: string;\n\t\t\treadonly registrationId: string;\n\t\t\treadonly kind: string;\n\t\t\treadonly error: unknown;\n\t\t}[];\n\t}[];\n\treadonly pluginRejections: RuntimeInspectorSnapshot[\"pluginRejections\"];\n\treadonly subscriptions: RuntimeInspectorSnapshot[\"subscriptions\"];\n\treadonly operations: RuntimeInspectorSnapshot[\"operations\"];\n\treadonly logs: readonly {\n\t\treadonly version: 1;\n\t\treadonly level: string;\n\t\treadonly message: string;\n\t\treadonly fields?: unknown;\n\t\treadonly cause?: unknown;\n\t\treadonly pluginId: string;\n\t\treadonly sessionId?: string;\n\t\treadonly operationId?: string;\n\t\treadonly correlationId?: string;\n\t\treadonly phase?: string;\n\t}[];\n\treadonly spans: readonly {\n\t\treadonly version: 1;\n\t\treadonly traceId: string;\n\t\treadonly spanId: string;\n\t\treadonly parentSpanId?: string;\n\t\treadonly name: string;\n\t\treadonly pluginId: string;\n\t\treadonly sessionId?: string;\n\t\treadonly status: string;\n\t\treadonly attributes: unknown;\n\t\treadonly result?: unknown;\n\t\treadonly cause?: unknown;\n\t\treadonly operationId?: string;\n\t\treadonly correlationId?: string;\n\t\treadonly phase?: string;\n\t}[];\n}\n\nexport interface SessionPluginTestKitTranscript {\n\treadonly version: 1;\n\treadonly sessionId: string;\n\treadonly revision: number;\n\treadonly loadOrder: readonly string[];\n\treadonly fauxCallCount: number;\n\treadonly messages: readonly { readonly role: string; readonly text: string }[];\n\treadonly entries: readonly { readonly type: string; readonly customType?: string; readonly data?: unknown }[];\n\treadonly inspector: SessionPluginTestKitInspector;\n}\n\nexport interface SessionPluginTestKit {\n\treadonly ready: Promise<void>;\n\treadonly session: AgentSession;\n\treadonly agent: Agent;\n\treadonly runtime: CapabilityRuntime;\n\treadonly faux: FauxProviderRegistration;\n\tapi(pluginId: string): CapabilityAPI;\n\trevoke(pluginId: string): void;\n\t/** Throws when a scripted response was not consumed by the fixture. */\n\tassertResponsesConsumed(): void;\n\tinspect(): RuntimeInspectorSnapshot;\n\ttranscript(): SessionPluginTestKitTranscript;\n\tdispose(): Promise<void>;\n}\n\nconst FIXED_SESSION_ID = \"session-plugin-testkit\";\nconst DEFAULT_PROVIDER_ID = \"faux-session-plugin-testkit\";\nconst DEFAULT_API = \"faux:session-plugin-testkit\";\n\nfunction stableText(message: unknown): string {\n\t// v8 ignore next -- 消息对象恒带 content 字段(AgentMessage 类型契约)\n\tif (!message || typeof message !== \"object\" || !(\"content\" in message)) return \"\";\n\tconst content = (message as { content?: unknown }).content;\n\t// v8 ignore next -- 助手消息的 content 恒为分段数组,字符串路径不会被命中\n\tif (typeof content === \"string\") return content;\n\t// v8 ignore next -- 同上:content 恒为数组\n\tif (!Array.isArray(content)) return \"\";\n\treturn content\n\t\t.filter((part): part is { type: \"text\"; text: string } => {\n\t\t\treturn (\n\t\t\t\ttypeof part === \"object\" &&\n\t\t\t\tpart !== null &&\n\t\t\t\t(part as { type?: unknown }).type === \"text\" &&\n\t\t\t\ttypeof (part as { text?: unknown }).text === \"string\"\n\t\t\t);\n\t\t})\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction freezeSnapshot<T>(value: T): T {\n\tconst clone = structuredClone(value);\n\tconst freeze = (candidate: unknown): void => {\n\t\tif (!candidate || typeof candidate !== \"object\" || ArrayBuffer.isView(candidate)) return;\n\t\tfor (const child of Object.values(candidate as Record<string, unknown>)) freeze(child);\n\t\tObject.freeze(candidate);\n\t};\n\tfreeze(clone);\n\treturn clone;\n}\n\nfunction transcriptValue(value: unknown, seen = new WeakSet<object>()): unknown {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") return value;\n\tif (typeof value === \"number\") return Number.isFinite(value) ? value : String(value);\n\tif (typeof value === \"bigint\") return `${value}n`;\n\tif (value === undefined) return null;\n\tif (value instanceof Error) {\n\t\t// v8 ignore next -- 错误经过 structuredClone 落盘,克隆体不可能形成循环引用\n\t\tif (seen.has(value)) return \"[Circular]\";\n\t\tseen.add(value);\n\t\tconst output: Record<string, unknown> = { name: value.name, message: value.message };\n\t\tconst code = (value as Error & { code?: unknown }).code;\n\t\tif (code !== undefined) output.code = transcriptValue(code, seen);\n\t\tconst cause = (value as Error & { cause?: unknown }).cause;\n\t\tif (cause !== undefined) output.cause = transcriptValue(cause, seen);\n\t\tfor (const key of Object.keys(value).sort()) {\n\t\t\tif (key === \"code\" || key === \"cause\") continue;\n\t\t\toutput[key] = transcriptValue((value as unknown as Record<string, unknown>)[key], seen);\n\t\t}\n\t\treturn output;\n\t}\n\t// v8 ignore next -- 值均来自 structuredClone 克隆,函数/符号无法存活\n\tif (typeof value !== \"object\") return String(value);\n\t// v8 ignore next -- 同上:克隆后的对象图无循环引用\n\tif (seen.has(value)) return \"[Circular]\";\n\tseen.add(value);\n\tif (Array.isArray(value)) return value.map((item) => transcriptValue(item, seen));\n\tconst output: Record<string, unknown> = {};\n\tfor (const key of Object.keys(value as Record<string, unknown>).sort()) {\n\t\toutput[key] = transcriptValue((value as Record<string, unknown>)[key], seen);\n\t}\n\treturn output;\n}\n\nfunction canonicalJson(value: unknown): string {\n\tconst serialized = JSON.stringify(transcriptValue(value));\n\t// v8 ignore next -- transcriptValue 已消毒全部值,JSON.stringify 不会返回 undefined\n\tif (serialized === undefined) throw new Error(\"Session plugin testkit transcript is not JSON-serializable\");\n\treturn serialized;\n}\n\n/**\n * The host's agentDir is the fixture's mkdtemp path — environment-specific and\n * random per run, not a behavioral signal. Mask it so repeated-run transcript\n * comparisons stay deterministic (D-075 S4 added agentDir to HostCapabilities).\n */\nfunction normalizeInspectorHost(host: HostCapabilities): HostCapabilities {\n\tif (typeof host.agentDir !== \"string\" || host.agentDir.length === 0) return host;\n\treturn { ...host, agentDir: \"<agentDir>\" };\n}\n\nfunction stableInspector(snapshot: RuntimeInspectorSnapshot): SessionPluginTestKitInspector {\n\treturn {\n\t\thost: normalizeInspectorHost(snapshot.host),\n\t\tplugins: snapshot.plugins.map(({ id, version, active, provides, requires }) => ({\n\t\t\tid,\n\t\t\tversion,\n\t\t\tactive,\n\t\t\tprovides,\n\t\t\trequires,\n\t\t})),\n\t\tregistrations: snapshot.registrations,\n\t\tcontributionPoints: snapshot.contributionPoints.map(({ id, version, lifecycle, owner, active }) => ({\n\t\t\tid,\n\t\t\tversion,\n\t\t\tlifecycle,\n\t\t\towner,\n\t\t\tactive,\n\t\t})),\n\t\tcontributions: snapshot.contributions.map(({ id, pointId, version, owner, lifecycle }) => ({\n\t\t\tid,\n\t\t\tpointId,\n\t\t\tversion,\n\t\t\towner,\n\t\t\tlifecycle,\n\t\t})),\n\t\tlifecycle: snapshot.lifecycle.map(({ id, version, phase, schema, owner, active, registrations }) => ({\n\t\t\tid,\n\t\t\tversion,\n\t\t\tphase,\n\t\t\tschema,\n\t\t\towner,\n\t\t\tactive,\n\t\t\tregistrations,\n\t\t})),\n\t\tlifecycleReports: snapshot.lifecycleReports.map(\n\t\t\t({ eventId, type, version, phase, status, attempted, succeeded, failed, failures }) => ({\n\t\t\t\teventId,\n\t\t\t\ttype,\n\t\t\t\tversion,\n\t\t\t\tphase,\n\t\t\t\tstatus,\n\t\t\t\tattempted,\n\t\t\t\tsucceeded,\n\t\t\t\tfailed,\n\t\t\t\tfailures: failures.map(({ pluginId, registrationId, kind, error }) => ({\n\t\t\t\t\tpluginId,\n\t\t\t\t\tregistrationId,\n\t\t\t\t\tkind,\n\t\t\t\t\terror: transcriptValue(error),\n\t\t\t\t})),\n\t\t\t}),\n\t\t),\n\t\tpluginRejections: snapshot.pluginRejections,\n\t\tsubscriptions: snapshot.subscriptions,\n\t\toperations: snapshot.operations,\n\t\tlogs: snapshot.logs.map(\n\t\t\t({ version, level, message, fields, cause, pluginId, sessionId, operationId, correlationId, phase }) => ({\n\t\t\t\tversion,\n\t\t\t\tlevel,\n\t\t\t\tmessage,\n\t\t\t\t...(fields === undefined ? {} : { fields: transcriptValue(fields) }),\n\t\t\t\t...(cause === undefined ? {} : { cause: transcriptValue(cause) }),\n\t\t\t\tpluginId,\n\t\t\t\t...(sessionId === undefined ? {} : { sessionId }),\n\t\t\t\t...(operationId === undefined ? {} : { operationId }),\n\t\t\t\t...(correlationId === undefined ? {} : { correlationId }),\n\t\t\t\t...(phase === undefined ? {} : { phase }),\n\t\t\t}),\n\t\t),\n\t\tspans: snapshot.spans.map(\n\t\t\t({\n\t\t\t\tversion,\n\t\t\t\ttraceId,\n\t\t\t\tspanId,\n\t\t\t\tparentSpanId,\n\t\t\t\tname,\n\t\t\t\tpluginId,\n\t\t\t\tsessionId,\n\t\t\t\tstatus,\n\t\t\t\tattributes,\n\t\t\t\tresult,\n\t\t\t\tcause,\n\t\t\t\toperationId,\n\t\t\t\tcorrelationId,\n\t\t\t\tphase,\n\t\t\t}) => ({\n\t\t\t\tversion,\n\t\t\t\ttraceId,\n\t\t\t\tspanId,\n\t\t\t\t...(parentSpanId === undefined ? {} : { parentSpanId }),\n\t\t\t\tname,\n\t\t\t\tpluginId,\n\t\t\t\t...(sessionId === undefined ? {} : { sessionId }),\n\t\t\t\tattributes: transcriptValue(attributes),\n\t\t\t\tstatus,\n\t\t\t\t...(result === undefined ? {} : { result: transcriptValue(result) }),\n\t\t\t\t...(cause === undefined ? {} : { cause: transcriptValue(cause) }),\n\t\t\t\t...(operationId === undefined ? {} : { operationId }),\n\t\t\t\t...(correlationId === undefined ? {} : { correlationId }),\n\t\t\t\t...(phase === undefined ? {} : { phase }),\n\t\t\t}),\n\t\t),\n\t};\n}\n\nfunction modelConfig(model: {\n\tid: string;\n\tname: string;\n\tapi: string;\n\tprovider: string;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: readonly (\"text\" | \"image\")[];\n\tcost: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\tcontextWindow: number;\n\tmaxTokens: number;\n}) {\n\treturn {\n\t\tid: model.id,\n\t\tname: model.name,\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tbaseUrl: model.baseUrl,\n\t\treasoning: model.reasoning,\n\t\tinput: [...model.input],\n\t\tcost: model.cost,\n\t\tcontextWindow: model.contextWindow,\n\t\tmaxTokens: model.maxTokens,\n\t};\n}\n\n/** Create a complete deterministic AgentSession fixture and load inline capability plugins. */\nexport async function createSessionPluginTestKit(options: SessionPluginTestKitOptions): Promise<SessionPluginTestKit> {\n\tconst tempDir = await mkdtemp(join(tmpdir(), \"agent-forge-session-plugin-testkit-\"));\n\tconst providerId = options.providerId ?? DEFAULT_PROVIDER_ID;\n\tconst apiName = options.api ?? DEFAULT_API;\n\tlet faux: FauxProviderRegistration | undefined;\n\tlet session: AgentSession | undefined;\n\ttry {\n\t\tfaux = registerFauxProvider({\n\t\t\tapi: apiName,\n\t\t\tprovider: providerId,\n\t\t\tclock: () => 0,\n\t\t\tidFactory: (prefix, sequence) => `${prefix}-${sequence}`,\n\t\t});\n\t\tif (options.responses) faux.setResponses([...options.responses]);\n\t\tconst fauxRegistration = faux;\n\t\tconst model = fauxRegistration.getModel();\n\t\tconst authStorage = AuthStorage.inMemory();\n\t\tawait authStorage.modify(providerId, async () => ({ type: \"api_key\", key: \"faux-key\" }));\n\t\tconst modelRuntime = await ModelRuntime.create({\n\t\t\tcredentials: authStorage,\n\t\t\tmodelsPath: null,\n\t\t\tmodelsStore: new InMemoryCodingAgentModelsStore(),\n\t\t\tallowModelNetwork: false,\n\t\t\trefreshOnCreate: false,\n\t\t});\n\t\tmodelRuntime.registerProvider(providerId, {\n\t\t\tbaseUrl: model.baseUrl,\n\t\t\tapi: apiName,\n\t\t\tapiKey: \"faux-key\",\n\t\t\tmodels: fauxRegistration.models.map(modelConfig),\n\t\t});\n\t\tconst settingsManager = SettingsManager.create(tempDir, tempDir);\n\t\tconst resourceLoader = new DefaultResourceLoader({\n\t\t\tcwd: tempDir,\n\t\t\tagentDir: tempDir,\n\t\t\tsettingsManager,\n\t\t\tnoSkills: true,\n\t\t\tnoPromptTemplates: true,\n\t\t\tnoThemes: true,\n\t\t\tnoContextFiles: true,\n\t\t});\n\t\tawait resourceLoader.reload();\n\t\tconst sessionManager = SessionManager.inMemory(tempDir, { id: FIXED_SESSION_ID });\n\t\tconst created = await createAgentSession({\n\t\t\tagentDir: tempDir,\n\t\t\tnoTools: \"all\",\n\t\t\t// Custom fixture tools must be allowlisted explicitly: noTools=\"all\"\n\t\t\t// clears the allowlist, which would otherwise leave them inactive.\n\t\t\t...(options.tools === undefined\n\t\t\t\t? {}\n\t\t\t\t: { tools: options.tools.map((tool) => tool.name), customTools: [...options.tools] }),\n\t\t\tdiscoverCapabilityPlugins: false,\n\t\t\tenableAgentTasks: false,\n\t\t\t...(options.runLoopStrategyName === undefined ? {} : { runLoopStrategyName: options.runLoopStrategyName }),\n\t\t\tstreamFn: streamSimple,\n\t\t\tmodel,\n\t\t\tmodelRuntime,\n\t\t\tresourceLoader,\n\t\t\tsessionManager,\n\t\t\tsettingsManager,\n\t\t\tcwd: tempDir,\n\t\t\tagentComposition: options.composition,\n\t\t}).then(({ session: createdSession }) => createdSession);\n\t\tsession = created;\n\t\tconst activeSession = session;\n\t\tconst initialRuntime = activeSession.getCapabilityRuntime();\n\t\tconst handles = new Map<string, CapabilityPluginHandle>();\n\t\tconst pluginByManifest = new Map(options.plugins.map((plugin) => [plugin.manifest, plugin]));\n\t\tlet closing = false;\n\t\tlet disposed = false;\n\t\tlet disposePromise: Promise<void> | undefined;\n\t\tconst cleanup = async (): Promise<void> => {\n\t\t\tconst failures: unknown[] = [];\n\t\t\tfor (const handle of [...handles.values()].reverse()) {\n\t\t\t\ttry {\n\t\t\t\t\tawait handle.dispose();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tfailures.push(error);\n\t\t\t\t}\n\t\t\t}\n\t\t\thandles.clear();\n\t\t\ttry {\n\t\t\t\tawait session?.dispose();\n\t\t\t} catch (error) {\n\t\t\t\tfailures.push(error);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tfaux?.unregister();\n\t\t\t\tawait rm(tempDir, { recursive: true, force: true });\n\t\t\t} catch (error) {\n\t\t\t\tfailures.push(error);\n\t\t\t}\n\t\t\tif (failures.length === 1) throw failures[0];\n\t\t\tif (failures.length > 1) throw new AggregateError(failures, \"Session plugin testkit cleanup failed\");\n\t\t};\n\t\tconst ready = (async () => {\n\t\t\ttry {\n\t\t\t\tfor (const manifest of resolvePluginCapabilityOrder(options.plugins.map((plugin) => plugin.manifest))) {\n\t\t\t\t\t// v8 ignore next -- kit 仅在 ready 成功后返回,startup 期间不会调用 dispose\n\t\t\t\t\tif (closing) throw new Error(\"Session plugin testkit was disposed during startup\");\n\t\t\t\t\tconst plugin = pluginByManifest.get(manifest);\n\t\t\t\t\t// v8 ignore next -- plugins 数组同时供给加载顺序与 factory 映射,必可解析\n\t\t\t\t\tif (!plugin) throw new Error(`Session plugin testkit cannot resolve factory: ${manifest.id}`);\n\t\t\t\t\tconst handle = await activeSession.loadCapabilityPlugin(manifest, plugin.factory);\n\t\t\t\t\thandles.set(manifest.id, handle);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tawait cleanup();\n\t\t\t\t} catch (cleanupError) {\n\t\t\t\t\tthrow new AggregateError([error, cleanupError], \"Session plugin testkit startup rollback failed\");\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t})();\n\t\tconst kit: SessionPluginTestKit = {\n\t\t\tready,\n\t\t\tsession: activeSession,\n\t\t\tagent: activeSession.agent,\n\t\t\tget runtime(): CapabilityRuntime {\n\t\t\t\tif (disposed) throw new Error(\"Session plugin testkit runtime is disposed\");\n\t\t\t\treturn activeSession.getCapabilityRuntime();\n\t\t\t},\n\t\t\tfaux: fauxRegistration,\n\t\t\tapi(pluginId) {\n\t\t\t\tif (activeSession.getCapabilityRuntime() !== initialRuntime) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Session plugin testkit plugin API handles expire after session reload; access the current runtime directly\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst handle = handles.get(pluginId);\n\t\t\t\tif (!handle) throw new Error(`Session plugin testkit has no loaded plugin: ${pluginId}`);\n\t\t\t\treturn handle.api;\n\t\t\t},\n\t\t\trevoke(pluginId) {\n\t\t\t\tif (activeSession.getCapabilityRuntime() !== initialRuntime) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Session plugin testkit plugin API handles expire after session reload; access the current runtime directly\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst handle = handles.get(pluginId);\n\t\t\t\tif (!handle) throw new Error(`Session plugin testkit has no loaded plugin: ${pluginId}`);\n\t\t\t\tactiveSession.getCapabilityRuntime().revokeAPI(handle.api);\n\t\t\t},\n\t\t\tassertResponsesConsumed() {\n\t\t\t\tconst pending = fauxRegistration.getPendingResponseCount();\n\t\t\t\tif (pending !== 0) {\n\t\t\t\t\tthrow new Error(`Session plugin testkit has ${pending} unused faux response${pending === 1 ? \"\" : \"s\"}`);\n\t\t\t\t}\n\t\t\t},\n\t\t\tinspect: () => activeSession.getCapabilityRuntime().inspect(),\n\t\t\ttranscript: () => {\n\t\t\t\tconst branch = sessionManager.getBranch();\n\t\t\t\tconst transcript: SessionPluginTestKitTranscript = {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tsessionId: sessionManager.getSessionId(),\n\t\t\t\t\trevision: sessionManager.getRevision().sequence,\n\t\t\t\t\tloadOrder: [...handles.keys()],\n\t\t\t\t\tfauxCallCount: fauxRegistration.state.callCount,\n\t\t\t\t\tmessages: activeSession.agent.state.messages.map((message) => ({\n\t\t\t\t\t\trole: message.role,\n\t\t\t\t\t\ttext: stableText(message),\n\t\t\t\t\t})),\n\t\t\t\t\tentries: branch.map((entry) => ({\n\t\t\t\t\t\ttype: entry.type,\n\t\t\t\t\t\t...(entry.type === \"custom\"\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tcustomType: entry.customType,\n\t\t\t\t\t\t\t\t\t...(entry.data === undefined ? {} : { data: transcriptValue(entry.data) }),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t})),\n\t\t\t\t\tinspector: stableInspector(activeSession.getCapabilityRuntime().inspect()),\n\t\t\t\t};\n\t\t\t\treturn freezeSnapshot(transcript);\n\t\t\t},\n\t\t\tdispose: async () => {\n\t\t\t\tdisposePromise ??= (async () => {\n\t\t\t\t\tclosing = true;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait ready;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Startup rollback already disposed the session and faux provider.\n\t\t\t\t\t\t// v8 ignore next -- ready 已在返回前 await,dispose 中不会进入该 catch\n\t\t\t\t\t\tif (session?.isDisposed) {\n\t\t\t\t\t\t\tdisposed = true;\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait cleanup();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tdisposed = true;\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t\treturn disposePromise;\n\t\t\t},\n\t\t};\n\t\tawait ready;\n\t\treturn kit;\n\t} catch (error) {\n\t\ttry {\n\t\t\tsession && (await session.dispose());\n\t\t} finally {\n\t\t\tfaux?.unregister();\n\t\t\tawait rm(tempDir, { recursive: true, force: true });\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** Runs a session fixture repeatedly and rejects on the first transcript divergence. */\nexport async function repeatSessionPluginTestKit(\n\ttimes: number,\n\trun: () => Promise<SessionPluginTestKitTranscript>,\n): Promise<SessionPluginTestKitTranscript> {\n\tif (!Number.isSafeInteger(times) || times < 1)\n\t\tthrow new Error(\"Session plugin testkit repeat count must be a positive integer\");\n\tlet baseline: SessionPluginTestKitTranscript | undefined;\n\tfor (let index = 0; index < times; index += 1) {\n\t\tconst transcript = await run();\n\t\tif (baseline && canonicalJson(transcript) !== canonicalJson(baseline)) {\n\t\t\tthrow new Error(`Session plugin testkit transcript diverged on run ${index + 1}`);\n\t\t}\n\t\tbaseline = transcript;\n\t}\n\treturn baseline!;\n}\n"]}
1
+ {"version":3,"file":"session-plugin-testkit.js","sourceRoot":"","sources":["../../src/testing/session-plugin-testkit.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { Agent } from \"@agent-forge/agent-core\";\nimport {\n\ttype FauxProviderRegistration,\n\ttype FauxResponseStep,\n\tregisterFauxProvider,\n\tstreamSimple,\n} from \"@agent-forge/ai/compat\";\nimport type { AgentSession } from \"../core/agent-session.ts\";\nimport { AuthStorage } from \"../core/auth-storage.ts\";\nimport type { CapabilityPluginFactory, CapabilityPluginHandle } from \"../core/extensions/capability-plugin.ts\";\nimport { type CapabilityRuntime, resolvePluginCapabilityOrder } from \"../core/extensions/capability-runtime.ts\";\nimport type {\n\tAgentCompositionAPI,\n\tCapabilityAPI,\n\tHostCapabilities,\n\tPluginManifest,\n\tRuntimeInspectorSnapshot,\n} from \"../core/extensions/public-api.ts\";\nimport { ModelRuntime } from \"../core/model-runtime.ts\";\nimport { InMemoryCodingAgentModelsStore } from \"../core/models-store.ts\";\nimport { DefaultResourceLoader } from \"../core/resource-loader.ts\";\nimport { createAgentSession } from \"../core/sdk.ts\";\nimport { SessionManager } from \"../core/session-manager.ts\";\nimport { SettingsManager } from \"../core/settings-manager.ts\";\nimport type { ToolDefinition } from \"../core/tools/tool-definition.ts\";\n\nexport interface SessionPluginTestKitPlugin {\n\treadonly manifest: PluginManifest;\n\treadonly factory: CapabilityPluginFactory;\n}\n\nexport interface SessionPluginTestKitOptions {\n\treadonly plugins: readonly SessionPluginTestKitPlugin[];\n\treadonly responses?: readonly FauxResponseStep[];\n\treadonly providerId?: string;\n\treadonly api?: string;\n\treadonly composition?: AgentCompositionAPI;\n\t/** Custom tools registered on the fixture session for gated lifecycle scenarios. */\n\treadonly tools?: readonly ToolDefinition[];\n\t/** Post-run continuation strategy name selected through the public AgentSession config. */\n\treadonly runLoopStrategyName?: string;\n}\n\nexport interface SessionPluginTestKitInspector {\n\treadonly host: HostCapabilities;\n\treadonly plugins: readonly {\n\t\treadonly id: string;\n\t\treadonly version: string;\n\t\treadonly active: boolean;\n\t\treadonly provides: RuntimeInspectorSnapshot[\"plugins\"][number][\"provides\"];\n\t\treadonly requires: RuntimeInspectorSnapshot[\"plugins\"][number][\"requires\"];\n\t}[];\n\treadonly registrations: RuntimeInspectorSnapshot[\"registrations\"];\n\treadonly contributionPoints: readonly {\n\t\treadonly id: string;\n\t\treadonly version: number;\n\t\treadonly lifecycle: string;\n\t\treadonly owner: string;\n\t\treadonly active: boolean;\n\t}[];\n\treadonly contributions: readonly {\n\t\treadonly id: string;\n\t\treadonly pointId: string;\n\t\treadonly version: number;\n\t\treadonly owner: string;\n\t\treadonly lifecycle: string;\n\t}[];\n\treadonly lifecycle: readonly {\n\t\treadonly id: string;\n\t\treadonly version: number;\n\t\treadonly phase: string;\n\t\treadonly schema: string;\n\t\treadonly owner: string;\n\t\treadonly active: boolean;\n\t\treadonly registrations: readonly { readonly id: string; readonly kind: string; readonly owner: string }[];\n\t}[];\n\treadonly lifecycleReports: readonly {\n\t\treadonly eventId: string;\n\t\treadonly type: string;\n\t\treadonly version: number;\n\t\treadonly phase: string;\n\t\treadonly status: string;\n\t\treadonly attempted: number;\n\t\treadonly succeeded: number;\n\t\treadonly queued?: number;\n\t\treadonly failed: number;\n\t\treadonly failures: readonly {\n\t\t\treadonly pluginId: string;\n\t\t\treadonly registrationId: string;\n\t\t\treadonly kind: string;\n\t\t\treadonly error: unknown;\n\t\t}[];\n\t}[];\n\treadonly pluginRejections: RuntimeInspectorSnapshot[\"pluginRejections\"];\n\treadonly subscriptions: RuntimeInspectorSnapshot[\"subscriptions\"];\n\treadonly operations: RuntimeInspectorSnapshot[\"operations\"];\n\treadonly logs: readonly {\n\t\treadonly version: 1;\n\t\treadonly level: string;\n\t\treadonly message: string;\n\t\treadonly fields?: unknown;\n\t\treadonly cause?: unknown;\n\t\treadonly pluginId: string;\n\t\treadonly sessionId?: string;\n\t\treadonly operationId?: string;\n\t\treadonly correlationId?: string;\n\t\treadonly phase?: string;\n\t}[];\n\treadonly spans: readonly {\n\t\treadonly version: 1;\n\t\treadonly traceId: string;\n\t\treadonly spanId: string;\n\t\treadonly parentSpanId?: string;\n\t\treadonly name: string;\n\t\treadonly pluginId: string;\n\t\treadonly sessionId?: string;\n\t\treadonly status: string;\n\t\treadonly attributes: unknown;\n\t\treadonly result?: unknown;\n\t\treadonly cause?: unknown;\n\t\treadonly operationId?: string;\n\t\treadonly correlationId?: string;\n\t\treadonly phase?: string;\n\t}[];\n}\n\nexport interface SessionPluginTestKitTranscript {\n\treadonly version: 1;\n\treadonly sessionId: string;\n\treadonly revision: number;\n\treadonly loadOrder: readonly string[];\n\treadonly fauxCallCount: number;\n\treadonly messages: readonly { readonly role: string; readonly text: string }[];\n\treadonly entries: readonly { readonly type: string; readonly customType?: string; readonly data?: unknown }[];\n\treadonly inspector: SessionPluginTestKitInspector;\n}\n\nexport interface SessionPluginTestKit {\n\treadonly ready: Promise<void>;\n\treadonly session: AgentSession;\n\treadonly agent: Agent;\n\treadonly runtime: CapabilityRuntime;\n\treadonly faux: FauxProviderRegistration;\n\tapi(pluginId: string): CapabilityAPI;\n\trevoke(pluginId: string): void;\n\t/** Throws when a scripted response was not consumed by the fixture. */\n\tassertResponsesConsumed(): void;\n\tinspect(): RuntimeInspectorSnapshot;\n\ttranscript(): SessionPluginTestKitTranscript;\n\tdispose(): Promise<void>;\n}\n\nconst FIXED_SESSION_ID = \"session-plugin-testkit\";\nconst DEFAULT_PROVIDER_ID = \"faux-session-plugin-testkit\";\nconst DEFAULT_API = \"faux:session-plugin-testkit\";\n\nfunction stableText(message: unknown): string {\n\t// v8 ignore next -- 消息对象恒带 content 字段(AgentMessage 类型契约)\n\tif (!message || typeof message !== \"object\" || !(\"content\" in message)) return \"\";\n\tconst content = (message as { content?: unknown }).content;\n\t// v8 ignore next -- 助手消息的 content 恒为分段数组,字符串路径不会被命中\n\tif (typeof content === \"string\") return content;\n\t// v8 ignore next -- 同上:content 恒为数组\n\tif (!Array.isArray(content)) return \"\";\n\treturn content\n\t\t.filter((part): part is { type: \"text\"; text: string } => {\n\t\t\treturn (\n\t\t\t\ttypeof part === \"object\" &&\n\t\t\t\tpart !== null &&\n\t\t\t\t(part as { type?: unknown }).type === \"text\" &&\n\t\t\t\ttypeof (part as { text?: unknown }).text === \"string\"\n\t\t\t);\n\t\t})\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction freezeSnapshot<T>(value: T): T {\n\tconst clone = structuredClone(value);\n\tconst freeze = (candidate: unknown): void => {\n\t\tif (!candidate || typeof candidate !== \"object\" || ArrayBuffer.isView(candidate)) return;\n\t\tfor (const child of Object.values(candidate as Record<string, unknown>)) freeze(child);\n\t\tObject.freeze(candidate);\n\t};\n\tfreeze(clone);\n\treturn clone;\n}\n\nfunction transcriptValue(value: unknown, seen = new WeakSet<object>()): unknown {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") return value;\n\tif (typeof value === \"number\") return Number.isFinite(value) ? value : String(value);\n\tif (typeof value === \"bigint\") return `${value}n`;\n\tif (value === undefined) return null;\n\tif (value instanceof Error) {\n\t\t// v8 ignore next -- 错误经过 structuredClone 落盘,克隆体不可能形成循环引用\n\t\tif (seen.has(value)) return \"[Circular]\";\n\t\tseen.add(value);\n\t\tconst output: Record<string, unknown> = { name: value.name, message: value.message };\n\t\tconst code = (value as Error & { code?: unknown }).code;\n\t\tif (code !== undefined) output.code = transcriptValue(code, seen);\n\t\tconst cause = (value as Error & { cause?: unknown }).cause;\n\t\tif (cause !== undefined) output.cause = transcriptValue(cause, seen);\n\t\tfor (const key of Object.keys(value).sort()) {\n\t\t\tif (key === \"code\" || key === \"cause\") continue;\n\t\t\toutput[key] = transcriptValue((value as unknown as Record<string, unknown>)[key], seen);\n\t\t}\n\t\treturn output;\n\t}\n\t// v8 ignore next -- 值均来自 structuredClone 克隆,函数/符号无法存活\n\tif (typeof value !== \"object\") return String(value);\n\t// v8 ignore next -- 同上:克隆后的对象图无循环引用\n\tif (seen.has(value)) return \"[Circular]\";\n\tseen.add(value);\n\tif (Array.isArray(value)) return value.map((item) => transcriptValue(item, seen));\n\tconst output: Record<string, unknown> = {};\n\tfor (const key of Object.keys(value as Record<string, unknown>).sort()) {\n\t\toutput[key] = transcriptValue((value as Record<string, unknown>)[key], seen);\n\t}\n\treturn output;\n}\n\nfunction canonicalJson(value: unknown): string {\n\tconst serialized = JSON.stringify(transcriptValue(value));\n\t// v8 ignore next -- transcriptValue 已消毒全部值,JSON.stringify 不会返回 undefined\n\tif (serialized === undefined) throw new Error(\"Session plugin testkit transcript is not JSON-serializable\");\n\treturn serialized;\n}\n\n/**\n * The host's agentDir and workspaceDirectory are the fixture's mkdtemp paths —\n * environment-specific and random per run, not a behavioral signal. Mask them\n * so repeated-run transcript comparisons stay deterministic (D-075 S4 added\n * agentDir to HostCapabilities; workspaceDirectory rides the same channel).\n */\nfunction normalizeInspectorHost(host: HostCapabilities): HostCapabilities {\n\tif (host.agentDir === undefined && host.workspaceDirectory === undefined) return host;\n\treturn {\n\t\t...host,\n\t\t...(typeof host.agentDir === \"string\" && host.agentDir.length > 0 ? { agentDir: \"<agentDir>\" } : {}),\n\t\t...(typeof host.workspaceDirectory === \"string\" && host.workspaceDirectory.length > 0\n\t\t\t? { workspaceDirectory: \"<workspaceDirectory>\" }\n\t\t\t: {}),\n\t};\n}\n\nfunction stableInspector(snapshot: RuntimeInspectorSnapshot): SessionPluginTestKitInspector {\n\treturn {\n\t\thost: normalizeInspectorHost(snapshot.host),\n\t\tplugins: snapshot.plugins.map(({ id, version, active, provides, requires }) => ({\n\t\t\tid,\n\t\t\tversion,\n\t\t\tactive,\n\t\t\tprovides,\n\t\t\trequires,\n\t\t})),\n\t\tregistrations: snapshot.registrations,\n\t\tcontributionPoints: snapshot.contributionPoints.map(({ id, version, lifecycle, owner, active }) => ({\n\t\t\tid,\n\t\t\tversion,\n\t\t\tlifecycle,\n\t\t\towner,\n\t\t\tactive,\n\t\t})),\n\t\tcontributions: snapshot.contributions.map(({ id, pointId, version, owner, lifecycle }) => ({\n\t\t\tid,\n\t\t\tpointId,\n\t\t\tversion,\n\t\t\towner,\n\t\t\tlifecycle,\n\t\t})),\n\t\tlifecycle: snapshot.lifecycle.map(({ id, version, phase, schema, owner, active, registrations }) => ({\n\t\t\tid,\n\t\t\tversion,\n\t\t\tphase,\n\t\t\tschema,\n\t\t\towner,\n\t\t\tactive,\n\t\t\tregistrations,\n\t\t})),\n\t\tlifecycleReports: snapshot.lifecycleReports.map(\n\t\t\t({ eventId, type, version, phase, status, attempted, succeeded, failed, failures }) => ({\n\t\t\t\teventId,\n\t\t\t\ttype,\n\t\t\t\tversion,\n\t\t\t\tphase,\n\t\t\t\tstatus,\n\t\t\t\tattempted,\n\t\t\t\tsucceeded,\n\t\t\t\tfailed,\n\t\t\t\tfailures: failures.map(({ pluginId, registrationId, kind, error }) => ({\n\t\t\t\t\tpluginId,\n\t\t\t\t\tregistrationId,\n\t\t\t\t\tkind,\n\t\t\t\t\terror: transcriptValue(error),\n\t\t\t\t})),\n\t\t\t}),\n\t\t),\n\t\tpluginRejections: snapshot.pluginRejections,\n\t\tsubscriptions: snapshot.subscriptions,\n\t\toperations: snapshot.operations,\n\t\tlogs: snapshot.logs.map(\n\t\t\t({ version, level, message, fields, cause, pluginId, sessionId, operationId, correlationId, phase }) => ({\n\t\t\t\tversion,\n\t\t\t\tlevel,\n\t\t\t\tmessage,\n\t\t\t\t...(fields === undefined ? {} : { fields: transcriptValue(fields) }),\n\t\t\t\t...(cause === undefined ? {} : { cause: transcriptValue(cause) }),\n\t\t\t\tpluginId,\n\t\t\t\t...(sessionId === undefined ? {} : { sessionId }),\n\t\t\t\t...(operationId === undefined ? {} : { operationId }),\n\t\t\t\t...(correlationId === undefined ? {} : { correlationId }),\n\t\t\t\t...(phase === undefined ? {} : { phase }),\n\t\t\t}),\n\t\t),\n\t\tspans: snapshot.spans.map(\n\t\t\t({\n\t\t\t\tversion,\n\t\t\t\ttraceId,\n\t\t\t\tspanId,\n\t\t\t\tparentSpanId,\n\t\t\t\tname,\n\t\t\t\tpluginId,\n\t\t\t\tsessionId,\n\t\t\t\tstatus,\n\t\t\t\tattributes,\n\t\t\t\tresult,\n\t\t\t\tcause,\n\t\t\t\toperationId,\n\t\t\t\tcorrelationId,\n\t\t\t\tphase,\n\t\t\t}) => ({\n\t\t\t\tversion,\n\t\t\t\ttraceId,\n\t\t\t\tspanId,\n\t\t\t\t...(parentSpanId === undefined ? {} : { parentSpanId }),\n\t\t\t\tname,\n\t\t\t\tpluginId,\n\t\t\t\t...(sessionId === undefined ? {} : { sessionId }),\n\t\t\t\tattributes: transcriptValue(attributes),\n\t\t\t\tstatus,\n\t\t\t\t...(result === undefined ? {} : { result: transcriptValue(result) }),\n\t\t\t\t...(cause === undefined ? {} : { cause: transcriptValue(cause) }),\n\t\t\t\t...(operationId === undefined ? {} : { operationId }),\n\t\t\t\t...(correlationId === undefined ? {} : { correlationId }),\n\t\t\t\t...(phase === undefined ? {} : { phase }),\n\t\t\t}),\n\t\t),\n\t};\n}\n\nfunction modelConfig(model: {\n\tid: string;\n\tname: string;\n\tapi: string;\n\tprovider: string;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: readonly (\"text\" | \"image\")[];\n\tcost: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\tcontextWindow: number;\n\tmaxTokens: number;\n}) {\n\treturn {\n\t\tid: model.id,\n\t\tname: model.name,\n\t\tapi: model.api,\n\t\tprovider: model.provider,\n\t\tbaseUrl: model.baseUrl,\n\t\treasoning: model.reasoning,\n\t\tinput: [...model.input],\n\t\tcost: model.cost,\n\t\tcontextWindow: model.contextWindow,\n\t\tmaxTokens: model.maxTokens,\n\t};\n}\n\n/** Create a complete deterministic AgentSession fixture and load inline capability plugins. */\nexport async function createSessionPluginTestKit(options: SessionPluginTestKitOptions): Promise<SessionPluginTestKit> {\n\tconst tempDir = await mkdtemp(join(tmpdir(), \"agent-forge-session-plugin-testkit-\"));\n\tconst providerId = options.providerId ?? DEFAULT_PROVIDER_ID;\n\tconst apiName = options.api ?? DEFAULT_API;\n\tlet faux: FauxProviderRegistration | undefined;\n\tlet session: AgentSession | undefined;\n\ttry {\n\t\tfaux = registerFauxProvider({\n\t\t\tapi: apiName,\n\t\t\tprovider: providerId,\n\t\t\tclock: () => 0,\n\t\t\tidFactory: (prefix, sequence) => `${prefix}-${sequence}`,\n\t\t});\n\t\tif (options.responses) faux.setResponses([...options.responses]);\n\t\tconst fauxRegistration = faux;\n\t\tconst model = fauxRegistration.getModel();\n\t\tconst authStorage = AuthStorage.inMemory();\n\t\tawait authStorage.modify(providerId, async () => ({ type: \"api_key\", key: \"faux-key\" }));\n\t\tconst modelRuntime = await ModelRuntime.create({\n\t\t\tcredentials: authStorage,\n\t\t\tmodelsPath: null,\n\t\t\tmodelsStore: new InMemoryCodingAgentModelsStore(),\n\t\t\tallowModelNetwork: false,\n\t\t\trefreshOnCreate: false,\n\t\t});\n\t\tmodelRuntime.registerProvider(providerId, {\n\t\t\tbaseUrl: model.baseUrl,\n\t\t\tapi: apiName,\n\t\t\tapiKey: \"faux-key\",\n\t\t\tmodels: fauxRegistration.models.map(modelConfig),\n\t\t});\n\t\tconst settingsManager = SettingsManager.create(tempDir, tempDir);\n\t\tconst resourceLoader = new DefaultResourceLoader({\n\t\t\tcwd: tempDir,\n\t\t\tagentDir: tempDir,\n\t\t\tsettingsManager,\n\t\t\tnoSkills: true,\n\t\t\tnoPromptTemplates: true,\n\t\t\tnoThemes: true,\n\t\t\tnoContextFiles: true,\n\t\t});\n\t\tawait resourceLoader.reload();\n\t\tconst sessionManager = SessionManager.inMemory(tempDir, { id: FIXED_SESSION_ID });\n\t\tconst created = await createAgentSession({\n\t\t\tagentDir: tempDir,\n\t\t\tnoTools: \"all\",\n\t\t\t// Custom fixture tools must be allowlisted explicitly: noTools=\"all\"\n\t\t\t// clears the allowlist, which would otherwise leave them inactive.\n\t\t\t...(options.tools === undefined\n\t\t\t\t? {}\n\t\t\t\t: { tools: options.tools.map((tool) => tool.name), customTools: [...options.tools] }),\n\t\t\tdiscoverCapabilityPlugins: false,\n\t\t\tenableAgentTasks: false,\n\t\t\t...(options.runLoopStrategyName === undefined ? {} : { runLoopStrategyName: options.runLoopStrategyName }),\n\t\t\tstreamFn: streamSimple,\n\t\t\tmodel,\n\t\t\tmodelRuntime,\n\t\t\tresourceLoader,\n\t\t\tsessionManager,\n\t\t\tsettingsManager,\n\t\t\tcwd: tempDir,\n\t\t\tagentComposition: options.composition,\n\t\t}).then(({ session: createdSession }) => createdSession);\n\t\tsession = created;\n\t\tconst activeSession = session;\n\t\tconst initialRuntime = activeSession.getCapabilityRuntime();\n\t\tconst handles = new Map<string, CapabilityPluginHandle>();\n\t\tconst pluginByManifest = new Map(options.plugins.map((plugin) => [plugin.manifest, plugin]));\n\t\tlet closing = false;\n\t\tlet disposed = false;\n\t\tlet disposePromise: Promise<void> | undefined;\n\t\tconst cleanup = async (): Promise<void> => {\n\t\t\tconst failures: unknown[] = [];\n\t\t\tfor (const handle of [...handles.values()].reverse()) {\n\t\t\t\ttry {\n\t\t\t\t\tawait handle.dispose();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tfailures.push(error);\n\t\t\t\t}\n\t\t\t}\n\t\t\thandles.clear();\n\t\t\ttry {\n\t\t\t\tawait session?.dispose();\n\t\t\t} catch (error) {\n\t\t\t\tfailures.push(error);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tfaux?.unregister();\n\t\t\t\tawait rm(tempDir, { recursive: true, force: true });\n\t\t\t} catch (error) {\n\t\t\t\tfailures.push(error);\n\t\t\t}\n\t\t\tif (failures.length === 1) throw failures[0];\n\t\t\tif (failures.length > 1) throw new AggregateError(failures, \"Session plugin testkit cleanup failed\");\n\t\t};\n\t\tconst ready = (async () => {\n\t\t\ttry {\n\t\t\t\tfor (const manifest of resolvePluginCapabilityOrder(options.plugins.map((plugin) => plugin.manifest))) {\n\t\t\t\t\t// v8 ignore next -- kit 仅在 ready 成功后返回,startup 期间不会调用 dispose\n\t\t\t\t\tif (closing) throw new Error(\"Session plugin testkit was disposed during startup\");\n\t\t\t\t\tconst plugin = pluginByManifest.get(manifest);\n\t\t\t\t\t// v8 ignore next -- plugins 数组同时供给加载顺序与 factory 映射,必可解析\n\t\t\t\t\tif (!plugin) throw new Error(`Session plugin testkit cannot resolve factory: ${manifest.id}`);\n\t\t\t\t\tconst handle = await activeSession.loadCapabilityPlugin(manifest, plugin.factory);\n\t\t\t\t\thandles.set(manifest.id, handle);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tawait cleanup();\n\t\t\t\t} catch (cleanupError) {\n\t\t\t\t\tthrow new AggregateError([error, cleanupError], \"Session plugin testkit startup rollback failed\");\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t})();\n\t\tconst kit: SessionPluginTestKit = {\n\t\t\tready,\n\t\t\tsession: activeSession,\n\t\t\tagent: activeSession.agent,\n\t\t\tget runtime(): CapabilityRuntime {\n\t\t\t\tif (disposed) throw new Error(\"Session plugin testkit runtime is disposed\");\n\t\t\t\treturn activeSession.getCapabilityRuntime();\n\t\t\t},\n\t\t\tfaux: fauxRegistration,\n\t\t\tapi(pluginId) {\n\t\t\t\tif (activeSession.getCapabilityRuntime() !== initialRuntime) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Session plugin testkit plugin API handles expire after session reload; access the current runtime directly\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst handle = handles.get(pluginId);\n\t\t\t\tif (!handle) throw new Error(`Session plugin testkit has no loaded plugin: ${pluginId}`);\n\t\t\t\treturn handle.api;\n\t\t\t},\n\t\t\trevoke(pluginId) {\n\t\t\t\tif (activeSession.getCapabilityRuntime() !== initialRuntime) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Session plugin testkit plugin API handles expire after session reload; access the current runtime directly\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst handle = handles.get(pluginId);\n\t\t\t\tif (!handle) throw new Error(`Session plugin testkit has no loaded plugin: ${pluginId}`);\n\t\t\t\tactiveSession.getCapabilityRuntime().revokeAPI(handle.api);\n\t\t\t},\n\t\t\tassertResponsesConsumed() {\n\t\t\t\tconst pending = fauxRegistration.getPendingResponseCount();\n\t\t\t\tif (pending !== 0) {\n\t\t\t\t\tthrow new Error(`Session plugin testkit has ${pending} unused faux response${pending === 1 ? \"\" : \"s\"}`);\n\t\t\t\t}\n\t\t\t},\n\t\t\tinspect: () => activeSession.getCapabilityRuntime().inspect(),\n\t\t\ttranscript: () => {\n\t\t\t\tconst branch = sessionManager.getBranch();\n\t\t\t\tconst transcript: SessionPluginTestKitTranscript = {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tsessionId: sessionManager.getSessionId(),\n\t\t\t\t\trevision: sessionManager.getRevision().sequence,\n\t\t\t\t\tloadOrder: [...handles.keys()],\n\t\t\t\t\tfauxCallCount: fauxRegistration.state.callCount,\n\t\t\t\t\tmessages: activeSession.agent.state.messages.map((message) => ({\n\t\t\t\t\t\trole: message.role,\n\t\t\t\t\t\ttext: stableText(message),\n\t\t\t\t\t})),\n\t\t\t\t\tentries: branch.map((entry) => ({\n\t\t\t\t\t\ttype: entry.type,\n\t\t\t\t\t\t...(entry.type === \"custom\"\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tcustomType: entry.customType,\n\t\t\t\t\t\t\t\t\t...(entry.data === undefined ? {} : { data: transcriptValue(entry.data) }),\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t})),\n\t\t\t\t\tinspector: stableInspector(activeSession.getCapabilityRuntime().inspect()),\n\t\t\t\t};\n\t\t\t\treturn freezeSnapshot(transcript);\n\t\t\t},\n\t\t\tdispose: async () => {\n\t\t\t\tdisposePromise ??= (async () => {\n\t\t\t\t\tclosing = true;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait ready;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Startup rollback already disposed the session and faux provider.\n\t\t\t\t\t\t// v8 ignore next -- ready 已在返回前 await,dispose 中不会进入该 catch\n\t\t\t\t\t\tif (session?.isDisposed) {\n\t\t\t\t\t\t\tdisposed = true;\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait cleanup();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tdisposed = true;\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t\treturn disposePromise;\n\t\t\t},\n\t\t};\n\t\tawait ready;\n\t\treturn kit;\n\t} catch (error) {\n\t\ttry {\n\t\t\tsession && (await session.dispose());\n\t\t} finally {\n\t\t\tfaux?.unregister();\n\t\t\tawait rm(tempDir, { recursive: true, force: true });\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** Runs a session fixture repeatedly and rejects on the first transcript divergence. */\nexport async function repeatSessionPluginTestKit(\n\ttimes: number,\n\trun: () => Promise<SessionPluginTestKitTranscript>,\n): Promise<SessionPluginTestKitTranscript> {\n\tif (!Number.isSafeInteger(times) || times < 1)\n\t\tthrow new Error(\"Session plugin testkit repeat count must be a positive integer\");\n\tlet baseline: SessionPluginTestKitTranscript | undefined;\n\tfor (let index = 0; index < times; index += 1) {\n\t\tconst transcript = await run();\n\t\tif (baseline && canonicalJson(transcript) !== canonicalJson(baseline)) {\n\t\t\tthrow new Error(`Session plugin testkit transcript diverged on run ${index + 1}`);\n\t\t}\n\t\tbaseline = transcript;\n\t}\n\treturn baseline!;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-agent-forge/agent-forge",
3
- "version": "0.85.4",
3
+ "version": "0.85.5",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "agentForgeConfig": {