Skip to content

feat(harness): deployable Harness server + veadk harness CLI (create/add/show/deploy/invoke), with OAuth2/JWT deploy#603

Merged
yaozheng-fang merged 15 commits into
mainfrom
feat/harness-runtime
Jun 12, 2026
Merged

feat(harness): deployable Harness server + veadk harness CLI (create/add/show/deploy/invoke), with OAuth2/JWT deploy#603
yaozheng-fang merged 15 commits into
mainfrom
feat/harness-runtime

Conversation

@yaozheng-fang

Copy link
Copy Markdown
Collaborator

What

Adds a deployable Harness server (veadk.cloud.harness_app) and a veadk harness CLI to scaffold, configure, deploy, and invoke it on Volcengine AgentKit — no app code to write, no local Docker.

A harness = an env-assembled agent spec (model + system prompt + tools + skills + knowledgebase/memory), described by a layered harness.yaml, served at POST /harness/invoke.

CLI

createaddshowdeployinvoke

  • create — scaffold a deploy dir (harness.yaml / .env.example / Dockerfile / README.md).
  • add — write agent params into harness.yaml; --tools/--skills comma lists + per-component --<component>-<param> connection flags.
  • show — print configured params + per-invoke overridable flags.
  • deploy — cloud AgentKit build + runtime create; records endpoint/key into harness.json.
  • invoke — call a deployed harness by --name (url/key resolved from harness.json); per-call once-time overrides (incremental tools/skills; memory/kb never overridable).

OAuth2 / JWT deploy (custom_jwt)

An auth block in harness.yaml (or --discovery-url / --allowed-id) gates the runtime via a Volcengine Identity user pool:

auth:
  discovery_url: "https://userpool-<id>.userpool.auth.id.cn-beijing.volces.com/.well-known/openid-configuration"
  allowed_ids: ["<client-id>"]
  • Presence of auth = custom_jwt; absence = the existing key_auth path (unchanged).
  • auth is excluded from the flattened runtime env — it only configures the gateway authorizer.
  • No secret involved: user pool / client / external IdP are set up in the Identity console; the CLI only references discovery_url + allowed_ids.
  • Verified end-to-end against a real user pool: deploy → runtime Ready with a custom_jwt authorizer carrying the given discovery_url + allowed_clients, no key_auth.

Tests / docs

  • Contract tests for the harness schemas + CLI (tests/cloud/test_harness_app_contract.py, tests/cli/test_cli_agentkit_harness_contract.py); full suite green (278 passed).
  • ruff + pyright clean.
  • Docs: docs/content/docs/cli/harness-cli.{mdx,en.mdx} + example 14_harness_server_on_agentkit rewritten for the current flow.

🤖 Generated with Claude Code

The Harness model now carries a `runtime` field (Literal["adk","codex"],
default "adk") passed through to the Agent, so a deployed Harness server can
run an agent on the codex runtime. Exposed on the CLI via `--runtime` on both
`harness add` and `harness invoke` (one-time override). Docs + example updated.
… CLI

- veadk/cloud/harness_app/: env-assembled agent + FastAPI harness server
  (/harness/invoke with clone-based once-time overrides; incremental,
  deduped tools/skills; per-invoke skill temp-dir cleanup)
- veadk harness create/deploy/invoke; deploy builds the image via AgentKit
  and creates an AgentKit runtime (Name=HARNESS_NAME, tag "Harness")
- invoke override flags are generated from HarnessOverrides
- replaces the single-file veadk/cloud/harness_app.py
…eate/add/deploy

- harness.yaml (layered, per-component) is the agent spec; env_mapping.to_runtime_env
  reuses veadk flatten_dict for generic fields and maps each component's backend
  connection params to the veadk DATABASE_* env vars the backend reads
- veadk harness create/add/deploy: create scaffolds harness.yaml + .env.example
  (AK/SK only) + domestic-source Dockerfile; add edits harness.yaml; deploy builds
  the image on AgentKit cloud and creates a runtime via sdk.launch
- runtime env names aligned (MODEL_NAME / KNOWLEDGE_BASE_TYPE / LONG_TERM_MEMORY_TYPE
  / SHORT_TERM_MEMORY_TYPE)
