mirror of
https://github.com/hanzoai/agent.git
synced 2026-09-11 21:08:51 +00:00
ci: restore the image build under .hanzo/workflows
Every workflow in this repo was deleted and nothing replaced them, so the sole producer of ghcr.io/hanzoai/agent no longer existed anywhere and there was no CI at all. That is silent staleness: no failing run, just an artifact that quietly stops being rebuilt. .github/workflows now holds sync.yml and nothing else, copied verbatim from universe infra/ci/sync.yml. It replaces a mirror-nudge file that POSTed /api/v1/repos/.../mirror-sync and described git.hanzo.ai as a downstream pull mirror; the forge is canonical and refs are pushed to it. Without it a .hanzo/workflows file has nothing to trigger it. deploy.yml restores docker-publish.yml. Two things could not come across as-is: - Its body was one `uses: hanzoai/.github/.github/workflows/docker-build.yml@main`. A private cross-repo reusable workflow does not resolve on the forge, so the amd64 build/push is vendored inline, as hanzoai/bot already does. - It built `context: control-plane`, and no control-plane directory exists on main; the orchestrator was hoisted to the root module in v0.1.1 and the directory survives only on the unmerged consolidate/held-work branch. Restoring that context restores a build that cannot run. It builds Dockerfile.sdk — the one Dockerfile on main whose context exists, previously referenced by nothing despite sdk-* tags being live on the image — and tags it sdk-* so the two Dockerfiles cannot collide in one tag namespace. The tag rule is shell rather than docker/metadata-action, so it is two readable lines with no action semantics to guess at, and it was tested standalone: v* -> :sdk-X.Y.Z + :sdk-latest, main -> :sdk-sha-<sha7> + :sdk-latest. ci.yml replaces tests.yml and test.yml, which checked the same things twice, the second with `|| true` on most steps so it could not fail. It gates what is verifiable on main today — gofmt/build/vet/test for the Go module, and the locked install plus `import agents` for Python, which is what Dockerfile.sdk's builder stage and HEALTHCHECK do. It deliberately does not run ruff, mypy or pytest: `make sync` cannot resolve (requires-python >=3.9, a transitive numpy needs >=3.10), ruff reports 2337 errors, and pytest INTERNALERRORs at collection because a test module sys.exit(1)s at import. tests.yml ran `make sync` first in all five jobs, so none of them could have gone green. Those four are written down in LLM.md as work rather than shipped as a permanently red check, which gets read as broken CI instead of broken code. gofmt over eight files so that gate is real instead of omitted; build, vet and test re-run green afterwards. Alignment whitespace only. Not restored, with reasons in LLM.md: docs.yml (mkdocs gh-deploy is GitHub Pages, never published anything, and Pages is not how we serve sites), publish.yml (pointed at the PyPI package hanzoai/python-sdk owns; deliberately removed earlier), issues.yml (upstream's stale-issue bot). LLM.md documents the chain, records the four broken Python checks, and states the open question this repo actually has: nothing in hanzoai/universe references ghcr.io/hanzoai/agent, so the image has no consumer and no App CR. .gitignore ignored .hanzo/ under an "# IDE" heading, which silently dropped both new workflows from the commit — the same silent-staleness shape this is meant to remove, one level down. Narrowed to .hanzo/* with .hanzo/workflows/ re-included. Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
+87
-45
@@ -1,60 +1,102 @@
|
||||
name: Sync to git.hanzo.ai
|
||||
# DIRECTION: this repo on git.hanzo.ai is a PULL MIRROR fetching github.com/hanzoai/agent.
|
||||
# GitHub is UPSTREAM, git.hanzo.ai is DOWNSTREAM. The giveaway is what this file does:
|
||||
# mirror-sync tells Gitea to PULL, which only makes sense if GitHub is the source.
|
||||
name: sync
|
||||
|
||||
# Carries pushed refs to git.hanzo.ai, the canonical forge, and does nothing
|
||||
# else: build, test and release run natively there.
|
||||
#
|
||||
# This matters beyond labeling: a pull mirror force-updates its refs from upstream on
|
||||
# every fetch, so anything committed directly on git.hanzo.ai is DISCARDED on the next
|
||||
# sync. Do not treat the mirror as writable, and do not reword this into a "native on
|
||||
# git.hanzo.ai" claim — that is the intended end state, not today's.
|
||||
#
|
||||
# What IS true: CI/CD runs on git.hanzo.ai — arcd executes .hanzo/workflows/ on the
|
||||
# Hanzo git-runner. Making git.hanzo.ai canonical means converting the repo
|
||||
# pull-mirror -> native and flipping the write path; an ops migration, not a config edit.
|
||||
#
|
||||
# So this nudge is a LATENCY fix, not a canonicality one: it asks Gitea to pull now
|
||||
# instead of waiting out the ~10-minute mirror interval, so arcd sees the new commit
|
||||
# sooner. Without this file the repo still mirrors — just later.
|
||||
#
|
||||
# IDEMPOTENT: mirror-sync just tells Gitea to pull HEAD, so N nudges == 1 (same latest
|
||||
# state); concurrency coalesces a burst of pushes to a single in-flight sync. FAST: no
|
||||
# checkout, one bounded curl, hard timeouts. FAIL-SOFT: a missing token or hiccup never
|
||||
# fails the push (the App webhook still mirrors). Set HANZO_GIT_TOKEN to enable the nudge.
|
||||
# Repo-agnostic. owner/name come from ${{ github.repository }}, so this file is
|
||||
# dropped into every repo unchanged as .github/workflows/sync.yml and is the
|
||||
# only workflow GitHub is permitted to run.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
# '**' matches slashes; '*' does not, and would skip feature/foo.
|
||||
branches: ['**']
|
||||
tags: ['**']
|
||||
workflow_dispatch:
|
||||
|
||||
# Only the newest push's sync needs to run — cancel any older in-flight one (it would
|
||||
# pull a now-stale HEAD). This is what makes rapid pushes idempotent + cheap.
|
||||
# Serialize per ref. Never cancel: a cancelled run drops that ref and nothing
|
||||
# reconciles it afterwards.
|
||||
concurrency:
|
||||
group: sync-git-hanzo-ai
|
||||
cancel-in-progress: true
|
||||
group: sync-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
# `.github/workflows` is also on Gitea's WORKFLOW_DIRS, so with Actions enabled on
|
||||
# the mirror this file runs THERE too on every sync — where asking git.hanzo.ai to
|
||||
# pull is circular. github.server_url is setting.AppURL on Gitea
|
||||
# (services/actions/context.go:89), so this is the exact test for "am I upstream".
|
||||
if: ${{ github.server_url == 'https://github.com' }}
|
||||
# .github/workflows is also on the forge's own workflow search path, so this
|
||||
# file executes there too in any repo without .hanzo/workflows, where it
|
||||
# would push the forge to itself. server_url is the forge's AppURL, which
|
||||
# makes this the test for "running on GitHub".
|
||||
if: github.server_url == 'https://github.com'
|
||||
# GitHub-hosted on purpose. This is the one workflow that must run ON GitHub,
|
||||
# and the self-hosted pool that used to serve it is retired — a job asking for
|
||||
# it now queues forever against a label nothing answers. Carrying refs is a
|
||||
# push, not a build, so it does not belong on the build fabric anyway: builds
|
||||
# run natively on git.hanzo.ai, which is the whole point of this file.
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
timeout-minutes: 15
|
||||
|
||||
steps:
|
||||
- name: Nudge git.hanzo.ai to pull HEAD (mirror-sync)
|
||||
continue-on-error: true
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
persist-credentials: false
|
||||
|
||||
- name: Push refs to git.hanzo.ai
|
||||
env:
|
||||
HANZO_GIT_TOKEN: ${{ secrets.HANZO_GIT_TOKEN }}
|
||||
FORGE: https://git.hanzo.ai
|
||||
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||
run: |
|
||||
set -u
|
||||
if [ -z "${HANZO_GIT_TOKEN:-}" ]; then
|
||||
echo "HANZO_GIT_TOKEN not set — relying on the mirror App webhook. Skipping nudge."
|
||||
exit 0
|
||||
set -euo pipefail
|
||||
|
||||
if [ -z "${GIT_TOKEN}" ]; then
|
||||
echo "::error::GIT_TOKEN is unset, so this push never reached the canonical forge. Add the org secret."
|
||||
exit 1
|
||||
fi
|
||||
if curl -fsS --max-time 20 --retry 2 --retry-delay 2 -X POST \
|
||||
-H "Authorization: token ${HANZO_GIT_TOKEN}" \
|
||||
"https://git.hanzo.ai/api/v1/repos/hanzoai/agent/mirror-sync"; then
|
||||
echo "git.hanzo.ai mirror-sync triggered"
|
||||
else
|
||||
echo "mirror-sync nudge failed (non-fatal) — the App webhook still mirrors"
|
||||
|
||||
REMOTE="${FORGE}/${GITHUB_REPOSITORY}.git"
|
||||
|
||||
# The forge reads the token from the basic-auth password and ignores
|
||||
# the username. base64 of a secret is not masked automatically.
|
||||
AUTH="$(printf 'x-access-token:%s' "${GIT_TOKEN}" | base64 -w0)"
|
||||
echo "::add-mask::${AUTH}"
|
||||
# Host-scoped, so the forge token is never sent to github.com.
|
||||
git config --local "http.${FORGE}/.extraheader" "Authorization: Basic ${AUTH}"
|
||||
|
||||
# Reachability is the only transient failure here, so it is the only
|
||||
# thing retried. ls-remote exits 0 on an existing empty repo and
|
||||
# non-zero when the forge is down or the repo is absent.
|
||||
ERR="$(mktemp)"
|
||||
REACHED=""
|
||||
for attempt in 1 2 3; do
|
||||
if git ls-remote "${REMOTE}" >/dev/null 2>"${ERR}"; then
|
||||
REACHED=1
|
||||
break
|
||||
fi
|
||||
echo "forge probe failed (attempt ${attempt}/3): $(cat "${ERR}")"
|
||||
if [ "${attempt}" -lt 3 ]; then
|
||||
sleep $((attempt * 5))
|
||||
fi
|
||||
done
|
||||
if [ -z "${REACHED}" ]; then
|
||||
echo "::error::git.hanzo.ai is unreachable or ${GITHUB_REPOSITORY} does not exist there. $(cat "${ERR}")"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Additive and fast-forward-only: no leading '+', no --force, no
|
||||
# --prune, no --mirror. Tags go every run so a tag that missed its own
|
||||
# event still lands; git refuses to move one that already differs.
|
||||
REFS=('refs/tags/*:refs/tags/*')
|
||||
case "${GITHUB_REF}" in
|
||||
refs/heads/*) REFS+=("${GITHUB_REF}:${GITHUB_REF}") ;;
|
||||
esac
|
||||
|
||||
# Not --atomic: a diverged ref must not hold back the refs that are
|
||||
# clean. Rejections still fail the job.
|
||||
if ! git push "${REMOTE}" "${REFS[@]}"; then
|
||||
echo "::error::git.hanzo.ai rejected a ref for ${GITHUB_REPOSITORY}. The forge is canonical and is never force-updated from here; reconcile the diverged branch or tag by hand."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
+6
-1
@@ -157,4 +157,9 @@ control-plane/web/client/node_modules/
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.hanzo/
|
||||
# Local scratch under .hanzo/ stays ignored, but not .hanzo/workflows: that is
|
||||
# where git.hanzo.ai reads this repo's CI from, so ignoring it silently drops
|
||||
# the build. `.hanzo/*` rather than `.hanzo/` so git descends far enough to see
|
||||
# the negation.
|
||||
.hanzo/*
|
||||
!.hanzo/workflows/
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# Native CI on git.hanzo.ai.
|
||||
#
|
||||
# This replaces tests.yml and test.yml, which were two workflows checking the
|
||||
# same things (the second with `|| true` on most steps, so it could not fail).
|
||||
# One file, one way.
|
||||
#
|
||||
# It gates what is actually verifiable on main today, and no more. Measured on
|
||||
# this commit:
|
||||
#
|
||||
# go build/vet/test ./... pass <- gated below
|
||||
# uv sync --frozen pass <- gated below
|
||||
# make sync (uv sync --all-extras --all-packages --group dev)
|
||||
# CANNOT RESOLVE: requires-python is >=3.9
|
||||
# and a transitive numpy needs >=3.10
|
||||
# make lint (ruff check) 2337 errors
|
||||
# make tests (pytest) INTERNALERROR at collection — a test module
|
||||
# sys.exit(1)s at import without ANTHROPIC_API_KEY
|
||||
#
|
||||
# tests.yml ran `make sync` as the first step of all five of its jobs, so none of
|
||||
# them could have gone green here. Restoring it would add a workflow that is red
|
||||
# on arrival for reasons no CI change can fix, and a permanently red check is
|
||||
# read as broken CI rather than as broken code. The three failures above are
|
||||
# recorded in LLM.md as work, not hidden behind `|| true` or a missing check.
|
||||
name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['**']
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
go:
|
||||
runs-on: hanzo-build-linux-amd64
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
# gofmt reports on stdout and exits 0, so the file list is the check.
|
||||
- name: gofmt
|
||||
run: |
|
||||
set -euo pipefail
|
||||
unformatted="$(gofmt -l .)"
|
||||
if [ -n "${unformatted}" ]; then
|
||||
echo "::error::gofmt would rewrite these files:"
|
||||
echo "${unformatted}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- run: go build ./...
|
||||
- run: go vet ./...
|
||||
- run: go test ./...
|
||||
|
||||
python:
|
||||
runs-on: hanzo-build-linux-amd64
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
with:
|
||||
enable-cache: true
|
||||
|
||||
# --frozen, so this fails when uv.lock and pyproject.toml disagree rather
|
||||
# than silently re-resolving to something the image will never install.
|
||||
# It is the same step Dockerfile.sdk's builder stage runs, which is why a
|
||||
# break here means the image cannot be built.
|
||||
- name: the lock installs
|
||||
run: uv sync --frozen --no-dev
|
||||
|
||||
# Dockerfile.sdk's HEALTHCHECK is `import agents`, and its CMD is
|
||||
# `python -m agents`. If the package does not import, the container is
|
||||
# unhealthy the moment it starts.
|
||||
- name: the package imports
|
||||
run: uv run --no-sync python -c "import agents; print(agents.__name__)"
|
||||
@@ -0,0 +1,109 @@
|
||||
# Builds and pushes ghcr.io/hanzoai/agent. Nothing else.
|
||||
#
|
||||
# This is .github/workflows/docker-publish.yml restored here: it was the sole
|
||||
# producer of this image and was deleted with no replacement, which is exactly
|
||||
# how an artifact goes stale with no failing run to show it.
|
||||
#
|
||||
# Two things could not come across verbatim.
|
||||
#
|
||||
# 1. Its body was one `uses: hanzoai/.github/.github/workflows/docker-build.yml@main`,
|
||||
# and a private cross-repo reusable workflow does not resolve on the forge, so
|
||||
# the amd64 build/push it performed is vendored inline, the way hanzoai/bot
|
||||
# already vendors it.
|
||||
# 2. It built `context: control-plane`, and no control-plane directory exists on
|
||||
# main — the orchestrator was hoisted into the root module (tag v0.1.1, "drop
|
||||
# control-plane/pkg nesting"); the directory survives only on the unmerged
|
||||
# consolidate/held-work branch, and deployments/docker/Dockerfile.control-plane
|
||||
# still COPYs from it. Restoring that context restores a build that cannot
|
||||
# run. This builds Dockerfile.sdk, the one Dockerfile on main whose context
|
||||
# exists, and tags it sdk-* to match what is already published here.
|
||||
#
|
||||
# No deploy step: the tag that runs is named by a CR in hanzoai/universe, not by
|
||||
# CI. Nothing in universe references this image yet — see LLM.md.
|
||||
name: deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags: ['v*']
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: deploy-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
image:
|
||||
# The forge's git-runner advertises this label (GIT_RUNNER_LABELS in
|
||||
# universe infra/k8s/git-runner/statefulset.yaml). A label nothing
|
||||
# advertises does not fail — it queues to the timeout, which is silence.
|
||||
runs-on: hanzo-build-linux-amd64
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Computed here rather than by docker/metadata-action: the rule is two
|
||||
# lines of shell, and shell is the same on both forges. The sdk- prefix
|
||||
# keeps this Dockerfile's tags from colliding with any other image built
|
||||
# out of this repo.
|
||||
# v* tag -> :sdk-X.Y.Z + :sdk-latest
|
||||
# main push -> :sdk-sha-<sha7> + :sdk-latest
|
||||
- id: tags
|
||||
run: |
|
||||
set -euo pipefail
|
||||
image=ghcr.io/hanzoai/agent
|
||||
case "${GITHUB_REF}" in
|
||||
refs/tags/v*) primary="${image}:sdk-${GITHUB_REF#refs/tags/v}" ;;
|
||||
*) primary="${image}:sdk-sha-$(printf '%s' "${GITHUB_SHA}" | cut -c1-7)" ;;
|
||||
esac
|
||||
{
|
||||
echo 'list<<EOF'
|
||||
echo "${primary}"
|
||||
echo "${image}:sdk-latest"
|
||||
echo 'EOF'
|
||||
} >> "${GITHUB_OUTPUT}"
|
||||
echo "publishing ${primary} and ${image}:sdk-latest"
|
||||
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
driver: docker-container
|
||||
driver-opts: network=host
|
||||
|
||||
# Without this the push is unauthenticated and the registry 403s.
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ secrets.GHCR_USER }}
|
||||
password: ${{ secrets.GHCR_TOKEN }}
|
||||
|
||||
- uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.sdk
|
||||
platforms: linux/amd64
|
||||
tags: ${{ steps.tags.outputs.list }}
|
||||
provenance: false
|
||||
push: true
|
||||
|
||||
# build-push-action can exit 0 before the manifest resolves, so a green
|
||||
# run could still mean a later ImagePullBackOff. Prove it pulls.
|
||||
- name: the pushed image resolves
|
||||
run: |
|
||||
set -euo pipefail
|
||||
for img in ${{ steps.tags.outputs.list }}; do
|
||||
for i in 1 2 3 4 5 6; do
|
||||
if docker buildx imagetools inspect "${img}" >/dev/null 2>&1; then
|
||||
echo "resolved ${img}"
|
||||
break
|
||||
fi
|
||||
if [ "${i}" = 6 ]; then
|
||||
echo "::error::pushed image never resolved: ${img}"
|
||||
exit 1
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
done
|
||||
@@ -52,3 +52,70 @@ make test # Run test suite
|
||||
- Pydantic models for configuration
|
||||
- Async-first design
|
||||
- MCP (Model Context Protocol) for tool integration
|
||||
|
||||
## How this ships
|
||||
|
||||
One way, and it runs on our own stack:
|
||||
|
||||
push -> github.com/hanzoai/agent (a mirror)
|
||||
.github/workflows/sync.yml carries refs onward
|
||||
-> git.hanzo.ai/hanzoai/agent CANONICAL
|
||||
.hanzo/workflows/ci.yml the checks
|
||||
.hanzo/workflows/deploy.yml builds ghcr.io/hanzoai/agent
|
||||
|
||||
**git.hanzo.ai is canonical; GitHub is a mirror.** `.github/workflows/` holds
|
||||
exactly one file, `sync.yml`, and its only job is getting refs to the forge.
|
||||
Every build, check and deploy is a workflow under `.hanzo/workflows/`, which the
|
||||
forge reads. `.hanzo/workflows` uses GitHub Actions syntax, so a workflow moves
|
||||
between the two by changing directory and nothing else.
|
||||
|
||||
`deploy.yml` builds `Dockerfile.sdk` and tags `sdk-*`. It does **not** build
|
||||
`control-plane`, which is what the workflow it replaces did: there is no
|
||||
`control-plane/` directory on `main`. The orchestrator was hoisted into the root
|
||||
Go module (tag `v0.1.1`, "drop control-plane/pkg nesting"), and the directory
|
||||
survives only on the unmerged `consolidate/held-work` branch. Two things still
|
||||
point at the old layout and are therefore stale, not load-bearing:
|
||||
`deployments/docker/Dockerfile.control-plane` (COPYs from `control-plane/`) and
|
||||
`Makefile.agents` (`cd control-plane && go build`).
|
||||
|
||||
A build never deploys itself. Nothing in `hanzoai/universe` references
|
||||
`ghcr.io/hanzoai/agent`, so this image has **no consumer and no App CR**. That is
|
||||
a real open question rather than an oversight: either a CR should exist, or the
|
||||
image should stop being published. It is published today because it was
|
||||
published yesterday, and because deleting the only producer of a live artifact is
|
||||
how something goes stale with nothing red to show it.
|
||||
|
||||
### What is checked, and what is not
|
||||
|
||||
`ci.yml` gates the Go module (`gofmt`, `go build`, `go vet`, `go test` — all
|
||||
pass) and the Python install the image depends on (`uv sync --frozen --no-dev`,
|
||||
then `import agents`, matching `Dockerfile.sdk`'s `HEALTHCHECK`).
|
||||
|
||||
It deliberately does not run the Python lint/type/test suite, because none of it
|
||||
passes on `main`:
|
||||
|
||||
| Command | State |
|
||||
|---|---|
|
||||
| `make sync` | **cannot resolve** — `requires-python` is `>=3.9`, a transitive `numpy` needs `>=3.10` |
|
||||
| `make lint` (`ruff check`) | 2337 errors |
|
||||
| `make tests` (`pytest`) | `INTERNALERROR` at collection; a test module `sys.exit(1)`s at import without `ANTHROPIC_API_KEY` |
|
||||
| `make old_version_tests` | runs 3.9, the version `make sync` cannot resolve |
|
||||
|
||||
`tests.yml` ran `make sync` as the first step of all five of its jobs, so none of
|
||||
them could have gone green. Fixing those four is real work with an owner; a
|
||||
permanently red check is read as broken CI rather than as broken code, so the
|
||||
debt is written down here instead.
|
||||
|
||||
### Deleted rather than migrated
|
||||
|
||||
- `test.yml` — a second copy of `tests.yml` with `|| true` on most steps, so it
|
||||
could not fail. Folded into one `ci.yml`.
|
||||
- `docs.yml` — `make deploy-docs` is `mkdocs gh-deploy`, i.e. GitHub Pages. There
|
||||
is no `gh-pages` branch and `hanzoai.github.io/agent` 404s, so it never
|
||||
published anything. Pages is not how Hanzo serves sites.
|
||||
- `publish.yml` — published this repo's dist to PyPI. `pyproject.toml` is
|
||||
`hanzo-agent 0.0.4`; when it was named `hanzoai` this workflow pointed at the
|
||||
package `hanzoai/python-sdk` owns (now 3.1.1), so a release here could have
|
||||
published a downgrade over it. Removed in "fix(pypi): stop publishing this
|
||||
repo's dist as hanzoai" and deliberately not restored.
|
||||
- `issues.yml` — upstream's stale-issue bot.
|
||||
|
||||
@@ -26,8 +26,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
luxlog "github.com/luxfi/log"
|
||||
openai "github.com/hanzoai/go-openai"
|
||||
luxlog "github.com/luxfi/log"
|
||||
"github.com/zap-proto/zip"
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -11,8 +11,8 @@ import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
luxlog "github.com/luxfi/log"
|
||||
openai "github.com/hanzoai/go-openai"
|
||||
luxlog "github.com/luxfi/log"
|
||||
fiber "github.com/zap-proto/fiber/v3"
|
||||
"github.com/zap-proto/zip"
|
||||
)
|
||||
|
||||
+69
-69
@@ -28,8 +28,8 @@ func TestNew(t *testing.T) {
|
||||
{
|
||||
name: "valid config",
|
||||
cfg: Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
},
|
||||
wantErr: false,
|
||||
@@ -42,7 +42,7 @@ func TestNew(t *testing.T) {
|
||||
{
|
||||
name: "missing NodeID",
|
||||
cfg: Config{
|
||||
Version: "1.0.0",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
},
|
||||
wantErr: true,
|
||||
@@ -50,7 +50,7 @@ func TestNew(t *testing.T) {
|
||||
{
|
||||
name: "missing Version",
|
||||
cfg: Config{
|
||||
NodeID: "node-1",
|
||||
NodeID: "node-1",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
},
|
||||
wantErr: true,
|
||||
@@ -69,8 +69,8 @@ func TestNew(t *testing.T) {
|
||||
{
|
||||
name: "defaults applied",
|
||||
cfg: Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
},
|
||||
wantErr: false,
|
||||
@@ -84,8 +84,8 @@ func TestNew(t *testing.T) {
|
||||
{
|
||||
name: "with AIConfig",
|
||||
cfg: Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
AIConfig: &ai.Config{
|
||||
APIKey: "test-key",
|
||||
@@ -101,10 +101,10 @@ func TestNew(t *testing.T) {
|
||||
{
|
||||
name: "invalid AIConfig",
|
||||
cfg: Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
AIConfig: &ai.Config{
|
||||
AIConfig: &ai.Config{
|
||||
// Missing required fields
|
||||
},
|
||||
},
|
||||
@@ -131,10 +131,10 @@ func TestNew(t *testing.T) {
|
||||
|
||||
func TestRegisterReasoner(t *testing.T) {
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -155,10 +155,10 @@ func TestRegisterReasoner(t *testing.T) {
|
||||
|
||||
func TestRegisterReasoner_WithOptions(t *testing.T) {
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -182,10 +182,10 @@ func TestRegisterReasoner_WithOptions(t *testing.T) {
|
||||
|
||||
func TestRegisterReasoner_NilHandler(t *testing.T) {
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -225,7 +225,7 @@ func TestInitialize(t *testing.T) {
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
TeamID: "team-1",
|
||||
HanzoAgentsURL: server.URL,
|
||||
HanzoAgentsURL: server.URL,
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
DisableLeaseLoop: true, // Disable for testing
|
||||
}
|
||||
@@ -244,10 +244,10 @@ func TestInitialize(t *testing.T) {
|
||||
|
||||
func TestInitialize_NoReasoners(t *testing.T) {
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -260,10 +260,10 @@ func TestInitialize_NoReasoners(t *testing.T) {
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -289,10 +289,10 @@ func TestHandler(t *testing.T) {
|
||||
|
||||
func TestHandleReasoner_Sync(t *testing.T) {
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -323,10 +323,10 @@ func TestHandleReasoner_Sync(t *testing.T) {
|
||||
|
||||
func TestHandleReasoner_NotFound(t *testing.T) {
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -347,10 +347,10 @@ func TestHandleReasoner_NotFound(t *testing.T) {
|
||||
|
||||
func TestHandleReasoner_WrongMethod(t *testing.T) {
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -371,10 +371,10 @@ func TestHandleReasoner_WrongMethod(t *testing.T) {
|
||||
|
||||
func TestHandleReasoner_Error(t *testing.T) {
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -428,10 +428,10 @@ func TestCall(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: server.URL,
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -485,10 +485,10 @@ func TestCall_ErrorHandling(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: server.URL,
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -523,10 +523,10 @@ func TestAI(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
AIConfig: &ai.Config{
|
||||
APIKey: "test-key",
|
||||
BaseURL: server.URL,
|
||||
@@ -545,10 +545,10 @@ func TestAI(t *testing.T) {
|
||||
|
||||
func TestAI_NotConfigured(t *testing.T) {
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
// No AIConfig
|
||||
}
|
||||
|
||||
@@ -582,10 +582,10 @@ func TestAIStream(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
AIConfig: &ai.Config{
|
||||
APIKey: "test-key",
|
||||
BaseURL: server.URL,
|
||||
@@ -627,10 +627,10 @@ func TestAIStream(t *testing.T) {
|
||||
|
||||
func TestAIStream_NotConfigured(t *testing.T) {
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "https://api.example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -688,13 +688,13 @@ func TestHandleReasonerAsyncPostsStatus(t *testing.T) {
|
||||
defer callbackServer.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
TeamID: "team",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
TeamID: "team",
|
||||
HanzoAgentsURL: callbackServer.URL,
|
||||
ListenAddress: ":0",
|
||||
PublicURL: "http://localhost:0",
|
||||
Logger: log.New(io.Discard, "[test] ", 0),
|
||||
ListenAddress: ":0",
|
||||
PublicURL: "http://localhost:0",
|
||||
Logger: log.New(io.Discard, "[test] ", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -770,10 +770,10 @@ func TestChildContextGeneratesRunID(t *testing.T) {
|
||||
|
||||
func TestBuildChildContext(t *testing.T) {
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "http://example.com",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
ag, err := New(cfg)
|
||||
@@ -836,10 +836,10 @@ func TestCallLocalEmitsEvents(t *testing.T) {
|
||||
defer eventServer.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: eventServer.URL,
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
ag, err := New(cfg)
|
||||
|
||||
@@ -41,8 +41,8 @@ func TestDiscoverJSON(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
a, err := New(Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: server.URL,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -77,8 +77,8 @@ func TestDiscoverCompactAndXML(t *testing.T) {
|
||||
defer xmlServer.Close()
|
||||
|
||||
aCompact, err := New(Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: compactServer.URL,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -90,8 +90,8 @@ func TestDiscoverCompactAndXML(t *testing.T) {
|
||||
assert.Equal(t, "a1", compactResult.Compact.Reasoners[0].AgentID)
|
||||
|
||||
aXML, err := New(Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: xmlServer.URL,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -106,8 +106,8 @@ func TestDiscoverCompactAndXML(t *testing.T) {
|
||||
|
||||
func TestDiscoverRejectsInvalidFormat(t *testing.T) {
|
||||
a, err := New(Config{
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
NodeID: "node-1",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: "http://localhost:8080",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -355,8 +355,8 @@ func (s *ScopedMemory) GetTyped(ctx context.Context, key string, dest any) error
|
||||
// InMemoryBackend provides a thread-safe in-memory implementation of MemoryBackend.
|
||||
// Data is lost when the process exits.
|
||||
type InMemoryBackend struct {
|
||||
mu sync.RWMutex
|
||||
data map[string]map[string]any // "scope:scopeID" -> key -> value
|
||||
mu sync.RWMutex
|
||||
data map[string]map[string]any // "scope:scopeID" -> key -> value
|
||||
vectorData map[string]map[string]vectorRecord // "scope:scopeID" -> key -> vectorRecord
|
||||
}
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@ import (
|
||||
|
||||
// MemoryMetrics holds memory measurement results
|
||||
type MemoryMetrics struct {
|
||||
Name string
|
||||
AllocBytes uint64
|
||||
TotalAlloc uint64
|
||||
HeapAlloc uint64
|
||||
HeapInuse uint64
|
||||
NumGC uint32
|
||||
Iterations int
|
||||
Duration time.Duration
|
||||
Name string
|
||||
AllocBytes uint64
|
||||
TotalAlloc uint64
|
||||
HeapAlloc uint64
|
||||
HeapInuse uint64
|
||||
NumGC uint32
|
||||
Iterations int
|
||||
Duration time.Duration
|
||||
}
|
||||
|
||||
// PerIterationKB returns memory per iteration in KB
|
||||
|
||||
+32
-32
@@ -37,10 +37,10 @@ func TestNote_Basic(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: server.URL + "/api/v1", // Will be converted to /api/ui/v1
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -95,10 +95,10 @@ func TestNotef_Formatted(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: server.URL + "/api/v1",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -132,10 +132,10 @@ func TestNote_NoTags(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: server.URL + "/api/v1",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -189,10 +189,10 @@ func TestNote_ServerError(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: server.URL + "/api/v1",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -221,19 +221,19 @@ func TestNote_URLConversion(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
controlPlaneURL string
|
||||
expectedPath string
|
||||
name string
|
||||
controlPlaneURL string
|
||||
expectedPath string
|
||||
}{
|
||||
{
|
||||
name: "Standard /api/v1 URL",
|
||||
name: "Standard /api/v1 URL",
|
||||
controlPlaneURL: server.URL + "/api/v1",
|
||||
expectedPath: "/api/ui/v1/executions/note",
|
||||
expectedPath: "/api/ui/v1/executions/note",
|
||||
},
|
||||
{
|
||||
name: "URL without /api/v1",
|
||||
name: "URL without /api/v1",
|
||||
controlPlaneURL: server.URL,
|
||||
expectedPath: "/api/ui/v1/executions/note",
|
||||
expectedPath: "/api/ui/v1/executions/note",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -243,10 +243,10 @@ func TestNote_URLConversion(t *testing.T) {
|
||||
requestPath = ""
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: tt.controlPlaneURL,
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -280,11 +280,11 @@ func TestNote_WithToken(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: server.URL + "/api/v1",
|
||||
Token: "test-token-123",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Token: "test-token-123",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -314,10 +314,10 @@ func TestNote_FireAndForget(t *testing.T) {
|
||||
defer slowServer.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: slowServer.URL + "/api/v1",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
@@ -348,10 +348,10 @@ func TestNote_MultipleNotes(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
cfg := Config{
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
NodeID: "test-node",
|
||||
Version: "1.0.0",
|
||||
HanzoAgentsURL: server.URL + "/api/v1",
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
Logger: log.New(io.Discard, "", 0),
|
||||
}
|
||||
|
||||
agent, err := New(cfg)
|
||||
|
||||
@@ -41,9 +41,9 @@ func TestDefaultConfig(t *testing.T) {
|
||||
}()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
setupEnv func()
|
||||
checkConfig func(t *testing.T, cfg *Config)
|
||||
name string
|
||||
setupEnv func()
|
||||
checkConfig func(t *testing.T, cfg *Config)
|
||||
}{
|
||||
{
|
||||
name: "default OpenAI config",
|
||||
|
||||
Reference in New Issue
Block a user