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
16 changes: 13 additions & 3 deletions .github/workflows/publish-clawhub-plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,18 @@ jobs:
throw new Error(`ClawHub exact version ${expected} was not found in version metadata`);
}

console.log(`ClawHub metadata verified for zeroapi@${expected}`);
const scanStatus =
inspect.package?.verification?.scanStatus ??
inspect.package?.scanStatus ??
inspect.verification?.scanStatus ??
inspect.scanStatus;
if (scanStatus !== "clean") {
throw new Error(
`ClawHub exact release ${expected} is not scan-clean (status: ${scanStatus ?? "missing"}); refusing automated risk acknowledgement`,
);
}

console.log(`ClawHub metadata and clean scan verified for zeroapi@${expected}`);
NODE

- name: Verify ClawHub package is downloadable
Expand All @@ -127,8 +138,7 @@ jobs:
trap 'rm -rf "$tmp_dir"' EXIT
cd "$tmp_dir"
for attempt in $(seq 1 10); do
if timeout 300s env npm_config_yes=true npx --yes "openclaw@$OPENCLAW_VERIFY_VERSION" plugins install "clawhub:zeroapi@${{ steps.version.outputs.value }}" \
--dangerously-force-unsafe-install; then
if timeout 300s env npm_config_yes=true npx --yes "openclaw@$OPENCLAW_VERIFY_VERSION" plugins install "clawhub:zeroapi@${{ steps.version.outputs.value }}"; then
exit 0
fi
if [ "$attempt" -eq 10 ]; then
Expand Down
33 changes: 27 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ permissions:
contents: read

env:
OPENCLAW_COMPAT_VERSION: '2026.7.1-2'
OPENCLAW_COMPAT_INTEGRITY: 'sha512-ycF3yPcbjN6bUPeaUx6Mh6vze1hQWoD3CT/wWcmD7a8xaHHHRUaAlaq+lFxMHf1ssEgODVAwjlzYqp2twkYZ7g=='
HERMES_COMPAT_REF: 'v2026.8.3'
HERMES_COMPAT_SHA: '3c27eb6234bf91b8ceee9e9071591b31e9b148cb'

Expand Down Expand Up @@ -39,8 +37,30 @@ jobs:
- run: npm test

