Download src/agents/sessions/agent-session-loop-correctness.test-support.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 5.85 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/agents/sessions/agent-session-loop-correctness.test-support.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/agents/sessions/agent-session-loop-correctness.test-support.ts
-
curl -L -o agent-session-loop-correctness.test-support.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/agents/sessions/agent-session-loop-correctness.test-support.ts
5.85 kB
| import { | |
| createAssistantMessageEventStream, | |
| type AssistantMessage, | |
| type Model, | |
| } from "openclaw/plugin-sdk/llm"; | |
| import { afterEach, beforeEach, vi } from "vitest"; | |
| import { createResourceLoader } from "./agent-session-loop-resource-loader.test-support.js"; | |
| import { AgentSession } from "./agent-session.js"; | |
| import { AuthStorage } from "./auth-storage.js"; | |
| import type { ToolDefinition } from "./extensions/types.js"; | |
| import { ModelRegistry } from "./model-registry.js"; | |
| import type { ResourceLoader } from "./resource-loader.js"; | |
| import { createAgentSession, createAgentSessionForEmbeddedRunner } from "./sdk.js"; | |
| import { SessionManager } from "./session-manager.js"; | |
| import { SettingsManager } from "./settings-manager.js"; | |
| const hoistedStreamMocks = vi.hoisted(() => ({ | |
| streamSimple: vi.fn(), | |
| })); | |
| export const streamMocks = hoistedStreamMocks; | |
| export const testModel: Model = { | |
| id: "test-model", | |
| name: "Test Model", | |
| api: "openai-responses", | |
| provider: "test-provider", | |
| baseUrl: "https://example.test", | |
| reasoning: false, | |
| input: ["text"], | |
| cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, | |
| contextWindow: 32_768, | |
| maxTokens: 8_192, | |
| }; | |
| const sessions: AgentSession[] = []; | |
| function createUsage(contextTokens: number) { | |
| return { | |
| input: contextTokens, | |
| output: 1, | |
| cacheRead: 0, | |
| cacheWrite: 0, | |
| totalTokens: contextTokens + 1, | |
| contextUsage: { | |
| state: "available" as const, | |
| promptTokens: contextTokens, | |
| totalTokens: contextTokens + 1, | |
| }, | |
| cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, | |
| }; | |
| } | |
| export function createAssistant( | |
| activeModel: Model, | |
| content: AssistantMessage["content"], | |
| stopReason: AssistantMessage["stopReason"] = "stop", | |
| contextTokens = 1, | |
| ): AssistantMessage { | |
| return { | |
| role: "assistant", | |
| content, | |
| api: activeModel.api, | |
| provider: activeModel.provider, | |
| model: activeModel.id, | |
| usage: createUsage(contextTokens), | |
| stopReason, | |
| timestamp: Date.now(), | |
| }; | |
| } | |
| export function createAssistantResultStream(message: AssistantMessage) { | |
| const stream = createAssistantMessageEventStream(); | |
| queueMicrotask(() => { | |
| if (message.stopReason === "error" || message.stopReason === "aborted") { | |
| stream.push({ type: "error", reason: message.stopReason, error: message }); | |
| } else { | |
| stream.push({ type: "done", reason: message.stopReason, message }); | |
| } | |
| stream.end(); | |
| }); | |
| return stream; | |
| } | |
| export function createOverflowAssistant(activeModel: Model) { | |
| const contextWindow = activeModel.contextWindow; | |
| if (typeof contextWindow !== "number" || !Number.isFinite(contextWindow) || contextWindow <= 0) { | |
| throw new Error("Overflow fixture requires a finite positive model context window"); | |
| } | |
| return { | |
| ...createAssistant( | |
| activeModel, | |
| [{ type: "text", text: "truncated answer" }], | |
| "length", | |
| contextWindow, | |
| ), | |
| usage: { ...createUsage(contextWindow), output: 0 }, | |
| }; | |
| } | |
| export const createAutoCompactionSettings = () => | |
| SettingsManager.inMemory({ | |
| compaction: { enabled: true, reserveTokens: 0, keepRecentTokens: 1 }, | |
| retry: { enabled: false }, | |
| }); | |
| export function mockInvalidThenTextSummary(recoveredText: string) { | |
| let requests = 0; | |
| streamMocks.streamSimple.mockImplementation((activeModel: Model) => { | |
| return createAssistantResultStream( | |
| createAssistant( | |
| activeModel, | |
| ++requests === 1 | |
| ? [{ type: "thinking", thinking: "internal summary reasoning" }] | |
| : [{ type: "text", text: recoveredText }], | |
| ), | |
| ); | |
| }); | |
| return () => requests; | |
| } | |
| export async function createTestSession( | |
| options: { | |
| model?: Model; | |
| settingsManager?: SettingsManager; | |
| sessionManager?: SessionManager; | |
| resourceLoader?: ResourceLoader; | |
| customTools?: ToolDefinition[]; | |
| contextOverflowRecoveryOwner?: "session" | "caller"; | |
| withSessionWriteSettlement?: NonNullable< | |
| Parameters<typeof createAgentSession>[0] | |
| >["withSessionWriteSettlement"]; | |
| } = {}, | |
| ) { | |
| const model = options.model ?? testModel; | |
| const authStorage = AuthStorage.inMemory(); | |
| authStorage.setRuntimeApiKey(model.provider, "test-api-key"); | |
| const settingsManager = | |
| options.settingsManager ?? | |
| SettingsManager.inMemory({ | |
| compaction: { enabled: false }, | |
| retry: { enabled: false }, | |
| }); | |
| const sessionManager = options.sessionManager ?? SessionManager.inMemory(); | |
| const modelRegistry = ModelRegistry.inMemory(authStorage); | |
| modelRegistry.registerProvider(model.provider, { | |
| api: model.api, | |
| streamSimple: streamMocks.streamSimple, | |
| }); | |
| const sessionOptions = { | |
| model, | |
| authStorage, | |
| noTools: "builtin" as const, | |
| customTools: options.customTools, | |
| resourceLoader: options.resourceLoader ?? createResourceLoader(), | |
| sessionManager, | |
| settingsManager, | |
| modelRegistry, | |
| withSessionWriteSettlement: options.withSessionWriteSettlement, | |
| }; | |
| const result = options.contextOverflowRecoveryOwner | |
| ? await createAgentSessionForEmbeddedRunner(sessionOptions, { | |
| contextOverflowRecoveryOwner: options.contextOverflowRecoveryOwner, | |
| }) | |
| : await createAgentSession(sessionOptions); | |
| sessions.push(result.session); | |
| return { ...result, modelRegistry, settingsManager, sessionManager }; | |
| } | |
| export function appendHistory(sessionManager: SessionManager, assistant: AssistantMessage): void { | |
| sessionManager.appendMessage({ role: "user", content: "old prompt", timestamp: Date.now() - 2 }); | |
| sessionManager.appendMessage({ ...assistant, timestamp: Date.now() - 1 }); | |
| } | |
| export function registerAgentSessionLoopTestLifecycle(): void { | |
| beforeEach(() => { | |
| streamMocks.streamSimple.mockReset(); | |
| }); | |
| afterEach(() => { | |
| for (const session of sessions.splice(0)) { | |
| session.dispose(); | |
| } | |
| }); | |
| } | |