Skip to content

Commit a90ee61

Browse files
committed
Merge remote-tracking branch 'upstream/main' into spinen/msteams-multi-account
2 parents b1ec741 + 90e4658 commit a90ee61

91 files changed

Lines changed: 4462 additions & 220 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift

Lines changed: 158 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,20 @@ public enum EnvironmentStatus: String, Codable, Sendable {
3737
case error = "error"
3838
}
3939

40+
public enum WorkerEnvironmentState: String, Codable, Sendable {
41+
case requested = "requested"
42+
case provisioning = "provisioning"
43+
case bootstrapping = "bootstrapping"
44+
case ready = "ready"
45+
case attached = "attached"
46+
case idle = "idle"
47+
case draining = "draining"
48+
case destroying = "destroying"
49+
case destroyed = "destroyed"
50+
case failed = "failed"
51+
case orphaned = "orphaned"
52+
}
53+
4054
public enum NodePresenceAliveReason: String, Codable, Sendable {
4155
case background = "background"
4256
case silentPush = "silent_push"
@@ -648,25 +662,162 @@ public struct GatewaySuspendResumeResult: Codable, Sendable {
648662
}
649663
}
650664

665+
public struct WorkerEnvironmentMetadata: Codable, Sendable {
666+
public let providerid: String
667+
public let leaseid: String?
668+
public let state: WorkerEnvironmentState
669+
public let agems: Int
670+
public let idlems: Int?
671+
public let attachedsessionids: [String]
672+
673+
public init(
674+
providerid: String,
675+
leaseid: String? = nil,
676+
state: WorkerEnvironmentState,
677+
agems: Int,
678+
idlems: Int? = nil,
679+
attachedsessionids: [String])
680+
{
681+
self.providerid = providerid
682+
self.leaseid = leaseid
683+
self.state = state
684+
self.agems = agems
685+
self.idlems = idlems
686+
self.attachedsessionids = attachedsessionids
687+
}
688+
689+
private enum CodingKeys: String, CodingKey {
690+
case providerid = "providerId"
691+
case leaseid = "leaseId"
692+
case state
693+
case agems = "ageMs"
694+
case idlems = "idleMs"
695+
case attachedsessionids = "attachedSessionIds"
696+
}
697+
}
698+
651699
public struct EnvironmentSummary: Codable, Sendable {
652700
public let id: String
653701
public let type: String
654702
public let label: String?
655703
public let status: EnvironmentStatus
656704
public let capabilities: [String]?
705+
public let worker: WorkerEnvironmentMetadata?
706+
707+
public init(
708+
id: String,
709+
type: String,
710+
label: String? = nil,
711+
status: EnvironmentStatus,
712+
capabilities: [String]? = nil,
713+
worker: WorkerEnvironmentMetadata? = nil)
714+
{
715+
self.id = id
716+
self.type = type
717+
self.label = label
718+
self.status = status
719+
self.capabilities = capabilities
720+
self.worker = worker
721+
}
722+
723+
private enum CodingKeys: String, CodingKey {
724+
case id
725+
case type
726+
case label
727+
case status
728+
case capabilities
729+
case worker
730+
}
731+
}
732+
733+
public struct EnvironmentsCreateParams: Codable, Sendable {
734+
public let profileid: String
735+
public let idempotencykey: String
736+
737+
public init(
738+
profileid: String,
739+
idempotencykey: String)
740+
{
741+
self.profileid = profileid
742+
self.idempotencykey = idempotencykey
743+
}
744+
745+
private enum CodingKeys: String, CodingKey {
746+
case profileid = "profileId"
747+
case idempotencykey = "idempotencyKey"
748+
}
749+
}
750+
751+
public struct EnvironmentsCreateResult: Codable, Sendable {
752+
public let id: String
753+
public let type: String
754+
public let label: String?
755+
public let status: EnvironmentStatus
756+
public let capabilities: [String]?
757+
public let worker: WorkerEnvironmentMetadata?
758+
759+
public init(
760+
id: String,
761+
type: String,
762+
label: String? = nil,
763+
status: EnvironmentStatus,
764+
capabilities: [String]? = nil,
765+
worker: WorkerEnvironmentMetadata? = nil)
766+
{
767+
self.id = id
768+
self.type = type
769+
self.label = label
770+
self.status = status
771+
self.capabilities = capabilities
772+
self.worker = worker
773+
}
774+
775+
private enum CodingKeys: String, CodingKey {
776+
case id
777+
case type
778+
case label
779+
case status
780+
case capabilities
781+
case worker
782+
}
783+
}
784+
785+
public struct EnvironmentsDestroyParams: Codable, Sendable {
786+
public let environmentid: String
787+
788+
public init(
789+
environmentid: String)
790+
{
791+
self.environmentid = environmentid
792+
}
793+
794+
private enum CodingKeys: String, CodingKey {
795+
case environmentid = "environmentId"
796+
}
797+
}
798+
799+
public struct EnvironmentsDestroyResult: Codable, Sendable {
800+
public let id: String
801+
public let type: String
802+
public let label: String?
803+
public let status: EnvironmentStatus
804+
public let capabilities: [String]?
805+
public let worker: WorkerEnvironmentMetadata?
657806

658807
public init(
659808
id: String,
660809
type: String,
661810
label: String? = nil,
662811
status: EnvironmentStatus,
663-
capabilities: [String]? = nil)
812+
capabilities: [String]? = nil,
813+
worker: WorkerEnvironmentMetadata? = nil)
664814
{
665815
self.id = id
666816
self.type = type
667817
self.label = label
668818
self.status = status
669819
self.capabilities = capabilities
820+
self.worker = worker
670821
}
671822

