mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-18 08:33:15 +08:00
重构主控编排与运行时预热链路,统一工作区提示词/专家调度协议并补齐 wiki 记忆注入与写回闭环。
同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
This commit is contained in:
parent
4a23b715a2
commit
dbbe3add6a
14438 changed files with 2693620 additions and 2546 deletions
|
|
@ -0,0 +1,229 @@
|
|||
import { expect, it } from "vitest";
|
||||
import type {
|
||||
ChannelDirectoryEntry,
|
||||
ChannelFocusedBindingContext,
|
||||
ChannelReplyTransport,
|
||||
ChannelThreadingToolContext,
|
||||
} from "../../../src/channels/plugins/types.core.js";
|
||||
import type { ChannelPlugin } from "../../../src/channels/plugins/types.js";
|
||||
import type { OpenClawConfig } from "../../../src/config/config.js";
|
||||
import { createNonExitingRuntime } from "../../../src/runtime.js";
|
||||
|
||||
const contractRuntime = createNonExitingRuntime();
|
||||
|
||||
function expectDirectoryEntryShape(entry: ChannelDirectoryEntry) {
|
||||
expect(["user", "group", "channel"]).toContain(entry.kind);
|
||||
expect(typeof entry.id).toBe("string");
|
||||
expect(entry.id.trim()).not.toBe("");
|
||||
if (entry.name !== undefined) {
|
||||
expect(typeof entry.name).toBe("string");
|
||||
}
|
||||
if (entry.handle !== undefined) {
|
||||
expect(typeof entry.handle).toBe("string");
|
||||
}
|
||||
if (entry.avatarUrl !== undefined) {
|
||||
expect(typeof entry.avatarUrl).toBe("string");
|
||||
}
|
||||
if (entry.rank !== undefined) {
|
||||
expect(typeof entry.rank).toBe("number");
|
||||
}
|
||||
}
|
||||
|
||||
function expectThreadingToolContextShape(context: ChannelThreadingToolContext) {
|
||||
if (context.currentChannelId !== undefined) {
|
||||
expect(typeof context.currentChannelId).toBe("string");
|
||||
}
|
||||
if (context.currentChannelProvider !== undefined) {
|
||||
expect(typeof context.currentChannelProvider).toBe("string");
|
||||
}
|
||||
if (context.currentThreadTs !== undefined) {
|
||||
expect(typeof context.currentThreadTs).toBe("string");
|
||||
}
|
||||
if (context.currentMessageId !== undefined) {
|
||||
expect(["string", "number"]).toContain(typeof context.currentMessageId);
|
||||
}
|
||||
if (context.replyToMode !== undefined) {
|
||||
expect(["off", "first", "all"]).toContain(context.replyToMode);
|
||||
}
|
||||
if (context.hasRepliedRef !== undefined) {
|
||||
expect(typeof context.hasRepliedRef).toBe("object");
|
||||
}
|
||||
if (context.skipCrossContextDecoration !== undefined) {
|
||||
expect(typeof context.skipCrossContextDecoration).toBe("boolean");
|
||||
}
|
||||
}
|
||||
|
||||
function expectReplyTransportShape(transport: ChannelReplyTransport) {
|
||||
if (transport.replyToId !== undefined && transport.replyToId !== null) {
|
||||
expect(typeof transport.replyToId).toBe("string");
|
||||
}
|
||||
if (transport.threadId !== undefined && transport.threadId !== null) {
|
||||
expect(["string", "number"]).toContain(typeof transport.threadId);
|
||||
}
|
||||
}
|
||||
|
||||
function expectFocusedBindingShape(binding: ChannelFocusedBindingContext) {
|
||||
expect(typeof binding.conversationId).toBe("string");
|
||||
expect(binding.conversationId.trim()).not.toBe("");
|
||||
if (binding.parentConversationId !== undefined) {
|
||||
expect(typeof binding.parentConversationId).toBe("string");
|
||||
}
|
||||
expect(["current", "child"]).toContain(binding.placement);
|
||||
expect(typeof binding.labelNoun).toBe("string");
|
||||
expect(binding.labelNoun.trim()).not.toBe("");
|
||||
}
|
||||
|
||||
export function installChannelThreadingContractSuite(params: {
|
||||
plugin: Pick<ChannelPlugin, "id" | "threading">;
|
||||
}) {
|
||||
it("exposes the base threading contract", () => {
|
||||
expect(params.plugin.threading).toBeDefined();
|
||||
});
|
||||
|
||||
it("keeps threading return values normalized", () => {
|
||||
const threading = params.plugin.threading;
|
||||
expect(threading).toBeDefined();
|
||||
|
||||
if (threading?.resolveReplyToMode) {
|
||||
expect(
|
||||
["off", "first", "all"].includes(
|
||||
threading.resolveReplyToMode({
|
||||
cfg: {} as OpenClawConfig,
|
||||
accountId: "default",
|
||||
chatType: "group",
|
||||
}),
|
||||
),
|
||||
).toBe(true);
|
||||
}
|
||||
|
||||
const repliedRef = { value: false };
|
||||
const toolContext = threading?.buildToolContext?.({
|
||||
cfg: {} as OpenClawConfig,
|
||||
accountId: "default",
|
||||
context: {
|
||||
Channel: "group:test",
|
||||
From: "user:test",
|
||||
To: "group:test",
|
||||
ChatType: "group",
|
||||
CurrentMessageId: "msg-1",
|
||||
ReplyToId: "msg-0",
|
||||
ReplyToIdFull: "thread-0",
|
||||
MessageThreadId: "thread-0",
|
||||
NativeChannelId: "native:test",
|
||||
},
|
||||
hasRepliedRef: repliedRef,
|
||||
});
|
||||
|
||||
if (toolContext) {
|
||||
expectThreadingToolContextShape(toolContext);
|
||||
if (toolContext.hasRepliedRef) {
|
||||
expect(toolContext.hasRepliedRef).toBe(repliedRef);
|
||||
}
|
||||
}
|
||||
|
||||
const autoThreadId = threading?.resolveAutoThreadId?.({
|
||||
cfg: {} as OpenClawConfig,
|
||||
accountId: "default",
|
||||
to: "group:test",
|
||||
toolContext,
|
||||
replyToId: null,
|
||||
});
|
||||
if (autoThreadId !== undefined) {
|
||||
expect(typeof autoThreadId).toBe("string");
|
||||
expect(autoThreadId.trim()).not.toBe("");
|
||||
}
|
||||
|
||||
const replyTransport = threading?.resolveReplyTransport?.({
|
||||
cfg: {} as OpenClawConfig,
|
||||
accountId: "default",
|
||||
threadId: "thread-0",
|
||||
replyToId: "msg-0",
|
||||
});
|
||||
if (replyTransport) {
|
||||
expectReplyTransportShape(replyTransport);
|
||||
}
|
||||
|
||||
const focusedBinding = threading?.resolveFocusedBinding?.({
|
||||
cfg: {} as OpenClawConfig,
|
||||
accountId: "default",
|
||||
context: {
|
||||
Channel: "group:test",
|
||||
From: "user:test",
|
||||
To: "group:test",
|
||||
ChatType: "group",
|
||||
CurrentMessageId: "msg-1",
|
||||
ReplyToId: "msg-0",
|
||||
ReplyToIdFull: "thread-0",
|
||||
MessageThreadId: "thread-0",
|
||||
NativeChannelId: "native:test",
|
||||
},
|
||||
});
|
||||
if (focusedBinding) {
|
||||
expectFocusedBindingShape(focusedBinding);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function installChannelDirectoryContractSuite(params: {
|
||||
plugin: Pick<ChannelPlugin, "id" | "directory">;
|
||||
coverage?: "lookups" | "presence";
|
||||
cfg?: OpenClawConfig;
|
||||
accountId?: string;
|
||||
}) {
|
||||
it("exposes the base directory contract", async () => {
|
||||
const directory = params.plugin.directory;
|
||||
expect(directory).toBeDefined();
|
||||
|
||||
if (params.coverage === "presence") {
|
||||
return;
|
||||
}
|
||||
const self = await directory?.self?.({
|
||||
cfg: params.cfg ?? ({} as OpenClawConfig),
|
||||
accountId: params.accountId ?? "default",
|
||||
runtime: contractRuntime,
|
||||
});
|
||||
if (self) {
|
||||
expectDirectoryEntryShape(self);
|
||||
}
|
||||
|
||||
const peers =
|
||||
(await directory?.listPeers?.({
|
||||
cfg: params.cfg ?? ({} as OpenClawConfig),
|
||||
accountId: params.accountId ?? "default",
|
||||
query: "",
|
||||
limit: 5,
|
||||
runtime: contractRuntime,
|
||||
})) ?? [];
|
||||
expect(Array.isArray(peers)).toBe(true);
|
||||
for (const peer of peers) {
|
||||
expectDirectoryEntryShape(peer);
|
||||
}
|
||||
|
||||
const groups =
|
||||
(await directory?.listGroups?.({
|
||||
cfg: params.cfg ?? ({} as OpenClawConfig),
|
||||
accountId: params.accountId ?? "default",
|
||||
query: "",
|
||||
limit: 5,
|
||||
runtime: contractRuntime,
|
||||
})) ?? [];
|
||||
expect(Array.isArray(groups)).toBe(true);
|
||||
for (const group of groups) {
|
||||
expectDirectoryEntryShape(group);
|
||||
}
|
||||
|
||||
if (directory?.listGroupMembers && groups[0]?.id) {
|
||||
const members = await directory.listGroupMembers({
|
||||
cfg: params.cfg ?? ({} as OpenClawConfig),
|
||||
accountId: params.accountId ?? "default",
|
||||
groupId: groups[0].id,
|
||||
limit: 5,
|
||||
runtime: contractRuntime,
|
||||
});
|
||||
expect(Array.isArray(members)).toBe(true);
|
||||
for (const member of members) {
|
||||
expectDirectoryEntryShape(member);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue