@amd-gaia/gaia 0.2.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1005 -72
- package/README.md +103 -13
- package/SCORECARD.md +180 -0
- package/SKILL.md +239 -71
- package/SPEC.md +369 -23
- package/binaries.lock.json +25 -25
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +45 -12
- package/dist/cli.js.map +1 -1
- package/dist/lifecycle.d.ts +2 -2
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +9 -3
- package/dist/lifecycle.js.map +1 -1
- package/package.json +2 -1
package/SPEC.md
CHANGED
|
@@ -135,6 +135,10 @@ failure anywhere: it is a 404 on a user's first run.
|
|
|
135
135
|
| `linux-arm64` | **no** | yes |
|
|
136
136
|
| `win32-arm64` | **no** | yes |
|
|
137
137
|
|
|
138
|
+
The `linux-x64` sidecar is built on a glibc 2.34 floor (#5545), so it needs
|
|
139
|
+
glibc 2.34 or newer at run time (Ubuntu 22.04, Debian 12, RHEL 9 or later).
|
|
140
|
+
On an older distro it fails at launch.
|
|
141
|
+
|
|
138
142
|
`terminal-hub` publishes all six. The sidecar is a PyInstaller freeze, produced on
|
|
139
143
|
the platform it targets, and there is no arm64 Linux or arm64 Windows freeze.
|
|
140
144
|
Resolving `sidecar` on those two keys raises `PlatformError` naming the platform
|
|
@@ -254,7 +258,7 @@ the header.
|
|
|
254
258
|
| ------------------ | --------------------------------------- |
|
|
255
259
|
| Default port | `8141` (`DEFAULT_PORT` in `server.py`) |
|
|
256
260
|
| Reserved port | `4001` — refused with a `RangeError` |
|
|
257
|
-
| Contract version | `API_VERSION = "2.
|
|
261
|
+
| Contract version | `API_VERSION = "2.24"` |
|
|
258
262
|
| Agent id / prefix | `gaia` → `/v1/gaia/...` |
|
|
259
263
|
|
|
260
264
|
### 5.1 Endpoints
|
|
@@ -265,13 +269,204 @@ the header.
|
|
|
265
269
|
| `GET` | `/version` | Contract probe. `{ "apiVersion", "agentVersion" }` |
|
|
266
270
|
| `GET` | `/v1/gaia/version` | The TUI's negotiation probe |
|
|
267
271
|
| `GET` | `/v1/gaia/init` | Readiness detail (Lemonade, model, connectors) |
|
|
272
|
+
| `GET` | `/v1/gaia/memory` | The `/memory` snapshot (contract ≥ 2.13) |
|
|
273
|
+
| `GET` | `/v1/gaia/skills` | The skills the agent can load (contract ≥ 2.17) |
|
|
268
274
|
| `POST` | `/v1/gaia/query` | The streaming surface (`text/event-stream`) |
|
|
269
275
|
| `POST` | `/v1/gaia/query/{run_id}/cancel` | Cancel a run by its host-minted `run_id` |
|
|
270
276
|
| `POST` | `/v1/gaia/query/{run_id}/respond`| Answer a mid-run question |
|
|
277
|
+
| `POST` | `/v1/gaia/query/{run_id}/tool_decision` | Answer a confirmation-gated tool (≥ 2.14) |
|
|
278
|
+
| `POST` | `/v1/gaia/sessions/{session_id}/bypass` | Stop the prompts for gated tools in one session (≥ 2.14); the shell gates stay on, so a gated shell command still answers `needs_confirmation` |
|
|
279
|
+
| `POST` | `/v1/gaia/sessions/{session_id}/internet` | Turn one session's internet on or off from its next tool call, including in a turn already running (≥ 2.23) |
|
|
280
|
+
| `POST` | `/v1/gaia/query/{run_id}/followup`| Add to a run already in flight (contract ≥ 2.15) |
|
|
281
|
+
|
|
282
|
+
#### `/query` request body
|
|
283
|
+
|
|
284
|
+
The full, machine-readable contract — every field, type, and which are
|
|
285
|
+
required — is the committed
|
|
286
|
+
[`openapi.gaia.json`](https://github.com/amd/gaia/blob/main/hub/agents/gaia/python/openapi.gaia.json),
|
|
287
|
+
regenerated from the live routes by `python -m gaia_agent.export_openapi` and
|
|
288
|
+
checked for drift in CI — the same pattern as the email agent's own
|
|
289
|
+
`openapi.email.json`. Required: **`query`**, **`run_id`**,
|
|
290
|
+
**`context`** — `additionalProperties: false`, so an unrecognized field or a
|
|
291
|
+
missing required one is `422` before the agent runs. `run_id` must parse as a
|
|
292
|
+
UUID (`uuid.UUID(v)`); a non-UUID string is also `422`. Everything else
|
|
293
|
+
(`model`, `provider`, `max_steps`, `session_id`, `can_answer_questions`,
|
|
294
|
+
`documents`, `allowed_paths`, `working_directory`, `memory`, `internet_off`,
|
|
295
|
+
`changes_turn_id`, `surface`) is optional.
|
|
296
|
+
|
|
297
|
+
`context` is the transcript you push. It replaces the agent's history for the
|
|
298
|
+
turn. If it doesn't fit beside the agent's prompt and tools in the model's
|
|
299
|
+
window, the agent drops the oldest whole turns until it does, and streams a
|
|
300
|
+
`status` event saying older messages are out of the model's view. A single turn
|
|
301
|
+
bigger than the whole budget is kept, not dropped: its longest messages are cut
|
|
302
|
+
with a note saying how many characters are missing, so its answer stays in view.
|
|
303
|
+
|
|
304
|
+
`documents` (contract ≥ 2.16) carries the absolute paths of the files the user
|
|
305
|
+
attached to the conversation. Send the whole set on every turn. Before the turn
|
|
306
|
+
runs, the agent indexes the ones it has not indexed yet, so a file attached
|
|
307
|
+
mid-conversation is read on the next turn. Each path is granted as that exact
|
|
308
|
+
file, never its folder. A relative path is a `422`. A missing file, a folder, or
|
|
309
|
+
a secret the path policy refuses is reported as not indexed in the turn's
|
|
310
|
+
`index_documents` step, and the turn still runs. Pre-2.16 binaries `422` the
|
|
311
|
+
field, so probe `/version` before sending it.
|
|
312
|
+
|
|
313
|
+
`allowed_paths` (contract ≥ 2.18) carries the conversation's file scope as the
|
|
314
|
+
caller computed it, so the agent works in the folders the caller's UI shows. A
|
|
315
|
+
new session is built with exactly that scope; a retained session gains any
|
|
316
|
+
entry it lacks and drops none until the session ends — neither what the user
|
|
317
|
+
granted mid-chat nor an entry the caller has since stopped sending. `GAIA_ALLOWED_PATHS`
|
|
318
|
+
still narrows it, and a path outside it is asked about, never silently
|
|
319
|
+
granted. Omit it for the agent's default scope. Pre-2.18 binaries `422` the
|
|
320
|
+
field. Whatever the scope, its existing folders are named in the system prompt
|
|
321
|
+
once, when the session is built, with GAIA's documents folder first; a folder
|
|
322
|
+
added to a retained session later is usable but not named. A caller that omits
|
|
323
|
+
the field, like the TUI, gets the default scope (the user's home folder) named.
|
|
324
|
+
|
|
325
|
+
`working_directory` (contract ≥ 2.24) is the absolute chat workspace used as the
|
|
326
|
+
base for relative file paths. It is separate from `allowed_paths`: the latter is
|
|
327
|
+
an access allowlist, while this field determines where a bare `notes.txt` lands.
|
|
328
|
+
New and retained sessions use it for relative reads, writes, edits and approval
|
|
329
|
+
prompts, so the path shown to the user matches the file that is actually changed.
|
|
330
|
+
A relative or empty value is a `422`; send it only when `/version` reports 2.24 or
|
|
331
|
+
later.
|
|
332
|
+
|
|
333
|
+
`memory` (contract ≥ 2.18) is `"on"`, `"private"` (a private chat) or `"off"`
|
|
334
|
+
(memory turned off in the caller's settings). Under `"private"` or `"off"` the
|
|
335
|
+
turn saves nothing to memory, including the errors and lessons the agent saves
|
|
336
|
+
on its own. A retained session keeps the last value, so send it every turn;
|
|
337
|
+
omit it to leave memory as the agent has it. `"on"` never turns memory on when
|
|
338
|
+
the agent has none (no store, or `GAIA_MEMORY_DISABLED=1`). Pre-2.18 binaries
|
|
339
|
+
`422` the field.
|
|
340
|
+
|
|
341
|
+
`internet_off` (contract ≥ 2.23) is `true` when the caller's chat has the
|
|
342
|
+
Internet switched off and `false` when it is on. With `true` the turn refuses
|
|
343
|
+
web search and page fetches, the browser, connector (MCP), mailbox and Agent
|
|
344
|
+
Hub tools and any call or shell command that contacts a host other than the agent's own machine, and
|
|
345
|
+
the refusal tells the model the internet is off for this chat. A retained
|
|
346
|
+
session keeps the last value, so send it every turn; omit it to leave the
|
|
347
|
+
agent as it is. Pre-2.23 binaries `422` the field, so a caller whose chat has
|
|
348
|
+
the internet off should check `/version` and refuse the turn on an older
|
|
349
|
+
binary rather than answer it online, and cancel an older binary's running
|
|
350
|
+
turn when the switch goes off.
|
|
351
|
+
|
|
352
|
+
`internet_off` is read when a turn starts. To change it for a turn already
|
|
353
|
+
running, `POST /v1/gaia/sessions/{session_id}/internet` with
|
|
354
|
+
`{ "internet_off": true }` (or `false`): the session's next tool call follows
|
|
355
|
+
it, and so do later turns until a `/query` sends another value. An unknown
|
|
356
|
+
session is a **404** rather than a new one.
|
|
357
|
+
|
|
358
|
+
Send it only once `/query` has answered. The response starts after the turn's
|
|
359
|
+
own `internet_off` is applied, so a switch posted earlier is replaced by the
|
|
360
|
+
body's value, and on a session's first turn it is a **404** because the
|
|
361
|
+
session does not exist yet. A caller whose user can flip the switch while a
|
|
362
|
+
turn starts re-reads it when `/query` answers and posts it if it changed.
|
|
363
|
+
|
|
364
|
+
`changes_turn_id` (contract ≥ 2.19) asks the agent to record the turn's file
|
|
365
|
+
changes for undo. Before a tool writes, edits, creates or deletes a file, the
|
|
366
|
+
agent saves a copy of it under `<GAIA home>/snapshots/<session_id>/<changes_turn_id>/`,
|
|
367
|
+
the store the Agent UI's Changes view, Outputs and Undo read. The recording is
|
|
368
|
+
complete before the terminal `final` or `error` event is sent, even while the
|
|
369
|
+
agent finishes post-answer work, so a caller may read or restore it as soon as
|
|
370
|
+
the stream ends. It needs `session_id` (`422` without one) and must look like
|
|
371
|
+
`file_snapshots.new_turn_id()` makes it — 14 digits of local time, a hyphen and
|
|
372
|
+
8 hex digits — so a session's turns sort in the order they ran; anything else
|
|
373
|
+
is a `422`. Work the agent cannot copy, such as a shell command, is noted in
|
|
374
|
+
the turn as untracked. Omit the field to record nothing. Pre-2.19 binaries
|
|
375
|
+
`422` it.
|
|
376
|
+
|
|
377
|
+
`surface` (contract ≥ 2.20) is the front-end the turn comes from: `"agent_ui"`,
|
|
378
|
+
`"tui"` or `"cli"`. With `"agent_ui"` the agent points recurring requests at the
|
|
379
|
+
Agent UI's **Scheduled tasks** page instead of saying it cannot schedule. It is
|
|
380
|
+
read when a session is built and kept for that session. It also picks where a
|
|
381
|
+
model-provider error tells the user to fix it: each front-end gets its own
|
|
382
|
+
settings screen, and a headless caller, which omits it, is pointed at the model
|
|
383
|
+
server the GAIA host uses (`LEMONADE_BASE_URL`). A failed model request also
|
|
384
|
+
names the `host:port` it went through; on a base URL the user set, a local
|
|
385
|
+
model's failure reads "the model server at `host:port`", not "Lemonade on this
|
|
386
|
+
machine". Pre-2.20 binaries `422` the field and word every such error for the
|
|
387
|
+
TUI.
|
|
388
|
+
|
|
389
|
+
`reasoning` (contract ≥ 2.22), when `true`, streams the model's reasoning as
|
|
390
|
+
`reasoning` events, `{ "type": "reasoning", "delta": "…" }`, so a client can
|
|
391
|
+
show it apart from `status` lines and from the answer's `token`s. Each delta
|
|
392
|
+
keeps its own spacing: join them as they arrive. Without the field, reasoning
|
|
393
|
+
folds into `status` lines as before. Pre-2.22 binaries `422` it.
|
|
394
|
+
|
|
395
|
+
```json
|
|
396
|
+
{
|
|
397
|
+
"query": "What's in this directory?",
|
|
398
|
+
"run_id": "5b1f6e2a-7c34-4b4d-9b3e-2b6d9a7a1c3e",
|
|
399
|
+
"context": [],
|
|
400
|
+
"session_id": "my-session-1",
|
|
401
|
+
"can_answer_questions": true
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
#### `needs_confirmation` arguments
|
|
406
|
+
|
|
407
|
+
A `needs_confirmation` event carries the gated call in `args`: exactly the
|
|
408
|
+
arguments the model sent, each value capped at 64,000 characters with a note
|
|
409
|
+
saying how much was cut, and `args_truncated: true` when any was. `summary`
|
|
410
|
+
shortens long code, so show `args` when the user should read all of it; a
|
|
411
|
+
policy client matches its rules on `args` and should not auto-approve a call
|
|
412
|
+
with `args_truncated`. The agent never adds a key to `args`. What it adds to
|
|
413
|
+
its own prompt is in `prompt_context`: `working_directory` (where a shell call
|
|
414
|
+
runs, when the model's arguments don't say it), `risk_note` (why the
|
|
415
|
+
agent's checks don't cover the call, which is then approved once) and
|
|
416
|
+
`file_path` (the absolute path a write lands at, when the model gave a relative
|
|
417
|
+
one). A prompt
|
|
418
|
+
the agent raises on its own, such as `allow_path_access`, has the path it asks
|
|
419
|
+
about in `args`.
|
|
271
420
|
|
|
272
421
|
`/health` is liveness only. It says nothing about whether Lemonade is up or a
|
|
273
422
|
model is loaded — `/v1/gaia/init` answers that.
|
|
274
423
|
|
|
424
|
+
`GET /v1/gaia/memory` returns the read-only snapshot behind the TUI's
|
|
425
|
+
`/memory` view: `{ "available", "reason", "stats", "contexts", "shown",
|
|
426
|
+
"total", "items" }`. `available: false` means the session has no live memory
|
|
427
|
+
store (Lemonade down, embedding model not pulled, disabled via env) — `reason`
|
|
428
|
+
names why, so an outage never renders as "you have no memories". This is the
|
|
429
|
+
daemon-transport counterpart of the stdio `MEMORY_DUMP_QUERY` sentinel; both
|
|
430
|
+
paths call the same `build_memory_dump()` and return the identical shape.
|
|
431
|
+
|
|
432
|
+
`GET /v1/gaia/skills` (contract ≥ 2.17) lists the skills the agent can load:
|
|
433
|
+
`{ "skills": [{ "name", "description", "version", "tier", "tools", "path",
|
|
434
|
+
"source" }], "invalid": { "<folder>": "<why it failed to parse>" } }`. It reads
|
|
435
|
+
the same roots the agent does — its bundled skills, `~/.gaia/skills`, Claude
|
|
436
|
+
Code skill folders — so a host without the Python package (the bundled skills
|
|
437
|
+
live inside the binary) can still show them. `source` names the root a skill
|
|
438
|
+
came from: `agent-bundled`, `user` or `claude-import`, or `null` for any other
|
|
439
|
+
root. An agent that predates `source` omits the field; a host must treat a list
|
|
440
|
+
where any skill lacks it as ungrouped and show it flat, not drop the skill. A skill root that cannot be read is a `500`
|
|
441
|
+
naming it.
|
|
442
|
+
|
|
443
|
+
`/query` streams the answer as `token` events before its terminal `final`. A
|
|
444
|
+
run cancelled mid-answer (`/cancel`, or a dropped connection) ends with an
|
|
445
|
+
empty `final` and sends no `token` after the cancel, so a host keeps the text
|
|
446
|
+
the `token` events already delivered. Answer text the model produced but the
|
|
447
|
+
stream had not yet sent when the cancel landed is discarded with the
|
|
448
|
+
half-written tail.
|
|
449
|
+
|
|
450
|
+
`final` carries `context` (contract ≥ 2.21): what the next model call holds
|
|
451
|
+
if the caller pushes this turn back as history — the same payload the Agent
|
|
452
|
+
UI's Context panel shows. `window` is the model's context window in tokens,
|
|
453
|
+
`used` the tokens taken, and `system`, `tools`, `documents`, `history` split it
|
|
454
|
+
by kind; `categories` lists the panel's rows (their tokens add up to `used`),
|
|
455
|
+
`tool_loading` which tools ride every request, and `tokenizer.exact` whether
|
|
456
|
+
the counts came from the loaded model's own tokenizer or the shared estimate.
|
|
457
|
+
A turn that was stopped or ended on a model failure carries no `context`; a
|
|
458
|
+
measurement that failed carries `context_error`, one sentence saying why, and
|
|
459
|
+
the answer still stands. Older binaries send neither, so read `context` only
|
|
460
|
+
when `/version` reports 2.21 or later.
|
|
461
|
+
|
|
462
|
+
`final` also carries `performance`: the turn's step timings, as
|
|
463
|
+
`{ "timing_summary", "conversation" }`. `timing_summary` holds the run's model
|
|
464
|
+
and tool seconds and its model call count; `conversation` holds one
|
|
465
|
+
`{ "role": "system", "content": { "type": "stats", ... } }` entry per model
|
|
466
|
+
call, with that call's token counts and speed. The Agent UI turns it into the
|
|
467
|
+
Context panel's "Under the hood" figures. A run that timed nothing
|
|
468
|
+
carries none, and older binaries never send it, so read it only when present.
|
|
469
|
+
|
|
275
470
|
### 5.2 `session_id` and agent retention
|
|
276
471
|
|
|
277
472
|
`POST /v1/gaia/query` accepts an optional `session_id` in the request body.
|
|
@@ -279,27 +474,48 @@ model is loaded — `/v1/gaia/init` answers that.
|
|
|
279
474
|
whole conversation.** Contract ≥ 2.12 resolves `session_id` to a *retained*
|
|
280
475
|
agent instead of a throwaway built fresh per call — indexed documents and
|
|
281
476
|
`load_skill` state only survive between turns when the same `session_id`
|
|
282
|
-
threads them together.
|
|
477
|
+
threads them together. A `session_id` must be 1–128 characters from
|
|
478
|
+
`A-Z a-z 0-9 . _ -`, not only dots (a UUID works); any other value is a **400**
|
|
479
|
+
naming the allowed characters, on `/query`, `/sessions/{session_id}/bypass` and
|
|
480
|
+
`/sessions/{session_id}/internet`.
|
|
481
|
+
Omitting it is a valid, explicit one-shot: nothing persists past that single
|
|
482
|
+
turn, and the agent is not told otherwise.
|
|
483
|
+
|
|
484
|
+
Internal explicit deletion follows the same idle-only rule as eviction: it returns
|
|
485
|
+
`False` for an absent or busy session and preserves a running agent. Successful
|
|
486
|
+
deletion claims the turn lock before removal and closes outside the registry lock.
|
|
487
|
+
|
|
488
|
+
A skill **captured** in-conversation (the `capture_skill` tool — itself
|
|
489
|
+
confirmation-gated, so over `/query` it needs a session that can answer) loads
|
|
490
|
+
**instruction-only** until a human runs `gaia skill promote <name>` in a
|
|
491
|
+
terminal: `load_skill` injects its body but defers registering any tools it
|
|
492
|
+
declares, and reports the deferral in its result. Integrators must not expect
|
|
493
|
+
a captured skill's `<skill>/<tool>` names to exist before that promote.
|
|
283
494
|
|
|
284
495
|
A retained skill stays *loaded* but its body is not necessarily in the prompt
|
|
285
496
|
every turn: the agent selects per turn which loaded bodies match the query and
|
|
286
497
|
collapses the rest to a one-line menu entry (re-activated by calling
|
|
287
498
|
`load_skill` again). `GAIA_DYNAMIC_SKILLS=0` disables the selection;
|
|
288
499
|
`GAIA_DYNAMIC_SKILLS_TAU=<float>` overrides its threshold; an embedder outage
|
|
289
|
-
disables it for the session and every body renders.
|
|
290
|
-
persists past that single turn, and the agent is not told otherwise.
|
|
500
|
+
disables it for the session and every body renders.
|
|
291
501
|
|
|
292
502
|
A retained session also carries a **project map** — up to 600 prompt tokens of
|
|
293
503
|
directory shape, entry points, installed commands and platform quirks, present
|
|
294
504
|
whenever the agent's working directory resolves to a code repository (a VCS
|
|
295
505
|
directory or a recognised manifest at its root). `GAIA_PROJECT_ROOT=<path>`
|
|
296
506
|
picks the project when the working directory is not it. If that repository has
|
|
297
|
-
no code index, the first
|
|
298
|
-
`GAIA_PROJECT_MAP_AUTO_INDEX=
|
|
299
|
-
|
|
507
|
+
no code index, the first `search_code_index` builds one;
|
|
508
|
+
`GAIA_PROJECT_MAP_AUTO_INDEX=1` builds it in a background thread at task start
|
|
509
|
+
instead. The same repository check also
|
|
510
|
+
makes `run_shell_command` always-on for the session instead of semantically
|
|
511
|
+
selected. Neither affects the wire contract — they change what the agent
|
|
512
|
+
knows, what tools it is offered, and what the first turn costs.
|
|
300
513
|
|
|
301
514
|
A second `/query` for a `session_id` that already has a turn in flight gets
|
|
302
|
-
`409 Conflict` — cancel the running turn or wait for it, then retry.
|
|
515
|
+
`409 Conflict` — cancel the running turn or wait for it, then retry. Once that
|
|
516
|
+
turn has been cancelled, the new `/query` is held until it finishes its
|
|
517
|
+
in-flight model call (up to **240 s**) and then runs, instead of getting `409`;
|
|
518
|
+
only a cancelled turn that outlasts the wait still gets `409`. A
|
|
303
519
|
`/query` that needs a **new** session while every retained slot is busy and
|
|
304
520
|
none is idle enough to evict gets `503` with the reason in `detail` — a
|
|
305
521
|
temporary, retryable condition, not a bug: wait for a turn to finish (or
|
|
@@ -317,10 +533,24 @@ not survive and should be reloaded.
|
|
|
317
533
|
A second `/query` reusing a `run_id` that is still in flight gets `409` —
|
|
318
534
|
`run_id` is caller-minted, so mint a fresh UUID per request; reusing one would
|
|
319
535
|
leave the earlier run with no way to be cancelled. A `/query` supplying a `model`
|
|
320
|
-
that differs from the one its `session_id` was built with
|
|
321
|
-
agent
|
|
322
|
-
|
|
323
|
-
|
|
536
|
+
that differs from the one its `session_id` was built with **switches the retained
|
|
537
|
+
agent in place** (≥ 2.14), so the conversation and any loaded skills survive the
|
|
538
|
+
change; the same machinery the stdio transport's `/model` uses. A switch that
|
|
539
|
+
fails — a missing Claude credential, an unknown local model — is a `409` naming
|
|
540
|
+
the reason, and leaves the session on its previous model. The session records its
|
|
541
|
+
`provider` too: a turn naming a different `provider` switches it the same way,
|
|
542
|
+
onto that turn's `model` or, if it names none, the provider's default model. A
|
|
543
|
+
`model` from the other provider than the one named (a `claude-*` id with
|
|
544
|
+
`"lemonade"`, or a non-Claude id with `"claude"`) is a `400` on a new session and
|
|
545
|
+
an existing one alike, before anything is built or switched.
|
|
546
|
+
|
|
547
|
+
`provider` is optional, and an omitted one is **not** read as `"lemonade"` — it
|
|
548
|
+
means "whatever the `model` implies", so a `claude-*` id alone reaches Anthropic
|
|
549
|
+
and any other id runs locally. The `400` above therefore fires only when a
|
|
550
|
+
request names a `provider` that disagrees with its `model`; there is no pair to
|
|
551
|
+
disagree when only one is given. On a retained session, omitting both leaves the
|
|
552
|
+
session on the provider it is already using, so an ordinary follow-up turn never
|
|
553
|
+
moves a Claude conversation back to Lemonade.
|
|
324
554
|
|
|
325
555
|
### 5.3 Version gate
|
|
326
556
|
|
|
@@ -367,6 +597,15 @@ mints a per-session token and passes it as `GAIA_GAIA_SIDECAR_TOKEN_FILE`
|
|
|
367
597
|
(`gaia.daemon.sidecars.spec` mirrors both names as plain strings so core never
|
|
368
598
|
imports this wheel).
|
|
369
599
|
|
|
600
|
+
**Child processes.** The programs the agent starts — shell commands, MCP
|
|
601
|
+
servers, CLI installs and sign-ins, native hub agents, media tools, the Lemonade
|
|
602
|
+
server — never inherit the sidecar token or GAIA's other internal credentials
|
|
603
|
+
(the model-broker token, custody secret and engineering pairing token): their
|
|
604
|
+
environment comes from `gaia.env.child_env`, which also drops any name listed
|
|
605
|
+
in `GAIA_CHILD_ENV_DENY` (comma or space separated). User credentials such as `GH_TOKEN` pass through unchanged.
|
|
606
|
+
`GAIA_NO_DOTENV=1` in the sidecar's launch environment stops it loading `.env`
|
|
607
|
+
files; a `.env` file cannot set that switch itself.
|
|
608
|
+
|
|
370
609
|
### 5.5 Other transports
|
|
371
610
|
|
|
372
611
|
The HTTP server above is the surface this package drives, and everything in
|
|
@@ -378,18 +617,30 @@ the hub, which is what this package delivers, is supervised by the daemon over
|
|
|
378
617
|
the HTTP surface above instead (§6.1).
|
|
379
618
|
|
|
380
619
|
It emits the identical canonical event vocabulary, but its input channel accepts
|
|
381
|
-
a JSON line carrying a `gaia_control` key
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
620
|
+
a JSON line carrying a `gaia_control` key: a back-channel that answers a
|
|
621
|
+
confirmation prompt *while* a turn is in flight, toggles full access or
|
|
622
|
+
"accept edits" (file edits inside the starting folder run unasked; commands still
|
|
623
|
+
ask), and stops a turn (`cancel`) without ending the process — so loaded skills,
|
|
624
|
+
"always" grants, history and the permission mode survive a cancel. When stdin
|
|
625
|
+
closes mid-turn (the host has gone), the running turn is cancelled and saved in
|
|
626
|
+
the session history as interrupted: "This answer was interrupted when GAIA
|
|
627
|
+
closed." The question is saved when the turn starts, so it survives even if the
|
|
628
|
+
host kills the process before the turn ends. Another process sharing the
|
|
629
|
+
history file leaves a turn that is still running out of its model view.
|
|
630
|
+
|
|
631
|
+
Contract 2.14 gave the HTTP surface the same three capabilities per run and per
|
|
632
|
+
session — `/tool_decision`, `/sessions/{id}/bypass` (the route keeps its
|
|
633
|
+
original spelling), and `provider: "claude"`. What remains stdio-only is the
|
|
634
|
+
*launch* form of those switches: `--full-access` starts a process with gating
|
|
635
|
+
already off, `--accept-edits` starts it in accept-edits mode, and `--use-claude` / `--claude-model` pin the backend for the life
|
|
636
|
+
of the process (embeddings stay on Lemonade either way).
|
|
389
637
|
|
|
390
638
|
The stdio TUI also supports Local, Fireworks AI, and AMD LLM Gateway through
|
|
391
|
-
Lemonade. `/model` lists downloaded local and discovered cloud chat models
|
|
639
|
+
Lemonade. `/model` lists downloaded local and discovered cloud chat models,
|
|
640
|
+
grouped by provider, with `(default)` beside the configured default model;
|
|
392
641
|
`/model <id>` switches the live client while preserving conversation and skills.
|
|
642
|
+
The switch reply is one line naming the model, where it runs, and, for a cloud
|
|
643
|
+
model, that messages and anything read from files or memory are sent there.
|
|
393
644
|
Cloud IDs (`fireworks.*`, `amd.*`) route through Lemonade without local model
|
|
394
645
|
loading. Model-state status events identify the provider and remote inference.
|
|
395
646
|
The TUI's `/provider` panel configures credentials directly with local Lemonade;
|
|
@@ -397,8 +648,82 @@ keys never travel through stdio queries. These controls are not exposed over
|
|
|
397
648
|
`/v1/gaia/query`. Lemonade may independently be configured to route a model
|
|
398
649
|
remotely, so a local server URL alone does not establish local inference.
|
|
399
650
|
|
|
651
|
+
`--bypass-permissions` turns off more than the prompt. It also lifts the shell
|
|
652
|
+
tool's own guardrails for the session: the shell-only operators — redirection
|
|
653
|
+
(`>`, `>>`, `<`), backgrounding (`&`), substitution (`` ` ``, `$()`) and the
|
|
654
|
+
newline — parse and run, chaining (`&&`, `||`, `;`, `|`) already ran by
|
|
655
|
+
default, the read-only binary allowlist is replaced by a developer set
|
|
656
|
+
(`node`, `npm`, `make`, `cmake`, `go`, `cargo`, `sed`, `awk`, `curl`, `sleep`,
|
|
657
|
+
`timeout`, `export`, `cp`, `mv`, plus `python`/`python3`/`pytest`/`gh`/`git`,
|
|
658
|
+
which already had their own paths), and the shell rate limit is dropped. `git`
|
|
659
|
+
being in that set means its policy's outright refusals — push, reset, rebase —
|
|
660
|
+
also stop applying under bypass. That is
|
|
661
|
+
arbitrary code execution in the working directory, which is why it exists only
|
|
662
|
+
on this transport: one local parent process on a private pipe. It is **not**
|
|
663
|
+
reachable over HTTP, and the request body cannot ask for it —
|
|
664
|
+
`POST /v1/gaia/sessions/{id}/bypass` stops an HTTP session's approval prompts
|
|
665
|
+
but never lifts these shell gates. A command those gates hold is never run
|
|
666
|
+
unasked there: on a run someone can answer it still emits `needs_confirmation`
|
|
667
|
+
and waits for `/tool_decision`, and on a run nobody can answer it is refused.
|
|
668
|
+
`rm` is excluded
|
|
669
|
+
from the developer set — not a boundary, since anything in the set can delete a
|
|
670
|
+
file, but a tripwire against an accidental recursive delete. Redirection has one
|
|
671
|
+
exception: a command that is nothing but a skill-granted CLI runs argv-only
|
|
672
|
+
rather than through a shell, so a `>` there is refused with an explanation
|
|
673
|
+
instead of reaching the binary as a literal argument.
|
|
674
|
+
|
|
675
|
+
Every shell command run under bypass is recorded with its full arguments and its
|
|
676
|
+
per-segment breakdown in `~/.gaia/cache/file_audit.log` — skipping the prompt
|
|
677
|
+
does not skip the record. Treat that file as sensitive; arguments are verbatim.
|
|
678
|
+
The host can toggle bypass mid-session over `gaia_control`, and the shell gates
|
|
679
|
+
follow on the very next command.
|
|
680
|
+
|
|
681
|
+
`--use-claude` is the one with a reach beyond the machine, and it cannot be
|
|
682
|
+
turned on for what this package delivers: the terminal UI **refuses** the launch
|
|
683
|
+
flag for a daemon-transport agent, with an error saying so, because it pins the
|
|
684
|
+
backend for the life of the process and the daemon relay has no such lever.
|
|
685
|
+
|
|
686
|
+
That is a limit on the *launch flag*, not on the agent. Since contract 2.14 a
|
|
687
|
+
caller can ask for Anthropic per request with `/query`'s `provider` field (§5.2),
|
|
688
|
+
so local inference is this package's **default**, not a property of the transport
|
|
689
|
+
that nobody can change. Anything reaching Anthropic is named by the request that
|
|
690
|
+
asked for it.
|
|
691
|
+
|
|
400
692
|
---
|
|
401
693
|
|
|
694
|
+
### 5.6 Adding to a turn already running
|
|
695
|
+
|
|
696
|
+
`POST /v1/gaia/query/{run_id}/followup` with `{ "text": "…" }` hands a live run
|
|
697
|
+
something the user typed after it started. Contract ≥ 2.15.
|
|
698
|
+
|
|
699
|
+
It is not a second turn and not an interrupt. The run keeps going on its
|
|
700
|
+
existing SSE stream; the agent folds the text into that turn's context at its
|
|
701
|
+
next agent-loop step boundary, labelled as arriving mid-task, and answers it
|
|
702
|
+
alongside the work already in progress. A five-minute turn can therefore be
|
|
703
|
+
corrected ("actually, only the unread ones") while it is still running, instead
|
|
704
|
+
of the correction waiting out the turn it was meant to change.
|
|
705
|
+
|
|
706
|
+
Two refusals, both loud, because the caller has already taken the message from
|
|
707
|
+
the user and owes them a truthful answer about where it went:
|
|
708
|
+
|
|
709
|
+
| Status | Meaning |
|
|
710
|
+
| ------ | ------------------------------------------------------------ |
|
|
711
|
+
| `404` | No such run in flight — it finished or was cancelled. Send it as a new `/query`. |
|
|
712
|
+
| `409` | The run's agent is not accepting mid-turn input. |
|
|
713
|
+
|
|
714
|
+
A turn that has already formed its answer takes one more step to address a
|
|
715
|
+
follow-up, so a turn answering in a single step is covered too. The one
|
|
716
|
+
exception is a turn already at its step limit: the message stays queued rather
|
|
717
|
+
than being consumed into a context no model call will read.
|
|
718
|
+
|
|
719
|
+
Because `/query` is stateless (§2.4) the host still owns the transcript: record
|
|
720
|
+
a delivered follow-up in the `context` you push on the **next** turn, between
|
|
721
|
+
that turn's question and its answer, or the conversation loses words the agent
|
|
722
|
+
demonstrably saw.
|
|
723
|
+
|
|
724
|
+
Clients that predate 2.15 get a `404` on the path itself. Probe `/version`
|
|
725
|
+
before sending rather than reading a 404 as "the run ended".
|
|
726
|
+
|
|
402
727
|
## 6. Process ownership
|
|
403
728
|
|
|
404
729
|
Two distinct paths, deliberately:
|
|
@@ -458,8 +783,8 @@ failed start never leaks a process.
|
|
|
458
783
|
| Code | Meaning |
|
|
459
784
|
| ------- | ----------------------------------------------------------------------- |
|
|
460
785
|
| `0` | Success |
|
|
461
|
-
| `1` | A typed failure: `IntegrityError`, `PlatformError`, `HealthTimeoutError`, `VersionMismatchError`, `BinaryNotFoundError`, `PortInUseError`, `SidecarExitedError`, `MalformedResponseError`, or an unexpected error |
|
|
462
|
-
| `2` | Usage error: unknown command, invalid `--port`, or a flag the command does not read (`run --port`, `serve --component`, `serve --cache-dir`, `run`/`serve` `--platform`), an unknown `--component`, or a non-https `--base-url` without `--allow-insecure-base-url` |
|
|
786
|
+
| `1` | A typed failure: `IntegrityError`, `PlatformError`, `HealthTimeoutError`, `VersionMismatchError`, `BinaryNotFoundError`, `PortInUseError`, `SidecarExitedError`, `MalformedResponseError`, or an unexpected error; also `serve` on Ctrl+C when the sidecar survives the forced kill (the message names its pid and the kill command) |
|
|
787
|
+
| `2` | Usage error: unknown command, an unknown option, invalid `--port`, or a flag the command does not read (`run --port`, `serve --component`, `serve --cache-dir`, `run`/`serve` `--platform`), an unknown `--component`, or a non-https `--base-url` without `--allow-insecure-base-url` |
|
|
463
788
|
| *other* | From `run`: the TUI's own exit code, propagated verbatim |
|
|
464
789
|
|
|
465
790
|
A TUI killed by a signal propagates as `128 + signum` (the shell convention), so a
|
|
@@ -535,3 +860,24 @@ yourself, which no lock describes, and `{ lock }` to reuse an already-loaded loc
|
|
|
535
860
|
`DEBUG=gaia` (or `DEBUG=*`) enables debug output. **Everything goes to stderr** —
|
|
536
861
|
stdout belongs to the TUI once it is exec'd, and to machine-readable JSON for
|
|
537
862
|
`fetch` / `version`.
|
|
863
|
+
|
|
864
|
+
## Developer engineering mode
|
|
865
|
+
|
|
866
|
+
- **Opt-in.** The agent enables it with `--developer-mode` or `GAIA_DEVELOPER_MODE=1`
|
|
867
|
+
in the host process. `gaia engineering` and the engineering MCP server accept only
|
|
868
|
+
the explicit `--developer-mode` flag. It is separate from diagnostic `--dev`.
|
|
869
|
+
- **Surface.** Only in that mode does the agent load the `gaia-harness-engineering`
|
|
870
|
+
skill and the `share_engineering_context`, `append_engineering_context`,
|
|
871
|
+
`approve_engineering_code`, `engineering_status`, `open_engineering_app` and
|
|
872
|
+
`revoke_engineering_context` tools. Sessions without it have none of them.
|
|
873
|
+
- **Consent.** Sharing, appending and code approval each ask for a fresh approval of
|
|
874
|
+
the exact content or scope shown. None of them can be remembered or auto-approved.
|
|
875
|
+
Snapshots are recipient-bound and expire; revoking stops future reads.
|
|
876
|
+
- **Pairing.** Configure the coding app's MCP connection from a Python GAIA install
|
|
877
|
+
with the `[mcp]` extra. The frozen binary this package ships can reuse that
|
|
878
|
+
configuration but cannot launch the Python MCP server itself.
|
|
879
|
+
- **Code.** Fixes happen in the coding app, in worktrees from GAIA's managed source
|
|
880
|
+
cache. Preview results are reported by that app, not verified by GAIA. Nothing
|
|
881
|
+
self-assesses or updates the installed GAIA.
|
|
882
|
+
|
|
883
|
+
See the [usage guide](https://amd-gaia.ai/docs/guides/harness-engineering).
|
package/binaries.lock.json
CHANGED
|
@@ -1,76 +1,76 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "3.0",
|
|
3
|
-
"agentVersion": "0.2
|
|
3
|
+
"agentVersion": "0.3.2",
|
|
4
4
|
"components": {
|
|
5
5
|
"sidecar": {
|
|
6
|
-
"componentVersion": "0.2
|
|
7
|
-
"baseUrl": "https://hub.amd-gaia.ai/agents/gaia/0.2
|
|
6
|
+
"componentVersion": "0.3.2",
|
|
7
|
+
"baseUrl": "https://hub.amd-gaia.ai/agents/gaia/0.3.2",
|
|
8
8
|
"platforms": {
|
|
9
9
|
"win32-x64": {
|
|
10
10
|
"filename": "gaia-agent-win32-x64.exe",
|
|
11
11
|
"executable": "gaia-agent.exe",
|
|
12
|
-
"sha256": "
|
|
13
|
-
"size":
|
|
12
|
+
"sha256": "b107ed0740408b3ea50ab2556503549f173bcea13756e0cab0a5d0c98c867eab",
|
|
13
|
+
"size": 172894251
|
|
14
14
|
},
|
|
15
15
|
"darwin-arm64": {
|
|
16
16
|
"filename": "gaia-agent-darwin-arm64",
|
|
17
17
|
"executable": "gaia-agent",
|
|
18
|
-
"sha256": "
|
|
19
|
-
"size":
|
|
18
|
+
"sha256": "2a339e225396df8f1623ff32051dd92800bf2224c76ba482cd25ae7ba30ebe30",
|
|
19
|
+
"size": 162463472
|
|
20
20
|
},
|
|
21
21
|
"darwin-x64": {
|
|
22
22
|
"filename": "gaia-agent-darwin-x64",
|
|
23
23
|
"executable": "gaia-agent",
|
|
24
|
-
"sha256": "
|
|
25
|
-
"size":
|
|
24
|
+
"sha256": "a796c734a72f43489062faa7d011399bcfdbd97280992e0ff8fea9734702aa28",
|
|
25
|
+
"size": 173074704
|
|
26
26
|
},
|
|
27
27
|
"linux-x64": {
|
|
28
28
|
"filename": "gaia-agent-linux-x64",
|
|
29
29
|
"executable": "gaia-agent",
|
|
30
|
-
"sha256": "
|
|
31
|
-
"size":
|
|
30
|
+
"sha256": "815817da63df38ae08dc96df226b758f53c54e56b59588b79a5e605c27c2ab64",
|
|
31
|
+
"size": 211939056
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"tui": {
|
|
36
|
-
"componentVersion": "0.
|
|
37
|
-
"baseUrl": "https://hub.amd-gaia.ai/agents/terminal-hub/0.
|
|
36
|
+
"componentVersion": "0.25.0",
|
|
37
|
+
"baseUrl": "https://hub.amd-gaia.ai/agents/terminal-hub/0.25.0",
|
|
38
38
|
"platforms": {
|
|
39
39
|
"win32-x64": {
|
|
40
40
|
"filename": "gaia-win-x64.exe",
|
|
41
41
|
"executable": "gaia-tui.exe",
|
|
42
|
-
"sha256": "
|
|
43
|
-
"size":
|
|
42
|
+
"sha256": "9b1c467b04b267f172a6024589f1ba0ddc882729337913d8afa7dcd43a7a7967",
|
|
43
|
+
"size": 20604416
|
|
44
44
|
},
|
|
45
45
|
"win32-arm64": {
|
|
46
46
|
"filename": "gaia-win-arm64.exe",
|
|
47
47
|
"executable": "gaia-tui.exe",
|
|
48
|
-
"sha256": "
|
|
49
|
-
"size":
|
|
48
|
+
"sha256": "332068c5588e5639213225d63e4a1827d9258928e4053b7d6602668dc7eda60c",
|
|
49
|
+
"size": 19030016
|
|
50
50
|
},
|
|
51
51
|
"darwin-arm64": {
|
|
52
52
|
"filename": "gaia-darwin-arm64",
|
|
53
53
|
"executable": "gaia-tui",
|
|
54
|
-
"sha256": "
|
|
55
|
-
"size":
|
|
54
|
+
"sha256": "bb5ae28ae99ad25c095b3f57c4abf4e2ff67fa560122dc0a99036aedf9184802",
|
|
55
|
+
"size": 18801330
|
|
56
56
|
},
|
|
57
57
|
"darwin-x64": {
|
|
58
58
|
"filename": "gaia-darwin-x64",
|
|
59
59
|
"executable": "gaia-tui",
|
|
60
|
-
"sha256": "
|
|
61
|
-
"size":
|
|
60
|
+
"sha256": "5259c82dc195297130e16377586ed6e0e668c5ec7f8b27a76ee029d67d776b52",
|
|
61
|
+
"size": 20015840
|
|
62
62
|
},
|
|
63
63
|
"linux-x64": {
|
|
64
64
|
"filename": "gaia-linux-x64",
|
|
65
65
|
"executable": "gaia-tui",
|
|
66
|
-
"sha256": "
|
|
67
|
-
"size":
|
|
66
|
+
"sha256": "07f1cc448f8056b5915eff2869f9f3eec3a5d04485d93e448ccad00d186d23c5",
|
|
67
|
+
"size": 19669154
|
|
68
68
|
},
|
|
69
69
|
"linux-arm64": {
|
|
70
70
|
"filename": "gaia-linux-arm64",
|
|
71
71
|
"executable": "gaia-tui",
|
|
72
|
-
"sha256": "
|
|
73
|
-
"size":
|
|
72
|
+
"sha256": "c324100d2de989823e816a6aae7eb4e1224019096b9a46ef1a6983ca6b98598f",
|
|
73
|
+
"size": 18350242
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAGA;;;;;;;;;;;GAWG;AA8BH,UAAU,UAAU;IAClB,CAAC,EAAE,MAAM,EAAE,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;IACxC,mEAAmE;IACnE,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAaD,4EAA4E;AAC5E,qBAAa,UAAW,SAAQ,KAAK;CAAG;AAExC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAGA;;;;;;;;;;;GAWG;AA8BH,UAAU,UAAU;IAClB,CAAC,EAAE,MAAM,EAAE,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;IACxC,mEAAmE;IACnE,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAaD,4EAA4E;AAC5E,qBAAa,UAAW,SAAQ,KAAK;CAAG;AAExC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAwCpD;AA8JD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,GAAE,MAAM,GAAG,SAA+B,EACjD,KAAK,GAAE,MAAM,GAAG,SAA2B,GAC1C,MAAM,GAAG,SAAS,CAsBpB;AA+CD,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAUnG;AAsLD,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAkC1D"}
|