@theokit/agents 8.5.2 → 8.7.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 +1637 -0
- package/README.md +94 -0
- package/dist/auth.d.ts +84 -2
- package/dist/auth.js +152 -3
- package/dist/auth.js.map +1 -1
- package/dist/{bridge-entry-BEniSXWE.d.ts → bridge-entry-51lU7LQw.d.ts} +15 -0
- package/dist/bridge.d.ts +1 -1
- package/dist/bridge.js +2 -1
- package/dist/chunk-KMJVKPKH.js +72 -0
- package/dist/chunk-KMJVKPKH.js.map +1 -0
- package/dist/chunk-RKWCXVYG.js +100 -0
- package/dist/chunk-RKWCXVYG.js.map +1 -0
- package/dist/{chunk-C7UXZWVY.js → chunk-RZCNKKOG.js} +19 -2
- package/dist/chunk-RZCNKKOG.js.map +1 -0
- package/dist/config.d.ts +534 -0
- package/dist/config.js +655 -0
- package/dist/config.js.map +1 -0
- package/dist/hooks.d.ts +90 -1
- package/dist/hooks.js +119 -28
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/session.d.ts +33 -10
- package/dist/session.js +34 -3
- package/dist/session.js.map +1 -1
- package/package.json +6 -1
- package/dist/chunk-C7UXZWVY.js.map +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,1637 @@
|
|
|
1
|
+
# @theokit/agents
|
|
2
|
+
|
|
3
|
+
## 8.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- **`PermissionStore` — conceder "sempre permita isto" sem conceder "permita tudo".** Medido por
|
|
8
|
+
grep nos dois lados: nada persistia uma concessao permanente para tools. A unica saida era o
|
|
9
|
+
`full-auto`, que remove o portao em vez de estreita-lo — e a decima aprovacao da mesma coisa e
|
|
10
|
+
onde a pessoa para de ler o que aprova, o que faz da opcao "segura" a que produz comportamento
|
|
11
|
+
inseguro. A chave `(tool, scope, signature)` E a propriedade de seguranca: o escopo passa por
|
|
12
|
+
`realpath` (um symlink nao toma emprestado concessao feita para outro lugar) e a assinatura nunca
|
|
13
|
+
e casada por aproximacao (`npm test` nao autoriza `npm test --force`).
|
|
14
|
+
|
|
15
|
+
- **`HookApprovalStore` — o portao de fingerprint ganha um produtor.** `buildHookHandlers` exige
|
|
16
|
+
`approved` e nega por padrao; o framework entregava o portao e nada que produzisse o conjunto,
|
|
17
|
+
deixando ao consumidor duas saidas — aprovar tudo, ou escrever o store. Tres estados, nao dois:
|
|
18
|
+
`modified` (alguem editou um comando DEPOIS de aprovado) e um evento diferente de `unknown`.
|
|
19
|
+
|
|
20
|
+
- **`@theokit/agents/config` — configuracao de agente, trust e arvore de instrucoes ganham porta
|
|
21
|
+
propria.** Estavam alcancaveis so por um barrel que anuncia a propria remocao, num pacote que o
|
|
22
|
+
consumidor nao instala. Foi por isso que um consumidor reescreveu 533 linhas e reintroduziu a
|
|
23
|
+
falha de contencao de symlink que `assertNoSymlinkEscape` existe para fechar.
|
|
24
|
+
|
|
25
|
+
- **O pacote publicado passa a levar prosa.** O tarball entregava `dist/`, `LICENSE` e
|
|
26
|
+
`package.json`. O README estava declarado em `files` e **nao existia em disco** (o npm omite o
|
|
27
|
+
declarado-e-ausente em silencio); o CHANGELOG existia e nao estava declarado.
|
|
28
|
+
|
|
29
|
+
- **`resolveCredential` passa a produzir a variante `oauth`.** O tipo publicado declarava
|
|
30
|
+
`'api-key' | 'oauth'` e todo caminho de retorno construia `'api-key'`. Uma variante declarada e
|
|
31
|
+
improduzivel e pior que ausente: o consumidor escreve o `case 'oauth':` que nunca roda.
|
|
32
|
+
|
|
33
|
+
- **A protecao de ponteiro do GC de transcricoes fica injetavel.** Ela derivava a protecao da
|
|
34
|
+
convencao DESTE framework; para um consumidor cujo ponteiro de sessao viva mora em outro lugar, a
|
|
35
|
+
guarda era inerte — em silencio, dentro de algo que apaga transcricoes. A injecao so ADICIONA
|
|
36
|
+
protecao, nunca remove, e um provedor que lanca falha FECHADO.
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- **Duas escritas simultaneas no store de consentimento podiam disputar o mesmo arquivo
|
|
41
|
+
temporario.** O nome saia de relogio + pid; medido, doze escritas de um mesmo processo produziam
|
|
42
|
+
UM nome, e o segundo `rename` de um temp ja renomeado lanca `ENOENT`. Chamadas sincronas numa
|
|
43
|
+
unica thread serializam e nunca colidem — por isso a suite estava verde —, mas `worker_threads`
|
|
44
|
+
compartilham pid. O nome agora sai de `randomUUID()` e a unicidade e asserida diretamente.
|
|
45
|
+
|
|
46
|
+
- **`forkBeforeUserTurn` estava publicado quebrado.** Discriminava por `role`, que no
|
|
47
|
+
`SessionRecord` do SDK mora aninhado sob `message.role`; o campo de topo e `type`. Toda chamada
|
|
48
|
+
lancava. Junto, uma guarda para o caso de a sessao de origem e a nova coincidirem.
|
|
49
|
+
|
|
50
|
+
- **Um observador de hook herdado que falhasse desaparecia sem deixar rastro.** Nao derrubar o turno
|
|
51
|
+
esta certo; sumir em silencio nao — um notificador que nunca dispara le igual a um que nao tem
|
|
52
|
+
nada a reportar.
|
|
53
|
+
|
|
54
|
+
- **Um membro delegado passa a herdar o veto do supervisor.** A ordem e a propriedade de seguranca:
|
|
55
|
+
a recusa do pai e avaliada primeiro, e o membro so pode ADICIONAR motivo para recusar.
|
|
56
|
+
|
|
57
|
+
## 8.6.0
|
|
58
|
+
|
|
59
|
+
### Minor Changes
|
|
60
|
+
|
|
61
|
+
- `transform_tool_result` roda UMA VEZ POR TOOL CALL, nao uma por lote, e o payload passa a ser o
|
|
62
|
+
mesmo formato dos irmaos: `{ tool, name, args, result }`.
|
|
63
|
+
|
|
64
|
+
A primeira versao mandava o lote inteiro como `{ tools: [...] }` — um TERCEIRO formato, num modulo
|
|
65
|
+
cujos outros dois handlers mandam `{ tool, args, ... }`. Um script de hook escrito contra os irmaos
|
|
66
|
+
nao conseguia ler, e um hook que decide sobre "qual tool, com quais argumentos" quer uma chamada
|
|
67
|
+
por vez de qualquer forma.
|
|
68
|
+
|
|
69
|
+
`name` e alias de `tool`, e e deliberado em vez de redundante: scripts de hook moldados na
|
|
70
|
+
convencao do Claude Code leem `.name`, e esses scripts estao no disco de usuarios. Mandar so uma
|
|
71
|
+
chave e quebrar todos eles seria mudanca de formato disfarcada de refactor.
|
|
72
|
+
|
|
73
|
+
Um hook SEM matcher continua rodando uma vez mesmo com o lote vazio — e o que "sem matcher"
|
|
74
|
+
significa, e `.some()` sobre array vazio dizia o contrario.
|
|
75
|
+
|
|
76
|
+
**Nota de proveniencia:** o codigo desta mudanca entrou no repositorio junto com o `8.5.2`, porque
|
|
77
|
+
o comando que faria o bump de versao foi bloqueado e o commit do codigo nao. Durante algumas horas
|
|
78
|
+
o fonte e o `8.5.2` do registry divergiram sob o mesmo numero — a mesma deriva que o
|
|
79
|
+
`@theokit/http@1.0.0` teve e que esta sessao passou a caçar. Esta versao e o que fecha.
|
|
80
|
+
|
|
81
|
+
## 8.5.2
|
|
82
|
+
|
|
83
|
+
### Patch Changes
|
|
84
|
+
|
|
85
|
+
- Duas regressoes no `transform_tool_result` que estreou no 8.5.0. As duas eram minhas, e as duas
|
|
86
|
+
foram encontradas pelos testes que ja existiam num produto — nao por revisao.
|
|
87
|
+
|
|
88
|
+
**Um hook SEM matcher parava de rodar quando o lote de tool calls estava vazio.** A checagem era
|
|
89
|
+
`ctx.toolCalls.some(...)`, e `.some()` sobre array vazio e `false` — entao um hook que pediu para
|
|
90
|
+
ver TUDO nao via nada no momento em que nao havia nada com que casar. Agora um hook sem matcher
|
|
91
|
+
roda sempre; com matcher, a regra de casar por qualquer chamada do lote continua.
|
|
92
|
+
|
|
93
|
+
**Os ARGUMENTOS da tool nao chegavam ao payload.** Eu mandava so os nomes. O produto que motivou
|
|
94
|
+
este milestone ja tinha corrigido esse mesmo defeito na copia dele, com a razao escrita: um hook
|
|
95
|
+
conseguia ver QUAL tool rodou e o resultado dela, e nunca com o que ela foi chamada. Uma guarda que
|
|
96
|
+
nao le os argumentos nao consegue decidir sobre eles. Agora vao `{ name, args }`.
|
|
97
|
+
|
|
98
|
+
Os dois casos entraram como teste aqui, com contra-prova — sem elas, "rodar sempre" satisfaria o
|
|
99
|
+
primeiro e apagaria o matcher.
|
|
100
|
+
|
|
101
|
+
## 8.5.1
|
|
102
|
+
|
|
103
|
+
### Patch Changes
|
|
104
|
+
|
|
105
|
+
- Republicacao do 8.5.0 a partir do fonte commitado. Nenhuma mudanca de comportamento — os mesmos 37
|
|
106
|
+
testes do motor de hooks passam nos dois.
|
|
107
|
+
|
|
108
|
+
O 8.5.0 foi publicado a partir de uma arvore de trabalho cujo commit o `lint-staged` recusou
|
|
109
|
+
(`buildHookHandlers` tinha passado do teto de 120 linhas). Corrigi extraindo dois construtores de
|
|
110
|
+
handler e commitei — mas o `dist` no registry ficou sendo o de ANTES da extracao.
|
|
111
|
+
|
|
112
|
+
Isso e a mesma deriva que o `@theokit/http@1.0.0` teve e que custou uma investigacao inteira: fonte
|
|
113
|
+
e registry divergirem sob o mesmo numero de versao. Um patch e mais barato que deixar a divergencia
|
|
114
|
+
de pe.
|
|
115
|
+
|
|
116
|
+
## 8.5.0
|
|
117
|
+
|
|
118
|
+
### Minor Changes
|
|
119
|
+
|
|
120
|
+
- Tres eventos passam a ser CONECTADOS de verdade: `transform_tool_result`, `on_session_start` e
|
|
121
|
+
`post_assistant_reply`. O motor sai de dois handlers para cinco.
|
|
122
|
+
|
|
123
|
+
`transform_tool_result` e o que o par `pre`/`post` nao consegue expressar: um hook que le o
|
|
124
|
+
RESULTADO de uma tool e anexa feedback que o modelo depois ve. Era o unico evento cujo retorno o
|
|
125
|
+
SDK consome, e era declarado, aceito pelo schema e nunca construido.
|
|
126
|
+
|
|
127
|
+
- **`continuationBudget` deixa de ser inerte.** Ele e `DEFAULT_CONTINUATION_BUDGET` estavam
|
|
128
|
+
exportados e **lidos por nada** — um `grep` achava a declaracao e nenhum uso. Um knob que o
|
|
129
|
+
chamador pode ajustar e que nunca faz nada le como funcionalidade, que foi o motivo do M74 ter
|
|
130
|
+
REMOVIDO quatro. Este nao foi removido: implementar `transform_tool_result` e exatamente o que lhe
|
|
131
|
+
da um trabalho, porque feedback anexado e o que permite um hook se realimentar. O orcamento e o que
|
|
132
|
+
para o laco.
|
|
133
|
+
|
|
134
|
+
Os dois observacionais sao FAIL-OPEN sem excecao: disparam depois do fato, e um notificador
|
|
135
|
+
quebrado nunca pode ser o motivo de um turno concluido ser descartado.
|
|
136
|
+
|
|
137
|
+
Restam tres eventos sem consumidor pedindo (`transform_llm_output`, `on_session_end`,
|
|
138
|
+
`pre_user_send`). Eles seguem cobertos pelo aviso do 8.4.0 — construi-los seria superficie que
|
|
139
|
+
ninguem pediu.
|
|
140
|
+
|
|
141
|
+
## 8.4.0
|
|
142
|
+
|
|
143
|
+
### Minor Changes
|
|
144
|
+
|
|
145
|
+
- Um hook declarado num evento que este motor **nao conecta** agora AVISA, em vez de nao fazer nada
|
|
146
|
+
em silencio.
|
|
147
|
+
|
|
148
|
+
`HOOK_EVENTS` publica oito nomes e `hookSpecSchema` aceita os oito — mas `buildHookHandlers` so
|
|
149
|
+
conecta dois: `pre_tool_call` e `post_tool_call`. Medido sobre os oito: **seis nao produziam
|
|
150
|
+
handler nem aviso**.
|
|
151
|
+
|
|
152
|
+
O efeito: um operador escreve `on_session_start` no arquivo de hooks, ele passa no parse, ganha
|
|
153
|
+
fingerprint, e a pessoa aprova — e nunca dispara, sem nada dito. O docblock deste modulo proibe
|
|
154
|
+
exatamente isso, escrito sobre um evento COM ERRO DE DIGITACAO; o mesmo silencio cobria seis
|
|
155
|
+
corretamente escritos.
|
|
156
|
+
|
|
157
|
+
Conectar os outros seis e trabalho de verdade. Dizer que eles nao existem e um `if`, e e a metade
|
|
158
|
+
que nao podia esperar.
|
|
159
|
+
|
|
160
|
+
Apareceu tentando migrar um consumidor real, que conecta quatro eventos — incluindo um
|
|
161
|
+
`transform_tool_result` com orcamento de continuacao proprio, que este motor nao tem.
|
|
162
|
+
|
|
163
|
+
## 8.3.0
|
|
164
|
+
|
|
165
|
+
### Minor Changes
|
|
166
|
+
|
|
167
|
+
- `buildHookHandlers` aceita `onVeto` — chamado quando um hook `pre_tool_call` VETA uma chamada,
|
|
168
|
+
para que uma superficie possa dizer isso ao usuario.
|
|
169
|
+
|
|
170
|
+
O sinal precisa sair dali. Um veto bloqueia a chamada e entrega ao modelo uma mensagem para ele se
|
|
171
|
+
corrigir, e no fio isso e deliberadamente indistinguivel de um resultado de tool comum — o SDK
|
|
172
|
+
documenta assim. Entao uma superficie nao consegue reconhecer um veto observando o stream; este e o
|
|
173
|
+
unico ponto que sabe que houve um.
|
|
174
|
+
|
|
175
|
+
Sem ele, um consumidor que mostra "um hook bloqueou isto" precisava manter a copia inteira deste
|
|
176
|
+
builder so para disparar uma notificacao. Era exatamente o caso medido numa migracao real.
|
|
177
|
+
|
|
178
|
+
Dispara tambem no veto por ESTOURO DE ORCAMENTO da cadeia. Omitir ali faria a superficie reportar
|
|
179
|
+
todo bloqueio menos o causado por lentidao — que e o que um operador mais precisa ver nomeado.
|
|
180
|
+
|
|
181
|
+
**Opcional, e nao e default de seguranca:** o veto bloqueia de qualquer forma. Isto decide apenas
|
|
182
|
+
se alguem e informado — uma superficie headless nao tem a quem contar.
|
|
183
|
+
|
|
184
|
+
## 8.2.0
|
|
185
|
+
|
|
186
|
+
### Minor Changes
|
|
187
|
+
|
|
188
|
+
- `buildHookHandlers` aceita um `fingerprint` opcional — como um spec vira a chave conferida contra
|
|
189
|
+
`approved`. O default continua sendo o nosso `hookFingerprint`.
|
|
190
|
+
|
|
191
|
+
A lacuna apareceu numa migracao real, nao em hipotese. Um consumidor chegou com um store de
|
|
192
|
+
aprovacoes JA EM DISCO, chaveado pelo esquema dele (projecao JSON com chaves ordenadas e prefixo
|
|
193
|
+
`sha256:`), enquanto o nosso junta os campos com U+001E e emite hex cru. Os dois sao solidos; sao
|
|
194
|
+
diferentes — o mesmo hook gera dois valores.
|
|
195
|
+
|
|
196
|
+
Com a funcao fixa no codigo, o `approved` daquele consumidor nao casava com nada e **todo hook era
|
|
197
|
+
recusado**. Nao um crash: um aviso por hook e silencio depois, que e a pior forma que uma regressao
|
|
198
|
+
de seguranca pode ter.
|
|
199
|
+
|
|
200
|
+
A alternativa era migrar os dados do store de aprovacoes — e uma migracao pela metade re-pergunta
|
|
201
|
+
ao operador por hooks que ele ja aprovou. Re-perguntar tudo e como um usuario aprende a aprovar por
|
|
202
|
+
reflexo, que e exatamente o que este gate existe para impedir.
|
|
203
|
+
|
|
204
|
+
**O que NAO muda:** `approved` continua obrigatorio, um set vazio continua recusando tudo, e o
|
|
205
|
+
default continua o nosso. Injetar a funcao decide como um hook e NOMEADO, nunca se o gate se
|
|
206
|
+
aplica — e ha teste para os dois lados.
|
|
207
|
+
|
|
208
|
+
## 8.1.0
|
|
209
|
+
|
|
210
|
+
### Minor Changes
|
|
211
|
+
|
|
212
|
+
- Os tres erros do canal de pergunta (`ConcurrentQuestionError`, `ConcurrentListenerError`,
|
|
213
|
+
`QuestionAbandonedError`) passam a carregar um `code` estavel:
|
|
214
|
+
`question_already_pending`, `listener_already_attached`, `question_abandoned`.
|
|
215
|
+
|
|
216
|
+
Eles ja eram tipados e ja diziam o que fazer — mas sem `code`. `name` e string de exibicao; `code`
|
|
217
|
+
e o que um `switch` consome e o que sobrevive a minificacao. Os erros irmaos deste mesmo pacote
|
|
218
|
+
(`DELEGATION_TIMEOUT`, `DELEGATION_FAILED`) sempre tiveram um; estes tres sairam sem, e apareceu
|
|
219
|
+
quando um consumidor migrou da propria copia e encontrou `undefined`.
|
|
220
|
+
|
|
221
|
+
O teste que deveria ter pego se chamava `test_every_error_is_a_TheokitAgentError_with_a_stable_code`
|
|
222
|
+
e verificava `name` e a mensagem — nunca o `code`. Agora verifica os tres.
|
|
223
|
+
|
|
224
|
+
## 7.6.0
|
|
225
|
+
|
|
226
|
+
### Minor Changes
|
|
227
|
+
|
|
228
|
+
- M67 — the config/trust/wiring family crosses the layered boundary, and the `@theokit/sdk` floor
|
|
229
|
+
rises to `^4.49.0` to make that possible.
|
|
230
|
+
|
|
231
|
+
**Installation-contract change.** `theokit` and `@theokit/presenter` publish `@theokit/sdk` as a
|
|
232
|
+
`peerDependency`; raising the floor means a consumer pinned below 4.49.0 will now fail peer
|
|
233
|
+
resolution. Sized as a minor because the API is additive — nothing removed or renamed — but the
|
|
234
|
+
peer floor is a real break at install time and is named here rather than left to be discovered.
|
|
235
|
+
|
|
236
|
+
Six values (`foldLayers`, `verifyLayerOrdering`, `applySecurityFloor`, `resolveTrustPosture`,
|
|
237
|
+
`auditEnvReachability`, `recordWiring`) and two types (`WiredEntity`, `ToolResultContentBlock`)
|
|
238
|
+
now cross. Four more arrived with the floor: `classifySessionArtifact` + `SessionArtifact`,
|
|
239
|
+
`atomicWriteTempTarget`, `writableRootsFor`, `assertSecureModes`. Plus the five root-bar typed
|
|
240
|
+
error classes the `/errors` subpath never reached: `LayerOrderError`, `ToolError`,
|
|
241
|
+
`GenerateObjectError`, `StreamObjectError`, `UngatedCapabilityError`.
|
|
242
|
+
|
|
243
|
+
M68 (in progress) additionally crosses the trust vocabulary — `TrustLevel`, `TrustSource`,
|
|
244
|
+
`TrustPosture`, `TrustPostureInput`.
|
|
245
|
+
|
|
246
|
+
**Why 7.6.0 and not 7.5.0.** The first attempt at this release computed 7.5.0, which was already
|
|
247
|
+
published on 2026-08-10 with different content. `workspace` had never received the back-merge from
|
|
248
|
+
`main` after that release, so two already-consumed changeset files were still sitting there and
|
|
249
|
+
changesets recomputed them on top of a stale base. Publishing would have put a different artifact
|
|
250
|
+
under a version that already exists.
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
## 7.5.0
|
|
254
|
+
|
|
255
|
+
### Minor Changes
|
|
256
|
+
|
|
257
|
+
- 762c446: Forward `onRunEvent` through the in-process turn. The HTTP path threaded the SDK's typed `RunEvent` sink since theokit#132; the in-process entry point declared no field for it, so an embedded surface could not observe any run event. Additive — absent, the key is omitted and the SDK call is byte-identical to before.
|
|
258
|
+
- 92b962a: `ToolsetError` now extends `TheokitAgentError` instead of `Error`.
|
|
259
|
+
|
|
260
|
+
It sat outside the SDK's error hierarchy, so `catch (e) { if (e instanceof TheokitAgentError) }` —
|
|
261
|
+
the shape consumers use to tell an SDK failure from any other throw — missed it, leaving name or
|
|
262
|
+
message matching as the only way to recognise it. A consumer reported writing a `translateError()`
|
|
263
|
+
shim for precisely that.
|
|
264
|
+
|
|
265
|
+
This layer had already settled the same argument in M61, when two `ConfigurationError` classes (one
|
|
266
|
+
`extends Error`, one `extends TheokitAgentError`) made an `instanceof` check catch one path and
|
|
267
|
+
silently miss the other. Same defect, same package, simply left standing here.
|
|
268
|
+
|
|
269
|
+
`code` remains a public readonly field and `name` is unchanged, so existing
|
|
270
|
+
`new ToolsetError(msg, 'unknown_tool')` calls and `err.code` reads keep working. It is still
|
|
271
|
+
`instanceof Error`, via `TheokitAgentError`.
|
|
272
|
+
|
|
273
|
+
## 7.4.0
|
|
274
|
+
|
|
275
|
+
### Minor Changes
|
|
276
|
+
|
|
277
|
+
- 2cae085: `@theokit/agents/auth` now lets the OAuth engine cross over: `ensureFreshCredential`,
|
|
278
|
+
`persistOAuthTokens`, `refreshOAuthTokens` and `extractAccountId`.
|
|
279
|
+
|
|
280
|
+
M73 opened the credential-store mechanics and M110 opened the RFC 8628 device flow. What sits
|
|
281
|
+
**between** them — exchanging a device grant for tokens, refreshing before expiry, persisting the
|
|
282
|
+
result, knowing which account the tokens belong to — had no door. Since consumers have an unbreakable
|
|
283
|
+
rule never to import `@theokit/sdk*` directly, the only legal way out was to reimplement; that is
|
|
284
|
+
what happened, for the third time in this same subsystem.
|
|
285
|
+
|
|
286
|
+
Pure pass-through (same reference as the SDK, locked with `toBe`), by the criterion M73 fixed: these
|
|
287
|
+
are stateless I/O functions.
|
|
288
|
+
|
|
289
|
+
`resolveCredential` deliberately stays out, and now has a test proving it — two functions share that
|
|
290
|
+
name with divergent semantics (sync vs async, throws vs `undefined`, reads env vs does not), and
|
|
291
|
+
exposing both in one scope invites importing the wrong one, silently.
|
|
292
|
+
|
|
293
|
+
## 7.3.1
|
|
294
|
+
|
|
295
|
+
### Patch Changes
|
|
296
|
+
|
|
297
|
+
- Updated dependencies [a6dd4c1]
|
|
298
|
+
- @theokit/presenter@0.5.0
|
|
299
|
+
|
|
300
|
+
## 7.3.0
|
|
301
|
+
|
|
302
|
+
### Minor Changes
|
|
303
|
+
|
|
304
|
+
- A bridge consome UMA timeline ordenada do SDK — o merge de duas fontes acabou (#140).
|
|
305
|
+
|
|
306
|
+
Antes, ela fundia `onDelta` (tokens e ciclo de vida de tool, sem `run_started`/`system`) com um
|
|
307
|
+
`run.stream()` pós-conclusão (mensagens completas, em lote). Nenhuma das duas era completa sozinha,
|
|
308
|
+
então todo o aparelho de dedup existia só para reconciliá-las — e essa reconciliação é de onde saíram
|
|
309
|
+
o #47 (ordem), o #138 (namespace de `callId`) e o fallback de timestamp.
|
|
310
|
+
|
|
311
|
+
`sdk-adapter-merge.ts` (221 linhas) foi deletado; `sdk-timeline.ts` (137) o substitui. Foram junto a
|
|
312
|
+
fila assíncrona, o sink de delta, `mergeDeltaStream`, `MergeState` — e a dedup **por comparação de
|
|
313
|
+
conteúdo**.
|
|
314
|
+
|
|
315
|
+
Sobrevive uma dedup de tool **keyed por id** (`callId` + `modelCallId`), e ela não é resíduo: só o
|
|
316
|
+
delta carrega `modelCallId`, e só a mensagem reporta um erro de tool que o delta apenas abriu.
|
|
317
|
+
Preferir uma das fontes perde os casos da outra em silêncio. Comparar texto era a doença; comparar
|
|
318
|
+
ids não é.
|
|
319
|
+
|
|
320
|
+
Nada muda no que o consumidor recebe: os mesmos `StreamEvent`s, na mesma ordem. O que muda é de onde
|
|
321
|
+
eles vêm — e que a classe de bug que produziu #47 e #138 deixa de ser representável.
|
|
322
|
+
|
|
323
|
+
Requer `@theokit/sdk >= 4.40.0` (já declarado como dependência direta deste pacote).
|
|
324
|
+
|
|
325
|
+
## 7.2.0
|
|
326
|
+
|
|
327
|
+
### Minor Changes
|
|
328
|
+
|
|
329
|
+
- `setDiagnosticsSink` e o tipo `DiagnosticsSink` passam a ser exportados pelo barril (#173).
|
|
330
|
+
|
|
331
|
+
Um consumidor cuja fronteira de camadas proíbe importar `@theokit/sdk` diretamente não tinha como
|
|
332
|
+
instalar um sink: o canal existia e era inalcançável de dentro da fronteira. Reexport puro, sem
|
|
333
|
+
semântica nova — o silêncio-por-padrão do SDK continua sendo a postura certa para uma biblioteca, e
|
|
334
|
+
**onde** escrever segue sendo decisão do consumidor.
|
|
335
|
+
|
|
336
|
+
```ts
|
|
337
|
+
import { setDiagnosticsSink } from '@theokit/agents'
|
|
338
|
+
setDiagnosticsSink((m) => process.stderr.write(m + '\n'))
|
|
339
|
+
// retry 1/3 in 431ms — RateLimitError (Retry-After: 400ms)
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Acompanha o `@theokit/sdk@4.39.2`, que é o release em que esse canal passou a funcionar de fato: até
|
|
343
|
+
o 4.39.1 o registro do sink era um singleton **por instância de módulo**, então com duas cópias do
|
|
344
|
+
SDK na árvore o sink instalado aqui caía num registro diferente daquele em que o emissor escreve — o
|
|
345
|
+
símbolo resolvia, nada lançava, e nenhum diagnóstico chegava.
|
|
346
|
+
|
|
347
|
+
## 7.1.0
|
|
348
|
+
|
|
349
|
+
### Minor Changes
|
|
350
|
+
|
|
351
|
+
- O TheoKit passa a ser dono do wire `UIMessageStream`: instalar `theokit` não traz mais o `ai`.
|
|
352
|
+
|
|
353
|
+
Schema, parser e reconstrutor vivem em `@theokit/presenter/wire`. **O formato da frame não muda** —
|
|
354
|
+
um cliente ai-sdk continua conversando com um servidor TheoKit, e nenhum app existente precisa
|
|
355
|
+
migrar. `ai` deixa de ser `peerDependency`; quem o declarava só por causa do TheoKit pode removê-lo.
|
|
356
|
+
|
|
357
|
+
Por que **minor** e não major: nada que um consumidor faz deixa de funcionar. Remover um peer é
|
|
358
|
+
relaxamento, não quebra; os tipos são estruturalmente compatíveis (medido: as declarações do ai-sdk
|
|
359
|
+
não têm brand), então código que ainda importa de `ai` segue compilando. O `@theokit/presenter` ganha
|
|
360
|
+
`zod` como peer — a única exigência nova, e ele está em 0.x.
|
|
361
|
+
|
|
362
|
+
Correções que vêm junto, todas de defeitos que existiriam em qualquer parser de wire escrito sem
|
|
363
|
+
elas:
|
|
364
|
+
|
|
365
|
+
- O frame terminal `data: [DONE]` não é JSON. Sem guarda, um parser quebraria no **último frame de
|
|
366
|
+
toda resposta**.
|
|
367
|
+
- Terminadores CRLF/CR passam a ser normalizados. Sem isso, um proxy que os reescreve produzia
|
|
368
|
+
silêncio total — nem erro, nem renderização.
|
|
369
|
+
- Um erro de provider no meio do stream preserva o texto já entregue e só então falha.
|
|
370
|
+
|
|
371
|
+
`ai` permanece como `devDependency`: um teste diferencial alimenta o mesmo stream nele e no nosso
|
|
372
|
+
parser, exigindo saída idêntica variante por variante. É o que torna a reimplementação verificável
|
|
373
|
+
em vez de uma aposta.
|
|
374
|
+
|
|
375
|
+
### Patch Changes
|
|
376
|
+
|
|
377
|
+
- Updated dependencies
|
|
378
|
+
- @theokit/presenter@0.4.0
|
|
379
|
+
|
|
380
|
+
## 7.0.0
|
|
381
|
+
|
|
382
|
+
### Major Changes
|
|
383
|
+
|
|
384
|
+
- Dois re-exports mudam de nome, acompanhando o `@theokit/sdk@4.39.0`.
|
|
385
|
+
|
|
386
|
+
- `@theokit/agents/persistence`: `sessaoTemEscritor` → `sessionHasWriter`
|
|
387
|
+
- `@theokit/agents/sandbox`: `detectBwrapMemoizado` → `detectBwrapMemoized`
|
|
388
|
+
|
|
389
|
+
Os dois nomes eram portugueses e atravessavam a camada verbatim. O SDK os traduziu
|
|
390
|
+
ao tornar seu código inglês-only, e a camada **não guarda alias**: um alias manteria
|
|
391
|
+
o identificador português vivo na superfície publicada, que é justamente o que a
|
|
392
|
+
mudança existe para remover. Quem importa qualquer um dos dois renomeia na chamada;
|
|
393
|
+
o comportamento é idêntico.
|
|
394
|
+
|
|
395
|
+
Junto vem o bump de `@theokit/sdk` 4.27.0 → 4.39.0, com doze correções pedidas deste
|
|
396
|
+
repo — entre elas `run.stream()` deixando de terminar em silêncio quando o run falha
|
|
397
|
+
(#101), `Agent.describe()` reportando os subagents que o runtime de fato resolve
|
|
398
|
+
(#123), `mcpLifecycle: 'session'` mantendo o servidor MCP vivo entre turnos (#155) e
|
|
399
|
+
as embeddings de `azure-openai`/`cohere`/`gemini` passando a funcionar (#128, #159).
|
|
400
|
+
|
|
401
|
+
Atenção a uma quebra de **comportamento** herdada do SDK: as diagnostics agora são
|
|
402
|
+
silenciosas por padrão. Sem um sink instalado a biblioteca não escreve no terminal —
|
|
403
|
+
antes ia direto ao stderr e corrompia o frame de qualquer TUI. Para restaurar:
|
|
404
|
+
`setDiagnosticsSink((m) => process.stderr.write(m))`.
|
|
405
|
+
|
|
406
|
+
## 6.4.2
|
|
407
|
+
|
|
408
|
+
### Patch Changes
|
|
409
|
+
|
|
410
|
+
- **Correção de segurança.** O release anterior repassava a entrada do `.mcp.json` como veio do arquivo,
|
|
411
|
+
em vez de montá-la a partir dos campos declarados. Isso deixava o `envPolicy` atravessar — e ele é o
|
|
412
|
+
campo que decide se o processo do servidor MCP herda o ambiente **com** ou **sem** as variáveis
|
|
413
|
+
sensíveis do host. Um `.mcp.json` (arquivo de projeto, versionado) podia declarar `envPolicy: "all"` e
|
|
414
|
+
entregar chaves de API do ambiente a um binário de terceiro.
|
|
415
|
+
|
|
416
|
+
Agora a entrada é montada por allowlist, ramo a ramo: `command`/`args`/`env`/`cwd` no stdio,
|
|
417
|
+
`url`/`type`/`headers`/`auth`/`requestTimeoutMs` no remoto. Campo desconhecido não atravessa —
|
|
418
|
+
inclusive um que o SDK venha a criar. `envPolicy` fica de fora deliberadamente: é decisão de postura do
|
|
419
|
+
host, e o SDK a aceita do código que constrói o agente, onde um humano revisa.
|
|
420
|
+
|
|
421
|
+
**E o aviso deixou de poder sumir.** `onWarn` continua opcional, mas quando omitido os avisos vão para
|
|
422
|
+
`stderr` em vez de para lugar nenhum — antes, um chamador que não assinasse o canal descartava entradas
|
|
423
|
+
em silêncio absoluto.
|
|
424
|
+
|
|
425
|
+
## 6.4.1
|
|
426
|
+
|
|
427
|
+
### Patch Changes
|
|
428
|
+
|
|
429
|
+
- a432fda: Os tipos de configuração de servidor MCP passaram a alcançar a raiz do pacote. Estavam em `types.ts` e
|
|
430
|
+
não chegavam ao `index.d.ts` — na prática, o consumidor conseguia _usar_ um servidor remoto mas não
|
|
431
|
+
conseguia **nomear** o tipo do mapa que `loadMcpJson` devolve, que é metade do problema que o release
|
|
432
|
+
anterior resolveu. `McpServerConfig`, `McpServersMap`, `McpStdioServerConfig`, `McpHttpServerConfig`,
|
|
433
|
+
`McpAuthConfig` e `McpOAuthConfig` agora atravessam.
|
|
434
|
+
|
|
435
|
+
## 6.4.0
|
|
436
|
+
|
|
437
|
+
### Minor Changes
|
|
438
|
+
|
|
439
|
+
- f950538: Um servidor MCP que o carregador não entende deixou de derrubar os que ele entende, e o transporte
|
|
440
|
+
remoto passou a atravessar.
|
|
441
|
+
|
|
442
|
+
Antes, um `.mcp.json` com um servidor stdio perfeitamente válido e um vizinho que o parser não
|
|
443
|
+
reconhecia produzia `McpFileError` — e **os dois** eram perdidos. Fail-closed no raio errado: recusar
|
|
444
|
+
_uma entrada_ é correto; recusar _o arquivo_ transforma "esse servidor não é suportado" em "você não
|
|
445
|
+
tem MCP nenhum".
|
|
446
|
+
|
|
447
|
+
Agora o raio é a entrada:
|
|
448
|
+
|
|
449
|
+
```jsonc
|
|
450
|
+
{
|
|
451
|
+
"mcpServers": {
|
|
452
|
+
"local": { "command": "npx", "args": ["servidor"] },
|
|
453
|
+
"remoto": { "type": "http", "url": "https://…/mcp", "headers": { "Authorization": "…" } },
|
|
454
|
+
},
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
Os dois sobem. Uma entrada inválida é **omitida e NOMEADA** pelo canal `onWarn` — o erro continua
|
|
459
|
+
tipado e visível, apenas deixou de ser fatal para os vizinhos. Um arquivo **impartível** (JSON quebrado,
|
|
460
|
+
`mcpServers` que não é objeto) continua lançando: ali não há entradas para separar.
|
|
461
|
+
|
|
462
|
+
**Nenhuma dependência nova.** O transporte remoto já era do SDK — `McpServerConfig` é
|
|
463
|
+
`McpStdioServerConfig | McpHttpServerConfig`, com `type`/`url`/`headers`/`auth`/`requestTimeoutMs`.
|
|
464
|
+
Este pacote declarava um tipo **mais estreito** e recusava o que o runtime aceita; agora re-exporta o
|
|
465
|
+
do SDK. `McpAuthConfig`, `McpHttpServerConfig`, `McpOAuthConfig` e `McpStdioServerConfig` passaram a
|
|
466
|
+
atravessar junto.
|
|
467
|
+
|
|
468
|
+
**Mudança de contrato:** `loadMcpJson` deixa de lançar em defeito de entrada. Quem dependia disso
|
|
469
|
+
recebe a entrada omitida e um aviso no `onWarn` opcional; o comportamento em defeito de **arquivo** é
|
|
470
|
+
o mesmo de antes.
|
|
471
|
+
|
|
472
|
+
O valor de `headers` nunca entra num aviso — a mensagem descreve a **forma** do campo, nunca o
|
|
473
|
+
conteúdo.
|
|
474
|
+
|
|
475
|
+
## 6.3.1
|
|
476
|
+
|
|
477
|
+
### Patch Changes
|
|
478
|
+
|
|
479
|
+
- 8847d94: Testes do device provider endurecidos após review: o override de `clientId` por ambiente
|
|
480
|
+
(`CODEX_CLIENT_ID_ENV_VAR`) ganhou oráculo — antes era API pública documentada com zero teste, e
|
|
481
|
+
remover a leitura da variável mantinha tudo verde. Um teste que não invocava nenhum símbolo de
|
|
482
|
+
produção (passava com o pacote deletado) foi removido; a cobertura real do caso vive no consumidor.
|
|
483
|
+
Nenhuma mudança de comportamento.
|
|
484
|
+
|
|
485
|
+
## 6.3.0
|
|
486
|
+
|
|
487
|
+
### Minor Changes
|
|
488
|
+
|
|
489
|
+
- e7d99d9: O device flow **RFC 8628** atravessa a camada, e o do Codex também.
|
|
490
|
+
|
|
491
|
+
`@theokit/sdk` já implementava o padrão (`deviceLogin`, `requestDeviceCode`, `pollDeviceToken`,
|
|
492
|
+
`DeviceOAuthConfig`), e `@theokit/agents/auth` não re-exportava nenhum deles. Como o consumidor tem
|
|
493
|
+
regra inquebrável de nunca importar `@theokit/sdk*` direto, quem precisasse do padrão tinha duas
|
|
494
|
+
saídas: violar a fronteira, ou reimplementar o protocolo — exatamente a situação que o M73 já
|
|
495
|
+
documentou neste arquivo (_"a lacuna era daqui, não indisciplina de lá"_).
|
|
496
|
+
|
|
497
|
+
Medido junto: `openaiDeviceLogin` era **importado** para uso interno do `AuthProvider` e nunca
|
|
498
|
+
re-exportado. Consequência — o flow do Codex só era alcançável construindo um `AuthProvider` (que
|
|
499
|
+
exige `config` + `store`). Ele atravessa agora também.
|
|
500
|
+
|
|
501
|
+
As duas formas **coexistem e não são unificadas**: `DeviceOAuthConfig` tem um `deviceCodeEndpoint`
|
|
502
|
+
(RFC); `OpenAIDeviceConfig` tem dois (`deviceUsercodeEndpoint` → `devicePollEndpoint`, com PKCE).
|
|
503
|
+
Fundi-las quebraria o Codex.
|
|
504
|
+
|
|
505
|
+
Pass-through **puro**, pelo critério que o M73 escreveu: são funções de I/O sem estado a segurar, e
|
|
506
|
+
envolver quebraria `instanceof`. `tests/unit/auth-parity.test.ts` trava a identidade dos quatro com
|
|
507
|
+
`toBe`.
|
|
508
|
+
|
|
509
|
+
- 18fa6ef: Autenticar por device flow passa a caber numa chamada, e um provider novo entra sem editar a camada.
|
|
510
|
+
|
|
511
|
+
Antes, quem usava `@theokit/agents/auth` para autenticar no Codex precisava saber que existem **duas**
|
|
512
|
+
formas de device flow, copiar o `clientId` e três URLs da OpenAI para dentro do próprio código, montar
|
|
513
|
+
`{ fetch, sleep, now }`, chamar `deviceLogin` e **lembrar** de chamar `persist` — e esquecer o último
|
|
514
|
+
custava um round-trip OAuth completo que não guardava nada.
|
|
515
|
+
|
|
516
|
+
Agora:
|
|
517
|
+
|
|
518
|
+
```ts
|
|
519
|
+
import { CODEX_PROVIDER, loginWithDevice } from '@theokit/agents/auth'
|
|
520
|
+
|
|
521
|
+
const [metodo] = CODEX_PROVIDER.methods // rotulado, para a sua UI mostrar
|
|
522
|
+
const { path } = await loginWithDevice(CODEX_PROVIDER, metodo, store, { onPrompt })
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
Um provider de terceiro usa a **mesma** chamada: basta construir um `DeviceAuthProvider` com os seus
|
|
526
|
+
métodos. Nada na camada muda.
|
|
527
|
+
|
|
528
|
+
**Novos símbolos:** `CODEX_PROVIDER`, `loginWithDevice`, `CODEX_CLIENT_ID_ENV_VAR`, e os tipos
|
|
529
|
+
`AuthMethod`, `DeviceAuthProvider`, `PromptHooks`, `LoginWithDeviceOptions`.
|
|
530
|
+
|
|
531
|
+
`AuthMethod` é união discriminada — um método `type: 'oauth'` **tem** de carregar `authorize`, e o
|
|
532
|
+
compilador recusa `{ label, type: 'oauth' }`. Não há discriminante de protocolo: cada método aponta
|
|
533
|
+
para a sua própria função, então o RFC 8628 e a variante da OpenAI coexistem sem `switch` e sem risco
|
|
534
|
+
de serem fundidas.
|
|
535
|
+
|
|
536
|
+
`deps` é opcional; `AuthProvider.deviceLogin` e `.persist` continuam públicos para quem precisa da
|
|
537
|
+
granularidade. Nenhum símbolo existente mudou de assinatura.
|
|
538
|
+
|
|
539
|
+
## 6.1.1
|
|
540
|
+
|
|
541
|
+
### Patch Changes
|
|
542
|
+
|
|
543
|
+
- M107 (review HIGH-2) — require `@theokit/sdk@^4.37.0`, not `^4.36.0`.
|
|
544
|
+
|
|
545
|
+
`6.1.0` shipped with `^4.36.0`, so a fresh install could resolve `4.36.0` — where `Agent.list`
|
|
546
|
+
**silently ignores the `cwd` it advertises**. That is not a cosmetic mismatch: a consumer that
|
|
547
|
+
narrows a listing by workspace to decide which sessions are still active would get the _process_
|
|
548
|
+
directory's answer instead, and this project consumes exactly that list to protect transcripts from
|
|
549
|
+
deletion.
|
|
550
|
+
|
|
551
|
+
The range now names the version that actually honours the contract. Nothing else changed; `6.1.0`
|
|
552
|
+
and `6.1.1` are byte-identical apart from this field. Consumers already resolving `4.37.0` (through
|
|
553
|
+
an override or a fresh install) were never affected.
|
|
554
|
+
|
|
555
|
+
## 6.1.0
|
|
556
|
+
|
|
557
|
+
### Minor Changes
|
|
558
|
+
|
|
559
|
+
- 3575c8e: Two additions: `loadMcpJson(cwd)` reads the `.mcp.json` project convention from disk, and `reasoningEffortOf(model)` reads back the reasoning effort that `buildModelSelection` writes.
|
|
560
|
+
|
|
561
|
+
**`loadMcpJson(cwd)`** — the layer already shipped the rare MCP cases (`resolveMcpServers` for per-request selection, `mcpRegistry` for a known provider) and not the common one: reading `<cwd>/.mcp.json`, the convention Claude Code and Cursor established. Every application that wanted it wrote the loader by hand, which is why the same 120-odd lines of read-parse-validate exist in more than one consumer.
|
|
562
|
+
|
|
563
|
+
It returns the `McpServersMap` the package already exports — no new type. An **absent** file returns `{}`, because MCP is opt-in and a project without the file is a project without MCP. A **present but broken** file throws `McpFileError` naming the path: a read failure, invalid JSON, a root that is not an object, a server without a non-empty `command`, or an `args`/`env`/`cwd` of the wrong type. A valid JSON object with no `mcpServers` key returns `{}` — that is a project declaring no server, not a malformed file. An empty (0-byte) file is invalid JSON and throws, deliberately: "absent" and "present and empty" are different situations, and treating the second as `{}` would disable MCP in silence.
|
|
564
|
+
|
|
565
|
+
`McpFileError` descends from `TheokitAgentError`, so `isTransientError` classifies it like every other error from this package (`isRetryable` is `false` — a malformed config file does not improve on retry).
|
|
566
|
+
|
|
567
|
+
**Scope, so it is not a surprise later:** stdio servers only. HTTP/SSE entries are not accepted in this release. Widening it later is additive and breaks nothing written against this version.
|
|
568
|
+
|
|
569
|
+
**`reasoningEffortOf(model)`** — the inverse of `buildModelSelection`, which is documented as the single site that maps a reasoning effort onto a `ModelSelection`. Only the write half was public, so callers that needed to read the effort back re-derived the parameter key by hand. Two spellings of one key drift apart quietly; now both directions live in one module and share one constant.
|
|
570
|
+
|
|
571
|
+
It accepts a bare model id or a full selection, and returns `undefined` when there is no effort to read — a string id, a selection without parameters, or parameters that do not include the reasoning key. None of those throw: absence is a normal answer, not a failure. A value that is present but not one of the documented levels comes back **verbatim**, and the return type is `string | undefined` for exactly that reason: validating the value stays with the caller, and typing the result as the effort union would promise a check this function does not perform.
|
|
572
|
+
|
|
573
|
+
Both symbols are reachable from the package root and from `@theokit/agents/bridge`.
|
|
574
|
+
|
|
575
|
+
## 6.0.0
|
|
576
|
+
|
|
577
|
+
### Major Changes
|
|
578
|
+
|
|
579
|
+
- 24c8011: **BREAKING:** `Agent.list` no longer accepts `limit` or `cursor`, and its result no longer declares `nextCursor`.
|
|
580
|
+
|
|
581
|
+
The SDK's type promises all three; the runtime references none of them — `Agent.list` reads only `options.runtime`. A caller that writes `limit: 500` against a 688-entry registry believes it asked for a bounded page and silently gets the whole set, and on the day the runtime starts honouring the parameter that _same_ line silently gets a truncated one instead. Both directions are silent, and the consumer that motivated this change feeds the result into a NEVER-delete guard of a session garbage collector: a truncated list there means deleting a transcript the guard should have protected.
|
|
582
|
+
|
|
583
|
+
This is a type-only change — the exported value is still the SDK's `Agent`, asserted by identity in `tests/unit/agent-list-narrowed.test.ts`. Every other static (`create`, `getOrCreate`, `get`, `delete`, `archive`, `unarchive`, `rename`, `compact`, `listRuns`, `getRun`, `registry`) keeps its shape, asserted in `tests/type/agent-list-narrowed.test-d.ts`.
|
|
584
|
+
|
|
585
|
+
Migration is one line per call site: delete the `limit`/`cursor` property. The result is the full population, which is what the runtime was already returning.
|
|
586
|
+
|
|
587
|
+
Exit criterion, written in `src/index.ts` next to the narrowing: when the SDK runtime actually honours `limit`/`cursor`/`cwd`, delete the block and restore the plain re-export.
|
|
588
|
+
|
|
589
|
+
## 5.0.0
|
|
590
|
+
|
|
591
|
+
### Major Changes
|
|
592
|
+
|
|
593
|
+
- 6aa5b6d: **BREAKING:** `toAgentFactory` now requires an `approvals` option declaring the surface's `ApprovalPosture` — one of `interactive`, `auto-approve`, `auto-reject` or `owned-by-surface`.
|
|
594
|
+
|
|
595
|
+
Until now the factory compiled the HITL gate map that `.approvals({…})` produces and then discarded it, so tools declared as requiring approval executed with no policy consulted — while the sibling bridge (`streamAgentTurnInProcess`) refused for the same definition. The permissive behaviour is still fully available; it just has to be named, with a written reason, instead of happening by omission. Migration is one line per call site: pass the posture that describes what your surface actually does.
|
|
596
|
+
|
|
597
|
+
`streamAgentTurnInProcess` also accepts `approvals`, but additively — omitting it preserves today's fail-closed refusal exactly.
|
|
598
|
+
|
|
599
|
+
## 4.30.2
|
|
600
|
+
|
|
601
|
+
### Patch Changes
|
|
602
|
+
|
|
603
|
+
- O mapeamento de erro do SDK para o evento de stream ganha módulo próprio.
|
|
604
|
+
|
|
605
|
+
Um mapeador puro, com o mesmo tratamento que a seleção de modelo já tinha. Ter casa própria também deixa óbvio que existe **um** lugar construindo o evento de erro — antes era um objeto literal dentro de um `catch`, e era exatamente ali que o código do erro se perdia.
|
|
606
|
+
|
|
607
|
+
## 4.30.1
|
|
608
|
+
|
|
609
|
+
### Patch Changes
|
|
610
|
+
|
|
611
|
+
- Re-exporta a consulta que responde se uma sessão já tem escritor, sem tomar a trava.
|
|
612
|
+
|
|
613
|
+
## 4.30.0
|
|
614
|
+
|
|
615
|
+
### Minor Changes
|
|
616
|
+
|
|
617
|
+
- O chunk de erro do stream passa a carregar o código do erro, não só o texto.
|
|
618
|
+
|
|
619
|
+
Uma falha de runtime não sobe como exceção para quem consome o stream — é convertida num chunk de erro, e esse é o contrato. Mas o chunk levava **só a mensagem**, então um consumidor que precise distinguir a falha (por exemplo, derivar uma sessão nova quando a original já tem escritor) não tinha alternativa senão casar texto de mensagem de erro. O código sempre existiu no evento de origem; ele só não atravessava. Um erro sem código continua exatamente como antes.
|
|
620
|
+
|
|
621
|
+
## 4.29.1
|
|
622
|
+
|
|
623
|
+
### Patch Changes
|
|
624
|
+
|
|
625
|
+
- Corrige um turno que quebrava quando a janela de contexto era declarada na seleção de modelo.
|
|
626
|
+
|
|
627
|
+
A versão anterior passou a **aceitar** a seleção completa em `AgentBuilder.model()` e parou aí: o caminho de runtime por onde todo turno passa continuava assumindo um id em texto, e aninhava a seleção dentro de si mesma. O resultado era uma falha em **todo** turno de quem declarasse a janela. Passar um id continua funcionando exatamente como antes, e a janela declarada agora sobrevive à conversão.
|
|
628
|
+
|
|
629
|
+
## 4.29.0
|
|
630
|
+
|
|
631
|
+
### Minor Changes
|
|
632
|
+
|
|
633
|
+
- `AgentBuilder.model()` aceita `ModelSelection`, não só o id cru.
|
|
634
|
+
|
|
635
|
+
A implementação do SDK sempre aceitou as duas formas; era a fachada tipada desta camada que estreitava para `string`. O estreitamento tornava **inalcançável** qualquer campo da seleção — incluindo a janela de contexto que o SDK passou a publicar. Passar um id continua funcionando exatamente como antes.
|
|
636
|
+
|
|
637
|
+
## 4.28.0
|
|
638
|
+
|
|
639
|
+
### Minor Changes
|
|
640
|
+
|
|
641
|
+
- M94 — re-exporta os resolvedores que o SDK passou a publicar.
|
|
642
|
+
|
|
643
|
+
- `transcriptRoot` — a raiz do estado de transcript, que honra `THEOKIT_HOME`. O consumidor a duplicava em três arquivos, e as três cópias ignoravam a variável junto com a original.
|
|
644
|
+
- `TranscriptMessage` / `TranscriptBlock` — a forma do corpo de um registro de sessão, que antes era `Record<string, unknown>` e obrigava o consumidor a recuperar o tipo com cast a cada leitura.
|
|
645
|
+
|
|
646
|
+
`Provider.forModel` já atravessa a camada pelo re-export existente de `Provider`.
|
|
647
|
+
|
|
648
|
+
## 4.27.1
|
|
649
|
+
|
|
650
|
+
### Patch Changes
|
|
651
|
+
|
|
652
|
+
- 191aef8: **Correções da revisão adversarial do M92 — dois BLOCKERs e três furos de eviction.**
|
|
653
|
+
|
|
654
|
+
- **O `concat` que o `4.27.0` prometeu e não entregou.** O `#prefixo` era um **alias** do `#committed`
|
|
655
|
+
(mesma referência) e o `#emit` continuava espalhando: byte-idêntico ao anterior, medido em ~2 µs @400.
|
|
656
|
+
Agora é um `concat` único. O ganho é de constante, não de ordem — e é honesto dizer isso.
|
|
657
|
+
- **O coalescing não tinha teste capaz de falhar.** Substituir o corpo inteiro de `#agendarEmit` por
|
|
658
|
+
`return` deixava **580/580 verdes**: os testes instalavam timers falsos e nunca os avançavam, e só
|
|
659
|
+
exercitavam `reset()`, que faz flush síncrono por decisão. Os testes novos dirigem 30 deltas por um
|
|
660
|
+
transporte falso e medem a razão de emits — **32 contra 2**, e o mutante mata 2 testes.
|
|
661
|
+
- **Três furos na eviction de aprovação, todos medidos:**
|
|
662
|
+
- Sinal **já abortado** no `sendMessages` não dispara `addEventListener`, então uma aprovação que
|
|
663
|
+
estacionasse depois ficava pendente para sempre — o travamento que o milestone existe para fechar,
|
|
664
|
+
alcançável por outro caminho. Agora o sinal é consultado **no momento em que a aprovação estaciona**.
|
|
665
|
+
- O turno era lido de um **campo compartilhado**, então um runner do turno 1 estacionando depois do
|
|
666
|
+
`send` do turno 2 nascia etiquetado turno 2 e o abort do turno 1 não o alcançava. O turno passou a
|
|
667
|
+
viver num **closure por turno** — o único lugar onde não é sobrescrito.
|
|
668
|
+
- Rejeitar sem handler mata o processo em Node ≥ 15; o caminho tem teste.
|
|
669
|
+
|
|
670
|
+
## 4.27.0
|
|
671
|
+
|
|
672
|
+
### Minor Changes
|
|
673
|
+
|
|
674
|
+
- f486258: **O stream ganha coalescing opt-in, e o transporte para de vazar aprovação estacionada.**
|
|
675
|
+
|
|
676
|
+
- **`AgentClient` cacheia o prefixo commitado.** `#committed` só muda em dois lugares (o `done` de
|
|
677
|
+
`send()` e o `reset()`), então reconstruí-lo por delta de token era trabalho que a estrutura já
|
|
678
|
+
garantia inútil. Honestidade sobre o tamanho: medido, o spread custa **0,0062 ms por delta @400
|
|
679
|
+
mensagens** — 3,1 ms no turno inteiro. É real e é micro.
|
|
680
|
+
- **Coalescing opt-in: `new AgentClient(transport, ctx, { emitIntervalMs })`.** Sem o campo, emite por
|
|
681
|
+
delta como sempre. É aqui que está a ordem de grandeza: o que pende de cada emit é a derivação da
|
|
682
|
+
timeline, medida em **3,274 ms por chamada** no mesmo tamanho de thread — **≈ 528×** o spread. O
|
|
683
|
+
coalescing não torna o emit mais barato; faz **menos emits acontecerem**. As transições de status
|
|
684
|
+
(`done`/`error`/`abort`) fazem **flush síncrono**, porque um estado final preso num timer de 16 ms é
|
|
685
|
+
um estado final perdido se o processo sair antes.
|
|
686
|
+
- **`InProcessTransport` evicta aprovação de turno abortado**, rejeitando com `ApprovalAbortedError`.
|
|
687
|
+
Antes, `#pending` guardava só o `resolve` e nada apagava a entrada: a promessa ficava pendente **para
|
|
688
|
+
sempre** e a chamada de tool do SDK pendurava com ela. Uma promessa que nunca resolve **nem** rejeita
|
|
689
|
+
é a forma mais silenciosa de engolir um erro — nem stack trace existe. Rejeitar e não `resolve(false)`
|
|
690
|
+
porque `false` é indistinguível de _"o usuário negou"_: negar é decisão, abortar é interrupção. As
|
|
691
|
+
entradas passaram a ser chaveadas por turno, então um `send()` novo varre o anterior.
|
|
692
|
+
|
|
693
|
+
## 4.26.2
|
|
694
|
+
|
|
695
|
+
### Patch Changes
|
|
696
|
+
|
|
697
|
+
- 379e5c0: **Restaura a compatibilidade que o `4.26.0` quebrou em silêncio: `BudgetExceededError` volta a ser a
|
|
698
|
+
classe de DELEGAÇÃO no barril raiz.**
|
|
699
|
+
|
|
700
|
+
O `4.26.0` **reaproveitou** o nome — o barril passou a exportar a classe do SDK (orçamento de JANELA)
|
|
701
|
+
sob `BudgetExceededError`. Medido contra os tarballs publicados:
|
|
702
|
+
|
|
703
|
+
| | 4.25.1 | 4.26.1 |
|
|
704
|
+
| ------------------------------------------------- | -------- | ------------------------------------------------ |
|
|
705
|
+
| `new BudgetExceededError('agente', 5, 1)` da raiz | funciona | `TypeError: Cannot read properties of undefined` |
|
|
706
|
+
| raiz `===` `/bridge` | `true` | `false` |
|
|
707
|
+
|
|
708
|
+
Para quem estava em `^4.25` com `catch (e) { if (e instanceof BudgetExceededError) … }`, o ramo de
|
|
709
|
+
orçamento de delegação **deixou de casar, em silêncio** — o modo de falha exato que o rename existia
|
|
710
|
+
para matar, em espelho, e publicado como MINOR.
|
|
711
|
+
|
|
712
|
+
Agora: `BudgetExceededError` é o alias `@deprecated` de `DelegationBudgetExceededError` — mesma
|
|
713
|
+
identidade referencial de sempre, zero quebra. A classe do SDK atravessa como
|
|
714
|
+
`WindowBudgetExceededError`, que fecha a lacuna original **sem redefinir o que um nome significa**.
|
|
715
|
+
Travado por `tests/unit/erro-de-dominio.test.ts`, que assere `barril.BudgetExceededError` **é** a
|
|
716
|
+
classe de delegação e que as duas são classes distintas.
|
|
717
|
+
|
|
718
|
+
## 4.26.1
|
|
719
|
+
|
|
720
|
+
### Patch Changes
|
|
721
|
+
|
|
722
|
+
- 228d423: Corrige o tipo de `SdkAgentHandle.send` introduzido no `4.26.0`: ele devolve
|
|
723
|
+
`Promise<SdkTurnHandle>`, não `SdkTurnHandle`.
|
|
724
|
+
|
|
725
|
+
`SDKAgent.send` é `(message, options?) => Promise<Run>`, e o `GoalLoopAgent` do SDK declara
|
|
726
|
+
`send(prompt): Promise<{ wait(): … }>`. A primeira versão do tipo era síncrona — e o detalhe é que o
|
|
727
|
+
`tsc` do consumidor **não teria pegado**, porque o adaptador que este milestone existe para apagar
|
|
728
|
+
(`runner-facade.ts`, com um `as never` na origem) absorvia exatamente essa diferença.
|
|
729
|
+
|
|
730
|
+
É a divergência que o docstring daquele adaptador descrevia, reencontrada ao tentar removê-lo — a
|
|
731
|
+
prova de que o `unknown` não era só feio: ele desligava a checagem no ponto onde o contrato importa.
|
|
732
|
+
|
|
733
|
+
## 4.26.0
|
|
734
|
+
|
|
735
|
+
### Minor Changes
|
|
736
|
+
|
|
737
|
+
- 3fb0d9e: **Contratos de tipo honestos: a camada passa a devolver o tipo que já sabe.**
|
|
738
|
+
|
|
739
|
+
- **`toAgentFactory` aceita um THUNK de definição** — `(sessionId) => AgentDefinition`. O parâmetro
|
|
740
|
+
`apiKey` já aceitava thunk desde o M74, adicionado por exatamente esta razão; a assimetria custava
|
|
741
|
+
caro: com a forma objeto, trust, hooks, skills e MCP são compilados no load do módulo e ficam
|
|
742
|
+
**congelados para o processo inteiro**. Num `theokit acp` que uma IDE mantém aberto por horas, isso
|
|
743
|
+
reintroduzia a obsolescência que o M67 removeu. A forma objeto continua **byte-idêntica** — projeta
|
|
744
|
+
uma vez, fora do closure; só o thunk paga por sessão.
|
|
745
|
+
- **`SdkAgentHandle.send` deixa de ser `=> unknown`** e passa a `(msg, opts?) => { wait(): … }`, com
|
|
746
|
+
`SdkSendOptions`/`SdkTurnHandle` publicados. O `unknown` custava ao consumidor um módulo inteiro de
|
|
747
|
+
38 linhas cujo único trabalho era re-estreitar este retorno — e o docstring daquele módulo registra
|
|
748
|
+
que, antes dele, o chamador escrevia `as never`, sob cuja capa a superfície goal divergiu do agente
|
|
749
|
+
real por vários milestones.
|
|
750
|
+
- **`Toolset` é a primitiva que faltava** (`@theokit/agents` barril). Coleção nomeada e imutável com
|
|
751
|
+
política de resolução que falha alto em nome **desconhecido** e em **duplicado** — nos dois casos, o
|
|
752
|
+
silêncio seria uma mudança de autoridade não observável, que é o que uma whitelist existe para
|
|
753
|
+
impedir. **Não prefixa namespace**: o nome de uma tool é contrato com o modelo. Não constrói tools —
|
|
754
|
+
quais e com que escopo é decisão do consumidor.
|
|
755
|
+
- **`BudgetExceededError` → `DelegationBudgetExceededError`**, com alias `@deprecated` por uma major.
|
|
756
|
+
O nome antigo **sombreava** a classe homônima do SDK (orçamento de JANELA contra orçamento de
|
|
757
|
+
DELEGAÇÃO), e como o consumidor tem regra de nunca importar `@theokit/sdk` direto, ele nunca
|
|
758
|
+
alcançava a do SDK: `instanceof` casava com o domínio errado **em silêncio**. O barril agora exporta
|
|
759
|
+
as duas. A `lacuna` registrada em `subpath-coverage.test.ts` saiu junto com o conflito que a criou.
|
|
760
|
+
|
|
761
|
+
## 4.25.1
|
|
762
|
+
|
|
763
|
+
### Patch Changes
|
|
764
|
+
|
|
765
|
+
- 5167910: **Corrige uma regressão de superfície introduzida no `4.25.0`: `TruncationMode` voltou a ser exportado
|
|
766
|
+
por `@theokit/agents/tools`.**
|
|
767
|
+
|
|
768
|
+
A entrada do `4.25.0` afirma _"172 símbolos, superfície preservada inteira (nada sai)"_. Isso era falso:
|
|
769
|
+
o gerador de re-exports rodou contra uma cópia local de `@theokit/sdk-tools@0.26.0` (92 exports)
|
|
770
|
+
enquanto o registro já publicara `0.26.1` (93, com `TruncationMode`). O peer é uma faixa flutuante
|
|
771
|
+
(`>=0.24.1 <1.0.0`), então consumidores instalavam a versão nova e perdiam o símbolo: sob `export *` ele
|
|
772
|
+
atravessava; enumerado a partir da cópia velha, sumiu. A entrada anterior não pode ser editada, então
|
|
773
|
+
a correção fica aqui.
|
|
774
|
+
|
|
775
|
+
O gate que deveria ter pego isso era **vacuo para `/tools` e `/pty`** — 98 dos 173 símbolos, 57% da
|
|
776
|
+
superfície. Ele comparava _a fonte_ contra o snapshot, e nunca _a camada_ contra a fonte; remover
|
|
777
|
+
símbolos reais desses dois entries deixava a suíte inteira verde. `tests/unit/subpath-surface.test.ts`
|
|
778
|
+
passa a enumerar o `dist/*.d.ts` **emitido** e a comparar nas duas direções (nada da fonte falta na
|
|
779
|
+
camada; nada na camada é inventado), e deixa de engolir a ausência de `dist/`, que o fazia passar por
|
|
780
|
+
vacuidade num clone sem build.
|
|
781
|
+
|
|
782
|
+
Superfície agora: **173 símbolos** (`tools` 93, `sandbox` 36, `persistence` 29, `pty` 6,
|
|
783
|
+
`interactive` 9).
|
|
784
|
+
|
|
785
|
+
## 4.25.0
|
|
786
|
+
|
|
787
|
+
### Minor Changes
|
|
788
|
+
|
|
789
|
+
- 9aea11c: Os cinco subpaths de infra (`/tools`, `/sandbox`, `/persistence`, `/pty`, `/interactive`) deixam de ser
|
|
790
|
+
alias e viram camada.
|
|
791
|
+
|
|
792
|
+
Até aqui, o corpo inteiro de cada `*-entry.ts` era uma linha `export *`, e o `dist/*.d.ts` emitido
|
|
793
|
+
carregava a mesma coisa: o pacote emprestava o nome sem interpor decisão. Um rename upstream se
|
|
794
|
+
propagava verbatim, **sem erro de build aqui**, e o consumidor descobria em call site.
|
|
795
|
+
|
|
796
|
+
Agora os cinco enumeram — **172 símbolos**, superfície preservada inteira (nada sai; reduzir seria
|
|
797
|
+
breaking, e a regra do `auth-entry.ts` desde o M73 é que enriquecer nunca reduz). Medido lado a lado no
|
|
798
|
+
mesmo cenário de rename: com `export *` o build passa; com lista nomeada, `tsc` reprova com `TS2724` e
|
|
799
|
+
sugere o nome novo.
|
|
800
|
+
|
|
801
|
+
Acompanham a mudança um snapshot da superfície sobre `dist/*.d.ts`
|
|
802
|
+
(`tests/unit/subpath-surface.test.ts`) e a promoção dos três subpaths de SDK em
|
|
803
|
+
`subpath-coverage.test.ts` de `cobertura: 'amostra'` com lista **vazia** para `'total'`.
|
|
804
|
+
|
|
805
|
+
## 4.9.1
|
|
806
|
+
|
|
807
|
+
### Patch Changes
|
|
808
|
+
|
|
809
|
+
- O retry com backoff do refresh de OAuth passa a existir de fato no caminho de execução. As funções que
|
|
810
|
+
classificam a falha e calculam a espera estavam presentes e testadas, mas nenhuma era chamada — uma
|
|
811
|
+
reescrita de bloco as desconectou, e os testes que existiam validavam o classificador isolado, o que
|
|
812
|
+
não prova que ele está ligado. Uma falha transitória agora é repetida até três vezes; `invalid_grant`
|
|
813
|
+
continua falhando na primeira, porque repetir um token revogado só atrasa a mensagem.
|
|
814
|
+
|
|
815
|
+
## 4.9.0
|
|
816
|
+
|
|
817
|
+
### Minor Changes
|
|
818
|
+
|
|
819
|
+
- `toAgentFactory` também aceita um resolvedor de credencial (`() => string | Promise<string>`), resolvido
|
|
820
|
+
quando a sessão é criada.
|
|
821
|
+
|
|
822
|
+
A 4.8.0 alargou `AgentRunnerRunOptions.apiKey`, que é um seam real — mas não é o que as superfícies de
|
|
823
|
+
consumidor usam. Um cliente ACP, um loop autônomo e uma delegação de time constroem o agente por
|
|
824
|
+
`toAgentFactory`, e ali a credencial continuava sendo uma string obtida antes. O alargamento sem este
|
|
825
|
+
complemento não alcançava nenhuma das três.
|
|
826
|
+
|
|
827
|
+
## 4.8.0
|
|
828
|
+
|
|
829
|
+
### Minor Changes
|
|
830
|
+
|
|
831
|
+
- `AgentRunnerRunOptions.apiKey` passa a aceitar um resolvedor (`() => string | Promise<string>`) além do
|
|
832
|
+
valor. Ele é chamado quando o stream começa, não quando o agente é construído.
|
|
833
|
+
|
|
834
|
+
O ponto de injeção já era por run; o que travava era o tipo. Com `string`, quem chama precisa ter o
|
|
835
|
+
valor em mãos antes — então o momento era por run, mas o valor era obtido antes e congelado, e um
|
|
836
|
+
bearer OAuth de validade curta atravessava a run inteira sem ser reconsultado. Uma sessão de IDE que
|
|
837
|
+
dura horas, um loop autônomo de vinte turnos e uma delegação de time longa exibem o mesmo sintoma.
|
|
838
|
+
|
|
839
|
+
`string` continua válido e continua sendo o caminho de quem usa chave de API: ela não expira, e exigir
|
|
840
|
+
um resolvedor ali seria cerimônia sem ganho.
|
|
841
|
+
|
|
842
|
+
O refresh de OAuth passa a rodar sob lock entre processos, com releitura depois de adquiri-lo — sem a
|
|
843
|
+
releitura o lock apenas serializa, e o segundo processo refresca com estado velho, invalidando o token
|
|
844
|
+
que o primeiro acabou de gravar. Como o lock não é reentrante e o resolvedor agora é chamado de dentro
|
|
845
|
+
do stream, há um single-flight em processo antes dele: uma execução aninhada resolve pela promise em
|
|
846
|
+
voo em vez de disputar o arquivo consigo mesma.
|
|
847
|
+
|
|
848
|
+
Falhas de refresh passam a ser classificadas: rede e 5xx são repetidos com backoff e jitter,
|
|
849
|
+
`invalid_grant` falha na primeira tentativa. Repetir um token revogado só atrasa a mensagem que o
|
|
850
|
+
usuário precisa ler. A mensagem de erro nunca carrega material de token.
|
|
851
|
+
|
|
852
|
+
## 4.7.0
|
|
853
|
+
|
|
854
|
+
### Minor Changes
|
|
855
|
+
|
|
856
|
+
- `@theokit/agents/auth` passa a re-exportar a mecânica de store do `@theokit/sdk/auth` como
|
|
857
|
+
pass-through puro: `credentialHome`, `authFilePath`, `CredentialError`, `readAuthFile`,
|
|
858
|
+
`readStoredOAuth`, `writeCredential` e o tipo `ResolveCredentialOptions`.
|
|
859
|
+
|
|
860
|
+
O subpath exportava um valor e seis tipos contra os dezenove símbolos do SDK — nenhuma função
|
|
861
|
+
atravessava. Para um consumidor que não pode importar `@theokit/sdk*` direto, reimplementar era a
|
|
862
|
+
única saída legal; um deles reescreveu seis destes nomes. A camada existe para enriquecer, e enriquecer
|
|
863
|
+
nunca deve reduzir.
|
|
864
|
+
|
|
865
|
+
Pass-through puro, e não wrapper: são funções de I/O sem estado a segurar, e envolvê-las quebraria
|
|
866
|
+
`instanceof` para quem captura `CredentialError`. O novo `check:auth-parity` exige decisão escrita por
|
|
867
|
+
símbolo do SDK — coberto, ou fora de escopo com a razão — para que a lacuna não se repita em silêncio.
|
|
868
|
+
|
|
869
|
+
`resolveCredential` deliberadamente não atravessa: o SDK e o consumidor têm funções diferentes com
|
|
870
|
+
esse nome, e o próprio SDK declara a precedência de env e a inferência de provider como política do
|
|
871
|
+
consumidor.
|
|
872
|
+
|
|
873
|
+
## 4.6.0
|
|
874
|
+
|
|
875
|
+
### Minor Changes
|
|
876
|
+
|
|
877
|
+
- M63 — close the `SDK → Theokit → AgentBuilder` boundary: the main barrel now also re-exports
|
|
878
|
+
`SubAgent` (the a2a delegation primitive, `SubAgent.create()`) and the pure `path-safety` helpers
|
|
879
|
+
(`assertNoSymlinkEscape`, `isForbiddenPath`, `safePathJoin`). Same PASS-THROUGH doctrine as the M58
|
|
880
|
+
core re-exports (parsimony Rung 9 — already the target OO/pure shape, wrapping would be ceremony), so
|
|
881
|
+
a consumer can import ITS full runtime surface from `@theokit/agents` without touching `@theokit/sdk*`
|
|
882
|
+
directly. Additive only — no existing export changes.
|
|
883
|
+
|
|
884
|
+
## 4.5.0
|
|
885
|
+
|
|
886
|
+
### Minor Changes
|
|
887
|
+
|
|
888
|
+
- `@theokit/agents/tools` — pass-through of the `@theokit/sdk-tools` factory surface (M62).
|
|
889
|
+
|
|
890
|
+
The consumer imports its ready-made built-in tools (`createReadFileTool`, `createShellTool`, … +
|
|
891
|
+
`withName`/`withDescription`) from the Theokit layer instead of `@theokit/sdk-tools` directly. Pure
|
|
892
|
+
re-export, never enriched (parsimony Rung 9 — the sugar is the SDK-tools' own; wrapping it would be
|
|
893
|
+
reinventing, blueprint Q5). A surface test locks the 16 symbols the consumer uses. `@theokit/sdk-tools`
|
|
894
|
+
stays an OPTIONAL peer (only consumers of this subpath need it) and its range moves to `>=0.20.0` —
|
|
895
|
+
the newer tool factories (`createCurrentTimeTool`/`createInteractiveShellTool`/`createUpdatePlanTool`/
|
|
896
|
+
`createWriteStdinTool`) live there.
|
|
897
|
+
|
|
898
|
+
## 4.4.0
|
|
899
|
+
|
|
900
|
+
### Minor Changes
|
|
901
|
+
|
|
902
|
+
- ee9fb7b: Unify `ConfigurationError` on the SDK's class (M61).
|
|
903
|
+
|
|
904
|
+
`@theokit/agents` used to define its own `ConfigurationError extends Error` while `@theokit/sdk`
|
|
905
|
+
shipped a separate `ConfigurationError extends TheokitAgentError`. A `catch (e instanceof
|
|
906
|
+
ConfigurationError)` caught one throw path and silently missed the other. The layer now RE-EXPORTS the
|
|
907
|
+
SDK's class, so authoring throws (`@theokit/agents`) and runtime throws (`@theokit/sdk`) are the SAME
|
|
908
|
+
class — `instanceof` holds across the boundary in both directions. Existing single-arg
|
|
909
|
+
`new ConfigurationError('msg')` calls are unchanged (the SDK options are optional); the class stays
|
|
910
|
+
`instanceof Error`. Decision in `knowledge-base/adrs/0006-configuration-error-unification.md`.
|
|
911
|
+
|
|
912
|
+
## 4.3.1
|
|
913
|
+
|
|
914
|
+
### Patch Changes
|
|
915
|
+
|
|
916
|
+
- M60 follow-up: `AuthProvider.ensureFresh(resolved, deps, env)` — the HTTP deps and `env` are now
|
|
917
|
+
separate params (was a single `opts` bag). Corrects the just-shipped 4.3.0 shape before any consumer
|
|
918
|
+
depends on it; behavior (delegation to `ensureFreshCredential`) is unchanged.
|
|
919
|
+
|
|
920
|
+
## 4.3.0
|
|
921
|
+
|
|
922
|
+
### Minor Changes
|
|
923
|
+
|
|
924
|
+
- `AuthProvider` — the OO OAuth-lifecycle contract at `@theokit/agents/auth` (M60).
|
|
925
|
+
|
|
926
|
+
The SDK ships OAuth as free functions stateful across a shared config + store
|
|
927
|
+
(`openaiDeviceLogin` → `persistOAuthTokens` → `ensureFreshCredential`). The Theokit layer now unifies
|
|
928
|
+
them into an `AuthProvider` class that HOLDS the `config`+`store` and delegates each step, so a
|
|
929
|
+
consumer authors `new AuthProvider(config, store).persist(...)` / `.ensureFresh(...)` instead of
|
|
930
|
+
threading the shared state through every call. Enrich, not pass-through (auth carries state); it
|
|
931
|
+
DELEGATES, never reimplements (Rung 9) — login → persist → refresh yields identical state. SECRET-SAFE
|
|
932
|
+
by contract: the wrapper never logs or emits token material (pinned by a secret-safety test). The auth
|
|
933
|
+
domain's types (`OAuthProviderConfig`/`CredentialStoreConfig`/`OpenAIDeviceConfig`/`ResolvedCredential`/
|
|
934
|
+
`OAuthTokens`/`DeviceDeps`) are re-exported alongside it.
|
|
935
|
+
|
|
936
|
+
## 4.2.2
|
|
937
|
+
|
|
938
|
+
### Patch Changes
|
|
939
|
+
|
|
940
|
+
- fb89c9e: Fix: the goal domain types (`GoalEvent`/`GoalLoopAgent`/`GoalOptions`/`GoalResult`) are now actually
|
|
941
|
+
re-exported from the top-level barrel (the M59 re-export was only reachable from the loop submodule).
|
|
942
|
+
|
|
943
|
+
## 4.2.1
|
|
944
|
+
|
|
945
|
+
### Patch Changes
|
|
946
|
+
|
|
947
|
+
- 87fa3bb: Re-export the goal domain's types alongside `GoalRunner` (M59 follow-up).
|
|
948
|
+
|
|
949
|
+
`GoalEvent`, `GoalLoopAgent`, `GoalOptions`, `GoalResult` now travel with `GoalRunner` from
|
|
950
|
+
`@theokit/agents`, so a consumer types against the goal surface entirely from the Theokit layer
|
|
951
|
+
without reaching back to `@theokit/sdk`.
|
|
952
|
+
|
|
953
|
+
## 4.2.0
|
|
954
|
+
|
|
955
|
+
### Minor Changes
|
|
956
|
+
|
|
957
|
+
- 7e37347: `GoalRunner` — the OO twin of the SDK's free `runGoalLoop` (M59).
|
|
958
|
+
|
|
959
|
+
The layered boundary continues: the SDK ships goal orchestration as a free function
|
|
960
|
+
(`runGoalLoop(agent, goal, options, deps)`); the Theokit layer now imposes its OO shape with a
|
|
961
|
+
`GoalRunner` class parallel to `AgentRunner`, so a consumer authors `new GoalRunner(agent).run(goal,
|
|
962
|
+
options)` instead of a bare call. Unlike the M58 pass-through barrels, this ENRICHES an orchestration
|
|
963
|
+
primitive with a contract — but it DELEGATES, never reimplements (parsimony Rung 9): `run` forwards
|
|
964
|
+
verbatim to `runGoalLoop`, so the emitted `GoalEvent` stream and the final `GoalResult` are identical.
|
|
965
|
+
A parity test pins that both ways (exact forwarded tuple + identical stream/result).
|
|
966
|
+
|
|
967
|
+
## 4.1.0
|
|
968
|
+
|
|
969
|
+
### Minor Changes
|
|
970
|
+
|
|
971
|
+
- dd044c1: Pass-through barrels for the 5 already-OO / pure SDK domains (M58).
|
|
972
|
+
|
|
973
|
+
The layered boundary `SDK → Theokit → AgentBuilder`: `@theokit/agents` now re-exports the SDK domains
|
|
974
|
+
that are already object-oriented or pure helpers, so a consumer imports them from the Theokit layer
|
|
975
|
+
instead of `@theokit/sdk*` directly. Re-export, never a wrapper (parsimony Rung 9) — wrapping
|
|
976
|
+
`Agent.create()` or a pure `transcriptPath()` would be ceremony without value.
|
|
977
|
+
|
|
978
|
+
- **core** (main barrel): `Agent`, `Squad`, `Tool`, `Provider` + `SDKAgent` / `CustomTool` /
|
|
979
|
+
`SessionRecord` types.
|
|
980
|
+
- **`@theokit/agents/sandbox`**: `LocalSandbox`, `SandboxBackend`, `SandboxConfig`.
|
|
981
|
+
- **`@theokit/agents/persistence`**: `transcriptPath`, `encodeProjectDir`, `atomicWriteText`,
|
|
982
|
+
`SessionRecord`.
|
|
983
|
+
- **`@theokit/agents/interactive`**: `InteractiveBackend`, `StartInteractiveOptions`,
|
|
984
|
+
`StartInteractiveResult`.
|
|
985
|
+
- **`@theokit/agents/pty`**: `PtyInteractiveBackend` (optional peer `@theokit/sdk-pty` — only consumers
|
|
986
|
+
of this subpath need it installed).
|
|
987
|
+
|
|
988
|
+
A surface test locks each barrel's symbols so a dropped re-export fails loudly. The `@theokit/sdk`
|
|
989
|
+
peer range moves to `^4.19.0` — the `/interactive` and `/sandbox` subpaths this layer re-exports live
|
|
990
|
+
there. Consumers already on SDK 4.19+ are unaffected.
|
|
991
|
+
|
|
992
|
+
## 4.0.0
|
|
993
|
+
|
|
994
|
+
### Major Changes
|
|
995
|
+
|
|
996
|
+
- fcd1536: Authoring surface is now 100% object-oriented (M57) — the free "sugar" factories are gone.
|
|
997
|
+
|
|
998
|
+
The ~14 free capability factories and the two free builders are replaced by classes and static
|
|
999
|
+
factories, finishing the `X.create()` migration `@theokit/sdk` completed at v3.0. One idiom, aligned
|
|
1000
|
+
with the runtime this layer wraps.
|
|
1001
|
+
|
|
1002
|
+
**BREAKING — mechanical 1:1 rename, no behaviour change:**
|
|
1003
|
+
|
|
1004
|
+
```ts
|
|
1005
|
+
// before // after
|
|
1006
|
+
memory(x) new MemoryCapability(x)
|
|
1007
|
+
skills(x) new SkillsCapability(x)
|
|
1008
|
+
contextWindow(x) new ContextWindowCapability(x)
|
|
1009
|
+
checkpoint(x) new CheckpointCapability(x)
|
|
1010
|
+
subAgents(x) new SubAgentsCapability(x)
|
|
1011
|
+
projectContext(x) new ProjectContextCapability(x)
|
|
1012
|
+
mcpServers(x) new McpServersCapability(x)
|
|
1013
|
+
guardrails(x) new GuardrailsCapability(x)
|
|
1014
|
+
humanInTheLoop(x) new HumanInTheLoopCapability(x)
|
|
1015
|
+
skillsOptions(x) new SkillsOptionsCapability(x)
|
|
1016
|
+
settingSources(x) new SettingSourcesCapability(x)
|
|
1017
|
+
plugins(x) new PluginsCapability(x)
|
|
1018
|
+
runContext(x) new RunContextCapability(x)
|
|
1019
|
+
skillsResolver(x) new SkillsResolverCapability(x)
|
|
1020
|
+
agent() AgentBuilder.create()
|
|
1021
|
+
contextualTool(t) ContextualTool.of(t)
|
|
1022
|
+
```
|
|
1023
|
+
|
|
1024
|
+
The nine pure-assignment capabilities share a `FieldCapability` base (one line each); the five that
|
|
1025
|
+
carry behaviour (validation / delegation / merge / storage-metadata warning) keep the exact body.
|
|
1026
|
+
`AgentBuilder` / `ContextualTool` are each a type (generic interface) and a value (static factory) at
|
|
1027
|
+
once — the fluent type-state chain is unchanged.
|
|
1028
|
+
|
|
1029
|
+
Zero-behavior: the deterministic suite (608) and type suite (104) pass without editing a single
|
|
1030
|
+
expectation after repointing call-sites. Reverses ADR 0001 § 4; rationale in
|
|
1031
|
+
`knowledge-base/adrs/0005-sugar-to-oo.md`.
|
|
1032
|
+
|
|
1033
|
+
## 3.0.0
|
|
1034
|
+
|
|
1035
|
+
### Major Changes
|
|
1036
|
+
|
|
1037
|
+
- 0e4ea93: Inject a custom loop stop-criterion via `AgentRunnerBuilder.loopStrategy(custom)` (M54).
|
|
1038
|
+
|
|
1039
|
+
**MAJOR — type-level break.** `LoopStrategy.name` changed from the `'simple-chat' | 'plan-act-reflect' | 'react'` union to `string`. A consumer doing an exhaustive `switch (strategy.name)` over the three literals (no `default`) will now fail to typecheck — `string` is not exhausted by three cases. There is no runtime-only semver policy in this repo, so a source-breaking type change takes a major bump (M54 review F-3).
|
|
1040
|
+
|
|
1041
|
+
The runner already let you inject reflection, compaction, and the round stream factory; the stop
|
|
1042
|
+
criterion (`LoopStrategy.shouldContinue`) was the one axis locked to three built-in names. Now:
|
|
1043
|
+
|
|
1044
|
+
```ts
|
|
1045
|
+
const stopWhenConfident: LoopStrategy = {
|
|
1046
|
+
name: 'confident',
|
|
1047
|
+
maxIterations: 8,
|
|
1048
|
+
shouldContinue: (o) => !o.responseText.includes('confidence: high'),
|
|
1049
|
+
}
|
|
1050
|
+
AgentRunner.fromSpec(spec).loopStrategy(stopWhenConfident).build()
|
|
1051
|
+
```
|
|
1052
|
+
|
|
1053
|
+
The injected strategy WINS over the strategy the spec's name would resolve to, exactly as
|
|
1054
|
+
`.compaction()` outranks the spec.
|
|
1055
|
+
|
|
1056
|
+
**The ceiling is now the runner's guarantee, not each strategy's convention.** Previously the three
|
|
1057
|
+
built-ins embedded `round < maxIterations` inside their own `shouldContinue`, so a custom that never
|
|
1058
|
+
returned `false` would loop forever. The runner now caps every strategy at `maxIterations` — a
|
|
1059
|
+
`shouldContinue: () => true` terminates at the ceiling with `finishReason: 'step_limit'`.
|
|
1060
|
+
|
|
1061
|
+
**Type change (note):** `LoopStrategy.name` is now `string` (was the `'simple-chat' |
|
|
1062
|
+
'plan-act-reflect' | 'react'` union) so a custom can name itself freely. The internal resolver still
|
|
1063
|
+
validates the three built-in names via Zod; a custom never passes through it. Code that reads
|
|
1064
|
+
`strategy.name` expecting the exhaustive union should widen to `string`.
|
|
1065
|
+
|
|
1066
|
+
## 2.0.0
|
|
1067
|
+
|
|
1068
|
+
### Major Changes
|
|
1069
|
+
|
|
1070
|
+
- 96c0b05: Remove the backward-compatibility concessions the previous release carried (M56).
|
|
1071
|
+
|
|
1072
|
+
**BREAKING — `ToolboxCapability.compile()` deleted.** It had zero callers anywhere and was kept only
|
|
1073
|
+
because removing a public method breaks consumers. `apply()` is the one path an agent's tools flow
|
|
1074
|
+
through. If you called `compile()` directly, apply the capability instead:
|
|
1075
|
+
`applyCapabilities([new ToolboxCapability(...)])`.
|
|
1076
|
+
|
|
1077
|
+
**`ConfigurationError` is still exported from the package root — only the internal duplicate
|
|
1078
|
+
re-export was removed.** It used to reach the barrel through a compat shim in
|
|
1079
|
+
`capability/capabilities.js`; M56 removes the shim and pins the class to the barrel directly, so
|
|
1080
|
+
`import { ConfigurationError } from '@theokit/agents'` keeps working. Only a deep import from the
|
|
1081
|
+
internal `capability/capabilities.js` path — never a documented entry point — is affected. A
|
|
1082
|
+
`public-api-surface` test now locks the root export in place.
|
|
1083
|
+
|
|
1084
|
+
Also in this release: the two `compileTools` failure paths that threw a bare `Error` (missing toolbox
|
|
1085
|
+
instance, non-method handler) now throw the typed `ConfigurationError` the rest of the module uses, so
|
|
1086
|
+
an authoring mistake is distinguishable from an unexpected runtime failure.
|
|
1087
|
+
|
|
1088
|
+
## 1.1.0
|
|
1089
|
+
|
|
1090
|
+
### Minor Changes
|
|
1091
|
+
|
|
1092
|
+
- Tool names are now validated where they are minted, against all three rules the SDK enforces.
|
|
1093
|
+
|
|
1094
|
+
The fix for #145 changed the namespace separator but replicated only **one** of the three rules
|
|
1095
|
+
`@theokit/sdk`'s `validateToolName` imposes. The rule it missed was live: a toolbox with
|
|
1096
|
+
`namespace: 'mcp'` minted `mcp_*`, passed authoring validation, and was **rejected by
|
|
1097
|
+
`Agent.create`** with `tool_reserved_name` — the same defect class as #145, on a different axis.
|
|
1098
|
+
|
|
1099
|
+
Validation now lives inside `toolRuntimeName`, the only function that mints a runtime name, so no
|
|
1100
|
+
path can escape it — including `compileTools`, which is exported publicly. The message names the
|
|
1101
|
+
offending **composed** name (the parts often look valid alone) and tells "the composition overflowed
|
|
1102
|
+
64 characters" apart from "invalid character".
|
|
1103
|
+
|
|
1104
|
+
**Behavior change:** `compileTools` now throws `ConfigurationError` at compile time for a
|
|
1105
|
+
namespace/tool pair that previously failed later, at `Agent.create`. No working agent breaks — a
|
|
1106
|
+
name that reaches this error was already being rejected downstream; it now fails earlier and says
|
|
1107
|
+
why.
|
|
1108
|
+
|
|
1109
|
+
Also: the HITL gate map and the tool registry are derived from a **single** structure instead of
|
|
1110
|
+
being built twice. Building them twice is exactly how they drifted apart in #145 — the tool became
|
|
1111
|
+
`ns_tool` while its gate stayed `ns.tool`, silently ungating it. No observable output change.
|
|
1112
|
+
|
|
1113
|
+
## 1.0.1
|
|
1114
|
+
|
|
1115
|
+
### Patch Changes
|
|
1116
|
+
|
|
1117
|
+
- c2454f5: **Fix #145 — a namespaced toolbox produced a tool name the SDK rejects.**
|
|
1118
|
+
|
|
1119
|
+
`toolRuntimeName` joined namespace and tool with `.`, which is outside the charset `@theokit/sdk`
|
|
1120
|
+
accepts (`/^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/`). Every namespaced toolbox therefore failed at
|
|
1121
|
+
`Agent.create` — a **documented** path that never worked against a real provider, unnoticed since M4
|
|
1122
|
+
because the suites mock the SDK.
|
|
1123
|
+
|
|
1124
|
+
- Separator is now `_` (`ops_deploy`). No consumer had the old form working, so the break is
|
|
1125
|
+
theoretical; update any hardcoded gate key or allow-list entry.
|
|
1126
|
+
- The name is validated at **authoring** time: a namespace that cannot mint a valid name throws a
|
|
1127
|
+
typed `ConfigurationError` instead of exploding when the model calls the tool.
|
|
1128
|
+
- `ToolboxCapability` no longer duplicates the HITL key construction — that duplication is what let
|
|
1129
|
+
the gate drift from the tool (silently ungating a gated tool when the separator changed).
|
|
1130
|
+
|
|
1131
|
+
The regression test does **not** mock `@theokit/sdk`: it calls the real `Agent.create`, whose name
|
|
1132
|
+
validation runs before any network.
|
|
1133
|
+
|
|
1134
|
+
## 1.0.0
|
|
1135
|
+
|
|
1136
|
+
### Major Changes
|
|
1137
|
+
|
|
1138
|
+
- b77cf03: **Agent decorators removed — authoring is now capability composition (M53).**
|
|
1139
|
+
|
|
1140
|
+
BREAKING for `@theokit/agents`: every **agent** decorator is gone. The `@theokit/http` **controller**
|
|
1141
|
+
decorators (`@Controller`/`@Get`/`@Post`/`@UseGuards`) are untouched.
|
|
1142
|
+
|
|
1143
|
+
- **Removed:** `@Agent`, `@MainLoop`, `@Tool`, `@Toolbox`, `@HumanInTheLoop`, `@Skills`, `@Memory`,
|
|
1144
|
+
`@ContextWindow`, `@ProjectContext`, `@MCP`, `@Guardrails`, `@Checkpoint`, `@SubAgents`,
|
|
1145
|
+
`@Compaction`, `@Gateway`, `@Trace`, `@Audit`, `@RequiresApproval`, `@Mixin` — plus nine that
|
|
1146
|
+
wrote metadata **no production code read** (`@Artifact`, `@Hook`, `@Observable`, `@Sandbox`,
|
|
1147
|
+
`@EditFormat`, `@Model`, `@RequiresCapability`, `@Policy`, `@Budget`). `@Model` never set the
|
|
1148
|
+
model and `@Sandbox` never sandboxed anything; deleting them removes no behavior.
|
|
1149
|
+
- **Replacement:** `applyCapabilities([...])` composing `ModelCapability`, `AgentConfigCapability`,
|
|
1150
|
+
`MainLoopCapability`, `ToolboxCapability`, `skills()`, `memory()`, `mcpServers()`, `guardrails()`,
|
|
1151
|
+
`checkpoint()` and friends. Conflicting declarations now fail with a typed
|
|
1152
|
+
`CapabilityConflictError` instead of last-write-wins, and `provenance` records which capability
|
|
1153
|
+
contributed each field.
|
|
1154
|
+
- **Also removed:** `bridge/walk-agent-metadata.ts` (the metadata walk) and `compileAgent`. The
|
|
1155
|
+
`reflect-metadata` **required peer dependency** and `experimentalDecorators`/
|
|
1156
|
+
`emitDecoratorMetadata` are gone from `packages/agents` — consumers of the agent surface can drop
|
|
1157
|
+
all three.
|
|
1158
|
+
- **BREAKING for `@theokit/http`:** `TheoApp.create({ agents })` and `agentsPlugin({ agents })` take
|
|
1159
|
+
prepared entries (`{ name, route, compiled }`) instead of decorated classes; `delegate()` and
|
|
1160
|
+
`AgentRunner` take a spec instead of a class (`AgentRunner.builder(Class)` →
|
|
1161
|
+
`AgentRunner.fromSpec(spec)`).
|
|
1162
|
+
|
|
1163
|
+
Migration guide with the full decorator→capability map: [`MIGRATION.md`](./MIGRATION.md).
|
|
1164
|
+
|
|
1165
|
+
Two real defects were found and fixed while doing this: every HTTP-served agent was silently running
|
|
1166
|
+
the **fallback model** (`@Agent({ model })` and `llmModel` were both dropped because `walk` was
|
|
1167
|
+
passed where `compiled` was expected, through an untyped dynamic import), and the agents branch of
|
|
1168
|
+
`TheoApp` had **no test at all** — `@theokit/agents` was never declared in `packages/http`'s
|
|
1169
|
+
`package.json`, so nothing could link it.
|
|
1170
|
+
|
|
1171
|
+
## 0.47.0
|
|
1172
|
+
|
|
1173
|
+
### Minor Changes
|
|
1174
|
+
|
|
1175
|
+
- 5793ec1: Capability core for agent authoring (M52). `@theokit/agents` gains `Capability` — a two-member contract (`name`, `apply`) that enriches the EXISTING `CompiledAgentOptions` waist instead of inventing a parallel representation. Ships `ModelCapability` / `ToolsCapability` / `skills()`, a `CapabilityRegistry` (which unlocks declaring an agent from a config FILE, not only from code), `CapabilityPreset` (a preset behaves as one capability), typed fail-fast conflicts (`CapabilityConflictError`, whose message reports a value's SHAPE and never its content, since a config-built draft can carry tokens), and `provenance` so composition is auditable.
|
|
1176
|
+
|
|
1177
|
+
Proven zero-behavior: the capability path is deep-equal to BOTH the `defineAgent` compiler and the decorator `compileAgent` — the artifact M53 deletes — at the waist and through the shared `Agent.create` projection, including via the file/registry route, and confirmed end-to-end against a real provider. The proof also pins the waist fields no capability expresses yet (derived from the type, with a compile-time exhaustiveness check, verified to fail on over-claim as loudly as on omission) — that list is M53's entry criterion.
|
|
1178
|
+
|
|
1179
|
+
The agent decorators are untouched in this release; they are removed in M53.
|
|
1180
|
+
|
|
1181
|
+
## 0.45.0
|
|
1182
|
+
|
|
1183
|
+
### Minor Changes
|
|
1184
|
+
|
|
1185
|
+
- 70a4daa: Presentation layer (M49): new `@theokit/presenter` package — the canonical `AgentOutputEvent` (narrow-waist normalized event) + the `Presenter` Strategy contract + registry + `UIMessageStreamPresenter` (the web surface) + `fromSdk` source translator. `@theokit/agents` now composes its web `UIMessageStream` path over the shared presenter (`presentUIMessageStream`), replacing the inline `translateToUIMessageStream` (removed — the public export is now `presentUIMessageStream`). Behavior is byte-identical (the full existing web test corpus — unit + M1 E2E — passes unchanged against the new path). This closes the web/terminal translation duplication surfaced by dogfooding agent-builder; terminal/JSON presenters follow in M50/M51. No backward-compat shim (owner-approved clean break).
|
|
1186
|
+
|
|
1187
|
+
## 0.44.5
|
|
1188
|
+
|
|
1189
|
+
### Patch Changes
|
|
1190
|
+
|
|
1191
|
+
- e38db92: Fix stream event order so tool events precede the final answer text. For providers whose `onDelta` reports text but not `tool-call-started` (e.g. gpt-5.4 via OpenRouter), tool events surface only via `run.stream()` (post-completion), so live onDelta text was emitted BEFORE the tool that produced it — even though the model is tool-first (verified against the raw provider response). The SDK adapter now holds `text_delta` and flushes it after the drained stream, so the timeline order matches the model's true chronology (tool → result → answer). Non-text deltas keep their live order; duplicate text stays deduped. Trade-off: on a text-only turn the answer is emitted at generation-complete rather than token-by-token.
|
|
1192
|
+
- 4cc200b: M35 (multimodal) — thread images through the bridge to `agent.send`. `StreamAgentOptions` and `RuntimeOverrides` gain an optional `images` field; when present the adapter sends the SDK's structured `SDKUserMessage { text, images }` form instead of a plain string, so the model receives images alongside the text. Absent ⇒ the string send path is byte-unchanged (back-compat). Zero new dependencies.
|
|
1193
|
+
|
|
1194
|
+
## 0.43.0
|
|
1195
|
+
|
|
1196
|
+
### Minor Changes
|
|
1197
|
+
|
|
1198
|
+
- d398561: Surface per-turn usage on the streamed assistant message. `translateToUIMessageStream` now rides the turn's authoritative totals — `usage` (input/output/total + reasoning/cache buckets), `cost`, and `durationMs` — on the ai-sdk `finish` chunk's `messageMetadata`, so they reconstruct onto the client's assistant `UIMessage.metadata` (via `readUIMessageStream`) with no extra header or store wiring. A run that ends without a `done` event (error/abort) keeps a bare `finish` (no fabricated usage). New public type `AgentTurnMetadata`. This is what lets a surface (a TUI status bar, a web cost meter) show real tokens/cost for the turn it just streamed — previously the totals stopped at the server.
|
|
1199
|
+
|
|
1200
|
+
## 0.42.0
|
|
1201
|
+
|
|
1202
|
+
### Minor Changes
|
|
1203
|
+
|
|
1204
|
+
- Ecosystem integration guarantee for the `@theokit/sdk` seam (M48) — the load-bearing seam (the SDK is the only agent runtime) is now drift-guaranteed to the same FAANG-grade posture as the `@theokit/ui` and TheoCloud seams.
|
|
1205
|
+
|
|
1206
|
+
- **Tool handlers now see `ctx.threadId` (the run's session identity, #119) and `ctx.messages` (the turn transcript, SE12).** The local `CustomTool` type mirror is synced to the SDK and kept in sync by a `.test-d.ts` type gate, so a future SDK `ctx` change fails `tsc` instead of drifting silently — a stateful tool can scope state per session instead of leaking it.
|
|
1207
|
+
- **`theokit start` fails fast when the installed `@theokit/sdk` is incompatible** — a typed `SdkIncompatibleError` (found-vs-required) at boot, instead of only a per-request error. An api-only app with no SDK installed still boots (the SDK is an optional peer).
|
|
1208
|
+
- **Closed the SDK-family peer ranges** (`@theokit/sdk-tools` `>=0.11.0` → `^0.11.0`) and added a consumer + producer contract test plus a version-drift guard so a breaking SDK change is caught in CI or at publish, never in production.
|
|
1209
|
+
|
|
1210
|
+
No action needed for apps already on `@theokit/sdk ^4.0.1`.
|
|
1211
|
+
|
|
1212
|
+
## 0.41.0
|
|
1213
|
+
|
|
1214
|
+
### Minor Changes
|
|
1215
|
+
|
|
1216
|
+
- Adopt `@theokit/sdk@^4.0.1`. Agent conversation history now persists **automatically** via the SDK's native Claude-shaped `.jsonl` transcript — no storage adapter to wire. The framework roots each app's transcript under `<projectRoot>/.data/agent-sessions` (git-ignore `.data/`).
|
|
1217
|
+
|
|
1218
|
+
**Breaking:** the pluggable conversation-storage surface is removed (SDK 4.0 no longer ships it). `AgentBuilder.conversationStorage()` and the `@Conversation` decorator are gone. Apps that passed a storage adapter should delete that wiring — persistence is on by default. Sessions still thread by `sessionId` for resume.
|
|
1219
|
+
|
|
1220
|
+
## 0.40.0
|
|
1221
|
+
|
|
1222
|
+
### Minor Changes
|
|
1223
|
+
|
|
1224
|
+
- 2cfc717: Opt into `.theokit/` file-based config with `.settingSources([...])`.
|
|
1225
|
+
|
|
1226
|
+
A code-created agent can now discover its skills, subagents, hooks, MCP servers, context, and cron jobs from files under `.theokit/` — config-as-git. Add `.settingSources(['project'])` to the `agent()` builder and the framework wires the SDK's `local.settingSources` + the app-root `cwd`, so the SDK discovers `<cwd>/.theokit/` (and `~/.theokit/` with `'user'`).
|
|
1227
|
+
|
|
1228
|
+
```ts
|
|
1229
|
+
export default agent()
|
|
1230
|
+
.model('openai/gpt-4o-mini')
|
|
1231
|
+
.system(BASE_INSTRUCTIONS)
|
|
1232
|
+
.settingSources(['project']) // ← discover .theokit/ from the app root
|
|
1233
|
+
.build()
|
|
1234
|
+
```
|
|
1235
|
+
|
|
1236
|
+
- `.settingSources([...])` is an Axis-A "SWAP" value (per the `agent-dynamic-config` blueprint): an explicit, non-empty list wins; `[]` is treated as unset; an agent that declares inline `.skills()` still falls back to `['project']` (back-compat). Discovery is now **decoupled from inline skills** — an agent can use `.theokit/hooks.json` / `mcp.json` / subagents / context with no inline skill.
|
|
1237
|
+
- The app-root `cwd` is the **framework-resolved project root** threaded through `mountAgent`, NOT `process.cwd()` (which is not guaranteed to be the app root) — so discovery reliably points at `<app>/.theokit/`.
|
|
1238
|
+
- The SDK owns discovery + execution (skill loading, hook shell execution, MCP launch); theokit only wires `local.settingSources` + `cwd` (G2 / ADR-0040 — no runtime reimplementation).
|
|
1239
|
+
- **Security:** enabling `'project'` enables shell-executing hooks from `.theokit/hooks.json`. This is opt-in because `.theokit/` is your own repo (informed consent).
|
|
1240
|
+
|
|
1241
|
+
Verified end-to-end in a real browser: a showcase agent with `.settingSources(['project'])` discovered a `.theokit/skills/` skill and listed it alongside its inline skill.
|
|
1242
|
+
|
|
1243
|
+
## 0.39.0
|
|
1244
|
+
|
|
1245
|
+
### Minor Changes
|
|
1246
|
+
|
|
1247
|
+
- f61b77f: Adopt `@theokit/sdk@3.x` (SE36 uniform `X.create()` API).
|
|
1248
|
+
|
|
1249
|
+
SDK v3.0 removed the standalone factory functions in favor of static `X.create()` namespace methods. The `@theokit/agents` bridge now binds the new names — `Tool.create` (was `defineTool`), `SkillReadTool.create` (was `defineSkillReadTool`), `Retry.create` (was `withRetry`) — and the scaffold's code-defined skill uses `Skill.create` (was `createSkill`). While migrating, the tool-handler wrapper (`withRunContext`) was fixed to forward the **full** tool `ctx` — the SE12 `messages` transcript projection was being dropped, which would have silently broken a tool that reads the turn transcript; the handler types now track the SDK's canonical `CustomTool['handler']` instead of a hand-maintained duplicate.
|
|
1250
|
+
|
|
1251
|
+
**Breaking (peer requirement):** `theokit` and `@theokit/agents` now require `@theokit/sdk >= 3.5.0` (and `@theokit/sdk-tools >= 0.9.1`, the SE36-migrated build). Apps on `@theokit/sdk@2.x` must upgrade — run `npx @theokit/codemod-sdk-3-0 --write` to migrate app code that calls the old factories directly.
|
|
1252
|
+
|
|
1253
|
+
## 0.38.1
|
|
1254
|
+
|
|
1255
|
+
### Patch Changes
|
|
1256
|
+
|
|
1257
|
+
- d186cb1: DX: move the `.skills()` mechanism explanation from the scaffold into the API's JSDoc.
|
|
1258
|
+
|
|
1259
|
+
The `agents/chat.ts` scaffold carried a 4-line inline comment explaining _how_ skills work (the `<skills>` block + the on-demand `skill_read` tool). That belongs on the API, not in the developer's first file. The explanation now lives in the `.skills()` JSDoc (discoverable on hover / cmd-click) and the scaffold keeps a one-line pointer — so a freshly scaffolded `chat.ts` reads as intent (`.skills([dailyBriefingSkill])`) with the "how" one hover away.
|
|
1260
|
+
|
|
1261
|
+
## 0.38.0
|
|
1262
|
+
|
|
1263
|
+
### Minor Changes
|
|
1264
|
+
|
|
1265
|
+
- **`.skills([inlineSkill])` now auto-provisions the `skill_read` tool — one call, not two.** An inline
|
|
1266
|
+
`createSkill` lists in the `<skills>` block by name + description ONLY; its body is unreachable to the
|
|
1267
|
+
model without a `skill_read` tool, so registering an inline skill implies wanting it readable. The
|
|
1268
|
+
runtime (`createSkillAgentStream`, where `@theokit/sdk` is dynamically loaded) now auto-appends
|
|
1269
|
+
`skill_read` when the agent declares inline skills — so `agent().skills([mySkill]).build()` both
|
|
1270
|
+
registers the skill AND makes it readable. Dedup: an explicit `defineSkillReadTool` the app added wins
|
|
1271
|
+
(never duplicated). Graceful: an SDK older than `defineSkillReadTool` degrades to list-only (no crash).
|
|
1272
|
+
The auto-wire lives at the runtime layer so the pure compile module (`compileAgentDefinition`) keeps its
|
|
1273
|
+
type-only SDK dependency. `defineSkillReadTool` remains available as an escape hatch (custom skill sets).
|
|
1274
|
+
|
|
1275
|
+
## 0.37.0
|
|
1276
|
+
|
|
1277
|
+
### Minor Changes
|
|
1278
|
+
|
|
1279
|
+
- **`.skills([...])` now accepts inline `createSkill` objects — not just filesystem skill names.** The SDK
|
|
1280
|
+
has always supported code-defined skills (`SkillsSettings.inline`, auto-injected into the `<skills>`
|
|
1281
|
+
system-prompt block), but the builder's `.skills()` / `defineAgent({ skills })` only took `string[]`
|
|
1282
|
+
names, so an inline skill could only reach the model through a `skill_read` tool + persona hardcoding.
|
|
1283
|
+
`SkillsSelection` is widened to `readonly (string | InlineSkill)[] | resolver`; `compileSkillsSelection`
|
|
1284
|
+
splits a mixed list into `skills.enabled` (filesystem names) + `skills.inline` (createSkill objects).
|
|
1285
|
+
So `agent().skills([mySkill]).build()` registers the skill's name + description into the `<skills>`
|
|
1286
|
+
block — the model KNOWS the skill exists without repeating it in the system prompt. Backward-compatible:
|
|
1287
|
+
a pure name list still compiles to `{ enabled, autoInject }` (no `inline` key). The run path already
|
|
1288
|
+
forwarded `compiled.skills` to `Agent.create({ skills })`; only the builder input surface changed.
|
|
1289
|
+
|
|
1290
|
+
## 0.36.0
|
|
1291
|
+
|
|
1292
|
+
### Minor Changes
|
|
1293
|
+
|
|
1294
|
+
- **`.conversationStorage(adapter)` on the agent builder — control the agent's memory.** `agent()` (and
|
|
1295
|
+
`defineAgent({ conversationStorage })`) now accept a `ConversationStorageAdapter`, so an app declares
|
|
1296
|
+
WHERE the agent's conversation turns persist right where it defines the agent:
|
|
1297
|
+
`agent().model(...).conversationStorage(store).build()`. The adapter flows through
|
|
1298
|
+
`compileAgentDefinition` → the run path → `Agent.getOrCreate({ conversationStorage })`. Precedence:
|
|
1299
|
+
a per-run override wins over the agent-level default, which wins over the SDK's lazily-chosen default
|
|
1300
|
+
(byte-identical to the previous behaviour when unset). Swap `InMemoryConversationStorage` (ephemeral)
|
|
1301
|
+
⇄ `FileSystemConversationStorage` (durable) ⇄ a custom adapter without touching the runtime.
|
|
1302
|
+
|
|
1303
|
+
## 0.35.0
|
|
1304
|
+
|
|
1305
|
+
### Minor Changes
|
|
1306
|
+
|
|
1307
|
+
- 0e01bc6: M35 — TUI terminal-only in-process surface (Model A).
|
|
1308
|
+
|
|
1309
|
+
- `theokit/server` exports `streamAgentTurnInProcess(mod, apiKey, { message, awaitApproval? })`: run an
|
|
1310
|
+
agent turn in a SINGLE process — no HTTP loopback, no port, no CSRF — reusing `compileAgentModule` +
|
|
1311
|
+
`streamAgentUIMessages` (zero runtime reimplementation, G2). HITL is resolved INLINE via a caller
|
|
1312
|
+
`awaitApproval` callback (the Claude Code / Codex single-process shape); a gated agent run without a
|
|
1313
|
+
resolver throws `InProcessApprovalRequiredError` (fail-closed — the #99 lesson). Parity with the HTTP
|
|
1314
|
+
mount is by construction: both call the same `streamAgentUIMessages`.
|
|
1315
|
+
- `@theokit/agents` now publicly exports the `HitlDecision` type — the settled approval decision an
|
|
1316
|
+
`awaitApproval` resolver may return (bare boolean OR `{ approved, reason?, payload? }`).
|
|
1317
|
+
|
|
1318
|
+
## 0.31.0
|
|
1319
|
+
|
|
1320
|
+
### Minor Changes
|
|
1321
|
+
|
|
1322
|
+
- eb1b70e: Agent capabilities batch M9–M17.
|
|
1323
|
+
|
|
1324
|
+
- **M9 Guardrails** — `defineAgent({ guardrails })`: input/output guards at the boundary (`promptInjectionDetector`, `piiDetector`, `unicodeNormalizer`, `costGuard`, `outputModeration`), input applied fail-fast, output moderated before reaching the client.
|
|
1325
|
+
- **M10 Lifecycle hooks** — `createToolHooksPlugin({ beforeToolCall, afterToolCall, beforeLLMCall, afterLLMCall })` over the SDK's native tool/LLM hooks.
|
|
1326
|
+
- **M11 Conversation scoping** — `deriveConversationId`/`parseConversationId` for collision-safe `{resource, thread}` isolation.
|
|
1327
|
+
- **M12 Delegation hooks** — `onDelegationStart`/`onDelegationComplete` on `delegate()` (+ abortSignal, docs).
|
|
1328
|
+
- **M13 Per-request skills resolver** — `defineAgent({ skills: (ctx) => string[] })` resolved against the run-context at mount.
|
|
1329
|
+
- **M14 HITL surface** — `defineAgent({ approvals })`, `GET /api/agents/:name/approvals`, `toolName` forwarded to the registry.
|
|
1330
|
+
- **M15 A2A** — `buildAgentCard` + served at `/.well-known/<name>/agent-card.json`; `createA2ATool` client with auth.
|
|
1331
|
+
- **M16 MCP** — `buildMcpToolDescriptors`/`mcpServerInfo` + served at `POST /api/agents/<name>/mcp` (JSON-RPC).
|
|
1332
|
+
- **M17 ACP** — `AcpMessageDecoder`/`encodeAcpMessage` framing, `AcpClient`, and `createACPTool` + `NodeAcpTransport` (subprocess) with a required `onPermissionRequest` gate.
|
|
1333
|
+
|
|
1334
|
+
Governance: ADR-0040 (runtime-vs-home boundary).
|
|
1335
|
+
|
|
1336
|
+
## 0.30.2
|
|
1337
|
+
|
|
1338
|
+
### Patch Changes
|
|
1339
|
+
|
|
1340
|
+
- 6a91f17: Fix (#81): `defineAgent({ tools })` now type-accepts the `@theokit/sdk` `CustomTool` that `defineAgentTool` and every `@theokit/sdk-tools` factory return (previously `CustomTool` was not assignable to the internal `CompiledTool`, so the documented tool pattern failed `tsc` even though it ran). The `tools` field is typed `readonly CustomTool[]` and normalized to `CompiledTool` at compile.
|
|
1341
|
+
|
|
1342
|
+
Fix (#80): the `create-theokit` default template now type-checks, builds, AND renders on a fresh scaffold. `app/page.tsx` was migrated to the `@theokit/ui@1.0.0` auto-dispatch chat API (`ChatMessage` takes a `UIMessage` and renders its parts; the old manual `Message`/`ToolCallCard` flatten is gone), the template ships `@types/node` + `experimentalDecorators`/`emitDecoratorMetadata` (so tool handlers and the `@Agent` class surface type-check), and a jsdom render test (`app/page.test.tsx`) guards against future `@theokit/ui` drift. A pristine scaffold now passes `tsc --noEmit` with 0 errors (was 7).
|
|
1343
|
+
|
|
1344
|
+
## 0.30.1
|
|
1345
|
+
|
|
1346
|
+
### Patch Changes
|
|
1347
|
+
|
|
1348
|
+
- 2302dcb: M6 dogfood fixes — two real V1 bugs surfaced by a live `npx create-theokit` run.
|
|
1349
|
+
|
|
1350
|
+
- **Tool calls crashed** (`TypeError: ... reading 'def'`): `buildSdkTools` re-ran `defineAgentTool`'s
|
|
1351
|
+
already-lowered JSON-Schema tool through the SDK's `defineTool` (which expects a live Zod schema).
|
|
1352
|
+
It now routes by `inputSchema` shape — Zod schema → `defineTool`; already-SDK-ready `CustomTool`
|
|
1353
|
+
(JSON-Schema `inputSchema`) → forwarded raw. Regression test + confirmed minimal repro.
|
|
1354
|
+
- **Fresh scaffold failed to start** (`ERR_PACKAGE_PATH_NOT_EXPORTED` on `@theokit/sdk/compaction`):
|
|
1355
|
+
the default template pinned `@theokit/sdk@^1.1.0`, below the `@theokit/agents@0.30.0` peer floor
|
|
1356
|
+
(`>= 2.13.0`). Bumped the template + fixture pins to `^2.13.0`.
|
|
1357
|
+
|
|
1358
|
+
## 0.30.0
|
|
1359
|
+
|
|
1360
|
+
### Minor Changes
|
|
1361
|
+
|
|
1362
|
+
- 604bca9: Cohesive agent harness (M4, Eixo C) — make the shipped-but-dead `@HumanInTheLoop` + `@Checkpoint`
|
|
1363
|
+
decorators functional as an adapter over `@theokit/sdk`, with no parallel runtime (ADR 0038).
|
|
1364
|
+
|
|
1365
|
+
- **`@HumanInTheLoop`** now pauses the run before a gated tool: the stream emits the ai-sdk-native
|
|
1366
|
+
`tool-approval-request` chunk and the run stays paused (the SDK's own awaited `pre_tool_call`
|
|
1367
|
+
hook) until `POST /api/agents/<name>/approve/<approvalId>` resolves it — approve runs the tool,
|
|
1368
|
+
deny/timeout surfaces the denial and the run continues.
|
|
1369
|
+
- **`@Checkpoint({ storage: 'filesystem' })`** emits a transient `data-checkpoint` part and selects
|
|
1370
|
+
the SDK's durable `FileSystemConversationStorage`, so a same-session follow-up request resumes.
|
|
1371
|
+
- The M2 file convention gathers a class agent's `@Mixin` toolboxes so a gated tool actually gates
|
|
1372
|
+
through the endpoint. `@theokit/agents` adds `createHitlPlugin`; `theokit` adds the approve route
|
|
1373
|
+
- in-process approval registry. Additive — the M2 surface is unchanged.
|
|
1374
|
+
|
|
1375
|
+
## 0.29.0
|
|
1376
|
+
|
|
1377
|
+
### Minor Changes
|
|
1378
|
+
|
|
1379
|
+
- a1182ae: Ship an agent by writing one file — the zero-config `agents/<name>.ts` convention (theokit-ai-first M2, Eixo B).
|
|
1380
|
+
|
|
1381
|
+
Create a top-level `agents/support.ts` that default-exports `defineAgent({ input, model, system, tools })` and TheoKit auto-serves `POST /api/agents/support` at both `theokit dev` and the built server — streaming the M0/M1 canonical `UIMessageStream`. On the client, `import { useAgent } from '@theo/agents'` gives a typed React hook: `useAgent('support').send(input)` where `input` is inferred end-to-end from the agent's Zod schema via the generated `.theokit/agents.d.ts` — zero manual type wiring. The hook reconstructs the streamed assistant messages with the `ai` package's own `readUIMessageStream` (the exact reader `@ai-sdk/react`'s `useChat` runs — no reinvented parser); `theokit/client` also exports the pure `consumeUIMessageStream` and the base `useAgent(path)`.
|
|
1382
|
+
|
|
1383
|
+
`@theokit/agents` gains `defineAgent` — the canonical zero-config surface (ADR 0037) — a pure normalizer to the same SDK-ready shape the `@Agent` class decorator produces, so both surfaces converge on one runtime (`@theokit/sdk` stays the sole agent runtime). New exports: `defineAgent`, `compileAgentModule`, `streamAgentUIMessages`, `AgentDefinitionError`, `InferAgentInput`.
|
|
1384
|
+
|
|
1385
|
+
The build scans a top-level `agents/` directory and records each agent in the manifest; dev and prod mount through a single shared `mountAgent` point so they never drift. The request body accepts both the `useChat` shape (`{ messages }`) and a simple `{ message }`. Agent endpoints enforce CSRF (the `X-Theo-Action` header + Origin match, strict by default) at the same mode as routes/actions — a cross-origin POST that would spend LLM tokens is rejected with 403 before it reaches the SDK. A non-agent file or an unknown route fails fast with a typed error. `/api/agents/` is a reserved prefix (a manual route there is shadowed by design, like `/api/__actions/`).
|
|
1386
|
+
|
|
1387
|
+
Agents live in a top-level `agents/` (sibling of `server/`) per the LOCKED naming decision (ADR 0037). Non-breaking: additive API on both packages; the existing route/action/ws scanners still ignore `agents/`.
|
|
1388
|
+
|
|
1389
|
+
## 0.28.0
|
|
1390
|
+
|
|
1391
|
+
### Minor Changes
|
|
1392
|
+
|
|
1393
|
+
- 2ddfab9: A theokit agent's tool calls and reasoning now render in `@ai-sdk/react`'s `useChat` — a tool-call card (name + input + result) and a reasoning block, not just text (theokit-ai-first M1).
|
|
1394
|
+
|
|
1395
|
+
`translateToUIMessageStream` widens the M0 text-only mapping to emit ai-sdk tool chunks (`tool-input-available` → `tool-output-available` / `tool-output-error`) and reasoning chunks (`reasoning-start` → `reasoning-delta*` → `reasoning-end`) via an open-block state machine that closes the current text/reasoning block before switching kind. Runtime-discovered tools carry `dynamic: true`, so the ai-sdk consumer materializes a `dynamic-tool` part whose tool name survives to the rendered part; a tool result that arrives without a preceding tool call synthesizes the tool-input part first, so the consumer never throws. `UIMessageStream` stays the canonical wire (AG-UI rejected — ADR 0036). Backward-compatible: M0 text/error runs are byte-unchanged; the translator signature and barrel exports are unchanged.
|
|
1396
|
+
|
|
1397
|
+
## 0.27.0
|
|
1398
|
+
|
|
1399
|
+
### Minor Changes
|
|
1400
|
+
|
|
1401
|
+
- 8842bc6: Surface the SDK's `partial-tool-call` update as a typed `PartialToolCallEvent` (`type: 'partial_tool_call'`) on the `AgentStreamEvent` stream, so consumers can render tool arguments progressively as the model generates them (closes theokit-sdk#70).
|
|
1402
|
+
|
|
1403
|
+
Previously `translateInteractionUpdate` dropped `partial-tool-call`, forcing downstream apps to wait for the complete `tool_call` (args committed) — visible "dead air" for large Write/Edit tool bodies. The new event is emitted at a **distinct** lifecycle point (arg-streaming) and never duplicates `tool_call`: the same `callId` correlates the partials to the later committed `tool_call` and `tool_result`. Adds `isPartialToolCall` type-guard. Non-breaking union growth — existing consumers ignore the new variant.
|
|
1404
|
+
|
|
1405
|
+
- 403fdd7: A theokit agent's text stream now speaks the Vercel AI SDK `UIMessageStream` protocol, so `@ai-sdk/react`'s `useChat` renders it with no custom adapter (theokit-ai-first M0 walking skeleton).
|
|
1406
|
+
|
|
1407
|
+
`@theokit/agents` adds `translateToUIMessageStream(events, { textId })` — a pure mapping of the agent text stream to ai-sdk `UIMessageChunk`s (`start → text-start → text-delta* → text-end → finish`), surfacing an upstream stream error as an ai-sdk `error` chunk before a graceful `finish` (never swallowed, never thrown past the boundary). `theokit/server/define` adds `uiMessageStreamResponse(chunks)`, which serializes them to an SSE `Response` on the exact wire `useChat` parses (`x-vercel-ai-ui-message-stream: v1` header + `data: [DONE]` terminal). `ai` is an optional `peerDependency` (with a devDependency for local build/tests) — zero runtime weight on the agent path; `@theokit/sdk` stays the sole runtime. Additive and backward-compatible: the existing `AgentEvent` SSE path is untouched (its removal is the M3 clean break).
|
|
1408
|
+
|
|
1409
|
+
## 0.26.0
|
|
1410
|
+
|
|
1411
|
+
### Minor Changes
|
|
1412
|
+
|
|
1413
|
+
- c85145d: Add opt-in `recoverLeakedToolCalls` knob (`@Agent({ recoverLeakedToolCalls })` + per-run `AgentRunner.stream({ recoverLeakedToolCalls })`, default off). It is the execution sibling of `stripToolDialect` (theocode#32): where `stripToolDialect` only HIDES a leaked Hermes `<function=…></tool_call>` dialect from the visible text, `recoverLeakedToolCalls` makes the leaked call actually EXECUTE. When enabled, the adapter clones the per-run `providers.routes` with the SDK's `extractToolCallsFromContent` flag, so a `chat_completions` finish with ZERO native `tool_calls` has its assistant text scanned for the dialect and any recovered calls are dispatched by the loop — for models (qwen3-coder via OpenRouter) that intermittently leak tool calls as text (theokit#58 follow-up). Has effect only when a provider is routed via `providers.routes`; fail-open and default-off, so a non-leaking route is unaffected. Requires `@theokit/sdk >=2.13.0` (the per-route flag); the peer floor is bumped accordingly.
|
|
1414
|
+
|
|
1415
|
+
## 0.25.1
|
|
1416
|
+
|
|
1417
|
+
### Patch Changes
|
|
1418
|
+
|
|
1419
|
+
- 77672ab: Fix `tool_call` StreamEvent surfacing an empty `input` (`{}`), which blanked consumer tool cards (theokit#58).
|
|
1420
|
+
|
|
1421
|
+
`event-translator.ts`'s `translateToolCallEvent` read the running tool message's args from `msg.input ?? msg.arguments`, but the real `@theokit/sdk` `SDKToolUseMessage` field is `args` (`run-D22b53SU.d.ts:486`) — both read fields were `undefined`, so `input` fell back to `{}` and the UI tool card showed no command (e.g. a blank `SHELL_EXEC`), even though the tool executed correctly. Confirmed empirically (live Node 24 + OpenRouter: `msg.args={"command":…}`, `input`/`arguments` undefined) and by the SDK type.
|
|
1422
|
+
|
|
1423
|
+
The fix reads `msg.args` first — `input: msg.args ?? msg.input ?? msg.arguments ?? {}` — keeping the legacy fields as defensive cross-shape fallbacks. No new dependency, no dedup change, no behavior change for the `tool-call-started` onDelta path (already reads the correct field). Covered by 3 unit tests + 2 integration tests.
|
|
1424
|
+
|
|
1425
|
+
## 0.25.0
|
|
1426
|
+
|
|
1427
|
+
### Minor Changes
|
|
1428
|
+
|
|
1429
|
+
- Strip a leaked tool-call dialect out of the visible answer (theocode#32). When a model emits its Hermes `<function=NAME>…</function></tool_call>` XML as assistant TEXT instead of a native `tool_calls` (observed live with `qwen/qwen3-coder`), the raw XML used to render verbatim as the reply. A new opt-in `stripToolDialect` knob (`@Agent({ stripToolDialect: true })` or per-run `AgentRunner.run(msg, { stripToolDialect: true })`, per-run wins) wraps the agent's text stream with a streaming stripper that removes the leaked `<function=…></tool_call>` block from `text_delta`. It is chunk-straddle-safe (both the `<function=` open and the `</tool_call>` close split across stream deltas are recognized) and lossless on a truncated leak (an unclosed `<function=` at stream end is flushed back as text, never silently dropped). The leak is STRIPPED, never parsed back into a tool call — parsing a provider-broken channel would re-introduce the no-progress spin closed in #53. Off by default (zero behavior change for existing agents — a code assistant may legitimately emit a literal `<function=` in answer/code text). Sibling of `parseThinkTags`. New exports: `createToolDialectStripper`, `stripToolDialectStream`.
|
|
1430
|
+
|
|
1431
|
+
## 0.24.1
|
|
1432
|
+
|
|
1433
|
+
### Patch Changes
|
|
1434
|
+
|
|
1435
|
+
- 3c2bf61: Fix the reflective loop's `no_progress` detector being defeated by narration drift (theokit#53). `roundSignature` folded the assistant's text into the per-round fingerprint, so a model that re-ran identical tool calls while rephrasing its prose ("…e executá-lo." → "Agora vou executar…") produced a different signature each round and evaded `NO_PROGRESS_THRESHOLD` — the loop spun (observed live: deepseek-v3.2, 7 rounds / 12 tool-calls re-doing the same `write_file`+`shell_exec`). The signature now keys on the tool-call set ONLY (name + canonicalized input), excluding narration — mirroring opencode's `doom_loop`. Repeated identical tool calls now terminate `no_progress` within 2 rounds regardless of what the model says around them; genuinely varying tool inputs still count as progress.
|
|
1436
|
+
|
|
1437
|
+
## 0.24.0
|
|
1438
|
+
|
|
1439
|
+
### Minor Changes
|
|
1440
|
+
|
|
1441
|
+
- 6830737: Step-cap force-close: the reflective loop now gates tools OFF on the ceiling round (`round === maxIterations`), forcing the model to emit the closing summary the existing `STEP_LIMIT_HINT` requests instead of spinning on more tool calls. The round factory is called with `disableTools: true`, which the SDK adapter maps to `agent.send(msg, { toolChoice: "none" })` — applied per-send because a cached `getOrCreate` agent's tools cannot be un-registered. Below the ceiling, tools stay enabled; injected stream factories (tests / custom transport) ignore the optional flag (backward-compatible). Mirrors opencode's `MAX_STEPS_PROMPT` + `toolChoice:"none"`. The `@theokit/sdk` peer dependency is tightened to `>=2.11.2` (first release with `SendOptions.toolChoice`) so the force-close cannot silently no-op against an older SDK that ignores `tool_choice`.
|
|
1442
|
+
|
|
1443
|
+
## 0.23.0
|
|
1444
|
+
|
|
1445
|
+
### Minor Changes
|
|
1446
|
+
|
|
1447
|
+
- a4f668f: Add an opt-in `<think>`-tag reasoning middleware (M2). When `parseThinkTags` is set — declaratively via `@Agent({ parseThinkTags: true })` or per-run via `AgentRunner.run(msg, { parseThinkTags: true })` (per-run wins over compiled) — the agent's text stream is wrapped with a streaming extractor that converts inline `<think>…</think>` into `thinking` StreamEvents, so models that emit reasoning as inline tags (qwen/deepseek-class) surface it the same way native-reasoning providers do (M1's `reasoningEffort`). The extractor is chunk-straddle-safe, preserves interleaved order, flushes a truncated `<think>` at stream end, and treats a non-tag prefix like `<thinkers>` as text. Off by default — zero behavior change for existing agents. New exports: `createThinkTagExtractor`, `extractThinkTagStream`, `Segment`.
|
|
1448
|
+
|
|
1449
|
+
## 0.22.0
|
|
1450
|
+
|
|
1451
|
+
### Minor Changes
|
|
1452
|
+
|
|
1453
|
+
- 9c04863: Add a provider-agnostic `reasoningEffort` knob to enable extended thinking (M1). Set it declaratively via `@Agent({ reasoningEffort })` or per-run via `AgentRunner.run(msg, { reasoningEffort })` (per-run wins over compiled); it maps to the SDK `ModelSelection.params` reasoning slot (`{ id: 'thinking', value: effort }`) at the single `getOrCreate` site, so the provider emits the `thinking` StreamEvents the bridge already forwards. Accepts the common levels (`'minimal' | 'low' | 'medium' | 'high' | 'xhigh'`) plus any provider-specific string. Backward-compatible — with no effort set, the model is sent as a bare `{ id }` (byte-identical to before) and there is no static capability gate (the SDK validates against the model's catalog). New exports: `ReasoningEffort` type and `buildModelSelection` helper.
|
|
1454
|
+
|
|
1455
|
+
## 0.21.2
|
|
1456
|
+
|
|
1457
|
+
### Patch Changes
|
|
1458
|
+
|
|
1459
|
+
- 919e138: Fix chronological event ordering in `AgentRunner.stream()` (#44). Tool and thinking events now stream through the SDK's real-time `onDelta` callback in true arrival order, interleaved with text — instead of all text first, then all tool cards (a regression from the 0.21.1 streaming work, where tool events were pulled from the post-completion `run.stream()` buffer). The merge queue is consumed concurrently with `send()` for real-time delivery, with per-category/per-callId dedup so the `run.stream()` fallback (for providers that don't drive `onDelta`) never double-emits and never drops a tool result reported only via the stream (e.g. a tool error). No public API change.
|
|
1460
|
+
|
|
1461
|
+
## 0.21.1
|
|
1462
|
+
|
|
1463
|
+
### Patch Changes
|
|
1464
|
+
|
|
1465
|
+
- 2c6e03f: fix(agents): stream incremental tokens, populate tool output, emit running tool_call
|
|
1466
|
+
|
|
1467
|
+
The SDK↔agents bridge (`createSdkAgentStream` + `translateToolCallEvent`) now forwards
|
|
1468
|
+
the streaming + tool data the SDK already produces, fixing three SSE-DX defects:
|
|
1469
|
+
|
|
1470
|
+
- **#40 — token streaming.** `createSdkAgentStream` now passes `SendOptions.onDelta` to
|
|
1471
|
+
`agent.send` and merges the incremental `text_delta` tokens into the event stream
|
|
1472
|
+
(`mergeDeltaStream`), deduping the complete-assistant text (`sawDelta`) so it is not
|
|
1473
|
+
double-emitted. A provider that never calls `onDelta` falls back to the complete-assistant
|
|
1474
|
+
text (no loss). Previously the whole round was emitted at once at turn end.
|
|
1475
|
+
- **#41 — tool output.** `translateToolCallEvent` now serializes a non-string tool `result`
|
|
1476
|
+
(`serializeToolOutput` → JSON, BigInt-safe) instead of dropping it via `asString(...,'')`,
|
|
1477
|
+
so object tool results (`{ ok, files }`) reach consumers instead of `''`.
|
|
1478
|
+
- **#42 — running tool_call.** The `running` tool status now emits a `tool_call` StreamEvent
|
|
1479
|
+
(callId + toolName + input) so UIs can show a running card with args, instead of only the
|
|
1480
|
+
terminal `tool_result`.
|
|
1481
|
+
|
|
1482
|
+
Bridge-only; no SDK change, no runtime re-implementation (sdk-runtime.md/G2).
|
|
1483
|
+
|
|
1484
|
+
## 0.21.0
|
|
1485
|
+
|
|
1486
|
+
### Minor Changes
|
|
1487
|
+
|
|
1488
|
+
- 20338f5: `AgentRunnerRunOptions.plugins` now also accepts a `readonly Plugin[]` (an array of code Plugin objects), not only `PluginsSettings` ({ enabled }). Mirrors the @theokit/sdk `AgentOptions.plugins` widen — the runtime already forwards plugin arrays. Lets consumers pass `plugins: [permissionPlugin, cachePlugin]` without an `as unknown as` cast.
|
|
1489
|
+
|
|
1490
|
+
## 0.20.0
|
|
1491
|
+
|
|
1492
|
+
### Minor Changes
|
|
1493
|
+
|
|
1494
|
+
- 45f229a: V4-T: `delegate()` carries the same per-run config surface as `AgentRunner.stream()`.
|
|
1495
|
+
|
|
1496
|
+
`DelegateOptions` gains optional `model`/`cwd`/`plugins`/`providers`/`agents`/`budgetTracker`/`conversationStorage`/`sdkTools`/`retry`/`reflection`/`maxIterations`, and `delegate()` forwards them to `createSdkAgentStream` (the model opt wins over the sub-agent's `@Agent` model) + the reflective loop (retry; custom reflection overriding the strategy-derived ladder/noop; `maxIterations` re-resolves the loop ceiling). The two on-ramps to the shared `runReflectiveLoop` driver now expose the same per-run surface, so a sub-agent inherits the parent's runtime config (providers, mode-selected permission plugin, working dir, pre-built SDK tools). Additive + backward-compatible: absent fields ⇒ byte-identical to before (decorator model only; strategy-derived reflection; no retry). The fields were already accepted by the adapter's `RuntimeOverrides` + the loop's `RunReflectiveLoopConfig` — pure forwarding, no new dependency (Rule 9). Unblocks an app delegating to a sub-agent without losing per-run config.
|
|
1497
|
+
|
|
1498
|
+
## 0.19.0
|
|
1499
|
+
|
|
1500
|
+
### Minor Changes
|
|
1501
|
+
|
|
1502
|
+
- 01e9ea8: V4-S: `plan-act-reflect` defers the continuation decision to the `ReflectionStrategy`.
|
|
1503
|
+
|
|
1504
|
+
`resolveLoopStrategy('plan-act-reflect')`'s `shouldContinue` is now `round < maxIterations` (instead of the `finishReason === 'tool-calls'` gate). The reflective loop ANDs `reflection.continue` with `shouldContinue`, so this lets a custom `ReflectionStrategy` extend even a terminal (`stop`) round — e.g. "you answered without editing any file; make the edit now" — within the iteration ceiling. Backward-compatible with the shipped `ladderReflectionStrategy` (which itself returns `continue: true` only on `tool-calls`, so the observable behavior with the default ladder is unchanged). `react` is unchanged (the `noop` reflection means the strategy stays the gate: continue only on `tool-calls`). Closes the last seam for an app whose reflection ladder fires on final-answer rounds (theocode's `reflect_no_edit`/`verify`/`fix`).
|
|
1505
|
+
|
|
1506
|
+
## 0.18.0
|
|
1507
|
+
|
|
1508
|
+
### Minor Changes
|
|
1509
|
+
|
|
1510
|
+
- 6d02c56: V4-R: `AgentRunner` accepts an injectable `RoundStreamFactory` via `run-options.streamFactory`.
|
|
1511
|
+
|
|
1512
|
+
`AgentRunnerRunOptions.streamFactory?: RoundStreamFactory` drives the reflective loop with a caller-provided per-round stream INSTEAD of `createSdkAgentStream` (for tests or a custom transport). When set, the SDK-create options (`tools`/`sdkTools`/`model`/`cwd`/...) are not used for that call — the consumer owns the stream. Absent ⇒ the SDK adapter (the default runtime), byte-identical to before. `RoundStreamFactory` (`(message, sessionId) => AsyncIterable<StreamEvent>`) is now exported from the package barrel so consumers can type their factory (the loop DRIVER `runReflectiveLoop` stays internal). Lets an app adopt `AgentRunner.stream()` while keeping its existing stream-injection tests — closes the last adoption seam the theocode discover found. Additive + backward-compatible; no new dependency.
|
|
1513
|
+
|
|
1514
|
+
## 0.17.0
|
|
1515
|
+
|
|
1516
|
+
### Minor Changes
|
|
1517
|
+
|
|
1518
|
+
- 6ec6124: V4-Q: `AgentRunner` accepts pre-built SDK `CustomTool[]` via `run-options.sdkTools`.
|
|
1519
|
+
|
|
1520
|
+
`AgentRunnerRunOptions.sdkTools?: readonly CustomTool[]` (and `RuntimeOverrides.sdkTools`) forwards already-built SDK tools RAW to `Agent.create.tools`, appended after the `@Tool`-compiled tools, bypassing `defineTool` (which requires a Zod schema). Lets an app whose tools come from imperative SDK factories (`@theokit/sdk-tools` → `CustomTool[]`, JSON-Schema `inputSchema`, no recoverable Zod) adopt `AgentRunner.stream()` — closes the last tool-sourcing gap the theocode loop-adoption discover found. Additive + backward-compatible: absent ⇒ the compiled-tools path is byte-identical; distinct from `tools` (which REPLACES the compiled set). No new dependency (Rule 9).
|
|
1521
|
+
|
|
1522
|
+
## 0.16.0
|
|
1523
|
+
|
|
1524
|
+
### Minor Changes
|
|
1525
|
+
|
|
1526
|
+
- 208ea7f: V4-P: per-round transient retry in the reflective loop.
|
|
1527
|
+
|
|
1528
|
+
`AgentRunnerRunOptions.retry?: RetryOptions` (and `RunReflectiveLoopConfig.retry`) opt into retrying a transient failure at a round START — the factory creation + first event, before any event is yielded, so a recovered 429/5xx/network blip never re-applies an edit. Reuses the SDK `withRetry` (`@theokit/sdk/retry`, default `isRetryable: isTransientError`), dynamic-imported only when `retry` is set so the loop stays SDK-optional. Once an event is yielded, a throw propagates (exactly-one-terminal + no double-edit preserved). Absent ⇒ single attempt (backward-compatible). Lets a consumer (theocode) keep its per-continuation-round retry safety when it adopts `AgentRunner.stream()`. No new dependency (Rule 9).
|
|
1529
|
+
|
|
1530
|
+
## 0.15.0
|
|
1531
|
+
|
|
1532
|
+
### Minor Changes
|
|
1533
|
+
|
|
1534
|
+
- d69f7b4: V4-O: forward the SDK reasoning/cache token buckets through the adapter `done` event and `DelegationResult`.
|
|
1535
|
+
|
|
1536
|
+
`realUsageDone` (`createSdkAgentStream`) now reads `reasoningTokens`/`cacheReadTokens`/`cacheWriteTokens` from `RunResult.usage` and includes them on the `done` event (0 when the provider omits them); the reflective loop folds them per round and accumulates them into `DelegationResult` (alongside the V4-N split usage). The typed `DoneEvent.usage` declares the three optional buckets. Additive + backward-compatible: existing fields unchanged, the new fields are optional, absent buckets default to 0. Lets a consumer (theocode's `LlmUsage`) keep full per-turn usage when it adopts `AgentRunner.stream()` — closes the usage-richness regression the loop-adoption discover found. Reuses the `RunResult.usage` already read by `run.wait()` (Rule 9); no new dependency.
|
|
1537
|
+
|
|
1538
|
+
## 0.14.0
|
|
1539
|
+
|
|
1540
|
+
### Minor Changes
|
|
1541
|
+
|
|
1542
|
+
- 6f1a757: V4-N: the reflective loop now exposes faithful per-round tool calls + split token usage, so a custom `ReflectionStrategy` (and `DelegationResult` consumers) can read the tool-call command, correlate by id, and map split usage.
|
|
1543
|
+
|
|
1544
|
+
- `LoopOutcome.toolCalls` / `DelegationResult.toolCalls` entries now carry `{ id, name, input, output }` — `input` is the tool-call args (correlated from the `tool_call` event by callId), no longer always `{}`, and `id` is the call id.
|
|
1545
|
+
- `DelegationResult` now carries `tokensInput` / `tokensOutput` (accumulated across rounds); `tokens` (total) is preserved.
|
|
1546
|
+
|
|
1547
|
+
Additive + backward-compatible (existing fields unchanged; new fields are optional on `DelegationResult`). `consumeOneRound` correlates each round's `tool_call` events (which carry the input/command) with their `tool_result` events (which carry the output) by callId; an unmatched result degrades to `input: {}` (no worse than before). The tool-call id+input half flows on the real SDK path. NOTE: the split-usage half is plumbing — the SDK adapter must emit real per-turn token counts on the `done` event for `tokensInput`/`tokensOutput` to be non-zero (today it emits zeros, unchanged from before; a follow-up). Unblocks a consumer's verify-before-finish / fix-failed-test ladder + tool persistence that need the command and the id.
|
|
1548
|
+
|
|
1549
|
+
### Patch Changes
|
|
1550
|
+
|
|
1551
|
+
- a4e1c25: V4-N.1: `createSdkAgentStream` now emits the SDK Run's REAL token usage on the `done` event.
|
|
1552
|
+
|
|
1553
|
+
It reads `run.wait()` after the stream and emits one `done` carrying the real `TokenUsage` (`inputTokens`/`outputTokens`/derived `totalTokens`) + `cost`, suppressing the stream's zero-usage `done`. This completes V4-N's split-usage story end-to-end: `DelegationResult.tokens`/`tokensInput`/`tokensOutput` now report real values on the real SDK path (previously hardcoded to 0). An error round skips the `wait()` re-emit (exactly-one-terminal); a `wait()` rejection surfaces as an `error` (fail-loud). Additive; reuses the SDK's documented `run.wait()` (Rule 9); no new dependency.
|
|
1554
|
+
|
|
1555
|
+
## 0.13.0
|
|
1556
|
+
|
|
1557
|
+
### Minor Changes
|
|
1558
|
+
|
|
1559
|
+
- 8811577: V4-M: `AgentRunner.stream()` reflective-loop rounds now share a persisted SDK session, so round N+1 sees what rounds 1..N read and did.
|
|
1560
|
+
|
|
1561
|
+
- Each round resumes the same session via `Agent.getOrCreate(sessionId, { conversationStorage })` with ONE shared `conversationStorage` created per run (default `InMemoryConversationStorage` — per-run, no disk), survivable across the per-round agent dispose.
|
|
1562
|
+
- Rounds 2+ no longer re-send the original task — the persisted session carries it; the round-2+ prompt is the reflection block (or a short continuation). Round 1 sends the original message unchanged.
|
|
1563
|
+
- New `AgentRunnerRunOptions.conversationStorage` (and `RuntimeOverrides.conversationStorage`) lets an app plug a `FileSystemConversationStorage`/custom adapter for durable cross-run history.
|
|
1564
|
+
|
|
1565
|
+
**Behavior change (fix):** previously each round created a fresh, memoryless agent (history was NOT carried across rounds) — a multi-round reflective loop whose rounds could not see prior tool results. Rounds are now stateful by default. This reuses the SDK's own session-persistence primitives (Rule 9); no new dependency. It unblocks consumers (e.g. a code agent) adopting `AgentRunner.stream()` for continuation loops. The `delegate()` sub-agent path shares the same loop driver, so sub-agent delegation rounds gain session memory too.
|
|
1566
|
+
|
|
1567
|
+
## 0.12.0
|
|
1568
|
+
|
|
1569
|
+
### Minor Changes
|
|
1570
|
+
|
|
1571
|
+
- 47dd837: V4-L.3: `AgentRunner.stream()/run()` complete the per-request `Agent.create` surface with four more `AgentRunnerRunOptions` fields (Axis-A / SWAP), each forwarded to the SDK when present — parallel to the existing `tools`/`model`/`cwd`/`maxIterations`.
|
|
1572
|
+
|
|
1573
|
+
- **`plugins`** (`PluginsSettings`) — per-request plugins (e.g. a permission gate selected by request mode).
|
|
1574
|
+
- **`providers`** (`ProviderRoutingSettings`) — per-request provider routing.
|
|
1575
|
+
- **`agents`** (`Record<string, AgentDefinition>`) — per-request sub-agent definitions (opts-only; `@SubAgents` compiled agents stay deferred).
|
|
1576
|
+
- **`budgetTracker`** (`BudgetTracker`) — per-request SDK budget tracker capping the INNER tool-loop per send (distinct from the OUTER reflective-loop USD `budget`).
|
|
1577
|
+
|
|
1578
|
+
Internals: `createSdkAgentStream`'s per-request parameters are collapsed into a single `RuntimeOverrides` object (subsuming the prior `envModel`/`cwd` positionals) to avoid a parameter explosion; the model now resolves at a single site (`overrides.model ?? compiled.model ?? default`). Backward-compatible (absent fields ⇒ no `Agent.create` key; the 3-arg `createSdkAgentStream` call still compiles); no new dependency. With this slice the full per-request surface theocode needs is expressible through `AgentRunner`.
|
|
1579
|
+
|
|
1580
|
+
## 0.11.0
|
|
1581
|
+
|
|
1582
|
+
### Minor Changes
|
|
1583
|
+
|
|
1584
|
+
- b1c6a71: V4-L.2: `AgentRunner.stream()/run()` accept three per-request overrides on `AgentRunnerRunOptions` (Axis-A / SWAP), each merge-over-compiled, parallel to the V4-J `tools` override.
|
|
1585
|
+
|
|
1586
|
+
- **`model`** — overrides the compiled model for this call (`opts.model ?? compiled.model ?? default`).
|
|
1587
|
+
- **`cwd`** — forwarded into `Agent.create({ local: { cwd } })`, so the SDK populates `SystemPromptContext.cwd` (read by a V4-L.1 `SystemPromptResolver` / `@ProjectContext`). Absent ⇒ no `local.cwd`.
|
|
1588
|
+
- **`maxIterations`** — overrides the reflective-loop ceiling for this call by re-resolving the loop strategy (zod-validated — `< 1` throws, never a silent unbounded loop); the build-time strategy is not mutated. Terminal `step_limit` when the override stops a would-continue round.
|
|
1589
|
+
|
|
1590
|
+
All three are backward-compatible (absent ⇒ build-time defaults); a `{ apiKey }`-only call and existing `tools` overrides behave exactly as before. No new dependency.
|
|
1591
|
+
|
|
1592
|
+
## 0.10.0
|
|
1593
|
+
|
|
1594
|
+
### Minor Changes
|
|
1595
|
+
|
|
1596
|
+
- 13a4abc: V4-L.1: `@Agent`'s `systemPrompt` now accepts a per-request `SystemPromptResolver`, not just a static string.
|
|
1597
|
+
|
|
1598
|
+
- `@Agent({ systemPrompt: (ctx) => ... })` declares a prompt COMPUTED per request (from project rules, memory, cwd, etc.); the SDK invokes the resolver each send with the run's `SystemPromptContext`. A plain string still works unchanged (backward-compatible union widening — `string | SystemPromptResolver`).
|
|
1599
|
+
- The resolver flows byref through the compile boundary (`compileAgent` → `CompiledAgentOptions.systemPrompt`) into `Agent.create` — no translation, no new dependency (the type is the SDK's own `SystemPromptResolver`).
|
|
1600
|
+
- `@ProjectContext` now COMPOSES with a resolver base: env + repo map + project instructions are prepended to the resolved base output (resolve-then-prepend); a failing base resolver propagates (fail-loud). Previously `base` was `string`-only.
|
|
1601
|
+
- This is Axis-B (computed-per-request config) of the dynamic-`@Agent` design and closes the long-standing M8 edge case where the decorator could only carry a static prompt. Sub-agent resolver execution remains out of scope (the type is carried, not invoked).
|
|
1602
|
+
|
|
1603
|
+
## 0.9.0
|
|
1604
|
+
|
|
1605
|
+
### Minor Changes
|
|
1606
|
+
|
|
1607
|
+
- 079f725: V4-J + V4-K: two backward-compatible `AgentRunner` hooks that unblock loop adoption by apps with per-request tools and stateful reflection.
|
|
1608
|
+
|
|
1609
|
+
- **V4-J — runtime tool override:** `AgentRunner.stream(message, opts)` / `run(...)` accept `opts.tools?: readonly CompiledTool[]` that replaces the build-time `compiled.tools` for that call only (a consumer selecting tools by request mode/permission). Absent ⇒ the agent's compiled tools (unchanged). Decorators and the compile path are untouched.
|
|
1610
|
+
- **V4-K — ReflectionContext:** `ReflectionStrategy.reflect(outcome, ctx?)` now receives a per-run mutable `ReflectionContext` (a generic scratch bag). The reflective loop creates ONE per run and passes the SAME reference to every round, so a stateful custom strategy can accumulate cumulative state (counters, one-shot flags). The framework writes nothing app-specific into it (the strategy owns the contents). `ctx` is optional — shipped `ladderReflectionStrategy`/`noopReflectionStrategy` and existing custom strategies are unaffected.
|
|
1611
|
+
|
|
1612
|
+
## 0.8.0
|
|
1613
|
+
|
|
1614
|
+
### Minor Changes
|
|
1615
|
+
|
|
1616
|
+
- 0620275: V4-D-stream: the reflective `@MainLoop` runtime now streams events live. `AgentRunner` gains a `stream(message, opts)` method that yields each round's events incrementally (the on-ramp for SSE-first apps) while still returning the aggregated result. `run()` is unchanged for callers — it drains the stream internally. Fully backward-compatible: the collect-mode `delegate()` path is untouched.
|
|
1617
|
+
- 0620275: V4-F: a named, callable `TranscriptCompactionStrategy` authoring layer. `@Compaction('token-budget', { keepTokens })` (and `AgentRunner.builder(...).compaction(...)`) resolve a strategy exposed as `runner.compaction`, which the app calls directly — `runner.compaction?.compact(messages, { summarize })`. The `'token-budget'` strategy delegates to the SDK's `compactTranscript` (no reimplementation — the SDK owns the algorithm); the app keeps when-to-compact and the summarize callback. Compaction is opt-in (`runner.compaction` is `undefined` when undeclared); the builder override wins over the decorator. Requires `@theokit/sdk >= 2.9.0` (the `keepTokens` token-budget mode).
|
|
1618
|
+
|
|
1619
|
+
## 0.7.0
|
|
1620
|
+
|
|
1621
|
+
### Minor Changes
|
|
1622
|
+
|
|
1623
|
+
- V4-D — `@MainLoop` react/plan-act-reflect loops gain two outer-loop terminals on `LoopStrategy`, surfaced on `DelegationResult.finishReason`: `no_progress` (the loop ends when the agent repeats the same round signature — sorted, key-canonical tool-call set + text — for 2 consecutive rounds, so a stuck agent no longer drains the whole `maxIterations` budget) and `step_limit` (the loop reports when it stopped at the `maxIterations` ceiling, distinct from a natural `stop`, and injects a graceful "summarize, no more tools" prompt hint on the final round — modeled on opencode's `MAX_STEPS_PROMPT`). Both fire on both on-ramps (`delegate()` + `AgentRunner`) via the shared `runReflectiveLoop`; no new dependency, no `@theokit/sdk` change. Derived from the codex/opencode agent-loop study — neither implements no-progress, so it is a theokit value-add.
|
|
1624
|
+
|
|
1625
|
+
## 0.6.0
|
|
1626
|
+
|
|
1627
|
+
### Minor Changes
|
|
1628
|
+
|
|
1629
|
+
- d9012b4: V4-B/V4-C — `@MainLoop({ strategy })` gets a real multi-round reflective runtime (was metadata-only). A Zod-validated `LoopStrategy`/`ReflectionStrategy` contract + a shared `runReflectiveLoop` driver give the strategy field execution: `simple-chat` ⇒ one round (unchanged); `react`/`plan-act-reflect` ⇒ multi-round bounded by `maxIterations` (forced terminal at the ceiling), with a degenerate/empty round terminating as `stop`. Both on-ramps — `delegate()` (decorator) and `AgentRunner.builder()` (imperative twin) — route through the same driver, so the runtime metric, cumulative budget, typed errors and result shape are identical (ADR D4). The loop lives in the bridge while the model call stays in the SDK `Run.stream()` (no second runtime, ADR 0031). Modeled on Mastra's `agentic-loop`/`stopWhen` + `maxSteps` ceiling.
|
|
1630
|
+
|
|
1631
|
+
Also fixes the `event-translator` against the real `@theokit/sdk` `SDKMessage` union: assistant content is read from `msg.message.content`, the cloud-run status enum is matched UPPERCASE (`FINISHED`/`CANCELLED` → done, `ERROR`/`EXPIRED` → error — fail-loud), `tool_call` uses `call_id`, and `thinking` reads `msg.text`. Previously a live SDK run returned an empty response and silently swallowed `ERROR`. The adapter's fallback `done` is now conditional so a translated `FINISHED` does not double-emit the terminal.
|
|
1632
|
+
|
|
1633
|
+
## 0.5.0
|
|
1634
|
+
|
|
1635
|
+
### Minor Changes
|
|
1636
|
+
|
|
1637
|
+
- fa1518b: M8 — declarative decorators get SDK-backed runtime. `@Skills`, `@ContextWindow`, and `@ProjectContext` are no longer metadata-only: the bridge compiles each into a native `@theokit/sdk` `Agent.create()` field (`skills` → `SkillsSettings`, `@ContextWindow` → `ContextSettings.maxTokens`, `@ProjectContext` → a `systemPrompt` resolver composing the env block + repo map + nearest `THEO.md` via `@theokit/sdk-tools` + `@theokit/sdk/project`), and the SDK executes it (the bridge compiles; the SDK runs — `sdk-runtime.md`). Decorator knobs with no native SDK mapping now emit a stable `THEO_AGENT_*_METADATA_ONLY` warning at compile time instead of silently doing nothing. Requires `@theokit/sdk >= 2.5.0`; adds `@theokit/sdk-tools` as an optional peer.
|