@harness-kernel/core 0.1.1 → 0.2.1
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/dist/agent/context.d.ts +1 -1
- package/dist/agent/context.js +1 -1
- package/dist/agent/event.js +2 -2
- package/dist/agent/hook.d.ts +2 -2
- package/dist/agent/hook.js +1 -1
- package/dist/agent/mode.d.ts +1 -1
- package/dist/agent/mode.js +1 -1
- package/dist/agent/role.js +1 -1
- package/dist/agent/session.d.ts +1 -1
- package/dist/agent/session.js +1 -1
- package/dist/agent/tool.d.ts +1 -1
- package/dist/agent/tool.js +1 -1
- package/dist/agent.d.ts +4 -4
- package/dist/{approval-DfvjpbFs.d.ts → approval-D_G2w-fW.d.ts} +10 -14
- package/dist/{chunk-4A2P4QU5.js → chunk-B4Q6CPYO.js} +2 -1
- package/dist/chunk-B4Q6CPYO.js.map +1 -0
- package/dist/{chunk-4SYLFKIX.js → chunk-JIJHGB6H.js} +2 -2
- package/dist/chunk-ONYDIU4X.js +284 -0
- package/dist/chunk-ONYDIU4X.js.map +1 -0
- package/dist/{chunk-4WWSQAWA.js → chunk-QEVKKJ7N.js} +199 -75
- package/dist/chunk-QEVKKJ7N.js.map +1 -0
- package/dist/{chunk-AD3BCYWU.js → chunk-ZU6ADDET.js} +1 -1
- package/dist/chunk-ZU6ADDET.js.map +1 -0
- package/dist/{context-75mlon5x.d.ts → context-BfpLqV11.d.ts} +5 -3
- package/dist/{hook-DMb9fw9Z.d.ts → hook-CfBbhUQf.d.ts} +1 -1
- package/dist/index.d.ts +13 -11
- package/dist/index.js +9 -5
- package/dist/{model-provider-BrZ2RRmS.d.ts → model-provider-Ch7tzk1x.d.ts} +6 -8
- package/dist/runner/approval.d.ts +5 -5
- package/dist/runner/event.js +2 -2
- package/dist/runner/model-provider.d.ts +4 -4
- package/dist/runner/sandbox.d.ts +1 -1
- package/dist/runner/sandbox.js +1 -1
- package/dist/runner/storage.d.ts +2 -2
- package/dist/runner/storage.js +5 -1
- package/dist/{runner-Dxo7ALtp.d.ts → runner-B41JEovO.d.ts} +16 -9
- package/dist/runner.d.ts +6 -6
- package/dist/runner.js +5 -5
- package/dist/{storage-BmOEwW-p.d.ts → storage-DCZE_hES.d.ts} +84 -2
- package/package.json +2 -2
- package/dist/chunk-4A2P4QU5.js.map +0 -1
- package/dist/chunk-4WWSQAWA.js.map +0 -1
- package/dist/chunk-AD3BCYWU.js.map +0 -1
- package/dist/chunk-AZVA22HW.js +0 -135
- package/dist/chunk-AZVA22HW.js.map +0 -1
- /package/dist/{chunk-4SYLFKIX.js.map → chunk-JIJHGB6H.js.map} +0 -0
|
@@ -17,10 +17,11 @@ import {
|
|
|
17
17
|
import {
|
|
18
18
|
HarnessSandboxSession,
|
|
19
19
|
NoopSandbox
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-ZU6ADDET.js";
|
|
21
21
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
HarnessSessionStorage,
|
|
23
|
+
MemorySessionStorage
|
|
24
|
+
} from "./chunk-ONYDIU4X.js";
|
|
24
25
|
import {
|
|
25
26
|
ContextReadyEvent,
|
|
26
27
|
ErrorEvent,
|
|
@@ -43,7 +44,7 @@ import {
|
|
|
43
44
|
TurnEndEvent,
|
|
44
45
|
TurnStartEvent,
|
|
45
46
|
runtimeEventClasses
|
|
46
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-JIJHGB6H.js";
|
|
47
48
|
import {
|
|
48
49
|
normalizeSchema
|
|
49
50
|
} from "./chunk-OBKS4AJR.js";
|
|
@@ -58,7 +59,7 @@ import {
|
|
|
58
59
|
systemRole,
|
|
59
60
|
toolRole,
|
|
60
61
|
userRole
|
|
61
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-B4Q6CPYO.js";
|
|
62
63
|
|
|
63
64
|
// src/logging/tool-errors.ts
|
|
64
65
|
function createToolErrorPayload(input) {
|
|
@@ -576,7 +577,7 @@ var SandboxManager = class {
|
|
|
576
577
|
agentKey: this.input.agentKey,
|
|
577
578
|
workDir: this.input.workDir,
|
|
578
579
|
outputDir: this.input.getOutputDir(),
|
|
579
|
-
|
|
580
|
+
resources: this.input.resources
|
|
580
581
|
});
|
|
581
582
|
this.session = this.wrap(opened);
|
|
582
583
|
this.input.logOpened({ sandboxId: opened.id, workDir: opened.workDir });
|
|
@@ -633,7 +634,7 @@ var RunStorageCoordinator = class {
|
|
|
633
634
|
constructor(input) {
|
|
634
635
|
this.input = input;
|
|
635
636
|
this.runIdValue = input.runId;
|
|
636
|
-
this.
|
|
637
|
+
this.createRunOnOpen = !input.openExistingRun;
|
|
637
638
|
}
|
|
638
639
|
input;
|
|
639
640
|
runIdValue;
|
|
@@ -641,6 +642,7 @@ var RunStorageCoordinator = class {
|
|
|
641
642
|
storePromise;
|
|
642
643
|
initialized = false;
|
|
643
644
|
runtimeLoaded = false;
|
|
645
|
+
createRunOnOpen;
|
|
644
646
|
get runDir() {
|
|
645
647
|
return this.store?.runDir;
|
|
646
648
|
}
|
|
@@ -664,6 +666,7 @@ var RunStorageCoordinator = class {
|
|
|
664
666
|
await this.write("save_transcript", (store) => store.saveTranscript(messages));
|
|
665
667
|
}
|
|
666
668
|
async saveMetrics(metrics) {
|
|
669
|
+
if (this.input.storage instanceof HarnessSessionStorage) return;
|
|
667
670
|
await this.write("save_metrics", (store) => store.saveMetrics(metrics));
|
|
668
671
|
}
|
|
669
672
|
async saveSnapshot(snapshot) {
|
|
@@ -685,16 +688,27 @@ var RunStorageCoordinator = class {
|
|
|
685
688
|
await this.close();
|
|
686
689
|
this.runIdValue = runId;
|
|
687
690
|
this.store = void 0;
|
|
688
|
-
this.storePromise =
|
|
691
|
+
this.storePromise = void 0;
|
|
689
692
|
this.initialized = false;
|
|
690
693
|
this.runtimeLoaded = false;
|
|
694
|
+
this.createRunOnOpen = true;
|
|
691
695
|
}
|
|
692
696
|
async close() {
|
|
693
|
-
const store = this.store ?? await this.storePromise;
|
|
694
|
-
await store
|
|
697
|
+
const store = this.store ?? (this.storePromise ? await this.storePromise : void 0);
|
|
698
|
+
await store?.close?.();
|
|
695
699
|
}
|
|
696
700
|
async createStore(runId) {
|
|
697
701
|
try {
|
|
702
|
+
if (this.input.storage instanceof HarnessSessionStorage && this.createRunOnOpen) {
|
|
703
|
+
await this.input.storage.createRun({
|
|
704
|
+
runId,
|
|
705
|
+
sessionId: this.input.sessionId,
|
|
706
|
+
agentKey: this.input.agentKey,
|
|
707
|
+
outputDir: this.input.outputDir,
|
|
708
|
+
mode: this.input.mode()
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
this.createRunOnOpen = false;
|
|
698
712
|
const store = await this.input.storage.openRun({
|
|
699
713
|
runId,
|
|
700
714
|
sessionId: this.input.sessionId,
|
|
@@ -710,6 +724,7 @@ var RunStorageCoordinator = class {
|
|
|
710
724
|
}
|
|
711
725
|
async getStore() {
|
|
712
726
|
if (this.store) return this.store;
|
|
727
|
+
this.storePromise ??= this.createStore(this.runIdValue);
|
|
713
728
|
this.store = await this.storePromise;
|
|
714
729
|
return this.store;
|
|
715
730
|
}
|
|
@@ -1228,7 +1243,15 @@ var ToolExecutor = class {
|
|
|
1228
1243
|
return result;
|
|
1229
1244
|
}
|
|
1230
1245
|
const approved = await this.approveTool(
|
|
1231
|
-
{
|
|
1246
|
+
{
|
|
1247
|
+
id,
|
|
1248
|
+
name: input.tool.name,
|
|
1249
|
+
args: parsedArgs.data,
|
|
1250
|
+
modeId: this.input.getCurrentMode(),
|
|
1251
|
+
risk: input.tool.risk,
|
|
1252
|
+
permissions: input.tool.permissions,
|
|
1253
|
+
approvalTimeoutMs: input.tool.approvalTimeoutMs
|
|
1254
|
+
},
|
|
1232
1255
|
input.tool,
|
|
1233
1256
|
parsedArgs.data,
|
|
1234
1257
|
callerEventOptions
|
|
@@ -1728,13 +1751,15 @@ var AgentSessionRunner = class {
|
|
|
1728
1751
|
this.options = options;
|
|
1729
1752
|
this.agent = normalizeAgent(options.agent);
|
|
1730
1753
|
this.sessionIdValue = options.sessionId ?? randomId();
|
|
1754
|
+
this.runIdValue = options.initialRunId ?? randomId();
|
|
1755
|
+
this.restoredFromRun = Boolean(options.initialRunId);
|
|
1731
1756
|
this.workDir = options.workDir ?? ".";
|
|
1732
1757
|
this.outputDir = options.outputDir ?? ".harness-kernel/runs";
|
|
1733
|
-
const storage = options.storage ?? new
|
|
1758
|
+
const storage = options.storage ?? new MemorySessionStorage();
|
|
1734
1759
|
const sandbox = options.sandbox ?? new NoopSandbox();
|
|
1735
1760
|
this.providerRegistry = new HarnessModelProviderRegistry(options.providers);
|
|
1736
|
-
this.currentMode =
|
|
1737
|
-
this.
|
|
1761
|
+
this.currentMode = this.agent.initialMode;
|
|
1762
|
+
this.resources = options.resources ?? {};
|
|
1738
1763
|
this.roles = validateRoles(options.roles) ?? this.agent.roles ?? defaultRoles();
|
|
1739
1764
|
const initialProvider = this.resolveModelProvider(options.defaultModel).provider;
|
|
1740
1765
|
this.roleResolver = new RoleResolver(this.roles, {
|
|
@@ -1748,6 +1773,8 @@ var AgentSessionRunner = class {
|
|
|
1748
1773
|
sessionId: this.sessionIdValue,
|
|
1749
1774
|
agentKey: this.agent.key,
|
|
1750
1775
|
outputDir: this.outputDir,
|
|
1776
|
+
mode: () => this.currentMode,
|
|
1777
|
+
openExistingRun: Boolean(options.initialRunId),
|
|
1751
1778
|
logOpened: (fields) => this.log(RunStorageOpenedLog, fields),
|
|
1752
1779
|
logFailed: (fields) => this.log(StorageWriteFailedLog, fields)
|
|
1753
1780
|
});
|
|
@@ -1836,7 +1863,7 @@ var AgentSessionRunner = class {
|
|
|
1836
1863
|
sessionId: this.sessionIdValue,
|
|
1837
1864
|
agentKey: this.agent.key,
|
|
1838
1865
|
workDir: this.workDir,
|
|
1839
|
-
|
|
1866
|
+
resources: this.resources,
|
|
1840
1867
|
getRunId: () => this.runId,
|
|
1841
1868
|
getOutputDir: () => this.storeRunDir(),
|
|
1842
1869
|
logOpened: (fields) => this.log(SandboxOpenedLog, fields),
|
|
@@ -1848,7 +1875,7 @@ var AgentSessionRunner = class {
|
|
|
1848
1875
|
this.toolExecutor = new ToolExecutor({
|
|
1849
1876
|
getMetrics: () => this.metrics,
|
|
1850
1877
|
getCurrentMode: () => this.currentMode,
|
|
1851
|
-
getToolApprovalMode: () => this.
|
|
1878
|
+
getToolApprovalMode: () => this.getModeDefinition(this.currentMode).toolApproval,
|
|
1852
1879
|
approveTool: this.options.approveTool,
|
|
1853
1880
|
ensureSandboxOpen: () => this.ensureSandboxOpen(),
|
|
1854
1881
|
buildActionSession: (tool, source, correlationId, causationId) => this.buildActionSession(tool, source, correlationId, causationId),
|
|
@@ -1899,7 +1926,7 @@ var AgentSessionRunner = class {
|
|
|
1899
1926
|
snapshotManager;
|
|
1900
1927
|
toolExecutor;
|
|
1901
1928
|
modelPipeline;
|
|
1902
|
-
|
|
1929
|
+
resources;
|
|
1903
1930
|
roles;
|
|
1904
1931
|
roleResolver;
|
|
1905
1932
|
providerRegistry;
|
|
@@ -1917,6 +1944,7 @@ var AgentSessionRunner = class {
|
|
|
1917
1944
|
providerStack = [];
|
|
1918
1945
|
hookDepth = 0;
|
|
1919
1946
|
turnHandoffRequested = false;
|
|
1947
|
+
restoredFromRun = false;
|
|
1920
1948
|
logSource(source) {
|
|
1921
1949
|
if (!source) return { kind: "runtime" };
|
|
1922
1950
|
return {
|
|
@@ -2012,11 +2040,12 @@ var AgentSessionRunner = class {
|
|
|
2012
2040
|
});
|
|
2013
2041
|
}
|
|
2014
2042
|
async beginNewRun() {
|
|
2015
|
-
if (this.started) {
|
|
2043
|
+
if (this.started || this.restoredFromRun) {
|
|
2016
2044
|
await this.closeSandbox();
|
|
2017
2045
|
this.runIdValue = randomId();
|
|
2018
2046
|
await this.storageCoordinator.beginRun(this.runIdValue);
|
|
2019
2047
|
this.started = false;
|
|
2048
|
+
this.restoredFromRun = false;
|
|
2020
2049
|
}
|
|
2021
2050
|
this.startedAtPerf = 0;
|
|
2022
2051
|
this.metrics = emptyMetrics();
|
|
@@ -2039,7 +2068,7 @@ var AgentSessionRunner = class {
|
|
|
2039
2068
|
role: options.userRole,
|
|
2040
2069
|
external: true
|
|
2041
2070
|
});
|
|
2042
|
-
const maxRunnerTurns = this.
|
|
2071
|
+
const maxRunnerTurns = this.getModeDefinition(this.currentMode).maxTurns ?? 5;
|
|
2043
2072
|
while (this.pendingInputs.length > 0 && this.metrics.turnCount < maxRunnerTurns) {
|
|
2044
2073
|
if (options.signal?.aborted) throw new Error("Run aborted.");
|
|
2045
2074
|
const input = this.pendingInputs.shift();
|
|
@@ -2060,7 +2089,8 @@ var AgentSessionRunner = class {
|
|
|
2060
2089
|
this.log(RunCompletedLog, {
|
|
2061
2090
|
durationMs: this.metrics.durationMs,
|
|
2062
2091
|
messageCount: this.metrics.messageCount,
|
|
2063
|
-
eventCount: this.metrics.eventCount
|
|
2092
|
+
eventCount: this.metrics.eventCount,
|
|
2093
|
+
metrics: cloneJSON4(this.metrics)
|
|
2064
2094
|
});
|
|
2065
2095
|
return {
|
|
2066
2096
|
runId: this.runId,
|
|
@@ -2082,6 +2112,10 @@ var AgentSessionRunner = class {
|
|
|
2082
2112
|
async prompt(message, options = {}) {
|
|
2083
2113
|
return this.run(message, options);
|
|
2084
2114
|
}
|
|
2115
|
+
async hydrate() {
|
|
2116
|
+
if (!this.restoredFromRun) return;
|
|
2117
|
+
await this.ensureStoreInitialized();
|
|
2118
|
+
}
|
|
2085
2119
|
async close() {
|
|
2086
2120
|
await this.closeSandbox();
|
|
2087
2121
|
await this.closeStore();
|
|
@@ -2370,7 +2404,7 @@ var AgentSessionRunner = class {
|
|
|
2370
2404
|
agentKey: this.agent.key,
|
|
2371
2405
|
workDir: this.workDir,
|
|
2372
2406
|
outputDir: this.storeRunDir(),
|
|
2373
|
-
|
|
2407
|
+
resources: this.resources,
|
|
2374
2408
|
state: {
|
|
2375
2409
|
get: () => cloneJSON4(this.state)
|
|
2376
2410
|
},
|
|
@@ -2936,17 +2970,18 @@ var ApprovalController = class {
|
|
|
2936
2970
|
}
|
|
2937
2971
|
request(request) {
|
|
2938
2972
|
return new Promise((resolve) => {
|
|
2973
|
+
const timeoutMs = request.approvalTimeoutMs ?? this.input.defaultTimeoutMs;
|
|
2939
2974
|
const handle = createToolApprovalHandle({
|
|
2940
2975
|
sessionId: this.input.sessionId,
|
|
2941
2976
|
runId: this.input.getRunId(),
|
|
2942
2977
|
request,
|
|
2943
|
-
timeoutMs
|
|
2978
|
+
timeoutMs,
|
|
2944
2979
|
approve: async (id) => this.resolve(id, true),
|
|
2945
2980
|
deny: async (id, reason) => this.resolve(id, false, reason)
|
|
2946
2981
|
});
|
|
2947
|
-
const timeout = setTimeout(() => {
|
|
2982
|
+
const timeout = timeoutMs > 0 ? setTimeout(() => {
|
|
2948
2983
|
this.resolve(handle.id, false);
|
|
2949
|
-
},
|
|
2984
|
+
}, timeoutMs) : void 0;
|
|
2950
2985
|
this.pendingApprovals.set(handle.id, {
|
|
2951
2986
|
handle,
|
|
2952
2987
|
timeout,
|
|
@@ -2974,11 +3009,8 @@ var ApprovalController = class {
|
|
|
2974
3009
|
async function resolveAgent(input) {
|
|
2975
3010
|
return input.definition;
|
|
2976
3011
|
}
|
|
2977
|
-
function resolveWorkDir(workDir) {
|
|
2978
|
-
return workDir ?? ".";
|
|
2979
|
-
}
|
|
2980
3012
|
function resolveStorage(storage) {
|
|
2981
|
-
return storage ?? new
|
|
3013
|
+
return storage ?? new MemorySessionStorage();
|
|
2982
3014
|
}
|
|
2983
3015
|
|
|
2984
3016
|
// src/session/event-hub.ts
|
|
@@ -3353,14 +3385,6 @@ function nowIso6() {
|
|
|
3353
3385
|
function normalizeInput(input) {
|
|
3354
3386
|
return typeof input === "string" ? { content: input } : input;
|
|
3355
3387
|
}
|
|
3356
|
-
function resolveInitialMode(agent, mode) {
|
|
3357
|
-
if (mode === void 0) return void 0;
|
|
3358
|
-
if (typeof mode !== "string") return mode;
|
|
3359
|
-
if (!Array.isArray(agent.modes)) return void 0;
|
|
3360
|
-
const resolved = agent.modes.find((candidate) => getConstructType(candidate) === mode);
|
|
3361
|
-
if (!resolved) throw new Error(`Unknown initial mode '${mode}'.`);
|
|
3362
|
-
return resolved;
|
|
3363
|
-
}
|
|
3364
3388
|
function toErrorShape(error) {
|
|
3365
3389
|
if (error instanceof Error) {
|
|
3366
3390
|
return {
|
|
@@ -3376,6 +3400,8 @@ var HarnessSessionImpl = class {
|
|
|
3376
3400
|
constructor(config, input) {
|
|
3377
3401
|
this.config = config;
|
|
3378
3402
|
this.id = input.sessionId ?? randomId();
|
|
3403
|
+
this.createdAt = input.restoredSession?.createdAt ?? this.createdAt;
|
|
3404
|
+
this.lastActiveAt = input.restoredSession?.lastActiveAt ?? this.createdAt;
|
|
3379
3405
|
this.events = new SessionEventHub({
|
|
3380
3406
|
sessionId: this.id,
|
|
3381
3407
|
hydrateApprovalId: (toolCallId) => this.approvals.hydrateApprovalId(toolCallId)
|
|
@@ -3384,7 +3410,7 @@ var HarnessSessionImpl = class {
|
|
|
3384
3410
|
this.approvals = new ApprovalController({
|
|
3385
3411
|
sessionId: this.id,
|
|
3386
3412
|
getRunId: () => this.runner.runId,
|
|
3387
|
-
|
|
3413
|
+
defaultTimeoutMs: defaultApprovalTimeoutMs,
|
|
3388
3414
|
notifyRequested: (approval) => this.notify({ type: "tool.approval.requested", approval })
|
|
3389
3415
|
});
|
|
3390
3416
|
const storage = resolveStorage(config.storage);
|
|
@@ -3394,12 +3420,9 @@ var HarnessSessionImpl = class {
|
|
|
3394
3420
|
providers: config.providers,
|
|
3395
3421
|
defaultModel: config.defaultModel,
|
|
3396
3422
|
sandbox: config.sandbox,
|
|
3397
|
-
workDir: input.workDir,
|
|
3398
3423
|
storage,
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
maxTurns: config.maxTurns,
|
|
3402
|
-
services: config.services,
|
|
3424
|
+
initialRunId: input.restoredSession?.latestRunId,
|
|
3425
|
+
resources: config.resources,
|
|
3403
3426
|
approveTool: (request) => this.requestToolApproval(request),
|
|
3404
3427
|
logger: this.logger
|
|
3405
3428
|
});
|
|
@@ -3608,6 +3631,9 @@ var HarnessSessionImpl = class {
|
|
|
3608
3631
|
this.events.clear();
|
|
3609
3632
|
await this.logger.close();
|
|
3610
3633
|
}
|
|
3634
|
+
async hydrate() {
|
|
3635
|
+
await this.runner.hydrate();
|
|
3636
|
+
}
|
|
3611
3637
|
notify(event) {
|
|
3612
3638
|
this.events.notify(event);
|
|
3613
3639
|
}
|
|
@@ -3652,13 +3678,26 @@ var HarnessSessionImpl = class {
|
|
|
3652
3678
|
}
|
|
3653
3679
|
};
|
|
3654
3680
|
async function createHarnessSession(config, options = {}) {
|
|
3655
|
-
const workDir = resolveWorkDir(config.workDir);
|
|
3656
3681
|
const agent = await resolveAgent(config.agent);
|
|
3657
|
-
|
|
3682
|
+
const storage = resolveStorage(config.storage);
|
|
3683
|
+
const sessionConfig = { ...config, storage };
|
|
3684
|
+
const session = new HarnessSessionImpl(sessionConfig, {
|
|
3658
3685
|
sessionId: options.sessionId,
|
|
3659
3686
|
agent,
|
|
3660
|
-
|
|
3687
|
+
restoredSession: options.restoredSession
|
|
3661
3688
|
});
|
|
3689
|
+
if (!options.restoredSession) {
|
|
3690
|
+
const status = session.getStatus();
|
|
3691
|
+
await storage.createSession({
|
|
3692
|
+
sessionId: status.sessionId,
|
|
3693
|
+
agentKey: status.agentKey,
|
|
3694
|
+
createdAt: status.createdAt,
|
|
3695
|
+
lastActiveAt: status.lastActiveAt,
|
|
3696
|
+
mode: status.mode
|
|
3697
|
+
});
|
|
3698
|
+
}
|
|
3699
|
+
await session.hydrate();
|
|
3700
|
+
return session;
|
|
3662
3701
|
}
|
|
3663
3702
|
|
|
3664
3703
|
// src/session/store.ts
|
|
@@ -3668,53 +3707,150 @@ function mergeConfig(base, overrides) {
|
|
|
3668
3707
|
...overrides,
|
|
3669
3708
|
agent: overrides?.agent ?? base.agent,
|
|
3670
3709
|
providers: overrides?.providers ?? base.providers,
|
|
3671
|
-
|
|
3672
|
-
logging: overrides?.logging ?? base.logging
|
|
3710
|
+
resources: overrides?.resources ?? base.resources,
|
|
3711
|
+
logging: overrides?.logging ?? base.logging,
|
|
3712
|
+
storage: overrides?.storage ?? base.storage
|
|
3713
|
+
};
|
|
3714
|
+
}
|
|
3715
|
+
function statusToSummary(status, latestRunId) {
|
|
3716
|
+
return {
|
|
3717
|
+
sessionId: status.sessionId,
|
|
3718
|
+
agentKey: status.agentKey,
|
|
3719
|
+
createdAt: status.createdAt,
|
|
3720
|
+
lastActiveAt: status.lastActiveAt,
|
|
3721
|
+
mode: status.mode,
|
|
3722
|
+
latestRunId
|
|
3723
|
+
};
|
|
3724
|
+
}
|
|
3725
|
+
function sortSummaries(items) {
|
|
3726
|
+
return [...items].sort((a, b) => {
|
|
3727
|
+
const byLastActive = b.lastActiveAt.localeCompare(a.lastActiveAt);
|
|
3728
|
+
return byLastActive || a.sessionId.localeCompare(b.sessionId);
|
|
3729
|
+
});
|
|
3730
|
+
}
|
|
3731
|
+
function encodeCursor(summary) {
|
|
3732
|
+
return Buffer.from(JSON.stringify([summary.lastActiveAt, summary.sessionId]), "utf8").toString("base64url");
|
|
3733
|
+
}
|
|
3734
|
+
function decodeCursor(cursor) {
|
|
3735
|
+
if (!cursor) return void 0;
|
|
3736
|
+
try {
|
|
3737
|
+
const parsed = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
3738
|
+
if (!Array.isArray(parsed) || typeof parsed[0] !== "string" || typeof parsed[1] !== "string") return void 0;
|
|
3739
|
+
return [parsed[0], parsed[1]];
|
|
3740
|
+
} catch {
|
|
3741
|
+
return void 0;
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3744
|
+
function paginateActive(items, query) {
|
|
3745
|
+
const limit = Math.max(1, Math.min(query?.limit ?? 50, 100));
|
|
3746
|
+
const cursor = decodeCursor(query?.cursor);
|
|
3747
|
+
const filtered = sortSummaries(items).filter((summary) => !query?.agentKey || summary.agentKey === query.agentKey).filter((summary) => {
|
|
3748
|
+
if (!cursor) return true;
|
|
3749
|
+
const [lastActiveAt, sessionId] = cursor;
|
|
3750
|
+
return summary.lastActiveAt < lastActiveAt || summary.lastActiveAt === lastActiveAt && summary.sessionId > sessionId;
|
|
3751
|
+
});
|
|
3752
|
+
const page = filtered.slice(0, limit);
|
|
3753
|
+
return {
|
|
3754
|
+
items: page,
|
|
3755
|
+
nextCursor: filtered.length > limit && page.length > 0 ? encodeCursor(page[page.length - 1]) : void 0
|
|
3673
3756
|
};
|
|
3674
3757
|
}
|
|
3675
3758
|
var HarnessSessionStoreImpl = class {
|
|
3676
3759
|
constructor(config) {
|
|
3677
3760
|
this.config = config;
|
|
3761
|
+
this.storage = config.storage ?? new MemorySessionStorage();
|
|
3678
3762
|
}
|
|
3679
3763
|
config;
|
|
3680
3764
|
sessions = /* @__PURE__ */ new Map();
|
|
3681
3765
|
unsubscriptions = /* @__PURE__ */ new Map();
|
|
3766
|
+
latestRunIds = /* @__PURE__ */ new Map();
|
|
3682
3767
|
listeners = /* @__PURE__ */ new Set();
|
|
3768
|
+
storage;
|
|
3683
3769
|
closed = false;
|
|
3770
|
+
async init() {
|
|
3771
|
+
await this.storage.init?.();
|
|
3772
|
+
}
|
|
3684
3773
|
async getOrCreate(sessionId, overrides) {
|
|
3685
|
-
this.cleanupExpired();
|
|
3686
3774
|
if (this.closed) throw new Error("Harness session store is closed.");
|
|
3687
3775
|
const id = sessionId?.trim() || randomId();
|
|
3688
3776
|
const existing = this.sessions.get(id);
|
|
3689
3777
|
if (existing) return existing;
|
|
3690
|
-
const
|
|
3778
|
+
const config = mergeConfig({ ...this.config, storage: this.storage }, overrides);
|
|
3779
|
+
const stored = await this.storage.getSession(id);
|
|
3780
|
+
const session = await createHarnessSession(config, { sessionId: id, restoredSession: stored });
|
|
3781
|
+
const status = session.getStatus();
|
|
3782
|
+
if (stored?.latestRunId) this.latestRunIds.set(id, stored.latestRunId);
|
|
3783
|
+
else this.latestRunIds.delete(id);
|
|
3784
|
+
if (!stored) {
|
|
3785
|
+
await this.storage.createSession({
|
|
3786
|
+
sessionId: id,
|
|
3787
|
+
agentKey: status.agentKey,
|
|
3788
|
+
createdAt: status.createdAt,
|
|
3789
|
+
lastActiveAt: status.lastActiveAt,
|
|
3790
|
+
mode: status.mode
|
|
3791
|
+
});
|
|
3792
|
+
}
|
|
3691
3793
|
this.sessions.set(id, session);
|
|
3692
|
-
this.unsubscriptions.set(id, session.on((event) =>
|
|
3693
|
-
|
|
3794
|
+
this.unsubscriptions.set(id, session.on((event) => {
|
|
3795
|
+
if (event.type === "run.started") this.latestRunIds.set(id, event.runId);
|
|
3796
|
+
if (event.type === "run.completed") this.latestRunIds.set(id, event.result.runId);
|
|
3797
|
+
if (event.type === "session.status") {
|
|
3798
|
+
void this.storage.touchSession({
|
|
3799
|
+
sessionId: id,
|
|
3800
|
+
lastActiveAt: event.status.lastActiveAt,
|
|
3801
|
+
mode: event.status.mode
|
|
3802
|
+
});
|
|
3803
|
+
}
|
|
3804
|
+
this.notify({ type: "session.event", sessionId: id, event });
|
|
3805
|
+
}));
|
|
3806
|
+
this.notify({ type: "session.created", sessionId: id, status });
|
|
3694
3807
|
return session;
|
|
3695
3808
|
}
|
|
3696
3809
|
get(sessionId) {
|
|
3697
|
-
this.cleanupExpired();
|
|
3698
3810
|
return this.sessions.get(sessionId);
|
|
3699
3811
|
}
|
|
3700
|
-
list() {
|
|
3701
|
-
|
|
3702
|
-
|
|
3812
|
+
async list(query) {
|
|
3813
|
+
if (query?.active) {
|
|
3814
|
+
return paginateActive([...this.sessions.values()].map((session) => statusToSummary(session.getStatus(), this.latestRunIds.get(session.id))), query);
|
|
3815
|
+
}
|
|
3816
|
+
const result = await this.storage.listSessions(query);
|
|
3817
|
+
const active = new Map([...this.sessions.values()].map((session) => [session.id, statusToSummary(session.getStatus(), this.latestRunIds.get(session.id))]));
|
|
3818
|
+
return {
|
|
3819
|
+
items: result.items.map((item) => active.get(item.sessionId) ?? item),
|
|
3820
|
+
nextCursor: result.nextCursor
|
|
3821
|
+
};
|
|
3703
3822
|
}
|
|
3704
|
-
async
|
|
3823
|
+
async close(sessionId) {
|
|
3824
|
+
if (sessionId === void 0) {
|
|
3825
|
+
if (this.closed) return;
|
|
3826
|
+
this.closed = true;
|
|
3827
|
+
await this.closeAll();
|
|
3828
|
+
this.listeners.clear();
|
|
3829
|
+
return;
|
|
3830
|
+
}
|
|
3705
3831
|
const session = this.sessions.get(sessionId);
|
|
3706
3832
|
if (!session) return false;
|
|
3707
3833
|
this.sessions.delete(sessionId);
|
|
3834
|
+
this.latestRunIds.delete(sessionId);
|
|
3708
3835
|
this.unsubscriptions.get(sessionId)?.();
|
|
3709
3836
|
this.unsubscriptions.delete(sessionId);
|
|
3710
3837
|
await session.close();
|
|
3711
|
-
this.notify({ type: "session.deleted", sessionId });
|
|
3712
3838
|
return true;
|
|
3713
3839
|
}
|
|
3714
|
-
async
|
|
3715
|
-
|
|
3840
|
+
async delete(sessionId) {
|
|
3841
|
+
await this.close(sessionId);
|
|
3842
|
+
this.latestRunIds.delete(sessionId);
|
|
3843
|
+
const deleted = await this.storage.deleteSession(sessionId);
|
|
3844
|
+
if (deleted) this.notify({ type: "session.deleted", sessionId });
|
|
3845
|
+
return deleted;
|
|
3846
|
+
}
|
|
3847
|
+
async clearActive() {
|
|
3848
|
+
await this.closeAll();
|
|
3716
3849
|
this.notify({ type: "session.cleared" });
|
|
3717
3850
|
}
|
|
3851
|
+
async closeAll() {
|
|
3852
|
+
for (const sessionId of [...this.sessions.keys()]) await this.close(sessionId);
|
|
3853
|
+
}
|
|
3718
3854
|
async send(sessionId, input, options) {
|
|
3719
3855
|
const session = await this.getOrCreate(sessionId);
|
|
3720
3856
|
return session.send(input, options);
|
|
@@ -3744,26 +3880,14 @@ var HarnessSessionStoreImpl = class {
|
|
|
3744
3880
|
this.listeners.add(listener);
|
|
3745
3881
|
return () => this.listeners.delete(listener);
|
|
3746
3882
|
}
|
|
3747
|
-
async close() {
|
|
3748
|
-
if (this.closed) return;
|
|
3749
|
-
this.closed = true;
|
|
3750
|
-
await this.clear();
|
|
3751
|
-
this.listeners.clear();
|
|
3752
|
-
}
|
|
3753
3883
|
notify(event) {
|
|
3754
3884
|
for (const listener of this.listeners) void listener(event);
|
|
3755
3885
|
}
|
|
3756
|
-
cleanupExpired() {
|
|
3757
|
-
const ttl = this.config.sessionTtlMs;
|
|
3758
|
-
if (!ttl || ttl <= 0) return;
|
|
3759
|
-
const cutoff = Date.now() - ttl;
|
|
3760
|
-
for (const session of [...this.sessions.values()]) {
|
|
3761
|
-
if (Date.parse(session.getStatus().lastActiveAt) < cutoff) void this.delete(session.id);
|
|
3762
|
-
}
|
|
3763
|
-
}
|
|
3764
3886
|
};
|
|
3765
3887
|
async function createHarnessSessionStore(config) {
|
|
3766
|
-
|
|
3888
|
+
const store = new HarnessSessionStoreImpl(config);
|
|
3889
|
+
await store.init();
|
|
3890
|
+
return store;
|
|
3767
3891
|
}
|
|
3768
3892
|
|
|
3769
3893
|
export {
|
|
@@ -3775,4 +3899,4 @@ export {
|
|
|
3775
3899
|
HarnessSessionStoreImpl,
|
|
3776
3900
|
createHarnessSessionStore
|
|
3777
3901
|
};
|
|
3778
|
-
//# sourceMappingURL=chunk-
|
|
3902
|
+
//# sourceMappingURL=chunk-QEVKKJ7N.js.map
|