@adecore/agents 0.0.1 → 0.17.0-beta.1
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 +110 -0
- package/README.md +33 -0
- package/dist/async.d.ts +2 -0
- package/dist/async.js +31 -0
- package/dist/chat/attachment-store.d.ts +10 -0
- package/dist/chat/attachment-store.js +93 -0
- package/dist/chat/backend.d.ts +214 -0
- package/dist/chat/backend.js +1 -0
- package/dist/chat/background-work.d.ts +8 -0
- package/dist/chat/background-work.js +33 -0
- package/dist/chat/bookmark-store.d.ts +25 -0
- package/dist/chat/bookmark-store.js +141 -0
- package/dist/chat/chat-core.d.ts +311 -0
- package/dist/chat/chat-core.js +1025 -0
- package/dist/chat/chat-log.d.ts +33 -0
- package/dist/chat/chat-log.js +163 -0
- package/dist/chat/chat-process.d.ts +46 -0
- package/dist/chat/chat-process.js +190 -0
- package/dist/chat/chat-session.d.ts +209 -0
- package/dist/chat/chat-session.js +1511 -0
- package/dist/chat/chat-store.d.ts +37 -0
- package/dist/chat/chat-store.js +202 -0
- package/dist/chat/chat-title.d.ts +10 -0
- package/dist/chat/chat-title.js +74 -0
- package/dist/chat/claude-backend.d.ts +35 -0
- package/dist/chat/claude-backend.js +214 -0
- package/dist/chat/claude-protocol.d.ts +41 -0
- package/dist/chat/claude-protocol.js +642 -0
- package/dist/chat/claude-title.d.ts +11 -0
- package/dist/chat/claude-title.js +97 -0
- package/dist/chat/claude-transcript.d.ts +28 -0
- package/dist/chat/claude-transcript.js +211 -0
- package/dist/chat/codex-backend.d.ts +51 -0
- package/dist/chat/codex-backend.js +364 -0
- package/dist/chat/codex-protocol.d.ts +56 -0
- package/dist/chat/codex-protocol.js +767 -0
- package/dist/chat/codex-thread.d.ts +32 -0
- package/dist/chat/codex-thread.js +131 -0
- package/dist/chat/codex-transport.d.ts +42 -0
- package/dist/chat/codex-transport.js +188 -0
- package/dist/chat/composer-preferences.d.ts +15 -0
- package/dist/chat/composer-preferences.js +46 -0
- package/dist/chat/context-breakdown.d.ts +2 -0
- package/dist/chat/context-breakdown.js +74 -0
- package/dist/chat/delta-coalescer.d.ts +12 -0
- package/dist/chat/delta-coalescer.js +55 -0
- package/dist/chat/errors.d.ts +4 -0
- package/dist/chat/errors.js +4 -0
- package/dist/chat/fake-claude.d.ts +3 -0
- package/dist/chat/fake-claude.js +982 -0
- package/dist/chat/fake-cli.d.ts +25 -0
- package/dist/chat/fake-cli.js +157 -0
- package/dist/chat/fake-codex.d.ts +10 -0
- package/dist/chat/fake-codex.js +502 -0
- package/dist/chat/fixtures/claude-2.1.285-auto-fallback.json +24 -0
- package/dist/chat/fixtures/claude-2.1.285-native-children.json +6600 -0
- package/dist/chat/fixtures/claude-2.1.285-resume-direct-compact.json +202 -0
- package/dist/chat/fixtures/claude-2.1.285-resume-task-notification.json +57 -0
- package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a4c2e8f10b3d5a7e9.jsonl +10 -0
- package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a4c2e8f10b3d5a7e9.meta.json +1 -0
- package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a9b8c7d6e5f4a3b21.jsonl +2 -0
- package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a9b8c7d6e5f4a3b21.meta.json +1 -0
- package/dist/chat/fixtures/codex-0.159.2-native-approval.json +119 -0
- package/dist/chat/fixtures/codex-0.159.2-native-file-approval.json +136 -0
- package/dist/chat/fixtures/codex-0.159.2-native-interacted.json +220 -0
- package/dist/chat/fixtures/codex-0.159.2-usage-windows.json +74 -0
- package/dist/chat/input.d.ts +19 -0
- package/dist/chat/input.js +71 -0
- package/dist/chat/limit-resume.d.ts +11 -0
- package/dist/chat/limit-resume.js +68 -0
- package/dist/chat/projector.d.ts +60 -0
- package/dist/chat/projector.js +860 -0
- package/dist/chat/request-summary.d.ts +3 -0
- package/dist/chat/request-summary.js +143 -0
- package/dist/chat/subagent-projection.d.ts +8 -0
- package/dist/chat/subagent-projection.js +40 -0
- package/dist/chat/subagent-reader.d.ts +66 -0
- package/dist/chat/subagent-reader.js +396 -0
- package/dist/chat/subagent-settlement.d.ts +6 -0
- package/dist/chat/subagent-settlement.js +103 -0
- package/dist/chat/thread.d.ts +30 -0
- package/dist/chat/thread.js +147 -0
- package/dist/chat/wake-chat.d.ts +20 -0
- package/dist/chat/wake-chat.js +27 -0
- package/dist/client-sinks.d.ts +9 -0
- package/dist/client-sinks.js +34 -0
- package/dist/coded-error.d.ts +5 -0
- package/dist/coded-error.js +17 -0
- package/dist/context/argv.d.ts +11 -0
- package/dist/context/argv.js +58 -0
- package/dist/context/refusal.d.ts +9 -0
- package/dist/context/refusal.js +38 -0
- package/dist/context/verb.d.ts +85 -0
- package/dist/context/verb.js +233 -0
- package/dist/error-text.d.ts +5 -0
- package/dist/error-text.js +24 -0
- package/dist/events.d.ts +12 -0
- package/dist/events.js +1 -0
- package/dist/fs.d.ts +9 -0
- package/dist/fs.js +107 -0
- package/dist/host/agent-host.d.ts +28 -0
- package/dist/host/agent-host.js +105 -0
- package/dist/host/environment.d.ts +7 -0
- package/dist/host/environment.js +22 -0
- package/dist/host/handlers.d.ts +30 -0
- package/dist/host/handlers.js +111 -0
- package/dist/host/memory-port.d.ts +2 -0
- package/dist/host/memory-port.js +25 -0
- package/dist/host/wiring.d.ts +40 -0
- package/dist/host/wiring.js +120 -0
- package/dist/lineage.d.ts +44 -0
- package/dist/lineage.js +134 -0
- package/dist/messages/deliver-message.d.ts +21 -0
- package/dist/messages/deliver-message.js +42 -0
- package/dist/messages/deliver-notice.d.ts +25 -0
- package/dist/messages/deliver-notice.js +75 -0
- package/dist/messages/notice-notes.d.ts +15 -0
- package/dist/messages/notice-notes.js +26 -0
- package/dist/messages/notice-store.d.ts +30 -0
- package/dist/messages/notice-store.js +120 -0
- package/dist/modes.d.ts +11 -0
- package/dist/modes.js +28 -0
- package/dist/outbox/manual-clock.d.ts +10 -0
- package/dist/outbox/manual-clock.js +25 -0
- package/dist/outbox/outbox-worker.d.ts +44 -0
- package/dist/outbox/outbox-worker.js +173 -0
- package/dist/outbox/outbox.d.ts +37 -0
- package/dist/outbox/outbox.js +76 -0
- package/dist/providers/accounts/accounts.d.ts +20 -0
- package/dist/providers/accounts/accounts.js +158 -0
- package/dist/providers/accounts/launch.d.ts +17 -0
- package/dist/providers/accounts/launch.js +30 -0
- package/dist/providers/accounts/service.d.ts +87 -0
- package/dist/providers/accounts/service.js +538 -0
- package/dist/providers/accounts/shadow-home.d.ts +8 -0
- package/dist/providers/accounts/shadow-home.js +70 -0
- package/dist/providers/accounts/status.d.ts +12 -0
- package/dist/providers/accounts/status.js +85 -0
- package/dist/providers/accounts/store.d.ts +14 -0
- package/dist/providers/accounts/store.js +112 -0
- package/dist/providers/accounts/test-accounts.d.ts +12 -0
- package/dist/providers/accounts/test-accounts.js +38 -0
- package/dist/providers/accounts/variables.d.ts +27 -0
- package/dist/providers/accounts/variables.js +94 -0
- package/dist/providers/catalog.d.ts +17 -0
- package/dist/providers/catalog.js +76 -0
- package/dist/providers/claude-models.json +114 -0
- package/dist/providers/claude-provider.d.ts +4 -0
- package/dist/providers/claude-provider.js +29 -0
- package/dist/providers/claude.d.ts +15 -0
- package/dist/providers/claude.js +105 -0
- package/dist/providers/codex-models.json +135 -0
- package/dist/providers/codex-provider.d.ts +4 -0
- package/dist/providers/codex-provider.js +27 -0
- package/dist/providers/codex-rules.d.ts +9 -0
- package/dist/providers/codex-rules.js +35 -0
- package/dist/providers/codex.d.ts +14 -0
- package/dist/providers/codex.js +52 -0
- package/dist/providers/detect.d.ts +6 -0
- package/dist/providers/detect.js +30 -0
- package/dist/providers/provider.d.ts +25 -0
- package/dist/providers/provider.js +1 -0
- package/dist/providers/registry.d.ts +28 -0
- package/dist/providers/registry.js +118 -0
- package/dist/record-directory.d.ts +27 -0
- package/dist/record-directory.js +114 -0
- package/dist/run-process.d.ts +13 -0
- package/dist/run-process.js +42 -0
- package/dist/serializer.d.ts +9 -0
- package/dist/serializer.js +34 -0
- package/dist/skills.d.ts +21 -0
- package/dist/skills.js +174 -0
- package/dist/tasks/background-limit.d.ts +16 -0
- package/dist/tasks/background-limit.js +55 -0
- package/dist/tasks/end-children.d.ts +34 -0
- package/dist/tasks/end-children.js +53 -0
- package/dist/tasks/give-task.d.ts +14 -0
- package/dist/tasks/give-task.js +33 -0
- package/dist/tasks/task-coordinator.d.ts +52 -0
- package/dist/tasks/task-coordinator.js +323 -0
- package/dist/tasks/task-store.d.ts +49 -0
- package/dist/tasks/task-store.js +197 -0
- package/dist/tasks/task-work.d.ts +47 -0
- package/dist/tasks/task-work.js +28 -0
- package/dist/tasks/waiting-child.d.ts +51 -0
- package/dist/tasks/waiting-child.js +143 -0
- package/dist/tasks/wake-parent.d.ts +19 -0
- package/dist/tasks/wake-parent.js +109 -0
- package/dist/tasks/wiring.d.ts +51 -0
- package/dist/tasks/wiring.js +151 -0
- package/dist/title-file.d.ts +2 -0
- package/dist/title-file.js +55 -0
- package/dist/usage/accounts.d.ts +15 -0
- package/dist/usage/accounts.js +64 -0
- package/dist/usage/aggregate.d.ts +12 -0
- package/dist/usage/aggregate.js +154 -0
- package/dist/usage/exchange.d.ts +16 -0
- package/dist/usage/exchange.js +84 -0
- package/dist/usage/index-file.d.ts +15 -0
- package/dist/usage/index-file.js +123 -0
- package/dist/usage/limits/monitor.d.ts +50 -0
- package/dist/usage/limits/monitor.js +179 -0
- package/dist/usage/limits/normalize.d.ts +21 -0
- package/dist/usage/limits/normalize.js +160 -0
- package/dist/usage/limits/probe.d.ts +9 -0
- package/dist/usage/limits/probe.js +113 -0
- package/dist/usage/prices-snapshot.json +1071 -0
- package/dist/usage/pricing.d.ts +34 -0
- package/dist/usage/pricing.js +186 -0
- package/dist/usage/projects.d.ts +17 -0
- package/dist/usage/projects.js +49 -0
- package/dist/usage/readers/claude.d.ts +3 -0
- package/dist/usage/readers/claude.js +59 -0
- package/dist/usage/readers/codex.d.ts +23 -0
- package/dist/usage/readers/codex.js +155 -0
- package/dist/usage/record.d.ts +15 -0
- package/dist/usage/record.js +39 -0
- package/dist/usage/roots.d.ts +12 -0
- package/dist/usage/roots.js +29 -0
- package/dist/usage/scanner.d.ts +30 -0
- package/dist/usage/scanner.js +234 -0
- package/dist/usage/usage-service.d.ts +35 -0
- package/dist/usage/usage-service.js +130 -0
- package/dist/watch-seam.d.ts +29 -0
- package/dist/watch-seam.js +78 -0
- package/dist/watch-test-helpers.d.ts +28 -0
- package/dist/watch-test-helpers.js +86 -0
- package/package.json +42 -3
- package/src/async.ts +40 -0
- package/src/chat/attachment-store.ts +108 -0
- package/src/chat/backend.ts +199 -0
- package/src/chat/background-work.ts +42 -0
- package/src/chat/bookmark-store.ts +166 -0
- package/src/chat/chat-core.ts +1228 -0
- package/src/chat/chat-log.ts +187 -0
- package/src/chat/chat-process.ts +237 -0
- package/src/chat/chat-session.ts +1723 -0
- package/src/chat/chat-store.ts +261 -0
- package/src/chat/chat-title.ts +90 -0
- package/src/chat/claude-backend.ts +235 -0
- package/src/chat/claude-protocol.ts +684 -0
- package/src/chat/claude-title.ts +106 -0
- package/src/chat/claude-transcript.ts +233 -0
- package/src/chat/codex-backend.ts +397 -0
- package/src/chat/codex-protocol.ts +872 -0
- package/src/chat/codex-thread.ts +162 -0
- package/src/chat/codex-transport.ts +224 -0
- package/src/chat/composer-preferences.ts +67 -0
- package/src/chat/context-breakdown.ts +80 -0
- package/src/chat/delta-coalescer.ts +62 -0
- package/src/chat/errors.ts +25 -0
- package/src/chat/fake-claude.ts +1006 -0
- package/src/chat/fake-cli.ts +199 -0
- package/src/chat/fake-codex.ts +534 -0
- package/src/chat/fixtures/claude-2.1.285-auto-fallback.json +24 -0
- package/src/chat/fixtures/claude-2.1.285-native-children.json +6600 -0
- package/src/chat/fixtures/claude-2.1.285-resume-direct-compact.json +202 -0
- package/src/chat/fixtures/claude-2.1.285-resume-task-notification.json +57 -0
- package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a4c2e8f10b3d5a7e9.jsonl +10 -0
- package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a4c2e8f10b3d5a7e9.meta.json +1 -0
- package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a9b8c7d6e5f4a3b21.jsonl +2 -0
- package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a9b8c7d6e5f4a3b21.meta.json +1 -0
- package/src/chat/fixtures/codex-0.159.2-native-approval.json +119 -0
- package/src/chat/fixtures/codex-0.159.2-native-file-approval.json +136 -0
- package/src/chat/fixtures/codex-0.159.2-native-interacted.json +220 -0
- package/src/chat/fixtures/codex-0.159.2-usage-windows.json +74 -0
- package/src/chat/input.ts +89 -0
- package/src/chat/limit-resume.ts +74 -0
- package/src/chat/projector.ts +969 -0
- package/src/chat/request-summary.ts +168 -0
- package/src/chat/subagent-projection.ts +45 -0
- package/src/chat/subagent-reader.ts +469 -0
- package/src/chat/subagent-settlement.ts +111 -0
- package/src/chat/thread.ts +167 -0
- package/src/chat/wake-chat.ts +45 -0
- package/src/client-sinks.ts +39 -0
- package/src/coded-error.ts +18 -0
- package/src/context/argv.ts +61 -0
- package/src/context/refusal.ts +50 -0
- package/src/context/verb.ts +392 -0
- package/src/error-text.ts +28 -0
- package/src/events.ts +9 -0
- package/src/fs.ts +118 -0
- package/src/host/agent-host.ts +124 -0
- package/src/host/environment.ts +31 -0
- package/src/host/handlers.ts +142 -0
- package/src/host/memory-port.ts +27 -0
- package/src/host/wiring.ts +164 -0
- package/src/lineage.ts +159 -0
- package/src/messages/deliver-message.ts +61 -0
- package/src/messages/deliver-notice.ts +120 -0
- package/src/messages/notice-notes.ts +34 -0
- package/src/messages/notice-store.ts +142 -0
- package/src/modes.ts +38 -0
- package/src/outbox/manual-clock.ts +31 -0
- package/src/outbox/outbox-worker.ts +214 -0
- package/src/outbox/outbox.ts +106 -0
- package/src/providers/accounts/accounts.ts +192 -0
- package/src/providers/accounts/launch.ts +55 -0
- package/src/providers/accounts/service.ts +632 -0
- package/src/providers/accounts/shadow-home.ts +85 -0
- package/src/providers/accounts/status.ts +106 -0
- package/src/providers/accounts/store.ts +158 -0
- package/src/providers/accounts/test-accounts.ts +48 -0
- package/src/providers/accounts/variables.ts +132 -0
- package/src/providers/catalog.ts +90 -0
- package/src/providers/claude-models.json +114 -0
- package/src/providers/claude-provider.ts +32 -0
- package/src/providers/claude.ts +123 -0
- package/src/providers/codex-models.json +135 -0
- package/src/providers/codex-provider.ts +30 -0
- package/src/providers/codex-rules.ts +54 -0
- package/src/providers/codex.ts +69 -0
- package/src/providers/detect.ts +40 -0
- package/src/providers/provider.ts +46 -0
- package/src/providers/registry.ts +150 -0
- package/src/record-directory.ts +136 -0
- package/src/run-process.ts +61 -0
- package/src/serializer.ts +41 -0
- package/src/skills.ts +199 -0
- package/src/tasks/background-limit.ts +72 -0
- package/src/tasks/end-children.ts +100 -0
- package/src/tasks/give-task.ts +52 -0
- package/src/tasks/task-coordinator.ts +384 -0
- package/src/tasks/task-store.ts +236 -0
- package/src/tasks/task-work.ts +62 -0
- package/src/tasks/waiting-child.ts +203 -0
- package/src/tasks/wake-parent.ts +142 -0
- package/src/tasks/wiring.ts +231 -0
- package/src/title-file.ts +57 -0
- package/src/usage/accounts.ts +86 -0
- package/src/usage/aggregate.ts +220 -0
- package/src/usage/exchange.ts +93 -0
- package/src/usage/index-file.ts +178 -0
- package/src/usage/limits/monitor.ts +239 -0
- package/src/usage/limits/normalize.ts +188 -0
- package/src/usage/limits/probe.ts +120 -0
- package/src/usage/prices-snapshot.json +1071 -0
- package/src/usage/pricing.ts +236 -0
- package/src/usage/projects.ts +65 -0
- package/src/usage/readers/claude.ts +60 -0
- package/src/usage/readers/codex.ts +196 -0
- package/src/usage/record.ts +60 -0
- package/src/usage/roots.ts +39 -0
- package/src/usage/scanner.ts +265 -0
- package/src/usage/usage-service.ts +161 -0
- package/src/watch-seam.ts +111 -0
- package/src/watch-test-helpers.ts +102 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
const MINUTE_MS = 60_000;
|
|
2
|
+
const FIVE_HOURS_MS = 5 * 60 * MINUTE_MS;
|
|
3
|
+
const WEEK_MS = 7 * 24 * 60 * MINUTE_MS;
|
|
4
|
+
const MONTH_MS = 30 * 24 * 60 * MINUTE_MS;
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
function num(value) {
|
|
9
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
10
|
+
}
|
|
11
|
+
function fraction(value) {
|
|
12
|
+
return Math.min(1, Math.max(0, value));
|
|
13
|
+
}
|
|
14
|
+
/* A window is named after how long it lasts, never after the position it came in. */
|
|
15
|
+
export function kindOfDuration(durationMs) {
|
|
16
|
+
if (durationMs === null) {
|
|
17
|
+
return 'other';
|
|
18
|
+
}
|
|
19
|
+
if (durationMs >= MONTH_MS) {
|
|
20
|
+
return 'monthly';
|
|
21
|
+
}
|
|
22
|
+
if (durationMs >= WEEK_MS) {
|
|
23
|
+
return 'weekly';
|
|
24
|
+
}
|
|
25
|
+
return 'session';
|
|
26
|
+
}
|
|
27
|
+
const CLAUDE_WINDOWS = [
|
|
28
|
+
{ key: 'five_hour', id: 'five_hour', label: 'Session', kind: 'session', durationMs: FIVE_HOURS_MS },
|
|
29
|
+
{ key: 'seven_day', id: 'seven_day', label: 'Weekly', kind: 'weekly', durationMs: WEEK_MS },
|
|
30
|
+
{ key: 'seven_day_opus', id: 'seven_day_opus', label: 'Weekly · Opus', kind: 'weekly', durationMs: WEEK_MS },
|
|
31
|
+
{ key: 'seven_day_sonnet', id: 'seven_day_sonnet', label: 'Weekly · Sonnet', kind: 'weekly', durationMs: WEEK_MS }
|
|
32
|
+
];
|
|
33
|
+
function slug(value) {
|
|
34
|
+
return value
|
|
35
|
+
.toLowerCase()
|
|
36
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
37
|
+
.replace(/^_|_$/g, '');
|
|
38
|
+
}
|
|
39
|
+
/*
|
|
40
|
+
* What `get_usage` answers. Claude reports a percent and an ISO moment there, while the event a
|
|
41
|
+
* running turn sends reports a fraction and epoch seconds; both are turned into a fraction and epoch
|
|
42
|
+
* milliseconds here, so nothing past this file has to remember which of the two it is holding.
|
|
43
|
+
*/
|
|
44
|
+
export function readClaudeUsage(response) {
|
|
45
|
+
if (!isRecord(response)) {
|
|
46
|
+
return { unavailable: { reason: 'failed', message: 'Claude Code returned no readable usage' } };
|
|
47
|
+
}
|
|
48
|
+
const plan = typeof response.subscription_type === 'string' ? response.subscription_type : null;
|
|
49
|
+
const limits = isRecord(response.rate_limits) ? response.rate_limits : null;
|
|
50
|
+
if (response.rate_limits_available === false || limits === null) {
|
|
51
|
+
// An API key, Bedrock or Vertex account has no plan windows at all, which is not a failure.
|
|
52
|
+
return { unavailable: { reason: 'no-subscription', message: null } };
|
|
53
|
+
}
|
|
54
|
+
const windows = [];
|
|
55
|
+
const push = (id, label, kind, durationMs, entry) => {
|
|
56
|
+
const window = isRecord(entry) ? entry : null;
|
|
57
|
+
const utilization = window === null ? null : num(window.utilization);
|
|
58
|
+
if (utilization === null) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const resetsAt = typeof window?.resets_at === 'string' ? Date.parse(window.resets_at) : Number.NaN;
|
|
62
|
+
windows.push({ id, label, kind, used: fraction(utilization / 100), resetsAt: Number.isNaN(resetsAt) ? null : resetsAt, durationMs });
|
|
63
|
+
};
|
|
64
|
+
for (const known of CLAUDE_WINDOWS) {
|
|
65
|
+
push(known.id, known.label, known.kind, known.durationMs, limits[known.key]);
|
|
66
|
+
}
|
|
67
|
+
for (const entry of Array.isArray(limits.model_scoped) ? limits.model_scoped : []) {
|
|
68
|
+
const name = isRecord(entry) && typeof entry.display_name === 'string' ? entry.display_name : null;
|
|
69
|
+
if (name !== null) {
|
|
70
|
+
push(`seven_day_${slug(name)}`, `Weekly · ${name}`, 'weekly', WEEK_MS, entry);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const session = isRecord(response.session) ? response.session : null;
|
|
74
|
+
const sessionUsd = session === null ? null : num(session.total_cost_usd);
|
|
75
|
+
return { plan, windows, cost: sessionUsd === null ? null : { sessionUsd } };
|
|
76
|
+
}
|
|
77
|
+
/* The `rate_limit_event` a turn streams: one window, a fraction, and seconds where the read had ISO. */
|
|
78
|
+
export function readClaudeEvent(info) {
|
|
79
|
+
const event = isRecord(info) ? info : null;
|
|
80
|
+
const type = event !== null && typeof event.rateLimitType === 'string' ? event.rateLimitType : null;
|
|
81
|
+
const utilization = event === null ? null : num(event.utilization);
|
|
82
|
+
if (type === null || utilization === null) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const known = CLAUDE_WINDOWS.find((window) => window.key === type);
|
|
86
|
+
const resetsAt = num(event?.resetsAt);
|
|
87
|
+
return {
|
|
88
|
+
kind: 'claude',
|
|
89
|
+
windows: [
|
|
90
|
+
{
|
|
91
|
+
id: known?.id ?? type,
|
|
92
|
+
...(known ? { label: known.label, kind: known.kind, durationMs: known.durationMs } : {}),
|
|
93
|
+
used: fraction(utilization),
|
|
94
|
+
...(resetsAt === null ? {} : { resetsAt: Math.round(resetsAt * 1000) })
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/*
|
|
100
|
+
* A Codex rate limit snapshot, from a read or from the notification a turn sends. Only the main
|
|
101
|
+
* allowance counts: the other ids are one model's own budget and read as a second plan.
|
|
102
|
+
*/
|
|
103
|
+
export function readCodexLimits(snapshot) {
|
|
104
|
+
const limits = isRecord(snapshot) ? snapshot : null;
|
|
105
|
+
if (limits === null || (typeof limits.limitId === 'string' && limits.limitId !== 'codex')) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const plan = typeof limits.planType === 'string' ? limits.planType : null;
|
|
109
|
+
const windows = [];
|
|
110
|
+
for (const [position, entry] of [
|
|
111
|
+
['primary', limits.primary],
|
|
112
|
+
['secondary', limits.secondary]
|
|
113
|
+
]) {
|
|
114
|
+
const window = isRecord(entry) ? entry : null;
|
|
115
|
+
const usedPercent = window === null ? null : num(window.usedPercent);
|
|
116
|
+
if (usedPercent === null) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const minutes = num(window?.windowDurationMins);
|
|
120
|
+
const durationMs = minutes === null ? null : Math.round(minutes * MINUTE_MS);
|
|
121
|
+
const kind = kindOfDuration(durationMs);
|
|
122
|
+
const resetsAt = num(window?.resetsAt);
|
|
123
|
+
windows.push({
|
|
124
|
+
id: position,
|
|
125
|
+
kind,
|
|
126
|
+
label: kind === 'session' ? 'Session' : kind === 'weekly' ? 'Weekly' : kind === 'monthly' ? 'Monthly' : 'Usage',
|
|
127
|
+
used: fraction(usedPercent / 100),
|
|
128
|
+
resetsAt: resetsAt === null ? null : Math.round(resetsAt * 1000),
|
|
129
|
+
durationMs
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return { plan, windows, cost: null };
|
|
133
|
+
}
|
|
134
|
+
/*
|
|
135
|
+
* A sparse update folded onto what a full read drew. The row keeps its label, its reset and its
|
|
136
|
+
* length when the event leaves them out, which is what makes a mid-turn number land on the bar it
|
|
137
|
+
* belongs to instead of drawing a second one beside it.
|
|
138
|
+
*/
|
|
139
|
+
export function mergeWindows(known, updates) {
|
|
140
|
+
const merged = known.map((window) => ({ ...window }));
|
|
141
|
+
for (const update of updates) {
|
|
142
|
+
if (update.id === undefined || update.used === undefined) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const at = merged.findIndex((window) => window.id === update.id);
|
|
146
|
+
if (at === -1) {
|
|
147
|
+
merged.push({
|
|
148
|
+
id: update.id,
|
|
149
|
+
kind: update.kind ?? 'other',
|
|
150
|
+
label: update.label ?? 'Usage',
|
|
151
|
+
used: update.used,
|
|
152
|
+
resetsAt: update.resetsAt ?? null,
|
|
153
|
+
durationMs: update.durationMs ?? null
|
|
154
|
+
});
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
merged[at] = { ...merged[at], ...update };
|
|
158
|
+
}
|
|
159
|
+
return merged;
|
|
160
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { UsageLimitsProvider } from '@adecore/agent-contracts';
|
|
2
|
+
import { type SpawnChatProcess } from '../../chat/chat-process.ts';
|
|
3
|
+
import { type CodexClientInfo } from '../../chat/codex-transport.ts';
|
|
4
|
+
import { type ProviderReading } from './normalize.ts';
|
|
5
|
+
export type ProbeResult = ProviderReading | {
|
|
6
|
+
unavailable: UsageLimitsProvider['unavailable'];
|
|
7
|
+
};
|
|
8
|
+
export declare function probeClaude(command: readonly string[], env: Record<string, string>, spawn?: SpawnChatProcess): Promise<ProbeResult>;
|
|
9
|
+
export declare function probeCodex(command: readonly string[], env: Record<string, string>, client?: CodexClientInfo): Promise<ProbeResult>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { withTimeout } from '../../async.js';
|
|
2
|
+
import { spawnChatProcess } from '../../chat/chat-process.js';
|
|
3
|
+
import { CodexTransport, DEFAULT_CODEX_CLIENT } from '../../chat/codex-transport.js';
|
|
4
|
+
import { readClaudeUsage, readCodexLimits } from './normalize.js';
|
|
5
|
+
import { errorText } from '../../error-text.js';
|
|
6
|
+
/* A CLI that has not answered by now is not going to; the next pass tries again. */
|
|
7
|
+
const PROBE_TIMEOUT_MS = 20_000;
|
|
8
|
+
const CODEX_READ_TIMEOUT_MS = 3_000;
|
|
9
|
+
function failure(message) {
|
|
10
|
+
return { unavailable: { reason: 'failed', message } };
|
|
11
|
+
}
|
|
12
|
+
function timeoutOf(work, ms, what) {
|
|
13
|
+
return withTimeout(work, ms, `${what} did not answer in time`);
|
|
14
|
+
}
|
|
15
|
+
/*
|
|
16
|
+
* Asks Claude Code what is left of the plan, without a turn and without a token of our own. A
|
|
17
|
+
* `claude -p` on the stream-json protocol answers `get_usage` before any prompt, but only once it
|
|
18
|
+
* has been initialized: without that first control request the process waits and says nothing.
|
|
19
|
+
*/
|
|
20
|
+
export async function probeClaude(command, env, spawn = spawnChatProcess) {
|
|
21
|
+
let child;
|
|
22
|
+
try {
|
|
23
|
+
child = spawn({
|
|
24
|
+
command: [...command, '-p', '--input-format', 'stream-json', '--output-format', 'stream-json', '--verbose'],
|
|
25
|
+
cwd: process.cwd(),
|
|
26
|
+
env,
|
|
27
|
+
onExit: () => undefined
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
return failure(errorText(error));
|
|
32
|
+
}
|
|
33
|
+
const write = (frame) => {
|
|
34
|
+
child.stdin.write(`${JSON.stringify(frame)}\n`);
|
|
35
|
+
child.stdin.flush();
|
|
36
|
+
};
|
|
37
|
+
const read = async () => {
|
|
38
|
+
write({ type: 'control_request', request_id: 'probe-init', request: { subtype: 'initialize', hooks: {} } });
|
|
39
|
+
let asked = false;
|
|
40
|
+
let buffer = '';
|
|
41
|
+
const decoder = new TextDecoder();
|
|
42
|
+
for await (const chunk of child.stdout) {
|
|
43
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
44
|
+
let at = buffer.indexOf('\n');
|
|
45
|
+
for (; at !== -1; at = buffer.indexOf('\n')) {
|
|
46
|
+
const line = buffer.slice(0, at);
|
|
47
|
+
buffer = buffer.slice(at + 1);
|
|
48
|
+
let frame;
|
|
49
|
+
try {
|
|
50
|
+
frame = JSON.parse(line);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (typeof frame !== 'object' || frame === null) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const envelope = frame;
|
|
59
|
+
if (envelope.type !== 'control_response') {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (!asked) {
|
|
63
|
+
asked = true;
|
|
64
|
+
write({ type: 'control_request', request_id: 'probe-usage', request: { subtype: 'get_usage' } });
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (envelope.response?.subtype === 'error') {
|
|
68
|
+
return failure('Claude Code refused to report its usage');
|
|
69
|
+
}
|
|
70
|
+
return readClaudeUsage(envelope.response?.response ?? envelope.response);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return failure('Claude Code closed without reporting its usage');
|
|
74
|
+
};
|
|
75
|
+
try {
|
|
76
|
+
return await timeoutOf(read(), PROBE_TIMEOUT_MS, 'Claude Code');
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return failure(errorText(error));
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
child.stdin.end();
|
|
83
|
+
child.kill('SIGTERM');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/* The same question to Codex: the app-server answers it over JSON-RPC right after the handshake. */
|
|
87
|
+
export async function probeCodex(command, env, client = DEFAULT_CODEX_CLIENT) {
|
|
88
|
+
let transport = null;
|
|
89
|
+
try {
|
|
90
|
+
transport = new CodexTransport({
|
|
91
|
+
command: [...command],
|
|
92
|
+
cwd: process.cwd(),
|
|
93
|
+
env,
|
|
94
|
+
onFrame: () => undefined,
|
|
95
|
+
onExit: () => undefined
|
|
96
|
+
});
|
|
97
|
+
const open = transport;
|
|
98
|
+
await timeoutOf(open.request('initialize', { clientInfo: client, capabilities: { experimentalApi: true } }), PROBE_TIMEOUT_MS, 'Codex');
|
|
99
|
+
open.notify('initialized', {});
|
|
100
|
+
const answer = await timeoutOf(open.request('account/rateLimits/read', undefined), CODEX_READ_TIMEOUT_MS, 'Codex');
|
|
101
|
+
const snapshot = typeof answer === 'object' && answer !== null ? answer.rateLimits : null;
|
|
102
|
+
const reading = readCodexLimits(snapshot);
|
|
103
|
+
// An account on an API key has no plan windows; Codex answers, with nothing in it.
|
|
104
|
+
return reading ?? { unavailable: { reason: 'no-subscription', message: null } };
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return failure(errorText(error));
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
transport?.end();
|
|
111
|
+
transport?.kill();
|
|
112
|
+
}
|
|
113
|
+
}
|