refactor: extract gateway client package (#87797)

* refactor: extract gateway client package

* chore: drop generated gateway package artifacts

* refactor: move gateway protocol package

* refactor: remove old gateway protocol tree

* test: keep auth compat split in run mode

* test: expose gateway wrapper options for internals

* fix: watch moved gateway package sources

* test: normalize slash command import guard

* chore: teach knip gateway package entries

* ci: route gateway client package checks

* fix: reuse ipaddr for gateway client hosts

* fix: sync gateway protocol usage schema
This commit is contained in:
Peter Steinberger
2026-05-29 02:23:42 +01:00
committed by GitHub
parent fd8353012f
commit b1117d9862
258 changed files with 3166 additions and 1847 deletions

2
.github/CODEOWNERS vendored
View File

@@ -31,7 +31,7 @@
/src/gateway/**/*secret*.ts @openclaw/openclaw-secops
/src/gateway/security-path*.ts @openclaw/openclaw-secops
/src/gateway/resolve-configured-secret-input-string*.ts @openclaw/openclaw-secops
/src/gateway/protocol/**/*secret*.ts @openclaw/openclaw-secops
/packages/gateway-protocol/src/**/*secret*.ts @openclaw/openclaw-secops
/src/gateway/server-methods/secrets*.ts @openclaw/openclaw-secops
/src/agents/*auth*.ts @openclaw/openclaw-secops
/src/agents/**/*auth*.ts @openclaw/openclaw-secops

View File

@@ -19,7 +19,7 @@ paths:
- src/config/types.channel*.ts
- src/gateway/server-channel*.ts
- src/gateway/server-methods/channels.ts
- src/gateway/protocol/schema/channels.ts
- packages/gateway-protocol/src/schema/channels.ts
- src/infra/channel-*.ts
- src/infra/exec-approval-channel-runtime.ts
- src/infra/outbound/channel-*.ts

View File

@@ -30,7 +30,7 @@ paths:
- src/gateway/**/*auth*.ts
- src/gateway/*secret*.ts
- src/gateway/**/*secret*.ts
- src/gateway/protocol/**/*secret*.ts
- packages/gateway-protocol/src/**/*secret*.ts
- src/gateway/resolve-configured-secret-input-string*.ts
- src/gateway/security-path*.ts
- src/gateway/server-methods/secrets*.ts

View File

@@ -30,7 +30,7 @@ paths:
- src/gateway/**/*auth*.ts
- src/gateway/*secret*.ts
- src/gateway/**/*secret*.ts
- src/gateway/protocol/**/*secret*.ts
- packages/gateway-protocol/src/**/*secret*.ts
- src/gateway/resolve-configured-secret-input-string*.ts
- src/gateway/security-path*.ts
- src/gateway/server-methods/secrets*.ts

View File

@@ -15,7 +15,7 @@ query-filters:
paths:
- src/gateway/method-scopes.ts
- src/gateway/protocol
- packages/gateway-protocol/src
- src/gateway/server-methods
- src/gateway/server-methods.ts
- src/gateway/server-methods-list.ts

3
.github/labeler.yml vendored
View File

@@ -188,7 +188,7 @@
- "ui/**"
- "src/gateway/control-ui.ts"
- "src/gateway/control-ui-shared.ts"
- "src/gateway/protocol/**"
- "packages/gateway-protocol/src/**"
- "src/gateway/server-methods/chat.ts"
- "src/infra/control-ui-assets.ts"
@@ -196,6 +196,7 @@
- changed-files:
- any-glob-to-any-file:
- "src/gateway/**"
- "packages/gateway-protocol/src/**"
- "src/daemon/**"
- "docs/gateway/**"

View File

@@ -106,13 +106,13 @@ on:
- "src/gateway/**/*auth*.ts"
- "src/gateway/*secret*.ts"
- "src/gateway/**/*secret*.ts"
- "src/gateway/protocol/**/*secret*.ts"
- "packages/gateway-protocol/src/**/*secret*.ts"
- "src/gateway/resolve-configured-secret-input-string*.ts"
- "src/gateway/security-path*.ts"
- "src/gateway/server-methods/secrets*.ts"
- "src/gateway/server-startup-memory.ts"
- "src/gateway/method-scopes.ts"
- "src/gateway/protocol/**"
- "packages/gateway-protocol/src/**"
- "src/gateway/server-methods/**"
- "src/gateway/server-methods.ts"
- "src/gateway/server-methods-list.ts"
@@ -244,14 +244,14 @@ jobs:
src/config/*)
config=true
;;
src/gateway/protocol/*secret*.ts|src/gateway/server-methods/secrets*.ts)
packages/gateway-protocol/src/*secret*.ts|packages/gateway-protocol/src/**/*secret*.ts|src/gateway/server-methods/secrets*.ts)
core_auth_secrets=true
gateway=true
;;
src/agents/*auth*.ts|src/agents/auth-health*.ts|src/agents/auth-profiles|src/agents/auth-profiles/*|src/agents/bash-tools.exec-host-shared.ts|src/agents/sandbox|src/agents/sandbox.ts|src/agents/sandbox-*.ts|src/agents/sandbox/*|src/cron/service/jobs.ts|src/cron/stagger.ts|src/gateway/*auth*.ts|src/gateway/*secret*.ts|src/gateway/resolve-configured-secret-input-string*.ts|src/gateway/security-path*.ts|src/infra/secret-file*.ts|src/secrets/*|src/security/*)
core_auth_secrets=true
;;
src/gateway/method-scopes.ts|src/gateway/protocol/*|src/gateway/server-methods/*|src/gateway/server-methods.ts|src/gateway/server-methods-list.ts)
packages/gateway-protocol/src/*|packages/gateway-protocol/src/**/*|src/gateway/method-scopes.ts|src/gateway/server-methods/*|src/gateway/server-methods.ts|src/gateway/server-methods-list.ts)
gateway=true
;;
packages/memory-host-sdk/*|src/commands/doctor-cron-dreaming-payload-migration.ts|src/commands/doctor-memory-search.ts|src/gateway/server-startup-memory.ts|src/memory/*|src/memory-host-sdk/*)

View File

@@ -35,9 +35,9 @@ Skills own workflows; root owns hard policy and routing.
## Map
- Core TS: `src/`, `ui/`, `packages/`; plugins: `extensions/`; SDK: `src/plugin-sdk/*`; channels: `src/channels/*`; loader: `src/plugins/*`; protocol: `src/gateway/protocol/*`; docs/apps: `docs/`, `apps/`.
- Core TS: `src/`, `ui/`, `packages/`; plugins: `extensions/`; SDK: `src/plugin-sdk/*`; channels: `src/channels/*`; loader: `src/plugins/*`; protocol: `packages/gateway-protocol/*`; docs/apps: `docs/`, `apps/`.
- Installers: sibling `../openclaw.ai`.
- Scoped guides: `extensions/`, `src/{plugin-sdk,channels,plugins,gateway,gateway/protocol,agents}/`, `test/helpers*/`, `docs/`, `ui/`, `scripts/`.
- Scoped guides: `extensions/`, `src/{plugin-sdk,channels,plugins,gateway,agents}/`, `packages/`, `test/helpers*/`, `docs/`, `ui/`, `scripts/`.
## Docs

View File

@@ -168,6 +168,14 @@ const config = {
entry: ["src/index.ts!", "src/*.ts!", "src/harness/**/*.ts!"],
project: ["src/**/*.ts!"],
},
"packages/gateway-client": {
entry: ["src/index.ts!"],
project: ["src/**/*.ts!"],
},
"packages/gateway-protocol": {
entry: ["src/index.ts!", "src/schema.ts!"],
project: ["src/**/*.ts!"],
},
"packages/*": {
entry: ["index.js!", "scripts/postinstall.js!"],
project: ["index.js!", "scripts/**/*.js!"],

View File

@@ -53,8 +53,8 @@ Authoritative advertised **discovery** inventory lives in
## Where the schemas live
- Source: `src/gateway/protocol/schema.ts`
- Runtime validators (AJV): `src/gateway/protocol/index.ts`
- Source: `packages/gateway-protocol/src/schema.ts`
- Runtime validators (AJV): `packages/gateway-protocol/src/index.ts`
- Advertised feature/discovery registry: `src/gateway/server-methods-list.ts`
- Server handshake + method dispatch: `src/gateway/server.impl.ts`
- Node client: `src/gateway/client.ts`
@@ -195,7 +195,7 @@ Example: add a new `system.echo` request that returns `{ ok: true, text }`.
1. **Schema (source of truth)**
Add to `src/gateway/protocol/schema.ts`:
Add to `packages/gateway-protocol/src/schema.ts`:
```ts
export const SystemEchoParamsSchema = Type.Object(
@@ -223,7 +223,7 @@ export type SystemEchoResult = Static<typeof SystemEchoResultSchema>;
2. **Validation**
In `src/gateway/protocol/index.ts`, export an AJV validator:
In `packages/gateway-protocol/src/index.ts`, export an AJV validator:
```ts
export const validateSystemEchoParams = ajv.compile<SystemEchoParams>(SystemEchoParamsSchema);
@@ -272,7 +272,7 @@ Unknown frame types are preserved as raw payloads for forward compatibility.
## Versioning + compatibility
- `PROTOCOL_VERSION` lives in `src/gateway/protocol/version.ts`.
- `PROTOCOL_VERSION` lives in `packages/gateway-protocol/src/version.ts`.
- Clients send `minProtocol` + `maxProtocol`; the server rejects ranges that
do not include its current protocol.
- The Swift models keep unknown frame types to avoid breaking older clients.

View File

@@ -104,7 +104,7 @@ within their overall connection budget instead of surfacing it as a terminal
handshake failure.
`server`, `features`, `snapshot`, and `policy` are all required by the schema
(`src/gateway/protocol/schema/frames.ts`). `auth` is also required and reports
(`packages/gateway-protocol/src/schema/frames.ts`). `auth` is also required and reports
the negotiated role/scopes. `pluginSurfaceUrls` is optional and maps plugin
surface names, such as `canvas`, to scoped hosted URLs.
@@ -648,7 +648,7 @@ terminal summary, and sanitized error text.
## Versioning
- `PROTOCOL_VERSION` lives in `src/gateway/protocol/version.ts`.
- `PROTOCOL_VERSION` lives in `packages/gateway-protocol/src/version.ts`.
- Clients send `minProtocol` + `maxProtocol`; the server rejects ranges that
do not include its current protocol. Current clients and servers require
protocol v4.
@@ -664,8 +664,8 @@ stable across protocol v4 and are the expected baseline for third-party clients.
| Constant | Default | Source |
| ----------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `PROTOCOL_VERSION` | `4` | `src/gateway/protocol/version.ts` |
| `MIN_CLIENT_PROTOCOL_VERSION` | `4` | `src/gateway/protocol/version.ts` |
| `PROTOCOL_VERSION` | `4` | `packages/gateway-protocol/src/version.ts` |
| `MIN_CLIENT_PROTOCOL_VERSION` | `4` | `packages/gateway-protocol/src/version.ts` |
| Request timeout (per RPC) | `30_000` ms | `src/gateway/client.ts` (`requestTimeoutMs`) |
| Preauth / connect-challenge timeout | `15_000` ms | `src/gateway/handshake-timeouts.ts` (config/env can raise the paired server/client budget) |
| Initial reconnect backoff | `1_000` ms | `src/gateway/client.ts` (`backoffMs`) |
@@ -818,7 +818,7 @@ Migration target:
This protocol exposes the **full gateway API** (status, channels, models, chat,
agent, sessions, nodes, approvals, etc.). The exact surface is defined by the
TypeBox schemas in `src/gateway/protocol/schema.ts`.
TypeBox schemas in `packages/gateway-protocol/src/schema.ts`.
## Related

View File

@@ -1623,7 +1623,7 @@
"start": "node openclaw.mjs",
"test": "node scripts/test-projects.mjs",
"test:all": "pnpm lint && pnpm build && pnpm test && pnpm test:e2e && pnpm test:live && pnpm test:docker:all",
"test:auth:compat": "node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/server.auth.compat-baseline.test.ts src/gateway/client.test.ts src/gateway/reconnect-gating.test.ts src/gateway/protocol/connect-error-details.test.ts",
"test:auth:compat": "node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/server.auth.compat-baseline.test.ts src/gateway/client.test.ts src/gateway/reconnect-gating.test.ts && node scripts/run-vitest.mjs run packages/gateway-protocol/src/connect-error-details.test.ts",
"test:build:singleton": "node scripts/test-built-plugin-singleton.mjs",
"test:build:status-message-runtime": "node scripts/test-built-status-message-runtime.mjs",
"test:bundled": "node scripts/run-vitest.mjs run --config test/vitest/vitest.bundled.config.ts",

View File

@@ -0,0 +1,36 @@
{
"name": "@openclaw/gateway-client",
"version": "0.0.0-private",
"private": true,
"files": [
"dist"
],
"type": "module",
"main": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"exports": {
".": {
"types": "./dist/index.d.mts",
"import": "./dist/index.mjs",
"default": "./dist/index.mjs"
},
"./readiness": {
"types": "./dist/readiness.d.mts",
"import": "./dist/readiness.mjs",
"default": "./dist/readiness.mjs"
},
"./timeouts": {
"types": "./dist/timeouts.d.mts",
"import": "./dist/timeouts.mjs",
"default": "./dist/timeouts.mjs"
}
},
"scripts": {
"build": "tsdown src/index.ts src/readiness.ts src/timeouts.ts --no-config --platform node --format esm --dts --out-dir dist --clean"
},
"dependencies": {
"@openclaw/gateway-protocol": "workspace:*",
"ipaddr.js": "2.4.0",
"ws": "8.21.0"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
export function normalizeDeviceMetadataForAuth(value?: string | null): string {
if (typeof value !== "string") {
return "";
}
const trimmed = value.trim();
if (!trimmed) {
return "";
}
return trimmed.replace(/[A-Z]/g, (char) => String.fromCharCode(char.charCodeAt(0) + 32));
}
type DeviceAuthPayloadParams = {
deviceId: string;
clientId: string;
clientMode: string;
role: string;
scopes: string[];
signedAtMs: number;
token?: string | null;
nonce: string;
};
type DeviceAuthPayloadV3Params = DeviceAuthPayloadParams & {
platform?: string | null;
deviceFamily?: string | null;
};
export function buildDeviceAuthPayload(params: DeviceAuthPayloadParams): string {
const scopes = params.scopes.join(",");
const token = params.token ?? "";
return [
"v2",
params.deviceId,
params.clientId,
params.clientMode,
params.role,
scopes,
String(params.signedAtMs),
token,
params.nonce,
].join("|");
}
export function buildDeviceAuthPayloadV3(params: DeviceAuthPayloadV3Params): string {
const scopes = params.scopes.join(",");
const token = params.token ?? "";
// Device signatures are byte-for-byte compared by the gateway. Normalize
// optional metadata before joining so case differences do not break auth.
const platform = normalizeDeviceMetadataForAuth(params.platform);
const deviceFamily = normalizeDeviceMetadataForAuth(params.deviceFamily);
return [
"v3",
params.deviceId,
params.clientId,
params.clientMode,
params.role,
scopes,
String(params.signedAtMs),
token,
params.nonce,
platform,
deviceFamily,
].join("|");
}

View File

@@ -0,0 +1,116 @@
function resolveSafeTimeoutDelayMs(value: number): number {
return Math.max(0, Math.min(value, 2_147_483_647));
}
export type EventLoopReadyResult = {
ready: boolean;
elapsedMs: number;
maxDriftMs: number;
checks: number;
aborted: boolean;
};
type EventLoopReadyOptions = {
maxWaitMs?: number;
intervalMs?: number;
driftThresholdMs?: number;
consecutiveReadyChecks?: number;
signal?: AbortSignal;
};
const DEFAULT_MAX_WAIT_MS = 10_000;
const DEFAULT_INTERVAL_MS = 1;
const DEFAULT_DRIFT_THRESHOLD_MS = 200;
const DEFAULT_CONSECUTIVE_READY_CHECKS = 2;
function resolvePositiveInteger(value: number | undefined, fallback: number): number {
return Number.isFinite(value) && value !== undefined ? Math.max(1, Math.floor(value)) : fallback;
}
export async function waitForEventLoopReady(
options: EventLoopReadyOptions = {},
): Promise<EventLoopReadyResult> {
const maxWaitMs = resolveSafeTimeoutDelayMs(options.maxWaitMs ?? DEFAULT_MAX_WAIT_MS);
const intervalMs = resolvePositiveInteger(options.intervalMs, DEFAULT_INTERVAL_MS);
const driftThresholdMs = resolvePositiveInteger(
options.driftThresholdMs,
DEFAULT_DRIFT_THRESHOLD_MS,
);
const consecutiveReadyChecks = resolvePositiveInteger(
options.consecutiveReadyChecks,
DEFAULT_CONSECUTIVE_READY_CHECKS,
);
const signal = options.signal;
const startedAt = Date.now();
let readyChecks = 0;
let checks = 0;
let maxDriftMs = 0;
return await new Promise<EventLoopReadyResult>((resolve) => {
let settled = false;
let timer: ReturnType<typeof setTimeout> | null = null;
const clearTimer = () => {
if (timer) {
clearTimeout(timer);
timer = null;
}
};
const finish = (ready: boolean, aborted = false) => {
if (settled) {
return;
}
settled = true;
clearTimer();
signal?.removeEventListener("abort", onAbort);
resolve({
ready,
elapsedMs: Math.max(0, Date.now() - startedAt),
maxDriftMs,
checks,
aborted,
});
};
const onAbort = () => {
finish(false, true);
};
if (signal?.aborted) {
finish(false, true);
return;
}
signal?.addEventListener("abort", onAbort, { once: true });
const scheduleNext = () => {
if (signal?.aborted) {
finish(false, true);
return;
}
const elapsedMs = Math.max(0, Date.now() - startedAt);
const remainingMs = maxWaitMs - elapsedMs;
if (remainingMs <= 0) {
finish(false);
return;
}
const delayMs = Math.min(intervalMs, remainingMs);
const scheduledAt = Date.now();
timer = setTimeout(() => {
timer = null;
checks += 1;
const driftMs = Math.max(0, Date.now() - scheduledAt - delayMs);
maxDriftMs = Math.max(maxDriftMs, driftMs);
if (driftMs > driftThresholdMs) {
readyChecks = 0;
} else {
readyChecks += 1;
}
if (readyChecks >= consecutiveReadyChecks) {
finish(true);
return;
}
scheduleNext();
}, delayMs);
};
scheduleNext();
});
}

View File

@@ -0,0 +1,5 @@
export * from "./client.js";
export * from "./device-auth.js";
export * from "./event-loop-ready.js";
export * from "./readiness.js";
export * from "./timeouts.js";

View File

@@ -0,0 +1,46 @@
import type { GatewayClient, GatewayClientOptions } from "./client.js";
import { waitForEventLoopReady, type EventLoopReadyResult } from "./event-loop-ready.js";
import { resolveConnectChallengeTimeoutMs } from "./timeouts.js";
export type GatewayClientStartReadinessOptions = {
timeoutMs?: number;
clientOptions?: Pick<
GatewayClientOptions,
"connectChallengeTimeoutMs" | "connectDelayMs" | "preauthHandshakeTimeoutMs"
>;
signal?: AbortSignal;
};
function resolveGatewayClientStartReadinessTimeoutMs(
options: GatewayClientStartReadinessOptions = {},
): number {
if (typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs)) {
return options.timeoutMs;
}
const clientOptions = options.clientOptions ?? {};
const timeoutOverride =
typeof clientOptions.connectChallengeTimeoutMs === "number" &&
Number.isFinite(clientOptions.connectChallengeTimeoutMs)
? clientOptions.connectChallengeTimeoutMs
: typeof clientOptions.connectDelayMs === "number" &&
Number.isFinite(clientOptions.connectDelayMs)
? clientOptions.connectDelayMs
: undefined;
return resolveConnectChallengeTimeoutMs(timeoutOverride, {
configuredTimeoutMs: clientOptions.preauthHandshakeTimeoutMs,
});
}
export async function startGatewayClientWhenEventLoopReady(
client: GatewayClient,
options: GatewayClientStartReadinessOptions = {},
): Promise<EventLoopReadyResult> {
const readiness = await waitForEventLoopReady({
maxWaitMs: resolveGatewayClientStartReadinessTimeoutMs(options),
signal: options.signal,
});
if (readiness.ready && !readiness.aborted && options.signal?.aborted !== true) {
client.start();
}
return readiness;
}

View File

@@ -0,0 +1,96 @@
function parseStrictPositiveInteger(value: string): number | undefined {
if (!/^[1-9]\d*$/u.test(value)) {
return undefined;
}
const parsed = Number(value);
return Number.isSafeInteger(parsed) ? parsed : undefined;
}
export const DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS = 15_000;
export const MIN_CONNECT_CHALLENGE_TIMEOUT_MS = 250;
export const MAX_CONNECT_CHALLENGE_TIMEOUT_MS = DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS;
export function clampConnectChallengeTimeoutMs(
timeoutMs: number,
maxTimeoutMs = MAX_CONNECT_CHALLENGE_TIMEOUT_MS,
): number {
return Math.max(
MIN_CONNECT_CHALLENGE_TIMEOUT_MS,
Math.min(Math.max(MIN_CONNECT_CHALLENGE_TIMEOUT_MS, maxTimeoutMs), timeoutMs),
);
}
export function getConnectChallengeTimeoutMsFromEnv(
env: NodeJS.ProcessEnv = process.env,
): number | undefined {
const raw = env.OPENCLAW_CONNECT_CHALLENGE_TIMEOUT_MS;
if (raw) {
const parsed = parseStrictPositiveInteger(raw);
if (parsed !== undefined) {
return parsed;
}
}
return undefined;
}
function normalizePositiveTimeoutMs(timeoutMs: unknown): number | undefined {
return typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0
? timeoutMs
: undefined;
}
export function resolveConnectChallengeTimeoutMs(
timeoutMs?: number | null,
params?: {
env?: NodeJS.ProcessEnv;
configuredTimeoutMs?: number | null;
},
): number {
const configuredPreauthTimeoutMs = resolvePreauthHandshakeTimeoutMs({
env: params?.env,
configuredTimeoutMs: params?.configuredTimeoutMs,
});
// The client watchdog must never fire before the server-side preauth timeout.
// Tests may raise the env override above that server default, so widen the cap.
const maxTimeoutMs = Math.max(DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, configuredPreauthTimeoutMs);
if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs)) {
return clampConnectChallengeTimeoutMs(timeoutMs, maxTimeoutMs);
}
const envOverride = getConnectChallengeTimeoutMsFromEnv(params?.env);
if (envOverride !== undefined) {
return clampConnectChallengeTimeoutMs(envOverride, Math.max(maxTimeoutMs, envOverride));
}
return clampConnectChallengeTimeoutMs(configuredPreauthTimeoutMs, maxTimeoutMs);
}
export function getPreauthHandshakeTimeoutMsFromEnv(env: NodeJS.ProcessEnv = process.env): number {
const configuredTimeout =
env.OPENCLAW_HANDSHAKE_TIMEOUT_MS || (env.VITEST && env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS);
if (configuredTimeout) {
const parsed = parseStrictPositiveInteger(configuredTimeout);
if (parsed !== undefined) {
return parsed;
}
}
return DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS;
}
export function resolvePreauthHandshakeTimeoutMs(params?: {
env?: NodeJS.ProcessEnv;
configuredTimeoutMs?: number | null;
}): number {
const env = params?.env ?? process.env;
const configuredTimeout =
env.OPENCLAW_HANDSHAKE_TIMEOUT_MS || (env.VITEST && env.OPENCLAW_TEST_HANDSHAKE_TIMEOUT_MS);
if (configuredTimeout) {
const parsed = parseStrictPositiveInteger(configuredTimeout);
if (parsed !== undefined) {
return parsed;
}
}
const configured = normalizePositiveTimeoutMs(params?.configuredTimeoutMs);
if (configured !== undefined) {
return configured;
}
return DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS;
}

View File

@@ -0,0 +1,49 @@
{
"name": "@openclaw/gateway-protocol",
"version": "0.0.0-private",
"private": true,
"files": [
"dist"
],
"type": "module",
"main": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"exports": {
".": {
"types": "./dist/index.d.mts",
"import": "./dist/index.mjs",
"default": "./dist/index.mjs"
},
"./client-info": {
"types": "./dist/client-info.d.mts",
"import": "./dist/client-info.mjs",
"default": "./dist/client-info.mjs"
},
"./connect-error-details": {
"types": "./dist/connect-error-details.d.mts",
"import": "./dist/connect-error-details.mjs",
"default": "./dist/connect-error-details.mjs"
},
"./schema": {
"types": "./dist/schema.d.mts",
"import": "./dist/schema.mjs",
"default": "./dist/schema.mjs"
},
"./startup-unavailable": {
"types": "./dist/startup-unavailable.d.mts",
"import": "./dist/startup-unavailable.mjs",
"default": "./dist/startup-unavailable.mjs"
},
"./version": {
"types": "./dist/version.d.mts",
"import": "./dist/version.mjs",
"default": "./dist/version.mjs"
}
},
"scripts": {
"build": "tsdown src/index.ts src/client-info.ts src/connect-error-details.ts src/schema.ts src/startup-unavailable.ts src/version.ts --no-config --platform node --format esm --dts --out-dir dist --clean"
},
"dependencies": {
"typebox": "1.1.38"
}
}

View File

@@ -1,4 +1,10 @@
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
function normalizeOptionalLowercaseString(raw?: string | null): string | undefined {
if (typeof raw !== "string") {
return undefined;
}
const normalized = raw.trim().toLowerCase();
return normalized || undefined;
}
export const GATEWAY_CLIENT_IDS = {
WEBCHAT_UI: "webchat-ui",

View File

@@ -1,5 +1,22 @@
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import { normalizeArrayBackedTrimmedStringList } from "../../shared/string-normalization.js";
function normalizeOptionalString(value: unknown): string | undefined {
if (typeof value !== "string") {
return undefined;
}
const trimmed = value.trim();
return trimmed || undefined;
}
function normalizeArrayBackedTrimmedStringList(value: unknown): string[] | undefined {
if (!Array.isArray(value)) {
return undefined;
}
const values = value
.map((entry) => normalizeOptionalString(entry))
.filter((entry): entry is string => Boolean(entry));
// Pairing details omit absent lists. Emitting empty arrays makes clients think
// the gateway intentionally supplied scope/role context when it did not.
return values.length > 0 ? values : undefined;
}
export const ConnectErrorDetailCodes = {
AUTH_REQUIRED: "AUTH_REQUIRED",

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { TALK_TEST_PROVIDER_ID } from "../../test-utils/talk-test-provider.js";
import { TALK_TEST_PROVIDER_ID } from "../../../src/test-utils/talk-test-provider.js";
import * as protocol from "./index.js";
import {
formatValidationErrors,

View File

@@ -1,6 +1,4 @@
import { Compile, type Validator as TypeBoxValidator } from "typebox/compile";
import { uniqueStrings } from "../../shared/string-normalization.js";
import type { SessionsPatchResult } from "../session-utils.types.js";
import {
type AgentEvent,
AgentEventSchema,
@@ -1266,3 +1264,26 @@ export type {
UpdateRunParams,
ChatInjectParams,
};
function uniqueStrings(values: string[]): string[] {
return [...new Set(values)];
}
// The protocol package cannot import core session types. This local structural
// result mirrors the wire contract and keeps the package independent of src/.
type SessionsPatchResult = {
ok: true;
path: string;
key: string;
entry: Record<string, unknown>;
resolved?: {
modelProvider?: string;
model?: string;
agentRuntime?: GatewayAgentRuntime;
};
};
type GatewayAgentRuntime = {
id: string;
fallback?: "openclaw" | "none";
source: "env" | "agent" | "defaults" | "model" | "provider" | "implicit" | "session-key";
};

View File

@@ -26,7 +26,7 @@ function extractInteger(
const match = pattern.exec(content);
if (!match) {
throw new Error(
`${relativePath}: missing ${label}; keep native Gateway protocol levels in sync with src/gateway/protocol/version.ts.`,
`${relativePath}: missing ${label}; keep native Gateway protocol levels in sync with packages/gateway-protocol/src/version.ts.`,
);
}
return Number.parseInt(match[1], 10);
@@ -37,7 +37,7 @@ function assertLevelsMatch(relativePath: string, actual: ProtocolLevels): void {
return;
}
throw new Error(
`${relativePath}: Gateway protocol level mismatch: expected min=${expectedLevels.min} max=${expectedLevels.max} from src/gateway/protocol/version.ts, got min=${actual.min} max=${actual.max}. Update the native constants/generated artifacts before shipping.`,
`${relativePath}: Gateway protocol level mismatch: expected min=${expectedLevels.min} max=${expectedLevels.max} from packages/gateway-protocol/src/version.ts, got min=${actual.min} max=${actual.max}. Update the native constants/generated artifacts before shipping.`,
);
}
@@ -57,7 +57,7 @@ describe("native Gateway protocol levels", () => {
it("match the TypeScript source of truth", async () => {
if (MIN_CLIENT_PROTOCOL_VERSION > PROTOCOL_VERSION) {
throw new Error(
`src/gateway/protocol/version.ts: MIN_CLIENT_PROTOCOL_VERSION (${MIN_CLIENT_PROTOCOL_VERSION}) must not exceed PROTOCOL_VERSION (${PROTOCOL_VERSION}).`,
`packages/gateway-protocol/src/version.ts: MIN_CLIENT_PROTOCOL_VERSION (${MIN_CLIENT_PROTOCOL_VERSION}) must not exceed PROTOCOL_VERSION (${PROTOCOL_VERSION}).`,
);
}

View File

@@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";
import {
INVALID_EXEC_SECRET_REF_IDS,
VALID_EXEC_SECRET_REF_IDS,
} from "../../test-utils/secret-ref-test-vectors.js";
} from "../../../src/test-utils/secret-ref-test-vectors.js";
import { SecretInputSchema, SecretRefSchema } from "./schema/primitives.js";
describe("gateway protocol SecretRef schema", () => {

View File

@@ -1,3 +1,4 @@
export * from "./schema/primitives.js";
export * from "./schema/agent.js";
export * from "./schema/agents-models-skills.js";
export * from "./schema/artifacts.js";

View File

@@ -1,8 +1,22 @@
import { Value } from "typebox/value";
import { describe, expect, it } from "vitest";
import type { AgentInternalEvent } from "../../../agents/internal-events.js";
import { AgentParamsSchema } from "./agent.js";
type AgentInternalEvent = {
type: "task_completion";
source: string;
childSessionKey: string;
childSessionId: string;
announceType: string;
taskLabel: string;
status: "ok" | "error";
statusLabel: string;
result: string;
attachments?: unknown[];
mediaUrls?: string[];
replyInstruction?: string;
};
function makeAgentParamsWithInternalEvent(event: AgentInternalEvent) {
return {
message: "A music generation task finished. Process the completion update now.",

View File

@@ -1,11 +1,16 @@
import { Type } from "typebox";
import {
AGENT_INTERNAL_EVENT_SOURCES,
AGENT_INTERNAL_EVENT_STATUSES,
AGENT_INTERNAL_EVENT_TYPE_TASK_COMPLETION,
} from "../../../agents/internal-event-contract.js";
import { InputProvenanceSchema, NonEmptyString, SessionLabelString } from "./primitives.js";
const AGENT_INTERNAL_EVENT_TYPE_TASK_COMPLETION = "task_completion";
const AGENT_INTERNAL_EVENT_SOURCES = [
"subagent",
"cron",
"image_generation",
"video_generation",
"music_generation",
] as const;
const AGENT_INTERNAL_EVENT_STATUSES = ["ok", "timeout", "error", "unknown"] as const;
export const AgentGeneratedAttachmentSchema = Type.Object(
{
type: Type.Optional(Type.String({ enum: ["image", "audio", "video", "file"] })),

View File

@@ -1,11 +1,10 @@
import { Type } from "typebox";
import {
MAX_PLUGIN_APPROVAL_TIMEOUT_MS,
PLUGIN_APPROVAL_DESCRIPTION_MAX_LENGTH,
PLUGIN_APPROVAL_TITLE_MAX_LENGTH,
} from "../../../infra/plugin-approvals.js";
import { NonEmptyString } from "./primitives.js";
const MAX_PLUGIN_APPROVAL_TIMEOUT_MS = 600_000;
const PLUGIN_APPROVAL_TITLE_MAX_LENGTH = 80;
const PLUGIN_APPROVAL_DESCRIPTION_MAX_LENGTH = 256;
export const PluginApprovalRequestParamsSchema = Type.Object(
{
pluginId: Type.Optional(NonEmptyString),

View File

@@ -1,15 +1,16 @@
import { Type } from "typebox";
import { ENV_SECRET_REF_ID_RE } from "../../../config/types.secrets.js";
import { GATEWAY_CLIENT_IDS, GATEWAY_CLIENT_MODES } from "../client-info.js";
import {
EXEC_SECRET_REF_ID_JSON_SCHEMA_PATTERN,
FILE_SECRET_REF_ID_ABSOLUTE_JSON_SCHEMA_PATTERN,
FILE_SECRET_REF_ID_INVALID_ESCAPE_JSON_SCHEMA_PATTERN,
SECRET_PROVIDER_ALIAS_PATTERN,
SINGLE_VALUE_FILE_REF_ID,
} 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";
} from "../secret-ref-contract.js";
const ENV_SECRET_REF_ID_RE = /^[A-Z][A-Z0-9_]{0,127}$/;
const INPUT_PROVENANCE_KIND_VALUES = ["external_user", "inter_session", "internal_system"] as const;
const SESSION_LABEL_MAX_LENGTH = 512;
export const NonEmptyString = Type.String({ minLength: 1 });
export const CHAT_SEND_SESSION_KEY_MAX_LENGTH = 512;

View File

@@ -0,0 +1,7 @@
export const SINGLE_VALUE_FILE_REF_ID = "value";
export const SECRET_PROVIDER_ALIAS_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/;
export const FILE_SECRET_REF_ID_ABSOLUTE_JSON_SCHEMA_PATTERN = "^/";
export const FILE_SECRET_REF_ID_INVALID_ESCAPE_JSON_SCHEMA_PATTERN = "~(?:[^01]|$)";
export const EXEC_SECRET_REF_ID_JSON_SCHEMA_PATTERN =
"^(?!.*(?:^|/)\\.{1,2}(?:/|$))[A-Za-z0-9][A-Za-z0-9._:/#-]{0,255}$";

View File

@@ -1,6 +1,6 @@
import fs from "node:fs";
import { describe, expect, it } from "vitest";
import { buildTalkConfigResponse } from "../../config/talk.js";
import { buildTalkConfigResponse } from "../../../src/config/talk.js";
import { validateTalkConfigResult } from "./index.js";
type ExpectedSelection = {

18
pnpm-lock.yaml generated
View File

@@ -1743,6 +1743,24 @@ importers:
specifier: 2.9.0
version: 2.9.0
packages/gateway-client:
dependencies:
'@openclaw/gateway-protocol':
specifier: workspace:*
version: link:../gateway-protocol
ipaddr.js:
specifier: 2.4.0
version: 2.4.0
ws:
specifier: 8.21.0
version: 8.21.0
packages/gateway-protocol:
dependencies:
typebox:
specifier: 1.1.38
version: 1.1.38
packages/memory-host-sdk: {}
packages/plugin-package-contract: {}

View File

@@ -49,7 +49,8 @@ const FAST_INSTALL_SMOKE_SCOPE_RE =
/^(Dockerfile$|\.npmrc$|package\.json$|pnpm-lock\.yaml$|pnpm-workspace\.yaml$|scripts\/ci-changed-scope\.mjs$|scripts\/postinstall-bundled-plugins\.mjs$|scripts\/e2e\/(?:Dockerfile(?:\.qr-import)?|agents-delete-shared-workspace-docker\.sh|gateway-network-docker\.sh)$|extensions\/[^/]+\/(?:package\.json|openclaw\.plugin\.json)$|\.github\/workflows\/install-smoke\.yml$|\.github\/actions\/setup-node-env\/action\.yml$)/;
const FULL_INSTALL_SMOKE_SCOPE_RE =
/^(Dockerfile$|\.npmrc$|package\.json$|pnpm-lock\.yaml$|pnpm-workspace\.yaml$|scripts\/ci-changed-scope\.mjs$|scripts\/install(?:-cli)?\.sh$|scripts\/install\.ps1$|scripts\/test-install-sh-docker\.sh$|scripts\/docker\/|scripts\/e2e\/(?:Dockerfile(?:\.qr-import)?|qr-import-docker\.sh|bun-global-install-smoke\.sh)$|\.github\/workflows\/(?:install-smoke|website-installer-sync)\.yml$|\.github\/actions\/setup-node-env\/action\.yml$)/;
const FAST_INSTALL_SMOKE_RUNTIME_SCOPE_RE = /^src\/(?:channels|gateway|plugin-sdk|plugins)\//;
const FAST_INSTALL_SMOKE_RUNTIME_SCOPE_RE =
/^(?:src\/(?:channels|gateway|plugin-sdk|plugins)\/|packages\/gateway-(?:client|protocol)\/src\/)/;
const NODE_FAST_PLUGIN_CONTRACT_SCOPE_RE =
/^(src\/plugins\/contracts\/(?:inventory\/bundled-capability-metadata|registry|tts-contract-suites)\.ts$|scripts\/test-projects(?:\.test-support)?\.mjs$|test\/scripts\/test-projects\.test\.ts$)/;
const NODE_FAST_CI_ROUTING_SCOPE_RE =

View File

@@ -1,8 +1,8 @@
import { createArgReader, createGatewayWsClient, resolveGatewayUrl } from "./gateway-ws-client.ts";
import {
MIN_CLIENT_PROTOCOL_VERSION,
PROTOCOL_VERSION,
} from "../../src/gateway/protocol/version.ts";
} from "../../packages/gateway-protocol/src/version.js";
import { createArgReader, createGatewayWsClient, resolveGatewayUrl } from "./gateway-ws-client.ts";
function writeStdoutLine(message: string): void {
process.stdout.write(`${message}\n`);

View File

@@ -1,8 +1,8 @@
import { createArgReader, createGatewayWsClient, resolveGatewayUrl } from "./gateway-ws-client.ts";
import {
MIN_CLIENT_PROTOCOL_VERSION,
PROTOCOL_VERSION,
} from "../../src/gateway/protocol/version.ts";
} from "../../packages/gateway-protocol/src/version.js";
import { createArgReader, createGatewayWsClient, resolveGatewayUrl } from "./gateway-ws-client.ts";
function writeStdoutLine(message = ""): void {
process.stdout.write(`${message}\n`);

View File

@@ -6,7 +6,7 @@ import {
MIN_CLIENT_PROTOCOL_VERSION,
PROTOCOL_VERSION,
ProtocolSchemas,
} from "../src/gateway/protocol/schema.js";
} from "../packages/gateway-protocol/src/schema.js";
type JsonSchema = {
type?: string | string[];

View File

@@ -1,7 +1,7 @@
import { promises as fs } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { ProtocolSchemas } from "../src/gateway/protocol/schema.js";
import { ProtocolSchemas } from "../packages/gateway-protocol/src/schema.js";
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(scriptDir, "..");

View File

@@ -4,7 +4,18 @@ import {
BUNDLED_PLUGIN_ROOT_DIR,
} from "./lib/bundled-plugin-paths.mjs";
export const runNodeSourceRoots = ["src", BUNDLED_PLUGIN_ROOT_DIR];
const RUN_NODE_PACKAGE_SOURCE_ROOTS = [
// Gateway runtime code now lives in package sources, but pnpm dev/watch still
// runs the root dist entrypoint. Treat these package roots like src/.
"packages/gateway-client/src",
"packages/gateway-protocol/src",
];
export const runNodeSourceRoots = [
"src",
...RUN_NODE_PACKAGE_SOURCE_ROOTS,
BUNDLED_PLUGIN_ROOT_DIR,
];
export const runNodeConfigFiles = ["tsconfig.json", "package.json", "tsdown.config.ts"];
export const runNodeWatchedPaths = [...runNodeSourceRoots, ...runNodeConfigFiles];
export const extensionRestartMetadataFiles = new Set(["openclaw.plugin.json", "package.json"]);
@@ -50,6 +61,11 @@ const isRelevantRunNodePath = (repoPath, isRelevantBundledPluginPath) => {
if (normalizedPath.startsWith("src/")) {
return !isIgnoredSourcePath(normalizedPath.slice("src/".length));
}
for (const sourceRoot of RUN_NODE_PACKAGE_SOURCE_ROOTS) {
if (normalizedPath.startsWith(`${sourceRoot}/`)) {
return !isIgnoredSourcePath(normalizedPath.slice(sourceRoot.length + 1));
}
}
if (normalizedPath.startsWith(BUNDLED_PLUGIN_PATH_PREFIX)) {
return isRelevantBundledPluginPath(normalizedPath.slice(BUNDLED_PLUGIN_PATH_PREFIX.length));
}

View File

@@ -2,15 +2,15 @@
import { Readable, Writable } from "node:stream";
import { fileURLToPath } from "node:url";
import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
import { getRuntimeConfig } from "../config/config.js";
import { resolveGatewayClientBootstrap } from "../gateway/client-bootstrap.js";
import { startGatewayClientWhenEventLoopReady } from "../gateway/client-start-readiness.js";
import { GatewayClient } from "../gateway/client.js";
import {
GATEWAY_CLIENT_CAPS,
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../gateway/protocol/client-info.js";
} from "../../packages/gateway-protocol/src/client-info.js";
import { getRuntimeConfig } from "../config/config.js";
import { resolveGatewayClientBootstrap } from "../gateway/client-bootstrap.js";
import { startGatewayClientWhenEventLoopReady } from "../gateway/client-start-readiness.js";
import { GatewayClient } from "../gateway/client.js";
import { isMainModule } from "../infra/is-main.js";
import { routeLogsToStderr } from "../logging/console.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";

View File

@@ -1,7 +1,7 @@
import type { CancelNotification, PromptRequest, PromptResponse } from "@agentclientprotocol/sdk";
import { describe, expect, it, vi } from "vitest";
import type { EventFrame } from "../../packages/gateway-protocol/src/index.js";
import type { GatewayClient } from "../gateway/client.js";
import type { EventFrame } from "../gateway/protocol/index.js";
import { createInMemorySessionStore } from "./session.js";
import { AcpGatewayAgent } from "./translator.js";
import { createAcpConnection, createAcpGateway } from "./translator.test-helpers.js";

View File

@@ -4,8 +4,8 @@ import type {
PromptRequest,
} from "@agentclientprotocol/sdk";
import { describe, expect, it, vi } from "vitest";
import type { EventFrame } from "../../packages/gateway-protocol/src/index.js";
import type { GatewayClient } from "../gateway/client.js";
import type { EventFrame } from "../gateway/protocol/index.js";
import { createInMemoryAcpEventLedger, type AcpEventLedger } from "./event-ledger.js";
import { createInMemorySessionStore } from "./session.js";
import { AcpGatewayAgent } from "./translator.js";

View File

@@ -1,7 +1,7 @@
import type { CancelNotification } from "@agentclientprotocol/sdk";
import { describe, expect, it, vi } from "vitest";
import type { EventFrame } from "../../packages/gateway-protocol/src/index.js";
import type { GatewayClient } from "../gateway/client.js";
import type { EventFrame } from "../gateway/protocol/index.js";
import { createInMemorySessionStore } from "./session.js";
import { AcpGatewayAgent } from "./translator.js";
import { promptAgent } from "./translator.prompt-harness.test-support.js";

View File

@@ -1,7 +1,7 @@
import type { PromptRequest } from "@agentclientprotocol/sdk";
import { expect, vi } from "vitest";
import type { EventFrame } from "../../packages/gateway-protocol/src/index.js";
import type { GatewayClient } from "../gateway/client.js";
import type { EventFrame } from "../gateway/protocol/index.js";
import { createInMemorySessionStore } from "./session.js";
import { AcpGatewayAgent } from "./translator.js";
import { createAcpConnection, createAcpGateway } from "./translator.test-helpers.js";

View File

@@ -6,8 +6,8 @@ import type {
SetSessionModeRequest,
} from "@agentclientprotocol/sdk";
import { describe, expect, it, vi } from "vitest";
import type { EventFrame } from "../../packages/gateway-protocol/src/index.js";
import type { GatewayClient } from "../gateway/client.js";
import type { EventFrame } from "../gateway/protocol/index.js";
import { createInMemorySessionStore } from "./session.js";
import { AcpGatewayAgent } from "./translator.js";
import { createAcpConnection, createAcpGateway } from "./translator.test-helpers.js";

View File

@@ -33,9 +33,9 @@ import type {
ToolCallLocation,
ToolKind,
} from "@agentclientprotocol/sdk";
import type { EventFrame } from "../../packages/gateway-protocol/src/index.js";
import { BASE_THINKING_LEVELS } from "../auto-reply/thinking.shared.js";
import type { GatewayClient } from "../gateway/client.js";
import type { EventFrame } from "../gateway/protocol/index.js";
import type { GatewaySessionRow, SessionsListResult } from "../gateway/session-utils.js";
import {
createFixedWindowRateLimiter,

View File

@@ -198,7 +198,7 @@ describe("buildEmbeddedRunPayloads tool-error warnings", () => {
it("does not replay raw-looking accumulated tool output when final answer text is available", () => {
const payloads = buildPayloads({
assistantTexts: [
"/root/openclaw/src/gateway/protocol/schema/protocol-schemas.ts:181: PluginControlUiDescriptorSchema,",
"/root/openclaw/packages/gateway-protocol/src/schema/protocol-schemas.ts:181: PluginControlUiDescriptorSchema,",
"The schema export is fixed.",
],
lastAssistant: {

View File

@@ -1,6 +1,9 @@
import type {
SessionsListParams,
SessionsResolveParams,
} from "../../../packages/gateway-protocol/src/index.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { CallGatewayOptions } from "../../gateway/call.js";
import type { SessionsListParams, SessionsResolveParams } from "../../gateway/protocol/index.js";
import type { ReadSessionMessagesAsyncOptions } from "../../gateway/session-utils.fs.js";
import type { SessionsListResult } from "../../gateway/session-utils.types.js";
import type { SessionsResolveResult } from "../../gateway/sessions-resolve.js";

View File

@@ -1,3 +1,7 @@
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../../../packages/gateway-protocol/src/client-info.js";
import { getRuntimeConfig, resolveGatewayPort } from "../../config/config.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { callGateway } from "../../gateway/call.js";
@@ -7,7 +11,6 @@ import {
type OperatorScope,
} from "../../gateway/method-scopes.js";
import { getOperatorApprovalRuntimeToken } from "../../gateway/operator-approval-runtime-token.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../gateway/protocol/client-info.js";
import { formatErrorMessage } from "../../infra/errors.js";
import {
normalizeLowercaseStringOrEmpty,

View File

@@ -1,4 +1,8 @@
import { Type, type TSchema } from "typebox";
import {
GATEWAY_CLIENT_IDS,
GATEWAY_CLIENT_MODES,
} from "../../../packages/gateway-protocol/src/client-info.js";
import type { SourceReplyDeliveryMode } from "../../auto-reply/get-reply-options.types.js";
import type { InboundEventKind } from "../../channels/inbound-event/kind.js";
import {
@@ -21,7 +25,6 @@ import { getScopedChannelsCommandSecretTargets } from "../../cli/command-secret-
import { resolveMessageSecretScope } from "../../cli/message-secret-scope.js";
import { getRuntimeConfig } from "../../config/config.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { GATEWAY_CLIENT_IDS, GATEWAY_CLIENT_MODES } from "../../gateway/protocol/client-info.js";
import { getToolResult, runMessageAction } from "../../infra/outbound/message-action-runner.js";
import { resolveAllowedMessageActions } from "../../infra/outbound/outbound-policy.js";
import { stringifyRouteThreadId } from "../../plugin-sdk/channel-route.js";

View File

@@ -1,8 +1,8 @@
import crypto from "node:crypto";
import { Type } from "typebox";
import { readConnectPairingRequiredMessage } from "../../../packages/gateway-protocol/src/connect-error-details.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { OperatorScope } from "../../gateway/method-scopes.js";
import { readConnectPairingRequiredMessage } from "../../gateway/protocol/connect-error-details.js";
import { formatErrorMessage } from "../../infra/errors.js";
import { resolveNodePairApprovalScopes } from "../../infra/node-pairing-authz.js";
import type { GatewayMessageChannel } from "../../utils/message-channel.js";

View File

@@ -1,9 +1,9 @@
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { callGateway } from "../../gateway/call.js";
import {
GATEWAY_CLIENT_IDS,
normalizeGatewayClientId,
} from "../../gateway/protocol/client-info.js";
} from "../../../packages/gateway-protocol/src/client-info.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { callGateway } from "../../gateway/call.js";
import { formatErrorMessage } from "../../infra/errors.js";
import {
listSpawnedSessionKeys,

View File

@@ -1,10 +1,13 @@
import type { TSchema } from "typebox";
import type {
GatewayClientMode,
GatewayClientName,
} from "../../../packages/gateway-protocol/src/client-info.js";
import type { AgentTool, AgentToolResult } from "../../agents/runtime/index.js";
import type { ReplyPayload } from "../../auto-reply/reply-payload.js";
import type { MsgContext } from "../../auto-reply/templating.js";
import type { MarkdownTableMode } from "../../config/types.base.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { GatewayClientMode, GatewayClientName } from "../../gateway/protocol/client-info.js";
import type { MessagePresentation } from "../../interactive/payload.js";
import type { OutboundMediaAccess } from "../../media/load-options.js";
import type { PollInput } from "../../polls.js";

View File

@@ -5,6 +5,10 @@ import path from "node:path";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
import type { Command } from "commander";
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../../packages/gateway-protocol/src/client-info.js";
import { resolveAgentDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import {
listProfilesForProvider,
@@ -32,7 +36,6 @@ import { callGateway, randomIdempotencyKey } from "../gateway/call.js";
import { buildGatewayConnectionDetailsWithResolvers } from "../gateway/connection-details.js";
import { isLoopbackHost } from "../gateway/net.js";
import { ADMIN_SCOPE } from "../gateway/operator-scopes.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../gateway/protocol/client-info.js";
import { generateImage, listRuntimeImageGenerationProviders } from "../image-generation/runtime.js";
import type {
ImageGenerationBackground,

View File

@@ -1,8 +1,11 @@
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../../packages/gateway-protocol/src/client-info.js";
import { validateSecretsResolveResult } from "../../packages/gateway-protocol/src/index.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { resolveSecretInputRef } from "../config/types.secrets.js";
import { callGateway } from "../gateway/call.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../gateway/protocol/client-info.js";
import { validateSecretsResolveResult } from "../gateway/protocol/index.js";
import { formatErrorMessage } from "../infra/errors.js";
import { resolveManifestContractOwnerPluginId } from "../plugins/plugin-registry.js";
import {

View File

@@ -1,3 +1,11 @@
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../../packages/gateway-protocol/src/client-info.js";
import {
readConnectPairingRequiredMessage,
type ConnectPairingRequiredDetails,
} from "../../packages/gateway-protocol/src/connect-error-details.js";
import {
buildGatewayConnectionDetails,
callGateway,
@@ -5,11 +13,6 @@ import {
} from "../gateway/call.js";
import { ADMIN_SCOPE, PAIRING_SCOPE, type OperatorScope } from "../gateway/method-scopes.js";
import { isLoopbackHost } from "../gateway/net.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../gateway/protocol/client-info.js";
import {
readConnectPairingRequiredMessage,
type ConnectPairingRequiredDetails,
} from "../gateway/protocol/connect-error-details.js";
import {
approveDevicePairing,
formatDevicePairingForbiddenMessage,

View File

@@ -1,7 +1,10 @@
import type { Command } from "commander";
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../../../packages/gateway-protocol/src/client-info.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { callGateway } from "../../gateway/call.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../gateway/protocol/client-info.js";
import { parseTimeoutMsWithFallback } from "../parse-timeout.js";
import { withProgress } from "../progress.js";

View File

@@ -1,5 +1,8 @@
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../../packages/gateway-protocol/src/client-info.js";
import { callGateway } from "../gateway/call.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../gateway/protocol/client-info.js";
import type { GatewayRpcOpts } from "./gateway-rpc.types.js";
import { parseTimeoutMsWithFallback } from "./parse-timeout.js";
import { withProgress } from "./progress.js";

View File

@@ -1,6 +1,9 @@
import type { Command } from "commander";
import type {
GatewayClientMode,
GatewayClientName,
} from "../../packages/gateway-protocol/src/client-info.js";
import type { OperatorScope } from "../gateway/operator-scopes.js";
import type { GatewayClientMode, GatewayClientName } from "../gateway/protocol/client-info.js";
import type { DeviceIdentity } from "../infra/device-identity.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import type { GatewayRpcOpts } from "./gateway-rpc.types.js";

View File

@@ -1,13 +1,16 @@
import { setTimeout as delay } from "node:timers/promises";
import type { Command } from "commander";
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../../packages/gateway-protocol/src/client-info.js";
import { readConnectPairingRequiredMessage } from "../../packages/gateway-protocol/src/connect-error-details.js";
import {
buildGatewayConnectionDetails,
isGatewayTransportError,
type GatewayConnectionDetails,
} from "../gateway/call.js";
import { isLoopbackHost } from "../gateway/net.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../gateway/protocol/client-info.js";
import { readConnectPairingRequiredMessage } from "../gateway/protocol/connect-error-details.js";
import { computeBackoff } from "../infra/backoff.js";
import { formatErrorMessage } from "../infra/errors.js";
import { parseStrictPositiveInteger } from "../infra/parse-finite-number.js";

View File

@@ -1,6 +1,9 @@
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../../../packages/gateway-protocol/src/client-info.js";
import { callGateway } from "../../gateway/call.js";
import type { OperatorScope } from "../../gateway/method-scopes.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../gateway/protocol/client-info.js";
import { parseTimeoutMsWithFallback } from "../parse-timeout.js";
import { withProgress } from "../progress.js";
import type { NodesRpcOpts } from "./types.js";

View File

@@ -1,5 +1,9 @@
import { randomUUID } from "node:crypto";
import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../../packages/gateway-protocol/src/client-info.js";
import { listAgentIds, resolveDefaultAgentId } from "../agents/agent-scope.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { CliDeps } from "../cli/deps.types.js";
@@ -13,7 +17,6 @@ import {
type GatewayRequestFunction,
} from "../gateway/call.js";
import { ADMIN_SCOPE } from "../gateway/operator-scopes.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../gateway/protocol/client-info.js";
import { parseStrictNonNegativeInteger } from "../infra/parse-finite-number.js";
import { routeLogsToStderr } from "../logging/console.js";
import {

View File

@@ -24,7 +24,7 @@ export async function maybeRepairUiProtocolFreshness(
return;
}
const schemaPath = path.join(root, "src/gateway/protocol/schema.ts");
const schemaPath = path.join(root, "packages/gateway-protocol/src/schema.ts");
const uiHealth = await resolveControlUiDistIndexHealth({
root,
argv1: process.argv[1],
@@ -92,7 +92,7 @@ export async function maybeRepairUiProtocolFreshness(
"log",
`--since=${uiMtimeIso}`,
"--format=%h %s",
"src/gateway/protocol/schema.ts",
"packages/gateway-protocol/src/schema.ts",
],
{ timeoutMs: 5000 },
).catch(() => null);

View File

@@ -1,3 +1,7 @@
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../../packages/gateway-protocol/src/client-info.js";
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
import { CHANNEL_MESSAGE_ACTION_NAMES } from "../channels/plugins/message-action-names.js";
import type { ChannelMessageActionName } from "../channels/plugins/types.public.js";
@@ -8,7 +12,6 @@ import { resolveMessageSecretScope } from "../cli/message-secret-scope.js";
import { createOutboundSendDeps, type CliDeps } from "../cli/outbound-send-deps.js";
import { withProgress } from "../cli/progress.js";
import { getRuntimeConfig } from "../config/config.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../gateway/protocol/client-info.js";
import type { OutboundSendDeps } from "../infra/outbound/deliver.js";
import { runMessageAction } from "../infra/outbound/message-action-runner.js";
import { type RuntimeEnv, writeRuntimeJson } from "../runtime.js";

View File

@@ -1,4 +1,4 @@
import type { ConnectPairingRequiredReason } from "../gateway/protocol/connect-error-details.js";
import type { ConnectPairingRequiredReason } from "../../packages/gateway-protocol/src/connect-error-details.js";
import type { HeartbeatEventPayload } from "../infra/heartbeat-events.js";
import type { resolveOsSummary } from "../infra/os-summary.js";
import type { PluginCompatibilityNotice } from "../plugins/status.js";

View File

@@ -1,9 +1,9 @@
import { areRuntimeModelRefsEquivalent } from "../agents/model-runtime-aliases.js";
import {
buildPairingConnectRecoveryTitle,
describePairingConnectRequirement,
type ConnectPairingRequiredReason,
} from "../gateway/protocol/connect-error-details.js";
} from "../../packages/gateway-protocol/src/connect-error-details.js";
import { areRuntimeModelRefsEquivalent } from "../agents/model-runtime-aliases.js";
import type { HeartbeatEventPayload } from "../infra/heartbeat-events.js";
import type { Tone } from "../memory-host-sdk/status.js";
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";

View File

@@ -1,10 +1,10 @@
import { withProgress } from "../cli/progress.js";
import {
normalizePairingConnectRequestId,
readConnectPairingRequiredMessage,
readPairingConnectErrorDetails,
type ConnectPairingRequiredReason,
} from "../gateway/protocol/connect-error-details.js";
} from "../../packages/gateway-protocol/src/connect-error-details.js";
import { withProgress } from "../cli/progress.js";
import { readRestartSentinel } from "../infra/restart-sentinel.js";
import { type RuntimeEnv } from "../runtime.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";

View File

@@ -1,10 +1,13 @@
import { existsSync } from "node:fs";
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../../packages/gateway-protocol/src/client-info.js";
import type { OpenClawConfig } from "../config/types.js";
import { buildGatewayConnectionDetailsWithResolvers } from "../gateway/connection-details.js";
import { normalizeControlUiBasePath } from "../gateway/control-ui-shared.js";
import { resolveGatewayProbeTarget } from "../gateway/probe-target.js";
import type { GatewayProbeResult, probeGateway as probeGatewayFn } from "../gateway/probe.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../gateway/protocol/client-info.js";
import type { MemoryProviderStatus } from "../memory-host-sdk/engine-storage.js";
import { defaultSlotIdForKey } from "../plugins/slots.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";

View File

@@ -1,5 +1,8 @@
import { randomUUID } from "node:crypto";
import type { SessionsPatchParams, SessionsPatchResult } from "../gateway/protocol/index.js";
import type {
SessionsPatchParams,
SessionsPatchResult,
} from "../../packages/gateway-protocol/src/index.js";
import { buildAgentMainSessionKey } from "../routing/session-key.js";
import type { RuntimeEnv } from "../runtime.js";
import type {

Some files were not shown because too many files have changed in this diff Show More