openagentflow 0.1.3 → 0.1.5

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.
@@ -224,7 +224,7 @@ export function generateLlmHelperTemplate({ defaultModel, defaultTemperature })
224
224
  ` raise RuntimeError("Missing package: pip install langchain-anthropic")`,
225
225
  ` else:`,
226
226
  ` raise RuntimeError(`,
227
- ` "No LLM provider available or configured. Set GOOGLE_API_KEY (Gemini), OPENAI_API_KEY (OpenAI), or ANTHROPIC_API_KEY (Anthropic)."`,
227
+ ` "No LLM provider available or configured. Run 'npx openagentflow auth' to set up credentials, or set GOOGLE_API_KEY / OPENAI_API_KEY / ANTHROPIC_API_KEY in your local .env file."`,
228
228
  ` )`,
229
229
  ``,
230
230
  `def _parse_llm_output(raw_content, outputs):`,
@@ -431,8 +431,8 @@ export function generateMainTemplate({ workflowName, initialStateFields, require
431
431
  ` # Ensure at least one API key is set`,
432
432
  ` if not _LLM_PROVIDER:`,
433
433
  ` print("Error: No LLM provider configured.")`,
434
- ` print(" Set GOOGLE_API_KEY (Gemini, preferred) or OPENAI_API_KEY (OpenAI).")`,
435
- ` print(" Example: export GOOGLE_API_KEY='your-key-here'")`,
434
+ ` print(" Run 'npx openagentflow auth' to configure credentials or edit your local .env file.")`,
435
+ ` print(" Or set manually: export GOOGLE_API_KEY='AIza...'")`,
436
436
  ` exit(1)`,
437
437
  ``,
438
438
  ` print(f"Default fallback provider: {_LLM_PROVIDER}")`,
package/cli/env.js CHANGED
@@ -55,6 +55,29 @@ export function parseDotEnv(content) {
55
55
  return result;
56
56
  }
57
57
 
58
+ /**
59
+ * Check if an environment variable value is a dummy placeholder string or unset.
60
+ * Returns true if val is null, undefined, empty, or contains typical template placeholder markers.
61
+ */
62
+ export function isPlaceholder(val) {
63
+ if (val === null || val === undefined || typeof val !== 'string') {
64
+ return true;
65
+ }
66
+ const trimmed = val.trim();
67
+ if (trimmed === '') {
68
+ return true;
69
+ }
70
+ const lower = trimmed.toLowerCase();
71
+ return (
72
+ lower.startsWith('your_') ||
73
+ lower.startsWith('your-') ||
74
+ lower.includes('_here') ||
75
+ lower.includes('-here') ||
76
+ lower === 'todo' ||
77
+ lower === 'placeholder'
78
+ );
79
+ }
80
+
58
81
  /**
59
82
  * Resolve environment variables across the 4-tier hierarchy:
60
83
  * 1. Inline CLI overrides & System Environment Variables (already in process.env)
@@ -82,23 +105,24 @@ export function resolveEnvHierarchy(targetFilePath = null) {
82
105
  } catch (err) {}
83
106
  }
84
107
 
85
- let localEnvPath = null;
86
- if (targetFilePath && existsSync(targetFilePath)) {
87
- const absTarget = resolve(targetFilePath);
108
+ let localEnv = {};
109
+ const cwdEnvPath = join(process.cwd(), '.env');
110
+ let localEnvPath = cwdEnvPath;
111
+ if (existsSync(cwdEnvPath)) {
88
112
  try {
89
- const dir = statSync(absTarget).isDirectory() ? absTarget : dirname(absTarget);
90
- localEnvPath = join(dir, '.env');
91
- } catch (err) {
92
- localEnvPath = join(process.cwd(), '.env');
93
- }
94
- } else {
95
- localEnvPath = join(process.cwd(), '.env');
113
+ localEnv = parseDotEnv(readFileSync(cwdEnvPath, 'utf-8'));
114
+ } catch (err) {}
96
115
  }
97
116
 
98
- let localEnv = {};
99
- if (localEnvPath && existsSync(localEnvPath)) {
117
+ if (targetFilePath && existsSync(targetFilePath)) {
118
+ const absTarget = resolve(targetFilePath);
100
119
  try {
101
- localEnv = parseDotEnv(readFileSync(localEnvPath, 'utf-8'));
120
+ const dir = statSync(absTarget).isDirectory() ? absTarget : dirname(absTarget);
121
+ const targetEnvPath = join(dir, '.env');
122
+ if (resolve(targetEnvPath) !== resolve(cwdEnvPath) && existsSync(targetEnvPath)) {
123
+ localEnvPath = targetEnvPath;
124
+ Object.assign(localEnv, parseDotEnv(readFileSync(targetEnvPath, 'utf-8')));
125
+ }
102
126
  } catch (err) {}
103
127
  }
104
128
 
package/cli/index.js CHANGED
@@ -23,8 +23,9 @@ import { fileURLToPath } from 'url';
23
23
  import { execSync, spawn } from 'child_process';
24
24
  import os from 'os';
25
25
  import { Compiler } from '../compiler/compiler.js';
26
+ import { VERSION } from '../compiler/version.js';
26
27
  import { LangGraphAdapter } from '../adapters/langgraph/index.js';
27
- import { resolveEnvHierarchy, setupAuth } from './env.js';
28
+ import { resolveEnvHierarchy, setupAuth, isPlaceholder } from './env.js';
28
29
 
29
30
  // ─── ANSI Colors ───────────────────────────────────────────────────────────────
30
31
 
@@ -42,7 +43,7 @@ const colors = {
42
43
  // ─── Helpers ───────────────────────────────────────────────────────────────────
43
44
 
44
45
  function printBanner() {
45
- console.log(`${colors.cyan}${colors.bold}OpenAgentFlow${colors.reset} ${colors.dim}v0.1.0${colors.reset}`);
46
+ console.log(`${colors.cyan}${colors.bold}OpenAgentFlow${colors.reset} ${colors.dim}v${VERSION}${colors.reset}`);
46
47
  console.log();
47
48
  }
48
49
 
@@ -332,44 +333,48 @@ function cmdRun(filePath, flags, positional = []) {
332
333
  else if (targetModel.startsWith('gemini-') || targetModel.startsWith('gemma-')) provider = 'gemini';
333
334
  }
334
335
 
335
- if (provider === 'anthropic' && !process.env.ANTHROPIC_API_KEY) {
336
+ if (provider === 'anthropic' && (!process.env.ANTHROPIC_API_KEY || isPlaceholder(process.env.ANTHROPIC_API_KEY))) {
336
337
  console.error(`${colors.red}Error:${colors.reset} Missing required API key "ANTHROPIC_API_KEY" for agent "${agent.id}" (provider: anthropic).`);
337
338
  console.error(`Looked in order of priority:`);
338
339
  console.error(` 1. Inline CLI overrides`);
339
340
  console.error(` 2. Local Project .env`);
340
341
  console.error(` 3. System Environment Variables`);
341
342
  console.error(` 4. Global OAF Store (~/.oaf/.env)`);
342
- console.error(`Run \`oaf auth\` to set up your global credentials or create a local .env file.`);
343
+ console.error(`Run \`npx openagentflow auth\` (or \`oaf auth\` if globally installed) to set up your credentials or edit your local .env file.`);
343
344
  process.exit(1);
344
- } else if (provider === 'openai' && !process.env.OPENAI_API_KEY) {
345
+ } else if (provider === 'openai' && (!process.env.OPENAI_API_KEY || isPlaceholder(process.env.OPENAI_API_KEY))) {
345
346
  console.error(`${colors.red}Error:${colors.reset} Missing required API key "OPENAI_API_KEY" for agent "${agent.id}" (provider: openai).`);
346
347
  console.error(`Looked in order of priority:`);
347
348
  console.error(` 1. Inline CLI overrides`);
348
349
  console.error(` 2. Local Project .env`);
349
350
  console.error(` 3. System Environment Variables`);
350
351
  console.error(` 4. Global OAF Store (~/.oaf/.env)`);
351
- console.error(`Run \`oaf auth\` to set up your global credentials or create a local .env file.`);
352
+ console.error(`Run \`npx openagentflow auth\` (or \`oaf auth\` if globally installed) to set up your credentials or edit your local .env file.`);
352
353
  process.exit(1);
353
- } else if (provider === 'gemini' && !process.env.GOOGLE_API_KEY) {
354
+ } else if (provider === 'gemini' && (!process.env.GOOGLE_API_KEY || isPlaceholder(process.env.GOOGLE_API_KEY))) {
354
355
  console.error(`${colors.red}Error:${colors.reset} Missing required API key "GOOGLE_API_KEY" for agent "${agent.id}" (provider: gemini).`);
355
356
  console.error(`Looked in order of priority:`);
356
357
  console.error(` 1. Inline CLI overrides`);
357
358
  console.error(` 2. Local Project .env`);
358
359
  console.error(` 3. System Environment Variables`);
359
360
  console.error(` 4. Global OAF Store (~/.oaf/.env)`);
360
- console.error(`Run \`oaf auth\` to set up your global credentials or create a local .env file.`);
361
+ console.error(`Run \`npx openagentflow auth\` (or \`oaf auth\` if globally installed) to set up your credentials or edit your local .env file.`);
361
362
  process.exit(1);
362
363
  }
363
364
  }
364
365
 
365
- if (!process.env.GOOGLE_API_KEY && !process.env.OPENAI_API_KEY && !process.env.ANTHROPIC_API_KEY && result.ir.agents.length > 0) {
366
+ const hasValidGoogle = process.env.GOOGLE_API_KEY && !isPlaceholder(process.env.GOOGLE_API_KEY);
367
+ const hasValidOpenAI = process.env.OPENAI_API_KEY && !isPlaceholder(process.env.OPENAI_API_KEY);
368
+ const hasValidAnthropic = process.env.ANTHROPIC_API_KEY && !isPlaceholder(process.env.ANTHROPIC_API_KEY);
369
+
370
+ if (!hasValidGoogle && !hasValidOpenAI && !hasValidAnthropic && result.ir.agents.length > 0) {
366
371
  console.error(`${colors.red}Error:${colors.reset} No LLM API key configured. Set GOOGLE_API_KEY (Gemini), OPENAI_API_KEY (OpenAI), or ANTHROPIC_API_KEY (Anthropic) to execute workflows.`);
367
372
  console.error(`Looked in order of priority:`);
368
373
  console.error(` 1. Inline CLI overrides`);
369
374
  console.error(` 2. Local Project .env`);
370
375
  console.error(` 3. System Environment Variables`);
371
376
  console.error(` 4. Global OAF Store (~/.oaf/.env)`);
372
- console.error(`Run \`oaf auth\` to set up your global credentials or create a local .env file.`);
377
+ console.error(`Run \`npx openagentflow auth\` (or \`oaf auth\` if globally installed) to set up your credentials or edit your local .env file.`);
373
378
  process.exit(1);
374
379
  }
375
380
  }
@@ -546,7 +551,7 @@ function main() {
546
551
  }
547
552
 
548
553
  if (rawArgs.includes('--version') || rawArgs.includes('-v')) {
549
- console.log('0.1.0');
554
+ console.log(VERSION);
550
555
  process.exit(0);
551
556
  }
552
557
 
package/compiler/index.js CHANGED
@@ -5,3 +5,4 @@
5
5
  export { Compiler, CompilationResult } from './compiler.js';
6
6
  export { SemanticValidator, Diagnostic, ValidationResult } from './validator.js';
7
7
  export { IRGenerator } from './ir-generator.js';
8
+ export { VERSION, getVersion } from './version.js';
@@ -7,7 +7,9 @@
7
7
  * Pipeline: Validated AST → [IR Generator] → IR (JSON)
8
8
  */
9
9
 
10
- const IR_VERSION = '0.1.0';
10
+ import { VERSION } from './version.js';
11
+
12
+ const IR_VERSION = VERSION;
11
13
 
12
14
  export class IRGenerator {
13
15
  /**
@@ -0,0 +1,26 @@
1
+ /**
2
+ * OpenAgentFlow Version Utility
3
+ *
4
+ * Dynamically loads and caches the current version from package.json
5
+ * to ensure a single source of truth across the compiler, CLI, and adapters.
6
+ */
7
+
8
+ import { readFileSync } from 'fs';
9
+ import { resolve, dirname } from 'path';
10
+ import { fileURLToPath } from 'url';
11
+
12
+ let cachedVersion = null;
13
+
14
+ export function getVersion() {
15
+ if (cachedVersion !== null) return cachedVersion;
16
+ try {
17
+ const pkgPath = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');
18
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
19
+ cachedVersion = pkg.version || '0.1.0';
20
+ } catch {
21
+ cachedVersion = '0.1.0';
22
+ }
23
+ return cachedVersion;
24
+ }
25
+
26
+ export const VERSION = getVersion();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openagentflow",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "An open, portable specification for describing AI agent workflows using a human-readable text language.",
5
5
  "type": "module",
6
6
  "main": "compiler/index.js",
@@ -24,6 +24,9 @@
24
24
  ],
25
25
  "scripts": {
26
26
  "test": "node --test tests/**/*.test.js",
27
+ "test:update-snapshots": "node -e \"process.env.UPDATE_SNAPSHOTS='1'; import('./tests/snapshot.test.js')\"",
28
+ "preversion": "npm test",
29
+ "version": "npm run test:update-snapshots && git add tests/snapshots",
27
30
  "oaf": "node cli/index.js"
28
31
  },
29
32
  "keywords": [