@theokit/sdk 5.15.2 → 5.16.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 +22 -0
- package/dist/{agent-QRIFX2SY.js → agent-FB56RAXD.js} +11 -10
- package/dist/{agent-QRIFX2SY.js.map → agent-FB56RAXD.js.map} +1 -1
- package/dist/{agent-D6WBBNGR.cjs → agent-TM634NHQ.cjs} +12 -11
- package/dist/{agent-D6WBBNGR.cjs.map → agent-TM634NHQ.cjs.map} +1 -1
- package/dist/chunk-22HVMMXX.cjs +13 -0
- package/dist/chunk-22HVMMXX.cjs.map +1 -0
- package/dist/{chunk-PDFSLD5P.cjs → chunk-3JGRKXA7.cjs} +4 -4
- package/dist/{chunk-PDFSLD5P.cjs.map → chunk-3JGRKXA7.cjs.map} +1 -1
- package/dist/{chunk-CMDM4VF6.js → chunk-4XYCF5PA.js} +3 -3
- package/dist/{chunk-CMDM4VF6.js.map → chunk-4XYCF5PA.js.map} +1 -1
- package/dist/{chunk-PSMWZYW6.js → chunk-6WPNFZH3.js} +4 -4
- package/dist/{chunk-PSMWZYW6.js.map → chunk-6WPNFZH3.js.map} +1 -1
- package/dist/{chunk-5L7S2VOL.js → chunk-A3T2A2WU.js} +3 -69
- package/dist/chunk-A3T2A2WU.js.map +1 -0
- package/dist/{chunk-BTGYRM4J.cjs → chunk-BJB6RDEA.cjs} +59 -59
- package/dist/{chunk-BTGYRM4J.cjs.map → chunk-BJB6RDEA.cjs.map} +1 -1
- package/dist/{chunk-6XT5LAZG.cjs → chunk-BXEHUUDJ.cjs} +69 -30
- package/dist/chunk-BXEHUUDJ.cjs.map +1 -0
- package/dist/{chunk-ATGSV4GS.js → chunk-DLCYS5RI.js} +3 -3
- package/dist/{chunk-ATGSV4GS.js.map → chunk-DLCYS5RI.js.map} +1 -1
- package/dist/chunk-GA4ZRKYF.cjs +75 -0
- package/dist/chunk-GA4ZRKYF.cjs.map +1 -0
- package/dist/chunk-ICBNSAO4.js +11 -0
- package/dist/chunk-ICBNSAO4.js.map +1 -0
- package/dist/{chunk-JRQJMZKY.js → chunk-MNE4633K.js} +45 -6
- package/dist/chunk-MNE4633K.js.map +1 -0
- package/dist/{chunk-CG64VPPU.js → chunk-NHD5IN3E.js} +10 -10
- package/dist/{chunk-CG64VPPU.js.map → chunk-NHD5IN3E.js.map} +1 -1
- package/dist/{chunk-Q4UOCMAO.cjs → chunk-S5WTJ6LL.cjs} +5 -5
- package/dist/{chunk-Q4UOCMAO.cjs.map → chunk-S5WTJ6LL.cjs.map} +1 -1
- package/dist/chunk-SGKMTBCO.cjs +18 -0
- package/dist/{chunk-EDIYR4VR.cjs.map → chunk-SGKMTBCO.cjs.map} +1 -1
- package/dist/{chunk-VT3NWHFH.cjs → chunk-TDKLSWHU.cjs} +4 -4
- package/dist/{chunk-VT3NWHFH.cjs.map → chunk-TDKLSWHU.cjs.map} +1 -1
- package/dist/{chunk-AQ23NII7.js → chunk-UNUGF36D.js} +3 -3
- package/dist/{chunk-AQ23NII7.js.map → chunk-UNUGF36D.js.map} +1 -1
- package/dist/{chunk-Z5MB2HAN.cjs → chunk-WVQRE7CO.cjs} +4 -70
- package/dist/chunk-WVQRE7CO.cjs.map +1 -0
- package/dist/chunk-Z2UVCAYS.js +72 -0
- package/dist/chunk-Z2UVCAYS.js.map +1 -0
- package/dist/{compact-session-5DWFHMW4.cjs → compact-session-OHA543HN.cjs} +14 -13
- package/dist/{compact-session-5DWFHMW4.cjs.map → compact-session-OHA543HN.cjs.map} +1 -1
- package/dist/{compact-session-AL65PEMX.js → compact-session-XPJS27JD.js} +5 -4
- package/dist/{compact-session-AL65PEMX.js.map → compact-session-XPJS27JD.js.map} +1 -1
- package/dist/cron.cjs +11 -10
- package/dist/cron.js +10 -9
- package/dist/eval.cjs +10 -9
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +9 -8
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +219 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +106 -1
- package/dist/index.d.ts +106 -1
- package/dist/index.js +185 -14
- package/dist/index.js.map +1 -1
- package/dist/{inject-session-QZULG65O.cjs → inject-session-NTL2UAE6.cjs} +5 -5
- package/dist/{inject-session-QZULG65O.cjs.map → inject-session-NTL2UAE6.cjs.map} +1 -1
- package/dist/{inject-session-E2SZ4A35.js → inject-session-SCJ6MTUT.js} +4 -4
- package/dist/{inject-session-E2SZ4A35.js.map → inject-session-SCJ6MTUT.js.map} +1 -1
- package/dist/internal/llm/openai.d.ts +2 -0
- package/dist/internal/llm/responses.d.ts +2 -0
- package/dist/internal/llm/sse.d.ts +6 -0
- package/dist/internal/providers/builtin/openai-chatgpt.d.ts +8 -0
- package/dist/internal/trim-trailing-slashes.d.ts +6 -0
- package/dist/models.cjs +12 -16
- package/dist/models.cjs.map +1 -1
- package/dist/models.js +4 -8
- package/dist/models.js.map +1 -1
- package/dist/openai-chatgpt-IVAL4MW6.cjs +22 -0
- package/dist/openai-chatgpt-IVAL4MW6.cjs.map +1 -0
- package/dist/openai-chatgpt-ZFNZWT2L.js +9 -0
- package/dist/openai-chatgpt-ZFNZWT2L.js.map +1 -0
- package/dist/providers.cjs +5 -4
- package/dist/providers.js +3 -2
- package/dist/sandbox/e2b-sandbox.d.cts +61 -0
- package/dist/sandbox/e2b-sandbox.d.ts +61 -0
- package/dist/sandbox/index.cjs +55 -0
- package/dist/sandbox/index.cjs.map +1 -1
- package/dist/sandbox/index.d.cts +1 -0
- package/dist/sandbox/index.d.ts +1 -0
- package/dist/sandbox/index.js +54 -1
- package/dist/sandbox/index.js.map +1 -1
- package/docs/error-codes.md +6 -4
- package/docs/harness-capability-map.md +21 -1
- package/package.json +5 -1
- package/dist/chunk-5L7S2VOL.js.map +0 -1
- package/dist/chunk-6XT5LAZG.cjs.map +0 -1
- package/dist/chunk-EDIYR4VR.cjs +0 -18
- package/dist/chunk-JRQJMZKY.js.map +0 -1
- package/dist/chunk-Z5MB2HAN.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.16.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#986](https://github.com/usetheokit/theokit-sdk/pull/986) [`77e0813`](https://github.com/usetheokit/theokit-sdk/commit/77e081356a3f5df4b82c6ee49a625167af5219c7) Thanks [@aifactory-paulohenriquevn](https://github.com/apps/aifactory-paulohenriquevn)! - `E2BSandbox` in `@theokit/sdk/sandbox`: a `SandboxBackend` over an E2B sandbox you created. It maps `CommandExitError` to the real exit code and `TimeoutError` to 124, throws `SandboxNotAvailableError` for a stopped or unreachable sandbox instead of reporting a timeout, applies `envs` and `NODE_EXTRA_CA_CERTS` to every command, and exposes the `networkPolicy` it was given. It takes the `e2b` `Sandbox` instance, so `e2b` is not a dependency.
|
|
8
|
+
|
|
9
|
+
- [#978](https://github.com/usetheokit/theokit-sdk/pull/978) [`ae77f76`](https://github.com/usetheokit/theokit-sdk/commit/ae77f768fbec735249422569e9cbba739b199893) Thanks [@aifactory-paulohenriquevn](https://github.com/apps/aifactory-paulohenriquevn)! - Image generation: `generateImage` (OpenAI-compatible `/images/generations` call) in `@theokit/sdk`, and the `image_generate` tool (`createImageGenerateTool`) in `@theokit/sdk-tools`, which writes the image into the workspace and returns its path for `view_image`.
|
|
10
|
+
|
|
11
|
+
`generateImage` also takes `route: "chatgpt"` to use the ChatGPT-subscription login through the Responses API `image_generation` tool.
|
|
12
|
+
|
|
13
|
+
- [#982](https://github.com/usetheokit/theokit-sdk/pull/982) [`0eeec73`](https://github.com/usetheokit/theokit-sdk/commit/0eeec73938a884842905edcecdf9ead143200314) Thanks [@aifactory-paulohenriquevn](https://github.com/apps/aifactory-paulohenriquevn)! - `decide`: a typed decision (one label from a declared enum) answered by a pinned local ONNX classifier. The model file's SHA-256 is verified before it loads (`DecisionChecksumError` on mismatch) and no provider request is made. Needs the optional peer `onnxruntime-node`; no model or tokenizer is bundled. The result reports `source: "local-onnx"`.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- [#987](https://github.com/usetheokit/theokit-sdk/pull/987) [`facd09d`](https://github.com/usetheokit/theokit-sdk/commit/facd09d8b5d931f7c874bc06c4cf6f1c61e6a9de) Thanks [@usetheodev](https://github.com/usetheodev)! - `generateImage` no longer stalls on a `baseUrl` holding a long run of slashes: its trailing slashes are trimmed in one linear pass instead of with a backtracking regex (CodeQL `js/polynomial-redos`).
|
|
18
|
+
|
|
19
|
+
## 5.15.3
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- [#967](https://github.com/usetheokit/theokit-sdk/pull/967) [`2e162ca`](https://github.com/usetheokit/theokit-sdk/commit/2e162cad9b3dcc858536e1fc799f76528132f63f) Thanks [@aifactory-paulohenriquevn](https://github.com/apps/aifactory-paulohenriquevn)! - llm: bound the wait for response headers (default 30 s, `responseHeadersTimeoutMs`, `<= 0` disables); a stalled request now fails with a retryable `NetworkError` (`response_headers_timeout`) instead of waiting for undici's 300 s.
|
|
24
|
+
|
|
3
25
|
## 5.15.2
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
export { Agent } from './chunk-
|
|
1
|
+
export { Agent } from './chunk-NHD5IN3E.js';
|
|
2
|
+
import './chunk-2SFBB54R.js';
|
|
2
3
|
import './chunk-GEQLHBJM.js';
|
|
3
|
-
import './chunk-
|
|
4
|
+
import './chunk-6WPNFZH3.js';
|
|
4
5
|
import './chunk-3GQYMKVJ.js';
|
|
6
|
+
import './chunk-4E4D6H77.js';
|
|
5
7
|
import './chunk-L5B7EWWH.js';
|
|
6
8
|
import './chunk-ZUWVO442.js';
|
|
7
|
-
import './chunk-2SFBB54R.js';
|
|
8
9
|
import './chunk-TTXRNCXY.js';
|
|
9
10
|
import './chunk-H73MEMQB.js';
|
|
10
11
|
import './chunk-BH6M2DGV.js';
|
|
11
12
|
import './chunk-DB5RYCXX.js';
|
|
12
13
|
import './chunk-P7B64NFK.js';
|
|
13
|
-
import './chunk-
|
|
14
|
+
import './chunk-MNE4633K.js';
|
|
14
15
|
import './chunk-OIOSY5G6.js';
|
|
15
16
|
import './chunk-2XC6KDJM.js';
|
|
16
17
|
import './chunk-7ACS6P5Z.js';
|
|
17
18
|
import './chunk-24MGQDK3.js';
|
|
18
|
-
import './chunk-4E4D6H77.js';
|
|
19
19
|
import './chunk-HKCKOAIO.js';
|
|
20
20
|
import './chunk-YUQNHLKN.js';
|
|
21
21
|
import './chunk-S7IZEVXX.js';
|
|
@@ -48,16 +48,17 @@ import './chunk-MTNCJ7MQ.js';
|
|
|
48
48
|
import './chunk-PISZRLES.js';
|
|
49
49
|
import './chunk-TIYQDJFK.js';
|
|
50
50
|
import './chunk-SZQFCHU6.js';
|
|
51
|
-
import './chunk-
|
|
51
|
+
import './chunk-4XYCF5PA.js';
|
|
52
52
|
import './chunk-R7WIIPUR.js';
|
|
53
|
-
import './chunk-
|
|
54
|
-
import './chunk-
|
|
53
|
+
import './chunk-UNUGF36D.js';
|
|
54
|
+
import './chunk-A3T2A2WU.js';
|
|
55
55
|
import './chunk-AGACYRJ2.js';
|
|
56
|
+
import './chunk-Z2UVCAYS.js';
|
|
56
57
|
import './chunk-UNP4NCMZ.js';
|
|
57
58
|
import './chunk-L2KC2G7H.js';
|
|
58
59
|
import './chunk-5IUDICRK.js';
|
|
59
60
|
import './chunk-Q7GYMXVC.js';
|
|
60
61
|
import './chunk-TNFOU6SB.js';
|
|
61
62
|
import './chunk-3OY6H3I7.js';
|
|
62
|
-
//# sourceMappingURL=agent-
|
|
63
|
-
//# sourceMappingURL=agent-
|
|
63
|
+
//# sourceMappingURL=agent-FB56RAXD.js.map
|
|
64
|
+
//# sourceMappingURL=agent-FB56RAXD.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"agent-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"agent-FB56RAXD.js"}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkBJB6RDEA_cjs = require('./chunk-BJB6RDEA.cjs');
|
|
4
|
+
require('./chunk-BV2MWEMV.cjs');
|
|
4
5
|
require('./chunk-ER3BF23R.cjs');
|
|
5
|
-
require('./chunk-
|
|
6
|
+
require('./chunk-3JGRKXA7.cjs');
|
|
6
7
|
require('./chunk-PNL63WDP.cjs');
|
|
8
|
+
require('./chunk-EOWIUDKG.cjs');
|
|
7
9
|
require('./chunk-HI5TJWQE.cjs');
|
|
8
10
|
require('./chunk-NDXZXGVP.cjs');
|
|
9
|
-
require('./chunk-BV2MWEMV.cjs');
|
|
10
11
|
require('./chunk-DEHPRORL.cjs');
|
|
11
12
|
require('./chunk-GHX4P3V2.cjs');
|
|
12
13
|
require('./chunk-EBX6XUN7.cjs');
|
|
13
14
|
require('./chunk-KC2HKUPT.cjs');
|
|
14
15
|
require('./chunk-N2ORTDSO.cjs');
|
|
15
|
-
require('./chunk-
|
|
16
|
+
require('./chunk-BXEHUUDJ.cjs');
|
|
16
17
|
require('./chunk-MJGY3E3C.cjs');
|
|
17
18
|
require('./chunk-YJNYDJ2T.cjs');
|
|
18
19
|
require('./chunk-3F53FLQ7.cjs');
|
|
19
20
|
require('./chunk-QOGNZMHD.cjs');
|
|
20
|
-
require('./chunk-EOWIUDKG.cjs');
|
|
21
21
|
require('./chunk-2ZPEDVLM.cjs');
|
|
22
22
|
require('./chunk-XR6O6G3B.cjs');
|
|
23
23
|
require('./chunk-X4ZYEZPD.cjs');
|
|
@@ -50,11 +50,12 @@ require('./chunk-FZSPVIFK.cjs');
|
|
|
50
50
|
require('./chunk-JVH3NNJ3.cjs');
|
|
51
51
|
require('./chunk-3YCNBOX7.cjs');
|
|
52
52
|
require('./chunk-KX5QXLBS.cjs');
|
|
53
|
-
require('./chunk-
|
|
53
|
+
require('./chunk-S5WTJ6LL.cjs');
|
|
54
54
|
require('./chunk-3EE6LVWT.cjs');
|
|
55
|
-
require('./chunk-
|
|
56
|
-
require('./chunk-
|
|
55
|
+
require('./chunk-SGKMTBCO.cjs');
|
|
56
|
+
require('./chunk-WVQRE7CO.cjs');
|
|
57
57
|
require('./chunk-NVXXWAU7.cjs');
|
|
58
|
+
require('./chunk-GA4ZRKYF.cjs');
|
|
58
59
|
require('./chunk-UMCCYXFZ.cjs');
|
|
59
60
|
require('./chunk-PXYINWBC.cjs');
|
|
60
61
|
require('./chunk-IOFMRS6T.cjs');
|
|
@@ -66,7 +67,7 @@ require('./chunk-RNXXYF22.cjs');
|
|
|
66
67
|
|
|
67
68
|
Object.defineProperty(exports, "Agent", {
|
|
68
69
|
enumerable: true,
|
|
69
|
-
get: function () { return
|
|
70
|
+
get: function () { return chunkBJB6RDEA_cjs.Agent; }
|
|
70
71
|
});
|
|
71
|
-
//# sourceMappingURL=agent-
|
|
72
|
-
//# sourceMappingURL=agent-
|
|
72
|
+
//# sourceMappingURL=agent-TM634NHQ.cjs.map
|
|
73
|
+
//# sourceMappingURL=agent-TM634NHQ.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"agent-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"agent-TM634NHQ.cjs"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/internal/trim-trailing-slashes.ts
|
|
4
|
+
var SLASH_CODE = 47;
|
|
5
|
+
function trimTrailingSlashes(value) {
|
|
6
|
+
let end = value.length;
|
|
7
|
+
while (end > 0 && value.charCodeAt(end - 1) === SLASH_CODE) end--;
|
|
8
|
+
return end === value.length ? value : value.slice(0, end);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
exports.trimTrailingSlashes = trimTrailingSlashes;
|
|
12
|
+
//# sourceMappingURL=chunk-22HVMMXX.cjs.map
|
|
13
|
+
//# sourceMappingURL=chunk-22HVMMXX.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/internal/trim-trailing-slashes.ts"],"names":[],"mappings":";;;AAAA,IAAM,UAAA,GAAa,EAAA;AAOZ,SAAS,oBAAoB,KAAA,EAAuB;AACzD,EAAA,IAAI,MAAM,KAAA,CAAM,MAAA;AAChB,EAAA,OAAO,MAAM,CAAA,IAAK,KAAA,CAAM,WAAW,GAAA,GAAM,CAAC,MAAM,UAAA,EAAY,GAAA,EAAA;AAC5D,EAAA,OAAO,QAAQ,KAAA,CAAM,MAAA,GAAS,QAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,GAAG,CAAA;AAC1D","file":"chunk-22HVMMXX.cjs","sourcesContent":["const SLASH_CODE = 47; // \"/\"\n\n/**\n * Removes trailing `/` characters in one linear pass. Not `/\\/+$/`: on caller input such as a\n * model id or a base URL, a long run of slashes followed by anything else makes that regex\n * quadratic (CodeQL `js/polynomial-redos`, measured in tests/llm/model-option-redos.test.ts).\n */\nexport function trimTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value.charCodeAt(end - 1) === SLASH_CODE) end--;\n return end === value.length ? value : value.slice(0, end);\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var chunkYJNYDJ2T_cjs = require('./chunk-YJNYDJ2T.cjs');
|
|
4
3
|
var chunkEOWIUDKG_cjs = require('./chunk-EOWIUDKG.cjs');
|
|
4
|
+
var chunkYJNYDJ2T_cjs = require('./chunk-YJNYDJ2T.cjs');
|
|
5
5
|
var chunkRNXXYF22_cjs = require('./chunk-RNXXYF22.cjs');
|
|
6
6
|
|
|
7
7
|
// src/internal/session/agent-session.ts
|
|
@@ -48,7 +48,7 @@ function persistTurnToTranscript(store, loc, sessionId, turn, onCompact) {
|
|
|
48
48
|
const count = (recordCounts.get(key) ?? 0) + 1;
|
|
49
49
|
recordCounts.set(key, count);
|
|
50
50
|
if (turn.autoCompact !== void 0) {
|
|
51
|
-
const { autoCompactIfNeeded } = await import('./compact-session-
|
|
51
|
+
const { autoCompactIfNeeded } = await import('./compact-session-OHA543HN.cjs');
|
|
52
52
|
const fired = await autoCompactIfNeeded({
|
|
53
53
|
store,
|
|
54
54
|
loc,
|
|
@@ -114,5 +114,5 @@ exports.flushSessionWrites = flushSessionWrites;
|
|
|
114
114
|
exports.getSessionMessages = getSessionMessages;
|
|
115
115
|
exports.hydrateSession = hydrateSession;
|
|
116
116
|
exports.persistTurnToTranscript = persistTurnToTranscript;
|
|
117
|
-
//# sourceMappingURL=chunk-
|
|
118
|
-
//# sourceMappingURL=chunk-
|
|
117
|
+
//# sourceMappingURL=chunk-3JGRKXA7.cjs.map
|
|
118
|
+
//# sourceMappingURL=chunk-3JGRKXA7.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/session/agent-session.ts"],"names":["sessions","transcriptKey","hydratedKeys","persistTurn","diag","readSessionMessages"],"mappings":"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","file":"chunk-PDFSLD5P.cjs","sourcesContent":["import type { SessionStore } from \"../../types/session-store.js\";\nimport {\n type PersistTurnInput,\n persistTurn,\n readSessionMessages,\n type TranscriptLocation,\n} from \"./agent-session-store.js\";\n\n/**\n * Per-agent conversation history kept across runs (and across `Agent.resume()`\n * within the same process). Lets the fixture responder recall prior facts when\n * the user asks a follow-up question.\n *\n * SE40 — disk persistence IS the native Claude-shaped `.jsonl` transcript. The\n * in-memory cache holds the narrowed `SessionMessage[]` (user/assistant text) so\n * a send can read `priorMessages` synchronously; the whole rich turn (user +\n * assistant + tool blocks) lands on disk once per send via {@link persistTurnToTranscript}\n * (fed by `run.conversation()`). Hydration on resume reconstructs the session by\n * walking the transcript DAG (`readSessionMessages`).\n *\n * @internal\n */\n\n// `SessionMessage` lives in `./session-types.ts` (leaf types file). Re-exported\n// for back-compat with downstream importers that pulled it from here.\nexport type { SessionMessage } from \"./types.js\";\n\nimport type { SessionMessage } from \"./types.js\";\n\n// M75 — the cache lives in a leaf; see session-cache.ts for the reason (cycle broken by extraction).\nexport {\n hydratedKeys,\n invalidateSessionCache,\n sessions,\n transcriptKey,\n} from \"./session-cache.js\";\n\nimport { diag } from \"../diagnostics.js\";\nimport { globalSingleton } from \"../global-singleton.js\";\nimport { hydratedKeys, sessions, transcriptKey } from \"./session-cache.js\";\n\nconst pendingWrites = new Map<string, Promise<void>>();\nconst recordCounts = new Map<string, number>();\n\n/**\n * Append a session message to the in-memory cache only. Disk persistence for the\n * whole turn happens once per send via {@link persistTurnToTranscript}; the cache\n * feeds `priorMessages` / `onBeforeSend.previousMessageCount` synchronously.\n *\n * @internal\n */\nexport function appendSessionMessage(agentId: string, message: SessionMessage): void {\n const existing = sessions.get(agentId) ?? [];\n existing.push(message);\n // `delete` + `set` reinserts at the END: a JS `Map` preserves insertion order, so the first key\n // is always the least recently touched. That is the entire LRU, with no new structure (parsimony\n // rungs 2/5 — the ordering we need is already a language guarantee).\n sessions.delete(agentId);\n sessions.set(agentId, existing);\n enforceCeiling();\n}\n\n/**\n * Ceiling on sessions kept in memory.\n *\n * The runtime only reads the **active** session; the rest is pure cache, rebuildable from the\n * on-disk transcript. 32 is deliberately generous — the primary removal path is the explicit\n * `discardSession()` at the end of the agent's life, and this ceiling is a safety net against a\n * long-lived process running hundreds of sessions (plan risk #2: a tight ceiling could evict a\n * session still referenced by an in-flight async path).\n */\nexport const MAX_CACHED_SESSIONS = 32;\n\nfunction enforceCeiling(): void {\n while (sessions.size > MAX_CACHED_SESSIONS) {\n const oldest = sessions.keys().next().value;\n if (oldest === undefined) return;\n sessions.delete(oldest);\n forgetBookkeeping(oldest);\n }\n}\n\n/**\n * Erases the bookkeeping for an `agentId` across EVERY `cwd` it appears in.\n *\n * The three maps are keyed by `transcriptKey(cwd, agentId)`; `sessions` is the only one keyed by the\n * raw `agentId`. The ceiling's first version deleted from all three using `sessions`' key — that is,\n * deleted nothing — and left `hydratedKeys` **orphaned**. Since `hydrateSession` returns early when\n * the marker is present, an evicted session came back **empty** instead of rehydrating from disk:\n * silent amnesia, and a regression new to M95, because before it nothing evicted.\n *\n * The ceiling only knows the `agentId`, not the `cwd`, so it scans by suffix — which is the format\n * `transcriptKey` produces. A scan rather than an index because these maps hold tens of entries, not\n * thousands: a reverse index here would be new structure for a problem that does not exist.\n */\nfunction forgetBookkeeping(agentId: string): void {\n const suffix = transcriptKey(\"\", agentId).slice(0 - agentId.length - 2);\n for (const k of [...hydratedKeys]) if (k.endsWith(suffix)) hydratedKeys.delete(k);\n for (const k of [...pendingWrites.keys()]) if (k.endsWith(suffix)) pendingWrites.delete(k);\n for (const k of [...recordCounts.keys()]) if (k.endsWith(suffix)) recordCounts.delete(k);\n}\n\n/**\n * Erases the agent's module bookkeeping and returns how many entries were removed.\n *\n * M95 — `invalidateSessionCache` used to clear **two** of the four maps (`sessions`, `hydratedKeys`);\n * `pendingWrites` and `recordCounts` were never touched by id, so they grew for the life of the\n * process. Neither is large per entry — the leak is in count, not volume — but a cache with no owner\n * for removal is a cache that only grows.\n *\n * Returns the count so the caller can prove the removal; a second discard returns 0, which is what\n * makes the idempotency test possible without exposing the maps.\n */\nexport function discardSession(cwd: string, agentId: string): number {\n const key = transcriptKey(cwd, agentId);\n let removed = 0;\n // `sessions` is NOT erased here — and the distinction is measured, not aesthetic. It holds the\n // readable conversation, and there is a legitimate reader AFTER dispose: the golden\n // `two-concurrent-sends-serialize` calls `getSessionMessages(agentId)` after `agent.dispose()`.\n // Erasing it here returned an empty list and broke two goldens. What bounds it is the LRU ceiling\n // above; the three below are pure bookkeeping, with no post-dispose reader.\n //\n // The key is `transcriptKey(cwd, agentId)` in ALL THREE — not the raw `agentId`. The first version\n // erased two of them by `agentId` and therefore **never erased anything**; the test did not catch\n // it because it only asserted that the SECOND call returns 0, which is true either way.\n if (hydratedKeys.delete(key)) removed++;\n if (pendingWrites.delete(key)) removed++;\n if (recordCounts.delete(key)) removed++;\n return removed;\n}\n\nexport function getSessionMessages(agentId: string): SessionMessage[] {\n return sessions.get(agentId) ?? [];\n}\n\n/**\n * Persist a full conversation turn (user + assistant + tool blocks) to the native\n * transcript. Chained per-(agent, transcript) so on-disk order matches send order,\n * and fire-and-forget so `send()` is not blocked by disk I/O. Every\n * M50 — when the caller supplies `turn.autoCompact`, size-driven auto-compaction (usage real vs\n * the model's context window) runs in this same chain, surfaced via the optional `onCompact` observer.\n *\n * @internal\n */\nexport function persistTurnToTranscript(\n store: SessionStore,\n loc: TranscriptLocation,\n sessionId: string,\n turn: PersistTurnInput,\n onCompact?: () => void,\n): void {\n const key = transcriptKey(loc.cwd, loc.agentId);\n // PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n // sweeping these files (a nested root under refactor/). It is not new code and was not touched\n // by M75; refactoring SDK internals without review would trade a visible problem for a diff\n // risky. Tracked in usetheodev/theokit-sdk#151.\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: see the reason just above\n const chained = (pendingWrites.get(key) ?? Promise.resolve()).then(async () => {\n try {\n await persistTurn(store, loc, sessionId, turn);\n const count = (recordCounts.get(key) ?? 0) + 1;\n recordCounts.set(key, count);\n // M50 — the 50-turn no-summary boundary stub is GONE (it silently amnesia'd the session).\n // Auto-compaction is now size-driven with a real summary: see `maybeAutoCompact` below,\n // invoked in this same write chain by the post-run lifecycle when usage is known.\n if (turn.autoCompact !== undefined) {\n const { autoCompactIfNeeded } = await import(\"./compact-session.js\");\n const fired = await autoCompactIfNeeded({\n store,\n loc,\n sessionId,\n usageTotal: turn.autoCompact.usageTotal,\n contextWindow: turn.autoCompact.contextWindow,\n turnCount: count,\n summarize: turn.autoCompact.summarize,\n });\n if (fired) onCompact?.();\n }\n } catch (cause) {\n const msg = cause instanceof Error ? cause.message : String(cause);\n diag(`[theokit-sdk] session transcript write failed (${loc.agentId}): ${msg}\\n`);\n }\n });\n pendingWrites.set(\n key,\n chained.then(\n () => undefined,\n () => undefined,\n ),\n );\n}\n\n/**\n * Load the persisted transcript into the in-memory cache. Idempotent per\n * (baseDir, cwd, agentId). Call once per agent lifecycle before the first read.\n *\n * @internal\n */\nexport async function hydrateSession(\n agentId: string,\n loc: { store: SessionStore; cwd: string },\n): Promise<void> {\n const key = transcriptKey(loc.cwd, agentId);\n if (hydratedKeys.has(key)) return;\n hydratedKeys.add(key);\n\n const persisted = await readSessionMessages(loc.store, agentId);\n if (persisted.length === 0) return;\n // M51 review F4 — the DISK is the source of truth at hydration time: after an invalidation\n // (compact/inject), an in-flight turn may have repopulated the cache with a SINGLE message before\n // this hydrate ran; the old \"skip when non-empty\" guard then pinned the parent to a 1-message\n // context (history + injected pair lost until restart). The persist chain serializes writes, so\n // the disk already contains that in-flight turn — replacing is always correct.\n sessions.set(agentId, persisted);\n}\n\n/**\n * Wait for all pending transcript writes to settle. Used by tests and by the\n * agent dispose path so on-disk state matches in-memory before the caller proceeds.\n *\n * @internal\n */\nexport async function flushSessionWrites(): Promise<void> {\n while (pendingWrites.size > 0) {\n const all = Array.from(pendingWrites.values());\n pendingWrites.clear();\n await Promise.all(all);\n }\n}\n\n/**\n * Drop the in-memory message cache for `agentId` and NOTHING else — the hydration marker in\n * `hydratedKeys` deliberately stays.\n *\n * That asymmetry is the feature, not an oversight, and it is what separates this from\n * `invalidateSessionCache`, which drops both. The single caller is the personality switch's\n * `reset: true` path (`internal/personality/switch.ts`): leaving the marker set makes\n * `hydrateSession` return early, so the next send starts from an EMPTY context instead of\n * replaying the pre-reset transcript off disk. Clearing the marker here would re-hydrate the\n * conversation the reset was asked to discard.\n *\n * The same shape read as a bug one function up: `forgetBookkeeping` documents an evicted session\n * coming back empty as \"silent amnesia\". The difference is intent — eviction wants the transcript\n * back, a reset does not. Anyone reaching for this to invalidate a cache wants\n * `invalidateSessionCache(cwd, agentId)` instead.\n */\nexport function clearSession(agentId: string): void {\n sessions.delete(agentId);\n}\n\n/**\n * M50 review F5 — run `fn` serialized on the SAME per-(cwd,agentId) write chain the per-turn\n * persistence uses, so a manual `Agent.compact` can never interleave with an in-flight turn's\n * writes (boundary landing mid-turn would orphan the turn from the replay).\n */\nexport function enqueueSessionWrite<T>(\n cwd: string,\n agentId: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const key = transcriptKey(cwd, agentId);\n const prior = pendingWrites.get(key) ?? Promise.resolve();\n const result = prior.then(fn);\n pendingWrites.set(\n key,\n result.then(\n () => undefined,\n () => undefined,\n ),\n );\n return result;\n}\n\n/** Test-only: drop every cached session and hydration marker. @internal */\nexport function clearAllSessions(): void {\n sessions.clear();\n hydratedKeys.clear();\n recordCounts.clear();\n // M50 review F11 — the auto-compact attempt marks live on globalThis; tests reset them here.\n // Through the helper, with the SAME key compact-session.ts uses: two files hand-rolling one slot is\n // how two copies of a mechanism drift apart.\n globalSingleton(\n \"theokit-sdk.session.auto-compact-attempts\",\n () => new Map<string, number>(),\n ).clear();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/session/agent-session.ts"],"names":["sessions","transcriptKey","hydratedKeys","persistTurn","diag","readSessionMessages"],"mappings":"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","file":"chunk-3JGRKXA7.cjs","sourcesContent":["import type { SessionStore } from \"../../types/session-store.js\";\nimport {\n type PersistTurnInput,\n persistTurn,\n readSessionMessages,\n type TranscriptLocation,\n} from \"./agent-session-store.js\";\n\n/**\n * Per-agent conversation history kept across runs (and across `Agent.resume()`\n * within the same process). Lets the fixture responder recall prior facts when\n * the user asks a follow-up question.\n *\n * SE40 — disk persistence IS the native Claude-shaped `.jsonl` transcript. The\n * in-memory cache holds the narrowed `SessionMessage[]` (user/assistant text) so\n * a send can read `priorMessages` synchronously; the whole rich turn (user +\n * assistant + tool blocks) lands on disk once per send via {@link persistTurnToTranscript}\n * (fed by `run.conversation()`). Hydration on resume reconstructs the session by\n * walking the transcript DAG (`readSessionMessages`).\n *\n * @internal\n */\n\n// `SessionMessage` lives in `./session-types.ts` (leaf types file). Re-exported\n// for back-compat with downstream importers that pulled it from here.\nexport type { SessionMessage } from \"./types.js\";\n\nimport type { SessionMessage } from \"./types.js\";\n\n// M75 — the cache lives in a leaf; see session-cache.ts for the reason (cycle broken by extraction).\nexport {\n hydratedKeys,\n invalidateSessionCache,\n sessions,\n transcriptKey,\n} from \"./session-cache.js\";\n\nimport { diag } from \"../diagnostics.js\";\nimport { globalSingleton } from \"../global-singleton.js\";\nimport { hydratedKeys, sessions, transcriptKey } from \"./session-cache.js\";\n\nconst pendingWrites = new Map<string, Promise<void>>();\nconst recordCounts = new Map<string, number>();\n\n/**\n * Append a session message to the in-memory cache only. Disk persistence for the\n * whole turn happens once per send via {@link persistTurnToTranscript}; the cache\n * feeds `priorMessages` / `onBeforeSend.previousMessageCount` synchronously.\n *\n * @internal\n */\nexport function appendSessionMessage(agentId: string, message: SessionMessage): void {\n const existing = sessions.get(agentId) ?? [];\n existing.push(message);\n // `delete` + `set` reinserts at the END: a JS `Map` preserves insertion order, so the first key\n // is always the least recently touched. That is the entire LRU, with no new structure (parsimony\n // rungs 2/5 — the ordering we need is already a language guarantee).\n sessions.delete(agentId);\n sessions.set(agentId, existing);\n enforceCeiling();\n}\n\n/**\n * Ceiling on sessions kept in memory.\n *\n * The runtime only reads the **active** session; the rest is pure cache, rebuildable from the\n * on-disk transcript. 32 is deliberately generous — the primary removal path is the explicit\n * `discardSession()` at the end of the agent's life, and this ceiling is a safety net against a\n * long-lived process running hundreds of sessions (plan risk #2: a tight ceiling could evict a\n * session still referenced by an in-flight async path).\n */\nexport const MAX_CACHED_SESSIONS = 32;\n\nfunction enforceCeiling(): void {\n while (sessions.size > MAX_CACHED_SESSIONS) {\n const oldest = sessions.keys().next().value;\n if (oldest === undefined) return;\n sessions.delete(oldest);\n forgetBookkeeping(oldest);\n }\n}\n\n/**\n * Erases the bookkeeping for an `agentId` across EVERY `cwd` it appears in.\n *\n * The three maps are keyed by `transcriptKey(cwd, agentId)`; `sessions` is the only one keyed by the\n * raw `agentId`. The ceiling's first version deleted from all three using `sessions`' key — that is,\n * deleted nothing — and left `hydratedKeys` **orphaned**. Since `hydrateSession` returns early when\n * the marker is present, an evicted session came back **empty** instead of rehydrating from disk:\n * silent amnesia, and a regression new to M95, because before it nothing evicted.\n *\n * The ceiling only knows the `agentId`, not the `cwd`, so it scans by suffix — which is the format\n * `transcriptKey` produces. A scan rather than an index because these maps hold tens of entries, not\n * thousands: a reverse index here would be new structure for a problem that does not exist.\n */\nfunction forgetBookkeeping(agentId: string): void {\n const suffix = transcriptKey(\"\", agentId).slice(0 - agentId.length - 2);\n for (const k of [...hydratedKeys]) if (k.endsWith(suffix)) hydratedKeys.delete(k);\n for (const k of [...pendingWrites.keys()]) if (k.endsWith(suffix)) pendingWrites.delete(k);\n for (const k of [...recordCounts.keys()]) if (k.endsWith(suffix)) recordCounts.delete(k);\n}\n\n/**\n * Erases the agent's module bookkeeping and returns how many entries were removed.\n *\n * M95 — `invalidateSessionCache` used to clear **two** of the four maps (`sessions`, `hydratedKeys`);\n * `pendingWrites` and `recordCounts` were never touched by id, so they grew for the life of the\n * process. Neither is large per entry — the leak is in count, not volume — but a cache with no owner\n * for removal is a cache that only grows.\n *\n * Returns the count so the caller can prove the removal; a second discard returns 0, which is what\n * makes the idempotency test possible without exposing the maps.\n */\nexport function discardSession(cwd: string, agentId: string): number {\n const key = transcriptKey(cwd, agentId);\n let removed = 0;\n // `sessions` is NOT erased here — and the distinction is measured, not aesthetic. It holds the\n // readable conversation, and there is a legitimate reader AFTER dispose: the golden\n // `two-concurrent-sends-serialize` calls `getSessionMessages(agentId)` after `agent.dispose()`.\n // Erasing it here returned an empty list and broke two goldens. What bounds it is the LRU ceiling\n // above; the three below are pure bookkeeping, with no post-dispose reader.\n //\n // The key is `transcriptKey(cwd, agentId)` in ALL THREE — not the raw `agentId`. The first version\n // erased two of them by `agentId` and therefore **never erased anything**; the test did not catch\n // it because it only asserted that the SECOND call returns 0, which is true either way.\n if (hydratedKeys.delete(key)) removed++;\n if (pendingWrites.delete(key)) removed++;\n if (recordCounts.delete(key)) removed++;\n return removed;\n}\n\nexport function getSessionMessages(agentId: string): SessionMessage[] {\n return sessions.get(agentId) ?? [];\n}\n\n/**\n * Persist a full conversation turn (user + assistant + tool blocks) to the native\n * transcript. Chained per-(agent, transcript) so on-disk order matches send order,\n * and fire-and-forget so `send()` is not blocked by disk I/O. Every\n * M50 — when the caller supplies `turn.autoCompact`, size-driven auto-compaction (usage real vs\n * the model's context window) runs in this same chain, surfaced via the optional `onCompact` observer.\n *\n * @internal\n */\nexport function persistTurnToTranscript(\n store: SessionStore,\n loc: TranscriptLocation,\n sessionId: string,\n turn: PersistTurnInput,\n onCompact?: () => void,\n): void {\n const key = transcriptKey(loc.cwd, loc.agentId);\n // PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n // sweeping these files (a nested root under refactor/). It is not new code and was not touched\n // by M75; refactoring SDK internals without review would trade a visible problem for a diff\n // risky. Tracked in usetheodev/theokit-sdk#151.\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: see the reason just above\n const chained = (pendingWrites.get(key) ?? Promise.resolve()).then(async () => {\n try {\n await persistTurn(store, loc, sessionId, turn);\n const count = (recordCounts.get(key) ?? 0) + 1;\n recordCounts.set(key, count);\n // M50 — the 50-turn no-summary boundary stub is GONE (it silently amnesia'd the session).\n // Auto-compaction is now size-driven with a real summary: see `maybeAutoCompact` below,\n // invoked in this same write chain by the post-run lifecycle when usage is known.\n if (turn.autoCompact !== undefined) {\n const { autoCompactIfNeeded } = await import(\"./compact-session.js\");\n const fired = await autoCompactIfNeeded({\n store,\n loc,\n sessionId,\n usageTotal: turn.autoCompact.usageTotal,\n contextWindow: turn.autoCompact.contextWindow,\n turnCount: count,\n summarize: turn.autoCompact.summarize,\n });\n if (fired) onCompact?.();\n }\n } catch (cause) {\n const msg = cause instanceof Error ? cause.message : String(cause);\n diag(`[theokit-sdk] session transcript write failed (${loc.agentId}): ${msg}\\n`);\n }\n });\n pendingWrites.set(\n key,\n chained.then(\n () => undefined,\n () => undefined,\n ),\n );\n}\n\n/**\n * Load the persisted transcript into the in-memory cache. Idempotent per\n * (baseDir, cwd, agentId). Call once per agent lifecycle before the first read.\n *\n * @internal\n */\nexport async function hydrateSession(\n agentId: string,\n loc: { store: SessionStore; cwd: string },\n): Promise<void> {\n const key = transcriptKey(loc.cwd, agentId);\n if (hydratedKeys.has(key)) return;\n hydratedKeys.add(key);\n\n const persisted = await readSessionMessages(loc.store, agentId);\n if (persisted.length === 0) return;\n // M51 review F4 — the DISK is the source of truth at hydration time: after an invalidation\n // (compact/inject), an in-flight turn may have repopulated the cache with a SINGLE message before\n // this hydrate ran; the old \"skip when non-empty\" guard then pinned the parent to a 1-message\n // context (history + injected pair lost until restart). The persist chain serializes writes, so\n // the disk already contains that in-flight turn — replacing is always correct.\n sessions.set(agentId, persisted);\n}\n\n/**\n * Wait for all pending transcript writes to settle. Used by tests and by the\n * agent dispose path so on-disk state matches in-memory before the caller proceeds.\n *\n * @internal\n */\nexport async function flushSessionWrites(): Promise<void> {\n while (pendingWrites.size > 0) {\n const all = Array.from(pendingWrites.values());\n pendingWrites.clear();\n await Promise.all(all);\n }\n}\n\n/**\n * Drop the in-memory message cache for `agentId` and NOTHING else — the hydration marker in\n * `hydratedKeys` deliberately stays.\n *\n * That asymmetry is the feature, not an oversight, and it is what separates this from\n * `invalidateSessionCache`, which drops both. The single caller is the personality switch's\n * `reset: true` path (`internal/personality/switch.ts`): leaving the marker set makes\n * `hydrateSession` return early, so the next send starts from an EMPTY context instead of\n * replaying the pre-reset transcript off disk. Clearing the marker here would re-hydrate the\n * conversation the reset was asked to discard.\n *\n * The same shape read as a bug one function up: `forgetBookkeeping` documents an evicted session\n * coming back empty as \"silent amnesia\". The difference is intent — eviction wants the transcript\n * back, a reset does not. Anyone reaching for this to invalidate a cache wants\n * `invalidateSessionCache(cwd, agentId)` instead.\n */\nexport function clearSession(agentId: string): void {\n sessions.delete(agentId);\n}\n\n/**\n * M50 review F5 — run `fn` serialized on the SAME per-(cwd,agentId) write chain the per-turn\n * persistence uses, so a manual `Agent.compact` can never interleave with an in-flight turn's\n * writes (boundary landing mid-turn would orphan the turn from the replay).\n */\nexport function enqueueSessionWrite<T>(\n cwd: string,\n agentId: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const key = transcriptKey(cwd, agentId);\n const prior = pendingWrites.get(key) ?? Promise.resolve();\n const result = prior.then(fn);\n pendingWrites.set(\n key,\n result.then(\n () => undefined,\n () => undefined,\n ),\n );\n return result;\n}\n\n/** Test-only: drop every cached session and hydration marker. @internal */\nexport function clearAllSessions(): void {\n sessions.clear();\n hydratedKeys.clear();\n recordCounts.clear();\n // M50 review F11 — the auto-compact attempt marks live on globalThis; tests reset them here.\n // Through the helper, with the SAME key compact-session.ts uses: two files hand-rolling one slot is\n // how two copies of a mechanism drift apart.\n globalSingleton(\n \"theokit-sdk.session.auto-compact-attempts\",\n () => new Map<string, number>(),\n ).clear();\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getCatalogModelInfo } from './chunk-
|
|
1
|
+
import { getCatalogModelInfo } from './chunk-A3T2A2WU.js';
|
|
2
2
|
|
|
3
3
|
// src/internal/llm/model-capabilities.ts
|
|
4
4
|
var CONSERVATIVE_DEFAULTS = {
|
|
@@ -54,5 +54,5 @@ function inferVendorPrefix(bare) {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
export { isAnthropicFamilyModel, resolveModelCapabilities };
|
|
57
|
-
//# sourceMappingURL=chunk-
|
|
58
|
-
//# sourceMappingURL=chunk-
|
|
57
|
+
//# sourceMappingURL=chunk-4XYCF5PA.js.map
|
|
58
|
+
//# sourceMappingURL=chunk-4XYCF5PA.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/llm/model-capabilities.ts"],"names":[],"mappings":";;;AAgCA,IAAM,qBAAA,GAA2C;AAAA,EAC/C,cAAA,EAAgB,KAAA;AAAA,EAChB,wBAAA,EAA0B,KAAA;AAAA,EAC1B,eAAA,EAAiB,KAAA;AAAA,EACjB,oBAAA,EAAsB,KAAA;AAAA,EACtB,gBAAA,EAAkB,IAAA;AAAA,EAClB,eAAA,EAAiB;AACnB,CAAA;AAGA,IAAM,gBAAA,GAAmB,CAAC,aAAA,EAAe,SAAA,EAAW,UAAU,CAAA;AAM9D,SAAS,gBAAgB,CAAA,EAAoC;AAC3D,EAAA,OAAO;AAAA,IACL,cAAA,EAAgB,EAAE,UAAA,EAAY,KAAA,EAAO,SAAS,OAAO,CAAA,IAAK,EAAE,UAAA,IAAc,KAAA;AAAA,IAC1E,wBAAA,EAA0B,EAAE,iBAAA,IAAqB,KAAA;AAAA,IACjD,eAAA,EAAiB,EAAE,SAAA,IAAa,KAAA;AAAA,IAChC,oBAAA,EAAuB,EAAkC,aAAA,IAAiB,KAAA;AAAA,IAC1E,gBAAA,EAAkB,CAAA,CAAE,KAAA,EAAO,OAAA,IAAW,qBAAA,CAAsB,gBAAA;AAAA,IAC5D,eAAA,EAAiB,CAAA,CAAE,KAAA,EAAO,MAAA,IAAU,qBAAA,CAAsB;AAAA,GAC5D;AACF;AAWO,SAAS,yBAAyB,OAAA,EAAoC;AAC3E,EAAA,MAAM,IAAA,GAAO,kBAAA,CAAmB,kBAAA,CAAmB,OAAO,CAAC,CAAA;AAG3D,EAAA,MAAM,SAAA,GAAY,oBAAoB,IAAI,CAAA;AAC1C,EAAA,IAAI,SAAA,KAAc,MAAA,EAAW,OAAO,eAAA,CAAgB,SAAS,CAAA;AAG7D,EAAA,MAAM,UAAA,GAAa,kBAAkB,IAAI,CAAA;AACzC,EAAA,IAAI,eAAe,IAAA,EAAM;AACvB,IAAA,MAAM,QAAA,GAAW,oBAAoB,UAAU,CAAA;AAC/C,IAAA,IAAI,QAAA,KAAa,MAAA,EAAW,OAAO,eAAA,CAAgB,QAAQ,CAAA;AAAA,EAC7D;AACA,EAAA,OAAO,qBAAA;AACT;AAUO,SAAS,uBAAuB,OAAA,EAAsC;AAC3E,EAAA,IAAI,OAAA,KAAY,QAAW,OAAO,KAAA;AAClC,EAAA,OAAO,uBAAA,CAAwB,IAAA,CAAK,kBAAA,CAAmB,OAAO,CAAC,CAAA;AACjE;AAEA,SAAS,mBAAmB,OAAA,EAAyB;AACnD,EAAA,KAAA,MAAW,UAAU,gBAAA,EAAkB;AACrC,IAAA,IAAI,OAAA,CAAQ,WAAW,MAAM,CAAA,SAAU,OAAA,CAAQ,KAAA,CAAM,OAAO,MAAM,CAAA;AAAA,EACpE;AACA,EAAA,OAAO,OAAA;AACT;AAOA,SAAS,mBAAmB,OAAA,EAAyB;AACnD,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA;AAC7B,EAAA,OAAO,KAAK,CAAA,GAAI,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,GAAI,OAAA;AACxC;AAGA,SAAS,kBAAkB,IAAA,EAAsB;AAC/C,EAAA,IAAI,KAAK,UAAA,CAAW,QAAQ,CAAA,EAAG,OAAO,aAAa,IAAI,CAAA,CAAA;AACvD,EAAA,IAAI,IAAA,CAAK,UAAA,CAAW,MAAM,CAAA,IAAK,IAAA,CAAK,WAAW,IAAI,CAAA,IAAK,IAAA,CAAK,UAAA,CAAW,IAAI,CAAA;AAC1E,IAAA,OAAO,UAAU,IAAI,CAAA,CAAA;AACvB,EAAA,IAAI,KAAK,UAAA,CAAW,QAAQ,CAAA,EAAG,OAAO,UAAU,IAAI,CAAA,CAAA;AACpD,EAAA,OAAO,IAAA;AACT","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/internal/llm/model-capabilities.ts"],"names":[],"mappings":";;;AAgCA,IAAM,qBAAA,GAA2C;AAAA,EAC/C,cAAA,EAAgB,KAAA;AAAA,EAChB,wBAAA,EAA0B,KAAA;AAAA,EAC1B,eAAA,EAAiB,KAAA;AAAA,EACjB,oBAAA,EAAsB,KAAA;AAAA,EACtB,gBAAA,EAAkB,IAAA;AAAA,EAClB,eAAA,EAAiB;AACnB,CAAA;AAGA,IAAM,gBAAA,GAAmB,CAAC,aAAA,EAAe,SAAA,EAAW,UAAU,CAAA;AAM9D,SAAS,gBAAgB,CAAA,EAAoC;AAC3D,EAAA,OAAO;AAAA,IACL,cAAA,EAAgB,EAAE,UAAA,EAAY,KAAA,EAAO,SAAS,OAAO,CAAA,IAAK,EAAE,UAAA,IAAc,KAAA;AAAA,IAC1E,wBAAA,EAA0B,EAAE,iBAAA,IAAqB,KAAA;AAAA,IACjD,eAAA,EAAiB,EAAE,SAAA,IAAa,KAAA;AAAA,IAChC,oBAAA,EAAuB,EAAkC,aAAA,IAAiB,KAAA;AAAA,IAC1E,gBAAA,EAAkB,CAAA,CAAE,KAAA,EAAO,OAAA,IAAW,qBAAA,CAAsB,gBAAA;AAAA,IAC5D,eAAA,EAAiB,CAAA,CAAE,KAAA,EAAO,MAAA,IAAU,qBAAA,CAAsB;AAAA,GAC5D;AACF;AAWO,SAAS,yBAAyB,OAAA,EAAoC;AAC3E,EAAA,MAAM,IAAA,GAAO,kBAAA,CAAmB,kBAAA,CAAmB,OAAO,CAAC,CAAA;AAG3D,EAAA,MAAM,SAAA,GAAY,oBAAoB,IAAI,CAAA;AAC1C,EAAA,IAAI,SAAA,KAAc,MAAA,EAAW,OAAO,eAAA,CAAgB,SAAS,CAAA;AAG7D,EAAA,MAAM,UAAA,GAAa,kBAAkB,IAAI,CAAA;AACzC,EAAA,IAAI,eAAe,IAAA,EAAM;AACvB,IAAA,MAAM,QAAA,GAAW,oBAAoB,UAAU,CAAA;AAC/C,IAAA,IAAI,QAAA,KAAa,MAAA,EAAW,OAAO,eAAA,CAAgB,QAAQ,CAAA;AAAA,EAC7D;AACA,EAAA,OAAO,qBAAA;AACT;AAUO,SAAS,uBAAuB,OAAA,EAAsC;AAC3E,EAAA,IAAI,OAAA,KAAY,QAAW,OAAO,KAAA;AAClC,EAAA,OAAO,uBAAA,CAAwB,IAAA,CAAK,kBAAA,CAAmB,OAAO,CAAC,CAAA;AACjE;AAEA,SAAS,mBAAmB,OAAA,EAAyB;AACnD,EAAA,KAAA,MAAW,UAAU,gBAAA,EAAkB;AACrC,IAAA,IAAI,OAAA,CAAQ,WAAW,MAAM,CAAA,SAAU,OAAA,CAAQ,KAAA,CAAM,OAAO,MAAM,CAAA;AAAA,EACpE;AACA,EAAA,OAAO,OAAA;AACT;AAOA,SAAS,mBAAmB,OAAA,EAAyB;AACnD,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA;AAC7B,EAAA,OAAO,KAAK,CAAA,GAAI,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,GAAI,OAAA;AACxC;AAGA,SAAS,kBAAkB,IAAA,EAAsB;AAC/C,EAAA,IAAI,KAAK,UAAA,CAAW,QAAQ,CAAA,EAAG,OAAO,aAAa,IAAI,CAAA,CAAA;AACvD,EAAA,IAAI,IAAA,CAAK,UAAA,CAAW,MAAM,CAAA,IAAK,IAAA,CAAK,WAAW,IAAI,CAAA,IAAK,IAAA,CAAK,UAAA,CAAW,IAAI,CAAA;AAC1E,IAAA,OAAO,UAAU,IAAI,CAAA,CAAA;AACvB,EAAA,IAAI,KAAK,UAAA,CAAW,QAAQ,CAAA,EAAG,OAAO,UAAU,IAAI,CAAA,CAAA;AACpD,EAAA,OAAO,IAAA;AACT","file":"chunk-4XYCF5PA.js","sourcesContent":["/**\n * T3.10c — Model capability registry (DR3 #17).\n *\n * Typed per-model flags that let the SDK gate features at the boundary\n * (before hitting the provider) instead of letting opaque 400s surface.\n *\n * Resolution algorithm:\n * 1. Strip routing prefixes (openrouter/, vertex/, bedrock/) AND the\n * OpenRouter `:variant` suffix (:free/:nitro/…) to find the bare vendor id.\n * 2. Exact match in the `EXACT` catalog → return entry.\n * 3. Vendor inference (e.g., `claude-*` → `anthropic/claude-*`) → return entry.\n * 4. No match → conservative defaults (all false, minimum tokens).\n *\n * Module is internal, but `ModelCapabilities` + `resolveModelCapabilities` are\n * re-exported publicly via the `@theokit/sdk/models` subpath (see their @public tags).\n */\n\n/**\n * Per-model capability shape. Consumers use this to gate features at\n * the SDK boundary (before request construction, not after 400).\n *\n * @public\n */\nexport interface ModelCapabilities {\n supportsVision: boolean;\n supportsStructuredOutput: boolean;\n supportsToolUse: boolean;\n supportsCacheControl: boolean;\n maxContextTokens: number;\n maxOutputTokens: number;\n}\n\nconst CONSERVATIVE_DEFAULTS: ModelCapabilities = {\n supportsVision: false,\n supportsStructuredOutput: false,\n supportsToolUse: false,\n supportsCacheControl: false,\n maxContextTokens: 4096,\n maxOutputTokens: 4096,\n};\n\n/** Routing prefixes to strip to find the underlying vendor model. */\nconst ROUTING_PREFIXES = [\"openrouter/\", \"vertex/\", \"bedrock/\"] as const;\n\nimport { getCatalogModelInfo } from \"../providers/catalog-loader.js\";\nimport type { CatalogModel } from \"../providers/catalog-schema.js\";\n\n/** Map a catalog model block (models.dev shape) to the SDK's ModelCapabilities (M44 — catalog-backed). */\nfunction capsFromCatalog(m: CatalogModel): ModelCapabilities {\n return {\n supportsVision: m.modalities?.input?.includes(\"image\") ?? m.attachment ?? false,\n supportsStructuredOutput: m.structured_output ?? false,\n supportsToolUse: m.tool_call ?? false,\n supportsCacheControl: (m as { cache_control?: boolean }).cache_control ?? false,\n maxContextTokens: m.limit?.context ?? CONSERVATIVE_DEFAULTS.maxContextTokens,\n maxOutputTokens: m.limit?.output ?? CONSERVATIVE_DEFAULTS.maxOutputTokens,\n };\n}\n\n/**\n * Resolve per-model capability flags (vision/structured-output/tool-use/cache +\n * `maxContextTokens`/`maxOutputTokens`) for a model id. Pure, sync, offline (a\n * static catalog — no network). Strips routing prefixes (`openrouter/`/`vertex/`/\n * `bedrock/`) and OpenRouter `:variant` suffixes before lookup; unknown models get\n * conservative defaults. Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport function resolveModelCapabilities(modelId: string): ModelCapabilities {\n const bare = stripVariantSuffix(stripRoutingPrefix(modelId));\n // M44 — the catalog model-info index replaced the hand-curated EXACT map (single source of truth; the\n // vendored provider-catalog.json carries the migrated data — parity-tested against the old map snapshot).\n const fromIndex = getCatalogModelInfo(bare);\n if (fromIndex !== undefined) return capsFromCatalog(fromIndex);\n // Routing-prefixed models (vertex/claude-3-5-sonnet) strip to bare\n // model name without vendor. Try inferring the vendor from the name.\n const withVendor = inferVendorPrefix(bare);\n if (withVendor !== bare) {\n const vendored = getCatalogModelInfo(withVendor);\n if (vendored !== undefined) return capsFromCatalog(vendored);\n }\n return CONSERVATIVE_DEFAULTS;\n}\n\n/**\n * B-412 / B-475 — whether a model id names an Anthropic model the loop sends cacheable system\n * blocks to. Decided by the id, not by the catalog's `supportsCacheControl`, which is false for the\n * Anthropic ids measured on OpenRouter. After the same routing prefixes the capability lookup\n * strips (`openrouter/`, `vertex/`, `bedrock/`), the id must start with `anthropic/` or `claude`,\n * so Vertex Anthropic ids match and Bedrock ids (`anthropic.claude-…`) do not.\n * @internal\n */\nexport function isAnthropicFamilyModel(modelId: string | undefined): boolean {\n if (modelId === undefined) return false;\n return /^(anthropic\\/|claude)/.test(stripRoutingPrefix(modelId));\n}\n\nfunction stripRoutingPrefix(modelId: string): string {\n for (const prefix of ROUTING_PREFIXES) {\n if (modelId.startsWith(prefix)) return modelId.slice(prefix.length);\n }\n return modelId;\n}\n\n/**\n * Strip an OpenRouter variant suffix (`:free`/`:nitro`/`:floor`/`:beta`/…) so the\n * catalog lookup hits the underlying model. Model slugs contain no `:` except the\n * variant separator, so cutting at the first `:` is safe.\n */\nfunction stripVariantSuffix(modelId: string): string {\n const i = modelId.indexOf(\":\");\n return i >= 0 ? modelId.slice(0, i) : modelId;\n}\n\n/** Infer vendor prefix from bare model name for routing-prefixed lookups. */\nfunction inferVendorPrefix(bare: string): string {\n if (bare.startsWith(\"claude\")) return `anthropic/${bare}`;\n if (bare.startsWith(\"gpt-\") || bare.startsWith(\"o1\") || bare.startsWith(\"o3\"))\n return `openai/${bare}`;\n if (bare.startsWith(\"gemini\")) return `google/${bare}`;\n return bare;\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { sessions, transcriptKey, hydratedKeys } from './chunk-2XC6KDJM.js';
|
|
2
1
|
import { persistTurn, readSessionMessages } from './chunk-4E4D6H77.js';
|
|
2
|
+
import { sessions, transcriptKey, hydratedKeys } from './chunk-2XC6KDJM.js';
|
|
3
3
|
import { diag } from './chunk-3OY6H3I7.js';
|
|
4
4
|
|
|
5
5
|
// src/internal/session/agent-session.ts
|
|
@@ -46,7 +46,7 @@ function persistTurnToTranscript(store, loc, sessionId, turn, onCompact) {
|
|
|
46
46
|
const count = (recordCounts.get(key) ?? 0) + 1;
|
|
47
47
|
recordCounts.set(key, count);
|
|
48
48
|
if (turn.autoCompact !== void 0) {
|
|
49
|
-
const { autoCompactIfNeeded } = await import('./compact-session-
|
|
49
|
+
const { autoCompactIfNeeded } = await import('./compact-session-XPJS27JD.js');
|
|
50
50
|
const fired = await autoCompactIfNeeded({
|
|
51
51
|
store,
|
|
52
52
|
loc,
|
|
@@ -105,5 +105,5 @@ function enqueueSessionWrite(cwd, agentId, fn) {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
export { appendSessionMessage, clearSession, discardSession, enqueueSessionWrite, flushSessionWrites, getSessionMessages, hydrateSession, persistTurnToTranscript };
|
|
108
|
-
//# sourceMappingURL=chunk-
|
|
109
|
-
//# sourceMappingURL=chunk-
|
|
108
|
+
//# sourceMappingURL=chunk-6WPNFZH3.js.map
|
|
109
|
+
//# sourceMappingURL=chunk-6WPNFZH3.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/session/agent-session.ts"],"names":[],"mappings":"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","file":"chunk-PSMWZYW6.js","sourcesContent":["import type { SessionStore } from \"../../types/session-store.js\";\nimport {\n type PersistTurnInput,\n persistTurn,\n readSessionMessages,\n type TranscriptLocation,\n} from \"./agent-session-store.js\";\n\n/**\n * Per-agent conversation history kept across runs (and across `Agent.resume()`\n * within the same process). Lets the fixture responder recall prior facts when\n * the user asks a follow-up question.\n *\n * SE40 — disk persistence IS the native Claude-shaped `.jsonl` transcript. The\n * in-memory cache holds the narrowed `SessionMessage[]` (user/assistant text) so\n * a send can read `priorMessages` synchronously; the whole rich turn (user +\n * assistant + tool blocks) lands on disk once per send via {@link persistTurnToTranscript}\n * (fed by `run.conversation()`). Hydration on resume reconstructs the session by\n * walking the transcript DAG (`readSessionMessages`).\n *\n * @internal\n */\n\n// `SessionMessage` lives in `./session-types.ts` (leaf types file). Re-exported\n// for back-compat with downstream importers that pulled it from here.\nexport type { SessionMessage } from \"./types.js\";\n\nimport type { SessionMessage } from \"./types.js\";\n\n// M75 — the cache lives in a leaf; see session-cache.ts for the reason (cycle broken by extraction).\nexport {\n hydratedKeys,\n invalidateSessionCache,\n sessions,\n transcriptKey,\n} from \"./session-cache.js\";\n\nimport { diag } from \"../diagnostics.js\";\nimport { globalSingleton } from \"../global-singleton.js\";\nimport { hydratedKeys, sessions, transcriptKey } from \"./session-cache.js\";\n\nconst pendingWrites = new Map<string, Promise<void>>();\nconst recordCounts = new Map<string, number>();\n\n/**\n * Append a session message to the in-memory cache only. Disk persistence for the\n * whole turn happens once per send via {@link persistTurnToTranscript}; the cache\n * feeds `priorMessages` / `onBeforeSend.previousMessageCount` synchronously.\n *\n * @internal\n */\nexport function appendSessionMessage(agentId: string, message: SessionMessage): void {\n const existing = sessions.get(agentId) ?? [];\n existing.push(message);\n // `delete` + `set` reinserts at the END: a JS `Map` preserves insertion order, so the first key\n // is always the least recently touched. That is the entire LRU, with no new structure (parsimony\n // rungs 2/5 — the ordering we need is already a language guarantee).\n sessions.delete(agentId);\n sessions.set(agentId, existing);\n enforceCeiling();\n}\n\n/**\n * Ceiling on sessions kept in memory.\n *\n * The runtime only reads the **active** session; the rest is pure cache, rebuildable from the\n * on-disk transcript. 32 is deliberately generous — the primary removal path is the explicit\n * `discardSession()` at the end of the agent's life, and this ceiling is a safety net against a\n * long-lived process running hundreds of sessions (plan risk #2: a tight ceiling could evict a\n * session still referenced by an in-flight async path).\n */\nexport const MAX_CACHED_SESSIONS = 32;\n\nfunction enforceCeiling(): void {\n while (sessions.size > MAX_CACHED_SESSIONS) {\n const oldest = sessions.keys().next().value;\n if (oldest === undefined) return;\n sessions.delete(oldest);\n forgetBookkeeping(oldest);\n }\n}\n\n/**\n * Erases the bookkeeping for an `agentId` across EVERY `cwd` it appears in.\n *\n * The three maps are keyed by `transcriptKey(cwd, agentId)`; `sessions` is the only one keyed by the\n * raw `agentId`. The ceiling's first version deleted from all three using `sessions`' key — that is,\n * deleted nothing — and left `hydratedKeys` **orphaned**. Since `hydrateSession` returns early when\n * the marker is present, an evicted session came back **empty** instead of rehydrating from disk:\n * silent amnesia, and a regression new to M95, because before it nothing evicted.\n *\n * The ceiling only knows the `agentId`, not the `cwd`, so it scans by suffix — which is the format\n * `transcriptKey` produces. A scan rather than an index because these maps hold tens of entries, not\n * thousands: a reverse index here would be new structure for a problem that does not exist.\n */\nfunction forgetBookkeeping(agentId: string): void {\n const suffix = transcriptKey(\"\", agentId).slice(0 - agentId.length - 2);\n for (const k of [...hydratedKeys]) if (k.endsWith(suffix)) hydratedKeys.delete(k);\n for (const k of [...pendingWrites.keys()]) if (k.endsWith(suffix)) pendingWrites.delete(k);\n for (const k of [...recordCounts.keys()]) if (k.endsWith(suffix)) recordCounts.delete(k);\n}\n\n/**\n * Erases the agent's module bookkeeping and returns how many entries were removed.\n *\n * M95 — `invalidateSessionCache` used to clear **two** of the four maps (`sessions`, `hydratedKeys`);\n * `pendingWrites` and `recordCounts` were never touched by id, so they grew for the life of the\n * process. Neither is large per entry — the leak is in count, not volume — but a cache with no owner\n * for removal is a cache that only grows.\n *\n * Returns the count so the caller can prove the removal; a second discard returns 0, which is what\n * makes the idempotency test possible without exposing the maps.\n */\nexport function discardSession(cwd: string, agentId: string): number {\n const key = transcriptKey(cwd, agentId);\n let removed = 0;\n // `sessions` is NOT erased here — and the distinction is measured, not aesthetic. It holds the\n // readable conversation, and there is a legitimate reader AFTER dispose: the golden\n // `two-concurrent-sends-serialize` calls `getSessionMessages(agentId)` after `agent.dispose()`.\n // Erasing it here returned an empty list and broke two goldens. What bounds it is the LRU ceiling\n // above; the three below are pure bookkeeping, with no post-dispose reader.\n //\n // The key is `transcriptKey(cwd, agentId)` in ALL THREE — not the raw `agentId`. The first version\n // erased two of them by `agentId` and therefore **never erased anything**; the test did not catch\n // it because it only asserted that the SECOND call returns 0, which is true either way.\n if (hydratedKeys.delete(key)) removed++;\n if (pendingWrites.delete(key)) removed++;\n if (recordCounts.delete(key)) removed++;\n return removed;\n}\n\nexport function getSessionMessages(agentId: string): SessionMessage[] {\n return sessions.get(agentId) ?? [];\n}\n\n/**\n * Persist a full conversation turn (user + assistant + tool blocks) to the native\n * transcript. Chained per-(agent, transcript) so on-disk order matches send order,\n * and fire-and-forget so `send()` is not blocked by disk I/O. Every\n * M50 — when the caller supplies `turn.autoCompact`, size-driven auto-compaction (usage real vs\n * the model's context window) runs in this same chain, surfaced via the optional `onCompact` observer.\n *\n * @internal\n */\nexport function persistTurnToTranscript(\n store: SessionStore,\n loc: TranscriptLocation,\n sessionId: string,\n turn: PersistTurnInput,\n onCompact?: () => void,\n): void {\n const key = transcriptKey(loc.cwd, loc.agentId);\n // PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n // sweeping these files (a nested root under refactor/). It is not new code and was not touched\n // by M75; refactoring SDK internals without review would trade a visible problem for a diff\n // risky. Tracked in usetheodev/theokit-sdk#151.\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: see the reason just above\n const chained = (pendingWrites.get(key) ?? Promise.resolve()).then(async () => {\n try {\n await persistTurn(store, loc, sessionId, turn);\n const count = (recordCounts.get(key) ?? 0) + 1;\n recordCounts.set(key, count);\n // M50 — the 50-turn no-summary boundary stub is GONE (it silently amnesia'd the session).\n // Auto-compaction is now size-driven with a real summary: see `maybeAutoCompact` below,\n // invoked in this same write chain by the post-run lifecycle when usage is known.\n if (turn.autoCompact !== undefined) {\n const { autoCompactIfNeeded } = await import(\"./compact-session.js\");\n const fired = await autoCompactIfNeeded({\n store,\n loc,\n sessionId,\n usageTotal: turn.autoCompact.usageTotal,\n contextWindow: turn.autoCompact.contextWindow,\n turnCount: count,\n summarize: turn.autoCompact.summarize,\n });\n if (fired) onCompact?.();\n }\n } catch (cause) {\n const msg = cause instanceof Error ? cause.message : String(cause);\n diag(`[theokit-sdk] session transcript write failed (${loc.agentId}): ${msg}\\n`);\n }\n });\n pendingWrites.set(\n key,\n chained.then(\n () => undefined,\n () => undefined,\n ),\n );\n}\n\n/**\n * Load the persisted transcript into the in-memory cache. Idempotent per\n * (baseDir, cwd, agentId). Call once per agent lifecycle before the first read.\n *\n * @internal\n */\nexport async function hydrateSession(\n agentId: string,\n loc: { store: SessionStore; cwd: string },\n): Promise<void> {\n const key = transcriptKey(loc.cwd, agentId);\n if (hydratedKeys.has(key)) return;\n hydratedKeys.add(key);\n\n const persisted = await readSessionMessages(loc.store, agentId);\n if (persisted.length === 0) return;\n // M51 review F4 — the DISK is the source of truth at hydration time: after an invalidation\n // (compact/inject), an in-flight turn may have repopulated the cache with a SINGLE message before\n // this hydrate ran; the old \"skip when non-empty\" guard then pinned the parent to a 1-message\n // context (history + injected pair lost until restart). The persist chain serializes writes, so\n // the disk already contains that in-flight turn — replacing is always correct.\n sessions.set(agentId, persisted);\n}\n\n/**\n * Wait for all pending transcript writes to settle. Used by tests and by the\n * agent dispose path so on-disk state matches in-memory before the caller proceeds.\n *\n * @internal\n */\nexport async function flushSessionWrites(): Promise<void> {\n while (pendingWrites.size > 0) {\n const all = Array.from(pendingWrites.values());\n pendingWrites.clear();\n await Promise.all(all);\n }\n}\n\n/**\n * Drop the in-memory message cache for `agentId` and NOTHING else — the hydration marker in\n * `hydratedKeys` deliberately stays.\n *\n * That asymmetry is the feature, not an oversight, and it is what separates this from\n * `invalidateSessionCache`, which drops both. The single caller is the personality switch's\n * `reset: true` path (`internal/personality/switch.ts`): leaving the marker set makes\n * `hydrateSession` return early, so the next send starts from an EMPTY context instead of\n * replaying the pre-reset transcript off disk. Clearing the marker here would re-hydrate the\n * conversation the reset was asked to discard.\n *\n * The same shape read as a bug one function up: `forgetBookkeeping` documents an evicted session\n * coming back empty as \"silent amnesia\". The difference is intent — eviction wants the transcript\n * back, a reset does not. Anyone reaching for this to invalidate a cache wants\n * `invalidateSessionCache(cwd, agentId)` instead.\n */\nexport function clearSession(agentId: string): void {\n sessions.delete(agentId);\n}\n\n/**\n * M50 review F5 — run `fn` serialized on the SAME per-(cwd,agentId) write chain the per-turn\n * persistence uses, so a manual `Agent.compact` can never interleave with an in-flight turn's\n * writes (boundary landing mid-turn would orphan the turn from the replay).\n */\nexport function enqueueSessionWrite<T>(\n cwd: string,\n agentId: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const key = transcriptKey(cwd, agentId);\n const prior = pendingWrites.get(key) ?? Promise.resolve();\n const result = prior.then(fn);\n pendingWrites.set(\n key,\n result.then(\n () => undefined,\n () => undefined,\n ),\n );\n return result;\n}\n\n/** Test-only: drop every cached session and hydration marker. @internal */\nexport function clearAllSessions(): void {\n sessions.clear();\n hydratedKeys.clear();\n recordCounts.clear();\n // M50 review F11 — the auto-compact attempt marks live on globalThis; tests reset them here.\n // Through the helper, with the SAME key compact-session.ts uses: two files hand-rolling one slot is\n // how two copies of a mechanism drift apart.\n globalSingleton(\n \"theokit-sdk.session.auto-compact-attempts\",\n () => new Map<string, number>(),\n ).clear();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/session/agent-session.ts"],"names":[],"mappings":"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","file":"chunk-6WPNFZH3.js","sourcesContent":["import type { SessionStore } from \"../../types/session-store.js\";\nimport {\n type PersistTurnInput,\n persistTurn,\n readSessionMessages,\n type TranscriptLocation,\n} from \"./agent-session-store.js\";\n\n/**\n * Per-agent conversation history kept across runs (and across `Agent.resume()`\n * within the same process). Lets the fixture responder recall prior facts when\n * the user asks a follow-up question.\n *\n * SE40 — disk persistence IS the native Claude-shaped `.jsonl` transcript. The\n * in-memory cache holds the narrowed `SessionMessage[]` (user/assistant text) so\n * a send can read `priorMessages` synchronously; the whole rich turn (user +\n * assistant + tool blocks) lands on disk once per send via {@link persistTurnToTranscript}\n * (fed by `run.conversation()`). Hydration on resume reconstructs the session by\n * walking the transcript DAG (`readSessionMessages`).\n *\n * @internal\n */\n\n// `SessionMessage` lives in `./session-types.ts` (leaf types file). Re-exported\n// for back-compat with downstream importers that pulled it from here.\nexport type { SessionMessage } from \"./types.js\";\n\nimport type { SessionMessage } from \"./types.js\";\n\n// M75 — the cache lives in a leaf; see session-cache.ts for the reason (cycle broken by extraction).\nexport {\n hydratedKeys,\n invalidateSessionCache,\n sessions,\n transcriptKey,\n} from \"./session-cache.js\";\n\nimport { diag } from \"../diagnostics.js\";\nimport { globalSingleton } from \"../global-singleton.js\";\nimport { hydratedKeys, sessions, transcriptKey } from \"./session-cache.js\";\n\nconst pendingWrites = new Map<string, Promise<void>>();\nconst recordCounts = new Map<string, number>();\n\n/**\n * Append a session message to the in-memory cache only. Disk persistence for the\n * whole turn happens once per send via {@link persistTurnToTranscript}; the cache\n * feeds `priorMessages` / `onBeforeSend.previousMessageCount` synchronously.\n *\n * @internal\n */\nexport function appendSessionMessage(agentId: string, message: SessionMessage): void {\n const existing = sessions.get(agentId) ?? [];\n existing.push(message);\n // `delete` + `set` reinserts at the END: a JS `Map` preserves insertion order, so the first key\n // is always the least recently touched. That is the entire LRU, with no new structure (parsimony\n // rungs 2/5 — the ordering we need is already a language guarantee).\n sessions.delete(agentId);\n sessions.set(agentId, existing);\n enforceCeiling();\n}\n\n/**\n * Ceiling on sessions kept in memory.\n *\n * The runtime only reads the **active** session; the rest is pure cache, rebuildable from the\n * on-disk transcript. 32 is deliberately generous — the primary removal path is the explicit\n * `discardSession()` at the end of the agent's life, and this ceiling is a safety net against a\n * long-lived process running hundreds of sessions (plan risk #2: a tight ceiling could evict a\n * session still referenced by an in-flight async path).\n */\nexport const MAX_CACHED_SESSIONS = 32;\n\nfunction enforceCeiling(): void {\n while (sessions.size > MAX_CACHED_SESSIONS) {\n const oldest = sessions.keys().next().value;\n if (oldest === undefined) return;\n sessions.delete(oldest);\n forgetBookkeeping(oldest);\n }\n}\n\n/**\n * Erases the bookkeeping for an `agentId` across EVERY `cwd` it appears in.\n *\n * The three maps are keyed by `transcriptKey(cwd, agentId)`; `sessions` is the only one keyed by the\n * raw `agentId`. The ceiling's first version deleted from all three using `sessions`' key — that is,\n * deleted nothing — and left `hydratedKeys` **orphaned**. Since `hydrateSession` returns early when\n * the marker is present, an evicted session came back **empty** instead of rehydrating from disk:\n * silent amnesia, and a regression new to M95, because before it nothing evicted.\n *\n * The ceiling only knows the `agentId`, not the `cwd`, so it scans by suffix — which is the format\n * `transcriptKey` produces. A scan rather than an index because these maps hold tens of entries, not\n * thousands: a reverse index here would be new structure for a problem that does not exist.\n */\nfunction forgetBookkeeping(agentId: string): void {\n const suffix = transcriptKey(\"\", agentId).slice(0 - agentId.length - 2);\n for (const k of [...hydratedKeys]) if (k.endsWith(suffix)) hydratedKeys.delete(k);\n for (const k of [...pendingWrites.keys()]) if (k.endsWith(suffix)) pendingWrites.delete(k);\n for (const k of [...recordCounts.keys()]) if (k.endsWith(suffix)) recordCounts.delete(k);\n}\n\n/**\n * Erases the agent's module bookkeeping and returns how many entries were removed.\n *\n * M95 — `invalidateSessionCache` used to clear **two** of the four maps (`sessions`, `hydratedKeys`);\n * `pendingWrites` and `recordCounts` were never touched by id, so they grew for the life of the\n * process. Neither is large per entry — the leak is in count, not volume — but a cache with no owner\n * for removal is a cache that only grows.\n *\n * Returns the count so the caller can prove the removal; a second discard returns 0, which is what\n * makes the idempotency test possible without exposing the maps.\n */\nexport function discardSession(cwd: string, agentId: string): number {\n const key = transcriptKey(cwd, agentId);\n let removed = 0;\n // `sessions` is NOT erased here — and the distinction is measured, not aesthetic. It holds the\n // readable conversation, and there is a legitimate reader AFTER dispose: the golden\n // `two-concurrent-sends-serialize` calls `getSessionMessages(agentId)` after `agent.dispose()`.\n // Erasing it here returned an empty list and broke two goldens. What bounds it is the LRU ceiling\n // above; the three below are pure bookkeeping, with no post-dispose reader.\n //\n // The key is `transcriptKey(cwd, agentId)` in ALL THREE — not the raw `agentId`. The first version\n // erased two of them by `agentId` and therefore **never erased anything**; the test did not catch\n // it because it only asserted that the SECOND call returns 0, which is true either way.\n if (hydratedKeys.delete(key)) removed++;\n if (pendingWrites.delete(key)) removed++;\n if (recordCounts.delete(key)) removed++;\n return removed;\n}\n\nexport function getSessionMessages(agentId: string): SessionMessage[] {\n return sessions.get(agentId) ?? [];\n}\n\n/**\n * Persist a full conversation turn (user + assistant + tool blocks) to the native\n * transcript. Chained per-(agent, transcript) so on-disk order matches send order,\n * and fire-and-forget so `send()` is not blocked by disk I/O. Every\n * M50 — when the caller supplies `turn.autoCompact`, size-driven auto-compaction (usage real vs\n * the model's context window) runs in this same chain, surfaced via the optional `onCompact` observer.\n *\n * @internal\n */\nexport function persistTurnToTranscript(\n store: SessionStore,\n loc: TranscriptLocation,\n sessionId: string,\n turn: PersistTurnInput,\n onCompact?: () => void,\n): void {\n const key = transcriptKey(loc.cwd, loc.agentId);\n // PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n // sweeping these files (a nested root under refactor/). It is not new code and was not touched\n // by M75; refactoring SDK internals without review would trade a visible problem for a diff\n // risky. Tracked in usetheodev/theokit-sdk#151.\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: see the reason just above\n const chained = (pendingWrites.get(key) ?? Promise.resolve()).then(async () => {\n try {\n await persistTurn(store, loc, sessionId, turn);\n const count = (recordCounts.get(key) ?? 0) + 1;\n recordCounts.set(key, count);\n // M50 — the 50-turn no-summary boundary stub is GONE (it silently amnesia'd the session).\n // Auto-compaction is now size-driven with a real summary: see `maybeAutoCompact` below,\n // invoked in this same write chain by the post-run lifecycle when usage is known.\n if (turn.autoCompact !== undefined) {\n const { autoCompactIfNeeded } = await import(\"./compact-session.js\");\n const fired = await autoCompactIfNeeded({\n store,\n loc,\n sessionId,\n usageTotal: turn.autoCompact.usageTotal,\n contextWindow: turn.autoCompact.contextWindow,\n turnCount: count,\n summarize: turn.autoCompact.summarize,\n });\n if (fired) onCompact?.();\n }\n } catch (cause) {\n const msg = cause instanceof Error ? cause.message : String(cause);\n diag(`[theokit-sdk] session transcript write failed (${loc.agentId}): ${msg}\\n`);\n }\n });\n pendingWrites.set(\n key,\n chained.then(\n () => undefined,\n () => undefined,\n ),\n );\n}\n\n/**\n * Load the persisted transcript into the in-memory cache. Idempotent per\n * (baseDir, cwd, agentId). Call once per agent lifecycle before the first read.\n *\n * @internal\n */\nexport async function hydrateSession(\n agentId: string,\n loc: { store: SessionStore; cwd: string },\n): Promise<void> {\n const key = transcriptKey(loc.cwd, agentId);\n if (hydratedKeys.has(key)) return;\n hydratedKeys.add(key);\n\n const persisted = await readSessionMessages(loc.store, agentId);\n if (persisted.length === 0) return;\n // M51 review F4 — the DISK is the source of truth at hydration time: after an invalidation\n // (compact/inject), an in-flight turn may have repopulated the cache with a SINGLE message before\n // this hydrate ran; the old \"skip when non-empty\" guard then pinned the parent to a 1-message\n // context (history + injected pair lost until restart). The persist chain serializes writes, so\n // the disk already contains that in-flight turn — replacing is always correct.\n sessions.set(agentId, persisted);\n}\n\n/**\n * Wait for all pending transcript writes to settle. Used by tests and by the\n * agent dispose path so on-disk state matches in-memory before the caller proceeds.\n *\n * @internal\n */\nexport async function flushSessionWrites(): Promise<void> {\n while (pendingWrites.size > 0) {\n const all = Array.from(pendingWrites.values());\n pendingWrites.clear();\n await Promise.all(all);\n }\n}\n\n/**\n * Drop the in-memory message cache for `agentId` and NOTHING else — the hydration marker in\n * `hydratedKeys` deliberately stays.\n *\n * That asymmetry is the feature, not an oversight, and it is what separates this from\n * `invalidateSessionCache`, which drops both. The single caller is the personality switch's\n * `reset: true` path (`internal/personality/switch.ts`): leaving the marker set makes\n * `hydrateSession` return early, so the next send starts from an EMPTY context instead of\n * replaying the pre-reset transcript off disk. Clearing the marker here would re-hydrate the\n * conversation the reset was asked to discard.\n *\n * The same shape read as a bug one function up: `forgetBookkeeping` documents an evicted session\n * coming back empty as \"silent amnesia\". The difference is intent — eviction wants the transcript\n * back, a reset does not. Anyone reaching for this to invalidate a cache wants\n * `invalidateSessionCache(cwd, agentId)` instead.\n */\nexport function clearSession(agentId: string): void {\n sessions.delete(agentId);\n}\n\n/**\n * M50 review F5 — run `fn` serialized on the SAME per-(cwd,agentId) write chain the per-turn\n * persistence uses, so a manual `Agent.compact` can never interleave with an in-flight turn's\n * writes (boundary landing mid-turn would orphan the turn from the replay).\n */\nexport function enqueueSessionWrite<T>(\n cwd: string,\n agentId: string,\n fn: () => Promise<T>,\n): Promise<T> {\n const key = transcriptKey(cwd, agentId);\n const prior = pendingWrites.get(key) ?? Promise.resolve();\n const result = prior.then(fn);\n pendingWrites.set(\n key,\n result.then(\n () => undefined,\n () => undefined,\n ),\n );\n return result;\n}\n\n/** Test-only: drop every cached session and hydration marker. @internal */\nexport function clearAllSessions(): void {\n sessions.clear();\n hydratedKeys.clear();\n recordCounts.clear();\n // M50 review F11 — the auto-compact attempt marks live on globalThis; tests reset them here.\n // Through the helper, with the SAME key compact-session.ts uses: two files hand-rolling one slot is\n // how two copies of a mechanism drift apart.\n globalSingleton(\n \"theokit-sdk.session.auto-compact-attempts\",\n () => new Map<string, number>(),\n ).clear();\n}\n"]}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { globalSingleton } from './chunk-AGACYRJ2.js';
|
|
2
|
-
import {
|
|
3
|
-
import { readStoredOAuth } from './chunk-L2KC2G7H.js';
|
|
4
|
-
import { AuthenticationError } from './chunk-TNFOU6SB.js';
|
|
2
|
+
import { OPENAI_CHATGPT } from './chunk-Z2UVCAYS.js';
|
|
5
3
|
import { diag } from './chunk-3OY6H3I7.js';
|
|
6
4
|
import { z } from 'zod';
|
|
7
|
-
import { homedir } from 'node:os';
|
|
8
5
|
|
|
9
6
|
// src/internal/providers/registry.ts
|
|
10
7
|
var REGISTRY = globalSingleton(
|
|
@@ -1705,69 +1702,6 @@ var OPENAI = {
|
|
|
1705
1702
|
hostname: "api.openai.com",
|
|
1706
1703
|
fallbackModels: ["gpt-4o", "gpt-4o-mini"]
|
|
1707
1704
|
};
|
|
1708
|
-
var DEFAULT_STORE = {
|
|
1709
|
-
home: homedir(),
|
|
1710
|
-
dirName: ".theokit",
|
|
1711
|
-
fileName: "auth.json",
|
|
1712
|
-
homeEnvVar: "THEOKIT_AUTH_HOME"
|
|
1713
|
-
};
|
|
1714
|
-
var OPENAI_OAUTH_CONFIG = {
|
|
1715
|
-
provider: "openai",
|
|
1716
|
-
authorizeEndpoint: "https://auth.openai.com/oauth/authorize",
|
|
1717
|
-
tokenEndpoint: "https://auth.openai.com/oauth/token",
|
|
1718
|
-
clientId: "app_EMoamEEZ73f0CkXaXp7hrann",
|
|
1719
|
-
scopes: ["openid", "profile", "email", "offline_access"],
|
|
1720
|
-
redirectUri: "https://auth.openai.com/deviceauth/callback"
|
|
1721
|
-
};
|
|
1722
|
-
function codexFetch() {
|
|
1723
|
-
return (async (input, init) => {
|
|
1724
|
-
const env = process.env;
|
|
1725
|
-
const resolved = await resolveCredential({
|
|
1726
|
-
provider: "openai",
|
|
1727
|
-
store: DEFAULT_STORE,
|
|
1728
|
-
oauth: OPENAI_OAUTH_CONFIG,
|
|
1729
|
-
env
|
|
1730
|
-
});
|
|
1731
|
-
if (resolved === void 0) {
|
|
1732
|
-
throw new AuthenticationError(
|
|
1733
|
-
'openai-chatgpt: no ChatGPT credential found \u2014 run the OpenAI device login (e.g. "/login openai") first.',
|
|
1734
|
-
{ code: "missing_credential" }
|
|
1735
|
-
);
|
|
1736
|
-
}
|
|
1737
|
-
const accountId = readStoredOAuth(DEFAULT_STORE, env)?.account_id;
|
|
1738
|
-
const headers = new Headers(init?.headers);
|
|
1739
|
-
headers.set("authorization", `Bearer ${resolved.apiKey}`);
|
|
1740
|
-
if (accountId !== void 0) headers.set("ChatGPT-Account-Id", accountId);
|
|
1741
|
-
return fetch(input, { ...init, headers });
|
|
1742
|
-
});
|
|
1743
|
-
}
|
|
1744
|
-
var OPENAI_CHATGPT = {
|
|
1745
|
-
name: "openai-chatgpt",
|
|
1746
|
-
apiMode: "responses_api",
|
|
1747
|
-
authType: "oauth_device_code",
|
|
1748
|
-
baseUrl: "https://chatgpt.com/backend-api/codex",
|
|
1749
|
-
envVars: [],
|
|
1750
|
-
fallbackModels: [
|
|
1751
|
-
"openai-chatgpt/gpt-5.4",
|
|
1752
|
-
"openai-chatgpt/gpt-5.4-mini",
|
|
1753
|
-
"openai-chatgpt/gpt-5.5"
|
|
1754
|
-
],
|
|
1755
|
-
// #165 — this shipped as `codex_cli_rs`, another vendor's client identifier. Claiming to be a different
|
|
1756
|
-
// vendor's client is a false statement of identity. Third-party clients send their OWN name against
|
|
1757
|
-
// this same endpoint, which also shows the route is not restricted to the official client.
|
|
1758
|
-
extraHeaders: { originator: "theokit" },
|
|
1759
|
-
// usetheokit/theokit-sdk#383 — carry the model's encrypted reasoning between the rounds of a turn.
|
|
1760
|
-
// On for THIS profile and no other because this is the endpoint the issue measured: OpenAI Codex
|
|
1761
|
-
// sends `include: ["reasoning.encrypted_content"]` with `reasoning.context: "all_turns"` to the
|
|
1762
|
-
// same backend, same model, on the same account, so acceptance is observed rather than assumed.
|
|
1763
|
-
// The issue's measurement — a third of our bytes, 2.8x our tokens — is what this closes together
|
|
1764
|
-
// with `prompt_cache_key`.
|
|
1765
|
-
encryptedReasoning: true,
|
|
1766
|
-
transform: {
|
|
1767
|
-
// Only `fetch` (async) can await the credential refresh; `headers` is sync and cannot.
|
|
1768
|
-
fetch: () => codexFetch()
|
|
1769
|
-
}
|
|
1770
|
-
};
|
|
1771
1705
|
|
|
1772
1706
|
// src/internal/providers/builtin/openrouter.ts
|
|
1773
1707
|
var OPENROUTER = {
|
|
@@ -1878,5 +1812,5 @@ function registerBuiltins() {
|
|
|
1878
1812
|
}
|
|
1879
1813
|
|
|
1880
1814
|
export { catalogModelSchema, getCatalogCapabilities, getCatalogModelInfo, getProviderProfile, inferModelDialect, inferRegionFromModelId, isPatchedModelKey, listProviders, loadProviderCatalog, patchModelInfo, registerBuiltins, registerProvider, resolveBedrockBaseUrl, resolveVertexBaseUrl, stripBedrockPrefix, stripVertexPrefix };
|
|
1881
|
-
//# sourceMappingURL=chunk-
|
|
1882
|
-
//# sourceMappingURL=chunk-
|
|
1815
|
+
//# sourceMappingURL=chunk-A3T2A2WU.js.map
|
|
1816
|
+
//# sourceMappingURL=chunk-A3T2A2WU.js.map
|