mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-26 16:06:16 +00:00
fix: stabilize model catalog and pi discovery auth storage compatibility
This commit is contained in:
@@ -5,7 +5,8 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
|||||||
const sendMessageMatrixMock = vi.hoisted(() => vi.fn().mockResolvedValue({ messageId: "mx-1" }));
|
const sendMessageMatrixMock = vi.hoisted(() => vi.fn().mockResolvedValue({ messageId: "mx-1" }));
|
||||||
|
|
||||||
vi.mock("../send.js", () => ({
|
vi.mock("../send.js", () => ({
|
||||||
sendMessageMatrix: (...args: unknown[]) => sendMessageMatrixMock(...args),
|
sendMessageMatrix: (to: string, message: string, opts?: unknown) =>
|
||||||
|
sendMessageMatrixMock(to, message, opts),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
import { setMatrixRuntime } from "../../runtime.js";
|
import { setMatrixRuntime } from "../../runtime.js";
|
||||||
@@ -20,14 +21,14 @@ describe("deliverMatrixReplies", () => {
|
|||||||
|
|
||||||
const runtimeStub = {
|
const runtimeStub = {
|
||||||
config: {
|
config: {
|
||||||
loadConfig: (...args: unknown[]) => loadConfigMock(...args),
|
loadConfig: () => loadConfigMock(),
|
||||||
},
|
},
|
||||||
channel: {
|
channel: {
|
||||||
text: {
|
text: {
|
||||||
resolveMarkdownTableMode: (...args: unknown[]) => resolveMarkdownTableModeMock(...args),
|
resolveMarkdownTableMode: () => resolveMarkdownTableModeMock(),
|
||||||
convertMarkdownTables: (...args: unknown[]) => convertMarkdownTablesMock(...args),
|
convertMarkdownTables: (text: string) => convertMarkdownTablesMock(text),
|
||||||
resolveChunkMode: (...args: unknown[]) => resolveChunkModeMock(...args),
|
resolveChunkMode: () => resolveChunkModeMock(),
|
||||||
chunkMarkdownTextWithMode: (...args: unknown[]) => chunkMarkdownTextWithModeMock(...args),
|
chunkMarkdownTextWithMode: (text: string) => chunkMarkdownTextWithModeMock(text),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
logging: {
|
logging: {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { type Api, completeSimple, type Model } from "@mariozechner/pi-ai";
|
|
||||||
import { randomUUID } from "node:crypto";
|
import { randomUUID } from "node:crypto";
|
||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
import { type Api, completeSimple, type Model } from "@mariozechner/pi-ai";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import {
|
import {
|
||||||
ANTHROPIC_SETUP_TOKEN_PREFIX,
|
ANTHROPIC_SETUP_TOKEN_PREFIX,
|
||||||
|
|||||||
@@ -67,6 +67,14 @@ export function __setModelCatalogImportForTest(loader?: () => Promise<PiSdkModul
|
|||||||
importPiSdk = loader ?? defaultImportPiSdk;
|
importPiSdk = loader ?? defaultImportPiSdk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createAuthStorage(AuthStorageLike: unknown, path: string) {
|
||||||
|
const withFactory = AuthStorageLike as { create?: (path: string) => unknown };
|
||||||
|
if (typeof withFactory.create === "function") {
|
||||||
|
return withFactory.create(path);
|
||||||
|
}
|
||||||
|
return new (AuthStorageLike as { new (path: string): unknown })(path);
|
||||||
|
}
|
||||||
|
|
||||||
export async function loadModelCatalog(params?: {
|
export async function loadModelCatalog(params?: {
|
||||||
config?: OpenClawConfig;
|
config?: OpenClawConfig;
|
||||||
useCache?: boolean;
|
useCache?: boolean;
|
||||||
@@ -101,12 +109,17 @@ export async function loadModelCatalog(params?: {
|
|||||||
const piSdk = await importPiSdk();
|
const piSdk = await importPiSdk();
|
||||||
const agentDir = resolveOpenClawAgentDir();
|
const agentDir = resolveOpenClawAgentDir();
|
||||||
const { join } = await import("node:path");
|
const { join } = await import("node:path");
|
||||||
const authStorage = new piSdk.AuthStorage(join(agentDir, "auth.json"));
|
const authStorage = createAuthStorage(piSdk.AuthStorage, join(agentDir, "auth.json"));
|
||||||
const registry = new piSdk.ModelRegistry(authStorage, join(agentDir, "models.json")) as
|
const registry = new (piSdk.ModelRegistry as unknown as {
|
||||||
| {
|
new (
|
||||||
getAll: () => Array<DiscoveredModel>;
|
authStorage: unknown,
|
||||||
}
|
modelsFile: string,
|
||||||
| Array<DiscoveredModel>;
|
):
|
||||||
|
| Array<DiscoveredModel>
|
||||||
|
| {
|
||||||
|
getAll: () => Array<DiscoveredModel>;
|
||||||
|
};
|
||||||
|
})(authStorage, join(agentDir, "models.json"));
|
||||||
const entries = Array.isArray(registry) ? registry : registry.getAll();
|
const entries = Array.isArray(registry) ? registry : registry.getAll();
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
const id = String(entry?.id ?? "").trim();
|
const id = String(entry?.id ?? "").trim();
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { Api, Model } from "@mariozechner/pi-ai";
|
import type { Api, Model } from "@mariozechner/pi-ai";
|
||||||
import type { ModelRegistry } from "./pi-model-discovery.js";
|
|
||||||
import { DEFAULT_CONTEXT_TOKENS } from "./defaults.js";
|
import { DEFAULT_CONTEXT_TOKENS } from "./defaults.js";
|
||||||
import { normalizeModelCompat } from "./model-compat.js";
|
import { normalizeModelCompat } from "./model-compat.js";
|
||||||
import { normalizeProviderId } from "./model-selection.js";
|
import { normalizeProviderId } from "./model-selection.js";
|
||||||
|
import type { ModelRegistry } from "./pi-model-discovery.js";
|
||||||
|
|
||||||
const OPENAI_CODEX_GPT_53_MODEL_ID = "gpt-5.3-codex";
|
const OPENAI_CODEX_GPT_53_MODEL_ID = "gpt-5.3-codex";
|
||||||
const OPENAI_CODEX_TEMPLATE_MODEL_IDS = ["gpt-5.2-codex"] as const;
|
const OPENAI_CODEX_TEMPLATE_MODEL_IDS = ["gpt-5.2-codex"] as const;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
import type { ModelCatalogEntry } from "./model-catalog.js";
|
|
||||||
import { resolveAgentModelPrimary } from "./agent-scope.js";
|
import { resolveAgentModelPrimary } from "./agent-scope.js";
|
||||||
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "./defaults.js";
|
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "./defaults.js";
|
||||||
|
import type { ModelCatalogEntry } from "./model-catalog.js";
|
||||||
import { normalizeGoogleModelId } from "./models-config.providers.js";
|
import { normalizeGoogleModelId } from "./models-config.providers.js";
|
||||||
|
|
||||||
export type ModelRef = {
|
export type ModelRef = {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
import type { GatewayMessageChannel } from "../utils/message-channel.js";
|
|
||||||
import type { SandboxFsBridge } from "./sandbox/fs-bridge.js";
|
|
||||||
import type { AnyAgentTool } from "./tools/common.js";
|
|
||||||
import { resolvePluginTools } from "../plugins/tools.js";
|
import { resolvePluginTools } from "../plugins/tools.js";
|
||||||
|
import type { GatewayMessageChannel } from "../utils/message-channel.js";
|
||||||
import { resolveSessionAgentId } from "./agent-scope.js";
|
import { resolveSessionAgentId } from "./agent-scope.js";
|
||||||
|
import type { SandboxFsBridge } from "./sandbox/fs-bridge.js";
|
||||||
import { createAgentsListTool } from "./tools/agents-list-tool.js";
|
import { createAgentsListTool } from "./tools/agents-list-tool.js";
|
||||||
import { createBrowserTool } from "./tools/browser-tool.js";
|
import { createBrowserTool } from "./tools/browser-tool.js";
|
||||||
import { createCanvasTool } from "./tools/canvas-tool.js";
|
import { createCanvasTool } from "./tools/canvas-tool.js";
|
||||||
|
import type { AnyAgentTool } from "./tools/common.js";
|
||||||
import { createCronTool } from "./tools/cron-tool.js";
|
import { createCronTool } from "./tools/cron-tool.js";
|
||||||
import { createGatewayTool } from "./tools/gateway-tool.js";
|
import { createGatewayTool } from "./tools/gateway-tool.js";
|
||||||
import { createImageTool } from "./tools/image-tool.js";
|
import { createImageTool } from "./tools/image-tool.js";
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import fs from "node:fs/promises";
|
||||||
|
import os from "node:os";
|
||||||
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
||||||
import {
|
import {
|
||||||
createAgentSession,
|
createAgentSession,
|
||||||
@@ -5,14 +7,10 @@ import {
|
|||||||
SessionManager,
|
SessionManager,
|
||||||
SettingsManager,
|
SettingsManager,
|
||||||
} from "@mariozechner/pi-coding-agent";
|
} from "@mariozechner/pi-coding-agent";
|
||||||
import fs from "node:fs/promises";
|
|
||||||
import os from "node:os";
|
|
||||||
import type { ReasoningLevel, ThinkLevel } from "../../auto-reply/thinking.js";
|
|
||||||
import type { OpenClawConfig } from "../../config/config.js";
|
|
||||||
import type { ExecElevatedDefaults } from "../bash-tools.js";
|
|
||||||
import type { EmbeddedPiCompactResult } from "./types.js";
|
|
||||||
import { resolveHeartbeatPrompt } from "../../auto-reply/heartbeat.js";
|
import { resolveHeartbeatPrompt } from "../../auto-reply/heartbeat.js";
|
||||||
|
import type { ReasoningLevel, ThinkLevel } from "../../auto-reply/thinking.js";
|
||||||
import { resolveChannelCapabilities } from "../../config/channel-capabilities.js";
|
import { resolveChannelCapabilities } from "../../config/channel-capabilities.js";
|
||||||
|
import type { OpenClawConfig } from "../../config/config.js";
|
||||||
import { getMachineDisplayName } from "../../infra/machine-name.js";
|
import { getMachineDisplayName } from "../../infra/machine-name.js";
|
||||||
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
|
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
|
||||||
import { type enqueueCommand, enqueueCommandInLane } from "../../process/command-queue.js";
|
import { type enqueueCommand, enqueueCommandInLane } from "../../process/command-queue.js";
|
||||||
@@ -26,6 +24,7 @@ import { normalizeMessageChannel } from "../../utils/message-channel.js";
|
|||||||
import { isReasoningTagProvider } from "../../utils/provider-utils.js";
|
import { isReasoningTagProvider } from "../../utils/provider-utils.js";
|
||||||
import { resolveOpenClawAgentDir } from "../agent-paths.js";
|
import { resolveOpenClawAgentDir } from "../agent-paths.js";
|
||||||
import { resolveSessionAgentIds } from "../agent-scope.js";
|
import { resolveSessionAgentIds } from "../agent-scope.js";
|
||||||
|
import type { ExecElevatedDefaults } from "../bash-tools.js";
|
||||||
import { makeBootstrapWarn, resolveBootstrapContextForRun } from "../bootstrap-files.js";
|
import { makeBootstrapWarn, resolveBootstrapContextForRun } from "../bootstrap-files.js";
|
||||||
import { listChannelSupportedActions, resolveChannelMessageToolHints } from "../channel-tools.js";
|
import { listChannelSupportedActions, resolveChannelMessageToolHints } from "../channel-tools.js";
|
||||||
import { formatUserTime, resolveUserTimeFormat, resolveUserTimezone } from "../date-time.js";
|
import { formatUserTime, resolveUserTimeFormat, resolveUserTimezone } from "../date-time.js";
|
||||||
@@ -82,6 +81,7 @@ import {
|
|||||||
createSystemPromptOverride,
|
createSystemPromptOverride,
|
||||||
} from "./system-prompt.js";
|
} from "./system-prompt.js";
|
||||||
import { splitSdkTools } from "./tool-split.js";
|
import { splitSdkTools } from "./tool-split.js";
|
||||||
|
import type { EmbeddedPiCompactResult } from "./types.js";
|
||||||
import { describeUnknownError, mapThinkingLevel } from "./utils.js";
|
import { describeUnknownError, mapThinkingLevel } from "./utils.js";
|
||||||
import { flushPendingToolResultsAfterIdle } from "./wait-for-idle-before-flush.js";
|
import { flushPendingToolResultsAfterIdle } from "./wait-for-idle-before-flush.js";
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
|
import { EventEmitter } from "node:events";
|
||||||
import type { AgentMessage, AgentTool } from "@mariozechner/pi-agent-core";
|
import type { AgentMessage, AgentTool } from "@mariozechner/pi-agent-core";
|
||||||
import type { SessionManager } from "@mariozechner/pi-coding-agent";
|
import type { SessionManager } from "@mariozechner/pi-coding-agent";
|
||||||
import type { TSchema } from "@sinclair/typebox";
|
import type { TSchema } from "@sinclair/typebox";
|
||||||
import { EventEmitter } from "node:events";
|
|
||||||
import type { OpenClawConfig } from "../../config/config.js";
|
import type { OpenClawConfig } from "../../config/config.js";
|
||||||
import type { TranscriptPolicy } from "../transcript-policy.js";
|
|
||||||
import { registerUnhandledRejectionHandler } from "../../infra/unhandled-rejections.js";
|
import { registerUnhandledRejectionHandler } from "../../infra/unhandled-rejections.js";
|
||||||
import {
|
import {
|
||||||
hasInterSessionUserProvenance,
|
hasInterSessionUserProvenance,
|
||||||
@@ -23,6 +22,7 @@ import {
|
|||||||
stripToolResultDetails,
|
stripToolResultDetails,
|
||||||
sanitizeToolUseResultPairing,
|
sanitizeToolUseResultPairing,
|
||||||
} from "../session-transcript-repair.js";
|
} from "../session-transcript-repair.js";
|
||||||
|
import type { TranscriptPolicy } from "../transcript-policy.js";
|
||||||
import { resolveTranscriptPolicy } from "../transcript-policy.js";
|
import { resolveTranscriptPolicy } from "../transcript-policy.js";
|
||||||
import { log } from "./logger.js";
|
import { log } from "./logger.js";
|
||||||
import { describeUnknownError } from "./utils.js";
|
import { describeUnknownError } from "./utils.js";
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
|
import fs from "node:fs/promises";
|
||||||
|
import os from "node:os";
|
||||||
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
||||||
import type { ImageContent } from "@mariozechner/pi-ai";
|
import type { ImageContent } from "@mariozechner/pi-ai";
|
||||||
import { streamSimple } from "@mariozechner/pi-ai";
|
import { streamSimple } from "@mariozechner/pi-ai";
|
||||||
import { createAgentSession, SessionManager, SettingsManager } from "@mariozechner/pi-coding-agent";
|
import { createAgentSession, SessionManager, SettingsManager } from "@mariozechner/pi-coding-agent";
|
||||||
import fs from "node:fs/promises";
|
|
||||||
import os from "node:os";
|
|
||||||
import type { EmbeddedRunAttemptParams, EmbeddedRunAttemptResult } from "./types.js";
|
|
||||||
import { resolveHeartbeatPrompt } from "../../../auto-reply/heartbeat.js";
|
import { resolveHeartbeatPrompt } from "../../../auto-reply/heartbeat.js";
|
||||||
import { resolveChannelCapabilities } from "../../../config/channel-capabilities.js";
|
import { resolveChannelCapabilities } from "../../../config/channel-capabilities.js";
|
||||||
import { getMachineDisplayName } from "../../../infra/machine-name.js";
|
import { getMachineDisplayName } from "../../../infra/machine-name.js";
|
||||||
@@ -107,6 +106,7 @@ import {
|
|||||||
shouldFlagCompactionTimeout,
|
shouldFlagCompactionTimeout,
|
||||||
} from "./compaction-timeout.js";
|
} from "./compaction-timeout.js";
|
||||||
import { detectAndLoadPromptImages } from "./images.js";
|
import { detectAndLoadPromptImages } from "./images.js";
|
||||||
|
import type { EmbeddedRunAttemptParams, EmbeddedRunAttemptResult } from "./types.js";
|
||||||
|
|
||||||
export function injectHistoryImagesIntoMessages(
|
export function injectHistoryImagesIntoMessages(
|
||||||
messages: AgentMessage[],
|
messages: AgentMessage[],
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { ImageContent } from "@mariozechner/pi-ai";
|
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import type { ImageSanitizationLimits } from "../../image-sanitization.js";
|
import type { ImageContent } from "@mariozechner/pi-ai";
|
||||||
import type { SandboxFsBridge } from "../../sandbox/fs-bridge.js";
|
|
||||||
import { resolveUserPath } from "../../../utils.js";
|
import { resolveUserPath } from "../../../utils.js";
|
||||||
import { loadWebMedia } from "../../../web/media.js";
|
import { loadWebMedia } from "../../../web/media.js";
|
||||||
|
import type { ImageSanitizationLimits } from "../../image-sanitization.js";
|
||||||
|
import type { SandboxFsBridge } from "../../sandbox/fs-bridge.js";
|
||||||
import { sanitizeImageBlocks } from "../../tool-images.js";
|
import { sanitizeImageBlocks } from "../../tool-images.js";
|
||||||
import { log } from "../logger.js";
|
import { log } from "../logger.js";
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,17 @@ import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
|
|||||||
|
|
||||||
export { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
|
export { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
|
||||||
|
|
||||||
|
function createAuthStorage(AuthStorageLike: unknown, path: string) {
|
||||||
|
const withFactory = AuthStorageLike as { create?: (path: string) => unknown };
|
||||||
|
if (typeof withFactory.create === "function") {
|
||||||
|
return withFactory.create(path) as AuthStorage;
|
||||||
|
}
|
||||||
|
return new (AuthStorageLike as { new (path: string): unknown })(path) as AuthStorage;
|
||||||
|
}
|
||||||
|
|
||||||
// Compatibility helpers for pi-coding-agent 0.50+ (discover* helpers removed).
|
// Compatibility helpers for pi-coding-agent 0.50+ (discover* helpers removed).
|
||||||
export function discoverAuthStorage(agentDir: string): AuthStorage {
|
export function discoverAuthStorage(agentDir: string): AuthStorage {
|
||||||
return new AuthStorage(path.join(agentDir, "auth.json"));
|
return createAuthStorage(AuthStorage, path.join(agentDir, "auth.json"));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function discoverModels(authStorage: AuthStorage, agentDir: string): ModelRegistry {
|
export function discoverModels(authStorage: AuthStorage, agentDir: string): ModelRegistry {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import type { AgentTool } from "@mariozechner/pi-agent-core";
|
import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core";
|
||||||
import { Type } from "@sinclair/typebox";
|
import { Type } from "@sinclair/typebox";
|
||||||
import { describe, expect, it, vi } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
import "./test-helpers/fast-coding-tools.js";
|
import "./test-helpers/fast-coding-tools.js";
|
||||||
@@ -577,6 +577,17 @@ describe("createOpenClawCodingTools", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("strips truncation.content details from read results while preserving other fields", async () => {
|
it("strips truncation.content details from read results while preserving other fields", async () => {
|
||||||
|
const readResult: AgentToolResult<unknown> = {
|
||||||
|
content: [{ type: "text" as const, text: "line-0001" }],
|
||||||
|
details: {
|
||||||
|
truncation: {
|
||||||
|
truncated: true,
|
||||||
|
outputLines: 1,
|
||||||
|
firstLineExceedsLimit: false,
|
||||||
|
content: "hidden duplicate payload",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
const baseRead: AgentTool = {
|
const baseRead: AgentTool = {
|
||||||
name: "read",
|
name: "read",
|
||||||
label: "read",
|
label: "read",
|
||||||
@@ -586,17 +597,7 @@ describe("createOpenClawCodingTools", () => {
|
|||||||
offset: Type.Optional(Type.Number()),
|
offset: Type.Optional(Type.Number()),
|
||||||
limit: Type.Optional(Type.Number()),
|
limit: Type.Optional(Type.Number()),
|
||||||
}),
|
}),
|
||||||
execute: vi.fn(async () => ({
|
execute: vi.fn(async () => readResult),
|
||||||
content: [{ type: "text", text: "line-0001" }],
|
|
||||||
details: {
|
|
||||||
truncation: {
|
|
||||||
truncated: true,
|
|
||||||
outputLines: 1,
|
|
||||||
firstLineExceedsLimit: false,
|
|
||||||
content: "hidden duplicate payload",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const wrapped = createOpenClawReadTool(
|
const wrapped = createOpenClawReadTool(
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
||||||
import { createEditTool, createReadTool, createWriteTool } from "@mariozechner/pi-coding-agent";
|
import { createEditTool, createReadTool, createWriteTool } from "@mariozechner/pi-coding-agent";
|
||||||
import type { ImageSanitizationLimits } from "./image-sanitization.js";
|
|
||||||
import type { AnyAgentTool } from "./pi-tools.types.js";
|
|
||||||
import type { SandboxFsBridge } from "./sandbox/fs-bridge.js";
|
|
||||||
import { detectMime } from "../media/mime.js";
|
import { detectMime } from "../media/mime.js";
|
||||||
import { sniffMimeFromBase64 } from "../media/sniff-mime-from-base64.js";
|
import { sniffMimeFromBase64 } from "../media/sniff-mime-from-base64.js";
|
||||||
|
import type { ImageSanitizationLimits } from "./image-sanitization.js";
|
||||||
|
import type { AnyAgentTool } from "./pi-tools.types.js";
|
||||||
import { assertSandboxPath } from "./sandbox-paths.js";
|
import { assertSandboxPath } from "./sandbox-paths.js";
|
||||||
|
import type { SandboxFsBridge } from "./sandbox/fs-bridge.js";
|
||||||
import { sanitizeToolResultImages } from "./tool-images.js";
|
import { sanitizeToolResultImages } from "./tool-images.js";
|
||||||
|
|
||||||
// NOTE(steipete): Upstream read now does file-magic MIME detection; we keep the wrapper
|
// NOTE(steipete): Upstream read now does file-magic MIME detection; we keep the wrapper
|
||||||
|
|||||||
@@ -7,9 +7,6 @@ import {
|
|||||||
} from "@mariozechner/pi-coding-agent";
|
} from "@mariozechner/pi-coding-agent";
|
||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
import type { ToolLoopDetectionConfig } from "../config/types.tools.js";
|
import type { ToolLoopDetectionConfig } from "../config/types.tools.js";
|
||||||
import type { ModelAuthMode } from "./model-auth.js";
|
|
||||||
import type { AnyAgentTool } from "./pi-tools.types.js";
|
|
||||||
import type { SandboxContext } from "./sandbox.js";
|
|
||||||
import { logWarn } from "../logger.js";
|
import { logWarn } from "../logger.js";
|
||||||
import { getPluginToolMeta } from "../plugins/tools.js";
|
import { getPluginToolMeta } from "../plugins/tools.js";
|
||||||
import { isSubagentSessionKey } from "../routing/session-key.js";
|
import { isSubagentSessionKey } from "../routing/session-key.js";
|
||||||
@@ -24,6 +21,7 @@ import {
|
|||||||
} from "./bash-tools.js";
|
} from "./bash-tools.js";
|
||||||
import { listChannelAgentTools } from "./channel-tools.js";
|
import { listChannelAgentTools } from "./channel-tools.js";
|
||||||
import { resolveImageSanitizationLimits } from "./image-sanitization.js";
|
import { resolveImageSanitizationLimits } from "./image-sanitization.js";
|
||||||
|
import type { ModelAuthMode } from "./model-auth.js";
|
||||||
import { createOpenClawTools } from "./openclaw-tools.js";
|
import { createOpenClawTools } from "./openclaw-tools.js";
|
||||||
import { wrapToolWithAbortSignal } from "./pi-tools.abort.js";
|
import { wrapToolWithAbortSignal } from "./pi-tools.abort.js";
|
||||||
import { wrapToolWithBeforeToolCallHook } from "./pi-tools.before-tool-call.js";
|
import { wrapToolWithBeforeToolCallHook } from "./pi-tools.before-tool-call.js";
|
||||||
@@ -46,6 +44,8 @@ import {
|
|||||||
wrapToolParamNormalization,
|
wrapToolParamNormalization,
|
||||||
} from "./pi-tools.read.js";
|
} from "./pi-tools.read.js";
|
||||||
import { cleanToolSchemaForGemini, normalizeToolParameters } from "./pi-tools.schema.js";
|
import { cleanToolSchemaForGemini, normalizeToolParameters } from "./pi-tools.schema.js";
|
||||||
|
import type { AnyAgentTool } from "./pi-tools.types.js";
|
||||||
|
import type { SandboxContext } from "./sandbox.js";
|
||||||
import { getSubagentDepthFromSessionStore } from "./subagent-depth.js";
|
import { getSubagentDepthFromSessionStore } from "./subagent-depth.js";
|
||||||
import {
|
import {
|
||||||
applyToolPolicyPipeline,
|
applyToolPolicyPipeline,
|
||||||
|
|||||||
@@ -477,7 +477,11 @@ export function buildWorkspaceSkillSnapshot(
|
|||||||
? `⚠️ Skills truncated: included ${skillsForPrompt.length} of ${resolvedSkills.length}. Run \`openclaw skills check\` to audit.`
|
? `⚠️ Skills truncated: included ${skillsForPrompt.length} of ${resolvedSkills.length}. Run \`openclaw skills check\` to audit.`
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const prompt = [remoteNote, truncationNote, formatSkillsForPrompt(compactSkillPaths(skillsForPrompt))]
|
const prompt = [
|
||||||
|
remoteNote,
|
||||||
|
truncationNote,
|
||||||
|
formatSkillsForPrompt(compactSkillPaths(skillsForPrompt)),
|
||||||
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
const skillFilter = normalizeSkillFilter(opts?.skillFilter);
|
const skillFilter = normalizeSkillFilter(opts?.skillFilter);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Type } from "@sinclair/typebox";
|
|
||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import type { OpenClawConfig } from "../../config/config.js";
|
import { Type } from "@sinclair/typebox";
|
||||||
import { writeBase64ToFile } from "../../cli/nodes-camera.js";
|
import { writeBase64ToFile } from "../../cli/nodes-camera.js";
|
||||||
import { canvasSnapshotTempPath, parseCanvasSnapshotPayload } from "../../cli/nodes-canvas.js";
|
import { canvasSnapshotTempPath, parseCanvasSnapshotPayload } from "../../cli/nodes-canvas.js";
|
||||||
|
import type { OpenClawConfig } from "../../config/config.js";
|
||||||
import { imageMimeFromFormat } from "../../media/mime.js";
|
import { imageMimeFromFormat } from "../../media/mime.js";
|
||||||
import { resolveImageSanitizationLimits } from "../image-sanitization.js";
|
import { resolveImageSanitizationLimits } from "../image-sanitization.js";
|
||||||
import { optionalStringEnum, stringEnum } from "../schema/typebox.js";
|
import { optionalStringEnum, stringEnum } from "../schema/typebox.js";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core";
|
|
||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import type { ImageSanitizationLimits } from "../image-sanitization.js";
|
import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core";
|
||||||
import { detectMime } from "../../media/mime.js";
|
import { detectMime } from "../../media/mime.js";
|
||||||
|
import type { ImageSanitizationLimits } from "../image-sanitization.js";
|
||||||
import { sanitizeToolResultImages } from "../tool-images.js";
|
import { sanitizeToolResultImages } from "../tool-images.js";
|
||||||
|
|
||||||
// oxlint-disable-next-line typescript/no-explicit-any
|
// oxlint-disable-next-line typescript/no-explicit-any
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
import crypto from "node:crypto";
|
||||||
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
||||||
import { Type } from "@sinclair/typebox";
|
import { Type } from "@sinclair/typebox";
|
||||||
import crypto from "node:crypto";
|
|
||||||
import type { OpenClawConfig } from "../../config/config.js";
|
|
||||||
import {
|
import {
|
||||||
type CameraFacing,
|
type CameraFacing,
|
||||||
cameraTempPath,
|
cameraTempPath,
|
||||||
@@ -17,6 +16,7 @@ import {
|
|||||||
writeScreenRecordToFile,
|
writeScreenRecordToFile,
|
||||||
} from "../../cli/nodes-screen.js";
|
} from "../../cli/nodes-screen.js";
|
||||||
import { parseDurationMs } from "../../cli/parse-duration.js";
|
import { parseDurationMs } from "../../cli/parse-duration.js";
|
||||||
|
import type { OpenClawConfig } from "../../config/config.js";
|
||||||
import { imageMimeFromFormat } from "../../media/mime.js";
|
import { imageMimeFromFormat } from "../../media/mime.js";
|
||||||
import { resolveSessionAgentId } from "../agent-scope.js";
|
import { resolveSessionAgentId } from "../agent-scope.js";
|
||||||
import { resolveImageSanitizationLimits } from "../image-sanitization.js";
|
import { resolveImageSanitizationLimits } from "../image-sanitization.js";
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import type { OpenClawConfig } from "../../config/config.js";
|
|
||||||
import type { FinalizedMsgContext } from "../templating.js";
|
|
||||||
import type { GetReplyOptions, ReplyPayload } from "../types.js";
|
|
||||||
import type { ReplyDispatcher, ReplyDispatchKind } from "./reply-dispatcher.js";
|
|
||||||
import { resolveSessionAgentId } from "../../agents/agent-scope.js";
|
import { resolveSessionAgentId } from "../../agents/agent-scope.js";
|
||||||
|
import type { OpenClawConfig } from "../../config/config.js";
|
||||||
import { loadSessionStore, resolveStorePath } from "../../config/sessions.js";
|
import { loadSessionStore, resolveStorePath } from "../../config/sessions.js";
|
||||||
import { logVerbose } from "../../globals.js";
|
import { logVerbose } from "../../globals.js";
|
||||||
import { createInternalHookEvent, triggerInternalHook } from "../../hooks/internal-hooks.js";
|
import { createInternalHookEvent, triggerInternalHook } from "../../hooks/internal-hooks.js";
|
||||||
@@ -15,8 +12,11 @@ import {
|
|||||||
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
|
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
|
||||||
import { maybeApplyTtsToPayload, normalizeTtsAutoMode, resolveTtsConfig } from "../../tts/tts.js";
|
import { maybeApplyTtsToPayload, normalizeTtsAutoMode, resolveTtsConfig } from "../../tts/tts.js";
|
||||||
import { getReplyFromConfig } from "../reply.js";
|
import { getReplyFromConfig } from "../reply.js";
|
||||||
|
import type { FinalizedMsgContext } from "../templating.js";
|
||||||
|
import type { GetReplyOptions, ReplyPayload } from "../types.js";
|
||||||
import { formatAbortReplyText, tryFastAbortFromMessage } from "./abort.js";
|
import { formatAbortReplyText, tryFastAbortFromMessage } from "./abort.js";
|
||||||
import { shouldSkipDuplicateInbound } from "./inbound-dedupe.js";
|
import { shouldSkipDuplicateInbound } from "./inbound-dedupe.js";
|
||||||
|
import type { ReplyDispatcher, ReplyDispatchKind } from "./reply-dispatcher.js";
|
||||||
import { isRoutableChannel, routeReply } from "./route-reply.js";
|
import { isRoutableChannel, routeReply } from "./route-reply.js";
|
||||||
|
|
||||||
const AUDIO_PLACEHOLDER_RE = /^<media:audio>(\s*\([^)]*\))?$/i;
|
const AUDIO_PLACEHOLDER_RE = /^<media:audio>(\s*\([^)]*\))?$/i;
|
||||||
|
|||||||
@@ -545,6 +545,8 @@ describe("cron cli", () => {
|
|||||||
}
|
}
|
||||||
if (method === "cron.list") {
|
if (method === "cron.list") {
|
||||||
return {
|
return {
|
||||||
|
ok: true,
|
||||||
|
params: {},
|
||||||
jobs: [
|
jobs: [
|
||||||
{
|
{
|
||||||
id: "job-1",
|
id: "job-1",
|
||||||
@@ -581,6 +583,8 @@ describe("cron cli", () => {
|
|||||||
}
|
}
|
||||||
if (method === "cron.list") {
|
if (method === "cron.list") {
|
||||||
return {
|
return {
|
||||||
|
ok: true,
|
||||||
|
params: {},
|
||||||
jobs: [{ id: "job-1", schedule: { kind: "every", everyMs: 60_000 } }],
|
jobs: [{ id: "job-1", schedule: { kind: "every", everyMs: 60_000 } }],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { Command } from "commander";
|
import type { Command } from "commander";
|
||||||
import type { CronJob } from "../../cron/types.js";
|
import type { CronJob } from "../../cron/types.js";
|
||||||
import type { GatewayRpcOpts } from "../gateway-rpc.js";
|
|
||||||
import { danger } from "../../globals.js";
|
import { danger } from "../../globals.js";
|
||||||
import { sanitizeAgentId } from "../../routing/session-key.js";
|
import { sanitizeAgentId } from "../../routing/session-key.js";
|
||||||
import { defaultRuntime } from "../../runtime.js";
|
import { defaultRuntime } from "../../runtime.js";
|
||||||
|
import type { GatewayRpcOpts } from "../gateway-rpc.js";
|
||||||
import { addGatewayClientOptions, callGatewayFromCli } from "../gateway-rpc.js";
|
import { addGatewayClientOptions, callGatewayFromCli } from "../gateway-rpc.js";
|
||||||
import { parsePositiveIntOrUndefined } from "../program/helpers.js";
|
import { parsePositiveIntOrUndefined } from "../program/helpers.js";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import type { CronJob, CronSchedule } from "../../cron/types.js";
|
|
||||||
import type { GatewayRpcOpts } from "../gateway-rpc.js";
|
|
||||||
import { listChannelPlugins } from "../../channels/plugins/index.js";
|
import { listChannelPlugins } from "../../channels/plugins/index.js";
|
||||||
import { parseAbsoluteTimeMs } from "../../cron/parse.js";
|
import { parseAbsoluteTimeMs } from "../../cron/parse.js";
|
||||||
import { resolveCronStaggerMs } from "../../cron/stagger.js";
|
import { resolveCronStaggerMs } from "../../cron/stagger.js";
|
||||||
|
import type { CronJob, CronSchedule } from "../../cron/types.js";
|
||||||
import { formatDurationHuman } from "../../infra/format-time/format-duration.ts";
|
import { formatDurationHuman } from "../../infra/format-time/format-duration.ts";
|
||||||
import { defaultRuntime } from "../../runtime.js";
|
import { defaultRuntime } from "../../runtime.js";
|
||||||
import { colorize, isRich, theme } from "../../terminal/theme.js";
|
import { colorize, isRich, theme } from "../../terminal/theme.js";
|
||||||
|
import type { GatewayRpcOpts } from "../gateway-rpc.js";
|
||||||
import { callGatewayFromCli } from "../gateway-rpc.js";
|
import { callGatewayFromCli } from "../gateway-rpc.js";
|
||||||
|
|
||||||
export const getCronChannelOptions = () =>
|
export const getCronChannelOptions = () =>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import { ensureAuthProfileStore } from "../agents/auth-profiles.js";
|
||||||
import type { OpenClawConfig, GatewayAuthConfig } from "../config/config.js";
|
import type { OpenClawConfig, GatewayAuthConfig } from "../config/config.js";
|
||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||||
import { ensureAuthProfileStore } from "../agents/auth-profiles.js";
|
|
||||||
import { promptAuthChoiceGrouped } from "./auth-choice-prompt.js";
|
import { promptAuthChoiceGrouped } from "./auth-choice-prompt.js";
|
||||||
import { applyAuthChoice, resolvePreferredProviderForAuthChoice } from "./auth-choice.js";
|
import { applyAuthChoice, resolvePreferredProviderForAuthChoice } from "./auth-choice.js";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { OpenClawConfig } from "./types.js";
|
|
||||||
import type { ModelDefinitionConfig } from "./types.models.js";
|
|
||||||
import { DEFAULT_CONTEXT_TOKENS } from "../agents/defaults.js";
|
import { DEFAULT_CONTEXT_TOKENS } from "../agents/defaults.js";
|
||||||
import { parseModelRef } from "../agents/model-selection.js";
|
import { parseModelRef } from "../agents/model-selection.js";
|
||||||
import { DEFAULT_AGENT_MAX_CONCURRENT, DEFAULT_SUBAGENT_MAX_CONCURRENT } from "./agent-limits.js";
|
import { DEFAULT_AGENT_MAX_CONCURRENT, DEFAULT_SUBAGENT_MAX_CONCURRENT } from "./agent-limits.js";
|
||||||
import { resolveTalkApiKey } from "./talk.js";
|
import { resolveTalkApiKey } from "./talk.js";
|
||||||
|
import type { OpenClawConfig } from "./types.js";
|
||||||
|
import type { ModelDefinitionConfig } from "./types.models.js";
|
||||||
|
|
||||||
type WarnState = { warned: boolean };
|
type WarnState = { warned: boolean };
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { CronJobCreate, CronJobPatch } from "./types.js";
|
|
||||||
import { sanitizeAgentId } from "../routing/session-key.js";
|
import { sanitizeAgentId } from "../routing/session-key.js";
|
||||||
import { isRecord } from "../utils.js";
|
import { isRecord } from "../utils.js";
|
||||||
import {
|
import {
|
||||||
@@ -10,6 +9,7 @@ import { parseAbsoluteTimeMs } from "./parse.js";
|
|||||||
import { migrateLegacyCronPayload } from "./payload-migration.js";
|
import { migrateLegacyCronPayload } from "./payload-migration.js";
|
||||||
import { inferLegacyName } from "./service/normalize.js";
|
import { inferLegacyName } from "./service/normalize.js";
|
||||||
import { normalizeCronStaggerMs, resolveDefaultCronStaggerMs } from "./stagger.js";
|
import { normalizeCronStaggerMs, resolveDefaultCronStaggerMs } from "./stagger.js";
|
||||||
|
import type { CronJobCreate, CronJobPatch } from "./types.js";
|
||||||
|
|
||||||
type UnknownRecord = Record<string, unknown>;
|
type UnknownRecord = Record<string, unknown>;
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import fs from "node:fs/promises";
|
|||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import type { CronJob, CronJobState } from "./types.js";
|
|
||||||
import * as schedule from "./schedule.js";
|
import * as schedule from "./schedule.js";
|
||||||
import { CronService } from "./service.js";
|
import { CronService } from "./service.js";
|
||||||
import { computeJobNextRunAtMs } from "./service/jobs.js";
|
import { computeJobNextRunAtMs } from "./service/jobs.js";
|
||||||
import { createCronServiceState, type CronEvent } from "./service/state.js";
|
import { createCronServiceState, type CronEvent } from "./service/state.js";
|
||||||
import { onTimer } from "./service/timer.js";
|
import { onTimer } from "./service/timer.js";
|
||||||
|
import type { CronJob, CronJobState } from "./types.js";
|
||||||
|
|
||||||
const noopLogger = {
|
const noopLogger = {
|
||||||
info: vi.fn(),
|
info: vi.fn(),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import type { CronServiceState } from "./service/state.js";
|
|
||||||
import type { CronJob, CronJobPatch } from "./types.js";
|
|
||||||
import { applyJobPatch, createJob } from "./service/jobs.js";
|
import { applyJobPatch, createJob } from "./service/jobs.js";
|
||||||
|
import type { CronServiceState } from "./service/state.js";
|
||||||
import { DEFAULT_TOP_OF_HOUR_STAGGER_MS } from "./stagger.js";
|
import { DEFAULT_TOP_OF_HOUR_STAGGER_MS } from "./stagger.js";
|
||||||
|
import type { CronJob, CronJobPatch } from "./types.js";
|
||||||
|
|
||||||
describe("applyJobPatch", () => {
|
describe("applyJobPatch", () => {
|
||||||
it("clears delivery when switching to main session", () => {
|
it("clears delivery when switching to main session", () => {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import type { CronJob } from "./types.js";
|
|
||||||
import { computeJobNextRunAtMs } from "./service/jobs.js";
|
import { computeJobNextRunAtMs } from "./service/jobs.js";
|
||||||
import { DEFAULT_TOP_OF_HOUR_STAGGER_MS } from "./stagger.js";
|
import { DEFAULT_TOP_OF_HOUR_STAGGER_MS } from "./stagger.js";
|
||||||
|
import type { CronJob } from "./types.js";
|
||||||
|
|
||||||
function stableOffsetMs(jobId: string, windowMs: number) {
|
function stableOffsetMs(jobId: string, windowMs: number) {
|
||||||
const digest = crypto.createHash("sha256").update(jobId).digest();
|
const digest = crypto.createHash("sha256").update(jobId).digest();
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
|
import { parseAbsoluteTimeMs } from "../parse.js";
|
||||||
|
import { computeNextRunAtMs } from "../schedule.js";
|
||||||
|
import {
|
||||||
|
normalizeCronStaggerMs,
|
||||||
|
resolveCronStaggerMs,
|
||||||
|
resolveDefaultCronStaggerMs,
|
||||||
|
} from "../stagger.js";
|
||||||
import type {
|
import type {
|
||||||
CronDelivery,
|
CronDelivery,
|
||||||
CronDeliveryPatch,
|
CronDeliveryPatch,
|
||||||
@@ -8,14 +15,6 @@ import type {
|
|||||||
CronPayload,
|
CronPayload,
|
||||||
CronPayloadPatch,
|
CronPayloadPatch,
|
||||||
} from "../types.js";
|
} from "../types.js";
|
||||||
import type { CronServiceState } from "./state.js";
|
|
||||||
import { parseAbsoluteTimeMs } from "../parse.js";
|
|
||||||
import { computeNextRunAtMs } from "../schedule.js";
|
|
||||||
import {
|
|
||||||
normalizeCronStaggerMs,
|
|
||||||
resolveCronStaggerMs,
|
|
||||||
resolveDefaultCronStaggerMs,
|
|
||||||
} from "../stagger.js";
|
|
||||||
import { normalizeHttpWebhookUrl } from "../webhook-url.js";
|
import { normalizeHttpWebhookUrl } from "../webhook-url.js";
|
||||||
import {
|
import {
|
||||||
normalizeOptionalAgentId,
|
normalizeOptionalAgentId,
|
||||||
@@ -24,6 +23,7 @@ import {
|
|||||||
normalizePayloadToSystemText,
|
normalizePayloadToSystemText,
|
||||||
normalizeRequiredName,
|
normalizeRequiredName,
|
||||||
} from "./normalize.js";
|
} from "./normalize.js";
|
||||||
|
import type { CronServiceState } from "./state.js";
|
||||||
|
|
||||||
const STUCK_RUN_MS = 2 * 60 * 60 * 1000;
|
const STUCK_RUN_MS = 2 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import type { CronJob } from "../types.js";
|
|
||||||
import type { CronServiceState } from "./state.js";
|
|
||||||
import {
|
import {
|
||||||
buildDeliveryFromLegacyPayload,
|
buildDeliveryFromLegacyPayload,
|
||||||
hasLegacyDeliveryHints,
|
hasLegacyDeliveryHints,
|
||||||
@@ -10,8 +8,10 @@ import { parseAbsoluteTimeMs } from "../parse.js";
|
|||||||
import { migrateLegacyCronPayload } from "../payload-migration.js";
|
import { migrateLegacyCronPayload } from "../payload-migration.js";
|
||||||
import { normalizeCronStaggerMs, resolveDefaultCronStaggerMs } from "../stagger.js";
|
import { normalizeCronStaggerMs, resolveDefaultCronStaggerMs } from "../stagger.js";
|
||||||
import { loadCronStore, saveCronStore } from "../store.js";
|
import { loadCronStore, saveCronStore } from "../store.js";
|
||||||
|
import type { CronJob } from "../types.js";
|
||||||
import { recomputeNextRuns } from "./jobs.js";
|
import { recomputeNextRuns } from "./jobs.js";
|
||||||
import { inferLegacyName, normalizeOptionalText } from "./normalize.js";
|
import { inferLegacyName, normalizeOptionalText } from "./normalize.js";
|
||||||
|
import type { CronServiceState } from "./state.js";
|
||||||
|
|
||||||
function buildDeliveryPatchFromLegacyPayload(payload: Record<string, unknown>) {
|
function buildDeliveryPatchFromLegacyPayload(payload: Record<string, unknown>) {
|
||||||
const deliver = payload.deliver;
|
const deliver = payload.deliver;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import type { ChannelId } from "../channels/plugins/types.js";
|
import type { ChannelId } from "../channels/plugins/types.js";
|
||||||
import type { ChannelAccountSnapshot } from "../channels/plugins/types.js";
|
import type { ChannelAccountSnapshot } from "../channels/plugins/types.js";
|
||||||
import type { ChannelManager, ChannelRuntimeSnapshot } from "./server-channels.js";
|
|
||||||
import { startChannelHealthMonitor } from "./channel-health-monitor.js";
|
import { startChannelHealthMonitor } from "./channel-health-monitor.js";
|
||||||
|
import type { ChannelManager, ChannelRuntimeSnapshot } from "./server-channels.js";
|
||||||
|
|
||||||
function createMockChannelManager(overrides?: Partial<ChannelManager>): ChannelManager {
|
function createMockChannelManager(overrides?: Partial<ChannelManager>): ChannelManager {
|
||||||
return {
|
return {
|
||||||
@@ -322,9 +322,9 @@ describe("channel-health-monitor", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("runs checks single-flight when restart work is still in progress", async () => {
|
it("runs checks single-flight when restart work is still in progress", async () => {
|
||||||
let releaseStart: (() => void) | null = null;
|
let releaseStart: (() => void) | undefined;
|
||||||
const startGate = new Promise<void>((resolve) => {
|
const startGate = new Promise<void>((resolve) => {
|
||||||
releaseStart = resolve;
|
releaseStart = () => resolve();
|
||||||
});
|
});
|
||||||
const manager = createMockChannelManager({
|
const manager = createMockChannelManager({
|
||||||
getRuntimeSnapshot: vi.fn(() =>
|
getRuntimeSnapshot: vi.fn(() =>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { ChannelId } from "../channels/plugins/types.js";
|
import type { ChannelId } from "../channels/plugins/types.js";
|
||||||
import type { ChannelManager } from "./server-channels.js";
|
|
||||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||||
|
import type { ChannelManager } from "./server-channels.js";
|
||||||
|
|
||||||
const log = createSubsystemLogger("gateway/health-monitor");
|
const log = createSubsystemLogger("gateway/health-monitor");
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,28 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
|
import type { loadSessionEntry as loadSessionEntryType } from "./session-utils.js";
|
||||||
|
|
||||||
|
const buildSessionLookup = (
|
||||||
|
sessionKey: string,
|
||||||
|
entry: {
|
||||||
|
sessionId?: string;
|
||||||
|
lastChannel?: string;
|
||||||
|
lastTo?: string;
|
||||||
|
updatedAt?: number;
|
||||||
|
} = {},
|
||||||
|
): ReturnType<typeof loadSessionEntryType> => ({
|
||||||
|
cfg: { session: { mainKey: "agent:main:main" } } as OpenClawConfig,
|
||||||
|
storePath: "/tmp/sessions.json",
|
||||||
|
store: {} as ReturnType<typeof loadSessionEntryType>["store"],
|
||||||
|
entry: {
|
||||||
|
sessionId: entry.sessionId ?? `sid-${sessionKey}`,
|
||||||
|
updatedAt: entry.updatedAt ?? Date.now(),
|
||||||
|
lastChannel: entry.lastChannel,
|
||||||
|
lastTo: entry.lastTo,
|
||||||
|
},
|
||||||
|
canonicalKey: sessionKey,
|
||||||
|
legacyKey: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
vi.mock("../infra/system-events.js", () => ({
|
vi.mock("../infra/system-events.js", () => ({
|
||||||
enqueueSystemEvent: vi.fn(),
|
enqueueSystemEvent: vi.fn(),
|
||||||
@@ -17,11 +41,7 @@ vi.mock("../config/sessions.js", () => ({
|
|||||||
updateSessionStore: vi.fn(),
|
updateSessionStore: vi.fn(),
|
||||||
}));
|
}));
|
||||||
vi.mock("./session-utils.js", () => ({
|
vi.mock("./session-utils.js", () => ({
|
||||||
loadSessionEntry: vi.fn((sessionKey: string) => ({
|
loadSessionEntry: vi.fn((sessionKey: string) => buildSessionLookup(sessionKey)),
|
||||||
storePath: "/tmp/sessions.json",
|
|
||||||
entry: { sessionId: `sid-${sessionKey}` },
|
|
||||||
canonicalKey: sessionKey,
|
|
||||||
})),
|
|
||||||
pruneLegacyStoreKeys: vi.fn(),
|
pruneLegacyStoreKeys: vi.fn(),
|
||||||
resolveGatewaySessionStoreTarget: vi.fn(({ key }: { key: string }) => ({
|
resolveGatewaySessionStoreTarget: vi.fn(({ key }: { key: string }) => ({
|
||||||
canonicalKey: key,
|
canonicalKey: key,
|
||||||
@@ -30,12 +50,12 @@ vi.mock("./session-utils.js", () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
import type { CliDeps } from "../cli/deps.js";
|
import type { CliDeps } from "../cli/deps.js";
|
||||||
import type { HealthSummary } from "../commands/health.js";
|
|
||||||
import type { NodeEventContext } from "./server-node-events-types.js";
|
|
||||||
import { agentCommand } from "../commands/agent.js";
|
import { agentCommand } from "../commands/agent.js";
|
||||||
|
import type { HealthSummary } from "../commands/health.js";
|
||||||
import { updateSessionStore } from "../config/sessions.js";
|
import { updateSessionStore } from "../config/sessions.js";
|
||||||
import { requestHeartbeatNow } from "../infra/heartbeat-wake.js";
|
import { requestHeartbeatNow } from "../infra/heartbeat-wake.js";
|
||||||
import { enqueueSystemEvent } from "../infra/system-events.js";
|
import { enqueueSystemEvent } from "../infra/system-events.js";
|
||||||
|
import type { NodeEventContext } from "./server-node-events-types.js";
|
||||||
import { handleNodeEvent } from "./server-node-events.js";
|
import { handleNodeEvent } from "./server-node-events.js";
|
||||||
import { loadSessionEntry } from "./session-utils.js";
|
import { loadSessionEntry } from "./session-utils.js";
|
||||||
|
|
||||||
@@ -279,11 +299,7 @@ describe("agent request events", () => {
|
|||||||
updateSessionStoreMock.mockImplementation(async (_storePath, update) => {
|
updateSessionStoreMock.mockImplementation(async (_storePath, update) => {
|
||||||
update({});
|
update({});
|
||||||
});
|
});
|
||||||
loadSessionEntryMock.mockImplementation((sessionKey: string) => ({
|
loadSessionEntryMock.mockImplementation((sessionKey: string) => buildSessionLookup(sessionKey));
|
||||||
storePath: "/tmp/sessions.json",
|
|
||||||
entry: { sessionId: `sid-${sessionKey}` },
|
|
||||||
canonicalKey: sessionKey,
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("disables delivery when route is unresolved instead of falling back globally", async () => {
|
it("disables delivery when route is unresolved instead of falling back globally", async () => {
|
||||||
@@ -317,12 +333,11 @@ describe("agent request events", () => {
|
|||||||
it("reuses the current session route when delivery target is omitted", async () => {
|
it("reuses the current session route when delivery target is omitted", async () => {
|
||||||
const ctx = buildCtx();
|
const ctx = buildCtx();
|
||||||
loadSessionEntryMock.mockReturnValueOnce({
|
loadSessionEntryMock.mockReturnValueOnce({
|
||||||
storePath: "/tmp/sessions.json",
|
...buildSessionLookup("agent:main:main", {
|
||||||
entry: {
|
|
||||||
sessionId: "sid-current",
|
sessionId: "sid-current",
|
||||||
lastChannel: "telegram",
|
lastChannel: "telegram",
|
||||||
lastTo: "123",
|
lastTo: "123",
|
||||||
},
|
}),
|
||||||
canonicalKey: "agent:main:main",
|
canonicalKey: "agent:main:main",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { randomUUID } from "node:crypto";
|
import { randomUUID } from "node:crypto";
|
||||||
import type { NodeEvent, NodeEventContext } from "./server-node-events-types.js";
|
|
||||||
import { resolveSessionAgentId } from "../agents/agent-scope.js";
|
import { resolveSessionAgentId } from "../agents/agent-scope.js";
|
||||||
import { normalizeChannelId } from "../channels/plugins/index.js";
|
import { normalizeChannelId } from "../channels/plugins/index.js";
|
||||||
import { createOutboundSendDeps } from "../cli/outbound-send-deps.js";
|
import { createOutboundSendDeps } from "../cli/outbound-send-deps.js";
|
||||||
@@ -14,6 +13,7 @@ import { normalizeMainKey } from "../routing/session-key.js";
|
|||||||
import { defaultRuntime } from "../runtime.js";
|
import { defaultRuntime } from "../runtime.js";
|
||||||
import { parseMessageWithAttachments } from "./chat-attachments.js";
|
import { parseMessageWithAttachments } from "./chat-attachments.js";
|
||||||
import { normalizeRpcAttachmentsToChatAttachments } from "./server-methods/attachment-normalize.js";
|
import { normalizeRpcAttachmentsToChatAttachments } from "./server-methods/attachment-normalize.js";
|
||||||
|
import type { NodeEvent, NodeEventContext } from "./server-node-events-types.js";
|
||||||
import {
|
import {
|
||||||
loadSessionEntry,
|
loadSessionEntry,
|
||||||
pruneLegacyStoreKeys,
|
pruneLegacyStoreKeys,
|
||||||
|
|||||||
@@ -10,12 +10,13 @@ const convertMarkdownTablesMock = vi.hoisted(() => vi.fn((text: string) => text)
|
|||||||
const resolveMarkdownTableModeMock = vi.hoisted(() => vi.fn(() => "code"));
|
const resolveMarkdownTableModeMock = vi.hoisted(() => vi.fn(() => "code"));
|
||||||
|
|
||||||
vi.mock("../send.js", () => ({
|
vi.mock("../send.js", () => ({
|
||||||
sendMessageIMessage: (...args: unknown[]) => sendMessageIMessageMock(...args),
|
sendMessageIMessage: (to: string, message: string, opts?: unknown) =>
|
||||||
|
sendMessageIMessageMock(to, message, opts),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("../../auto-reply/chunk.js", () => ({
|
vi.mock("../../auto-reply/chunk.js", () => ({
|
||||||
chunkTextWithMode: (...args: unknown[]) => chunkTextWithModeMock(...args),
|
chunkTextWithMode: (text: string) => chunkTextWithModeMock(text),
|
||||||
resolveChunkMode: (...args: unknown[]) => resolveChunkModeMock(...args),
|
resolveChunkMode: () => resolveChunkModeMock(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("../../config/config.js", () => ({
|
vi.mock("../../config/config.js", () => ({
|
||||||
@@ -23,11 +24,11 @@ vi.mock("../../config/config.js", () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("../../config/markdown-tables.js", () => ({
|
vi.mock("../../config/markdown-tables.js", () => ({
|
||||||
resolveMarkdownTableMode: (...args: unknown[]) => resolveMarkdownTableModeMock(...args),
|
resolveMarkdownTableMode: () => resolveMarkdownTableModeMock(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("../../markdown/tables.js", () => ({
|
vi.mock("../../markdown/tables.js", () => ({
|
||||||
convertMarkdownTables: (...args: unknown[]) => convertMarkdownTablesMock(...args),
|
convertMarkdownTables: (text: string) => convertMarkdownTablesMock(text),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
import { deliverReplies } from "./deliver.js";
|
import { deliverReplies } from "./deliver.js";
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import type { OpenClawConfig } from "../../config/config.js";
|
|
||||||
import { signalOutbound } from "../../channels/plugins/outbound/signal.js";
|
import { signalOutbound } from "../../channels/plugins/outbound/signal.js";
|
||||||
import { telegramOutbound } from "../../channels/plugins/outbound/telegram.js";
|
import { telegramOutbound } from "../../channels/plugins/outbound/telegram.js";
|
||||||
import { whatsappOutbound } from "../../channels/plugins/outbound/whatsapp.js";
|
import { whatsappOutbound } from "../../channels/plugins/outbound/whatsapp.js";
|
||||||
|
import type { OpenClawConfig } from "../../config/config.js";
|
||||||
import { STATE_DIR } from "../../config/paths.js";
|
import { STATE_DIR } from "../../config/paths.js";
|
||||||
import { setActivePluginRegistry } from "../../plugins/runtime.js";
|
import { setActivePluginRegistry } from "../../plugins/runtime.js";
|
||||||
import { markdownToSignalTextChunks } from "../../signal/format.js";
|
import { markdownToSignalTextChunks } from "../../signal/format.js";
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
import type { ReplyPayload } from "../../auto-reply/types.js";
|
|
||||||
import type {
|
|
||||||
ChannelOutboundAdapter,
|
|
||||||
ChannelOutboundContext,
|
|
||||||
} from "../../channels/plugins/types.js";
|
|
||||||
import type { OpenClawConfig } from "../../config/config.js";
|
|
||||||
import type { sendMessageDiscord } from "../../discord/send.js";
|
|
||||||
import type { sendMessageIMessage } from "../../imessage/send.js";
|
|
||||||
import type { sendMessageSlack } from "../../slack/send.js";
|
|
||||||
import type { sendMessageTelegram } from "../../telegram/send.js";
|
|
||||||
import type { sendMessageWhatsApp } from "../../web/outbound.js";
|
|
||||||
import type { OutboundIdentity } from "./identity.js";
|
|
||||||
import type { NormalizedOutboundPayload } from "./payloads.js";
|
|
||||||
import type { OutboundChannel } from "./targets.js";
|
|
||||||
import {
|
import {
|
||||||
chunkByParagraph,
|
chunkByParagraph,
|
||||||
chunkMarkdownTextWithMode,
|
chunkMarkdownTextWithMode,
|
||||||
resolveChunkMode,
|
resolveChunkMode,
|
||||||
resolveTextChunkLimit,
|
resolveTextChunkLimit,
|
||||||
} from "../../auto-reply/chunk.js";
|
} from "../../auto-reply/chunk.js";
|
||||||
|
import type { ReplyPayload } from "../../auto-reply/types.js";
|
||||||
import { resolveChannelMediaMaxBytes } from "../../channels/plugins/media-limits.js";
|
import { resolveChannelMediaMaxBytes } from "../../channels/plugins/media-limits.js";
|
||||||
import { loadChannelOutboundAdapter } from "../../channels/plugins/outbound/load.js";
|
import { loadChannelOutboundAdapter } from "../../channels/plugins/outbound/load.js";
|
||||||
|
import type {
|
||||||
|
ChannelOutboundAdapter,
|
||||||
|
ChannelOutboundContext,
|
||||||
|
} from "../../channels/plugins/types.js";
|
||||||
|
import type { OpenClawConfig } from "../../config/config.js";
|
||||||
import { resolveMarkdownTableMode } from "../../config/markdown-tables.js";
|
import { resolveMarkdownTableMode } from "../../config/markdown-tables.js";
|
||||||
import {
|
import {
|
||||||
appendAssistantMessageToSessionTranscript,
|
appendAssistantMessageToSessionTranscript,
|
||||||
resolveMirroredTranscriptText,
|
resolveMirroredTranscriptText,
|
||||||
} from "../../config/sessions.js";
|
} from "../../config/sessions.js";
|
||||||
|
import type { sendMessageDiscord } from "../../discord/send.js";
|
||||||
import { createInternalHookEvent, triggerInternalHook } from "../../hooks/internal-hooks.js";
|
import { createInternalHookEvent, triggerInternalHook } from "../../hooks/internal-hooks.js";
|
||||||
|
import type { sendMessageIMessage } from "../../imessage/send.js";
|
||||||
import { getAgentScopedMediaLocalRoots } from "../../media/local-roots.js";
|
import { getAgentScopedMediaLocalRoots } from "../../media/local-roots.js";
|
||||||
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
|
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
|
||||||
import { markdownToSignalTextChunks, type SignalTextStyleRange } from "../../signal/format.js";
|
import { markdownToSignalTextChunks, type SignalTextStyleRange } from "../../signal/format.js";
|
||||||
import { sendMessageSignal } from "../../signal/send.js";
|
import { sendMessageSignal } from "../../signal/send.js";
|
||||||
|
import type { sendMessageSlack } from "../../slack/send.js";
|
||||||
|
import type { sendMessageTelegram } from "../../telegram/send.js";
|
||||||
|
import type { sendMessageWhatsApp } from "../../web/outbound.js";
|
||||||
import { throwIfAborted } from "./abort.js";
|
import { throwIfAborted } from "./abort.js";
|
||||||
import { ackDelivery, enqueueDelivery, failDelivery } from "./delivery-queue.js";
|
import { ackDelivery, enqueueDelivery, failDelivery } from "./delivery-queue.js";
|
||||||
|
import type { OutboundIdentity } from "./identity.js";
|
||||||
|
import type { NormalizedOutboundPayload } from "./payloads.js";
|
||||||
import { normalizeReplyPayloadsForDelivery } from "./payloads.js";
|
import { normalizeReplyPayloadsForDelivery } from "./payloads.js";
|
||||||
|
import type { OutboundChannel } from "./targets.js";
|
||||||
|
|
||||||
export type { NormalizedOutboundPayload } from "./payloads.js";
|
export type { NormalizedOutboundPayload } from "./payloads.js";
|
||||||
export { normalizeOutboundPayloads } from "./payloads.js";
|
export { normalizeOutboundPayloads } from "./payloads.js";
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { requireApiKey, resolveApiKeyForProvider } from "../agents/model-auth.js";
|
|
||||||
import {
|
import {
|
||||||
collectProviderApiKeysForExecution,
|
collectProviderApiKeysForExecution,
|
||||||
executeWithApiKeyRotation,
|
executeWithApiKeyRotation,
|
||||||
} from "../agents/api-key-rotation.js";
|
} from "../agents/api-key-rotation.js";
|
||||||
|
import { requireApiKey, resolveApiKeyForProvider } from "../agents/model-auth.js";
|
||||||
import type { MsgContext } from "../auto-reply/templating.js";
|
import type { MsgContext } from "../auto-reply/templating.js";
|
||||||
import { applyTemplate } from "../auto-reply/templating.js";
|
import { applyTemplate } from "../auto-reply/templating.js";
|
||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
@@ -400,6 +400,7 @@ export async function runProviderEntry(params: {
|
|||||||
if (!provider.transcribeAudio) {
|
if (!provider.transcribeAudio) {
|
||||||
throw new Error(`Audio transcription provider "${providerId}" not available.`);
|
throw new Error(`Audio transcription provider "${providerId}" not available.`);
|
||||||
}
|
}
|
||||||
|
const transcribeAudio = provider.transcribeAudio;
|
||||||
const media = await params.cache.getBuffer({
|
const media = await params.cache.getBuffer({
|
||||||
attachmentIndex: params.attachmentIndex,
|
attachmentIndex: params.attachmentIndex,
|
||||||
maxBytes,
|
maxBytes,
|
||||||
@@ -434,7 +435,7 @@ export async function runProviderEntry(params: {
|
|||||||
provider: providerId,
|
provider: providerId,
|
||||||
apiKeys,
|
apiKeys,
|
||||||
execute: async (apiKey) =>
|
execute: async (apiKey) =>
|
||||||
provider.transcribeAudio({
|
transcribeAudio({
|
||||||
buffer: media.buffer,
|
buffer: media.buffer,
|
||||||
fileName: media.fileName,
|
fileName: media.fileName,
|
||||||
mime: media.mime,
|
mime: media.mime,
|
||||||
@@ -460,6 +461,7 @@ export async function runProviderEntry(params: {
|
|||||||
if (!provider.describeVideo) {
|
if (!provider.describeVideo) {
|
||||||
throw new Error(`Video understanding provider "${providerId}" not available.`);
|
throw new Error(`Video understanding provider "${providerId}" not available.`);
|
||||||
}
|
}
|
||||||
|
const describeVideo = provider.describeVideo;
|
||||||
const media = await params.cache.getBuffer({
|
const media = await params.cache.getBuffer({
|
||||||
attachmentIndex: params.attachmentIndex,
|
attachmentIndex: params.attachmentIndex,
|
||||||
maxBytes,
|
maxBytes,
|
||||||
@@ -489,7 +491,7 @@ export async function runProviderEntry(params: {
|
|||||||
provider: providerId,
|
provider: providerId,
|
||||||
apiKeys,
|
apiKeys,
|
||||||
execute: (apiKey) =>
|
execute: (apiKey) =>
|
||||||
provider.describeVideo({
|
describeVideo({
|
||||||
buffer: media.buffer,
|
buffer: media.buffer,
|
||||||
fileName: media.fileName,
|
fileName: media.fileName,
|
||||||
mime: media.mime,
|
mime: media.mime,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { EmbeddingProvider, EmbeddingProviderOptions } from "./embeddings.js";
|
|
||||||
import {
|
import {
|
||||||
collectProviderApiKeysForExecution,
|
collectProviderApiKeysForExecution,
|
||||||
executeWithApiKeyRotation,
|
executeWithApiKeyRotation,
|
||||||
@@ -6,6 +5,7 @@ import {
|
|||||||
import { requireApiKey, resolveApiKeyForProvider } from "../agents/model-auth.js";
|
import { requireApiKey, resolveApiKeyForProvider } from "../agents/model-auth.js";
|
||||||
import { parseGeminiAuth } from "../infra/gemini-auth.js";
|
import { parseGeminiAuth } from "../infra/gemini-auth.js";
|
||||||
import { debugEmbeddingsLog } from "./embeddings-debug.js";
|
import { debugEmbeddingsLog } from "./embeddings-debug.js";
|
||||||
|
import type { EmbeddingProvider, EmbeddingProviderOptions } from "./embeddings.js";
|
||||||
|
|
||||||
export type GeminiEmbeddingClient = {
|
export type GeminiEmbeddingClient = {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import type { ReplyPayload } from "../../../auto-reply/types.js";
|
|
||||||
import type { SlackStreamSession } from "../../streaming.js";
|
|
||||||
import type { PreparedSlackMessage } from "./types.js";
|
|
||||||
import { resolveHumanDelayConfig } from "../../../agents/identity.js";
|
import { resolveHumanDelayConfig } from "../../../agents/identity.js";
|
||||||
import { dispatchInboundMessage } from "../../../auto-reply/dispatch.js";
|
import { dispatchInboundMessage } from "../../../auto-reply/dispatch.js";
|
||||||
import { clearHistoryEntriesIfEnabled } from "../../../auto-reply/reply/history.js";
|
import { clearHistoryEntriesIfEnabled } from "../../../auto-reply/reply/history.js";
|
||||||
import { createReplyDispatcherWithTyping } from "../../../auto-reply/reply/reply-dispatcher.js";
|
import { createReplyDispatcherWithTyping } from "../../../auto-reply/reply/reply-dispatcher.js";
|
||||||
|
import type { ReplyPayload } from "../../../auto-reply/types.js";
|
||||||
import { removeAckReactionAfterReply } from "../../../channels/ack-reactions.js";
|
import { removeAckReactionAfterReply } from "../../../channels/ack-reactions.js";
|
||||||
import { logAckFailure, logTypingFailure } from "../../../channels/logging.js";
|
import { logAckFailure, logTypingFailure } from "../../../channels/logging.js";
|
||||||
import { createReplyPrefixOptions } from "../../../channels/reply-prefix.js";
|
import { createReplyPrefixOptions } from "../../../channels/reply-prefix.js";
|
||||||
@@ -18,9 +16,11 @@ import {
|
|||||||
buildStatusFinalPreviewText,
|
buildStatusFinalPreviewText,
|
||||||
resolveSlackStreamMode,
|
resolveSlackStreamMode,
|
||||||
} from "../../stream-mode.js";
|
} from "../../stream-mode.js";
|
||||||
|
import type { SlackStreamSession } from "../../streaming.js";
|
||||||
import { appendSlackStream, startSlackStream, stopSlackStream } from "../../streaming.js";
|
import { appendSlackStream, startSlackStream, stopSlackStream } from "../../streaming.js";
|
||||||
import { resolveSlackThreadTargets } from "../../threading.js";
|
import { resolveSlackThreadTargets } from "../../threading.js";
|
||||||
import { createSlackReplyDeliveryPlan, deliverReplies, resolveSlackThreadTs } from "../replies.js";
|
import { createSlackReplyDeliveryPlan, deliverReplies, resolveSlackThreadTs } from "../replies.js";
|
||||||
|
import type { PreparedSlackMessage } from "./types.js";
|
||||||
|
|
||||||
function hasMedia(payload: ReplyPayload): boolean {
|
function hasMedia(payload: ReplyPayload): boolean {
|
||||||
return Boolean(payload.mediaUrl) || (payload.mediaUrls?.length ?? 0) > 0;
|
return Boolean(payload.mediaUrl) || (payload.mediaUrls?.length ?? 0) > 0;
|
||||||
@@ -180,9 +180,11 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
|||||||
}
|
}
|
||||||
|
|
||||||
const text = payload.text.trim();
|
const text = payload.text.trim();
|
||||||
|
let plannedThreadTs: string | undefined;
|
||||||
try {
|
try {
|
||||||
if (!streamSession) {
|
if (!streamSession) {
|
||||||
const streamThreadTs = replyPlan.nextThreadTs();
|
const streamThreadTs = replyPlan.nextThreadTs();
|
||||||
|
plannedThreadTs = streamThreadTs;
|
||||||
if (!streamThreadTs) {
|
if (!streamThreadTs) {
|
||||||
logVerbose(
|
logVerbose(
|
||||||
"slack-stream: no reply thread target for stream start, falling back to normal delivery",
|
"slack-stream: no reply thread target for stream start, falling back to normal delivery",
|
||||||
@@ -211,7 +213,7 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
|||||||
danger(`slack-stream: streaming API call failed: ${String(err)}, falling back`),
|
danger(`slack-stream: streaming API call failed: ${String(err)}, falling back`),
|
||||||
);
|
);
|
||||||
streamFailed = true;
|
streamFailed = true;
|
||||||
await deliverNormally(payload, streamSession?.threadTs);
|
await deliverNormally(payload, streamSession?.threadTs ?? plannedThreadTs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1442,9 +1442,7 @@ describe("createForumTopicTelegram", () => {
|
|||||||
message_thread_id: 272,
|
message_thread_id: 272,
|
||||||
name: "Build Updates",
|
name: "Build Updates",
|
||||||
});
|
});
|
||||||
const api = { createForumTopic } as unknown as {
|
const api = { createForumTopic } as unknown as Bot["api"];
|
||||||
createForumTopic: typeof createForumTopic;
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = await createForumTopicTelegram("telegram:group:-1001234567890:topic:271", "x", {
|
const result = await createForumTopicTelegram("telegram:group:-1001234567890:topic:271", "x", {
|
||||||
token: "tok",
|
token: "tok",
|
||||||
@@ -1464,9 +1462,7 @@ describe("createForumTopicTelegram", () => {
|
|||||||
message_thread_id: 300,
|
message_thread_id: 300,
|
||||||
name: "Roadmap",
|
name: "Roadmap",
|
||||||
});
|
});
|
||||||
const api = { createForumTopic } as unknown as {
|
const api = { createForumTopic } as unknown as Bot["api"];
|
||||||
createForumTopic: typeof createForumTopic;
|
|
||||||
};
|
|
||||||
|
|
||||||
await createForumTopicTelegram("-1001234567890", "Roadmap", {
|
await createForumTopicTelegram("-1001234567890", "Roadmap", {
|
||||||
token: "tok",
|
token: "tok",
|
||||||
|
|||||||
Reference in New Issue
Block a user