moltblock 0.4.0 → 0.5.0

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/dist/cli.js CHANGED
@@ -14,6 +14,8 @@ async function main() {
14
14
  .argument("<task>", "Task description (e.g. 'Implement a function add(a,b) that returns a+b.')")
15
15
  .option("-t, --test <path>", "Path to file containing test code (e.g. vitest test module). If omitted, only syntax check.")
16
16
  .option("--json", "Output result as JSON (draft, critique, final, verification_passed, authoritative_artifact).")
17
+ .option("-p, --provider <name>", "LLM provider (openai, google, zai, local). Auto-detected from env if omitted.")
18
+ .option("-m, --model <name>", "Model for all roles (overrides provider default).")
17
19
  .action(async (task, options) => {
18
20
  // Validate task input
19
21
  const validation = validateTask(task);
@@ -30,7 +32,10 @@ async function main() {
30
32
  if (options.test && fs.existsSync(options.test)) {
31
33
  testCode = fs.readFileSync(options.test, "utf-8");
32
34
  }
33
- const entity = new CodeEntity(defaultCodeEntityBindings());
35
+ const entity = new CodeEntity(defaultCodeEntityBindings({
36
+ provider: options.provider,
37
+ model: options.model,
38
+ }));
34
39
  const memory = await entity.run(task, { testCode });
35
40
  if (options.json) {
36
41
  const out = {
package/dist/config.d.ts CHANGED
@@ -48,8 +48,23 @@ export declare function getConfigSource(): ConfigSource;
48
48
  * Returns null if no file or parse error.
49
49
  */
50
50
  export declare function loadMoltblockConfig(): MoltblockConfig | null;
51
+ /** Overrides for provider/model selection (e.g. from CLI flags). */
52
+ export interface BindingOverrides {
53
+ provider?: string;
54
+ model?: string;
55
+ }
56
+ /**
57
+ * Auto-detect the best available provider from environment variables.
58
+ * Priority: explicit override > OPENAI_API_KEY > GOOGLE_API_KEY > MOLTBLOCK_ZAI_API_KEY/ZAI_API_KEY > local.
59
+ */
60
+ export declare function detectProvider(overrideProvider?: string, overrideModel?: string): {
61
+ backend: string;
62
+ baseUrl: string;
63
+ model: string;
64
+ apiKey: string | null;
65
+ };
51
66
  /**
52
67
  * Model bindings for Code Entity. Load from moltblock.json if present, then env overrides.
53
- * If no JSON, uses env/.env only (backward compatible). API keys from env win over JSON.
68
+ * If no JSON, auto-detects provider from env vars. API keys from env win over JSON.
54
69
  */
55
- export declare function defaultCodeEntityBindings(): Record<string, ModelBinding>;
70
+ export declare function defaultCodeEntityBindings(overrides?: BindingOverrides): Record<string, ModelBinding>;
package/dist/config.js CHANGED
@@ -23,6 +23,13 @@ try {
23
23
  catch {
24
24
  // dotenv not required
25
25
  }
26
+ // --- Provider defaults registry ---
27
+ const PROVIDER_DEFAULTS = {
28
+ openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4o", envKey: "OPENAI_API_KEY" },
29
+ google: { baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai/", model: "gemini-2.0-flash", envKey: "GOOGLE_API_KEY" },
30
+ zai: { baseUrl: "https://api.z.ai/api/paas/v4", model: "glm-4.7-flash", envKey: "MOLTBLOCK_ZAI_API_KEY" },
31
+ local: { baseUrl: "http://localhost:1234/v1", model: "local", envKey: "" },
32
+ };
26
33
  // --- Zod schemas (OpenClaw-style config) ---
27
34
  export const BindingEntrySchema = z.object({
28
35
  backend: z.string().describe("e.g. 'local' or 'zai' or 'openai'"),
@@ -138,18 +145,49 @@ export function loadMoltblockConfig() {
138
145
  }
139
146
  /**
140
147
  * Parse OpenClaw config and convert to MoltblockConfig format.
141
- * OpenClaw uses a similar structure but may have different field names.
148
+ * Handles multiple OpenClaw formats: agents.defaults.model.primary ("provider/model"),
149
+ * agent.bindings, providers section, and models section.
142
150
  */
143
151
  function parseOpenClawConfig(data) {
144
152
  if (!data || typeof data !== "object") {
145
153
  return null;
146
154
  }
147
155
  const obj = data;
148
- // OpenClaw may have agent.bindings or providers section
149
- // Try to extract bindings from various possible locations
150
156
  let bindings;
157
+ // Check for agents.defaults.model.primary (OpenClaw's actual format: "provider/model")
158
+ if (obj["agents"] && typeof obj["agents"] === "object") {
159
+ const agents = obj["agents"];
160
+ if (agents["defaults"] && typeof agents["defaults"] === "object") {
161
+ const defaults = agents["defaults"];
162
+ if (defaults["model"] && typeof defaults["model"] === "object") {
163
+ const modelConfig = defaults["model"];
164
+ const primary = modelConfig["primary"];
165
+ if (typeof primary === "string" && primary.includes("/")) {
166
+ const parts = primary.split("/");
167
+ const providerName = parts[0] ?? "";
168
+ const modelName = parts.slice(1).join("/");
169
+ const provider = PROVIDER_DEFAULTS[providerName.toLowerCase()];
170
+ if (providerName && provider) {
171
+ const apiKey = getApiKeyForBackend(providerName);
172
+ const binding = {
173
+ backend: providerName.toLowerCase(),
174
+ base_url: provider.baseUrl,
175
+ model: modelName || provider.model,
176
+ api_key: apiKey,
177
+ };
178
+ bindings = {
179
+ generator: binding,
180
+ critic: { ...binding },
181
+ judge: { ...binding },
182
+ verifier: { ...binding },
183
+ };
184
+ }
185
+ }
186
+ }
187
+ }
188
+ }
151
189
  // Check for agent.bindings (same as moltblock)
152
- if (obj["agent"] && typeof obj["agent"] === "object") {
190
+ if (!bindings && obj["agent"] && typeof obj["agent"] === "object") {
153
191
  const agent = obj["agent"];
154
192
  if (agent["bindings"] && typeof agent["bindings"] === "object") {
155
193
  bindings = extractBindings(agent["bindings"]);
@@ -242,23 +280,66 @@ function getApiKeyForBackend(backend) {
242
280
  return env("GOOGLE_API_KEY") || null;
243
281
  }
244
282
  if (backendLower === "zai") {
245
- return env("MOLTBLOCK_ZAI_API_KEY") || null;
283
+ return env("MOLTBLOCK_ZAI_API_KEY") || env("ZAI_API_KEY") || null;
246
284
  }
247
285
  return null;
248
286
  }
287
+ /**
288
+ * Auto-detect the best available provider from environment variables.
289
+ * Priority: explicit override > OPENAI_API_KEY > GOOGLE_API_KEY > MOLTBLOCK_ZAI_API_KEY/ZAI_API_KEY > local.
290
+ */
291
+ export function detectProvider(overrideProvider, overrideModel) {
292
+ if (overrideProvider) {
293
+ const p = PROVIDER_DEFAULTS[overrideProvider.toLowerCase()];
294
+ if (!p) {
295
+ throw new Error(`Unknown provider "${overrideProvider}". Valid providers: ${Object.keys(PROVIDER_DEFAULTS).join(", ")}`);
296
+ }
297
+ const apiKey = p.envKey ? env(p.envKey) || null : null;
298
+ return {
299
+ backend: overrideProvider.toLowerCase(),
300
+ baseUrl: p.baseUrl,
301
+ model: overrideModel || p.model,
302
+ apiKey,
303
+ };
304
+ }
305
+ // Scan env vars in priority order
306
+ const priority = [
307
+ { name: "openai", envKey: "OPENAI_API_KEY" },
308
+ { name: "google", envKey: "GOOGLE_API_KEY" },
309
+ { name: "zai", envKey: "MOLTBLOCK_ZAI_API_KEY" },
310
+ { name: "zai", envKey: "ZAI_API_KEY" },
311
+ ];
312
+ for (const { name, envKey } of priority) {
313
+ const key = env(envKey);
314
+ if (key) {
315
+ const p = PROVIDER_DEFAULTS[name];
316
+ return {
317
+ backend: name,
318
+ baseUrl: p.baseUrl,
319
+ model: overrideModel || p.model,
320
+ apiKey: key,
321
+ };
322
+ }
323
+ }
324
+ // Fallback to local
325
+ const local = PROVIDER_DEFAULTS["local"];
326
+ return {
327
+ backend: "local",
328
+ baseUrl: local.baseUrl,
329
+ model: overrideModel || local.model,
330
+ apiKey: null,
331
+ };
332
+ }
249
333
  /**
250
334
  * Model bindings for Code Entity. Load from moltblock.json if present, then env overrides.
251
- * If no JSON, uses env/.env only (backward compatible). API keys from env win over JSON.
335
+ * If no JSON, auto-detects provider from env vars. API keys from env win over JSON.
252
336
  */
253
- export function defaultCodeEntityBindings() {
337
+ export function defaultCodeEntityBindings(overrides) {
254
338
  const cfg = loadMoltblockConfig();
255
- const zaiKey = env("MOLTBLOCK_ZAI_API_KEY");
256
- const localUrl = env("MOLTBLOCK_GENERATOR_BASE_URL") || "http://localhost:1234/v1";
257
- const localModel = env("MOLTBLOCK_GENERATOR_MODEL") || "local";
258
339
  const envUrl = (key, fallback) => env(key) || fallback;
259
340
  const envModel = (key, fallback) => env(key) || fallback;
260
341
  const bindingsFromJson = cfg?.agent?.bindings ?? {};
261
- function bindingFor(role, defaultBackend, defaultBase, defaultModel, defaultApiKey) {
342
+ function bindingFor(role) {
262
343
  const entry = bindingsFromJson[role];
263
344
  if (entry) {
264
345
  const baseUrl = envUrl(`MOLTBLOCK_${role.toUpperCase()}_BASE_URL`, entry.base_url);
@@ -271,42 +352,16 @@ export function defaultCodeEntityBindings() {
271
352
  const apiKey = envApiKey || entry.api_key || getApiKeyForBackend(entry.backend) || null;
272
353
  return { backend: entry.backend, baseUrl, apiKey, model };
273
354
  }
274
- // No JSON: legacy env-only behavior
275
- if (role === "generator") {
276
- return { backend: "local", baseUrl: localUrl, apiKey: null, model: localModel };
277
- }
278
- if (role === "critic") {
279
- const useZai = Boolean(zaiKey);
280
- return {
281
- backend: useZai ? "zai" : "local",
282
- baseUrl: envUrl("MOLTBLOCK_CRITIC_BASE_URL", useZai ? "https://api.z.ai/api/paas/v4" : localUrl),
283
- apiKey: useZai ? zaiKey : null,
284
- model: envModel("MOLTBLOCK_CRITIC_MODEL", useZai ? "glm-4.7-flash" : localModel),
285
- };
286
- }
287
- if (role === "judge") {
288
- const useZai = Boolean(zaiKey);
289
- return {
290
- backend: useZai ? "zai" : "local",
291
- baseUrl: envUrl("MOLTBLOCK_JUDGE_BASE_URL", useZai ? "https://api.z.ai/api/paas/v4" : localUrl),
292
- apiKey: useZai ? zaiKey : null,
293
- model: envModel("MOLTBLOCK_JUDGE_MODEL", useZai ? "glm-4.7-flash" : localModel),
294
- };
295
- }
296
- if (role === "verifier") {
297
- return {
298
- backend: "local",
299
- baseUrl: envUrl("MOLTBLOCK_VERIFIER_BASE_URL", localUrl),
300
- apiKey: null,
301
- model: envModel("MOLTBLOCK_VERIFIER_MODEL", localModel),
302
- };
303
- }
304
- return { backend: defaultBackend, baseUrl: defaultBase, apiKey: defaultApiKey, model: defaultModel };
355
+ // No JSON entry for this role: auto-detect provider
356
+ const detected = detectProvider(overrides?.provider, overrides?.model);
357
+ const baseUrl = envUrl(`MOLTBLOCK_${role.toUpperCase()}_BASE_URL`, detected.baseUrl);
358
+ const model = envModel(`MOLTBLOCK_${role.toUpperCase()}_MODEL`, detected.model);
359
+ return { backend: detected.backend, baseUrl, apiKey: detected.apiKey, model };
305
360
  }
306
361
  return {
307
- generator: bindingFor("generator", "local", localUrl, localModel, null),
308
- critic: bindingFor("critic", zaiKey ? "zai" : "local", localUrl, localModel, zaiKey || null),
309
- judge: bindingFor("judge", zaiKey ? "zai" : "local", localUrl, localModel, zaiKey || null),
310
- verifier: bindingFor("verifier", "local", localUrl, localModel, null),
362
+ generator: bindingFor("generator"),
363
+ critic: bindingFor("critic"),
364
+ judge: bindingFor("judge"),
365
+ verifier: bindingFor("verifier"),
311
366
  };
312
367
  }
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Moltblock — framework for evolving composite intelligences (Entities).
3
3
  */
4
- export declare const VERSION = "0.2.0";
4
+ export declare const VERSION = "0.5.0";
5
5
  export type { ModelBinding, BindingEntry, AgentConfig, MoltblockConfig, ChatMessage, VerifiedMemoryEntry, CheckpointEntry, OutcomeEntry, InboxEntry, StrategySuggestion, ReceivedArtifact, GovernanceConfig, } from "./types.js";
6
6
  export { WorkingMemory } from "./memory.js";
7
7
  export { signArtifact, verifyArtifact, artifactHash } from "./signing.js";
8
- export { loadMoltblockConfig, defaultCodeEntityBindings, getConfigSource, BindingEntrySchema, AgentConfigSchema, MoltblockConfigSchema, ModelBindingSchema, type ConfigSource, } from "./config.js";
8
+ export { loadMoltblockConfig, defaultCodeEntityBindings, detectProvider, getConfigSource, BindingEntrySchema, AgentConfigSchema, MoltblockConfigSchema, ModelBindingSchema, type BindingOverrides, type ConfigSource, } from "./config.js";
9
9
  export { Store, hashGraph, hashMemory, auditLog, getGovernanceValue, setGovernanceValue, putInbox, getInbox, recordOutcome, getRecentOutcomes, getStrategy, setStrategy, } from "./persistence.js";
10
10
  export { LLMGateway } from "./gateway.js";
11
11
  export { runGenerator, runCritic, runJudge, runRole, } from "./agents.js";
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Moltblock — framework for evolving composite intelligences (Entities).
3
3
  */
4
- export const VERSION = "0.2.0";
4
+ export const VERSION = "0.5.0";
5
5
  // Memory
6
6
  export { WorkingMemory } from "./memory.js";
7
7
  // Signing
8
8
  export { signArtifact, verifyArtifact, artifactHash } from "./signing.js";
9
9
  // Config
10
- export { loadMoltblockConfig, defaultCodeEntityBindings, getConfigSource, BindingEntrySchema, AgentConfigSchema, MoltblockConfigSchema, ModelBindingSchema, } from "./config.js";
10
+ export { loadMoltblockConfig, defaultCodeEntityBindings, detectProvider, getConfigSource, BindingEntrySchema, AgentConfigSchema, MoltblockConfigSchema, ModelBindingSchema, } from "./config.js";
11
11
  // Persistence
12
12
  export { Store, hashGraph, hashMemory, auditLog, getGovernanceValue, setGovernanceValue, putInbox, getInbox, recordOutcome, getRecentOutcomes, getStrategy, setStrategy, } from "./persistence.js";
13
13
  // Gateway
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moltblock",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Framework for building evolving composite AI intelligences (Entities)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/readme.md CHANGED
@@ -67,7 +67,7 @@ Blockchain is optional and used only for anchoring.
67
67
 
68
68
  ## Run (Code Entity MVP)
69
69
 
70
- Requires Node.js 18+, and (for full loop) any OpenAI-compatible API:
70
+ Requires Node.js 22+, and (for full loop) any OpenAI-compatible API:
71
71
  - **OpenAI** — `https://api.openai.com/v1` with `OPENAI_API_KEY`
72
72
  - **Anthropic Claude** — `https://api.anthropic.com/v1` with `ANTHROPIC_API_KEY`
73
73
  - **Google Gemini** — `https://generativelanguage.googleapis.com/v1beta/openai` with `GOOGLE_API_KEY`
@@ -105,6 +105,19 @@ npx moltblock "Implement add(a, b)."
105
105
 
106
106
  ## Configuration
107
107
 
108
+ ### Zero-config (auto-detect)
109
+
110
+ If you have an API key set in your environment, moltblock detects the provider automatically — no config file needed:
111
+
112
+ ```bash
113
+ export OPENAI_API_KEY="sk-..." # auto-detects OpenAI
114
+ npx moltblock "Implement add(a, b)." --json
115
+ ```
116
+
117
+ Override with CLI flags: `--provider google --model gemini-2.0-flash` or `-p zai -m glm-4.7`.
118
+
119
+ Detection priority: `OPENAI_API_KEY` > `GOOGLE_API_KEY` > `MOLTBLOCK_ZAI_API_KEY` > localhost.
120
+
108
121
  ### Quick setup
109
122
 
110
123
  Create a config file at `~/.moltblock/moltblock.json` (user-wide) or `./moltblock.json` (project-specific):