672823
private enum CodingKeys: String, CodingKey {
@@ -675,6 +826,7 @@ public struct EnvironmentSummary: Codable, Sendable {
675826
case label
676827
case status
677828
case capabilities
829+
case worker
678830
}
679831
}
680832

@@ -714,19 +866,22 @@ public struct EnvironmentsStatusResult: Codable, Sendable {
714866
public let label: String?
715867
public let status: EnvironmentStatus
716868
public let capabilities: [String]?
869+
public let worker: WorkerEnvironmentMetadata?
717870

718871
public init(
719872
id: String,
720873
type: String,
721874
label: String? = nil,
722875
status: EnvironmentStatus,
723-
capabilities: [String]? = nil)
876+
capabilities: [String]? = nil,
877+
worker: WorkerEnvironmentMetadata? = nil)
724878
{
725879
self.id = id
726880
self.type = type
727881
self.label = label
728882
self.status = status
729883
self.capabilities = capabilities
884+
self.worker = worker
730885
}
731886

732887
private enum CodingKeys: String, CodingKey {
@@ -735,6 +890,7 @@ public struct EnvironmentsStatusResult: Codable, Sendable {
735890
case label
736891
case status
737892
case capabilities
893+
case worker
738894
}
739895
}
740896

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
400a65d2b531f9fbe10b3521c2298f77573885cf5d04392f993f5f6ba99a47de config-baseline.json
2-
fb142a42f8c4a4a342e2d456369d3985d1900a20eb86ffa2e945990dcf1e5b70 config-baseline.core.json
1+
d9cc6270097d31dd0d6f0a1c3b50d0508da4eb0cf75b4e6d8a5f1b5bb49c56fe config-baseline.json
2+
1f29109a5677fe020fe186f57229fc8e91aa877459b9733c63bb14d30c033143 config-baseline.core.json
33
923a34547068a6fb3230c6a5744b430e81cf2a83e0028b3688d27eb6acd54bc0 config-baseline.channel.json
4-
1e5a26150af9846c045ba42524cfcd0971fd95a77140fd6ffe185851ecf5c3e1 config-baseline.plugin.json
4+
2367b166d5d1f45a6973ad8c25ad2ccabfb22163fb28ba51de91649b7334fe37 config-baseline.plugin.json
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
f2d972dbab87e0d1024c67af392059df3a2528648bfea24f9b57f0d39d93c4ff plugin-sdk-api-baseline.json
2-
eb721c5d62c46280e09f234a1864d07ea6d097ac5916f280792b77fa27ff4740 plugin-sdk-api-baseline.jsonl
1+
96c016603dd132e8a255554825758330b59669a74e66a940b4f489eeffbddbfd plugin-sdk-api-baseline.json
2+
92494514d548bca63dd95b2b72991ba61fca8cd4c33a779da11d246c0b4b5485 plugin-sdk-api-baseline.jsonl

docs/docs_map.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3247,6 +3247,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
32473247
- H3: Multi-instance isolation
32483248
- H3: gateway.tls
32493249
- H3: gateway.reload
3250+
- H2: Cloud worker environments
32503251
- H2: Hooks
32513252
- H3: Gmail integration
32523253
- H2: Canvas plugin host
@@ -4854,6 +4855,32 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
48544855
- Headings:
48554856
- H2: Related
48564857

4858+
## plan/cloud-workers.md
4859+
4860+
- Route: /plan/cloud-workers
4861+
- Headings:
4862+
- H2: Status
4863+
- H2: Problem
4864+
- H2: Goals
4865+
- H2: Non-goals (v1)
4866+
- H2: Prior art (what we copy, what we invert)
4867+
- H2: Architecture decision: loop on the worker, inference through the gateway
4868+
- H2: Components
4869+
- H3: 1. Environment state machine + provider contract
4870+
- H3: 2. Worker bootstrap: install OpenClaw on the box
4871+
- H3: 3. Transport: everything over one SSH connection
4872+
- H3: 4. Worker protocol (dedicated; not the node protocol)
4873+
- H3: 5. Session backend RPCs
4874+
- H3: 6. Workspace sync
4875+
- H3: 7. Placement state machine, sessions, and UI
4876+
- H2: Dispatch and handoff
4877+
- H2: Security model
4878+
- H2: Capacity
4879+
- H2: Lifecycle
4880+
- H2: Configuration surface
4881+
- H2: Milestones
4882+
- H2: Open questions
4883+
48574884
## plan/ui-channels.md
48584885

