From 68a73e94d506ef44ffaf868b67b62c4a86e55ef9 Mon Sep 17 00:00:00 2001 From: Scott Griffiths <1687746+sgriffiths@users.noreply.github.com> Date: Mon, 11 May 2026 13:07:16 +1000 Subject: [PATCH] =?UTF-8?q?feat:=20close=20stale=20issues=20#22=20#23=20#2?= =?UTF-8?q?5=20=E2=80=94=20npm=20`oa=20validate`,=20dynamic=20version,=20p?= =?UTF-8?q?er-engine=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - npm CLI now reads `--version` from package.json instead of a hard-coded literal (#23 npm side; Python CLI already reads from package metadata). - npm CLI gains `oa validate --spec ` mirroring the Python command's required-field check, so Node users have the same pre-flight validation (#25 npm side). - README "Multiple engines" expanded with a runnable block per engine (OpenAI, Anthropic, Grok/xAI, Local, Cortex, Custom) — `intelligence:` YAML + env var + matching `oa run` command (#22). - Bumps both packages to 1.5.2. --- CHANGELOG.md | 9 +++++ README.md | 88 +++++++++++++++++++++++++++++++++++++++++++ npm/package-lock.json | 8 ++-- npm/package.json | 2 +- npm/src/cli.ts | 42 +++++++++++++++++++-- pyproject.toml | 2 +- 6 files changed, 142 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7580088..fe13041 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to **open-agent-spec** (Open Agent CLI) will be documented i The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.5.2] - 2026-05-11 + +### Added +- **npm CLI `oa validate`** — `oa validate --spec ` in the Node.js CLI now mirrors the Python command, performing the same required-field check (`open_agent_spec`, `agent`, `intelligence`, `tasks`) without any model call. Closes #25 for the npm port. +- **Per-engine README examples** — README "Multiple engines" section now ships a runnable block per engine (OpenAI, Anthropic, Grok/xAI, Local, Cortex, Custom), each showing the `intelligence:` YAML, the env var to export, and the matching `oa run` command. Closes #22. + +### Changed +- **npm CLI `--version`** — the Node CLI now reads the version dynamically from `package.json` instead of a hard-coded literal, so `oa --version` cannot drift from the published release. Closes #23 for the npm port. The Python CLI has read its version from package metadata since 1.5.0. + ## [1.5.1] - 2026-04-13 ### Changed diff --git a/README.md b/README.md index 081d57a..04225e1 100644 --- a/README.md +++ b/README.md @@ -360,6 +360,94 @@ intelligence: model: gpt-4o-mini ``` +The same `oa run` command works against any engine — drop the `intelligence:` block below into your spec, export the matching key, and run. + +#### OpenAI + +```yaml +intelligence: + type: llm + engine: openai + model: gpt-4o-mini +``` + +```bash +export OPENAI_API_KEY=sk-... +oa run --spec agent.yaml --task greet --input '{"name":"Alice"}' --quiet +``` + +#### Anthropic (Claude) + +```yaml +intelligence: + type: llm + engine: anthropic + model: claude-3-5-sonnet-20241022 +``` + +```bash +export ANTHROPIC_API_KEY=sk-ant-... +oa run --spec agent.yaml --task greet --input '{"name":"Alice"}' --quiet +``` + +#### Grok / xAI + +```yaml +intelligence: + type: llm + engine: grok # or "xai" — same provider + model: grok-3-latest +``` + +```bash +export XAI_API_KEY=xai-... +oa run --spec agent.yaml --task greet --input '{"name":"Alice"}' --quiet +``` + +#### Local (Ollama, LM Studio, vLLM, llama.cpp) + +```yaml +intelligence: + type: llm + engine: local + endpoint: http://localhost:11434/v1 # default: Ollama + model: llama3.2 +``` + +```bash +# No API key required. +ollama serve && ollama pull llama3.2 +oa run --spec agent.yaml --task greet --input '{"name":"Alice"}' --quiet +``` + +#### Cortex (self-hosted, OpenAI-compatible) + +```yaml +intelligence: + type: llm + engine: cortex + endpoint: https://cortex.mycompany.com/v1 + model: my-cortex-model + config: + api_key_env: CORTEX_API_KEY +``` + +```bash +export CORTEX_API_KEY=... +oa run --spec agent.yaml --task greet --input '{"name":"Alice"}' --quiet +``` + +#### Custom (your own Python class) + +```yaml +intelligence: + type: llm + engine: custom + module: my_pkg.providers:MyProvider +``` + +Implement `invoke(system, user, config, history)` on `MyProvider`. See [`docs/REFERENCE.md`](docs/REFERENCE.md) for the protocol. + --- ### npm / Node.js CLI diff --git a/npm/package-lock.json b/npm/package-lock.json index db1f12f..ed5ca00 100644 --- a/npm/package-lock.json +++ b/npm/package-lock.json @@ -1,12 +1,12 @@ { - "name": "open-agent-spec", - "version": "1.4.0", + "name": "@prime-vector/open-agent-spec", + "version": "1.5.2", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "open-agent-spec", - "version": "1.4.0", + "name": "@prime-vector/open-agent-spec", + "version": "1.5.2", "license": "MIT", "dependencies": { "commander": "^12.0.0", diff --git a/npm/package.json b/npm/package.json index fb4f52e..d27d74f 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@prime-vector/open-agent-spec", - "version": "1.5.1", + "version": "1.5.2", "description": "Run Open Agent Spec YAML files from Node.js — no Python required.", "keywords": [ "ai", diff --git a/npm/src/cli.ts b/npm/src/cli.ts index f5635b4..76b6b51 100644 --- a/npm/src/cli.ts +++ b/npm/src/cli.ts @@ -1,10 +1,27 @@ import { readFileSync } from "node:fs"; -import { resolve } from "node:path"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; import { Command } from "commander"; import { runTask } from "./runner.js"; -import { OAError } from "./loader.js"; +import { loadSpecFromFile, OAError } from "./loader.js"; import type { RunInput } from "./types.js"; +function readPackageVersion(): string { + const here = dirname(fileURLToPath(import.meta.url)); + for (const candidate of [ + resolve(here, "..", "package.json"), + resolve(here, "..", "..", "package.json"), + ]) { + try { + const pkg = JSON.parse(readFileSync(candidate, "utf8")) as { version?: string }; + if (pkg.version) return pkg.version; + } catch { + // try next candidate + } + } + return "unknown"; +} + function parseInput(raw: string): RunInput { const trimmed = raw.trim(); @@ -52,7 +69,26 @@ export function createCli(): Command { program .name("oa") .description("Open Agent Spec runner — execute YAML agent specs from the command line.") - .version("1.5.1"); + .version(readPackageVersion()); + + program + .command("validate") + .description("Validate a spec file against the Open Agent Spec schema (no model calls).") + .requiredOption("--spec ", "Path to the spec YAML file") + .action((opts: { spec: string }) => { + const specPath = resolve(opts.spec); + try { + loadSpecFromFile(specPath); + } catch (err) { + if (err instanceof OAError) { + console.error(`Error [${err.code}]: ${err.message}`); + } else { + console.error(`Error: ${String(err)}`); + } + process.exit(1); + } + console.log(`Spec is valid: ${specPath}`); + }); program .command("run") diff --git a/pyproject.toml b/pyproject.toml index d3144f8..5f6bc91 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "hatchling.build" [project] name = "open-agent-spec" -version = "1.5.1" +version = "1.5.2" description = "YAML-first agent specs: run with `oa run` or generate a full Python project with `oa init`." authors = [{ name = "Andrew Whitehouse", email = "andrewswhitehouse@gmail.com" }] license = { text = "MIT" }