@amd-gaia/gaia 0.2.0 → 0.3.0
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 +626 -72
- package/README.md +33 -11
- package/SCORECARD.md +180 -0
- package/SKILL.md +210 -64
- package/SPEC.md +218 -22
- package/binaries.lock.json +25 -25
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +15 -3
- 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/CHANGELOG.md
CHANGED
|
@@ -4,13 +4,554 @@ All notable changes to `@amd-gaia/gaia` are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this package adheres
|
|
5
5
|
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
-
## [
|
|
7
|
+
## [Unreleased]
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
the
|
|
9
|
+
- **Finished work is no longer replaced by "I can't confirm this is done".** A
|
|
10
|
+
redaction task that loaded the `document-extract` skill had its answer swapped
|
|
11
|
+
for a coverage warning about its own `redaction_log.csv`, and a task with two
|
|
12
|
+
named outputs only knew about the last one. Every file the request names, and
|
|
13
|
+
every file the turn wrote, is now an output and never a source; the skill
|
|
14
|
+
checks coverage only when the request names a source document or asks for
|
|
15
|
+
every item. No check replaces a non-empty answer any more: an unproven
|
|
16
|
+
save, test result or extraction keeps the answer and adds a short "I
|
|
17
|
+
couldn't confirm all of this" list after it; a turn that ends early keeps
|
|
18
|
+
what it said ahead of its report; and a tool that keeps failing ends with the
|
|
19
|
+
model's answer from what it found, then the failure. A failed image request
|
|
20
|
+
is no longer rewritten into advice to start GAIA with an `--sd` flag that
|
|
21
|
+
does not exist. `load_skill` no longer tells the model the extraction tools
|
|
22
|
+
cannot run when it is about to register them, and a rejected extractor reply
|
|
23
|
+
is now logged.
|
|
24
|
+
- **`run_python` works in the Agent UI without a project.** It ran from the
|
|
25
|
+
server's own folder, which is not an allowed path, so every approved snippet
|
|
26
|
+
was refused and the agent fell back to slower shell commands. With no project
|
|
27
|
+
and a working directory you did not allow, a snippet now runs in the agent's
|
|
28
|
+
scratch directory, and its result says so. A project outside the allowed
|
|
29
|
+
paths is still refused.
|
|
30
|
+
- **An "always" answer for a shell command no longer covers code in the
|
|
31
|
+
scratch folder.** A command run there or naming a path there — `cd` into it
|
|
32
|
+
then `python -m explore`, or `pytest`, `make`, `pip install`, `uv run` or
|
|
33
|
+
`go run` pointed at it — and a script handed a scratch path as an argument
|
|
34
|
+
now ask every time, with no `always_scope`, the same as a script there.
|
|
35
|
+
`always_scope` labels for commands that run code they do not show now say so:
|
|
36
|
+
`pytest (runs the test code it finds)`, `make (runs the Makefile's
|
|
37
|
+
commands)`, `python -m explore (runs that Python module)`.
|
|
38
|
+
- **Exploring data no longer asks twice per step.** Each step wrote a helper
|
|
39
|
+
script into the agent's own scratch folder and ran it, so a data task asked
|
|
40
|
+
for approval about 30 times. Writes inside that folder now run unasked
|
|
41
|
+
(writes anywhere else still ask). Running a script from it asks each time
|
|
42
|
+
and offers no `always_scope`, since what is in that folder changes without
|
|
43
|
+
a prompt.
|
|
44
|
+
- **A command no loaded skill grants asks you instead of failing.** `python
|
|
45
|
+
script.py`, `git commit` or `pip install` with no skill granting them used to
|
|
46
|
+
come back as "needs a skill grant … declares 'shell:execute:git' in its
|
|
47
|
+
SKILL.md", which nobody could act on. They now raise the approval prompt; a
|
|
48
|
+
skill grant still skips it for reads. A prompt's `summary` for a write or
|
|
49
|
+
code-running command ends with one plain line on what it can do, and the
|
|
50
|
+
`in <folder>` line also appears when an earlier `cd` moved the session. A
|
|
51
|
+
call you decline tells the agent not to reach the same result another way,
|
|
52
|
+
and a run nobody can answer refuses in one plain sentence.
|
|
53
|
+
- **Commands GAIA's checks don't cover ask once instead of failing.** `git
|
|
54
|
+
push`, `git fetch`, `python -c`, PowerShell the checks can't read, a line with
|
|
55
|
+
shell operators, or a path outside the allowed folders used to be refused
|
|
56
|
+
outright. They now raise a prompt whose `summary` is the exact line the shell
|
|
57
|
+
will run, its full folder and a risk sentence, with no `always_scope`; an
|
|
58
|
+
approval runs that line once. Still refused with no prompt: an encoded
|
|
59
|
+
PowerShell command or invisible characters, a line whose quoting can't be
|
|
60
|
+
split the way the shell would, such a line that also deletes or discards work
|
|
61
|
+
(`git push --force`, `git reset --hard`, `rm` outside the project), and
|
|
62
|
+
folders no approval can open.
|
|
63
|
+
- **`run_python` and `execute_python_file` work in the released binary.** The
|
|
64
|
+
binary has no Python interpreter, so it handed every script to its own
|
|
65
|
+
argument parser, which rejected it, and no calculation, chart or `.xlsx`
|
|
66
|
+
could be produced. It now runs scripts itself, with openpyxl, python-docx,
|
|
67
|
+
python-pptx, reportlab, pypdf, pandas, numpy, matplotlib and the full
|
|
68
|
+
standard library bundled for them. The Windows binary grows from 147 MB to
|
|
69
|
+
168 MB.
|
|
70
|
+
- **Long Python data jobs can finish.** `run_python` gave up after 60 s and
|
|
71
|
+
the agent abandoned `execute_python_file` at 180 s even when it had asked
|
|
72
|
+
for 15 minutes, while the script kept running and left a corrupt workbook
|
|
73
|
+
behind. Python runs now get 120 s by default and up to 1800 s on request,
|
|
74
|
+
the agent waits that long, and a run that runs out of time is killed with
|
|
75
|
+
every process it started; the result names the files that changed while it
|
|
76
|
+
ran so the agent checks them instead of reporting them finished.
|
|
77
|
+
- **Document search says when it could not search.** With the embedding
|
|
78
|
+
model or Lemonade Server down, `query_documents` and `query_specific_file`
|
|
79
|
+
answered "no relevant information found", so the agent told the user their
|
|
80
|
+
documents held nothing on the topic. They now return an error naming the
|
|
81
|
+
cause (Lemonade unreachable, or the embedding model failing) and how to fix
|
|
82
|
+
it. `index_document` and `index_directory` report the same cause, and
|
|
83
|
+
`index_directory` stops at the first such file and reports an error when no
|
|
84
|
+
file could be indexed. Hints for a missing optional package (RAG, PDF, Excel,
|
|
85
|
+
HTML parsing) say in a frozen build that it isn't bundled, and from source
|
|
86
|
+
give the install command for the running Python.
|
|
87
|
+
- **A failed tool call is reported as a failure.** `run_shell_command` returned
|
|
88
|
+
`status: success` for a command that exited non-zero, so the TUI and Agent UI
|
|
89
|
+
showed a failed build or test run as a passed step. It is now `status: error`
|
|
90
|
+
with an `error` naming the failing step, its exit code and the last stderr
|
|
91
|
+
line; `stdout`, `stderr` and `return_code` are unchanged. grep's no-match and
|
|
92
|
+
diff's "inputs differ" (exit 1) stay a success and say so in `expected_exit`.
|
|
93
|
+
An MCP tool that answers `isError`, a DuckDuckGo search that was blocked, a
|
|
94
|
+
`tasklist`/`wmctrl`/`osascript` window listing that failed, a notification
|
|
95
|
+
whose PowerShell died, and an `open_url` with no browser to open are errors
|
|
96
|
+
too. Install hints in a frozen build no longer name the binary as a Python to
|
|
97
|
+
run pip with.
|
|
98
|
+
- **Reviewing a few documents reads them in full.** `read_file` on a Word,
|
|
99
|
+
PDF or Excel file returned `[Binary file, N bytes]`, so to compare a term
|
|
100
|
+
sheet against a draft agreement the agent indexed them and ran a handful of
|
|
101
|
+
searches, and missed a closing date that differed between the two because no
|
|
102
|
+
search asked for it. `read_file` now returns the extracted text, in parts sized
|
|
103
|
+
to the model's budget that say where the next part starts, and the prompt
|
|
104
|
+
tells the agent to read a few documents in full for a review, comparison or
|
|
105
|
+
reconciliation and keep indexing for large collections and single lookups.
|
|
106
|
+
- **`fetch_page` no longer drops the middle of a long page.** Text past
|
|
107
|
+
`max_length` was cut to its head and tail, which is where a product page keeps
|
|
108
|
+
its menus and footer, not its price. It now returns the first part with a
|
|
109
|
+
marker naming the offset of the next, takes `offset` to continue and `find` to
|
|
110
|
+
jump to the passages containing a word, says so when a word is not on the
|
|
111
|
+
page, and flags a page with almost no static text as rendered by JavaScript.
|
|
112
|
+
`Length:` now reports the whole page rather than the excerpt.
|
|
113
|
+
- **Long desktop tasks finish with their deliverables instead of a bare "I
|
|
114
|
+
can't confirm this is done".** Picking a controller from nine datasheets and
|
|
115
|
+
pricing a 40-unit BOM ran out of its 50 steps while still searching for
|
|
116
|
+
prices, and the reply dropped the recommendation the agent had already
|
|
117
|
+
written. The agent's default step limit is now **150** (a `/query`
|
|
118
|
+
`max_steps` or `GAIA_AGENT_MAX_STEPS` still wins); at 20, 10 and 5 steps left
|
|
119
|
+
it is told to write the requested files from what it has, marking unverified
|
|
120
|
+
values, and a turn that still runs out keeps its findings and lists what is
|
|
121
|
+
missing after them.
|
|
122
|
+
- **The model notice is one line.** Switching or restoring a model printed a
|
|
123
|
+
four-sentence paragraph that named the model twice and said "via Lemonade".
|
|
124
|
+
It now reads like "Switched to **DeepSeek-V4.1-Flash** on the AMD LLM Gateway
|
|
125
|
+
(cloud). Your messages, and anything read from files or memory, are sent
|
|
126
|
+
there." The `/model` list drops "via Lemonade" from its headings and marks
|
|
127
|
+
the configured default model with `(default)`.
|
|
128
|
+
- **Single-file search results name their file.** `query_specific_file` put the
|
|
129
|
+
path only at the top of its result, so each chunk arrived with no source and
|
|
130
|
+
the chunk cards showed none. Every chunk now carries `source_file`, and the
|
|
131
|
+
result lists it in `source_files`, as `query_documents` already did.
|
|
132
|
+
- **The turn log counts the answer of a streamed turn.** With `GAIA_TURN_LOG`
|
|
133
|
+
set, a turn whose answer streamed out recorded `answer_chars: 0`. It now
|
|
134
|
+
records the length of the answer the user saw.
|
|
135
|
+
- **`run_python` and `execute_python_file` work in the released binary.** The
|
|
136
|
+
binary has no Python interpreter, so it handed every script to its own
|
|
137
|
+
argument parser, which rejected it, and no calculation, chart or `.xlsx`
|
|
138
|
+
could be produced. It now runs scripts itself, with pypdf, pymupdf,
|
|
139
|
+
python-docx, python-pptx, openpyxl, xlsxwriter, reportlab, pandas, numpy,
|
|
140
|
+
matplotlib and the full standard library bundled for them, and both tools
|
|
141
|
+
name those libraries to the model. A script that starts `sys.executable`
|
|
142
|
+
(`-m`, `-c`, a file) runs too; `-m pip` says packages can't be installed
|
|
143
|
+
and lists what is bundled. The Windows binary grows from 147 MB to 168 MB.
|
|
144
|
+
- **A Python script that fails is reported as a failure.** A non-zero exit
|
|
145
|
+
came back as `status: success`, so the TUI showed a failed run as
|
|
146
|
+
successful. It is now `status: error`, with an `error` naming the exit code
|
|
147
|
+
and the last stderr line; `stdout`, `stderr` and `return_code` are unchanged.
|
|
148
|
+
- **`GAIA_ALLOWED_PATHS` confines a run to the folders you name.** The agent
|
|
149
|
+
could read anything under the user's home and nothing narrowed that short of
|
|
150
|
+
embedding it, so an evaluation run could read the graders' answer keys. Set
|
|
151
|
+
to absolute folders, it narrows every file tool, search, index and shell path
|
|
152
|
+
check to them — it never widens, an invalid value stops startup, and code the
|
|
153
|
+
agent runs (`run_python`, shell) is not confined.
|
|
154
|
+
|
|
155
|
+
- **The sidecar's start-up warm-up now makes the first question fast.** It
|
|
156
|
+
primed only the agent's own instructions, without the tool list or the rest
|
|
157
|
+
of the system prompt, so the first question re-read all ~19K prompt tokens
|
|
158
|
+
(34 s on Qwen3.6-35B-A3B). It now sends exactly what a turn sends, and the
|
|
159
|
+
first question reads only its own ~50 tokens (5 s). A warm-up that fails is
|
|
160
|
+
logged as a warning with its cause instead of an info line.
|
|
161
|
+
- **`/model` names the command that connects a cloud provider.** With no
|
|
162
|
+
Fireworks or AMD gateway connection, the list told users to "connect this
|
|
163
|
+
provider in the TUI provider settings", a screen with no obvious way in. It
|
|
164
|
+
now says to run `/provider`, the command that opens it.
|
|
165
|
+
- **The TUI's provider picker works after GAIA's Lemonade restarts.** When the
|
|
166
|
+
agent ran as the TUI's own child, its model-state ping kept naming the port
|
|
167
|
+
Lemonade started on, so after a restart the picker said "Lemonade did not
|
|
168
|
+
respond" while chat worked. With a local or cloud chat model the ping now
|
|
169
|
+
reports the port the agent talks to, and it still never starts a stopped
|
|
170
|
+
server. A Claude session still reports the port it started with.
|
|
171
|
+
- **The Agent UI's Skills settings list this agent's skills.** With the agent
|
|
172
|
+
installed from the Hub, the page said the agent package was not installed
|
|
173
|
+
and to run `gaia init`, which changed nothing: the bundled skills live
|
|
174
|
+
inside the binary, where the UI could not read them. `GET /v1/gaia/skills`
|
|
175
|
+
(contract **2.17**) now returns them.
|
|
176
|
+
- **A message sent right after Stop is answered instead of refused.** A stopped
|
|
177
|
+
turn holds its session until its model call returns, so the next `/query`
|
|
178
|
+
got `409 … is already running a turn` for as long as the stopped answer would
|
|
179
|
+
have taken — about 40 s for a long one. It now waits for the stopped turn to
|
|
180
|
+
finish (up to 240 s) and then runs. A turn that was not cancelled is still
|
|
181
|
+
refused at once.
|
|
182
|
+
- **Documents attached to a chat now reach the agent.** In the Agent UI, a
|
|
183
|
+
Hub-installed agent answered "no documents are indexed" about a file the user
|
|
184
|
+
had attached, because the relayed turn never carried the chat's files.
|
|
185
|
+
`/query` now takes a `documents` field (contract **2.16**): the agent indexes
|
|
186
|
+
them before the turn, granting each exact file and not its folder, including
|
|
187
|
+
a file attached partway through a conversation.
|
|
188
|
+
- **The first chat after the agent starts uses its own tools.** A session built
|
|
189
|
+
while the start-up warm-up was still building could end up running the
|
|
190
|
+
warm-up agent's tools, so a file it had just indexed read as access denied.
|
|
191
|
+
Agents are now built one at a time.
|
|
192
|
+
- **Web requests work behind a corporate TLS-inspecting proxy.** HTTPS now
|
|
193
|
+
trusts the operating system's certificate store, as pip does, instead of only
|
|
194
|
+
Python's bundled list, so a proxy root such as Zscaler's no longer fails every
|
|
195
|
+
fetch with `CERTIFICATE_VERIFY_FAILED`.
|
|
196
|
+
- **Starting the agent no longer downloads a model you skipped.** The HTTP
|
|
197
|
+
sidecar's start-up warm-up skips the default local model when it is not
|
|
198
|
+
downloaded, so someone using a cloud model is not handed a multi-GB download
|
|
199
|
+
they never asked for.
|
|
200
|
+
|
|
201
|
+
## [0.3.0]
|
|
202
|
+
|
|
203
|
+
Released with GAIA 0.25.0, and requires it.
|
|
204
|
+
|
|
205
|
+
### Changed
|
|
206
|
+
|
|
207
|
+
- **Requires `amd-gaia>=0.25.0` and `gaia-agent-chat>=0.2.0`.** Every file tool
|
|
208
|
+
now checks the allowed-folders rule, and that check ships in core 0.25.0; an
|
|
209
|
+
older core cannot import the chat agent this one builds on.
|
|
210
|
+
- **`~/.gaia/logs/gaia-agent.log` stays bounded.** It rotates like `gaia.log`
|
|
211
|
+
(10 MB, three backups; `GAIA_LOG_MAX_MB`, `GAIA_LOG_BACKUPS`) instead of
|
|
212
|
+
growing without limit.
|
|
213
|
+
|
|
214
|
+
- **Everyday questions get short, plain answers.** "Why is the sky blue?" got
|
|
215
|
+
140 words with an equation, and a Wi-Fi question got diagnostic shell runs.
|
|
216
|
+
The voice skill now caps an everyday answer at three plain sentences, goes
|
|
217
|
+
one level deeper only when asked, honours a stored short/detailed preference,
|
|
218
|
+
and answers general-knowledge questions without running tools.
|
|
219
|
+
- **Memory off no longer loads the embedding model.** A private chat, or one
|
|
220
|
+
with memory switched off, used to load the ~300 MB embedder on its first turn
|
|
221
|
+
only to validate it and to score the always-on `gaia-voice` skill. It now
|
|
222
|
+
loads when memory is first used, such as when memory is switched back on or
|
|
223
|
+
the agent recalls something. A turn with only always-on skills loaded embeds
|
|
224
|
+
nothing.
|
|
225
|
+
- **Every tool is offered on every turn again, as in the Agent UI.** Per-turn
|
|
226
|
+
tool selection swapped about a dozen tools in and out at its cap, which broke
|
|
227
|
+
the local model's prompt cache (17s to first token on a one-line question,
|
|
228
|
+
0.4s without it) and left out the tool a question needed: a CSV question was
|
|
229
|
+
given web tools and fetched an unrelated page. `GAIA_DYNAMIC_TOOLS=1` turns
|
|
230
|
+
selection back on. The registered count is 95: `load_tools`, the selector's
|
|
231
|
+
escape hatch, registers only while selection is on.
|
|
232
|
+
- **A turn's silent opening now says what the model is doing.** A thinking
|
|
233
|
+
model sat on "Getting started" for 10-20 s while it read the prompt and then
|
|
234
|
+
reasoned in a paragraph released only once finished. `status` events gain an
|
|
235
|
+
optional `phase` (`loading_model`, `downloading_model`, `reading`,
|
|
236
|
+
`reasoning`, `tool_call`) with a `words` or `chars` count, sent when each phase
|
|
237
|
+
actually starts; the terminal UI shows them as "Reading your request",
|
|
238
|
+
"Reasoning · 214 words" and so on. Clients that ignore the field see the same
|
|
239
|
+
sentence in `message`.
|
|
240
|
+
- **GPU models no longer load at 32K on an NPU-profile machine.** The NPU's
|
|
241
|
+
32,768-token ceiling was applied to every model whenever `default_device` was
|
|
242
|
+
`npu`, so a GGUF model ran at half its window and long tasks overflowed. It now
|
|
243
|
+
binds NPU (FLM) models only. A model can also opt in to a window sized to the
|
|
244
|
+
machine's memory, up to its native maximum.
|
|
245
|
+
- **A stale `GAIA_SKILL_SET` now stops startup.** An undeclared name used to be
|
|
246
|
+
dropped silently, so the agent came up healthy with no skills. The sidecar
|
|
247
|
+
and the stdio entry now exit non-zero before serving, with a message naming
|
|
248
|
+
the valid sets; leave the variable unset to start without one.
|
|
249
|
+
- **The code index is built on first search, not at task start.** In 32
|
|
250
|
+
SWE-bench tasks the agent never searched it, yet every task embedded the whole
|
|
251
|
+
repository in the background: about 2,000 local embedding requests per six
|
|
252
|
+
tasks. The first `search_code_index` now builds it; `GAIA_PROJECT_MAP_AUTO_INDEX=1`
|
|
253
|
+
restores building at task start.
|
|
254
|
+
- **The first answer on a local model starts in seconds, not after a ~20 s
|
|
255
|
+
silence.** The terminal UI now shows a "Getting GAIA ready" stage before the
|
|
256
|
+
chat: the agent starts, loads its model and reads its system prompt there,
|
|
257
|
+
step by step. New stdio sentinel `warm_up` (answers `warmed_up`, or
|
|
258
|
+
`warm_up_skipped` for a remote model).
|
|
259
|
+
- **Permission prompts say what a command does, once.** Running the tests is
|
|
260
|
+
labelled `RUNS CODE`, not `DESTRUCTIVE`; the command appears once, relative to
|
|
261
|
+
the project; and `a` ("always this session") is offered for shell commands and
|
|
262
|
+
Python too, covering the command's family — `pytest` covers
|
|
263
|
+
`python -m pytest`, `cd proj && pytest 2>&1 | tail`. Deletes never offer it.
|
|
264
|
+
`needs_confirmation` gains an optional `risk` field.
|
|
265
|
+
- **Shift+Tab permission modes in the terminal UI**: ask → accept edits → full
|
|
266
|
+
access. Accept edits lets file edits inside the starting folder run unasked;
|
|
267
|
+
the stdio control verb is `accept_edits`, and `--accept-edits` starts in it.
|
|
268
|
+
Full access is still never turned on by a stray keypress.
|
|
269
|
+
- **An unanswered prompt is reported as a timeout.** `tool_decision` accepts
|
|
270
|
+
`timeout`; the agent tells the user the request expired rather than that they
|
|
271
|
+
refused it.
|
|
272
|
+
- The default chat model now follows the hardware. On a PC whose GPU has
|
|
273
|
+
~27 GB for models — a 64 GB+ Strix Halo or a 32 GB GPU; the 23.3 GB model also
|
|
274
|
+
needs its context cache — `gaia init` sets up Qwen3.6 35B A3B (a 23 GB Lemonade
|
|
275
|
+
built-in MoE, run with thinking on) and records it as `default_model`; the
|
|
276
|
+
agent and its `GET /v1/gaia/init` readiness check use it for chat. Gemma 4 E4B
|
|
277
|
+
is still downloaded for vision. Every other PC, including a CPU-only one, keeps
|
|
278
|
+
Gemma alone.
|
|
279
|
+
- **Qwen3.6 gets the longest context this PC's memory holds.** Up to its native
|
|
280
|
+
262,144 tokens on a Strix Halo (a 5.4 GB KV cache), about 152K on a 32 GB GPU,
|
|
281
|
+
never under 64K. Gemma stays at 64K.
|
|
282
|
+
- Qwen3.8 Flash Next (82 GB, multimodal, thinking on) is available on a
|
|
283
|
+
128 GB Strix Halo and never picked as a default; it needs ~90 GB for models.
|
|
284
|
+
Choose it with `gaia config set default_model user.Qwen3.8-Flash-Next-GGUF`;
|
|
285
|
+
`gaia init` refuses it on a PC that cannot hold it.
|
|
286
|
+
- **Bypass permissions is now called full access, everywhere.** `--full-access`
|
|
287
|
+
and `/full-access` replace `--bypass-permissions` and `/bypass`; the old names
|
|
288
|
+
fail with a message naming the new one. `/full-access always` (or
|
|
289
|
+
`gaia config set full_access true`) keeps it on across launches.
|
|
290
|
+
- **The agent has to read a file before it changes it.** `edit_file`, and
|
|
291
|
+
`write_file` on an existing file, now refuse a file the agent hasn't read with
|
|
292
|
+
`read_file` in this session, or one that changed on disk since it did. Benchmark
|
|
293
|
+
runs caught the agent patching files it had never opened, from a grep snippet
|
|
294
|
+
or a guess; now it has to look first. A partial read counts, creating a file
|
|
295
|
+
needs no read, and the refusal comes before any approval prompt. It applies
|
|
296
|
+
with confirmations bypassed too.
|
|
297
|
+
- **The agent sees every installed skill and loads the one that fits.**
|
|
298
|
+
Previously a per-turn matcher scored the request against skill descriptions
|
|
299
|
+
and loaded a skill on 0 of 24 benchmark tasks, so most GitHub requests never
|
|
300
|
+
learned `gh` was available. The system prompt now lists each installed skill
|
|
301
|
+
in one line (~1,000 tokens for the starter pack), and refusing a skill-gated
|
|
302
|
+
CLI names the skill to load. `GAIA_SKILL_DISCOVERY=0` still hides the list.
|
|
303
|
+
**Removed:** `GAIA_SKILL_DISCOVERY_TAU` is now ignored, and
|
|
304
|
+
`GaiaAgentConfig(skill_discovery_threshold=…)` raises `TypeError` — drop the
|
|
305
|
+
argument. See the Agent Skills spec, "Skill catalogue".
|
|
306
|
+
- Contract `apiVersion` is now **2.14** (2.13 added `GET /memory`) for the two new routes and
|
|
307
|
+
the `claude` provider value. A differing major still raises
|
|
308
|
+
`VersionMismatchError`; a higher minor is accepted.
|
|
309
|
+
- **Changing `model` on a live `session_id` switches in place** instead of
|
|
310
|
+
returning 409, so the conversation and any loaded skills survive it. A switch
|
|
311
|
+
that fails still returns 409 and leaves the session on its previous model.
|
|
312
|
+
|
|
313
|
+
### Fixed
|
|
314
|
+
|
|
315
|
+
- **Answering the agent's question from the Agent UI or the TUI works.**
|
|
316
|
+
`POST /query/{run_id}/respond` only took the answer as `response`, while
|
|
317
|
+
both front-ends send `{ request_id, value }` as the contract specifies, so
|
|
318
|
+
every answer was refused and the run waited until the question timed out.
|
|
319
|
+
It now takes `value`. `response` is still accepted; sending both, or
|
|
320
|
+
neither, is a 422.
|
|
321
|
+
- **A file you allow is usable by every tool, including document Q&A.** Indexing
|
|
322
|
+
or querying a file outside the chat's scope was refused with no prompt, and
|
|
323
|
+
approving it through another tool still left it unreadable to the document
|
|
324
|
+
index. Indexing now asks the same question `read_file` does, and one approval
|
|
325
|
+
covers both. A tool waiting on that question is no longer abandoned at its
|
|
326
|
+
180 s limit while the question is still on screen. A refusal now tells the
|
|
327
|
+
model not to copy or move the file elsewhere to get around it.
|
|
328
|
+
- **`--use-claude` works with the downloaded binary.** The release build left
|
|
329
|
+
out the Anthropic client, so every Claude launch from the terminal UI, and
|
|
330
|
+
every `/model` switch to Claude, failed with "The 'anthropic' package is
|
|
331
|
+
required", which a frozen binary cannot act on. The client is now bundled, and
|
|
332
|
+
the release build fails if it is missing.
|
|
333
|
+
|
|
334
|
+
- **Code search works in an Agent UI chat that is not inside a project.** It
|
|
335
|
+
started in GAIA's own documents folder, which usually does not exist yet, so
|
|
336
|
+
every `search_code_index` failed with "repo_path does not exist". It now starts
|
|
337
|
+
in a repository the chat can reach, else any folder it can reach that exists.
|
|
338
|
+
|
|
339
|
+
- **`/model` no longer offers speech or other non-chat models as chat
|
|
340
|
+
targets.** Whisper was listed as a "chat-capable" local model; switching to it
|
|
341
|
+
reported success and broke the next turn. Transcription, speech, music,
|
|
342
|
+
classification, upscaling and 3D models are excluded; a model labeled `chat`
|
|
343
|
+
still qualifies even if it also transcribes.
|
|
344
|
+
- **The agent no longer starts an unrelated job after answering.** A bugfix
|
|
345
|
+
request loaded the `coding` skill, whose "find every call site" tip switched
|
|
346
|
+
on document inventorying; after the fix was done and verified, the agent spent
|
|
347
|
+
minutes extracting every file it had read until the user cancelled. Only a
|
|
348
|
+
skill built on the extraction tool turns inventorying on now. Separately,
|
|
349
|
+
once a turn has answered, a tool call on nothing the request touched is not
|
|
350
|
+
run and a second one ends the turn, and a tool that keeps failing with new
|
|
351
|
+
arguments is stopped like an identical repeat.
|
|
352
|
+
- A "no" now covers what an action does, not the one tool it was asked
|
|
353
|
+
through. After you decline `pytest`, or leave its prompt unanswered, the
|
|
354
|
+
agent no longer writes `run_tests.py` and runs it with another tool: any
|
|
355
|
+
call that would run the tests, reach the same host, or change the same file
|
|
356
|
+
is stopped for the rest of that request. Where the surface can ask, you get
|
|
357
|
+
the exact command and why, with Allow once / Don't run it; otherwise the
|
|
358
|
+
agent stops and asks in its reply.
|
|
359
|
+
- `/v1/gaia/query` now honours `provider` on an existing session. It used to
|
|
360
|
+
matter only when the session was created, so `provider: "lemonade"` could keep
|
|
361
|
+
sending a Claude session's conversation to Anthropic, and `provider: "claude"`
|
|
362
|
+
could run locally. A different provider now switches the session in place.
|
|
363
|
+
Naming a `model` that belongs to the other provider is a 400, on new and
|
|
364
|
+
existing sessions alike. Omitting `provider` and naming a Claude `model` now
|
|
365
|
+
starts a Claude session, the way it already switched an existing one — it used
|
|
366
|
+
to point the local backend at an id it cannot serve.
|
|
367
|
+
- "Lemonade is not reachable" errors no longer tell users to run
|
|
368
|
+
`lemonade-server serve`, a command current Lemonade installs don't have. The
|
|
369
|
+
`GET /v1/gaia/init` hint, run errors, and `/model` now say how to start
|
|
370
|
+
Lemonade on the user's own install (tray app, macOS app, service, or CLI).
|
|
371
|
+
`/model <unknown>` with nothing downloaded likewise names the download command
|
|
372
|
+
the host actually has, instead of the removed `lemonade-server pull`.
|
|
373
|
+
- `gaia serve` no longer exits 0 when Ctrl+C fails to stop the sidecar. The
|
|
374
|
+
error naming the surviving process and how to kill it was discarded, so the
|
|
375
|
+
next `serve` hit an unexplained port conflict. It now prints that error and
|
|
376
|
+
exits 1.
|
|
377
|
+
- Conversation state is saved under `~/.gaia/sessions` instead of the directory
|
|
378
|
+
the agent was started from. A `session_id` must be 1–128 characters from
|
|
379
|
+
`A-Z a-z 0-9 . _ -`; any other value is a 400 on `/query` and
|
|
380
|
+
`/sessions/{session_id}/bypass` instead of a 500. A corrupt saved session fails
|
|
381
|
+
the request instead of being silently replaced.
|
|
382
|
+
- `gaia hub install gaia` no longer refuses Intel Macs: the hub manifest now
|
|
383
|
+
lists `darwin-x64`, which the release already builds and the lock already ships.
|
|
384
|
+
- The hub install card advertises the declared npm package instead of an unpublished PyPI wheel.
|
|
385
|
+
- The readiness check (`GET /v1/gaia/init`) and the terminal session's health
|
|
386
|
+
report name GAIA's own Lemonade Server instead of Lemonade's default port.
|
|
387
|
+
- Clearing a TUI conversation now also clears the flagship stdio agent’s prior
|
|
388
|
+
conversation context, while preserving the selected model, skills, and permissions.
|
|
389
|
+
- Internal session deletion (not yet exposed by a route) refuses busy agents instead of closing them mid-turn.
|
|
390
|
+
- Scratch files no longer land in the user's project. The system temp dir was
|
|
391
|
+
out of scope, so the agent wrote throwaway test runners and intermediate files
|
|
392
|
+
into the repository instead. It now gets its own scratch directory, named in its
|
|
393
|
+
prompt and deleted when the agent closes; the rest of the temp dir stays denied.
|
|
394
|
+
- Every file tool now checks the same allowed-folders rule as `read_file`:
|
|
395
|
+
browsing, folder and content search, recent files, document indexing, folder
|
|
396
|
+
watching, code indexing, and where screenshots, transcripts and exports are
|
|
397
|
+
saved. A folder outside the scope gets the usual approval prompt, and a folder
|
|
398
|
+
you approve is readable by document indexing too.
|
|
399
|
+
|
|
400
|
+
### Added
|
|
401
|
+
|
|
402
|
+
- **A committed, machine-readable `/query` contract.** `openapi.gaia.json` in
|
|
403
|
+
the Python package is generated from the live routes
|
|
404
|
+
(`python -m gaia_agent.export_openapi`) and checked for drift in CI, so a
|
|
405
|
+
typed client no longer has to reverse-engineer the body from prose —
|
|
406
|
+
`query`, `run_id`, and `context` are required, `run_id` must be a UUID, and
|
|
407
|
+
the bearer-auth posture is declared in the schema. Swagger UI (`/docs`) is
|
|
408
|
+
disabled on the sidecar — it loads its JS from a CDN, an unexpected network
|
|
409
|
+
call for an offline embedder — but `/openapi.json` is still served.
|
|
410
|
+
- **Programs the agent starts no longer inherit GAIA's internal credentials.**
|
|
411
|
+
Shell commands, MCP servers, CLI installs and sign-ins, native hub agents,
|
|
412
|
+
media tools and the Lemonade server get the sidecar's environment minus
|
|
413
|
+
GAIA's own tokens. Your own variables (`GH_TOKEN` and the like) still pass through, so CLI skills
|
|
414
|
+
keep working. An embedding app can withhold more names with
|
|
415
|
+
`GAIA_CHILD_ENV_DENY` (comma or space separated), and can stop GAIA loading
|
|
416
|
+
`.env` files with `GAIA_NO_DOTENV=1` — read from the real environment, so a
|
|
417
|
+
`.env` cannot set it.
|
|
418
|
+
- **The agent can drive a real browser.** Pages behind JavaScript or a login
|
|
419
|
+
used to be out of reach — `fetch_page` is one HTTP GET, so a signed-in inbox
|
|
420
|
+
or a dashboard came back empty. Eight new tools open a real Chromium, read
|
|
421
|
+
it, click and type in it, and sign in to a site; the password goes to the
|
|
422
|
+
human, never the model, and the session is stored encrypted. Acting inside a
|
|
423
|
+
session you signed in to asks first. Ships behind the optional `browser`
|
|
424
|
+
extra; without it none of the eight register. Registered tool count goes
|
|
425
|
+
88 → 96.
|
|
426
|
+
- **Fast mode, for a session that's only conversation.** `GAIA_FAST=1` drops
|
|
427
|
+
the flagship to a plain conversational surface for the whole session —
|
|
428
|
+
3,110 tokens of fixed prompt instead of 17,942 — so saying "hi" no longer
|
|
429
|
+
costs as much as a repo search. Session-scoped and one-way: a fast session
|
|
430
|
+
has no documents, files, web or skills and cannot pick them up mid-way.
|
|
431
|
+
- **`chat`, `doc` and `file` are no longer offered as agents.** New users saw
|
|
432
|
+
four entries in the picker where only one is the product. The three ids still
|
|
433
|
+
resolve, so existing sessions, `*-lite` aliases and eval scenarios keep
|
|
434
|
+
working — they are hidden, not deleted, and `ChatAgent` remains the
|
|
435
|
+
flagship's base class. A session created without an explicit agent now lands
|
|
436
|
+
on the flagship rather than a hidden agent.
|
|
437
|
+
- **Complete inventories from long documents.** Asking for every exercise,
|
|
438
|
+
action item or finding in a transcript now returns all of them, each with its
|
|
439
|
+
source quote, instead of a condensed list. The opt-in `document-extract` skill
|
|
440
|
+
drives new `extract_document_items` and `save_extracted_items` tools; a save is
|
|
441
|
+
reported only after the exact file is written and read back, and anything
|
|
442
|
+
unfinished is reported as incomplete. `gaia-voice` gains one routing line
|
|
443
|
+
(702 tokens).
|
|
444
|
+
- **The agent can set up a skill's CLI instead of handing the job back.** Asking
|
|
445
|
+
it to triage GitHub issues on a machine without `gh` used to end the
|
|
446
|
+
conversation. Three new tools — `check_cli_setup` (read-only), `install_cli`
|
|
447
|
+
and `sign_in_cli` — let it report exactly what is wrong, install the CLI with
|
|
448
|
+
the machine's package manager, and drive the browser sign-in. Both mutating
|
|
449
|
+
tools are confirmation-gated on every call and no skill grant pre-approves
|
|
450
|
+
them; over `/v1/gaia/query` they are refused, like every other gated tool
|
|
451
|
+
(§8). Registered tool count goes 83 → 86.
|
|
452
|
+
- **A shell command's `cd` now survives to the next one.** Every
|
|
453
|
+
`run_shell_command` call used to start from scratch, so `cd build` in one
|
|
454
|
+
call was invisible to the next. `get_shell_state` reads the session's
|
|
455
|
+
current directory, and `reset_shell_session` returns it to where the task
|
|
456
|
+
started. Registered tool count goes 86 → 88.
|
|
457
|
+
- **Say something while the agent is still working.** `POST
|
|
458
|
+
/v1/gaia/query/{run_id}/followup` hands a live run a message the user typed
|
|
459
|
+
after it started (contract **2.15**). The run is not interrupted and no
|
|
460
|
+
second turn starts — the agent folds the text into the turn already running
|
|
461
|
+
at its next step boundary, so a correction during a five-minute task changes
|
|
462
|
+
that task instead of arriving after it finished. Unknown run → `404`, an
|
|
463
|
+
agent that cannot take one → `409`; both loud, because the caller has already
|
|
464
|
+
taken the message from the user. See SPEC §5.6 and SKILL §7.
|
|
465
|
+
- **Approve a gated tool over HTTP.** `write_file`, `run_shell_command` and the
|
|
466
|
+
seven other confirmation-gated tools can now run through `/v1/gaia/query`:
|
|
467
|
+
the stream stays open on `needs_confirmation` and
|
|
468
|
+
`POST /v1/gaia/query/{run_id}/tool_decision` answers it. Previously the only
|
|
469
|
+
possible answer was a refusal, so those tools were unreachable over HTTP.
|
|
470
|
+
`POST /v1/gaia/sessions/{session_id}/bypass` turns the asking off for a
|
|
471
|
+
session. A run that cannot answer — no `session_id`, or
|
|
472
|
+
`can_answer_questions: false` — is still refused. See SKILL §8.
|
|
473
|
+
- **Claude as an inference backend.** `provider: "claude"` sends the
|
|
474
|
+
conversation to Anthropic's API instead of the local server; `model` then
|
|
475
|
+
names a Claude model. Anything outside `lemonade` / `claude` is still a 400.
|
|
476
|
+
- **`gaia-agent --serve` works from a pip install.** The console script pointed
|
|
477
|
+
past the transport dispatcher, so the documented HTTP mode exited with
|
|
478
|
+
"unrecognized arguments".
|
|
479
|
+
- **Tracked eval scorecard ([`SCORECARD.md`](./SCORECARD.md)).** The agent now
|
|
480
|
+
ships a per-release scorecard: judged-scenario pass rate (the aggregate)
|
|
481
|
+
plus per-category rates and the judge's average score across the
|
|
482
|
+
13-category eval corpus (`eval/scenarios/gaia_*`), generated by
|
|
483
|
+
`hub/agents/gaia/python/packaging/gen_scorecard.py` from real
|
|
484
|
+
`gaia eval agent --agent-type gaia` runs. CI runs a PR subset
|
|
485
|
+
(`test_gaia_agent_eval.yml`), the weekly sweep runs the full corpus, and the
|
|
486
|
+
release pipeline gates on the committed card
|
|
487
|
+
(`scorecard-gate` + a judged eval subset in `release_agent_gaia.yml`).
|
|
488
|
+
The initially committed card is a harness validation measured with the
|
|
489
|
+
agent on `claude-haiku-4-5` (the dev environment cannot run Lemonade); the
|
|
490
|
+
first full runner refresh (`gaia_scorecard_refresh.yml`) replaces it with
|
|
491
|
+
the Gemma-4-E4B product baseline.
|
|
492
|
+
- **`capture_skill` — capture a skill from pasted `SKILL.md` text, a URL, or a
|
|
493
|
+
local folder, with code inert until trusted.** The agent can now bring a
|
|
494
|
+
skill into `~/.gaia/skills` straight from the conversation (68 registered
|
|
495
|
+
tools, up from 67). Every capture is confirmation-gated, security-audited (a
|
|
496
|
+
`BLOCK` verdict refuses it), SSRF-guarded on the URL path, and lands at the
|
|
497
|
+
`experimental` tier. Instructions load immediately; any `tools.py`/scripts
|
|
498
|
+
the bundle carries stay **inert** until the user runs
|
|
499
|
+
`gaia skill promote <name>` in a terminal, which re-audits and binds trust
|
|
500
|
+
to the audited bytes. Over `/query`, `capture_skill` is gated like the
|
|
501
|
+
other confirmation tools (SKILL §8; SPEC §5.2 documents the load-time
|
|
502
|
+
deferral).
|
|
503
|
+
- **`run_python`, always on.** A quick calculation or data transform is now one
|
|
504
|
+
confirmation-gated call that runs from the project root and returns what it
|
|
505
|
+
printed, instead of a throwaway script left in your repository. It joins the
|
|
506
|
+
always-on tool set (about 250 more prompt tokens per call) and the `shell`
|
|
507
|
+
bundle.
|
|
508
|
+
- Opt-in developer-mode skill and consent-gated MCP handoffs to Claude Code/Codex,
|
|
509
|
+
with managed worktrees, approved feedback snapshots and reported preview results.
|
|
510
|
+
Python `[mcp]` installation is required for the bridge; normal mode has no access.
|
|
511
|
+
- **The shell, always on inside a code repository.** When the project map
|
|
512
|
+
resolves to a repository (a VCS directory or a known manifest at its root),
|
|
513
|
+
`run_shell_command` is offered on every turn instead of only when the request
|
|
514
|
+
happens to sound like a shell request. Coding tasks such as "skip these tests
|
|
515
|
+
on PRs" previously ran without a shell and did every grep through `run_python`.
|
|
516
|
+
It follows the *same* root the map already uses, so the sidecar needs
|
|
517
|
+
`GAIA_PROJECT_ROOT=/path/to/repo` (or `GaiaAgentConfig(project_root=...)` when
|
|
518
|
+
embedding) to see your repository — its own working directory is whatever
|
|
519
|
+
started it, not yours. With no repository nothing changes, and the shell's
|
|
520
|
+
approval gate still applies either way. See SKILL §11.
|
|
521
|
+
- **`sleep`, always on.** The agent can now wait before retrying, e.g. until a
|
|
522
|
+
rate limit resets, instead of giving up; before, its only way to wait was
|
|
523
|
+
`time.sleep` inside a confirmation-gated `run_python`. Up to five minutes per
|
|
524
|
+
call, no approval needed, and Stop ends the wait within a second. It joins the
|
|
525
|
+
always-on tool set (about 190 more prompt tokens per call) and the
|
|
526
|
+
`loop_control` bundle (80 tools → 81).
|
|
527
|
+
- **`--bypass-permissions` now lifts the shell guardrails too.** It used to skip
|
|
528
|
+
only the confirmation prompt, which left the agent unable to run a build or a
|
|
529
|
+
test suite even with the user's blanket consent: no interpreter, test runner
|
|
530
|
+
or package manager was reachable, and nothing could write its output anywhere.
|
|
531
|
+
Under bypass, redirection (`>`, `>>`, `<`), backgrounding (`&`), substitution
|
|
532
|
+
(`` ` ``, `$()`) and the newline now parse and run — chaining with `&&` / `||`
|
|
533
|
+
/ `;` / `|` already worked by default — the
|
|
534
|
+
read-only allowlist is replaced by a developer set (`node`, `npm`, `make`,
|
|
535
|
+
`cmake`, `go`, `cargo`, `sed`, `awk`, `curl`, `sleep`, `timeout`, `export`,
|
|
536
|
+
`cp`, `mv`, plus `python` / `python3` / `pytest` / `gh` / `git`), and the
|
|
537
|
+
shell rate limit is dropped. Off by default and byte-identical to before when
|
|
538
|
+
off. `git` in that set means its policy's outright refusals — push, reset,
|
|
539
|
+
rebase — also stop applying under bypass. `rm` stays excluded. Every command run this way is audit-logged with its full
|
|
540
|
+
arguments. Stdio only — an HTTP session's `/bypass` stops its approval prompts
|
|
541
|
+
but never lifts the shell gates, and the request body cannot ask for it.
|
|
542
|
+
Redirection has one exception: a command that
|
|
543
|
+
is nothing but a skill-granted CLI runs argv-only, so `>` there is refused
|
|
544
|
+
with an explanation instead of reaching the binary as text. See SPEC §5.5.
|
|
545
|
+
|
|
546
|
+
### Notes
|
|
547
|
+
|
|
548
|
+
- Tracks sidecar contract `apiVersion` **2.14**; a differing major raises
|
|
549
|
+
`VersionMismatchError`.
|
|
550
|
+
- `GET /v1/gaia/memory` (contract 2.13) answers the same read-only snapshot the
|
|
551
|
+
stdio transport's `/memory` sentinel produces, so a daemon-supervised
|
|
552
|
+
install of the flagship exposes `/memory` too, not just a subprocess one.
|
|
553
|
+
|
|
554
|
+
## [0.2.0] — 2026-09-16
|
|
14
555
|
|
|
15
556
|
### Fixed
|
|
16
557
|
|
|
@@ -29,7 +570,6 @@ the terminal UI meant building it from source.
|
|
|
29
570
|
on the previous image.
|
|
30
571
|
- TUI provider setup for Local, Fireworks AI, and AMD LLM Gateway, with masked
|
|
31
572
|
runtime API keys, discovered models, and remote-inference status.
|
|
32
|
-
|
|
33
573
|
- **A project map at task start.** In a code repository the agent now opens
|
|
34
574
|
every task knowing the directory shape, the likely entry points, which
|
|
35
575
|
commands are installed, and the three platform differences that change
|
|
@@ -38,10 +578,6 @@ the terminal UI meant building it from source.
|
|
|
38
578
|
starts one in the background; `GAIA_PROJECT_MAP_AUTO_INDEX=0` turns that off,
|
|
39
579
|
and `GAIA_PROJECT_ROOT` picks the project when the working directory is not
|
|
40
580
|
it. See SKILL §11.
|
|
41
|
-
- **`503` from `/query` at session capacity.** When every retained session
|
|
42
|
-
slot is busy and none is idle enough to evict, starting a new session
|
|
43
|
-
returns `503` with the reason in `detail` — retryable, distinct from a
|
|
44
|
-
bug-shaped `500`. See SPEC §5.2.
|
|
45
581
|
- **Three further client-visible refusals from `/query`.** Reusing a `run_id`
|
|
46
582
|
that is still in flight gets `409` — it used to replace the live run, leaving
|
|
47
583
|
it with no way to be cancelled. Supplying a `model` that differs from the one
|
|
@@ -49,21 +585,17 @@ the terminal UI meant building it from source.
|
|
|
49
585
|
the old model. A request with an absent or empty `Host` header gets `400`
|
|
50
586
|
rather than being served, closing a DNS-rebinding check that failed open.
|
|
51
587
|
See SPEC §5 and §5.2.
|
|
52
|
-
- **Per-turn skill-body selection.** A loaded skill stays loaded, but its body
|
|
53
|
-
only renders in the prompt on turns whose query matches its description; the
|
|
54
|
-
rest collapse to a one-line menu the model re-activates with `load_skill`.
|
|
55
|
-
`GAIA_DYNAMIC_SKILLS=0` turns the selection off, `GAIA_DYNAMIC_SKILLS_TAU`
|
|
56
|
-
overrides the match threshold, and an embedder outage disables it for the
|
|
57
|
-
session (every body renders — capability is never lost to a failed match).
|
|
58
588
|
- **Per-turn tool selection, now on by default for the flagship `full`
|
|
59
|
-
profile.** The model is sent
|
|
589
|
+
profile.** The model is sent about 28 of its 84 tools on any one call — a
|
|
60
590
|
fixed core plus whichever cohesion bundles the query matched — instead of the
|
|
61
591
|
whole registry every time. No capability is lost: `load_tools` is an escape
|
|
62
|
-
hatch the model calls mid-turn to pull in a bundle the selector missed
|
|
592
|
+
hatch the model calls mid-turn to pull in a bundle the selector missed; that
|
|
593
|
+
bundle is appended for the rest of the turn (briefly above the cap, which the
|
|
594
|
+
next turn restores) so the prompt already sent stays cached.
|
|
63
595
|
`GAIA_DYNAMIC_TOOLS=0` turns the selection off, `GAIA_DYNAMIC_TOOLS_MAX`
|
|
64
596
|
moves the cap and `GAIA_DYNAMIC_TOOLS_TAU` the match threshold.
|
|
65
597
|
- **One bundled skill ships enabled: `gaia-voice`.** It is a manifest `skills:`
|
|
66
|
-
entry, so it is always on and rendered in full on every LLM call —
|
|
598
|
+
entry, so it is always on and rendered in full on every LLM call — 702 tokens
|
|
67
599
|
of every prompt, and it declares no tools. It is the agent's honesty floor
|
|
68
600
|
(don't claim work you didn't do, don't present empty output as a result,
|
|
69
601
|
don't substitute a near-miss and report success), which is why it is not in an
|
|
@@ -75,46 +607,6 @@ the terminal UI meant building it from source.
|
|
|
75
607
|
behavioural rules intact. It had been a rationale document — every rule
|
|
76
608
|
followed by the incident that motivated it — and the model needs the rule,
|
|
77
609
|
not the incident report.
|
|
78
|
-
- **`gaia run` (the default command)** — resolves the host platform, fetches and
|
|
79
|
-
SHA-256 verifies both binaries, then launches the terminal UI and propagates its
|
|
80
|
-
exit code. Arguments after a bare `--` are forwarded to the TUI verbatim.
|
|
81
|
-
- **Dual-binary delivery.** The package installs two published artifacts: the
|
|
82
|
-
frozen agent sidecar (`gaia-agent`), published by this package's own release,
|
|
83
|
-
and the terminal UI (`gaia-tui`), which is the published **`terminal-hub`**
|
|
84
|
-
component. The TUI is consumed, not rebuilt — it is byte-for-byte the binary a
|
|
85
|
-
full GAIA install runs as `gaia tui`, so an npm user and a core user cannot end
|
|
86
|
-
up on terminal UIs that behave differently. A second build under this package's
|
|
87
|
-
own lane would have been the same bytes at a different version under a third
|
|
88
|
-
naming convention, and the two would have drifted.
|
|
89
|
-
- **`binaries.lock.json` `schemaVersion` 3.0** — a component-keyed checksum
|
|
90
|
-
manifest where **each component carries its own `componentVersion`, `baseUrl`
|
|
91
|
-
and `platforms`**. Component-first rather than the email agent's flat `binaries`
|
|
92
|
-
map because the two differ in every dimension: hub lane, version, and platform
|
|
93
|
-
coverage (terminal-hub covers arm64 Linux and arm64 Windows; the PyInstaller
|
|
94
|
-
sidecar does not). A single shared base URL cannot address two lanes, so a
|
|
95
|
-
`1.x`- or `2.x`-shaped lock is rejected at load with an error naming the schema.
|
|
96
|
-
- **Terminal-hub artifact naming is handled in data.** That lane names its Windows
|
|
97
|
-
builds `gaia-win-x64.exe` / `gaia-win-arm64.exe`, while platform keys come from
|
|
98
|
-
`process.platform` and say `win32`. The lock keeps the `win32-*` key and carries
|
|
99
|
-
the hub's spelling in `filename`, so nothing branches on platform to construct a
|
|
100
|
-
URL. The mapping is asserted on both sides (`TUI_ARTIFACT_NAMES` in
|
|
101
|
-
`src/platform.ts` and in the lock generator) because a wrong name there is not a
|
|
102
|
-
build failure anywhere — it is a 404 on a user's first run.
|
|
103
|
-
- **Mandatory SHA-256 verification.** Every download is hashed and compared
|
|
104
|
-
against the lock before it is written. A mismatch deletes the download and
|
|
105
|
-
raises `IntegrityError` naming expected vs actual. A placeholder hash blocks the
|
|
106
|
-
fetch before any network call. There is no flag that relaxes either.
|
|
107
|
-
- **`gaia fetch`** — download and verify without launching; prints JSON. Supports
|
|
108
|
-
`--component` and `--platform` for cross-platform staging in CI.
|
|
109
|
-
- **`gaia serve`** — run the agent sidecar alone on `127.0.0.1:8141` for
|
|
110
|
-
integrators who want the REST surface without a daemon or a UI. Health-polls
|
|
111
|
-
`GET /health`, checks the contract version, and tree-kills on exit. Port `4001`
|
|
112
|
-
is refused.
|
|
113
|
-
- **`gaia version`** — prints, per component, its version, the URL it is fetched
|
|
114
|
-
from, and its platform matrix.
|
|
115
|
-
- **Programmatic exports** — `fetchAll`, `startSidecar`, `shutdown`, `runTui`, the
|
|
116
|
-
platform helpers, and the typed error classes, for embedding GAIA in another
|
|
117
|
-
app.
|
|
118
610
|
- **The `.installed` record is written after a verified sidecar install.**
|
|
119
611
|
Staging the binary was only half an install: the daemon and the terminal UI
|
|
120
612
|
both key "this agent is installed" on `~/.gaia/agents/gaia/.installed`, and
|
|
@@ -205,14 +697,83 @@ the terminal UI meant building it from source.
|
|
|
205
697
|
that killed only the launcher: the cancelled tool call ran to completion and
|
|
206
698
|
the surviving process consumed the next message. The first Esc now sends the
|
|
207
699
|
agent a `cancel` control message, so the turn ends and the session keeps its
|
|
208
|
-
loaded skills, "always" grants, history and
|
|
700
|
+
loaded skills, "always" grants, history and full access. A second Esc stops
|
|
209
701
|
the whole process tree.
|
|
210
|
-
- **A restart after a hard stop no longer turns
|
|
702
|
+
- **A restart after a hard stop no longer turns full access back on.**
|
|
211
703
|
The replacement agent is launched in the session's current permission mode
|
|
212
704
|
instead of from the original flags, and the TUI says what the restart lost.
|
|
213
705
|
|
|
214
706
|
### Notes
|
|
215
707
|
|
|
708
|
+
- `gaia_agent` enforces a per-session caller-auth bearer on every `/v1/gaia/*`
|
|
709
|
+
request, plus a loopback `Host` allowlist and non-loopback `Origin` rejection.
|
|
710
|
+
This package mints no token, so a sidecar it spawns comes up in dev mode (token
|
|
711
|
+
check skipped, loudly warned, Host/Origin still enforced) — pass your own
|
|
712
|
+
through `spawnSidecar`'s `env` to turn it on. See SPEC §5.4.
|
|
713
|
+
|
|
714
|
+
## [0.1.1] — 2026-08-21
|
|
715
|
+
|
|
716
|
+
First working release. `npx @amd-gaia/gaia` is now the single command that gets a
|
|
717
|
+
user running GAIA: it fetches and verifies everything GAIA needs and drops them
|
|
718
|
+
into the terminal UI. Before this there was no packaged path at all — the flagship
|
|
719
|
+
agent had to be run from a repo checkout with a Python environment, and reaching
|
|
720
|
+
the terminal UI meant building it from source.
|
|
721
|
+
|
|
722
|
+
### Added
|
|
723
|
+
|
|
724
|
+
- **`503` from `/query` at session capacity.** When every retained session
|
|
725
|
+
slot is busy and none is idle enough to evict, starting a new session
|
|
726
|
+
returns `503` with the reason in `detail` — retryable, distinct from a
|
|
727
|
+
bug-shaped `500`. See SPEC §5.2.
|
|
728
|
+
- **Per-turn skill-body selection.** A loaded skill stays loaded, but its body
|
|
729
|
+
only renders in the prompt on turns whose query matches its description; the
|
|
730
|
+
rest collapse to a one-line menu the model re-activates with `load_skill`.
|
|
731
|
+
`GAIA_DYNAMIC_SKILLS=0` turns the selection off, `GAIA_DYNAMIC_SKILLS_TAU`
|
|
732
|
+
overrides the match threshold, and an embedder outage disables it for the
|
|
733
|
+
session (every body renders — capability is never lost to a failed match).
|
|
734
|
+
- **`gaia run` (the default command)** — resolves the host platform, fetches and
|
|
735
|
+
SHA-256 verifies both binaries, then launches the terminal UI and propagates its
|
|
736
|
+
exit code. Arguments after a bare `--` are forwarded to the TUI verbatim.
|
|
737
|
+
- **Dual-binary delivery.** The package installs two published artifacts: the
|
|
738
|
+
frozen agent sidecar (`gaia-agent`), published by this package's own release,
|
|
739
|
+
and the terminal UI (`gaia-tui`), which is the published **`terminal-hub`**
|
|
740
|
+
component. The TUI is consumed, not rebuilt — it is byte-for-byte the binary a
|
|
741
|
+
full GAIA install runs as `gaia tui`, so an npm user and a core user cannot end
|
|
742
|
+
up on terminal UIs that behave differently. A second build under this package's
|
|
743
|
+
own lane would have been the same bytes at a different version under a third
|
|
744
|
+
naming convention, and the two would have drifted.
|
|
745
|
+
- **`binaries.lock.json` `schemaVersion` 3.0** — a component-keyed checksum
|
|
746
|
+
manifest where **each component carries its own `componentVersion`, `baseUrl`
|
|
747
|
+
and `platforms`**. Component-first rather than the email agent's flat `binaries`
|
|
748
|
+
map because the two differ in every dimension: hub lane, version, and platform
|
|
749
|
+
coverage (terminal-hub covers arm64 Linux and arm64 Windows; the PyInstaller
|
|
750
|
+
sidecar does not). A single shared base URL cannot address two lanes, so a
|
|
751
|
+
`1.x`- or `2.x`-shaped lock is rejected at load with an error naming the schema.
|
|
752
|
+
- **Terminal-hub artifact naming is handled in data.** That lane names its Windows
|
|
753
|
+
builds `gaia-win-x64.exe` / `gaia-win-arm64.exe`, while platform keys come from
|
|
754
|
+
`process.platform` and say `win32`. The lock keeps the `win32-*` key and carries
|
|
755
|
+
the hub's spelling in `filename`, so nothing branches on platform to construct a
|
|
756
|
+
URL. The mapping is asserted on both sides (`TUI_ARTIFACT_NAMES` in
|
|
757
|
+
`src/platform.ts` and in the lock generator) because a wrong name there is not a
|
|
758
|
+
build failure anywhere — it is a 404 on a user's first run.
|
|
759
|
+
- **Mandatory SHA-256 verification.** Every download is hashed and compared
|
|
760
|
+
against the lock before it is written. A mismatch deletes the download and
|
|
761
|
+
raises `IntegrityError` naming expected vs actual. A placeholder hash blocks the
|
|
762
|
+
fetch before any network call. There is no flag that relaxes either.
|
|
763
|
+
- **`gaia fetch`** — download and verify without launching; prints JSON. Supports
|
|
764
|
+
`--component` and `--platform` for cross-platform staging in CI.
|
|
765
|
+
- **`gaia serve`** — run the agent sidecar alone on `127.0.0.1:8141` for
|
|
766
|
+
integrators who want the REST surface without a daemon or a UI. Health-polls
|
|
767
|
+
`GET /health`, checks the contract version, and tree-kills on exit. Port `4001`
|
|
768
|
+
is refused.
|
|
769
|
+
- **`gaia version`** — prints, per component, its version, the URL it is fetched
|
|
770
|
+
from, and its platform matrix.
|
|
771
|
+
- **Programmatic exports** — `fetchAll`, `startSidecar`, `shutdown`, `runTui`, the
|
|
772
|
+
platform helpers, and the typed error classes, for embedding GAIA in another
|
|
773
|
+
app.
|
|
774
|
+
|
|
775
|
+
### Notes
|
|
776
|
+
|
|
216
777
|
- The sidecar is installed into `~/.gaia/agents/gaia/`, the GAIA daemon's own
|
|
217
778
|
cache directory. The daemon spawns and supervises the sidecar; putting an
|
|
218
779
|
already-verified binary where it looks turns its fetch into a cache hit instead
|
|
@@ -229,16 +790,9 @@ the terminal UI meant building it from source.
|
|
|
229
790
|
building its own TUI. Each terminal-hub artifact is additionally cross-checked
|
|
230
791
|
against the hub's own server-side SHA-256 before its hash enters the lock.
|
|
231
792
|
- Requires Node.js 18+ (built-in `fetch`), a running Lemonade Server for
|
|
232
|
-
inference, and the `gaia` Python CLI 0.
|
|
233
|
-
starts. 0.
|
|
234
|
-
|
|
793
|
+
inference, and the `gaia` Python CLI 0.25.0+ on `PATH` for the daemon the TUI
|
|
794
|
+
starts. 0.25.0 is the first core that can run this agent; on an earlier core
|
|
795
|
+
the UI starts with nothing behind it.
|
|
235
796
|
- The sidecar has no arm64 Linux or arm64 Windows build. On those platforms the
|
|
236
797
|
run stops with an error naming the platform and the supported set rather than
|
|
237
798
|
launching a UI with no agent behind it.
|
|
238
|
-
- `gaia_agent` enforces a per-session caller-auth bearer on every `/v1/gaia/*`
|
|
239
|
-
request, plus a loopback `Host` allowlist and non-loopback `Origin` rejection.
|
|
240
|
-
This package mints no token, so a sidecar it spawns comes up in dev mode (token
|
|
241
|
-
check skipped, loudly warned, Host/Origin still enforced) — pass your own
|
|
242
|
-
through `spawnSidecar`'s `env` to turn it on. See SPEC §5.4.
|
|
243
|
-
- Tracks sidecar contract `apiVersion` **2.12**; a differing major raises
|
|
244
|
-
`VersionMismatchError`.
|