@earendil-works/pi-agent-core 0.84.1 → 0.84.2
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/harness/events.d.ts +43 -0
- package/dist/harness/events.d.ts.map +1 -0
- package/dist/harness/events.js +65 -0
- package/dist/harness/events.js.map +1 -0
- package/dist/harness/session/jsonl/codec.d.ts +4 -2
- package/dist/harness/session/jsonl/codec.d.ts.map +1 -1
- package/dist/harness/session/jsonl/codec.js +127 -88
- package/dist/harness/session/jsonl/codec.js.map +1 -1
- package/dist/harness/session/jsonl/errors.d.ts +5 -1
- package/dist/harness/session/jsonl/errors.d.ts.map +1 -1
- package/dist/harness/session/jsonl/errors.js +10 -2
- package/dist/harness/session/jsonl/errors.js.map +1 -1
- package/dist/harness/session/jsonl/repo.d.ts +7 -3
- package/dist/harness/session/jsonl/repo.d.ts.map +1 -1
- package/dist/harness/session/jsonl/repo.js +88 -45
- package/dist/harness/session/jsonl/repo.js.map +1 -1
- package/dist/harness/session/jsonl/storage.d.ts +1 -1
- package/dist/harness/session/jsonl/storage.d.ts.map +1 -1
- package/dist/harness/session/jsonl/storage.js +28 -19
- package/dist/harness/session/jsonl/storage.js.map +1 -1
- package/dist/harness/session/jsonl/types.d.ts +1 -1
- package/dist/harness/session/jsonl/types.d.ts.map +1 -1
- package/dist/harness/session/jsonl/types.js.map +1 -1
- package/dist/harness/session/memory.d.ts +1 -1
- package/dist/harness/session/memory.d.ts.map +1 -1
- package/dist/harness/session/memory.js.map +1 -1
- package/dist/harness/session/session.d.ts +1 -1
- package/dist/harness/session/session.d.ts.map +1 -1
- package/dist/harness/session/session.js +7 -2
- package/dist/harness/session/session.js.map +1 -1
- package/dist/harness/session/state.d.ts +1 -1
- package/dist/harness/session/state.d.ts.map +1 -1
- package/dist/harness/session/state.js.map +1 -1
- package/dist/harness/session/testing/conformance.d.ts.map +1 -1
- package/dist/harness/session/testing/conformance.js +19 -0
- package/dist/harness/session/testing/conformance.js.map +1 -1
- package/dist/harness/session/types.d.ts +18 -5
- package/dist/harness/session/types.d.ts.map +1 -1
- package/dist/harness/session/types.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/proxy.d.ts +2 -1
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +1 -0
- package/dist/proxy.js.map +1 -1
- package/dist/search/index.d.ts +21 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +2 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/scanning.d.ts +29 -0
- package/dist/search/scanning.d.ts.map +1 -0
- package/dist/search/scanning.js +103 -0
- package/dist/search/scanning.js.map +1 -0
- package/package.json +3 -3
- package/dist/harness/session/search.d.ts +0 -19
- package/dist/harness/session/search.d.ts.map +0 -1
- package/dist/harness/session/search.js +0 -42
- package/dist/harness/session/search.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FileSystem } from "../../types.ts";
|
|
2
2
|
import type { JsonValue, SessionCreateOptions, SessionMetadata } from "../types.ts";
|
|
3
|
-
export type JsonlSessionRepoFileSystem = Pick<FileSystem, "absolutePath" | "joinPath" | "readTextFile" | "writeFile" | "appendFile" | "renameFile" | "fileInfo" | "listDir" | "exists" | "createDir" | "remove">;
|
|
3
|
+
export type JsonlSessionRepoFileSystem = Pick<FileSystem, "absolutePath" | "joinPath" | "readTextFile" | "readTextLines" | "writeFile" | "appendFile" | "renameFile" | "fileInfo" | "listDir" | "exists" | "createDir" | "remove">;
|
|
4
4
|
export interface JsonlSessionRepoOptions {
|
|
5
5
|
fs: JsonlSessionRepoFileSystem;
|
|
6
6
|
/** Root containing coding-agent-compatible cwd-encoded session directories. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEpF,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAC5C,UAAU,EACR,cAAc,GACd,UAAU,GACV,cAAc,GACd,WAAW,GACX,YAAY,GACZ,YAAY,GACZ,UAAU,GACV,SAAS,GACT,QAAQ,GACR,WAAW,GACX,QAAQ,CACV,CAAC;AAEF,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,0BAA0B,CAAC;IAC/B,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC;IACpB,gFAAgF;IAChF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,yBAA0B,SAAQ,oBAAoB;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,uBAAuB;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,CAAC,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kFAAkF;IAClF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC","sourcesContent":["import type { FileSystem } from \"../../types.ts\";\nimport type { JsonValue, SessionCreateOptions, SessionMetadata } from \"../types.ts\";\n\nexport type JsonlSessionRepoFileSystem = Pick<\n\tFileSystem,\n\t| \"absolutePath\"\n\t| \"joinPath\"\n\t| \"readTextFile\"\n\t| \"writeFile\"\n\t| \"appendFile\"\n\t| \"renameFile\"\n\t| \"fileInfo\"\n\t| \"listDir\"\n\t| \"exists\"\n\t| \"createDir\"\n\t| \"remove\"\n>;\n\nexport interface JsonlSessionRepoOptions {\n\tfs: JsonlSessionRepoFileSystem;\n\t/** Root containing coding-agent-compatible cwd-encoded session directories. */\n\tsessionsRoot: string;\n}\n\nexport interface JsonlSessionMetadata extends SessionMetadata {\n\tcwd: string;\n\tpath: string;\n\t/** Filesystem modification time as milliseconds since Unix epoch. */\n\tmodifiedAt: number;\n\tsourceFormat: 3 | 4;\n\t/** Present only when a v3 parent path could not be resolved to a session id. */\n\tlegacyParentSessionPath?: string;\n\t/** Opaque application-owned metadata. */\n\tmetadata?: Record<string, JsonValue>;\n}\n\nexport interface JsonlSessionCreateOptions extends SessionCreateOptions {\n\tcwd: string;\n\tmetadata?: Record<string, JsonValue>;\n}\n\nexport interface JsonlSessionListOptions {\n\tcwd?: string;\n}\n\nexport interface JsonlV4Header {\n\tkind: \"header\";\n\tversion: 4;\n\tid: string;\n\tcreatedAt: number;\n\tcwd: string;\n\tparentSessionId?: string;\n\t/** Preserved only when a v3 parent path could not be resolved to a session id. */\n\tlegacyParentSessionPath?: string;\n\tmetadata?: Record<string, JsonValue>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEpF,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAC5C,UAAU,EACR,cAAc,GACd,UAAU,GACV,cAAc,GACd,eAAe,GACf,WAAW,GACX,YAAY,GACZ,YAAY,GACZ,UAAU,GACV,SAAS,GACT,QAAQ,GACR,WAAW,GACX,QAAQ,CACV,CAAC;AAEF,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,0BAA0B,CAAC;IAC/B,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC;IACpB,gFAAgF;IAChF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,yBAA0B,SAAQ,oBAAoB;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,uBAAuB;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,CAAC,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kFAAkF;IAClF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrC","sourcesContent":["import type { FileSystem } from \"../../types.ts\";\nimport type { JsonValue, SessionCreateOptions, SessionMetadata } from \"../types.ts\";\n\nexport type JsonlSessionRepoFileSystem = Pick<\n\tFileSystem,\n\t| \"absolutePath\"\n\t| \"joinPath\"\n\t| \"readTextFile\"\n\t| \"readTextLines\"\n\t| \"writeFile\"\n\t| \"appendFile\"\n\t| \"renameFile\"\n\t| \"fileInfo\"\n\t| \"listDir\"\n\t| \"exists\"\n\t| \"createDir\"\n\t| \"remove\"\n>;\n\nexport interface JsonlSessionRepoOptions {\n\tfs: JsonlSessionRepoFileSystem;\n\t/** Root containing coding-agent-compatible cwd-encoded session directories. */\n\tsessionsRoot: string;\n}\n\nexport interface JsonlSessionMetadata extends SessionMetadata {\n\tcwd: string;\n\tpath: string;\n\t/** Filesystem modification time as milliseconds since Unix epoch. */\n\tmodifiedAt: number;\n\tsourceFormat: 3 | 4;\n\t/** Present only when a v3 parent path could not be resolved to a session id. */\n\tlegacyParentSessionPath?: string;\n\t/** Opaque application-owned metadata. */\n\tmetadata?: Record<string, JsonValue>;\n}\n\nexport interface JsonlSessionCreateOptions extends SessionCreateOptions {\n\tcwd: string;\n\tmetadata?: Record<string, JsonValue>;\n}\n\nexport interface JsonlSessionListOptions {\n\tcwd?: string;\n}\n\nexport interface JsonlV4Header {\n\tkind: \"header\";\n\tversion: 4;\n\tid: string;\n\tcreatedAt: number;\n\tcwd: string;\n\tparentSessionId?: string;\n\t/** Preserved only when a v3 parent path could not be resolved to a session id. */\n\tlegacyParentSessionPath?: string;\n\tmetadata?: Record<string, JsonValue>;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { FileSystem } from \"../../types.ts\";\nimport type { JsonValue, SessionCreateOptions, SessionMetadata } from \"../types.ts\";\n\nexport type JsonlSessionRepoFileSystem = Pick<\n\tFileSystem,\n\t| \"absolutePath\"\n\t| \"joinPath\"\n\t| \"readTextFile\"\n\t| \"writeFile\"\n\t| \"appendFile\"\n\t| \"renameFile\"\n\t| \"fileInfo\"\n\t| \"listDir\"\n\t| \"exists\"\n\t| \"createDir\"\n\t| \"remove\"\n>;\n\nexport interface JsonlSessionRepoOptions {\n\tfs: JsonlSessionRepoFileSystem;\n\t/** Root containing coding-agent-compatible cwd-encoded session directories. */\n\tsessionsRoot: string;\n}\n\nexport interface JsonlSessionMetadata extends SessionMetadata {\n\tcwd: string;\n\tpath: string;\n\t/** Filesystem modification time as milliseconds since Unix epoch. */\n\tmodifiedAt: number;\n\tsourceFormat: 3 | 4;\n\t/** Present only when a v3 parent path could not be resolved to a session id. */\n\tlegacyParentSessionPath?: string;\n\t/** Opaque application-owned metadata. */\n\tmetadata?: Record<string, JsonValue>;\n}\n\nexport interface JsonlSessionCreateOptions extends SessionCreateOptions {\n\tcwd: string;\n\tmetadata?: Record<string, JsonValue>;\n}\n\nexport interface JsonlSessionListOptions {\n\tcwd?: string;\n}\n\nexport interface JsonlV4Header {\n\tkind: \"header\";\n\tversion: 4;\n\tid: string;\n\tcreatedAt: number;\n\tcwd: string;\n\tparentSessionId?: string;\n\t/** Preserved only when a v3 parent path could not be resolved to a session id. */\n\tlegacyParentSessionPath?: string;\n\tmetadata?: Record<string, JsonValue>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { FileSystem } from \"../../types.ts\";\nimport type { JsonValue, SessionCreateOptions, SessionMetadata } from \"../types.ts\";\n\nexport type JsonlSessionRepoFileSystem = Pick<\n\tFileSystem,\n\t| \"absolutePath\"\n\t| \"joinPath\"\n\t| \"readTextFile\"\n\t| \"readTextLines\"\n\t| \"writeFile\"\n\t| \"appendFile\"\n\t| \"renameFile\"\n\t| \"fileInfo\"\n\t| \"listDir\"\n\t| \"exists\"\n\t| \"createDir\"\n\t| \"remove\"\n>;\n\nexport interface JsonlSessionRepoOptions {\n\tfs: JsonlSessionRepoFileSystem;\n\t/** Root containing coding-agent-compatible cwd-encoded session directories. */\n\tsessionsRoot: string;\n}\n\nexport interface JsonlSessionMetadata extends SessionMetadata {\n\tcwd: string;\n\tpath: string;\n\t/** Filesystem modification time as milliseconds since Unix epoch. */\n\tmodifiedAt: number;\n\tsourceFormat: 3 | 4;\n\t/** Present only when a v3 parent path could not be resolved to a session id. */\n\tlegacyParentSessionPath?: string;\n\t/** Opaque application-owned metadata. */\n\tmetadata?: Record<string, JsonValue>;\n}\n\nexport interface JsonlSessionCreateOptions extends SessionCreateOptions {\n\tcwd: string;\n\tmetadata?: Record<string, JsonValue>;\n}\n\nexport interface JsonlSessionListOptions {\n\tcwd?: string;\n}\n\nexport interface JsonlV4Header {\n\tkind: \"header\";\n\tversion: 4;\n\tid: string;\n\tcreatedAt: number;\n\tcwd: string;\n\tparentSessionId?: string;\n\t/** Preserved only when a v3 parent path could not be resolved to a session id. */\n\tlegacyParentSessionPath?: string;\n\tmetadata?: Record<string, JsonValue>;\n}\n"]}
|
|
@@ -27,7 +27,7 @@ export declare class InMemorySessionStorage implements SessionStorage {
|
|
|
27
27
|
}): Promise<OperationStartedRecord[]>;
|
|
28
28
|
getLog(options?: LogOptions): Promise<LogItem[]>;
|
|
29
29
|
getName(): Promise<string | undefined>;
|
|
30
|
-
setName(name: string): Promise<void>;
|
|
30
|
+
setName(name: string | undefined): Promise<void>;
|
|
31
31
|
getLabel(id: string): Promise<string | undefined>;
|
|
32
32
|
setLabel(id: string, label: string | undefined): Promise<void>;
|
|
33
33
|
getStats(): Promise<SessionStats>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/harness/session/memory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,oBAAoB,EAEzB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,MAAM,YAAY,CAAC;AAEpB,qBAAa,sBAAuB,YAAW,cAAc;IAC5D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;IAE5C,YAAY,QAAQ,EAAE,eAAe,EAEpC;IAED,IAAI,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,WAAW,GAAG,oBAAoB,GAAG,sBAAsB,CAInG;IAEK,WAAW,IAAI,OAAO,CAAC,eAAe,CAAC,CAE5C;IAEK,QAAQ,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAEvC;IAEK,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAI/D;IAEK,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D;IAEK,WAAW,CAAC,MAAM,SAAS,KAAK,EAAE,QAAQ,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWzG;IAEK,YAAY,CAAC,OAAO,SAAS,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAiB9F;IAEK,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAGrD;IAEK,WAAW,CAAC,KAAK,GAAE,UAAe,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAE1D;IAEK,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,YAAY,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAEhG;IAEK,WAAW,CAAC,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,EAC7C,KAAK,EAAE,WAAW,GAAG;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,GAC9B,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,EAAE,CAAC,CAAC;IACzC,WAAW,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAKxD,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAEtG;IAEK,MAAM,CAAC,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAEzD;IAEK,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE3C;IAEK,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/harness/session/memory.ts"],"names":[],"mappings":"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","sourcesContent":["import { uuidv7 } from \"@earendil-works/pi-ai\";\nimport { Session } from \"./session.ts\";\nimport { SessionState } from \"./state.ts\";\nimport {\n\ttype BranchBounds,\n\ttype Entry,\n\ttype EntryQuery,\n\ttype ForkOptions,\n\ttype LanePointer,\n\ttype LaneRecord,\n\ttype LogItem,\n\ttype LogOptions,\n\ttype NewRecord,\n\ttype OperationStartedRecord,\n\ttype ProvisionedEntry,\n\ttype RecordQuery,\n\ttype SessionCreateOptions,\n\tSessionError,\n\ttype SessionMetadata,\n\ttype SessionRepo,\n\ttype SessionStats,\n\ttype SessionStorage,\n} from \"./types.ts\";\n\nexport class InMemorySessionStorage implements SessionStorage {\n\tprivate readonly metadata: SessionMetadata;\n\tprivate readonly state = new SessionState();\n\n\tconstructor(metadata: SessionMetadata) {\n\t\tthis.metadata = structuredClone(metadata);\n\t}\n\n\tfork(metadata: SessionMetadata, options: ForkOptions & SessionCreateOptions): InMemorySessionStorage {\n\t\tconst storage = new InMemorySessionStorage(metadata);\n\t\tfor (const mutation of this.state.createForkMutations(options)) storage.state.applyMutation(mutation);\n\t\treturn storage;\n\t}\n\n\tasync getMetadata(): Promise<SessionMetadata> {\n\t\treturn structuredClone(this.metadata);\n\t}\n\n\tasync getLanes(): Promise<LanePointer[]> {\n\t\treturn this.state.getLanes();\n\t}\n\n\tasync createLane(lane: string, at: string | null): Promise<void> {\n\t\tthis.state.validateNewLane(lane);\n\t\tthis.state.validateTarget(at);\n\t\tthis.state.applyMutation({ kind: \"lane\", seq: this.state.nextSequence, lane, leafId: at });\n\t}\n\n\tasync moveLane(lane: string, to: string | null): Promise<void> {\n\t\tthis.state.requireLane(lane);\n\t\tthis.state.validateTarget(to);\n\t\tthis.state.applyMutation({ kind: \"lane\", seq: this.state.nextSequence, lane, leafId: to });\n\t}\n\n\tasync appendEntry<TEntry extends Entry>(newEntry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\tconst parentId = this.state.requireLane(lane);\n\t\tthis.state.validateUnusedId(newEntry.id);\n\t\tconst entry = {\n\t\t\t...structuredClone(newEntry),\n\t\t\tparentId,\n\t\t\tseq: this.state.nextSequence,\n\t\t\ttimestamp: Date.now(),\n\t\t} as unknown as TEntry;\n\t\tthis.state.applyMutation({ kind: \"entry\", lane, entry });\n\t\treturn structuredClone(entry);\n\t}\n\n\tasync appendRecord<TRecord extends LaneRecord>(newRecord: NewRecord<TRecord>): Promise<TRecord> {\n\t\tthis.state.requireLane(newRecord.lane);\n\t\tthis.state.validateUnusedId(newRecord.id);\n\t\tconst currentOpenOperationId = this.state.findOpenOperations(newRecord.lane, { limit: 1 })[0]?.id;\n\t\tif (newRecord.type === \"operation_started\" && currentOpenOperationId !== undefined) {\n\t\t\tthrow new SessionError(\n\t\t\t\t\"storage\",\n\t\t\t\t`Lane ${newRecord.lane} already has an open operation ${currentOpenOperationId}`,\n\t\t\t);\n\t\t}\n\t\tconst record = {\n\t\t\t...structuredClone(newRecord),\n\t\t\tseq: this.state.nextSequence,\n\t\t\ttimestamp: Date.now(),\n\t\t} as unknown as TRecord;\n\t\tthis.state.applyMutation({ kind: \"record\", record });\n\t\treturn structuredClone(record);\n\t}\n\n\tasync getEntry(id: string): Promise<Entry | undefined> {\n\t\tconst entry = this.state.getEntry(id);\n\t\treturn entry === undefined ? undefined : structuredClone(entry);\n\t}\n\n\tasync findEntries(query: EntryQuery = {}): Promise<Entry[]> {\n\t\treturn structuredClone(this.state.findEntries(query));\n\t}\n\n\tasync findEntriesOnBranch(query: EntryQuery & BranchBounds & { start: string }): Promise<Entry[]> {\n\t\treturn structuredClone(this.state.findEntriesOnBranch(query));\n\t}\n\n\tasync findRecords<K extends LaneRecord[\"type\"]>(\n\t\tquery: RecordQuery & { type: K },\n\t): Promise<Extract<LaneRecord, { type: K }>[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]>;\n\tasync findRecords(query: RecordQuery = {}): Promise<LaneRecord[]> {\n\t\treturn structuredClone(this.state.findRecords(query));\n\t}\n\n\tasync findOpenOperations(lane: string, options?: { limit?: number }): Promise<OperationStartedRecord[]> {\n\t\treturn structuredClone(this.state.findOpenOperations(lane, options));\n\t}\n\n\tasync getLog(options: LogOptions = {}): Promise<LogItem[]> {\n\t\treturn structuredClone(this.state.getLog(options));\n\t}\n\n\tasync getName(): Promise<string | undefined> {\n\t\treturn this.state.getName();\n\t}\n\n\tasync setName(name: string | undefined): Promise<void> {\n\t\tthis.state.applyMutation({ kind: \"fact\", seq: this.state.nextSequence, fact: \"name\", name });\n\t}\n\n\tasync getLabel(id: string): Promise<string | undefined> {\n\t\treturn this.state.getLabel(id);\n\t}\n\n\tasync setLabel(id: string, label: string | undefined): Promise<void> {\n\t\tthis.state.validateTarget(id);\n\t\tthis.state.applyMutation({\n\t\t\tkind: \"fact\",\n\t\t\tseq: this.state.nextSequence,\n\t\t\tfact: \"label\",\n\t\t\ttargetId: id,\n\t\t\tlabel,\n\t\t});\n\t}\n\n\tasync getStats(): Promise<SessionStats> {\n\t\treturn structuredClone(this.state.getStats());\n\t}\n}\n\nexport class InMemorySessionRepo implements SessionRepo {\n\tprivate readonly sessions = new Map<string, InMemorySessionStorage>();\n\n\tasync create(options: SessionCreateOptions = {}): Promise<Session> {\n\t\tconst id = options.id ?? uuidv7();\n\t\tif (this.sessions.has(id)) throw new SessionError(\"already_exists\", `Session already exists: ${id}`);\n\t\tconst storage = new InMemorySessionStorage({\n\t\t\tid,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tparentSessionId: options.parentSessionId,\n\t\t});\n\t\tthis.sessions.set(id, storage);\n\t\treturn new Session(storage);\n\t}\n\n\tasync open(metadata: SessionMetadata): Promise<Session> {\n\t\treturn new Session(this.requireStorage(metadata.id));\n\t}\n\n\tasync list(): Promise<SessionMetadata[]> {\n\t\treturn Promise.all([...this.sessions.values()].map((storage) => storage.getMetadata()));\n\t}\n\n\tasync delete(metadata: SessionMetadata): Promise<void> {\n\t\tthis.sessions.delete(metadata.id);\n\t}\n\n\tasync fork(source: SessionMetadata, options: ForkOptions & SessionCreateOptions = {}): Promise<Session> {\n\t\tconst sourceStorage = this.requireStorage(source.id);\n\t\tconst id = options.id ?? uuidv7();\n\t\tif (this.sessions.has(id)) throw new SessionError(\"already_exists\", `Session already exists: ${id}`);\n\t\tconst storage = sourceStorage.fork(\n\t\t\t{ id, createdAt: Date.now(), parentSessionId: options.parentSessionId ?? source.id },\n\t\t\toptions,\n\t\t);\n\t\tthis.sessions.set(id, storage);\n\t\treturn new Session(storage);\n\t}\n\n\tprivate requireStorage(id: string): InMemorySessionStorage {\n\t\tconst storage = this.sessions.get(id);\n\t\tif (!storage) throw new SessionError(\"not_found\", `Session not found: ${id}`);\n\t\treturn storage;\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/harness/session/memory.ts"],"names":[],"mappings":"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","sourcesContent":["import { uuidv7 } from \"@earendil-works/pi-ai\";\nimport { Session } from \"./session.ts\";\nimport { SessionState } from \"./state.ts\";\nimport {\n\ttype BranchBounds,\n\ttype Entry,\n\ttype EntryQuery,\n\ttype ForkOptions,\n\ttype LanePointer,\n\ttype LaneRecord,\n\ttype LogItem,\n\ttype LogOptions,\n\ttype NewRecord,\n\ttype OperationStartedRecord,\n\ttype ProvisionedEntry,\n\ttype RecordQuery,\n\ttype SessionCreateOptions,\n\tSessionError,\n\ttype SessionMetadata,\n\ttype SessionRepo,\n\ttype SessionStats,\n\ttype SessionStorage,\n} from \"./types.ts\";\n\nexport class InMemorySessionStorage implements SessionStorage {\n\tprivate readonly metadata: SessionMetadata;\n\tprivate readonly state = new SessionState();\n\n\tconstructor(metadata: SessionMetadata) {\n\t\tthis.metadata = structuredClone(metadata);\n\t}\n\n\tfork(metadata: SessionMetadata, options: ForkOptions & SessionCreateOptions): InMemorySessionStorage {\n\t\tconst storage = new InMemorySessionStorage(metadata);\n\t\tfor (const mutation of this.state.createForkMutations(options)) storage.state.applyMutation(mutation);\n\t\treturn storage;\n\t}\n\n\tasync getMetadata(): Promise<SessionMetadata> {\n\t\treturn structuredClone(this.metadata);\n\t}\n\n\tasync getLanes(): Promise<LanePointer[]> {\n\t\treturn this.state.getLanes();\n\t}\n\n\tasync createLane(lane: string, at: string | null): Promise<void> {\n\t\tthis.state.validateNewLane(lane);\n\t\tthis.state.validateTarget(at);\n\t\tthis.state.applyMutation({ kind: \"lane\", seq: this.state.nextSequence, lane, leafId: at });\n\t}\n\n\tasync moveLane(lane: string, to: string | null): Promise<void> {\n\t\tthis.state.requireLane(lane);\n\t\tthis.state.validateTarget(to);\n\t\tthis.state.applyMutation({ kind: \"lane\", seq: this.state.nextSequence, lane, leafId: to });\n\t}\n\n\tasync appendEntry<TEntry extends Entry>(newEntry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\tconst parentId = this.state.requireLane(lane);\n\t\tthis.state.validateUnusedId(newEntry.id);\n\t\tconst entry = {\n\t\t\t...structuredClone(newEntry),\n\t\t\tparentId,\n\t\t\tseq: this.state.nextSequence,\n\t\t\ttimestamp: Date.now(),\n\t\t} as unknown as TEntry;\n\t\tthis.state.applyMutation({ kind: \"entry\", lane, entry });\n\t\treturn structuredClone(entry);\n\t}\n\n\tasync appendRecord<TRecord extends LaneRecord>(newRecord: NewRecord<TRecord>): Promise<TRecord> {\n\t\tthis.state.requireLane(newRecord.lane);\n\t\tthis.state.validateUnusedId(newRecord.id);\n\t\tconst currentOpenOperationId = this.state.findOpenOperations(newRecord.lane, { limit: 1 })[0]?.id;\n\t\tif (newRecord.type === \"operation_started\" && currentOpenOperationId !== undefined) {\n\t\t\tthrow new SessionError(\n\t\t\t\t\"storage\",\n\t\t\t\t`Lane ${newRecord.lane} already has an open operation ${currentOpenOperationId}`,\n\t\t\t);\n\t\t}\n\t\tconst record = {\n\t\t\t...structuredClone(newRecord),\n\t\t\tseq: this.state.nextSequence,\n\t\t\ttimestamp: Date.now(),\n\t\t} as unknown as TRecord;\n\t\tthis.state.applyMutation({ kind: \"record\", record });\n\t\treturn structuredClone(record);\n\t}\n\n\tasync getEntry(id: string): Promise<Entry | undefined> {\n\t\tconst entry = this.state.getEntry(id);\n\t\treturn entry === undefined ? undefined : structuredClone(entry);\n\t}\n\n\tasync findEntries(query: EntryQuery = {}): Promise<Entry[]> {\n\t\treturn structuredClone(this.state.findEntries(query));\n\t}\n\n\tasync findEntriesOnBranch(query: EntryQuery & BranchBounds & { start: string }): Promise<Entry[]> {\n\t\treturn structuredClone(this.state.findEntriesOnBranch(query));\n\t}\n\n\tasync findRecords<K extends LaneRecord[\"type\"]>(\n\t\tquery: RecordQuery & { type: K },\n\t): Promise<Extract<LaneRecord, { type: K }>[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]>;\n\tasync findRecords(query: RecordQuery = {}): Promise<LaneRecord[]> {\n\t\treturn structuredClone(this.state.findRecords(query));\n\t}\n\n\tasync findOpenOperations(lane: string, options?: { limit?: number }): Promise<OperationStartedRecord[]> {\n\t\treturn structuredClone(this.state.findOpenOperations(lane, options));\n\t}\n\n\tasync getLog(options: LogOptions = {}): Promise<LogItem[]> {\n\t\treturn structuredClone(this.state.getLog(options));\n\t}\n\n\tasync getName(): Promise<string | undefined> {\n\t\treturn this.state.getName();\n\t}\n\n\tasync setName(name: string): Promise<void> {\n\t\tthis.state.applyMutation({ kind: \"fact\", seq: this.state.nextSequence, fact: \"name\", name });\n\t}\n\n\tasync getLabel(id: string): Promise<string | undefined> {\n\t\treturn this.state.getLabel(id);\n\t}\n\n\tasync setLabel(id: string, label: string | undefined): Promise<void> {\n\t\tthis.state.validateTarget(id);\n\t\tthis.state.applyMutation({\n\t\t\tkind: \"fact\",\n\t\t\tseq: this.state.nextSequence,\n\t\t\tfact: \"label\",\n\t\t\ttargetId: id,\n\t\t\tlabel,\n\t\t});\n\t}\n\n\tasync getStats(): Promise<SessionStats> {\n\t\treturn structuredClone(this.state.getStats());\n\t}\n}\n\nexport class InMemorySessionRepo implements SessionRepo {\n\tprivate readonly sessions = new Map<string, InMemorySessionStorage>();\n\n\tasync create(options: SessionCreateOptions = {}): Promise<Session> {\n\t\tconst id = options.id ?? uuidv7();\n\t\tif (this.sessions.has(id)) throw new SessionError(\"already_exists\", `Session already exists: ${id}`);\n\t\tconst storage = new InMemorySessionStorage({\n\t\t\tid,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tparentSessionId: options.parentSessionId,\n\t\t});\n\t\tthis.sessions.set(id, storage);\n\t\treturn new Session(storage);\n\t}\n\n\tasync open(metadata: SessionMetadata): Promise<Session> {\n\t\treturn new Session(this.requireStorage(metadata.id));\n\t}\n\n\tasync list(): Promise<SessionMetadata[]> {\n\t\treturn Promise.all([...this.sessions.values()].map((storage) => storage.getMetadata()));\n\t}\n\n\tasync delete(metadata: SessionMetadata): Promise<void> {\n\t\tthis.sessions.delete(metadata.id);\n\t}\n\n\tasync fork(source: SessionMetadata, options: ForkOptions & SessionCreateOptions = {}): Promise<Session> {\n\t\tconst sourceStorage = this.requireStorage(source.id);\n\t\tconst id = options.id ?? uuidv7();\n\t\tif (this.sessions.has(id)) throw new SessionError(\"already_exists\", `Session already exists: ${id}`);\n\t\tconst storage = sourceStorage.fork(\n\t\t\t{ id, createdAt: Date.now(), parentSessionId: options.parentSessionId ?? source.id },\n\t\t\toptions,\n\t\t);\n\t\tthis.sessions.set(id, storage);\n\t\treturn new Session(storage);\n\t}\n\n\tprivate requireStorage(id: string): InMemorySessionStorage {\n\t\tconst storage = this.sessions.get(id);\n\t\tif (!storage) throw new SessionError(\"not_found\", `Session not found: ${id}`);\n\t\treturn storage;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/harness/session/memory.ts"],"names":[],"mappings":"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","sourcesContent":["import { uuidv7 } from \"@earendil-works/pi-ai\";\nimport { Session } from \"./session.ts\";\nimport { SessionState } from \"./state.ts\";\nimport {\n\ttype BranchBounds,\n\ttype Entry,\n\ttype EntryQuery,\n\ttype ForkOptions,\n\ttype LanePointer,\n\ttype LaneRecord,\n\ttype LogItem,\n\ttype LogOptions,\n\ttype NewRecord,\n\ttype OperationStartedRecord,\n\ttype ProvisionedEntry,\n\ttype RecordQuery,\n\ttype SessionCreateOptions,\n\tSessionError,\n\ttype SessionMetadata,\n\ttype SessionRepo,\n\ttype SessionStats,\n\ttype SessionStorage,\n} from \"./types.ts\";\n\nexport class InMemorySessionStorage implements SessionStorage {\n\tprivate readonly metadata: SessionMetadata;\n\tprivate readonly state = new SessionState();\n\n\tconstructor(metadata: SessionMetadata) {\n\t\tthis.metadata = structuredClone(metadata);\n\t}\n\n\tfork(metadata: SessionMetadata, options: ForkOptions & SessionCreateOptions): InMemorySessionStorage {\n\t\tconst storage = new InMemorySessionStorage(metadata);\n\t\tfor (const mutation of this.state.createForkMutations(options)) storage.state.applyMutation(mutation);\n\t\treturn storage;\n\t}\n\n\tasync getMetadata(): Promise<SessionMetadata> {\n\t\treturn structuredClone(this.metadata);\n\t}\n\n\tasync getLanes(): Promise<LanePointer[]> {\n\t\treturn this.state.getLanes();\n\t}\n\n\tasync createLane(lane: string, at: string | null): Promise<void> {\n\t\tthis.state.validateNewLane(lane);\n\t\tthis.state.validateTarget(at);\n\t\tthis.state.applyMutation({ kind: \"lane\", seq: this.state.nextSequence, lane, leafId: at });\n\t}\n\n\tasync moveLane(lane: string, to: string | null): Promise<void> {\n\t\tthis.state.requireLane(lane);\n\t\tthis.state.validateTarget(to);\n\t\tthis.state.applyMutation({ kind: \"lane\", seq: this.state.nextSequence, lane, leafId: to });\n\t}\n\n\tasync appendEntry<TEntry extends Entry>(newEntry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\tconst parentId = this.state.requireLane(lane);\n\t\tthis.state.validateUnusedId(newEntry.id);\n\t\tconst entry = {\n\t\t\t...structuredClone(newEntry),\n\t\t\tparentId,\n\t\t\tseq: this.state.nextSequence,\n\t\t\ttimestamp: Date.now(),\n\t\t} as unknown as TEntry;\n\t\tthis.state.applyMutation({ kind: \"entry\", lane, entry });\n\t\treturn structuredClone(entry);\n\t}\n\n\tasync appendRecord<TRecord extends LaneRecord>(newRecord: NewRecord<TRecord>): Promise<TRecord> {\n\t\tthis.state.requireLane(newRecord.lane);\n\t\tthis.state.validateUnusedId(newRecord.id);\n\t\tconst currentOpenOperationId = this.state.findOpenOperations(newRecord.lane, { limit: 1 })[0]?.id;\n\t\tif (newRecord.type === \"operation_started\" && currentOpenOperationId !== undefined) {\n\t\t\tthrow new SessionError(\n\t\t\t\t\"storage\",\n\t\t\t\t`Lane ${newRecord.lane} already has an open operation ${currentOpenOperationId}`,\n\t\t\t);\n\t\t}\n\t\tconst record = {\n\t\t\t...structuredClone(newRecord),\n\t\t\tseq: this.state.nextSequence,\n\t\t\ttimestamp: Date.now(),\n\t\t} as unknown as TRecord;\n\t\tthis.state.applyMutation({ kind: \"record\", record });\n\t\treturn structuredClone(record);\n\t}\n\n\tasync getEntry(id: string): Promise<Entry | undefined> {\n\t\tconst entry = this.state.getEntry(id);\n\t\treturn entry === undefined ? undefined : structuredClone(entry);\n\t}\n\n\tasync findEntries(query: EntryQuery = {}): Promise<Entry[]> {\n\t\treturn structuredClone(this.state.findEntries(query));\n\t}\n\n\tasync findEntriesOnBranch(query: EntryQuery & BranchBounds & { start: string }): Promise<Entry[]> {\n\t\treturn structuredClone(this.state.findEntriesOnBranch(query));\n\t}\n\n\tasync findRecords<K extends LaneRecord[\"type\"]>(\n\t\tquery: RecordQuery & { type: K },\n\t): Promise<Extract<LaneRecord, { type: K }>[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]>;\n\tasync findRecords(query: RecordQuery = {}): Promise<LaneRecord[]> {\n\t\treturn structuredClone(this.state.findRecords(query));\n\t}\n\n\tasync findOpenOperations(lane: string, options?: { limit?: number }): Promise<OperationStartedRecord[]> {\n\t\treturn structuredClone(this.state.findOpenOperations(lane, options));\n\t}\n\n\tasync getLog(options: LogOptions = {}): Promise<LogItem[]> {\n\t\treturn structuredClone(this.state.getLog(options));\n\t}\n\n\tasync getName(): Promise<string | undefined> {\n\t\treturn this.state.getName();\n\t}\n\n\tasync setName(name: string | undefined): Promise<void> {\n\t\tthis.state.applyMutation({ kind: \"fact\", seq: this.state.nextSequence, fact: \"name\", name });\n\t}\n\n\tasync getLabel(id: string): Promise<string | undefined> {\n\t\treturn this.state.getLabel(id);\n\t}\n\n\tasync setLabel(id: string, label: string | undefined): Promise<void> {\n\t\tthis.state.validateTarget(id);\n\t\tthis.state.applyMutation({\n\t\t\tkind: \"fact\",\n\t\t\tseq: this.state.nextSequence,\n\t\t\tfact: \"label\",\n\t\t\ttargetId: id,\n\t\t\tlabel,\n\t\t});\n\t}\n\n\tasync getStats(): Promise<SessionStats> {\n\t\treturn structuredClone(this.state.getStats());\n\t}\n}\n\nexport class InMemorySessionRepo implements SessionRepo {\n\tprivate readonly sessions = new Map<string, InMemorySessionStorage>();\n\n\tasync create(options: SessionCreateOptions = {}): Promise<Session> {\n\t\tconst id = options.id ?? uuidv7();\n\t\tif (this.sessions.has(id)) throw new SessionError(\"already_exists\", `Session already exists: ${id}`);\n\t\tconst storage = new InMemorySessionStorage({\n\t\t\tid,\n\t\t\tcreatedAt: Date.now(),\n\t\t\tparentSessionId: options.parentSessionId,\n\t\t});\n\t\tthis.sessions.set(id, storage);\n\t\treturn new Session(storage);\n\t}\n\n\tasync open(metadata: SessionMetadata): Promise<Session> {\n\t\treturn new Session(this.requireStorage(metadata.id));\n\t}\n\n\tasync list(): Promise<SessionMetadata[]> {\n\t\treturn Promise.all([...this.sessions.values()].map((storage) => storage.getMetadata()));\n\t}\n\n\tasync delete(metadata: SessionMetadata): Promise<void> {\n\t\tthis.sessions.delete(metadata.id);\n\t}\n\n\tasync fork(source: SessionMetadata, options: ForkOptions & SessionCreateOptions = {}): Promise<Session> {\n\t\tconst sourceStorage = this.requireStorage(source.id);\n\t\tconst id = options.id ?? uuidv7();\n\t\tif (this.sessions.has(id)) throw new SessionError(\"already_exists\", `Session already exists: ${id}`);\n\t\tconst storage = sourceStorage.fork(\n\t\t\t{ id, createdAt: Date.now(), parentSessionId: options.parentSessionId ?? source.id },\n\t\t\toptions,\n\t\t);\n\t\tthis.sessions.set(id, storage);\n\t\treturn new Session(storage);\n\t}\n\n\tprivate requireStorage(id: string): InMemorySessionStorage {\n\t\tconst storage = this.sessions.get(id);\n\t\tif (!storage) throw new SessionError(\"not_found\", `Session not found: ${id}`);\n\t\treturn storage;\n\t}\n}\n"]}
|
|
@@ -13,7 +13,7 @@ export declare class Session<TMetadata extends SessionMetadata = SessionMetadata
|
|
|
13
13
|
getEntry(id: string): Promise<Entry | undefined>;
|
|
14
14
|
getStats(): Promise<SessionStats>;
|
|
15
15
|
getName(): Promise<string | undefined>;
|
|
16
|
-
setName(name: string): Promise<void>;
|
|
16
|
+
setName(name: string | undefined): Promise<void>;
|
|
17
17
|
getLabel(targetId: string): Promise<string | undefined>;
|
|
18
18
|
setLabel(targetId: string, label: string | undefined): Promise<void>;
|
|
19
19
|
findEntries(query?: EntryQuery): Promise<Entry[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/harness/session/session.ts"],"names":[],"mappings":"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","sourcesContent":["import { uuidv7 } from \"@earendil-works/pi-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\nimport type {\n\tBranchBounds,\n\tEntry,\n\tEntryQuery,\n\tIdGenerator,\n\tLanePointer,\n\tLaneRecord,\n\tLogItem,\n\tLogOptions,\n\tNewRecord,\n\tOperationStartedRecord,\n\tProvisionedEntry,\n\tRecordBase,\n\tRecordQuery,\n\tSessionMetadata,\n\tSessionStats,\n\tSessionStorage,\n\tSessionTree,\n} from \"./types.ts\";\nimport { SessionError } from \"./types.ts\";\n\ntype JsonValidationFrame = { value: unknown } | { exit: object };\n\nfunction invalidPayload(reason: string): never {\n\tthrow new SessionError(\"invalid_payload\", `Durable payload ${reason}`);\n}\n\nfunction assertValidLimit(limit: number | undefined): void {\n\tif (limit !== undefined && (!Number.isInteger(limit) || limit <= 0)) {\n\t\tthrow new SessionError(\"invalid_query\", \"limit must be a positive integer\");\n\t}\n}\n\nfunction assertValidCursor(afterSeq: number | undefined): void {\n\tif (afterSeq !== undefined && (!Number.isInteger(afterSeq) || afterSeq < 0)) {\n\t\tthrow new SessionError(\"invalid_query\", \"cursor sequence must be a non-negative integer\");\n\t}\n}\n\nexport function assertJsonSerializable(value: unknown): void {\n\tconst active = new WeakSet<object>();\n\tconst stack: JsonValidationFrame[] = [{ value }];\n\twhile (stack.length > 0) {\n\t\tconst frame = stack.pop()!;\n\t\tif (\"exit\" in frame) {\n\t\t\tactive.delete(frame.exit);\n\t\t\tcontinue;\n\t\t}\n\t\tconst candidate = frame.value;\n\t\tif (candidate === null || typeof candidate === \"string\" || typeof candidate === \"boolean\") {\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof candidate === \"number\") {\n\t\t\tif (!Number.isFinite(candidate)) invalidPayload(\"contains a non-finite number\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof candidate !== \"object\") invalidPayload(`contains ${typeof candidate}`);\n\t\tif (active.has(candidate)) invalidPayload(\"contains a cycle\");\n\t\tactive.add(candidate);\n\t\tstack.push({ exit: candidate });\n\n\t\tif (Array.isArray(candidate)) {\n\t\t\tif (Object.getPrototypeOf(candidate) !== Array.prototype) {\n\t\t\t\tinvalidPayload(\"contains a non-standard array\");\n\t\t\t}\n\t\t\tif (\n\t\t\t\tObject.getOwnPropertySymbols(candidate).length > 0 ||\n\t\t\t\tObject.getOwnPropertyNames(candidate).length !== candidate.length + 1\n\t\t\t) {\n\t\t\t\tinvalidPayload(\"contains an array with unsupported properties\");\n\t\t\t}\n\t\t\tfor (let index = candidate.length - 1; index >= 0; index--) {\n\t\t\t\tif (!Object.hasOwn(candidate, index)) invalidPayload(\"contains a sparse array\");\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(candidate, index)!;\n\t\t\t\tif (!(\"value\" in descriptor)) invalidPayload(\"contains an array accessor\");\n\t\t\t\tstack.push({ value: descriptor.value });\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst prototype = Object.getPrototypeOf(candidate);\n\t\tif (prototype !== Object.prototype && prototype !== null) {\n\t\t\tinvalidPayload(\"contains a non-plain object\");\n\t\t}\n\t\tif (Object.getOwnPropertySymbols(candidate).length > 0) {\n\t\t\tinvalidPayload(\"contains a symbol-keyed property\");\n\t\t}\n\t\tconst keys = Object.keys(candidate);\n\t\tif (Object.getOwnPropertyNames(candidate).length !== keys.length) {\n\t\t\tinvalidPayload(\"contains a non-enumerable property\");\n\t\t}\n\t\tfor (let index = keys.length - 1; index >= 0; index--) {\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(candidate, keys[index]!)!;\n\t\t\tif (!(\"value\" in descriptor)) invalidPayload(\"contains an accessor\");\n\t\t\tstack.push({ value: descriptor.value });\n\t\t}\n\t}\n}\n\nexport class Session<TMetadata extends SessionMetadata = SessionMetadata> implements SessionTree {\n\tprivate readonly storage: SessionStorage<TMetadata>;\n\treadonly idGenerator: IdGenerator;\n\n\tconstructor(storage: SessionStorage<TMetadata>, options: { idGenerator?: IdGenerator } = {}) {\n\t\tthis.storage = storage;\n\t\tthis.idGenerator = options.idGenerator ?? { next: () => uuidv7() };\n\t}\n\n\tasync getMetadata(): Promise<TMetadata> {\n\t\treturn this.storage.getMetadata();\n\t}\n\n\tview(lane: string): SessionTree {\n\t\tif (lane === \"main\") return this;\n\t\treturn {\n\t\t\tgetLeafId: () => this.getLeafIdForLane(lane),\n\t\t\tgetEntry: (id) => this.getEntry(id),\n\t\t\tgetStats: () => this.getStats(),\n\t\t\tgetName: () => this.getName(),\n\t\t\tsetName: (name) => this.setName(name),\n\t\t\tgetLabel: (targetId) => this.getLabel(targetId),\n\t\t\tsetLabel: (targetId, label) => this.setLabel(targetId, label),\n\t\t\tfindEntries: (query) => this.queryEntries(query),\n\t\t\tfindEntry: async (query = {}) => (await this.queryEntries(query, 1))[0],\n\t\t\tfindEntriesOnBranch: (query) => this.queryBranchEntries(lane, query),\n\t\t\tfindEntryOnBranch: async (query = {}) => (await this.queryBranchEntries(lane, query, 1))[0],\n\t\t\tappendMessage: (message) => this.appendMessageToLane(lane, message),\n\t\t\tappendCustomEntry: (customType, data) => this.appendCustomEntryToLane(lane, customType, data),\n\t\t};\n\t}\n\n\tasync getLeafId(): Promise<string | null> {\n\t\treturn this.getLeafIdForLane(\"main\");\n\t}\n\n\tasync getEntry(id: string): Promise<Entry | undefined> {\n\t\treturn this.storage.getEntry(id);\n\t}\n\n\tasync getStats(): Promise<SessionStats> {\n\t\treturn this.storage.getStats();\n\t}\n\n\tasync getName(): Promise<string | undefined> {\n\t\treturn this.storage.getName();\n\t}\n\n\tasync setName(name: string): Promise<void> {\n\t\tawait this.storage.setName(name);\n\t}\n\n\tasync getLabel(targetId: string): Promise<string | undefined> {\n\t\treturn this.storage.getLabel(targetId);\n\t}\n\n\tasync setLabel(targetId: string, label: string | undefined): Promise<void> {\n\t\tawait this.storage.setLabel(targetId, label);\n\t}\n\n\tasync findEntries(query?: EntryQuery): Promise<Entry[]> {\n\t\treturn this.queryEntries(query);\n\t}\n\n\tasync findEntry(query: EntryQuery = {}): Promise<Entry | undefined> {\n\t\treturn (await this.queryEntries(query, 1))[0];\n\t}\n\n\tasync findEntriesOnBranch(query?: EntryQuery & BranchBounds): Promise<Entry[]> {\n\t\treturn this.queryBranchEntries(\"main\", query);\n\t}\n\n\tasync findEntryOnBranch(query: EntryQuery & BranchBounds = {}): Promise<Entry | undefined> {\n\t\treturn (await this.queryBranchEntries(\"main\", query, 1))[0];\n\t}\n\n\tasync appendMessage(message: AgentMessage): Promise<string> {\n\t\treturn this.appendMessageToLane(\"main\", message);\n\t}\n\n\tasync appendCustomEntry(customType: string, data?: unknown): Promise<string> {\n\t\treturn this.appendCustomEntryToLane(\"main\", customType, data);\n\t}\n\n\tasync getLanes(): Promise<LanePointer[]> {\n\t\treturn this.storage.getLanes();\n\t}\n\n\tasync createLane(lane: string, at: string | null): Promise<void> {\n\t\tawait this.storage.createLane(lane, at);\n\t}\n\n\tasync moveLane(lane: string, to: string | null): Promise<void> {\n\t\tawait this.storage.moveLane(lane, to);\n\t}\n\n\tasync appendEntry<TEntry extends Entry>(entry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\treturn this.commitEntry(entry, lane);\n\t}\n\n\tasync appendRecord<TNewRecord extends NewRecord>(\n\t\trecord: TNewRecord,\n\t): Promise<TNewRecord & Pick<RecordBase, \"seq\" | \"timestamp\">>;\n\tasync appendRecord(record: NewRecord): Promise<LaneRecord> {\n\t\treturn this.commitRecord(record);\n\t}\n\n\tasync findRecords<K extends LaneRecord[\"type\"]>(\n\t\tquery: RecordQuery & { type: K },\n\t): Promise<Extract<LaneRecord, { type: K }>[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]> {\n\t\treturn this.queryRecords(query);\n\t}\n\n\tasync findOpenOperations(lane: string, options?: { limit?: number }): Promise<OperationStartedRecord[]> {\n\t\tassertValidLimit(options?.limit);\n\t\treturn this.storage.findOpenOperations(lane, options);\n\t}\n\n\tasync getLog(options?: LogOptions): Promise<LogItem[]> {\n\t\treturn this.queryLog(options);\n\t}\n\n\tprivate async getLeafIdForLane(lane: string): Promise<string | null> {\n\t\tconst pointer = (await this.getLanes()).find((candidate) => candidate.lane === lane);\n\t\tif (!pointer) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\t\treturn pointer.leafId;\n\t}\n\n\tprivate async queryEntries(query: EntryQuery = {}, resultLimit = query.limit): Promise<Entry[]> {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.cursor?.afterSeq);\n\t\treturn this.storage.findEntries(resultLimit === query.limit ? query : { ...query, limit: resultLimit });\n\t}\n\n\tprivate async queryBranchEntries(\n\t\tlane: string,\n\t\tquery: EntryQuery & BranchBounds = {},\n\t\tresultLimit = query.limit,\n\t): Promise<Entry[]> {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.cursor?.afterSeq);\n\t\tconst start = query.start ?? (await this.getLeafIdForLane(lane));\n\t\tif (start === null) return [];\n\t\tconst storageQuery = resultLimit === query.limit ? query : { ...query, limit: resultLimit };\n\t\treturn this.storage.findEntriesOnBranch({ ...storageQuery, start });\n\t}\n\n\tprivate async queryRecords(query: RecordQuery = {}): Promise<LaneRecord[]> {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.afterSeq);\n\t\tif (query.operationKind !== undefined && query.type !== \"operation_started\") {\n\t\t\tthrow new SessionError(\"invalid_query\", 'operationKind requires type \"operation_started\"');\n\t\t}\n\t\treturn this.storage.findRecords(query);\n\t}\n\n\tprivate async queryLog(options: LogOptions = {}): Promise<LogItem[]> {\n\t\tassertValidLimit(options.limit);\n\t\tassertValidCursor(options.afterSeq);\n\t\treturn this.storage.getLog(options);\n\t}\n\n\tprivate async appendMessageToLane(lane: string, message: AgentMessage): Promise<string> {\n\t\tconst entry = await this.commitEntry({ type: \"message\", id: this.idGenerator.next(), message }, lane);\n\t\treturn entry.id;\n\t}\n\n\tprivate async appendCustomEntryToLane(lane: string, customType: string, data?: unknown): Promise<string> {\n\t\tconst entry = await this.commitEntry(\n\t\t\tdata === undefined\n\t\t\t\t? { type: \"custom\", id: this.idGenerator.next(), customType }\n\t\t\t\t: { type: \"custom\", id: this.idGenerator.next(), customType, data },\n\t\t\tlane,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tprivate async commitEntry<TEntry extends Entry>(entry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\tassertJsonSerializable(entry);\n\t\treturn this.storage.appendEntry(entry, lane);\n\t}\n\n\tprivate async commitRecord<TNewRecord extends NewRecord>(\n\t\trecord: TNewRecord,\n\t): Promise<TNewRecord & Pick<RecordBase, \"seq\" | \"timestamp\">> {\n\t\tassertJsonSerializable(record);\n\t\treturn this.storage.appendRecord<LaneRecord>(record) as unknown as Promise<\n\t\t\tTNewRecord & Pick<RecordBase, \"seq\" | \"timestamp\">\n\t\t>;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/harness/session/session.ts"],"names":[],"mappings":"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","sourcesContent":["import { uuidv7 } from \"@earendil-works/pi-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\nimport type {\n\tBranchBounds,\n\tEntry,\n\tEntryQuery,\n\tIdGenerator,\n\tLanePointer,\n\tLaneRecord,\n\tLogItem,\n\tLogOptions,\n\tNewRecord,\n\tOperationStartedRecord,\n\tProvisionedEntry,\n\tRecordBase,\n\tRecordQuery,\n\tSessionMetadata,\n\tSessionStats,\n\tSessionStorage,\n\tSessionTree,\n} from \"./types.ts\";\nimport { SessionError } from \"./types.ts\";\n\ntype JsonValidationFrame = { value: unknown } | { exit: object };\n\nfunction invalidPayload(reason: string): never {\n\tthrow new SessionError(\"invalid_payload\", `Durable payload ${reason}`);\n}\n\nfunction assertValidLimit(limit: number | undefined): void {\n\tif (limit !== undefined && (!Number.isInteger(limit) || limit <= 0)) {\n\t\tthrow new SessionError(\"invalid_query\", \"limit must be a positive integer\");\n\t}\n}\n\nfunction assertValidCursor(afterSeq: number | undefined): void {\n\tif (afterSeq !== undefined && (!Number.isInteger(afterSeq) || afterSeq < 0)) {\n\t\tthrow new SessionError(\"invalid_query\", \"cursor sequence must be a non-negative integer\");\n\t}\n}\n\nexport function assertJsonSerializable(value: unknown): void {\n\tconst active = new WeakSet<object>();\n\tconst stack: JsonValidationFrame[] = [{ value }];\n\twhile (stack.length > 0) {\n\t\tconst frame = stack.pop()!;\n\t\tif (\"exit\" in frame) {\n\t\t\tactive.delete(frame.exit);\n\t\t\tcontinue;\n\t\t}\n\t\tconst candidate = frame.value;\n\t\tif (candidate === null || typeof candidate === \"string\" || typeof candidate === \"boolean\") {\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof candidate === \"number\") {\n\t\t\tif (!Number.isFinite(candidate)) invalidPayload(\"contains a non-finite number\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof candidate !== \"object\") invalidPayload(`contains ${typeof candidate}`);\n\t\tif (active.has(candidate)) invalidPayload(\"contains a cycle\");\n\t\tactive.add(candidate);\n\t\tstack.push({ exit: candidate });\n\n\t\tif (Array.isArray(candidate)) {\n\t\t\tif (Object.getPrototypeOf(candidate) !== Array.prototype) {\n\t\t\t\tinvalidPayload(\"contains a non-standard array\");\n\t\t\t}\n\t\t\tif (\n\t\t\t\tObject.getOwnPropertySymbols(candidate).length > 0 ||\n\t\t\t\tObject.getOwnPropertyNames(candidate).length !== candidate.length + 1\n\t\t\t) {\n\t\t\t\tinvalidPayload(\"contains an array with unsupported properties\");\n\t\t\t}\n\t\t\tfor (let index = candidate.length - 1; index >= 0; index--) {\n\t\t\t\tif (!Object.hasOwn(candidate, index)) invalidPayload(\"contains a sparse array\");\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(candidate, index)!;\n\t\t\t\tif (!(\"value\" in descriptor)) invalidPayload(\"contains an array accessor\");\n\t\t\t\tstack.push({ value: descriptor.value });\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst prototype = Object.getPrototypeOf(candidate);\n\t\tif (prototype !== Object.prototype && prototype !== null) {\n\t\t\tinvalidPayload(\"contains a non-plain object\");\n\t\t}\n\t\tif (Object.getOwnPropertySymbols(candidate).length > 0) {\n\t\t\tinvalidPayload(\"contains a symbol-keyed property\");\n\t\t}\n\t\tconst keys = Object.keys(candidate);\n\t\tif (Object.getOwnPropertyNames(candidate).length !== keys.length) {\n\t\t\tinvalidPayload(\"contains a non-enumerable property\");\n\t\t}\n\t\tfor (let index = keys.length - 1; index >= 0; index--) {\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(candidate, keys[index]!)!;\n\t\t\tif (!(\"value\" in descriptor)) invalidPayload(\"contains an accessor\");\n\t\t\tstack.push({ value: descriptor.value });\n\t\t}\n\t}\n}\n\nexport class Session<TMetadata extends SessionMetadata = SessionMetadata> implements SessionTree {\n\tprivate readonly storage: SessionStorage<TMetadata>;\n\treadonly idGenerator: IdGenerator;\n\n\tconstructor(storage: SessionStorage<TMetadata>, options: { idGenerator?: IdGenerator } = {}) {\n\t\tthis.storage = storage;\n\t\tthis.idGenerator = options.idGenerator ?? { next: () => uuidv7() };\n\t}\n\n\tasync getMetadata(): Promise<TMetadata> {\n\t\treturn this.storage.getMetadata();\n\t}\n\n\tview(lane: string): SessionTree {\n\t\tif (lane === \"main\") return this;\n\t\treturn {\n\t\t\tgetLeafId: () => this.getLeafIdForLane(lane),\n\t\t\tgetEntry: (id) => this.getEntry(id),\n\t\t\tgetStats: () => this.getStats(),\n\t\t\tgetName: () => this.getName(),\n\t\t\tsetName: (name) => this.setName(name),\n\t\t\tgetLabel: (targetId) => this.getLabel(targetId),\n\t\t\tsetLabel: (targetId, label) => this.setLabel(targetId, label),\n\t\t\tfindEntries: (query) => this.queryEntries(query),\n\t\t\tfindEntry: async (query = {}) => (await this.queryEntries(query, 1))[0],\n\t\t\tfindEntriesOnBranch: (query) => this.queryBranchEntries(lane, query),\n\t\t\tfindEntryOnBranch: async (query = {}) => (await this.queryBranchEntries(lane, query, 1))[0],\n\t\t\tappendMessage: (message) => this.appendMessageToLane(lane, message),\n\t\t\tappendCustomEntry: (customType, data) => this.appendCustomEntryToLane(lane, customType, data),\n\t\t};\n\t}\n\n\tasync getLeafId(): Promise<string | null> {\n\t\treturn this.getLeafIdForLane(\"main\");\n\t}\n\n\tasync getEntry(id: string): Promise<Entry | undefined> {\n\t\treturn this.storage.getEntry(id);\n\t}\n\n\tasync getStats(): Promise<SessionStats> {\n\t\treturn this.storage.getStats();\n\t}\n\n\tasync getName(): Promise<string | undefined> {\n\t\treturn this.storage.getName();\n\t}\n\n\tasync setName(name: string | undefined): Promise<void> {\n\t\tawait this.storage.setName(name);\n\t}\n\n\tasync getLabel(targetId: string): Promise<string | undefined> {\n\t\treturn this.storage.getLabel(targetId);\n\t}\n\n\tasync setLabel(targetId: string, label: string | undefined): Promise<void> {\n\t\tawait this.storage.setLabel(targetId, label);\n\t}\n\n\tasync findEntries(query?: EntryQuery): Promise<Entry[]> {\n\t\treturn this.queryEntries(query);\n\t}\n\n\tasync findEntry(query: EntryQuery = {}): Promise<Entry | undefined> {\n\t\treturn (await this.queryEntries(query, 1))[0];\n\t}\n\n\tasync findEntriesOnBranch(query?: EntryQuery & BranchBounds): Promise<Entry[]> {\n\t\treturn this.queryBranchEntries(\"main\", query);\n\t}\n\n\tasync findEntryOnBranch(query: EntryQuery & BranchBounds = {}): Promise<Entry | undefined> {\n\t\treturn (await this.queryBranchEntries(\"main\", query, 1))[0];\n\t}\n\n\tasync appendMessage(message: AgentMessage): Promise<string> {\n\t\treturn this.appendMessageToLane(\"main\", message);\n\t}\n\n\tasync appendCustomEntry(customType: string, data?: unknown): Promise<string> {\n\t\treturn this.appendCustomEntryToLane(\"main\", customType, data);\n\t}\n\n\tasync getLanes(): Promise<LanePointer[]> {\n\t\treturn this.storage.getLanes();\n\t}\n\n\tasync createLane(lane: string, at: string | null): Promise<void> {\n\t\tawait this.storage.createLane(lane, at);\n\t}\n\n\tasync moveLane(lane: string, to: string | null): Promise<void> {\n\t\tawait this.storage.moveLane(lane, to);\n\t}\n\n\tasync appendEntry<TEntry extends Entry>(entry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\treturn this.commitEntry(entry, lane);\n\t}\n\n\tasync appendRecord<TNewRecord extends NewRecord>(\n\t\trecord: TNewRecord,\n\t): Promise<TNewRecord & Pick<RecordBase, \"seq\" | \"timestamp\">>;\n\tasync appendRecord(record: NewRecord): Promise<LaneRecord> {\n\t\treturn this.commitRecord(record);\n\t}\n\n\tasync findRecords<K extends LaneRecord[\"type\"]>(\n\t\tquery: RecordQuery & { type: K },\n\t): Promise<Extract<LaneRecord, { type: K }>[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]> {\n\t\treturn this.queryRecords(query);\n\t}\n\n\tasync findOpenOperations(lane: string, options?: { limit?: number }): Promise<OperationStartedRecord[]> {\n\t\tassertValidLimit(options?.limit);\n\t\treturn this.storage.findOpenOperations(lane, options);\n\t}\n\n\tasync getLog(options?: LogOptions): Promise<LogItem[]> {\n\t\treturn this.queryLog(options);\n\t}\n\n\t/** Returns the lane's current leaf, or null when empty. Throws when the lane does not exist. */\n\tprivate async getLeafIdForLane(lane: string): Promise<string | null> {\n\t\tconst pointer = (await this.getLanes()).find((candidate) => candidate.lane === lane);\n\t\tif (!pointer) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\t\treturn pointer.leafId;\n\t}\n\n\tprivate async queryEntries(query: EntryQuery = {}, resultLimit = query.limit): Promise<Entry[]> {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.cursor?.afterSeq);\n\t\treturn this.storage.findEntries(resultLimit === query.limit ? query : { ...query, limit: resultLimit });\n\t}\n\n\t/**\n\t * Queries from `query.start` toward the root, defaulting to the lane's current leaf.\n\t * `resultLimit` lets single-entry queries cap results without changing the caller's query.\n\t */\n\tprivate async queryBranchEntries(\n\t\tdefaultLane: string,\n\t\tquery: EntryQuery & BranchBounds = {},\n\t\tresultLimit = query.limit,\n\t): Promise<Entry[]> {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.cursor?.afterSeq);\n\t\tconst start = query.start ?? (await this.getLeafIdForLane(defaultLane));\n\t\tif (start === null) return [];\n\t\tconst storageQuery = resultLimit === query.limit ? query : { ...query, limit: resultLimit };\n\t\treturn this.storage.findEntriesOnBranch({ ...storageQuery, start });\n\t}\n\n\tprivate async queryRecords(query: RecordQuery = {}): Promise<LaneRecord[]> {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.afterSeq);\n\t\tif (query.operationKind !== undefined && query.type !== \"operation_started\") {\n\t\t\tthrow new SessionError(\"invalid_query\", 'operationKind requires type \"operation_started\"');\n\t\t}\n\t\treturn this.storage.findRecords(query);\n\t}\n\n\tprivate async queryLog(options: LogOptions = {}): Promise<LogItem[]> {\n\t\tassertValidLimit(options.limit);\n\t\tassertValidCursor(options.afterSeq);\n\t\treturn this.storage.getLog(options);\n\t}\n\n\tprivate async appendMessageToLane(lane: string, message: AgentMessage): Promise<string> {\n\t\tconst entry = await this.commitEntry({ type: \"message\", id: this.idGenerator.next(), message }, lane);\n\t\treturn entry.id;\n\t}\n\n\tprivate async appendCustomEntryToLane(lane: string, customType: string, data?: unknown): Promise<string> {\n\t\tconst entry = await this.commitEntry(\n\t\t\tdata === undefined\n\t\t\t\t? { type: \"custom\", id: this.idGenerator.next(), customType }\n\t\t\t\t: { type: \"custom\", id: this.idGenerator.next(), customType, data },\n\t\t\tlane,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tprivate async commitEntry<TEntry extends Entry>(entry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\tassertJsonSerializable(entry);\n\t\treturn this.storage.appendEntry(entry, lane);\n\t}\n\n\tprivate async commitRecord<TNewRecord extends NewRecord>(\n\t\trecord: TNewRecord,\n\t): Promise<TNewRecord & Pick<RecordBase, \"seq\" | \"timestamp\">> {\n\t\tassertJsonSerializable(record);\n\t\treturn this.storage.appendRecord<LaneRecord>(record) as unknown as Promise<\n\t\t\tTNewRecord & Pick<RecordBase, \"seq\" | \"timestamp\">\n\t\t>;\n\t}\n}\n"]}
|
|
@@ -167,6 +167,7 @@ export class Session {
|
|
|
167
167
|
async getLog(options) {
|
|
168
168
|
return this.queryLog(options);
|
|
169
169
|
}
|
|
170
|
+
/** Returns the lane's current leaf, or null when empty. Throws when the lane does not exist. */
|
|
170
171
|
async getLeafIdForLane(lane) {
|
|
171
172
|
const pointer = (await this.getLanes()).find((candidate) => candidate.lane === lane);
|
|
172
173
|
if (!pointer)
|
|
@@ -178,10 +179,14 @@ export class Session {
|
|
|
178
179
|
assertValidCursor(query.cursor?.afterSeq);
|
|
179
180
|
return this.storage.findEntries(resultLimit === query.limit ? query : { ...query, limit: resultLimit });
|
|
180
181
|
}
|
|
181
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Queries from `query.start` toward the root, defaulting to the lane's current leaf.
|
|
184
|
+
* `resultLimit` lets single-entry queries cap results without changing the caller's query.
|
|
185
|
+
*/
|
|
186
|
+
async queryBranchEntries(defaultLane, query = {}, resultLimit = query.limit) {
|
|
182
187
|
assertValidLimit(query.limit);
|
|
183
188
|
assertValidCursor(query.cursor?.afterSeq);
|
|
184
|
-
const start = query.start ?? (await this.getLeafIdForLane(
|
|
189
|
+
const start = query.start ?? (await this.getLeafIdForLane(defaultLane));
|
|
185
190
|
if (start === null)
|
|
186
191
|
return [];
|
|
187
192
|
const storageQuery = resultLimit === query.limit ? query : { ...query, limit: resultLimit };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/harness/session/session.ts"],"names":[],"mappings":"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","sourcesContent":["import { uuidv7 } from \"@earendil-works/pi-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\nimport type {\n\tBranchBounds,\n\tEntry,\n\tEntryQuery,\n\tIdGenerator,\n\tLanePointer,\n\tLaneRecord,\n\tLogItem,\n\tLogOptions,\n\tNewRecord,\n\tOperationStartedRecord,\n\tProvisionedEntry,\n\tRecordBase,\n\tRecordQuery,\n\tSessionMetadata,\n\tSessionStats,\n\tSessionStorage,\n\tSessionTree,\n} from \"./types.ts\";\nimport { SessionError } from \"./types.ts\";\n\ntype JsonValidationFrame = { value: unknown } | { exit: object };\n\nfunction invalidPayload(reason: string): never {\n\tthrow new SessionError(\"invalid_payload\", `Durable payload ${reason}`);\n}\n\nfunction assertValidLimit(limit: number | undefined): void {\n\tif (limit !== undefined && (!Number.isInteger(limit) || limit <= 0)) {\n\t\tthrow new SessionError(\"invalid_query\", \"limit must be a positive integer\");\n\t}\n}\n\nfunction assertValidCursor(afterSeq: number | undefined): void {\n\tif (afterSeq !== undefined && (!Number.isInteger(afterSeq) || afterSeq < 0)) {\n\t\tthrow new SessionError(\"invalid_query\", \"cursor sequence must be a non-negative integer\");\n\t}\n}\n\nexport function assertJsonSerializable(value: unknown): void {\n\tconst active = new WeakSet<object>();\n\tconst stack: JsonValidationFrame[] = [{ value }];\n\twhile (stack.length > 0) {\n\t\tconst frame = stack.pop()!;\n\t\tif (\"exit\" in frame) {\n\t\t\tactive.delete(frame.exit);\n\t\t\tcontinue;\n\t\t}\n\t\tconst candidate = frame.value;\n\t\tif (candidate === null || typeof candidate === \"string\" || typeof candidate === \"boolean\") {\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof candidate === \"number\") {\n\t\t\tif (!Number.isFinite(candidate)) invalidPayload(\"contains a non-finite number\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof candidate !== \"object\") invalidPayload(`contains ${typeof candidate}`);\n\t\tif (active.has(candidate)) invalidPayload(\"contains a cycle\");\n\t\tactive.add(candidate);\n\t\tstack.push({ exit: candidate });\n\n\t\tif (Array.isArray(candidate)) {\n\t\t\tif (Object.getPrototypeOf(candidate) !== Array.prototype) {\n\t\t\t\tinvalidPayload(\"contains a non-standard array\");\n\t\t\t}\n\t\t\tif (\n\t\t\t\tObject.getOwnPropertySymbols(candidate).length > 0 ||\n\t\t\t\tObject.getOwnPropertyNames(candidate).length !== candidate.length + 1\n\t\t\t) {\n\t\t\t\tinvalidPayload(\"contains an array with unsupported properties\");\n\t\t\t}\n\t\t\tfor (let index = candidate.length - 1; index >= 0; index--) {\n\t\t\t\tif (!Object.hasOwn(candidate, index)) invalidPayload(\"contains a sparse array\");\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(candidate, index)!;\n\t\t\t\tif (!(\"value\" in descriptor)) invalidPayload(\"contains an array accessor\");\n\t\t\t\tstack.push({ value: descriptor.value });\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst prototype = Object.getPrototypeOf(candidate);\n\t\tif (prototype !== Object.prototype && prototype !== null) {\n\t\t\tinvalidPayload(\"contains a non-plain object\");\n\t\t}\n\t\tif (Object.getOwnPropertySymbols(candidate).length > 0) {\n\t\t\tinvalidPayload(\"contains a symbol-keyed property\");\n\t\t}\n\t\tconst keys = Object.keys(candidate);\n\t\tif (Object.getOwnPropertyNames(candidate).length !== keys.length) {\n\t\t\tinvalidPayload(\"contains a non-enumerable property\");\n\t\t}\n\t\tfor (let index = keys.length - 1; index >= 0; index--) {\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(candidate, keys[index]!)!;\n\t\t\tif (!(\"value\" in descriptor)) invalidPayload(\"contains an accessor\");\n\t\t\tstack.push({ value: descriptor.value });\n\t\t}\n\t}\n}\n\nexport class Session<TMetadata extends SessionMetadata = SessionMetadata> implements SessionTree {\n\tprivate readonly storage: SessionStorage<TMetadata>;\n\treadonly idGenerator: IdGenerator;\n\n\tconstructor(storage: SessionStorage<TMetadata>, options: { idGenerator?: IdGenerator } = {}) {\n\t\tthis.storage = storage;\n\t\tthis.idGenerator = options.idGenerator ?? { next: () => uuidv7() };\n\t}\n\n\tasync getMetadata(): Promise<TMetadata> {\n\t\treturn this.storage.getMetadata();\n\t}\n\n\tview(lane: string): SessionTree {\n\t\tif (lane === \"main\") return this;\n\t\treturn {\n\t\t\tgetLeafId: () => this.getLeafIdForLane(lane),\n\t\t\tgetEntry: (id) => this.getEntry(id),\n\t\t\tgetStats: () => this.getStats(),\n\t\t\tgetName: () => this.getName(),\n\t\t\tsetName: (name) => this.setName(name),\n\t\t\tgetLabel: (targetId) => this.getLabel(targetId),\n\t\t\tsetLabel: (targetId, label) => this.setLabel(targetId, label),\n\t\t\tfindEntries: (query) => this.queryEntries(query),\n\t\t\tfindEntry: async (query = {}) => (await this.queryEntries(query, 1))[0],\n\t\t\tfindEntriesOnBranch: (query) => this.queryBranchEntries(lane, query),\n\t\t\tfindEntryOnBranch: async (query = {}) => (await this.queryBranchEntries(lane, query, 1))[0],\n\t\t\tappendMessage: (message) => this.appendMessageToLane(lane, message),\n\t\t\tappendCustomEntry: (customType, data) => this.appendCustomEntryToLane(lane, customType, data),\n\t\t};\n\t}\n\n\tasync getLeafId(): Promise<string | null> {\n\t\treturn this.getLeafIdForLane(\"main\");\n\t}\n\n\tasync getEntry(id: string): Promise<Entry | undefined> {\n\t\treturn this.storage.getEntry(id);\n\t}\n\n\tasync getStats(): Promise<SessionStats> {\n\t\treturn this.storage.getStats();\n\t}\n\n\tasync getName(): Promise<string | undefined> {\n\t\treturn this.storage.getName();\n\t}\n\n\tasync setName(name: string): Promise<void> {\n\t\tawait this.storage.setName(name);\n\t}\n\n\tasync getLabel(targetId: string): Promise<string | undefined> {\n\t\treturn this.storage.getLabel(targetId);\n\t}\n\n\tasync setLabel(targetId: string, label: string | undefined): Promise<void> {\n\t\tawait this.storage.setLabel(targetId, label);\n\t}\n\n\tasync findEntries(query?: EntryQuery): Promise<Entry[]> {\n\t\treturn this.queryEntries(query);\n\t}\n\n\tasync findEntry(query: EntryQuery = {}): Promise<Entry | undefined> {\n\t\treturn (await this.queryEntries(query, 1))[0];\n\t}\n\n\tasync findEntriesOnBranch(query?: EntryQuery & BranchBounds): Promise<Entry[]> {\n\t\treturn this.queryBranchEntries(\"main\", query);\n\t}\n\n\tasync findEntryOnBranch(query: EntryQuery & BranchBounds = {}): Promise<Entry | undefined> {\n\t\treturn (await this.queryBranchEntries(\"main\", query, 1))[0];\n\t}\n\n\tasync appendMessage(message: AgentMessage): Promise<string> {\n\t\treturn this.appendMessageToLane(\"main\", message);\n\t}\n\n\tasync appendCustomEntry(customType: string, data?: unknown): Promise<string> {\n\t\treturn this.appendCustomEntryToLane(\"main\", customType, data);\n\t}\n\n\tasync getLanes(): Promise<LanePointer[]> {\n\t\treturn this.storage.getLanes();\n\t}\n\n\tasync createLane(lane: string, at: string | null): Promise<void> {\n\t\tawait this.storage.createLane(lane, at);\n\t}\n\n\tasync moveLane(lane: string, to: string | null): Promise<void> {\n\t\tawait this.storage.moveLane(lane, to);\n\t}\n\n\tasync appendEntry<TEntry extends Entry>(entry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\treturn this.commitEntry(entry, lane);\n\t}\n\n\tasync appendRecord<TNewRecord extends NewRecord>(\n\t\trecord: TNewRecord,\n\t): Promise<TNewRecord & Pick<RecordBase, \"seq\" | \"timestamp\">>;\n\tasync appendRecord(record: NewRecord): Promise<LaneRecord> {\n\t\treturn this.commitRecord(record);\n\t}\n\n\tasync findRecords<K extends LaneRecord[\"type\"]>(\n\t\tquery: RecordQuery & { type: K },\n\t): Promise<Extract<LaneRecord, { type: K }>[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]> {\n\t\treturn this.queryRecords(query);\n\t}\n\n\tasync findOpenOperations(lane: string, options?: { limit?: number }): Promise<OperationStartedRecord[]> {\n\t\tassertValidLimit(options?.limit);\n\t\treturn this.storage.findOpenOperations(lane, options);\n\t}\n\n\tasync getLog(options?: LogOptions): Promise<LogItem[]> {\n\t\treturn this.queryLog(options);\n\t}\n\n\tprivate async getLeafIdForLane(lane: string): Promise<string | null> {\n\t\tconst pointer = (await this.getLanes()).find((candidate) => candidate.lane === lane);\n\t\tif (!pointer) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\t\treturn pointer.leafId;\n\t}\n\n\tprivate async queryEntries(query: EntryQuery = {}, resultLimit = query.limit): Promise<Entry[]> {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.cursor?.afterSeq);\n\t\treturn this.storage.findEntries(resultLimit === query.limit ? query : { ...query, limit: resultLimit });\n\t}\n\n\tprivate async queryBranchEntries(\n\t\tlane: string,\n\t\tquery: EntryQuery & BranchBounds = {},\n\t\tresultLimit = query.limit,\n\t): Promise<Entry[]> {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.cursor?.afterSeq);\n\t\tconst start = query.start ?? (await this.getLeafIdForLane(lane));\n\t\tif (start === null) return [];\n\t\tconst storageQuery = resultLimit === query.limit ? query : { ...query, limit: resultLimit };\n\t\treturn this.storage.findEntriesOnBranch({ ...storageQuery, start });\n\t}\n\n\tprivate async queryRecords(query: RecordQuery = {}): Promise<LaneRecord[]> {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.afterSeq);\n\t\tif (query.operationKind !== undefined && query.type !== \"operation_started\") {\n\t\t\tthrow new SessionError(\"invalid_query\", 'operationKind requires type \"operation_started\"');\n\t\t}\n\t\treturn this.storage.findRecords(query);\n\t}\n\n\tprivate async queryLog(options: LogOptions = {}): Promise<LogItem[]> {\n\t\tassertValidLimit(options.limit);\n\t\tassertValidCursor(options.afterSeq);\n\t\treturn this.storage.getLog(options);\n\t}\n\n\tprivate async appendMessageToLane(lane: string, message: AgentMessage): Promise<string> {\n\t\tconst entry = await this.commitEntry({ type: \"message\", id: this.idGenerator.next(), message }, lane);\n\t\treturn entry.id;\n\t}\n\n\tprivate async appendCustomEntryToLane(lane: string, customType: string, data?: unknown): Promise<string> {\n\t\tconst entry = await this.commitEntry(\n\t\t\tdata === undefined\n\t\t\t\t? { type: \"custom\", id: this.idGenerator.next(), customType }\n\t\t\t\t: { type: \"custom\", id: this.idGenerator.next(), customType, data },\n\t\t\tlane,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tprivate async commitEntry<TEntry extends Entry>(entry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\tassertJsonSerializable(entry);\n\t\treturn this.storage.appendEntry(entry, lane);\n\t}\n\n\tprivate async commitRecord<TNewRecord extends NewRecord>(\n\t\trecord: TNewRecord,\n\t): Promise<TNewRecord & Pick<RecordBase, \"seq\" | \"timestamp\">> {\n\t\tassertJsonSerializable(record);\n\t\treturn this.storage.appendRecord<LaneRecord>(record) as unknown as Promise<\n\t\t\tTNewRecord & Pick<RecordBase, \"seq\" | \"timestamp\">\n\t\t>;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/harness/session/session.ts"],"names":[],"mappings":"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","sourcesContent":["import { uuidv7 } from \"@earendil-works/pi-ai\";\nimport type { AgentMessage } from \"../../types.ts\";\nimport type {\n\tBranchBounds,\n\tEntry,\n\tEntryQuery,\n\tIdGenerator,\n\tLanePointer,\n\tLaneRecord,\n\tLogItem,\n\tLogOptions,\n\tNewRecord,\n\tOperationStartedRecord,\n\tProvisionedEntry,\n\tRecordBase,\n\tRecordQuery,\n\tSessionMetadata,\n\tSessionStats,\n\tSessionStorage,\n\tSessionTree,\n} from \"./types.ts\";\nimport { SessionError } from \"./types.ts\";\n\ntype JsonValidationFrame = { value: unknown } | { exit: object };\n\nfunction invalidPayload(reason: string): never {\n\tthrow new SessionError(\"invalid_payload\", `Durable payload ${reason}`);\n}\n\nfunction assertValidLimit(limit: number | undefined): void {\n\tif (limit !== undefined && (!Number.isInteger(limit) || limit <= 0)) {\n\t\tthrow new SessionError(\"invalid_query\", \"limit must be a positive integer\");\n\t}\n}\n\nfunction assertValidCursor(afterSeq: number | undefined): void {\n\tif (afterSeq !== undefined && (!Number.isInteger(afterSeq) || afterSeq < 0)) {\n\t\tthrow new SessionError(\"invalid_query\", \"cursor sequence must be a non-negative integer\");\n\t}\n}\n\nexport function assertJsonSerializable(value: unknown): void {\n\tconst active = new WeakSet<object>();\n\tconst stack: JsonValidationFrame[] = [{ value }];\n\twhile (stack.length > 0) {\n\t\tconst frame = stack.pop()!;\n\t\tif (\"exit\" in frame) {\n\t\t\tactive.delete(frame.exit);\n\t\t\tcontinue;\n\t\t}\n\t\tconst candidate = frame.value;\n\t\tif (candidate === null || typeof candidate === \"string\" || typeof candidate === \"boolean\") {\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof candidate === \"number\") {\n\t\t\tif (!Number.isFinite(candidate)) invalidPayload(\"contains a non-finite number\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof candidate !== \"object\") invalidPayload(`contains ${typeof candidate}`);\n\t\tif (active.has(candidate)) invalidPayload(\"contains a cycle\");\n\t\tactive.add(candidate);\n\t\tstack.push({ exit: candidate });\n\n\t\tif (Array.isArray(candidate)) {\n\t\t\tif (Object.getPrototypeOf(candidate) !== Array.prototype) {\n\t\t\t\tinvalidPayload(\"contains a non-standard array\");\n\t\t\t}\n\t\t\tif (\n\t\t\t\tObject.getOwnPropertySymbols(candidate).length > 0 ||\n\t\t\t\tObject.getOwnPropertyNames(candidate).length !== candidate.length + 1\n\t\t\t) {\n\t\t\t\tinvalidPayload(\"contains an array with unsupported properties\");\n\t\t\t}\n\t\t\tfor (let index = candidate.length - 1; index >= 0; index--) {\n\t\t\t\tif (!Object.hasOwn(candidate, index)) invalidPayload(\"contains a sparse array\");\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(candidate, index)!;\n\t\t\t\tif (!(\"value\" in descriptor)) invalidPayload(\"contains an array accessor\");\n\t\t\t\tstack.push({ value: descriptor.value });\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst prototype = Object.getPrototypeOf(candidate);\n\t\tif (prototype !== Object.prototype && prototype !== null) {\n\t\t\tinvalidPayload(\"contains a non-plain object\");\n\t\t}\n\t\tif (Object.getOwnPropertySymbols(candidate).length > 0) {\n\t\t\tinvalidPayload(\"contains a symbol-keyed property\");\n\t\t}\n\t\tconst keys = Object.keys(candidate);\n\t\tif (Object.getOwnPropertyNames(candidate).length !== keys.length) {\n\t\t\tinvalidPayload(\"contains a non-enumerable property\");\n\t\t}\n\t\tfor (let index = keys.length - 1; index >= 0; index--) {\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(candidate, keys[index]!)!;\n\t\t\tif (!(\"value\" in descriptor)) invalidPayload(\"contains an accessor\");\n\t\t\tstack.push({ value: descriptor.value });\n\t\t}\n\t}\n}\n\nexport class Session<TMetadata extends SessionMetadata = SessionMetadata> implements SessionTree {\n\tprivate readonly storage: SessionStorage<TMetadata>;\n\treadonly idGenerator: IdGenerator;\n\n\tconstructor(storage: SessionStorage<TMetadata>, options: { idGenerator?: IdGenerator } = {}) {\n\t\tthis.storage = storage;\n\t\tthis.idGenerator = options.idGenerator ?? { next: () => uuidv7() };\n\t}\n\n\tasync getMetadata(): Promise<TMetadata> {\n\t\treturn this.storage.getMetadata();\n\t}\n\n\tview(lane: string): SessionTree {\n\t\tif (lane === \"main\") return this;\n\t\treturn {\n\t\t\tgetLeafId: () => this.getLeafIdForLane(lane),\n\t\t\tgetEntry: (id) => this.getEntry(id),\n\t\t\tgetStats: () => this.getStats(),\n\t\t\tgetName: () => this.getName(),\n\t\t\tsetName: (name) => this.setName(name),\n\t\t\tgetLabel: (targetId) => this.getLabel(targetId),\n\t\t\tsetLabel: (targetId, label) => this.setLabel(targetId, label),\n\t\t\tfindEntries: (query) => this.queryEntries(query),\n\t\t\tfindEntry: async (query = {}) => (await this.queryEntries(query, 1))[0],\n\t\t\tfindEntriesOnBranch: (query) => this.queryBranchEntries(lane, query),\n\t\t\tfindEntryOnBranch: async (query = {}) => (await this.queryBranchEntries(lane, query, 1))[0],\n\t\t\tappendMessage: (message) => this.appendMessageToLane(lane, message),\n\t\t\tappendCustomEntry: (customType, data) => this.appendCustomEntryToLane(lane, customType, data),\n\t\t};\n\t}\n\n\tasync getLeafId(): Promise<string | null> {\n\t\treturn this.getLeafIdForLane(\"main\");\n\t}\n\n\tasync getEntry(id: string): Promise<Entry | undefined> {\n\t\treturn this.storage.getEntry(id);\n\t}\n\n\tasync getStats(): Promise<SessionStats> {\n\t\treturn this.storage.getStats();\n\t}\n\n\tasync getName(): Promise<string | undefined> {\n\t\treturn this.storage.getName();\n\t}\n\n\tasync setName(name: string | undefined): Promise<void> {\n\t\tawait this.storage.setName(name);\n\t}\n\n\tasync getLabel(targetId: string): Promise<string | undefined> {\n\t\treturn this.storage.getLabel(targetId);\n\t}\n\n\tasync setLabel(targetId: string, label: string | undefined): Promise<void> {\n\t\tawait this.storage.setLabel(targetId, label);\n\t}\n\n\tasync findEntries(query?: EntryQuery): Promise<Entry[]> {\n\t\treturn this.queryEntries(query);\n\t}\n\n\tasync findEntry(query: EntryQuery = {}): Promise<Entry | undefined> {\n\t\treturn (await this.queryEntries(query, 1))[0];\n\t}\n\n\tasync findEntriesOnBranch(query?: EntryQuery & BranchBounds): Promise<Entry[]> {\n\t\treturn this.queryBranchEntries(\"main\", query);\n\t}\n\n\tasync findEntryOnBranch(query: EntryQuery & BranchBounds = {}): Promise<Entry | undefined> {\n\t\treturn (await this.queryBranchEntries(\"main\", query, 1))[0];\n\t}\n\n\tasync appendMessage(message: AgentMessage): Promise<string> {\n\t\treturn this.appendMessageToLane(\"main\", message);\n\t}\n\n\tasync appendCustomEntry(customType: string, data?: unknown): Promise<string> {\n\t\treturn this.appendCustomEntryToLane(\"main\", customType, data);\n\t}\n\n\tasync getLanes(): Promise<LanePointer[]> {\n\t\treturn this.storage.getLanes();\n\t}\n\n\tasync createLane(lane: string, at: string | null): Promise<void> {\n\t\tawait this.storage.createLane(lane, at);\n\t}\n\n\tasync moveLane(lane: string, to: string | null): Promise<void> {\n\t\tawait this.storage.moveLane(lane, to);\n\t}\n\n\tasync appendEntry<TEntry extends Entry>(entry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\treturn this.commitEntry(entry, lane);\n\t}\n\n\tasync appendRecord<TNewRecord extends NewRecord>(\n\t\trecord: TNewRecord,\n\t): Promise<TNewRecord & Pick<RecordBase, \"seq\" | \"timestamp\">>;\n\tasync appendRecord(record: NewRecord): Promise<LaneRecord> {\n\t\treturn this.commitRecord(record);\n\t}\n\n\tasync findRecords<K extends LaneRecord[\"type\"]>(\n\t\tquery: RecordQuery & { type: K },\n\t): Promise<Extract<LaneRecord, { type: K }>[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]>;\n\tasync findRecords(query?: RecordQuery): Promise<LaneRecord[]> {\n\t\treturn this.queryRecords(query);\n\t}\n\n\tasync findOpenOperations(lane: string, options?: { limit?: number }): Promise<OperationStartedRecord[]> {\n\t\tassertValidLimit(options?.limit);\n\t\treturn this.storage.findOpenOperations(lane, options);\n\t}\n\n\tasync getLog(options?: LogOptions): Promise<LogItem[]> {\n\t\treturn this.queryLog(options);\n\t}\n\n\t/** Returns the lane's current leaf, or null when empty. Throws when the lane does not exist. */\n\tprivate async getLeafIdForLane(lane: string): Promise<string | null> {\n\t\tconst pointer = (await this.getLanes()).find((candidate) => candidate.lane === lane);\n\t\tif (!pointer) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\t\treturn pointer.leafId;\n\t}\n\n\tprivate async queryEntries(query: EntryQuery = {}, resultLimit = query.limit): Promise<Entry[]> {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.cursor?.afterSeq);\n\t\treturn this.storage.findEntries(resultLimit === query.limit ? query : { ...query, limit: resultLimit });\n\t}\n\n\t/**\n\t * Queries from `query.start` toward the root, defaulting to the lane's current leaf.\n\t * `resultLimit` lets single-entry queries cap results without changing the caller's query.\n\t */\n\tprivate async queryBranchEntries(\n\t\tdefaultLane: string,\n\t\tquery: EntryQuery & BranchBounds = {},\n\t\tresultLimit = query.limit,\n\t): Promise<Entry[]> {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.cursor?.afterSeq);\n\t\tconst start = query.start ?? (await this.getLeafIdForLane(defaultLane));\n\t\tif (start === null) return [];\n\t\tconst storageQuery = resultLimit === query.limit ? query : { ...query, limit: resultLimit };\n\t\treturn this.storage.findEntriesOnBranch({ ...storageQuery, start });\n\t}\n\n\tprivate async queryRecords(query: RecordQuery = {}): Promise<LaneRecord[]> {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.afterSeq);\n\t\tif (query.operationKind !== undefined && query.type !== \"operation_started\") {\n\t\t\tthrow new SessionError(\"invalid_query\", 'operationKind requires type \"operation_started\"');\n\t\t}\n\t\treturn this.storage.findRecords(query);\n\t}\n\n\tprivate async queryLog(options: LogOptions = {}): Promise<LogItem[]> {\n\t\tassertValidLimit(options.limit);\n\t\tassertValidCursor(options.afterSeq);\n\t\treturn this.storage.getLog(options);\n\t}\n\n\tprivate async appendMessageToLane(lane: string, message: AgentMessage): Promise<string> {\n\t\tconst entry = await this.commitEntry({ type: \"message\", id: this.idGenerator.next(), message }, lane);\n\t\treturn entry.id;\n\t}\n\n\tprivate async appendCustomEntryToLane(lane: string, customType: string, data?: unknown): Promise<string> {\n\t\tconst entry = await this.commitEntry(\n\t\t\tdata === undefined\n\t\t\t\t? { type: \"custom\", id: this.idGenerator.next(), customType }\n\t\t\t\t: { type: \"custom\", id: this.idGenerator.next(), customType, data },\n\t\t\tlane,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tprivate async commitEntry<TEntry extends Entry>(entry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry> {\n\t\tassertJsonSerializable(entry);\n\t\treturn this.storage.appendEntry(entry, lane);\n\t}\n\n\tprivate async commitRecord<TNewRecord extends NewRecord>(\n\t\trecord: TNewRecord,\n\t): Promise<TNewRecord & Pick<RecordBase, \"seq\" | \"timestamp\">> {\n\t\tassertJsonSerializable(record);\n\t\treturn this.storage.appendRecord<LaneRecord>(record) as unknown as Promise<\n\t\t\tTNewRecord & Pick<RecordBase, \"seq\" | \"timestamp\">\n\t\t>;\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/harness/session/state.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype BranchBounds,\n\ttype Entry,\n\ttype EntryOrder,\n\ttype EntryQuery,\n\ttype ForkOptions,\n\ttype LanePointer,\n\ttype LaneRecord,\n\ttype LogItem,\n\ttype LogOptions,\n\ttype OperationStartedRecord,\n\ttype RecordQuery,\n\tSessionError,\n\ttype SessionStats,\n} from \"./types.ts\";\n\nexport type SessionMutation =\n\t| { kind: \"entry\"; lane?: string; entry: Entry }\n\t| { kind: \"record\"; record: LaneRecord }\n\t| { kind: \"lane\"; seq: number; lane: string; leafId: string | null }\n\t| { kind: \"fact\"; seq: number; fact: \"name\"; name: string }\n\t| { kind: \"fact\"; seq: number; fact: \"label\"; targetId: string; label: string | undefined };\n\ntype InvalidMutation = (message: string) => never;\n\nfunction invalidMutation(message: string): never {\n\tthrow new SessionError(\"invalid_entry\", `Invalid session mutation: ${message}`);\n}\n\nfunction assertValidLimit(limit: number | undefined): void {\n\tif (limit !== undefined && (!Number.isInteger(limit) || limit <= 0)) {\n\t\tthrow new SessionError(\"invalid_query\", \"limit must be a positive integer\");\n\t}\n}\n\nfunction assertValidCursor(afterSeq: number | undefined): void {\n\tif (afterSeq !== undefined && (!Number.isInteger(afterSeq) || afterSeq < 0)) {\n\t\tthrow new SessionError(\"invalid_query\", \"cursor sequence must be a non-negative integer\");\n\t}\n}\n\nfunction* ordered<T>(items: readonly T[], order: EntryOrder | undefined): IterableIterator<T> {\n\tif (order === \"oldestFirst\") {\n\t\tyield* items;\n\t\treturn;\n\t}\n\tfor (let index = items.length - 1; index >= 0; index--) yield items[index]!;\n}\n\nexport class SessionState {\n\tprivate sequence = 0;\n\tprivate readonly usedIds = new Set<string>();\n\tprivate readonly entries: Entry[] = [];\n\tprivate readonly entriesById = new Map<string, Entry>();\n\tprivate readonly records: LaneRecord[] = [];\n\tprivate readonly openOperationsByLane = new Map<string, Map<string, OperationStartedRecord>>();\n\tprivate readonly lanes = new Map<string, string | null>([[\"main\", null]]);\n\tprivate readonly log: LogItem[] = [];\n\tprivate readonly stats: SessionStats = {\n\t\tmessageCount: 0,\n\t\tcachedTokens: 0,\n\t\tuncachedTokens: 0,\n\t\ttotalTokens: 0,\n\t\tcostTotal: 0,\n\t};\n\tprivate name: string | undefined;\n\tprivate readonly labels = new Map<string, string>();\n\n\tget nextSequence(): number {\n\t\treturn this.sequence + 1;\n\t}\n\n\tgetLanes(): LanePointer[] {\n\t\treturn [...this.lanes].map(([lane, leafId]) => ({ lane, leafId }));\n\t}\n\n\trequireLane(lane: string): string | null {\n\t\tconst leafId = this.lanes.get(lane);\n\t\tif (leafId === undefined) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\t\treturn leafId;\n\t}\n\n\tvalidateNewLane(lane: string): void {\n\t\tif (this.lanes.has(lane)) throw new SessionError(\"already_exists\", `Lane already exists: ${lane}`);\n\t}\n\n\tvalidateTarget(targetId: string | null): void {\n\t\tif (targetId !== null && !this.entriesById.has(targetId)) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry not found: ${targetId}`);\n\t\t}\n\t}\n\n\tvalidateUnusedId(id: string): void {\n\t\tif (this.usedIds.has(id)) throw new SessionError(\"already_exists\", `Session id already exists: ${id}`);\n\t}\n\n\tapplyMutation(mutation: SessionMutation, invalid: InvalidMutation = invalidMutation): void {\n\t\tconst seq =\n\t\t\tmutation.kind === \"entry\"\n\t\t\t\t? mutation.entry.seq\n\t\t\t\t: mutation.kind === \"record\"\n\t\t\t\t\t? mutation.record.seq\n\t\t\t\t\t: mutation.seq;\n\t\tif (seq !== this.sequence + 1) invalid(`has non-consecutive seq ${seq}`);\n\n\t\tswitch (mutation.kind) {\n\t\t\tcase \"entry\": {\n\t\t\t\tif (this.usedIds.has(mutation.entry.id)) invalid(`contains duplicate id ${mutation.entry.id}`);\n\t\t\t\tif (mutation.lane !== undefined) {\n\t\t\t\t\tconst leafId = this.lanes.get(mutation.lane);\n\t\t\t\t\tif (leafId === undefined) invalid(`references missing lane ${mutation.lane}`);\n\t\t\t\t\tif (mutation.entry.parentId !== leafId) invalid(\"does not chain to the lane leaf\");\n\t\t\t\t}\n\t\t\t\tif (mutation.entry.parentId !== null && !this.entriesById.has(mutation.entry.parentId)) {\n\t\t\t\t\tinvalid(`references missing parent ${mutation.entry.parentId}`);\n\t\t\t\t}\n\t\t\t\tthis.sequence = seq;\n\t\t\t\tthis.usedIds.add(mutation.entry.id);\n\t\t\t\tthis.entries.push(mutation.entry);\n\t\t\t\tthis.entriesById.set(mutation.entry.id, mutation.entry);\n\t\t\t\tif (mutation.lane !== undefined) this.lanes.set(mutation.lane, mutation.entry.id);\n\t\t\t\tthis.log.push({ kind: \"entry\", seq, entry: mutation.entry });\n\t\t\t\tif (mutation.entry.type === \"message\") this.stats.messageCount += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"record\": {\n\t\t\t\tif (!this.lanes.has(mutation.record.lane)) invalid(`references missing lane ${mutation.record.lane}`);\n\t\t\t\tif (this.usedIds.has(mutation.record.id)) invalid(`contains duplicate id ${mutation.record.id}`);\n\t\t\t\tthis.sequence = seq;\n\t\t\t\tthis.usedIds.add(mutation.record.id);\n\t\t\t\tthis.records.push(mutation.record);\n\t\t\t\tif (mutation.record.type === \"operation_started\") {\n\t\t\t\t\tlet openOperations = this.openOperationsByLane.get(mutation.record.lane);\n\t\t\t\t\tif (!openOperations) {\n\t\t\t\t\t\topenOperations = new Map();\n\t\t\t\t\t\tthis.openOperationsByLane.set(mutation.record.lane, openOperations);\n\t\t\t\t\t}\n\t\t\t\t\topenOperations.set(mutation.record.id, mutation.record);\n\t\t\t\t} else if (mutation.record.type === \"operation_finished\") {\n\t\t\t\t\tthis.openOperationsByLane.get(mutation.record.lane)?.delete(mutation.record.runId);\n\t\t\t\t}\n\t\t\t\tthis.log.push({ kind: \"record\", seq, record: mutation.record });\n\t\t\t\tif (mutation.record.type === \"usage\") {\n\t\t\t\t\tthis.stats.cachedTokens += mutation.record.usage.cacheRead;\n\t\t\t\t\tthis.stats.uncachedTokens += mutation.record.usage.input + mutation.record.usage.cacheWrite;\n\t\t\t\t\tthis.stats.totalTokens += mutation.record.usage.totalTokens;\n\t\t\t\t\tthis.stats.costTotal += mutation.record.usage.cost.total;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"lane\":\n\t\t\t\tif (mutation.leafId !== null && !this.entriesById.has(mutation.leafId)) {\n\t\t\t\t\tinvalid(`references missing lane target ${mutation.leafId}`);\n\t\t\t\t}\n\t\t\t\tthis.sequence = seq;\n\t\t\t\tthis.lanes.set(mutation.lane, mutation.leafId);\n\t\t\t\tthis.log.push({ kind: \"lane\", seq, lane: mutation.lane, leafId: mutation.leafId });\n\t\t\t\tbreak;\n\t\t\tcase \"fact\":\n\t\t\t\tif (mutation.fact === \"label\" && !this.entriesById.has(mutation.targetId)) {\n\t\t\t\t\tinvalid(`references missing label target ${mutation.targetId}`);\n\t\t\t\t}\n\t\t\t\tthis.sequence = seq;\n\t\t\t\tif (mutation.fact === \"name\") {\n\t\t\t\t\tthis.name = mutation.name;\n\t\t\t\t\tthis.log.push({ kind: \"fact\", seq, fact: \"name\", name: mutation.name });\n\t\t\t\t} else {\n\t\t\t\t\tif (mutation.label === undefined) this.labels.delete(mutation.targetId);\n\t\t\t\t\telse this.labels.set(mutation.targetId, mutation.label);\n\t\t\t\t\tthis.log.push({\n\t\t\t\t\t\tkind: \"fact\",\n\t\t\t\t\t\tseq,\n\t\t\t\t\t\tfact: \"label\",\n\t\t\t\t\t\ttargetId: mutation.targetId,\n\t\t\t\t\t\tlabel: mutation.label,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tgetEntry(id: string): Entry | undefined {\n\t\treturn this.entriesById.get(id);\n\t}\n\n\tfindEntries(query: EntryQuery = {}): Entry[] {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.cursor?.afterSeq);\n\t\tconst results: Entry[] = [];\n\t\tfor (const entry of ordered(this.entries, query.order)) {\n\t\t\tif (!this.matchesEntryQuery(entry, query)) continue;\n\t\t\tresults.push(entry);\n\t\t\tif (results.length === query.limit) break;\n\t\t}\n\t\treturn results;\n\t}\n\n\tfindEntriesOnBranch(query: EntryQuery & BranchBounds & { start: string }): Entry[] {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.cursor?.afterSeq);\n\t\tconst results: Entry[] = [];\n\t\tif (query.order === \"oldestFirst\") {\n\t\t\tfor (const entry of [...this.walkToRoot(query.start)].reverse()) {\n\t\t\t\tconst reachedBound = entry.id === query.stopAtId || entry.type === query.stopAtType;\n\t\t\t\tif (this.matchesEntryQuery(entry, query)) results.push(entry);\n\t\t\t\tif (reachedBound || results.length === query.limit) break;\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const entry of this.walkToRoot(query.start, query)) {\n\t\t\t\tif (this.matchesEntryQuery(entry, query)) results.push(entry);\n\t\t\t\tif (results.length === query.limit) break;\n\t\t\t}\n\t\t}\n\t\treturn results;\n\t}\n\n\tfindRecords(query: RecordQuery = {}): LaneRecord[] {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.afterSeq);\n\t\tconst results: LaneRecord[] = [];\n\t\tfor (const record of ordered(this.records, query.order)) {\n\t\t\tif (!this.matchesRecordQuery(record, query)) continue;\n\t\t\tresults.push(record);\n\t\t\tif (results.length === query.limit) break;\n\t\t}\n\t\treturn results;\n\t}\n\n\tfindOpenOperations(lane: string, options?: { limit?: number }): OperationStartedRecord[] {\n\t\tassertValidLimit(options?.limit);\n\t\tconst openOperationsById = this.openOperationsByLane.get(lane);\n\t\tconst openOperations = openOperationsById ? [...openOperationsById.values()].reverse() : [];\n\t\treturn options?.limit === undefined ? openOperations : openOperations.slice(0, options.limit);\n\t}\n\n\tgetLog(options: LogOptions = {}): LogItem[] {\n\t\tassertValidLimit(options.limit);\n\t\tassertValidCursor(options.afterSeq);\n\t\tconst results: LogItem[] = [];\n\t\tfor (const item of this.log) {\n\t\t\tif (options.afterSeq !== undefined && item.seq <= options.afterSeq) continue;\n\t\t\tresults.push(item);\n\t\t\tif (results.length === options.limit) break;\n\t\t}\n\t\treturn results;\n\t}\n\n\tgetName(): string | undefined {\n\t\treturn this.name;\n\t}\n\n\tgetLabel(id: string): string | undefined {\n\t\treturn this.labels.get(id);\n\t}\n\n\tgetStats(): SessionStats {\n\t\treturn this.stats;\n\t}\n\n\tcreateForkMutations(options: ForkOptions): SessionMutation[] {\n\t\tlet copiedEntries: Entry[];\n\t\tlet forkLanes: LanePointer[];\n\t\tif (options.scope === \"tree\") {\n\t\t\tcopiedEntries = this.findEntries({ order: \"oldestFirst\" });\n\t\t\tforkLanes = this.getLanes();\n\t\t} else {\n\t\t\tconst selectedEntryId = options.entryId ?? this.requireLane(\"main\");\n\t\t\tlet targetId: string | null = null;\n\t\t\tif (selectedEntryId !== null) {\n\t\t\t\tconst entry = this.getEntry(selectedEntryId);\n\t\t\t\tif (!entry || entry.type !== \"message\") {\n\t\t\t\t\tthrow new SessionError(\"invalid_fork_target\", `Fork target is not a message entry: ${selectedEntryId}`);\n\t\t\t\t}\n\t\t\t\tconst position = options.position ?? (options.entryId === undefined ? \"at\" : \"before\");\n\t\t\t\ttargetId = position === \"at\" ? entry.id : entry.parentId;\n\t\t\t}\n\t\t\tcopiedEntries = targetId === null ? [] : this.findEntriesOnBranch({ start: targetId, order: \"oldestFirst\" });\n\t\t\tforkLanes = [{ lane: \"main\", leafId: targetId }];\n\t\t}\n\n\t\tconst mutations: SessionMutation[] = [];\n\t\tlet sequence = 1;\n\t\tfor (const sourceEntry of copiedEntries) {\n\t\t\tmutations.push({ kind: \"entry\", entry: { ...structuredClone(sourceEntry), seq: sequence++ } });\n\t\t}\n\t\tfor (const pointer of forkLanes) {\n\t\t\tmutations.push({ kind: \"lane\", seq: sequence++, lane: pointer.lane, leafId: pointer.leafId });\n\t\t}\n\t\tif (this.name !== undefined) {\n\t\t\tmutations.push({ kind: \"fact\", seq: sequence++, fact: \"name\", name: this.name });\n\t\t}\n\t\tfor (const entry of copiedEntries) {\n\t\t\tconst label = this.labels.get(entry.id);\n\t\t\tif (label !== undefined) {\n\t\t\t\tmutations.push({ kind: \"fact\", seq: sequence++, fact: \"label\", targetId: entry.id, label });\n\t\t\t}\n\t\t}\n\t\treturn mutations;\n\t}\n\n\tprivate *walkToRoot(\n\t\tstart: string | null,\n\t\tbounds?: Pick<BranchBounds, \"stopAtId\" | \"stopAtType\">,\n\t): IterableIterator<Entry> {\n\t\tif (start === null) return;\n\t\tconst visited = new Set<string>();\n\t\tlet current = this.entriesById.get(start);\n\t\tif (!current) throw new SessionError(\"not_found\", `Entry not found: ${start}`);\n\t\twhile (current) {\n\t\t\tif (visited.has(current.id)) {\n\t\t\t\tthrow new SessionError(\"invalid_entry\", `Session branch contains a cycle at ${current.id}`);\n\t\t\t}\n\t\t\tvisited.add(current.id);\n\t\t\tyield current;\n\t\t\tif (current.id === bounds?.stopAtId || current.type === bounds?.stopAtType || current.parentId === null) break;\n\t\t\tconst parentId: string = current.parentId;\n\t\t\tcurrent = this.entriesById.get(parentId);\n\t\t\tif (!current) throw new SessionError(\"invalid_entry\", `Entry not found: ${parentId}`);\n\t\t}\n\t}\n\n\tprivate matchesEntryQuery(entry: Entry, query: EntryQuery): boolean {\n\t\treturn (\n\t\t\t(query.type === undefined || entry.type === query.type) &&\n\t\t\t(query.customType === undefined || (entry.type === \"custom\" && entry.customType === query.customType)) &&\n\t\t\t(query.cursor === undefined ||\n\t\t\t\t(query.order === \"oldestFirst\" ? entry.seq > query.cursor.afterSeq : entry.seq < query.cursor.afterSeq))\n\t\t);\n\t}\n\n\tprivate matchesRecordQuery(record: LaneRecord, query: RecordQuery): boolean {\n\t\treturn (\n\t\t\t(query.lane === undefined || record.lane === query.lane) &&\n\t\t\t(query.type === undefined || record.type === query.type) &&\n\t\t\t(query.runId === undefined ||\n\t\t\t\t(record.type === \"operation_started\"\n\t\t\t\t\t? record.id === query.runId\n\t\t\t\t\t: \"runId\" in record && record.runId === query.runId)) &&\n\t\t\t(query.operationKind === undefined ||\n\t\t\t\t(record.type === \"operation_started\" && record.intent.kind === query.operationKind)) &&\n\t\t\t(query.afterSeq === undefined || record.seq > query.afterSeq)\n\t\t);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/harness/session/state.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype BranchBounds,\n\ttype Entry,\n\ttype EntryOrder,\n\ttype EntryQuery,\n\ttype ForkOptions,\n\ttype LanePointer,\n\ttype LaneRecord,\n\ttype LogItem,\n\ttype LogOptions,\n\ttype OperationStartedRecord,\n\ttype RecordQuery,\n\tSessionError,\n\ttype SessionStats,\n} from \"./types.ts\";\n\nexport type SessionMutation =\n\t| { kind: \"entry\"; lane?: string; entry: Entry }\n\t| { kind: \"record\"; record: LaneRecord }\n\t| { kind: \"lane\"; seq: number; lane: string; leafId: string | null }\n\t| { kind: \"fact\"; seq: number; fact: \"name\"; name: string | undefined }\n\t| { kind: \"fact\"; seq: number; fact: \"label\"; targetId: string; label: string | undefined };\n\ntype InvalidMutation = (message: string) => never;\n\nfunction invalidMutation(message: string): never {\n\tthrow new SessionError(\"invalid_entry\", `Invalid session mutation: ${message}`);\n}\n\nfunction assertValidLimit(limit: number | undefined): void {\n\tif (limit !== undefined && (!Number.isInteger(limit) || limit <= 0)) {\n\t\tthrow new SessionError(\"invalid_query\", \"limit must be a positive integer\");\n\t}\n}\n\nfunction assertValidCursor(afterSeq: number | undefined): void {\n\tif (afterSeq !== undefined && (!Number.isInteger(afterSeq) || afterSeq < 0)) {\n\t\tthrow new SessionError(\"invalid_query\", \"cursor sequence must be a non-negative integer\");\n\t}\n}\n\nfunction* ordered<T>(items: readonly T[], order: EntryOrder | undefined): IterableIterator<T> {\n\tif (order === \"oldestFirst\") {\n\t\tyield* items;\n\t\treturn;\n\t}\n\tfor (let index = items.length - 1; index >= 0; index--) yield items[index]!;\n}\n\nexport class SessionState {\n\tprivate sequence = 0;\n\tprivate readonly usedIds = new Set<string>();\n\tprivate readonly entries: Entry[] = [];\n\tprivate readonly entriesById = new Map<string, Entry>();\n\tprivate readonly records: LaneRecord[] = [];\n\tprivate readonly openOperationsByLane = new Map<string, Map<string, OperationStartedRecord>>();\n\tprivate readonly lanes = new Map<string, string | null>([[\"main\", null]]);\n\tprivate readonly log: LogItem[] = [];\n\tprivate readonly stats: SessionStats = {\n\t\tmessageCount: 0,\n\t\tcachedTokens: 0,\n\t\tuncachedTokens: 0,\n\t\ttotalTokens: 0,\n\t\tcostTotal: 0,\n\t};\n\tprivate name: string | undefined;\n\tprivate readonly labels = new Map<string, string>();\n\n\tget nextSequence(): number {\n\t\treturn this.sequence + 1;\n\t}\n\n\tgetLanes(): LanePointer[] {\n\t\treturn [...this.lanes].map(([lane, leafId]) => ({ lane, leafId }));\n\t}\n\n\trequireLane(lane: string): string | null {\n\t\tconst leafId = this.lanes.get(lane);\n\t\tif (leafId === undefined) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\t\treturn leafId;\n\t}\n\n\tvalidateNewLane(lane: string): void {\n\t\tif (this.lanes.has(lane)) throw new SessionError(\"already_exists\", `Lane already exists: ${lane}`);\n\t}\n\n\tvalidateTarget(targetId: string | null): void {\n\t\tif (targetId !== null && !this.entriesById.has(targetId)) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry not found: ${targetId}`);\n\t\t}\n\t}\n\n\tvalidateUnusedId(id: string): void {\n\t\tif (this.usedIds.has(id)) throw new SessionError(\"already_exists\", `Session id already exists: ${id}`);\n\t}\n\n\tapplyMutation(mutation: SessionMutation, invalid: InvalidMutation = invalidMutation): void {\n\t\tconst seq =\n\t\t\tmutation.kind === \"entry\"\n\t\t\t\t? mutation.entry.seq\n\t\t\t\t: mutation.kind === \"record\"\n\t\t\t\t\t? mutation.record.seq\n\t\t\t\t\t: mutation.seq;\n\t\tif (seq !== this.sequence + 1) invalid(`has non-consecutive seq ${seq}`);\n\n\t\tswitch (mutation.kind) {\n\t\t\tcase \"entry\": {\n\t\t\t\tif (this.usedIds.has(mutation.entry.id)) invalid(`contains duplicate id ${mutation.entry.id}`);\n\t\t\t\tif (mutation.lane !== undefined) {\n\t\t\t\t\tconst leafId = this.lanes.get(mutation.lane);\n\t\t\t\t\tif (leafId === undefined) invalid(`references missing lane ${mutation.lane}`);\n\t\t\t\t\tif (mutation.entry.parentId !== leafId) invalid(\"does not chain to the lane leaf\");\n\t\t\t\t}\n\t\t\t\tif (mutation.entry.parentId !== null && !this.entriesById.has(mutation.entry.parentId)) {\n\t\t\t\t\tinvalid(`references missing parent ${mutation.entry.parentId}`);\n\t\t\t\t}\n\t\t\t\tthis.sequence = seq;\n\t\t\t\tthis.usedIds.add(mutation.entry.id);\n\t\t\t\tthis.entries.push(mutation.entry);\n\t\t\t\tthis.entriesById.set(mutation.entry.id, mutation.entry);\n\t\t\t\tif (mutation.lane !== undefined) this.lanes.set(mutation.lane, mutation.entry.id);\n\t\t\t\tthis.log.push({ kind: \"entry\", seq, entry: mutation.entry });\n\t\t\t\tif (mutation.entry.type === \"message\") this.stats.messageCount += 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"record\": {\n\t\t\t\tif (!this.lanes.has(mutation.record.lane)) invalid(`references missing lane ${mutation.record.lane}`);\n\t\t\t\tif (this.usedIds.has(mutation.record.id)) invalid(`contains duplicate id ${mutation.record.id}`);\n\t\t\t\tthis.sequence = seq;\n\t\t\t\tthis.usedIds.add(mutation.record.id);\n\t\t\t\tthis.records.push(mutation.record);\n\t\t\t\tif (mutation.record.type === \"operation_started\") {\n\t\t\t\t\tlet openOperations = this.openOperationsByLane.get(mutation.record.lane);\n\t\t\t\t\tif (!openOperations) {\n\t\t\t\t\t\topenOperations = new Map();\n\t\t\t\t\t\tthis.openOperationsByLane.set(mutation.record.lane, openOperations);\n\t\t\t\t\t}\n\t\t\t\t\topenOperations.set(mutation.record.id, mutation.record);\n\t\t\t\t} else if (mutation.record.type === \"operation_finished\") {\n\t\t\t\t\tthis.openOperationsByLane.get(mutation.record.lane)?.delete(mutation.record.runId);\n\t\t\t\t}\n\t\t\t\tthis.log.push({ kind: \"record\", seq, record: mutation.record });\n\t\t\t\tif (mutation.record.type === \"usage\") {\n\t\t\t\t\tthis.stats.cachedTokens += mutation.record.usage.cacheRead;\n\t\t\t\t\tthis.stats.uncachedTokens += mutation.record.usage.input + mutation.record.usage.cacheWrite;\n\t\t\t\t\tthis.stats.totalTokens += mutation.record.usage.totalTokens;\n\t\t\t\t\tthis.stats.costTotal += mutation.record.usage.cost.total;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"lane\":\n\t\t\t\tif (mutation.leafId !== null && !this.entriesById.has(mutation.leafId)) {\n\t\t\t\t\tinvalid(`references missing lane target ${mutation.leafId}`);\n\t\t\t\t}\n\t\t\t\tthis.sequence = seq;\n\t\t\t\tthis.lanes.set(mutation.lane, mutation.leafId);\n\t\t\t\tthis.log.push({ kind: \"lane\", seq, lane: mutation.lane, leafId: mutation.leafId });\n\t\t\t\tbreak;\n\t\t\tcase \"fact\":\n\t\t\t\tif (mutation.fact === \"label\" && !this.entriesById.has(mutation.targetId)) {\n\t\t\t\t\tinvalid(`references missing label target ${mutation.targetId}`);\n\t\t\t\t}\n\t\t\t\tthis.sequence = seq;\n\t\t\t\tif (mutation.fact === \"name\") {\n\t\t\t\t\tthis.name = mutation.name;\n\t\t\t\t\tthis.log.push({ kind: \"fact\", seq, fact: \"name\", name: mutation.name });\n\t\t\t\t} else {\n\t\t\t\t\tif (mutation.label === undefined) this.labels.delete(mutation.targetId);\n\t\t\t\t\telse this.labels.set(mutation.targetId, mutation.label);\n\t\t\t\t\tthis.log.push({\n\t\t\t\t\t\tkind: \"fact\",\n\t\t\t\t\t\tseq,\n\t\t\t\t\t\tfact: \"label\",\n\t\t\t\t\t\ttargetId: mutation.targetId,\n\t\t\t\t\t\tlabel: mutation.label,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tgetEntry(id: string): Entry | undefined {\n\t\treturn this.entriesById.get(id);\n\t}\n\n\tfindEntries(query: EntryQuery = {}): Entry[] {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.cursor?.afterSeq);\n\t\tconst results: Entry[] = [];\n\t\tfor (const entry of ordered(this.entries, query.order)) {\n\t\t\tif (!this.matchesEntryQuery(entry, query)) continue;\n\t\t\tresults.push(entry);\n\t\t\tif (results.length === query.limit) break;\n\t\t}\n\t\treturn results;\n\t}\n\n\tfindEntriesOnBranch(query: EntryQuery & BranchBounds & { start: string }): Entry[] {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.cursor?.afterSeq);\n\t\tconst results: Entry[] = [];\n\t\tif (query.order === \"oldestFirst\") {\n\t\t\tfor (const entry of [...this.walkToRoot(query.start)].reverse()) {\n\t\t\t\tconst reachedBound = entry.id === query.stopAtId || entry.type === query.stopAtType;\n\t\t\t\tif (this.matchesEntryQuery(entry, query)) results.push(entry);\n\t\t\t\tif (reachedBound || results.length === query.limit) break;\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const entry of this.walkToRoot(query.start, query)) {\n\t\t\t\tif (this.matchesEntryQuery(entry, query)) results.push(entry);\n\t\t\t\tif (results.length === query.limit) break;\n\t\t\t}\n\t\t}\n\t\treturn results;\n\t}\n\n\tfindRecords(query: RecordQuery = {}): LaneRecord[] {\n\t\tassertValidLimit(query.limit);\n\t\tassertValidCursor(query.afterSeq);\n\t\tconst results: LaneRecord[] = [];\n\t\tfor (const record of ordered(this.records, query.order)) {\n\t\t\tif (!this.matchesRecordQuery(record, query)) continue;\n\t\t\tresults.push(record);\n\t\t\tif (results.length === query.limit) break;\n\t\t}\n\t\treturn results;\n\t}\n\n\tfindOpenOperations(lane: string, options?: { limit?: number }): OperationStartedRecord[] {\n\t\tassertValidLimit(options?.limit);\n\t\tconst openOperationsById = this.openOperationsByLane.get(lane);\n\t\tconst openOperations = openOperationsById ? [...openOperationsById.values()].reverse() : [];\n\t\treturn options?.limit === undefined ? openOperations : openOperations.slice(0, options.limit);\n\t}\n\n\tgetLog(options: LogOptions = {}): LogItem[] {\n\t\tassertValidLimit(options.limit);\n\t\tassertValidCursor(options.afterSeq);\n\t\tconst results: LogItem[] = [];\n\t\tfor (const item of this.log) {\n\t\t\tif (options.afterSeq !== undefined && item.seq <= options.afterSeq) continue;\n\t\t\tresults.push(item);\n\t\t\tif (results.length === options.limit) break;\n\t\t}\n\t\treturn results;\n\t}\n\n\tgetName(): string | undefined {\n\t\treturn this.name;\n\t}\n\n\tgetLabel(id: string): string | undefined {\n\t\treturn this.labels.get(id);\n\t}\n\n\tgetStats(): SessionStats {\n\t\treturn this.stats;\n\t}\n\n\tcreateForkMutations(options: ForkOptions): SessionMutation[] {\n\t\tlet copiedEntries: Entry[];\n\t\tlet forkLanes: LanePointer[];\n\t\tif (options.scope === \"tree\") {\n\t\t\tcopiedEntries = this.findEntries({ order: \"oldestFirst\" });\n\t\t\tforkLanes = this.getLanes();\n\t\t} else {\n\t\t\tconst selectedEntryId = options.entryId ?? this.requireLane(\"main\");\n\t\t\tlet targetId: string | null = null;\n\t\t\tif (selectedEntryId !== null) {\n\t\t\t\tconst entry = this.getEntry(selectedEntryId);\n\t\t\t\tif (!entry || entry.type !== \"message\") {\n\t\t\t\t\tthrow new SessionError(\"invalid_fork_target\", `Fork target is not a message entry: ${selectedEntryId}`);\n\t\t\t\t}\n\t\t\t\tconst position = options.position ?? (options.entryId === undefined ? \"at\" : \"before\");\n\t\t\t\ttargetId = position === \"at\" ? entry.id : entry.parentId;\n\t\t\t}\n\t\t\tcopiedEntries = targetId === null ? [] : this.findEntriesOnBranch({ start: targetId, order: \"oldestFirst\" });\n\t\t\tforkLanes = [{ lane: \"main\", leafId: targetId }];\n\t\t}\n\n\t\tconst mutations: SessionMutation[] = [];\n\t\tlet sequence = 1;\n\t\tfor (const sourceEntry of copiedEntries) {\n\t\t\tmutations.push({ kind: \"entry\", entry: { ...structuredClone(sourceEntry), seq: sequence++ } });\n\t\t}\n\t\tfor (const pointer of forkLanes) {\n\t\t\tmutations.push({ kind: \"lane\", seq: sequence++, lane: pointer.lane, leafId: pointer.leafId });\n\t\t}\n\t\tif (this.name !== undefined) {\n\t\t\tmutations.push({ kind: \"fact\", seq: sequence++, fact: \"name\", name: this.name });\n\t\t}\n\t\tfor (const entry of copiedEntries) {\n\t\t\tconst label = this.labels.get(entry.id);\n\t\t\tif (label !== undefined) {\n\t\t\t\tmutations.push({ kind: \"fact\", seq: sequence++, fact: \"label\", targetId: entry.id, label });\n\t\t\t}\n\t\t}\n\t\treturn mutations;\n\t}\n\n\tprivate *walkToRoot(\n\t\tstart: string | null,\n\t\tbounds?: Pick<BranchBounds, \"stopAtId\" | \"stopAtType\">,\n\t): IterableIterator<Entry> {\n\t\tif (start === null) return;\n\t\tconst visited = new Set<string>();\n\t\tlet current = this.entriesById.get(start);\n\t\tif (!current) throw new SessionError(\"not_found\", `Entry not found: ${start}`);\n\t\twhile (current) {\n\t\t\tif (visited.has(current.id)) {\n\t\t\t\tthrow new SessionError(\"invalid_entry\", `Session branch contains a cycle at ${current.id}`);\n\t\t\t}\n\t\t\tvisited.add(current.id);\n\t\t\tyield current;\n\t\t\tif (current.id === bounds?.stopAtId || current.type === bounds?.stopAtType || current.parentId === null) break;\n\t\t\tconst parentId: string = current.parentId;\n\t\t\tcurrent = this.entriesById.get(parentId);\n\t\t\tif (!current) throw new SessionError(\"invalid_entry\", `Entry not found: ${parentId}`);\n\t\t}\n\t}\n\n\tprivate matchesEntryQuery(entry: Entry, query: EntryQuery): boolean {\n\t\treturn (\n\t\t\t(query.type === undefined || entry.type === query.type) &&\n\t\t\t(query.customType === undefined || (entry.type === \"custom\" && entry.customType === query.customType)) &&\n\t\t\t(query.cursor === undefined ||\n\t\t\t\t(query.order === \"oldestFirst\" ? entry.seq > query.cursor.afterSeq : entry.seq < query.cursor.afterSeq))\n\t\t);\n\t}\n\n\tprivate matchesRecordQuery(record: LaneRecord, query: RecordQuery): boolean {\n\t\treturn (\n\t\t\t(query.lane === undefined || record.lane === query.lane) &&\n\t\t\t(query.type === undefined || record.type === query.type) &&\n\t\t\t(query.runId === undefined ||\n\t\t\t\t(record.type === \"operation_started\"\n\t\t\t\t\t? record.id === query.runId\n\t\t\t\t\t: \"runId\" in record && record.runId === query.runId)) &&\n\t\t\t(query.operationKind === undefined ||\n\t\t\t\t(record.type === \"operation_started\" && record.intent.kind === query.operationKind)) &&\n\t\t\t(query.afterSeq === undefined || record.seq > query.afterSeq)\n\t\t);\n\t}\n}\n"]}
|