From 08ba5a72f7a72a5ed2a70b316cdf4e5e3263659b Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 11 Apr 2026 10:39:16 +0100 Subject: [PATCH] fix(cycles): add remaining seam files --- .../compact.runtime.types.ts | 6 + src/agents/subagent-registry-announce-read.ts | 76 +++++++++++ .../reply/dispatch-from-config.types.ts | 25 ++++ src/channels/plugins/outbound.types.ts | 112 +++++++++++++++ src/channels/plugins/outbound/load.types.ts | 6 + src/channels/plugins/pairing.types.ts | 13 ++ src/config/markdown-tables.types.ts | 12 ++ src/gateway/server-broadcast-types.ts | 22 +++ src/image-generation/runtime-types.ts | 40 ++++++ src/media-generation/normalization.types.ts | 15 +++ src/music-generation/runtime-types.ts | 41 ++++++ src/plugin-sdk/infra-runtime.test.ts | 74 ++++++++++ src/plugins/conversation-binding.types.ts | 56 ++++++++ src/plugins/hook-message.types.ts | 57 ++++++++ src/plugins/plugin-origin.types.ts | 1 + src/plugins/provider-external-auth.types.ts | 34 +++++ src/plugins/tool-types.ts | 50 +++++++ src/plugins/web-provider-types.ts | 127 ++++++++++++++++++ src/video-generation/runtime-types.ts | 43 ++++++ src/web-search/runtime-types.ts | 37 +++++ 20 files changed, 847 insertions(+) create mode 100644 src/agents/pi-embedded-runner/compact.runtime.types.ts create mode 100644 src/agents/subagent-registry-announce-read.ts create mode 100644 src/auto-reply/reply/dispatch-from-config.types.ts create mode 100644 src/channels/plugins/outbound.types.ts create mode 100644 src/channels/plugins/outbound/load.types.ts create mode 100644 src/channels/plugins/pairing.types.ts create mode 100644 src/config/markdown-tables.types.ts create mode 100644 src/gateway/server-broadcast-types.ts create mode 100644 src/image-generation/runtime-types.ts create mode 100644 src/media-generation/normalization.types.ts create mode 100644 src/music-generation/runtime-types.ts create mode 100644 src/plugin-sdk/infra-runtime.test.ts create mode 100644 src/plugins/conversation-binding.types.ts create mode 100644 src/plugins/hook-message.types.ts create mode 100644 src/plugins/plugin-origin.types.ts create mode 100644 src/plugins/provider-external-auth.types.ts create mode 100644 src/plugins/tool-types.ts create mode 100644 src/plugins/web-provider-types.ts create mode 100644 src/video-generation/runtime-types.ts create mode 100644 src/web-search/runtime-types.ts diff --git a/src/agents/pi-embedded-runner/compact.runtime.types.ts b/src/agents/pi-embedded-runner/compact.runtime.types.ts new file mode 100644 index 00000000000..1d554dae461 --- /dev/null +++ b/src/agents/pi-embedded-runner/compact.runtime.types.ts @@ -0,0 +1,6 @@ +import type { CompactEmbeddedPiSessionParams } from "./compact.types.js"; +import type { EmbeddedPiCompactResult } from "./types.js"; + +export type CompactEmbeddedPiSessionDirect = ( + params: CompactEmbeddedPiSessionParams, +) => Promise; diff --git a/src/agents/subagent-registry-announce-read.ts b/src/agents/subagent-registry-announce-read.ts new file mode 100644 index 00000000000..da1908aa005 --- /dev/null +++ b/src/agents/subagent-registry-announce-read.ts @@ -0,0 +1,76 @@ +import { type DeliveryContext, normalizeDeliveryContext } from "../utils/delivery-context.js"; +import { subagentRuns } from "./subagent-registry-memory.js"; +import { + countPendingDescendantRunsExcludingRunFromRuns, + countPendingDescendantRunsFromRuns, + findRunIdsByChildSessionKeyFromRuns, + listRunsForRequesterFromRuns, + resolveRequesterForChildSessionFromRuns, + shouldIgnorePostCompletionAnnounceForSessionFromRuns, +} from "./subagent-registry-queries.js"; +import { getSubagentRunsSnapshotForRead } from "./subagent-registry-state.js"; +import type { SubagentRunRecord } from "./subagent-registry.types.js"; + +export function resolveRequesterForChildSession(childSessionKey: string): { + requesterSessionKey: string; + requesterOrigin?: DeliveryContext; +} | null { + const resolved = resolveRequesterForChildSessionFromRuns( + getSubagentRunsSnapshotForRead(subagentRuns), + childSessionKey, + ); + if (!resolved) { + return null; + } + return { + requesterSessionKey: resolved.requesterSessionKey, + requesterOrigin: normalizeDeliveryContext(resolved.requesterOrigin), + }; +} + +export function isSubagentSessionRunActive(childSessionKey: string): boolean { + const runIds = findRunIdsByChildSessionKeyFromRuns(subagentRuns, childSessionKey); + let latest: SubagentRunRecord | undefined; + for (const runId of runIds) { + const entry = subagentRuns.get(runId); + if (!entry) { + continue; + } + if (!latest || entry.createdAt > latest.createdAt) { + latest = entry; + } + } + return Boolean(latest && typeof latest.endedAt !== "number"); +} + +export function shouldIgnorePostCompletionAnnounceForSession(childSessionKey: string): boolean { + return shouldIgnorePostCompletionAnnounceForSessionFromRuns( + getSubagentRunsSnapshotForRead(subagentRuns), + childSessionKey, + ); +} + +export function listSubagentRunsForRequester( + requesterSessionKey: string, + options?: { requesterRunId?: string }, +): SubagentRunRecord[] { + return listRunsForRequesterFromRuns(subagentRuns, requesterSessionKey, options); +} + +export function countPendingDescendantRuns(rootSessionKey: string): number { + return countPendingDescendantRunsFromRuns( + getSubagentRunsSnapshotForRead(subagentRuns), + rootSessionKey, + ); +} + +export function countPendingDescendantRunsExcludingRun( + rootSessionKey: string, + excludeRunId: string, +): number { + return countPendingDescendantRunsExcludingRunFromRuns( + getSubagentRunsSnapshotForRead(subagentRuns), + rootSessionKey, + excludeRunId, + ); +} diff --git a/src/auto-reply/reply/dispatch-from-config.types.ts b/src/auto-reply/reply/dispatch-from-config.types.ts new file mode 100644 index 00000000000..ec4ee25016e --- /dev/null +++ b/src/auto-reply/reply/dispatch-from-config.types.ts @@ -0,0 +1,25 @@ +import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import type { FinalizedMsgContext } from "../templating.js"; +import type { GetReplyOptions } from "../types.js"; +import type { ReplyDispatcher, ReplyDispatchKind } from "./reply-dispatcher.js"; + +export type DispatchFromConfigResult = { + queuedFinal: boolean; + counts: Record; +}; + +export type DispatchFromConfigParams = { + ctx: FinalizedMsgContext; + cfg: OpenClawConfig; + dispatcher: ReplyDispatcher; + replyOptions?: Omit; + replyResolver?: typeof import("./get-reply-from-config.runtime.js").getReplyFromConfig; + fastAbortResolver?: typeof import("./abort.runtime.js").tryFastAbortFromMessage; + formatAbortReplyTextResolver?: typeof import("./abort.runtime.js").formatAbortReplyText; + /** Optional config override passed to getReplyFromConfig (e.g. per-sender timezone). */ + configOverride?: OpenClawConfig; +}; + +export type DispatchReplyFromConfig = ( + params: DispatchFromConfigParams, +) => Promise; diff --git a/src/channels/plugins/outbound.types.ts b/src/channels/plugins/outbound.types.ts new file mode 100644 index 00000000000..c170a8ddfe3 --- /dev/null +++ b/src/channels/plugins/outbound.types.ts @@ -0,0 +1,112 @@ +import type { ReplyPayload } from "../../auto-reply/types.js"; +import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import type { OutboundDeliveryResult } from "../../infra/outbound/deliver-types.js"; +import type { OutboundIdentity } from "../../infra/outbound/identity-types.js"; +import type { OutboundSendDeps } from "../../infra/outbound/send-deps.js"; +import type { OutboundMediaAccess } from "../../media/load-options.js"; +import type { + ChannelOutboundTargetMode, + ChannelPollContext, + ChannelPollResult, +} from "./types.core.js"; + +export type ChannelOutboundContext = { + cfg: OpenClawConfig; + to: string; + text: string; + mediaUrl?: string; + audioAsVoice?: boolean; + mediaAccess?: OutboundMediaAccess; + mediaLocalRoots?: readonly string[]; + mediaReadFile?: (filePath: string) => Promise; + gifPlayback?: boolean; + /** Send image as document to avoid Telegram compression. */ + forceDocument?: boolean; + replyToId?: string | null; + threadId?: string | number | null; + accountId?: string | null; + identity?: OutboundIdentity; + deps?: OutboundSendDeps; + silent?: boolean; + gatewayClientScopes?: readonly string[]; +}; + +export type ChannelOutboundPayloadContext = ChannelOutboundContext & { + payload: ReplyPayload; +}; + +export type ChannelOutboundPayloadHint = + | { kind: "approval-pending"; approvalKind: "exec" | "plugin" } + | { kind: "approval-resolved"; approvalKind: "exec" | "plugin" }; + +export type ChannelOutboundTargetRef = { + channel: string; + to: string; + accountId?: string | null; + threadId?: string | number | null; +}; + +export type ChannelOutboundFormattedContext = ChannelOutboundContext & { + abortSignal?: AbortSignal; +}; + +export type ChannelOutboundAdapter = { + deliveryMode: "direct" | "gateway" | "hybrid"; + chunker?: ((text: string, limit: number) => string[]) | null; + chunkerMode?: "text" | "markdown"; + textChunkLimit?: number; + sanitizeText?: (params: { text: string; payload: ReplyPayload }) => string; + pollMaxOptions?: number; + supportsPollDurationSeconds?: boolean; + supportsAnonymousPolls?: boolean; + normalizePayload?: (params: { payload: ReplyPayload }) => ReplyPayload | null; + shouldSkipPlainTextSanitization?: (params: { payload: ReplyPayload }) => boolean; + resolveEffectiveTextChunkLimit?: (params: { + cfg: OpenClawConfig; + accountId?: string | null; + fallbackLimit?: number; + }) => number | undefined; + shouldSuppressLocalPayloadPrompt?: (params: { + cfg: OpenClawConfig; + accountId?: string | null; + payload: ReplyPayload; + hint?: ChannelOutboundPayloadHint; + }) => boolean; + beforeDeliverPayload?: (params: { + cfg: OpenClawConfig; + target: ChannelOutboundTargetRef; + payload: ReplyPayload; + hint?: ChannelOutboundPayloadHint; + }) => Promise | void; + /** + * @deprecated Use shouldTreatDeliveredTextAsVisible instead. + */ + shouldTreatRoutedTextAsVisible?: (params: { + kind: "tool" | "block" | "final"; + text?: string; + }) => boolean; + shouldTreatDeliveredTextAsVisible?: (params: { + kind: "tool" | "block" | "final"; + text?: string; + }) => boolean; + targetsMatchForReplySuppression?: (params: { + originTarget: string; + targetKey: string; + targetThreadId?: string; + }) => boolean; + resolveTarget?: (params: { + cfg?: OpenClawConfig; + to?: string; + allowFrom?: string[]; + accountId?: string | null; + mode?: ChannelOutboundTargetMode; + }) => { ok: true; to: string } | { ok: false; error: Error }; + sendPayload?: (ctx: ChannelOutboundPayloadContext) => Promise; + sendFormattedText?: (ctx: ChannelOutboundFormattedContext) => Promise; + sendFormattedMedia?: ( + ctx: ChannelOutboundFormattedContext & { mediaUrl: string }, + ) => Promise; + sendText?: (ctx: ChannelOutboundContext) => Promise; + sendMedia?: (ctx: ChannelOutboundContext) => Promise; + sendPoll?: (ctx: ChannelPollContext) => Promise; +}; diff --git a/src/channels/plugins/outbound/load.types.ts b/src/channels/plugins/outbound/load.types.ts new file mode 100644 index 00000000000..9d1655b87de --- /dev/null +++ b/src/channels/plugins/outbound/load.types.ts @@ -0,0 +1,6 @@ +import type { ChannelId } from "../channel-id.types.js"; +import type { ChannelOutboundAdapter } from "../outbound.types.js"; + +export type LoadChannelOutboundAdapter = ( + id: ChannelId, +) => Promise; diff --git a/src/channels/plugins/pairing.types.ts b/src/channels/plugins/pairing.types.ts new file mode 100644 index 00000000000..54b5c1c15e9 --- /dev/null +++ b/src/channels/plugins/pairing.types.ts @@ -0,0 +1,13 @@ +import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import type { RuntimeEnv } from "../../runtime.js"; + +export type ChannelPairingAdapter = { + idLabel: string; + normalizeAllowEntry?: (entry: string) => string; + notifyApproval?: (params: { + cfg: OpenClawConfig; + id: string; + accountId?: string; + runtime?: RuntimeEnv; + }) => Promise; +}; diff --git a/src/config/markdown-tables.types.ts b/src/config/markdown-tables.types.ts new file mode 100644 index 00000000000..85daeae4816 --- /dev/null +++ b/src/config/markdown-tables.types.ts @@ -0,0 +1,12 @@ +import type { OpenClawConfig } from "./config.js"; +import type { MarkdownTableMode } from "./types.base.js"; + +export type ResolveMarkdownTableModeParams = { + cfg?: Partial; + channel?: string | null; + accountId?: string | null; +}; + +export type ResolveMarkdownTableMode = ( + params: ResolveMarkdownTableModeParams, +) => MarkdownTableMode; diff --git a/src/gateway/server-broadcast-types.ts b/src/gateway/server-broadcast-types.ts new file mode 100644 index 00000000000..6e18ef07f7b --- /dev/null +++ b/src/gateway/server-broadcast-types.ts @@ -0,0 +1,22 @@ +export type GatewayBroadcastStateVersion = { + presence?: number; + health?: number; +}; + +export type GatewayBroadcastOpts = { + dropIfSlow?: boolean; + stateVersion?: GatewayBroadcastStateVersion; +}; + +export type GatewayBroadcastFn = ( + event: string, + payload: unknown, + opts?: GatewayBroadcastOpts, +) => void; + +export type GatewayBroadcastToConnIdsFn = ( + event: string, + payload: unknown, + connIds: ReadonlySet, + opts?: GatewayBroadcastOpts, +) => void; diff --git a/src/image-generation/runtime-types.ts b/src/image-generation/runtime-types.ts new file mode 100644 index 00000000000..5557a85743a --- /dev/null +++ b/src/image-generation/runtime-types.ts @@ -0,0 +1,40 @@ +import type { AuthProfileStore } from "../agents/auth-profiles.js"; +import type { FallbackAttempt } from "../agents/model-fallback.types.js"; +import type { OpenClawConfig } from "../config/types.openclaw.js"; +import type { + GeneratedImageAsset, + ImageGenerationIgnoredOverride, + ImageGenerationNormalization, + ImageGenerationProvider, + ImageGenerationResolution, + ImageGenerationSourceImage, +} from "./types.js"; + +export type GenerateImageParams = { + cfg: OpenClawConfig; + prompt: string; + agentDir?: string; + authStore?: AuthProfileStore; + modelOverride?: string; + count?: number; + size?: string; + aspectRatio?: string; + resolution?: ImageGenerationResolution; + inputImages?: ImageGenerationSourceImage[]; +}; + +export type GenerateImageRuntimeResult = { + images: GeneratedImageAsset[]; + provider: string; + model: string; + attempts: FallbackAttempt[]; + normalization?: ImageGenerationNormalization; + metadata?: Record; + ignoredOverrides: ImageGenerationIgnoredOverride[]; +}; + +export type ListRuntimeImageGenerationProvidersParams = { + config?: OpenClawConfig; +}; + +export type RuntimeImageGenerationProvider = ImageGenerationProvider; diff --git a/src/media-generation/normalization.types.ts b/src/media-generation/normalization.types.ts new file mode 100644 index 00000000000..633585c8b6a --- /dev/null +++ b/src/media-generation/normalization.types.ts @@ -0,0 +1,15 @@ +export type MediaNormalizationValue = string | number | boolean; + +export type MediaNormalizationEntry = { + requested?: TValue; + applied?: TValue; + derivedFrom?: string; + supportedValues?: readonly TValue[]; +}; + +export type MediaGenerationNormalizationMetadataInput = { + size?: MediaNormalizationEntry; + aspectRatio?: MediaNormalizationEntry; + resolution?: MediaNormalizationEntry; + durationSeconds?: MediaNormalizationEntry; +}; diff --git a/src/music-generation/runtime-types.ts b/src/music-generation/runtime-types.ts new file mode 100644 index 00000000000..5d492ec4d80 --- /dev/null +++ b/src/music-generation/runtime-types.ts @@ -0,0 +1,41 @@ +import type { AuthProfileStore } from "../agents/auth-profiles.js"; +import type { FallbackAttempt } from "../agents/model-fallback.types.js"; +import type { OpenClawConfig } from "../config/types.openclaw.js"; +import type { + GeneratedMusicAsset, + MusicGenerationIgnoredOverride, + MusicGenerationNormalization, + MusicGenerationOutputFormat, + MusicGenerationProvider, + MusicGenerationSourceImage, +} from "./types.js"; + +export type GenerateMusicParams = { + cfg: OpenClawConfig; + prompt: string; + agentDir?: string; + authStore?: AuthProfileStore; + modelOverride?: string; + lyrics?: string; + instrumental?: boolean; + durationSeconds?: number; + format?: MusicGenerationOutputFormat; + inputImages?: MusicGenerationSourceImage[]; +}; + +export type GenerateMusicRuntimeResult = { + tracks: GeneratedMusicAsset[]; + provider: string; + model: string; + attempts: FallbackAttempt[]; + lyrics?: string[]; + normalization?: MusicGenerationNormalization; + metadata?: Record; + ignoredOverrides: MusicGenerationIgnoredOverride[]; +}; + +export type ListRuntimeMusicGenerationProvidersParams = { + config?: OpenClawConfig; +}; + +export type RuntimeMusicGenerationProvider = MusicGenerationProvider; diff --git a/src/plugin-sdk/infra-runtime.test.ts b/src/plugin-sdk/infra-runtime.test.ts new file mode 100644 index 00000000000..48fdf1b3923 --- /dev/null +++ b/src/plugin-sdk/infra-runtime.test.ts @@ -0,0 +1,74 @@ +import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +const mocks = vi.hoisted(() => ({ + coreDrainPendingDeliveries: vi.fn(async () => {}), + deliverOutboundPayloads: vi.fn(async () => []), +})); + +vi.mock("../infra/outbound/delivery-queue.js", () => ({ + drainPendingDeliveries: mocks.coreDrainPendingDeliveries, +})); + +vi.mock("../infra/outbound/deliver-runtime.js", () => ({ + deliverOutboundPayloads: mocks.deliverOutboundPayloads, +})); + +type InfraRuntimeModule = typeof import("./infra-runtime.js"); + +let drainPendingDeliveries: InfraRuntimeModule["drainPendingDeliveries"]; + +const log = { + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), +}; + +beforeAll(async () => { + ({ drainPendingDeliveries } = await import("./infra-runtime.js")); +}); + +beforeEach(() => { + mocks.coreDrainPendingDeliveries.mockClear(); + mocks.deliverOutboundPayloads.mockClear(); + log.info.mockClear(); + log.warn.mockClear(); + log.error.mockClear(); +}); + +describe("plugin-sdk drainPendingDeliveries", () => { + it("injects the lazy outbound deliver runtime when no deliver fn is provided", async () => { + await drainPendingDeliveries({ + drainKey: "whatsapp:test", + logLabel: "WhatsApp reconnect drain", + cfg: {}, + log, + selectEntry: () => ({ match: false }), + }); + + expect(mocks.coreDrainPendingDeliveries).toHaveBeenCalledWith( + expect.objectContaining({ + deliver: mocks.deliverOutboundPayloads, + }), + ); + }); + + it("preserves an explicit deliver fn without loading the lazy runtime", async () => { + const deliver = vi.fn(async () => []); + + await drainPendingDeliveries({ + drainKey: "whatsapp:test", + logLabel: "WhatsApp reconnect drain", + cfg: {}, + log, + deliver, + selectEntry: () => ({ match: false }), + }); + + expect(mocks.coreDrainPendingDeliveries).toHaveBeenCalledWith( + expect.objectContaining({ + deliver, + }), + ); + expect(mocks.deliverOutboundPayloads).not.toHaveBeenCalled(); + }); +}); diff --git a/src/plugins/conversation-binding.types.ts b/src/plugins/conversation-binding.types.ts new file mode 100644 index 00000000000..a4423745047 --- /dev/null +++ b/src/plugins/conversation-binding.types.ts @@ -0,0 +1,56 @@ +import type { ReplyPayload } from "../auto-reply/types.js"; + +export type PluginConversationBindingRequestParams = { + summary?: string; + detachHint?: string; +}; + +export type PluginConversationBindingResolutionDecision = "allow-once" | "allow-always" | "deny"; + +export type PluginConversationBinding = { + bindingId: string; + pluginId: string; + pluginName?: string; + pluginRoot: string; + channel: string; + accountId: string; + conversationId: string; + parentConversationId?: string; + threadId?: string | number; + boundAt: number; + summary?: string; + detachHint?: string; +}; + +export type PluginConversationBindingRequestResult = + | { + status: "bound"; + binding: PluginConversationBinding; + } + | { + status: "pending"; + approvalId: string; + reply: ReplyPayload; + } + | { + status: "error"; + message: string; + }; + +export type PluginConversationBindingResolvedEvent = { + status: "approved" | "denied"; + binding?: PluginConversationBinding; + decision: PluginConversationBindingResolutionDecision; + request: { + summary?: string; + detachHint?: string; + requestedBySenderId?: string; + conversation: { + channel: string; + accountId: string; + conversationId: string; + parentConversationId?: string; + threadId?: string | number; + }; + }; +}; diff --git a/src/plugins/hook-message.types.ts b/src/plugins/hook-message.types.ts new file mode 100644 index 00000000000..ddf82384c4f --- /dev/null +++ b/src/plugins/hook-message.types.ts @@ -0,0 +1,57 @@ +export type PluginHookMessageContext = { + channelId: string; + accountId?: string; + conversationId?: string; +}; + +export type PluginHookInboundClaimContext = PluginHookMessageContext & { + parentConversationId?: string; + senderId?: string; + messageId?: string; +}; + +export type PluginHookInboundClaimEvent = { + content: string; + body?: string; + bodyForAgent?: string; + transcript?: string; + timestamp?: number; + channel: string; + accountId?: string; + conversationId?: string; + parentConversationId?: string; + senderId?: string; + senderName?: string; + senderUsername?: string; + threadId?: string | number; + messageId?: string; + isGroup: boolean; + commandAuthorized?: boolean; + wasMentioned?: boolean; + metadata?: Record; +}; + +export type PluginHookMessageReceivedEvent = { + from: string; + content: string; + timestamp?: number; + metadata?: Record; +}; + +export type PluginHookMessageSendingEvent = { + to: string; + content: string; + metadata?: Record; +}; + +export type PluginHookMessageSendingResult = { + content?: string; + cancel?: boolean; +}; + +export type PluginHookMessageSentEvent = { + to: string; + content: string; + success: boolean; + error?: string; +}; diff --git a/src/plugins/plugin-origin.types.ts b/src/plugins/plugin-origin.types.ts new file mode 100644 index 00000000000..99ba036568b --- /dev/null +++ b/src/plugins/plugin-origin.types.ts @@ -0,0 +1 @@ +export type PluginOrigin = "bundled" | "global" | "workspace" | "config"; diff --git a/src/plugins/provider-external-auth.types.ts b/src/plugins/provider-external-auth.types.ts new file mode 100644 index 00000000000..09bf5b4c8e4 --- /dev/null +++ b/src/plugins/provider-external-auth.types.ts @@ -0,0 +1,34 @@ +import type { AuthProfileStore, OAuthCredential } from "../agents/auth-profiles/types.js"; +import type { ModelProviderAuthMode, ModelProviderConfig } from "../config/types.js"; +import type { OpenClawConfig } from "../config/types.openclaw.js"; + +export type ProviderResolveSyntheticAuthContext = { + config?: OpenClawConfig; + provider: string; + providerConfig?: ModelProviderConfig; +}; + +export type ProviderSyntheticAuthResult = { + apiKey: string; + source: string; + mode: Exclude; +}; + +export type ProviderResolveExternalOAuthProfilesContext = { + config?: OpenClawConfig; + agentDir?: string; + workspaceDir?: string; + env: NodeJS.ProcessEnv; + store: AuthProfileStore; +}; + +export type ProviderResolveExternalAuthProfilesContext = + ProviderResolveExternalOAuthProfilesContext; + +export type ProviderExternalOAuthProfile = { + profileId: string; + credential: OAuthCredential; + persistence?: "runtime-only" | "persisted"; +}; + +export type ProviderExternalAuthProfile = ProviderExternalOAuthProfile; diff --git a/src/plugins/tool-types.ts b/src/plugins/tool-types.ts new file mode 100644 index 00000000000..263a5cc6965 --- /dev/null +++ b/src/plugins/tool-types.ts @@ -0,0 +1,50 @@ +import type { ToolFsPolicy } from "../agents/tool-fs-policy.js"; +import type { AnyAgentTool } from "../agents/tools/common.js"; +import type { OpenClawConfig } from "../config/types.openclaw.js"; +import type { HookEntry } from "../hooks/types.js"; +import type { DeliveryContext } from "../utils/delivery-context.js"; + +/** Trusted execution context passed to plugin-owned agent tool factories. */ +export type OpenClawPluginToolContext = { + config?: OpenClawConfig; + /** Active runtime-resolved config snapshot when one is available. */ + runtimeConfig?: OpenClawConfig; + /** Effective filesystem policy for the active tool run. */ + fsPolicy?: ToolFsPolicy; + workspaceDir?: string; + agentDir?: string; + agentId?: string; + sessionKey?: string; + /** Ephemeral session UUID - regenerated on /new and /reset. Use for per-conversation isolation. */ + sessionId?: string; + browser?: { + sandboxBridgeUrl?: string; + allowHostControl?: boolean; + }; + messageChannel?: string; + agentAccountId?: string; + /** Trusted ambient delivery route for the active agent/session. */ + deliveryContext?: DeliveryContext; + /** Trusted sender id from inbound context (runtime-provided, not tool args). */ + requesterSenderId?: string; + /** Whether the trusted sender is an owner. */ + senderIsOwner?: boolean; + sandboxed?: boolean; +}; + +export type OpenClawPluginToolFactory = ( + ctx: OpenClawPluginToolContext, +) => AnyAgentTool | AnyAgentTool[] | null | undefined; + +export type OpenClawPluginToolOptions = { + name?: string; + names?: string[]; + optional?: boolean; +}; + +export type OpenClawPluginHookOptions = { + entry?: HookEntry; + name?: string; + description?: string; + register?: boolean; +}; diff --git a/src/plugins/web-provider-types.ts b/src/plugins/web-provider-types.ts new file mode 100644 index 00000000000..f17916ce169 --- /dev/null +++ b/src/plugins/web-provider-types.ts @@ -0,0 +1,127 @@ +import type { OpenClawConfig } from "../config/types.openclaw.js"; +import type { RuntimeEnv } from "../runtime.js"; +import type { + RuntimeWebFetchMetadata, + RuntimeWebSearchMetadata, +} from "../secrets/runtime-web-tools.types.js"; +import type { WizardPrompter } from "../wizard/prompts.js"; +import type { SecretInputMode } from "./provider-auth-types.js"; + +export type WebSearchProviderId = string; +export type WebFetchProviderId = string; + +export type WebSearchProviderToolDefinition = { + description: string; + parameters: Record; + execute: (args: Record) => Promise>; +}; + +export type WebFetchProviderToolDefinition = { + description: string; + parameters: Record; + execute: (args: Record) => Promise>; +}; + +export type WebSearchProviderContext = { + config?: OpenClawConfig; + searchConfig?: Record; + runtimeMetadata?: RuntimeWebSearchMetadata; +}; + +export type WebFetchProviderContext = { + config?: OpenClawConfig; + fetchConfig?: Record; + runtimeMetadata?: RuntimeWebFetchMetadata; +}; + +export type WebSearchCredentialResolutionSource = "config" | "secretRef" | "env" | "missing"; + +export type WebSearchRuntimeMetadataContext = { + config?: OpenClawConfig; + searchConfig?: Record; + runtimeMetadata?: RuntimeWebSearchMetadata; + resolvedCredential?: { + value?: string; + source: WebSearchCredentialResolutionSource; + fallbackEnvVar?: string; + }; +}; + +export type WebSearchProviderSetupContext = { + config: OpenClawConfig; + runtime: RuntimeEnv; + prompter: WizardPrompter; + quickstartDefaults?: boolean; + secretInputMode?: SecretInputMode; +}; + +export type WebFetchCredentialResolutionSource = "config" | "secretRef" | "env" | "missing"; + +export type WebFetchRuntimeMetadataContext = { + config?: OpenClawConfig; + fetchConfig?: Record; + runtimeMetadata?: RuntimeWebFetchMetadata; + resolvedCredential?: { + value?: string; + source: WebFetchCredentialResolutionSource; + fallbackEnvVar?: string; + }; +}; + +export type WebSearchProviderPlugin = { + id: WebSearchProviderId; + label: string; + hint: string; + onboardingScopes?: Array<"text-inference">; + requiresCredential?: boolean; + credentialLabel?: string; + envVars: string[]; + placeholder: string; + signupUrl: string; + docsUrl?: string; + autoDetectOrder?: number; + credentialPath: string; + inactiveSecretPaths?: string[]; + getCredentialValue: (searchConfig?: Record) => unknown; + setCredentialValue: (searchConfigTarget: Record, value: unknown) => void; + getConfiguredCredentialValue?: (config?: OpenClawConfig) => unknown; + setConfiguredCredentialValue?: (configTarget: OpenClawConfig, value: unknown) => void; + applySelectionConfig?: (config: OpenClawConfig) => OpenClawConfig; + runSetup?: (ctx: WebSearchProviderSetupContext) => OpenClawConfig | Promise; + resolveRuntimeMetadata?: ( + ctx: WebSearchRuntimeMetadataContext, + ) => Partial | Promise>; + createTool: (ctx: WebSearchProviderContext) => WebSearchProviderToolDefinition | null; +}; + +export type PluginWebSearchProviderEntry = WebSearchProviderPlugin & { + pluginId: string; +}; + +export type WebFetchProviderPlugin = { + id: WebFetchProviderId; + label: string; + hint: string; + requiresCredential?: boolean; + credentialLabel?: string; + envVars: string[]; + placeholder: string; + signupUrl: string; + docsUrl?: string; + autoDetectOrder?: number; + credentialPath: string; + inactiveSecretPaths?: string[]; + getCredentialValue: (fetchConfig?: Record) => unknown; + setCredentialValue: (fetchConfigTarget: Record, value: unknown) => void; + getConfiguredCredentialValue?: (config?: OpenClawConfig) => unknown; + setConfiguredCredentialValue?: (configTarget: OpenClawConfig, value: unknown) => void; + applySelectionConfig?: (config: OpenClawConfig) => OpenClawConfig; + resolveRuntimeMetadata?: ( + ctx: WebFetchRuntimeMetadataContext, + ) => Partial | Promise>; + createTool: (ctx: WebFetchProviderContext) => WebFetchProviderToolDefinition | null; +}; + +export type PluginWebFetchProviderEntry = WebFetchProviderPlugin & { + pluginId: string; +}; diff --git a/src/video-generation/runtime-types.ts b/src/video-generation/runtime-types.ts new file mode 100644 index 00000000000..e89bcb91cf5 --- /dev/null +++ b/src/video-generation/runtime-types.ts @@ -0,0 +1,43 @@ +import type { AuthProfileStore } from "../agents/auth-profiles.js"; +import type { FallbackAttempt } from "../agents/model-fallback.types.js"; +import type { OpenClawConfig } from "../config/types.openclaw.js"; +import type { + GeneratedVideoAsset, + VideoGenerationIgnoredOverride, + VideoGenerationNormalization, + VideoGenerationProvider, + VideoGenerationResolution, + VideoGenerationSourceAsset, +} from "./types.js"; + +export type GenerateVideoParams = { + cfg: OpenClawConfig; + prompt: string; + agentDir?: string; + authStore?: AuthProfileStore; + modelOverride?: string; + size?: string; + aspectRatio?: string; + resolution?: VideoGenerationResolution; + durationSeconds?: number; + audio?: boolean; + watermark?: boolean; + inputImages?: VideoGenerationSourceAsset[]; + inputVideos?: VideoGenerationSourceAsset[]; +}; + +export type GenerateVideoRuntimeResult = { + videos: GeneratedVideoAsset[]; + provider: string; + model: string; + attempts: FallbackAttempt[]; + normalization?: VideoGenerationNormalization; + metadata?: Record; + ignoredOverrides: VideoGenerationIgnoredOverride[]; +}; + +export type ListRuntimeVideoGenerationProvidersParams = { + config?: OpenClawConfig; +}; + +export type RuntimeVideoGenerationProvider = VideoGenerationProvider; diff --git a/src/web-search/runtime-types.ts b/src/web-search/runtime-types.ts new file mode 100644 index 00000000000..641b9500b0f --- /dev/null +++ b/src/web-search/runtime-types.ts @@ -0,0 +1,37 @@ +import type { OpenClawConfig } from "../config/types.openclaw.js"; +import type { + PluginWebSearchProviderEntry, + WebSearchProviderToolDefinition, +} from "../plugins/web-provider-types.js"; +import type { RuntimeWebSearchMetadata } from "../secrets/runtime-web-tools.types.js"; + +type WebSearchConfig = NonNullable["web"] extends infer Web + ? Web extends { search?: infer Search } + ? Search + : undefined + : undefined; + +export type ResolveWebSearchDefinitionParams = { + config?: OpenClawConfig; + sandboxed?: boolean; + runtimeWebSearch?: RuntimeWebSearchMetadata; + providerId?: string; + preferRuntimeProviders?: boolean; +}; + +export type RunWebSearchParams = ResolveWebSearchDefinitionParams & { + args: Record; +}; + +export type RunWebSearchResult = { + provider: string; + result: Record; +}; + +export type ListWebSearchProvidersParams = { + config?: OpenClawConfig; +}; + +export type RuntimeWebSearchProviderEntry = PluginWebSearchProviderEntry; +export type RuntimeWebSearchToolDefinition = WebSearchProviderToolDefinition; +export type RuntimeWebSearchConfig = WebSearchConfig;