mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-22 10:25:20 -06:00
8ee945b907
* refactor(channels): flatten channel turn dispatch naming * docs(plugin-sdk): narrow inbound reply compat guidance * docs(channels): point stale references at turn defining modules * fix(channels): preserve dispatch contracts after flattening * chore(plugin-sdk): ratchet surface budgets after flattening * chore(channels): ratchet removed export collisions * fix(plugin-sdk): restore inbound reply compat exports Restore eight still-existing legacy callable re-exports from canonical SDK seams and cover the deprecated package subpath with a table-driven compatibility test. Raise the public export, callable export, and deprecated export budgets by exactly eight; the three maintainer-authorized zero-consumer symbols remain removed. * test(channels): split channel turn kernel coverage Replace the oversized kernel test with independently mocked delivery, pipeline, and finalize suites, preserving all 51 tests while removing the max-lines suppression and stale ratchet entry. * chore(plugin-sdk): refresh inbound reply API hash * fix(ci): align channel turn review fixes Restore the test-local DeliveryResult type removed during the split. Ratchet the public export, callable export, and deprecated export budgets by exactly seven: six channel-inbound plus one channel-outbound legacy re-export.
143 lines
5.4 KiB
TypeScript
143 lines
5.4 KiB
TypeScript
import { describe, expect, expectTypeOf, it, vi } from "vitest";
|
|
import type { DispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.types.js";
|
|
import type { FinalizedMsgContext } from "../auto-reply/templating.js";
|
|
import type { RecordInboundSession } from "../channels/session.types.js";
|
|
import type {
|
|
AssembledChannelTurn,
|
|
ChannelTurnResult,
|
|
PreparedChannelTurn,
|
|
} from "../channels/turn/types.js";
|
|
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
|
import {
|
|
dispatchChannelInboundReply,
|
|
dispatchChannelInboundTurn,
|
|
runPreparedInboundReply,
|
|
} from "./channel-inbound.js";
|
|
import {
|
|
deliverInboundReplyWithMessageSendContext,
|
|
dispatchChannelInboundReply as dispatchChannelInboundReplyFromLegacySubpath,
|
|
dispatchInboundReplyWithBase,
|
|
hasFinalInboundReplyDispatch,
|
|
hasVisibleInboundReplyDispatch,
|
|
recordChannelBotPairLoopAndCheckSuppression,
|
|
recordDroppedChannelInboundHistory,
|
|
recordDroppedChannelTurnHistory,
|
|
resolveInboundReplyDispatchCounts,
|
|
runChannelInboundEvent,
|
|
runPreparedInboundReply as runPreparedInboundReplyFromLegacySubpath,
|
|
type AssembledInboundReply,
|
|
type ChannelBotLoopProtectionFacts,
|
|
type ChannelInboundDroppedHistoryOptions,
|
|
type ChannelInboundEventRunnerParams,
|
|
type ChannelTurnDroppedHistoryOptions,
|
|
type ChannelTurnRecordOptions,
|
|
type DurableInboundReplyDeliveryParams,
|
|
type InboundReplyDispatchResult,
|
|
type InboundReplyRecordOptions,
|
|
type PreparedInboundReply,
|
|
} from "./inbound-reply-dispatch.js";
|
|
|
|
describe("inbound reply dispatch compatibility", () => {
|
|
it("keeps the deprecated package subpath compatibility exports", () => {
|
|
const callableExports = [
|
|
["hasFinalInboundReplyDispatch", hasFinalInboundReplyDispatch],
|
|
["hasVisibleInboundReplyDispatch", hasVisibleInboundReplyDispatch],
|
|
["resolveInboundReplyDispatchCounts", resolveInboundReplyDispatchCounts],
|
|
["recordDroppedChannelTurnHistory", recordDroppedChannelTurnHistory],
|
|
["recordDroppedChannelInboundHistory", recordDroppedChannelInboundHistory],
|
|
["recordChannelBotPairLoopAndCheckSuppression", recordChannelBotPairLoopAndCheckSuppression],
|
|
["deliverInboundReplyWithMessageSendContext", deliverInboundReplyWithMessageSendContext],
|
|
["dispatchInboundReplyWithBase", dispatchInboundReplyWithBase],
|
|
["runPreparedInboundReply", runPreparedInboundReplyFromLegacySubpath],
|
|
["runChannelInboundEvent", runChannelInboundEvent],
|
|
["dispatchChannelInboundReply", dispatchChannelInboundReplyFromLegacySubpath],
|
|
] as const;
|
|
|
|
for (const [exportName, exportedValue] of callableExports) {
|
|
expect(exportedValue, exportName).toBeTypeOf("function");
|
|
}
|
|
|
|
type LegacyTypeExports = [
|
|
AssembledInboundReply,
|
|
ChannelBotLoopProtectionFacts,
|
|
ChannelInboundDroppedHistoryOptions,
|
|
ChannelInboundEventRunnerParams<unknown>,
|
|
ChannelTurnDroppedHistoryOptions,
|
|
ChannelTurnRecordOptions,
|
|
DurableInboundReplyDeliveryParams,
|
|
InboundReplyDispatchResult<unknown>,
|
|
InboundReplyRecordOptions,
|
|
PreparedInboundReply<unknown>,
|
|
];
|
|
expectTypeOf<LegacyTypeExports>().not.toBeNever();
|
|
});
|
|
|
|
it("keeps public channel-inbound entry points drop-capable", () => {
|
|
type DispatchResult = { queuedFinal: true };
|
|
const prepared = {} as PreparedChannelTurn<DispatchResult>;
|
|
const assembled = {} as AssembledChannelTurn;
|
|
|
|
if (Date.now() < 0) {
|
|
expectTypeOf(runPreparedInboundReply(prepared)).toEqualTypeOf<
|
|
Promise<ChannelTurnResult<DispatchResult>>
|
|
>();
|
|
expectTypeOf(dispatchChannelInboundReply(assembled)).toEqualTypeOf<
|
|
Promise<ChannelTurnResult>
|
|
>();
|
|
expectTypeOf(dispatchChannelInboundTurn({} as never)).toEqualTypeOf<
|
|
Promise<ChannelTurnResult>
|
|
>();
|
|
}
|
|
});
|
|
|
|
it("records and dispatches through dispatchInboundReplyWithBase", async () => {
|
|
const recordInboundSession = vi.fn(async () => undefined) as unknown as RecordInboundSession;
|
|
const deliver = vi.fn(async () => undefined);
|
|
const dispatchReplyWithBufferedBlockDispatcher = vi.fn(async (params) => {
|
|
await params.dispatcherOptions.deliver(
|
|
{ text: "hello", mediaUrls: ["https://example.com/a.png"] },
|
|
{ kind: "final" },
|
|
);
|
|
return { queuedFinal: true, counts: { tool: 0, block: 0, final: 1 } };
|
|
}) as DispatchReplyWithBufferedBlockDispatcher;
|
|
const ctxPayload = {
|
|
Body: "body",
|
|
RawBody: "body",
|
|
CommandBody: "body",
|
|
From: "sender",
|
|
To: "target",
|
|
SessionKey: "agent:main:test:peer",
|
|
Provider: "test",
|
|
Surface: "test",
|
|
} as FinalizedMsgContext;
|
|
|
|
await dispatchInboundReplyWithBase({
|
|
cfg: {} as OpenClawConfig,
|
|
channel: "test",
|
|
accountId: "default",
|
|
route: { agentId: "main", sessionKey: "agent:main:test:peer" },
|
|
storePath: "/tmp/sessions.json",
|
|
ctxPayload,
|
|
core: {
|
|
channel: {
|
|
session: { recordInboundSession },
|
|
reply: { dispatchReplyWithBufferedBlockDispatcher },
|
|
},
|
|
},
|
|
deliver,
|
|
onRecordError: vi.fn(),
|
|
onDispatchError: vi.fn(),
|
|
});
|
|
|
|
expect(recordInboundSession).toHaveBeenCalledOnce();
|
|
expect(dispatchReplyWithBufferedBlockDispatcher).toHaveBeenCalledOnce();
|
|
expect(deliver).toHaveBeenCalledWith({
|
|
text: "hello",
|
|
mediaUrls: ["https://example.com/a.png"],
|
|
mediaUrl: undefined,
|
|
sensitiveMedia: undefined,
|
|
replyToId: undefined,
|
|
});
|
|
});
|
|
});
|