diff --git a/apps/macos/Sources/OpenClawProtocol/GatewayModels.swift b/apps/macos/Sources/OpenClawProtocol/GatewayModels.swift index ea85e6c15..b743060f6 100644 --- a/apps/macos/Sources/OpenClawProtocol/GatewayModels.swift +++ b/apps/macos/Sources/OpenClawProtocol/GatewayModels.swift @@ -538,8 +538,6 @@ public struct AgentParams: Codable, Sendable { public let inputprovenance: [String: AnyCodable]? public let idempotencykey: String public let label: String? - public let spawnedby: String? - public let workspacedir: String? public init( message: String, @@ -566,9 +564,7 @@ public struct AgentParams: Codable, Sendable { internalevents: [[String: AnyCodable]]?, inputprovenance: [String: AnyCodable]?, idempotencykey: String, - label: String?, - spawnedby: String?, - workspacedir: String?) + label: String?) { self.message = message self.agentid = agentid @@ -595,8 +591,6 @@ public struct AgentParams: Codable, Sendable { self.inputprovenance = inputprovenance self.idempotencykey = idempotencykey self.label = label - self.spawnedby = spawnedby - self.workspacedir = workspacedir } private enum CodingKeys: String, CodingKey { @@ -625,8 +619,6 @@ public struct AgentParams: Codable, Sendable { case inputprovenance = "inputProvenance" case idempotencykey = "idempotencyKey" case label - case spawnedby = "spawnedBy" - case workspacedir = "workspaceDir" } } @@ -1336,6 +1328,7 @@ public struct SessionsPatchParams: Codable, Sendable { public let execnode: AnyCodable? public let model: AnyCodable? public let spawnedby: AnyCodable? + public let spawnedworkspacedir: AnyCodable? public let spawndepth: AnyCodable? public let subagentrole: AnyCodable? public let subagentcontrolscope: AnyCodable? @@ -1356,6 +1349,7 @@ public struct SessionsPatchParams: Codable, Sendable { execnode: AnyCodable?, model: AnyCodable?, spawnedby: AnyCodable?, + spawnedworkspacedir: AnyCodable?, spawndepth: AnyCodable?, subagentrole: AnyCodable?, subagentcontrolscope: AnyCodable?, @@ -1375,6 +1369,7 @@ public struct SessionsPatchParams: Codable, Sendable { self.execnode = execnode self.model = model self.spawnedby = spawnedby + self.spawnedworkspacedir = spawnedworkspacedir self.spawndepth = spawndepth self.subagentrole = subagentrole self.subagentcontrolscope = subagentcontrolscope @@ -1396,6 +1391,7 @@ public struct SessionsPatchParams: Codable, Sendable { case execnode = "execNode" case model case spawnedby = "spawnedBy" + case spawnedworkspacedir = "spawnedWorkspaceDir" case spawndepth = "spawnDepth" case subagentrole = "subagentRole" case subagentcontrolscope = "subagentControlScope" diff --git a/apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift b/apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift index ea85e6c15..b743060f6 100644 --- a/apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift +++ b/apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift @@ -538,8 +538,6 @@ public struct AgentParams: Codable, Sendable { public let inputprovenance: [String: AnyCodable]? public let idempotencykey: String public let label: String? - public let spawnedby: String? - public let workspacedir: String? public init( message: String, @@ -566,9 +564,7 @@ public struct AgentParams: Codable, Sendable { internalevents: [[String: AnyCodable]]?, inputprovenance: [String: AnyCodable]?, idempotencykey: String, - label: String?, - spawnedby: String?, - workspacedir: String?) + label: String?) { self.message = message self.agentid = agentid @@ -595,8 +591,6 @@ public struct AgentParams: Codable, Sendable { self.inputprovenance = inputprovenance self.idempotencykey = idempotencykey self.label = label - self.spawnedby = spawnedby - self.workspacedir = workspacedir } private enum CodingKeys: String, CodingKey { @@ -625,8 +619,6 @@ public struct AgentParams: Codable, Sendable { case inputprovenance = "inputProvenance" case idempotencykey = "idempotencyKey" case label - case spawnedby = "spawnedBy" - case workspacedir = "workspaceDir" } } @@ -1336,6 +1328,7 @@ public struct SessionsPatchParams: Codable, Sendable { public let execnode: AnyCodable? public let model: AnyCodable? public let spawnedby: AnyCodable? + public let spawnedworkspacedir: AnyCodable? public let spawndepth: AnyCodable? public let subagentrole: AnyCodable? public let subagentcontrolscope: AnyCodable? @@ -1356,6 +1349,7 @@ public struct SessionsPatchParams: Codable, Sendable { execnode: AnyCodable?, model: AnyCodable?, spawnedby: AnyCodable?, + spawnedworkspacedir: AnyCodable?, spawndepth: AnyCodable?, subagentrole: AnyCodable?, subagentcontrolscope: AnyCodable?, @@ -1375,6 +1369,7 @@ public struct SessionsPatchParams: Codable, Sendable { self.execnode = execnode self.model = model self.spawnedby = spawnedby + self.spawnedworkspacedir = spawnedworkspacedir self.spawndepth = spawndepth self.subagentrole = subagentrole self.subagentcontrolscope = subagentcontrolscope @@ -1396,6 +1391,7 @@ public struct SessionsPatchParams: Codable, Sendable { case execnode = "execNode" case model case spawnedby = "spawnedBy" + case spawnedworkspacedir = "spawnedWorkspaceDir" case spawndepth = "spawnDepth" case subagentrole = "subagentRole" case subagentcontrolscope = "subagentControlScope" diff --git a/src/channels/plugins/onboarding/helpers.ts b/src/channels/plugins/onboarding/helpers.ts index 6eab25fd2..77d03a412 100644 --- a/src/channels/plugins/onboarding/helpers.ts +++ b/src/channels/plugins/onboarding/helpers.ts @@ -164,11 +164,11 @@ export function setAccountAllowFromForChannel(params: { }); } -export function setTopLevelChannelAllowFrom(params: { +function patchTopLevelChannelConfig(params: { cfg: OpenClawConfig; channel: string; - allowFrom: string[]; enabled?: boolean; + patch: Record; }): OpenClawConfig { const channelConfig = (params.cfg.channels?.[params.channel] as Record | undefined) ?? {}; @@ -179,12 +179,26 @@ export function setTopLevelChannelAllowFrom(params: { [params.channel]: { ...channelConfig, ...(params.enabled ? { enabled: true } : {}), - allowFrom: params.allowFrom, + ...params.patch, }, }, }; } +export function setTopLevelChannelAllowFrom(params: { + cfg: OpenClawConfig; + channel: string; + allowFrom: string[]; + enabled?: boolean; +}): OpenClawConfig { + return patchTopLevelChannelConfig({ + cfg: params.cfg, + channel: params.channel, + enabled: params.enabled, + patch: { allowFrom: params.allowFrom }, + }); +} + export function setTopLevelChannelDmPolicyWithAllowFrom(params: { cfg: OpenClawConfig; channel: string; @@ -199,17 +213,14 @@ export function setTopLevelChannelDmPolicyWithAllowFrom(params: { undefined; const allowFrom = params.dmPolicy === "open" ? addWildcardAllowFrom(existingAllowFrom) : undefined; - return { - ...params.cfg, - channels: { - ...params.cfg.channels, - [params.channel]: { - ...channelConfig, - dmPolicy: params.dmPolicy, - ...(allowFrom ? { allowFrom } : {}), - }, + return patchTopLevelChannelConfig({ + cfg: params.cfg, + channel: params.channel, + patch: { + dmPolicy: params.dmPolicy, + ...(allowFrom ? { allowFrom } : {}), }, - }; + }); } export function setTopLevelChannelGroupPolicy(params: { @@ -218,19 +229,12 @@ export function setTopLevelChannelGroupPolicy(params: { groupPolicy: GroupPolicy; enabled?: boolean; }): OpenClawConfig { - const channelConfig = - (params.cfg.channels?.[params.channel] as Record | undefined) ?? {}; - return { - ...params.cfg, - channels: { - ...params.cfg.channels, - [params.channel]: { - ...channelConfig, - ...(params.enabled ? { enabled: true } : {}), - groupPolicy: params.groupPolicy, - }, - }, - }; + return patchTopLevelChannelConfig({ + cfg: params.cfg, + channel: params.channel, + enabled: params.enabled, + patch: { groupPolicy: params.groupPolicy }, + }); } export function setChannelDmPolicyWithAllowFrom(params: { diff --git a/src/gateway/protocol/schema/agent.ts b/src/gateway/protocol/schema/agent.ts index eaa54860a..11369a4ed 100644 --- a/src/gateway/protocol/schema/agent.ts +++ b/src/gateway/protocol/schema/agent.ts @@ -1,6 +1,5 @@ import { Type } from "@sinclair/typebox"; -import { INPUT_PROVENANCE_KIND_VALUES } from "../../../sessions/input-provenance.js"; -import { NonEmptyString, SessionLabelString } from "./primitives.js"; +import { InputProvenanceSchema, NonEmptyString, SessionLabelString } from "./primitives.js"; export const AgentInternalEventSchema = Type.Object( { @@ -96,18 +95,7 @@ export const AgentParamsSchema = Type.Object( lane: Type.Optional(Type.String()), extraSystemPrompt: Type.Optional(Type.String()), internalEvents: Type.Optional(Type.Array(AgentInternalEventSchema)), - inputProvenance: Type.Optional( - Type.Object( - { - kind: Type.String({ enum: [...INPUT_PROVENANCE_KIND_VALUES] }), - originSessionId: Type.Optional(Type.String()), - sourceSessionKey: Type.Optional(Type.String()), - sourceChannel: Type.Optional(Type.String()), - sourceTool: Type.Optional(Type.String()), - }, - { additionalProperties: false }, - ), - ), + inputProvenance: Type.Optional(InputProvenanceSchema), idempotencyKey: NonEmptyString, label: Type.Optional(SessionLabelString), }, diff --git a/src/gateway/protocol/schema/logs-chat.ts b/src/gateway/protocol/schema/logs-chat.ts index 5545bd443..5c4003acb 100644 --- a/src/gateway/protocol/schema/logs-chat.ts +++ b/src/gateway/protocol/schema/logs-chat.ts @@ -1,6 +1,5 @@ import { Type } from "@sinclair/typebox"; -import { INPUT_PROVENANCE_KIND_VALUES } from "../../../sessions/input-provenance.js"; -import { ChatSendSessionKeyString, NonEmptyString } from "./primitives.js"; +import { ChatSendSessionKeyString, InputProvenanceSchema, NonEmptyString } from "./primitives.js"; export const LogsTailParamsSchema = Type.Object( { @@ -40,18 +39,7 @@ export const ChatSendParamsSchema = Type.Object( deliver: Type.Optional(Type.Boolean()), attachments: Type.Optional(Type.Array(Type.Unknown())), timeoutMs: Type.Optional(Type.Integer({ minimum: 0 })), - systemInputProvenance: Type.Optional( - Type.Object( - { - kind: Type.String({ enum: [...INPUT_PROVENANCE_KIND_VALUES] }), - originSessionId: Type.Optional(Type.String()), - sourceSessionKey: Type.Optional(Type.String()), - sourceChannel: Type.Optional(Type.String()), - sourceTool: Type.Optional(Type.String()), - }, - { additionalProperties: false }, - ), - ), + systemInputProvenance: Type.Optional(InputProvenanceSchema), systemProvenanceReceipt: Type.Optional(Type.String()), idempotencyKey: NonEmptyString, }, diff --git a/src/gateway/protocol/schema/primitives.ts b/src/gateway/protocol/schema/primitives.ts index 6ac6a71b6..2983c834f 100644 --- a/src/gateway/protocol/schema/primitives.ts +++ b/src/gateway/protocol/schema/primitives.ts @@ -5,6 +5,7 @@ import { FILE_SECRET_REF_ID_PATTERN, SECRET_PROVIDER_ALIAS_PATTERN, } from "../../../secrets/ref-contract.js"; +import { INPUT_PROVENANCE_KIND_VALUES } from "../../../sessions/input-provenance.js"; import { SESSION_LABEL_MAX_LENGTH } from "../../../sessions/session-label.js"; import { GATEWAY_CLIENT_IDS, GATEWAY_CLIENT_MODES } from "../client-info.js"; @@ -18,6 +19,16 @@ export const SessionLabelString = Type.String({ minLength: 1, maxLength: SESSION_LABEL_MAX_LENGTH, }); +export const InputProvenanceSchema = Type.Object( + { + kind: Type.String({ enum: [...INPUT_PROVENANCE_KIND_VALUES] }), + originSessionId: Type.Optional(Type.String()), + sourceSessionKey: Type.Optional(Type.String()), + sourceChannel: Type.Optional(Type.String()), + sourceTool: Type.Optional(Type.String()), + }, + { additionalProperties: false }, +); export const GatewayClientIdSchema = Type.Union( Object.values(GATEWAY_CLIENT_IDS).map((value) => Type.Literal(value)), diff --git a/src/utils.test.ts b/src/utils.test.ts index ec9a0f4a1..0f4823c40 100644 --- a/src/utils.test.ts +++ b/src/utils.test.ts @@ -8,7 +8,6 @@ import { ensureDir, jidToE164, normalizeE164, - normalizePath, resolveConfigDir, resolveHomeDir, resolveJidToE164, @@ -17,7 +16,6 @@ import { shortenHomePath, sleep, toWhatsappJid, - withWhatsAppPrefix, } from "./utils.js"; function withTempDirSync(prefix: string, run: (dir: string) => T): T { @@ -29,26 +27,6 @@ function withTempDirSync(prefix: string, run: (dir: string) => T): T { } } -describe("normalizePath", () => { - it("adds leading slash when missing", () => { - expect(normalizePath("foo")).toBe("/foo"); - }); - - it("keeps existing slash", () => { - expect(normalizePath("/bar")).toBe("/bar"); - }); -}); - -describe("withWhatsAppPrefix", () => { - it("adds whatsapp prefix", () => { - expect(withWhatsAppPrefix("+1555")).toBe("whatsapp:+1555"); - }); - - it("leaves prefixed intact", () => { - expect(withWhatsAppPrefix("whatsapp:+1555")).toBe("whatsapp:+1555"); - }); -}); - describe("ensureDir", () => { it("creates nested directory", async () => { await withTempDirSync("openclaw-test-", async (tmp) => { diff --git a/src/utils.ts b/src/utils.ts index 55efabb1b..cb044d05b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -73,17 +73,6 @@ export function assertWebChannel(input: string): asserts input is WebChannel { } } -export function normalizePath(p: string): string { - if (!p.startsWith("/")) { - return `/${p}`; - } - return p; -} - -export function withWhatsAppPrefix(number: string): string { - return number.startsWith("whatsapp:") ? number : `whatsapp:${number}`; -} - export function normalizeE164(number: string): string { const withoutPrefix = number.replace(/^whatsapp:/, "").trim(); const digits = withoutPrefix.replace(/[^\d+]/g, "");