fix: resolve plugin tool meta typing

This commit is contained in:
Peter Steinberger
2026-01-18 04:24:16 +00:00
parent fabc2882aa
commit 82e49af5a7
10 changed files with 78 additions and 67 deletions

View File

@@ -3,7 +3,8 @@ import type { SessionManager } from "@mariozechner/pi-coding-agent";
import { beforeEach, describe, expect, it, vi } from "vitest"; import { beforeEach, describe, expect, it, vi } from "vitest";
import * as helpers from "./pi-embedded-helpers.js"; import * as helpers from "./pi-embedded-helpers.js";
type SanitizeSessionHistory = typeof import("./pi-embedded-runner/google.js").sanitizeSessionHistory; type SanitizeSessionHistory =
typeof import("./pi-embedded-runner/google.js").sanitizeSessionHistory;
let sanitizeSessionHistory: SanitizeSessionHistory; let sanitizeSessionHistory: SanitizeSessionHistory;
// Mock dependencies // Mock dependencies

View File

@@ -262,20 +262,11 @@ export function createClawdbotCodingTools(options?: {
toolMeta: (tool) => getPluginToolMeta(tool), toolMeta: (tool) => getPluginToolMeta(tool),
}); });
const profilePolicyExpanded = expandPolicyWithPluginGroups(profilePolicy, pluginGroups); const profilePolicyExpanded = expandPolicyWithPluginGroups(profilePolicy, pluginGroups);
const providerProfileExpanded = expandPolicyWithPluginGroups( const providerProfileExpanded = expandPolicyWithPluginGroups(providerProfilePolicy, pluginGroups);
providerProfilePolicy,
pluginGroups,
);
const globalPolicyExpanded = expandPolicyWithPluginGroups(globalPolicy, pluginGroups); const globalPolicyExpanded = expandPolicyWithPluginGroups(globalPolicy, pluginGroups);
const globalProviderExpanded = expandPolicyWithPluginGroups( const globalProviderExpanded = expandPolicyWithPluginGroups(globalProviderPolicy, pluginGroups);
globalProviderPolicy,
pluginGroups,
);
const agentPolicyExpanded = expandPolicyWithPluginGroups(agentPolicy, pluginGroups); const agentPolicyExpanded = expandPolicyWithPluginGroups(agentPolicy, pluginGroups);
const agentProviderExpanded = expandPolicyWithPluginGroups( const agentProviderExpanded = expandPolicyWithPluginGroups(agentProviderPolicy, pluginGroups);
agentProviderPolicy,
pluginGroups,
);
const sandboxPolicyExpanded = expandPolicyWithPluginGroups(sandbox?.tools, pluginGroups); const sandboxPolicyExpanded = expandPolicyWithPluginGroups(sandbox?.tools, pluginGroups);
const subagentPolicyExpanded = expandPolicyWithPluginGroups(subagentPolicy, pluginGroups); const subagentPolicyExpanded = expandPolicyWithPluginGroups(subagentPolicy, pluginGroups);

View File