openclaw-compat:
name: openclaw-compat (${{ matrix.label }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
# The minimum host gets a runtime fallback witness, v2026.7.1-2 is the
# typed target-stable contract, and the prerelease proves SQLite.
- version: '2026.5.2'
integrity: 'sha512-Jz00jdV/yE0/RfAln0tVlEq1hX9DIZdc7NRZVQRpt98XINduqoua9uOc1Ty4GeYlg5c746Lhl5ZCe6A4rsOmng=='
label: min-json
layout: json
typecheck: false
- version: '2026.7.1-2'
integrity: 'sha512-ycF3yPcbjN6bUPeaUx6Mh6vze1hQWoD3CT/wWcmD7a8xaHHHRUaAlaq+lFxMHf1ssEgODVAwjlzYqp2twkYZ7g=='
label: stable-json
layout: json
typecheck: true
- version: '2026.8.1-beta.1'
integrity: 'sha512-ugsMNhvfDMQYZa4EpHk+2Y6IdMYRCoe9BiwJVv9ZFFKPeYcgypbMmLvPG1XvMdanixZU+oZb/knLGAoHGREc9Q=='
label: sqlite-beta
layout: sqlite
typecheck: false
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
Expand All @@ -49,10 +69,11 @@ jobs:
- run: npm ci
- name: Install exact OpenClaw package
run: |
actual_integrity="$(npm view "openclaw@${OPENCLAW_COMPAT_VERSION}" dist.integrity)"
test "$actual_integrity" = "$OPENCLAW_COMPAT_INTEGRITY"
npm install --no-save --package-lock=false "openclaw@${OPENCLAW_COMPAT_VERSION}"
actual_integrity="$(npm view "openclaw@${{ matrix.version }}" dist.integrity)"
test "$actual_integrity" = "${{ matrix.integrity }}"
npm install --no-save --package-lock=false "openclaw@${{ matrix.version }}"
- name: Typecheck adapter and public SDK contract witness
if: matrix.typecheck
run: npx tsc --project tsconfig.openclaw-compat.json
- name: Stage ClawHub plugin artifact
run: node scripts/stage_clawhub_plugin.mjs /tmp/zeroapi-staged
Expand All @@ -76,7 +97,7 @@ jobs:
run: |
OPENCLAW_STATE_DIR=/tmp/zeroapi-openclaw-state \
OPENCLAW_CONFIG_PATH=/tmp/zeroapi-openclaw-state/openclaw.json \
node scripts/openclaw_compat_smoke.mjs /tmp/zeroapi-staged
node scripts/openclaw_compat_smoke.mjs /tmp/zeroapi-staged "${{ matrix.layout }}"

hermes-compat:
runs-on: ubuntu-latest
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

## [Unreleased]

## [3.10.3] - 2026-08-10

### Fixed

- Persist OpenClaw account/profile overrides through the public storage-neutral session API instead of inferring the active backend from `openclaw-agent.sqlite`; this keeps `v2026.7.1-2` JSON sessions working when its auth database is present and follows newer SQLite session storage without touching stale JSON.
- Use OpenClaw's official `auto` ownership marker for generated auth-profile overrides while continuing to recognize and clean up legacy `zeroapi` markers; user-pinned overrides remain untouched.

### Changed

- Make the ClawHub post-publish install smoke fail closed unless the exact release reports a clean scan, and remove the deprecated `--dangerously-force-unsafe-install` flag.

### Tests

- Exercise account routing against the exact `2026.5.2` legacy public session API, exact `2026.7.1-2` JSON storage, and exact `2026.8.1-beta.1` SQLite storage, including the stable auth-database regression and stale-JSON protection.

## [3.10.2] - 2026-08-07

### Fixed
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![Tests](https://github.com/dorukardahan/ZeroAPI/actions/workflows/test.yml/badge.svg)](https://github.com/dorukardahan/ZeroAPI/actions/workflows/test.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![OpenClaw](https://img.shields.io/badge/OpenClaw-2026.5.2+-blue)](https://openclaw.ai)
[![Version](https://img.shields.io/badge/version-3.10.2-green)](https://github.com/dorukardahan/ZeroAPI/releases/tag/v3.10.2)
[![Version](https://img.shields.io/badge/version-3.10.3-green)](https://github.com/dorukardahan/ZeroAPI/releases/tag/v3.10.3)

**Your AI subscriptions. One plugin. Routing policy that improves with data.**

Expand Down Expand Up @@ -170,7 +170,7 @@ ZeroAPI is a source-linked ClawHub package. Before installing from ClawHub, veri
- source path: `plugin`
- source tag or commit: matches the GitHub release you intend to install

Prefer exact version installs such as `clawhub:zeroapi@3.10.2` instead of an unpinned `latest` install. Do not install mirror packages, standalone skills, or similarly named packages that do not link back to this repository.
Prefer exact version installs such as `clawhub:zeroapi@3.10.3` instead of an unpinned `latest` install. Do not install mirror packages, standalone skills, or similarly named packages that do not link back to this repository.

ZeroAPI does not require shell-piped installer commands. The GitHub release workflow publishes the ClawHub package from `plugin/`, verifies ClawHub latest/exact-version metadata, and runs an OpenClaw install smoke test before treating the release as published.

Expand Down
6 changes: 3 additions & 3 deletions SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: zeroapi
version: 3.10.2
version: 3.10.3
description: >
Route tasks to the best AI model across paid subscriptions via OpenClaw gateway plugin.
Use when the user mentions model routing, multi-model setup, "which model should I use",
Expand All @@ -13,7 +13,7 @@ compatibility: Requires OpenClaw 2026.4.2+ with at least one AI subscription. Cu
metadata: {"openclaw":{"emoji":"⚡","category":"routing","os":["darwin","linux"],"requires":{"anyBins":["openclaw"],"config":["agents"]}}}
---

# ZeroAPI v3.10.2 - Plugin-Based Model Routing
# ZeroAPI v3.10.3 - Plugin-Based Model Routing

You are configuring an OpenClaw **gateway plugin**. ZeroAPI routes **eligible** messages at runtime through the `before_model_resolve` hook. You do **not** route messages manually. Your job is to inspect the user's setup, generate `zeroapi-config.json`, align `openclaw.json`, install/update the plugin, and verify the result.

Expand Down Expand Up @@ -235,7 +235,7 @@ Required config shape:

```json
{
"version": "3.10.2",
"version": "3.10.3",
"generated": "<ISO timestamp>",
"benchmarks_date": "<fetched date>",
"subscription_catalog_version": "1.1.0",
Expand Down
2 changes: 1 addition & 1 deletion benchmarks.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "3.10.2",
"version": "3.10.3",
"source": "Artificial Analysis Data API v2",
"api": "https://artificialanalysis.ai/api/v2/data/llms/models",
"fetched": "2026-08-09",
Expand Down
2 changes: 1 addition & 1 deletion examples/full-stack.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "3.10.2",
"version": "3.10.3",
"generated": "2026-08-09T00:00:00.000Z",
"benchmarks_date": "2026-08-09",
"subscription_catalog_version": "1.1.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/openai-glm-kimi.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "3.10.2",
"version": "3.10.3",
"generated": "2026-08-09T00:00:00.000Z",
"benchmarks_date": "2026-08-09",
"subscription_catalog_version": "1.1.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/openai-glm.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "3.10.2",
"version": "3.10.3",
"generated": "2026-08-09T00:00:00.000Z",
"benchmarks_date": "2026-08-09",
"subscription_catalog_version": "1.1.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/openai-multi-account.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "3.10.2",
"version": "3.10.3",
"generated": "2026-08-09T00:00:00.000Z",
"benchmarks_date": "2026-08-09",
"subscription_catalog_version": "1.1.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/openai-only.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "3.10.2",
"version": "3.10.3",
"generated": "2026-08-09T00:00:00.000Z",
"benchmarks_date": "2026-08-09",
"subscription_catalog_version": "1.1.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/subscription-profile.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "3.10.2",
"version": "3.10.3",
"generated": "2026-08-09T00:00:00.000Z",
"benchmarks_date": "2026-08-09",
"subscription_catalog_version": "1.1.0",
Expand Down
2 changes: 1 addition & 1 deletion integrations/hermes/plugin.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: zeroapi-router
version: 3.10.2
version: 3.10.3
description: Benchmark-aware model routing for Hermes Agent using ZeroAPI policy config
provides_hooks:
- pre_model_route
6 changes: 3 additions & 3 deletions 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 package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zeroapi-workspace",
"version": "3.10.2",
"version": "3.10.3",
"private": true,
"description": "Subscription-aware, benchmark-informed routing policy for the OpenClaw plugin and experimental Hermes Agent adapter",
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ The advisory file and logs can still be used for operators who do not want chann
Install only from the source-linked package:

```bash
openclaw plugins install clawhub:zeroapi@3.10.2
openclaw plugins install clawhub:zeroapi@3.10.3
```

Verify the package source points to:
Expand Down
12 changes: 9 additions & 3 deletions plugin/__tests__/plugin-entry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ vi.mock("openclaw/plugin-sdk/plugin-entry", () => ({
definePluginEntry: (entry: unknown) => entry,
}));

vi.mock("openclaw/plugin-sdk/session-store-runtime", () => ({
patchSessionEntry: vi.fn(async () => null),
}));

const startSubscriptionAdvisoryMonitor = vi.fn(() => ({ stop: vi.fn() }));
const maybePrefixChannelAdvisory = vi.fn(() => null);

Expand Down Expand Up @@ -187,6 +191,7 @@ describe("plugin entry registration", () => {
logRoutingEvent: vi.fn(),
}));
vi.doMock("../session-auth.js", () => ({
createSessionEntryPatcher: (runtime: { patchSessionEntry: unknown }) => runtime.patchSessionEntry,
syncSessionAuthProfileOverride: () => ({
action: "blocked",
reason: "user_pinned_override",
Expand All @@ -210,7 +215,7 @@ describe("plugin entry registration", () => {
const handler = on.mock.calls[0]?.[1];
expect(typeof handler).toBe("function");

const result = handler(
const result = await handler(
{ prompt: "coordinate a workflow across 3 services" },
{
agentId: "main",
Expand Down Expand Up @@ -383,6 +388,7 @@ describe("plugin entry registration", () => {
logRoutingEvent: vi.fn(),
}));
vi.doMock("../session-auth.js", () => ({
createSessionEntryPatcher: (runtime: { patchSessionEntry: unknown }) => runtime.patchSessionEntry,
syncSessionAuthProfileOverride: () => ({
action: "noop",
reason: "already_current",
Expand All @@ -406,7 +412,7 @@ describe("plugin entry registration", () => {
const handler = on.mock.calls[0]?.[1];
expect(typeof handler).toBe("function");

handler(
await handler(
{ prompt: "implement the provider adapter" },
{
agentId: "main",
Expand All @@ -415,7 +421,7 @@ describe("plugin entry registration", () => {
sessionKey: "agent:main:signal:dm:u1",
},
);
handler(
await handler(
{ prompt: "devam et" },
{
agentId: "main",
Expand Down
Loading