48594886
- Route: /plan/ui-channels

docs/gateway/configuration-reference.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,52 @@ See [Multiple Gateways](/gateway/multiple-gateways).
732732

733733
---
734734

735+
## Cloud worker environments
736+
737+
Cloud workers are opt-in. If `cloudWorkers` is absent, or `profiles` is empty, OpenClaw accepts no new worker creation. Durable records created earlier still reconcile and remain visible; the existing gateway/node projection is unchanged.
738+
739+
```json5
740+
{
741+
cloudWorkers: {
742+
profiles: {
743+
development: {
744+
provider: "static-ssh",
745+
settings: {
746+
host: "worker.example.test",
747+
port: 22,
748+
user: "openclaw",
749+
keyRef: {
750+
source: "env",
751+
provider: "default",
752+
id: "OPENCLAW_WORKER_SSH_KEY",
753+
},
754+
},
755+
lifetime: {
756+
idleTimeoutMinutes: 60,
757+
maxLifetimeMinutes: 1440,
758+
},
759+
},
760+
},
761+
},
762+
}
763+
```
764+
765+
- `profiles`: named worker profiles with non-empty, whitespace-trimmed ids. Each profile selects a provider registered by a plugin.
766+
- `provider`: non-empty worker provider id. The example uses the `static-ssh` provider from the QA Lab plugin.
767+
- Bundled provider plugins are enabled automatically when selected. External provider plugins must be installed and explicitly enabled (and included in `plugins.allow` when that allowlist is set).
768+
- `settings`: provider-owned bounded JSON. The selected plugin defines and validates its keys; use [SecretRef objects](/gateway/secrets) for secret-bearing values. The static SSH provider requires `host`, `user`, and `keyRef`; `port` defaults to `22`.
769+
- `lifetime.idleTimeoutMinutes`: positive integer minutes stored for later idle-reclamation policy.
770+
- `lifetime.maxLifetimeMinutes`: positive integer minutes stored for later lifecycle policy.
771+
772+
Lifetime values are data only in the first cloud-worker release; automatic enforcement lands with later lifecycle work. Profile changes require a gateway restart.
773+
774+
<Warning>
775+
The `static-ssh` provider is a source-tree QA Lab development harness and is excluded from packaged distributions. A worker running on its shared host can read unrelated host data, so do not use this provider as a production isolation boundary.
776+
Destroying its lease only releases OpenClaw's logical record; it does not stop or clean the host.
777+
</Warning>
778+
779+
---
780+
735781
## Hooks
736782

737783
```json5

docs/gateway/protocol.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,8 @@ methods. Treat this as feature discovery, not a full enumeration of
451451
- `agents.workspace.list` and `agents.workspace.get` (`operator.read`) expose read-only, paginated browsing of an agent's workspace directory for clients in the trusted operator domain described in [Operator scopes](/gateway/operator-scopes). Requests accept workspace-relative paths only; reads stay confined to the realpathed workspace root (symlink and hardlink escapes rejected), size-capped, and limited to UTF-8 text plus common image types (base64). Responses do not expose the host workspace path. There are no write operations in this namespace.
452452
- `tasks.list`, `tasks.get`, and `tasks.cancel` expose the gateway task ledger to SDK and operator clients. See [Task ledger RPCs](#task-ledger-rpcs) below.
453453
- `artifacts.list`, `artifacts.get`, and `artifacts.download` expose transcript-derived artifact summaries and downloads for an explicit `sessionKey`, `runId`, or `taskId` scope. Run and task queries resolve the owning session server-side and only return transcript media with matching provenance; unsafe or local URL sources return unsupported downloads instead of fetching server-side.
454-
- `environments.list` and `environments.status` expose read-only gateway-local and node environment discovery for SDK clients.
454+
- `environments.list` and `environments.status` preserve gateway-local and node environment discovery. Configured cloud workers and durable records left by earlier profiles add `worker` metadata with `providerId`, optional `leaseId`, `state`, `ageMs`, optional `idleMs`, and `attachedSessionIds`. Worker lifecycle states are `requested`, `provisioning`, `bootstrapping`, `ready`, `attached`, `idle`, `draining`, `destroying`, `destroyed`, `failed`, and `orphaned`.
455+
- `environments.create` (`{ profileId, idempotencyKey }`) provisions a worker from a configured plugin provider profile; retries with the same key reuse the durable operation. `environments.destroy` (`{ environmentId }`) requests idempotent teardown of a durable worker environment. Both require `operator.admin`, are control-plane writes, and return the same environment summary shape used by status responses.
455456
- `agent.identity.get` returns the effective assistant identity for an agent or session.
456457
- `agent.wait` waits for a run to finish and returns the terminal snapshot when available.
457458

0 commit comments

Comments
 (0)