@formthefog/stratus 2026.2.20 → 2026.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/sentinel/action.yml +100 -0
- package/.github/sentinel/dist/codebase.d.ts +3 -0
- package/.github/sentinel/dist/codebase.d.ts.map +1 -0
- package/.github/sentinel/dist/context.d.ts +6 -0
- package/.github/sentinel/dist/context.d.ts.map +1 -0
- package/.github/sentinel/dist/fixer.d.ts +6 -0
- package/.github/sentinel/dist/fixer.d.ts.map +1 -0
- package/.github/sentinel/dist/index.d.ts +1 -0
- package/.github/sentinel/dist/index.d.ts.map +1 -0
- package/.github/sentinel/dist/index.js +68808 -0
- package/.github/sentinel/dist/index.js.map +1 -0
- package/.github/sentinel/dist/licenses.txt +1152 -0
- package/.github/sentinel/dist/models/anthropic.d.ts +26 -0
- package/.github/sentinel/dist/models/anthropic.d.ts.map +1 -0
- package/.github/sentinel/dist/models/openai.d.ts +26 -0
- package/.github/sentinel/dist/models/openai.d.ts.map +1 -0
- package/.github/sentinel/dist/models/openrouter.d.ts +31 -0
- package/.github/sentinel/dist/models/openrouter.d.ts.map +1 -0
- package/.github/sentinel/dist/models/types.d.ts +37 -0
- package/.github/sentinel/dist/models/types.d.ts.map +1 -0
- package/.github/sentinel/dist/orchestrator.d.ts +3 -0
- package/.github/sentinel/dist/orchestrator.d.ts.map +1 -0
- package/.github/sentinel/dist/policy.d.ts +15 -0
- package/.github/sentinel/dist/policy.d.ts.map +1 -0
- package/.github/sentinel/dist/reporter.d.ts +8 -0
- package/.github/sentinel/dist/reporter.d.ts.map +1 -0
- package/.github/sentinel/dist/responder.d.ts +6 -0
- package/.github/sentinel/dist/responder.d.ts.map +1 -0
- package/.github/sentinel/dist/router.d.ts +2 -0
- package/.github/sentinel/dist/router.d.ts.map +1 -0
- package/.github/sentinel/dist/schemas/config.d.ts +195 -0
- package/.github/sentinel/dist/schemas/config.d.ts.map +1 -0
- package/.github/sentinel/dist/schemas/fix.d.ts +130 -0
- package/.github/sentinel/dist/schemas/fix.d.ts.map +1 -0
- package/.github/sentinel/dist/schemas/review.d.ts +275 -0
- package/.github/sentinel/dist/schemas/review.d.ts.map +1 -0
- package/.github/sentinel/dist/sourcemap-register.js +1 -0
- package/.github/sentinel/dist/subway.d.ts +31 -0
- package/.github/sentinel/dist/subway.d.ts.map +1 -0
- package/.github/sentinel/dist/types.d.ts +210 -0
- package/.github/sentinel/dist/types.d.ts.map +1 -0
- package/.github/sentinel/package-lock.json +2389 -0
- package/.github/sentinel/package.json +29 -0
- package/.github/sentinel/src/codebase.ts +265 -0
- package/.github/sentinel/src/context.ts +182 -0
- package/.github/sentinel/src/fixer.ts +353 -0
- package/.github/sentinel/src/index.ts +263 -0
- package/.github/sentinel/src/models/anthropic.ts +244 -0
- package/.github/sentinel/src/models/openai.ts +242 -0
- package/.github/sentinel/src/models/openrouter.ts +319 -0
- package/.github/sentinel/src/models/types.ts +35 -0
- package/.github/sentinel/src/orchestrator.ts +287 -0
- package/.github/sentinel/src/policy.ts +133 -0
- package/.github/sentinel/src/reporter.ts +666 -0
- package/.github/sentinel/src/responder.ts +156 -0
- package/.github/sentinel/src/router.ts +308 -0
- package/.github/sentinel/src/schemas/config.ts +84 -0
- package/.github/sentinel/src/schemas/fix.ts +44 -0
- package/.github/sentinel/src/schemas/review.ts +73 -0
- package/.github/sentinel/src/subway.ts +250 -0
- package/.github/sentinel/src/types.ts +234 -0
- package/.github/sentinel/tsconfig.json +19 -0
- package/.github/sentinel.yml +34 -0
- package/.github/workflows/publish.yml +28 -0
- package/.github/workflows/sentinel.yml +55 -0
- package/README.md +90 -41
- package/SECURITY.md +85 -0
- package/TROUBLESHOOTING.md +2 -2
- package/index.ts +219 -109
- package/openclaw.plugin.json +50 -26
- package/package.json +1 -1
- package/skills/stratus-info/SKILL.md +70 -10
- package/src/client.ts +78 -18
- package/src/config.ts +29 -8
- package/src/setup.ts +53 -61
- package/src/types.ts +11 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stratus-info
|
|
3
3
|
description: Knowledge base about Stratus X1-AC world model system
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
author: Stratus Team
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -25,10 +25,12 @@ This is a **hybrid architecture** with two capabilities:
|
|
|
25
25
|
- Predicts compressed representations, not raw outputs
|
|
26
26
|
- Enables planning by simulating action sequences before executing
|
|
27
27
|
|
|
28
|
-
### 2. Policy Head (Action Selector): "What action achieves this goal?"
|
|
28
|
+
### 2. Policy Head v3 (Action Selector): "What action achieves this goal?"
|
|
29
|
+
- 94.41% masked accuracy — brain-guided action sequencing
|
|
29
30
|
- Predicts the best action given current state + goal state
|
|
31
|
+
- Returns `brain_confidence` and `brain_goal_proximity` scores
|
|
30
32
|
- Fast decision-making for known patterns
|
|
31
|
-
-
|
|
33
|
+
- Low confidence → escalate to LLM
|
|
32
34
|
|
|
33
35
|
**Key Innovation:**
|
|
34
36
|
Instead of just guessing the next action, Stratus can **simulate the outcome of multiple actions** and pick the one most likely to achieve the goal.
|
|
@@ -44,6 +46,7 @@ Agents learn from each other in real-time:
|
|
|
44
46
|
- When one agent discovers an effective approach, that knowledge flows to all agents
|
|
45
47
|
- **Continuous learning**: successful patterns get canonicalized and fine-tuned into the model
|
|
46
48
|
- **Domain-specific fine-tunes** (e-commerce, dev tools, research, etc.) share learnings back to the base model
|
|
49
|
+
- **Hierarchical tool architecture**: Brain handles sub-agent routing (orchestrator → sub-agents with specialized tool sets)
|
|
47
50
|
|
|
48
51
|
It's like a hive mind for AI agents — practical distributed learning at scale.
|
|
49
52
|
|
|
@@ -78,10 +81,35 @@ see → simulate outcomes → pick best action → act
|
|
|
78
81
|
|
|
79
82
|
---
|
|
80
83
|
|
|
84
|
+
## Authentication & Keys
|
|
85
|
+
|
|
86
|
+
### Zero-Config (Formation Pool)
|
|
87
|
+
No API key needed. Formation holds pooled OpenRouter keys as a universal fallback.
|
|
88
|
+
- 25% markup on usage
|
|
89
|
+
- Instant access to all 2050+ models on day 0
|
|
90
|
+
- No setup required
|
|
91
|
+
|
|
92
|
+
### BYOK (Bring Your Own Key)
|
|
93
|
+
Set `STRATUS_API_KEY` to bypass the Formation pool (no markup).
|
|
94
|
+
- Keys must start with `stratus_sk_`
|
|
95
|
+
- Get yours at https://stratus.run
|
|
96
|
+
|
|
97
|
+
### Inline Provider Keys
|
|
98
|
+
Pass provider keys per-request for direct BYOK passthrough:
|
|
99
|
+
- `openai_key` — OpenAI direct
|
|
100
|
+
- `anthropic_key` — Anthropic direct
|
|
101
|
+
- `gemini_key` — Google Gemini direct (also sent as `X-Google-Key` header)
|
|
102
|
+
- Three-tier priority: headers > body > vault
|
|
103
|
+
|
|
104
|
+
Responses include `key_source: "user"` or `key_source: "formation"` so you always know which path was used.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
81
108
|
## Available Models
|
|
82
109
|
|
|
83
|
-
Stratus provides **
|
|
110
|
+
Stratus provides **2050+ models** dynamically discovered via OpenRouter at startup.
|
|
84
111
|
|
|
112
|
+
Model format:
|
|
85
113
|
```
|
|
86
114
|
stratus-x1ac-{size}-{llm}
|
|
87
115
|
```
|
|
@@ -89,9 +117,10 @@ stratus-x1ac-{size}-{llm}
|
|
|
89
117
|
**Sizes:** `small`, `base`, `large`, `xl`, `huge`
|
|
90
118
|
|
|
91
119
|
**Recommended LLMs:**
|
|
92
|
-
- `claude-sonnet-4-5`
|
|
93
|
-
- `gpt-4o`
|
|
94
|
-
- `claude-haiku-4-5`
|
|
120
|
+
- `claude-sonnet-4-5` — Claude 4.5 Sonnet (recommended)
|
|
121
|
+
- `gpt-4o` — GPT-4 Optimized
|
|
122
|
+
- `claude-haiku-4-5` — Fast, cost-effective
|
|
123
|
+
- `gemini-2.0-flash` — High context, fast
|
|
95
124
|
|
|
96
125
|
**Example:**
|
|
97
126
|
```bash
|
|
@@ -99,6 +128,8 @@ openclaw agent "Plan a multi-step research task" \
|
|
|
99
128
|
--model stratus/stratus-x1ac-base-claude-sonnet-4-5
|
|
100
129
|
```
|
|
101
130
|
|
|
131
|
+
Use `/stratus models` to fetch the full live list from the API.
|
|
132
|
+
|
|
102
133
|
---
|
|
103
134
|
|
|
104
135
|
## Available Tools
|
|
@@ -121,7 +152,7 @@ Generate 768-dimensional semantic state embeddings.
|
|
|
121
152
|
```
|
|
122
153
|
|
|
123
154
|
### `stratus_rollout`
|
|
124
|
-
Multi-step action sequence planning.
|
|
155
|
+
Multi-step action sequence planning via Policy Head v3.
|
|
125
156
|
|
|
126
157
|
**Use cases:**
|
|
127
158
|
- Task decomposition
|
|
@@ -129,6 +160,12 @@ Multi-step action sequence planning.
|
|
|
129
160
|
- Goal-oriented reasoning
|
|
130
161
|
- Multi-step workflows
|
|
131
162
|
|
|
163
|
+
**Response fields:**
|
|
164
|
+
- `steps` — ordered action sequence
|
|
165
|
+
- `metadata.brain_confidence` — how confident the brain is in the plan
|
|
166
|
+
- `metadata.brain_goal_proximity` — estimated closeness to goal state
|
|
167
|
+
- `metadata.key_source` — "user" or "formation"
|
|
168
|
+
|
|
132
169
|
**Example:**
|
|
133
170
|
```typescript
|
|
134
171
|
{
|
|
@@ -162,6 +199,27 @@ const response = await openai.chat.completions.create({
|
|
|
162
199
|
|
|
163
200
|
Stratus handles planning, then routes execution to the specified LLM (GPT-4o, Claude, etc.).
|
|
164
201
|
|
|
202
|
+
Non-Stratus models (e.g. raw `gpt-4o`) bypass the world model pipeline entirely (LLM passthrough).
|
|
203
|
+
|
|
204
|
+
Tool limit: **1024 tools per request** (raised from 100).
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## SDKs
|
|
209
|
+
|
|
210
|
+
- **TypeScript**: This OpenClaw plugin (`@formthefog/stratus`)
|
|
211
|
+
- **Python**: `pip install stratus-sdk-py` (v0.0.6, full TS SDK parity, 76 tests)
|
|
212
|
+
- **Pi Agent**: `pi-formation` package (7 curated X1-AC models for Pi coding agent)
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Billing
|
|
217
|
+
|
|
218
|
+
- **Signup credits**: 200 credits (20K units) for new users
|
|
219
|
+
- **Saved cards**: Stripe-backed auto top-up when balance is low
|
|
220
|
+
- **Subscriptions**: Monthly credit bundles (starter/pro/enterprise) — 25% more credits vs one-time
|
|
221
|
+
- **Formation pool**: 25% markup on pooled key usage; BYOK users pay no markup
|
|
222
|
+
|
|
165
223
|
---
|
|
166
224
|
|
|
167
225
|
## Common Misconceptions
|
|
@@ -171,6 +229,7 @@ Stratus handles planning, then routes execution to the specified LLM (GPT-4o, Cl
|
|
|
171
229
|
| "Stratus is just Claude with extended reasoning" | Stratus is a world model that predicts action consequences + collective learning network |
|
|
172
230
|
| "It's a language model" | It's a hybrid architecture (world model + policy head) that routes to LLMs for execution |
|
|
173
231
|
| "It's an LLM wrapper" | It's a JEPA-based predictive system with its own training and inference pipeline |
|
|
232
|
+
| "You need an API key" | Formation pool provides zero-config access; BYOK is optional |
|
|
174
233
|
|
|
175
234
|
---
|
|
176
235
|
|
|
@@ -187,10 +246,10 @@ For full technical details, see:
|
|
|
187
246
|
|
|
188
247
|
1. **Install plugin:**
|
|
189
248
|
```bash
|
|
190
|
-
openclaw plugins install @
|
|
249
|
+
openclaw plugins install @formthefog/stratus
|
|
191
250
|
```
|
|
192
251
|
|
|
193
|
-
2. **Set API key:**
|
|
252
|
+
2. **(Optional) Set API key for BYOK:**
|
|
194
253
|
```bash
|
|
195
254
|
export STRATUS_API_KEY=stratus_sk_your_key_here
|
|
196
255
|
```
|
|
@@ -215,6 +274,7 @@ For full technical details, see:
|
|
|
215
274
|
- Research workflows
|
|
216
275
|
- Complex decision-making with uncertain outcomes
|
|
217
276
|
- Tasks requiring "what-if" simulation
|
|
277
|
+
- Large tool sets (up to 1024 tools)
|
|
218
278
|
|
|
219
279
|
**Overkill for:**
|
|
220
280
|
- Simple Q&A
|
package/src/client.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
StratusEmbeddingsRequest,
|
|
3
3
|
StratusEmbeddingsResponse,
|
|
4
|
+
StratusInlineKeys,
|
|
4
5
|
StratusPluginConfig,
|
|
5
6
|
StratusRolloutRequest,
|
|
6
7
|
StratusRolloutResponse,
|
|
@@ -10,44 +11,74 @@ import type {
|
|
|
10
11
|
* SECURITY MANIFEST
|
|
11
12
|
*
|
|
12
13
|
* Environment Variables Accessed:
|
|
13
|
-
* - STRATUS_API_KEY: User's Stratus API key (optional
|
|
14
|
+
* - STRATUS_API_KEY: User's Stratus API key (optional — Formation pool used as fallback)
|
|
15
|
+
* - OPENAI_API_KEY: Optional inline key for BYOK passthrough
|
|
16
|
+
* - ANTHROPIC_API_KEY: Optional inline key for BYOK passthrough
|
|
17
|
+
* - GOOGLE_API_KEY: Optional inline key for BYOK passthrough (also sent as X-Google-Key header)
|
|
14
18
|
*
|
|
15
19
|
* Network Endpoints:
|
|
16
20
|
* - https://api.stratus.run/v1/embeddings (POST)
|
|
17
21
|
* - https://api.stratus.run/v1/rollout (POST)
|
|
22
|
+
* - https://api.stratus.run/v1/models (GET)
|
|
18
23
|
*
|
|
19
24
|
* Data Transmitted:
|
|
20
|
-
* - Authorization header: Bearer token (Stratus API key)
|
|
21
|
-
* -
|
|
25
|
+
* - Authorization header: Bearer token (Stratus API key, when provided)
|
|
26
|
+
* - X-Google-Key header: Google API key (when provided)
|
|
27
|
+
* - Request body: User-provided text, goals, parameters, and optional inline LLM keys
|
|
22
28
|
*
|
|
23
29
|
* Data Retention:
|
|
24
30
|
* - All data sent to Stratus API per their privacy policy: https://stratus.run/privacy
|
|
25
31
|
* - No local storage of credentials beyond process memory
|
|
26
32
|
*
|
|
27
33
|
* Security:
|
|
28
|
-
* - API key validated (must start with 'stratus_sk_')
|
|
34
|
+
* - API key validated when present (must start with 'stratus_sk_')
|
|
35
|
+
* - Keyless operation uses Formation pooled keys (25% markup)
|
|
29
36
|
* - HTTPS-only connections
|
|
30
37
|
* - Keys never logged or persisted to disk by this plugin
|
|
31
38
|
*/
|
|
32
39
|
|
|
33
40
|
export interface StratusClientConfig {
|
|
34
|
-
apiKey
|
|
41
|
+
apiKey?: string;
|
|
35
42
|
baseUrl: string;
|
|
43
|
+
inlineKeys?: StratusInlineKeys;
|
|
36
44
|
}
|
|
37
45
|
|
|
38
46
|
export class StratusClient {
|
|
39
47
|
constructor(private config: StratusClientConfig) {}
|
|
40
48
|
|
|
49
|
+
private buildHeaders(): Record<string, string> {
|
|
50
|
+
const headers: Record<string, string> = {
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
if (this.config.apiKey) {
|
|
55
|
+
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (this.config.inlineKeys?.gemini_key) {
|
|
59
|
+
headers["X-Google-Key"] = this.config.inlineKeys.gemini_key;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return headers;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private buildInlineKeyBody(): Record<string, string> {
|
|
66
|
+
const body: Record<string, string> = {};
|
|
67
|
+
if (this.config.inlineKeys?.openai_key) body.openai_key = this.config.inlineKeys.openai_key;
|
|
68
|
+
if (this.config.inlineKeys?.anthropic_key) body.anthropic_key = this.config.inlineKeys.anthropic_key;
|
|
69
|
+
if (this.config.inlineKeys?.gemini_key) body.gemini_key = this.config.inlineKeys.gemini_key;
|
|
70
|
+
return body;
|
|
71
|
+
}
|
|
72
|
+
|
|
41
73
|
private async request<T>(endpoint: string, body: unknown): Promise<T> {
|
|
42
74
|
const url = `${this.config.baseUrl}${endpoint}`;
|
|
75
|
+
const inlineKeys = this.buildInlineKeyBody();
|
|
76
|
+
const mergedBody = { ...(body as Record<string, unknown>), ...inlineKeys };
|
|
43
77
|
|
|
44
78
|
const response = await fetch(url, {
|
|
45
79
|
method: "POST",
|
|
46
|
-
headers:
|
|
47
|
-
|
|
48
|
-
"Content-Type": "application/json",
|
|
49
|
-
},
|
|
50
|
-
body: JSON.stringify(body),
|
|
80
|
+
headers: this.buildHeaders(),
|
|
81
|
+
body: JSON.stringify(mergedBody),
|
|
51
82
|
});
|
|
52
83
|
|
|
53
84
|
if (!response.ok) {
|
|
@@ -76,23 +107,52 @@ export class StratusClient {
|
|
|
76
107
|
return_intermediate: params.return_intermediate ?? true,
|
|
77
108
|
});
|
|
78
109
|
}
|
|
110
|
+
|
|
111
|
+
async listModels(): Promise<{ object: string; data: Array<{ id: string; object: string; created: number; owned_by: string }> }> {
|
|
112
|
+
const url = `${this.config.baseUrl}/v1/models`;
|
|
113
|
+
const headers: Record<string, string> = {};
|
|
114
|
+
if (this.config.apiKey) {
|
|
115
|
+
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const response = await fetch(url, {
|
|
119
|
+
method: "GET",
|
|
120
|
+
headers,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (!response.ok) {
|
|
124
|
+
const errorText = await response.text();
|
|
125
|
+
throw new Error(
|
|
126
|
+
`Stratus API error (${response.status}): ${errorText || response.statusText}`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return response.json();
|
|
131
|
+
}
|
|
79
132
|
}
|
|
80
133
|
|
|
81
134
|
export function createStratusClient(config: StratusPluginConfig | undefined): StratusClient {
|
|
82
135
|
const apiKey = config?.apiKey || process.env.STRATUS_API_KEY;
|
|
83
136
|
const baseUrl = config?.baseUrl || "https://api.stratus.run";
|
|
84
137
|
|
|
85
|
-
if (!apiKey) {
|
|
86
|
-
throw new Error(
|
|
87
|
-
"Stratus API key not configured. Set STRATUS_API_KEY env var or plugins.stratus.apiKey in config.",
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (!apiKey.startsWith("stratus_sk_")) {
|
|
138
|
+
if (apiKey && !apiKey.startsWith("stratus_sk_")) {
|
|
92
139
|
throw new Error(
|
|
93
140
|
`Invalid Stratus API key format. Expected key starting with 'stratus_sk_', got '${apiKey.substring(0, 10)}...'`,
|
|
94
141
|
);
|
|
95
142
|
}
|
|
96
143
|
|
|
97
|
-
|
|
144
|
+
const inlineKeys: StratusInlineKeys = {
|
|
145
|
+
...config?.inlineKeys,
|
|
146
|
+
openai_key: config?.inlineKeys?.openai_key || process.env.OPENAI_API_KEY,
|
|
147
|
+
anthropic_key: config?.inlineKeys?.anthropic_key || process.env.ANTHROPIC_API_KEY,
|
|
148
|
+
gemini_key: config?.inlineKeys?.gemini_key || process.env.GOOGLE_API_KEY,
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const hasAnyInlineKey = inlineKeys.openai_key || inlineKeys.anthropic_key || inlineKeys.gemini_key;
|
|
152
|
+
|
|
153
|
+
return new StratusClient({
|
|
154
|
+
apiKey: apiKey || undefined,
|
|
155
|
+
baseUrl,
|
|
156
|
+
inlineKeys: hasAnyInlineKey ? inlineKeys : undefined,
|
|
157
|
+
});
|
|
98
158
|
}
|
package/src/config.ts
CHANGED
|
@@ -3,12 +3,18 @@ import type { StratusPluginConfig } from "./types.js";
|
|
|
3
3
|
|
|
4
4
|
export const StratusConfigSchema: OpenClawPluginConfigSchema = {
|
|
5
5
|
parse(value: unknown): StratusPluginConfig {
|
|
6
|
-
const
|
|
6
|
+
const entry =
|
|
7
7
|
value && typeof value === "object" && !Array.isArray(value)
|
|
8
8
|
? (value as Record<string, unknown>)
|
|
9
9
|
: {};
|
|
10
10
|
|
|
11
|
-
const enabled = typeof
|
|
11
|
+
const enabled = typeof entry.enabled === "boolean" ? entry.enabled : true;
|
|
12
|
+
|
|
13
|
+
const raw =
|
|
14
|
+
entry.config && typeof entry.config === "object" && !Array.isArray(entry.config)
|
|
15
|
+
? (entry.config as Record<string, unknown>)
|
|
16
|
+
: {};
|
|
17
|
+
|
|
12
18
|
const apiKey = typeof raw.apiKey === "string" ? raw.apiKey : process.env.STRATUS_API_KEY;
|
|
13
19
|
const baseUrl = typeof raw.baseUrl === "string" ? raw.baseUrl : "https://api.stratus.run";
|
|
14
20
|
|
|
@@ -37,10 +43,22 @@ export const StratusConfigSchema: OpenClawPluginConfigSchema = {
|
|
|
37
43
|
? (tools.rollout as Record<string, unknown>)
|
|
38
44
|
: {};
|
|
39
45
|
|
|
46
|
+
const inlineKeysRaw =
|
|
47
|
+
raw.inlineKeys && typeof raw.inlineKeys === "object" && !Array.isArray(raw.inlineKeys)
|
|
48
|
+
? (raw.inlineKeys as Record<string, unknown>)
|
|
49
|
+
: {};
|
|
50
|
+
|
|
51
|
+
const inlineKeys = {
|
|
52
|
+
openai_key: typeof inlineKeysRaw.openai_key === "string" ? inlineKeysRaw.openai_key : undefined,
|
|
53
|
+
anthropic_key: typeof inlineKeysRaw.anthropic_key === "string" ? inlineKeysRaw.anthropic_key : undefined,
|
|
54
|
+
gemini_key: typeof inlineKeysRaw.gemini_key === "string" ? inlineKeysRaw.gemini_key : undefined,
|
|
55
|
+
};
|
|
56
|
+
|
|
40
57
|
return {
|
|
41
58
|
enabled,
|
|
42
59
|
apiKey,
|
|
43
60
|
baseUrl,
|
|
61
|
+
inlineKeys,
|
|
44
62
|
provider: {
|
|
45
63
|
enabled: providerEnabled,
|
|
46
64
|
defaultModel,
|
|
@@ -57,14 +75,17 @@ export const StratusConfigSchema: OpenClawPluginConfigSchema = {
|
|
|
57
75
|
},
|
|
58
76
|
uiHints: {
|
|
59
77
|
enabled: { label: "Enabled" },
|
|
60
|
-
apiKey: { label: "API Key", sensitive: true },
|
|
61
|
-
baseUrl: { label: "Base URL", placeholder: "https://api.stratus.run" },
|
|
62
|
-
"
|
|
63
|
-
"
|
|
78
|
+
"config.apiKey": { label: "API Key", sensitive: true },
|
|
79
|
+
"config.baseUrl": { label: "Base URL", placeholder: "https://api.stratus.run" },
|
|
80
|
+
"config.inlineKeys.openai_key": { label: "OpenAI Key (BYOK)", sensitive: true },
|
|
81
|
+
"config.inlineKeys.anthropic_key": { label: "Anthropic Key (BYOK)", sensitive: true },
|
|
82
|
+
"config.inlineKeys.gemini_key": { label: "Google Gemini Key (BYOK)", sensitive: true },
|
|
83
|
+
"config.provider.enabled": { label: "Provider Enabled" },
|
|
84
|
+
"config.provider.defaultModel": {
|
|
64
85
|
label: "Default Model",
|
|
65
86
|
placeholder: "stratus-x1ac-base-claude-sonnet-4-5",
|
|
66
87
|
},
|
|
67
|
-
"tools.embeddings.enabled": { label: "Embeddings Tool Enabled" },
|
|
68
|
-
"tools.rollout.enabled": { label: "Rollout Tool Enabled" },
|
|
88
|
+
"config.tools.embeddings.enabled": { label: "Embeddings Tool Enabled" },
|
|
89
|
+
"config.tools.rollout.enabled": { label: "Rollout Tool Enabled" },
|
|
69
90
|
},
|
|
70
91
|
};
|
package/src/setup.ts
CHANGED
|
@@ -18,31 +18,28 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
|
|
|
18
18
|
const details: string[] = [];
|
|
19
19
|
|
|
20
20
|
try {
|
|
21
|
-
// Step 1: Check for existing API key
|
|
22
21
|
const apiKey = process.env.STRATUS_API_KEY;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
22
|
+
const usingFormationPool = !apiKey;
|
|
23
|
+
|
|
24
|
+
if (apiKey) {
|
|
25
|
+
if (!apiKey.startsWith("stratus_sk_")) {
|
|
26
|
+
return {
|
|
27
|
+
success: false,
|
|
28
|
+
message: "Invalid STRATUS_API_KEY format",
|
|
29
|
+
details: [
|
|
30
|
+
"API key must start with 'stratus_sk_'",
|
|
31
|
+
"",
|
|
32
|
+
"Get your API key at: https://stratus.run",
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
details.push("✓ Using STRATUS_API_KEY from environment (BYOK — no markup)");
|
|
37
|
+
} else {
|
|
38
|
+
details.push("✓ No API key found — using Formation pooled keys (zero-config)");
|
|
39
|
+
details.push(" ℹ Formation pool applies a 25% markup on usage");
|
|
40
|
+
details.push(" 💡 Set STRATUS_API_KEY for BYOK (no markup)");
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
details.push("✓ Using STRATUS_API_KEY from environment");
|
|
44
|
-
|
|
45
|
-
// Paths
|
|
46
43
|
const homeDir = os.homedir();
|
|
47
44
|
const openclawConfig = path.join(homeDir, ".openclaw", "openclaw.json");
|
|
48
45
|
const authProfiles = path.join(
|
|
@@ -54,25 +51,18 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
|
|
|
54
51
|
"auth-profiles.json"
|
|
55
52
|
);
|
|
56
53
|
|
|
57
|
-
// Step 2: Update OpenClaw config
|
|
58
54
|
details.push("🔧 Updating OpenClaw configuration...");
|
|
59
55
|
|
|
60
56
|
if (fs.existsSync(openclawConfig)) {
|
|
61
|
-
// Backup
|
|
62
57
|
const backupPath = `${openclawConfig}.backup-${Date.now()}`;
|
|
63
58
|
fs.copyFileSync(openclawConfig, backupPath);
|
|
64
59
|
details.push(` 📦 Created backup: ${path.basename(backupPath)}`);
|
|
65
60
|
|
|
66
|
-
// Read and update config
|
|
67
61
|
const config = JSON.parse(fs.readFileSync(openclawConfig, "utf-8"));
|
|
68
62
|
|
|
69
|
-
|
|
70
|
-
if (!config.models) {
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
if (!config.models.providers) {
|
|
74
|
-
config.models.providers = {};
|
|
75
|
-
}
|
|
63
|
+
if (!config.models) config.models = {};
|
|
64
|
+
if (!config.models.providers) config.models.providers = {};
|
|
65
|
+
|
|
76
66
|
if (!config.models.providers.stratus) {
|
|
77
67
|
config.models.providers.stratus = {
|
|
78
68
|
baseUrl: "https://api.stratus.run/v1",
|
|
@@ -94,24 +84,11 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
|
|
|
94
84
|
details.push(" ✓ Stratus provider already configured");
|
|
95
85
|
}
|
|
96
86
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (!config.agents.defaults) config.agents.defaults = {};
|
|
101
|
-
if (!config.agents.defaults.models) config.agents.defaults.models = {};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (!config.agents.defaults.models["stratus/stratus-x1ac-base-claude-sonnet-4-5"]) {
|
|
105
|
-
config.agents.defaults.models["stratus/stratus-x1ac-base-claude-sonnet-4-5"] = {
|
|
106
|
-
alias: "stratus",
|
|
107
|
-
params: {},
|
|
108
|
-
};
|
|
109
|
-
details.push(" ✓ Added model alias 'stratus'");
|
|
110
|
-
} else {
|
|
111
|
-
details.push(" ✓ Model alias already configured");
|
|
87
|
+
if (config.agents?.defaults?.models?.["stratus/stratus-x1ac-base-claude-sonnet-4-5"]) {
|
|
88
|
+
delete config.agents.defaults.models["stratus/stratus-x1ac-base-claude-sonnet-4-5"];
|
|
89
|
+
details.push(" ✓ Removed restrictive model alias (allows all Stratus models)");
|
|
112
90
|
}
|
|
113
91
|
|
|
114
|
-
// Write updated config
|
|
115
92
|
fs.writeFileSync(openclawConfig, JSON.stringify(config, null, 2));
|
|
116
93
|
} else {
|
|
117
94
|
return {
|
|
@@ -125,7 +102,6 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
|
|
|
125
102
|
};
|
|
126
103
|
}
|
|
127
104
|
|
|
128
|
-
// Step 3: Update auth profiles
|
|
129
105
|
details.push("🔑 Configuring authentication...");
|
|
130
106
|
|
|
131
107
|
const authDir = path.dirname(authProfiles);
|
|
@@ -135,14 +111,10 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
|
|
|
135
111
|
|
|
136
112
|
let authConfig: any;
|
|
137
113
|
if (fs.existsSync(authProfiles)) {
|
|
138
|
-
// Backup
|
|
139
114
|
const backupPath = `${authProfiles}.backup-${Date.now()}`;
|
|
140
115
|
fs.copyFileSync(authProfiles, backupPath);
|
|
141
|
-
|
|
142
|
-
// Update existing
|
|
143
116
|
authConfig = JSON.parse(fs.readFileSync(authProfiles, "utf-8"));
|
|
144
117
|
} else {
|
|
145
|
-
// Create new
|
|
146
118
|
authConfig = {
|
|
147
119
|
version: 1,
|
|
148
120
|
profiles: {},
|
|
@@ -151,16 +123,26 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
|
|
|
151
123
|
};
|
|
152
124
|
}
|
|
153
125
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
126
|
+
if (apiKey) {
|
|
127
|
+
authConfig.profiles["stratus:default"] = {
|
|
128
|
+
type: "api_key",
|
|
129
|
+
provider: "stratus",
|
|
130
|
+
key: apiKey,
|
|
131
|
+
};
|
|
132
|
+
authConfig.lastGood.stratus = "stratus:default";
|
|
133
|
+
details.push(" ✓ Updated auth profile (BYOK)");
|
|
134
|
+
} else {
|
|
135
|
+
authConfig.profiles["stratus:formation-pool"] = {
|
|
136
|
+
type: "formation_pool",
|
|
137
|
+
provider: "stratus",
|
|
138
|
+
};
|
|
139
|
+
authConfig.lastGood.stratus = "stratus:formation-pool";
|
|
140
|
+
details.push(" ✓ Configured Formation pool auth (zero-config)");
|
|
141
|
+
}
|
|
161
142
|
|
|
162
143
|
fs.writeFileSync(authProfiles, JSON.stringify(authConfig, null, 2));
|
|
163
|
-
|
|
144
|
+
|
|
145
|
+
const modeLabel = usingFormationPool ? "Formation pool (zero-config)" : "BYOK (no markup)";
|
|
164
146
|
|
|
165
147
|
return {
|
|
166
148
|
success: true,
|
|
@@ -168,6 +150,8 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
|
|
|
168
150
|
details: [
|
|
169
151
|
...details,
|
|
170
152
|
"",
|
|
153
|
+
`🔒 Auth mode: ${modeLabel}`,
|
|
154
|
+
"",
|
|
171
155
|
"🎯 Next steps:",
|
|
172
156
|
" 1. Restart gateway: openclaw gateway stop && openclaw gateway install",
|
|
173
157
|
" 2. Verify: openclaw models list | grep stratus",
|
|
@@ -176,6 +160,14 @@ export async function setupStratus(prompter?: any): Promise<SetupResult> {
|
|
|
176
160
|
"📚 Available tools:",
|
|
177
161
|
" • stratus_embeddings - Generate semantic embeddings",
|
|
178
162
|
" • stratus_rollout - Multi-step task planning",
|
|
163
|
+
...(usingFormationPool
|
|
164
|
+
? [
|
|
165
|
+
"",
|
|
166
|
+
"💡 To remove the 25% Formation markup, set your own key:",
|
|
167
|
+
" export STRATUS_API_KEY=stratus_sk_your_key_here",
|
|
168
|
+
" Then re-run /stratus setup",
|
|
169
|
+
]
|
|
170
|
+
: []),
|
|
179
171
|
],
|
|
180
172
|
};
|
|
181
173
|
} catch (error) {
|
package/src/types.ts
CHANGED
|
@@ -38,13 +38,24 @@ export interface StratusRolloutResponse {
|
|
|
38
38
|
metadata?: {
|
|
39
39
|
model: string;
|
|
40
40
|
duration_ms?: number;
|
|
41
|
+
brain_confidence?: number;
|
|
42
|
+
brain_goal_proximity?: number;
|
|
43
|
+
key_source?: "user" | "formation";
|
|
44
|
+
formation_markup_applied?: number;
|
|
41
45
|
};
|
|
42
46
|
}
|
|
43
47
|
|
|
48
|
+
export interface StratusInlineKeys {
|
|
49
|
+
openai_key?: string;
|
|
50
|
+
anthropic_key?: string;
|
|
51
|
+
gemini_key?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
44
54
|
export interface StratusPluginConfig {
|
|
45
55
|
enabled?: boolean;
|
|
46
56
|
apiKey?: string;
|
|
47
57
|
baseUrl?: string;
|
|
58
|
+
inlineKeys?: StratusInlineKeys;
|
|
48
59
|
provider?: {
|
|
49
60
|
enabled?: boolean;
|
|
50
61
|
defaultModel?: string;
|