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