@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/eval.cjs
CHANGED
|
@@ -3506,6 +3506,72 @@ var init_cloud_tool_parity = __esm({
|
|
|
3506
3506
|
init_errors();
|
|
3507
3507
|
}
|
|
3508
3508
|
});
|
|
3509
|
+
|
|
3510
|
+
// src/internal/persistence/file-lock.ts
|
|
3511
|
+
async function getProperLockfile() {
|
|
3512
|
+
if (cached !== void 0) return cached;
|
|
3513
|
+
try {
|
|
3514
|
+
const mod = await import('proper-lockfile');
|
|
3515
|
+
if (!validateLockModule(mod)) {
|
|
3516
|
+
if (!warnedStructural) {
|
|
3517
|
+
warnedStructural = true;
|
|
3518
|
+
process.stderr.write(
|
|
3519
|
+
"[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"
|
|
3520
|
+
);
|
|
3521
|
+
}
|
|
3522
|
+
cached = null;
|
|
3523
|
+
return cached;
|
|
3524
|
+
}
|
|
3525
|
+
cached = mod;
|
|
3526
|
+
} catch {
|
|
3527
|
+
cached = null;
|
|
3528
|
+
}
|
|
3529
|
+
return cached;
|
|
3530
|
+
}
|
|
3531
|
+
function validateLockModule(mod) {
|
|
3532
|
+
if (mod === null || mod === void 0 || typeof mod !== "object") return false;
|
|
3533
|
+
const m = mod;
|
|
3534
|
+
return typeof m.lock === "function" && typeof m.unlock === "function";
|
|
3535
|
+
}
|
|
3536
|
+
async function withFileLock(path, fn, options) {
|
|
3537
|
+
const lib = await getProperLockfile();
|
|
3538
|
+
if (lib === null) {
|
|
3539
|
+
if (!warnedMissing) {
|
|
3540
|
+
warnedMissing = true;
|
|
3541
|
+
process.stderr.write(
|
|
3542
|
+
"[theokit-sdk] proper-lockfile not installed; cross-process file lock unavailable. Install with: pnpm add proper-lockfile\n"
|
|
3543
|
+
);
|
|
3544
|
+
}
|
|
3545
|
+
return withCwdMutex(`file-lock:${path}`, fn);
|
|
3546
|
+
}
|
|
3547
|
+
return withCwdMutex(`file-lock:${path}`, async () => {
|
|
3548
|
+
const release = await lib.lock(path, {
|
|
3549
|
+
// EC-1: companion lockfile, target path may not exist yet.
|
|
3550
|
+
lockfilePath: `${path}.lock`,
|
|
3551
|
+
realpath: false,
|
|
3552
|
+
stale: 3e4,
|
|
3553
|
+
retries: {
|
|
3554
|
+
retries: 5,
|
|
3555
|
+
factor: 1.5,
|
|
3556
|
+
minTimeout: 100,
|
|
3557
|
+
maxTimeout: 5e3
|
|
3558
|
+
}
|
|
3559
|
+
});
|
|
3560
|
+
try {
|
|
3561
|
+
return await fn();
|
|
3562
|
+
} finally {
|
|
3563
|
+
await release();
|
|
3564
|
+
}
|
|
3565
|
+
});
|
|
3566
|
+
}
|
|
3567
|
+
var cached, warnedMissing, warnedStructural;
|
|
3568
|
+
var init_file_lock = __esm({
|
|
3569
|
+
"src/internal/persistence/file-lock.ts"() {
|
|
3570
|
+
init_cwd_mutex();
|
|
3571
|
+
warnedMissing = false;
|
|
3572
|
+
warnedStructural = false;
|
|
3573
|
+
}
|
|
3574
|
+
});
|
|
3509
3575
|
function encodeProjectDir(cwd) {
|
|
3510
3576
|
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
3511
3577
|
}
|
|
@@ -3732,70 +3798,31 @@ var init_session_transcript = __esm({
|
|
|
3732
3798
|
};
|
|
3733
3799
|
}
|
|
3734
3800
|
});
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
if (mod === null || mod === void 0 || typeof mod !== "object") return false;
|
|
3759
|
-
const m = mod;
|
|
3760
|
-
return typeof m.lock === "function" && typeof m.unlock === "function";
|
|
3761
|
-
}
|
|
3762
|
-
async function withFileLock(path, fn, options) {
|
|
3763
|
-
const lib = await getProperLockfile();
|
|
3764
|
-
if (lib === null) {
|
|
3765
|
-
if (!warnedMissing) {
|
|
3766
|
-
warnedMissing = true;
|
|
3767
|
-
process.stderr.write(
|
|
3768
|
-
"[theokit-sdk] proper-lockfile not installed; cross-process file lock unavailable. Install with: pnpm add proper-lockfile\n"
|
|
3769
|
-
);
|
|
3770
|
-
}
|
|
3771
|
-
return withCwdMutex(`file-lock:${path}`, fn);
|
|
3772
|
-
}
|
|
3773
|
-
return withCwdMutex(`file-lock:${path}`, async () => {
|
|
3774
|
-
const release = await lib.lock(path, {
|
|
3775
|
-
// EC-1: companion lockfile, target path may not exist yet.
|
|
3776
|
-
lockfilePath: `${path}.lock`,
|
|
3777
|
-
realpath: false,
|
|
3778
|
-
stale: 3e4,
|
|
3779
|
-
retries: {
|
|
3780
|
-
retries: 5,
|
|
3781
|
-
factor: 1.5,
|
|
3782
|
-
minTimeout: 100,
|
|
3783
|
-
maxTimeout: 5e3
|
|
3801
|
+
var FsSessionStore;
|
|
3802
|
+
var init_fs_session_store = __esm({
|
|
3803
|
+
"src/internal/persistence/fs-session-store.ts"() {
|
|
3804
|
+
init_file_lock();
|
|
3805
|
+
init_session_transcript();
|
|
3806
|
+
FsSessionStore = class {
|
|
3807
|
+
#baseDir;
|
|
3808
|
+
#cwd;
|
|
3809
|
+
constructor(options) {
|
|
3810
|
+
this.#baseDir = options.baseDir;
|
|
3811
|
+
this.#cwd = options.cwd;
|
|
3812
|
+
}
|
|
3813
|
+
async readRecords(agentId) {
|
|
3814
|
+
return readTranscript(transcriptPath(this.#baseDir, this.#cwd, agentId));
|
|
3815
|
+
}
|
|
3816
|
+
async appendRecords(agentId, records) {
|
|
3817
|
+
if (records.length === 0) return;
|
|
3818
|
+
const path$1 = transcriptPath(this.#baseDir, this.#cwd, agentId);
|
|
3819
|
+
await promises.mkdir(path.dirname(path$1), { recursive: true });
|
|
3820
|
+
await withFileLock(path$1, async () => {
|
|
3821
|
+
const prior = await readTranscript(path$1);
|
|
3822
|
+
await writeTranscript(path$1, [...prior, ...records]);
|
|
3823
|
+
});
|
|
3784
3824
|
}
|
|
3785
|
-
}
|
|
3786
|
-
try {
|
|
3787
|
-
return await fn();
|
|
3788
|
-
} finally {
|
|
3789
|
-
await release();
|
|
3790
|
-
}
|
|
3791
|
-
});
|
|
3792
|
-
}
|
|
3793
|
-
var cached, warnedMissing, warnedStructural;
|
|
3794
|
-
var init_file_lock = __esm({
|
|
3795
|
-
"src/internal/persistence/file-lock.ts"() {
|
|
3796
|
-
init_cwd_mutex();
|
|
3797
|
-
warnedMissing = false;
|
|
3798
|
-
warnedStructural = false;
|
|
3825
|
+
};
|
|
3799
3826
|
}
|
|
3800
3827
|
});
|
|
3801
3828
|
function getTheokitHome(cwd) {
|
|
@@ -5127,6 +5154,8 @@ var init_memory_path_selector = __esm({
|
|
|
5127
5154
|
PORT_MEMORY_PATH_ENV_VAR = "THEOKIT_PORT_MEMORY_PATH";
|
|
5128
5155
|
}
|
|
5129
5156
|
});
|
|
5157
|
+
|
|
5158
|
+
// src/internal/runtime/session/agent-session-store.ts
|
|
5130
5159
|
function seedTranscript(prior, opts) {
|
|
5131
5160
|
return SessionTranscript.fromRecords(prior, opts);
|
|
5132
5161
|
}
|
|
@@ -5164,8 +5193,8 @@ function appendConversation(transcript, conversation) {
|
|
|
5164
5193
|
if (toolResults.length > 0) transcript.appendToolResults(toolResults);
|
|
5165
5194
|
}
|
|
5166
5195
|
}
|
|
5167
|
-
async function readSessionMessages(
|
|
5168
|
-
const records = await
|
|
5196
|
+
async function readSessionMessages(store, agentId) {
|
|
5197
|
+
const records = await store.readRecords(agentId);
|
|
5169
5198
|
return reconstructMessages(records).map(narrowToSessionMessage);
|
|
5170
5199
|
}
|
|
5171
5200
|
function partToText(p) {
|
|
@@ -5182,37 +5211,31 @@ function narrowToSessionMessage(m) {
|
|
|
5182
5211
|
const text = m.content.map(partToText).filter((s) => s.length > 0).join("\n");
|
|
5183
5212
|
return { role, text };
|
|
5184
5213
|
}
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
await promises.mkdir(path.dirname(path$1), { recursive: true });
|
|
5188
|
-
await withFileLock(path$1, async () => {
|
|
5189
|
-
const prior = await readTranscript(path$1);
|
|
5190
|
-
const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });
|
|
5191
|
-
transcript.appendUserTurn(turn.userText);
|
|
5192
|
-
appendConversation(transcript, turn.conversation);
|
|
5193
|
-
await writeTranscript(path$1, transcript.records());
|
|
5194
|
-
});
|
|
5214
|
+
function deltaRecords(transcript, priorLength) {
|
|
5215
|
+
return transcript.records().slice(priorLength);
|
|
5195
5216
|
}
|
|
5196
|
-
async function
|
|
5197
|
-
const
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5217
|
+
async function persistTurn(store, loc, sessionId, turn) {
|
|
5218
|
+
const prior = await store.readRecords(loc.agentId);
|
|
5219
|
+
const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });
|
|
5220
|
+
transcript.appendUserTurn(turn.userText);
|
|
5221
|
+
appendConversation(transcript, turn.conversation);
|
|
5222
|
+
await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));
|
|
5223
|
+
}
|
|
5224
|
+
async function appendCompactBoundaryRecord(store, loc, sessionId, meta) {
|
|
5225
|
+
const prior = await store.readRecords(loc.agentId);
|
|
5226
|
+
const transcript = seedTranscript(prior, { cwd: loc.cwd, sessionId, model: loc.model });
|
|
5227
|
+
transcript.appendCompactBoundary(meta);
|
|
5228
|
+
await store.appendRecords(loc.agentId, deltaRecords(transcript, prior.length));
|
|
5205
5229
|
}
|
|
5206
5230
|
var init_agent_session_store = __esm({
|
|
5207
5231
|
"src/internal/runtime/session/agent-session-store.ts"() {
|
|
5208
|
-
init_file_lock();
|
|
5209
5232
|
init_session_transcript();
|
|
5210
5233
|
}
|
|
5211
5234
|
});
|
|
5212
5235
|
|
|
5213
5236
|
// src/internal/runtime/session/agent-session.ts
|
|
5214
|
-
function transcriptKey(
|
|
5215
|
-
return `${
|
|
5237
|
+
function transcriptKey(cwd, agentId) {
|
|
5238
|
+
return `${cwd}::${agentId}`;
|
|
5216
5239
|
}
|
|
5217
5240
|
function appendSessionMessage(agentId, message) {
|
|
5218
5241
|
const existing = sessions.get(agentId) ?? [];
|
|
@@ -5222,15 +5245,15 @@ function appendSessionMessage(agentId, message) {
|
|
|
5222
5245
|
function getSessionMessages(agentId) {
|
|
5223
5246
|
return sessions.get(agentId) ?? [];
|
|
5224
5247
|
}
|
|
5225
|
-
function persistTurnToTranscript(loc, sessionId, turn, onCompact) {
|
|
5226
|
-
const key = transcriptKey(loc.
|
|
5248
|
+
function persistTurnToTranscript(store, loc, sessionId, turn, onCompact) {
|
|
5249
|
+
const key = transcriptKey(loc.cwd, loc.agentId);
|
|
5227
5250
|
const chained = (pendingWrites.get(key) ?? Promise.resolve()).then(async () => {
|
|
5228
5251
|
try {
|
|
5229
|
-
await persistTurn(loc, sessionId, turn);
|
|
5252
|
+
await persistTurn(store, loc, sessionId, turn);
|
|
5230
5253
|
const count = (recordCounts.get(key) ?? 0) + 1;
|
|
5231
5254
|
recordCounts.set(key, count);
|
|
5232
5255
|
if (count % COMPACTION_CHECK_INTERVAL === 0) {
|
|
5233
|
-
await appendCompactBoundaryRecord(loc, sessionId, {
|
|
5256
|
+
await appendCompactBoundaryRecord(store, loc, sessionId, {
|
|
5234
5257
|
preTokens: 0,
|
|
5235
5258
|
trigger: "auto"
|
|
5236
5259
|
});
|
|
@@ -5253,10 +5276,10 @@ function persistTurnToTranscript(loc, sessionId, turn, onCompact) {
|
|
|
5253
5276
|
);
|
|
5254
5277
|
}
|
|
5255
5278
|
async function hydrateSession(agentId, loc) {
|
|
5256
|
-
const key = transcriptKey(loc.
|
|
5279
|
+
const key = transcriptKey(loc.cwd, agentId);
|
|
5257
5280
|
if (hydratedKeys.has(key)) return;
|
|
5258
5281
|
hydratedKeys.add(key);
|
|
5259
|
-
const persisted = await readSessionMessages(loc.
|
|
5282
|
+
const persisted = await readSessionMessages(loc.store, agentId);
|
|
5260
5283
|
if (persisted.length === 0) return;
|
|
5261
5284
|
if (!sessions.has(agentId) || sessions.get(agentId)?.length === 0) {
|
|
5262
5285
|
sessions.set(agentId, persisted);
|
|
@@ -5291,7 +5314,7 @@ async function runPostRunLifecycle(inputs) {
|
|
|
5291
5314
|
userText,
|
|
5292
5315
|
agentId,
|
|
5293
5316
|
workspaceCwd,
|
|
5294
|
-
|
|
5317
|
+
sessionStore,
|
|
5295
5318
|
model,
|
|
5296
5319
|
onRunEvent,
|
|
5297
5320
|
hooksExecutor,
|
|
@@ -5310,7 +5333,8 @@ async function runPostRunLifecycle(inputs) {
|
|
|
5310
5333
|
}
|
|
5311
5334
|
const conversation = await safeConversation(run);
|
|
5312
5335
|
persistTurnToTranscript(
|
|
5313
|
-
|
|
5336
|
+
sessionStore,
|
|
5337
|
+
{ cwd: workspaceCwd, agentId, model },
|
|
5314
5338
|
agentId,
|
|
5315
5339
|
{ userText, conversation },
|
|
5316
5340
|
onRunEvent !== void 0 ? () => emitRunEvent(onRunEvent, { type: "compact_boundary", trigger: "auto" }) : void 0
|
|
@@ -17917,6 +17941,7 @@ var init_local_agent = __esm({
|
|
|
17917
17941
|
init_errors();
|
|
17918
17942
|
init_ids();
|
|
17919
17943
|
init_cwd_mutex();
|
|
17944
|
+
init_fs_session_store();
|
|
17920
17945
|
init_session_transcript();
|
|
17921
17946
|
init_store();
|
|
17922
17947
|
init_manager();
|
|
@@ -17960,6 +17985,12 @@ var init_local_agent = __esm({
|
|
|
17960
17985
|
* `~/.theokit`; set `local.baseDir: "~/.claude"` for Claude Code CLI interop.
|
|
17961
17986
|
*/
|
|
17962
17987
|
transcriptBaseDir;
|
|
17988
|
+
/**
|
|
17989
|
+
* SE41 — the session record store. Defaults to the FS transcript store (byte-
|
|
17990
|
+
* identical to SE40); `local.sessionStore` injects an external store (Postgres /
|
|
17991
|
+
* Redis / KV) so resume works on serverless (ephemeral FS) and multi-host.
|
|
17992
|
+
*/
|
|
17993
|
+
sessionStore;
|
|
17963
17994
|
/**
|
|
17964
17995
|
* D319: lifecycle AbortController fired on `dispose()`. Composed with the
|
|
17965
17996
|
* caller's `SendOptions.signal` via `anySignal` so the LLM `fetch()`
|
|
@@ -18002,6 +18033,7 @@ var init_local_agent = __esm({
|
|
|
18002
18033
|
this.options = options;
|
|
18003
18034
|
this.workspaceCwd = resolveCwd(options.local?.cwd);
|
|
18004
18035
|
this.transcriptBaseDir = resolveBaseDir(options.local?.baseDir);
|
|
18036
|
+
this.sessionStore = options.local?.sessionStore ?? new FsSessionStore({ baseDir: this.transcriptBaseDir, cwd: this.workspaceCwd });
|
|
18005
18037
|
this.settingSourcesIncludeProject = includesSetting(options, "project");
|
|
18006
18038
|
this.settingSourcesIncludePlugins = includesSetting(options, "plugins");
|
|
18007
18039
|
const sub = bootstrapSubmanagers({
|
|
@@ -18049,7 +18081,7 @@ var init_local_agent = __esm({
|
|
|
18049
18081
|
this.settingSourcesIncludeProject,
|
|
18050
18082
|
this.options.agents
|
|
18051
18083
|
);
|
|
18052
|
-
await hydrateSession(this.agentId, {
|
|
18084
|
+
await hydrateSession(this.agentId, { store: this.sessionStore, cwd: this.workspaceCwd });
|
|
18053
18085
|
await this.personalityStore.hydrate(this.agentId);
|
|
18054
18086
|
}
|
|
18055
18087
|
/** T4.2 — expose PluginManager so agent-loop can fire pre_tool_call hooks. @internal */
|
|
@@ -18105,7 +18137,7 @@ var init_local_agent = __esm({
|
|
|
18105
18137
|
userText,
|
|
18106
18138
|
agentId: this.agentId,
|
|
18107
18139
|
workspaceCwd: this.workspaceCwd,
|
|
18108
|
-
|
|
18140
|
+
sessionStore: this.sessionStore,
|
|
18109
18141
|
model: this.model?.id ?? "unknown",
|
|
18110
18142
|
...options.onRunEvent !== void 0 ? { onRunEvent: options.onRunEvent } : {},
|
|
18111
18143
|
hooksExecutor: this.hooksExecutor,
|