@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
package/index.ts
CHANGED
|
@@ -4,6 +4,9 @@ import type { StratusPluginConfig } from "./src/types.js";
|
|
|
4
4
|
import { createStratusClient } from "./src/client.js";
|
|
5
5
|
import { StratusConfigSchema } from "./src/config.js";
|
|
6
6
|
import { setupStratus } from "./src/setup.js";
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
import { homedir } from "os";
|
|
7
10
|
|
|
8
11
|
const PROVIDER_ID = "stratus";
|
|
9
12
|
const PROVIDER_LABEL = "Stratus";
|
|
@@ -26,59 +29,108 @@ function buildModelDefinition(params: {
|
|
|
26
29
|
};
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
for (const size of STRATUS_SIZES) {
|
|
56
|
-
const sizeLabel = size.charAt(0).toUpperCase() + size.slice(1);
|
|
57
|
-
|
|
58
|
-
for (const llm of OPENAI_MODELS) {
|
|
59
|
-
models.push(
|
|
60
|
-
buildModelDefinition({
|
|
61
|
-
id: `stratus-x1ac-${size}-${llm.id}`,
|
|
62
|
-
name: `Stratus X1AC ${sizeLabel} (${llm.name})`,
|
|
63
|
-
contextWindow: llm.context,
|
|
64
|
-
maxTokens: llm.tokens,
|
|
65
|
-
}),
|
|
66
|
-
);
|
|
67
|
-
}
|
|
32
|
+
// Model metadata for naming/context/tokens (fallback if API doesn't provide details)
|
|
33
|
+
const MODEL_METADATA: Record<string, { name: string; context: number; tokens: number }> = {
|
|
34
|
+
"gpt-4o": { name: "GPT-4o", context: 128000, tokens: 8192 },
|
|
35
|
+
"gpt-4o-mini": { name: "GPT-4o Mini", context: 128000, tokens: 8192 },
|
|
36
|
+
"gpt-4-turbo": { name: "GPT-4 Turbo", context: 128000, tokens: 4096 },
|
|
37
|
+
"gpt-4": { name: "GPT-4", context: 8192, tokens: 4096 },
|
|
38
|
+
"gpt-3.5-turbo": { name: "GPT-3.5 Turbo", context: 16385, tokens: 4096 },
|
|
39
|
+
"claude-sonnet-4-6": { name: "Claude 4.6 Sonnet", context: 200000, tokens: 8192 },
|
|
40
|
+
"claude-opus-4-6": { name: "Claude 4.6 Opus", context: 200000, tokens: 8192 },
|
|
41
|
+
"claude-sonnet-4-5": { name: "Claude 4.5 Sonnet", context: 200000, tokens: 8192 },
|
|
42
|
+
"claude-opus-4-5": { name: "Claude 4.5 Opus", context: 200000, tokens: 8192 },
|
|
43
|
+
"claude-haiku-4-5": { name: "Claude 4.5 Haiku", context: 200000, tokens: 8192 },
|
|
44
|
+
"claude-sonnet-4": { name: "Claude 4 Sonnet", context: 200000, tokens: 8192 },
|
|
45
|
+
"claude-opus-4-1": { name: "Claude 4.1 Opus", context: 200000, tokens: 8192 },
|
|
46
|
+
"claude-opus-4": { name: "Claude 4 Opus", context: 200000, tokens: 8192 },
|
|
47
|
+
"claude-3-7-sonnet": { name: "Claude 3.7 Sonnet", context: 200000, tokens: 8192 },
|
|
48
|
+
"claude-3-5-sonnet": { name: "Claude 3.5 Sonnet", context: 200000, tokens: 8192 },
|
|
49
|
+
"claude-3-opus": { name: "Claude 3 Opus", context: 200000, tokens: 4096 },
|
|
50
|
+
"claude-3-sonnet": { name: "Claude 3 Sonnet", context: 200000, tokens: 4096 },
|
|
51
|
+
"claude-3-haiku": { name: "Claude 3 Haiku", context: 200000, tokens: 4096 },
|
|
52
|
+
"gemini-2.0-flash": { name: "Gemini 2.0 Flash", context: 1048576, tokens: 8192 },
|
|
53
|
+
"gemini-1.5-pro": { name: "Gemini 1.5 Pro", context: 2097152, tokens: 8192 },
|
|
54
|
+
"gemini-1.5-flash": { name: "Gemini 1.5 Flash", context: 1048576, tokens: 8192 },
|
|
55
|
+
"gemini-pro": { name: "Gemini Pro", context: 32768, tokens: 8192 },
|
|
56
|
+
};
|
|
68
57
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
58
|
+
function generateModelName(modelId: string): string {
|
|
59
|
+
// Parse model ID like "stratus-x1ac-base-claude-sonnet-4-5"
|
|
60
|
+
const parts = modelId.split("-");
|
|
61
|
+
|
|
62
|
+
// Extract size (small/base/large/xl/huge)
|
|
63
|
+
let size = "";
|
|
64
|
+
let baseModelId = "";
|
|
65
|
+
|
|
66
|
+
if (parts.length >= 4 && parts[0] === "stratus" && parts[1] === "x1ac") {
|
|
67
|
+
size = parts[2];
|
|
68
|
+
baseModelId = parts.slice(3).join("-");
|
|
69
|
+
} else {
|
|
70
|
+
// Fallback for non-standard format
|
|
71
|
+
return modelId;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const sizeLabel = size.charAt(0).toUpperCase() + size.slice(1);
|
|
75
|
+
const metadata = MODEL_METADATA[baseModelId];
|
|
76
|
+
|
|
77
|
+
if (metadata) {
|
|
78
|
+
return `Stratus X1AC ${sizeLabel} (${metadata.name})`;
|
|
79
79
|
}
|
|
80
|
+
|
|
81
|
+
// Fallback: capitalize base model
|
|
82
|
+
return `Stratus X1AC ${sizeLabel} (${baseModelId})`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function generateAllModels(apiKey?: string, baseUrl?: string) {
|
|
86
|
+
const root = (baseUrl || DEFAULT_BASE_URL).replace(/\/v\d+\/?$/, "");
|
|
87
|
+
try {
|
|
88
|
+
const url = `${root}/v1/models`;
|
|
89
|
+
const headers: Record<string, string> = {};
|
|
90
|
+
if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
|
|
91
|
+
|
|
92
|
+
const response = await fetch(url, { headers, signal: AbortSignal.timeout(5000) });
|
|
93
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
94
|
+
const data = await response.json() as { data: Array<{ id: string }> };
|
|
95
|
+
|
|
96
|
+
return data.data.map((model) => {
|
|
97
|
+
const modelId = model.id;
|
|
98
|
+
const baseModelId = modelId.replace(/^stratus-x1ac-(small|base|large|xl|huge)-/, "");
|
|
99
|
+
const metadata = MODEL_METADATA[baseModelId];
|
|
100
|
+
return buildModelDefinition({
|
|
101
|
+
id: modelId,
|
|
102
|
+
name: generateModelName(modelId),
|
|
103
|
+
contextWindow: metadata?.context || 128000,
|
|
104
|
+
maxTokens: metadata?.tokens || 8192,
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error("[stratus] Failed to fetch models from API:", error);
|
|
109
|
+
return [
|
|
110
|
+
buildModelDefinition({
|
|
111
|
+
id: "stratus-x1ac-base-claude-sonnet-4-5",
|
|
112
|
+
name: "Stratus X1AC Base (Claude 4.5 Sonnet)",
|
|
113
|
+
contextWindow: 200000,
|
|
114
|
+
maxTokens: 8192,
|
|
115
|
+
}),
|
|
116
|
+
];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
80
119
|
|
|
81
|
-
|
|
120
|
+
async function updateStoredModels(models: ReturnType<typeof buildModelDefinition>[]) {
|
|
121
|
+
const configPath = join(homedir(), ".openclaw", "openclaw.json");
|
|
122
|
+
if (!existsSync(configPath)) return;
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
126
|
+
const config = JSON.parse(raw);
|
|
127
|
+
if (!config?.models?.providers?.stratus) return;
|
|
128
|
+
|
|
129
|
+
config.models.providers.stratus.models = models;
|
|
130
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
131
|
+
} catch {
|
|
132
|
+
// Silent fail — stale models are better than a crash
|
|
133
|
+
}
|
|
82
134
|
}
|
|
83
135
|
|
|
84
136
|
const stratusPlugin = {
|
|
@@ -98,15 +150,13 @@ const stratusPlugin = {
|
|
|
98
150
|
auth: [
|
|
99
151
|
{
|
|
100
152
|
id: "api-key",
|
|
101
|
-
label: "API Key",
|
|
153
|
+
label: "API Key (optional — Formation pool available)",
|
|
102
154
|
kind: "api_key",
|
|
103
155
|
run: async (ctx) => {
|
|
104
156
|
const apiKey = await ctx.prompter.text({
|
|
105
|
-
message: "Enter your Stratus API key:",
|
|
157
|
+
message: "Enter your Stratus API key (leave blank for Formation pool — zero-config):",
|
|
106
158
|
validate: (val: string) => {
|
|
107
|
-
if (!val.trim())
|
|
108
|
-
return "API key is required";
|
|
109
|
-
}
|
|
159
|
+
if (!val.trim()) return undefined;
|
|
110
160
|
if (!val.startsWith("stratus_sk_")) {
|
|
111
161
|
return "API key must start with 'stratus_sk_'";
|
|
112
162
|
}
|
|
@@ -114,36 +164,30 @@ const stratusPlugin = {
|
|
|
114
164
|
},
|
|
115
165
|
});
|
|
116
166
|
|
|
117
|
-
const
|
|
167
|
+
const usingPool = !apiKey?.trim();
|
|
168
|
+
const resolvedKey = usingPool ? undefined : apiKey;
|
|
169
|
+
const profileId = `${PROVIDER_ID}:${usingPool ? "formation-pool" : "default"}`;
|
|
170
|
+
|
|
171
|
+
const models = await generateAllModels(resolvedKey, DEFAULT_BASE_URL);
|
|
172
|
+
|
|
173
|
+
const credential = usingPool
|
|
174
|
+
? { type: "formation_pool" as const, provider: PROVIDER_ID }
|
|
175
|
+
: { type: "api_key" as const, provider: PROVIDER_ID, key: resolvedKey! };
|
|
176
|
+
|
|
177
|
+
const authMode = usingPool
|
|
178
|
+
? "Formation pool (zero-config, 25% markup)"
|
|
179
|
+
: "BYOK (no markup)";
|
|
118
180
|
|
|
119
181
|
return {
|
|
120
|
-
profiles: [
|
|
121
|
-
{
|
|
122
|
-
profileId,
|
|
123
|
-
credential: {
|
|
124
|
-
type: "api_key",
|
|
125
|
-
provider: PROVIDER_ID,
|
|
126
|
-
key: apiKey,
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
],
|
|
182
|
+
profiles: [{ profileId, credential }],
|
|
130
183
|
configPatch: {
|
|
131
184
|
models: {
|
|
132
185
|
providers: {
|
|
133
186
|
[PROVIDER_ID]: {
|
|
134
187
|
baseUrl: DEFAULT_BASE_URL,
|
|
135
|
-
apiKey:
|
|
188
|
+
...(resolvedKey ? { apiKey: resolvedKey } : {}),
|
|
136
189
|
api: "openai-completions",
|
|
137
|
-
models:
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
agents: {
|
|
142
|
-
defaults: {
|
|
143
|
-
models: {
|
|
144
|
-
[`${PROVIDER_ID}/stratus-x1ac-base-claude-sonnet-4-5`]: {
|
|
145
|
-
alias: "stratus",
|
|
146
|
-
},
|
|
190
|
+
models: models,
|
|
147
191
|
},
|
|
148
192
|
},
|
|
149
193
|
},
|
|
@@ -152,20 +196,26 @@ const stratusPlugin = {
|
|
|
152
196
|
notes: [
|
|
153
197
|
"🌊 Stratus X1-AC: World Model + Collective Intelligence System",
|
|
154
198
|
"",
|
|
199
|
+
`🔒 Auth: ${authMode}`,
|
|
200
|
+
"",
|
|
155
201
|
"NOT just an LLM wrapper — this is predictive planning:",
|
|
156
202
|
" Traditional agents: see → think → act → see again",
|
|
157
203
|
" Stratus agents: see → simulate outcomes → pick best → act",
|
|
158
204
|
"",
|
|
159
205
|
"Architecture:",
|
|
160
206
|
" • World Model (X1): Predicts future states from actions (JEPA-based)",
|
|
161
|
-
" • Policy Head (X1-AC):
|
|
207
|
+
" • Policy Head v3 (X1-AC): 94.4% accuracy, brain-guided action sequencing",
|
|
162
208
|
" • Collective Network: Agents learn from each other in real-time",
|
|
163
209
|
"",
|
|
210
|
+
`Loaded ${models.length} models dynamically from Stratus API`,
|
|
211
|
+
" 2050+ models via OpenRouter — OpenAI, Anthropic, Google, and more",
|
|
212
|
+
" BYOK support: pass your own provider keys to bypass Formation pool",
|
|
213
|
+
"",
|
|
164
214
|
"Available Tools:",
|
|
165
215
|
" • stratus_embeddings() - 768-dim semantic state embeddings",
|
|
166
|
-
" • stratus_rollout() - Multi-step action sequence planning",
|
|
216
|
+
" • stratus_rollout() - Multi-step action sequence planning (Policy Head v3)",
|
|
167
217
|
"",
|
|
168
|
-
"
|
|
218
|
+
"Commands: /stratus setup | /stratus verify | /stratus models",
|
|
169
219
|
"Technical docs: https://stratus.run/docs/technical-overview",
|
|
170
220
|
],
|
|
171
221
|
};
|
|
@@ -174,6 +224,16 @@ const stratusPlugin = {
|
|
|
174
224
|
],
|
|
175
225
|
});
|
|
176
226
|
|
|
227
|
+
api.on("gateway_start", async () => {
|
|
228
|
+
const apiKey = pluginConfig.apiKey || process.env.STRATUS_API_KEY;
|
|
229
|
+
try {
|
|
230
|
+
const models = await generateAllModels(apiKey, pluginConfig.baseUrl);
|
|
231
|
+
await updateStoredModels(models);
|
|
232
|
+
} catch {
|
|
233
|
+
// Silent fail — don't disrupt gateway startup
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
177
237
|
if (!pluginConfig.tools?.embeddings?.enabled && !pluginConfig.tools?.rollout?.enabled) {
|
|
178
238
|
return;
|
|
179
239
|
}
|
|
@@ -285,11 +345,24 @@ const stratusPlugin = {
|
|
|
285
345
|
? `Successfully planned ${steps.length} steps to reach goal`
|
|
286
346
|
: `Planning incomplete (${steps.length} steps generated)`;
|
|
287
347
|
|
|
348
|
+
const meta = response.metadata;
|
|
349
|
+
const metaLines: string[] = [];
|
|
350
|
+
if (meta?.brain_confidence != null) {
|
|
351
|
+
metaLines.push(`Brain confidence: ${(meta.brain_confidence * 100).toFixed(1)}%`);
|
|
352
|
+
}
|
|
353
|
+
if (meta?.brain_goal_proximity != null) {
|
|
354
|
+
metaLines.push(`Goal proximity: ${(meta.brain_goal_proximity * 100).toFixed(1)}%`);
|
|
355
|
+
}
|
|
356
|
+
if (meta?.key_source) {
|
|
357
|
+
metaLines.push(`Key source: ${meta.key_source}${meta.formation_markup_applied ? ` (${meta.formation_markup_applied * 100}% markup)` : ""}`);
|
|
358
|
+
}
|
|
359
|
+
const metaText = metaLines.length > 0 ? `\n\n${metaLines.join("\n")}` : "";
|
|
360
|
+
|
|
288
361
|
return {
|
|
289
362
|
content: [
|
|
290
363
|
{
|
|
291
364
|
type: "text",
|
|
292
|
-
text: `${summary}\nGoal: ${response.goal}\n\nSteps:\n${stepText}`,
|
|
365
|
+
text: `${summary}\nGoal: ${response.goal}\n\nSteps:\n${stepText}${metaText}`,
|
|
293
366
|
},
|
|
294
367
|
],
|
|
295
368
|
details: response,
|
|
@@ -328,43 +401,79 @@ const stratusPlugin = {
|
|
|
328
401
|
process.exit(1);
|
|
329
402
|
}
|
|
330
403
|
return { text: "" }; // Return empty to avoid double output
|
|
404
|
+
} else if (subcommand === "models") {
|
|
405
|
+
const apiKey = pluginConfig.apiKey || process.env.STRATUS_API_KEY;
|
|
406
|
+
const models = await generateAllModels(apiKey, pluginConfig.baseUrl);
|
|
407
|
+
|
|
408
|
+
await updateStoredModels(models);
|
|
409
|
+
|
|
410
|
+
const sizes = ["small", "base", "large", "xl", "huge"];
|
|
411
|
+
const grouped = sizes
|
|
412
|
+
.map((size) => {
|
|
413
|
+
const sizeModels = models.filter(
|
|
414
|
+
(m) => m.id.includes(`-x1ac-${size}-`) || m.id.endsWith(`-x1ac-${size}`)
|
|
415
|
+
);
|
|
416
|
+
if (sizeModels.length === 0) return null;
|
|
417
|
+
return ` ${size.toUpperCase()} (${sizeModels.length})\n` +
|
|
418
|
+
sizeModels.map((m) => ` • ${m.id}`).join("\n");
|
|
419
|
+
})
|
|
420
|
+
.filter(Boolean)
|
|
421
|
+
.join("\n\n");
|
|
422
|
+
|
|
423
|
+
return {
|
|
424
|
+
text:
|
|
425
|
+
`Stratus Models (${models.length} total)\n` +
|
|
426
|
+
`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n` +
|
|
427
|
+
grouped +
|
|
428
|
+
`\n\nConfig synced. Run /models to see the full list.`,
|
|
429
|
+
};
|
|
331
430
|
} else if (subcommand === "verify") {
|
|
332
|
-
// Run verify
|
|
333
431
|
console.log("🔍 Verifying Stratus configuration...\n");
|
|
334
432
|
|
|
335
|
-
|
|
433
|
+
const hasKey = !!(pluginConfig.apiKey || process.env.STRATUS_API_KEY);
|
|
336
434
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
console.log(" ✓ STRATUS_API_KEY is set");
|
|
435
|
+
console.log("1️⃣ Auth mode:");
|
|
436
|
+
if (hasKey) {
|
|
437
|
+
console.log(" ✓ BYOK — using STRATUS_API_KEY (no markup)");
|
|
341
438
|
} else {
|
|
342
|
-
console.log("
|
|
343
|
-
|
|
439
|
+
console.log(" ✓ Formation pool — zero-config (25% markup)");
|
|
440
|
+
console.log(" 💡 Set STRATUS_API_KEY to remove markup");
|
|
344
441
|
}
|
|
345
442
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
443
|
+
console.log("\n2️⃣ API connectivity...");
|
|
444
|
+
try {
|
|
445
|
+
const models = await generateAllModels(
|
|
446
|
+
hasKey ? (pluginConfig.apiKey || process.env.STRATUS_API_KEY) : undefined,
|
|
447
|
+
pluginConfig.baseUrl,
|
|
448
|
+
);
|
|
449
|
+
console.log(` ✓ Connected — ${models.length} models available`);
|
|
450
|
+
} catch {
|
|
451
|
+
console.log(" ⚠ Could not reach API (may still work at runtime)");
|
|
353
452
|
}
|
|
354
453
|
|
|
355
|
-
console.log("\
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
454
|
+
console.log("\n3️⃣ Inline BYOK keys:");
|
|
455
|
+
const envKeys = [
|
|
456
|
+
["OPENAI_API_KEY", process.env.OPENAI_API_KEY],
|
|
457
|
+
["ANTHROPIC_API_KEY", process.env.ANTHROPIC_API_KEY],
|
|
458
|
+
["GOOGLE_API_KEY", process.env.GOOGLE_API_KEY],
|
|
459
|
+
] as const;
|
|
460
|
+
let anyInline = false;
|
|
461
|
+
for (const [name, val] of envKeys) {
|
|
462
|
+
if (val) {
|
|
463
|
+
console.log(` ✓ ${name} detected (BYOK passthrough)`);
|
|
464
|
+
anyInline = true;
|
|
465
|
+
}
|
|
366
466
|
}
|
|
367
|
-
|
|
467
|
+
if (!anyInline) {
|
|
468
|
+
console.log(" – None set (optional — Formation pool covers all providers)");
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
472
|
+
console.log("✅ Stratus is ready!");
|
|
473
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
|
|
474
|
+
console.log("🎯 Try it out:");
|
|
475
|
+
console.log(" openclaw agent 'Hello Stratus!' --model stratus\n");
|
|
476
|
+
return { text: "" };
|
|
368
477
|
} else {
|
|
369
478
|
// Show help
|
|
370
479
|
return {
|
|
@@ -372,7 +481,8 @@ const stratusPlugin = {
|
|
|
372
481
|
"🌊 Stratus X1-AC Plugin\n\n" +
|
|
373
482
|
"Commands:\n" +
|
|
374
483
|
" /stratus setup - Interactive setup wizard\n" +
|
|
375
|
-
" /stratus verify - Verify configuration\n
|
|
484
|
+
" /stratus verify - Verify configuration\n" +
|
|
485
|
+
" /stratus models - List all available models (fetches live from API)\n\n" +
|
|
376
486
|
"Get your API key: https://stratus.run\n" +
|
|
377
487
|
"Docs: https://stratus.run/docs\n" +
|
|
378
488
|
"Issues: https://github.com/formthefog/openclaw-stratus-x1-plugin/issues",
|
package/openclaw.plugin.json
CHANGED
|
@@ -12,46 +12,70 @@
|
|
|
12
12
|
"default": true,
|
|
13
13
|
"description": "Enable Stratus plugin"
|
|
14
14
|
},
|
|
15
|
-
"
|
|
16
|
-
"type": "string",
|
|
17
|
-
"description": "Stratus API key (or use STRATUS_API_KEY env var)"
|
|
18
|
-
},
|
|
19
|
-
"baseUrl": {
|
|
20
|
-
"type": "string",
|
|
21
|
-
"default": "https://api.stratus.run",
|
|
22
|
-
"description": "Stratus API base URL"
|
|
23
|
-
},
|
|
24
|
-
"provider": {
|
|
15
|
+
"config": {
|
|
25
16
|
"type": "object",
|
|
17
|
+
"description": "Stratus plugin configuration",
|
|
26
18
|
"properties": {
|
|
27
|
-
"
|
|
28
|
-
"type": "
|
|
29
|
-
"
|
|
19
|
+
"apiKey": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"description": "Stratus API key (optional — Formation pool used as fallback)"
|
|
30
22
|
},
|
|
31
|
-
"
|
|
23
|
+
"baseUrl": {
|
|
32
24
|
"type": "string",
|
|
33
|
-
"default": "stratus
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"tools": {
|
|
38
|
-
"type": "object",
|
|
39
|
-
"properties": {
|
|
40
|
-
"embeddings": {
|
|
25
|
+
"default": "https://api.stratus.run",
|
|
26
|
+
"description": "Stratus API base URL"
|
|
27
|
+
},
|
|
28
|
+
"inlineKeys": {
|
|
41
29
|
"type": "object",
|
|
30
|
+
"description": "Optional BYOK keys passed per-request to bypass Formation pool",
|
|
42
31
|
"properties": {
|
|
43
|
-
"
|
|
44
|
-
"type": "
|
|
45
|
-
"
|
|
32
|
+
"openai_key": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"description": "OpenAI API key for BYOK passthrough"
|
|
35
|
+
},
|
|
36
|
+
"anthropic_key": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "Anthropic API key for BYOK passthrough"
|
|
39
|
+
},
|
|
40
|
+
"gemini_key": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "Google Gemini API key for BYOK passthrough (also sent as X-Google-Key header)"
|
|
46
43
|
}
|
|
47
44
|
}
|
|
48
45
|
},
|
|
49
|
-
"
|
|
46
|
+
"provider": {
|
|
50
47
|
"type": "object",
|
|
51
48
|
"properties": {
|
|
52
49
|
"enabled": {
|
|
53
50
|
"type": "boolean",
|
|
54
51
|
"default": true
|
|
52
|
+
},
|
|
53
|
+
"defaultModel": {
|
|
54
|
+
"type": "string",
|
|
55
|
+
"default": "stratus-x1ac-base-claude-sonnet-4-5"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"tools": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"properties": {
|
|
62
|
+
"embeddings": {
|
|
63
|
+
"type": "object",
|
|
64
|
+
"properties": {
|
|
65
|
+
"enabled": {
|
|
66
|
+
"type": "boolean",
|
|
67
|
+
"default": true
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"rollout": {
|
|
72
|
+
"type": "object",
|
|
73
|
+
"properties": {
|
|
74
|
+
"enabled": {
|
|
75
|
+
"type": "boolean",
|
|
76
|
+
"default": true
|
|
77
|
+
}
|
|
78
|
+
}
|
|
55
79
|
}
|
|
56
80
|
}
|
|
57
81
|
}
|