refactor: dedupe shared config type definitions
This commit is contained in:
@@ -9,6 +9,22 @@ import {
|
||||
saveSessionStore,
|
||||
} from "./sessions.js";
|
||||
|
||||
function createSessionEntry(overrides: Partial<SessionEntry> = {}): SessionEntry {
|
||||
return {
|
||||
sessionId: "id-1",
|
||||
updatedAt: Date.now(),
|
||||
displayName: "Test Session 1",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function createSingleSessionStore(
|
||||
entry: SessionEntry = createSessionEntry(),
|
||||
key = "session:1",
|
||||
): Record<string, SessionEntry> {
|
||||
return { [key]: entry };
|
||||
}
|
||||
|
||||
describe("Session Store Cache", () => {
|
||||
let fixtureRoot = "";
|
||||
let caseId = 0;
|
||||
@@ -43,13 +59,7 @@ describe("Session Store Cache", () => {
|
||||
});
|
||||
|
||||
it("should load session store from disk on first call", async () => {
|
||||
const testStore: Record<string, SessionEntry> = {
|
||||
"session:1": {
|
||||
sessionId: "id-1",
|
||||
updatedAt: Date.now(),
|
||||
displayName: "Test Session 1",
|
||||
},
|
||||
};
|
||||
const testStore = createSingleSessionStore();
|
||||
|
||||
// Write test data
|
||||
await saveSessionStore(storePath, testStore);
|
||||
@@ -60,13 +70,7 @@ describe("Session Store Cache", () => {
|
||||
});
|
||||
|
||||
it("should cache session store on first load when file is unchanged", async () => {
|
||||
const testStore: Record<string, SessionEntry> = {
|
||||
"session:1": {
|
||||
sessionId: "id-1",
|
||||
updatedAt: Date.now(),
|
||||
displayName: "Test Session 1",
|
||||
},
|
||||
};
|
||||
const testStore = createSingleSessionStore();
|
||||
|
||||
await saveSessionStore(storePath, testStore);
|
||||
|
||||
@@ -84,17 +88,15 @@ describe("Session Store Cache", () => {
|
||||
});
|
||||
|
||||
it("should not allow cached session mutations to leak across loads", async () => {
|
||||
const testStore: Record<string, SessionEntry> = {
|
||||
"session:1": {
|
||||
sessionId: "id-1",
|
||||
updatedAt: Date.now(),
|
||||
const testStore = createSingleSessionStore(
|
||||
createSessionEntry({
|
||||
cliSessionIds: { openai: "sess-1" },
|
||||
skillsSnapshot: {
|
||||
prompt: "skills",
|
||||
skills: [{ name: "alpha" }],
|
||||
},
|
||||
},
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
await saveSessionStore(storePath, testStore);
|
||||
|
||||
@@ -110,13 +112,7 @@ describe("Session Store Cache", () => {
|
||||
});
|
||||
|
||||
it("should refresh cache when store file changes on disk", async () => {
|
||||
const testStore: Record<string, SessionEntry> = {
|
||||
"session:1": {
|
||||
sessionId: "id-1",
|
||||
updatedAt: Date.now(),
|
||||
displayName: "Test Session 1",
|
||||
},
|
||||
};
|
||||
const testStore = createSingleSessionStore();
|
||||
|
||||
await saveSessionStore(storePath, testStore);
|
||||
|
||||
@@ -138,13 +134,7 @@ describe("Session Store Cache", () => {
|
||||
});
|
||||
|
||||
it("should invalidate cache on write", async () => {
|
||||
const testStore: Record<string, SessionEntry> = {
|
||||
"session:1": {
|
||||
sessionId: "id-1",
|
||||
updatedAt: Date.now(),
|
||||
displayName: "Test Session 1",
|
||||
},
|
||||
};
|
||||
const testStore = createSingleSessionStore();
|
||||
|
||||
await saveSessionStore(storePath, testStore);
|
||||
|
||||
@@ -172,13 +162,7 @@ describe("Session Store Cache", () => {
|
||||
process.env.OPENCLAW_SESSION_CACHE_TTL_MS = "0";
|
||||
clearSessionStoreCacheForTest();
|
||||
|
||||
const testStore: Record<string, SessionEntry> = {
|
||||
"session:1": {
|
||||
sessionId: "id-1",
|
||||
updatedAt: Date.now(),
|
||||
displayName: "Test Session 1",
|
||||
},
|
||||
};
|
||||
const testStore = createSingleSessionStore();
|
||||
|
||||
await saveSessionStore(storePath, testStore);
|
||||
|
||||
@@ -187,13 +171,10 @@ describe("Session Store Cache", () => {
|
||||
expect(loaded1).toEqual(testStore);
|
||||
|
||||
// Modify file on disk
|
||||
const modifiedStore: Record<string, SessionEntry> = {
|
||||
"session:2": {
|
||||
sessionId: "id-2",
|
||||
updatedAt: Date.now(),
|
||||
displayName: "Test Session 2",
|
||||
},
|
||||
};
|
||||
const modifiedStore = createSingleSessionStore(
|
||||
createSessionEntry({ sessionId: "id-2", displayName: "Test Session 2" }),
|
||||
"session:2",
|
||||
);
|
||||
fs.writeFileSync(storePath, JSON.stringify(modifiedStore, null, 2));
|
||||
|
||||
// Second load - should read from disk (cache disabled)
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import type { ChannelId } from "../channels/plugins/types.js";
|
||||
import type { AgentModelConfig, AgentSandboxConfig } from "./types.agents-shared.js";
|
||||
import type {
|
||||
BlockStreamingChunkConfig,
|
||||
BlockStreamingCoalesceConfig,
|
||||
HumanDelayConfig,
|
||||
TypingMode,
|
||||
} from "./types.base.js";
|
||||
import type {
|
||||
SandboxBrowserSettings,
|
||||
SandboxDockerSettings,
|
||||
SandboxPruneSettings,
|
||||
} from "./types.sandbox.js";
|
||||
import type { MemorySearchConfig } from "./types.tools.js";
|
||||
|
||||
export type AgentModelEntryConfig = {
|
||||
@@ -248,40 +244,12 @@ export type AgentDefaultsConfig = {
|
||||
/** Auto-archive sub-agent sessions after N minutes (default: 60). */
|
||||
archiveAfterMinutes?: number;
|
||||
/** Default model selection for spawned sub-agents (string or {primary,fallbacks}). */
|
||||
model?: string | { primary?: string; fallbacks?: string[] };
|
||||
model?: AgentModelConfig;
|
||||
/** Default thinking level for spawned sub-agents (e.g. "off", "low", "medium", "high"). */
|
||||
thinking?: string;
|
||||
};
|
||||
/** Optional sandbox settings for non-main sessions. */
|
||||
sandbox?: {
|
||||
/** Enable sandboxing for sessions. */
|
||||
mode?: "off" | "non-main" | "all";
|
||||
/**
|
||||
* Agent workspace access inside the sandbox.
|
||||
* - "none": do not mount the agent workspace into the container; use a sandbox workspace under workspaceRoot
|
||||
* - "ro": mount the agent workspace read-only; disables write/edit tools
|
||||
* - "rw": mount the agent workspace read/write; enables write/edit tools
|
||||
*/
|
||||
workspaceAccess?: "none" | "ro" | "rw";
|
||||
/**
|
||||
* Session tools visibility for sandboxed sessions.
|
||||
* - "spawned": only allow session tools to target the current session and sessions spawned from it (default)
|
||||
* - "all": allow session tools to target any session
|
||||
*/
|
||||
sessionToolsVisibility?: "spawned" | "all";
|
||||
/** Container/workspace scope for sandbox isolation. */
|
||||
scope?: "session" | "agent" | "shared";
|
||||
/** Legacy alias for scope ("session" when true, "shared" when false). */
|
||||
perSession?: boolean;
|
||||
/** Root directory for sandbox workspaces. */
|
||||
workspaceRoot?: string;
|
||||
/** Docker-specific sandbox settings. */
|
||||
docker?: SandboxDockerSettings;
|
||||
/** Optional sandboxed browser settings. */
|
||||
browser?: SandboxBrowserSettings;
|
||||
/** Auto-prune sandbox containers. */
|
||||
prune?: SandboxPruneSettings;
|
||||
};
|
||||
sandbox?: AgentSandboxConfig;
|
||||
};
|
||||
|
||||
export type AgentCompactionMode = "default" | "safeguard";
|
||||
|
||||
37
src/config/types.agents-shared.ts
Normal file
37
src/config/types.agents-shared.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import type {
|
||||
SandboxBrowserSettings,
|
||||
SandboxDockerSettings,
|
||||
SandboxPruneSettings,
|
||||
} from "./types.sandbox.js";
|
||||
|
||||
export type AgentModelConfig =
|
||||
| string
|
||||
| {
|
||||
/** Primary model (provider/model). */
|
||||
primary?: string;
|
||||
/** Per-agent model fallbacks (provider/model). */
|
||||
fallbacks?: string[];
|
||||
};
|
||||
|
||||
export type AgentSandboxConfig = {
|
||||
mode?: "off" | "non-main" | "all";
|
||||
/** Agent workspace access inside the sandbox. */
|
||||
workspaceAccess?: "none" | "ro" | "rw";
|
||||
/**
|
||||
* Session tools visibility for sandboxed sessions.
|
||||
* - "spawned": only allow session tools to target sessions spawned from this session (default)
|
||||
* - "all": allow session tools to target any session
|
||||
*/
|
||||
sessionToolsVisibility?: "spawned" | "all";
|
||||
/** Container/workspace scope for sandbox isolation. */
|
||||
scope?: "session" | "agent" | "shared";
|
||||
/** Legacy alias for scope ("session" when true, "shared" when false). */
|
||||
perSession?: boolean;
|
||||
workspaceRoot?: string;
|
||||
/** Docker-specific sandbox settings. */
|
||||
docker?: SandboxDockerSettings;
|
||||
/** Optional sandboxed browser settings. */
|
||||
browser?: SandboxBrowserSettings;
|
||||
/** Auto-prune sandbox settings. */
|
||||
prune?: SandboxPruneSettings;
|
||||
};
|
||||
@@ -1,23 +1,10 @@
|
||||
import type { ChatType } from "../channels/chat-type.js";
|
||||
import type { AgentDefaultsConfig } from "./types.agent-defaults.js";
|
||||
import type { AgentModelConfig, AgentSandboxConfig } from "./types.agents-shared.js";
|
||||
import type { HumanDelayConfig, IdentityConfig } from "./types.base.js";
|
||||
import type { GroupChatConfig } from "./types.messages.js";
|
||||
import type {
|
||||
SandboxBrowserSettings,
|
||||
SandboxDockerSettings,
|
||||
SandboxPruneSettings,
|
||||
} from "./types.sandbox.js";
|
||||
import type { AgentToolsConfig, MemorySearchConfig } from "./types.tools.js";
|
||||
|
||||
export type AgentModelConfig =
|
||||
| string
|
||||
| {
|
||||
/** Primary model (provider/model). */
|
||||
primary?: string;
|
||||
/** Per-agent model fallbacks (provider/model). */
|
||||
fallbacks?: string[];
|
||||
};
|
||||
|
||||
export type AgentConfig = {
|
||||
id: string;
|
||||
default?: boolean;
|
||||
@@ -38,30 +25,10 @@ export type AgentConfig = {
|
||||
/** Allow spawning sub-agents under other agent ids. Use "*" to allow any. */
|
||||
allowAgents?: string[];
|
||||
/** Per-agent default model for spawned sub-agents (string or {primary,fallbacks}). */
|
||||
model?: string | { primary?: string; fallbacks?: string[] };
|
||||
};
|
||||
sandbox?: {
|
||||
mode?: "off" | "non-main" | "all";
|
||||
/** Agent workspace access inside the sandbox. */
|
||||
workspaceAccess?: "none" | "ro" | "rw";
|
||||
/**
|
||||
* Session tools visibility for sandboxed sessions.
|
||||
* - "spawned": only allow session tools to target sessions spawned from this session (default)
|
||||
* - "all": allow session tools to target any session
|
||||
*/
|
||||
sessionToolsVisibility?: "spawned" | "all";
|
||||
/** Container/workspace scope for sandbox isolation. */
|
||||
scope?: "session" | "agent" | "shared";
|
||||
/** Legacy alias for scope ("session" when true, "shared" when false). */
|
||||
perSession?: boolean;
|
||||
workspaceRoot?: string;
|
||||
/** Docker-specific sandbox overrides for this agent. */
|
||||
docker?: SandboxDockerSettings;
|
||||
/** Optional sandboxed browser overrides for this agent. */
|
||||
browser?: SandboxBrowserSettings;
|
||||
/** Auto-prune overrides for this agent. */
|
||||
prune?: SandboxPruneSettings;
|
||||
model?: AgentModelConfig;
|
||||
};
|
||||
/** Optional per-agent sandbox overrides. */
|
||||
sandbox?: AgentSandboxConfig;
|
||||
tools?: AgentToolsConfig;
|
||||
};
|
||||
|
||||
|
||||
50
src/config/types.channel-messaging-common.ts
Normal file
50
src/config/types.channel-messaging-common.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import type {
|
||||
BlockStreamingCoalesceConfig,
|
||||
DmPolicy,
|
||||
GroupPolicy,
|
||||
MarkdownConfig,
|
||||
} from "./types.base.js";
|
||||
import type { ChannelHeartbeatVisibilityConfig } from "./types.channels.js";
|
||||
import type { DmConfig } from "./types.messages.js";
|
||||
|
||||
export type CommonChannelMessagingConfig = {
|
||||
/** Optional display name for this account (used in CLI/UI lists). */
|
||||
name?: string;
|
||||
/** Optional provider capability tags used for agent/runtime guidance. */
|
||||
capabilities?: string[];
|
||||
/** Markdown formatting overrides (tables). */
|
||||
markdown?: MarkdownConfig;
|
||||
/** Allow channel-initiated config writes (default: true). */
|
||||
configWrites?: boolean;
|
||||
/** If false, do not start this account. Default: true. */
|
||||
enabled?: boolean;
|
||||
/** Direct message access policy (default: pairing). */
|
||||
dmPolicy?: DmPolicy;
|
||||
/** Optional allowlist for inbound DM senders. */
|
||||
allowFrom?: Array<string | number>;
|
||||
/** Default delivery target for CLI --deliver when no explicit --reply-to is provided. */
|
||||
defaultTo?: string;
|
||||
/** Optional allowlist for group/channel senders. */
|
||||
groupAllowFrom?: Array<string | number>;
|
||||
/** Group/channel message handling policy. */
|
||||
groupPolicy?: GroupPolicy;
|
||||
/** Max group/channel messages to keep as history context (0 disables). */
|
||||
historyLimit?: number;
|
||||
/** Max DM turns to keep as history context. */
|
||||
dmHistoryLimit?: number;
|
||||
/** Per-DM config overrides keyed by sender ID. */
|
||||
dms?: Record<string, DmConfig>;
|
||||
/** Outbound text chunk size (chars). */
|
||||
textChunkLimit?: number;
|
||||
/** Chunking mode: "length" (default) splits by size; "newline" splits on every newline. */
|
||||
chunkMode?: "length" | "newline";
|
||||
blockStreaming?: boolean;
|
||||
/** Merge streamed block replies before sending. */
|
||||
blockStreamingCoalesce?: BlockStreamingCoalesceConfig;
|
||||
/** Heartbeat visibility settings for this channel. */
|
||||
heartbeat?: ChannelHeartbeatVisibilityConfig;
|
||||
/** Outbound response prefix override for this channel/account. */
|
||||
responsePrefix?: string;
|
||||
/** Max outbound media size in MB. */
|
||||
mediaMaxMb?: number;
|
||||
};
|
||||
@@ -1,24 +1,7 @@
|
||||
import type {
|
||||
BlockStreamingCoalesceConfig,
|
||||
DmPolicy,
|
||||
GroupPolicy,
|
||||
MarkdownConfig,
|
||||
} from "./types.base.js";
|
||||
import type { ChannelHeartbeatVisibilityConfig } from "./types.channels.js";
|
||||
import type { DmConfig } from "./types.messages.js";
|
||||
import type { CommonChannelMessagingConfig } from "./types.channel-messaging-common.js";
|
||||
import type { GroupToolPolicyBySenderConfig, GroupToolPolicyConfig } from "./types.tools.js";
|
||||
|
||||
export type IrcAccountConfig = {
|
||||
/** Optional display name for this account (used in CLI/UI lists). */
|
||||
name?: string;
|
||||
/** Optional provider capability tags used for agent/runtime guidance. */
|
||||
capabilities?: string[];
|
||||
/** Markdown formatting overrides (tables). */
|
||||
markdown?: MarkdownConfig;
|
||||
/** Allow channel-initiated config writes (default: true). */
|
||||
configWrites?: boolean;
|
||||
/** If false, do not start this IRC account. Default: true. */
|
||||
enabled?: boolean;
|
||||
export type IrcAccountConfig = CommonChannelMessagingConfig & {
|
||||
/** IRC server hostname (example: irc.libera.chat). */
|
||||
host?: string;
|
||||
/** IRC server port (default: 6697 with TLS, otherwise 6667). */
|
||||
@@ -52,34 +35,8 @@ export type IrcAccountConfig = {
|
||||
};
|
||||
/** Auto-join channel list at connect (example: ["#openclaw"]). */
|
||||
channels?: string[];
|
||||
/** Direct message access policy (default: pairing). */
|
||||
dmPolicy?: DmPolicy;
|
||||
/** Optional allowlist for inbound DM senders. */
|
||||
allowFrom?: Array<string | number>;
|
||||
/** Default delivery target for CLI --deliver when no explicit --reply-to is provided. */
|
||||
defaultTo?: string;
|
||||
/** Optional allowlist for IRC channel senders. */
|
||||
groupAllowFrom?: Array<string | number>;
|
||||
/**
|
||||
* Controls how channel messages are handled:
|
||||
* - "open": channels bypass allowFrom; mention-gating applies
|
||||
* - "disabled": block all channel messages entirely
|
||||
* - "allowlist": only allow channel messages from senders in groupAllowFrom/allowFrom
|
||||
*/
|
||||
groupPolicy?: GroupPolicy;
|
||||
/** Max channel messages to keep as history context (0 disables). */
|
||||
historyLimit?: number;
|
||||
/** Max DM turns to keep as history context. */
|
||||
dmHistoryLimit?: number;
|
||||
/** Per-DM config overrides keyed by sender ID. */
|
||||
dms?: Record<string, DmConfig>;
|
||||
/** Outbound text chunk size (chars). Default: 350. */
|
||||
textChunkLimit?: number;
|
||||
/** Chunking mode: "length" (default) splits by size; "newline" splits on every newline. */
|
||||
chunkMode?: "length" | "newline";
|
||||
blockStreaming?: boolean;
|
||||
/** Merge streamed block replies before sending. */
|
||||
blockStreamingCoalesce?: BlockStreamingCoalesceConfig;
|
||||
groups?: Record<
|
||||
string,
|
||||
{
|
||||
@@ -94,12 +51,6 @@ export type IrcAccountConfig = {
|
||||
>;
|
||||
/** Optional mention patterns specific to IRC channel messages. */
|
||||
mentionPatterns?: string[];
|
||||
/** Heartbeat visibility settings for this channel. */
|
||||
heartbeat?: ChannelHeartbeatVisibilityConfig;
|
||||
/** Outbound response prefix override for this channel/account. */
|
||||
responsePrefix?: string;
|
||||
/** Max outbound media size in MB. */
|
||||
mediaMaxMb?: number;
|
||||
};
|
||||
|
||||
export type IrcConfig = {
|
||||
|
||||
@@ -1,26 +1,9 @@
|
||||
import type {
|
||||
BlockStreamingCoalesceConfig,
|
||||
DmPolicy,
|
||||
GroupPolicy,
|
||||
MarkdownConfig,
|
||||
} from "./types.base.js";
|
||||
import type { ChannelHeartbeatVisibilityConfig } from "./types.channels.js";
|
||||
import type { DmConfig } from "./types.messages.js";
|
||||
import type { CommonChannelMessagingConfig } from "./types.channel-messaging-common.js";
|
||||
|
||||
export type SignalReactionNotificationMode = "off" | "own" | "all" | "allowlist";
|
||||
export type SignalReactionLevel = "off" | "ack" | "minimal" | "extensive";
|
||||
|
||||
export type SignalAccountConfig = {
|
||||
/** Optional display name for this account (used in CLI/UI lists). */
|
||||
name?: string;
|
||||
/** Optional provider capability tags used for agent/runtime guidance. */
|
||||
capabilities?: string[];
|
||||
/** Markdown formatting overrides (tables). */
|
||||
markdown?: MarkdownConfig;
|
||||
/** Allow channel-initiated config writes (default: true). */
|
||||
configWrites?: boolean;
|
||||
/** If false, do not start this Signal account. Default: true. */
|
||||
enabled?: boolean;
|
||||
export type SignalAccountConfig = CommonChannelMessagingConfig & {
|
||||
/** Optional explicit E.164 account for signal-cli. */
|
||||
account?: string;
|
||||
/** Optional full base URL for signal-cli HTTP daemon. */
|
||||
@@ -39,34 +22,8 @@ export type SignalAccountConfig = {
|
||||
ignoreAttachments?: boolean;
|
||||
ignoreStories?: boolean;
|
||||
sendReadReceipts?: boolean;
|
||||
/** Direct message access policy (default: pairing). */
|
||||
dmPolicy?: DmPolicy;
|
||||
allowFrom?: Array<string | number>;
|
||||
/** Default delivery target for CLI --deliver when no explicit --reply-to is provided. */
|
||||
defaultTo?: string;
|
||||
/** Optional allowlist for Signal group senders (E.164). */
|
||||
groupAllowFrom?: Array<string | number>;
|
||||
/**
|
||||
* Controls how group messages are handled:
|
||||
* - "open": groups bypass allowFrom, no extra gating
|
||||
* - "disabled": block all group messages
|
||||
* - "allowlist": only allow group messages from senders in groupAllowFrom/allowFrom
|
||||
*/
|
||||
groupPolicy?: GroupPolicy;
|
||||
/** Max group messages to keep as history context (0 disables). */
|
||||
historyLimit?: number;
|
||||
/** Max DM turns to keep as history context. */
|
||||
dmHistoryLimit?: number;
|
||||
/** Per-DM config overrides keyed by user ID. */
|
||||
dms?: Record<string, DmConfig>;
|
||||
/** Outbound text chunk size (chars). Default: 4000. */
|
||||
textChunkLimit?: number;
|
||||
/** Chunking mode: "length" (default) splits by size; "newline" splits on every newline. */
|
||||
chunkMode?: "length" | "newline";
|
||||
blockStreaming?: boolean;
|
||||
/** Merge streamed block replies before sending. */
|
||||
blockStreamingCoalesce?: BlockStreamingCoalesceConfig;
|
||||
mediaMaxMb?: number;
|
||||
/** Reaction notification mode (off|own|all|allowlist). Default: own. */
|
||||
reactionNotifications?: SignalReactionNotificationMode;
|
||||
/** Allowlist for reaction notifications when mode is allowlist. */
|
||||
@@ -84,10 +41,6 @@ export type SignalAccountConfig = {
|
||||
* - "extensive": Agent can react liberally
|
||||
*/
|
||||
reactionLevel?: SignalReactionLevel;
|
||||
/** Heartbeat visibility settings for this channel. */
|
||||
heartbeat?: ChannelHeartbeatVisibilityConfig;
|
||||
/** Outbound response prefix override for this channel/account. */
|
||||
responsePrefix?: string;
|
||||
};
|
||||
|
||||
export type SignalConfig = {
|
||||
|
||||
Reference in New Issue
Block a user