mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 15:10:52 +00:00
refactor: move remaining agent test contract files
This commit is contained in:
@@ -1,60 +0,0 @@
|
||||
import {
|
||||
resolveProviderIdForAuth,
|
||||
type ProviderAuthAliasLookupParams,
|
||||
} from "../../../src/agents/provider-auth-aliases.js";
|
||||
import type { PluginManifestRegistry } from "../../../src/plugins/manifest-registry.js";
|
||||
|
||||
export const AUTH_PROFILE_RUNTIME_CONTRACT = {
|
||||
sessionId: "session-auth-contract",
|
||||
sessionKey: "agent:main:auth-contract",
|
||||
runId: "run-auth-contract",
|
||||
workspacePrompt: "continue with the bound Codex profile",
|
||||
openAiProvider: "openai",
|
||||
openAiCodexProvider: "openai-codex",
|
||||
codexCliProvider: "codex-cli",
|
||||
codexHarnessProvider: "codex",
|
||||
claudeCliProvider: "claude-cli",
|
||||
openAiProfileId: "openai:work",
|
||||
openAiCodexProfileId: "openai-codex:work",
|
||||
anthropicProfileId: "anthropic:work",
|
||||
} as const;
|
||||
|
||||
export function createAuthAliasManifestRegistry(): PluginManifestRegistry {
|
||||
return {
|
||||
plugins: [
|
||||
{
|
||||
id: "openai",
|
||||
origin: "bundled",
|
||||
channels: [],
|
||||
providers: [],
|
||||
cliBackends: [],
|
||||
skills: [],
|
||||
hooks: [],
|
||||
rootDir: "/tmp/openclaw-auth-contract-plugin",
|
||||
source: "test",
|
||||
manifestPath: "/tmp/openclaw-auth-contract-plugin/plugin.json",
|
||||
providerAuthChoices: [
|
||||
{
|
||||
provider: AUTH_PROFILE_RUNTIME_CONTRACT.openAiCodexProvider,
|
||||
method: "oauth",
|
||||
choiceId: AUTH_PROFILE_RUNTIME_CONTRACT.openAiCodexProvider,
|
||||
deprecatedChoiceIds: [AUTH_PROFILE_RUNTIME_CONTRACT.codexCliProvider],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
diagnostics: [],
|
||||
};
|
||||
}
|
||||
|
||||
export function expectedForwardedAuthProfile(params: {
|
||||
provider: string;
|
||||
authProfileProvider: string;
|
||||
aliasLookupParams: ProviderAuthAliasLookupParams;
|
||||
sessionAuthProfileId: string | undefined;
|
||||
}): string | undefined {
|
||||
return resolveProviderIdForAuth(params.provider, params.aliasLookupParams) ===
|
||||
resolveProviderIdForAuth(params.authProfileProvider, params.aliasLookupParams)
|
||||
? params.sessionAuthProfileId
|
||||
: undefined;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
export const DELIVERY_NO_REPLY_RUNTIME_CONTRACT = {
|
||||
sessionId: "session-delivery-contract",
|
||||
sessionKey: "agent:main:delivery-contract",
|
||||
runId: "run-delivery-contract",
|
||||
prompt: "deliver the follow-up contract turn",
|
||||
originChannel: "discord",
|
||||
originTo: "channel:C1",
|
||||
dispatcherText: "visible dispatcher fallback",
|
||||
visibleText: "visible follow-up",
|
||||
silentText: "NO_REPLY",
|
||||
jsonSilentText: '{"action":"NO_REPLY"}',
|
||||
} as const;
|
||||
@@ -1,94 +0,0 @@
|
||||
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
||||
import { vi } from "vitest";
|
||||
import { __testing as beforeToolCallTesting } from "../../../src/agents/pi-tools.before-tool-call.js";
|
||||
import type {
|
||||
CodexAppServerExtensionFactory,
|
||||
CodexAppServerToolResultEvent,
|
||||
} from "../../../src/plugins/codex-app-server-extension-types.js";
|
||||
import {
|
||||
initializeGlobalHookRunner,
|
||||
resetGlobalHookRunner,
|
||||
} from "../../../src/plugins/hook-runner-global.js";
|
||||
import { createMockPluginRegistry } from "../../../src/plugins/hooks.test-helpers.js";
|
||||
import { createEmptyPluginRegistry } from "../../../src/plugins/registry-empty.js";
|
||||
import {
|
||||
resetPluginRuntimeStateForTest,
|
||||
setActivePluginRegistry,
|
||||
} from "../../../src/plugins/runtime.js";
|
||||
|
||||
export function textToolResult(
|
||||
text: string,
|
||||
details: Record<string, unknown> = {},
|
||||
): AgentToolResult<unknown> {
|
||||
return {
|
||||
content: [{ type: "text", text }],
|
||||
details,
|
||||
};
|
||||
}
|
||||
|
||||
export function mediaToolResult(
|
||||
text: string,
|
||||
mediaUrl: string,
|
||||
audioAsVoice = false,
|
||||
): AgentToolResult<unknown> {
|
||||
return textToolResult(text, {
|
||||
media: {
|
||||
mediaUrl,
|
||||
...(audioAsVoice ? { audioAsVoice } : {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function installOpenClawOwnedToolHooks(params?: {
|
||||
adjustedParams?: Record<string, unknown>;
|
||||
blockReason?: string;
|
||||
}) {
|
||||
const beforeToolCall = vi.fn(async () => {
|
||||
if (params?.blockReason) {
|
||||
return {
|
||||
block: true,
|
||||
blockReason: params.blockReason,
|
||||
};
|
||||
}
|
||||
return params?.adjustedParams ? { params: params.adjustedParams } : {};
|
||||
});
|
||||
const afterToolCall = vi.fn(async () => {});
|
||||
initializeGlobalHookRunner(
|
||||
createMockPluginRegistry([
|
||||
{ hookName: "before_tool_call", handler: beforeToolCall },
|
||||
{ hookName: "after_tool_call", handler: afterToolCall },
|
||||
]),
|
||||
);
|
||||
return { beforeToolCall, afterToolCall };
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs only the Codex app-server `tool_result` middleware fixture.
|
||||
* Pair with `installOpenClawOwnedToolHooks()` when a test asserts before/after hook behavior.
|
||||
*/
|
||||
export function installCodexToolResultMiddleware(
|
||||
handler: (event: CodexAppServerToolResultEvent) => AgentToolResult<unknown>,
|
||||
) {
|
||||
const middleware = vi.fn(async (event: CodexAppServerToolResultEvent) => ({
|
||||
result: handler(event),
|
||||
}));
|
||||
const registry = createEmptyPluginRegistry();
|
||||
const factory: CodexAppServerExtensionFactory = async (codex) => {
|
||||
codex.on("tool_result", middleware);
|
||||
};
|
||||
registry.codexAppServerExtensionFactories.push({
|
||||
pluginId: "runtime-contract",
|
||||
pluginName: "Runtime Contract",
|
||||
rawFactory: factory,
|
||||
factory,
|
||||
source: "test",
|
||||
});
|
||||
setActivePluginRegistry(registry);
|
||||
return { middleware };
|
||||
}
|
||||
|
||||
export function resetOpenClawOwnedToolHooks(): void {
|
||||
resetGlobalHookRunner();
|
||||
resetPluginRuntimeStateForTest();
|
||||
beforeToolCallTesting.adjustedParamsByToolCallId.clear();
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import type { EmbeddedPiRunResult } from "../../../src/agents/pi-embedded-runner/types.js";
|
||||
|
||||
export const OUTCOME_FALLBACK_RUNTIME_CONTRACT = {
|
||||
primaryProvider: "openai-codex",
|
||||
primaryModel: "gpt-5.4",
|
||||
fallbackProvider: "anthropic",
|
||||
fallbackModel: "claude-haiku-3-5",
|
||||
sessionId: "session-outcome-contract",
|
||||
sessionKey: "agent:main:outcome-contract",
|
||||
runId: "run-outcome-contract",
|
||||
prompt: "finish the contract turn",
|
||||
reasoningOnlyText: "I need to reason about this before answering.",
|
||||
planningOnlyText: "Inspect state, then decide the next step.",
|
||||
} as const;
|
||||
|
||||
export function createContractRunResult(
|
||||
overrides: Partial<EmbeddedPiRunResult> = {},
|
||||
): EmbeddedPiRunResult {
|
||||
const { meta, ...rest } = overrides;
|
||||
return {
|
||||
payloads: [],
|
||||
didSendViaMessagingTool: false,
|
||||
messagingToolSentTexts: [],
|
||||
messagingToolSentMediaUrls: [],
|
||||
messagingToolSentTargets: [],
|
||||
successfulCronAdds: 0,
|
||||
...rest,
|
||||
meta: {
|
||||
durationMs: 1,
|
||||
...meta,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function createContractFallbackConfig() {
|
||||
return {
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: `${OUTCOME_FALLBACK_RUNTIME_CONTRACT.primaryProvider}/${OUTCOME_FALLBACK_RUNTIME_CONTRACT.primaryModel}`,
|
||||
fallbacks: [
|
||||
`${OUTCOME_FALLBACK_RUNTIME_CONTRACT.fallbackProvider}/${OUTCOME_FALLBACK_RUNTIME_CONTRACT.fallbackModel}`,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import type { OpenClawConfig } from "../../../src/config/types.openclaw.js";
|
||||
import type { ProviderSystemPromptContributionContext } from "../../../src/plugins/types.js";
|
||||
|
||||
export const GPT5_CONTRACT_MODEL_ID = "gpt-5.4";
|
||||
export const GPT5_PREFIXED_CONTRACT_MODEL_ID = "openai/gpt-5.4";
|
||||
export const NON_GPT5_CONTRACT_MODEL_ID = "gpt-4.1";
|
||||
export const OPENAI_CONTRACT_PROVIDER_ID = "openai";
|
||||
export const OPENAI_CODEX_CONTRACT_PROVIDER_ID = "openai-codex";
|
||||
export const CODEX_CONTRACT_PROVIDER_ID = "codex";
|
||||
export const NON_OPENAI_CONTRACT_PROVIDER_ID = "openrouter";
|
||||
|
||||
export function openAiPluginPersonalityConfig(personality: "friendly" | "off"): OpenClawConfig {
|
||||
return {
|
||||
plugins: {
|
||||
entries: {
|
||||
openai: {
|
||||
config: { personality },
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies OpenClawConfig;
|
||||
}
|
||||
|
||||
export function sharedGpt5PersonalityConfig(personality: "friendly" | "off"): OpenClawConfig {
|
||||
return {
|
||||
agents: {
|
||||
defaults: {
|
||||
promptOverlays: {
|
||||
gpt5: { personality },
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies OpenClawConfig;
|
||||
}
|
||||
|
||||
export function codexPromptOverlayContext(params?: {
|
||||
modelId?: string;
|
||||
config?: OpenClawConfig;
|
||||
}): ProviderSystemPromptContributionContext {
|
||||
return {
|
||||
provider: CODEX_CONTRACT_PROVIDER_ID,
|
||||
modelId: params?.modelId ?? GPT5_CONTRACT_MODEL_ID,
|
||||
promptMode: "full",
|
||||
agentDir: "/tmp/openclaw-codex-prompt-contract-agent",
|
||||
workspaceDir: "/tmp/openclaw-codex-prompt-contract-workspace",
|
||||
...(params?.config ? { config: params.config } : {}),
|
||||
};
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
export function createParameterFreeTool(name = "ping") {
|
||||
return {
|
||||
name,
|
||||
description: "Parameter-free test tool",
|
||||
parameters: {},
|
||||
};
|
||||
}
|
||||
|
||||
export function createStrictCompatibleTool(name = "lookup") {
|
||||
return {
|
||||
name,
|
||||
description: "Strict-compatible test tool",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
path: { type: "string" },
|
||||
},
|
||||
required: ["path"],
|
||||
additionalProperties: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function createPermissiveTool(name = "schedule") {
|
||||
return {
|
||||
name,
|
||||
description: "Permissive test tool",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
action: { type: "string" },
|
||||
cron: { type: "string" },
|
||||
},
|
||||
required: ["action"],
|
||||
additionalProperties: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function createNativeOpenAIResponsesModel() {
|
||||
return {
|
||||
id: "gpt-5.4",
|
||||
name: "GPT-5.4",
|
||||
api: "openai-responses",
|
||||
provider: "openai",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 200_000,
|
||||
maxTokens: 8_192,
|
||||
};
|
||||
}
|
||||
|
||||
export function createNativeOpenAICodexResponsesModel() {
|
||||
return {
|
||||
id: "gpt-5.4",
|
||||
name: "GPT-5.4",
|
||||
api: "openai-codex-responses",
|
||||
provider: "openai-codex",
|
||||
baseUrl: "https://chatgpt.com/backend-api",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 200_000,
|
||||
maxTokens: 8_192,
|
||||
};
|
||||
}
|
||||
|
||||
export function createProxyOpenAIResponsesModel() {
|
||||
return {
|
||||
id: "custom-gpt",
|
||||
name: "Custom GPT",
|
||||
api: "openai-responses",
|
||||
provider: "openai",
|
||||
baseUrl: "https://proxy.example.com/v1",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 200_000,
|
||||
maxTokens: 8_192,
|
||||
};
|
||||
}
|
||||
|
||||
export function normalizedParameterFreeSchema() {
|
||||
return {
|
||||
type: "object",
|
||||
properties: {},
|
||||
required: [],
|
||||
additionalProperties: false,
|
||||
};
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
||||
|
||||
export const QUEUED_USER_MESSAGE_MARKER =
|
||||
"[Queued user message that arrived while the previous turn was still active]";
|
||||
|
||||
export function textOrphanLeaf(text = "older active-turn message"): { content: string } {
|
||||
return { content: text };
|
||||
}
|
||||
|
||||
export function structuredOrphanLeaf(): { content: unknown[] } {
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: "please inspect this" },
|
||||
{ type: "image_url", image_url: { url: "https://example.test/cat.png" } },
|
||||
{ type: "input_audio", audio_url: "https://example.test/cat.wav" },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function inlineDataUriOrphanLeaf(): { content: unknown[] } {
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: "please inspect this inline image" },
|
||||
{ type: "image_url", image_url: { url: `data:image/png;base64,${"a".repeat(4096)}` } },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function mediaOnlyHistoryMessage(): AgentMessage {
|
||||
return {
|
||||
role: "user",
|
||||
content: [{ type: "image", data: "b".repeat(2048), mimeType: "image/png" }],
|
||||
timestamp: 1,
|
||||
} as AgentMessage;
|
||||
}
|
||||
|
||||
export function structuredHistoryMessage(): AgentMessage {
|
||||
return {
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: "older structured context" },
|
||||
{ type: "image", data: "c".repeat(64), mimeType: "image/png" },
|
||||
],
|
||||
timestamp: 1,
|
||||
} as AgentMessage;
|
||||
}
|
||||
|
||||
export function currentPromptHistoryMessage(prompt: string): AgentMessage {
|
||||
return {
|
||||
role: "user",
|
||||
content: [{ type: "text", text: prompt }],
|
||||
timestamp: 2,
|
||||
} as AgentMessage;
|
||||
}
|
||||
|
||||
export function assistantHistoryMessage(text = "ack"): AgentMessage {
|
||||
return {
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text }],
|
||||
timestamp: 2,
|
||||
} as AgentMessage;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import type {
|
||||
SandboxBrowserConfig,
|
||||
SandboxPruneConfig,
|
||||
SandboxSshConfig,
|
||||
} from "../../src/agents/sandbox/types.js";
|
||||
|
||||
export function createSandboxBrowserConfig(
|
||||
overrides: Partial<SandboxBrowserConfig> = {},
|
||||
): SandboxBrowserConfig {
|
||||
return {
|
||||
enabled: false,
|
||||
image: "openclaw-browser",
|
||||
containerPrefix: "openclaw-browser-",
|
||||
network: "bridge",
|
||||
cdpPort: 9222,
|
||||
vncPort: 5900,
|
||||
noVncPort: 6080,
|
||||
headless: true,
|
||||
enableNoVnc: false,
|
||||
allowHostControl: false,
|
||||
autoStart: false,
|
||||
autoStartTimeoutMs: 1000,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
export function createSandboxPruneConfig(
|
||||
overrides: Partial<SandboxPruneConfig> = {},
|
||||
): SandboxPruneConfig {
|
||||
return {
|
||||
idleHours: 24,
|
||||
maxAgeDays: 7,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
export function createSandboxSshConfig(
|
||||
workspaceRoot: string,
|
||||
overrides: Partial<SandboxSshConfig> = {},
|
||||
): SandboxSshConfig {
|
||||
return {
|
||||
command: "ssh",
|
||||
workspaceRoot,
|
||||
strictHostKeyChecking: true,
|
||||
updateHostKeys: true,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user