@fragno-dev/pi-harness 0.0.0-stage → 0.0.3
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/LICENSE.md +16 -0
- package/README.md +181 -2
- package/dist/browser/agent-harness-event-protocol-CuKubox1.js +666 -0
- package/dist/browser/agent-harness-event-protocol-CuKubox1.js.map +1 -0
- package/dist/browser/agent-harness-event-protocol-d6mH_9n3.d.ts +261 -0
- package/dist/browser/agent-harness-event-protocol-d6mH_9n3.d.ts.map +1 -0
- package/dist/browser/client/clients.d.ts +2 -0
- package/dist/browser/client/clients.js +2 -0
- package/dist/browser/client/pi-workflow-emission-stream.d.ts +13 -0
- package/dist/browser/client/pi-workflow-emission-stream.d.ts.map +1 -0
- package/dist/browser/client/pi-workflow-emission-stream.js +29 -0
- package/dist/browser/client/pi-workflow-emission-stream.js.map +1 -0
- package/dist/browser/client/react.d.ts +147 -0
- package/dist/browser/client/react.d.ts.map +1 -0
- package/dist/browser/client/react.js +187 -0
- package/dist/browser/client/react.js.map +1 -0
- package/dist/browser/client/solid.d.ts +150 -0
- package/dist/browser/client/solid.d.ts.map +1 -0
- package/dist/browser/client/solid.js +130 -0
- package/dist/browser/client/solid.js.map +1 -0
- package/dist/browser/client/svelte.d.ts +150 -0
- package/dist/browser/client/svelte.d.ts.map +1 -0
- package/dist/browser/client/svelte.js +132 -0
- package/dist/browser/client/svelte.js.map +1 -0
- package/dist/browser/client/vanilla.d.ts +177 -0
- package/dist/browser/client/vanilla.d.ts.map +1 -0
- package/dist/browser/client/vanilla.js +159 -0
- package/dist/browser/client/vanilla.js.map +1 -0
- package/dist/browser/client/vue.d.ts +150 -0
- package/dist/browser/client/vue.d.ts.map +1 -0
- package/dist/browser/client/vue.js +128 -0
- package/dist/browser/client/vue.js.map +1 -0
- package/dist/browser/client/workflow-lofi-session-projection.d.ts +17 -0
- package/dist/browser/client/workflow-lofi-session-projection.d.ts.map +1 -0
- package/dist/browser/client/workflow-lofi-session-projection.js +107 -0
- package/dist/browser/client/workflow-lofi-session-projection.js.map +1 -0
- package/dist/browser/clients-DYXj19je.d.ts +247 -0
- package/dist/browser/clients-DYXj19je.d.ts.map +1 -0
- package/dist/browser/clients-pIAk6ClP.js +1853 -0
- package/dist/browser/clients-pIAk6ClP.js.map +1 -0
- package/dist/browser/pi/context-usage.d.ts +20 -0
- package/dist/browser/pi/context-usage.d.ts.map +1 -0
- package/dist/browser/pi/context-usage.js +84 -0
- package/dist/browser/pi/context-usage.js.map +1 -0
- package/dist/browser/pi/harness/agent-harness-event-protocol.d.ts +2 -0
- package/dist/browser/pi/harness/agent-harness-event-protocol.js +2 -0
- package/dist/browser/pi/route-schemas.d.ts +2 -0
- package/dist/browser/pi/route-schemas.js +130 -0
- package/dist/browser/pi/route-schemas.js.map +1 -0
- package/dist/browser/pi/workflow-session-projection.d.ts +2 -0
- package/dist/browser/pi/workflow-session-projection.js +2 -0
- package/dist/browser/route-schemas-DQB5ZR1E.d.ts +109 -0
- package/dist/browser/route-schemas-DQB5ZR1E.d.ts.map +1 -0
- package/dist/browser/types-8q4RWFXT.js +23 -0
- package/dist/browser/types-8q4RWFXT.js.map +1 -0
- package/dist/browser/types-Dk856kV1.d.ts +527 -0
- package/dist/browser/types-Dk856kV1.d.ts.map +1 -0
- package/dist/browser/workflow-session-projection-CJ4MUkpJ.js +443 -0
- package/dist/browser/workflow-session-projection-CJ4MUkpJ.js.map +1 -0
- package/dist/browser/workflow-session-projection-Dj_a79GF.d.ts +93 -0
- package/dist/browser/workflow-session-projection-Dj_a79GF.d.ts.map +1 -0
- package/dist/node/pi/compact-command-outcome-projection.js +41 -0
- package/dist/node/pi/compact-command-outcome-projection.js.map +1 -0
- package/dist/node/pi/context-usage.d.ts +20 -0
- package/dist/node/pi/context-usage.d.ts.map +1 -0
- package/dist/node/pi/context-usage.js +84 -0
- package/dist/node/pi/context-usage.js.map +1 -0
- package/dist/node/pi/definition.d.ts +535 -0
- package/dist/node/pi/definition.d.ts.map +1 -0
- package/dist/node/pi/definition.js +71 -0
- package/dist/node/pi/definition.js.map +1 -0
- package/dist/node/pi/factory.d.ts +142 -0
- package/dist/node/pi/factory.d.ts.map +1 -0
- package/dist/node/pi/factory.js +22 -0
- package/dist/node/pi/factory.js.map +1 -0
- package/dist/node/pi/harness/agent-harness-event-protocol.d.ts +261 -0
- package/dist/node/pi/harness/agent-harness-event-protocol.d.ts.map +1 -0
- package/dist/node/pi/harness/agent-harness-event-protocol.js +588 -0
- package/dist/node/pi/harness/agent-harness-event-protocol.js.map +1 -0
- package/dist/node/pi/harness/json-value.js +82 -0
- package/dist/node/pi/harness/json-value.js.map +1 -0
- package/dist/node/pi/harness/pi-operation-completed.d.ts +16 -0
- package/dist/node/pi/harness/pi-operation-completed.d.ts.map +1 -0
- package/dist/node/pi/harness/pi-operation-completed.js +71 -0
- package/dist/node/pi/harness/pi-operation-completed.js.map +1 -0
- package/dist/node/pi/harness/session-storage.d.ts +62 -0
- package/dist/node/pi/harness/session-storage.d.ts.map +1 -0
- package/dist/node/pi/harness/session-storage.js +174 -0
- package/dist/node/pi/harness/session-storage.js.map +1 -0
- package/dist/node/pi/pi-jsonl-export.d.ts +11 -0
- package/dist/node/pi/pi-jsonl-export.d.ts.map +1 -0
- package/dist/node/pi/pi-jsonl-export.js +31 -0
- package/dist/node/pi/pi-jsonl-export.js.map +1 -0
- package/dist/node/pi/route-schemas.d.ts +109 -0
- package/dist/node/pi/route-schemas.d.ts.map +1 -0
- package/dist/node/pi/route-schemas.js +130 -0
- package/dist/node/pi/route-schemas.js.map +1 -0
- package/dist/node/pi/session-command-protocol.d.ts +14 -0
- package/dist/node/pi/session-command-protocol.d.ts.map +1 -0
- package/dist/node/pi/session-command-protocol.js +25 -0
- package/dist/node/pi/session-command-protocol.js.map +1 -0
- package/dist/node/pi/session-entry-projection.js +79 -0
- package/dist/node/pi/session-entry-projection.js.map +1 -0
- package/dist/node/pi/skills.d.ts +70 -0
- package/dist/node/pi/skills.d.ts.map +1 -0
- package/dist/node/pi/skills.js +150 -0
- package/dist/node/pi/skills.js.map +1 -0
- package/dist/node/pi/tools.d.ts +12 -0
- package/dist/node/pi/tools.d.ts.map +1 -0
- package/dist/node/pi/tools.js +8 -0
- package/dist/node/pi/tools.js.map +1 -0
- package/dist/node/pi/types.d.ts +165 -0
- package/dist/node/pi/types.d.ts.map +1 -0
- package/dist/node/pi/types.js +49 -0
- package/dist/node/pi/types.js.map +1 -0
- package/dist/node/pi/wait-for-command-step.js +46 -0
- package/dist/node/pi/wait-for-command-step.js.map +1 -0
- package/dist/node/pi/workflow-session-live-projection.js +220 -0
- package/dist/node/pi/workflow-session-live-projection.js.map +1 -0
- package/dist/node/pi/workflow-session-projection.d.ts +84 -0
- package/dist/node/pi/workflow-session-projection.d.ts.map +1 -0
- package/dist/node/pi/workflow-session-projection.js +100 -0
- package/dist/node/pi/workflow-session-projection.js.map +1 -0
- package/dist/node/pi/workflows/interactive-chat-workflow.d.ts +37 -0
- package/dist/node/pi/workflows/interactive-chat-workflow.d.ts.map +1 -0
- package/dist/node/pi/workflows/interactive-chat-workflow.js +219 -0
- package/dist/node/pi/workflows/interactive-chat-workflow.js.map +1 -0
- package/dist/node/pi/workflows/workflow-agent-harness.d.ts +142 -0
- package/dist/node/pi/workflows/workflow-agent-harness.d.ts.map +1 -0
- package/dist/node/pi/workflows/workflow-agent-harness.js +450 -0
- package/dist/node/pi/workflows/workflow-agent-harness.js.map +1 -0
- package/dist/node/routes.d.ts +631 -0
- package/dist/node/routes.d.ts.map +1 -0
- package/dist/node/routes.js +355 -0
- package/dist/node/routes.js.map +1 -0
- package/dist/node/schema.d.ts +5 -0
- package/dist/node/schema.d.ts.map +1 -0
- package/dist/node/schema.js +7 -0
- package/dist/node/schema.js.map +1 -0
- package/package.json +175 -3
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { PiSessionDataIntegrityError } from "./types.js";
|
|
2
|
+
import { asPersistedPiHarnessStepResult } from "./session-entry-projection.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
//#region src/pi/compact-command-outcome-projection.ts
|
|
5
|
+
const compactCommandOutcomeSchema = z.discriminatedUnion("status", [z.object({
|
|
6
|
+
kind: z.literal("compact"),
|
|
7
|
+
commandId: z.string(),
|
|
8
|
+
status: z.literal("succeeded")
|
|
9
|
+
}), z.object({
|
|
10
|
+
kind: z.literal("compact"),
|
|
11
|
+
commandId: z.string(),
|
|
12
|
+
status: z.literal("rejected"),
|
|
13
|
+
code: z.enum(["nothing_to_compact", "compaction_failed"]),
|
|
14
|
+
message: z.string()
|
|
15
|
+
})]);
|
|
16
|
+
const parseCompactCommandOutcome = (value, identity) => {
|
|
17
|
+
if (typeof value !== "object" || value === null || value.kind !== "compact") return null;
|
|
18
|
+
const outcome = compactCommandOutcomeSchema.safeParse(value);
|
|
19
|
+
if (!outcome.success) throw new PiSessionDataIntegrityError(identity.workflowName, identity.sessionId, new Error("Persisted Pi compact command outcome is invalid.", { cause: outcome.error }));
|
|
20
|
+
return outcome.data;
|
|
21
|
+
};
|
|
22
|
+
const projectPiCompactCommandOutcomes = (steps, identity) => {
|
|
23
|
+
const byCommandId = {};
|
|
24
|
+
let latestCommandCompactOutcome = null;
|
|
25
|
+
for (const step of steps) {
|
|
26
|
+
if (step.status !== "completed" || !step.stepKey.startsWith("command:")) continue;
|
|
27
|
+
const result = asPersistedPiHarnessStepResult(step.result);
|
|
28
|
+
if (!result) throw new PiSessionDataIntegrityError(identity.workflowName, identity.sessionId, /* @__PURE__ */ new Error(`Pi command step ${step.stepKey} does not contain a harness result.`));
|
|
29
|
+
if (result.outcome !== "completed") continue;
|
|
30
|
+
latestCommandCompactOutcome = parseCompactCommandOutcome(result.value, identity);
|
|
31
|
+
if (latestCommandCompactOutcome) byCommandId[latestCommandCompactOutcome.commandId] = latestCommandCompactOutcome;
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
byCommandId,
|
|
35
|
+
latestCommandCompactOutcome
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
export { projectPiCompactCommandOutcomes };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=compact-command-outcome-projection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compact-command-outcome-projection.js","names":[],"sources":["../../../src/pi/compact-command-outcome-projection.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport {\n asPersistedPiHarnessStepResult,\n type PiProjectionSessionIdentity,\n} from \"./session-entry-projection\";\nimport {\n PI_SESSION_COMMAND_STEP_PREFIX,\n PiSessionDataIntegrityError,\n type PiCompactCommandOutcome,\n} from \"./types\";\n\nconst compactCommandOutcomeSchema = z.discriminatedUnion(\"status\", [\n z.object({\n kind: z.literal(\"compact\"),\n commandId: z.string(),\n status: z.literal(\"succeeded\"),\n }),\n z.object({\n kind: z.literal(\"compact\"),\n commandId: z.string(),\n status: z.literal(\"rejected\"),\n code: z.enum([\"nothing_to_compact\", \"compaction_failed\"]),\n message: z.string(),\n }),\n]) satisfies z.ZodType<PiCompactCommandOutcome>;\n\nconst parseCompactCommandOutcome = (\n value: unknown,\n identity: PiProjectionSessionIdentity,\n): PiCompactCommandOutcome | null => {\n if (\n typeof value !== \"object\" ||\n value === null ||\n (value as { kind?: unknown }).kind !== \"compact\"\n ) {\n return null;\n }\n\n const outcome = compactCommandOutcomeSchema.safeParse(value);\n if (!outcome.success) {\n throw new PiSessionDataIntegrityError(\n identity.workflowName,\n identity.sessionId,\n new Error(\"Persisted Pi compact command outcome is invalid.\", { cause: outcome.error }),\n );\n }\n return outcome.data;\n};\n\nexport const projectPiCompactCommandOutcomes = (\n steps: readonly { stepKey: string; status: string; result: unknown }[],\n identity: PiProjectionSessionIdentity,\n): {\n byCommandId: Readonly<Record<string, PiCompactCommandOutcome>>;\n latestCommandCompactOutcome: PiCompactCommandOutcome | null;\n} => {\n const byCommandId: Record<string, PiCompactCommandOutcome> = {};\n let latestCommandCompactOutcome: PiCompactCommandOutcome | null = null;\n\n for (const step of steps) {\n if (step.status !== \"completed\" || !step.stepKey.startsWith(PI_SESSION_COMMAND_STEP_PREFIX)) {\n continue;\n }\n\n const result = asPersistedPiHarnessStepResult(step.result);\n if (!result) {\n throw new PiSessionDataIntegrityError(\n identity.workflowName,\n identity.sessionId,\n new Error(`Pi command step ${step.stepKey} does not contain a harness result.`),\n );\n }\n if (result.outcome !== \"completed\") {\n continue;\n }\n\n latestCommandCompactOutcome = parseCompactCommandOutcome(result.value, identity);\n if (latestCommandCompactOutcome) {\n byCommandId[latestCommandCompactOutcome.commandId] = latestCommandCompactOutcome;\n }\n }\n\n return { byCommandId, latestCommandCompactOutcome };\n};\n"],"mappings":";;;;AAYA,MAAM,8BAA8B,EAAE,mBAAmB,UAAU,CACjE,EAAE,OAAO;CACP,MAAM,EAAE,QAAQ,SAAS;CACzB,WAAW,EAAE,OAAO;CACpB,QAAQ,EAAE,QAAQ,WAAW;AAC/B,CAAC,GACD,EAAE,OAAO;CACP,MAAM,EAAE,QAAQ,SAAS;CACzB,WAAW,EAAE,OAAO;CACpB,QAAQ,EAAE,QAAQ,UAAU;CAC5B,MAAM,EAAE,KAAK,CAAC,sBAAsB,mBAAmB,CAAC;CACxD,SAAS,EAAE,OAAO;AACpB,CAAC,CACH,CAAC;AAED,MAAM,8BACJ,OACA,aACmC;CACnC,IACE,OAAO,UAAU,YACjB,UAAU,QACT,MAA6B,SAAS,WAEvC,OAAO;CAGT,MAAM,UAAU,4BAA4B,UAAU,KAAK;CAC3D,IAAI,CAAC,QAAQ,SACX,MAAM,IAAI,4BACR,SAAS,cACT,SAAS,WACT,IAAI,MAAM,oDAAoD,EAAE,OAAO,QAAQ,MAAM,CAAC,CACxF;CAEF,OAAO,QAAQ;AACjB;AAEA,MAAa,mCACX,OACA,aAIG;CACH,MAAM,cAAuD,CAAC;CAC9D,IAAI,8BAA8D;CAElE,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,WAAW,eAAe,CAAC,KAAK,QAAQ,WAAA,UAAyC,GACxF;EAGF,MAAM,SAAS,+BAA+B,KAAK,MAAM;EACzD,IAAI,CAAC,QACH,MAAM,IAAI,4BACR,SAAS,cACT,SAAS,2BACT,IAAI,MAAM,mBAAmB,KAAK,QAAQ,oCAAoC,CAChF;EAEF,IAAI,OAAO,YAAY,aACrB;EAGF,8BAA8B,2BAA2B,OAAO,OAAO,QAAQ;EAC/E,IAAI,6BACF,YAAY,4BAA4B,aAAa;CAEzD;CAEA,OAAO;EAAE;EAAa;CAA4B;AACpD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { PiHarnessFrontendAgentMessage } from "./harness/agent-harness-event-protocol.js";
|
|
2
|
+
//#region src/pi/context-usage.d.ts
|
|
3
|
+
type PiContextUsageEstimate = {
|
|
4
|
+
tokens: number;
|
|
5
|
+
usageTokens: number;
|
|
6
|
+
trailingTokens: number;
|
|
7
|
+
lastUsageIndex: number | null;
|
|
8
|
+
};
|
|
9
|
+
/** Estimate one message using the same conservative four-characters-per-token heuristic as Pi. */
|
|
10
|
+
declare const estimatePiMessageTokens: (message: PiHarnessFrontendAgentMessage) => number;
|
|
11
|
+
/**
|
|
12
|
+
* Estimate the context represented by an ordered message list.
|
|
13
|
+
*
|
|
14
|
+
* Provider usage is authoritative through the latest completed assistant message. Messages after
|
|
15
|
+
* that point use the same character heuristic Pi applies while preparing compaction.
|
|
16
|
+
*/
|
|
17
|
+
declare const estimatePiContextUsage: (messages: readonly PiHarnessFrontendAgentMessage[]) => PiContextUsageEstimate;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { PiContextUsageEstimate, estimatePiContextUsage, estimatePiMessageTokens };
|
|
20
|
+
//# sourceMappingURL=context-usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-usage.d.ts","names":[],"sources":["../../../src/pi/context-usage.ts"],"mappings":";;KAIY;EACV;EACA;EACA;EACA;;;cAqDW,0BAA2B,SAAS;;;;;;;cAwCpC,yBACX,mBAAmB,oCAClB"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
//#region src/pi/context-usage.ts
|
|
2
|
+
const ESTIMATED_IMAGE_CHARS = 4800;
|
|
3
|
+
const contextTokensFromUsage = (usage) => usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
|
|
4
|
+
const validAssistantUsage = (message) => {
|
|
5
|
+
if (message.role !== "assistant") return;
|
|
6
|
+
const assistant = message;
|
|
7
|
+
if (assistant.stopReason === "aborted" || assistant.stopReason === "error" || !assistant.usage || contextTokensFromUsage(assistant.usage) === 0) return;
|
|
8
|
+
return assistant.usage;
|
|
9
|
+
};
|
|
10
|
+
const textAndImageContentChars = (content) => {
|
|
11
|
+
if (typeof content === "string") return content.length;
|
|
12
|
+
return content.reduce((chars, block) => {
|
|
13
|
+
if (block.type === "text" && block.text) return chars + block.text.length;
|
|
14
|
+
if (block.type === "image") return chars + ESTIMATED_IMAGE_CHARS;
|
|
15
|
+
return chars;
|
|
16
|
+
}, 0);
|
|
17
|
+
};
|
|
18
|
+
const readableJsonLength = (value) => {
|
|
19
|
+
try {
|
|
20
|
+
return (JSON.stringify(value) ?? "undefined").length;
|
|
21
|
+
} catch {
|
|
22
|
+
return 16;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/** Estimate one message using the same conservative four-characters-per-token heuristic as Pi. */
|
|
26
|
+
const estimatePiMessageTokens = (message) => {
|
|
27
|
+
let chars = 0;
|
|
28
|
+
switch (message.role) {
|
|
29
|
+
case "user":
|
|
30
|
+
chars = textAndImageContentChars(message.content);
|
|
31
|
+
break;
|
|
32
|
+
case "assistant":
|
|
33
|
+
for (const block of message.content) if (block.type === "text") chars += block.text.length;
|
|
34
|
+
else if (block.type === "thinking") chars += block.thinking.length;
|
|
35
|
+
else if (block.type === "toolCall") chars += block.name.length + readableJsonLength(block.arguments);
|
|
36
|
+
break;
|
|
37
|
+
case "custom":
|
|
38
|
+
case "toolResult":
|
|
39
|
+
chars = textAndImageContentChars(message.content);
|
|
40
|
+
break;
|
|
41
|
+
case "bashExecution":
|
|
42
|
+
chars = message.command.length + message.output.length;
|
|
43
|
+
break;
|
|
44
|
+
case "branchSummary":
|
|
45
|
+
case "compactionSummary":
|
|
46
|
+
chars = message.summary.length;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
return Math.ceil(chars / 4);
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Estimate the context represented by an ordered message list.
|
|
53
|
+
*
|
|
54
|
+
* Provider usage is authoritative through the latest completed assistant message. Messages after
|
|
55
|
+
* that point use the same character heuristic Pi applies while preparing compaction.
|
|
56
|
+
*/
|
|
57
|
+
const estimatePiContextUsage = (messages) => {
|
|
58
|
+
let lastUsageIndex = null;
|
|
59
|
+
let usageTokens = 0;
|
|
60
|
+
let latestPrefixTimestamp = Number.NEGATIVE_INFINITY;
|
|
61
|
+
for (let index = 0; index < messages.length; index += 1) {
|
|
62
|
+
const message = messages[index];
|
|
63
|
+
const usage = validAssistantUsage(message);
|
|
64
|
+
const timestampIsFinite = Number.isFinite(message.timestamp);
|
|
65
|
+
if (usage && (!timestampIsFinite || message.timestamp >= latestPrefixTimestamp)) {
|
|
66
|
+
lastUsageIndex = index;
|
|
67
|
+
usageTokens = contextTokensFromUsage(usage);
|
|
68
|
+
}
|
|
69
|
+
if (timestampIsFinite) latestPrefixTimestamp = Math.max(latestPrefixTimestamp, message.timestamp);
|
|
70
|
+
}
|
|
71
|
+
const trailingStart = lastUsageIndex === null ? 0 : lastUsageIndex + 1;
|
|
72
|
+
let trailingTokens = 0;
|
|
73
|
+
for (let index = trailingStart; index < messages.length; index += 1) trailingTokens += estimatePiMessageTokens(messages[index]);
|
|
74
|
+
return {
|
|
75
|
+
tokens: usageTokens + trailingTokens,
|
|
76
|
+
usageTokens,
|
|
77
|
+
trailingTokens,
|
|
78
|
+
lastUsageIndex
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
//#endregion
|
|
82
|
+
export { estimatePiContextUsage, estimatePiMessageTokens };
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=context-usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-usage.js","names":[],"sources":["../../../src/pi/context-usage.ts"],"sourcesContent":["import type { Usage } from \"@earendil-works/pi-ai\";\n\nimport type { PiHarnessFrontendAgentMessage } from \"./harness/agent-harness-event-protocol\";\n\nexport type PiContextUsageEstimate = {\n tokens: number;\n usageTokens: number;\n trailingTokens: number;\n lastUsageIndex: number | null;\n};\n\nconst ESTIMATED_IMAGE_CHARS = 4_800;\n\nconst contextTokensFromUsage = (usage: Usage): number =>\n usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;\n\nconst validAssistantUsage = (message: PiHarnessFrontendAgentMessage): Usage | undefined => {\n if (message.role !== \"assistant\") {\n return undefined;\n }\n\n const assistant = message;\n if (\n assistant.stopReason === \"aborted\" ||\n assistant.stopReason === \"error\" ||\n !assistant.usage ||\n contextTokensFromUsage(assistant.usage) === 0\n ) {\n return undefined;\n }\n\n return assistant.usage;\n};\n\nconst textAndImageContentChars = (\n content: string | Array<{ type: string; text?: string }>,\n): number => {\n if (typeof content === \"string\") {\n return content.length;\n }\n\n return content.reduce((chars, block) => {\n if (block.type === \"text\" && block.text) {\n return chars + block.text.length;\n }\n if (block.type === \"image\") {\n return chars + ESTIMATED_IMAGE_CHARS;\n }\n return chars;\n }, 0);\n};\n\nconst readableJsonLength = (value: unknown): number => {\n try {\n return (JSON.stringify(value) ?? \"undefined\").length;\n } catch {\n return \"[unserializable]\".length;\n }\n};\n\n/** Estimate one message using the same conservative four-characters-per-token heuristic as Pi. */\nexport const estimatePiMessageTokens = (message: PiHarnessFrontendAgentMessage): number => {\n let chars = 0;\n\n switch (message.role) {\n case \"user\":\n chars = textAndImageContentChars(message.content);\n break;\n case \"assistant\":\n for (const block of message.content) {\n if (block.type === \"text\") {\n chars += block.text.length;\n } else if (block.type === \"thinking\") {\n chars += block.thinking.length;\n } else if (block.type === \"toolCall\") {\n chars += block.name.length + readableJsonLength(block.arguments);\n }\n }\n break;\n case \"custom\":\n case \"toolResult\":\n chars = textAndImageContentChars(message.content);\n break;\n case \"bashExecution\":\n chars = message.command.length + message.output.length;\n break;\n case \"branchSummary\":\n case \"compactionSummary\":\n chars = message.summary.length;\n break;\n }\n\n return Math.ceil(chars / 4);\n};\n\n/**\n * Estimate the context represented by an ordered message list.\n *\n * Provider usage is authoritative through the latest completed assistant message. Messages after\n * that point use the same character heuristic Pi applies while preparing compaction.\n */\nexport const estimatePiContextUsage = (\n messages: readonly PiHarnessFrontendAgentMessage[],\n): PiContextUsageEstimate => {\n let lastUsageIndex: number | null = null;\n let usageTokens = 0;\n let latestPrefixTimestamp = Number.NEGATIVE_INFINITY;\n\n for (let index = 0; index < messages.length; index += 1) {\n const message = messages[index];\n const usage = validAssistantUsage(message);\n const timestampIsFinite = Number.isFinite(message.timestamp);\n if (usage && (!timestampIsFinite || message.timestamp >= latestPrefixTimestamp)) {\n lastUsageIndex = index;\n usageTokens = contextTokensFromUsage(usage);\n }\n if (timestampIsFinite) {\n latestPrefixTimestamp = Math.max(latestPrefixTimestamp, message.timestamp);\n }\n }\n\n const trailingStart = lastUsageIndex === null ? 0 : lastUsageIndex + 1;\n let trailingTokens = 0;\n for (let index = trailingStart; index < messages.length; index += 1) {\n trailingTokens += estimatePiMessageTokens(messages[index]);\n }\n\n return {\n tokens: usageTokens + trailingTokens,\n usageTokens,\n trailingTokens,\n lastUsageIndex,\n };\n};\n"],"mappings":";AAWA,MAAM,wBAAwB;AAE9B,MAAM,0BAA0B,UAC9B,MAAM,eAAe,MAAM,QAAQ,MAAM,SAAS,MAAM,YAAY,MAAM;AAE5E,MAAM,uBAAuB,YAA8D;CACzF,IAAI,QAAQ,SAAS,aACnB;CAGF,MAAM,YAAY;CAClB,IACE,UAAU,eAAe,aACzB,UAAU,eAAe,WACzB,CAAC,UAAU,SACX,uBAAuB,UAAU,KAAK,MAAM,GAE5C;CAGF,OAAO,UAAU;AACnB;AAEA,MAAM,4BACJ,YACW;CACX,IAAI,OAAO,YAAY,UACrB,OAAO,QAAQ;CAGjB,OAAO,QAAQ,QAAQ,OAAO,UAAU;EACtC,IAAI,MAAM,SAAS,UAAU,MAAM,MACjC,OAAO,QAAQ,MAAM,KAAK;EAE5B,IAAI,MAAM,SAAS,SACjB,OAAO,QAAQ;EAEjB,OAAO;CACT,GAAG,CAAC;AACN;AAEA,MAAM,sBAAsB,UAA2B;CACrD,IAAI;EACF,QAAQ,KAAK,UAAU,KAAK,KAAK,YAAA,CAAa;CAChD,QAAQ;EACN,OAAO;CACT;AACF;;AAGA,MAAa,2BAA2B,YAAmD;CACzF,IAAI,QAAQ;CAEZ,QAAQ,QAAQ,MAAhB;EACE,KAAK;GACH,QAAQ,yBAAyB,QAAQ,OAAO;GAChD;EACF,KAAK;GACH,KAAK,MAAM,SAAS,QAAQ,SAC1B,IAAI,MAAM,SAAS,QACjB,SAAS,MAAM,KAAK;QACf,IAAI,MAAM,SAAS,YACxB,SAAS,MAAM,SAAS;QACnB,IAAI,MAAM,SAAS,YACxB,SAAS,MAAM,KAAK,SAAS,mBAAmB,MAAM,SAAS;GAGnE;EACF,KAAK;EACL,KAAK;GACH,QAAQ,yBAAyB,QAAQ,OAAO;GAChD;EACF,KAAK;GACH,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,OAAO;GAChD;EACF,KAAK;EACL,KAAK;GACH,QAAQ,QAAQ,QAAQ;GACxB;CACJ;CAEA,OAAO,KAAK,KAAK,QAAQ,CAAC;AAC5B;;;;;;;AAQA,MAAa,0BACX,aAC2B;CAC3B,IAAI,iBAAgC;CACpC,IAAI,cAAc;CAClB,IAAI,wBAAwB,OAAO;CAEnC,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS,GAAG;EACvD,MAAM,UAAU,SAAS;EACzB,MAAM,QAAQ,oBAAoB,OAAO;EACzC,MAAM,oBAAoB,OAAO,SAAS,QAAQ,SAAS;EAC3D,IAAI,UAAU,CAAC,qBAAqB,QAAQ,aAAa,wBAAwB;GAC/E,iBAAiB;GACjB,cAAc,uBAAuB,KAAK;EAC5C;EACA,IAAI,mBACF,wBAAwB,KAAK,IAAI,uBAAuB,QAAQ,SAAS;CAE7E;CAEA,MAAM,gBAAgB,mBAAmB,OAAO,IAAI,iBAAiB;CACrE,IAAI,iBAAiB;CACrB,KAAK,IAAI,QAAQ,eAAe,QAAQ,SAAS,QAAQ,SAAS,GAChE,kBAAkB,wBAAwB,SAAS,MAAM;CAG3D,OAAO;EACL,QAAQ,cAAc;EACtB;EACA;EACA;CACF;AACF"}
|