Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <path>` 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
Expand Down
88 changes: 88 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions npm/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion npm/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
42 changes: 39 additions & 3 deletions npm/src/cli.ts
Original file line number Diff line number Diff line change
@@ -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();

Expand Down Expand Up @@ -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>", "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")
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
Loading