@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/CHANGELOG.md
CHANGED
|
@@ -4,13 +4,933 @@ 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
|
-
|
|
9
|
+
## [0.3.2]
|
|
10
|
+
|
|
11
|
+
Released with GAIA 0.25.2, and requires the `gaia`
|
|
12
|
+
Python CLI 0.25.2+ on `PATH`. Integrators: the sidecar contract is now
|
|
13
|
+
**2.24**; clients built for 2.18 keep working, and the new
|
|
14
|
+
`/query` fields are refused with `422` by older binaries, so probe
|
|
15
|
+
`/version` before sending them.
|
|
16
|
+
|
|
17
|
+
- **Memory downloads its embedding model when it is missing.** On the first
|
|
18
|
+
start that uses memory, the agent now fetches the required embedding model
|
|
19
|
+
from Lemonade instead of silently running without memory; the initial
|
|
20
|
+
download can be about 300 MB.
|
|
21
|
+
- **Unknown or misplaced switches are refused.** `gaia --forse` and
|
|
22
|
+
`gaia fetch --developer-mode` now exit 2 instead of silently starting the TUI;
|
|
23
|
+
pass terminal-UI arguments after a bare `--`.
|
|
24
|
+
|
|
25
|
+
- **The Agent UI's "Under the hood" figures cover GAIA chats.** It said every
|
|
26
|
+
answer was "not measured", because only the agent saw its own step timings.
|
|
27
|
+
`final` now carries `performance` with them: the turn's model and tool
|
|
28
|
+
seconds and each model call's token counts. Older binaries never send it.
|
|
29
|
+
- **`GET /v1/gaia/skills` says where each skill came from.** Each skill now
|
|
30
|
+
carries a `source` (`agent-bundled`, `user` or `claude-import`; `null` for
|
|
31
|
+
any other root), so the Agent UI can group the Skills list by origin. An
|
|
32
|
+
older agent omits it and the UI shows the list flat.
|
|
33
|
+
- **One very long turn no longer vanishes from the conversation.** A turn
|
|
34
|
+
bigger than the whole history budget, like a pasted log or a long document
|
|
35
|
+
read, was dropped from what the model saw next, answer included, so "now
|
|
36
|
+
shorten that" ran with no record of it. It is now kept: long tool results
|
|
37
|
+
become a short note naming the tool, and its longest messages are cut with
|
|
38
|
+
a note saying how much.
|
|
39
|
+
- **Internet off also stops the mailbox and Agent Hub tools.** With a chat's
|
|
40
|
+
Internet switched off, GAIA could still read Gmail or Outlook and search or
|
|
41
|
+
install skills from the Agent Hub, because those tools carry no URL for the
|
|
42
|
+
check to see. They are now refused with the same message as a web search.
|
|
43
|
+
|
|
44
|
+
### For integrators: contract 2.24
|
|
45
|
+
|
|
46
|
+
- **Relative file paths use the chat workspace.** A new `working_directory` field
|
|
47
|
+
on `/query` tells the agent where bare file names resolve, separately from
|
|
48
|
+
`allowed_paths`. New and retained sessions use the same workspace for reads,
|
|
49
|
+
writes, edits and approval prompts. Send it only after `/version` reports
|
|
50
|
+
contract 2.24 or later.
|
|
51
|
+
|
|
52
|
+
### For integrators: contract 2.23
|
|
53
|
+
|
|
54
|
+
- **`/query` takes `internet_off`** (contract **2.23**, #5883). The Agent UI
|
|
55
|
+
never told the agent when a chat's Internet switch was off, so the switch
|
|
56
|
+
stayed locked in every GAIA chat on a standard install. `true` refuses web
|
|
57
|
+
search, page fetches, the browser, connector, mailbox and Agent Hub tools and
|
|
58
|
+
commands that contact another host, as it does when the agent runs inside the Agent UI. `false`
|
|
59
|
+
allows them, and omitting it leaves the agent as it is. A retained session
|
|
60
|
+
keeps the last value. Older binaries `422` the field.
|
|
61
|
+
- **`POST /v1/gaia/sessions/{session_id}/internet`** (contract **2.23**)
|
|
62
|
+
reaches a turn already running. Without it, a user who turned the internet
|
|
63
|
+
off mid-turn watched the agent keep searching until the turn ended. Body
|
|
64
|
+
`{"internet_off": bool}`; the session's next tool call follows it. An
|
|
65
|
+
unknown session is a `404`, as for `/bypass`. Post it only once `/query`
|
|
66
|
+
has answered: until then the turn's own `internet_off` replaces it.
|
|
67
|
+
|
|
68
|
+
### For integrators: contract 2.22
|
|
69
|
+
|
|
70
|
+
- **A client can show the model's reasoning.** Over `/query` the reasoning
|
|
71
|
+
only arrived folded into `status` lines, so the Agent UI showed none of it
|
|
72
|
+
for an installed GAIA. A request with `reasoning: true` now gets it as
|
|
73
|
+
`reasoning` events, `{ delta }`, kept apart from the answer. Without the
|
|
74
|
+
field nothing changes. Older binaries reject it with `422`.
|
|
75
|
+
|
|
76
|
+
### For integrators: contract 2.21
|
|
77
|
+
|
|
78
|
+
- **`final` says how full the model's window is** (contract **2.21**,
|
|
79
|
+
#5738). The Agent UI's Context panel and the meter beside its message box
|
|
80
|
+
stayed empty for every GAIA chat, because only the agent can measure its
|
|
81
|
+
own prompt, tools and window. `final` now carries `context` with that
|
|
82
|
+
measurement for the next call, or `context_error` when measuring failed.
|
|
83
|
+
A stopped or failed turn carries neither. Older binaries never send it.
|
|
84
|
+
- **A relayed write prompt names where the file lands.** When the model asks to
|
|
85
|
+
write `shop2.txt`, `needs_confirmation` now carries the absolute path the
|
|
86
|
+
write resolves to in `prompt_context.file_path`, so a front-end can show
|
|
87
|
+
`/Users/you/shop2.txt` instead of a bare name. `args` still holds exactly the
|
|
88
|
+
model's `file_path`.
|
|
89
|
+
- **A web search's results reach the client.** The Agent UI listed no Sources
|
|
90
|
+
for a GAIA web search, because a `search_web` `tool_result` carried only a
|
|
91
|
+
300-character summary. Its `data` now also carries `sources`, a list of
|
|
92
|
+
`{ title, url }` for each hit. Older binaries never send it.
|
|
93
|
+
|
|
94
|
+
- **An old failure in memory no longer stops a request you make now.** A note
|
|
95
|
+
like "this page returned 503, don't waste tool calls on it" was obeyed as a
|
|
96
|
+
standing ban, so the agent refused a URL you handed it. Memories now reach
|
|
97
|
+
the model as dated notes your request outranks, and a passing failure is
|
|
98
|
+
marked as one. A 429 or 502-504 "try later" failure is no longer saved as
|
|
99
|
+
an error memory at all.
|
|
100
|
+
- **Text from a file is not saved as your details.** The agent could save a
|
|
101
|
+
line from a document it read, or call it something you had saved. It now
|
|
102
|
+
saves text from a file, page or tool result only when you ask it to keep
|
|
103
|
+
something, and an empty memory search says that file text is not saved.
|
|
104
|
+
|
|
105
|
+
- **Pushed history that doesn't fit the model's window no longer overflows
|
|
106
|
+
it.** `/query` used the `context` you pushed as-is, but you size it without
|
|
107
|
+
seeing the agent's prompt and tools. On a 32K window the two together could
|
|
108
|
+
exceed the window and fail the turn. The agent now keeps the newest whole
|
|
109
|
+
turns that fit beside its prompt and streams a `status` event when older
|
|
110
|
+
ones drop out of view.
|
|
111
|
+
|
|
112
|
+
- **Homebrew tools are visible to the agent on a Mac.** An app opened from Finder
|
|
113
|
+
or the Dock starts with only the system folders on its search path, so the
|
|
114
|
+
agent could not run `gh`, `node` or anything else Homebrew installed, and its
|
|
115
|
+
prompt said they were "not installed". The agent now starts with the `PATH`
|
|
116
|
+
your login shell builds (only when opened that way: started from a terminal it
|
|
117
|
+
keeps the terminal's own `PATH`, so an activated virtualenv still wins), and a
|
|
118
|
+
tool it still cannot find is reported as not
|
|
119
|
+
reachable from its shell rather than missing from your machine. If your shell
|
|
120
|
+
startup is slow or fails, the agent logs a warning and keeps the old path.
|
|
121
|
+
|
|
122
|
+
### For integrators: contract 2.20
|
|
123
|
+
|
|
124
|
+
- **A failed model request says which endpoint failed, worded for your
|
|
125
|
+
front-end** (contract **2.20**, #5295). A headless caller of `/query` whose
|
|
126
|
+
hosted model returned HTTP 502 was told the "cloud request through Lemonade
|
|
127
|
+
failed" and to check "the TUI provider settings", though no TUI was
|
|
128
|
+
involved. The error now names the provider and the `host:port` the request
|
|
129
|
+
went through. A local model on a base URL you set is reported as "the model
|
|
130
|
+
server at `host:port`" instead of "Lemonade on this machine", since GAIA
|
|
131
|
+
can't tell what serves it. The advice follows the `surface` field: a caller
|
|
132
|
+
that omits it is pointed at the model server the GAIA host uses; `"tui"`,
|
|
133
|
+
`"agent_ui"` and `"cli"` keep their own settings screens. Older binaries
|
|
134
|
+
refuse the field with `422`, so probe `/version` before sending it.
|
|
135
|
+
Version skew: a front-end older than this release never sends `surface`, so
|
|
136
|
+
against this agent it gets the headless advice (the model server's
|
|
137
|
+
`LEMONADE_BASE_URL`) instead of its own settings screen. GAIA ships the TUI,
|
|
138
|
+
the Agent UI and this agent together, so this only shows when one of them is
|
|
139
|
+
updated without the others, or when the TUI's `/version` probe times out and
|
|
140
|
+
it can't confirm the agent takes the field.
|
|
141
|
+
- **Answers stream over `/query`.** The HTTP sidecar ran its agent with
|
|
142
|
+
streaming off, so a relayed turn (the Agent UI, and the TUI's later sessions)
|
|
143
|
+
showed "Waiting on the model" until the whole answer landed at once, Stop could
|
|
144
|
+
not cut a model call short, and a stopped turn kept no text. Every `/query`
|
|
145
|
+
turn now streams its model calls and sends the answer as `token` events before
|
|
146
|
+
`final`, the same as the stdio transport. A run cancelled mid-answer stops
|
|
147
|
+
within a token and ends with an empty `final`, as stdio does; text not yet
|
|
148
|
+
sent when the cancel lands is dropped.
|
|
149
|
+
### Fixed
|
|
150
|
+
|
|
151
|
+
- **"Save it to my Documents folder" saves to the user's Documents folder.**
|
|
152
|
+
The system prompt told GAIA that "my documents" meant its own documents
|
|
153
|
+
folder (`~/.gaia/documents`), so a new file the user asked for in Documents
|
|
154
|
+
went into GAIA's hidden folder, where they would never find it. Finding an
|
|
155
|
+
existing file still checks GAIA's folders first.
|
|
156
|
+
- **Secrets stay out of memory and the conversation log.** A bank PIN was saved
|
|
157
|
+
as a memory, because the filter knew passwords and API keys but not PINs. The
|
|
158
|
+
conversation log also kept the PIN, a password the agent had refused, a card
|
|
159
|
+
number and an SSN verbatim, where `search_past_conversations` read them back.
|
|
160
|
+
PINs, passcodes, card security codes, Luhn-valid card numbers and SSNs are now
|
|
161
|
+
refused as memories, and every credential-shaped span is replaced with
|
|
162
|
+
`[secret removed]` before a turn is logged.
|
|
163
|
+
- **"How much free disk space do I have?" gets the right number, first try.**
|
|
164
|
+
On a Mac, GAIA said a nearly full disk had ~233 GB free: its system-info
|
|
165
|
+
tool reported only the share the system volume uses, so 97.8% used read as
|
|
166
|
+
5%. It now reports free space as macOS counts it, and says it answers
|
|
167
|
+
free-space questions, so GAIA no longer tries a shell command that is refused.
|
|
168
|
+
- **Full access in the Agent UI asks before a gated shell command instead of
|
|
169
|
+
refusing it.** With `/sessions/{id}/bypass` on, a command such as a delete or
|
|
170
|
+
`git add` was refused outright, so a Full access chat could not run it at
|
|
171
|
+
all. On a run someone can answer it now emits `needs_confirmation` and runs
|
|
172
|
+
only on an allow from `/tool_decision`. The shell gates still stay on over
|
|
173
|
+
HTTP, commands that need no approval still run unasked, and a run nobody can
|
|
174
|
+
answer still refuses.
|
|
175
|
+
- **Local models with a large window can write longer replies.** The output
|
|
176
|
+
cap is a quarter of the loaded window (16K at 64K, between 8K and 32K)
|
|
177
|
+
instead of a flat 8K, and a reply cut off at the cap is told to write the
|
|
178
|
+
file in smaller parts.
|
|
179
|
+
- **`search_file_content` searches the workspace.** A relative or default
|
|
180
|
+
directory resolved against the sidecar's own folder and reported "0 files";
|
|
181
|
+
it now resolves against the workspace, searches text files of any extension,
|
|
182
|
+
and says when nothing was searched.
|
|
183
|
+
- **Token counts are exact in the published binary, offline too.** The binary
|
|
184
|
+
could not load its tokenizer, so every turn trimmed history and sized
|
|
185
|
+
context from an estimate that overcounts, and logged `Unknown encoding
|
|
186
|
+
cl100k_base`. The tokenizer and its data now ship inside the binary, so it
|
|
187
|
+
no longer downloads anything to count tokens.
|
|
188
|
+
|
|
189
|
+
### For integrators: contract 2.20
|
|
190
|
+
|
|
191
|
+
- **`/query` takes `surface`** (contract **2.20**): `"agent_ui"`, `"tui"` or
|
|
192
|
+
`"cli"`. Asked to run something on a schedule from the Agent UI, the agent
|
|
193
|
+
said it had no scheduler and sent the user to Windows Task Scheduler; with
|
|
194
|
+
`"agent_ui"` it points them at the **Scheduled tasks** page instead. Older
|
|
195
|
+
binaries `422` the field, so probe `/version` before sending it.
|
|
196
|
+
- **The agent knows which folders it can work in.** The system prompt now names
|
|
197
|
+
the session's folders and labels GAIA's documents folder, so "summarize X in
|
|
198
|
+
my documents folder" looks there first instead of trying `~/Documents` and
|
|
199
|
+
the home folder.
|
|
200
|
+
|
|
201
|
+
### For integrators
|
|
202
|
+
|
|
203
|
+
- **A tool result keeps the tool's own status.** When a tool's result had no
|
|
204
|
+
structured payload, the `tool_result` event's `data` carried only `summary`
|
|
205
|
+
and `success`, so a client could not tell a skipped `remember` (a private
|
|
206
|
+
chat saves nothing) from a saved one, and the Agent UI listed it as saved.
|
|
207
|
+
`data` now also carries `status` when the tool returned one. Additive, so
|
|
208
|
+
the contract version is unchanged.
|
|
209
|
+
|
|
210
|
+
- **An MCP tool call says which connector it used and what came back.** A Git
|
|
211
|
+
connector call reached a client as a bare `mcp_git_git_log`, and its result
|
|
212
|
+
as "Tool 'git_log' returned data". `tool_call` gains optional `mcp_server`,
|
|
213
|
+
`mcp_server_label` ("Git") and `mcp_tool` ("git_log"), and the result's
|
|
214
|
+
`data` carries the tool's text in `mcp_output` (`{ text, truncated }`, capped
|
|
215
|
+
at 16,000 characters). Clients that ignore the fields see the same events.
|
|
216
|
+
|
|
217
|
+
### For integrators: contract 2.19
|
|
218
|
+
|
|
219
|
+
- **`/query` can record a turn's file changes for undo** (contract **2.19**).
|
|
220
|
+
Desktop chats run in this agent and the Agent UI relays them, so a file the
|
|
221
|
+
agent wrote never reached the chat's Changes view or its Undo. With
|
|
222
|
+
`changes_turn_id` (and `session_id`), the agent copies each file before
|
|
223
|
+
changing it into the snapshot store the Agent UI reads, and finishes the
|
|
224
|
+
recording before the terminal event. Older binaries refuse the field with
|
|
225
|
+
`422`, so probe `/version` before sending it.
|
|
226
|
+
- **A confirmation's `args` are only what the model sent.** `needs_confirmation`
|
|
227
|
+
`args` also carried keys the agent adds to its own prompt — a risk note, a
|
|
228
|
+
scratch-folder marker, and the folder a shell call runs in — so a policy
|
|
229
|
+
client auto-approving on `args` matched fields the model never sent. `args`
|
|
230
|
+
is now exactly the call's arguments; the folder and risk note moved to a new
|
|
231
|
+
`prompt_context` object.
|
|
232
|
+
- **A tool result names the file it wrote.** When a tool's result carries
|
|
233
|
+
`file_path` or `image_path`, the `tool_result` event's `data` now keeps it, so
|
|
234
|
+
a client can list the files a turn produced.
|
|
235
|
+
|
|
236
|
+
## [0.3.1]
|
|
237
|
+
|
|
238
|
+
Released with GAIA 0.25.1, and requires it. Integrators: the sidecar
|
|
239
|
+
contract is now **2.18**; clients built for 2.17 keep working, and the new
|
|
240
|
+
`/query` fields are refused with `422` by older binaries, so probe
|
|
241
|
+
`/version` before sending them.
|
|
242
|
+
|
|
243
|
+
### Linux
|
|
244
|
+
|
|
245
|
+
- **The Linux agent runs on glibc 2.34 or newer.** The `linux-x64` agent is
|
|
246
|
+
now built against glibc 2.34 (#5545), so it starts on Ubuntu 22.04, Debian 12
|
|
247
|
+
and RHEL 9. Before, it needed glibc 2.38 and failed at launch on those.
|
|
248
|
+
|
|
249
|
+
### For integrators: contract 2.18
|
|
250
|
+
|
|
251
|
+
- **`/query` takes the chat's file scope and memory mode** (contract **2.18**).
|
|
252
|
+
`allowed_paths` lets the Agent UI hand the agent the same scope its session
|
|
253
|
+
panel shows. `memory` fixes private chats saving to memory: the relayed turn
|
|
254
|
+
never said the chat was private or that memory was off, so the agent went on
|
|
255
|
+
saving the errors and lessons it records on its own. `"private"` or `"off"`
|
|
256
|
+
now turns off every memory write for the turn.
|
|
257
|
+
- **A confirmation carries the call it asks about.** `needs_confirmation` now
|
|
258
|
+
has `args` (each value capped at 64,000 characters, with `args_truncated`
|
|
259
|
+
when one was cut) and `tool_label`, so a client can show all of the code it
|
|
260
|
+
is approving rather than the shortened `summary`, and word a path prompt for
|
|
261
|
+
a file or folder that exists.
|
|
262
|
+
- **A turn the model gave up on ends as failed, not done.** When the model
|
|
263
|
+
stopped responding or refused mid-turn (a stall, a 404, every retry spent),
|
|
264
|
+
the turn ended on the model's opening sentence and the Agent UI listed the
|
|
265
|
+
chat as done. The final answer now names the step, the provider and the
|
|
266
|
+
cause, what already ran, and what is unfinished, and the `final` event
|
|
267
|
+
carries `failed: true`.
|
|
268
|
+
- **A turn queued for the model says so on the stream.** When another process
|
|
269
|
+
or request is using the model, `/query` now sends `status` events with
|
|
270
|
+
`phase: "model_queue"` every ~2 s, carrying a `queue` object with the turn's
|
|
271
|
+
place in line, who holds the model and how long it has waited, then one
|
|
272
|
+
`granted` update. A turn queued this way leases ahead of background work, and
|
|
273
|
+
`/query/{run_id}/cancel` takes it out of the queue. Before, the stream went
|
|
274
|
+
silent for the whole wait, so a client could not tell a queued turn from a
|
|
275
|
+
dead one.
|
|
276
|
+
- **Needs core 0.25.1.** The chat agent this one builds on imports the
|
|
277
|
+
reasoning-effort tool, which first ships in core 0.25.1, so its
|
|
278
|
+
`amd-gaia` floor and `min_gaia_version` rise to 0.25.1 with that release.
|
|
279
|
+
|
|
280
|
+
### File access and privacy
|
|
281
|
+
|
|
282
|
+
- **Full access in the Agent UI grants the folders you name.** Turning it on
|
|
283
|
+
over `/sessions/{id}/bypass` refused every path outside the chat's scope with
|
|
284
|
+
nobody asked. On a run the caller can answer for, Full access now grants the
|
|
285
|
+
path without a prompt, as it does in-process; Ask mode asks. Unattended runs,
|
|
286
|
+
the home folder and drive roots are still refused.
|
|
287
|
+
- **No more approval prompts for files that aren't there.** Naming a missing
|
|
288
|
+
file or folder outside the allowed paths opened a 10-minute approval prompt,
|
|
289
|
+
and only after it did the agent learn the file didn't exist; a retry asked
|
|
290
|
+
again. The tool now says the file wasn't found straight away, without asking,
|
|
291
|
+
and names an allowed or attached file with the same name. `analyze_data_file`
|
|
292
|
+
given a bare file name uses the attached file of that name instead of asking
|
|
293
|
+
about one in the working folder. Secret and protected paths are refused
|
|
294
|
+
exactly as before, whether or not they exist.
|
|
295
|
+
- **A turn's file changes can be undone.** The agent saves a copy of every
|
|
296
|
+
file before a tool writes, edits, creates or deletes it, so the Agent UI
|
|
297
|
+
can show the turn's changes and put every file back, even after a restart.
|
|
298
|
+
A turn that also ran a shell command, Python or an MCP tool says undo may
|
|
299
|
+
be incomplete.
|
|
300
|
+
- **Saving a download asks about the file, not its folder.** A download into
|
|
301
|
+
the home folder failed without asking, because the agent asked to grant the
|
|
302
|
+
whole folder. It now asks about the one file it is about to create.
|
|
303
|
+
- **A document another program has open is re-indexed once it is free.** On
|
|
304
|
+
Windows, a watched file that Word, PowerPoint or another program held locked
|
|
305
|
+
was read once, reported as corrupted, and never re-indexed. It is now retried
|
|
306
|
+
a few times, and if it stays locked the log says to close the program and
|
|
307
|
+
save the file again.
|
|
308
|
+
|
|
309
|
+
### Long and busy turns finish
|
|
310
|
+
|
|
311
|
+
- **A context overflow no longer throws away the evidence.** A task that read
|
|
312
|
+
many documents used to fill a 32K–64K window, after which the overflow retry
|
|
313
|
+
dropped every older result and the answer was built on whatever was left
|
|
314
|
+
(#2780). The retry now keeps each result whole behind a handle the model can
|
|
315
|
+
re-read, and retries only when the request will then fit.
|
|
316
|
+
- **Token counts no longer undercount when the tokenizer data can't load.** On
|
|
317
|
+
an offline or locked-down machine the counter fell back to characters ÷ 4.28,
|
|
318
|
+
which undercounts JSON and CJK text, so history that should take half the
|
|
319
|
+
window could fill it (#5066). It now warns and counts at least one token per
|
|
320
|
+
three UTF-8 bytes.
|
|
321
|
+
- **Opening a session or switching its model no longer freezes the other
|
|
322
|
+
sessions.** The sidecar built a new session's agent, and ran a `/model`
|
|
323
|
+
switch (which builds a new client and checks its server), on its event
|
|
324
|
+
loop. Every other session's stream stopped for that long, heartbeats
|
|
325
|
+
included, so the TUI and the daemon relay saw an idle connection. That
|
|
326
|
+
setup now runs on a worker thread, and a request that goes away mid-setup
|
|
327
|
+
still releases its session.
|
|
328
|
+
- **Background memory upkeep no longer wipes the chat's cached prompt.**
|
|
329
|
+
Memory consolidation, reconciliation and skill distillation ran on the
|
|
330
|
+
model slot the conversation uses, so the next message re-read the whole
|
|
331
|
+
~19K-token prompt (~45 s on Gemma-4-E4B). They now run on the side slot,
|
|
332
|
+
as memory extraction already did.
|
|
333
|
+
- **A turn cut short by closing the TUI is saved as interrupted.** The session
|
|
334
|
+
history got a turn only once it ended, so closing the TUI mid-turn saved it
|
|
335
|
+
as an ordinary "stopped" answer, or, if the TUI had to kill the agent, lost
|
|
336
|
+
the question entirely. The question is now saved when the turn starts, and a
|
|
337
|
+
turn the TUI's closing cut short ends with "This answer was interrupted when
|
|
338
|
+
GAIA closed." A resumed session (`GAIA_HISTORY_FILE`) sees it. Questions
|
|
339
|
+
queued before the close are saved as they ended.
|
|
340
|
+
- **A busy, restarting or sleeping model server no longer fails the turn.**
|
|
341
|
+
The agent waits for a shared Lemonade that is loading another app's model,
|
|
342
|
+
waits up to 60 s for GAIA's own server to come back after a restart, and a
|
|
343
|
+
PC that sleeps mid-answer resumes instead of reporting a stall. A shared
|
|
344
|
+
KV-cache collision is no longer reported as "conversation too long".
|
|
345
|
+
- **Nothing a tool waits on can hang the turn for good.** A hung MCP server,
|
|
346
|
+
a web server sending one byte at a time (page fetches stop at 120 s,
|
|
347
|
+
downloads at 30 min) and a busy embedder during indexing (one 300 s wait
|
|
348
|
+
per batch, with a message saying why) all end with a clear error. One bad
|
|
349
|
+
batch of parallel tool calls no longer trips the failure breaker and ends
|
|
350
|
+
the task with no answer.
|
|
351
|
+
- **The agent's own scripts get time to run.** A script run through an
|
|
352
|
+
interpreter (`python analyze.py big.csv`) gets a 600 s default instead of
|
|
353
|
+
the 30 s kill for quick commands.
|
|
354
|
+
- **Web search survives DuckDuckGo rate limits.** A refused search is retried
|
|
355
|
+
with backoff and through DuckDuckGo's lite endpoint, or answered by Tavily
|
|
356
|
+
when that connector is set up, instead of failing and being saved to memory
|
|
357
|
+
as a known error.
|
|
358
|
+
|
|
359
|
+
### Memory you can trust
|
|
360
|
+
|
|
361
|
+
- **Memory keeps what the user says, and keeps it current.** Facts come only
|
|
362
|
+
from what the user says about themselves, a forgotten fact is not re-learned
|
|
363
|
+
from old chats, a newer fact outranks the one it replaced, and a write that
|
|
364
|
+
carries tool-call markup or model reasoning is refused instead of saved
|
|
365
|
+
corrupted. Relevant memories now surface in the chats they are about.
|
|
366
|
+
|
|
367
|
+
### Models and answers
|
|
368
|
+
|
|
369
|
+
- **gpt-oss 20B and 120B are supported models.** On a model that grades its
|
|
370
|
+
reasoning, the agent gets `set_reasoning_effort` (low, medium or high) to
|
|
371
|
+
choose how hard it thinks for the rest of the request; every new message
|
|
372
|
+
starts again at medium. It is not registered on other models, so the
|
|
373
|
+
agent's 95 tools on Gemma and Qwen are unchanged.
|
|
374
|
+
- **gpt-oss runs the agent.** Every array tool parameter now declares
|
|
375
|
+
`items`, without which gpt-oss's chat template rejected every request
|
|
376
|
+
with HTTP 500, and gpt-oss control markers inside a file or page the agent
|
|
377
|
+
reads are broken up so the model no longer answers with nothing.
|
|
378
|
+
- **Answers are checked more honestly.** A claim such as "all 55 tests pass"
|
|
379
|
+
is checked even when the same sentence says "but" or "not", and asking the
|
|
380
|
+
agent to run a shell command runs it rather than reading the shell's state.
|
|
381
|
+
|
|
382
|
+
### Diagnostics
|
|
383
|
+
|
|
384
|
+
- **The turn log says how busy the model server was.** With `GAIA_TURN_LOG`
|
|
385
|
+
set, each model call records the server's own prefill, decode and cache-reuse
|
|
386
|
+
figures and the time spent waiting on the model-slot lease, the slot lock and
|
|
387
|
+
the status probe; each turn records its server compute, its non-model time,
|
|
388
|
+
and what filled the gaps between model calls. `GET /v1/gaia/debug/turns`
|
|
389
|
+
returns the last records while recording is on (off the versioned contract).
|
|
390
|
+
|
|
391
|
+
## [0.3.0]
|
|
392
|
+
|
|
393
|
+
Released with GAIA 0.25.0, and requires it.
|
|
394
|
+
|
|
395
|
+
### Changed
|
|
396
|
+
|
|
397
|
+
- **Requires `amd-gaia>=0.25.0` and `gaia-agent-chat>=0.2.0`.** Every file tool
|
|
398
|
+
now checks the allowed-folders rule, and that check ships in core 0.25.0; an
|
|
399
|
+
older core cannot import the chat agent this one builds on.
|
|
400
|
+
- **`~/.gaia/logs/gaia-agent.log` stays bounded.** It rotates like `gaia.log`
|
|
401
|
+
(10 MB, three backups; `GAIA_LOG_MAX_MB`, `GAIA_LOG_BACKUPS`) instead of
|
|
402
|
+
growing without limit.
|
|
403
|
+
|
|
404
|
+
- **Everyday questions get short, plain answers.** "Why is the sky blue?" got
|
|
405
|
+
140 words with an equation, and a Wi-Fi question got diagnostic shell runs.
|
|
406
|
+
The voice skill now caps an everyday answer at three plain sentences, goes
|
|
407
|
+
one level deeper only when asked, honours a stored short/detailed preference,
|
|
408
|
+
and answers general-knowledge questions without running tools.
|
|
409
|
+
- **Memory off no longer loads the embedding model.** A private chat, or one
|
|
410
|
+
with memory switched off, used to load the ~300 MB embedder on its first turn
|
|
411
|
+
only to validate it and to score the always-on `gaia-voice` skill. It now
|
|
412
|
+
loads when memory is first used, such as when memory is switched back on or
|
|
413
|
+
the agent recalls something. A turn with only always-on skills loaded embeds
|
|
414
|
+
nothing.
|
|
415
|
+
- **Every tool is offered on every turn again, as in the Agent UI.** Per-turn
|
|
416
|
+
tool selection swapped about a dozen tools in and out at its cap, which broke
|
|
417
|
+
the local model's prompt cache (17s to first token on a one-line question,
|
|
418
|
+
0.4s without it) and left out the tool a question needed: a CSV question was
|
|
419
|
+
given web tools and fetched an unrelated page. `GAIA_DYNAMIC_TOOLS=1` turns
|
|
420
|
+
selection back on. The registered count is 95: `load_tools`, the selector's
|
|
421
|
+
escape hatch, registers only while selection is on.
|
|
422
|
+
- **A turn's silent opening now says what the model is doing.** A thinking
|
|
423
|
+
model sat on "Getting started" for 10-20 s while it read the prompt and then
|
|
424
|
+
reasoned in a paragraph released only once finished. `status` events gain an
|
|
425
|
+
optional `phase` (`loading_model`, `downloading_model`, `reading`,
|
|
426
|
+
`reasoning`, `tool_call`) with a `words` or `chars` count, sent when each phase
|
|
427
|
+
actually starts; the terminal UI shows them as "Reading your request",
|
|
428
|
+
"Reasoning · 214 words" and so on. Clients that ignore the field see the same
|
|
429
|
+
sentence in `message`.
|
|
430
|
+
- **GPU models no longer load at 32K on an NPU-profile machine.** The NPU's
|
|
431
|
+
32,768-token ceiling was applied to every model whenever `default_device` was
|
|
432
|
+
`npu`, so a GGUF model ran at half its window and long tasks overflowed. It now
|
|
433
|
+
binds NPU (FLM) models only. A model can also opt in to a window sized to the
|
|
434
|
+
machine's memory, up to its native maximum.
|
|
435
|
+
- **A stale `GAIA_SKILL_SET` now stops startup.** An undeclared name used to be
|
|
436
|
+
dropped silently, so the agent came up healthy with no skills. The sidecar
|
|
437
|
+
and the stdio entry now exit non-zero before serving, with a message naming
|
|
438
|
+
the valid sets; leave the variable unset to start without one.
|
|
439
|
+
- **The code index is built on first search, not at task start.** In 32
|
|
440
|
+
SWE-bench tasks the agent never searched it, yet every task embedded the whole
|
|
441
|
+
repository in the background: about 2,000 local embedding requests per six
|
|
442
|
+
tasks. The first `search_code_index` now builds it; `GAIA_PROJECT_MAP_AUTO_INDEX=1`
|
|
443
|
+
restores building at task start.
|
|
444
|
+
- **The first answer on a local model starts in seconds, not after a ~20 s
|
|
445
|
+
silence.** The terminal UI now shows a "Getting GAIA ready" stage before the
|
|
446
|
+
chat: the agent starts, loads its model and reads its system prompt there,
|
|
447
|
+
step by step. New stdio sentinel `warm_up` (answers `warmed_up`, or
|
|
448
|
+
`warm_up_skipped` for a remote model).
|
|
449
|
+
- **Permission prompts say what a command does, once.** Running the tests is
|
|
450
|
+
labelled `RUNS CODE`, not `DESTRUCTIVE`; the command appears once, relative to
|
|
451
|
+
the project; and `a` ("always this session") is offered for shell commands and
|
|
452
|
+
Python too, covering the command's family — `pytest` covers
|
|
453
|
+
`python -m pytest`, `cd proj && pytest 2>&1 | tail`. Deletes never offer it.
|
|
454
|
+
`needs_confirmation` gains an optional `risk` field.
|
|
455
|
+
- **Shift+Tab permission modes in the terminal UI**: ask → accept edits → full
|
|
456
|
+
access. Accept edits lets file edits inside the starting folder run unasked;
|
|
457
|
+
the stdio control verb is `accept_edits`, and `--accept-edits` starts in it.
|
|
458
|
+
Full access is still never turned on by a stray keypress.
|
|
459
|
+
- **An unanswered prompt is reported as a timeout.** `tool_decision` accepts
|
|
460
|
+
`timeout`; the agent tells the user the request expired rather than that they
|
|
461
|
+
refused it.
|
|
462
|
+
- The default chat model now follows the hardware. On a PC whose GPU has
|
|
463
|
+
~27 GB for models — a 64 GB+ Strix Halo or a 32 GB GPU; the 23.3 GB model also
|
|
464
|
+
needs its context cache — `gaia init` sets up Qwen3.6 35B A3B (a 23 GB Lemonade
|
|
465
|
+
built-in MoE, run with thinking on) and records it as `default_model`; the
|
|
466
|
+
agent and its `GET /v1/gaia/init` readiness check use it for chat. Gemma 4 E4B
|
|
467
|
+
is still downloaded for vision. Every other PC, including a CPU-only one, keeps
|
|
468
|
+
Gemma alone.
|
|
469
|
+
- **Qwen3.6 gets the longest context this PC's memory holds.** Up to its native
|
|
470
|
+
262,144 tokens on a Strix Halo (a 5.4 GB KV cache), about 152K on a 32 GB GPU,
|
|
471
|
+
never under 64K. Gemma stays at 64K.
|
|
472
|
+
- Qwen3.8 Flash Next (82 GB, multimodal, thinking on) is available on a
|
|
473
|
+
128 GB Strix Halo and never picked as a default; it needs ~90 GB for models.
|
|
474
|
+
Choose it with `gaia config set default_model user.Qwen3.8-Flash-Next-GGUF`;
|
|
475
|
+
`gaia init` refuses it on a PC that cannot hold it.
|
|
476
|
+
- **Bypass permissions is now called full access, everywhere.** `--full-access`
|
|
477
|
+
and `/full-access` replace `--bypass-permissions` and `/bypass`; the old names
|
|
478
|
+
fail with a message naming the new one. `/full-access always` (or
|
|
479
|
+
`gaia config set full_access true`) keeps it on across launches.
|
|
480
|
+
- **The agent has to read a file before it changes it.** `edit_file`, and
|
|
481
|
+
`write_file` on an existing file, now refuse a file the agent hasn't read with
|
|
482
|
+
`read_file` in this session, or one that changed on disk since it did. Benchmark
|
|
483
|
+
runs caught the agent patching files it had never opened, from a grep snippet
|
|
484
|
+
or a guess; now it has to look first. A partial read counts, creating a file
|
|
485
|
+
needs no read, and the refusal comes before any approval prompt. It applies
|
|
486
|
+
with confirmations bypassed too.
|
|
487
|
+
- **The agent sees every installed skill and loads the one that fits.**
|
|
488
|
+
Previously a per-turn matcher scored the request against skill descriptions
|
|
489
|
+
and loaded a skill on 0 of 24 benchmark tasks, so most GitHub requests never
|
|
490
|
+
learned `gh` was available. The system prompt now lists each installed skill
|
|
491
|
+
in one line (~1,000 tokens for the starter pack), and refusing a skill-gated
|
|
492
|
+
CLI names the skill to load. `GAIA_SKILL_DISCOVERY=0` still hides the list.
|
|
493
|
+
**Removed:** `GAIA_SKILL_DISCOVERY_TAU` is now ignored, and
|
|
494
|
+
`GaiaAgentConfig(skill_discovery_threshold=…)` raises `TypeError` — drop the
|
|
495
|
+
argument. See the Agent Skills spec, "Skill catalogue".
|
|
496
|
+
- Contract `apiVersion` is now **2.14** (2.13 added `GET /memory`) for the two new routes and
|
|
497
|
+
the `claude` provider value. A differing major still raises
|
|
498
|
+
`VersionMismatchError`; a higher minor is accepted.
|
|
499
|
+
- **Changing `model` on a live `session_id` switches in place** instead of
|
|
500
|
+
returning 409, so the conversation and any loaded skills survive it. A switch
|
|
501
|
+
that fails still returns 409 and leaves the session on its previous model.
|
|
502
|
+
|
|
503
|
+
### Fixed
|
|
504
|
+
|
|
505
|
+
- **Answering the agent's question from the Agent UI or the TUI works.**
|
|
506
|
+
`POST /query/{run_id}/respond` only took the answer as `response`, while
|
|
507
|
+
both front-ends send `{ request_id, value }` as the contract specifies, so
|
|
508
|
+
every answer was refused and the run waited until the question timed out.
|
|
509
|
+
It now takes `value`. `response` is still accepted; sending both, or
|
|
510
|
+
neither, is a 422.
|
|
511
|
+
- **A file you allow is usable by every tool, including document Q&A.** Indexing
|
|
512
|
+
or querying a file outside the chat's scope was refused with no prompt, and
|
|
513
|
+
approving it through another tool still left it unreadable to the document
|
|
514
|
+
index. Indexing now asks the same question `read_file` does, and one approval
|
|
515
|
+
covers both. A tool waiting on that question is no longer abandoned at its
|
|
516
|
+
180 s limit while the question is still on screen. A refusal now tells the
|
|
517
|
+
model not to copy or move the file elsewhere to get around it.
|
|
518
|
+
- **`--use-claude` works with the downloaded binary.** The release build left
|
|
519
|
+
out the Anthropic client, so every Claude launch from the terminal UI, and
|
|
520
|
+
every `/model` switch to Claude, failed with "The 'anthropic' package is
|
|
521
|
+
required", which a frozen binary cannot act on. The client is now bundled, and
|
|
522
|
+
the release build fails if it is missing.
|
|
523
|
+
|
|
524
|
+
- **Code search works in an Agent UI chat that is not inside a project.** It
|
|
525
|
+
started in GAIA's own documents folder, which usually does not exist yet, so
|
|
526
|
+
every `search_code_index` failed with "repo_path does not exist". It now starts
|
|
527
|
+
in a repository the chat can reach, else any folder it can reach that exists.
|
|
528
|
+
|
|
529
|
+
- **`/model` no longer offers speech or other non-chat models as chat
|
|
530
|
+
targets.** Whisper was listed as a "chat-capable" local model; switching to it
|
|
531
|
+
reported success and broke the next turn. Transcription, speech, music,
|
|
532
|
+
classification, upscaling and 3D models are excluded; a model labeled `chat`
|
|
533
|
+
still qualifies even if it also transcribes.
|
|
534
|
+
- **The agent no longer starts an unrelated job after answering.** A bugfix
|
|
535
|
+
request loaded the `coding` skill, whose "find every call site" tip switched
|
|
536
|
+
on document inventorying; after the fix was done and verified, the agent spent
|
|
537
|
+
minutes extracting every file it had read until the user cancelled. Only a
|
|
538
|
+
skill built on the extraction tool turns inventorying on now. Separately,
|
|
539
|
+
once a turn has answered, a tool call on nothing the request touched is not
|
|
540
|
+
run and a second one ends the turn, and a tool that keeps failing with new
|
|
541
|
+
arguments is stopped like an identical repeat.
|
|
542
|
+
- A "no" now covers what an action does, not the one tool it was asked
|
|
543
|
+
through. After you decline `pytest`, or leave its prompt unanswered, the
|
|
544
|
+
agent no longer writes `run_tests.py` and runs it with another tool: any
|
|
545
|
+
call that would run the tests, reach the same host, or change the same file
|
|
546
|
+
is stopped for the rest of that request. Where the surface can ask, you get
|
|
547
|
+
the exact command and why, with Allow once / Don't run it; otherwise the
|
|
548
|
+
agent stops and asks in its reply.
|
|
549
|
+
- `/v1/gaia/query` now honours `provider` on an existing session. It used to
|
|
550
|
+
matter only when the session was created, so `provider: "lemonade"` could keep
|
|
551
|
+
sending a Claude session's conversation to Anthropic, and `provider: "claude"`
|
|
552
|
+
could run locally. A different provider now switches the session in place.
|
|
553
|
+
Naming a `model` that belongs to the other provider is a 400, on new and
|
|
554
|
+
existing sessions alike. Omitting `provider` and naming a Claude `model` now
|
|
555
|
+
starts a Claude session, the way it already switched an existing one — it used
|
|
556
|
+
to point the local backend at an id it cannot serve.
|
|
557
|
+
- "Lemonade is not reachable" errors no longer tell users to run
|
|
558
|
+
`lemonade-server serve`, a command current Lemonade installs don't have. The
|
|
559
|
+
`GET /v1/gaia/init` hint, run errors, and `/model` now say how to start
|
|
560
|
+
Lemonade on the user's own install (tray app, macOS app, service, or CLI).
|
|
561
|
+
`/model <unknown>` with nothing downloaded likewise names the download command
|
|
562
|
+
the host actually has, instead of the removed `lemonade-server pull`.
|
|
563
|
+
- `gaia serve` no longer exits 0 when Ctrl+C fails to stop the sidecar. The
|
|
564
|
+
error naming the surviving process and how to kill it was discarded, so the
|
|
565
|
+
next `serve` hit an unexplained port conflict. It now prints that error and
|
|
566
|
+
exits 1.
|
|
567
|
+
- Conversation state is saved under `~/.gaia/sessions` instead of the directory
|
|
568
|
+
the agent was started from. A `session_id` must be 1–128 characters from
|
|
569
|
+
`A-Z a-z 0-9 . _ -`; any other value is a 400 on `/query` and
|
|
570
|
+
`/sessions/{session_id}/bypass` instead of a 500. A corrupt saved session fails
|
|
571
|
+
the request instead of being silently replaced.
|
|
572
|
+
- `gaia hub install gaia` no longer refuses Intel Macs: the hub manifest now
|
|
573
|
+
lists `darwin-x64`, which the release already builds and the lock already ships.
|
|
574
|
+
- The hub install card advertises the declared npm package instead of an unpublished PyPI wheel.
|
|
575
|
+
- The readiness check (`GET /v1/gaia/init`) and the terminal session's health
|
|
576
|
+
report name GAIA's own Lemonade Server instead of Lemonade's default port.
|
|
577
|
+
- Clearing a TUI conversation now also clears the flagship stdio agent’s prior
|
|
578
|
+
conversation context, while preserving the selected model, skills, and permissions.
|
|
579
|
+
- Internal session deletion (not yet exposed by a route) refuses busy agents instead of closing them mid-turn.
|
|
580
|
+
- Scratch files no longer land in the user's project. The system temp dir was
|
|
581
|
+
out of scope, so the agent wrote throwaway test runners and intermediate files
|
|
582
|
+
into the repository instead. It now gets its own scratch directory, named in its
|
|
583
|
+
prompt and deleted when the agent closes; the rest of the temp dir stays denied.
|
|
584
|
+
- Every file tool now checks the same allowed-folders rule as `read_file`:
|
|
585
|
+
browsing, folder and content search, recent files, document indexing, folder
|
|
586
|
+
watching, code indexing, and where screenshots, transcripts and exports are
|
|
587
|
+
saved. A folder outside the scope gets the usual approval prompt, and a folder
|
|
588
|
+
you approve is readable by document indexing too.
|
|
589
|
+
|
|
590
|
+
### Added
|
|
591
|
+
|
|
592
|
+
- **A committed, machine-readable `/query` contract.** `openapi.gaia.json` in
|
|
593
|
+
the Python package is generated from the live routes
|
|
594
|
+
(`python -m gaia_agent.export_openapi`) and checked for drift in CI, so a
|
|
595
|
+
typed client no longer has to reverse-engineer the body from prose —
|
|
596
|
+
`query`, `run_id`, and `context` are required, `run_id` must be a UUID, and
|
|
597
|
+
the bearer-auth posture is declared in the schema. Swagger UI (`/docs`) is
|
|
598
|
+
disabled on the sidecar — it loads its JS from a CDN, an unexpected network
|
|
599
|
+
call for an offline embedder — but `/openapi.json` is still served.
|
|
600
|
+
- **Programs the agent starts no longer inherit GAIA's internal credentials.**
|
|
601
|
+
Shell commands, MCP servers, CLI installs and sign-ins, native hub agents,
|
|
602
|
+
media tools and the Lemonade server get the sidecar's environment minus
|
|
603
|
+
GAIA's own tokens. Your own variables (`GH_TOKEN` and the like) still pass through, so CLI skills
|
|
604
|
+
keep working. An embedding app can withhold more names with
|
|
605
|
+
`GAIA_CHILD_ENV_DENY` (comma or space separated), and can stop GAIA loading
|
|
606
|
+
`.env` files with `GAIA_NO_DOTENV=1` — read from the real environment, so a
|
|
607
|
+
`.env` cannot set it.
|
|
608
|
+
- **The agent can drive a real browser.** Pages behind JavaScript or a login
|
|
609
|
+
used to be out of reach — `fetch_page` is one HTTP GET, so a signed-in inbox
|
|
610
|
+
or a dashboard came back empty. Eight new tools open a real Chromium, read
|
|
611
|
+
it, click and type in it, and sign in to a site; the password goes to the
|
|
612
|
+
human, never the model, and the session is stored encrypted. Acting inside a
|
|
613
|
+
session you signed in to asks first. Ships behind the optional `browser`
|
|
614
|
+
extra; without it none of the eight register. Registered tool count goes
|
|
615
|
+
88 → 96.
|
|
616
|
+
- **Fast mode, for a session that's only conversation.** `GAIA_FAST=1` drops
|
|
617
|
+
the flagship to a plain conversational surface for the whole session —
|
|
618
|
+
3,110 tokens of fixed prompt instead of 17,942 — so saying "hi" no longer
|
|
619
|
+
costs as much as a repo search. Session-scoped and one-way: a fast session
|
|
620
|
+
has no documents, files, web or skills and cannot pick them up mid-way.
|
|
621
|
+
- **`chat`, `doc` and `file` are no longer offered as agents.** New users saw
|
|
622
|
+
four entries in the picker where only one is the product. The three ids still
|
|
623
|
+
resolve, so existing sessions, `*-lite` aliases and eval scenarios keep
|
|
624
|
+
working — they are hidden, not deleted, and `ChatAgent` remains the
|
|
625
|
+
flagship's base class. A session created without an explicit agent now lands
|
|
626
|
+
on the flagship rather than a hidden agent.
|
|
627
|
+
- **Complete inventories from long documents.** Asking for every exercise,
|
|
628
|
+
action item or finding in a transcript now returns all of them, each with its
|
|
629
|
+
source quote, instead of a condensed list. The opt-in `document-extract` skill
|
|
630
|
+
drives new `extract_document_items` and `save_extracted_items` tools; a save is
|
|
631
|
+
reported only after the exact file is written and read back, and anything
|
|
632
|
+
unfinished is reported as incomplete. `gaia-voice` gains one routing line
|
|
633
|
+
(702 tokens).
|
|
634
|
+
- **The agent can set up a skill's CLI instead of handing the job back.** Asking
|
|
635
|
+
it to triage GitHub issues on a machine without `gh` used to end the
|
|
636
|
+
conversation. Three new tools — `check_cli_setup` (read-only), `install_cli`
|
|
637
|
+
and `sign_in_cli` — let it report exactly what is wrong, install the CLI with
|
|
638
|
+
the machine's package manager, and drive the browser sign-in. Both mutating
|
|
639
|
+
tools are confirmation-gated on every call and no skill grant pre-approves
|
|
640
|
+
them; over `/v1/gaia/query` they are refused, like every other gated tool
|
|
641
|
+
(§8). Registered tool count goes 83 → 86.
|
|
642
|
+
- **A shell command's `cd` now survives to the next one.** Every
|
|
643
|
+
`run_shell_command` call used to start from scratch, so `cd build` in one
|
|
644
|
+
call was invisible to the next. `get_shell_state` reads the session's
|
|
645
|
+
current directory, and `reset_shell_session` returns it to where the task
|
|
646
|
+
started. Registered tool count goes 86 → 88.
|
|
647
|
+
- **Say something while the agent is still working.** `POST
|
|
648
|
+
/v1/gaia/query/{run_id}/followup` hands a live run a message the user typed
|
|
649
|
+
after it started (contract **2.15**). The run is not interrupted and no
|
|
650
|
+
second turn starts — the agent folds the text into the turn already running
|
|
651
|
+
at its next step boundary, so a correction during a five-minute task changes
|
|
652
|
+
that task instead of arriving after it finished. Unknown run → `404`, an
|
|
653
|
+
agent that cannot take one → `409`; both loud, because the caller has already
|
|
654
|
+
taken the message from the user. See SPEC §5.6 and SKILL §7.
|
|
655
|
+
- **Approve a gated tool over HTTP.** `write_file`, `run_shell_command` and the
|
|
656
|
+
seven other confirmation-gated tools can now run through `/v1/gaia/query`:
|
|
657
|
+
the stream stays open on `needs_confirmation` and
|
|
658
|
+
`POST /v1/gaia/query/{run_id}/tool_decision` answers it. Previously the only
|
|
659
|
+
possible answer was a refusal, so those tools were unreachable over HTTP.
|
|
660
|
+
`POST /v1/gaia/sessions/{session_id}/bypass` turns the asking off for a
|
|
661
|
+
session. A run that cannot answer — no `session_id`, or
|
|
662
|
+
`can_answer_questions: false` — is still refused. See SKILL §8.
|
|
663
|
+
- **Claude as an inference backend.** `provider: "claude"` sends the
|
|
664
|
+
conversation to Anthropic's API instead of the local server; `model` then
|
|
665
|
+
names a Claude model. Anything outside `lemonade` / `claude` is still a 400.
|
|
666
|
+
- **`gaia-agent --serve` works from a pip install.** The console script pointed
|
|
667
|
+
past the transport dispatcher, so the documented HTTP mode exited with
|
|
668
|
+
"unrecognized arguments".
|
|
669
|
+
- **Tracked eval scorecard ([`SCORECARD.md`](./SCORECARD.md)).** The agent now
|
|
670
|
+
ships a per-release scorecard: judged-scenario pass rate (the aggregate)
|
|
671
|
+
plus per-category rates and the judge's average score across the
|
|
672
|
+
13-category eval corpus (`eval/scenarios/gaia_*`), generated by
|
|
673
|
+
`hub/agents/gaia/python/packaging/gen_scorecard.py` from real
|
|
674
|
+
`gaia eval agent --agent-type gaia` runs. CI runs a PR subset
|
|
675
|
+
(`test_gaia_agent_eval.yml`), the weekly sweep runs the full corpus, and the
|
|
676
|
+
release pipeline gates on the committed card
|
|
677
|
+
(`scorecard-gate` + a judged eval subset in `release_agent_gaia.yml`).
|
|
678
|
+
The initially committed card is a harness validation measured with the
|
|
679
|
+
agent on `claude-haiku-4-5` (the dev environment cannot run Lemonade); the
|
|
680
|
+
first full runner refresh (`gaia_scorecard_refresh.yml`) replaces it with
|
|
681
|
+
the Gemma-4-E4B product baseline.
|
|
682
|
+
- **`capture_skill` — capture a skill from pasted `SKILL.md` text, a URL, or a
|
|
683
|
+
local folder, with code inert until trusted.** The agent can now bring a
|
|
684
|
+
skill into `~/.gaia/skills` straight from the conversation (68 registered
|
|
685
|
+
tools, up from 67). Every capture is confirmation-gated, security-audited (a
|
|
686
|
+
`BLOCK` verdict refuses it), SSRF-guarded on the URL path, and lands at the
|
|
687
|
+
`experimental` tier. Instructions load immediately; any `tools.py`/scripts
|
|
688
|
+
the bundle carries stay **inert** until the user runs
|
|
689
|
+
`gaia skill promote <name>` in a terminal, which re-audits and binds trust
|
|
690
|
+
to the audited bytes. Over `/query`, `capture_skill` is gated like the
|
|
691
|
+
other confirmation tools (SKILL §8; SPEC §5.2 documents the load-time
|
|
692
|
+
deferral).
|
|
693
|
+
- **`run_python`, always on.** A quick calculation or data transform is now one
|
|
694
|
+
confirmation-gated call that runs from the project root and returns what it
|
|
695
|
+
printed, instead of a throwaway script left in your repository. It joins the
|
|
696
|
+
always-on tool set (about 250 more prompt tokens per call) and the `shell`
|
|
697
|
+
bundle.
|
|
698
|
+
- Opt-in developer-mode skill and consent-gated MCP handoffs to Claude Code/Codex,
|
|
699
|
+
with managed worktrees, approved feedback snapshots and reported preview results.
|
|
700
|
+
Python `[mcp]` installation is required for the bridge; normal mode has no access.
|
|
701
|
+
- **The shell, always on inside a code repository.** When the project map
|
|
702
|
+
resolves to a repository (a VCS directory or a known manifest at its root),
|
|
703
|
+
`run_shell_command` is offered on every turn instead of only when the request
|
|
704
|
+
happens to sound like a shell request. Coding tasks such as "skip these tests
|
|
705
|
+
on PRs" previously ran without a shell and did every grep through `run_python`.
|
|
706
|
+
It follows the *same* root the map already uses, so the sidecar needs
|
|
707
|
+
`GAIA_PROJECT_ROOT=/path/to/repo` (or `GaiaAgentConfig(project_root=...)` when
|
|
708
|
+
embedding) to see your repository — its own working directory is whatever
|
|
709
|
+
started it, not yours. With no repository nothing changes, and the shell's
|
|
710
|
+
approval gate still applies either way. See SKILL §11.
|
|
711
|
+
- **`sleep`, always on.** The agent can now wait before retrying, e.g. until a
|
|
712
|
+
rate limit resets, instead of giving up; before, its only way to wait was
|
|
713
|
+
`time.sleep` inside a confirmation-gated `run_python`. Up to five minutes per
|
|
714
|
+
call, no approval needed, and Stop ends the wait within a second. It joins the
|
|
715
|
+
always-on tool set (about 190 more prompt tokens per call) and the
|
|
716
|
+
`loop_control` bundle (80 tools → 81).
|
|
717
|
+
- **`--bypass-permissions` now lifts the shell guardrails too.** It used to skip
|
|
718
|
+
only the confirmation prompt, which left the agent unable to run a build or a
|
|
719
|
+
test suite even with the user's blanket consent: no interpreter, test runner
|
|
720
|
+
or package manager was reachable, and nothing could write its output anywhere.
|
|
721
|
+
Under bypass, redirection (`>`, `>>`, `<`), backgrounding (`&`), substitution
|
|
722
|
+
(`` ` ``, `$()`) and the newline now parse and run — chaining with `&&` / `||`
|
|
723
|
+
/ `;` / `|` already worked by default — the
|
|
724
|
+
read-only allowlist is replaced by a developer set (`node`, `npm`, `make`,
|
|
725
|
+
`cmake`, `go`, `cargo`, `sed`, `awk`, `curl`, `sleep`, `timeout`, `export`,
|
|
726
|
+
`cp`, `mv`, plus `python` / `python3` / `pytest` / `gh` / `git`), and the
|
|
727
|
+
shell rate limit is dropped. Off by default and byte-identical to before when
|
|
728
|
+
off. `git` in that set means its policy's outright refusals — push, reset,
|
|
729
|
+
rebase — also stop applying under bypass. `rm` stays excluded. Every command run this way is audit-logged with its full
|
|
730
|
+
arguments. Stdio only — an HTTP session's `/bypass` stops its approval prompts
|
|
731
|
+
but never lifts the shell gates, and the request body cannot ask for it.
|
|
732
|
+
Redirection has one exception: a command that
|
|
733
|
+
is nothing but a skill-granted CLI runs argv-only, so `>` there is refused
|
|
734
|
+
with an explanation instead of reaching the binary as text. See SPEC §5.5.
|
|
735
|
+
|
|
736
|
+
### Also in 0.3.0
|
|
737
|
+
|
|
738
|
+
These were still listed under Unreleased when 0.3.0 was tagged, so they
|
|
739
|
+
shipped in it.
|
|
740
|
+
|
|
741
|
+
- **Finished work is no longer replaced by "I can't confirm this is done".** A
|
|
742
|
+
redaction task that loaded the `document-extract` skill had its answer swapped
|
|
743
|
+
for a coverage warning about its own `redaction_log.csv`, and a task with two
|
|
744
|
+
named outputs only knew about the last one. Every file the request names, and
|
|
745
|
+
every file the turn wrote, is now an output and never a source; the skill
|
|
746
|
+
checks coverage only when the request names a source document or asks for
|
|
747
|
+
every item. No check replaces a non-empty answer any more: an unproven
|
|
748
|
+
save, test result or extraction keeps the answer and adds a short "I
|
|
749
|
+
couldn't confirm all of this" list after it; a turn that ends early keeps
|
|
750
|
+
what it said ahead of its report; and a tool that keeps failing ends with the
|
|
751
|
+
model's answer from what it found, then the failure. A failed image request
|
|
752
|
+
is no longer rewritten into advice to start GAIA with an `--sd` flag that
|
|
753
|
+
does not exist. `load_skill` no longer tells the model the extraction tools
|
|
754
|
+
cannot run when it is about to register them, and a rejected extractor reply
|
|
755
|
+
is now logged.
|
|
756
|
+
- **`run_python` works in the Agent UI without a project.** It ran from the
|
|
757
|
+
server's own folder, which is not an allowed path, so every approved snippet
|
|
758
|
+
was refused and the agent fell back to slower shell commands. With no project
|
|
759
|
+
and a working directory you did not allow, a snippet now runs in the agent's
|
|
760
|
+
scratch directory, and its result says so. A project outside the allowed
|
|
761
|
+
paths is still refused.
|
|
762
|
+
- **An "always" answer for a shell command no longer covers code in the
|
|
763
|
+
scratch folder.** A command run there or naming a path there — `cd` into it
|
|
764
|
+
then `python -m explore`, or `pytest`, `make`, `pip install`, `uv run` or
|
|
765
|
+
`go run` pointed at it — and a script handed a scratch path as an argument
|
|
766
|
+
now ask every time, with no `always_scope`, the same as a script there.
|
|
767
|
+
`always_scope` labels for commands that run code they do not show now say so:
|
|
768
|
+
`pytest (runs the test code it finds)`, `make (runs the Makefile's
|
|
769
|
+
commands)`, `python -m explore (runs that Python module)`.
|
|
770
|
+
- **Exploring data no longer asks twice per step.** Each step wrote a helper
|
|
771
|
+
script into the agent's own scratch folder and ran it, so a data task asked
|
|
772
|
+
for approval about 30 times. Writes inside that folder now run unasked
|
|
773
|
+
(writes anywhere else still ask). Running a script from it asks each time
|
|
774
|
+
and offers no `always_scope`, since what is in that folder changes without
|
|
775
|
+
a prompt.
|
|
776
|
+
- **A command no loaded skill grants asks you instead of failing.** `python
|
|
777
|
+
script.py`, `git commit` or `pip install` with no skill granting them used to
|
|
778
|
+
come back as "needs a skill grant … declares 'shell:execute:git' in its
|
|
779
|
+
SKILL.md", which nobody could act on. They now raise the approval prompt; a
|
|
780
|
+
skill grant still skips it for reads. A prompt's `summary` for a write or
|
|
781
|
+
code-running command ends with one plain line on what it can do, and the
|
|
782
|
+
`in <folder>` line also appears when an earlier `cd` moved the session. A
|
|
783
|
+
call you decline tells the agent not to reach the same result another way,
|
|
784
|
+
and a run nobody can answer refuses in one plain sentence.
|
|
785
|
+
- **Commands GAIA's checks don't cover ask once instead of failing.** `git
|
|
786
|
+
push`, `git fetch`, `python -c`, PowerShell the checks can't read, a line with
|
|
787
|
+
shell operators, or a path outside the allowed folders used to be refused
|
|
788
|
+
outright. They now raise a prompt whose `summary` is the exact line the shell
|
|
789
|
+
will run, its full folder and a risk sentence, with no `always_scope`; an
|
|
790
|
+
approval runs that line once. Still refused with no prompt: an encoded
|
|
791
|
+
PowerShell command or invisible characters, a line whose quoting can't be
|
|
792
|
+
split the way the shell would, such a line that also deletes or discards work
|
|
793
|
+
(`git push --force`, `git reset --hard`, `rm` outside the project), and
|
|
794
|
+
folders no approval can open.
|
|
795
|
+
- **Long Python data jobs can finish.** `run_python` gave up after 60 s and
|
|
796
|
+
the agent abandoned `execute_python_file` at 180 s even when it had asked
|
|
797
|
+
for 15 minutes, while the script kept running and left a corrupt workbook
|
|
798
|
+
behind. Python runs now get 120 s by default and up to 1800 s on request,
|
|
799
|
+
the agent waits that long, and a run that runs out of time is killed with
|
|
800
|
+
every process it started; the result names the files that changed while it
|
|
801
|
+
ran so the agent checks them instead of reporting them finished.
|
|
802
|
+
- **Document search says when it could not search.** With the embedding
|
|
803
|
+
model or Lemonade Server down, `query_documents` and `query_specific_file`
|
|
804
|
+
answered "no relevant information found", so the agent told the user their
|
|
805
|
+
documents held nothing on the topic. They now return an error naming the
|
|
806
|
+
cause (Lemonade unreachable, or the embedding model failing) and how to fix
|
|
807
|
+
it. `index_document` and `index_directory` report the same cause, and
|
|
808
|
+
`index_directory` stops at the first such file and reports an error when no
|
|
809
|
+
file could be indexed. Hints for a missing optional package (RAG, PDF, Excel,
|
|
810
|
+
HTML parsing) say in a frozen build that it isn't bundled, and from source
|
|
811
|
+
give the install command for the running Python.
|
|
812
|
+
- **A failed tool call is reported as a failure.** `run_shell_command` returned
|
|
813
|
+
`status: success` for a command that exited non-zero, so the TUI and Agent UI
|
|
814
|
+
showed a failed build or test run as a passed step. It is now `status: error`
|
|
815
|
+
with an `error` naming the failing step, its exit code and the last stderr
|
|
816
|
+
line; `stdout`, `stderr` and `return_code` are unchanged. grep's no-match and
|
|
817
|
+
diff's "inputs differ" (exit 1) stay a success and say so in `expected_exit`.
|
|
818
|
+
An MCP tool that answers `isError`, a DuckDuckGo search that was blocked, a
|
|
819
|
+
`tasklist`/`wmctrl`/`osascript` window listing that failed, a notification
|
|
820
|
+
whose PowerShell died, and an `open_url` with no browser to open are errors
|
|
821
|
+
too. Install hints in a frozen build no longer name the binary as a Python to
|
|
822
|
+
run pip with.
|
|
823
|
+
- **Reviewing a few documents reads them in full.** `read_file` on a Word,
|
|
824
|
+
PDF or Excel file returned `[Binary file, N bytes]`, so to compare a term
|
|
825
|
+
sheet against a draft agreement the agent indexed them and ran a handful of
|
|
826
|
+
searches, and missed a closing date that differed between the two because no
|
|
827
|
+
search asked for it. `read_file` now returns the extracted text, in parts sized
|
|
828
|
+
to the model's budget that say where the next part starts, and the prompt
|
|
829
|
+
tells the agent to read a few documents in full for a review, comparison or
|
|
830
|
+
reconciliation and keep indexing for large collections and single lookups.
|
|
831
|
+
- **`fetch_page` no longer drops the middle of a long page.** Text past
|
|
832
|
+
`max_length` was cut to its head and tail, which is where a product page keeps
|
|
833
|
+
its menus and footer, not its price. It now returns the first part with a
|
|
834
|
+
marker naming the offset of the next, takes `offset` to continue and `find` to
|
|
835
|
+
jump to the passages containing a word, says so when a word is not on the
|
|
836
|
+
page, and flags a page with almost no static text as rendered by JavaScript.
|
|
837
|
+
`Length:` now reports the whole page rather than the excerpt.
|
|
838
|
+
- **Long desktop tasks finish with their deliverables instead of a bare "I
|
|
839
|
+
can't confirm this is done".** Picking a controller from nine datasheets and
|
|
840
|
+
pricing a 40-unit BOM ran out of its 50 steps while still searching for
|
|
841
|
+
prices, and the reply dropped the recommendation the agent had already
|
|
842
|
+
written. The agent's default step limit is now **150** (a `/query`
|
|
843
|
+
`max_steps` or `GAIA_AGENT_MAX_STEPS` still wins); at 20, 10 and 5 steps left
|
|
844
|
+
it is told to write the requested files from what it has, marking unverified
|
|
845
|
+
values, and a turn that still runs out keeps its findings and lists what is
|
|
846
|
+
missing after them.
|
|
847
|
+
- **The model notice is one line.** Switching or restoring a model printed a
|
|
848
|
+
four-sentence paragraph that named the model twice and said "via Lemonade".
|
|
849
|
+
It now reads like "Switched to **DeepSeek-V4.1-Flash** on the AMD LLM Gateway
|
|
850
|
+
(cloud). Your messages, and anything read from files or memory, are sent
|
|
851
|
+
there." The `/model` list drops "via Lemonade" from its headings and marks
|
|
852
|
+
the configured default model with `(default)`.
|
|
853
|
+
- **Single-file search results name their file.** `query_specific_file` put the
|
|
854
|
+
path only at the top of its result, so each chunk arrived with no source and
|
|
855
|
+
the chunk cards showed none. Every chunk now carries `source_file`, and the
|
|
856
|
+
result lists it in `source_files`, as `query_documents` already did.
|
|
857
|
+
- **The turn log counts the answer of a streamed turn.** With `GAIA_TURN_LOG`
|
|
858
|
+
set, a turn whose answer streamed out recorded `answer_chars: 0`. It now
|
|
859
|
+
records the length of the answer the user saw.
|
|
860
|
+
- **`run_python` and `execute_python_file` work in the released binary.** The
|
|
861
|
+
binary has no Python interpreter, so it handed every script to its own
|
|
862
|
+
argument parser, which rejected it, and no calculation, chart or `.xlsx`
|
|
863
|
+
could be produced. It now runs scripts itself, with pypdf, pymupdf,
|
|
864
|
+
python-docx, python-pptx, openpyxl, xlsxwriter, reportlab, pandas, numpy,
|
|
865
|
+
matplotlib and the full standard library bundled for them, and both tools
|
|
866
|
+
name those libraries to the model. A script that starts `sys.executable`
|
|
867
|
+
(`-m`, `-c`, a file) runs too; `-m pip` says packages can't be installed
|
|
868
|
+
and lists what is bundled. The Windows binary grows from 147 MB to 168 MB.
|
|
869
|
+
- **A Python script that fails is reported as a failure.** A non-zero exit
|
|
870
|
+
came back as `status: success`, so the TUI showed a failed run as
|
|
871
|
+
successful. It is now `status: error`, with an `error` naming the exit code
|
|
872
|
+
and the last stderr line; `stdout`, `stderr` and `return_code` are unchanged.
|
|
873
|
+
- **`GAIA_ALLOWED_PATHS` confines a run to the folders you name.** The agent
|
|
874
|
+
could read anything under the user's home and nothing narrowed that short of
|
|
875
|
+
embedding it, so an evaluation run could read the graders' answer keys. Set
|
|
876
|
+
to absolute folders, it narrows every file tool, search, index and shell path
|
|
877
|
+
check to them — it never widens, an invalid value stops startup, and code the
|
|
878
|
+
agent runs (`run_python`, shell) is not confined.
|
|
879
|
+
- **The sidecar's start-up warm-up now makes the first question fast.** It
|
|
880
|
+
primed only the agent's own instructions, without the tool list or the rest
|
|
881
|
+
of the system prompt, so the first question re-read all ~19K prompt tokens
|
|
882
|
+
(34 s on Qwen3.6-35B-A3B). It now sends exactly what a turn sends, and the
|
|
883
|
+
first question reads only its own ~50 tokens (5 s). A warm-up that fails is
|
|
884
|
+
logged as a warning with its cause instead of an info line.
|
|
885
|
+
- **`/model` names the command that connects a cloud provider.** With no
|
|
886
|
+
Fireworks or AMD gateway connection, the list told users to "connect this
|
|
887
|
+
provider in the TUI provider settings", a screen with no obvious way in. It
|
|
888
|
+
now says to run `/provider`, the command that opens it.
|
|
889
|
+
- **The TUI's provider picker works after GAIA's Lemonade restarts.** When the
|
|
890
|
+
agent ran as the TUI's own child, its model-state ping kept naming the port
|
|
891
|
+
Lemonade started on, so after a restart the picker said "Lemonade did not
|
|
892
|
+
respond" while chat worked. With a local or cloud chat model the ping now
|
|
893
|
+
reports the port the agent talks to, and it still never starts a stopped
|
|
894
|
+
server. A Claude session still reports the port it started with.
|
|
895
|
+
- **The Agent UI's Skills settings list this agent's skills.** With the agent
|
|
896
|
+
installed from the Hub, the page said the agent package was not installed
|
|
897
|
+
and to run `gaia init`, which changed nothing: the bundled skills live
|
|
898
|
+
inside the binary, where the UI could not read them. `GET /v1/gaia/skills`
|
|
899
|
+
(contract **2.17**) now returns them.
|
|
900
|
+
- **A message sent right after Stop is answered instead of refused.** A stopped
|
|
901
|
+
turn holds its session until its model call returns, so the next `/query`
|
|
902
|
+
got `409 … is already running a turn` for as long as the stopped answer would
|
|
903
|
+
have taken — about 40 s for a long one. It now waits for the stopped turn to
|
|
904
|
+
finish (up to 240 s) and then runs. A turn that was not cancelled is still
|
|
905
|
+
refused at once.
|
|
906
|
+
- **Documents attached to a chat now reach the agent.** In the Agent UI, a
|
|
907
|
+
Hub-installed agent answered "no documents are indexed" about a file the user
|
|
908
|
+
had attached, because the relayed turn never carried the chat's files.
|
|
909
|
+
`/query` now takes a `documents` field (contract **2.16**): the agent indexes
|
|
910
|
+
them before the turn, granting each exact file and not its folder, including
|
|
911
|
+
a file attached partway through a conversation.
|
|
912
|
+
- **The first chat after the agent starts uses its own tools.** A session built
|
|
913
|
+
while the start-up warm-up was still building could end up running the
|
|
914
|
+
warm-up agent's tools, so a file it had just indexed read as access denied.
|
|
915
|
+
Agents are now built one at a time.
|
|
916
|
+
- **Web requests work behind a corporate TLS-inspecting proxy.** HTTPS now
|
|
917
|
+
trusts the operating system's certificate store, as pip does, instead of only
|
|
918
|
+
Python's bundled list, so a proxy root such as Zscaler's no longer fails every
|
|
919
|
+
fetch with `CERTIFICATE_VERIFY_FAILED`.
|
|
920
|
+
- **Starting the agent no longer downloads a model you skipped.** The HTTP
|
|
921
|
+
sidecar's start-up warm-up skips the default local model when it is not
|
|
922
|
+
downloaded, so someone using a cloud model is not handed a multi-GB download
|
|
923
|
+
they never asked for.
|
|
924
|
+
|
|
925
|
+
### Notes
|
|
926
|
+
|
|
927
|
+
- Tracks sidecar contract `apiVersion` **2.17**; a differing major raises
|
|
928
|
+
`VersionMismatchError`.
|
|
929
|
+
- `GET /v1/gaia/memory` (contract 2.13) answers the same read-only snapshot the
|
|
930
|
+
stdio transport's `/memory` sentinel produces, so a daemon-supervised
|
|
931
|
+
install of the flagship exposes `/memory` too, not just a subprocess one.
|
|
932
|
+
|
|
933
|
+
## [0.2.0] — 2026-09-16
|
|
14
934
|
|
|
15
935
|
### Fixed
|
|
16
936
|
|
|
@@ -29,7 +949,6 @@ the terminal UI meant building it from source.
|
|
|
29
949
|
on the previous image.
|
|
30
950
|
- TUI provider setup for Local, Fireworks AI, and AMD LLM Gateway, with masked
|
|
31
951
|
runtime API keys, discovered models, and remote-inference status.
|
|
32
|
-
|
|
33
952
|
- **A project map at task start.** In a code repository the agent now opens
|
|
34
953
|
every task knowing the directory shape, the likely entry points, which
|
|
35
954
|
commands are installed, and the three platform differences that change
|
|
@@ -38,10 +957,6 @@ the terminal UI meant building it from source.
|
|
|
38
957
|
starts one in the background; `GAIA_PROJECT_MAP_AUTO_INDEX=0` turns that off,
|
|
39
958
|
and `GAIA_PROJECT_ROOT` picks the project when the working directory is not
|
|
40
959
|
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
960
|
- **Three further client-visible refusals from `/query`.** Reusing a `run_id`
|
|
46
961
|
that is still in flight gets `409` — it used to replace the live run, leaving
|
|
47
962
|
it with no way to be cancelled. Supplying a `model` that differs from the one
|
|
@@ -49,21 +964,17 @@ the terminal UI meant building it from source.
|
|
|
49
964
|
the old model. A request with an absent or empty `Host` header gets `400`
|
|
50
965
|
rather than being served, closing a DNS-rebinding check that failed open.
|
|
51
966
|
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
967
|
- **Per-turn tool selection, now on by default for the flagship `full`
|
|
59
|
-
profile.** The model is sent
|
|
968
|
+
profile.** The model is sent about 28 of its 84 tools on any one call — a
|
|
60
969
|
fixed core plus whichever cohesion bundles the query matched — instead of the
|
|
61
970
|
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
|
|
971
|
+
hatch the model calls mid-turn to pull in a bundle the selector missed; that
|
|
972
|
+
bundle is appended for the rest of the turn (briefly above the cap, which the
|
|
973
|
+
next turn restores) so the prompt already sent stays cached.
|
|
63
974
|
`GAIA_DYNAMIC_TOOLS=0` turns the selection off, `GAIA_DYNAMIC_TOOLS_MAX`
|
|
64
975
|
moves the cap and `GAIA_DYNAMIC_TOOLS_TAU` the match threshold.
|
|
65
976
|
- **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 —
|
|
977
|
+
entry, so it is always on and rendered in full on every LLM call — 702 tokens
|
|
67
978
|
of every prompt, and it declares no tools. It is the agent's honesty floor
|
|
68
979
|
(don't claim work you didn't do, don't present empty output as a result,
|
|
69
980
|
don't substitute a near-miss and report success), which is why it is not in an
|
|
@@ -75,46 +986,6 @@ the terminal UI meant building it from source.
|
|
|
75
986
|
behavioural rules intact. It had been a rationale document — every rule
|
|
76
987
|
followed by the incident that motivated it — and the model needs the rule,
|
|
77
988
|
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
989
|
- **The `.installed` record is written after a verified sidecar install.**
|
|
119
990
|
Staging the binary was only half an install: the daemon and the terminal UI
|
|
120
991
|
both key "this agent is installed" on `~/.gaia/agents/gaia/.installed`, and
|
|
@@ -205,14 +1076,83 @@ the terminal UI meant building it from source.
|
|
|
205
1076
|
that killed only the launcher: the cancelled tool call ran to completion and
|
|
206
1077
|
the surviving process consumed the next message. The first Esc now sends the
|
|
207
1078
|
agent a `cancel` control message, so the turn ends and the session keeps its
|
|
208
|
-
loaded skills, "always" grants, history and
|
|
1079
|
+
loaded skills, "always" grants, history and full access. A second Esc stops
|
|
209
1080
|
the whole process tree.
|
|
210
|
-
- **A restart after a hard stop no longer turns
|
|
1081
|
+
- **A restart after a hard stop no longer turns full access back on.**
|
|
211
1082
|
The replacement agent is launched in the session's current permission mode
|
|
212
1083
|
instead of from the original flags, and the TUI says what the restart lost.
|
|
213
1084
|
|
|
214
1085
|
### Notes
|
|
215
1086
|
|
|
1087
|
+
- `gaia_agent` enforces a per-session caller-auth bearer on every `/v1/gaia/*`
|
|
1088
|
+
request, plus a loopback `Host` allowlist and non-loopback `Origin` rejection.
|
|
1089
|
+
This package mints no token, so a sidecar it spawns comes up in dev mode (token
|
|
1090
|
+
check skipped, loudly warned, Host/Origin still enforced) — pass your own
|
|
1091
|
+
through `spawnSidecar`'s `env` to turn it on. See SPEC §5.4.
|
|
1092
|
+
|
|
1093
|
+
## [0.1.1] — 2026-08-21
|
|
1094
|
+
|
|
1095
|
+
First working release. `npx @amd-gaia/gaia` is now the single command that gets a
|
|
1096
|
+
user running GAIA: it fetches and verifies everything GAIA needs and drops them
|
|
1097
|
+
into the terminal UI. Before this there was no packaged path at all — the flagship
|
|
1098
|
+
agent had to be run from a repo checkout with a Python environment, and reaching
|
|
1099
|
+
the terminal UI meant building it from source.
|
|
1100
|
+
|
|
1101
|
+
### Added
|
|
1102
|
+
|
|
1103
|
+
- **`503` from `/query` at session capacity.** When every retained session
|
|
1104
|
+
slot is busy and none is idle enough to evict, starting a new session
|
|
1105
|
+
returns `503` with the reason in `detail` — retryable, distinct from a
|
|
1106
|
+
bug-shaped `500`. See SPEC §5.2.
|
|
1107
|
+
- **Per-turn skill-body selection.** A loaded skill stays loaded, but its body
|
|
1108
|
+
only renders in the prompt on turns whose query matches its description; the
|
|
1109
|
+
rest collapse to a one-line menu the model re-activates with `load_skill`.
|
|
1110
|
+
`GAIA_DYNAMIC_SKILLS=0` turns the selection off, `GAIA_DYNAMIC_SKILLS_TAU`
|
|
1111
|
+
overrides the match threshold, and an embedder outage disables it for the
|
|
1112
|
+
session (every body renders — capability is never lost to a failed match).
|
|
1113
|
+
- **`gaia run` (the default command)** — resolves the host platform, fetches and
|
|
1114
|
+
SHA-256 verifies both binaries, then launches the terminal UI and propagates its
|
|
1115
|
+
exit code. Arguments after a bare `--` are forwarded to the TUI verbatim.
|
|
1116
|
+
- **Dual-binary delivery.** The package installs two published artifacts: the
|
|
1117
|
+
frozen agent sidecar (`gaia-agent`), published by this package's own release,
|
|
1118
|
+
and the terminal UI (`gaia-tui`), which is the published **`terminal-hub`**
|
|
1119
|
+
component. The TUI is consumed, not rebuilt — it is byte-for-byte the binary a
|
|
1120
|
+
full GAIA install runs as `gaia tui`, so an npm user and a core user cannot end
|
|
1121
|
+
up on terminal UIs that behave differently. A second build under this package's
|
|
1122
|
+
own lane would have been the same bytes at a different version under a third
|
|
1123
|
+
naming convention, and the two would have drifted.
|
|
1124
|
+
- **`binaries.lock.json` `schemaVersion` 3.0** — a component-keyed checksum
|
|
1125
|
+
manifest where **each component carries its own `componentVersion`, `baseUrl`
|
|
1126
|
+
and `platforms`**. Component-first rather than the email agent's flat `binaries`
|
|
1127
|
+
map because the two differ in every dimension: hub lane, version, and platform
|
|
1128
|
+
coverage (terminal-hub covers arm64 Linux and arm64 Windows; the PyInstaller
|
|
1129
|
+
sidecar does not). A single shared base URL cannot address two lanes, so a
|
|
1130
|
+
`1.x`- or `2.x`-shaped lock is rejected at load with an error naming the schema.
|
|
1131
|
+
- **Terminal-hub artifact naming is handled in data.** That lane names its Windows
|
|
1132
|
+
builds `gaia-win-x64.exe` / `gaia-win-arm64.exe`, while platform keys come from
|
|
1133
|
+
`process.platform` and say `win32`. The lock keeps the `win32-*` key and carries
|
|
1134
|
+
the hub's spelling in `filename`, so nothing branches on platform to construct a
|
|
1135
|
+
URL. The mapping is asserted on both sides (`TUI_ARTIFACT_NAMES` in
|
|
1136
|
+
`src/platform.ts` and in the lock generator) because a wrong name there is not a
|
|
1137
|
+
build failure anywhere — it is a 404 on a user's first run.
|
|
1138
|
+
- **Mandatory SHA-256 verification.** Every download is hashed and compared
|
|
1139
|
+
against the lock before it is written. A mismatch deletes the download and
|
|
1140
|
+
raises `IntegrityError` naming expected vs actual. A placeholder hash blocks the
|
|
1141
|
+
fetch before any network call. There is no flag that relaxes either.
|
|
1142
|
+
- **`gaia fetch`** — download and verify without launching; prints JSON. Supports
|
|
1143
|
+
`--component` and `--platform` for cross-platform staging in CI.
|
|
1144
|
+
- **`gaia serve`** — run the agent sidecar alone on `127.0.0.1:8141` for
|
|
1145
|
+
integrators who want the REST surface without a daemon or a UI. Health-polls
|
|
1146
|
+
`GET /health`, checks the contract version, and tree-kills on exit. Port `4001`
|
|
1147
|
+
is refused.
|
|
1148
|
+
- **`gaia version`** — prints, per component, its version, the URL it is fetched
|
|
1149
|
+
from, and its platform matrix.
|
|
1150
|
+
- **Programmatic exports** — `fetchAll`, `startSidecar`, `shutdown`, `runTui`, the
|
|
1151
|
+
platform helpers, and the typed error classes, for embedding GAIA in another
|
|
1152
|
+
app.
|
|
1153
|
+
|
|
1154
|
+
### Notes
|
|
1155
|
+
|
|
216
1156
|
- The sidecar is installed into `~/.gaia/agents/gaia/`, the GAIA daemon's own
|
|
217
1157
|
cache directory. The daemon spawns and supervises the sidecar; putting an
|
|
218
1158
|
already-verified binary where it looks turns its fetch into a cache hit instead
|
|
@@ -229,16 +1169,9 @@ the terminal UI meant building it from source.
|
|
|
229
1169
|
building its own TUI. Each terminal-hub artifact is additionally cross-checked
|
|
230
1170
|
against the hub's own server-side SHA-256 before its hash enters the lock.
|
|
231
1171
|
- Requires Node.js 18+ (built-in `fetch`), a running Lemonade Server for
|
|
232
|
-
inference, and the `gaia` Python CLI 0.
|
|
233
|
-
starts. 0.
|
|
234
|
-
|
|
1172
|
+
inference, and the `gaia` Python CLI 0.25.2+ on `PATH` for the daemon the TUI
|
|
1173
|
+
starts. 0.25.2 is the first core that can run the current release; on an
|
|
1174
|
+
earlier core the UI starts with nothing behind it.
|
|
235
1175
|
- The sidecar has no arm64 Linux or arm64 Windows build. On those platforms the
|
|
236
1176
|
run stops with an error naming the platform and the supported set rather than
|
|
237
1177
|
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`.
|