@averyyy/pi-server 0.87.1-piclient.1 → 0.87.1-piclient.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/CHANGELOG.md CHANGED
@@ -38,6 +38,7 @@
38
38
  - Updated pi-server runtime dependencies to the current lockstep fork packages.
39
39
  - Used `--legacy-peer-deps` for npm-global fork updates so existing upstream Pi installs do not trigger peer override warnings for forked prerelease aliases.
40
40
  - Increased the pending chunk budget to 1 GiB so large session-tree appends do not fail at the previous 64 MiB Base64 limit.
41
+ - Reused authoritative prompt prefixes for eligible server-side compaction summaries while retaining chunked handling for mismatched or oversized contexts.
41
42
 
42
43
  ### Changed
43
44
 
@@ -1,10 +1,11 @@
1
1
  import type { SessionTreeEntry } from "@earendil-works/pi-agent-core";
2
- import type { Tool } from "@earendil-works/pi-ai";
2
+ import type { Message, Tool } from "@earendil-works/pi-ai";
3
3
  export interface PiServerStaticContext {
4
4
  systemPrompt?: string;
5
5
  tools?: Tool[];
6
6
  }
7
7
  export declare function hashPiServerStaticContext(context: PiServerStaticContext | undefined): string;
8
+ export declare function hashPiServerProviderMessages(messages: readonly Message[]): string;
8
9
  export declare const PI_SERVER_EMPTY_TREE_HASH: string;
9
10
  export declare function hashPiServerTreeEntry(entry: SessionTreeEntry): string;
10
11
  export declare function appendPiServerTreeHash(previousHash: string, entryHash: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"pi-server-protocol.d.ts","sourceRoot":"","sources":["../src/pi-server-protocol.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAElD,MAAM,WAAW,qBAAqB;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;CACf;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,qBAAqB,GAAG,SAAS,GAAG,MAAM,CAW5F;AAED,eAAO,MAAM,yBAAyB,QAA0D,CAAC;AAEjG,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAErE;AAED,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtF;AAED,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,MAAM,EAAE,CAMnF;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAE9E","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { SessionTreeEntry } from \"@earendil-works/pi-agent-core\";\nimport type { Tool } from \"@earendil-works/pi-ai\";\n\nexport interface PiServerStaticContext {\n\tsystemPrompt?: string;\n\ttools?: Tool[];\n}\n\nexport function hashPiServerStaticContext(context: PiServerStaticContext | undefined): string {\n\tif (!context) return \"\";\n\tconst canonical = {\n\t\tsystemPrompt: context.systemPrompt,\n\t\ttools: context.tools?.map((tool) => ({\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: tool.parameters,\n\t\t})),\n\t};\n\treturn createHash(\"sha256\").update(JSON.stringify(canonical)).digest(\"hex\");\n}\n\nexport const PI_SERVER_EMPTY_TREE_HASH = createHash(\"sha256\").update(\"pi-tree-v1\").digest(\"hex\");\n\nexport function hashPiServerTreeEntry(entry: SessionTreeEntry): string {\n\treturn createHash(\"sha256\").update(JSON.stringify(entry)).digest(\"hex\");\n}\n\nexport function appendPiServerTreeHash(previousHash: string, entryHash: string): string {\n\treturn createHash(\"sha256\").update(`${previousHash}:${entryHash}`).digest(\"hex\");\n}\n\nexport function buildPiServerTreePrefixHashes(entries: SessionTreeEntry[]): string[] {\n\tconst hashes = [PI_SERVER_EMPTY_TREE_HASH];\n\tfor (const entry of entries) {\n\t\thashes.push(appendPiServerTreeHash(hashes[hashes.length - 1], hashPiServerTreeEntry(entry)));\n\t}\n\treturn hashes;\n}\n\nexport function hashPiServerSessionEntries(entries: SessionTreeEntry[]): string {\n\treturn buildPiServerTreePrefixHashes(entries)[entries.length];\n}\n"]}
1
+ {"version":3,"file":"pi-server-protocol.d.ts","sourceRoot":"","sources":["../src/pi-server-protocol.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAE3D,MAAM,WAAW,qBAAqB;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;CACf;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,qBAAqB,GAAG,SAAS,GAAG,MAAM,CAW5F;AAeD,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAIjF;AAED,eAAO,MAAM,yBAAyB,QAA0D,CAAC;AAEjG,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAErE;AAED,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtF;AAED,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,MAAM,EAAE,CAMnF;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAE9E","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { SessionTreeEntry } from \"@earendil-works/pi-agent-core\";\nimport type { Message, Tool } from \"@earendil-works/pi-ai\";\n\nexport interface PiServerStaticContext {\n\tsystemPrompt?: string;\n\ttools?: Tool[];\n}\n\nexport function hashPiServerStaticContext(context: PiServerStaticContext | undefined): string {\n\tif (!context) return \"\";\n\tconst canonical = {\n\t\tsystemPrompt: context.systemPrompt,\n\t\ttools: context.tools?.map((tool) => ({\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: tool.parameters,\n\t\t})),\n\t};\n\treturn createHash(\"sha256\").update(JSON.stringify(canonical)).digest(\"hex\");\n}\n\nfunction canonicalizeJson(value: unknown): unknown {\n\tif (Array.isArray(value)) return value.map(canonicalizeJson);\n\tif (value && typeof value === \"object\") {\n\t\tconst record = value as Record<string, unknown>;\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(record)\n\t\t\t\t.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))\n\t\t\t\t.map(([key, item]) => [key, canonicalizeJson(item)]),\n\t\t);\n\t}\n\treturn value;\n}\n\nexport function hashPiServerProviderMessages(messages: readonly Message[]): string {\n\treturn createHash(\"sha256\")\n\t\t.update(JSON.stringify(canonicalizeJson(messages)))\n\t\t.digest(\"hex\");\n}\n\nexport const PI_SERVER_EMPTY_TREE_HASH = createHash(\"sha256\").update(\"pi-tree-v1\").digest(\"hex\");\n\nexport function hashPiServerTreeEntry(entry: SessionTreeEntry): string {\n\treturn createHash(\"sha256\").update(JSON.stringify(entry)).digest(\"hex\");\n}\n\nexport function appendPiServerTreeHash(previousHash: string, entryHash: string): string {\n\treturn createHash(\"sha256\").update(`${previousHash}:${entryHash}`).digest(\"hex\");\n}\n\nexport function buildPiServerTreePrefixHashes(entries: SessionTreeEntry[]): string[] {\n\tconst hashes = [PI_SERVER_EMPTY_TREE_HASH];\n\tfor (const entry of entries) {\n\t\thashes.push(appendPiServerTreeHash(hashes[hashes.length - 1], hashPiServerTreeEntry(entry)));\n\t}\n\treturn hashes;\n}\n\nexport function hashPiServerSessionEntries(entries: SessionTreeEntry[]): string {\n\treturn buildPiServerTreePrefixHashes(entries)[entries.length];\n}\n"]}
@@ -12,6 +12,22 @@ export function hashPiServerStaticContext(context) {
12
12
  };
13
13
  return createHash("sha256").update(JSON.stringify(canonical)).digest("hex");
14
14
  }
15
+ function canonicalizeJson(value) {
16
+ if (Array.isArray(value))
17
+ return value.map(canonicalizeJson);
18
+ if (value && typeof value === "object") {
19
+ const record = value;
20
+ return Object.fromEntries(Object.entries(record)
21
+ .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
22
+ .map(([key, item]) => [key, canonicalizeJson(item)]));
23
+ }
24
+ return value;
25
+ }
26
+ export function hashPiServerProviderMessages(messages) {
27
+ return createHash("sha256")
28
+ .update(JSON.stringify(canonicalizeJson(messages)))
29
+ .digest("hex");
30
+ }
15
31
  export const PI_SERVER_EMPTY_TREE_HASH = createHash("sha256").update("pi-tree-v1").digest("hex");
16
32
  export function hashPiServerTreeEntry(entry) {
17
33
  return createHash("sha256").update(JSON.stringify(entry)).digest("hex");
@@ -1 +1 @@
1
- {"version":3,"file":"pi-server-protocol.js","sourceRoot":"","sources":["../src/pi-server-protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AASzC,MAAM,UAAU,yBAAyB,CAAC,OAA0C,EAAU;IAC7F,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,MAAM,SAAS,GAAG;QACjB,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACpC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC,CAAC;KACH,CAAC;IACF,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAAA,CAC5E;AAED,MAAM,CAAC,MAAM,yBAAyB,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAEjG,MAAM,UAAU,qBAAqB,CAAC,KAAuB,EAAU;IACtE,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAAA,CACxE;AAED,MAAM,UAAU,sBAAsB,CAAC,YAAoB,EAAE,SAAiB,EAAU;IACvF,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,YAAY,IAAI,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAAA,CACjF;AAED,MAAM,UAAU,6BAA6B,CAAC,OAA2B,EAAY;IACpF,MAAM,MAAM,GAAG,CAAC,yBAAyB,CAAC,CAAC;IAC3C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACd;AAED,MAAM,UAAU,0BAA0B,CAAC,OAA2B,EAAU;IAC/E,OAAO,6BAA6B,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AAAA,CAC9D","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { SessionTreeEntry } from \"@earendil-works/pi-agent-core\";\nimport type { Tool } from \"@earendil-works/pi-ai\";\n\nexport interface PiServerStaticContext {\n\tsystemPrompt?: string;\n\ttools?: Tool[];\n}\n\nexport function hashPiServerStaticContext(context: PiServerStaticContext | undefined): string {\n\tif (!context) return \"\";\n\tconst canonical = {\n\t\tsystemPrompt: context.systemPrompt,\n\t\ttools: context.tools?.map((tool) => ({\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: tool.parameters,\n\t\t})),\n\t};\n\treturn createHash(\"sha256\").update(JSON.stringify(canonical)).digest(\"hex\");\n}\n\nexport const PI_SERVER_EMPTY_TREE_HASH = createHash(\"sha256\").update(\"pi-tree-v1\").digest(\"hex\");\n\nexport function hashPiServerTreeEntry(entry: SessionTreeEntry): string {\n\treturn createHash(\"sha256\").update(JSON.stringify(entry)).digest(\"hex\");\n}\n\nexport function appendPiServerTreeHash(previousHash: string, entryHash: string): string {\n\treturn createHash(\"sha256\").update(`${previousHash}:${entryHash}`).digest(\"hex\");\n}\n\nexport function buildPiServerTreePrefixHashes(entries: SessionTreeEntry[]): string[] {\n\tconst hashes = [PI_SERVER_EMPTY_TREE_HASH];\n\tfor (const entry of entries) {\n\t\thashes.push(appendPiServerTreeHash(hashes[hashes.length - 1], hashPiServerTreeEntry(entry)));\n\t}\n\treturn hashes;\n}\n\nexport function hashPiServerSessionEntries(entries: SessionTreeEntry[]): string {\n\treturn buildPiServerTreePrefixHashes(entries)[entries.length];\n}\n"]}
1
+ {"version":3,"file":"pi-server-protocol.js","sourceRoot":"","sources":["../src/pi-server-protocol.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { SessionTreeEntry } from \"@earendil-works/pi-agent-core\";\nimport type { Message, Tool } from \"@earendil-works/pi-ai\";\n\nexport interface PiServerStaticContext {\n\tsystemPrompt?: string;\n\ttools?: Tool[];\n}\n\nexport function hashPiServerStaticContext(context: PiServerStaticContext | undefined): string {\n\tif (!context) return \"\";\n\tconst canonical = {\n\t\tsystemPrompt: context.systemPrompt,\n\t\ttools: context.tools?.map((tool) => ({\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tparameters: tool.parameters,\n\t\t})),\n\t};\n\treturn createHash(\"sha256\").update(JSON.stringify(canonical)).digest(\"hex\");\n}\n\nfunction canonicalizeJson(value: unknown): unknown {\n\tif (Array.isArray(value)) return value.map(canonicalizeJson);\n\tif (value && typeof value === \"object\") {\n\t\tconst record = value as Record<string, unknown>;\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(record)\n\t\t\t\t.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))\n\t\t\t\t.map(([key, item]) => [key, canonicalizeJson(item)]),\n\t\t);\n\t}\n\treturn value;\n}\n\nexport function hashPiServerProviderMessages(messages: readonly Message[]): string {\n\treturn createHash(\"sha256\")\n\t\t.update(JSON.stringify(canonicalizeJson(messages)))\n\t\t.digest(\"hex\");\n}\n\nexport const PI_SERVER_EMPTY_TREE_HASH = createHash(\"sha256\").update(\"pi-tree-v1\").digest(\"hex\");\n\nexport function hashPiServerTreeEntry(entry: SessionTreeEntry): string {\n\treturn createHash(\"sha256\").update(JSON.stringify(entry)).digest(\"hex\");\n}\n\nexport function appendPiServerTreeHash(previousHash: string, entryHash: string): string {\n\treturn createHash(\"sha256\").update(`${previousHash}:${entryHash}`).digest(\"hex\");\n}\n\nexport function buildPiServerTreePrefixHashes(entries: SessionTreeEntry[]): string[] {\n\tconst hashes = [PI_SERVER_EMPTY_TREE_HASH];\n\tfor (const entry of entries) {\n\t\thashes.push(appendPiServerTreeHash(hashes[hashes.length - 1], hashPiServerTreeEntry(entry)));\n\t}\n\treturn hashes;\n}\n\nexport function hashPiServerSessionEntries(entries: SessionTreeEntry[]): string {\n\treturn buildPiServerTreePrefixHashes(entries)[entries.length];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,IAAI,UAAU,EAA6C,MAAM,WAAW,CAAC;AAY/G,OAAO,EAGN,KAAK,OAAO,EAGZ,KAAK,OAAO,EACZ,KAAK,KAAK,EAEV,KAAK,mBAAmB,EACxB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOhD,OAAO,EAWN,KAAK,YAAY,EACjB,KAAK,oBAAoB,EAGzB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAc5D,UAAU,iBAAiB;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,iBAAiB,CAAC,EAAE,OAAO,EAAE,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,EAAE,CAAC;CAC3B;AA+4BD,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,GAAG,mBAAmB,CAAC,GACnE,OAAO,CAOT;AAoMD,wBAAgB,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,UAAU,CAoIjF;AAqED,wBAAgB,WAAW,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,UAAU,CAU9E","sourcesContent":["import { createServer, type Server as HttpServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { createRequire } from \"node:module\";\nimport {\n\ttype CompactionPreparationOptions,\n\ttype CompactionSettings,\n\tcompactLegacy,\n\tDEFAULT_COMPACTION_SETTINGS,\n\ttype LegacyCompactResult,\n\ttype ProxyAssistantMessageEvent,\n\tprepareLegacyCompaction,\n\ttype SessionTreeEntry,\n} from \"@earendil-works/pi-agent-core\";\nimport {\n\ttype AssistantMessage,\n\ttype AssistantMessageEvent,\n\ttype Context,\n\tcreateModels,\n\tcreateProvider,\n\ttype Message,\n\ttype Model,\n\ttype ProviderStreams,\n\ttype SimpleStreamOptions,\n} from \"@earendil-works/pi-ai\";\nimport { streamSimple } from \"@earendil-works/pi-ai/compat\";\nimport type { ServerConfig } from \"./config.ts\";\nimport { loadConfig } from \"./config.ts\";\nimport { PiServerError, PiServerErrorCode, type PiServerErrorResponse } from \"./error-codes.ts\";\nimport { encodeErrorEvent, encodeProxyEvent } from \"./event-encoding.ts\";\nimport { ReceiveUploadError, receiveUpload } from \"./receive-upload.ts\";\nimport { CHUNK_ENDPOINT, type RequestChunkBody, receiveRequestChunk } from \"./request-chunks.ts\";\nimport { deletePersistedSession, loadPersistedSessions, savePersistedSession } from \"./session-persistence.ts\";\nimport {\n\tappendCompactionEntry,\n\tappendMessages,\n\tappendSessionEntries,\n\tdeleteSession as deleteSessionFromStore,\n\tgetOrCreateSession,\n\tgetSession,\n\tgetSessionBranch,\n\tlistSessions,\n\treplaceMessages,\n\treplaceSessionTree,\n\ttype SessionState,\n\ttype SessionStaticContext,\n\tsetStaticContext,\n\tswitchSessionLeaf,\n} from \"./session-store.ts\";\n\nexport { loadConfig, type ServerConfig } from \"./config.ts\";\n\ninterface PackageMetadata {\n\tversion: string;\n}\n\nconst packageMetadata = createRequire(import.meta.url)(\"../package.json\") as PackageMetadata;\nconst PI_SERVER_VERSION = packageMetadata.version;\n\ninterface SessionInitBody {\n\tsessionId: string;\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface StreamRequestBody {\n\tsessionId: string;\n\trunId?: string;\n\tmodel: Model<any>;\n\toptions?: SimpleStreamOptions;\n\tstaticContext?: SessionStaticContext;\n\tephemeralMessages?: Message[];\n\tcontextOverlay?: Message[];\n}\n\ninterface SessionSyncBody {\n\tsessionId: string;\n\tmessages: Message[];\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface SessionAppendBody {\n\tsessionId: string;\n\tmessages: Message[];\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface SessionTreeSyncBody {\n\tsessionId: string;\n\tentries: SessionTreeEntry[];\n\tleafId: string | null;\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface SessionTreeSwitchBody {\n\tsessionId: string;\n\tleafId: string | null;\n}\n\ninterface SessionCompactBody {\n\tsessionId: string;\n\trunId?: string;\n\tmodel: Model<any>;\n\toptions?: SimpleStreamOptions;\n\tsettings?: CompactionSettings;\n\tpreparation?: CompactionPreparationOptions;\n\tcustomInstructions?: string;\n\tbaseTreeHash?: string;\n\tfullResponse?: boolean;\n\tstreamResponse?: boolean;\n}\n\nfunction createRequestModels(model: Model<any>, options: SimpleStreamOptions) {\n\tconst models = createModels();\n\tconst requestStream: ProviderStreams[\"streamSimple\"] = (requestModel, context, streamOptions) =>\n\t\tstreamSimple(requestModel, context, {\n\t\t\t...streamOptions,\n\t\t\t...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n\t\t});\n\tmodels.setProvider(\n\t\tcreateProvider({\n\t\t\tid: model.provider,\n\t\t\tname: model.provider,\n\t\t\tmodels: [model],\n\t\t\tauth: {\n\t\t\t\tapiKey: {\n\t\t\t\t\tname: \"pi-server request auth\",\n\t\t\t\t\tresolve: async () => ({ auth: { apiKey: options.apiKey, headers: options.headers } }),\n\t\t\t\t},\n\t\t\t},\n\t\t\tapi: {\n\t\t\t\tstream: requestStream,\n\t\t\t\tstreamSimple: requestStream,\n\t\t\t},\n\t\t}),\n\t);\n\treturn models;\n}\n\ninterface StreamRunRecord {\n\tsessionId: string;\n\trunId: string;\n\tkind: \"stream\" | \"compact\";\n\tstatus: \"running\" | \"completed\" | \"failed\" | \"aborted\";\n\tmessage?: AssistantMessage;\n\tcompactResult?: SessionCompactSuccessBody;\n\terrorMessage?: string;\n\tcreatedAt: number;\n\tupdatedAt: number;\n\tcancelRequested: boolean;\n\tcontroller: AbortController;\n\tsettled: Promise<void>;\n\tresolveSettled: (() => void) | undefined;\n}\n\nconst STREAM_HEARTBEAT = \": keep-alive\\n\\n\";\nconst JSON_HEARTBEAT = \" \\n\";\nconst STREAM_HEARTBEAT_INTERVAL_MS = 25_000;\nconst STREAM_RUN_TTL_MS = 60 * 60 * 1000; // 1 hour\nconst streamRuns = new Map<string, StreamRunRecord>();\n\nfunction readBody(req: IncomingMessage): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst chunks: Buffer[] = [];\n\t\treq.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n\t\treq.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf-8\")));\n\t\treq.on(\"error\", reject);\n\t});\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n\tconst data = JSON.stringify(body);\n\tres.writeHead(status, { \"Content-Type\": \"application/json\", \"Content-Length\": Buffer.byteLength(data) });\n\tres.end(data);\n}\n\nfunction sendError(\n\tres: ServerResponse,\n\tstatus: number,\n\tmessage: string,\n\tcode?: PiServerErrorCode,\n\tdetails?: Record<string, unknown>,\n): void {\n\tconst body: PiServerErrorResponse = { error: message };\n\tif (code) body.code = code;\n\tif (details) body.details = details;\n\tsendJson(res, status, body);\n}\n\nfunction logRequestError(req: IncomingMessage, error: unknown): void {\n\tconst message = error instanceof Error ? error.stack || error.message : String(error);\n\tconsole.error(`${req.method ?? \"UNKNOWN\"} ${req.url ?? \"/\"} failed: ${message}`);\n}\n\nfunction authenticate(config: ServerConfig, req: IncomingMessage): boolean {\n\tif (!config.authToken) return true;\n\tconst header = req.headers.authorization;\n\tif (!header) return false;\n\tconst token = header.startsWith(\"Bearer \") ? header.slice(7) : header;\n\treturn token === config.authToken;\n}\n\nfunction sessionResponseBody(session: SessionState) {\n\treturn {\n\t\tsessionId: session.sessionId,\n\t\tstaticContextHash: session.staticContextHash,\n\t\ttreeHash: session.treeHash,\n\t\tmessageCount: session.messages.length,\n\t\tentryCount: session.entries.length,\n\t\tleafId: session.leafId,\n\t\trevision: session.revision,\n\t};\n}\n\nfunction persistSession(config: ServerConfig, session: SessionState): void {\n\tsavePersistedSession(config.sessionStoreDir, session);\n}\n\nfunction runKey(sessionId: string, runId: string): string {\n\treturn `${sessionId}\\0${runId}`;\n}\n\nfunction getStreamRun(sessionId: string, runId: string): StreamRunRecord | undefined {\n\treturn streamRuns.get(runKey(sessionId, runId));\n}\n\nfunction createRunRecord(sessionId: string, runId: string, kind: StreamRunRecord[\"kind\"]): StreamRunRecord {\n\tlet resolveSettled: (() => void) | undefined;\n\tconst settled = new Promise<void>((resolve) => {\n\t\tresolveSettled = resolve;\n\t});\n\treturn {\n\t\tsessionId,\n\t\trunId,\n\t\tkind,\n\t\tstatus: \"running\",\n\t\tcreatedAt: Date.now(),\n\t\tupdatedAt: Date.now(),\n\t\tcancelRequested: false,\n\t\tcontroller: new AbortController(),\n\t\tsettled,\n\t\tresolveSettled,\n\t};\n}\n\nfunction settleRun(run: StreamRunRecord | undefined): void {\n\tif (!run) return;\n\tconst resolve = run.resolveSettled;\n\trun.resolveSettled = undefined;\n\tresolve?.();\n}\n\nfunction startStreamRun(sessionId: string, runId: string, kind: StreamRunRecord[\"kind\"] = \"stream\"): StreamRunRecord {\n\tconst existing = getStreamRun(sessionId, runId);\n\tif (existing?.status === \"completed\" || existing?.status === \"aborted\") return existing;\n\tconst run = existing ?? createRunRecord(sessionId, runId, kind);\n\tif (existing) {\n\t\trun.message = undefined;\n\t\trun.errorMessage = undefined;\n\t\trun.cancelRequested = false;\n\t\trun.controller = new AbortController();\n\t\tlet resolveSettled: (() => void) | undefined;\n\t\trun.settled = new Promise<void>((resolve) => {\n\t\t\tresolveSettled = resolve;\n\t\t});\n\t\trun.resolveSettled = resolveSettled;\n\t}\n\trun.kind = kind;\n\trun.status = \"running\";\n\trun.updatedAt = Date.now();\n\tstreamRuns.set(runKey(sessionId, runId), run);\n\treturn run;\n}\n\nfunction streamRunResponseBody(run: StreamRunRecord) {\n\treturn {\n\t\tsessionId: run.sessionId,\n\t\trunId: run.runId,\n\t\tstatus: run.status,\n\t\tcreatedAt: run.createdAt,\n\t\tupdatedAt: run.updatedAt,\n\t\t...(run.message ? { message: run.message } : {}),\n\t\t...(run.compactResult ? { compactResult: run.compactResult } : {}),\n\t\t...(run.errorMessage ? { errorMessage: run.errorMessage } : {}),\n\t};\n}\n\nfunction replayStreamRun(run: StreamRunRecord): ProxyAssistantMessageEvent[] {\n\tif (!run.message) return [];\n\tif (\n\t\trun.message.stopReason !== \"stop\" &&\n\t\trun.message.stopReason !== \"length\" &&\n\t\trun.message.stopReason !== \"toolUse\" &&\n\t\trun.message.stopReason !== \"deferred\"\n\t) {\n\t\treturn [];\n\t}\n\tconst events: ProxyAssistantMessageEvent[] = [{ type: \"start\" }];\n\tfor (const [contentIndex, content] of run.message.content.entries()) {\n\t\tswitch (content.type) {\n\t\t\tcase \"text\":\n\t\t\t\tevents.push(\n\t\t\t\t\t{ type: \"text_start\", contentIndex },\n\t\t\t\t\t{ type: \"text_delta\", contentIndex, delta: content.text },\n\t\t\t\t\t{ type: \"text_end\", contentIndex, contentSignature: content.textSignature },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"thinking\":\n\t\t\t\tevents.push(\n\t\t\t\t\t{ type: \"thinking_start\", contentIndex },\n\t\t\t\t\t{ type: \"thinking_delta\", contentIndex, delta: content.thinking },\n\t\t\t\t\t{ type: \"thinking_end\", contentIndex, contentSignature: content.thinkingSignature },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"toolCall\":\n\t\t\t\tevents.push(\n\t\t\t\t\t{ type: \"toolcall_start\", contentIndex, id: content.id, toolName: content.name },\n\t\t\t\t\t{ type: \"toolcall_delta\", contentIndex, delta: JSON.stringify(content.arguments) },\n\t\t\t\t\t{ type: \"toolcall_end\", contentIndex, toolCall: content },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tevents.push({\n\t\ttype: \"done\",\n\t\treason: run.message.stopReason,\n\t\tusage: run.message.usage,\n\t\tdeferred: run.message.deferred,\n\t\tmessage: run.message,\n\t});\n\treturn events;\n}\n\nfunction completeStreamRun(run: StreamRunRecord | undefined, message: AssistantMessage): void {\n\tif (!run) return;\n\tif (run.cancelRequested) {\n\t\trun.status = \"aborted\";\n\t\trun.message = undefined;\n\t\trun.errorMessage = \"Stream run aborted\";\n\t\trun.updatedAt = Date.now();\n\t\treturn;\n\t}\n\trun.status = \"completed\";\n\trun.message = message;\n\trun.errorMessage = undefined;\n\trun.updatedAt = Date.now();\n}\n\nfunction failStreamRun(run: StreamRunRecord | undefined, errorMessage: string): void {\n\tif (!run) return;\n\tif (run.cancelRequested) {\n\t\trun.status = \"aborted\";\n\t\trun.errorMessage = \"Stream run aborted\";\n\t\trun.updatedAt = Date.now();\n\t\treturn;\n\t}\n\trun.status = \"failed\";\n\trun.errorMessage = errorMessage;\n\trun.updatedAt = Date.now();\n}\n\nfunction touchStreamRun(run: StreamRunRecord | undefined): void {\n\tif (run) run.updatedAt = Date.now();\n}\n\nfunction writeStreamEvent(res: ServerResponse, event: ProxyAssistantMessageEvent): void {\n\tif (!res.writableEnded && !res.destroyed) {\n\t\tres.write(encodeProxyEvent(event));\n\t}\n}\n\nfunction writeStreamError(res: ServerResponse, message: string): void {\n\tif (!res.writableEnded && !res.destroyed) {\n\t\tres.write(encodeErrorEvent(message));\n\t}\n}\n\nfunction endStreamResponse(res: ServerResponse): void {\n\tif (!res.writableEnded && !res.destroyed) {\n\t\tres.end();\n\t}\n}\n\nfunction cleanupExpiredStreamRuns(nowMs: number): void {\n\tfor (const [key, run] of streamRuns) {\n\t\tif (nowMs - run.updatedAt > STREAM_RUN_TTL_MS) {\n\t\t\tstreamRuns.delete(key);\n\t\t}\n\t}\n}\n\nfunction deleteStreamRunsForSession(sessionId: string): void {\n\tfor (const [key, run] of streamRuns) {\n\t\tif (run.sessionId === sessionId) streamRuns.delete(key);\n\t}\n}\n\nconst streamRunCleanupTimer = setInterval(() => cleanupExpiredStreamRuns(Date.now()), STREAM_RUN_TTL_MS / 4);\nstreamRunCleanupTimer.unref();\n\nfunction sessionHistoryFullResponseBody(session: SessionState, baseMessageCount: number) {\n\treturn {\n\t\tsessionId: session.sessionId,\n\t\tstaticContext: session.staticContext,\n\t\tstaticContextHash: session.staticContextHash,\n\t\ttreeHash: session.treeHash,\n\t\tmessageCount: session.messages.length,\n\t\tentryCount: session.entries.length,\n\t\tleafId: session.leafId,\n\t\trevision: session.revision,\n\t\tentries: session.entries,\n\t\tbaseMessageCount,\n\t\tmessages: session.messages.slice(baseMessageCount),\n\t};\n}\n\nfunction sessionTreePatchResponseBody(\n\tsession: SessionState,\n\tbaseMessageCount: number,\n\tentriesFrom: number,\n\tbaseRevision: number | undefined,\n) {\n\treturn {\n\t\tsessionId: session.sessionId,\n\t\tstaticContext: session.staticContext,\n\t\tstaticContextHash: session.staticContextHash,\n\t\ttreeHash: session.treeHash,\n\t\tmessageCount: session.messages.length,\n\t\tentryCount: session.entries.length,\n\t\tleafId: session.leafId,\n\t\trevision: session.revision,\n\t\tbaseMessageCount,\n\t\tmessages: session.messages.slice(baseMessageCount),\n\t\ttreePatch: {\n\t\t\tentriesFrom,\n\t\t\tbaseRevision,\n\t\t\tentries: session.entries.slice(entriesFrom),\n\t\t\tleafId: session.leafId,\n\t\t\trevision: session.revision,\n\t\t},\n\t};\n}\n\ntype PreparedCompaction = Parameters<typeof compactLegacy>[0];\n\ninterface PreparedSessionCompact {\n\tsession: SessionState;\n\tsessionId: string;\n\trevision: number;\n\ttreeHash: string;\n\tleafId: string | null;\n\tentryCount: number;\n\tpreparation: PreparedCompaction;\n\toptions: SimpleStreamOptions;\n}\n\ninterface SessionCompactSuccessBody {\n\tsuccess: true;\n\tcompaction: Omit<LegacyCompactResult, \"retainedTail\">;\n\tcompactionEntry: SessionTreeEntry;\n\tsessionId: string;\n\tstaticContextHash: string;\n\ttreeHash: string;\n\tmessageCount: number;\n\tentryCount: number;\n\tleafId: string | null;\n\trevision: number;\n\tstaticContext?: SessionStaticContext;\n\ttreePatch?: {\n\t\tbaseTreeHash: string;\n\t\tentriesFrom: number;\n\t\tentries: SessionTreeEntry[];\n\t\tleafId: string | null;\n\t\trevision: number;\n\t};\n\tentries?: SessionTreeEntry[];\n\tmessages?: Message[];\n}\n\ninterface SessionCompactHttpResponse {\n\tstatus: number;\n\tbody: PiServerErrorResponse | SessionCompactSuccessBody;\n}\n\nfunction handleSessionInit(config: ServerConfig, body: SessionInitBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t} else {\n\t\tgetOrCreateSession(body.sessionId);\n\t}\n\tconst session = getSession(body.sessionId)!;\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionUpdate(\n\tconfig: ServerConfig,\n\tbody: SessionInitBody & { staticContext: SessionStaticContext },\n\tres: ServerResponse,\n): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!body.staticContext) {\n\t\tsendError(res, 400, \"staticContext is required for update\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tsetStaticContext(body.sessionId, body.staticContext);\n\tconst session = getSession(body.sessionId)!;\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionSync(config: ServerConfig, body: SessionSyncBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.messages)) {\n\t\tsendError(res, 400, \"messages is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t}\n\tconst session = replaceMessages(body.sessionId, body.messages);\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionAppend(config: ServerConfig, body: SessionAppendBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.messages)) {\n\t\tsendError(res, 400, \"messages is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t}\n\tconst session = appendMessages(body.sessionId, body.messages);\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionTreeSync(config: ServerConfig, body: SessionTreeSyncBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.entries)) {\n\t\tsendError(res, 400, \"entries is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t}\n\tconst session = replaceSessionTree(body.sessionId, body.entries, body.leafId ?? null);\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionTreeAppend(config: ServerConfig, body: SessionTreeSyncBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.entries)) {\n\t\tsendError(res, 400, \"entries is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\ttry {\n\t\tif (body.staticContext) {\n\t\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t\t}\n\t\tconst session = appendSessionEntries(body.sessionId, body.entries, body.leafId ?? null);\n\t\tpersistSession(config, session);\n\t\tsendJson(res, 200, sessionResponseBody(session));\n\t} catch (error) {\n\t\tif (error instanceof PiServerError) {\n\t\t\tsendError(res, 400, error.message, error.code, error.details);\n\t\t} else {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tsendError(res, 500, message, PiServerErrorCode.INTERNAL_ERROR);\n\t\t}\n\t}\n}\n\nfunction handleSessionTreeSwitch(config: ServerConfig, body: SessionTreeSwitchBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\ttry {\n\t\tconst session = switchSessionLeaf(body.sessionId, body.leafId ?? null);\n\t\tpersistSession(config, session);\n\t\tsendJson(res, 200, sessionResponseBody(session));\n\t} catch (error) {\n\t\tif (error instanceof PiServerError) {\n\t\t\tsendError(res, 400, error.message, error.code, error.details);\n\t\t} else {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tsendError(res, 500, message, PiServerErrorCode.INTERNAL_ERROR);\n\t\t}\n\t}\n}\n\nfunction prepareSessionCompact(body: SessionCompactBody): PreparedSessionCompact | SessionCompactHttpResponse {\n\tif (!body.sessionId) {\n\t\treturn { status: 400, body: { error: \"sessionId is required\" } };\n\t}\n\tif (!body.model) {\n\t\treturn { status: 400, body: { error: \"model is required\" } };\n\t}\n\n\tconst session = getSession(body.sessionId);\n\tif (!session) {\n\t\treturn { status: 404, body: { error: \"session not found\", code: PiServerErrorCode.SESSION_NOT_FOUND } };\n\t}\n\n\tconst entries = getSessionBranch(session);\n\tconst leaf = entries.at(-1);\n\tif (leaf?.type === \"compaction\") {\n\t\tif (!leaf.firstKeptEntryId) {\n\t\t\treturn { status: 400, body: { error: \"Stored compaction is missing firstKeptEntryId\" } };\n\t\t}\n\t\treturn {\n\t\t\tstatus: 200,\n\t\t\tbody: {\n\t\t\t\tsuccess: true,\n\t\t\t\tcompaction: {\n\t\t\t\t\tsummary: leaf.summary,\n\t\t\t\t\tfirstKeptEntryId: leaf.firstKeptEntryId,\n\t\t\t\t\ttokensBefore: leaf.tokensBefore,\n\t\t\t\t\tdetails: leaf.details,\n\t\t\t\t},\n\t\t\t\tcompactionEntry: leaf,\n\t\t\t\t...sessionResponseBody(session),\n\t\t\t\tentries: session.entries,\n\t\t\t\tmessages: session.messages,\n\t\t\t},\n\t\t};\n\t}\n\tconst preparationResult = prepareLegacyCompaction(\n\t\tentries,\n\t\tbody.settings ?? DEFAULT_COMPACTION_SETTINGS,\n\t\tbody.preparation,\n\t);\n\tif (!preparationResult.ok) {\n\t\treturn { status: 400, body: { error: preparationResult.error.message } };\n\t}\n\tif (!preparationResult.value) {\n\t\treturn { status: 400, body: { error: \"Nothing to compact\" } };\n\t}\n\n\tconst options = body.options ?? {};\n\treturn {\n\t\tsession,\n\t\tsessionId: session.sessionId,\n\t\trevision: session.revision,\n\t\ttreeHash: session.treeHash,\n\t\tleafId: session.leafId,\n\t\tentryCount: session.entries.length,\n\t\tpreparation: preparationResult.value,\n\t\toptions,\n\t};\n}\n\nfunction sessionCompactConflict(\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\tcurrentSession: SessionState | undefined,\n): SessionCompactHttpResponse {\n\treturn {\n\t\tstatus: 409,\n\t\tbody: {\n\t\t\terror: \"Session changed while compaction was running\",\n\t\t\tcode: PiServerErrorCode.SESSION_STATE_CONFLICT,\n\t\t\tdetails: {\n\t\t\t\tsessionId: body.sessionId,\n\t\t\t\texpectedRevision: prepared.revision,\n\t\t\t\texpectedTreeHash: prepared.treeHash,\n\t\t\t\texpectedLeafId: prepared.leafId,\n\t\t\t\tactualRevision: currentSession?.revision ?? null,\n\t\t\t\tactualTreeHash: currentSession?.treeHash ?? null,\n\t\t\t\tactualLeafId: currentSession?.leafId ?? null,\n\t\t\t},\n\t\t},\n\t};\n}\n\nasync function completeSessionCompact(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\trun?: StreamRunRecord,\n): Promise<SessionCompactHttpResponse> {\n\tconst result = await compactLegacy(\n\t\tprepared.preparation,\n\t\tcreateRequestModels(body.model, prepared.options),\n\t\tbody.model,\n\t\tbody.customInstructions,\n\t\trun?.controller.signal,\n\t\tprepared.options.reasoning,\n\t);\n\tif (!result.ok) {\n\t\treturn { status: 500, body: { error: result.error.message, code: PiServerErrorCode.INTERNAL_ERROR } };\n\t}\n\tif (run?.cancelRequested || run?.controller.signal.aborted) {\n\t\treturn { status: 409, body: { error: \"Compaction aborted\", code: PiServerErrorCode.INVALID_REQUEST } };\n\t}\n\n\tconst currentSession = getSession(prepared.sessionId);\n\tif (\n\t\t!currentSession ||\n\t\tcurrentSession !== prepared.session ||\n\t\tcurrentSession.revision !== prepared.revision ||\n\t\tcurrentSession.treeHash !== prepared.treeHash ||\n\t\tcurrentSession.leafId !== prepared.leafId\n\t) {\n\t\treturn sessionCompactConflict(body, prepared, currentSession);\n\t}\n\n\tconst baseTreeHash = prepared.treeHash;\n\tconst baseEntryCount = prepared.entryCount;\n\tconst compaction = result.value;\n\tconst { session: updatedSession, entry: compactionEntry } = appendCompactionEntry(body.sessionId, compaction);\n\tpersistSession(config, updatedSession);\n\tif (!body.fullResponse && body.baseTreeHash === baseTreeHash) {\n\t\treturn {\n\t\t\tstatus: 200,\n\t\t\tbody: {\n\t\t\t\tsuccess: true,\n\t\t\t\tcompaction: compaction satisfies LegacyCompactResult,\n\t\t\t\tcompactionEntry,\n\t\t\t\t...sessionResponseBody(updatedSession),\n\t\t\t\tstaticContext: updatedSession.staticContext,\n\t\t\t\ttreePatch: {\n\t\t\t\t\tbaseTreeHash,\n\t\t\t\t\tentriesFrom: baseEntryCount,\n\t\t\t\t\tentries: [compactionEntry],\n\t\t\t\t\tleafId: updatedSession.leafId,\n\t\t\t\t\trevision: updatedSession.revision,\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\treturn {\n\t\tstatus: 200,\n\t\tbody: {\n\t\t\tsuccess: true,\n\t\t\tcompaction: compaction satisfies LegacyCompactResult,\n\t\t\tcompactionEntry,\n\t\t\t...sessionResponseBody(updatedSession),\n\t\t\tstaticContext: updatedSession.staticContext,\n\t\t\tentries: updatedSession.entries,\n\t\t\tmessages: updatedSession.messages,\n\t\t},\n\t};\n}\n\nfunction writeServerSentEvent(res: ServerResponse, event: string, body: unknown): void {\n\tres.write(`event: ${event}\\n`);\n\tres.write(`data: ${JSON.stringify(body)}\\n\\n`);\n}\n\nasync function handleSessionCompactStream(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\tres: ServerResponse,\n\trun?: StreamRunRecord,\n): Promise<void> {\n\tres.writeHead(200, {\n\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\"Cache-Control\": \"no-cache\",\n\t\tConnection: \"keep-alive\",\n\t});\n\tres.flushHeaders();\n\tres.write(STREAM_HEARTBEAT);\n\n\tconst heartbeat = setInterval(() => {\n\t\ttouchStreamRun(run);\n\t\tif (!res.writableEnded) {\n\t\t\tres.write(STREAM_HEARTBEAT);\n\t\t}\n\t}, STREAM_HEARTBEAT_INTERVAL_MS);\n\theartbeat.unref();\n\n\ttry {\n\t\tconst result = await completeSessionCompact(config, body, prepared, run);\n\t\tfinishCompactRun(run, result);\n\t\twriteServerSentEvent(res, result.status >= 400 ? \"error\" : \"result\", result.body);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tif (run?.status === \"running\") {\n\t\t\trun.status = run.cancelRequested ? \"aborted\" : \"failed\";\n\t\t\trun.errorMessage = message;\n\t\t\trun.updatedAt = Date.now();\n\t\t}\n\t\twriteServerSentEvent(res, \"error\", { error: message });\n\t} finally {\n\t\tclearInterval(heartbeat);\n\t\tsettleRun(run);\n\t\tres.end();\n\t}\n}\n\nasync function handleSessionCompactJsonStream(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\tres: ServerResponse,\n\trun?: StreamRunRecord,\n): Promise<void> {\n\tres.writeHead(200, {\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"Cache-Control\": \"no-cache\",\n\t\tConnection: \"keep-alive\",\n\t});\n\tres.flushHeaders();\n\tres.write(JSON_HEARTBEAT);\n\n\tconst heartbeat = setInterval(() => {\n\t\ttouchStreamRun(run);\n\t\tif (!res.writableEnded) {\n\t\t\tres.write(JSON_HEARTBEAT);\n\t\t}\n\t}, STREAM_HEARTBEAT_INTERVAL_MS);\n\theartbeat.unref();\n\n\ttry {\n\t\tconst result = await completeSessionCompact(config, body, prepared, run);\n\t\tfinishCompactRun(run, result);\n\t\tres.write(JSON.stringify(result.body));\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tif (run?.status === \"running\") {\n\t\t\trun.status = run.cancelRequested ? \"aborted\" : \"failed\";\n\t\t\trun.errorMessage = message;\n\t\t\trun.updatedAt = Date.now();\n\t\t}\n\t\tres.write(JSON.stringify({ error: message }));\n\t} finally {\n\t\tclearInterval(heartbeat);\n\t\tsettleRun(run);\n\t\tres.end();\n\t}\n}\n\nfunction finishCompactRun(run: StreamRunRecord | undefined, result: SessionCompactHttpResponse): void {\n\tif (!run) return;\n\tif (run.cancelRequested || run.controller.signal.aborted) {\n\t\trun.status = \"aborted\";\n\t\trun.errorMessage = \"Compaction aborted\";\n\t} else {\n\t\trun.status = result.status >= 400 ? \"failed\" : \"completed\";\n\t\tif (result.status >= 400 && \"error\" in result.body) {\n\t\t\trun.errorMessage = result.body.error;\n\t\t} else if (\"success\" in result.body) {\n\t\t\trun.compactResult = { ...result.body, entries: result.body.entries?.slice() };\n\t\t}\n\t}\n\trun.updatedAt = Date.now();\n}\n\nasync function handleSessionCompact(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tres: ServerResponse,\n): Promise<void> {\n\tconst existingRun = body.runId ? getStreamRun(body.sessionId, body.runId) : undefined;\n\tif (existingRun?.status === \"aborted\") {\n\t\tsendJson(res, 409, { error: \"Compaction run was aborted\", code: PiServerErrorCode.INVALID_REQUEST });\n\t\treturn;\n\t}\n\tif (existingRun?.status === \"completed\" && existingRun.compactResult) {\n\t\tsendJson(res, 200, existingRun.compactResult);\n\t\treturn;\n\t}\n\tconst prepared = prepareSessionCompact(body);\n\tif (\"status\" in prepared) {\n\t\tsendJson(res, prepared.status, prepared.body);\n\t\treturn;\n\t}\n\n\tlet run: StreamRunRecord | undefined;\n\tif (body.runId) {\n\t\tconst existingRun = getStreamRun(body.sessionId, body.runId);\n\t\tif (existingRun?.status === \"aborted\") {\n\t\t\tsendJson(res, 409, { error: \"Compaction run was aborted\", code: PiServerErrorCode.INVALID_REQUEST });\n\t\t\treturn;\n\t\t}\n\t\tif (existingRun?.status === \"running\") {\n\t\t\tsendError(res, 409, \"A run with this runId is already in progress\", PiServerErrorCode.RUN_IN_PROGRESS);\n\t\t\treturn;\n\t\t}\n\t\trun = startStreamRun(body.sessionId, body.runId, \"compact\");\n\t}\n\n\tif (body.streamResponse) {\n\t\tawait handleSessionCompactStream(config, body, prepared, res, run);\n\t\treturn;\n\t}\n\n\tawait handleSessionCompactJsonStream(config, body, prepared, res, run);\n}\n\nfunction handleSessionHistory(\n\tsessionId: string,\n\tfrom: number | undefined,\n\tentriesFrom: number | undefined,\n\trevision: number | undefined,\n\tbaseTreeHash: string | undefined,\n\tres: ServerResponse,\n): void {\n\tconst session = getSession(sessionId);\n\tif (!session) {\n\t\tsendError(res, 404, \"session not found\", PiServerErrorCode.SESSION_NOT_FOUND);\n\t\treturn;\n\t}\n\tconst baseMessageCount = from ?? 0;\n\tif (\n\t\tentriesFrom !== undefined &&\n\t\tentriesFrom <= session.entries.length &&\n\t\t(revision === undefined || revision <= session.revision) &&\n\t\t(baseTreeHash === undefined || baseTreeHash === session.prefixHashes[entriesFrom])\n\t) {\n\t\tsendJson(res, 200, sessionTreePatchResponseBody(session, baseMessageCount, entriesFrom, revision));\n\t\treturn;\n\t}\n\tsendJson(res, 200, sessionHistoryFullResponseBody(session, baseMessageCount));\n}\n\nfunction handleSessionRun(sessionId: string, runId: string, res: ServerResponse): void {\n\tconst run = getStreamRun(sessionId, runId);\n\tif (!run) {\n\t\tsendError(res, 404, \"run not found\", PiServerErrorCode.RUN_NOT_FOUND);\n\t\treturn;\n\t}\n\tsendJson(res, 200, streamRunResponseBody(run));\n}\n\nasync function handleSessionRunAbort(sessionId: string, runId: string, res: ServerResponse): Promise<void> {\n\tif (!sessionId || !runId) {\n\t\tsendError(res, 400, \"sessionId and runId are required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\n\tlet run = getStreamRun(sessionId, runId);\n\tif (!run) {\n\t\trun = createRunRecord(sessionId, runId, \"stream\");\n\t\trun.status = \"aborted\";\n\t\trun.cancelRequested = true;\n\t\trun.errorMessage = \"Stream run aborted before it started\";\n\t\trun.updatedAt = Date.now();\n\t\tsettleRun(run);\n\t\tstreamRuns.set(runKey(sessionId, runId), run);\n\t\tsendJson(res, 200, streamRunResponseBody(run));\n\t\treturn;\n\t}\n\n\tif (run.status !== \"running\") {\n\t\tawait run.settled;\n\t\tsendJson(res, 200, streamRunResponseBody(run));\n\t\treturn;\n\t}\n\n\trun.cancelRequested = true;\n\trun.updatedAt = Date.now();\n\trun.controller.abort();\n\tawait run.settled;\n\tsendJson(res, 200, streamRunResponseBody(run));\n}\n\nexport function buildStreamContext(\n\tsession: SessionState,\n\tbody: Pick<StreamRequestBody, \"contextOverlay\" | \"ephemeralMessages\">,\n): Context {\n\tconst messages = body.contextOverlay ?? [...session.messages, ...(body.ephemeralMessages ?? [])];\n\treturn {\n\t\tsystemPrompt: session.staticContext?.systemPrompt,\n\t\tmessages,\n\t\ttools: session.staticContext?.tools,\n\t};\n}\n\nfunction handleStream(config: ServerConfig, body: StreamRequestBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!body.model) {\n\t\tsendError(res, 400, \"model is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\n\tcleanupExpiredStreamRuns(Date.now());\n\n\tconst session = getOrCreateSession(body.sessionId);\n\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t\tpersistSession(config, session);\n\t}\n\n\tif (!session.staticContext && !body.staticContext) {\n\t\tsendError(\n\t\t\tres,\n\t\t\t400,\n\t\t\t\"Session has no static context. Initialize with /api/session/init first.\",\n\t\t\tPiServerErrorCode.SESSION_NO_STATIC_CONTEXT,\n\t\t);\n\t\treturn;\n\t}\n\n\tif (body.ephemeralMessages !== undefined && !Array.isArray(body.ephemeralMessages)) {\n\t\tsendError(res, 400, \"ephemeralMessages must be an array\", PiServerErrorCode.INVALID_REQUEST);\n\t\treturn;\n\t}\n\tif (body.contextOverlay !== undefined && !Array.isArray(body.contextOverlay)) {\n\t\tsendError(res, 400, \"contextOverlay must be an array\", PiServerErrorCode.INVALID_REQUEST);\n\t\treturn;\n\t}\n\n\tconst context = buildStreamContext(session, body);\n\tconst existingRun = body.runId ? getStreamRun(body.sessionId, body.runId) : undefined;\n\n\tconst resolvedModel = body.model;\n\n\tif (existingRun?.status === \"completed\") {\n\t\tres.writeHead(200, {\n\t\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\t\"Cache-Control\": \"no-cache\",\n\t\t\tConnection: \"keep-alive\",\n\t\t});\n\t\tres.flushHeaders();\n\t\tres.write(STREAM_HEARTBEAT);\n\t\tfor (const event of replayStreamRun(existingRun)) {\n\t\t\twriteStreamEvent(res, event);\n\t\t}\n\t\tendStreamResponse(res);\n\t\treturn;\n\t}\n\tif (existingRun?.status === \"aborted\") {\n\t\tsendError(res, 409, \"The stream run was aborted\", PiServerErrorCode.INVALID_REQUEST);\n\t\treturn;\n\t}\n\tif (existingRun?.status === \"running\") {\n\t\tsendError(res, 409, \"A stream with this runId is already in progress\", PiServerErrorCode.RUN_IN_PROGRESS);\n\t\treturn;\n\t}\n\n\tconst run = body.runId ? startStreamRun(body.sessionId, body.runId) : undefined;\n\tconst streamOptions: SimpleStreamOptions = {\n\t\t...(body.options ?? {}),\n\t\t...(run ? { signal: run.controller.signal } : {}),\n\t};\n\n\tres.writeHead(200, {\n\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\"Cache-Control\": \"no-cache\",\n\t\tConnection: \"keep-alive\",\n\t});\n\tres.flushHeaders();\n\tres.write(STREAM_HEARTBEAT);\n\n\tconst heartbeat = setInterval(() => {\n\t\ttouchStreamRun(run);\n\t\tif (!res.writableEnded && !res.destroyed) {\n\t\t\tres.write(STREAM_HEARTBEAT);\n\t\t}\n\t}, STREAM_HEARTBEAT_INTERVAL_MS);\n\theartbeat.unref();\n\n\tlet stream: AsyncIterable<AssistantMessageEvent>;\n\ttry {\n\t\tstream = streamSimple(resolvedModel, context, streamOptions);\n\t} catch (err) {\n\t\tclearInterval(heartbeat);\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tfailStreamRun(run, message);\n\t\tsettleRun(run);\n\t\twriteStreamError(res, message);\n\t\tendStreamResponse(res);\n\t\treturn;\n\t}\n\n\tvoid (async () => {\n\t\ttry {\n\t\t\tfor await (const event of stream) {\n\t\t\t\tconst proxyEvent = toProxyEvent(event);\n\t\t\t\tif (proxyEvent) {\n\t\t\t\t\ttouchStreamRun(run);\n\t\t\t\t\twriteStreamEvent(res, proxyEvent);\n\t\t\t\t}\n\t\t\t\tif (event.type === \"done\") {\n\t\t\t\t\tcompleteStreamRun(run, event.message);\n\t\t\t\t} else if (event.type === \"error\") {\n\t\t\t\t\tfailStreamRun(run, event.error.errorMessage ?? event.reason);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tfailStreamRun(run, message);\n\t\t\twriteStreamError(res, message);\n\t\t} finally {\n\t\t\tclearInterval(heartbeat);\n\t\t\tif (run?.status === \"running\") {\n\t\t\t\tfailStreamRun(run, run.cancelRequested ? \"Stream run aborted\" : \"Stream ended before a terminal event\");\n\t\t\t}\n\t\t\tsettleRun(run);\n\t\t\tendStreamResponse(res);\n\t\t}\n\t})();\n}\n\nasync function handlePostRequest(\n\tconfig: ServerConfig,\n\tpathname: string,\n\tbody: unknown,\n\tres: ServerResponse,\n): Promise<boolean> {\n\tif (pathname === \"/api/receive\") {\n\t\ttry {\n\t\t\tsendJson(res, 200, receiveUpload(config.uploadDir, body));\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof ReceiveUploadError)) throw error;\n\t\t\tsendJson(res, error.status, { error: error.message });\n\t\t}\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/init\") {\n\t\thandleSessionInit(config, body as SessionInitBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/update\") {\n\t\thandleSessionUpdate(config, body as SessionInitBody & { staticContext: SessionStaticContext }, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/sync\") {\n\t\thandleSessionSync(config, body as SessionSyncBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/append\") {\n\t\thandleSessionAppend(config, body as SessionAppendBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/tree/sync\") {\n\t\thandleSessionTreeSync(config, body as SessionTreeSyncBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/tree/append\") {\n\t\thandleSessionTreeAppend(config, body as SessionTreeSyncBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/tree/switch\") {\n\t\thandleSessionTreeSwitch(config, body as SessionTreeSwitchBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/compact\") {\n\t\tawait handleSessionCompact(config, body as SessionCompactBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/stream\") {\n\t\thandleStream(config, body as StreamRequestBody, res);\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nexport function createPiServer(configOverride?: Partial<ServerConfig>): HttpServer {\n\tconst config = loadConfig(configOverride);\n\tloadPersistedSessions(config.sessionStoreDir);\n\n\tconst server = createServer(async (req, res) => {\n\t\tconst url = new URL(req.url ?? \"/\", \"http://localhost\");\n\n\t\tif (req.method === \"GET\" && url.pathname === \"/health\") {\n\t\t\tsendJson(res, 200, { status: \"ok\" });\n\t\t\treturn;\n\t\t}\n\n\t\tif (!authenticate(config, req)) {\n\t\t\tconst body =\n\t\t\t\treq.method === \"GET\" && url.pathname === \"/\"\n\t\t\t\t\t? { error: \"Unauthorized\", version: PI_SERVER_VERSION }\n\t\t\t\t\t: { error: \"Unauthorized\" };\n\t\t\tsendJson(res, 401, body);\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"GET\" && url.pathname === \"/api/sessions\") {\n\t\t\tsendJson(res, 200, { sessions: listSessions() });\n\t\t\treturn;\n\t\t}\n\n\t\tconst runMatch = /^\\/api\\/session\\/([^/]+)\\/runs\\/([^/]+)$/.exec(url.pathname);\n\t\tif (req.method === \"GET\" && runMatch) {\n\t\t\thandleSessionRun(decodeURIComponent(runMatch[1]), decodeURIComponent(runMatch[2]), res);\n\t\t\treturn;\n\t\t}\n\n\t\tconst runAbortMatch = /^\\/api\\/session\\/([^/]+)\\/runs\\/([^/]+)\\/abort$/.exec(url.pathname);\n\t\tif (req.method === \"POST\" && runAbortMatch) {\n\t\t\tawait readBody(req);\n\t\t\tawait handleSessionRunAbort(decodeURIComponent(runAbortMatch[1]), decodeURIComponent(runAbortMatch[2]), res);\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"GET\" && url.pathname.startsWith(\"/api/session/\") && url.pathname.endsWith(\"/history\")) {\n\t\t\tconst encodedSessionId = url.pathname.slice(\"/api/session/\".length, -\"/history\".length);\n\t\t\tconst fromParam = url.searchParams.get(\"from\");\n\t\t\tconst from = fromParam === null ? undefined : Number(fromParam);\n\t\t\tif (from !== undefined && (!Number.isInteger(from) || from < 0)) {\n\t\t\t\tsendError(res, 400, \"from must be a non-negative integer\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst entriesFromParam = url.searchParams.get(\"entriesFrom\");\n\t\t\tconst entriesFrom = entriesFromParam === null ? undefined : Number(entriesFromParam);\n\t\t\tif (entriesFrom !== undefined && (!Number.isInteger(entriesFrom) || entriesFrom < 0)) {\n\t\t\t\tsendError(res, 400, \"entriesFrom must be a non-negative integer\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst revisionParam = url.searchParams.get(\"revision\");\n\t\t\tconst revision = revisionParam === null ? undefined : Number(revisionParam);\n\t\t\tif (revision !== undefined && (!Number.isInteger(revision) || revision < 0)) {\n\t\t\t\tsendError(res, 400, \"revision must be a non-negative integer\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thandleSessionHistory(\n\t\t\t\tdecodeURIComponent(encodedSessionId),\n\t\t\t\tfrom,\n\t\t\t\tentriesFrom,\n\t\t\t\trevision,\n\t\t\t\turl.searchParams.get(\"baseTreeHash\") ?? undefined,\n\t\t\t\tres,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"POST\" && url.pathname === CHUNK_ENDPOINT) {\n\t\t\ttry {\n\t\t\t\tconst body = JSON.parse(await readBody(req)) as RequestChunkBody;\n\t\t\t\tconst chunkResult = receiveRequestChunk(body);\n\t\t\t\tif (!chunkResult.complete) {\n\t\t\t\t\tsendJson(res, 200, chunkResult.ack);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst handled = await handlePostRequest(\n\t\t\t\t\tconfig,\n\t\t\t\t\tchunkResult.target,\n\t\t\t\t\tJSON.parse(chunkResult.bodyJson) as unknown,\n\t\t\t\t\tres,\n\t\t\t\t);\n\t\t\t\tif (!handled && !res.headersSent) {\n\t\t\t\t\tsendError(res, 404, \"Not found\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tlogRequestError(req, err);\n\t\t\t\tif (!res.headersSent) {\n\t\t\t\t\tsendError(res, 400, err instanceof Error ? err.message : String(err), PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\t} else {\n\t\t\t\t\tres.write(encodeErrorEvent(err instanceof Error ? err.message : String(err)));\n\t\t\t\t\tres.end();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"POST\") {\n\t\t\ttry {\n\t\t\t\tconst body = JSON.parse(await readBody(req)) as unknown;\n\t\t\t\tif (await handlePostRequest(config, url.pathname, body, res)) return;\n\t\t\t\tif (!res.headersSent) {\n\t\t\t\t\tsendError(res, 404, \"Not found\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tlogRequestError(req, err);\n\t\t\t\tif (!res.headersSent) {\n\t\t\t\t\tsendError(res, 500, err instanceof Error ? err.message : String(err), PiServerErrorCode.INTERNAL_ERROR);\n\t\t\t\t} else {\n\t\t\t\t\tres.write(encodeErrorEvent(err instanceof Error ? err.message : String(err)));\n\t\t\t\t\tres.end();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif (req.method === \"DELETE\" && url.pathname.startsWith(\"/api/session/\")) {\n\t\t\tconst sessionId = decodeURIComponent(url.pathname.slice(\"/api/session/\".length));\n\t\t\tdeleteSessionFromStore(sessionId);\n\t\t\tdeleteStreamRunsForSession(sessionId);\n\t\t\tdeletePersistedSession(config.sessionStoreDir, sessionId);\n\t\t\tsendJson(res, 200, { deleted: sessionId });\n\t\t\treturn;\n\t\t}\n\n\t\tsendError(res, 404, \"Not found\", PiServerErrorCode.INVALID_REQUEST);\n\t});\n\n\treturn server;\n}\n\nfunction toProxyEvent(event: AssistantMessageEvent): ProxyAssistantMessageEvent | undefined {\n\tswitch (event.type) {\n\t\tcase \"start\":\n\t\t\treturn { type: \"start\" };\n\t\tcase \"text_start\":\n\t\t\treturn { type: \"text_start\", contentIndex: event.contentIndex };\n\t\tcase \"text_delta\":\n\t\t\treturn { type: \"text_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\tcase \"text_end\":\n\t\t\treturn {\n\t\t\t\ttype: \"text_end\",\n\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\tcontentSignature:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"text\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { textSignature?: string }).textSignature\n\t\t\t\t\t\t: undefined,\n\t\t\t};\n\t\tcase \"thinking_start\":\n\t\t\treturn { type: \"thinking_start\", contentIndex: event.contentIndex };\n\t\tcase \"thinking_delta\":\n\t\t\treturn { type: \"thinking_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\tcase \"thinking_end\":\n\t\t\treturn {\n\t\t\t\ttype: \"thinking_end\",\n\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\tcontentSignature:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"thinking\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { thinkingSignature?: string }).thinkingSignature\n\t\t\t\t\t\t: undefined,\n\t\t\t};\n\t\tcase \"toolcall_start\":\n\t\t\treturn {\n\t\t\t\ttype: \"toolcall_start\",\n\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\tid:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"toolCall\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { id: string }).id\n\t\t\t\t\t\t: \"\",\n\t\t\t\ttoolName:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"toolCall\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { name: string }).name\n\t\t\t\t\t\t: \"\",\n\t\t\t};\n\t\tcase \"toolcall_delta\":\n\t\t\treturn { type: \"toolcall_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\tcase \"toolcall_end\":\n\t\t\treturn { type: \"toolcall_end\", contentIndex: event.contentIndex, toolCall: event.toolCall };\n\t\tcase \"done\":\n\t\t\treturn {\n\t\t\t\ttype: \"done\",\n\t\t\t\treason: event.reason,\n\t\t\t\tusage: event.message.usage,\n\t\t\t\tdeferred: event.message.deferred,\n\t\t\t\tmessage: event.message,\n\t\t\t};\n\t\tcase \"error\":\n\t\t\treturn {\n\t\t\t\ttype: \"error\",\n\t\t\t\treason: event.reason,\n\t\t\t\terrorMessage: event.error.errorMessage,\n\t\t\t\tusage: event.error.usage,\n\t\t\t};\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nexport function startServer(configOverride?: Partial<ServerConfig>): HttpServer {\n\tconst config = loadConfig(configOverride);\n\tconst server = createPiServer(configOverride);\n\tserver.listen(config.port, config.host, () => {\n\t\tconst address = server.address();\n\t\tconst port = typeof address === \"object\" && address !== null ? address.port : config.port;\n\t\tconst host = config.host.includes(\":\") && !config.host.startsWith(\"[\") ? `[${config.host}]` : config.host;\n\t\tconsole.log(`pi-server listening on ${host}:${port}`);\n\t});\n\treturn server;\n}\n"]}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,IAAI,UAAU,EAA6C,MAAM,WAAW,CAAC;AAc/G,OAAO,EAGN,KAAK,OAAO,EAGZ,KAAK,OAAO,EACZ,KAAK,KAAK,EAEV,KAAK,mBAAmB,EACxB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQhD,OAAO,EAWN,KAAK,YAAY,EACjB,KAAK,oBAAoB,EAGzB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAc5D,UAAU,iBAAiB;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,iBAAiB,CAAC,EAAE,OAAO,EAAE,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,EAAE,CAAC;CAC3B;AA67BD,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,GAAG,mBAAmB,CAAC,GACnE,OAAO,CAOT;AAoMD,wBAAgB,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,UAAU,CAoIjF;AAqED,wBAAgB,WAAW,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,UAAU,CAU9E","sourcesContent":["import { createServer, type Server as HttpServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { createRequire } from \"node:module\";\nimport {\n\ttype CompactionCacheRequestOptions,\n\ttype CompactionPreparationOptions,\n\ttype CompactionSettings,\n\tcompactLegacy,\n\tconvertToLlm,\n\tDEFAULT_COMPACTION_SETTINGS,\n\ttype LegacyCompactResult,\n\ttype ProxyAssistantMessageEvent,\n\tprepareLegacyCompaction,\n\ttype SessionTreeEntry,\n} from \"@earendil-works/pi-agent-core\";\nimport {\n\ttype AssistantMessage,\n\ttype AssistantMessageEvent,\n\ttype Context,\n\tcreateModels,\n\tcreateProvider,\n\ttype Message,\n\ttype Model,\n\ttype ProviderStreams,\n\ttype SimpleStreamOptions,\n} from \"@earendil-works/pi-ai\";\nimport { streamSimple } from \"@earendil-works/pi-ai/compat\";\nimport type { ServerConfig } from \"./config.ts\";\nimport { loadConfig } from \"./config.ts\";\nimport { PiServerError, PiServerErrorCode, type PiServerErrorResponse } from \"./error-codes.ts\";\nimport { encodeErrorEvent, encodeProxyEvent } from \"./event-encoding.ts\";\nimport { hashPiServerProviderMessages } from \"./pi-server-protocol.ts\";\nimport { ReceiveUploadError, receiveUpload } from \"./receive-upload.ts\";\nimport { CHUNK_ENDPOINT, type RequestChunkBody, receiveRequestChunk } from \"./request-chunks.ts\";\nimport { deletePersistedSession, loadPersistedSessions, savePersistedSession } from \"./session-persistence.ts\";\nimport {\n\tappendCompactionEntry,\n\tappendMessages,\n\tappendSessionEntries,\n\tdeleteSession as deleteSessionFromStore,\n\tgetOrCreateSession,\n\tgetSession,\n\tgetSessionBranch,\n\tlistSessions,\n\treplaceMessages,\n\treplaceSessionTree,\n\ttype SessionState,\n\ttype SessionStaticContext,\n\tsetStaticContext,\n\tswitchSessionLeaf,\n} from \"./session-store.ts\";\n\nexport { loadConfig, type ServerConfig } from \"./config.ts\";\n\ninterface PackageMetadata {\n\tversion: string;\n}\n\nconst packageMetadata = createRequire(import.meta.url)(\"../package.json\") as PackageMetadata;\nconst PI_SERVER_VERSION = packageMetadata.version;\n\ninterface SessionInitBody {\n\tsessionId: string;\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface StreamRequestBody {\n\tsessionId: string;\n\trunId?: string;\n\tmodel: Model<any>;\n\toptions?: SimpleStreamOptions;\n\tstaticContext?: SessionStaticContext;\n\tephemeralMessages?: Message[];\n\tcontextOverlay?: Message[];\n}\n\ninterface SessionSyncBody {\n\tsessionId: string;\n\tmessages: Message[];\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface SessionAppendBody {\n\tsessionId: string;\n\tmessages: Message[];\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface SessionTreeSyncBody {\n\tsessionId: string;\n\tentries: SessionTreeEntry[];\n\tleafId: string | null;\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface SessionTreeSwitchBody {\n\tsessionId: string;\n\tleafId: string | null;\n}\n\ninterface SessionCompactBody {\n\tsessionId: string;\n\trunId?: string;\n\tmodel: Model<any>;\n\toptions?: SimpleStreamOptions;\n\tsettings?: CompactionSettings;\n\tpreparation?: CompactionPreparationOptions;\n\tcustomInstructions?: string;\n\tcacheContextHash?: string;\n\tcacheStaticContextHash?: string;\n\tcacheFallbackReason?: string;\n\tbaseTreeHash?: string;\n\tfullResponse?: boolean;\n\tstreamResponse?: boolean;\n}\n\nfunction createRequestModels(model: Model<any>, options: SimpleStreamOptions) {\n\tconst models = createModels();\n\tconst requestStream: ProviderStreams[\"streamSimple\"] = (requestModel, context, streamOptions) =>\n\t\tstreamSimple(requestModel, context, {\n\t\t\t...streamOptions,\n\t\t\t...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n\t\t});\n\tmodels.setProvider(\n\t\tcreateProvider({\n\t\t\tid: model.provider,\n\t\t\tname: model.provider,\n\t\t\tmodels: [model],\n\t\t\tauth: {\n\t\t\t\tapiKey: {\n\t\t\t\t\tname: \"pi-server request auth\",\n\t\t\t\t\tresolve: async () => ({ auth: { apiKey: options.apiKey, headers: options.headers } }),\n\t\t\t\t},\n\t\t\t},\n\t\t\tapi: {\n\t\t\t\tstream: requestStream,\n\t\t\t\tstreamSimple: requestStream,\n\t\t\t},\n\t\t}),\n\t);\n\treturn models;\n}\n\ninterface StreamRunRecord {\n\tsessionId: string;\n\trunId: string;\n\tkind: \"stream\" | \"compact\";\n\tstatus: \"running\" | \"completed\" | \"failed\" | \"aborted\";\n\tmessage?: AssistantMessage;\n\tcompactResult?: SessionCompactSuccessBody;\n\terrorMessage?: string;\n\tcreatedAt: number;\n\tupdatedAt: number;\n\tcancelRequested: boolean;\n\tcontroller: AbortController;\n\tsettled: Promise<void>;\n\tresolveSettled: (() => void) | undefined;\n}\n\nconst STREAM_HEARTBEAT = \": keep-alive\\n\\n\";\nconst JSON_HEARTBEAT = \" \\n\";\nconst STREAM_HEARTBEAT_INTERVAL_MS = 25_000;\nconst STREAM_RUN_TTL_MS = 60 * 60 * 1000; // 1 hour\nconst streamRuns = new Map<string, StreamRunRecord>();\n\nfunction readBody(req: IncomingMessage): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst chunks: Buffer[] = [];\n\t\treq.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n\t\treq.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf-8\")));\n\t\treq.on(\"error\", reject);\n\t});\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n\tconst data = JSON.stringify(body);\n\tres.writeHead(status, { \"Content-Type\": \"application/json\", \"Content-Length\": Buffer.byteLength(data) });\n\tres.end(data);\n}\n\nfunction sendError(\n\tres: ServerResponse,\n\tstatus: number,\n\tmessage: string,\n\tcode?: PiServerErrorCode,\n\tdetails?: Record<string, unknown>,\n): void {\n\tconst body: PiServerErrorResponse = { error: message };\n\tif (code) body.code = code;\n\tif (details) body.details = details;\n\tsendJson(res, status, body);\n}\n\nfunction logRequestError(req: IncomingMessage, error: unknown): void {\n\tconst message = error instanceof Error ? error.stack || error.message : String(error);\n\tconsole.error(`${req.method ?? \"UNKNOWN\"} ${req.url ?? \"/\"} failed: ${message}`);\n}\n\nfunction authenticate(config: ServerConfig, req: IncomingMessage): boolean {\n\tif (!config.authToken) return true;\n\tconst header = req.headers.authorization;\n\tif (!header) return false;\n\tconst token = header.startsWith(\"Bearer \") ? header.slice(7) : header;\n\treturn token === config.authToken;\n}\n\nfunction sessionResponseBody(session: SessionState) {\n\treturn {\n\t\tsessionId: session.sessionId,\n\t\tstaticContextHash: session.staticContextHash,\n\t\ttreeHash: session.treeHash,\n\t\tmessageCount: session.messages.length,\n\t\tentryCount: session.entries.length,\n\t\tleafId: session.leafId,\n\t\trevision: session.revision,\n\t};\n}\n\nfunction persistSession(config: ServerConfig, session: SessionState): void {\n\tsavePersistedSession(config.sessionStoreDir, session);\n}\n\nfunction runKey(sessionId: string, runId: string): string {\n\treturn `${sessionId}\\0${runId}`;\n}\n\nfunction getStreamRun(sessionId: string, runId: string): StreamRunRecord | undefined {\n\treturn streamRuns.get(runKey(sessionId, runId));\n}\n\nfunction createRunRecord(sessionId: string, runId: string, kind: StreamRunRecord[\"kind\"]): StreamRunRecord {\n\tlet resolveSettled: (() => void) | undefined;\n\tconst settled = new Promise<void>((resolve) => {\n\t\tresolveSettled = resolve;\n\t});\n\treturn {\n\t\tsessionId,\n\t\trunId,\n\t\tkind,\n\t\tstatus: \"running\",\n\t\tcreatedAt: Date.now(),\n\t\tupdatedAt: Date.now(),\n\t\tcancelRequested: false,\n\t\tcontroller: new AbortController(),\n\t\tsettled,\n\t\tresolveSettled,\n\t};\n}\n\nfunction settleRun(run: StreamRunRecord | undefined): void {\n\tif (!run) return;\n\tconst resolve = run.resolveSettled;\n\trun.resolveSettled = undefined;\n\tresolve?.();\n}\n\nfunction startStreamRun(sessionId: string, runId: string, kind: StreamRunRecord[\"kind\"] = \"stream\"): StreamRunRecord {\n\tconst existing = getStreamRun(sessionId, runId);\n\tif (existing?.status === \"completed\" || existing?.status === \"aborted\") return existing;\n\tconst run = existing ?? createRunRecord(sessionId, runId, kind);\n\tif (existing) {\n\t\trun.message = undefined;\n\t\trun.errorMessage = undefined;\n\t\trun.cancelRequested = false;\n\t\trun.controller = new AbortController();\n\t\tlet resolveSettled: (() => void) | undefined;\n\t\trun.settled = new Promise<void>((resolve) => {\n\t\t\tresolveSettled = resolve;\n\t\t});\n\t\trun.resolveSettled = resolveSettled;\n\t}\n\trun.kind = kind;\n\trun.status = \"running\";\n\trun.updatedAt = Date.now();\n\tstreamRuns.set(runKey(sessionId, runId), run);\n\treturn run;\n}\n\nfunction streamRunResponseBody(run: StreamRunRecord) {\n\treturn {\n\t\tsessionId: run.sessionId,\n\t\trunId: run.runId,\n\t\tstatus: run.status,\n\t\tcreatedAt: run.createdAt,\n\t\tupdatedAt: run.updatedAt,\n\t\t...(run.message ? { message: run.message } : {}),\n\t\t...(run.compactResult ? { compactResult: run.compactResult } : {}),\n\t\t...(run.errorMessage ? { errorMessage: run.errorMessage } : {}),\n\t};\n}\n\nfunction replayStreamRun(run: StreamRunRecord): ProxyAssistantMessageEvent[] {\n\tif (!run.message) return [];\n\tif (\n\t\trun.message.stopReason !== \"stop\" &&\n\t\trun.message.stopReason !== \"length\" &&\n\t\trun.message.stopReason !== \"toolUse\" &&\n\t\trun.message.stopReason !== \"deferred\"\n\t) {\n\t\treturn [];\n\t}\n\tconst events: ProxyAssistantMessageEvent[] = [{ type: \"start\" }];\n\tfor (const [contentIndex, content] of run.message.content.entries()) {\n\t\tswitch (content.type) {\n\t\t\tcase \"text\":\n\t\t\t\tevents.push(\n\t\t\t\t\t{ type: \"text_start\", contentIndex },\n\t\t\t\t\t{ type: \"text_delta\", contentIndex, delta: content.text },\n\t\t\t\t\t{ type: \"text_end\", contentIndex, contentSignature: content.textSignature },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"thinking\":\n\t\t\t\tevents.push(\n\t\t\t\t\t{ type: \"thinking_start\", contentIndex },\n\t\t\t\t\t{ type: \"thinking_delta\", contentIndex, delta: content.thinking },\n\t\t\t\t\t{ type: \"thinking_end\", contentIndex, contentSignature: content.thinkingSignature },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"toolCall\":\n\t\t\t\tevents.push(\n\t\t\t\t\t{ type: \"toolcall_start\", contentIndex, id: content.id, toolName: content.name },\n\t\t\t\t\t{ type: \"toolcall_delta\", contentIndex, delta: JSON.stringify(content.arguments) },\n\t\t\t\t\t{ type: \"toolcall_end\", contentIndex, toolCall: content },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tevents.push({\n\t\ttype: \"done\",\n\t\treason: run.message.stopReason,\n\t\tusage: run.message.usage,\n\t\tdeferred: run.message.deferred,\n\t\tmessage: run.message,\n\t});\n\treturn events;\n}\n\nfunction completeStreamRun(run: StreamRunRecord | undefined, message: AssistantMessage): void {\n\tif (!run) return;\n\tif (run.cancelRequested) {\n\t\trun.status = \"aborted\";\n\t\trun.message = undefined;\n\t\trun.errorMessage = \"Stream run aborted\";\n\t\trun.updatedAt = Date.now();\n\t\treturn;\n\t}\n\trun.status = \"completed\";\n\trun.message = message;\n\trun.errorMessage = undefined;\n\trun.updatedAt = Date.now();\n}\n\nfunction failStreamRun(run: StreamRunRecord | undefined, errorMessage: string): void {\n\tif (!run) return;\n\tif (run.cancelRequested) {\n\t\trun.status = \"aborted\";\n\t\trun.errorMessage = \"Stream run aborted\";\n\t\trun.updatedAt = Date.now();\n\t\treturn;\n\t}\n\trun.status = \"failed\";\n\trun.errorMessage = errorMessage;\n\trun.updatedAt = Date.now();\n}\n\nfunction touchStreamRun(run: StreamRunRecord | undefined): void {\n\tif (run) run.updatedAt = Date.now();\n}\n\nfunction writeStreamEvent(res: ServerResponse, event: ProxyAssistantMessageEvent): void {\n\tif (!res.writableEnded && !res.destroyed) {\n\t\tres.write(encodeProxyEvent(event));\n\t}\n}\n\nfunction writeStreamError(res: ServerResponse, message: string): void {\n\tif (!res.writableEnded && !res.destroyed) {\n\t\tres.write(encodeErrorEvent(message));\n\t}\n}\n\nfunction endStreamResponse(res: ServerResponse): void {\n\tif (!res.writableEnded && !res.destroyed) {\n\t\tres.end();\n\t}\n}\n\nfunction cleanupExpiredStreamRuns(nowMs: number): void {\n\tfor (const [key, run] of streamRuns) {\n\t\tif (nowMs - run.updatedAt > STREAM_RUN_TTL_MS) {\n\t\t\tstreamRuns.delete(key);\n\t\t}\n\t}\n}\n\nfunction deleteStreamRunsForSession(sessionId: string): void {\n\tfor (const [key, run] of streamRuns) {\n\t\tif (run.sessionId === sessionId) streamRuns.delete(key);\n\t}\n}\n\nconst streamRunCleanupTimer = setInterval(() => cleanupExpiredStreamRuns(Date.now()), STREAM_RUN_TTL_MS / 4);\nstreamRunCleanupTimer.unref();\n\nfunction sessionHistoryFullResponseBody(session: SessionState, baseMessageCount: number) {\n\treturn {\n\t\tsessionId: session.sessionId,\n\t\tstaticContext: session.staticContext,\n\t\tstaticContextHash: session.staticContextHash,\n\t\ttreeHash: session.treeHash,\n\t\tmessageCount: session.messages.length,\n\t\tentryCount: session.entries.length,\n\t\tleafId: session.leafId,\n\t\trevision: session.revision,\n\t\tentries: session.entries,\n\t\tbaseMessageCount,\n\t\tmessages: session.messages.slice(baseMessageCount),\n\t};\n}\n\nfunction sessionTreePatchResponseBody(\n\tsession: SessionState,\n\tbaseMessageCount: number,\n\tentriesFrom: number,\n\tbaseRevision: number | undefined,\n) {\n\treturn {\n\t\tsessionId: session.sessionId,\n\t\tstaticContext: session.staticContext,\n\t\tstaticContextHash: session.staticContextHash,\n\t\ttreeHash: session.treeHash,\n\t\tmessageCount: session.messages.length,\n\t\tentryCount: session.entries.length,\n\t\tleafId: session.leafId,\n\t\trevision: session.revision,\n\t\tbaseMessageCount,\n\t\tmessages: session.messages.slice(baseMessageCount),\n\t\ttreePatch: {\n\t\t\tentriesFrom,\n\t\t\tbaseRevision,\n\t\t\tentries: session.entries.slice(entriesFrom),\n\t\t\tleafId: session.leafId,\n\t\t\trevision: session.revision,\n\t\t},\n\t};\n}\n\ntype PreparedCompaction = Parameters<typeof compactLegacy>[0];\n\ninterface PreparedSessionCompact {\n\tsession: SessionState;\n\tsessionId: string;\n\trevision: number;\n\ttreeHash: string;\n\tleafId: string | null;\n\tentryCount: number;\n\tpreparation: PreparedCompaction;\n\toptions: SimpleStreamOptions;\n\tcacheContext?: Context;\n\tcacheFallbackReason: string;\n}\n\ninterface SessionCompactSuccessBody {\n\tsuccess: true;\n\tcompaction: Omit<LegacyCompactResult, \"retainedTail\">;\n\tcompactionEntry: SessionTreeEntry;\n\tsessionId: string;\n\tstaticContextHash: string;\n\ttreeHash: string;\n\tmessageCount: number;\n\tentryCount: number;\n\tleafId: string | null;\n\trevision: number;\n\tstaticContext?: SessionStaticContext;\n\ttreePatch?: {\n\t\tbaseTreeHash: string;\n\t\tentriesFrom: number;\n\t\tentries: SessionTreeEntry[];\n\t\tleafId: string | null;\n\t\trevision: number;\n\t};\n\tentries?: SessionTreeEntry[];\n\tmessages?: Message[];\n}\n\ninterface SessionCompactHttpResponse {\n\tstatus: number;\n\tbody: PiServerErrorResponse | SessionCompactSuccessBody;\n}\n\nfunction handleSessionInit(config: ServerConfig, body: SessionInitBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t} else {\n\t\tgetOrCreateSession(body.sessionId);\n\t}\n\tconst session = getSession(body.sessionId)!;\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionUpdate(\n\tconfig: ServerConfig,\n\tbody: SessionInitBody & { staticContext: SessionStaticContext },\n\tres: ServerResponse,\n): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!body.staticContext) {\n\t\tsendError(res, 400, \"staticContext is required for update\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tsetStaticContext(body.sessionId, body.staticContext);\n\tconst session = getSession(body.sessionId)!;\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionSync(config: ServerConfig, body: SessionSyncBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.messages)) {\n\t\tsendError(res, 400, \"messages is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t}\n\tconst session = replaceMessages(body.sessionId, body.messages);\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionAppend(config: ServerConfig, body: SessionAppendBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.messages)) {\n\t\tsendError(res, 400, \"messages is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t}\n\tconst session = appendMessages(body.sessionId, body.messages);\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionTreeSync(config: ServerConfig, body: SessionTreeSyncBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.entries)) {\n\t\tsendError(res, 400, \"entries is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t}\n\tconst session = replaceSessionTree(body.sessionId, body.entries, body.leafId ?? null);\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionTreeAppend(config: ServerConfig, body: SessionTreeSyncBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.entries)) {\n\t\tsendError(res, 400, \"entries is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\ttry {\n\t\tif (body.staticContext) {\n\t\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t\t}\n\t\tconst session = appendSessionEntries(body.sessionId, body.entries, body.leafId ?? null);\n\t\tpersistSession(config, session);\n\t\tsendJson(res, 200, sessionResponseBody(session));\n\t} catch (error) {\n\t\tif (error instanceof PiServerError) {\n\t\t\tsendError(res, 400, error.message, error.code, error.details);\n\t\t} else {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tsendError(res, 500, message, PiServerErrorCode.INTERNAL_ERROR);\n\t\t}\n\t}\n}\n\nfunction handleSessionTreeSwitch(config: ServerConfig, body: SessionTreeSwitchBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\ttry {\n\t\tconst session = switchSessionLeaf(body.sessionId, body.leafId ?? null);\n\t\tpersistSession(config, session);\n\t\tsendJson(res, 200, sessionResponseBody(session));\n\t} catch (error) {\n\t\tif (error instanceof PiServerError) {\n\t\t\tsendError(res, 400, error.message, error.code, error.details);\n\t\t} else {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tsendError(res, 500, message, PiServerErrorCode.INTERNAL_ERROR);\n\t\t}\n\t}\n}\n\nfunction prepareSessionCompact(body: SessionCompactBody): PreparedSessionCompact | SessionCompactHttpResponse {\n\tif (!body.sessionId) {\n\t\treturn { status: 400, body: { error: \"sessionId is required\" } };\n\t}\n\tif (!body.model) {\n\t\treturn { status: 400, body: { error: \"model is required\" } };\n\t}\n\tconst validDigest = (value: string | undefined): boolean => value === undefined || /^[a-f0-9]{64}$/.test(value);\n\tif (!validDigest(body.cacheContextHash) || !validDigest(body.cacheStaticContextHash)) {\n\t\treturn { status: 400, body: { error: \"cache context digests must be 64-character SHA-256 hex strings\" } };\n\t}\n\tif ((body.cacheContextHash === undefined) !== (body.cacheStaticContextHash === undefined)) {\n\t\treturn { status: 400, body: { error: \"cacheContextHash and cacheStaticContextHash must be supplied together\" } };\n\t}\n\n\tconst session = getSession(body.sessionId);\n\tif (!session) {\n\t\treturn { status: 404, body: { error: \"session not found\", code: PiServerErrorCode.SESSION_NOT_FOUND } };\n\t}\n\n\tconst entries = getSessionBranch(session);\n\tconst leaf = entries.at(-1);\n\tif (leaf?.type === \"compaction\") {\n\t\tif (!leaf.firstKeptEntryId) {\n\t\t\treturn { status: 400, body: { error: \"Stored compaction is missing firstKeptEntryId\" } };\n\t\t}\n\t\treturn {\n\t\t\tstatus: 200,\n\t\t\tbody: {\n\t\t\t\tsuccess: true,\n\t\t\t\tcompaction: {\n\t\t\t\t\tsummary: leaf.summary,\n\t\t\t\t\tfirstKeptEntryId: leaf.firstKeptEntryId,\n\t\t\t\t\ttokensBefore: leaf.tokensBefore,\n\t\t\t\t\tdetails: leaf.details,\n\t\t\t\t},\n\t\t\t\tcompactionEntry: leaf,\n\t\t\t\t...sessionResponseBody(session),\n\t\t\t\tentries: session.entries,\n\t\t\t\tmessages: session.messages,\n\t\t\t},\n\t\t};\n\t}\n\tconst preparationResult = prepareLegacyCompaction(\n\t\tentries,\n\t\tbody.settings ?? DEFAULT_COMPACTION_SETTINGS,\n\t\tbody.preparation,\n\t);\n\tif (!preparationResult.ok) {\n\t\treturn { status: 400, body: { error: preparationResult.error.message } };\n\t}\n\tif (!preparationResult.value) {\n\t\treturn { status: 400, body: { error: \"Nothing to compact\" } };\n\t}\n\n\tconst options = body.options ?? {};\n\tlet cacheContext: Context | undefined;\n\tlet cacheFallbackReason = body.cacheFallbackReason ?? \"cache_context_digest_missing\";\n\tif (body.cacheContextHash && body.cacheStaticContextHash) {\n\t\tif (options.sessionId !== session.sessionId) {\n\t\t\tcacheFallbackReason = \"session_id_mismatch\";\n\t\t} else if (options.cacheRetention === \"none\") {\n\t\t\tcacheFallbackReason = \"prompt_cache_disabled\";\n\t\t} else if (body.cacheStaticContextHash !== session.staticContextHash) {\n\t\t\tcacheFallbackReason = \"static_context_hash_mismatch\";\n\t\t} else {\n\t\t\tconst projectedMessages = convertToLlm(session.messages);\n\t\t\tconst priorAssistant = [...session.messages].reverse().find((message) => message.role === \"assistant\");\n\t\t\tif (hashPiServerProviderMessages(projectedMessages) !== body.cacheContextHash) {\n\t\t\t\tcacheFallbackReason = \"request_context_digest_mismatch\";\n\t\t\t} else if (\n\t\t\t\t!priorAssistant ||\n\t\t\t\tpriorAssistant.provider !== body.model.provider ||\n\t\t\t\tpriorAssistant.model !== body.model.id ||\n\t\t\t\tpriorAssistant.api !== body.model.api\n\t\t\t) {\n\t\t\t\tcacheFallbackReason = \"summary_model_mismatch\";\n\t\t\t} else {\n\t\t\t\tcacheContext = buildStreamContext(session, { contextOverlay: projectedMessages });\n\t\t\t\tcacheFallbackReason = \"exact_prefix_unavailable\";\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tsession,\n\t\tsessionId: session.sessionId,\n\t\trevision: session.revision,\n\t\ttreeHash: session.treeHash,\n\t\tleafId: session.leafId,\n\t\tentryCount: session.entries.length,\n\t\tpreparation: preparationResult.value,\n\t\toptions,\n\t\tcacheContext,\n\t\tcacheFallbackReason,\n\t};\n}\n\nfunction sessionCompactConflict(\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\tcurrentSession: SessionState | undefined,\n): SessionCompactHttpResponse {\n\treturn {\n\t\tstatus: 409,\n\t\tbody: {\n\t\t\terror: \"Session changed while compaction was running\",\n\t\t\tcode: PiServerErrorCode.SESSION_STATE_CONFLICT,\n\t\t\tdetails: {\n\t\t\t\tsessionId: body.sessionId,\n\t\t\t\texpectedRevision: prepared.revision,\n\t\t\t\texpectedTreeHash: prepared.treeHash,\n\t\t\t\texpectedLeafId: prepared.leafId,\n\t\t\t\tactualRevision: currentSession?.revision ?? null,\n\t\t\t\tactualTreeHash: currentSession?.treeHash ?? null,\n\t\t\t\tactualLeafId: currentSession?.leafId ?? null,\n\t\t\t},\n\t\t},\n\t};\n}\n\nasync function completeSessionCompact(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\trun?: StreamRunRecord,\n): Promise<SessionCompactHttpResponse> {\n\tconst result = await compactLegacy(\n\t\tprepared.preparation,\n\t\tcreateRequestModels(body.model, prepared.options),\n\t\tbody.model,\n\t\tbody.customInstructions,\n\t\trun?.controller.signal,\n\t\tprepared.options.reasoning,\n\t\tundefined,\n\t\tundefined,\n\t\tprepared.cacheContext,\n\t\tprepared.options as CompactionCacheRequestOptions,\n\t\tprepared.cacheFallbackReason,\n\t);\n\tif (!result.ok) {\n\t\treturn { status: 500, body: { error: result.error.message, code: PiServerErrorCode.INTERNAL_ERROR } };\n\t}\n\tif (run?.cancelRequested || run?.controller.signal.aborted) {\n\t\treturn { status: 409, body: { error: \"Compaction aborted\", code: PiServerErrorCode.INVALID_REQUEST } };\n\t}\n\n\tconst currentSession = getSession(prepared.sessionId);\n\tif (\n\t\t!currentSession ||\n\t\tcurrentSession !== prepared.session ||\n\t\tcurrentSession.revision !== prepared.revision ||\n\t\tcurrentSession.treeHash !== prepared.treeHash ||\n\t\tcurrentSession.leafId !== prepared.leafId\n\t) {\n\t\treturn sessionCompactConflict(body, prepared, currentSession);\n\t}\n\n\tconst baseTreeHash = prepared.treeHash;\n\tconst baseEntryCount = prepared.entryCount;\n\tconst compaction = result.value;\n\tconst { session: updatedSession, entry: compactionEntry } = appendCompactionEntry(body.sessionId, compaction);\n\tpersistSession(config, updatedSession);\n\tif (!body.fullResponse && body.baseTreeHash === baseTreeHash) {\n\t\treturn {\n\t\t\tstatus: 200,\n\t\t\tbody: {\n\t\t\t\tsuccess: true,\n\t\t\t\tcompaction: compaction satisfies LegacyCompactResult,\n\t\t\t\tcompactionEntry,\n\t\t\t\t...sessionResponseBody(updatedSession),\n\t\t\t\tstaticContext: updatedSession.staticContext,\n\t\t\t\ttreePatch: {\n\t\t\t\t\tbaseTreeHash,\n\t\t\t\t\tentriesFrom: baseEntryCount,\n\t\t\t\t\tentries: [compactionEntry],\n\t\t\t\t\tleafId: updatedSession.leafId,\n\t\t\t\t\trevision: updatedSession.revision,\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\treturn {\n\t\tstatus: 200,\n\t\tbody: {\n\t\t\tsuccess: true,\n\t\t\tcompaction: compaction satisfies LegacyCompactResult,\n\t\t\tcompactionEntry,\n\t\t\t...sessionResponseBody(updatedSession),\n\t\t\tstaticContext: updatedSession.staticContext,\n\t\t\tentries: updatedSession.entries,\n\t\t\tmessages: updatedSession.messages,\n\t\t},\n\t};\n}\n\nfunction writeServerSentEvent(res: ServerResponse, event: string, body: unknown): void {\n\tres.write(`event: ${event}\\n`);\n\tres.write(`data: ${JSON.stringify(body)}\\n\\n`);\n}\n\nasync function handleSessionCompactStream(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\tres: ServerResponse,\n\trun?: StreamRunRecord,\n): Promise<void> {\n\tres.writeHead(200, {\n\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\"Cache-Control\": \"no-cache\",\n\t\tConnection: \"keep-alive\",\n\t});\n\tres.flushHeaders();\n\tres.write(STREAM_HEARTBEAT);\n\n\tconst heartbeat = setInterval(() => {\n\t\ttouchStreamRun(run);\n\t\tif (!res.writableEnded) {\n\t\t\tres.write(STREAM_HEARTBEAT);\n\t\t}\n\t}, STREAM_HEARTBEAT_INTERVAL_MS);\n\theartbeat.unref();\n\n\ttry {\n\t\tconst result = await completeSessionCompact(config, body, prepared, run);\n\t\tfinishCompactRun(run, result);\n\t\twriteServerSentEvent(res, result.status >= 400 ? \"error\" : \"result\", result.body);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tif (run?.status === \"running\") {\n\t\t\trun.status = run.cancelRequested ? \"aborted\" : \"failed\";\n\t\t\trun.errorMessage = message;\n\t\t\trun.updatedAt = Date.now();\n\t\t}\n\t\twriteServerSentEvent(res, \"error\", { error: message });\n\t} finally {\n\t\tclearInterval(heartbeat);\n\t\tsettleRun(run);\n\t\tres.end();\n\t}\n}\n\nasync function handleSessionCompactJsonStream(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\tres: ServerResponse,\n\trun?: StreamRunRecord,\n): Promise<void> {\n\tres.writeHead(200, {\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"Cache-Control\": \"no-cache\",\n\t\tConnection: \"keep-alive\",\n\t});\n\tres.flushHeaders();\n\tres.write(JSON_HEARTBEAT);\n\n\tconst heartbeat = setInterval(() => {\n\t\ttouchStreamRun(run);\n\t\tif (!res.writableEnded) {\n\t\t\tres.write(JSON_HEARTBEAT);\n\t\t}\n\t}, STREAM_HEARTBEAT_INTERVAL_MS);\n\theartbeat.unref();\n\n\ttry {\n\t\tconst result = await completeSessionCompact(config, body, prepared, run);\n\t\tfinishCompactRun(run, result);\n\t\tres.write(JSON.stringify(result.body));\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tif (run?.status === \"running\") {\n\t\t\trun.status = run.cancelRequested ? \"aborted\" : \"failed\";\n\t\t\trun.errorMessage = message;\n\t\t\trun.updatedAt = Date.now();\n\t\t}\n\t\tres.write(JSON.stringify({ error: message }));\n\t} finally {\n\t\tclearInterval(heartbeat);\n\t\tsettleRun(run);\n\t\tres.end();\n\t}\n}\n\nfunction finishCompactRun(run: StreamRunRecord | undefined, result: SessionCompactHttpResponse): void {\n\tif (!run) return;\n\tif (run.cancelRequested || run.controller.signal.aborted) {\n\t\trun.status = \"aborted\";\n\t\trun.errorMessage = \"Compaction aborted\";\n\t} else {\n\t\trun.status = result.status >= 400 ? \"failed\" : \"completed\";\n\t\tif (result.status >= 400 && \"error\" in result.body) {\n\t\t\trun.errorMessage = result.body.error;\n\t\t} else if (\"success\" in result.body) {\n\t\t\trun.compactResult = { ...result.body, entries: result.body.entries?.slice() };\n\t\t}\n\t}\n\trun.updatedAt = Date.now();\n}\n\nasync function handleSessionCompact(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tres: ServerResponse,\n): Promise<void> {\n\tconst existingRun = body.runId ? getStreamRun(body.sessionId, body.runId) : undefined;\n\tif (existingRun?.status === \"aborted\") {\n\t\tsendJson(res, 409, { error: \"Compaction run was aborted\", code: PiServerErrorCode.INVALID_REQUEST });\n\t\treturn;\n\t}\n\tif (existingRun?.status === \"completed\" && existingRun.compactResult) {\n\t\tsendJson(res, 200, existingRun.compactResult);\n\t\treturn;\n\t}\n\tconst prepared = prepareSessionCompact(body);\n\tif (\"status\" in prepared) {\n\t\tsendJson(res, prepared.status, prepared.body);\n\t\treturn;\n\t}\n\n\tlet run: StreamRunRecord | undefined;\n\tif (body.runId) {\n\t\tconst existingRun = getStreamRun(body.sessionId, body.runId);\n\t\tif (existingRun?.status === \"aborted\") {\n\t\t\tsendJson(res, 409, { error: \"Compaction run was aborted\", code: PiServerErrorCode.INVALID_REQUEST });\n\t\t\treturn;\n\t\t}\n\t\tif (existingRun?.status === \"running\") {\n\t\t\tsendError(res, 409, \"A run with this runId is already in progress\", PiServerErrorCode.RUN_IN_PROGRESS);\n\t\t\treturn;\n\t\t}\n\t\trun = startStreamRun(body.sessionId, body.runId, \"compact\");\n\t}\n\n\tif (body.streamResponse) {\n\t\tawait handleSessionCompactStream(config, body, prepared, res, run);\n\t\treturn;\n\t}\n\n\tawait handleSessionCompactJsonStream(config, body, prepared, res, run);\n}\n\nfunction handleSessionHistory(\n\tsessionId: string,\n\tfrom: number | undefined,\n\tentriesFrom: number | undefined,\n\trevision: number | undefined,\n\tbaseTreeHash: string | undefined,\n\tres: ServerResponse,\n): void {\n\tconst session = getSession(sessionId);\n\tif (!session) {\n\t\tsendError(res, 404, \"session not found\", PiServerErrorCode.SESSION_NOT_FOUND);\n\t\treturn;\n\t}\n\tconst baseMessageCount = from ?? 0;\n\tif (\n\t\tentriesFrom !== undefined &&\n\t\tentriesFrom <= session.entries.length &&\n\t\t(revision === undefined || revision <= session.revision) &&\n\t\t(baseTreeHash === undefined || baseTreeHash === session.prefixHashes[entriesFrom])\n\t) {\n\t\tsendJson(res, 200, sessionTreePatchResponseBody(session, baseMessageCount, entriesFrom, revision));\n\t\treturn;\n\t}\n\tsendJson(res, 200, sessionHistoryFullResponseBody(session, baseMessageCount));\n}\n\nfunction handleSessionRun(sessionId: string, runId: string, res: ServerResponse): void {\n\tconst run = getStreamRun(sessionId, runId);\n\tif (!run) {\n\t\tsendError(res, 404, \"run not found\", PiServerErrorCode.RUN_NOT_FOUND);\n\t\treturn;\n\t}\n\tsendJson(res, 200, streamRunResponseBody(run));\n}\n\nasync function handleSessionRunAbort(sessionId: string, runId: string, res: ServerResponse): Promise<void> {\n\tif (!sessionId || !runId) {\n\t\tsendError(res, 400, \"sessionId and runId are required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\n\tlet run = getStreamRun(sessionId, runId);\n\tif (!run) {\n\t\trun = createRunRecord(sessionId, runId, \"stream\");\n\t\trun.status = \"aborted\";\n\t\trun.cancelRequested = true;\n\t\trun.errorMessage = \"Stream run aborted before it started\";\n\t\trun.updatedAt = Date.now();\n\t\tsettleRun(run);\n\t\tstreamRuns.set(runKey(sessionId, runId), run);\n\t\tsendJson(res, 200, streamRunResponseBody(run));\n\t\treturn;\n\t}\n\n\tif (run.status !== \"running\") {\n\t\tawait run.settled;\n\t\tsendJson(res, 200, streamRunResponseBody(run));\n\t\treturn;\n\t}\n\n\trun.cancelRequested = true;\n\trun.updatedAt = Date.now();\n\trun.controller.abort();\n\tawait run.settled;\n\tsendJson(res, 200, streamRunResponseBody(run));\n}\n\nexport function buildStreamContext(\n\tsession: SessionState,\n\tbody: Pick<StreamRequestBody, \"contextOverlay\" | \"ephemeralMessages\">,\n): Context {\n\tconst messages = body.contextOverlay ?? [...session.messages, ...(body.ephemeralMessages ?? [])];\n\treturn {\n\t\tsystemPrompt: session.staticContext?.systemPrompt,\n\t\tmessages,\n\t\ttools: session.staticContext?.tools,\n\t};\n}\n\nfunction handleStream(config: ServerConfig, body: StreamRequestBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!body.model) {\n\t\tsendError(res, 400, \"model is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\n\tcleanupExpiredStreamRuns(Date.now());\n\n\tconst session = getOrCreateSession(body.sessionId);\n\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t\tpersistSession(config, session);\n\t}\n\n\tif (!session.staticContext && !body.staticContext) {\n\t\tsendError(\n\t\t\tres,\n\t\t\t400,\n\t\t\t\"Session has no static context. Initialize with /api/session/init first.\",\n\t\t\tPiServerErrorCode.SESSION_NO_STATIC_CONTEXT,\n\t\t);\n\t\treturn;\n\t}\n\n\tif (body.ephemeralMessages !== undefined && !Array.isArray(body.ephemeralMessages)) {\n\t\tsendError(res, 400, \"ephemeralMessages must be an array\", PiServerErrorCode.INVALID_REQUEST);\n\t\treturn;\n\t}\n\tif (body.contextOverlay !== undefined && !Array.isArray(body.contextOverlay)) {\n\t\tsendError(res, 400, \"contextOverlay must be an array\", PiServerErrorCode.INVALID_REQUEST);\n\t\treturn;\n\t}\n\n\tconst context = buildStreamContext(session, body);\n\tconst existingRun = body.runId ? getStreamRun(body.sessionId, body.runId) : undefined;\n\n\tconst resolvedModel = body.model;\n\n\tif (existingRun?.status === \"completed\") {\n\t\tres.writeHead(200, {\n\t\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\t\"Cache-Control\": \"no-cache\",\n\t\t\tConnection: \"keep-alive\",\n\t\t});\n\t\tres.flushHeaders();\n\t\tres.write(STREAM_HEARTBEAT);\n\t\tfor (const event of replayStreamRun(existingRun)) {\n\t\t\twriteStreamEvent(res, event);\n\t\t}\n\t\tendStreamResponse(res);\n\t\treturn;\n\t}\n\tif (existingRun?.status === \"aborted\") {\n\t\tsendError(res, 409, \"The stream run was aborted\", PiServerErrorCode.INVALID_REQUEST);\n\t\treturn;\n\t}\n\tif (existingRun?.status === \"running\") {\n\t\tsendError(res, 409, \"A stream with this runId is already in progress\", PiServerErrorCode.RUN_IN_PROGRESS);\n\t\treturn;\n\t}\n\n\tconst run = body.runId ? startStreamRun(body.sessionId, body.runId) : undefined;\n\tconst streamOptions: SimpleStreamOptions = {\n\t\t...(body.options ?? {}),\n\t\t...(run ? { signal: run.controller.signal } : {}),\n\t};\n\n\tres.writeHead(200, {\n\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\"Cache-Control\": \"no-cache\",\n\t\tConnection: \"keep-alive\",\n\t});\n\tres.flushHeaders();\n\tres.write(STREAM_HEARTBEAT);\n\n\tconst heartbeat = setInterval(() => {\n\t\ttouchStreamRun(run);\n\t\tif (!res.writableEnded && !res.destroyed) {\n\t\t\tres.write(STREAM_HEARTBEAT);\n\t\t}\n\t}, STREAM_HEARTBEAT_INTERVAL_MS);\n\theartbeat.unref();\n\n\tlet stream: AsyncIterable<AssistantMessageEvent>;\n\ttry {\n\t\tstream = streamSimple(resolvedModel, context, streamOptions);\n\t} catch (err) {\n\t\tclearInterval(heartbeat);\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tfailStreamRun(run, message);\n\t\tsettleRun(run);\n\t\twriteStreamError(res, message);\n\t\tendStreamResponse(res);\n\t\treturn;\n\t}\n\n\tvoid (async () => {\n\t\ttry {\n\t\t\tfor await (const event of stream) {\n\t\t\t\tconst proxyEvent = toProxyEvent(event);\n\t\t\t\tif (proxyEvent) {\n\t\t\t\t\ttouchStreamRun(run);\n\t\t\t\t\twriteStreamEvent(res, proxyEvent);\n\t\t\t\t}\n\t\t\t\tif (event.type === \"done\") {\n\t\t\t\t\tcompleteStreamRun(run, event.message);\n\t\t\t\t} else if (event.type === \"error\") {\n\t\t\t\t\tfailStreamRun(run, event.error.errorMessage ?? event.reason);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tfailStreamRun(run, message);\n\t\t\twriteStreamError(res, message);\n\t\t} finally {\n\t\t\tclearInterval(heartbeat);\n\t\t\tif (run?.status === \"running\") {\n\t\t\t\tfailStreamRun(run, run.cancelRequested ? \"Stream run aborted\" : \"Stream ended before a terminal event\");\n\t\t\t}\n\t\t\tsettleRun(run);\n\t\t\tendStreamResponse(res);\n\t\t}\n\t})();\n}\n\nasync function handlePostRequest(\n\tconfig: ServerConfig,\n\tpathname: string,\n\tbody: unknown,\n\tres: ServerResponse,\n): Promise<boolean> {\n\tif (pathname === \"/api/receive\") {\n\t\ttry {\n\t\t\tsendJson(res, 200, receiveUpload(config.uploadDir, body));\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof ReceiveUploadError)) throw error;\n\t\t\tsendJson(res, error.status, { error: error.message });\n\t\t}\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/init\") {\n\t\thandleSessionInit(config, body as SessionInitBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/update\") {\n\t\thandleSessionUpdate(config, body as SessionInitBody & { staticContext: SessionStaticContext }, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/sync\") {\n\t\thandleSessionSync(config, body as SessionSyncBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/append\") {\n\t\thandleSessionAppend(config, body as SessionAppendBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/tree/sync\") {\n\t\thandleSessionTreeSync(config, body as SessionTreeSyncBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/tree/append\") {\n\t\thandleSessionTreeAppend(config, body as SessionTreeSyncBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/tree/switch\") {\n\t\thandleSessionTreeSwitch(config, body as SessionTreeSwitchBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/compact\") {\n\t\tawait handleSessionCompact(config, body as SessionCompactBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/stream\") {\n\t\thandleStream(config, body as StreamRequestBody, res);\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nexport function createPiServer(configOverride?: Partial<ServerConfig>): HttpServer {\n\tconst config = loadConfig(configOverride);\n\tloadPersistedSessions(config.sessionStoreDir);\n\n\tconst server = createServer(async (req, res) => {\n\t\tconst url = new URL(req.url ?? \"/\", \"http://localhost\");\n\n\t\tif (req.method === \"GET\" && url.pathname === \"/health\") {\n\t\t\tsendJson(res, 200, { status: \"ok\" });\n\t\t\treturn;\n\t\t}\n\n\t\tif (!authenticate(config, req)) {\n\t\t\tconst body =\n\t\t\t\treq.method === \"GET\" && url.pathname === \"/\"\n\t\t\t\t\t? { error: \"Unauthorized\", version: PI_SERVER_VERSION }\n\t\t\t\t\t: { error: \"Unauthorized\" };\n\t\t\tsendJson(res, 401, body);\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"GET\" && url.pathname === \"/api/sessions\") {\n\t\t\tsendJson(res, 200, { sessions: listSessions() });\n\t\t\treturn;\n\t\t}\n\n\t\tconst runMatch = /^\\/api\\/session\\/([^/]+)\\/runs\\/([^/]+)$/.exec(url.pathname);\n\t\tif (req.method === \"GET\" && runMatch) {\n\t\t\thandleSessionRun(decodeURIComponent(runMatch[1]), decodeURIComponent(runMatch[2]), res);\n\t\t\treturn;\n\t\t}\n\n\t\tconst runAbortMatch = /^\\/api\\/session\\/([^/]+)\\/runs\\/([^/]+)\\/abort$/.exec(url.pathname);\n\t\tif (req.method === \"POST\" && runAbortMatch) {\n\t\t\tawait readBody(req);\n\t\t\tawait handleSessionRunAbort(decodeURIComponent(runAbortMatch[1]), decodeURIComponent(runAbortMatch[2]), res);\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"GET\" && url.pathname.startsWith(\"/api/session/\") && url.pathname.endsWith(\"/history\")) {\n\t\t\tconst encodedSessionId = url.pathname.slice(\"/api/session/\".length, -\"/history\".length);\n\t\t\tconst fromParam = url.searchParams.get(\"from\");\n\t\t\tconst from = fromParam === null ? undefined : Number(fromParam);\n\t\t\tif (from !== undefined && (!Number.isInteger(from) || from < 0)) {\n\t\t\t\tsendError(res, 400, \"from must be a non-negative integer\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst entriesFromParam = url.searchParams.get(\"entriesFrom\");\n\t\t\tconst entriesFrom = entriesFromParam === null ? undefined : Number(entriesFromParam);\n\t\t\tif (entriesFrom !== undefined && (!Number.isInteger(entriesFrom) || entriesFrom < 0)) {\n\t\t\t\tsendError(res, 400, \"entriesFrom must be a non-negative integer\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst revisionParam = url.searchParams.get(\"revision\");\n\t\t\tconst revision = revisionParam === null ? undefined : Number(revisionParam);\n\t\t\tif (revision !== undefined && (!Number.isInteger(revision) || revision < 0)) {\n\t\t\t\tsendError(res, 400, \"revision must be a non-negative integer\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thandleSessionHistory(\n\t\t\t\tdecodeURIComponent(encodedSessionId),\n\t\t\t\tfrom,\n\t\t\t\tentriesFrom,\n\t\t\t\trevision,\n\t\t\t\turl.searchParams.get(\"baseTreeHash\") ?? undefined,\n\t\t\t\tres,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"POST\" && url.pathname === CHUNK_ENDPOINT) {\n\t\t\ttry {\n\t\t\t\tconst body = JSON.parse(await readBody(req)) as RequestChunkBody;\n\t\t\t\tconst chunkResult = receiveRequestChunk(body);\n\t\t\t\tif (!chunkResult.complete) {\n\t\t\t\t\tsendJson(res, 200, chunkResult.ack);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst handled = await handlePostRequest(\n\t\t\t\t\tconfig,\n\t\t\t\t\tchunkResult.target,\n\t\t\t\t\tJSON.parse(chunkResult.bodyJson) as unknown,\n\t\t\t\t\tres,\n\t\t\t\t);\n\t\t\t\tif (!handled && !res.headersSent) {\n\t\t\t\t\tsendError(res, 404, \"Not found\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tlogRequestError(req, err);\n\t\t\t\tif (!res.headersSent) {\n\t\t\t\t\tsendError(res, 400, err instanceof Error ? err.message : String(err), PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\t} else {\n\t\t\t\t\tres.write(encodeErrorEvent(err instanceof Error ? err.message : String(err)));\n\t\t\t\t\tres.end();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"POST\") {\n\t\t\ttry {\n\t\t\t\tconst body = JSON.parse(await readBody(req)) as unknown;\n\t\t\t\tif (await handlePostRequest(config, url.pathname, body, res)) return;\n\t\t\t\tif (!res.headersSent) {\n\t\t\t\t\tsendError(res, 404, \"Not found\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tlogRequestError(req, err);\n\t\t\t\tif (!res.headersSent) {\n\t\t\t\t\tsendError(res, 500, err instanceof Error ? err.message : String(err), PiServerErrorCode.INTERNAL_ERROR);\n\t\t\t\t} else {\n\t\t\t\t\tres.write(encodeErrorEvent(err instanceof Error ? err.message : String(err)));\n\t\t\t\t\tres.end();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif (req.method === \"DELETE\" && url.pathname.startsWith(\"/api/session/\")) {\n\t\t\tconst sessionId = decodeURIComponent(url.pathname.slice(\"/api/session/\".length));\n\t\t\tdeleteSessionFromStore(sessionId);\n\t\t\tdeleteStreamRunsForSession(sessionId);\n\t\t\tdeletePersistedSession(config.sessionStoreDir, sessionId);\n\t\t\tsendJson(res, 200, { deleted: sessionId });\n\t\t\treturn;\n\t\t}\n\n\t\tsendError(res, 404, \"Not found\", PiServerErrorCode.INVALID_REQUEST);\n\t});\n\n\treturn server;\n}\n\nfunction toProxyEvent(event: AssistantMessageEvent): ProxyAssistantMessageEvent | undefined {\n\tswitch (event.type) {\n\t\tcase \"start\":\n\t\t\treturn { type: \"start\" };\n\t\tcase \"text_start\":\n\t\t\treturn { type: \"text_start\", contentIndex: event.contentIndex };\n\t\tcase \"text_delta\":\n\t\t\treturn { type: \"text_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\tcase \"text_end\":\n\t\t\treturn {\n\t\t\t\ttype: \"text_end\",\n\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\tcontentSignature:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"text\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { textSignature?: string }).textSignature\n\t\t\t\t\t\t: undefined,\n\t\t\t};\n\t\tcase \"thinking_start\":\n\t\t\treturn { type: \"thinking_start\", contentIndex: event.contentIndex };\n\t\tcase \"thinking_delta\":\n\t\t\treturn { type: \"thinking_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\tcase \"thinking_end\":\n\t\t\treturn {\n\t\t\t\ttype: \"thinking_end\",\n\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\tcontentSignature:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"thinking\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { thinkingSignature?: string }).thinkingSignature\n\t\t\t\t\t\t: undefined,\n\t\t\t};\n\t\tcase \"toolcall_start\":\n\t\t\treturn {\n\t\t\t\ttype: \"toolcall_start\",\n\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\tid:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"toolCall\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { id: string }).id\n\t\t\t\t\t\t: \"\",\n\t\t\t\ttoolName:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"toolCall\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { name: string }).name\n\t\t\t\t\t\t: \"\",\n\t\t\t};\n\t\tcase \"toolcall_delta\":\n\t\t\treturn { type: \"toolcall_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\tcase \"toolcall_end\":\n\t\t\treturn { type: \"toolcall_end\", contentIndex: event.contentIndex, toolCall: event.toolCall };\n\t\tcase \"done\":\n\t\t\treturn {\n\t\t\t\ttype: \"done\",\n\t\t\t\treason: event.reason,\n\t\t\t\tusage: event.message.usage,\n\t\t\t\tdeferred: event.message.deferred,\n\t\t\t\tmessage: event.message,\n\t\t\t};\n\t\tcase \"error\":\n\t\t\treturn {\n\t\t\t\ttype: \"error\",\n\t\t\t\treason: event.reason,\n\t\t\t\terrorMessage: event.error.errorMessage,\n\t\t\t\tusage: event.error.usage,\n\t\t\t};\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nexport function startServer(configOverride?: Partial<ServerConfig>): HttpServer {\n\tconst config = loadConfig(configOverride);\n\tconst server = createPiServer(configOverride);\n\tserver.listen(config.port, config.host, () => {\n\t\tconst address = server.address();\n\t\tconst port = typeof address === \"object\" && address !== null ? address.port : config.port;\n\t\tconst host = config.host.includes(\":\") && !config.host.startsWith(\"[\") ? `[${config.host}]` : config.host;\n\t\tconsole.log(`pi-server listening on ${host}:${port}`);\n\t});\n\treturn server;\n}\n"]}
package/dist/server.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import { createServer } from "node:http";
2
2
  import { createRequire } from "node:module";
3
- import { compactLegacy, DEFAULT_COMPACTION_SETTINGS, prepareLegacyCompaction, } from "@earendil-works/pi-agent-core";
3
+ import { compactLegacy, convertToLlm, DEFAULT_COMPACTION_SETTINGS, prepareLegacyCompaction, } from "@earendil-works/pi-agent-core";
4
4
  import { createModels, createProvider, } from "@earendil-works/pi-ai";
5
5
  import { streamSimple } from "@earendil-works/pi-ai/compat";
6
6
  import { loadConfig } from "./config.js";
7
7
  import { PiServerError, PiServerErrorCode } from "./error-codes.js";
8
8
  import { encodeErrorEvent, encodeProxyEvent } from "./event-encoding.js";
9
+ import { hashPiServerProviderMessages } from "./pi-server-protocol.js";
9
10
  import { ReceiveUploadError, receiveUpload } from "./receive-upload.js";
10
11
  import { CHUNK_ENDPOINT, receiveRequestChunk } from "./request-chunks.js";
11
12
  import { deletePersistedSession, loadPersistedSessions, savePersistedSession } from "./session-persistence.js";
@@ -417,6 +418,13 @@ function prepareSessionCompact(body) {
417
418
  if (!body.model) {
418
419
  return { status: 400, body: { error: "model is required" } };
419
420
  }
421
+ const validDigest = (value) => value === undefined || /^[a-f0-9]{64}$/.test(value);
422
+ if (!validDigest(body.cacheContextHash) || !validDigest(body.cacheStaticContextHash)) {
423
+ return { status: 400, body: { error: "cache context digests must be 64-character SHA-256 hex strings" } };
424
+ }
425
+ if ((body.cacheContextHash === undefined) !== (body.cacheStaticContextHash === undefined)) {
426
+ return { status: 400, body: { error: "cacheContextHash and cacheStaticContextHash must be supplied together" } };
427
+ }
420
428
  const session = getSession(body.sessionId);
421
429
  if (!session) {
422
430
  return { status: 404, body: { error: "session not found", code: PiServerErrorCode.SESSION_NOT_FOUND } };
@@ -452,6 +460,36 @@ function prepareSessionCompact(body) {
452
460
  return { status: 400, body: { error: "Nothing to compact" } };
453
461
  }
454
462
  const options = body.options ?? {};
463
+ let cacheContext;
464
+ let cacheFallbackReason = body.cacheFallbackReason ?? "cache_context_digest_missing";
465
+ if (body.cacheContextHash && body.cacheStaticContextHash) {
466
+ if (options.sessionId !== session.sessionId) {
467
+ cacheFallbackReason = "session_id_mismatch";
468
+ }
469
+ else if (options.cacheRetention === "none") {
470
+ cacheFallbackReason = "prompt_cache_disabled";
471
+ }
472
+ else if (body.cacheStaticContextHash !== session.staticContextHash) {
473
+ cacheFallbackReason = "static_context_hash_mismatch";
474
+ }
475
+ else {
476
+ const projectedMessages = convertToLlm(session.messages);
477
+ const priorAssistant = [...session.messages].reverse().find((message) => message.role === "assistant");
478
+ if (hashPiServerProviderMessages(projectedMessages) !== body.cacheContextHash) {
479
+ cacheFallbackReason = "request_context_digest_mismatch";
480
+ }
481
+ else if (!priorAssistant ||
482
+ priorAssistant.provider !== body.model.provider ||
483
+ priorAssistant.model !== body.model.id ||
484
+ priorAssistant.api !== body.model.api) {
485
+ cacheFallbackReason = "summary_model_mismatch";
486
+ }
487
+ else {
488
+ cacheContext = buildStreamContext(session, { contextOverlay: projectedMessages });
489
+ cacheFallbackReason = "exact_prefix_unavailable";
490
+ }
491
+ }
492
+ }
455
493
  return {
456
494
  session,
457
495
  sessionId: session.sessionId,
@@ -461,6 +499,8 @@ function prepareSessionCompact(body) {
461
499
  entryCount: session.entries.length,
462
500
  preparation: preparationResult.value,
463
501
  options,
502
+ cacheContext,
503
+ cacheFallbackReason,
464
504
  };
465
505
  }
466
506
  function sessionCompactConflict(body, prepared, currentSession) {
@@ -482,7 +522,7 @@ function sessionCompactConflict(body, prepared, currentSession) {
482
522
  };
483
523
  }
484
524
  async function completeSessionCompact(config, body, prepared, run) {
485
- const result = await compactLegacy(prepared.preparation, createRequestModels(body.model, prepared.options), body.model, body.customInstructions, run?.controller.signal, prepared.options.reasoning);
525
+ const result = await compactLegacy(prepared.preparation, createRequestModels(body.model, prepared.options), body.model, body.customInstructions, run?.controller.signal, prepared.options.reasoning, undefined, undefined, prepared.cacheContext, prepared.options, prepared.cacheFallbackReason);
486
526
  if (!result.ok) {
487
527
  return { status: 500, body: { error: result.error.message, code: PiServerErrorCode.INTERNAL_ERROR } };
488
528
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer, type Server as HttpServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { createRequire } from \"node:module\";\nimport {\n\ttype CompactionPreparationOptions,\n\ttype CompactionSettings,\n\tcompactLegacy,\n\tDEFAULT_COMPACTION_SETTINGS,\n\ttype LegacyCompactResult,\n\ttype ProxyAssistantMessageEvent,\n\tprepareLegacyCompaction,\n\ttype SessionTreeEntry,\n} from \"@earendil-works/pi-agent-core\";\nimport {\n\ttype AssistantMessage,\n\ttype AssistantMessageEvent,\n\ttype Context,\n\tcreateModels,\n\tcreateProvider,\n\ttype Message,\n\ttype Model,\n\ttype ProviderStreams,\n\ttype SimpleStreamOptions,\n} from \"@earendil-works/pi-ai\";\nimport { streamSimple } from \"@earendil-works/pi-ai/compat\";\nimport type { ServerConfig } from \"./config.ts\";\nimport { loadConfig } from \"./config.ts\";\nimport { PiServerError, PiServerErrorCode, type PiServerErrorResponse } from \"./error-codes.ts\";\nimport { encodeErrorEvent, encodeProxyEvent } from \"./event-encoding.ts\";\nimport { ReceiveUploadError, receiveUpload } from \"./receive-upload.ts\";\nimport { CHUNK_ENDPOINT, type RequestChunkBody, receiveRequestChunk } from \"./request-chunks.ts\";\nimport { deletePersistedSession, loadPersistedSessions, savePersistedSession } from \"./session-persistence.ts\";\nimport {\n\tappendCompactionEntry,\n\tappendMessages,\n\tappendSessionEntries,\n\tdeleteSession as deleteSessionFromStore,\n\tgetOrCreateSession,\n\tgetSession,\n\tgetSessionBranch,\n\tlistSessions,\n\treplaceMessages,\n\treplaceSessionTree,\n\ttype SessionState,\n\ttype SessionStaticContext,\n\tsetStaticContext,\n\tswitchSessionLeaf,\n} from \"./session-store.ts\";\n\nexport { loadConfig, type ServerConfig } from \"./config.ts\";\n\ninterface PackageMetadata {\n\tversion: string;\n}\n\nconst packageMetadata = createRequire(import.meta.url)(\"../package.json\") as PackageMetadata;\nconst PI_SERVER_VERSION = packageMetadata.version;\n\ninterface SessionInitBody {\n\tsessionId: string;\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface StreamRequestBody {\n\tsessionId: string;\n\trunId?: string;\n\tmodel: Model<any>;\n\toptions?: SimpleStreamOptions;\n\tstaticContext?: SessionStaticContext;\n\tephemeralMessages?: Message[];\n\tcontextOverlay?: Message[];\n}\n\ninterface SessionSyncBody {\n\tsessionId: string;\n\tmessages: Message[];\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface SessionAppendBody {\n\tsessionId: string;\n\tmessages: Message[];\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface SessionTreeSyncBody {\n\tsessionId: string;\n\tentries: SessionTreeEntry[];\n\tleafId: string | null;\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface SessionTreeSwitchBody {\n\tsessionId: string;\n\tleafId: string | null;\n}\n\ninterface SessionCompactBody {\n\tsessionId: string;\n\trunId?: string;\n\tmodel: Model<any>;\n\toptions?: SimpleStreamOptions;\n\tsettings?: CompactionSettings;\n\tpreparation?: CompactionPreparationOptions;\n\tcustomInstructions?: string;\n\tbaseTreeHash?: string;\n\tfullResponse?: boolean;\n\tstreamResponse?: boolean;\n}\n\nfunction createRequestModels(model: Model<any>, options: SimpleStreamOptions) {\n\tconst models = createModels();\n\tconst requestStream: ProviderStreams[\"streamSimple\"] = (requestModel, context, streamOptions) =>\n\t\tstreamSimple(requestModel, context, {\n\t\t\t...streamOptions,\n\t\t\t...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n\t\t});\n\tmodels.setProvider(\n\t\tcreateProvider({\n\t\t\tid: model.provider,\n\t\t\tname: model.provider,\n\t\t\tmodels: [model],\n\t\t\tauth: {\n\t\t\t\tapiKey: {\n\t\t\t\t\tname: \"pi-server request auth\",\n\t\t\t\t\tresolve: async () => ({ auth: { apiKey: options.apiKey, headers: options.headers } }),\n\t\t\t\t},\n\t\t\t},\n\t\t\tapi: {\n\t\t\t\tstream: requestStream,\n\t\t\t\tstreamSimple: requestStream,\n\t\t\t},\n\t\t}),\n\t);\n\treturn models;\n}\n\ninterface StreamRunRecord {\n\tsessionId: string;\n\trunId: string;\n\tkind: \"stream\" | \"compact\";\n\tstatus: \"running\" | \"completed\" | \"failed\" | \"aborted\";\n\tmessage?: AssistantMessage;\n\tcompactResult?: SessionCompactSuccessBody;\n\terrorMessage?: string;\n\tcreatedAt: number;\n\tupdatedAt: number;\n\tcancelRequested: boolean;\n\tcontroller: AbortController;\n\tsettled: Promise<void>;\n\tresolveSettled: (() => void) | undefined;\n}\n\nconst STREAM_HEARTBEAT = \": keep-alive\\n\\n\";\nconst JSON_HEARTBEAT = \" \\n\";\nconst STREAM_HEARTBEAT_INTERVAL_MS = 25_000;\nconst STREAM_RUN_TTL_MS = 60 * 60 * 1000; // 1 hour\nconst streamRuns = new Map<string, StreamRunRecord>();\n\nfunction readBody(req: IncomingMessage): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst chunks: Buffer[] = [];\n\t\treq.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n\t\treq.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf-8\")));\n\t\treq.on(\"error\", reject);\n\t});\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n\tconst data = JSON.stringify(body);\n\tres.writeHead(status, { \"Content-Type\": \"application/json\", \"Content-Length\": Buffer.byteLength(data) });\n\tres.end(data);\n}\n\nfunction sendError(\n\tres: ServerResponse,\n\tstatus: number,\n\tmessage: string,\n\tcode?: PiServerErrorCode,\n\tdetails?: Record<string, unknown>,\n): void {\n\tconst body: PiServerErrorResponse = { error: message };\n\tif (code) body.code = code;\n\tif (details) body.details = details;\n\tsendJson(res, status, body);\n}\n\nfunction logRequestError(req: IncomingMessage, error: unknown): void {\n\tconst message = error instanceof Error ? error.stack || error.message : String(error);\n\tconsole.error(`${req.method ?? \"UNKNOWN\"} ${req.url ?? \"/\"} failed: ${message}`);\n}\n\nfunction authenticate(config: ServerConfig, req: IncomingMessage): boolean {\n\tif (!config.authToken) return true;\n\tconst header = req.headers.authorization;\n\tif (!header) return false;\n\tconst token = header.startsWith(\"Bearer \") ? header.slice(7) : header;\n\treturn token === config.authToken;\n}\n\nfunction sessionResponseBody(session: SessionState) {\n\treturn {\n\t\tsessionId: session.sessionId,\n\t\tstaticContextHash: session.staticContextHash,\n\t\ttreeHash: session.treeHash,\n\t\tmessageCount: session.messages.length,\n\t\tentryCount: session.entries.length,\n\t\tleafId: session.leafId,\n\t\trevision: session.revision,\n\t};\n}\n\nfunction persistSession(config: ServerConfig, session: SessionState): void {\n\tsavePersistedSession(config.sessionStoreDir, session);\n}\n\nfunction runKey(sessionId: string, runId: string): string {\n\treturn `${sessionId}\\0${runId}`;\n}\n\nfunction getStreamRun(sessionId: string, runId: string): StreamRunRecord | undefined {\n\treturn streamRuns.get(runKey(sessionId, runId));\n}\n\nfunction createRunRecord(sessionId: string, runId: string, kind: StreamRunRecord[\"kind\"]): StreamRunRecord {\n\tlet resolveSettled: (() => void) | undefined;\n\tconst settled = new Promise<void>((resolve) => {\n\t\tresolveSettled = resolve;\n\t});\n\treturn {\n\t\tsessionId,\n\t\trunId,\n\t\tkind,\n\t\tstatus: \"running\",\n\t\tcreatedAt: Date.now(),\n\t\tupdatedAt: Date.now(),\n\t\tcancelRequested: false,\n\t\tcontroller: new AbortController(),\n\t\tsettled,\n\t\tresolveSettled,\n\t};\n}\n\nfunction settleRun(run: StreamRunRecord | undefined): void {\n\tif (!run) return;\n\tconst resolve = run.resolveSettled;\n\trun.resolveSettled = undefined;\n\tresolve?.();\n}\n\nfunction startStreamRun(sessionId: string, runId: string, kind: StreamRunRecord[\"kind\"] = \"stream\"): StreamRunRecord {\n\tconst existing = getStreamRun(sessionId, runId);\n\tif (existing?.status === \"completed\" || existing?.status === \"aborted\") return existing;\n\tconst run = existing ?? createRunRecord(sessionId, runId, kind);\n\tif (existing) {\n\t\trun.message = undefined;\n\t\trun.errorMessage = undefined;\n\t\trun.cancelRequested = false;\n\t\trun.controller = new AbortController();\n\t\tlet resolveSettled: (() => void) | undefined;\n\t\trun.settled = new Promise<void>((resolve) => {\n\t\t\tresolveSettled = resolve;\n\t\t});\n\t\trun.resolveSettled = resolveSettled;\n\t}\n\trun.kind = kind;\n\trun.status = \"running\";\n\trun.updatedAt = Date.now();\n\tstreamRuns.set(runKey(sessionId, runId), run);\n\treturn run;\n}\n\nfunction streamRunResponseBody(run: StreamRunRecord) {\n\treturn {\n\t\tsessionId: run.sessionId,\n\t\trunId: run.runId,\n\t\tstatus: run.status,\n\t\tcreatedAt: run.createdAt,\n\t\tupdatedAt: run.updatedAt,\n\t\t...(run.message ? { message: run.message } : {}),\n\t\t...(run.compactResult ? { compactResult: run.compactResult } : {}),\n\t\t...(run.errorMessage ? { errorMessage: run.errorMessage } : {}),\n\t};\n}\n\nfunction replayStreamRun(run: StreamRunRecord): ProxyAssistantMessageEvent[] {\n\tif (!run.message) return [];\n\tif (\n\t\trun.message.stopReason !== \"stop\" &&\n\t\trun.message.stopReason !== \"length\" &&\n\t\trun.message.stopReason !== \"toolUse\" &&\n\t\trun.message.stopReason !== \"deferred\"\n\t) {\n\t\treturn [];\n\t}\n\tconst events: ProxyAssistantMessageEvent[] = [{ type: \"start\" }];\n\tfor (const [contentIndex, content] of run.message.content.entries()) {\n\t\tswitch (content.type) {\n\t\t\tcase \"text\":\n\t\t\t\tevents.push(\n\t\t\t\t\t{ type: \"text_start\", contentIndex },\n\t\t\t\t\t{ type: \"text_delta\", contentIndex, delta: content.text },\n\t\t\t\t\t{ type: \"text_end\", contentIndex, contentSignature: content.textSignature },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"thinking\":\n\t\t\t\tevents.push(\n\t\t\t\t\t{ type: \"thinking_start\", contentIndex },\n\t\t\t\t\t{ type: \"thinking_delta\", contentIndex, delta: content.thinking },\n\t\t\t\t\t{ type: \"thinking_end\", contentIndex, contentSignature: content.thinkingSignature },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"toolCall\":\n\t\t\t\tevents.push(\n\t\t\t\t\t{ type: \"toolcall_start\", contentIndex, id: content.id, toolName: content.name },\n\t\t\t\t\t{ type: \"toolcall_delta\", contentIndex, delta: JSON.stringify(content.arguments) },\n\t\t\t\t\t{ type: \"toolcall_end\", contentIndex, toolCall: content },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tevents.push({\n\t\ttype: \"done\",\n\t\treason: run.message.stopReason,\n\t\tusage: run.message.usage,\n\t\tdeferred: run.message.deferred,\n\t\tmessage: run.message,\n\t});\n\treturn events;\n}\n\nfunction completeStreamRun(run: StreamRunRecord | undefined, message: AssistantMessage): void {\n\tif (!run) return;\n\tif (run.cancelRequested) {\n\t\trun.status = \"aborted\";\n\t\trun.message = undefined;\n\t\trun.errorMessage = \"Stream run aborted\";\n\t\trun.updatedAt = Date.now();\n\t\treturn;\n\t}\n\trun.status = \"completed\";\n\trun.message = message;\n\trun.errorMessage = undefined;\n\trun.updatedAt = Date.now();\n}\n\nfunction failStreamRun(run: StreamRunRecord | undefined, errorMessage: string): void {\n\tif (!run) return;\n\tif (run.cancelRequested) {\n\t\trun.status = \"aborted\";\n\t\trun.errorMessage = \"Stream run aborted\";\n\t\trun.updatedAt = Date.now();\n\t\treturn;\n\t}\n\trun.status = \"failed\";\n\trun.errorMessage = errorMessage;\n\trun.updatedAt = Date.now();\n}\n\nfunction touchStreamRun(run: StreamRunRecord | undefined): void {\n\tif (run) run.updatedAt = Date.now();\n}\n\nfunction writeStreamEvent(res: ServerResponse, event: ProxyAssistantMessageEvent): void {\n\tif (!res.writableEnded && !res.destroyed) {\n\t\tres.write(encodeProxyEvent(event));\n\t}\n}\n\nfunction writeStreamError(res: ServerResponse, message: string): void {\n\tif (!res.writableEnded && !res.destroyed) {\n\t\tres.write(encodeErrorEvent(message));\n\t}\n}\n\nfunction endStreamResponse(res: ServerResponse): void {\n\tif (!res.writableEnded && !res.destroyed) {\n\t\tres.end();\n\t}\n}\n\nfunction cleanupExpiredStreamRuns(nowMs: number): void {\n\tfor (const [key, run] of streamRuns) {\n\t\tif (nowMs - run.updatedAt > STREAM_RUN_TTL_MS) {\n\t\t\tstreamRuns.delete(key);\n\t\t}\n\t}\n}\n\nfunction deleteStreamRunsForSession(sessionId: string): void {\n\tfor (const [key, run] of streamRuns) {\n\t\tif (run.sessionId === sessionId) streamRuns.delete(key);\n\t}\n}\n\nconst streamRunCleanupTimer = setInterval(() => cleanupExpiredStreamRuns(Date.now()), STREAM_RUN_TTL_MS / 4);\nstreamRunCleanupTimer.unref();\n\nfunction sessionHistoryFullResponseBody(session: SessionState, baseMessageCount: number) {\n\treturn {\n\t\tsessionId: session.sessionId,\n\t\tstaticContext: session.staticContext,\n\t\tstaticContextHash: session.staticContextHash,\n\t\ttreeHash: session.treeHash,\n\t\tmessageCount: session.messages.length,\n\t\tentryCount: session.entries.length,\n\t\tleafId: session.leafId,\n\t\trevision: session.revision,\n\t\tentries: session.entries,\n\t\tbaseMessageCount,\n\t\tmessages: session.messages.slice(baseMessageCount),\n\t};\n}\n\nfunction sessionTreePatchResponseBody(\n\tsession: SessionState,\n\tbaseMessageCount: number,\n\tentriesFrom: number,\n\tbaseRevision: number | undefined,\n) {\n\treturn {\n\t\tsessionId: session.sessionId,\n\t\tstaticContext: session.staticContext,\n\t\tstaticContextHash: session.staticContextHash,\n\t\ttreeHash: session.treeHash,\n\t\tmessageCount: session.messages.length,\n\t\tentryCount: session.entries.length,\n\t\tleafId: session.leafId,\n\t\trevision: session.revision,\n\t\tbaseMessageCount,\n\t\tmessages: session.messages.slice(baseMessageCount),\n\t\ttreePatch: {\n\t\t\tentriesFrom,\n\t\t\tbaseRevision,\n\t\t\tentries: session.entries.slice(entriesFrom),\n\t\t\tleafId: session.leafId,\n\t\t\trevision: session.revision,\n\t\t},\n\t};\n}\n\ntype PreparedCompaction = Parameters<typeof compactLegacy>[0];\n\ninterface PreparedSessionCompact {\n\tsession: SessionState;\n\tsessionId: string;\n\trevision: number;\n\ttreeHash: string;\n\tleafId: string | null;\n\tentryCount: number;\n\tpreparation: PreparedCompaction;\n\toptions: SimpleStreamOptions;\n}\n\ninterface SessionCompactSuccessBody {\n\tsuccess: true;\n\tcompaction: Omit<LegacyCompactResult, \"retainedTail\">;\n\tcompactionEntry: SessionTreeEntry;\n\tsessionId: string;\n\tstaticContextHash: string;\n\ttreeHash: string;\n\tmessageCount: number;\n\tentryCount: number;\n\tleafId: string | null;\n\trevision: number;\n\tstaticContext?: SessionStaticContext;\n\ttreePatch?: {\n\t\tbaseTreeHash: string;\n\t\tentriesFrom: number;\n\t\tentries: SessionTreeEntry[];\n\t\tleafId: string | null;\n\t\trevision: number;\n\t};\n\tentries?: SessionTreeEntry[];\n\tmessages?: Message[];\n}\n\ninterface SessionCompactHttpResponse {\n\tstatus: number;\n\tbody: PiServerErrorResponse | SessionCompactSuccessBody;\n}\n\nfunction handleSessionInit(config: ServerConfig, body: SessionInitBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t} else {\n\t\tgetOrCreateSession(body.sessionId);\n\t}\n\tconst session = getSession(body.sessionId)!;\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionUpdate(\n\tconfig: ServerConfig,\n\tbody: SessionInitBody & { staticContext: SessionStaticContext },\n\tres: ServerResponse,\n): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!body.staticContext) {\n\t\tsendError(res, 400, \"staticContext is required for update\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tsetStaticContext(body.sessionId, body.staticContext);\n\tconst session = getSession(body.sessionId)!;\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionSync(config: ServerConfig, body: SessionSyncBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.messages)) {\n\t\tsendError(res, 400, \"messages is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t}\n\tconst session = replaceMessages(body.sessionId, body.messages);\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionAppend(config: ServerConfig, body: SessionAppendBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.messages)) {\n\t\tsendError(res, 400, \"messages is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t}\n\tconst session = appendMessages(body.sessionId, body.messages);\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionTreeSync(config: ServerConfig, body: SessionTreeSyncBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.entries)) {\n\t\tsendError(res, 400, \"entries is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t}\n\tconst session = replaceSessionTree(body.sessionId, body.entries, body.leafId ?? null);\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionTreeAppend(config: ServerConfig, body: SessionTreeSyncBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.entries)) {\n\t\tsendError(res, 400, \"entries is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\ttry {\n\t\tif (body.staticContext) {\n\t\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t\t}\n\t\tconst session = appendSessionEntries(body.sessionId, body.entries, body.leafId ?? null);\n\t\tpersistSession(config, session);\n\t\tsendJson(res, 200, sessionResponseBody(session));\n\t} catch (error) {\n\t\tif (error instanceof PiServerError) {\n\t\t\tsendError(res, 400, error.message, error.code, error.details);\n\t\t} else {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tsendError(res, 500, message, PiServerErrorCode.INTERNAL_ERROR);\n\t\t}\n\t}\n}\n\nfunction handleSessionTreeSwitch(config: ServerConfig, body: SessionTreeSwitchBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\ttry {\n\t\tconst session = switchSessionLeaf(body.sessionId, body.leafId ?? null);\n\t\tpersistSession(config, session);\n\t\tsendJson(res, 200, sessionResponseBody(session));\n\t} catch (error) {\n\t\tif (error instanceof PiServerError) {\n\t\t\tsendError(res, 400, error.message, error.code, error.details);\n\t\t} else {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tsendError(res, 500, message, PiServerErrorCode.INTERNAL_ERROR);\n\t\t}\n\t}\n}\n\nfunction prepareSessionCompact(body: SessionCompactBody): PreparedSessionCompact | SessionCompactHttpResponse {\n\tif (!body.sessionId) {\n\t\treturn { status: 400, body: { error: \"sessionId is required\" } };\n\t}\n\tif (!body.model) {\n\t\treturn { status: 400, body: { error: \"model is required\" } };\n\t}\n\n\tconst session = getSession(body.sessionId);\n\tif (!session) {\n\t\treturn { status: 404, body: { error: \"session not found\", code: PiServerErrorCode.SESSION_NOT_FOUND } };\n\t}\n\n\tconst entries = getSessionBranch(session);\n\tconst leaf = entries.at(-1);\n\tif (leaf?.type === \"compaction\") {\n\t\tif (!leaf.firstKeptEntryId) {\n\t\t\treturn { status: 400, body: { error: \"Stored compaction is missing firstKeptEntryId\" } };\n\t\t}\n\t\treturn {\n\t\t\tstatus: 200,\n\t\t\tbody: {\n\t\t\t\tsuccess: true,\n\t\t\t\tcompaction: {\n\t\t\t\t\tsummary: leaf.summary,\n\t\t\t\t\tfirstKeptEntryId: leaf.firstKeptEntryId,\n\t\t\t\t\ttokensBefore: leaf.tokensBefore,\n\t\t\t\t\tdetails: leaf.details,\n\t\t\t\t},\n\t\t\t\tcompactionEntry: leaf,\n\t\t\t\t...sessionResponseBody(session),\n\t\t\t\tentries: session.entries,\n\t\t\t\tmessages: session.messages,\n\t\t\t},\n\t\t};\n\t}\n\tconst preparationResult = prepareLegacyCompaction(\n\t\tentries,\n\t\tbody.settings ?? DEFAULT_COMPACTION_SETTINGS,\n\t\tbody.preparation,\n\t);\n\tif (!preparationResult.ok) {\n\t\treturn { status: 400, body: { error: preparationResult.error.message } };\n\t}\n\tif (!preparationResult.value) {\n\t\treturn { status: 400, body: { error: \"Nothing to compact\" } };\n\t}\n\n\tconst options = body.options ?? {};\n\treturn {\n\t\tsession,\n\t\tsessionId: session.sessionId,\n\t\trevision: session.revision,\n\t\ttreeHash: session.treeHash,\n\t\tleafId: session.leafId,\n\t\tentryCount: session.entries.length,\n\t\tpreparation: preparationResult.value,\n\t\toptions,\n\t};\n}\n\nfunction sessionCompactConflict(\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\tcurrentSession: SessionState | undefined,\n): SessionCompactHttpResponse {\n\treturn {\n\t\tstatus: 409,\n\t\tbody: {\n\t\t\terror: \"Session changed while compaction was running\",\n\t\t\tcode: PiServerErrorCode.SESSION_STATE_CONFLICT,\n\t\t\tdetails: {\n\t\t\t\tsessionId: body.sessionId,\n\t\t\t\texpectedRevision: prepared.revision,\n\t\t\t\texpectedTreeHash: prepared.treeHash,\n\t\t\t\texpectedLeafId: prepared.leafId,\n\t\t\t\tactualRevision: currentSession?.revision ?? null,\n\t\t\t\tactualTreeHash: currentSession?.treeHash ?? null,\n\t\t\t\tactualLeafId: currentSession?.leafId ?? null,\n\t\t\t},\n\t\t},\n\t};\n}\n\nasync function completeSessionCompact(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\trun?: StreamRunRecord,\n): Promise<SessionCompactHttpResponse> {\n\tconst result = await compactLegacy(\n\t\tprepared.preparation,\n\t\tcreateRequestModels(body.model, prepared.options),\n\t\tbody.model,\n\t\tbody.customInstructions,\n\t\trun?.controller.signal,\n\t\tprepared.options.reasoning,\n\t);\n\tif (!result.ok) {\n\t\treturn { status: 500, body: { error: result.error.message, code: PiServerErrorCode.INTERNAL_ERROR } };\n\t}\n\tif (run?.cancelRequested || run?.controller.signal.aborted) {\n\t\treturn { status: 409, body: { error: \"Compaction aborted\", code: PiServerErrorCode.INVALID_REQUEST } };\n\t}\n\n\tconst currentSession = getSession(prepared.sessionId);\n\tif (\n\t\t!currentSession ||\n\t\tcurrentSession !== prepared.session ||\n\t\tcurrentSession.revision !== prepared.revision ||\n\t\tcurrentSession.treeHash !== prepared.treeHash ||\n\t\tcurrentSession.leafId !== prepared.leafId\n\t) {\n\t\treturn sessionCompactConflict(body, prepared, currentSession);\n\t}\n\n\tconst baseTreeHash = prepared.treeHash;\n\tconst baseEntryCount = prepared.entryCount;\n\tconst compaction = result.value;\n\tconst { session: updatedSession, entry: compactionEntry } = appendCompactionEntry(body.sessionId, compaction);\n\tpersistSession(config, updatedSession);\n\tif (!body.fullResponse && body.baseTreeHash === baseTreeHash) {\n\t\treturn {\n\t\t\tstatus: 200,\n\t\t\tbody: {\n\t\t\t\tsuccess: true,\n\t\t\t\tcompaction: compaction satisfies LegacyCompactResult,\n\t\t\t\tcompactionEntry,\n\t\t\t\t...sessionResponseBody(updatedSession),\n\t\t\t\tstaticContext: updatedSession.staticContext,\n\t\t\t\ttreePatch: {\n\t\t\t\t\tbaseTreeHash,\n\t\t\t\t\tentriesFrom: baseEntryCount,\n\t\t\t\t\tentries: [compactionEntry],\n\t\t\t\t\tleafId: updatedSession.leafId,\n\t\t\t\t\trevision: updatedSession.revision,\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\treturn {\n\t\tstatus: 200,\n\t\tbody: {\n\t\t\tsuccess: true,\n\t\t\tcompaction: compaction satisfies LegacyCompactResult,\n\t\t\tcompactionEntry,\n\t\t\t...sessionResponseBody(updatedSession),\n\t\t\tstaticContext: updatedSession.staticContext,\n\t\t\tentries: updatedSession.entries,\n\t\t\tmessages: updatedSession.messages,\n\t\t},\n\t};\n}\n\nfunction writeServerSentEvent(res: ServerResponse, event: string, body: unknown): void {\n\tres.write(`event: ${event}\\n`);\n\tres.write(`data: ${JSON.stringify(body)}\\n\\n`);\n}\n\nasync function handleSessionCompactStream(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\tres: ServerResponse,\n\trun?: StreamRunRecord,\n): Promise<void> {\n\tres.writeHead(200, {\n\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\"Cache-Control\": \"no-cache\",\n\t\tConnection: \"keep-alive\",\n\t});\n\tres.flushHeaders();\n\tres.write(STREAM_HEARTBEAT);\n\n\tconst heartbeat = setInterval(() => {\n\t\ttouchStreamRun(run);\n\t\tif (!res.writableEnded) {\n\t\t\tres.write(STREAM_HEARTBEAT);\n\t\t}\n\t}, STREAM_HEARTBEAT_INTERVAL_MS);\n\theartbeat.unref();\n\n\ttry {\n\t\tconst result = await completeSessionCompact(config, body, prepared, run);\n\t\tfinishCompactRun(run, result);\n\t\twriteServerSentEvent(res, result.status >= 400 ? \"error\" : \"result\", result.body);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tif (run?.status === \"running\") {\n\t\t\trun.status = run.cancelRequested ? \"aborted\" : \"failed\";\n\t\t\trun.errorMessage = message;\n\t\t\trun.updatedAt = Date.now();\n\t\t}\n\t\twriteServerSentEvent(res, \"error\", { error: message });\n\t} finally {\n\t\tclearInterval(heartbeat);\n\t\tsettleRun(run);\n\t\tres.end();\n\t}\n}\n\nasync function handleSessionCompactJsonStream(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\tres: ServerResponse,\n\trun?: StreamRunRecord,\n): Promise<void> {\n\tres.writeHead(200, {\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"Cache-Control\": \"no-cache\",\n\t\tConnection: \"keep-alive\",\n\t});\n\tres.flushHeaders();\n\tres.write(JSON_HEARTBEAT);\n\n\tconst heartbeat = setInterval(() => {\n\t\ttouchStreamRun(run);\n\t\tif (!res.writableEnded) {\n\t\t\tres.write(JSON_HEARTBEAT);\n\t\t}\n\t}, STREAM_HEARTBEAT_INTERVAL_MS);\n\theartbeat.unref();\n\n\ttry {\n\t\tconst result = await completeSessionCompact(config, body, prepared, run);\n\t\tfinishCompactRun(run, result);\n\t\tres.write(JSON.stringify(result.body));\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tif (run?.status === \"running\") {\n\t\t\trun.status = run.cancelRequested ? \"aborted\" : \"failed\";\n\t\t\trun.errorMessage = message;\n\t\t\trun.updatedAt = Date.now();\n\t\t}\n\t\tres.write(JSON.stringify({ error: message }));\n\t} finally {\n\t\tclearInterval(heartbeat);\n\t\tsettleRun(run);\n\t\tres.end();\n\t}\n}\n\nfunction finishCompactRun(run: StreamRunRecord | undefined, result: SessionCompactHttpResponse): void {\n\tif (!run) return;\n\tif (run.cancelRequested || run.controller.signal.aborted) {\n\t\trun.status = \"aborted\";\n\t\trun.errorMessage = \"Compaction aborted\";\n\t} else {\n\t\trun.status = result.status >= 400 ? \"failed\" : \"completed\";\n\t\tif (result.status >= 400 && \"error\" in result.body) {\n\t\t\trun.errorMessage = result.body.error;\n\t\t} else if (\"success\" in result.body) {\n\t\t\trun.compactResult = { ...result.body, entries: result.body.entries?.slice() };\n\t\t}\n\t}\n\trun.updatedAt = Date.now();\n}\n\nasync function handleSessionCompact(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tres: ServerResponse,\n): Promise<void> {\n\tconst existingRun = body.runId ? getStreamRun(body.sessionId, body.runId) : undefined;\n\tif (existingRun?.status === \"aborted\") {\n\t\tsendJson(res, 409, { error: \"Compaction run was aborted\", code: PiServerErrorCode.INVALID_REQUEST });\n\t\treturn;\n\t}\n\tif (existingRun?.status === \"completed\" && existingRun.compactResult) {\n\t\tsendJson(res, 200, existingRun.compactResult);\n\t\treturn;\n\t}\n\tconst prepared = prepareSessionCompact(body);\n\tif (\"status\" in prepared) {\n\t\tsendJson(res, prepared.status, prepared.body);\n\t\treturn;\n\t}\n\n\tlet run: StreamRunRecord | undefined;\n\tif (body.runId) {\n\t\tconst existingRun = getStreamRun(body.sessionId, body.runId);\n\t\tif (existingRun?.status === \"aborted\") {\n\t\t\tsendJson(res, 409, { error: \"Compaction run was aborted\", code: PiServerErrorCode.INVALID_REQUEST });\n\t\t\treturn;\n\t\t}\n\t\tif (existingRun?.status === \"running\") {\n\t\t\tsendError(res, 409, \"A run with this runId is already in progress\", PiServerErrorCode.RUN_IN_PROGRESS);\n\t\t\treturn;\n\t\t}\n\t\trun = startStreamRun(body.sessionId, body.runId, \"compact\");\n\t}\n\n\tif (body.streamResponse) {\n\t\tawait handleSessionCompactStream(config, body, prepared, res, run);\n\t\treturn;\n\t}\n\n\tawait handleSessionCompactJsonStream(config, body, prepared, res, run);\n}\n\nfunction handleSessionHistory(\n\tsessionId: string,\n\tfrom: number | undefined,\n\tentriesFrom: number | undefined,\n\trevision: number | undefined,\n\tbaseTreeHash: string | undefined,\n\tres: ServerResponse,\n): void {\n\tconst session = getSession(sessionId);\n\tif (!session) {\n\t\tsendError(res, 404, \"session not found\", PiServerErrorCode.SESSION_NOT_FOUND);\n\t\treturn;\n\t}\n\tconst baseMessageCount = from ?? 0;\n\tif (\n\t\tentriesFrom !== undefined &&\n\t\tentriesFrom <= session.entries.length &&\n\t\t(revision === undefined || revision <= session.revision) &&\n\t\t(baseTreeHash === undefined || baseTreeHash === session.prefixHashes[entriesFrom])\n\t) {\n\t\tsendJson(res, 200, sessionTreePatchResponseBody(session, baseMessageCount, entriesFrom, revision));\n\t\treturn;\n\t}\n\tsendJson(res, 200, sessionHistoryFullResponseBody(session, baseMessageCount));\n}\n\nfunction handleSessionRun(sessionId: string, runId: string, res: ServerResponse): void {\n\tconst run = getStreamRun(sessionId, runId);\n\tif (!run) {\n\t\tsendError(res, 404, \"run not found\", PiServerErrorCode.RUN_NOT_FOUND);\n\t\treturn;\n\t}\n\tsendJson(res, 200, streamRunResponseBody(run));\n}\n\nasync function handleSessionRunAbort(sessionId: string, runId: string, res: ServerResponse): Promise<void> {\n\tif (!sessionId || !runId) {\n\t\tsendError(res, 400, \"sessionId and runId are required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\n\tlet run = getStreamRun(sessionId, runId);\n\tif (!run) {\n\t\trun = createRunRecord(sessionId, runId, \"stream\");\n\t\trun.status = \"aborted\";\n\t\trun.cancelRequested = true;\n\t\trun.errorMessage = \"Stream run aborted before it started\";\n\t\trun.updatedAt = Date.now();\n\t\tsettleRun(run);\n\t\tstreamRuns.set(runKey(sessionId, runId), run);\n\t\tsendJson(res, 200, streamRunResponseBody(run));\n\t\treturn;\n\t}\n\n\tif (run.status !== \"running\") {\n\t\tawait run.settled;\n\t\tsendJson(res, 200, streamRunResponseBody(run));\n\t\treturn;\n\t}\n\n\trun.cancelRequested = true;\n\trun.updatedAt = Date.now();\n\trun.controller.abort();\n\tawait run.settled;\n\tsendJson(res, 200, streamRunResponseBody(run));\n}\n\nexport function buildStreamContext(\n\tsession: SessionState,\n\tbody: Pick<StreamRequestBody, \"contextOverlay\" | \"ephemeralMessages\">,\n): Context {\n\tconst messages = body.contextOverlay ?? [...session.messages, ...(body.ephemeralMessages ?? [])];\n\treturn {\n\t\tsystemPrompt: session.staticContext?.systemPrompt,\n\t\tmessages,\n\t\ttools: session.staticContext?.tools,\n\t};\n}\n\nfunction handleStream(config: ServerConfig, body: StreamRequestBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!body.model) {\n\t\tsendError(res, 400, \"model is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\n\tcleanupExpiredStreamRuns(Date.now());\n\n\tconst session = getOrCreateSession(body.sessionId);\n\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t\tpersistSession(config, session);\n\t}\n\n\tif (!session.staticContext && !body.staticContext) {\n\t\tsendError(\n\t\t\tres,\n\t\t\t400,\n\t\t\t\"Session has no static context. Initialize with /api/session/init first.\",\n\t\t\tPiServerErrorCode.SESSION_NO_STATIC_CONTEXT,\n\t\t);\n\t\treturn;\n\t}\n\n\tif (body.ephemeralMessages !== undefined && !Array.isArray(body.ephemeralMessages)) {\n\t\tsendError(res, 400, \"ephemeralMessages must be an array\", PiServerErrorCode.INVALID_REQUEST);\n\t\treturn;\n\t}\n\tif (body.contextOverlay !== undefined && !Array.isArray(body.contextOverlay)) {\n\t\tsendError(res, 400, \"contextOverlay must be an array\", PiServerErrorCode.INVALID_REQUEST);\n\t\treturn;\n\t}\n\n\tconst context = buildStreamContext(session, body);\n\tconst existingRun = body.runId ? getStreamRun(body.sessionId, body.runId) : undefined;\n\n\tconst resolvedModel = body.model;\n\n\tif (existingRun?.status === \"completed\") {\n\t\tres.writeHead(200, {\n\t\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\t\"Cache-Control\": \"no-cache\",\n\t\t\tConnection: \"keep-alive\",\n\t\t});\n\t\tres.flushHeaders();\n\t\tres.write(STREAM_HEARTBEAT);\n\t\tfor (const event of replayStreamRun(existingRun)) {\n\t\t\twriteStreamEvent(res, event);\n\t\t}\n\t\tendStreamResponse(res);\n\t\treturn;\n\t}\n\tif (existingRun?.status === \"aborted\") {\n\t\tsendError(res, 409, \"The stream run was aborted\", PiServerErrorCode.INVALID_REQUEST);\n\t\treturn;\n\t}\n\tif (existingRun?.status === \"running\") {\n\t\tsendError(res, 409, \"A stream with this runId is already in progress\", PiServerErrorCode.RUN_IN_PROGRESS);\n\t\treturn;\n\t}\n\n\tconst run = body.runId ? startStreamRun(body.sessionId, body.runId) : undefined;\n\tconst streamOptions: SimpleStreamOptions = {\n\t\t...(body.options ?? {}),\n\t\t...(run ? { signal: run.controller.signal } : {}),\n\t};\n\n\tres.writeHead(200, {\n\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\"Cache-Control\": \"no-cache\",\n\t\tConnection: \"keep-alive\",\n\t});\n\tres.flushHeaders();\n\tres.write(STREAM_HEARTBEAT);\n\n\tconst heartbeat = setInterval(() => {\n\t\ttouchStreamRun(run);\n\t\tif (!res.writableEnded && !res.destroyed) {\n\t\t\tres.write(STREAM_HEARTBEAT);\n\t\t}\n\t}, STREAM_HEARTBEAT_INTERVAL_MS);\n\theartbeat.unref();\n\n\tlet stream: AsyncIterable<AssistantMessageEvent>;\n\ttry {\n\t\tstream = streamSimple(resolvedModel, context, streamOptions);\n\t} catch (err) {\n\t\tclearInterval(heartbeat);\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tfailStreamRun(run, message);\n\t\tsettleRun(run);\n\t\twriteStreamError(res, message);\n\t\tendStreamResponse(res);\n\t\treturn;\n\t}\n\n\tvoid (async () => {\n\t\ttry {\n\t\t\tfor await (const event of stream) {\n\t\t\t\tconst proxyEvent = toProxyEvent(event);\n\t\t\t\tif (proxyEvent) {\n\t\t\t\t\ttouchStreamRun(run);\n\t\t\t\t\twriteStreamEvent(res, proxyEvent);\n\t\t\t\t}\n\t\t\t\tif (event.type === \"done\") {\n\t\t\t\t\tcompleteStreamRun(run, event.message);\n\t\t\t\t} else if (event.type === \"error\") {\n\t\t\t\t\tfailStreamRun(run, event.error.errorMessage ?? event.reason);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tfailStreamRun(run, message);\n\t\t\twriteStreamError(res, message);\n\t\t} finally {\n\t\t\tclearInterval(heartbeat);\n\t\t\tif (run?.status === \"running\") {\n\t\t\t\tfailStreamRun(run, run.cancelRequested ? \"Stream run aborted\" : \"Stream ended before a terminal event\");\n\t\t\t}\n\t\t\tsettleRun(run);\n\t\t\tendStreamResponse(res);\n\t\t}\n\t})();\n}\n\nasync function handlePostRequest(\n\tconfig: ServerConfig,\n\tpathname: string,\n\tbody: unknown,\n\tres: ServerResponse,\n): Promise<boolean> {\n\tif (pathname === \"/api/receive\") {\n\t\ttry {\n\t\t\tsendJson(res, 200, receiveUpload(config.uploadDir, body));\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof ReceiveUploadError)) throw error;\n\t\t\tsendJson(res, error.status, { error: error.message });\n\t\t}\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/init\") {\n\t\thandleSessionInit(config, body as SessionInitBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/update\") {\n\t\thandleSessionUpdate(config, body as SessionInitBody & { staticContext: SessionStaticContext }, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/sync\") {\n\t\thandleSessionSync(config, body as SessionSyncBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/append\") {\n\t\thandleSessionAppend(config, body as SessionAppendBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/tree/sync\") {\n\t\thandleSessionTreeSync(config, body as SessionTreeSyncBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/tree/append\") {\n\t\thandleSessionTreeAppend(config, body as SessionTreeSyncBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/tree/switch\") {\n\t\thandleSessionTreeSwitch(config, body as SessionTreeSwitchBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/compact\") {\n\t\tawait handleSessionCompact(config, body as SessionCompactBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/stream\") {\n\t\thandleStream(config, body as StreamRequestBody, res);\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nexport function createPiServer(configOverride?: Partial<ServerConfig>): HttpServer {\n\tconst config = loadConfig(configOverride);\n\tloadPersistedSessions(config.sessionStoreDir);\n\n\tconst server = createServer(async (req, res) => {\n\t\tconst url = new URL(req.url ?? \"/\", \"http://localhost\");\n\n\t\tif (req.method === \"GET\" && url.pathname === \"/health\") {\n\t\t\tsendJson(res, 200, { status: \"ok\" });\n\t\t\treturn;\n\t\t}\n\n\t\tif (!authenticate(config, req)) {\n\t\t\tconst body =\n\t\t\t\treq.method === \"GET\" && url.pathname === \"/\"\n\t\t\t\t\t? { error: \"Unauthorized\", version: PI_SERVER_VERSION }\n\t\t\t\t\t: { error: \"Unauthorized\" };\n\t\t\tsendJson(res, 401, body);\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"GET\" && url.pathname === \"/api/sessions\") {\n\t\t\tsendJson(res, 200, { sessions: listSessions() });\n\t\t\treturn;\n\t\t}\n\n\t\tconst runMatch = /^\\/api\\/session\\/([^/]+)\\/runs\\/([^/]+)$/.exec(url.pathname);\n\t\tif (req.method === \"GET\" && runMatch) {\n\t\t\thandleSessionRun(decodeURIComponent(runMatch[1]), decodeURIComponent(runMatch[2]), res);\n\t\t\treturn;\n\t\t}\n\n\t\tconst runAbortMatch = /^\\/api\\/session\\/([^/]+)\\/runs\\/([^/]+)\\/abort$/.exec(url.pathname);\n\t\tif (req.method === \"POST\" && runAbortMatch) {\n\t\t\tawait readBody(req);\n\t\t\tawait handleSessionRunAbort(decodeURIComponent(runAbortMatch[1]), decodeURIComponent(runAbortMatch[2]), res);\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"GET\" && url.pathname.startsWith(\"/api/session/\") && url.pathname.endsWith(\"/history\")) {\n\t\t\tconst encodedSessionId = url.pathname.slice(\"/api/session/\".length, -\"/history\".length);\n\t\t\tconst fromParam = url.searchParams.get(\"from\");\n\t\t\tconst from = fromParam === null ? undefined : Number(fromParam);\n\t\t\tif (from !== undefined && (!Number.isInteger(from) || from < 0)) {\n\t\t\t\tsendError(res, 400, \"from must be a non-negative integer\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst entriesFromParam = url.searchParams.get(\"entriesFrom\");\n\t\t\tconst entriesFrom = entriesFromParam === null ? undefined : Number(entriesFromParam);\n\t\t\tif (entriesFrom !== undefined && (!Number.isInteger(entriesFrom) || entriesFrom < 0)) {\n\t\t\t\tsendError(res, 400, \"entriesFrom must be a non-negative integer\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst revisionParam = url.searchParams.get(\"revision\");\n\t\t\tconst revision = revisionParam === null ? undefined : Number(revisionParam);\n\t\t\tif (revision !== undefined && (!Number.isInteger(revision) || revision < 0)) {\n\t\t\t\tsendError(res, 400, \"revision must be a non-negative integer\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thandleSessionHistory(\n\t\t\t\tdecodeURIComponent(encodedSessionId),\n\t\t\t\tfrom,\n\t\t\t\tentriesFrom,\n\t\t\t\trevision,\n\t\t\t\turl.searchParams.get(\"baseTreeHash\") ?? undefined,\n\t\t\t\tres,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"POST\" && url.pathname === CHUNK_ENDPOINT) {\n\t\t\ttry {\n\t\t\t\tconst body = JSON.parse(await readBody(req)) as RequestChunkBody;\n\t\t\t\tconst chunkResult = receiveRequestChunk(body);\n\t\t\t\tif (!chunkResult.complete) {\n\t\t\t\t\tsendJson(res, 200, chunkResult.ack);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst handled = await handlePostRequest(\n\t\t\t\t\tconfig,\n\t\t\t\t\tchunkResult.target,\n\t\t\t\t\tJSON.parse(chunkResult.bodyJson) as unknown,\n\t\t\t\t\tres,\n\t\t\t\t);\n\t\t\t\tif (!handled && !res.headersSent) {\n\t\t\t\t\tsendError(res, 404, \"Not found\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tlogRequestError(req, err);\n\t\t\t\tif (!res.headersSent) {\n\t\t\t\t\tsendError(res, 400, err instanceof Error ? err.message : String(err), PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\t} else {\n\t\t\t\t\tres.write(encodeErrorEvent(err instanceof Error ? err.message : String(err)));\n\t\t\t\t\tres.end();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"POST\") {\n\t\t\ttry {\n\t\t\t\tconst body = JSON.parse(await readBody(req)) as unknown;\n\t\t\t\tif (await handlePostRequest(config, url.pathname, body, res)) return;\n\t\t\t\tif (!res.headersSent) {\n\t\t\t\t\tsendError(res, 404, \"Not found\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tlogRequestError(req, err);\n\t\t\t\tif (!res.headersSent) {\n\t\t\t\t\tsendError(res, 500, err instanceof Error ? err.message : String(err), PiServerErrorCode.INTERNAL_ERROR);\n\t\t\t\t} else {\n\t\t\t\t\tres.write(encodeErrorEvent(err instanceof Error ? err.message : String(err)));\n\t\t\t\t\tres.end();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif (req.method === \"DELETE\" && url.pathname.startsWith(\"/api/session/\")) {\n\t\t\tconst sessionId = decodeURIComponent(url.pathname.slice(\"/api/session/\".length));\n\t\t\tdeleteSessionFromStore(sessionId);\n\t\t\tdeleteStreamRunsForSession(sessionId);\n\t\t\tdeletePersistedSession(config.sessionStoreDir, sessionId);\n\t\t\tsendJson(res, 200, { deleted: sessionId });\n\t\t\treturn;\n\t\t}\n\n\t\tsendError(res, 404, \"Not found\", PiServerErrorCode.INVALID_REQUEST);\n\t});\n\n\treturn server;\n}\n\nfunction toProxyEvent(event: AssistantMessageEvent): ProxyAssistantMessageEvent | undefined {\n\tswitch (event.type) {\n\t\tcase \"start\":\n\t\t\treturn { type: \"start\" };\n\t\tcase \"text_start\":\n\t\t\treturn { type: \"text_start\", contentIndex: event.contentIndex };\n\t\tcase \"text_delta\":\n\t\t\treturn { type: \"text_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\tcase \"text_end\":\n\t\t\treturn {\n\t\t\t\ttype: \"text_end\",\n\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\tcontentSignature:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"text\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { textSignature?: string }).textSignature\n\t\t\t\t\t\t: undefined,\n\t\t\t};\n\t\tcase \"thinking_start\":\n\t\t\treturn { type: \"thinking_start\", contentIndex: event.contentIndex };\n\t\tcase \"thinking_delta\":\n\t\t\treturn { type: \"thinking_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\tcase \"thinking_end\":\n\t\t\treturn {\n\t\t\t\ttype: \"thinking_end\",\n\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\tcontentSignature:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"thinking\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { thinkingSignature?: string }).thinkingSignature\n\t\t\t\t\t\t: undefined,\n\t\t\t};\n\t\tcase \"toolcall_start\":\n\t\t\treturn {\n\t\t\t\ttype: \"toolcall_start\",\n\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\tid:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"toolCall\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { id: string }).id\n\t\t\t\t\t\t: \"\",\n\t\t\t\ttoolName:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"toolCall\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { name: string }).name\n\t\t\t\t\t\t: \"\",\n\t\t\t};\n\t\tcase \"toolcall_delta\":\n\t\t\treturn { type: \"toolcall_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\tcase \"toolcall_end\":\n\t\t\treturn { type: \"toolcall_end\", contentIndex: event.contentIndex, toolCall: event.toolCall };\n\t\tcase \"done\":\n\t\t\treturn {\n\t\t\t\ttype: \"done\",\n\t\t\t\treason: event.reason,\n\t\t\t\tusage: event.message.usage,\n\t\t\t\tdeferred: event.message.deferred,\n\t\t\t\tmessage: event.message,\n\t\t\t};\n\t\tcase \"error\":\n\t\t\treturn {\n\t\t\t\ttype: \"error\",\n\t\t\t\treason: event.reason,\n\t\t\t\terrorMessage: event.error.errorMessage,\n\t\t\t\tusage: event.error.usage,\n\t\t\t};\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nexport function startServer(configOverride?: Partial<ServerConfig>): HttpServer {\n\tconst config = loadConfig(configOverride);\n\tconst server = createPiServer(configOverride);\n\tserver.listen(config.port, config.host, () => {\n\t\tconst address = server.address();\n\t\tconst port = typeof address === \"object\" && address !== null ? address.port : config.port;\n\t\tconst host = config.host.includes(\":\") && !config.host.startsWith(\"[\") ? `[${config.host}]` : config.host;\n\t\tconsole.log(`pi-server listening on ${host}:${port}`);\n\t});\n\treturn server;\n}\n"]}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAwE,MAAM,WAAW,CAAC;AAC/G,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAIN,aAAa,EACb,YAAY,EACZ,2BAA2B,EAG3B,uBAAuB,GAEvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAIN,YAAY,EACZ,cAAc,GAKd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAA8B,MAAM,kBAAkB,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAyB,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACjG,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAC/G,OAAO,EACN,qBAAqB,EACrB,cAAc,EACd,oBAAoB,EACpB,aAAa,IAAI,sBAAsB,EACvC,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,kBAAkB,EAGlB,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAC;AAM5D,MAAM,eAAe,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAoB,CAAC;AAC7F,MAAM,iBAAiB,GAAG,eAAe,CAAC,OAAO,CAAC;AAyDlD,SAAS,mBAAmB,CAAC,KAAiB,EAAE,OAA4B,EAAE;IAC7E,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,aAAa,GAAoC,CAAC,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,CAC/F,YAAY,CAAC,YAAY,EAAE,OAAO,EAAE;QACnC,GAAG,aAAa;QAChB,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAC,CAAC;IACJ,MAAM,CAAC,WAAW,CACjB,cAAc,CAAC;QACd,EAAE,EAAE,KAAK,CAAC,QAAQ;QAClB,IAAI,EAAE,KAAK,CAAC,QAAQ;QACpB,MAAM,EAAE,CAAC,KAAK,CAAC;QACf,IAAI,EAAE;YACL,MAAM,EAAE;gBACP,IAAI,EAAE,wBAAwB;gBAC9B,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;aACrF;SACD;QACD,GAAG,EAAE;YACJ,MAAM,EAAE,aAAa;YACrB,YAAY,EAAE,aAAa;SAC3B;KACD,CAAC,CACF,CAAC;IACF,OAAO,MAAM,CAAC;AAAA,CACd;AAkBD,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;AAC5C,MAAM,cAAc,GAAG,KAAK,CAAC;AAC7B,MAAM,4BAA4B,GAAG,MAAM,CAAC;AAC5C,MAAM,iBAAiB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;AACnD,MAAM,UAAU,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEtD,SAAS,QAAQ,CAAC,GAAoB,EAAmB;IACxD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;QACvC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACtD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACtE,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAAA,CACxB,CAAC,CAAC;AAAA,CACH;AAED,SAAS,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa,EAAQ;IAC3E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAAA,CACd;AAED,SAAS,SAAS,CACjB,GAAmB,EACnB,MAAc,EACd,OAAe,EACf,IAAwB,EACxB,OAAiC,EAC1B;IACP,MAAM,IAAI,GAA0B,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IACvD,IAAI,IAAI;QAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAC3B,IAAI,OAAO;QAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;AAAA,CAC5B;AAED,SAAS,eAAe,CAAC,GAAoB,EAAE,KAAc,EAAQ;IACpE,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtF,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,IAAI,SAAS,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,YAAY,OAAO,EAAE,CAAC,CAAC;AAAA,CACjF;AAED,SAAS,YAAY,CAAC,MAAoB,EAAE,GAAoB,EAAW;IAC1E,IAAI,CAAC,MAAM,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;IACzC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACtE,OAAO,KAAK,KAAK,MAAM,CAAC,SAAS,CAAC;AAAA,CAClC;AAED,SAAS,mBAAmB,CAAC,OAAqB,EAAE;IACnD,OAAO;QACN,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;QAC5C,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;QACrC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM;QAClC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC1B,CAAC;AAAA,CACF;AAED,SAAS,cAAc,CAAC,MAAoB,EAAE,OAAqB,EAAQ;IAC1E,oBAAoB,CAAC,MAAM,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;AAAA,CACtD;AAED,SAAS,MAAM,CAAC,SAAiB,EAAE,KAAa,EAAU;IACzD,OAAO,GAAG,SAAS,KAAK,KAAK,EAAE,CAAC;AAAA,CAChC;AAED,SAAS,YAAY,CAAC,SAAiB,EAAE,KAAa,EAA+B;IACpF,OAAO,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;AAAA,CAChD;AAED,SAAS,eAAe,CAAC,SAAiB,EAAE,KAAa,EAAE,IAA6B,EAAmB;IAC1G,IAAI,cAAwC,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QAC9C,cAAc,GAAG,OAAO,CAAC;IAAA,CACzB,CAAC,CAAC;IACH,OAAO;QACN,SAAS;QACT,KAAK;QACL,IAAI;QACJ,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,eAAe,EAAE,KAAK;QACtB,UAAU,EAAE,IAAI,eAAe,EAAE;QACjC,OAAO;QACP,cAAc;KACd,CAAC;AAAA,CACF;AAED,SAAS,SAAS,CAAC,GAAgC,EAAQ;IAC1D,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,MAAM,OAAO,GAAG,GAAG,CAAC,cAAc,CAAC;IACnC,GAAG,CAAC,cAAc,GAAG,SAAS,CAAC;IAC/B,OAAO,EAAE,EAAE,CAAC;AAAA,CACZ;AAED,SAAS,cAAc,CAAC,SAAiB,EAAE,KAAa,EAAE,IAAI,GAA4B,QAAQ,EAAmB;IACpH,MAAM,QAAQ,GAAG,YAAY,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAChD,IAAI,QAAQ,EAAE,MAAM,KAAK,WAAW,IAAI,QAAQ,EAAE,MAAM,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IACxF,MAAM,GAAG,GAAG,QAAQ,IAAI,eAAe,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAChE,IAAI,QAAQ,EAAE,CAAC;QACd,GAAG,CAAC,OAAO,GAAG,SAAS,CAAC;QACxB,GAAG,CAAC,YAAY,GAAG,SAAS,CAAC;QAC7B,GAAG,CAAC,eAAe,GAAG,KAAK,CAAC;QAC5B,GAAG,CAAC,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACvC,IAAI,cAAwC,CAAC;QAC7C,GAAG,CAAC,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAC5C,cAAc,GAAG,OAAO,CAAC;QAAA,CACzB,CAAC,CAAC;QACH,GAAG,CAAC,cAAc,GAAG,cAAc,CAAC;IACrC,CAAC;IACD,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;IAChB,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC;IACvB,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC3B,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IAC9C,OAAO,GAAG,CAAC;AAAA,CACX;AAED,SAAS,qBAAqB,CAAC,GAAoB,EAAE;IACpD,OAAO;QACN,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/D,CAAC;AAAA,CACF;AAED,SAAS,eAAe,CAAC,GAAoB,EAAgC;IAC5E,IAAI,CAAC,GAAG,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAC5B,IACC,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,MAAM;QACjC,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,QAAQ;QACnC,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS;QACpC,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,UAAU,EACpC,CAAC;QACF,OAAO,EAAE,CAAC;IACX,CAAC;IACD,MAAM,MAAM,GAAiC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACjE,KAAK,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QACrE,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACtB,KAAK,MAAM;gBACV,MAAM,CAAC,IAAI,CACV,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,EACpC,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,EACzD,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,OAAO,CAAC,aAAa,EAAE,CAC3E,CAAC;gBACF,MAAM;YACP,KAAK,UAAU;gBACd,MAAM,CAAC,IAAI,CACV,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,EACxC,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,EACjE,EAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,OAAO,CAAC,iBAAiB,EAAE,CACnF,CAAC;gBACF,MAAM;YACP,KAAK,UAAU;gBACd,MAAM,CAAC,IAAI,CACV,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,IAAI,EAAE,EAChF,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAClF,EAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,CACzD,CAAC;gBACF,MAAM;YACP;gBACC,MAAM;QACR,CAAC;IACF,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;QACX,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,UAAU;QAC9B,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK;QACxB,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ;QAC9B,OAAO,EAAE,GAAG,CAAC,OAAO;KACpB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAAA,CACd;AAED,SAAS,iBAAiB,CAAC,GAAgC,EAAE,OAAyB,EAAQ;IAC7F,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;QACzB,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC;QACvB,GAAG,CAAC,OAAO,GAAG,SAAS,CAAC;QACxB,GAAG,CAAC,YAAY,GAAG,oBAAoB,CAAC;QACxC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,OAAO;IACR,CAAC;IACD,GAAG,CAAC,MAAM,GAAG,WAAW,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;IACtB,GAAG,CAAC,YAAY,GAAG,SAAS,CAAC;IAC7B,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAAA,CAC3B;AAED,SAAS,aAAa,CAAC,GAAgC,EAAE,YAAoB,EAAQ;IACpF,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;QACzB,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC;QACvB,GAAG,CAAC,YAAY,GAAG,oBAAoB,CAAC;QACxC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,OAAO;IACR,CAAC;IACD,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC;IACtB,GAAG,CAAC,YAAY,GAAG,YAAY,CAAC;IAChC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAAA,CAC3B;AAED,SAAS,cAAc,CAAC,GAAgC,EAAQ;IAC/D,IAAI,GAAG;QAAE,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAAA,CACpC;AAED,SAAS,gBAAgB,CAAC,GAAmB,EAAE,KAAiC,EAAQ;IACvF,IAAI,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QAC1C,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;IACpC,CAAC;AAAA,CACD;AAED,SAAS,gBAAgB,CAAC,GAAmB,EAAE,OAAe,EAAQ;IACrE,IAAI,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QAC1C,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IACtC,CAAC;AAAA,CACD;AAED,SAAS,iBAAiB,CAAC,GAAmB,EAAQ;IACrD,IAAI,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QAC1C,GAAG,CAAC,GAAG,EAAE,CAAC;IACX,CAAC;AAAA,CACD;AAED,SAAS,wBAAwB,CAAC,KAAa,EAAQ;IACtD,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,UAAU,EAAE,CAAC;QACrC,IAAI,KAAK,GAAG,GAAG,CAAC,SAAS,GAAG,iBAAiB,EAAE,CAAC;YAC/C,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;IACF,CAAC;AAAA,CACD;AAED,SAAS,0BAA0B,CAAC,SAAiB,EAAQ;IAC5D,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,UAAU,EAAE,CAAC;QACrC,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS;YAAE,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzD,CAAC;AAAA,CACD;AAED,MAAM,qBAAqB,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,iBAAiB,GAAG,CAAC,CAAC,CAAC;AAC7G,qBAAqB,CAAC,KAAK,EAAE,CAAC;AAE9B,SAAS,8BAA8B,CAAC,OAAqB,EAAE,gBAAwB,EAAE;IACxF,OAAO;QACN,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;QAC5C,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;QACrC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM;QAClC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,gBAAgB;QAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,gBAAgB,CAAC;KAClD,CAAC;AAAA,CACF;AAED,SAAS,4BAA4B,CACpC,OAAqB,EACrB,gBAAwB,EACxB,WAAmB,EACnB,YAAgC,EAC/B;IACD,OAAO;QACN,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;QAC5C,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;QACrC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM;QAClC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,gBAAgB;QAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,gBAAgB,CAAC;QAClD,SAAS,EAAE;YACV,WAAW;YACX,YAAY;YACZ,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC;YAC3C,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC1B;KACD,CAAC;AAAA,CACF;AA6CD,SAAS,iBAAiB,CAAC,MAAoB,EAAE,IAAqB,EAAE,GAAmB,EAAQ;IAClG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,uBAAuB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACvF,OAAO;IACR,CAAC;IACD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACxB,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACtD,CAAC;SAAM,CAAC;QACP,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAE,CAAC;IAC5C,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;AAAA,CACjD;AAED,SAAS,mBAAmB,CAC3B,MAAoB,EACpB,IAA+D,EAC/D,GAAmB,EACZ;IACP,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,uBAAuB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACvF,OAAO;IACR,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QACzB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,sCAAsC,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACtG,OAAO;IACR,CAAC;IACD,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAE,CAAC;IAC5C,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;AAAA,CACjD;AAED,SAAS,iBAAiB,CAAC,MAAoB,EAAE,IAAqB,EAAE,GAAmB,EAAQ;IAClG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,uBAAuB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACvF,OAAO;IACR,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,sBAAsB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACtF,OAAO;IACR,CAAC;IACD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACxB,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACtD,CAAC;IACD,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/D,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;AAAA,CACjD;AAED,SAAS,mBAAmB,CAAC,MAAoB,EAAE,IAAuB,EAAE,GAAmB,EAAQ;IACtG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,uBAAuB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACvF,OAAO;IACR,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,sBAAsB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACtF,OAAO;IACR,CAAC;IACD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACxB,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACtD,CAAC;IACD,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9D,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;AAAA,CACjD;AAED,SAAS,qBAAqB,CAAC,MAAoB,EAAE,IAAyB,EAAE,GAAmB,EAAQ;IAC1G,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,uBAAuB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACvF,OAAO;IACR,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,qBAAqB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACrF,OAAO;IACR,CAAC;IACD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACxB,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IACtD,CAAC;IACD,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC;IACtF,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;AAAA,CACjD;AAED,SAAS,uBAAuB,CAAC,MAAoB,EAAE,IAAyB,EAAE,GAAmB,EAAQ;IAC5G,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,uBAAuB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACvF,OAAO;IACR,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,qBAAqB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACrF,OAAO;IACR,CAAC;IACD,IAAI,CAAC;QACJ,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,OAAO,GAAG,oBAAoB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC;QACxF,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;YACpC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/D,CAAC;aAAM,CAAC;YACP,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;QAChE,CAAC;IACF,CAAC;AAAA,CACD;AAED,SAAS,uBAAuB,CAAC,MAAoB,EAAE,IAA2B,EAAE,GAAmB,EAAQ;IAC9G,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,uBAAuB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACvF,OAAO;IACR,CAAC;IACD,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC;QACvE,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;YACpC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/D,CAAC;aAAM,CAAC;YACP,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;QAChE,CAAC;IACF,CAAC;AAAA,CACD;AAED,SAAS,qBAAqB,CAAC,IAAwB,EAAuD;IAC7G,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACrB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAAE,CAAC;IAClE,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,CAAC;IAC9D,CAAC;IACD,MAAM,WAAW,GAAG,CAAC,KAAyB,EAAW,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChH,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,sBAAsB,CAAC,EAAE,CAAC;QACtF,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,gEAAgE,EAAE,EAAE,CAAC;IAC3G,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,gBAAgB,KAAK,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,KAAK,SAAS,CAAC,EAAE,CAAC;QAC3F,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,uEAAuE,EAAE,EAAE,CAAC;IAClH,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,IAAI,EAAE,iBAAiB,CAAC,iBAAiB,EAAE,EAAE,CAAC;IACzG,CAAC;IAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,IAAI,EAAE,IAAI,KAAK,YAAY,EAAE,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC5B,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,+CAA+C,EAAE,EAAE,CAAC;QAC1F,CAAC;QACD,OAAO;YACN,MAAM,EAAE,GAAG;YACX,IAAI,EAAE;gBACL,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE;oBACX,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;oBACvC,YAAY,EAAE,IAAI,CAAC,YAAY;oBAC/B,OAAO,EAAE,IAAI,CAAC,OAAO;iBACrB;gBACD,eAAe,EAAE,IAAI;gBACrB,GAAG,mBAAmB,CAAC,OAAO,CAAC;gBAC/B,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;aAC1B;SACD,CAAC;IACH,CAAC;IACD,MAAM,iBAAiB,GAAG,uBAAuB,CAChD,OAAO,EACP,IAAI,CAAC,QAAQ,IAAI,2BAA2B,EAC5C,IAAI,CAAC,WAAW,CAChB,CAAC;IACF,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,CAAC;QAC3B,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,iBAAiB,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;IAC1E,CAAC;IACD,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;QAC9B,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,CAAC;IAC/D,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;IACnC,IAAI,YAAiC,CAAC;IACtC,IAAI,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,IAAI,8BAA8B,CAAC;IACrF,IAAI,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC1D,IAAI,OAAO,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC;YAC7C,mBAAmB,GAAG,qBAAqB,CAAC;QAC7C,CAAC;aAAM,IAAI,OAAO,CAAC,cAAc,KAAK,MAAM,EAAE,CAAC;YAC9C,mBAAmB,GAAG,uBAAuB,CAAC;QAC/C,CAAC;aAAM,IAAI,IAAI,CAAC,sBAAsB,KAAK,OAAO,CAAC,iBAAiB,EAAE,CAAC;YACtE,mBAAmB,GAAG,8BAA8B,CAAC;QACtD,CAAC;aAAM,CAAC;YACP,MAAM,iBAAiB,GAAG,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACzD,MAAM,cAAc,GAAG,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;YACvG,IAAI,4BAA4B,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAC/E,mBAAmB,GAAG,iCAAiC,CAAC;YACzD,CAAC;iBAAM,IACN,CAAC,cAAc;gBACf,cAAc,CAAC,QAAQ,KAAK,IAAI,CAAC,KAAK,CAAC,QAAQ;gBAC/C,cAAc,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,EAAE;gBACtC,cAAc,CAAC,GAAG,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,EACpC,CAAC;gBACF,mBAAmB,GAAG,wBAAwB,CAAC;YAChD,CAAC;iBAAM,CAAC;gBACP,YAAY,GAAG,kBAAkB,CAAC,OAAO,EAAE,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC,CAAC;gBAClF,mBAAmB,GAAG,0BAA0B,CAAC;YAClD,CAAC;QACF,CAAC;IACF,CAAC;IACD,OAAO;QACN,OAAO;QACP,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM;QAClC,WAAW,EAAE,iBAAiB,CAAC,KAAK;QACpC,OAAO;QACP,YAAY;QACZ,mBAAmB;KACnB,CAAC;AAAA,CACF;AAED,SAAS,sBAAsB,CAC9B,IAAwB,EACxB,QAAgC,EAChC,cAAwC,EACX;IAC7B,OAAO;QACN,MAAM,EAAE,GAAG;QACX,IAAI,EAAE;YACL,KAAK,EAAE,8CAA8C;YACrD,IAAI,EAAE,iBAAiB,CAAC,sBAAsB;YAC9C,OAAO,EAAE;gBACR,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,gBAAgB,EAAE,QAAQ,CAAC,QAAQ;gBACnC,gBAAgB,EAAE,QAAQ,CAAC,QAAQ;gBACnC,cAAc,EAAE,QAAQ,CAAC,MAAM;gBAC/B,cAAc,EAAE,cAAc,EAAE,QAAQ,IAAI,IAAI;gBAChD,cAAc,EAAE,cAAc,EAAE,QAAQ,IAAI,IAAI;gBAChD,YAAY,EAAE,cAAc,EAAE,MAAM,IAAI,IAAI;aAC5C;SACD;KACD,CAAC;AAAA,CACF;AAED,KAAK,UAAU,sBAAsB,CACpC,MAAoB,EACpB,IAAwB,EACxB,QAAgC,EAChC,GAAqB,EACiB;IACtC,MAAM,MAAM,GAAG,MAAM,aAAa,CACjC,QAAQ,CAAC,WAAW,EACpB,mBAAmB,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,EACjD,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,kBAAkB,EACvB,GAAG,EAAE,UAAU,CAAC,MAAM,EACtB,QAAQ,CAAC,OAAO,CAAC,SAAS,EAC1B,SAAS,EACT,SAAS,EACT,QAAQ,CAAC,YAAY,EACrB,QAAQ,CAAC,OAAwC,EACjD,QAAQ,CAAC,mBAAmB,CAC5B,CAAC;IACF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QAChB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,iBAAiB,CAAC,cAAc,EAAE,EAAE,CAAC;IACvG,CAAC;IACD,IAAI,GAAG,EAAE,eAAe,IAAI,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAC5D,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,IAAI,EAAE,iBAAiB,CAAC,eAAe,EAAE,EAAE,CAAC;IACxG,CAAC;IAED,MAAM,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACtD,IACC,CAAC,cAAc;QACf,cAAc,KAAK,QAAQ,CAAC,OAAO;QACnC,cAAc,CAAC,QAAQ,KAAK,QAAQ,CAAC,QAAQ;QAC7C,cAAc,CAAC,QAAQ,KAAK,QAAQ,CAAC,QAAQ;QAC7C,cAAc,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EACxC,CAAC;QACF,OAAO,sBAAsB,CAAC,IAAI,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC;IACvC,MAAM,cAAc,GAAG,QAAQ,CAAC,UAAU,CAAC;IAC3C,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC;IAChC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,qBAAqB,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC9G,cAAc,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACvC,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,KAAK,YAAY,EAAE,CAAC;QAC9D,OAAO;YACN,MAAM,EAAE,GAAG;YACX,IAAI,EAAE;gBACL,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,UAAwC;gBACpD,eAAe;gBACf,GAAG,mBAAmB,CAAC,cAAc,CAAC;gBACtC,aAAa,EAAE,cAAc,CAAC,aAAa;gBAC3C,SAAS,EAAE;oBACV,YAAY;oBACZ,WAAW,EAAE,cAAc;oBAC3B,OAAO,EAAE,CAAC,eAAe,CAAC;oBAC1B,MAAM,EAAE,cAAc,CAAC,MAAM;oBAC7B,QAAQ,EAAE,cAAc,CAAC,QAAQ;iBACjC;aACD;SACD,CAAC;IACH,CAAC;IACD,OAAO;QACN,MAAM,EAAE,GAAG;QACX,IAAI,EAAE;YACL,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,UAAwC;YACpD,eAAe;YACf,GAAG,mBAAmB,CAAC,cAAc,CAAC;YACtC,aAAa,EAAE,cAAc,CAAC,aAAa;YAC3C,OAAO,EAAE,cAAc,CAAC,OAAO;YAC/B,QAAQ,EAAE,cAAc,CAAC,QAAQ;SACjC;KACD,CAAC;AAAA,CACF;AAED,SAAS,oBAAoB,CAAC,GAAmB,EAAE,KAAa,EAAE,IAAa,EAAQ;IACtF,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC;IAC/B,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAAA,CAC/C;AAED,KAAK,UAAU,0BAA0B,CACxC,MAAoB,EACpB,IAAwB,EACxB,QAAgC,EAChC,GAAmB,EACnB,GAAqB,EACL;IAChB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QAClB,cAAc,EAAE,mBAAmB;QACnC,eAAe,EAAE,UAAU;QAC3B,UAAU,EAAE,YAAY;KACxB,CAAC,CAAC;IACH,GAAG,CAAC,YAAY,EAAE,CAAC;IACnB,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAE5B,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QACnC,cAAc,CAAC,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;YACxB,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC7B,CAAC;IAAA,CACD,EAAE,4BAA4B,CAAC,CAAC;IACjC,SAAS,CAAC,KAAK,EAAE,CAAC;IAElB,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;QACzE,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC9B,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IACnF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,GAAG,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;YAC/B,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;YACxD,GAAG,CAAC,YAAY,GAAG,OAAO,CAAC;YAC3B,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5B,CAAC;QACD,oBAAoB,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;YAAS,CAAC;QACV,aAAa,CAAC,SAAS,CAAC,CAAC;QACzB,SAAS,CAAC,GAAG,CAAC,CAAC;QACf,GAAG,CAAC,GAAG,EAAE,CAAC;IACX,CAAC;AAAA,CACD;AAED,KAAK,UAAU,8BAA8B,CAC5C,MAAoB,EACpB,IAAwB,EACxB,QAAgC,EAChC,GAAmB,EACnB,GAAqB,EACL;IAChB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QAClB,cAAc,EAAE,kBAAkB;QAClC,eAAe,EAAE,UAAU;QAC3B,UAAU,EAAE,YAAY;KACxB,CAAC,CAAC;IACH,GAAG,CAAC,YAAY,EAAE,CAAC;IACnB,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAE1B,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QACnC,cAAc,CAAC,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;YACxB,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC3B,CAAC;IAAA,CACD,EAAE,4BAA4B,CAAC,CAAC;IACjC,SAAS,CAAC,KAAK,EAAE,CAAC;IAElB,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;QACzE,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC9B,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,GAAG,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;YAC/B,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;YACxD,GAAG,CAAC,YAAY,GAAG,OAAO,CAAC;YAC3B,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5B,CAAC;QACD,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IAC/C,CAAC;YAAS,CAAC;QACV,aAAa,CAAC,SAAS,CAAC,CAAC;QACzB,SAAS,CAAC,GAAG,CAAC,CAAC;QACf,GAAG,CAAC,GAAG,EAAE,CAAC;IACX,CAAC;AAAA,CACD;AAED,SAAS,gBAAgB,CAAC,GAAgC,EAAE,MAAkC,EAAQ;IACrG,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,IAAI,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAC1D,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC;QACvB,GAAG,CAAC,YAAY,GAAG,oBAAoB,CAAC;IACzC,CAAC;SAAM,CAAC;QACP,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;QAC3D,IAAI,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,OAAO,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YACpD,GAAG,CAAC,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;QACtC,CAAC;aAAM,IAAI,SAAS,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YACrC,GAAG,CAAC,aAAa,GAAG,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC;QAC/E,CAAC;IACF,CAAC;IACD,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAAA,CAC3B;AAED,KAAK,UAAU,oBAAoB,CAClC,MAAoB,EACpB,IAAwB,EACxB,GAAmB,EACH;IAChB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACtF,IAAI,WAAW,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;QACvC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,4BAA4B,EAAE,IAAI,EAAE,iBAAiB,CAAC,eAAe,EAAE,CAAC,CAAC;QACrG,OAAO;IACR,CAAC;IACD,IAAI,WAAW,EAAE,MAAM,KAAK,WAAW,IAAI,WAAW,CAAC,aAAa,EAAE,CAAC;QACtE,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;QAC9C,OAAO;IACR,CAAC;IACD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,QAAQ,IAAI,QAAQ,EAAE,CAAC;QAC1B,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC9C,OAAO;IACR,CAAC;IAED,IAAI,GAAgC,CAAC;IACrC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAChB,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7D,IAAI,WAAW,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;YACvC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,4BAA4B,EAAE,IAAI,EAAE,iBAAiB,CAAC,eAAe,EAAE,CAAC,CAAC;YACrG,OAAO;QACR,CAAC;QACD,IAAI,WAAW,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;YACvC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,8CAA8C,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;YACvG,OAAO;QACR,CAAC;QACD,GAAG,GAAG,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QACzB,MAAM,0BAA0B,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACnE,OAAO;IACR,CAAC;IAED,MAAM,8BAA8B,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAAA,CACvE;AAED,SAAS,oBAAoB,CAC5B,SAAiB,EACjB,IAAwB,EACxB,WAA+B,EAC/B,QAA4B,EAC5B,YAAgC,EAChC,GAAmB,EACZ;IACP,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACtC,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,mBAAmB,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;QAC9E,OAAO;IACR,CAAC;IACD,MAAM,gBAAgB,GAAG,IAAI,IAAI,CAAC,CAAC;IACnC,IACC,WAAW,KAAK,SAAS;QACzB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM;QACrC,CAAC,QAAQ,KAAK,SAAS,IAAI,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;QACxD,CAAC,YAAY,KAAK,SAAS,IAAI,YAAY,KAAK,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,EACjF,CAAC;QACF,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,4BAA4B,CAAC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;QACnG,OAAO;IACR,CAAC;IACD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,8BAA8B,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAAA,CAC9E;AAED,SAAS,gBAAgB,CAAC,SAAiB,EAAE,KAAa,EAAE,GAAmB,EAAQ;IACtF,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC3C,IAAI,CAAC,GAAG,EAAE,CAAC;QACV,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,iBAAiB,CAAC,aAAa,CAAC,CAAC;QACtE,OAAO;IACR,CAAC;IACD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC;AAAA,CAC/C;AAED,KAAK,UAAU,qBAAqB,CAAC,SAAiB,EAAE,KAAa,EAAE,GAAmB,EAAiB;IAC1G,IAAI,CAAC,SAAS,IAAI,CAAC,KAAK,EAAE,CAAC;QAC1B,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,kCAAkC,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QAClG,OAAO;IACR,CAAC;IAED,IAAI,GAAG,GAAG,YAAY,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACzC,IAAI,CAAC,GAAG,EAAE,CAAC;QACV,GAAG,GAAG,eAAe,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QAClD,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC;QACvB,GAAG,CAAC,eAAe,GAAG,IAAI,CAAC;QAC3B,GAAG,CAAC,YAAY,GAAG,sCAAsC,CAAC;QAC1D,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,SAAS,CAAC,GAAG,CAAC,CAAC;QACf,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;QAC9C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/C,OAAO;IACR,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,GAAG,CAAC,OAAO,CAAC;QAClB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/C,OAAO;IACR,CAAC;IAED,GAAG,CAAC,eAAe,GAAG,IAAI,CAAC;IAC3B,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC3B,GAAG,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACvB,MAAM,GAAG,CAAC,OAAO,CAAC;IAClB,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC;AAAA,CAC/C;AAED,MAAM,UAAU,kBAAkB,CACjC,OAAqB,EACrB,IAAqE,EAC3D;IACV,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,IAAI,CAAC,GAAG,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,CAAC;IACjG,OAAO;QACN,YAAY,EAAE,OAAO,CAAC,aAAa,EAAE,YAAY;QACjD,QAAQ;QACR,KAAK,EAAE,OAAO,CAAC,aAAa,EAAE,KAAK;KACnC,CAAC;AAAA,CACF;AAED,SAAS,YAAY,CAAC,MAAoB,EAAE,IAAuB,EAAE,GAAmB,EAAQ;IAC/F,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,uBAAuB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACvF,OAAO;IACR,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACjB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,mBAAmB,EAAE,iBAAiB,CAAC,sBAAsB,CAAC,CAAC;QACnF,OAAO;IACR,CAAC;IAED,wBAAwB,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAErC,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAEnD,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACxB,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACrD,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,aAAa,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QACnD,SAAS,CACR,GAAG,EACH,GAAG,EACH,yEAAyE,EACzE,iBAAiB,CAAC,yBAAyB,CAC3C,CAAC;QACF,OAAO;IACR,CAAC;IAED,IAAI,IAAI,CAAC,iBAAiB,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACpF,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,oCAAoC,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;QAC7F,OAAO;IACR,CAAC;IACD,IAAI,IAAI,CAAC,cAAc,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QAC9E,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iCAAiC,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;QAC1F,OAAO;IACR,CAAC;IAED,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEtF,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC;IAEjC,IAAI,WAAW,EAAE,MAAM,KAAK,WAAW,EAAE,CAAC;QACzC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YAClB,cAAc,EAAE,mBAAmB;YACnC,eAAe,EAAE,UAAU;YAC3B,UAAU,EAAE,YAAY;SACxB,CAAC,CAAC;QACH,GAAG,CAAC,YAAY,EAAE,CAAC;QACnB,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC5B,KAAK,MAAM,KAAK,IAAI,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC;YAClD,gBAAgB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9B,CAAC;QACD,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO;IACR,CAAC;IACD,IAAI,WAAW,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;QACvC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,4BAA4B,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;QACrF,OAAO;IACR,CAAC;IACD,IAAI,WAAW,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;QACvC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iDAAiD,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;QAC1G,OAAO;IACR,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAChF,MAAM,aAAa,GAAwB;QAC1C,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;QACvB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjD,CAAC;IAEF,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QAClB,cAAc,EAAE,mBAAmB;QACnC,eAAe,EAAE,UAAU;QAC3B,UAAU,EAAE,YAAY;KACxB,CAAC,CAAC;IACH,GAAG,CAAC,YAAY,EAAE,CAAC;IACnB,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAE5B,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QACnC,cAAc,CAAC,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YAC1C,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC7B,CAAC;IAAA,CACD,EAAE,4BAA4B,CAAC,CAAC;IACjC,SAAS,CAAC,KAAK,EAAE,CAAC;IAElB,IAAI,MAA4C,CAAC;IACjD,IAAI,CAAC;QACJ,MAAM,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,aAAa,CAAC,SAAS,CAAC,CAAC;QACzB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC5B,SAAS,CAAC,GAAG,CAAC,CAAC;QACf,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC/B,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACvB,OAAO;IACR,CAAC;IAED,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;QACjB,IAAI,CAAC;YACJ,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAClC,MAAM,UAAU,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;gBACvC,IAAI,UAAU,EAAE,CAAC;oBAChB,cAAc,CAAC,GAAG,CAAC,CAAC;oBACpB,gBAAgB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;gBACnC,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBAC3B,iBAAiB,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBACvC,CAAC;qBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBACnC,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC;gBAC9D,CAAC;YACF,CAAC;QACF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YAC5B,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAChC,CAAC;gBAAS,CAAC;YACV,aAAa,CAAC,SAAS,CAAC,CAAC;YACzB,IAAI,GAAG,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC/B,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,sCAAsC,CAAC,CAAC;YACzG,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,CAAC;YACf,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;IAAA,CACD,CAAC,EAAE,CAAC;AAAA,CACL;AAED,KAAK,UAAU,iBAAiB,CAC/B,MAAoB,EACpB,QAAgB,EAChB,IAAa,EACb,GAAmB,EACA;IACnB,IAAI,QAAQ,KAAK,cAAc,EAAE,CAAC;QACjC,IAAI,CAAC;YACJ,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,CAAC,KAAK,YAAY,kBAAkB,CAAC;gBAAE,MAAM,KAAK,CAAC;YACxD,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,QAAQ,KAAK,mBAAmB,EAAE,CAAC;QACtC,iBAAiB,CAAC,MAAM,EAAE,IAAuB,EAAE,GAAG,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,QAAQ,KAAK,qBAAqB,EAAE,CAAC;QACxC,mBAAmB,CAAC,MAAM,EAAE,IAAiE,EAAE,GAAG,CAAC,CAAC;QACpG,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,QAAQ,KAAK,mBAAmB,EAAE,CAAC;QACtC,iBAAiB,CAAC,MAAM,EAAE,IAAuB,EAAE,GAAG,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,QAAQ,KAAK,qBAAqB,EAAE,CAAC;QACxC,mBAAmB,CAAC,MAAM,EAAE,IAAyB,EAAE,GAAG,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,QAAQ,KAAK,wBAAwB,EAAE,CAAC;QAC3C,qBAAqB,CAAC,MAAM,EAAE,IAA2B,EAAE,GAAG,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,QAAQ,KAAK,0BAA0B,EAAE,CAAC;QAC7C,uBAAuB,CAAC,MAAM,EAAE,IAA2B,EAAE,GAAG,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,QAAQ,KAAK,0BAA0B,EAAE,CAAC;QAC7C,uBAAuB,CAAC,MAAM,EAAE,IAA6B,EAAE,GAAG,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,QAAQ,KAAK,sBAAsB,EAAE,CAAC;QACzC,MAAM,oBAAoB,CAAC,MAAM,EAAE,IAA0B,EAAE,GAAG,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,QAAQ,KAAK,aAAa,EAAE,CAAC;QAChC,YAAY,CAAC,MAAM,EAAE,IAAyB,EAAE,GAAG,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO,KAAK,CAAC;AAAA,CACb;AAED,MAAM,UAAU,cAAc,CAAC,cAAsC,EAAc;IAClF,MAAM,MAAM,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAC1C,qBAAqB,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAE9C,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;QAC/C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;QAExD,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACxD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACrC,OAAO;QACR,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,GACT,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG;gBAC3C,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,iBAAiB,EAAE;gBACvD,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;YAC9B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YACzB,OAAO;QACR,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,KAAK,eAAe,EAAE,CAAC;YAC9D,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;YACjD,OAAO;QACR,CAAC;QAED,MAAM,QAAQ,GAAG,0CAA0C,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC/E,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,QAAQ,EAAE,CAAC;YACtC,gBAAgB,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACxF,OAAO;QACR,CAAC;QAED,MAAM,aAAa,GAAG,iDAAiD,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3F,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,aAAa,EAAE,CAAC;YAC5C,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;YACpB,MAAM,qBAAqB,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC7G,OAAO;QACR,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3G,MAAM,gBAAgB,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YACxF,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC/C,MAAM,IAAI,GAAG,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAChE,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC;gBACjE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,qCAAqC,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;gBAC9F,OAAO;YACR,CAAC;YACD,MAAM,gBAAgB,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YAC7D,MAAM,WAAW,GAAG,gBAAgB,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;YACrF,IAAI,WAAW,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,WAAW,GAAG,CAAC,CAAC,EAAE,CAAC;gBACtF,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,4CAA4C,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;gBACrG,OAAO;YACR,CAAC;YACD,MAAM,aAAa,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACvD,MAAM,QAAQ,GAAG,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAC5E,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC;gBAC7E,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,yCAAyC,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;gBAClG,OAAO;YACR,CAAC;YACD,oBAAoB,CACnB,kBAAkB,CAAC,gBAAgB,CAAC,EACpC,IAAI,EACJ,WAAW,EACX,QAAQ,EACR,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,SAAS,EACjD,GAAG,CACH,CAAC;YACF,OAAO;QACR,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,KAAK,cAAc,EAAE,CAAC;YAC9D,IAAI,CAAC;gBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAqB,CAAC;gBACjE,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;gBAC9C,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;oBAC3B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC;oBACpC,OAAO;gBACR,CAAC;gBACD,MAAM,OAAO,GAAG,MAAM,iBAAiB,CACtC,MAAM,EACN,WAAW,CAAC,MAAM,EAClB,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAY,EAC3C,GAAG,CACH,CAAC;gBACF,IAAI,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;oBAClC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;gBACrE,CAAC;YACF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC1B,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;oBACtB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;gBAC1G,CAAC;qBAAM,CAAC;oBACP,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBAC9E,GAAG,CAAC,GAAG,EAAE,CAAC;gBACX,CAAC;YACF,CAAC;YACD,OAAO;QACR,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAY,CAAC;gBACxD,IAAI,MAAM,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC;oBAAE,OAAO;gBACrE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;oBACtB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;oBACpE,OAAO;gBACR,CAAC;YACF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC1B,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;oBACtB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;gBACzG,CAAC;qBAAM,CAAC;oBACP,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBAC9E,GAAG,CAAC,GAAG,EAAE,CAAC;gBACX,CAAC;gBACD,OAAO;YACR,CAAC;QACF,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YACzE,MAAM,SAAS,GAAG,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;YACjF,sBAAsB,CAAC,SAAS,CAAC,CAAC;YAClC,0BAA0B,CAAC,SAAS,CAAC,CAAC;YACtC,sBAAsB,CAAC,MAAM,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;YAC1D,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;YAC3C,OAAO;QACR,CAAC;QAED,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;IAAA,CACpE,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAAA,CACd;AAED,SAAS,YAAY,CAAC,KAA4B,EAA0C;IAC3F,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,OAAO;YACX,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC1B,KAAK,YAAY;YAChB,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC;QACjE,KAAK,YAAY;YAChB,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;QACrF,KAAK,UAAU;YACd,OAAO;gBACN,IAAI,EAAE,UAAU;gBAChB,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,gBAAgB,EACf,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,IAAI,KAAK,MAAM;oBACzD,CAAC,CAAE,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAgC,CAAC,aAAa;oBACzF,CAAC,CAAC,SAAS;aACb,CAAC;QACH,KAAK,gBAAgB;YACpB,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC;QACrE,KAAK,gBAAgB;YACpB,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;QACzF,KAAK,cAAc;YAClB,OAAO;gBACN,IAAI,EAAE,cAAc;gBACpB,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,gBAAgB,EACf,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,IAAI,KAAK,UAAU;oBAC7D,CAAC,CAAE,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAoC,CAAC,iBAAiB;oBACjG,CAAC,CAAC,SAAS;aACb,CAAC;QACH,KAAK,gBAAgB;YACpB,OAAO;gBACN,IAAI,EAAE,gBAAgB;gBACtB,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,EAAE,EACD,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,IAAI,KAAK,UAAU;oBAC7D,CAAC,CAAE,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAoB,CAAC,EAAE;oBAClE,CAAC,CAAC,EAAE;gBACN,QAAQ,EACP,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,IAAI,KAAK,UAAU;oBAC7D,CAAC,CAAE,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAsB,CAAC,IAAI;oBACtE,CAAC,CAAC,EAAE;aACN,CAAC;QACH,KAAK,gBAAgB;YACpB,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;QACzF,KAAK,cAAc;YAClB,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC7F,KAAK,MAAM;YACV,OAAO;gBACN,IAAI,EAAE,MAAM;gBACZ,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK;gBAC1B,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ;gBAChC,OAAO,EAAE,KAAK,CAAC,OAAO;aACtB,CAAC;QACH,KAAK,OAAO;YACX,OAAO;gBACN,IAAI,EAAE,OAAO;gBACb,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY;gBACtC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK;aACxB,CAAC;QACH;YACC,OAAO,SAAS,CAAC;IACnB,CAAC;AAAA,CACD;AAED,MAAM,UAAU,WAAW,CAAC,cAAsC,EAAc;IAC/E,MAAM,MAAM,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;IAC9C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;QAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;QAC1F,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;QAC1G,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;IAAA,CACtD,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAAA,CACd","sourcesContent":["import { createServer, type Server as HttpServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { createRequire } from \"node:module\";\nimport {\n\ttype CompactionCacheRequestOptions,\n\ttype CompactionPreparationOptions,\n\ttype CompactionSettings,\n\tcompactLegacy,\n\tconvertToLlm,\n\tDEFAULT_COMPACTION_SETTINGS,\n\ttype LegacyCompactResult,\n\ttype ProxyAssistantMessageEvent,\n\tprepareLegacyCompaction,\n\ttype SessionTreeEntry,\n} from \"@earendil-works/pi-agent-core\";\nimport {\n\ttype AssistantMessage,\n\ttype AssistantMessageEvent,\n\ttype Context,\n\tcreateModels,\n\tcreateProvider,\n\ttype Message,\n\ttype Model,\n\ttype ProviderStreams,\n\ttype SimpleStreamOptions,\n} from \"@earendil-works/pi-ai\";\nimport { streamSimple } from \"@earendil-works/pi-ai/compat\";\nimport type { ServerConfig } from \"./config.ts\";\nimport { loadConfig } from \"./config.ts\";\nimport { PiServerError, PiServerErrorCode, type PiServerErrorResponse } from \"./error-codes.ts\";\nimport { encodeErrorEvent, encodeProxyEvent } from \"./event-encoding.ts\";\nimport { hashPiServerProviderMessages } from \"./pi-server-protocol.ts\";\nimport { ReceiveUploadError, receiveUpload } from \"./receive-upload.ts\";\nimport { CHUNK_ENDPOINT, type RequestChunkBody, receiveRequestChunk } from \"./request-chunks.ts\";\nimport { deletePersistedSession, loadPersistedSessions, savePersistedSession } from \"./session-persistence.ts\";\nimport {\n\tappendCompactionEntry,\n\tappendMessages,\n\tappendSessionEntries,\n\tdeleteSession as deleteSessionFromStore,\n\tgetOrCreateSession,\n\tgetSession,\n\tgetSessionBranch,\n\tlistSessions,\n\treplaceMessages,\n\treplaceSessionTree,\n\ttype SessionState,\n\ttype SessionStaticContext,\n\tsetStaticContext,\n\tswitchSessionLeaf,\n} from \"./session-store.ts\";\n\nexport { loadConfig, type ServerConfig } from \"./config.ts\";\n\ninterface PackageMetadata {\n\tversion: string;\n}\n\nconst packageMetadata = createRequire(import.meta.url)(\"../package.json\") as PackageMetadata;\nconst PI_SERVER_VERSION = packageMetadata.version;\n\ninterface SessionInitBody {\n\tsessionId: string;\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface StreamRequestBody {\n\tsessionId: string;\n\trunId?: string;\n\tmodel: Model<any>;\n\toptions?: SimpleStreamOptions;\n\tstaticContext?: SessionStaticContext;\n\tephemeralMessages?: Message[];\n\tcontextOverlay?: Message[];\n}\n\ninterface SessionSyncBody {\n\tsessionId: string;\n\tmessages: Message[];\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface SessionAppendBody {\n\tsessionId: string;\n\tmessages: Message[];\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface SessionTreeSyncBody {\n\tsessionId: string;\n\tentries: SessionTreeEntry[];\n\tleafId: string | null;\n\tstaticContext?: SessionStaticContext;\n}\n\ninterface SessionTreeSwitchBody {\n\tsessionId: string;\n\tleafId: string | null;\n}\n\ninterface SessionCompactBody {\n\tsessionId: string;\n\trunId?: string;\n\tmodel: Model<any>;\n\toptions?: SimpleStreamOptions;\n\tsettings?: CompactionSettings;\n\tpreparation?: CompactionPreparationOptions;\n\tcustomInstructions?: string;\n\tcacheContextHash?: string;\n\tcacheStaticContextHash?: string;\n\tcacheFallbackReason?: string;\n\tbaseTreeHash?: string;\n\tfullResponse?: boolean;\n\tstreamResponse?: boolean;\n}\n\nfunction createRequestModels(model: Model<any>, options: SimpleStreamOptions) {\n\tconst models = createModels();\n\tconst requestStream: ProviderStreams[\"streamSimple\"] = (requestModel, context, streamOptions) =>\n\t\tstreamSimple(requestModel, context, {\n\t\t\t...streamOptions,\n\t\t\t...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),\n\t\t});\n\tmodels.setProvider(\n\t\tcreateProvider({\n\t\t\tid: model.provider,\n\t\t\tname: model.provider,\n\t\t\tmodels: [model],\n\t\t\tauth: {\n\t\t\t\tapiKey: {\n\t\t\t\t\tname: \"pi-server request auth\",\n\t\t\t\t\tresolve: async () => ({ auth: { apiKey: options.apiKey, headers: options.headers } }),\n\t\t\t\t},\n\t\t\t},\n\t\t\tapi: {\n\t\t\t\tstream: requestStream,\n\t\t\t\tstreamSimple: requestStream,\n\t\t\t},\n\t\t}),\n\t);\n\treturn models;\n}\n\ninterface StreamRunRecord {\n\tsessionId: string;\n\trunId: string;\n\tkind: \"stream\" | \"compact\";\n\tstatus: \"running\" | \"completed\" | \"failed\" | \"aborted\";\n\tmessage?: AssistantMessage;\n\tcompactResult?: SessionCompactSuccessBody;\n\terrorMessage?: string;\n\tcreatedAt: number;\n\tupdatedAt: number;\n\tcancelRequested: boolean;\n\tcontroller: AbortController;\n\tsettled: Promise<void>;\n\tresolveSettled: (() => void) | undefined;\n}\n\nconst STREAM_HEARTBEAT = \": keep-alive\\n\\n\";\nconst JSON_HEARTBEAT = \" \\n\";\nconst STREAM_HEARTBEAT_INTERVAL_MS = 25_000;\nconst STREAM_RUN_TTL_MS = 60 * 60 * 1000; // 1 hour\nconst streamRuns = new Map<string, StreamRunRecord>();\n\nfunction readBody(req: IncomingMessage): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst chunks: Buffer[] = [];\n\t\treq.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n\t\treq.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf-8\")));\n\t\treq.on(\"error\", reject);\n\t});\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n\tconst data = JSON.stringify(body);\n\tres.writeHead(status, { \"Content-Type\": \"application/json\", \"Content-Length\": Buffer.byteLength(data) });\n\tres.end(data);\n}\n\nfunction sendError(\n\tres: ServerResponse,\n\tstatus: number,\n\tmessage: string,\n\tcode?: PiServerErrorCode,\n\tdetails?: Record<string, unknown>,\n): void {\n\tconst body: PiServerErrorResponse = { error: message };\n\tif (code) body.code = code;\n\tif (details) body.details = details;\n\tsendJson(res, status, body);\n}\n\nfunction logRequestError(req: IncomingMessage, error: unknown): void {\n\tconst message = error instanceof Error ? error.stack || error.message : String(error);\n\tconsole.error(`${req.method ?? \"UNKNOWN\"} ${req.url ?? \"/\"} failed: ${message}`);\n}\n\nfunction authenticate(config: ServerConfig, req: IncomingMessage): boolean {\n\tif (!config.authToken) return true;\n\tconst header = req.headers.authorization;\n\tif (!header) return false;\n\tconst token = header.startsWith(\"Bearer \") ? header.slice(7) : header;\n\treturn token === config.authToken;\n}\n\nfunction sessionResponseBody(session: SessionState) {\n\treturn {\n\t\tsessionId: session.sessionId,\n\t\tstaticContextHash: session.staticContextHash,\n\t\ttreeHash: session.treeHash,\n\t\tmessageCount: session.messages.length,\n\t\tentryCount: session.entries.length,\n\t\tleafId: session.leafId,\n\t\trevision: session.revision,\n\t};\n}\n\nfunction persistSession(config: ServerConfig, session: SessionState): void {\n\tsavePersistedSession(config.sessionStoreDir, session);\n}\n\nfunction runKey(sessionId: string, runId: string): string {\n\treturn `${sessionId}\\0${runId}`;\n}\n\nfunction getStreamRun(sessionId: string, runId: string): StreamRunRecord | undefined {\n\treturn streamRuns.get(runKey(sessionId, runId));\n}\n\nfunction createRunRecord(sessionId: string, runId: string, kind: StreamRunRecord[\"kind\"]): StreamRunRecord {\n\tlet resolveSettled: (() => void) | undefined;\n\tconst settled = new Promise<void>((resolve) => {\n\t\tresolveSettled = resolve;\n\t});\n\treturn {\n\t\tsessionId,\n\t\trunId,\n\t\tkind,\n\t\tstatus: \"running\",\n\t\tcreatedAt: Date.now(),\n\t\tupdatedAt: Date.now(),\n\t\tcancelRequested: false,\n\t\tcontroller: new AbortController(),\n\t\tsettled,\n\t\tresolveSettled,\n\t};\n}\n\nfunction settleRun(run: StreamRunRecord | undefined): void {\n\tif (!run) return;\n\tconst resolve = run.resolveSettled;\n\trun.resolveSettled = undefined;\n\tresolve?.();\n}\n\nfunction startStreamRun(sessionId: string, runId: string, kind: StreamRunRecord[\"kind\"] = \"stream\"): StreamRunRecord {\n\tconst existing = getStreamRun(sessionId, runId);\n\tif (existing?.status === \"completed\" || existing?.status === \"aborted\") return existing;\n\tconst run = existing ?? createRunRecord(sessionId, runId, kind);\n\tif (existing) {\n\t\trun.message = undefined;\n\t\trun.errorMessage = undefined;\n\t\trun.cancelRequested = false;\n\t\trun.controller = new AbortController();\n\t\tlet resolveSettled: (() => void) | undefined;\n\t\trun.settled = new Promise<void>((resolve) => {\n\t\t\tresolveSettled = resolve;\n\t\t});\n\t\trun.resolveSettled = resolveSettled;\n\t}\n\trun.kind = kind;\n\trun.status = \"running\";\n\trun.updatedAt = Date.now();\n\tstreamRuns.set(runKey(sessionId, runId), run);\n\treturn run;\n}\n\nfunction streamRunResponseBody(run: StreamRunRecord) {\n\treturn {\n\t\tsessionId: run.sessionId,\n\t\trunId: run.runId,\n\t\tstatus: run.status,\n\t\tcreatedAt: run.createdAt,\n\t\tupdatedAt: run.updatedAt,\n\t\t...(run.message ? { message: run.message } : {}),\n\t\t...(run.compactResult ? { compactResult: run.compactResult } : {}),\n\t\t...(run.errorMessage ? { errorMessage: run.errorMessage } : {}),\n\t};\n}\n\nfunction replayStreamRun(run: StreamRunRecord): ProxyAssistantMessageEvent[] {\n\tif (!run.message) return [];\n\tif (\n\t\trun.message.stopReason !== \"stop\" &&\n\t\trun.message.stopReason !== \"length\" &&\n\t\trun.message.stopReason !== \"toolUse\" &&\n\t\trun.message.stopReason !== \"deferred\"\n\t) {\n\t\treturn [];\n\t}\n\tconst events: ProxyAssistantMessageEvent[] = [{ type: \"start\" }];\n\tfor (const [contentIndex, content] of run.message.content.entries()) {\n\t\tswitch (content.type) {\n\t\t\tcase \"text\":\n\t\t\t\tevents.push(\n\t\t\t\t\t{ type: \"text_start\", contentIndex },\n\t\t\t\t\t{ type: \"text_delta\", contentIndex, delta: content.text },\n\t\t\t\t\t{ type: \"text_end\", contentIndex, contentSignature: content.textSignature },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"thinking\":\n\t\t\t\tevents.push(\n\t\t\t\t\t{ type: \"thinking_start\", contentIndex },\n\t\t\t\t\t{ type: \"thinking_delta\", contentIndex, delta: content.thinking },\n\t\t\t\t\t{ type: \"thinking_end\", contentIndex, contentSignature: content.thinkingSignature },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"toolCall\":\n\t\t\t\tevents.push(\n\t\t\t\t\t{ type: \"toolcall_start\", contentIndex, id: content.id, toolName: content.name },\n\t\t\t\t\t{ type: \"toolcall_delta\", contentIndex, delta: JSON.stringify(content.arguments) },\n\t\t\t\t\t{ type: \"toolcall_end\", contentIndex, toolCall: content },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tevents.push({\n\t\ttype: \"done\",\n\t\treason: run.message.stopReason,\n\t\tusage: run.message.usage,\n\t\tdeferred: run.message.deferred,\n\t\tmessage: run.message,\n\t});\n\treturn events;\n}\n\nfunction completeStreamRun(run: StreamRunRecord | undefined, message: AssistantMessage): void {\n\tif (!run) return;\n\tif (run.cancelRequested) {\n\t\trun.status = \"aborted\";\n\t\trun.message = undefined;\n\t\trun.errorMessage = \"Stream run aborted\";\n\t\trun.updatedAt = Date.now();\n\t\treturn;\n\t}\n\trun.status = \"completed\";\n\trun.message = message;\n\trun.errorMessage = undefined;\n\trun.updatedAt = Date.now();\n}\n\nfunction failStreamRun(run: StreamRunRecord | undefined, errorMessage: string): void {\n\tif (!run) return;\n\tif (run.cancelRequested) {\n\t\trun.status = \"aborted\";\n\t\trun.errorMessage = \"Stream run aborted\";\n\t\trun.updatedAt = Date.now();\n\t\treturn;\n\t}\n\trun.status = \"failed\";\n\trun.errorMessage = errorMessage;\n\trun.updatedAt = Date.now();\n}\n\nfunction touchStreamRun(run: StreamRunRecord | undefined): void {\n\tif (run) run.updatedAt = Date.now();\n}\n\nfunction writeStreamEvent(res: ServerResponse, event: ProxyAssistantMessageEvent): void {\n\tif (!res.writableEnded && !res.destroyed) {\n\t\tres.write(encodeProxyEvent(event));\n\t}\n}\n\nfunction writeStreamError(res: ServerResponse, message: string): void {\n\tif (!res.writableEnded && !res.destroyed) {\n\t\tres.write(encodeErrorEvent(message));\n\t}\n}\n\nfunction endStreamResponse(res: ServerResponse): void {\n\tif (!res.writableEnded && !res.destroyed) {\n\t\tres.end();\n\t}\n}\n\nfunction cleanupExpiredStreamRuns(nowMs: number): void {\n\tfor (const [key, run] of streamRuns) {\n\t\tif (nowMs - run.updatedAt > STREAM_RUN_TTL_MS) {\n\t\t\tstreamRuns.delete(key);\n\t\t}\n\t}\n}\n\nfunction deleteStreamRunsForSession(sessionId: string): void {\n\tfor (const [key, run] of streamRuns) {\n\t\tif (run.sessionId === sessionId) streamRuns.delete(key);\n\t}\n}\n\nconst streamRunCleanupTimer = setInterval(() => cleanupExpiredStreamRuns(Date.now()), STREAM_RUN_TTL_MS / 4);\nstreamRunCleanupTimer.unref();\n\nfunction sessionHistoryFullResponseBody(session: SessionState, baseMessageCount: number) {\n\treturn {\n\t\tsessionId: session.sessionId,\n\t\tstaticContext: session.staticContext,\n\t\tstaticContextHash: session.staticContextHash,\n\t\ttreeHash: session.treeHash,\n\t\tmessageCount: session.messages.length,\n\t\tentryCount: session.entries.length,\n\t\tleafId: session.leafId,\n\t\trevision: session.revision,\n\t\tentries: session.entries,\n\t\tbaseMessageCount,\n\t\tmessages: session.messages.slice(baseMessageCount),\n\t};\n}\n\nfunction sessionTreePatchResponseBody(\n\tsession: SessionState,\n\tbaseMessageCount: number,\n\tentriesFrom: number,\n\tbaseRevision: number | undefined,\n) {\n\treturn {\n\t\tsessionId: session.sessionId,\n\t\tstaticContext: session.staticContext,\n\t\tstaticContextHash: session.staticContextHash,\n\t\ttreeHash: session.treeHash,\n\t\tmessageCount: session.messages.length,\n\t\tentryCount: session.entries.length,\n\t\tleafId: session.leafId,\n\t\trevision: session.revision,\n\t\tbaseMessageCount,\n\t\tmessages: session.messages.slice(baseMessageCount),\n\t\ttreePatch: {\n\t\t\tentriesFrom,\n\t\t\tbaseRevision,\n\t\t\tentries: session.entries.slice(entriesFrom),\n\t\t\tleafId: session.leafId,\n\t\t\trevision: session.revision,\n\t\t},\n\t};\n}\n\ntype PreparedCompaction = Parameters<typeof compactLegacy>[0];\n\ninterface PreparedSessionCompact {\n\tsession: SessionState;\n\tsessionId: string;\n\trevision: number;\n\ttreeHash: string;\n\tleafId: string | null;\n\tentryCount: number;\n\tpreparation: PreparedCompaction;\n\toptions: SimpleStreamOptions;\n\tcacheContext?: Context;\n\tcacheFallbackReason: string;\n}\n\ninterface SessionCompactSuccessBody {\n\tsuccess: true;\n\tcompaction: Omit<LegacyCompactResult, \"retainedTail\">;\n\tcompactionEntry: SessionTreeEntry;\n\tsessionId: string;\n\tstaticContextHash: string;\n\ttreeHash: string;\n\tmessageCount: number;\n\tentryCount: number;\n\tleafId: string | null;\n\trevision: number;\n\tstaticContext?: SessionStaticContext;\n\ttreePatch?: {\n\t\tbaseTreeHash: string;\n\t\tentriesFrom: number;\n\t\tentries: SessionTreeEntry[];\n\t\tleafId: string | null;\n\t\trevision: number;\n\t};\n\tentries?: SessionTreeEntry[];\n\tmessages?: Message[];\n}\n\ninterface SessionCompactHttpResponse {\n\tstatus: number;\n\tbody: PiServerErrorResponse | SessionCompactSuccessBody;\n}\n\nfunction handleSessionInit(config: ServerConfig, body: SessionInitBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t} else {\n\t\tgetOrCreateSession(body.sessionId);\n\t}\n\tconst session = getSession(body.sessionId)!;\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionUpdate(\n\tconfig: ServerConfig,\n\tbody: SessionInitBody & { staticContext: SessionStaticContext },\n\tres: ServerResponse,\n): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!body.staticContext) {\n\t\tsendError(res, 400, \"staticContext is required for update\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tsetStaticContext(body.sessionId, body.staticContext);\n\tconst session = getSession(body.sessionId)!;\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionSync(config: ServerConfig, body: SessionSyncBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.messages)) {\n\t\tsendError(res, 400, \"messages is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t}\n\tconst session = replaceMessages(body.sessionId, body.messages);\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionAppend(config: ServerConfig, body: SessionAppendBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.messages)) {\n\t\tsendError(res, 400, \"messages is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t}\n\tconst session = appendMessages(body.sessionId, body.messages);\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionTreeSync(config: ServerConfig, body: SessionTreeSyncBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.entries)) {\n\t\tsendError(res, 400, \"entries is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t}\n\tconst session = replaceSessionTree(body.sessionId, body.entries, body.leafId ?? null);\n\tpersistSession(config, session);\n\tsendJson(res, 200, sessionResponseBody(session));\n}\n\nfunction handleSessionTreeAppend(config: ServerConfig, body: SessionTreeSyncBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!Array.isArray(body.entries)) {\n\t\tsendError(res, 400, \"entries is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\ttry {\n\t\tif (body.staticContext) {\n\t\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t\t}\n\t\tconst session = appendSessionEntries(body.sessionId, body.entries, body.leafId ?? null);\n\t\tpersistSession(config, session);\n\t\tsendJson(res, 200, sessionResponseBody(session));\n\t} catch (error) {\n\t\tif (error instanceof PiServerError) {\n\t\t\tsendError(res, 400, error.message, error.code, error.details);\n\t\t} else {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tsendError(res, 500, message, PiServerErrorCode.INTERNAL_ERROR);\n\t\t}\n\t}\n}\n\nfunction handleSessionTreeSwitch(config: ServerConfig, body: SessionTreeSwitchBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\ttry {\n\t\tconst session = switchSessionLeaf(body.sessionId, body.leafId ?? null);\n\t\tpersistSession(config, session);\n\t\tsendJson(res, 200, sessionResponseBody(session));\n\t} catch (error) {\n\t\tif (error instanceof PiServerError) {\n\t\t\tsendError(res, 400, error.message, error.code, error.details);\n\t\t} else {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tsendError(res, 500, message, PiServerErrorCode.INTERNAL_ERROR);\n\t\t}\n\t}\n}\n\nfunction prepareSessionCompact(body: SessionCompactBody): PreparedSessionCompact | SessionCompactHttpResponse {\n\tif (!body.sessionId) {\n\t\treturn { status: 400, body: { error: \"sessionId is required\" } };\n\t}\n\tif (!body.model) {\n\t\treturn { status: 400, body: { error: \"model is required\" } };\n\t}\n\tconst validDigest = (value: string | undefined): boolean => value === undefined || /^[a-f0-9]{64}$/.test(value);\n\tif (!validDigest(body.cacheContextHash) || !validDigest(body.cacheStaticContextHash)) {\n\t\treturn { status: 400, body: { error: \"cache context digests must be 64-character SHA-256 hex strings\" } };\n\t}\n\tif ((body.cacheContextHash === undefined) !== (body.cacheStaticContextHash === undefined)) {\n\t\treturn { status: 400, body: { error: \"cacheContextHash and cacheStaticContextHash must be supplied together\" } };\n\t}\n\n\tconst session = getSession(body.sessionId);\n\tif (!session) {\n\t\treturn { status: 404, body: { error: \"session not found\", code: PiServerErrorCode.SESSION_NOT_FOUND } };\n\t}\n\n\tconst entries = getSessionBranch(session);\n\tconst leaf = entries.at(-1);\n\tif (leaf?.type === \"compaction\") {\n\t\tif (!leaf.firstKeptEntryId) {\n\t\t\treturn { status: 400, body: { error: \"Stored compaction is missing firstKeptEntryId\" } };\n\t\t}\n\t\treturn {\n\t\t\tstatus: 200,\n\t\t\tbody: {\n\t\t\t\tsuccess: true,\n\t\t\t\tcompaction: {\n\t\t\t\t\tsummary: leaf.summary,\n\t\t\t\t\tfirstKeptEntryId: leaf.firstKeptEntryId,\n\t\t\t\t\ttokensBefore: leaf.tokensBefore,\n\t\t\t\t\tdetails: leaf.details,\n\t\t\t\t},\n\t\t\t\tcompactionEntry: leaf,\n\t\t\t\t...sessionResponseBody(session),\n\t\t\t\tentries: session.entries,\n\t\t\t\tmessages: session.messages,\n\t\t\t},\n\t\t};\n\t}\n\tconst preparationResult = prepareLegacyCompaction(\n\t\tentries,\n\t\tbody.settings ?? DEFAULT_COMPACTION_SETTINGS,\n\t\tbody.preparation,\n\t);\n\tif (!preparationResult.ok) {\n\t\treturn { status: 400, body: { error: preparationResult.error.message } };\n\t}\n\tif (!preparationResult.value) {\n\t\treturn { status: 400, body: { error: \"Nothing to compact\" } };\n\t}\n\n\tconst options = body.options ?? {};\n\tlet cacheContext: Context | undefined;\n\tlet cacheFallbackReason = body.cacheFallbackReason ?? \"cache_context_digest_missing\";\n\tif (body.cacheContextHash && body.cacheStaticContextHash) {\n\t\tif (options.sessionId !== session.sessionId) {\n\t\t\tcacheFallbackReason = \"session_id_mismatch\";\n\t\t} else if (options.cacheRetention === \"none\") {\n\t\t\tcacheFallbackReason = \"prompt_cache_disabled\";\n\t\t} else if (body.cacheStaticContextHash !== session.staticContextHash) {\n\t\t\tcacheFallbackReason = \"static_context_hash_mismatch\";\n\t\t} else {\n\t\t\tconst projectedMessages = convertToLlm(session.messages);\n\t\t\tconst priorAssistant = [...session.messages].reverse().find((message) => message.role === \"assistant\");\n\t\t\tif (hashPiServerProviderMessages(projectedMessages) !== body.cacheContextHash) {\n\t\t\t\tcacheFallbackReason = \"request_context_digest_mismatch\";\n\t\t\t} else if (\n\t\t\t\t!priorAssistant ||\n\t\t\t\tpriorAssistant.provider !== body.model.provider ||\n\t\t\t\tpriorAssistant.model !== body.model.id ||\n\t\t\t\tpriorAssistant.api !== body.model.api\n\t\t\t) {\n\t\t\t\tcacheFallbackReason = \"summary_model_mismatch\";\n\t\t\t} else {\n\t\t\t\tcacheContext = buildStreamContext(session, { contextOverlay: projectedMessages });\n\t\t\t\tcacheFallbackReason = \"exact_prefix_unavailable\";\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tsession,\n\t\tsessionId: session.sessionId,\n\t\trevision: session.revision,\n\t\ttreeHash: session.treeHash,\n\t\tleafId: session.leafId,\n\t\tentryCount: session.entries.length,\n\t\tpreparation: preparationResult.value,\n\t\toptions,\n\t\tcacheContext,\n\t\tcacheFallbackReason,\n\t};\n}\n\nfunction sessionCompactConflict(\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\tcurrentSession: SessionState | undefined,\n): SessionCompactHttpResponse {\n\treturn {\n\t\tstatus: 409,\n\t\tbody: {\n\t\t\terror: \"Session changed while compaction was running\",\n\t\t\tcode: PiServerErrorCode.SESSION_STATE_CONFLICT,\n\t\t\tdetails: {\n\t\t\t\tsessionId: body.sessionId,\n\t\t\t\texpectedRevision: prepared.revision,\n\t\t\t\texpectedTreeHash: prepared.treeHash,\n\t\t\t\texpectedLeafId: prepared.leafId,\n\t\t\t\tactualRevision: currentSession?.revision ?? null,\n\t\t\t\tactualTreeHash: currentSession?.treeHash ?? null,\n\t\t\t\tactualLeafId: currentSession?.leafId ?? null,\n\t\t\t},\n\t\t},\n\t};\n}\n\nasync function completeSessionCompact(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\trun?: StreamRunRecord,\n): Promise<SessionCompactHttpResponse> {\n\tconst result = await compactLegacy(\n\t\tprepared.preparation,\n\t\tcreateRequestModels(body.model, prepared.options),\n\t\tbody.model,\n\t\tbody.customInstructions,\n\t\trun?.controller.signal,\n\t\tprepared.options.reasoning,\n\t\tundefined,\n\t\tundefined,\n\t\tprepared.cacheContext,\n\t\tprepared.options as CompactionCacheRequestOptions,\n\t\tprepared.cacheFallbackReason,\n\t);\n\tif (!result.ok) {\n\t\treturn { status: 500, body: { error: result.error.message, code: PiServerErrorCode.INTERNAL_ERROR } };\n\t}\n\tif (run?.cancelRequested || run?.controller.signal.aborted) {\n\t\treturn { status: 409, body: { error: \"Compaction aborted\", code: PiServerErrorCode.INVALID_REQUEST } };\n\t}\n\n\tconst currentSession = getSession(prepared.sessionId);\n\tif (\n\t\t!currentSession ||\n\t\tcurrentSession !== prepared.session ||\n\t\tcurrentSession.revision !== prepared.revision ||\n\t\tcurrentSession.treeHash !== prepared.treeHash ||\n\t\tcurrentSession.leafId !== prepared.leafId\n\t) {\n\t\treturn sessionCompactConflict(body, prepared, currentSession);\n\t}\n\n\tconst baseTreeHash = prepared.treeHash;\n\tconst baseEntryCount = prepared.entryCount;\n\tconst compaction = result.value;\n\tconst { session: updatedSession, entry: compactionEntry } = appendCompactionEntry(body.sessionId, compaction);\n\tpersistSession(config, updatedSession);\n\tif (!body.fullResponse && body.baseTreeHash === baseTreeHash) {\n\t\treturn {\n\t\t\tstatus: 200,\n\t\t\tbody: {\n\t\t\t\tsuccess: true,\n\t\t\t\tcompaction: compaction satisfies LegacyCompactResult,\n\t\t\t\tcompactionEntry,\n\t\t\t\t...sessionResponseBody(updatedSession),\n\t\t\t\tstaticContext: updatedSession.staticContext,\n\t\t\t\ttreePatch: {\n\t\t\t\t\tbaseTreeHash,\n\t\t\t\t\tentriesFrom: baseEntryCount,\n\t\t\t\t\tentries: [compactionEntry],\n\t\t\t\t\tleafId: updatedSession.leafId,\n\t\t\t\t\trevision: updatedSession.revision,\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\treturn {\n\t\tstatus: 200,\n\t\tbody: {\n\t\t\tsuccess: true,\n\t\t\tcompaction: compaction satisfies LegacyCompactResult,\n\t\t\tcompactionEntry,\n\t\t\t...sessionResponseBody(updatedSession),\n\t\t\tstaticContext: updatedSession.staticContext,\n\t\t\tentries: updatedSession.entries,\n\t\t\tmessages: updatedSession.messages,\n\t\t},\n\t};\n}\n\nfunction writeServerSentEvent(res: ServerResponse, event: string, body: unknown): void {\n\tres.write(`event: ${event}\\n`);\n\tres.write(`data: ${JSON.stringify(body)}\\n\\n`);\n}\n\nasync function handleSessionCompactStream(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\tres: ServerResponse,\n\trun?: StreamRunRecord,\n): Promise<void> {\n\tres.writeHead(200, {\n\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\"Cache-Control\": \"no-cache\",\n\t\tConnection: \"keep-alive\",\n\t});\n\tres.flushHeaders();\n\tres.write(STREAM_HEARTBEAT);\n\n\tconst heartbeat = setInterval(() => {\n\t\ttouchStreamRun(run);\n\t\tif (!res.writableEnded) {\n\t\t\tres.write(STREAM_HEARTBEAT);\n\t\t}\n\t}, STREAM_HEARTBEAT_INTERVAL_MS);\n\theartbeat.unref();\n\n\ttry {\n\t\tconst result = await completeSessionCompact(config, body, prepared, run);\n\t\tfinishCompactRun(run, result);\n\t\twriteServerSentEvent(res, result.status >= 400 ? \"error\" : \"result\", result.body);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tif (run?.status === \"running\") {\n\t\t\trun.status = run.cancelRequested ? \"aborted\" : \"failed\";\n\t\t\trun.errorMessage = message;\n\t\t\trun.updatedAt = Date.now();\n\t\t}\n\t\twriteServerSentEvent(res, \"error\", { error: message });\n\t} finally {\n\t\tclearInterval(heartbeat);\n\t\tsettleRun(run);\n\t\tres.end();\n\t}\n}\n\nasync function handleSessionCompactJsonStream(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tprepared: PreparedSessionCompact,\n\tres: ServerResponse,\n\trun?: StreamRunRecord,\n): Promise<void> {\n\tres.writeHead(200, {\n\t\t\"Content-Type\": \"application/json\",\n\t\t\"Cache-Control\": \"no-cache\",\n\t\tConnection: \"keep-alive\",\n\t});\n\tres.flushHeaders();\n\tres.write(JSON_HEARTBEAT);\n\n\tconst heartbeat = setInterval(() => {\n\t\ttouchStreamRun(run);\n\t\tif (!res.writableEnded) {\n\t\t\tres.write(JSON_HEARTBEAT);\n\t\t}\n\t}, STREAM_HEARTBEAT_INTERVAL_MS);\n\theartbeat.unref();\n\n\ttry {\n\t\tconst result = await completeSessionCompact(config, body, prepared, run);\n\t\tfinishCompactRun(run, result);\n\t\tres.write(JSON.stringify(result.body));\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tif (run?.status === \"running\") {\n\t\t\trun.status = run.cancelRequested ? \"aborted\" : \"failed\";\n\t\t\trun.errorMessage = message;\n\t\t\trun.updatedAt = Date.now();\n\t\t}\n\t\tres.write(JSON.stringify({ error: message }));\n\t} finally {\n\t\tclearInterval(heartbeat);\n\t\tsettleRun(run);\n\t\tres.end();\n\t}\n}\n\nfunction finishCompactRun(run: StreamRunRecord | undefined, result: SessionCompactHttpResponse): void {\n\tif (!run) return;\n\tif (run.cancelRequested || run.controller.signal.aborted) {\n\t\trun.status = \"aborted\";\n\t\trun.errorMessage = \"Compaction aborted\";\n\t} else {\n\t\trun.status = result.status >= 400 ? \"failed\" : \"completed\";\n\t\tif (result.status >= 400 && \"error\" in result.body) {\n\t\t\trun.errorMessage = result.body.error;\n\t\t} else if (\"success\" in result.body) {\n\t\t\trun.compactResult = { ...result.body, entries: result.body.entries?.slice() };\n\t\t}\n\t}\n\trun.updatedAt = Date.now();\n}\n\nasync function handleSessionCompact(\n\tconfig: ServerConfig,\n\tbody: SessionCompactBody,\n\tres: ServerResponse,\n): Promise<void> {\n\tconst existingRun = body.runId ? getStreamRun(body.sessionId, body.runId) : undefined;\n\tif (existingRun?.status === \"aborted\") {\n\t\tsendJson(res, 409, { error: \"Compaction run was aborted\", code: PiServerErrorCode.INVALID_REQUEST });\n\t\treturn;\n\t}\n\tif (existingRun?.status === \"completed\" && existingRun.compactResult) {\n\t\tsendJson(res, 200, existingRun.compactResult);\n\t\treturn;\n\t}\n\tconst prepared = prepareSessionCompact(body);\n\tif (\"status\" in prepared) {\n\t\tsendJson(res, prepared.status, prepared.body);\n\t\treturn;\n\t}\n\n\tlet run: StreamRunRecord | undefined;\n\tif (body.runId) {\n\t\tconst existingRun = getStreamRun(body.sessionId, body.runId);\n\t\tif (existingRun?.status === \"aborted\") {\n\t\t\tsendJson(res, 409, { error: \"Compaction run was aborted\", code: PiServerErrorCode.INVALID_REQUEST });\n\t\t\treturn;\n\t\t}\n\t\tif (existingRun?.status === \"running\") {\n\t\t\tsendError(res, 409, \"A run with this runId is already in progress\", PiServerErrorCode.RUN_IN_PROGRESS);\n\t\t\treturn;\n\t\t}\n\t\trun = startStreamRun(body.sessionId, body.runId, \"compact\");\n\t}\n\n\tif (body.streamResponse) {\n\t\tawait handleSessionCompactStream(config, body, prepared, res, run);\n\t\treturn;\n\t}\n\n\tawait handleSessionCompactJsonStream(config, body, prepared, res, run);\n}\n\nfunction handleSessionHistory(\n\tsessionId: string,\n\tfrom: number | undefined,\n\tentriesFrom: number | undefined,\n\trevision: number | undefined,\n\tbaseTreeHash: string | undefined,\n\tres: ServerResponse,\n): void {\n\tconst session = getSession(sessionId);\n\tif (!session) {\n\t\tsendError(res, 404, \"session not found\", PiServerErrorCode.SESSION_NOT_FOUND);\n\t\treturn;\n\t}\n\tconst baseMessageCount = from ?? 0;\n\tif (\n\t\tentriesFrom !== undefined &&\n\t\tentriesFrom <= session.entries.length &&\n\t\t(revision === undefined || revision <= session.revision) &&\n\t\t(baseTreeHash === undefined || baseTreeHash === session.prefixHashes[entriesFrom])\n\t) {\n\t\tsendJson(res, 200, sessionTreePatchResponseBody(session, baseMessageCount, entriesFrom, revision));\n\t\treturn;\n\t}\n\tsendJson(res, 200, sessionHistoryFullResponseBody(session, baseMessageCount));\n}\n\nfunction handleSessionRun(sessionId: string, runId: string, res: ServerResponse): void {\n\tconst run = getStreamRun(sessionId, runId);\n\tif (!run) {\n\t\tsendError(res, 404, \"run not found\", PiServerErrorCode.RUN_NOT_FOUND);\n\t\treturn;\n\t}\n\tsendJson(res, 200, streamRunResponseBody(run));\n}\n\nasync function handleSessionRunAbort(sessionId: string, runId: string, res: ServerResponse): Promise<void> {\n\tif (!sessionId || !runId) {\n\t\tsendError(res, 400, \"sessionId and runId are required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\n\tlet run = getStreamRun(sessionId, runId);\n\tif (!run) {\n\t\trun = createRunRecord(sessionId, runId, \"stream\");\n\t\trun.status = \"aborted\";\n\t\trun.cancelRequested = true;\n\t\trun.errorMessage = \"Stream run aborted before it started\";\n\t\trun.updatedAt = Date.now();\n\t\tsettleRun(run);\n\t\tstreamRuns.set(runKey(sessionId, runId), run);\n\t\tsendJson(res, 200, streamRunResponseBody(run));\n\t\treturn;\n\t}\n\n\tif (run.status !== \"running\") {\n\t\tawait run.settled;\n\t\tsendJson(res, 200, streamRunResponseBody(run));\n\t\treturn;\n\t}\n\n\trun.cancelRequested = true;\n\trun.updatedAt = Date.now();\n\trun.controller.abort();\n\tawait run.settled;\n\tsendJson(res, 200, streamRunResponseBody(run));\n}\n\nexport function buildStreamContext(\n\tsession: SessionState,\n\tbody: Pick<StreamRequestBody, \"contextOverlay\" | \"ephemeralMessages\">,\n): Context {\n\tconst messages = body.contextOverlay ?? [...session.messages, ...(body.ephemeralMessages ?? [])];\n\treturn {\n\t\tsystemPrompt: session.staticContext?.systemPrompt,\n\t\tmessages,\n\t\ttools: session.staticContext?.tools,\n\t};\n}\n\nfunction handleStream(config: ServerConfig, body: StreamRequestBody, res: ServerResponse): void {\n\tif (!body.sessionId) {\n\t\tsendError(res, 400, \"sessionId is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\tif (!body.model) {\n\t\tsendError(res, 400, \"model is required\", PiServerErrorCode.REQUIRED_FIELD_MISSING);\n\t\treturn;\n\t}\n\n\tcleanupExpiredStreamRuns(Date.now());\n\n\tconst session = getOrCreateSession(body.sessionId);\n\n\tif (body.staticContext) {\n\t\tsetStaticContext(body.sessionId, body.staticContext);\n\t\tpersistSession(config, session);\n\t}\n\n\tif (!session.staticContext && !body.staticContext) {\n\t\tsendError(\n\t\t\tres,\n\t\t\t400,\n\t\t\t\"Session has no static context. Initialize with /api/session/init first.\",\n\t\t\tPiServerErrorCode.SESSION_NO_STATIC_CONTEXT,\n\t\t);\n\t\treturn;\n\t}\n\n\tif (body.ephemeralMessages !== undefined && !Array.isArray(body.ephemeralMessages)) {\n\t\tsendError(res, 400, \"ephemeralMessages must be an array\", PiServerErrorCode.INVALID_REQUEST);\n\t\treturn;\n\t}\n\tif (body.contextOverlay !== undefined && !Array.isArray(body.contextOverlay)) {\n\t\tsendError(res, 400, \"contextOverlay must be an array\", PiServerErrorCode.INVALID_REQUEST);\n\t\treturn;\n\t}\n\n\tconst context = buildStreamContext(session, body);\n\tconst existingRun = body.runId ? getStreamRun(body.sessionId, body.runId) : undefined;\n\n\tconst resolvedModel = body.model;\n\n\tif (existingRun?.status === \"completed\") {\n\t\tres.writeHead(200, {\n\t\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\t\"Cache-Control\": \"no-cache\",\n\t\t\tConnection: \"keep-alive\",\n\t\t});\n\t\tres.flushHeaders();\n\t\tres.write(STREAM_HEARTBEAT);\n\t\tfor (const event of replayStreamRun(existingRun)) {\n\t\t\twriteStreamEvent(res, event);\n\t\t}\n\t\tendStreamResponse(res);\n\t\treturn;\n\t}\n\tif (existingRun?.status === \"aborted\") {\n\t\tsendError(res, 409, \"The stream run was aborted\", PiServerErrorCode.INVALID_REQUEST);\n\t\treturn;\n\t}\n\tif (existingRun?.status === \"running\") {\n\t\tsendError(res, 409, \"A stream with this runId is already in progress\", PiServerErrorCode.RUN_IN_PROGRESS);\n\t\treturn;\n\t}\n\n\tconst run = body.runId ? startStreamRun(body.sessionId, body.runId) : undefined;\n\tconst streamOptions: SimpleStreamOptions = {\n\t\t...(body.options ?? {}),\n\t\t...(run ? { signal: run.controller.signal } : {}),\n\t};\n\n\tres.writeHead(200, {\n\t\t\"Content-Type\": \"text/event-stream\",\n\t\t\"Cache-Control\": \"no-cache\",\n\t\tConnection: \"keep-alive\",\n\t});\n\tres.flushHeaders();\n\tres.write(STREAM_HEARTBEAT);\n\n\tconst heartbeat = setInterval(() => {\n\t\ttouchStreamRun(run);\n\t\tif (!res.writableEnded && !res.destroyed) {\n\t\t\tres.write(STREAM_HEARTBEAT);\n\t\t}\n\t}, STREAM_HEARTBEAT_INTERVAL_MS);\n\theartbeat.unref();\n\n\tlet stream: AsyncIterable<AssistantMessageEvent>;\n\ttry {\n\t\tstream = streamSimple(resolvedModel, context, streamOptions);\n\t} catch (err) {\n\t\tclearInterval(heartbeat);\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tfailStreamRun(run, message);\n\t\tsettleRun(run);\n\t\twriteStreamError(res, message);\n\t\tendStreamResponse(res);\n\t\treturn;\n\t}\n\n\tvoid (async () => {\n\t\ttry {\n\t\t\tfor await (const event of stream) {\n\t\t\t\tconst proxyEvent = toProxyEvent(event);\n\t\t\t\tif (proxyEvent) {\n\t\t\t\t\ttouchStreamRun(run);\n\t\t\t\t\twriteStreamEvent(res, proxyEvent);\n\t\t\t\t}\n\t\t\t\tif (event.type === \"done\") {\n\t\t\t\t\tcompleteStreamRun(run, event.message);\n\t\t\t\t} else if (event.type === \"error\") {\n\t\t\t\t\tfailStreamRun(run, event.error.errorMessage ?? event.reason);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tfailStreamRun(run, message);\n\t\t\twriteStreamError(res, message);\n\t\t} finally {\n\t\t\tclearInterval(heartbeat);\n\t\t\tif (run?.status === \"running\") {\n\t\t\t\tfailStreamRun(run, run.cancelRequested ? \"Stream run aborted\" : \"Stream ended before a terminal event\");\n\t\t\t}\n\t\t\tsettleRun(run);\n\t\t\tendStreamResponse(res);\n\t\t}\n\t})();\n}\n\nasync function handlePostRequest(\n\tconfig: ServerConfig,\n\tpathname: string,\n\tbody: unknown,\n\tres: ServerResponse,\n): Promise<boolean> {\n\tif (pathname === \"/api/receive\") {\n\t\ttry {\n\t\t\tsendJson(res, 200, receiveUpload(config.uploadDir, body));\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof ReceiveUploadError)) throw error;\n\t\t\tsendJson(res, error.status, { error: error.message });\n\t\t}\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/init\") {\n\t\thandleSessionInit(config, body as SessionInitBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/update\") {\n\t\thandleSessionUpdate(config, body as SessionInitBody & { staticContext: SessionStaticContext }, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/sync\") {\n\t\thandleSessionSync(config, body as SessionSyncBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/append\") {\n\t\thandleSessionAppend(config, body as SessionAppendBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/tree/sync\") {\n\t\thandleSessionTreeSync(config, body as SessionTreeSyncBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/tree/append\") {\n\t\thandleSessionTreeAppend(config, body as SessionTreeSyncBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/tree/switch\") {\n\t\thandleSessionTreeSwitch(config, body as SessionTreeSwitchBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/session/compact\") {\n\t\tawait handleSessionCompact(config, body as SessionCompactBody, res);\n\t\treturn true;\n\t}\n\n\tif (pathname === \"/api/stream\") {\n\t\thandleStream(config, body as StreamRequestBody, res);\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nexport function createPiServer(configOverride?: Partial<ServerConfig>): HttpServer {\n\tconst config = loadConfig(configOverride);\n\tloadPersistedSessions(config.sessionStoreDir);\n\n\tconst server = createServer(async (req, res) => {\n\t\tconst url = new URL(req.url ?? \"/\", \"http://localhost\");\n\n\t\tif (req.method === \"GET\" && url.pathname === \"/health\") {\n\t\t\tsendJson(res, 200, { status: \"ok\" });\n\t\t\treturn;\n\t\t}\n\n\t\tif (!authenticate(config, req)) {\n\t\t\tconst body =\n\t\t\t\treq.method === \"GET\" && url.pathname === \"/\"\n\t\t\t\t\t? { error: \"Unauthorized\", version: PI_SERVER_VERSION }\n\t\t\t\t\t: { error: \"Unauthorized\" };\n\t\t\tsendJson(res, 401, body);\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"GET\" && url.pathname === \"/api/sessions\") {\n\t\t\tsendJson(res, 200, { sessions: listSessions() });\n\t\t\treturn;\n\t\t}\n\n\t\tconst runMatch = /^\\/api\\/session\\/([^/]+)\\/runs\\/([^/]+)$/.exec(url.pathname);\n\t\tif (req.method === \"GET\" && runMatch) {\n\t\t\thandleSessionRun(decodeURIComponent(runMatch[1]), decodeURIComponent(runMatch[2]), res);\n\t\t\treturn;\n\t\t}\n\n\t\tconst runAbortMatch = /^\\/api\\/session\\/([^/]+)\\/runs\\/([^/]+)\\/abort$/.exec(url.pathname);\n\t\tif (req.method === \"POST\" && runAbortMatch) {\n\t\t\tawait readBody(req);\n\t\t\tawait handleSessionRunAbort(decodeURIComponent(runAbortMatch[1]), decodeURIComponent(runAbortMatch[2]), res);\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"GET\" && url.pathname.startsWith(\"/api/session/\") && url.pathname.endsWith(\"/history\")) {\n\t\t\tconst encodedSessionId = url.pathname.slice(\"/api/session/\".length, -\"/history\".length);\n\t\t\tconst fromParam = url.searchParams.get(\"from\");\n\t\t\tconst from = fromParam === null ? undefined : Number(fromParam);\n\t\t\tif (from !== undefined && (!Number.isInteger(from) || from < 0)) {\n\t\t\t\tsendError(res, 400, \"from must be a non-negative integer\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst entriesFromParam = url.searchParams.get(\"entriesFrom\");\n\t\t\tconst entriesFrom = entriesFromParam === null ? undefined : Number(entriesFromParam);\n\t\t\tif (entriesFrom !== undefined && (!Number.isInteger(entriesFrom) || entriesFrom < 0)) {\n\t\t\t\tsendError(res, 400, \"entriesFrom must be a non-negative integer\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst revisionParam = url.searchParams.get(\"revision\");\n\t\t\tconst revision = revisionParam === null ? undefined : Number(revisionParam);\n\t\t\tif (revision !== undefined && (!Number.isInteger(revision) || revision < 0)) {\n\t\t\t\tsendError(res, 400, \"revision must be a non-negative integer\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thandleSessionHistory(\n\t\t\t\tdecodeURIComponent(encodedSessionId),\n\t\t\t\tfrom,\n\t\t\t\tentriesFrom,\n\t\t\t\trevision,\n\t\t\t\turl.searchParams.get(\"baseTreeHash\") ?? undefined,\n\t\t\t\tres,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"POST\" && url.pathname === CHUNK_ENDPOINT) {\n\t\t\ttry {\n\t\t\t\tconst body = JSON.parse(await readBody(req)) as RequestChunkBody;\n\t\t\t\tconst chunkResult = receiveRequestChunk(body);\n\t\t\t\tif (!chunkResult.complete) {\n\t\t\t\t\tsendJson(res, 200, chunkResult.ack);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst handled = await handlePostRequest(\n\t\t\t\t\tconfig,\n\t\t\t\t\tchunkResult.target,\n\t\t\t\t\tJSON.parse(chunkResult.bodyJson) as unknown,\n\t\t\t\t\tres,\n\t\t\t\t);\n\t\t\t\tif (!handled && !res.headersSent) {\n\t\t\t\t\tsendError(res, 404, \"Not found\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tlogRequestError(req, err);\n\t\t\t\tif (!res.headersSent) {\n\t\t\t\t\tsendError(res, 400, err instanceof Error ? err.message : String(err), PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\t} else {\n\t\t\t\t\tres.write(encodeErrorEvent(err instanceof Error ? err.message : String(err)));\n\t\t\t\t\tres.end();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (req.method === \"POST\") {\n\t\t\ttry {\n\t\t\t\tconst body = JSON.parse(await readBody(req)) as unknown;\n\t\t\t\tif (await handlePostRequest(config, url.pathname, body, res)) return;\n\t\t\t\tif (!res.headersSent) {\n\t\t\t\t\tsendError(res, 404, \"Not found\", PiServerErrorCode.INVALID_REQUEST);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tlogRequestError(req, err);\n\t\t\t\tif (!res.headersSent) {\n\t\t\t\t\tsendError(res, 500, err instanceof Error ? err.message : String(err), PiServerErrorCode.INTERNAL_ERROR);\n\t\t\t\t} else {\n\t\t\t\t\tres.write(encodeErrorEvent(err instanceof Error ? err.message : String(err)));\n\t\t\t\t\tres.end();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif (req.method === \"DELETE\" && url.pathname.startsWith(\"/api/session/\")) {\n\t\t\tconst sessionId = decodeURIComponent(url.pathname.slice(\"/api/session/\".length));\n\t\t\tdeleteSessionFromStore(sessionId);\n\t\t\tdeleteStreamRunsForSession(sessionId);\n\t\t\tdeletePersistedSession(config.sessionStoreDir, sessionId);\n\t\t\tsendJson(res, 200, { deleted: sessionId });\n\t\t\treturn;\n\t\t}\n\n\t\tsendError(res, 404, \"Not found\", PiServerErrorCode.INVALID_REQUEST);\n\t});\n\n\treturn server;\n}\n\nfunction toProxyEvent(event: AssistantMessageEvent): ProxyAssistantMessageEvent | undefined {\n\tswitch (event.type) {\n\t\tcase \"start\":\n\t\t\treturn { type: \"start\" };\n\t\tcase \"text_start\":\n\t\t\treturn { type: \"text_start\", contentIndex: event.contentIndex };\n\t\tcase \"text_delta\":\n\t\t\treturn { type: \"text_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\tcase \"text_end\":\n\t\t\treturn {\n\t\t\t\ttype: \"text_end\",\n\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\tcontentSignature:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"text\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { textSignature?: string }).textSignature\n\t\t\t\t\t\t: undefined,\n\t\t\t};\n\t\tcase \"thinking_start\":\n\t\t\treturn { type: \"thinking_start\", contentIndex: event.contentIndex };\n\t\tcase \"thinking_delta\":\n\t\t\treturn { type: \"thinking_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\tcase \"thinking_end\":\n\t\t\treturn {\n\t\t\t\ttype: \"thinking_end\",\n\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\tcontentSignature:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"thinking\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { thinkingSignature?: string }).thinkingSignature\n\t\t\t\t\t\t: undefined,\n\t\t\t};\n\t\tcase \"toolcall_start\":\n\t\t\treturn {\n\t\t\t\ttype: \"toolcall_start\",\n\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\tid:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"toolCall\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { id: string }).id\n\t\t\t\t\t\t: \"\",\n\t\t\t\ttoolName:\n\t\t\t\t\tevent.partial.content[event.contentIndex]?.type === \"toolCall\"\n\t\t\t\t\t\t? (event.partial.content[event.contentIndex] as { name: string }).name\n\t\t\t\t\t\t: \"\",\n\t\t\t};\n\t\tcase \"toolcall_delta\":\n\t\t\treturn { type: \"toolcall_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\tcase \"toolcall_end\":\n\t\t\treturn { type: \"toolcall_end\", contentIndex: event.contentIndex, toolCall: event.toolCall };\n\t\tcase \"done\":\n\t\t\treturn {\n\t\t\t\ttype: \"done\",\n\t\t\t\treason: event.reason,\n\t\t\t\tusage: event.message.usage,\n\t\t\t\tdeferred: event.message.deferred,\n\t\t\t\tmessage: event.message,\n\t\t\t};\n\t\tcase \"error\":\n\t\t\treturn {\n\t\t\t\ttype: \"error\",\n\t\t\t\treason: event.reason,\n\t\t\t\terrorMessage: event.error.errorMessage,\n\t\t\t\tusage: event.error.usage,\n\t\t\t};\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nexport function startServer(configOverride?: Partial<ServerConfig>): HttpServer {\n\tconst config = loadConfig(configOverride);\n\tconst server = createPiServer(configOverride);\n\tserver.listen(config.port, config.host, () => {\n\t\tconst address = server.address();\n\t\tconst port = typeof address === \"object\" && address !== null ? address.port : config.port;\n\t\tconst host = config.host.includes(\":\") && !config.host.startsWith(\"[\") ? `[${config.host}]` : config.host;\n\t\tconsole.log(`pi-server listening on ${host}:${port}`);\n\t});\n\treturn server;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@averyyy/pi-server",
3
- "version": "0.87.1-piclient.1",
3
+ "version": "0.87.1-piclient.2",
4
4
  "description": "Proxy server for pi-client that stores session state and forwards incremental requests to upstream LLM providers",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,8 +27,8 @@
27
27
  "prepublishOnly": "npm run clean && npm run build"
28
28
  },
29
29
  "dependencies": {
30
- "@earendil-works/pi-ai": "npm:@averyyy/pi-ai@0.87.1-piclient.1",
31
- "@earendil-works/pi-agent-core": "npm:@averyyy/pi-agent-core@0.87.1-piclient.1"
30
+ "@earendil-works/pi-ai": "npm:@averyyy/pi-ai@0.87.1-piclient.2",
31
+ "@earendil-works/pi-agent-core": "npm:@averyyy/pi-agent-core@0.87.1-piclient.2"
32
32
  },
33
33
  "keywords": [
34
34
  "pi-server",