@code-yeongyu/senpi 2026.7.9-2 → 2026.7.9
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 +1 -25
- package/README.md +1 -1
- package/dist/cli/args.js +3 -3
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts +2 -4
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/core/agent-session.d.ts +3 -18
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +36 -153
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +2 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +79 -54
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/builtin/goal/continuation.js +1 -1
- package/dist/core/extensions/builtin/goal/continuation.js.map +1 -1
- package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/index.js +0 -1
- package/dist/core/extensions/builtin/goal/index.js.map +1 -1
- package/dist/core/extensions/builtin/import-repro.d.ts.map +1 -1
- package/dist/core/extensions/builtin/import-repro.js +6 -100
- package/dist/core/extensions/builtin/import-repro.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/connection.d.ts +0 -1
- package/dist/core/extensions/builtin/mcp/connection.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/connection.js +0 -15
- package/dist/core/extensions/builtin/mcp/connection.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/service.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/service.js +1 -3
- package/dist/core/extensions/builtin/mcp/service.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -4
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +24 -30
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +3 -23
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-registry.d.ts +0 -3
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +3 -20
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/package-manager.d.ts +1 -4
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +26 -68
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts +2 -2
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +7 -6
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +2 -9
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +2 -11
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +0 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +0 -8
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts +0 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +3 -3
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +2 -2
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +0 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts +3 -34
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +24 -272
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +0 -4
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +2 -5
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +1 -3
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +6 -16
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +0 -2
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +0 -10
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +0 -10
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +37 -261
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.js +1 -1
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +6 -6
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +3 -3
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/package-manager-cli.d.ts +2 -2
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +17 -64
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/clipboard-image.js +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/docs/extensions.md +9 -33
- package/docs/models.md +4 -4
- package/docs/packages.md +10 -7
- package/docs/rpc.md +3 -13
- package/docs/sdk.md +0 -22
- package/docs/settings.md +0 -1
- package/docs/usage.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/reload-runtime.ts +2 -2
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/README.md +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +2 -37
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-repo.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-repo.js +0 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-repo.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.d.ts +0 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.js +0 -7
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts +4 -18
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +37 -72
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +0 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts +0 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/index.js +0 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +1 -2
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js +1 -4
- package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +195 -446
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.d.ts +0 -84
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.js +0 -72
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js +4 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.d.ts +0 -63
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.js +0 -54
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.d.ts +0 -84
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.js +0 -72
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +63 -138
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +76 -136
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts +0 -77
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js +0 -71
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.d.ts +44 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js +45 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.d.ts +44 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js +45 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.d.ts +44 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js +45 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +0 -3
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +1 -1
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +1 -22
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/npm-shrinkwrap.json +14 -14
- package/package.json +6 -6
- package/dist/core/cache-stats.d.ts +0 -49
- package/dist/core/cache-stats.d.ts.map +0 -1
- package/dist/core/cache-stats.js +0 -101
- package/dist/core/cache-stats.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earendil-works/pi-tui",
|
|
3
3
|
"private": true,
|
|
4
|
-
"version": "2026.7.9
|
|
4
|
+
"version": "2026.7.9",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/senpi",
|
|
3
|
-
"version": "2026.7.9
|
|
3
|
+
"version": "2026.7.9",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@code-yeongyu/senpi",
|
|
9
|
-
"version": "2026.7.9
|
|
9
|
+
"version": "2026.7.9",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@anthropic-ai/sdk": "0.91.1",
|
|
13
13
|
"@aws-sdk/client-bedrock-runtime": "3.1048.0",
|
|
14
|
-
"@code-yeongyu/senpi-codemode": "^2026.7.9
|
|
15
|
-
"@earendil-works/pi-agent-core": "^2026.7.9
|
|
16
|
-
"@earendil-works/pi-ai": "^2026.7.9
|
|
17
|
-
"@earendil-works/pi-pty": "^2026.7.9
|
|
18
|
-
"@earendil-works/pi-tui": "^2026.7.9
|
|
14
|
+
"@code-yeongyu/senpi-codemode": "^2026.7.9",
|
|
15
|
+
"@earendil-works/pi-agent-core": "^2026.7.9",
|
|
16
|
+
"@earendil-works/pi-ai": "^2026.7.9",
|
|
17
|
+
"@earendil-works/pi-pty": "^2026.7.9",
|
|
18
|
+
"@earendil-works/pi-tui": "^2026.7.9",
|
|
19
19
|
"@mistralai/mistralai": "2.2.6",
|
|
20
20
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
21
21
|
"@mozilla/readability": "0.6.0",
|
|
@@ -554,11 +554,11 @@
|
|
|
554
554
|
}
|
|
555
555
|
},
|
|
556
556
|
"node_modules/@code-yeongyu/senpi-codemode": {
|
|
557
|
-
"version": "2026.7.9
|
|
557
|
+
"version": "2026.7.9",
|
|
558
558
|
"inBundle": true,
|
|
559
559
|
"license": "MIT",
|
|
560
560
|
"dependencies": {
|
|
561
|
-
"@earendil-works/pi-ai": "^2026.7.9
|
|
561
|
+
"@earendil-works/pi-ai": "^2026.7.9",
|
|
562
562
|
"typebox": "1.1.38"
|
|
563
563
|
},
|
|
564
564
|
"peerDependencies": {
|
|
@@ -703,11 +703,11 @@
|
|
|
703
703
|
]
|
|
704
704
|
},
|
|
705
705
|
"node_modules/@earendil-works/pi-agent-core": {
|
|
706
|
-
"version": "2026.7.9
|
|
706
|
+
"version": "2026.7.9",
|
|
707
707
|
"inBundle": true,
|
|
708
708
|
"license": "MIT",
|
|
709
709
|
"dependencies": {
|
|
710
|
-
"@earendil-works/pi-ai": "^2026.7.9
|
|
710
|
+
"@earendil-works/pi-ai": "^2026.7.9",
|
|
711
711
|
"ignore": "7.0.5",
|
|
712
712
|
"typebox": "1.1.38",
|
|
713
713
|
"yaml": "2.9.0"
|
|
@@ -717,7 +717,7 @@
|
|
|
717
717
|
}
|
|
718
718
|
},
|
|
719
719
|
"node_modules/@earendil-works/pi-ai": {
|
|
720
|
-
"version": "2026.7.9
|
|
720
|
+
"version": "2026.7.9",
|
|
721
721
|
"inBundle": true,
|
|
722
722
|
"license": "MIT",
|
|
723
723
|
"dependencies": {
|
|
@@ -745,7 +745,7 @@
|
|
|
745
745
|
}
|
|
746
746
|
},
|
|
747
747
|
"node_modules/@earendil-works/pi-pty": {
|
|
748
|
-
"version": "2026.7.9
|
|
748
|
+
"version": "2026.7.9",
|
|
749
749
|
"inBundle": true,
|
|
750
750
|
"license": "MIT",
|
|
751
751
|
"dependencies": {
|
|
@@ -756,7 +756,7 @@
|
|
|
756
756
|
}
|
|
757
757
|
},
|
|
758
758
|
"node_modules/@earendil-works/pi-tui": {
|
|
759
|
-
"version": "2026.7.9
|
|
759
|
+
"version": "2026.7.9",
|
|
760
760
|
"inBundle": true,
|
|
761
761
|
"license": "MIT",
|
|
762
762
|
"dependencies": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/senpi",
|
|
3
|
-
"version": "2026.7.9
|
|
3
|
+
"version": "2026.7.9",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"piConfig": {
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@anthropic-ai/sdk": "0.91.1",
|
|
46
46
|
"@aws-sdk/client-bedrock-runtime": "3.1048.0",
|
|
47
|
-
"@code-yeongyu/senpi-codemode": "^2026.7.9
|
|
48
|
-
"@earendil-works/pi-agent-core": "^2026.7.9
|
|
49
|
-
"@earendil-works/pi-ai": "^2026.7.9
|
|
50
|
-
"@earendil-works/pi-pty": "^2026.7.9
|
|
51
|
-
"@earendil-works/pi-tui": "^2026.7.9
|
|
47
|
+
"@code-yeongyu/senpi-codemode": "^2026.7.9",
|
|
48
|
+
"@earendil-works/pi-agent-core": "^2026.7.9",
|
|
49
|
+
"@earendil-works/pi-ai": "^2026.7.9",
|
|
50
|
+
"@earendil-works/pi-pty": "^2026.7.9",
|
|
51
|
+
"@earendil-works/pi-tui": "^2026.7.9",
|
|
52
52
|
"@mistralai/mistralai": "2.2.6",
|
|
53
53
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
54
54
|
"@mozilla/readability": "0.6.0",
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { AssistantMessage } from "@earendil-works/pi-ai";
|
|
2
|
-
import type { SessionEntry } from "./session-manager.ts";
|
|
3
|
-
/**
|
|
4
|
-
* Prompt-cache TTL: idle gaps longer than this are worth mentioning as the
|
|
5
|
-
* likely cause of a miss. Anthropic's default cache TTL is 5 minutes.
|
|
6
|
-
*/
|
|
7
|
-
export declare const CACHE_TTL_MS: number;
|
|
8
|
-
/** A counted cache miss on a single assistant message. */
|
|
9
|
-
export interface CacheMiss {
|
|
10
|
-
/** Prompt tokens that were in the previous turn's prompt but not read from cache. */
|
|
11
|
-
missedTokens: number;
|
|
12
|
-
/** Extra dollars paid vs. a full cache hit; 0 when pricing is unknown. */
|
|
13
|
-
missedCost: number;
|
|
14
|
-
/** Milliseconds since the previous request (which last refreshed the cache). */
|
|
15
|
-
idleMs: number;
|
|
16
|
-
/** True when the model changed relative to the previous request. */
|
|
17
|
-
modelChanged: boolean;
|
|
18
|
-
}
|
|
19
|
-
export interface CacheWasteTotals {
|
|
20
|
-
missedTokens: number;
|
|
21
|
-
missedCost: number;
|
|
22
|
-
/** Number of counted misses (turns above the noise floor). */
|
|
23
|
-
missCount: number;
|
|
24
|
-
}
|
|
25
|
-
/** Minimal pricing lookup, satisfied by ModelRegistry. Cost is $/million tokens. */
|
|
26
|
-
export interface ModelPriceSource {
|
|
27
|
-
find(provider: string, modelId: string): {
|
|
28
|
-
cost: {
|
|
29
|
-
cacheRead: number;
|
|
30
|
-
};
|
|
31
|
-
} | undefined;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Cumulative cache waste across a session: prompt tokens that should have been
|
|
35
|
-
* cache reads (they were in the previous turn's prompt) but were re-billed.
|
|
36
|
-
*/
|
|
37
|
-
export declare function computeCacheWaste(entries: SessionEntry[], models: ModelPriceSource): CacheWasteTotals;
|
|
38
|
-
/**
|
|
39
|
-
* All counted cache misses across a session, keyed by the assistant message
|
|
40
|
-
* (by reference) that paid for them. Used to re-derive transcript notices when
|
|
41
|
-
* rebuilding the chat from entries (resume, post-compaction rebuild).
|
|
42
|
-
*/
|
|
43
|
-
export declare function collectCacheMisses(entries: SessionEntry[], models: ModelPriceSource): Map<AssistantMessage, CacheMiss>;
|
|
44
|
-
/**
|
|
45
|
-
* Detect a cache miss on a just-completed assistant message.
|
|
46
|
-
* `entries` must not yet contain `message` (message_end fires before persistence).
|
|
47
|
-
*/
|
|
48
|
-
export declare function detectCacheMiss(entries: SessionEntry[], message: AssistantMessage, models: ModelPriceSource): CacheMiss | undefined;
|
|
49
|
-
//# sourceMappingURL=cache-stats.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cache-stats.d.ts","sourceRoot":"","sources":["../../src/core/cache-stats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD;;;GAGG;AACH,eAAO,MAAM,YAAY,QAAgB,CAAC;AAK1C,0DAA0D;AAC1D,MAAM,WAAW,SAAS;IACzB,qFAAqF;IACrF,YAAY,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,YAAY,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,oFAAoF;AACpF,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE;YAAE,SAAS,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,GAAG,SAAS,CAAC;CACrF;AAmGD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CAErG;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,YAAY,EAAE,EACvB,MAAM,EAAE,gBAAgB,GACtB,GAAG,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAElC;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,gBAAgB,GACtB,SAAS,GAAG,SAAS,CAEvB"}
|
package/dist/core/cache-stats.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prompt-cache TTL: idle gaps longer than this are worth mentioning as the
|
|
3
|
-
* likely cause of a miss. Anthropic's default cache TTL is 5 minutes.
|
|
4
|
-
*/
|
|
5
|
-
export const CACHE_TTL_MS = 5 * 60 * 1000;
|
|
6
|
-
/** Per-turn misses at or below this are cache breakpoint granularity noise. */
|
|
7
|
-
const NOISE_FLOOR_TOKENS = 1024;
|
|
8
|
-
/**
|
|
9
|
-
* Compute the cache miss for one assistant message relative to the previous
|
|
10
|
-
* request. Returns undefined when nothing is counted: first turn, after a
|
|
11
|
-
* reset, no cache activity ever reported (provider without cache support), or
|
|
12
|
-
* miss below the noise floor.
|
|
13
|
-
*/
|
|
14
|
-
function detectMiss(prev, message, models) {
|
|
15
|
-
const usage = message.usage;
|
|
16
|
-
const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
17
|
-
// A zero-cache turn only counts when cache activity was reported before:
|
|
18
|
-
// on cache-read-only providers that is a total miss, while on providers
|
|
19
|
-
// that never report caching it means nothing.
|
|
20
|
-
if (!prev || promptTokens <= 0 || (usage.cacheRead + usage.cacheWrite === 0 && !prev.reportedCache)) {
|
|
21
|
-
return undefined;
|
|
22
|
-
}
|
|
23
|
-
const missedTokens = Math.min(prev.promptTokens, promptTokens) - usage.cacheRead;
|
|
24
|
-
if (missedTokens <= NOISE_FLOOR_TOKENS)
|
|
25
|
-
return undefined;
|
|
26
|
-
// Extra cost = missed tokens billed at the actual paid rate (input/cacheWrite,
|
|
27
|
-
// incl. write premium) instead of the cache-read rate. Missed tokens can only
|
|
28
|
-
// land in the input or cacheWrite buckets, so the paid rate comes straight
|
|
29
|
-
// from this message's own cost breakdown.
|
|
30
|
-
const paidTokens = usage.input + usage.cacheWrite;
|
|
31
|
-
const paidPerToken = paidTokens > 0 ? (usage.cost.input + usage.cost.cacheWrite) / paidTokens : 0;
|
|
32
|
-
const readPerToken = usage.cacheRead > 0
|
|
33
|
-
? usage.cost.cacheRead / usage.cacheRead
|
|
34
|
-
: (models.find(message.provider, message.model)?.cost.cacheRead ?? 0) / 1_000_000;
|
|
35
|
-
return {
|
|
36
|
-
missedTokens,
|
|
37
|
-
missedCost: missedTokens * Math.max(0, paidPerToken - readPerToken),
|
|
38
|
-
idleMs: Math.max(0, message.timestamp - prev.timestamp),
|
|
39
|
-
modelChanged: `${message.provider}/${message.model}` !== prev.modelKey,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
function asPreviousRequest(message, reportedCache) {
|
|
43
|
-
const usage = message.usage;
|
|
44
|
-
const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
45
|
-
if (promptTokens <= 0)
|
|
46
|
-
return undefined;
|
|
47
|
-
return {
|
|
48
|
-
promptTokens,
|
|
49
|
-
modelKey: `${message.provider}/${message.model}`,
|
|
50
|
-
timestamp: message.timestamp,
|
|
51
|
-
reportedCache: reportedCache || usage.cacheRead + usage.cacheWrite > 0,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
function scan(entries, models) {
|
|
55
|
-
let prev;
|
|
56
|
-
const totals = { missedTokens: 0, missedCost: 0, missCount: 0 };
|
|
57
|
-
const misses = new Map();
|
|
58
|
-
for (const entry of entries) {
|
|
59
|
-
if (entry.type === "compaction" || entry.type === "branch_summary") {
|
|
60
|
-
// The context legitimately changed; the next turn's prompt is new content,
|
|
61
|
-
// not re-billed content. Model switches are NOT exempt: they re-bill the
|
|
62
|
-
// full prompt and should be counted.
|
|
63
|
-
prev = undefined;
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
if (entry.type === "message" && entry.message.role === "assistant") {
|
|
67
|
-
const miss = detectMiss(prev, entry.message, models);
|
|
68
|
-
if (miss) {
|
|
69
|
-
totals.missedTokens += miss.missedTokens;
|
|
70
|
-
totals.missedCost += miss.missedCost;
|
|
71
|
-
totals.missCount += 1;
|
|
72
|
-
misses.set(entry.message, miss);
|
|
73
|
-
}
|
|
74
|
-
prev = asPreviousRequest(entry.message, prev?.reportedCache ?? false) ?? prev;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return { prev, totals, misses };
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Cumulative cache waste across a session: prompt tokens that should have been
|
|
81
|
-
* cache reads (they were in the previous turn's prompt) but were re-billed.
|
|
82
|
-
*/
|
|
83
|
-
export function computeCacheWaste(entries, models) {
|
|
84
|
-
return scan(entries, models).totals;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* All counted cache misses across a session, keyed by the assistant message
|
|
88
|
-
* (by reference) that paid for them. Used to re-derive transcript notices when
|
|
89
|
-
* rebuilding the chat from entries (resume, post-compaction rebuild).
|
|
90
|
-
*/
|
|
91
|
-
export function collectCacheMisses(entries, models) {
|
|
92
|
-
return scan(entries, models).misses;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Detect a cache miss on a just-completed assistant message.
|
|
96
|
-
* `entries` must not yet contain `message` (message_end fires before persistence).
|
|
97
|
-
*/
|
|
98
|
-
export function detectCacheMiss(entries, message, models) {
|
|
99
|
-
return detectMiss(scan(entries, models).prev, message, models);
|
|
100
|
-
}
|
|
101
|
-
//# sourceMappingURL=cache-stats.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cache-stats.js","sourceRoot":"","sources":["../../src/core/cache-stats.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"@earendil-works/pi-ai\";\nimport type { SessionEntry } from \"./session-manager.ts\";\n\n/**\n * Prompt-cache TTL: idle gaps longer than this are worth mentioning as the\n * likely cause of a miss. Anthropic's default cache TTL is 5 minutes.\n */\nexport const CACHE_TTL_MS = 5 * 60 * 1000;\n\n/** Per-turn misses at or below this are cache breakpoint granularity noise. */\nconst NOISE_FLOOR_TOKENS = 1024;\n\n/** A counted cache miss on a single assistant message. */\nexport interface CacheMiss {\n\t/** Prompt tokens that were in the previous turn's prompt but not read from cache. */\n\tmissedTokens: number;\n\t/** Extra dollars paid vs. a full cache hit; 0 when pricing is unknown. */\n\tmissedCost: number;\n\t/** Milliseconds since the previous request (which last refreshed the cache). */\n\tidleMs: number;\n\t/** True when the model changed relative to the previous request. */\n\tmodelChanged: boolean;\n}\n\nexport interface CacheWasteTotals {\n\tmissedTokens: number;\n\tmissedCost: number;\n\t/** Number of counted misses (turns above the noise floor). */\n\tmissCount: number;\n}\n\n/** Minimal pricing lookup, satisfied by ModelRegistry. Cost is $/million tokens. */\nexport interface ModelPriceSource {\n\tfind(provider: string, modelId: string): { cost: { cacheRead: number } } | undefined;\n}\n\n/** The last request seen by the scan; everything in its prompt should be cached. */\ninterface PreviousRequest {\n\tpromptTokens: number;\n\tmodelKey: string;\n\ttimestamp: number;\n\t/**\n\t * Sticky: some earlier request in this scan segment reported cache activity.\n\t * Distinguishes a total miss on a cache-read-only provider (OpenAI-style,\n\t * writes unreported) from a provider that never reports caching at all.\n\t */\n\treportedCache: boolean;\n}\n\n/**\n * Compute the cache miss for one assistant message relative to the previous\n * request. Returns undefined when nothing is counted: first turn, after a\n * reset, no cache activity ever reported (provider without cache support), or\n * miss below the noise floor.\n */\nfunction detectMiss(\n\tprev: PreviousRequest | undefined,\n\tmessage: AssistantMessage,\n\tmodels: ModelPriceSource,\n): CacheMiss | undefined {\n\tconst usage = message.usage;\n\tconst promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n\t// A zero-cache turn only counts when cache activity was reported before:\n\t// on cache-read-only providers that is a total miss, while on providers\n\t// that never report caching it means nothing.\n\tif (!prev || promptTokens <= 0 || (usage.cacheRead + usage.cacheWrite === 0 && !prev.reportedCache)) {\n\t\treturn undefined;\n\t}\n\n\tconst missedTokens = Math.min(prev.promptTokens, promptTokens) - usage.cacheRead;\n\tif (missedTokens <= NOISE_FLOOR_TOKENS) return undefined;\n\n\t// Extra cost = missed tokens billed at the actual paid rate (input/cacheWrite,\n\t// incl. write premium) instead of the cache-read rate. Missed tokens can only\n\t// land in the input or cacheWrite buckets, so the paid rate comes straight\n\t// from this message's own cost breakdown.\n\tconst paidTokens = usage.input + usage.cacheWrite;\n\tconst paidPerToken = paidTokens > 0 ? (usage.cost.input + usage.cost.cacheWrite) / paidTokens : 0;\n\tconst readPerToken =\n\t\tusage.cacheRead > 0\n\t\t\t? usage.cost.cacheRead / usage.cacheRead\n\t\t\t: (models.find(message.provider, message.model)?.cost.cacheRead ?? 0) / 1_000_000;\n\n\treturn {\n\t\tmissedTokens,\n\t\tmissedCost: missedTokens * Math.max(0, paidPerToken - readPerToken),\n\t\tidleMs: Math.max(0, message.timestamp - prev.timestamp),\n\t\tmodelChanged: `${message.provider}/${message.model}` !== prev.modelKey,\n\t};\n}\n\nfunction asPreviousRequest(message: AssistantMessage, reportedCache: boolean): PreviousRequest | undefined {\n\tconst usage = message.usage;\n\tconst promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n\tif (promptTokens <= 0) return undefined;\n\treturn {\n\t\tpromptTokens,\n\t\tmodelKey: `${message.provider}/${message.model}`,\n\t\ttimestamp: message.timestamp,\n\t\treportedCache: reportedCache || usage.cacheRead + usage.cacheWrite > 0,\n\t};\n}\n\nfunction scan(\n\tentries: SessionEntry[],\n\tmodels: ModelPriceSource,\n): { prev: PreviousRequest | undefined; totals: CacheWasteTotals; misses: Map<AssistantMessage, CacheMiss> } {\n\tlet prev: PreviousRequest | undefined;\n\tconst totals: CacheWasteTotals = { missedTokens: 0, missedCost: 0, missCount: 0 };\n\tconst misses = new Map<AssistantMessage, CacheMiss>();\n\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"compaction\" || entry.type === \"branch_summary\") {\n\t\t\t// The context legitimately changed; the next turn's prompt is new content,\n\t\t\t// not re-billed content. Model switches are NOT exempt: they re-bill the\n\t\t\t// full prompt and should be counted.\n\t\t\tprev = undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tconst miss = detectMiss(prev, entry.message, models);\n\t\t\tif (miss) {\n\t\t\t\ttotals.missedTokens += miss.missedTokens;\n\t\t\t\ttotals.missedCost += miss.missedCost;\n\t\t\t\ttotals.missCount += 1;\n\t\t\t\tmisses.set(entry.message, miss);\n\t\t\t}\n\t\t\tprev = asPreviousRequest(entry.message, prev?.reportedCache ?? false) ?? prev;\n\t\t}\n\t}\n\treturn { prev, totals, misses };\n}\n\n/**\n * Cumulative cache waste across a session: prompt tokens that should have been\n * cache reads (they were in the previous turn's prompt) but were re-billed.\n */\nexport function computeCacheWaste(entries: SessionEntry[], models: ModelPriceSource): CacheWasteTotals {\n\treturn scan(entries, models).totals;\n}\n\n/**\n * All counted cache misses across a session, keyed by the assistant message\n * (by reference) that paid for them. Used to re-derive transcript notices when\n * rebuilding the chat from entries (resume, post-compaction rebuild).\n */\nexport function collectCacheMisses(\n\tentries: SessionEntry[],\n\tmodels: ModelPriceSource,\n): Map<AssistantMessage, CacheMiss> {\n\treturn scan(entries, models).misses;\n}\n\n/**\n * Detect a cache miss on a just-completed assistant message.\n * `entries` must not yet contain `message` (message_end fires before persistence).\n */\nexport function detectCacheMiss(\n\tentries: SessionEntry[],\n\tmessage: AssistantMessage,\n\tmodels: ModelPriceSource,\n): CacheMiss | undefined {\n\treturn detectMiss(scan(entries, models).prev, message, models);\n}\n"]}
|