@@ -109,9 +109,7 @@ export function expandToolGroups(list?: string[]) {
return Array.from(new Set(expanded)); return Array.from(new Set(expanded));
} }
export function collectExplicitAllowlist( export function collectExplicitAllowlist(policies: Array<ToolPolicyLike | undefined>): string[] {
policies: Array<ToolPolicyLike | undefined>,
): string[] {
const entries: string[] = []; const entries: string[] = [];
for (const policy of policies) { for (const policy of policies) {
if (!policy?.allow) continue; if (!policy?.allow) continue;
@@ -124,9 +122,9 @@ export function collectExplicitAllowlist(
return entries; return entries;
} }
export function buildPluginToolGroups(params: { export function buildPluginToolGroups<T extends { name: string }>(params: {
tools: Array<{ name: string }>; tools: T[];
toolMeta: (tool: { name: string }) => { pluginId: string } | undefined; toolMeta: (tool: T) => { pluginId: string } | undefined;
}): PluginToolGroups { }): PluginToolGroups {
const all: string[] = []; const all: string[] = [];
const byPlugin = new Map<string, string[]>(); const byPlugin = new Map<string, string[]>();

View File

@@ -73,13 +73,11 @@ export function deriveGroupSessionPatch(params: {
const normalizedChannel = normalizeChannelId(channel); const normalizedChannel = normalizeChannelId(channel);
const isChannelProvider = Boolean( const isChannelProvider = Boolean(
normalizedChannel && normalizedChannel &&
getChannelDock(normalizedChannel)?.capabilities.chatTypes.includes("channel"), getChannelDock(normalizedChannel)?.capabilities.chatTypes.includes("channel"),
); );
const nextGroupChannel = const nextGroupChannel =
explicitChannel ?? explicitChannel ??
((resolution.chatType === "channel" || isChannelProvider) && ((resolution.chatType === "channel" || isChannelProvider) && subject && subject.startsWith("#")
subject &&
subject.startsWith("#")
? subject ? subject
: undefined); : undefined);
const nextSubject = nextGroupChannel ? undefined : subject; const nextSubject = nextGroupChannel ? undefined : subject;

View File

@@ -406,7 +406,10 @@ export async function updateLastRoute(params: {
lastTo: normalized.lastTo, lastTo: normalized.lastTo,
lastAccountId: normalized.lastAccountId, lastAccountId: normalized.lastAccountId,
}; };
const next = mergeSessionEntry(existing, metaPatch ? { ...basePatch, ...metaPatch } : basePatch); const next = mergeSessionEntry(
existing,
metaPatch ? { ...basePatch, ...metaPatch } : basePatch,
);
store[sessionKey] = next; store[sessionKey] = next;
await saveSessionStoreUnlocked(storePath, store); await saveSessionStoreUnlocked(storePath, store);
return next; return next;

View File

@@ -107,9 +107,16 @@ export {
} from "../channels/plugins/channel-config.js"; } from "../channels/plugins/channel-config.js";
export type { AllowlistMatch } from "../channels/plugins/allowlist-match.js"; export type { AllowlistMatch } from "../channels/plugins/allowlist-match.js";
export { formatAllowlistMatchMeta } from "../channels/plugins/allowlist-match.js"; export { formatAllowlistMatchMeta } from "../channels/plugins/allowlist-match.js";
export { readChannelAllowFromStore, upsertChannelPairingRequest } from "../pairing/pairing-store.js"; export {
readChannelAllowFromStore,
upsertChannelPairingRequest,
} from "../pairing/pairing-store.js";
export { resolveAgentRoute } from "../routing/resolve-route.js"; export { resolveAgentRoute } from "../routing/resolve-route.js";
export { recordSessionMetaFromInbound, resolveStorePath, updateLastRoute } from "../config/sessions.js"; export {
recordSessionMetaFromInbound,
resolveStorePath,
updateLastRoute,
} from "../config/sessions.js";
export { resolveStateDir } from "../config/paths.js"; export { resolveStateDir } from "../config/paths.js";
export { loadConfig } from "../config/config.js"; export { loadConfig } from "../config/config.js";
export { danger } from "../globals.js"; export { danger } from "../globals.js";
@@ -130,7 +137,10 @@ export {
deleteAccountFromConfigSection, deleteAccountFromConfigSection,
setAccountEnabledInConfigSection, setAccountEnabledInConfigSection,
} from "../channels/plugins/config-helpers.js"; } from "../channels/plugins/config-helpers.js";
export { applyAccountNameToChannelSection, migrateBaseNameToDefaultAccount } from "../channels/plugins/setup-helpers.js"; export {
applyAccountNameToChannelSection,
migrateBaseNameToDefaultAccount,
} from "../channels/plugins/setup-helpers.js";
export { formatPairingApproveHint } from "../channels/plugins/helpers.js"; export { formatPairingApproveHint } from "../channels/plugins/helpers.js";
export { PAIRING_APPROVED_MESSAGE } from "../channels/plugins/pairing-message.js"; export { PAIRING_APPROVED_MESSAGE } from "../channels/plugins/pairing-message.js";

View File

@@ -2,20 +2,29 @@ import { createRequire } from "node:module";
import { chunkMarkdownText, resolveTextChunkLimit } from "../../auto-reply/chunk.js"; import { chunkMarkdownText, resolveTextChunkLimit } from "../../auto-reply/chunk.js";
import { hasControlCommand } from "../../auto-reply/command-detection.js"; import { hasControlCommand } from "../../auto-reply/command-detection.js";
import { createInboundDebouncer, resolveInboundDebounceMs } from "../../auto-reply/inbound-debounce.js"; import {
createInboundDebouncer,
resolveInboundDebounceMs,
} from "../../auto-reply/inbound-debounce.js";
import { buildMentionRegexes, matchesMentionPatterns } from "../../auto-reply/reply/mentions.js"; import { buildMentionRegexes, matchesMentionPatterns } from "../../auto-reply/reply/mentions.js";
import { dispatchReplyWithBufferedBlockDispatcher } from "../../auto-reply/reply/provider-dispatcher.js"; import { dispatchReplyWithBufferedBlockDispatcher } from "../../auto-reply/reply/provider-dispatcher.js";
import { createReplyDispatcherWithTyping } from "../../auto-reply/reply/reply-dispatcher.js"; import { createReplyDispatcherWithTyping } from "../../auto-reply/reply/reply-dispatcher.js";
import { resolveEffectiveMessagesConfig, resolveHumanDelayConfig } from "../../agents/identity.js"; import { resolveEffectiveMessagesConfig, resolveHumanDelayConfig } from "../../agents/identity.js";
import { resolveCommandAuthorizedFromAuthorizers } from "../../channels/command-gating.js"; import { resolveCommandAuthorizedFromAuthorizers } from "../../channels/command-gating.js";
import { resolveChannelGroupPolicy, resolveChannelGroupRequireMention } from "../../config/group-policy.js"; import {
resolveChannelGroupPolicy,
resolveChannelGroupRequireMention,
} from "../../config/group-policy.js";
import { resolveStateDir } from "../../config/paths.js"; import { resolveStateDir } from "../../config/paths.js";
import { shouldLogVerbose } from "../../globals.js"; import { shouldLogVerbose } from "../../globals.js";
import { getChildLogger } from "../../logging.js"; import { getChildLogger } from "../../logging.js";
import { fetchRemoteMedia } from "../../media/fetch.js"; import { fetchRemoteMedia } from "../../media/fetch.js";
import { saveMediaBuffer } from "../../media/store.js"; import { saveMediaBuffer } from "../../media/store.js";
import { buildPairingReply } from "../../pairing/pairing-messages.js"; import { buildPairingReply } from "../../pairing/pairing-messages.js";
import { readChannelAllowFromStore, upsertChannelPairingRequest } from "../../pairing/pairing-store.js"; import {
readChannelAllowFromStore,
upsertChannelPairingRequest,
} from "../../pairing/pairing-store.js";
import { resolveAgentRoute } from "../../routing/resolve-route.js"; import { resolveAgentRoute } from "../../routing/resolve-route.js";
import type { PluginRuntime } from "./types.js"; import type { PluginRuntime } from "./types.js";

View File

@@ -51,7 +51,10 @@ export type PluginRuntime = {
}; };
logging: { logging: {
shouldLogVerbose: typeof import("../../globals.js").shouldLogVerbose; shouldLogVerbose: typeof import("../../globals.js").shouldLogVerbose;
getChildLogger: (bindings?: Record<string, unknown>, opts?: { level?: LogLevel }) => RuntimeLogger; getChildLogger: (
bindings?: Record<string, unknown>,
opts?: { level?: LogLevel },
) => RuntimeLogger;
}; };
state: { state: {
resolveStateDir: typeof import("../../config/paths.js").resolveStateDir; resolveStateDir: typeof import("../../config/paths.js").resolveStateDir;

View File

@@ -52,9 +52,7 @@ export function resolvePluginTools(params: {
const tools: AnyAgentTool[] = []; const tools: AnyAgentTool[] = [];
const existing = params.existingToolNames ?? new Set<string>(); const existing = params.existingToolNames ?? new Set<string>();
const existingNormalized = new Set( const existingNormalized = new Set(Array.from(existing, (tool) => normalizeToolName(tool)));
Array.from(existing, (tool) => normalizeToolName(tool)),
);
const allowlist = normalizeAllowlist(params.toolAllowlist); const allowlist = normalizeAllowlist(params.toolAllowlist);
const blockedPlugins = new Set<string>(); const blockedPlugins = new Set<string>();

View File

@@ -240,39 +240,39 @@ export async function processMessage(params: {
}; };
const ctxPayload = finalizeInboundContext({ const ctxPayload = finalizeInboundContext({
Body: combinedBody, Body: combinedBody,
RawBody: params.msg.body, RawBody: params.msg.body,
CommandBody: params.msg.body, CommandBody: params.msg.body,
From: params.msg.from, From: params.msg.from,
To: params.msg.to, To: params.msg.to,
SessionKey: params.route.sessionKey, SessionKey: params.route.sessionKey,
AccountId: params.route.accountId, AccountId: params.route.accountId,
MessageSid: params.msg.id, MessageSid: params.msg.id,
ReplyToId: params.msg.replyToId, ReplyToId: params.msg.replyToId,
ReplyToBody: params.msg.replyToBody, ReplyToBody: params.msg.replyToBody,
ReplyToSender: params.msg.replyToSender, ReplyToSender: params.msg.replyToSender,
MediaPath: params.msg.mediaPath, MediaPath: params.msg.mediaPath,
MediaUrl: params.msg.mediaUrl, MediaUrl: params.msg.mediaUrl,
MediaType: params.msg.mediaType, MediaType: params.msg.mediaType,
ChatType: params.msg.chatType, ChatType: params.msg.chatType,
ConversationLabel: params.msg.chatType === "group" ? conversationId : params.msg.from, ConversationLabel: params.msg.chatType === "group" ? conversationId : params.msg.from,
GroupSubject: params.msg.groupSubject, GroupSubject: params.msg.groupSubject,
GroupMembers: formatGroupMembers({ GroupMembers: formatGroupMembers({
participants: params.msg.groupParticipants, participants: params.msg.groupParticipants,
roster: params.groupMemberNames.get(params.groupHistoryKey), roster: params.groupMemberNames.get(params.groupHistoryKey),
fallbackE164: params.msg.senderE164, fallbackE164: params.msg.senderE164,
}), }),
SenderName: params.msg.senderName, SenderName: params.msg.senderName,
SenderId: params.msg.senderJid?.trim() || params.msg.senderE164, SenderId: params.msg.senderJid?.trim() || params.msg.senderE164,
SenderE164: params.msg.senderE164, SenderE164: params.msg.senderE164,
CommandAuthorized: commandAuthorized, CommandAuthorized: commandAuthorized,
WasMentioned: params.msg.wasMentioned, WasMentioned: params.msg.wasMentioned,
...(params.msg.location ? toLocationContext(params.msg.location) : {}), ...(params.msg.location ? toLocationContext(params.msg.location) : {}),
Provider: "whatsapp", Provider: "whatsapp",
Surface: "whatsapp", Surface: "whatsapp",
OriginatingChannel: "whatsapp", OriginatingChannel: "whatsapp",
OriginatingTo: params.msg.from, OriginatingTo: params.msg.from,
}); });
if (dmRouteTarget) { if (dmRouteTarget) {
updateLastRouteInBackground({ updateLastRouteInBackground({