…ikey + invoke cmd; add --path takes a dir

- create's harness.yaml now documents every component's supported backends and
  their connection params as comments (uncomment for your chosen type)
- deploy surfaces the created runtime's id / endpoint / api key and a ready-to-run
  invoke command (from the deploy result's config_updates)
- harness add --path now takes the harness directory (consistent with deploy);
  setting a component type preserves its existing connection params
…o harness.yaml

Lets users fill backend connection params from the CLI, e.g.
  veadk harness add --long-term-memory-type viking \
    --set long_term_memory.project=my-proj --set long_term_memory.region=cn-beijing
Values are parsed as YAML scalars (ints/bools stay typed); deploy maps them to
the veadk DATABASE_* env vars.
Replace the generic '--set KEY=VALUE' with explicit flags in the same style as
'--short-term-memory-type', e.g. --long-term-memory-project, --short-term-memory-host.
Flags are auto-generated from env_mapping.COMPONENT_BACKENDS so they stay in sync
with the backends; values are written under the matching component section and
mapped to the veadk DATABASE_* env vars on deploy.
…harness.yaml

- add reuses invoke's HarnessOverrides-generated flags (--model-name/--tools/
  --skills/--system-prompt/--runtime identical in both); --tools/--skills are
  comma-separated; --name (alias --harness-name) for the harness name; invoke
  also accepts --name
- rename component knowledge_base -> knowledgebase (env KNOWLEDGEBASE_TYPE)
- add writes connection params via explicit --<component>-<param> flags
- add output: inline-style lists, and drop unset components (knowledgebase /
  long_term_memory); short_term_memory always shown
- create's harness.yaml annotates each field with its env var + add flag
- register demo tools (get_city_weather / get_location_weather) as built-ins
…rom it + --message

- deploy writes/updates ./harness.json: {name: {url, key, runtime_id}}
- invoke takes --name (reads url/key from harness.json), --message/-m (or positional);
  --url/--key optional overrides; --path for harness.json location
…oy/invoke flow

The reference still described the removed server-side `/harness/add` registration
and the old `--harness/--url/--key` invoke design. Rewrite it around the current
`veadk harness` flow: layered harness.yaml (knowledgebase/KNOWLEDGEBASE_TYPE),
comma-separated --tools/--skills, per-component connection flags, deploy writing
harness.json, and invoke resolving url/key by --name.
The contract tests still imported the removed `/harness/add` design
(`AddHarnessRequest`/`AddHarnessResponse`/`Harness`/`_split_csv`), so the module
failed to import. Rewrite against the current schemas: HarnessOverrides (per-call
overridable) vs HarnessConfig (creation-time, with memory/kb), the InvokeHarness
request/response models, and split_csv.
The server (harness_app) no longer exposes /harness/add — agents are assembled
from env at deploy time, not registered at runtime — so the client 'add' command
posted to a route that 404s. Remove it (and its contract tests); keep the working
'invoke' client and the shared _harness_request helper.
The example documented the removed /harness/add registration, the old
`agentkit config --entry_point ...` deploy flow, and `python -m
veadk.cloud.harness_app` (now a package, no __main__). Rewrite both READMEs
around create -> add -> deploy -> invoke with harness.json, and drop the
orphaned .env.example / requirements.txt (the scaffold is now generated by
`veadk harness create`).
An `auth` block in harness.yaml (or --discovery-url / --allowed-id on deploy)
switches the runtime gateway to custom_jwt: it admits only JWTs issued by the
user pool at `discovery_url` whose audience is in `allowed_ids`. Absent an
`auth` block, deploy keeps the existing key_auth path unchanged.

The auth block is excluded from the flattened runtime env (it configures the
gateway authorizer, not the container). No secret is involved — the user pool /
client / external IdP are set up in the Volcengine Identity console and the CLI
only references discovery_url + allowed_ids. custom_jwt deploys record
{url, runtime_id, auth_type, discovery_url, allowed_ids} in harness.json.

Verified end-to-end against a real user pool: deploy -> runtime Ready with a
custom_jwt authorizer carrying the given discovery_url + allowed_clients, no
key_auth. Docs (zh/en) updated.
@yaozheng-fang yaozheng-fang merged commit 0f47bdc into main Jun 12, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants