GatewayConnection: validate agent message
This commit is contained in:
@@ -165,9 +165,11 @@ extension GatewayConnection {
|
|||||||
channel: String? = nil,
|
channel: String? = nil,
|
||||||
idempotencyKey: String = UUID().uuidString) async -> (ok: Bool, error: String?)
|
idempotencyKey: String = UUID().uuidString) async -> (ok: Bool, error: String?)
|
||||||
{
|
{
|
||||||
|
let trimmed = message.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
|
guard !trimmed.isEmpty else { return (false, "message empty") }
|
||||||
do {
|
do {
|
||||||
let params: [String: Any] = [
|
let params: [String: Any] = [
|
||||||
"message": message,
|
"message": trimmed,
|
||||||
"sessionKey": sessionKey,
|
"sessionKey": sessionKey,
|
||||||
"thinking": thinking ?? "default",
|
"thinking": thinking ?? "default",
|
||||||
"deliver": deliver,
|
"deliver": deliver,
|
||||||
|
|||||||
@@ -2,16 +2,21 @@ import Testing
|
|||||||
@testable import Clawdis
|
@testable import Clawdis
|
||||||
@testable import ClawdisIPC
|
@testable import ClawdisIPC
|
||||||
|
|
||||||
@Suite(.serialized) struct AgentRPCTests {
|
@Suite(.serialized) struct GatewayConnectionControlTests {
|
||||||
@Test func statusFailsWhenProcessMissing() async {
|
@Test func statusFailsWhenProcessMissing() async {
|
||||||
let result = await AgentRPC.shared.status()
|
let result = await GatewayConnection.shared.status()
|
||||||
// We don't assert ok because the worker may not be available in CI.
|
// We don't assert ok because the worker may not be available in CI.
|
||||||
// Instead, ensure the call returns without throwing and provides a message.
|
// Instead, ensure the call returns without throwing and provides a message.
|
||||||
#expect(result.ok == true || result.error != nil)
|
#expect(result.ok == true || result.error != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func rejectEmptyMessage() async {
|
@Test func rejectEmptyMessage() async {
|
||||||
let result = await AgentRPC.shared.send(text: "", thinking: nil, sessionKey: "main", deliver: false, to: nil)
|
let result = await GatewayConnection.shared.sendAgent(
|
||||||
|
message: "",
|
||||||
|
thinking: nil,
|
||||||
|
sessionKey: "main",
|
||||||
|
deliver: false,
|
||||||
|
to: nil)
|
||||||
#expect(result.ok == false)
|
#expect(result.ok == false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ Non-goals (v1):
|
|||||||
## Current repo reality (constraints we respect)
|
## Current repo reality (constraints we respect)
|
||||||
- The Gateway WebSocket server binds to `127.0.0.1:18789` (`src/gateway/server.ts`) with an optional `CLAWDIS_GATEWAY_TOKEN`.
|
- The Gateway WebSocket server binds to `127.0.0.1:18789` (`src/gateway/server.ts`) with an optional `CLAWDIS_GATEWAY_TOKEN`.
|
||||||
- macOS “Canvas” exists today, but is **mac-only** and controlled via mac app IPC (`clawdis-mac canvas ...`) rather than the Gateway protocol (`docs/mac/canvas.md`).
|
- macOS “Canvas” exists today, but is **mac-only** and controlled via mac app IPC (`clawdis-mac canvas ...`) rather than the Gateway protocol (`docs/mac/canvas.md`).
|
||||||
- Voice wake forwards via `GatewayChannel` to Gateway `agent` (mac app: `VoiceWakeForwarder` → `AgentRPC`).
|
- Voice wake forwards via `GatewayChannel` to Gateway `agent` (mac app: `VoiceWakeForwarder` → `GatewayConnection.sendAgent`).
|
||||||
|
|
||||||
## Recommended topology (B): Gateway-owned Bridge + loopback Gateway
|
## Recommended topology (B): Gateway-owned Bridge + loopback Gateway
|
||||||
Keep the Node gateway loopback-only; expose a dedicated **gateway-owned bridge** to the LAN/tailnet.
|
Keep the Node gateway loopback-only; expose a dedicated **gateway-owned bridge** to the LAN/tailnet.
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ Goal: replace legacy gateway/stdin/TCP control with a single WebSocket Gateway,
|
|||||||
|
|
||||||
## Phase 5 — Clients migration
|
## Phase 5 — Clients migration
|
||||||
- **macOS app**:
|
- **macOS app**:
|
||||||
- Replace stdio/SSH RPC with WS client (tunneled via SSH/Tailscale for remote). ✅ AgentRPC/ControlChannel now use Gateway WS.
|
- Replace stdio/SSH RPC with WS client (tunneled via SSH/Tailscale for remote). ✅ GatewayConnection/ControlChannel now use Gateway WS.
|
||||||
- Implement handshake, snapshot hydration, subscriptions to `presence`, `tick`, `agent`, `shutdown`. ✅ snapshot + presence events broadcast to InstancesStore; agent events still to wire to UI if desired.
|
- Implement handshake, snapshot hydration, subscriptions to `presence`, `tick`, `agent`, `shutdown`. ✅ snapshot + presence events broadcast to InstancesStore; agent events still to wire to UI if desired.
|
||||||
- Remove immediate `health/system-presence` fetch on connect. ✅ presence hydrated from snapshot; periodic refresh kept as fallback.
|
- Remove immediate `health/system-presence` fetch on connect. ✅ presence hydrated from snapshot; periodic refresh kept as fallback.
|
||||||
- Handle connect failures (`res ok:false`) and retry with backoff if version/token mismatched. ✅ macOS GatewayChannel reconnects with exponential backoff.
|
- Handle connect failures (`res ok:false`) and retry with backoff if version/token mismatched. ✅ macOS GatewayChannel reconnects with exponential backoff.
|
||||||
|
|||||||
Reference in New Issue
Block a user