mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-24 07:31:44 +00:00
fix(extensions): split shared runtime type seams
This commit is contained in:
@@ -1,21 +1,19 @@
|
||||
import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
|
||||
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
|
||||
import { type OpenClawConfig, type RuntimeEnv } from "../runtime-api.js";
|
||||
import type { MSTeamsConversationStore } from "./conversation-store.js";
|
||||
import { formatUnknownError } from "./errors.js";
|
||||
import { buildFeedbackEvent, runFeedbackReflection } from "./feedback-reflection.js";
|
||||
import { buildFileInfoCard, parseFileConsentInvoke, uploadToConsentUrl } from "./file-consent.js";
|
||||
import { extractMSTeamsConversationMessageId, normalizeMSTeamsConversationId } from "./inbound.js";
|
||||
import type { MSTeamsAdapter } from "./messenger.js";
|
||||
import { resolveMSTeamsSenderAccess } from "./monitor-handler/access.js";
|
||||
import { createMSTeamsMessageHandler } from "./monitor-handler/message-handler.js";
|
||||
import type { MSTeamsMonitorLogger } from "./monitor-types.js";
|
||||
import { getPendingUpload, removePendingUpload } from "./pending-uploads.js";
|
||||
import type { MSTeamsPollStore } from "./polls.js";
|
||||
import { withRevokedProxyFallback } from "./revoked-context.js";
|
||||
import { getMSTeamsRuntime } from "./runtime.js";
|
||||
import type { MSTeamsTurnContext } from "./sdk-types.js";
|
||||
import { buildGroupWelcomeText, buildWelcomeCard } from "./welcome-card.js";
|
||||
export type { MSTeamsMessageHandlerDeps } from "./monitor-handler.types.js";
|
||||
import type { MSTeamsMessageHandlerDeps } from "./monitor-handler.types.js";
|
||||
|
||||
export type MSTeamsAccessTokenProvider = {
|
||||
getAccessToken: (scope: string) => Promise<string>;
|
||||
@@ -37,19 +35,6 @@ export type MSTeamsActivityHandler = {
|
||||
run?: (context: unknown) => Promise<void>;
|
||||
};
|
||||
|
||||
export type MSTeamsMessageHandlerDeps = {
|
||||
cfg: OpenClawConfig;
|
||||
runtime: RuntimeEnv;
|
||||
appId: string;
|
||||
adapter: MSTeamsAdapter;
|
||||
tokenProvider: MSTeamsAccessTokenProvider;
|
||||
textLimit: number;
|
||||
mediaMaxBytes: number;
|
||||
conversationStore: MSTeamsConversationStore;
|
||||
pollStore: MSTeamsPollStore;
|
||||
log: MSTeamsMonitorLogger;
|
||||
};
|
||||
|
||||
function serializeAdaptiveCardActionValue(value: unknown): string | null {
|
||||
if (typeof value === "string") {
|
||||
const trimmed = value.trim();
|
||||
|
||||
20
extensions/msteams/src/monitor-handler.types.ts
Normal file
20
extensions/msteams/src/monitor-handler.types.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { type OpenClawConfig, type RuntimeEnv } from "../runtime-api.js";
|
||||
import type { MSTeamsConversationStore } from "./conversation-store.js";
|
||||
import type { MSTeamsAdapter } from "./messenger.js";
|
||||
import type { MSTeamsMonitorLogger } from "./monitor-types.js";
|
||||
import type { MSTeamsPollStore } from "./polls.js";
|
||||
|
||||
export type MSTeamsMessageHandlerDeps = {
|
||||
cfg: OpenClawConfig;
|
||||
runtime: RuntimeEnv;
|
||||
appId: string;
|
||||
adapter: MSTeamsAdapter;
|
||||
tokenProvider: {
|
||||
getAccessToken: (scope: string) => Promise<string>;
|
||||
};
|
||||
textLimit: number;
|
||||
mediaMaxBytes: number;
|
||||
conversationStore: MSTeamsConversationStore;
|
||||
pollStore: MSTeamsPollStore;
|
||||
log: MSTeamsMonitorLogger;
|
||||
};
|
||||
@@ -75,7 +75,7 @@ function extractTextFromHtmlAttachments(attachments: MSTeamsAttachmentLike[]): s
|
||||
}
|
||||
return "";
|
||||
}
|
||||
import type { MSTeamsMessageHandlerDeps } from "../monitor-handler.js";
|
||||
import type { MSTeamsMessageHandlerDeps } from "../monitor-handler.types.js";
|
||||
import {
|
||||
isMSTeamsGroupAllowed,
|
||||
resolveMSTeamsAllowlistMatch,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import crypto from "node:crypto";
|
||||
import { safeEqualSecret } from "openclaw/plugin-sdk/browser-security-runtime";
|
||||
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
|
||||
import type { TwilioConfig, WebhookSecurityConfig } from "../config.js";
|
||||
import type { TwilioConfig } from "../config.js";
|
||||
import { getHeader } from "../http-headers.js";
|
||||
import type { MediaStreamHandler } from "../media-stream.js";
|
||||
import { chunkAudio } from "../telephony-audio.js";
|
||||
@@ -29,13 +29,11 @@ import {
|
||||
normalizeProviderStatus,
|
||||
} from "./shared/call-status.js";
|
||||
import { guardedJsonApiRequest } from "./shared/guarded-json-api.js";
|
||||
import type { TwilioProviderOptions } from "./twilio.types.js";
|
||||
import { twilioApiRequest } from "./twilio/api.js";
|
||||
import { decideTwimlResponse, readTwimlRequestView } from "./twilio/twiml-policy.js";
|
||||
import { verifyTwilioProviderWebhook } from "./twilio/webhook.js";
|
||||
|
||||
type StreamSendResult = {
|
||||
sent: boolean;
|
||||
};
|
||||
export type { TwilioProviderOptions } from "./twilio.types.js";
|
||||
|
||||
function createTwilioRequestDedupeKey(ctx: WebhookContext, verifiedRequestKey?: string): string {
|
||||
if (verifiedRequestKey) {
|
||||
@@ -58,27 +56,9 @@ function createTwilioRequestDedupeKey(ctx: WebhookContext, verifiedRequestKey?:
|
||||
.digest("hex")}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Twilio Voice API provider implementation.
|
||||
*
|
||||
* Uses Twilio Programmable Voice API with Media Streams for real-time
|
||||
* bidirectional audio streaming.
|
||||
*
|
||||
* @see https://www.twilio.com/docs/voice
|
||||
* @see https://www.twilio.com/docs/voice/media-streams
|
||||
*/
|
||||
export interface TwilioProviderOptions {
|
||||
/** Allow ngrok free tier compatibility mode (loopback only, less secure) */
|
||||
allowNgrokFreeTierLoopbackBypass?: boolean;
|
||||
/** Override public URL for signature verification */
|
||||
publicUrl?: string;
|
||||
/** Path for media stream WebSocket (e.g., /voice/stream) */
|
||||
streamPath?: string;
|
||||
/** Skip webhook signature verification (development only) */
|
||||
skipVerification?: boolean;
|
||||
/** Webhook security options (forwarded headers/allowlist) */
|
||||
webhookSecurity?: WebhookSecurityConfig;
|
||||
}
|
||||
type StreamSendResult = {
|
||||
sent: boolean;
|
||||
};
|
||||
|
||||
export class TwilioProvider implements VoiceCallProvider {
|
||||
readonly name = "twilio" as const;
|
||||
|
||||
17
extensions/voice-call/src/providers/twilio.types.ts
Normal file
17
extensions/voice-call/src/providers/twilio.types.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { WebhookSecurityConfig } from "../config.js";
|
||||
|
||||
/**
|
||||
* Twilio Voice API provider options.
|
||||
*/
|
||||
export interface TwilioProviderOptions {
|
||||
/** Allow ngrok free tier compatibility mode (loopback only, less secure) */
|
||||
allowNgrokFreeTierLoopbackBypass?: boolean;
|
||||
/** Override public URL for signature verification */
|
||||
publicUrl?: string;
|
||||
/** Path for media stream WebSocket (e.g., /voice/stream) */
|
||||
streamPath?: string;
|
||||
/** Skip webhook signature verification (development only) */
|
||||
skipVerification?: boolean;
|
||||
/** Webhook security options (forwarded headers/allowlist) */
|
||||
webhookSecurity?: WebhookSecurityConfig;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { WebhookContext, WebhookVerificationResult } from "../../types.js";
|
||||
import { verifyTwilioWebhook } from "../../webhook-security.js";
|
||||
import type { TwilioProviderOptions } from "../twilio.js";
|
||||
import type { TwilioProviderOptions } from "../twilio.types.js";
|
||||
|
||||
export function verifyTwilioProviderWebhook(params: {
|
||||
ctx: WebhookContext;
|
||||
|
||||
@@ -22,6 +22,7 @@ import type { VoiceCallProvider } from "./providers/base.js";
|
||||
import { isProviderStatusTerminal } from "./providers/shared/call-status.js";
|
||||
import type { TwilioProvider } from "./providers/twilio.js";
|
||||
import type { CallRecord, NormalizedEvent, WebhookContext } from "./types.js";
|
||||
import type { WebhookResponsePayload } from "./webhook.types.js";
|
||||
import type { RealtimeCallHandler } from "./webhook/realtime-handler.js";
|
||||
import { startStaleCallReaper } from "./webhook/stale-call-reaper.js";
|
||||
|
||||
@@ -48,12 +49,6 @@ function sanitizeTranscriptForLog(value: string): string {
|
||||
return `${sanitized.slice(0, TRANSCRIPT_LOG_MAX_CHARS)}...`;
|
||||
}
|
||||
|
||||
export type WebhookResponsePayload = {
|
||||
statusCode: number;
|
||||
body: string;
|
||||
headers?: Record<string, string>;
|
||||
};
|
||||
|
||||
function buildRequestUrl(
|
||||
requestUrl: string | undefined,
|
||||
requestHost: string | undefined,
|
||||
|
||||
5
extensions/voice-call/src/webhook.types.ts
Normal file
5
extensions/voice-call/src/webhook.types.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export type WebhookResponsePayload = {
|
||||
statusCode: number;
|
||||
body: string;
|
||||
headers?: Record<string, string>;
|
||||
};
|
||||
@@ -12,7 +12,7 @@ import type { VoiceCallRealtimeConfig } from "../config.js";
|
||||
import type { CallManager } from "../manager.js";
|
||||
import type { VoiceCallProvider } from "../providers/base.js";
|
||||
import type { CallRecord, NormalizedEvent } from "../types.js";
|
||||
import type { WebhookResponsePayload } from "../webhook.js";
|
||||
import type { WebhookResponsePayload } from "../webhook.types.js";
|
||||
|
||||
export type ToolHandlerFn = (args: unknown, callId: string) => Promise<unknown>;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { XaiWebSearchResponse } from "./web-search-shared.js";
|
||||
import type { XaiWebSearchResponse } from "./web-search-response.types.js";
|
||||
|
||||
export const XAI_RESPONSES_ENDPOINT = "https://api.x.ai/v1/responses";
|
||||
|
||||
|
||||
25
extensions/xai/src/web-search-response.types.ts
Normal file
25
extensions/xai/src/web-search-response.types.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export type XaiWebSearchResponse = {
|
||||
output?: Array<{
|
||||
type?: string;
|
||||
text?: string;
|
||||
content?: Array<{
|
||||
type?: string;
|
||||
text?: string;
|
||||
annotations?: Array<{
|
||||
type?: string;
|
||||
url?: string;
|
||||
}>;
|
||||
}>;
|
||||
annotations?: Array<{
|
||||
type?: string;
|
||||
url?: string;
|
||||
}>;
|
||||
}>;
|
||||
output_text?: string;
|
||||
citations?: string[];
|
||||
inline_citations?: Array<{
|
||||
start_index: number;
|
||||
end_index: number;
|
||||
url: string;
|
||||
}>;
|
||||
};
|
||||
@@ -7,37 +7,13 @@ import {
|
||||
XAI_RESPONSES_ENDPOINT,
|
||||
} from "./responses-tool-shared.js";
|
||||
import { isRecord } from "./tool-config-shared.js";
|
||||
import type { XaiWebSearchResponse } from "./web-search-response.types.js";
|
||||
export { extractXaiWebSearchContent } from "./responses-tool-shared.js";
|
||||
export type { XaiWebSearchResponse } from "./web-search-response.types.js";
|
||||
|
||||
export const XAI_WEB_SEARCH_ENDPOINT = XAI_RESPONSES_ENDPOINT;
|
||||
export const XAI_DEFAULT_WEB_SEARCH_MODEL = "grok-4-1-fast";
|
||||
|
||||
export type XaiWebSearchResponse = {
|
||||
output?: Array<{
|
||||
type?: string;
|
||||
text?: string;
|
||||
content?: Array<{
|
||||
type?: string;
|
||||
text?: string;
|
||||
annotations?: Array<{
|
||||
type?: string;
|
||||
url?: string;
|
||||
}>;
|
||||
}>;
|
||||
annotations?: Array<{
|
||||
type?: string;
|
||||
url?: string;
|
||||
}>;
|
||||
}>;
|
||||
output_text?: string;
|
||||
citations?: string[];
|
||||
inline_citations?: Array<{
|
||||
start_index: number;
|
||||
end_index: number;
|
||||
url: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
type XaiWebSearchConfig = Record<string, unknown> & {
|
||||
model?: unknown;
|
||||
inlineCitations?: unknown;
|
||||
|
||||
Reference in New Issue
Block a user