@di-code/coding-agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts +26 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +117 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/models-loader.d.ts +4 -0
- package/dist/config/models-loader.d.ts.map +1 -0
- package/dist/config/models-loader.js +134 -0
- package/dist/config/models-loader.js.map +1 -0
- package/dist/config/models-types.d.ts +23 -0
- package/dist/config/models-types.d.ts.map +1 -0
- package/dist/config/models-types.js +2 -0
- package/dist/config/models-types.js.map +1 -0
- package/dist/config/settings-loader.d.ts +3 -0
- package/dist/config/settings-loader.d.ts.map +1 -0
- package/dist/config/settings-loader.js +130 -0
- package/dist/config/settings-loader.js.map +1 -0
- package/dist/config/settings-types.d.ts +21 -0
- package/dist/config/settings-types.d.ts.map +1 -0
- package/dist/config/settings-types.js +2 -0
- package/dist/config/settings-types.js.map +1 -0
- package/dist/core/context-builder.d.ts +8 -0
- package/dist/core/context-builder.d.ts.map +1 -0
- package/dist/core/context-builder.js +46 -0
- package/dist/core/context-builder.js.map +1 -0
- package/dist/core/model-catalog-store.d.ts +8 -0
- package/dist/core/model-catalog-store.d.ts.map +1 -0
- package/dist/core/model-catalog-store.js +68 -0
- package/dist/core/model-catalog-store.js.map +1 -0
- package/dist/core/model-composer.d.ts +4 -0
- package/dist/core/model-composer.d.ts.map +1 -0
- package/dist/core/model-composer.js +37 -0
- package/dist/core/model-composer.js.map +1 -0
- package/dist/core/session/session-manager.d.ts +44 -0
- package/dist/core/session/session-manager.d.ts.map +1 -0
- package/dist/core/session/session-manager.js +138 -0
- package/dist/core/session/session-manager.js.map +1 -0
- package/dist/core/session/session-storage.d.ts +11 -0
- package/dist/core/session/session-storage.d.ts.map +1 -0
- package/dist/core/session/session-storage.js +382 -0
- package/dist/core/session/session-storage.js.map +1 -0
- package/dist/core/session/types.d.ts +65 -0
- package/dist/core/session/types.d.ts.map +1 -0
- package/dist/core/session/types.js +28 -0
- package/dist/core/session/types.js.map +1 -0
- package/dist/core/session.d.ts +80 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +262 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/tools/bash.d.ts +39 -0
- package/dist/core/tools/bash.d.ts.map +1 -0
- package/dist/core/tools/bash.js +208 -0
- package/dist/core/tools/bash.js.map +1 -0
- package/dist/core/tools/edit.d.ts +18 -0
- package/dist/core/tools/edit.d.ts.map +1 -0
- package/dist/core/tools/edit.js +107 -0
- package/dist/core/tools/edit.js.map +1 -0
- package/dist/core/tools/file-mutation-queue.d.ts +2 -0
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -0
- package/dist/core/tools/file-mutation-queue.js +24 -0
- package/dist/core/tools/file-mutation-queue.js.map +1 -0
- package/dist/core/tools/path-boundary.d.ts +3 -0
- package/dist/core/tools/path-boundary.d.ts.map +1 -0
- package/dist/core/tools/path-boundary.js +62 -0
- package/dist/core/tools/path-boundary.js.map +1 -0
- package/dist/core/tools/read.d.ts +17 -0
- package/dist/core/tools/read.d.ts.map +1 -0
- package/dist/core/tools/read.js +132 -0
- package/dist/core/tools/read.js.map +1 -0
- package/dist/core/tools/write.d.ts +17 -0
- package/dist/core/tools/write.d.ts.map +1 -0
- package/dist/core/tools/write.js +45 -0
- package/dist/core/tools/write.js.map +1 -0
- package/dist/entry.d.ts +3 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +27 -0
- package/dist/entry.js.map +1 -0
- package/dist/extensions/index.d.ts +5 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/index.js +3 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/runtime.d.ts +46 -0
- package/dist/extensions/runtime.d.ts.map +1 -0
- package/dist/extensions/runtime.js +179 -0
- package/dist/extensions/runtime.js.map +1 -0
- package/dist/extensions/trust.d.ts +8 -0
- package/dist/extensions/trust.d.ts.map +1 -0
- package/dist/extensions/trust.js +59 -0
- package/dist/extensions/trust.js.map +1 -0
- package/dist/extensions/types.d.ts +46 -0
- package/dist/extensions/types.d.ts.map +1 -0
- package/dist/extensions/types.js +2 -0
- package/dist/extensions/types.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +19 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +198 -0
- package/dist/main.js.map +1 -0
- package/dist/modes/interactive-components.d.ts +41 -0
- package/dist/modes/interactive-components.d.ts.map +1 -0
- package/dist/modes/interactive-components.js +195 -0
- package/dist/modes/interactive-components.js.map +1 -0
- package/dist/modes/interactive-layout.d.ts +20 -0
- package/dist/modes/interactive-layout.d.ts.map +1 -0
- package/dist/modes/interactive-layout.js +34 -0
- package/dist/modes/interactive-layout.js.map +1 -0
- package/dist/modes/interactive-state.d.ts +61 -0
- package/dist/modes/interactive-state.d.ts.map +1 -0
- package/dist/modes/interactive-state.js +201 -0
- package/dist/modes/interactive-state.js.map +1 -0
- package/dist/modes/interactive.d.ts +61 -0
- package/dist/modes/interactive.d.ts.map +1 -0
- package/dist/modes/interactive.js +436 -0
- package/dist/modes/interactive.js.map +1 -0
- package/dist/modes/json.d.ts +14 -0
- package/dist/modes/json.d.ts.map +1 -0
- package/dist/modes/json.js +26 -0
- package/dist/modes/json.js.map +1 -0
- package/dist/modes/print.d.ts +10 -0
- package/dist/modes/print.d.ts.map +1 -0
- package/dist/modes/print.js +28 -0
- package/dist/modes/print.js.map +1 -0
- package/dist/provider-onboarding.d.ts +13 -0
- package/dist/provider-onboarding.d.ts.map +1 -0
- package/dist/provider-onboarding.js +162 -0
- package/dist/provider-onboarding.js.map +1 -0
- package/dist/rpc/client.d.ts +38 -0
- package/dist/rpc/client.d.ts.map +1 -0
- package/dist/rpc/client.js +153 -0
- package/dist/rpc/client.js.map +1 -0
- package/dist/rpc/index.d.ts +5 -0
- package/dist/rpc/index.d.ts.map +1 -0
- package/dist/rpc/index.js +5 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/rpc/jsonl.d.ts +17 -0
- package/dist/rpc/jsonl.d.ts.map +1 -0
- package/dist/rpc/jsonl.js +52 -0
- package/dist/rpc/jsonl.js.map +1 -0
- package/dist/rpc/protocol.d.ts +80 -0
- package/dist/rpc/protocol.d.ts.map +1 -0
- package/dist/rpc/protocol.js +231 -0
- package/dist/rpc/protocol.js.map +1 -0
- package/dist/rpc/server.d.ts +41 -0
- package/dist/rpc/server.d.ts.map +1 -0
- package/dist/rpc/server.js +186 -0
- package/dist/rpc/server.js.map +1 -0
- package/dist/rpc-entry.d.ts +3 -0
- package/dist/rpc-entry.d.ts.map +1 -0
- package/dist/rpc-entry.js +28 -0
- package/dist/rpc-entry.js.map +1 -0
- package/dist/startup.d.ts +24 -0
- package/dist/startup.d.ts.map +1 -0
- package/dist/startup.js +227 -0
- package/dist/startup.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-builder.js","sourceRoot":"","sources":["../../src/core/context-builder.ts"],"names":[],"mappings":"AAQA,SAAS,oBAAoB,CAAC,KAA0B;IACvD,OAAO;QACN,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE;YACR;gBACC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,2BAA2B,KAAK,CAAC,OAAO,2BAA2B;aACzE;SACD;QACD,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC;KACtC,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,OAAgC;IACvD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAgC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;AAC1F,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAgC;IACnE,MAAM,QAAQ,GAAG,eAAe,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAC/C,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC;IACtB,KAAK,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QAC3D,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;YACzC,YAAY,GAAG,KAAK,CAAC;YACrB,MAAM;QACP,CAAC;IACF,CAAC;IAED,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC1C,OAAO;YACN,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;YAChD,cAAc,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;SACjD,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC;IACvC,IAAI,OAAO,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,cAAc,GAAG,QAAQ,CAAC,SAAS,CACxC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,gBAAgB,CAC3G,CAAC;IACF,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,WAAW,GAAG,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;IACnE,OAAO;QACN,QAAQ,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACvF,cAAc,EAAE,CAAC,IAAI,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;KAC/D,CAAC;AACH,CAAC","sourcesContent":["import type { Message, UserMessage } from \"@di-code/ai\";\nimport type { SessionEntry, SessionMessageEntry, SessionSummaryEntry } from \"./session/types.ts\";\n\nexport interface BuiltSessionContext {\n\treadonly messages: readonly Message[];\n\treadonly sourceEntryIds: readonly (string | null)[];\n}\n\nfunction createSummaryMessage(entry: SessionSummaryEntry): UserMessage {\n\treturn {\n\t\trole: \"user\",\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `<conversation-summary>\\n${entry.summary}\\n</conversation-summary>`,\n\t\t\t},\n\t\t],\n\t\ttimestamp: Date.parse(entry.timestamp),\n\t};\n}\n\nfunction messageEntries(entries: readonly SessionEntry[]): SessionMessageEntry[] {\n\treturn entries.filter((entry): entry is SessionMessageEntry => entry.type === \"message\");\n}\n\nexport function buildSessionContext(entries: readonly SessionEntry[]): BuiltSessionContext {\n\tconst snapshot = structuredClone([...entries]);\n\tlet summaryIndex = -1;\n\tfor (let index = snapshot.length - 1; index >= 0; index--) {\n\t\tif (snapshot[index]?.type === \"summary\") {\n\t\t\tsummaryIndex = index;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (summaryIndex < 0) {\n\t\tconst messages = messageEntries(snapshot);\n\t\treturn {\n\t\t\tmessages: messages.map((entry) => entry.message),\n\t\t\tsourceEntryIds: messages.map((entry) => entry.id),\n\t\t};\n\t}\n\n\tconst summary = snapshot[summaryIndex];\n\tif (summary?.type !== \"summary\") {\n\t\tthrow new Error(\"Latest summary entry could not be resolved.\");\n\t}\n\tconst firstKeptIndex = snapshot.findIndex(\n\t\t(entry, index) => index < summaryIndex && entry.type === \"message\" && entry.id === summary.firstKeptEntryId,\n\t);\n\tif (firstKeptIndex < 0) {\n\t\tthrow new Error(\"Summary firstKeptEntryId must reference an earlier message entry.\");\n\t}\n\n\tconst keptEntries = messageEntries(snapshot.slice(firstKeptIndex));\n\treturn {\n\t\tmessages: [createSummaryMessage(summary), ...keptEntries.map((entry) => entry.message)],\n\t\tsourceEntryIds: [null, ...keptEntries.map((entry) => entry.id)],\n\t};\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ModelCatalogEntry, ModelCatalogStore } from "@di-code/ai";
|
|
2
|
+
export declare class FileModelCatalogStore implements ModelCatalogStore {
|
|
3
|
+
private readonly path;
|
|
4
|
+
constructor(path: string);
|
|
5
|
+
read(): Promise<ModelCatalogEntry | undefined>;
|
|
6
|
+
write(entry: ModelCatalogEntry): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=model-catalog-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-catalog-store.d.ts","sourceRoot":"","sources":["../../src/core/model-catalog-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAS,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA+C/E,qBAAa,qBAAsB,YAAW,iBAAiB;IAC9D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,IAAI,EAAE,MAAM;IAIlB,IAAI,IAAI,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAuB9C,KAAK,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;CAKpD"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
function isRecord(value) {
|
|
4
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
function isModel(value) {
|
|
7
|
+
if (!isRecord(value))
|
|
8
|
+
return false;
|
|
9
|
+
return (typeof value.id === "string" &&
|
|
10
|
+
typeof value.name === "string" &&
|
|
11
|
+
typeof value.provider === "string" &&
|
|
12
|
+
typeof value.api === "string" &&
|
|
13
|
+
Array.isArray(value.input) &&
|
|
14
|
+
value.input.every((item) => item === "text" || item === "image") &&
|
|
15
|
+
typeof value.reasoning === "boolean" &&
|
|
16
|
+
Number.isInteger(value.contextWindow) &&
|
|
17
|
+
Number.isInteger(value.maxOutputTokens) &&
|
|
18
|
+
isRecord(value.cost) &&
|
|
19
|
+
["input", "output", "cacheRead", "cacheWrite"].every((field) => {
|
|
20
|
+
const cost = value.cost;
|
|
21
|
+
return typeof cost[field] === "number" && Number.isFinite(cost[field]);
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
function parsePersisted(path, value) {
|
|
25
|
+
if (!isRecord(value) || value.version !== 1) {
|
|
26
|
+
throw new Error(`Unsupported model catalog cache version in ${path}`);
|
|
27
|
+
}
|
|
28
|
+
if (!Array.isArray(value.models) ||
|
|
29
|
+
!value.models.every(isModel) ||
|
|
30
|
+
typeof value.checkedAt !== "number" ||
|
|
31
|
+
!Number.isFinite(value.checkedAt)) {
|
|
32
|
+
throw new Error(`Invalid model catalog cache ${path}`);
|
|
33
|
+
}
|
|
34
|
+
return { models: value.models, checkedAt: value.checkedAt };
|
|
35
|
+
}
|
|
36
|
+
export class FileModelCatalogStore {
|
|
37
|
+
path;
|
|
38
|
+
constructor(path) {
|
|
39
|
+
this.path = path;
|
|
40
|
+
}
|
|
41
|
+
async read() {
|
|
42
|
+
let text;
|
|
43
|
+
try {
|
|
44
|
+
text = await readFile(this.path, "utf8");
|
|
45
|
+
}
|
|
46
|
+
catch (cause) {
|
|
47
|
+
if (cause.code === "ENOENT")
|
|
48
|
+
return undefined;
|
|
49
|
+
throw new Error(`Unable to read model catalog cache ${this.path}: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
return parsePersisted(this.path, JSON.parse(text));
|
|
53
|
+
}
|
|
54
|
+
catch (cause) {
|
|
55
|
+
if (cause instanceof Error &&
|
|
56
|
+
(cause.message.startsWith("Invalid model catalog cache") ||
|
|
57
|
+
cause.message.startsWith("Unsupported model catalog cache")))
|
|
58
|
+
throw cause;
|
|
59
|
+
throw new Error(`Invalid model catalog cache ${this.path}: malformed JSON`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async write(entry) {
|
|
63
|
+
const persisted = { version: 1, models: entry.models, checkedAt: entry.checkedAt };
|
|
64
|
+
await mkdir(dirname(this.path), { recursive: true });
|
|
65
|
+
await writeFile(this.path, `${JSON.stringify(persisted, null, 2)}\n`, "utf8");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=model-catalog-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-catalog-store.js","sourceRoot":"","sources":["../../src/core/model-catalog-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { Model, ModelCatalogEntry, ModelCatalogStore } from \"@di-code/ai\";\n\ninterface PersistedModelCatalog {\n\treadonly version: 1;\n\treadonly models: readonly Model[];\n\treadonly checkedAt: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isModel(value: unknown): value is Model {\n\tif (!isRecord(value)) return false;\n\treturn (\n\t\ttypeof value.id === \"string\" &&\n\t\ttypeof value.name === \"string\" &&\n\t\ttypeof value.provider === \"string\" &&\n\t\ttypeof value.api === \"string\" &&\n\t\tArray.isArray(value.input) &&\n\t\tvalue.input.every((item) => item === \"text\" || item === \"image\") &&\n\t\ttypeof value.reasoning === \"boolean\" &&\n\t\tNumber.isInteger(value.contextWindow) &&\n\t\tNumber.isInteger(value.maxOutputTokens) &&\n\t\tisRecord(value.cost) &&\n\t\t[\"input\", \"output\", \"cacheRead\", \"cacheWrite\"].every((field) => {\n\t\t\tconst cost = value.cost as Record<string, unknown>;\n\t\t\treturn typeof cost[field] === \"number\" && Number.isFinite(cost[field] as number);\n\t\t})\n\t);\n}\n\nfunction parsePersisted(path: string, value: unknown): ModelCatalogEntry {\n\tif (!isRecord(value) || value.version !== 1) {\n\t\tthrow new Error(`Unsupported model catalog cache version in ${path}`);\n\t}\n\tif (\n\t\t!Array.isArray(value.models) ||\n\t\t!value.models.every(isModel) ||\n\t\ttypeof value.checkedAt !== \"number\" ||\n\t\t!Number.isFinite(value.checkedAt)\n\t) {\n\t\tthrow new Error(`Invalid model catalog cache ${path}`);\n\t}\n\treturn { models: value.models, checkedAt: value.checkedAt };\n}\n\nexport class FileModelCatalogStore implements ModelCatalogStore {\n\tprivate readonly path: string;\n\n\tconstructor(path: string) {\n\t\tthis.path = path;\n\t}\n\n\tasync read(): Promise<ModelCatalogEntry | undefined> {\n\t\tlet text: string;\n\t\ttry {\n\t\t\ttext = await readFile(this.path, \"utf8\");\n\t\t} catch (cause) {\n\t\t\tif ((cause as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n\t\t\tthrow new Error(\n\t\t\t\t`Unable to read model catalog cache ${this.path}: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\treturn parsePersisted(this.path, JSON.parse(text) as unknown);\n\t\t} catch (cause) {\n\t\t\tif (\n\t\t\t\tcause instanceof Error &&\n\t\t\t\t(cause.message.startsWith(\"Invalid model catalog cache\") ||\n\t\t\t\t\tcause.message.startsWith(\"Unsupported model catalog cache\"))\n\t\t\t)\n\t\t\t\tthrow cause;\n\t\t\tthrow new Error(`Invalid model catalog cache ${this.path}: malformed JSON`);\n\t\t}\n\t}\n\n\tasync write(entry: ModelCatalogEntry): Promise<void> {\n\t\tconst persisted: PersistedModelCatalog = { version: 1, models: entry.models, checkedAt: entry.checkedAt };\n\t\tawait mkdir(dirname(this.path), { recursive: true });\n\t\tawait writeFile(this.path, `${JSON.stringify(persisted, null, 2)}\\n`, \"utf8\");\n\t}\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Model } from "@di-code/ai";
|
|
2
|
+
import type { CustomProviderDefinition } from "../config/models-types.ts";
|
|
3
|
+
export declare function composeProviderModels(providerId: string, baseline: readonly Model[], definition: CustomProviderDefinition): Model[];
|
|
4
|
+
//# sourceMappingURL=model-composer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-composer.d.ts","sourceRoot":"","sources":["../../src/core/model-composer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAE1E,wBAAgB,qBAAqB,CACpC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,SAAS,KAAK,EAAE,EAC1B,UAAU,EAAE,wBAAwB,GAClC,KAAK,EAAE,CAgCT"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export function composeProviderModels(providerId, baseline, definition) {
|
|
2
|
+
const models = baseline.map((model) => ({ ...model, input: [...model.input], cost: { ...model.cost } }));
|
|
3
|
+
const defaultApi = definition.api ?? models[0]?.api ?? "openai-responses";
|
|
4
|
+
for (const custom of definition.models ?? []) {
|
|
5
|
+
const model = {
|
|
6
|
+
id: custom.id,
|
|
7
|
+
name: custom.name ?? custom.id,
|
|
8
|
+
provider: providerId,
|
|
9
|
+
api: custom.api ?? defaultApi,
|
|
10
|
+
input: [...(custom.input ?? ["text"])],
|
|
11
|
+
reasoning: custom.reasoning ?? false,
|
|
12
|
+
contextWindow: custom.contextWindow ?? 128_000,
|
|
13
|
+
maxOutputTokens: custom.maxOutputTokens ?? 16_384,
|
|
14
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, ...custom.cost },
|
|
15
|
+
};
|
|
16
|
+
const index = models.findIndex((entry) => entry.id === model.id);
|
|
17
|
+
if (index >= 0)
|
|
18
|
+
models[index] = model;
|
|
19
|
+
else
|
|
20
|
+
models.push(model);
|
|
21
|
+
}
|
|
22
|
+
for (const [id, override] of Object.entries(definition.modelOverrides ?? {})) {
|
|
23
|
+
const index = models.findIndex((entry) => entry.id === id);
|
|
24
|
+
if (index < 0)
|
|
25
|
+
continue;
|
|
26
|
+
models[index] = {
|
|
27
|
+
...models[index],
|
|
28
|
+
...override,
|
|
29
|
+
...(override.input ? { input: [...override.input] } : {}),
|
|
30
|
+
provider: providerId,
|
|
31
|
+
id,
|
|
32
|
+
...(override.cost ? { cost: { ...models[index].cost, ...override.cost } } : {}),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return models;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=model-composer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-composer.js","sourceRoot":"","sources":["../../src/core/model-composer.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,qBAAqB,CACpC,UAAkB,EAClB,QAA0B,EAC1B,UAAoC;IAEpC,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACzG,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,kBAAkB,CAAC;IAC1E,KAAK,MAAM,MAAM,IAAI,UAAU,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAU;YACpB,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE;YAC9B,QAAQ,EAAE,UAAU;YACpB,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,UAAU;YAC7B,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAyB;YAC9D,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,KAAK;YACpC,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,OAAO;YAC9C,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,MAAM;YACjD,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE;SAC1E,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC;QACjE,IAAI,KAAK,IAAI,CAAC;YAAE,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;;YACjC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IACD,KAAK,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,cAAc,IAAI,EAAE,CAAC,EAAE,CAAC;QAC9E,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3D,IAAI,KAAK,GAAG,CAAC;YAAE,SAAS;QACxB,MAAM,CAAC,KAAK,CAAC,GAAG;YACf,GAAG,MAAM,CAAC,KAAK,CAAC;YAChB,GAAG,QAAQ;YACX,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAyB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,QAAQ,EAAE,UAAU;YACpB,EAAE;YACF,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtE,CAAC;IACZ,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC","sourcesContent":["import type { Model } from \"@di-code/ai\";\nimport type { CustomProviderDefinition } from \"../config/models-types.ts\";\n\nexport function composeProviderModels(\n\tproviderId: string,\n\tbaseline: readonly Model[],\n\tdefinition: CustomProviderDefinition,\n): Model[] {\n\tconst models = baseline.map((model) => ({ ...model, input: [...model.input], cost: { ...model.cost } }));\n\tconst defaultApi = definition.api ?? models[0]?.api ?? \"openai-responses\";\n\tfor (const custom of definition.models ?? []) {\n\t\tconst model: Model = {\n\t\t\tid: custom.id,\n\t\t\tname: custom.name ?? custom.id,\n\t\t\tprovider: providerId,\n\t\t\tapi: custom.api ?? defaultApi,\n\t\t\tinput: [...(custom.input ?? [\"text\"])] as (\"text\" | \"image\")[],\n\t\t\treasoning: custom.reasoning ?? false,\n\t\t\tcontextWindow: custom.contextWindow ?? 128_000,\n\t\t\tmaxOutputTokens: custom.maxOutputTokens ?? 16_384,\n\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, ...custom.cost },\n\t\t};\n\t\tconst index = models.findIndex((entry) => entry.id === model.id);\n\t\tif (index >= 0) models[index] = model;\n\t\telse models.push(model);\n\t}\n\tfor (const [id, override] of Object.entries(definition.modelOverrides ?? {})) {\n\t\tconst index = models.findIndex((entry) => entry.id === id);\n\t\tif (index < 0) continue;\n\t\tmodels[index] = {\n\t\t\t...models[index],\n\t\t\t...override,\n\t\t\t...(override.input ? { input: [...override.input] as (\"text\" | \"image\")[] } : {}),\n\t\t\tprovider: providerId,\n\t\t\tid,\n\t\t\t...(override.cost ? { cost: { ...models[index].cost, ...override.cost } } : {}),\n\t\t} as Model;\n\t}\n\treturn models;\n}\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Message } from "@di-code/ai";
|
|
2
|
+
import { type SessionAppendOptions } from "./session-storage.ts";
|
|
3
|
+
import { type SessionDiagnostic, type SessionEntry, type SessionHeader, type SessionMessageEntry, type SessionSummaryEntry } from "./types.ts";
|
|
4
|
+
export interface SessionManagerCreateOptions {
|
|
5
|
+
readonly filePath: string;
|
|
6
|
+
readonly cwd: string;
|
|
7
|
+
readonly now?: () => number;
|
|
8
|
+
readonly createId?: () => string;
|
|
9
|
+
readonly appendOptions?: SessionAppendOptions;
|
|
10
|
+
readonly deferCreate?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface SessionManagerOpenOptions {
|
|
13
|
+
readonly now?: () => number;
|
|
14
|
+
readonly createId?: () => string;
|
|
15
|
+
readonly appendOptions?: SessionAppendOptions;
|
|
16
|
+
}
|
|
17
|
+
export declare class SessionManager {
|
|
18
|
+
readonly filePath: string;
|
|
19
|
+
private readonly sessionHeader;
|
|
20
|
+
private readonly now;
|
|
21
|
+
private readonly createId;
|
|
22
|
+
private readonly appendOptions;
|
|
23
|
+
private readonly sessionEntries;
|
|
24
|
+
private readonly sessionDiagnostics;
|
|
25
|
+
private fileCreated;
|
|
26
|
+
private appendQueue;
|
|
27
|
+
private constructor();
|
|
28
|
+
static create(options: SessionManagerCreateOptions): Promise<SessionManager>;
|
|
29
|
+
static open(filePath: string, options?: SessionManagerOpenOptions): Promise<SessionManager>;
|
|
30
|
+
get entries(): readonly SessionEntry[];
|
|
31
|
+
get header(): SessionHeader;
|
|
32
|
+
get messages(): readonly Message[];
|
|
33
|
+
get latestSummary(): SessionSummaryEntry | undefined;
|
|
34
|
+
get diagnostics(): readonly SessionDiagnostic[];
|
|
35
|
+
get leafId(): string;
|
|
36
|
+
private ensureFileCreated;
|
|
37
|
+
appendMessage(message: Message): Promise<SessionMessageEntry>;
|
|
38
|
+
appendSummary(input: {
|
|
39
|
+
readonly summary: string;
|
|
40
|
+
readonly firstKeptEntryId: string;
|
|
41
|
+
readonly tokensBefore: number;
|
|
42
|
+
}): Promise<SessionSummaryEntry>;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=session-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAIN,KAAK,oBAAoB,EACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAGN,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,oBAAoB,CAAC;IAC9C,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,oBAAoB,CAAC;CAC9C;AAgBD,qBAAa,cAAc;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuB;IACrD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;IACzD,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,WAAW,CAAoC;IAEvD,OAAO;WAWM,MAAM,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,cAAc,CAAC;WAwBrE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,yBAA8B,GAAG,OAAO,CAAC,cAAc,CAAC;IAKrG,IAAI,OAAO,IAAI,SAAS,YAAY,EAAE,CAErC;IAED,IAAI,MAAM,IAAI,aAAa,CAE1B;IAED,IAAI,QAAQ,IAAI,SAAS,OAAO,EAAE,CAMjC;IAED,IAAI,aAAa,IAAI,mBAAmB,GAAG,SAAS,CAMnD;IAED,IAAI,WAAW,IAAI,SAAS,iBAAiB,EAAE,CAE9C;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;YAEa,iBAAiB;IAM/B,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA2B7D,aAAa,CAAC,KAAK,EAAE;QACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;QAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;KAC9B,GAAG,OAAO,CAAC,mBAAmB,CAAC;CA4BhC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { appendSessionEntry, createSessionFile, loadSessionFile, } from "./session-storage.js";
|
|
4
|
+
import { SESSION_FORMAT_VERSION, } from "./types.js";
|
|
5
|
+
function assertRecordId(id) {
|
|
6
|
+
if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(id)) {
|
|
7
|
+
throw new Error(`Generated session record id is invalid: ${JSON.stringify(id)}.`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function createIsoTimestamp(now) {
|
|
11
|
+
const milliseconds = now();
|
|
12
|
+
if (!Number.isFinite(milliseconds)) {
|
|
13
|
+
throw new Error("Session clock must return a finite Unix millisecond timestamp.");
|
|
14
|
+
}
|
|
15
|
+
return new Date(milliseconds).toISOString();
|
|
16
|
+
}
|
|
17
|
+
export class SessionManager {
|
|
18
|
+
filePath;
|
|
19
|
+
sessionHeader;
|
|
20
|
+
now;
|
|
21
|
+
createId;
|
|
22
|
+
appendOptions;
|
|
23
|
+
sessionEntries;
|
|
24
|
+
sessionDiagnostics;
|
|
25
|
+
fileCreated;
|
|
26
|
+
appendQueue = Promise.resolve();
|
|
27
|
+
constructor(filePath, loaded, options, fileCreated = true) {
|
|
28
|
+
this.filePath = filePath;
|
|
29
|
+
this.sessionHeader = structuredClone(loaded.header);
|
|
30
|
+
this.sessionEntries = structuredClone([...loaded.entries]);
|
|
31
|
+
this.sessionDiagnostics = structuredClone([...loaded.diagnostics]);
|
|
32
|
+
this.now = options.now ?? Date.now;
|
|
33
|
+
this.createId = options.createId ?? randomUUID;
|
|
34
|
+
this.appendOptions = options.appendOptions ?? {};
|
|
35
|
+
this.fileCreated = fileCreated;
|
|
36
|
+
}
|
|
37
|
+
static async create(options) {
|
|
38
|
+
const filePath = resolve(options.filePath);
|
|
39
|
+
const cwd = resolve(options.cwd);
|
|
40
|
+
const now = options.now ?? Date.now;
|
|
41
|
+
const createId = options.createId ?? randomUUID;
|
|
42
|
+
const id = createId();
|
|
43
|
+
assertRecordId(id);
|
|
44
|
+
const header = {
|
|
45
|
+
type: "session",
|
|
46
|
+
version: SESSION_FORMAT_VERSION,
|
|
47
|
+
id,
|
|
48
|
+
parentId: null,
|
|
49
|
+
timestamp: createIsoTimestamp(now),
|
|
50
|
+
cwd,
|
|
51
|
+
};
|
|
52
|
+
if (!options.deferCreate)
|
|
53
|
+
await createSessionFile(filePath, header);
|
|
54
|
+
return new SessionManager(filePath, { header, entries: [], messages: [], diagnostics: [] }, { now, createId, appendOptions: options.appendOptions }, !options.deferCreate);
|
|
55
|
+
}
|
|
56
|
+
static async open(filePath, options = {}) {
|
|
57
|
+
const resolvedPath = resolve(filePath);
|
|
58
|
+
return new SessionManager(resolvedPath, await loadSessionFile(resolvedPath), options);
|
|
59
|
+
}
|
|
60
|
+
get entries() {
|
|
61
|
+
return structuredClone(this.sessionEntries);
|
|
62
|
+
}
|
|
63
|
+
get header() {
|
|
64
|
+
return structuredClone(this.sessionHeader);
|
|
65
|
+
}
|
|
66
|
+
get messages() {
|
|
67
|
+
return structuredClone(this.sessionEntries
|
|
68
|
+
.filter((entry) => entry.type === "message")
|
|
69
|
+
.map((entry) => entry.message));
|
|
70
|
+
}
|
|
71
|
+
get latestSummary() {
|
|
72
|
+
for (let index = this.sessionEntries.length - 1; index >= 0; index--) {
|
|
73
|
+
const entry = this.sessionEntries[index];
|
|
74
|
+
if (entry?.type === "summary")
|
|
75
|
+
return structuredClone(entry);
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
get diagnostics() {
|
|
80
|
+
return structuredClone(this.sessionDiagnostics);
|
|
81
|
+
}
|
|
82
|
+
get leafId() {
|
|
83
|
+
return this.sessionEntries.at(-1)?.id ?? this.sessionHeader.id;
|
|
84
|
+
}
|
|
85
|
+
async ensureFileCreated() {
|
|
86
|
+
if (this.fileCreated)
|
|
87
|
+
return;
|
|
88
|
+
await createSessionFile(this.filePath, this.sessionHeader);
|
|
89
|
+
this.fileCreated = true;
|
|
90
|
+
}
|
|
91
|
+
appendMessage(message) {
|
|
92
|
+
const messageSnapshot = structuredClone(message);
|
|
93
|
+
const operation = this.appendQueue.then(async () => {
|
|
94
|
+
await this.ensureFileCreated();
|
|
95
|
+
const id = this.createId();
|
|
96
|
+
assertRecordId(id);
|
|
97
|
+
const expectedParentId = this.leafId;
|
|
98
|
+
const entry = {
|
|
99
|
+
type: "message",
|
|
100
|
+
version: SESSION_FORMAT_VERSION,
|
|
101
|
+
id,
|
|
102
|
+
parentId: expectedParentId,
|
|
103
|
+
timestamp: createIsoTimestamp(this.now),
|
|
104
|
+
message: messageSnapshot,
|
|
105
|
+
};
|
|
106
|
+
await appendSessionEntry(this.filePath, entry, expectedParentId, this.appendOptions);
|
|
107
|
+
this.sessionEntries.push(structuredClone(entry));
|
|
108
|
+
return structuredClone(entry);
|
|
109
|
+
});
|
|
110
|
+
this.appendQueue = operation.then(() => undefined, () => undefined);
|
|
111
|
+
return operation;
|
|
112
|
+
}
|
|
113
|
+
appendSummary(input) {
|
|
114
|
+
const inputSnapshot = structuredClone(input);
|
|
115
|
+
const operation = this.appendQueue.then(async () => {
|
|
116
|
+
await this.ensureFileCreated();
|
|
117
|
+
const id = this.createId();
|
|
118
|
+
assertRecordId(id);
|
|
119
|
+
const expectedParentId = this.leafId;
|
|
120
|
+
const entry = {
|
|
121
|
+
type: "summary",
|
|
122
|
+
version: SESSION_FORMAT_VERSION,
|
|
123
|
+
id,
|
|
124
|
+
parentId: expectedParentId,
|
|
125
|
+
timestamp: createIsoTimestamp(this.now),
|
|
126
|
+
summary: inputSnapshot.summary,
|
|
127
|
+
firstKeptEntryId: inputSnapshot.firstKeptEntryId,
|
|
128
|
+
tokensBefore: inputSnapshot.tokensBefore,
|
|
129
|
+
};
|
|
130
|
+
await appendSessionEntry(this.filePath, entry, expectedParentId, this.appendOptions);
|
|
131
|
+
this.sessionEntries.push(structuredClone(entry));
|
|
132
|
+
return structuredClone(entry);
|
|
133
|
+
});
|
|
134
|
+
this.appendQueue = operation.then(() => undefined, () => undefined);
|
|
135
|
+
return operation;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=session-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../../src/core/session/session-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { resolve } from \"node:path\";\nimport type { Message } from \"@di-code/ai\";\nimport {\n\tappendSessionEntry,\n\tcreateSessionFile,\n\tloadSessionFile,\n\ttype SessionAppendOptions,\n} from \"./session-storage.ts\";\nimport {\n\ttype LoadedSession,\n\tSESSION_FORMAT_VERSION,\n\ttype SessionDiagnostic,\n\ttype SessionEntry,\n\ttype SessionHeader,\n\ttype SessionMessageEntry,\n\ttype SessionSummaryEntry,\n} from \"./types.ts\";\n\nexport interface SessionManagerCreateOptions {\n\treadonly filePath: string;\n\treadonly cwd: string;\n\treadonly now?: () => number;\n\treadonly createId?: () => string;\n\treadonly appendOptions?: SessionAppendOptions;\n\treadonly deferCreate?: boolean;\n}\n\nexport interface SessionManagerOpenOptions {\n\treadonly now?: () => number;\n\treadonly createId?: () => string;\n\treadonly appendOptions?: SessionAppendOptions;\n}\n\nfunction assertRecordId(id: string): void {\n\tif (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(id)) {\n\t\tthrow new Error(`Generated session record id is invalid: ${JSON.stringify(id)}.`);\n\t}\n}\n\nfunction createIsoTimestamp(now: () => number): string {\n\tconst milliseconds = now();\n\tif (!Number.isFinite(milliseconds)) {\n\t\tthrow new Error(\"Session clock must return a finite Unix millisecond timestamp.\");\n\t}\n\treturn new Date(milliseconds).toISOString();\n}\n\nexport class SessionManager {\n\treadonly filePath: string;\n\tprivate readonly sessionHeader: SessionHeader;\n\tprivate readonly now: () => number;\n\tprivate readonly createId: () => string;\n\tprivate readonly appendOptions: SessionAppendOptions;\n\tprivate readonly sessionEntries: SessionEntry[];\n\tprivate readonly sessionDiagnostics: SessionDiagnostic[];\n\tprivate fileCreated: boolean;\n\tprivate appendQueue: Promise<void> = Promise.resolve();\n\n\tprivate constructor(filePath: string, loaded: LoadedSession, options: SessionManagerOpenOptions, fileCreated = true) {\n\t\tthis.filePath = filePath;\n\t\tthis.sessionHeader = structuredClone(loaded.header);\n\t\tthis.sessionEntries = structuredClone([...loaded.entries]);\n\t\tthis.sessionDiagnostics = structuredClone([...loaded.diagnostics]);\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.createId = options.createId ?? randomUUID;\n\t\tthis.appendOptions = options.appendOptions ?? {};\n\t\tthis.fileCreated = fileCreated;\n\t}\n\n\tstatic async create(options: SessionManagerCreateOptions): Promise<SessionManager> {\n\t\tconst filePath = resolve(options.filePath);\n\t\tconst cwd = resolve(options.cwd);\n\t\tconst now = options.now ?? Date.now;\n\t\tconst createId = options.createId ?? randomUUID;\n\t\tconst id = createId();\n\t\tassertRecordId(id);\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: SESSION_FORMAT_VERSION,\n\t\t\tid,\n\t\t\tparentId: null,\n\t\t\ttimestamp: createIsoTimestamp(now),\n\t\t\tcwd,\n\t\t};\n\t\tif (!options.deferCreate) await createSessionFile(filePath, header);\n\t\treturn new SessionManager(\n\t\t\tfilePath,\n\t\t\t{ header, entries: [], messages: [], diagnostics: [] },\n\t\t\t{ now, createId, appendOptions: options.appendOptions },\n\t\t\t!options.deferCreate,\n\t\t);\n\t}\n\n\tstatic async open(filePath: string, options: SessionManagerOpenOptions = {}): Promise<SessionManager> {\n\t\tconst resolvedPath = resolve(filePath);\n\t\treturn new SessionManager(resolvedPath, await loadSessionFile(resolvedPath), options);\n\t}\n\n\tget entries(): readonly SessionEntry[] {\n\t\treturn structuredClone(this.sessionEntries);\n\t}\n\n\tget header(): SessionHeader {\n\t\treturn structuredClone(this.sessionHeader);\n\t}\n\n\tget messages(): readonly Message[] {\n\t\treturn structuredClone(\n\t\t\tthis.sessionEntries\n\t\t\t\t.filter((entry): entry is SessionMessageEntry => entry.type === \"message\")\n\t\t\t\t.map((entry) => entry.message),\n\t\t);\n\t}\n\n\tget latestSummary(): SessionSummaryEntry | undefined {\n\t\tfor (let index = this.sessionEntries.length - 1; index >= 0; index--) {\n\t\t\tconst entry = this.sessionEntries[index];\n\t\t\tif (entry?.type === \"summary\") return structuredClone(entry);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tget diagnostics(): readonly SessionDiagnostic[] {\n\t\treturn structuredClone(this.sessionDiagnostics);\n\t}\n\n\tget leafId(): string {\n\t\treturn this.sessionEntries.at(-1)?.id ?? this.sessionHeader.id;\n\t}\n\n\tprivate async ensureFileCreated(): Promise<void> {\n\t\tif (this.fileCreated) return;\n\t\tawait createSessionFile(this.filePath, this.sessionHeader);\n\t\tthis.fileCreated = true;\n\t}\n\n\tappendMessage(message: Message): Promise<SessionMessageEntry> {\n\t\tconst messageSnapshot = structuredClone(message);\n\t\tconst operation = this.appendQueue.then(async () => {\n\t\t\tawait this.ensureFileCreated();\n\t\t\tconst id = this.createId();\n\t\t\tassertRecordId(id);\n\t\t\tconst expectedParentId = this.leafId;\n\t\t\tconst entry: SessionMessageEntry = {\n\t\t\t\ttype: \"message\",\n\t\t\t\tversion: SESSION_FORMAT_VERSION,\n\t\t\t\tid,\n\t\t\t\tparentId: expectedParentId,\n\t\t\t\ttimestamp: createIsoTimestamp(this.now),\n\t\t\t\tmessage: messageSnapshot,\n\t\t\t};\n\t\t\tawait appendSessionEntry(this.filePath, entry, expectedParentId, this.appendOptions);\n\t\t\tthis.sessionEntries.push(structuredClone(entry));\n\t\t\treturn structuredClone(entry);\n\t\t});\n\n\t\tthis.appendQueue = operation.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn operation;\n\t}\n\n\tappendSummary(input: {\n\t\treadonly summary: string;\n\t\treadonly firstKeptEntryId: string;\n\t\treadonly tokensBefore: number;\n\t}): Promise<SessionSummaryEntry> {\n\t\tconst inputSnapshot = structuredClone(input);\n\t\tconst operation = this.appendQueue.then(async () => {\n\t\t\tawait this.ensureFileCreated();\n\t\t\tconst id = this.createId();\n\t\t\tassertRecordId(id);\n\t\t\tconst expectedParentId = this.leafId;\n\t\t\tconst entry: SessionSummaryEntry = {\n\t\t\t\ttype: \"summary\",\n\t\t\t\tversion: SESSION_FORMAT_VERSION,\n\t\t\t\tid,\n\t\t\t\tparentId: expectedParentId,\n\t\t\t\ttimestamp: createIsoTimestamp(this.now),\n\t\t\t\tsummary: inputSnapshot.summary,\n\t\t\t\tfirstKeptEntryId: inputSnapshot.firstKeptEntryId,\n\t\t\t\ttokensBefore: inputSnapshot.tokensBefore,\n\t\t\t};\n\t\t\tawait appendSessionEntry(this.filePath, entry, expectedParentId, this.appendOptions);\n\t\t\tthis.sessionEntries.push(structuredClone(entry));\n\t\t\treturn structuredClone(entry);\n\t\t});\n\n\t\tthis.appendQueue = operation.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn operation;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type LoadedSession, type SessionEntry, type SessionHeader } from "./types.ts";
|
|
2
|
+
export declare function loadSessionFile(filePath: string): Promise<LoadedSession>;
|
|
3
|
+
export interface SessionAppendOptions {
|
|
4
|
+
readonly lockTimeoutMs?: number;
|
|
5
|
+
readonly lockRetryMs?: number;
|
|
6
|
+
readonly now?: () => number;
|
|
7
|
+
readonly sleep?: (milliseconds: number) => Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare function createSessionFile(filePath: string, header: SessionHeader): Promise<void>;
|
|
10
|
+
export declare function appendSessionEntry(filePath: string, entry: SessionEntry, expectedParentId: string, options?: SessionAppendOptions): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=session-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-storage.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-storage.ts"],"names":[],"mappings":"AAGA,OAAO,EACN,KAAK,aAAa,EAElB,KAAK,YAAY,EACjB,KAAK,aAAa,EAKlB,MAAM,YAAY,CAAC;AA4MpB,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA+E9E;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAaD,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9F;AA8CD,wBAAsB,kBAAkB,CACvC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,YAAY,EACnB,gBAAgB,EAAE,MAAM,EACxB,OAAO,GAAE,oBAAyB,GAChC,OAAO,CAAC,IAAI,CAAC,CAkFf"}
|