@theokit/sdk 4.0.1 → 4.1.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 +12 -0
- package/README.md +16 -1
- package/dist/a2a/index.cjs +129 -97
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.js +129 -97
- package/dist/a2a/index.js.map +1 -1
- package/dist/{cron-L5QTlAtl.d.ts → cron-AzT5D0VP.d.ts} +89 -1
- package/dist/{cron-BfPhZjRJ.d.cts → cron-BlAjYOew.d.cts} +89 -1
- package/dist/cron.cjs +129 -97
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.d.cts +1 -1
- package/dist/cron.d.ts +1 -1
- package/dist/cron.js +129 -97
- package/dist/cron.js.map +1 -1
- package/dist/eval.cjs +129 -97
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +129 -97
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +129 -97
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +129 -97
- package/dist/index.js.map +1 -1
- package/dist/internal/persistence/fs-session-store.d.cts +26 -0
- package/dist/internal/persistence/fs-session-store.d.ts +26 -0
- package/dist/internal/runtime/session/agent-session-store.d.ts +21 -13
- package/dist/types/agent.d.ts +10 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/session-store.d.ts +59 -0
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -3520,6 +3520,72 @@ var init_cloud_tool_parity = __esm({
|
|
|
3520
3520
|
init_errors();
|
|
3521
3521
|
}
|
|
3522
3522
|
});
|
|
3523
|
+
|
|
3524
|
+
// src/internal/persistence/file-lock.ts
|
|
3525
|
+
async function getProperLockfile() {
|
|
3526
|
+
if (cached !== void 0) return cached;
|
|
3527
|
+
try {
|
|
3528
|
+
const mod = await import('proper-lockfile');
|
|
3529
|
+
if (!validateLockModule(mod)) {
|
|
3530
|
+
if (!warnedStructural) {
|
|
3531
|
+
warnedStructural = true;
|
|
3532
|
+
process.stderr.write(
|
|
3533
|
+
"[theokit-sdk] proper-lockfile: imported module does NOT expose the expected `lock`/`unlock` API surface. This may indicate a supply-chain compromise or an incompatible major version. Falling back to in-process mutex (no cross-process safety). Reinstall with: pnpm add proper-lockfile@^11\n"
|
|
3534
|
+
);
|
|
3535
|
+
}
|
|
3536
|
+
cached = null;
|
|
3537
|
+
return cached;
|
|
3538
|
+
}
|
|
3539
|
+
cached = mod;
|
|
3540
|
+
} catch {
|
|
3541
|
+
cached = null;
|
|
3542
|
+
}
|
|
3543
|
+
return cached;
|
|
3544
|
+
}
|
|
3545
|
+
function validateLockModule(mod) {
|
|
3546
|
+
if (mod === null || mod === void 0 || typeof mod !== "object") return false;
|
|
3547
|
+
const m = mod;
|
|
3548
|
+
return typeof m.lock === "function" && typeof m.unlock === "function";
|
|
3549
|
+
}
|
|
3550
|
+
async function withFileLock(path, fn, options) {
|
|
3551
|
+
const lib = await getProperLockfile();
|
|
3552
|
+
if (lib === null) {
|
|
3553
|
+
if (!warnedMissing) {
|
|
3554
|
+
warnedMissing = true;
|
|
3555
|
+
process.stderr.write(
|
|
3556
|
+
"[theokit-sdk] proper-lockfile not installed; cross-process file lock unavailable. Install with: pnpm add proper-lockfile\n"
|
|
3557
|
+
);
|
|
3558
|
+
}
|
|
3559
|
+
return withCwdMutex(`file-lock:${path}`, fn);
|
|
3560
|
+
}
|
|
3561
|
+
return withCwdMutex(`file-lock:${path}`, async () => {
|
|
3562
|
+
const release = await lib.lock(path, {
|
|
3563
|
+
// EC-1: companion lockfile, target path may not exist yet.
|
|
3564
|
+
lockfilePath: `${path}.lock`,
|
|
3565
|
+
realpath: false,
|
|
3566
|
+
stale: 3e4,
|
|
3567
|
+
retries: {
|
|
3568
|
+
retries: 5,
|
|
3569
|
+
factor: 1.5,
|
|
3570
|
+
minTimeout: 100,
|
|
3571
|
+
maxTimeout: 5e3
|
|
3572
|
+
}
|
|
3573
|
+
});
|
|
3574
|
+
try {
|
|
3575
|
+
return await fn();
|
|
3576
|
+
} finally {
|
|
3577
|
+
await release();
|
|
3578
|
+
}
|
|
3579
|
+
});
|
|
3580
|
+
}
|
|
3581
|
+
var cached, warnedMissing, warnedStructural;
|
|
3582
|
+
var init_file_lock = __esm({
|
|
3583
|
+
"src/internal/persistence/file-lock.ts"() {
|
|
3584
|
+
init_cwd_mutex();
|
|
3585
|
+
warnedMissing = false;
|
|
3586
|
+
warnedStructural = false;
|
|
3587
|
+
}
|
|
3588
|
+
});
|
|
3523
3589
|
function encodeProjectDir(cwd) {
|
|
3524
3590
|
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
3525
3591
|
}
|
|
@@ -3746,70 +3812,31 @@ var init_session_transcript = __esm({
|
|
|
3746
3812
|
};
|
|
3747
3813
|
}
|
|
3748
3814
|
});
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
if (mod === null || mod === void 0 || typeof mod !== "object") return false;
|
|
3773
|
-
const m = mod;
|
|
3774
|
-
return typeof m.lock === "function" && typeof m.unlock === "function";
|
|
3775
|
-
}
|
|
3776
|
-
async function withFileLock(path, fn, options) {
|
|
3777
|
-
const lib = await getProperLockfile();
|
|
3778
|
-
if (lib === null) {
|
|
3779
|
-
if (!warnedMissing) {
|
|
3780
|
-
warnedMissing = true;
|
|
3781
|
-
process.stderr.write(
|
|
3782
|
-
"[theokit-sdk] proper-lockfile not installed; cross-process file lock unavailable. Install with: pnpm add proper-lockfile\n"
|
|
3783
|
-
);
|
|
3784
|
-
}
|
|
3785
|
-
return withCwdMutex(`file-lock:${path}`, fn);
|
|
3786
|
-
}
|
|
3787
|
-
return withCwdMutex(`file-lock:${path}`, async () => {
|
|
3788
|
-
const release = await lib.lock(path, {
|
|
3789
|
-
// EC-1: companion lockfile, target path may not exist yet.
|
|
3790
|
-
lockfilePath: `${path}.lock`,
|
|
3791
|
-
realpath: false,
|
|
3792
|
-
stale: 3e4,
|
|
3793
|
-
retries: {
|
|
3794
|
-
retries: 5,
|
|
3795
|
-
factor: 1.5,
|
|
3796
|
-
minTimeout: 100,
|
|
3797
|
-
maxTimeout: 5e3
|
|
3815
|
+
var FsSessionStore;
|
|
3816
|
+
var init_fs_session_store = __esm({
|
|
3817
|
+
"src/internal/persistence/fs-session-store.ts"() {
|
|
3818
|
+
init_file_lock();
|
|
3819
|
+
init_session_transcript();
|
|
3820
|
+
FsSessionStore = class {
|
|
3821
|
+
#baseDir;
|
|
3822
|
+
#cwd;
|
|
3823
|
+
constructor(options) {
|
|
3824
|
+
this.#baseDir = options.baseDir;
|
|
3825
|
+
this.#cwd = options.cwd;
|
|
3826
|
+
}
|
|
3827
|
+
async readRecords(agentId) {
|
|
3828
|
+
return readTranscript(transcriptPath(this.#baseDir, this.#cwd, agentId));
|
|
3829
|
+
}
|
|
3830
|
+
async appendRecords(agentId, records) {
|
|
3831
|
+
if (records.length === 0) return;
|
|
3832
|
+
const path$1 = transcriptPath(this.#baseDir, this.#cwd, agentId);
|
|
3833
|
+
await promises.mkdir(path.dirname(path$1), { recursive: true });
|
|
3834
|
+
await withFileLock(path$1, async () => {
|
|
3835
|
+
const prior = await readTranscript(path$1);
|
|
3836
|
+
await writeTranscript(path$1, [...prior, ...records]);
|
|
3837
|
+
});
|
|
3798
3838
|
}
|
|
3799
|
-
}
|
|
3800
|
-
try {
|
|
3801
|
-
return await fn();
|
|
3802
|
-
} finally {
|
|
3803
|
-
await release();
|
|
3804
|
-
}
|
|
3805
|
-
});
|
|
3806
|
-
}
|
|
3807
|
-
var cached, warnedMissing, warnedStructural;
|
|
3808
|
-
var init_file_lock = __esm({
|
|
3809
|
-
"src/internal/persistence/file-lock.ts"() {
|
|
3810
|
-
init_cwd_mutex();
|
|
3811
|
-
warnedMissing = false;
|
|
3812
|
-
warnedStructural = false;
|
|
3839
|
+
};
|
|
3813
3840
|
}
|
|
3814
3841
|
});
|
|
3815
3842
|
function getTheokitHome(cwd) {
|
|
@@ -5141,6 +5168,8 @@ var init_memory_path_selector = __esm({
|
|
|
5141
5168
|
PORT_MEMORY_PATH_ENV_VAR = "THEOKIT_PORT_MEMORY_PATH";
|
|
5142
5169
|
}
|
|
5143
5170
|
});
|
|
5171
|
+
|
|
5172
|
+
// src/internal/runtime/session/agent-session-store.ts
|
|
5144
5173
|
function seedTranscript(prior, opts) {
|
|
5145
5174
|
return SessionTranscript.fromRecords(prior, opts);
|
|
5146
5175
|
}
|
|
@@ -5178,8 +5207,8 @@ function appendConversation(transcript, conversation) {
|
|
|
5178
5207
|
if (toolResults.length > 0) transcript.appendToolResults(toolResults);
|
|
5179
5208
|
}
|
|
5180
5209
|
}
|
|
5181
|
-
async function readSessionMessages(
|
|
5182
|
-
const records = await
|
|
5210
|
+
async function readSessionMessages(store, agentId) {
|
|
5211
|
+
const records = await store.readRecords(agentId);
|
|
5183
5212
|
return reconstructMessages(records).map(narrowToSessionMessage);
|
|
5184
5213
|
}
|
|
5185
5214
|
function partToText(p) {
|
|
@@ -5196,37 +5225,31 @@ function narrowToSessionMessage(m) {
|
|
|
5196
5225
|
const text = m.content.map(partToText).filter((s) => s.length > 0).join("\n");
|
|
5197
5226
|
return { role, text };
|
|
5198
5227
|
}
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
await promises.mkdir(path.dirname(path$1), { recursive: true });
|
|
5202
|
-
await withFileLock(path$1, async () => {
|
|
5203
|
-
const prior = await readTranscript(path$1);
|
|
5204
|
-
const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });
|
|
5205
|
-
transcript.appendUserTurn(turn.userText);
|
|
5206
|
-
appendConversation(transcript, turn.conversation);
|
|
5207
|
-
await writeTranscript(path$1, transcript.records());
|
|
5208
|
-
});
|
|
5228
|
+
function deltaRecords(transcript, priorLength) {
|
|
5229
|
+
return transcript.records().slice(priorLength);
|
|
5209
5230
|
}
|
|
5210
|
-
async function
|
|
5211
|
-
const
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5231
|
+
async function persistTurn(store, loc, sessionId, turn) {
|
|
5232
|
+
const prior = await store.readRecords(loc.agentId);
|
|
5233
|
+
const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });
|
|
5234
|
+
transcript.appendUserTurn(turn.userText);
|
|
5235
|
+
appendConversation(transcript, turn.conversation);
|
|
5236
|
+
await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));
|
|
5237
|
+
}
|
|
5238
|
+
async function appendCompactBoundaryRecord(store, loc, sessionId, meta) {
|
|
5239
|
+
const prior = await store.readRecords(loc.agentId);
|
|
5240
|
+
const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });
|
|
5241
|
+
transcript.appendCompactBoundary(meta);
|
|
5242
|
+
await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));
|
|
5219
5243
|
}
|
|
5220
5244
|
var init_agent_session_store = __esm({
|
|
5221
5245
|
"src/internal/runtime/session/agent-session-store.ts"() {
|
|
5222
|
-
init_file_lock();
|
|
5223
5246
|
init_session_transcript();
|
|
5224
5247
|
}
|
|
5225
5248
|
});
|
|
5226
5249
|
|
|
5227
5250
|
// src/internal/runtime/session/agent-session.ts
|
|
5228
|
-
function transcriptKey(
|
|
5229
|
-
return `${
|
|
5251
|
+
function transcriptKey(cwd, agentId) {
|
|
5252
|
+
return `${cwd}::${agentId}`;
|
|
5230
5253
|
}
|
|
5231
5254
|
function appendSessionMessage(agentId, message) {
|
|
5232
5255
|
const existing = sessions.get(agentId) ?? [];
|
|
@@ -5236,15 +5259,15 @@ function appendSessionMessage(agentId, message) {
|
|
|
5236
5259
|
function getSessionMessages(agentId) {
|
|
5237
5260
|
return sessions.get(agentId) ?? [];
|
|
5238
5261
|
}
|
|
5239
|
-
function persistTurnToTranscript(loc, sessionId, turn, onCompact) {
|
|
5240
|
-
const key2 = transcriptKey(loc.
|
|
5262
|
+
function persistTurnToTranscript(store, loc, sessionId, turn, onCompact) {
|
|
5263
|
+
const key2 = transcriptKey(loc.cwd, loc.agentId);
|
|
5241
5264
|
const chained = (pendingWrites.get(key2) ?? Promise.resolve()).then(async () => {
|
|
5242
5265
|
try {
|
|
5243
|
-
await persistTurn(loc, sessionId, turn);
|
|
5266
|
+
await persistTurn(store, loc, sessionId, turn);
|
|
5244
5267
|
const count = (recordCounts.get(key2) ?? 0) + 1;
|
|
5245
5268
|
recordCounts.set(key2, count);
|
|
5246
5269
|
if (count % COMPACTION_CHECK_INTERVAL === 0) {
|
|
5247
|
-
await appendCompactBoundaryRecord(loc, sessionId, {
|
|
5270
|
+
await appendCompactBoundaryRecord(store, loc, sessionId, {
|
|
5248
5271
|
preTokens: 0,
|
|
5249
5272
|
trigger: "auto"
|
|
5250
5273
|
});
|
|
@@ -5267,10 +5290,10 @@ function persistTurnToTranscript(loc, sessionId, turn, onCompact) {
|
|
|
5267
5290
|
);
|
|
5268
5291
|
}
|
|
5269
5292
|
async function hydrateSession(agentId, loc) {
|
|
5270
|
-
const key2 = transcriptKey(loc.
|
|
5293
|
+
const key2 = transcriptKey(loc.cwd, agentId);
|
|
5271
5294
|
if (hydratedKeys.has(key2)) return;
|
|
5272
5295
|
hydratedKeys.add(key2);
|
|
5273
|
-
const persisted = await readSessionMessages(loc.
|
|
5296
|
+
const persisted = await readSessionMessages(loc.store, agentId);
|
|
5274
5297
|
if (persisted.length === 0) return;
|
|
5275
5298
|
if (!sessions.has(agentId) || sessions.get(agentId)?.length === 0) {
|
|
5276
5299
|
sessions.set(agentId, persisted);
|
|
@@ -5305,7 +5328,7 @@ async function runPostRunLifecycle(inputs) {
|
|
|
5305
5328
|
userText,
|
|
5306
5329
|
agentId,
|
|
5307
5330
|
workspaceCwd,
|
|
5308
|
-
|
|
5331
|
+
sessionStore,
|
|
5309
5332
|
model,
|
|
5310
5333
|
onRunEvent,
|
|
5311
5334
|
hooksExecutor,
|
|
@@ -5324,7 +5347,8 @@ async function runPostRunLifecycle(inputs) {
|
|
|
5324
5347
|
}
|
|
5325
5348
|
const conversation = await safeConversation(run);
|
|
5326
5349
|
persistTurnToTranscript(
|
|
5327
|
-
|
|
5350
|
+
sessionStore,
|
|
5351
|
+
{ cwd: workspaceCwd, agentId, model },
|
|
5328
5352
|
agentId,
|
|
5329
5353
|
{ userText, conversation },
|
|
5330
5354
|
onRunEvent !== void 0 ? () => emitRunEvent(onRunEvent, { type: "compact_boundary", trigger: "auto" }) : void 0
|
|
@@ -18139,6 +18163,7 @@ var init_local_agent = __esm({
|
|
|
18139
18163
|
init_errors();
|
|
18140
18164
|
init_ids();
|
|
18141
18165
|
init_cwd_mutex();
|
|
18166
|
+
init_fs_session_store();
|
|
18142
18167
|
init_session_transcript();
|
|
18143
18168
|
init_store();
|
|
18144
18169
|
init_manager();
|
|
@@ -18182,6 +18207,12 @@ var init_local_agent = __esm({
|
|
|
18182
18207
|
* `~/.theokit`; set `local.baseDir: "~/.claude"` for Claude Code CLI interop.
|
|
18183
18208
|
*/
|
|
18184
18209
|
transcriptBaseDir;
|
|
18210
|
+
/**
|
|
18211
|
+
* SE41 — the session record store. Defaults to the FS transcript store (byte-
|
|
18212
|
+
* identical to SE40); `local.sessionStore` injects an external store (Postgres /
|
|
18213
|
+
* Redis / KV) so resume works on serverless (ephemeral FS) and multi-host.
|
|
18214
|
+
*/
|
|
18215
|
+
sessionStore;
|
|
18185
18216
|
/**
|
|
18186
18217
|
* D319: lifecycle AbortController fired on `dispose()`. Composed with the
|
|
18187
18218
|
* caller's `SendOptions.signal` via `anySignal` so the LLM `fetch()`
|
|
@@ -18224,6 +18255,7 @@ var init_local_agent = __esm({
|
|
|
18224
18255
|
this.options = options;
|
|
18225
18256
|
this.workspaceCwd = resolveCwd(options.local?.cwd);
|
|
18226
18257
|
this.transcriptBaseDir = resolveBaseDir(options.local?.baseDir);
|
|
18258
|
+
this.sessionStore = options.local?.sessionStore ?? new FsSessionStore({ baseDir: this.transcriptBaseDir, cwd: this.workspaceCwd });
|
|
18227
18259
|
this.settingSourcesIncludeProject = includesSetting(options, "project");
|
|
18228
18260
|
this.settingSourcesIncludePlugins = includesSetting(options, "plugins");
|
|
18229
18261
|
const sub = bootstrapSubmanagers({
|
|
@@ -18271,7 +18303,7 @@ var init_local_agent = __esm({
|
|
|
18271
18303
|
this.settingSourcesIncludeProject,
|
|
18272
18304
|
this.options.agents
|
|
18273
18305
|
);
|
|
18274
|
-
await hydrateSession(this.agentId, {
|
|
18306
|
+
await hydrateSession(this.agentId, { store: this.sessionStore, cwd: this.workspaceCwd });
|
|
18275
18307
|
await this.personalityStore.hydrate(this.agentId);
|
|
18276
18308
|
}
|
|
18277
18309
|
/** T4.2 — expose PluginManager so agent-loop can fire pre_tool_call hooks. @internal */
|
|
@@ -18327,7 +18359,7 @@ var init_local_agent = __esm({
|
|
|
18327
18359
|
userText,
|
|
18328
18360
|
agentId: this.agentId,
|
|
18329
18361
|
workspaceCwd: this.workspaceCwd,
|
|
18330
|
-
|
|
18362
|
+
sessionStore: this.sessionStore,
|
|
18331
18363
|
model: this.model?.id ?? "unknown",
|
|
18332
18364
|
...options.onRunEvent !== void 0 ? { onRunEvent: options.onRunEvent } : {},
|
|
18333
18365
|
hooksExecutor: this.hooksExecutor,
|