@adecore/agents 0.39.0 → 0.40.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/dist/async.d.ts +5 -0
- package/dist/async.js +13 -5
- package/dist/chat/acp-protocol.js +3 -5
- package/dist/chat/chat-core.js +0 -2
- package/dist/chat/chat-process.d.ts +1 -0
- package/dist/chat/chat-process.js +1 -1
- package/dist/chat/chat-session.js +6 -8
- package/dist/chat/claude-protocol.js +1 -6
- package/dist/chat/claude-transcript.js +1 -3
- package/dist/chat/codex-protocol.js +1 -6
- package/dist/chat/projector.js +1 -3
- package/dist/chat/request-summary.js +1 -3
- package/dist/coded-error.js +1 -5
- package/dist/context/argv.js +1 -2
- package/dist/context/verb.js +1 -3
- package/dist/error-text.d.ts +1 -0
- package/dist/error-text.js +4 -0
- package/dist/fields.d.ts +3 -0
- package/dist/fields.js +12 -0
- package/dist/fs.d.ts +1 -0
- package/dist/fs.js +8 -4
- package/dist/lineage.js +11 -5
- package/dist/messages/notice-store.js +3 -4
- package/dist/providers/accounts/acp-account.js +3 -20
- package/dist/providers/accounts/service.d.ts +1 -2
- package/dist/providers/accounts/service.js +5 -9
- package/dist/providers/accounts/status.js +1 -3
- package/dist/providers/acp-agent-state.js +1 -3
- package/dist/providers/claude.js +0 -1
- package/dist/providers/codex-models.json +3 -2
- package/dist/providers/codex.js +0 -1
- package/dist/providers/detect.js +1 -1
- package/dist/providers/shell-commands.js +1 -2
- package/dist/run-process.js +1 -3
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +5 -8
- package/dist/tasks/background-limit.js +3 -2
- package/dist/tasks/task-coordinator.js +11 -17
- package/dist/testing/watch.js +0 -1
- package/dist/usage/limits/monitor.js +1 -2
- package/dist/usage/prices-snapshot.json +8 -0
- package/dist/usage/readers/claude.js +3 -10
- package/dist/usage/readers/codex.js +2 -9
- package/dist/usage/readers/grok.js +3 -10
- package/dist/usage/readers/host-log.js +3 -10
- package/dist/usage/record.d.ts +2 -0
- package/dist/usage/record.js +13 -0
- package/package.json +6 -6
- package/src/async.ts +23 -5
- package/src/chat/acp-backend.ts +121 -0
- package/src/chat/acp-protocol.ts +172 -6
- package/src/chat/attachment-store.ts +21 -0
- package/src/chat/backend.ts +0 -2
- package/src/chat/bookmark-store.ts +23 -0
- package/src/chat/chat-core.ts +208 -7
- package/src/chat/chat-log.ts +19 -0
- package/src/chat/chat-process.ts +52 -1
- package/src/chat/chat-session.ts +401 -10
- package/src/chat/chat-store.ts +50 -0
- package/src/chat/chat-title.ts +9 -0
- package/src/chat/claude-backend.ts +50 -0
- package/src/chat/claude-protocol.ts +155 -8
- package/src/chat/claude-title.ts +10 -0
- package/src/chat/claude-transcript.ts +47 -4
- package/src/chat/codex-backend.ts +131 -0
- package/src/chat/codex-protocol.ts +180 -8
- package/src/chat/codex-thread.ts +23 -0
- package/src/chat/composer-preferences.ts +6 -0
- package/src/chat/context-breakdown.ts +11 -0
- package/src/chat/delta-coalescer.ts +8 -0
- package/src/chat/external-sessions.ts +28 -0
- package/src/chat/generated-image.ts +25 -0
- package/src/chat/index.ts +5 -0
- package/src/chat/input.ts +13 -0
- package/src/chat/json-rpc-transport.ts +28 -0
- package/src/chat/limit-resume.ts +13 -0
- package/src/chat/projector.ts +160 -4
- package/src/chat/readable-text.ts +3 -0
- package/src/chat/request-summary.ts +18 -4
- package/src/chat/subagent-projection.ts +3 -0
- package/src/chat/subagent-reader.ts +76 -0
- package/src/chat/subagent-settlement.ts +24 -0
- package/src/chat/thread-search.ts +13 -0
- package/src/chat/thread.ts +31 -0
- package/src/chat/ui-queries.ts +122 -0
- package/src/chat/ui-replies.ts +34 -0
- package/src/chat/visual-store.ts +49 -0
- package/src/chat/wake-chat.ts +3 -0
- package/src/client-sinks.ts +2 -0
- package/src/coded-error.ts +1 -5
- package/src/context/argv.ts +18 -2
- package/src/context/index.ts +1 -0
- package/src/context/refusal.ts +3 -0
- package/src/context/verb.ts +32 -4
- package/src/coordination/index.ts +10 -0
- package/src/error-text.ts +7 -0
- package/src/fields.ts +14 -0
- package/src/fs.ts +20 -4
- package/src/host/agent-host.ts +20 -0
- package/src/host/environment.ts +6 -0
- package/src/host/handlers.ts +18 -0
- package/src/host/memory-port.ts +4 -0
- package/src/host/wiring.ts +10 -0
- package/src/index.ts +1 -0
- package/src/lineage.ts +24 -5
- package/src/messages/deliver-message.ts +6 -0
- package/src/messages/deliver-notice.ts +13 -0
- package/src/messages/notice-store.ts +16 -4
- package/src/modes.ts +1 -0
- package/src/outbox/outbox-worker.ts +31 -0
- package/src/outbox/outbox.ts +5 -0
- package/src/providers/accounts/accounts.ts +36 -0
- package/src/providers/accounts/acp-account.ts +22 -27
- package/src/providers/accounts/launch.ts +4 -0
- package/src/providers/accounts/service.ts +110 -12
- package/src/providers/accounts/shadow-home.ts +10 -0
- package/src/providers/accounts/status.ts +13 -4
- package/src/providers/accounts/store.ts +25 -0
- package/src/providers/accounts/variables.ts +11 -1
- package/src/providers/acp-agent-state.ts +24 -3
- package/src/providers/acp-provider.ts +5 -0
- package/src/providers/acp-usage-log.ts +2 -0
- package/src/providers/catalog.ts +17 -0
- package/src/providers/claude.ts +10 -1
- package/src/providers/codex-models.json +3 -2
- package/src/providers/codex-rules.ts +3 -0
- package/src/providers/codex.ts +2 -1
- package/src/providers/detect.ts +6 -1
- package/src/providers/provider.ts +1 -1
- package/src/providers/registry.ts +18 -2
- package/src/providers/shell-commands.ts +37 -2
- package/src/record-directory.ts +19 -0
- package/src/run-process.ts +24 -3
- package/src/serializer.ts +3 -0
- package/src/skills.ts +73 -10
- package/src/tasks/background-limit.ts +9 -2
- package/src/tasks/end-children.ts +9 -0
- package/src/tasks/give-task.ts +8 -0
- package/src/tasks/task-coordinator.ts +81 -17
- package/src/tasks/task-store.ts +28 -0
- package/src/tasks/waiting-child.ts +21 -0
- package/src/tasks/wake-parent.ts +26 -0
- package/src/tasks/wiring.ts +22 -0
- package/src/testing/accounts.ts +2 -0
- package/src/testing/fake-acp-capture.ts +16 -0
- package/src/testing/fake-acp.ts +66 -0
- package/src/testing/fake-claude.ts +177 -0
- package/src/testing/fake-cli.ts +29 -0
- package/src/testing/fake-codex.ts +122 -0
- package/src/testing/manual-clock.ts +2 -0
- package/src/testing/watch.ts +7 -1
- package/src/title-file.ts +12 -0
- package/src/usage/accounts.ts +6 -0
- package/src/usage/aggregate.ts +19 -0
- package/src/usage/exchange.ts +12 -0
- package/src/usage/index-file.ts +27 -0
- package/src/usage/limits/monitor.ts +31 -3
- package/src/usage/limits/normalize.ts +30 -0
- package/src/usage/limits/probe.ts +17 -0
- package/src/usage/prices-snapshot.json +8 -0
- package/src/usage/pricing.ts +35 -0
- package/src/usage/projects.ts +8 -0
- package/src/usage/readers/claude.ts +12 -9
- package/src/usage/readers/codex.ts +40 -8
- package/src/usage/readers/grok.ts +17 -9
- package/src/usage/readers/host-log.ts +9 -9
- package/src/usage/record.ts +22 -0
- package/src/usage/roots.ts +6 -0
- package/src/usage/scanner.ts +61 -0
- package/src/usage/usage-service.ts +14 -0
- package/src/watch-seam.ts +8 -0
- package/src/windows-command.ts +12 -0
package/dist/run-process.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { killProcessTree } from './chat/chat-process.js';
|
|
2
|
+
import { KILL_GRACE_MS, killProcessTree } from './chat/chat-process.js';
|
|
3
3
|
import { spawnTarget } from './windows-command.js';
|
|
4
|
-
// What a command and everything it started get between the SIGTERM and the SIGKILL.
|
|
5
|
-
const KILL_GRACE_MS = 2000;
|
|
6
4
|
// Stdout and stderr together; a short command that prints more is ended and fails instead of filling memory.
|
|
7
5
|
const MAX_OUTPUT_BYTES = 16 * 1024 * 1024;
|
|
8
6
|
/* One short command to its end, with what it printed. A command that cannot start rejects. */
|
package/dist/skills.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface SkillRootOptions {
|
|
|
17
17
|
export declare function parseFrontmatter(text: string): Record<string, string>;
|
|
18
18
|
export declare function pluginSkillRoots(configDir: string): Promise<SkillRoot[]>;
|
|
19
19
|
export declare function skillRootsFor(kind: AgentKind, cwd: string, options?: SkillRootOptions): Promise<SkillRoot[]>;
|
|
20
|
-
export declare function whileBusy<T>(operation: () => Promise<T>,
|
|
20
|
+
export declare function whileBusy<T>(operation: () => Promise<T>, sleep?: (ms: number) => Promise<void>): Promise<T>;
|
|
21
21
|
export declare function mapLimited<T, R>(items: readonly T[], limit: number, work: (item: T) => Promise<R>): Promise<R[]>;
|
|
22
22
|
export declare function scanSkillRoots(roots: SkillRoot[], limits?: SkillScanLimits): Promise<ChatSkill[]>;
|
|
23
23
|
export declare function discoverSkills(kind: AgentKind, cwd: string, options?: SkillRootOptions): Promise<ChatSkill[]>;
|
package/dist/skills.js
CHANGED
|
@@ -2,7 +2,8 @@ import { existsSync } from 'node:fs';
|
|
|
2
2
|
import { open, readdir, readFile, realpath, stat } from 'node:fs/promises';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { dirname, join, parse } from 'node:path';
|
|
5
|
-
import {
|
|
5
|
+
import { wait } from './async.js';
|
|
6
|
+
import { hasErrorCode, isNotFound } from './fs.js';
|
|
6
7
|
const SCAN_LIMITS = { directories: 2000, skills: 1000 };
|
|
7
8
|
const ENTRIES_PER_FOLDER = 1000;
|
|
8
9
|
// Paths one folder resolves or reads at once, so a large folder never runs the process out of file handles.
|
|
@@ -143,13 +144,10 @@ export async function skillRootsFor(kind, cwd, options = {}) {
|
|
|
143
144
|
}
|
|
144
145
|
/* Too many files open, in this process or on the system: it says nothing about the path that was asked for. */
|
|
145
146
|
function isBusy(e) {
|
|
146
|
-
return
|
|
147
|
-
}
|
|
148
|
-
function sleep(ms) {
|
|
149
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
147
|
+
return hasErrorCode(e, 'EMFILE', 'ENFILE');
|
|
150
148
|
}
|
|
151
149
|
/* Runs `operation` again a few times while the process is short of file handles, and throws if it still is. */
|
|
152
|
-
export async function whileBusy(operation,
|
|
150
|
+
export async function whileBusy(operation, sleep = wait) {
|
|
153
151
|
for (let attempt = 1;; attempt++) {
|
|
154
152
|
try {
|
|
155
153
|
return await operation();
|
|
@@ -158,7 +156,7 @@ export async function whileBusy(operation, wait = sleep) {
|
|
|
158
156
|
if (!isBusy(e) || attempt > BUSY_RETRIES) {
|
|
159
157
|
throw e;
|
|
160
158
|
}
|
|
161
|
-
await
|
|
159
|
+
await sleep(BUSY_RETRY_MS * attempt);
|
|
162
160
|
}
|
|
163
161
|
}
|
|
164
162
|
}
|
|
@@ -310,7 +308,6 @@ export async function scanSkillRoots(roots, limits = SCAN_LIMITS) {
|
|
|
310
308
|
export async function discoverSkills(kind, cwd, options = {}) {
|
|
311
309
|
return scanSkillRoots(await skillRootsFor(kind, cwd, options));
|
|
312
310
|
}
|
|
313
|
-
// How long a scan stays good; a skill written mid-session shows up on the next look.
|
|
314
311
|
const CACHE_TTL_MS = 30_000;
|
|
315
312
|
/* The skills of one CLI in one folder, scanned at most once per half minute. There is no watcher. */
|
|
316
313
|
export class SkillIndex {
|
|
@@ -41,12 +41,13 @@ export async function restartBackgroundLimits(outbox, now) {
|
|
|
41
41
|
}
|
|
42
42
|
/* The `background-limit` entries of a host's outbox, one per task at most, as the coordinator owes and drops them. */
|
|
43
43
|
export function backgroundLimits(outbox) {
|
|
44
|
+
const limitOf = (entry, taskId) => isBackgroundLimit(entry) && entry.payload.taskId === taskId;
|
|
44
45
|
return {
|
|
45
|
-
owed: (taskId) => outbox.list().some((entry) =>
|
|
46
|
+
owed: (taskId) => outbox.list().some((entry) => limitOf(entry, taskId)),
|
|
46
47
|
owe: (task, commands, at) => outbox.enqueue(task.projectId, task.childId, { kind: 'background-limit', payload: { taskId: task.id, commands: [...commands] } }, at),
|
|
47
48
|
lapse: async (taskId) => {
|
|
48
49
|
for (const entry of outbox.list()) {
|
|
49
|
-
if (
|
|
50
|
+
if (limitOf(entry, taskId)) {
|
|
50
51
|
await outbox.remove(entry.id);
|
|
51
52
|
}
|
|
52
53
|
}
|
|
@@ -52,11 +52,9 @@ export function resultOfTurn(turn, items, at) {
|
|
|
52
52
|
/*
|
|
53
53
|
* Settles tasks from what children do and does nothing else: it writes the task store and owes wakes
|
|
54
54
|
* in the outbox, never starts a turn, since it runs inside the broadcast of the child it heard. A chat
|
|
55
|
-
* child settles when a turn ends with
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* an agent that is not a chat, which the host tells it about, settles only on `done`, or fails when it
|
|
59
|
-
* ends without one.
|
|
55
|
+
* child settles when a turn ends with no task of its own open or waiting to wake it, no active goal and
|
|
56
|
+
* no background work running, or once its background commands outlast their limit. An agent that is
|
|
57
|
+
* not a chat settles only on `done`, or fails when it ends without one.
|
|
60
58
|
*/
|
|
61
59
|
export class TaskCoordinator {
|
|
62
60
|
deps;
|
|
@@ -114,14 +112,9 @@ export class TaskCoordinator {
|
|
|
114
112
|
* which says how that kind of agent reports back.
|
|
115
113
|
*/
|
|
116
114
|
agentEnded(childId, text) {
|
|
117
|
-
if (this.
|
|
118
|
-
|
|
115
|
+
if (this.deps.placed(childId)) {
|
|
116
|
+
this.failed(childId, text);
|
|
119
117
|
}
|
|
120
|
-
const task = this.localTask(childId);
|
|
121
|
-
if (!task || !this.deps.placed(childId)) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
this.settle(task, 'failed', { text, source: 'exit', at: this.deps.now() });
|
|
125
118
|
}
|
|
126
119
|
startFailed(childId, error) {
|
|
127
120
|
this.failed(childId, `The agent could not be started: ${errorText(error)}`);
|
|
@@ -183,7 +176,7 @@ export class TaskCoordinator {
|
|
|
183
176
|
* gets a turn of its own that names it; the turn that was in its way answers the person who sent it,
|
|
184
177
|
* not the task, and nothing settles while that turn is still owed. A turn after it answers too, as the
|
|
185
178
|
* one the CLI opens about work that turn left running. A child opened with its task has no turn of that
|
|
186
|
-
* kind, so its first turn settles it
|
|
179
|
+
* kind, so its first turn settles it.
|
|
187
180
|
*/
|
|
188
181
|
answers(items, turn, task) {
|
|
189
182
|
if ((turn.taskIds ?? []).includes(task.id)) {
|
|
@@ -216,7 +209,7 @@ export class TaskCoordinator {
|
|
|
216
209
|
this.settle(task, 'failed', { ...result, text: `${result.text}\n\n${goalLostNote(goal.objective)}`, source: 'exit' });
|
|
217
210
|
return;
|
|
218
211
|
}
|
|
219
|
-
// A turn a person stopped or that failed ends the task
|
|
212
|
+
// A turn a person stopped or that failed ends the task, whatever still runs beside it.
|
|
220
213
|
if (turn.state === 'done' && this.heldInBackground(chatId, task, items)) {
|
|
221
214
|
this.track(this.deps.tasks.holdBackground(task.id, {
|
|
222
215
|
turnId: turn.id,
|
|
@@ -247,13 +240,14 @@ export class TaskCoordinator {
|
|
|
247
240
|
if (background.itemIds.length === 0 && this.deps.limit.owed(task.id)) {
|
|
248
241
|
return;
|
|
249
242
|
}
|
|
243
|
+
const rowOf = (id) => items.find((item) => item.id === id);
|
|
250
244
|
const lost = background.itemIds.filter((id) => {
|
|
251
|
-
const item =
|
|
245
|
+
const item = rowOf(id);
|
|
252
246
|
return !item || (item.kind === 'subagent' ? item.status !== 'done' : item.kind !== 'tool' || item.state !== 'done');
|
|
253
247
|
});
|
|
254
248
|
if (lost.length > 0 || background.commands.length > 0) {
|
|
255
249
|
const names = lost.map((id) => {
|
|
256
|
-
const row =
|
|
250
|
+
const row = rowOf(id);
|
|
257
251
|
return row?.kind === 'subagent' ? row.description || row.toolUseId : row?.kind === 'tool' ? row.name : id;
|
|
258
252
|
});
|
|
259
253
|
this.settle(task, 'failed', {
|
|
@@ -264,7 +258,7 @@ export class TaskCoordinator {
|
|
|
264
258
|
return;
|
|
265
259
|
}
|
|
266
260
|
const reports = background.itemIds.flatMap((id) => {
|
|
267
|
-
const row =
|
|
261
|
+
const row = rowOf(id);
|
|
268
262
|
const report = row?.kind === 'subagent' ? row.result : row?.kind === 'tool' ? row.output : null;
|
|
269
263
|
return report ? [report] : [];
|
|
270
264
|
});
|
package/dist/testing/watch.js
CHANGED
|
@@ -193,7 +193,6 @@ export class UsageMonitor {
|
|
|
193
193
|
return this.probe(account.kind, this.registry.get(account.kind).command, env);
|
|
194
194
|
}
|
|
195
195
|
emit() {
|
|
196
|
-
|
|
197
|
-
this.sinks.emit(event);
|
|
196
|
+
this.sinks.emit({ event: 'usage.limitsChanged', payload: this.snapshot() });
|
|
198
197
|
}
|
|
199
198
|
}
|
|
@@ -648,6 +648,14 @@
|
|
|
648
648
|
"cache_read_input_token_cost": 1e-7,
|
|
649
649
|
"cache_creation_input_token_cost": 0.0000025
|
|
650
650
|
},
|
|
651
|
+
"gpt-6.1-terra": {
|
|
652
|
+
"litellm_provider": "openai",
|
|
653
|
+
"mode": "chat",
|
|
654
|
+
"input_cost_per_token": 0.000001,
|
|
655
|
+
"output_cost_per_token": 0.000005,
|
|
656
|
+
"cache_read_input_token_cost": 5e-8,
|
|
657
|
+
"cache_creation_input_token_cost": 0.00000125
|
|
658
|
+
},
|
|
651
659
|
"gpt-6-luna": {
|
|
652
660
|
"litellm_provider": "openai",
|
|
653
661
|
"mode": "responses",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { asObject, asString, int } from '../record.js';
|
|
1
|
+
import { asObject, asString, countsTokens, int, parseObject } from '../record.js';
|
|
2
2
|
/* Only a line with this in it can carry counts, which keeps `JSON.parse` off about two thirds of them. */
|
|
3
3
|
export function claudeMightCarryUsage(line) {
|
|
4
4
|
return line.includes('"usage"');
|
|
@@ -9,14 +9,7 @@ export function claudeMightCarryUsage(line) {
|
|
|
9
9
|
* Anthropic's, so `input_tokens` already excludes what was read from or written to the cache.
|
|
10
10
|
*/
|
|
11
11
|
export function parseClaudeLine(line) {
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
parsed = JSON.parse(line);
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
const record = asObject(parsed);
|
|
12
|
+
const record = parseObject(line);
|
|
20
13
|
if (record === null || record.type !== 'assistant') {
|
|
21
14
|
return null;
|
|
22
15
|
}
|
|
@@ -44,7 +37,7 @@ export function parseClaudeLine(line) {
|
|
|
44
37
|
output: int(usage.output_tokens),
|
|
45
38
|
reasoning: outputDetails === null ? 0 : int(outputDetails.thinking_tokens)
|
|
46
39
|
};
|
|
47
|
-
if (totals
|
|
40
|
+
if (!countsTokens(totals)) {
|
|
48
41
|
return null;
|
|
49
42
|
}
|
|
50
43
|
return {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { asObject, asString, int } from '../record.js';
|
|
1
|
+
import { asObject, asString, int, parseObject } from '../record.js';
|
|
2
2
|
export function codexMightCarryUsage(line) {
|
|
3
3
|
return ['token_count', 'turn_context', 'session_meta', 'thread_settings_applied', 'token_usage_record', 'compacted'].some((type) => line.includes(type));
|
|
4
4
|
}
|
|
@@ -59,14 +59,7 @@ export function isForkOrSubagent(payload) {
|
|
|
59
59
|
/* Codex includes cache reads and writes in input_tokens. Compaction can appear separately from
|
|
60
60
|
cumulative token_count events, so response identities prevent charging the same request twice. */
|
|
61
61
|
export function parseCodexLine(line, state) {
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
parsed = JSON.parse(line);
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
const record = asObject(parsed);
|
|
62
|
+
const record = parseObject(line);
|
|
70
63
|
const payload = record === null ? null : asObject(record.payload);
|
|
71
64
|
if (record === null || payload === null) {
|
|
72
65
|
return null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { basename, dirname } from 'node:path';
|
|
2
|
-
import { asObject, asString, int } from '../record.js';
|
|
2
|
+
import { asObject, asString, countsTokens, int, parseObject } from '../record.js';
|
|
3
3
|
/* The file Grok keeps the counts of a session in, beside its other files in the session's folder. */
|
|
4
4
|
export const GROK_USAGE_FILE = 'usage.json';
|
|
5
5
|
// `costUsdTicks` counts in ticks of 10^-10 USD, as Grok's own docs on `grok usage` say.
|
|
@@ -26,7 +26,7 @@ function recordOf(counts, model, base, turn) {
|
|
|
26
26
|
output: int(counts.outputTokens),
|
|
27
27
|
reasoning: int(counts.reasoningTokens)
|
|
28
28
|
};
|
|
29
|
-
if (totals
|
|
29
|
+
if (!countsTokens(totals)) {
|
|
30
30
|
return null;
|
|
31
31
|
}
|
|
32
32
|
const ticks = int(counts.costUsdTicks);
|
|
@@ -45,14 +45,7 @@ function recordOf(counts, model, base, turn) {
|
|
|
45
45
|
* read as one, which leaves what the scanner held of it.
|
|
46
46
|
*/
|
|
47
47
|
export function parseGrokUsage(text, path) {
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
parsed = JSON.parse(text);
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
const file = asObject(parsed);
|
|
48
|
+
const file = parseObject(text);
|
|
56
49
|
if (file === null || !Array.isArray(file.turns)) {
|
|
57
50
|
return null;
|
|
58
51
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { asString, countsTokens, int, parseObject } from '../record.js';
|
|
2
2
|
export function hostUsageLine(entry) {
|
|
3
3
|
return `${JSON.stringify(entry)}\n`;
|
|
4
4
|
}
|
|
@@ -8,14 +8,7 @@ export function hostLogMightCarryUsage(line) {
|
|
|
8
8
|
}
|
|
9
9
|
/* The provider is the root's, so one reader serves every API a host logs. */
|
|
10
10
|
export function parseHostUsageLine(line, provider) {
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
parsed = JSON.parse(line);
|
|
14
|
-
}
|
|
15
|
-
catch {
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
const entry = asObject(parsed);
|
|
11
|
+
const entry = parseObject(line);
|
|
19
12
|
if (entry === null) {
|
|
20
13
|
return null;
|
|
21
14
|
}
|
|
@@ -33,7 +26,7 @@ export function parseHostUsageLine(line, provider) {
|
|
|
33
26
|
output: int(entry.output),
|
|
34
27
|
reasoning: int(entry.reasoning)
|
|
35
28
|
};
|
|
36
|
-
if (totals
|
|
29
|
+
if (!countsTokens(totals)) {
|
|
37
30
|
return null;
|
|
38
31
|
}
|
|
39
32
|
return {
|
package/dist/usage/record.d.ts
CHANGED
|
@@ -13,5 +13,7 @@ export interface UsageRecord {
|
|
|
13
13
|
}
|
|
14
14
|
export declare function int(value: unknown): number;
|
|
15
15
|
export declare function asObject(value: unknown): Record<string, unknown> | null;
|
|
16
|
+
export declare function parseObject(text: string): Record<string, unknown> | null;
|
|
17
|
+
export declare function countsTokens(totals: UsageTotals): boolean;
|
|
16
18
|
export declare function asString(value: unknown): string;
|
|
17
19
|
export declare function foldByKey(records: readonly UsageRecord[]): UsageRecord[];
|
package/dist/usage/record.js
CHANGED
|
@@ -6,6 +6,19 @@ export function int(value) {
|
|
|
6
6
|
export function asObject(value) {
|
|
7
7
|
return typeof value === 'object' && value !== null ? value : null;
|
|
8
8
|
}
|
|
9
|
+
/* A line or file of a transcript as a JSON object, or null for anything else. */
|
|
10
|
+
export function parseObject(text) {
|
|
11
|
+
try {
|
|
12
|
+
return asObject(JSON.parse(text));
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/* Whether a call moved any tokens at all; one that moved none is not a call worth a record. */
|
|
19
|
+
export function countsTokens(totals) {
|
|
20
|
+
return totals.input + totals.cacheRead + totals.cacheWrite + totals.output !== 0;
|
|
21
|
+
}
|
|
9
22
|
export function asString(value) {
|
|
10
23
|
return typeof value === 'string' ? value : '';
|
|
11
24
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adecore/agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.1",
|
|
4
4
|
"description": "Node-compatible agent chat hosts, providers, accounts, usage and durable task coordination.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -81,13 +81,13 @@
|
|
|
81
81
|
"test": "bun --conditions=source test"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@adecore/agent-contracts": "0.
|
|
85
|
-
"@adecore/intelligent-ui": "0.
|
|
86
|
-
"zod": "^4.6.
|
|
84
|
+
"@adecore/agent-contracts": "0.40.1",
|
|
85
|
+
"@adecore/intelligent-ui": "0.40.1",
|
|
86
|
+
"zod": "^4.6.7"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
|
-
"@types/bun": "^1.4.
|
|
90
|
-
"@types/node": "^26.6.
|
|
89
|
+
"@types/bun": "^1.4.4",
|
|
90
|
+
"@types/node": "^26.6.5",
|
|
91
91
|
"typescript": "^7.0.2"
|
|
92
92
|
},
|
|
93
93
|
"license": "FSL-1.1-MIT",
|
package/src/async.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { asError } from './error-text.ts';
|
|
2
|
+
|
|
1
3
|
/*
|
|
2
4
|
* Resolves after `ms`, or at once when the signal is raised. An abort resolves instead of rejecting:
|
|
3
5
|
* every caller is a loop that checks the signal itself on its next turn.
|
|
@@ -5,6 +7,7 @@
|
|
|
5
7
|
export function wait(ms: number, signal?: AbortSignal): Promise<void> {
|
|
6
8
|
return new Promise((resolve) => {
|
|
7
9
|
const timer = setTimeout(resolve, ms);
|
|
10
|
+
|
|
8
11
|
signal?.addEventListener(
|
|
9
12
|
'abort',
|
|
10
13
|
() => {
|
|
@@ -16,19 +19,34 @@ export function wait(ms: number, signal?: AbortSignal): Promise<void> {
|
|
|
16
19
|
});
|
|
17
20
|
}
|
|
18
21
|
|
|
22
|
+
export interface DeadlineTimer {
|
|
23
|
+
setTimeout(run: () => void, ms: number): unknown;
|
|
24
|
+
clearTimeout(handle: unknown): void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const SYSTEM_TIMER: DeadlineTimer = {
|
|
28
|
+
setTimeout: (run, ms) => setTimeout(run, ms),
|
|
29
|
+
clearTimeout: (handle) => clearTimeout(handle as ReturnType<typeof setTimeout>)
|
|
30
|
+
};
|
|
31
|
+
|
|
19
32
|
/* The timer is cleared either way, so a call that answers at once does not hold the process until its deadline. */
|
|
20
|
-
export function
|
|
33
|
+
export function withDeadline<T>(promise: Promise<T>, ms: number, message: string, timer: DeadlineTimer = SYSTEM_TIMER): Promise<T> {
|
|
21
34
|
return new Promise((resolve, reject) => {
|
|
22
|
-
const
|
|
35
|
+
const handle = timer.setTimeout(() => reject(new Error(message)), ms);
|
|
36
|
+
|
|
23
37
|
promise.then(
|
|
24
38
|
(value) => {
|
|
25
|
-
clearTimeout(
|
|
39
|
+
timer.clearTimeout(handle);
|
|
26
40
|
resolve(value);
|
|
27
41
|
},
|
|
28
42
|
(e: unknown) => {
|
|
29
|
-
clearTimeout(
|
|
30
|
-
reject(
|
|
43
|
+
timer.clearTimeout(handle);
|
|
44
|
+
reject(asError(e));
|
|
31
45
|
}
|
|
32
46
|
);
|
|
33
47
|
});
|
|
34
48
|
}
|
|
49
|
+
|
|
50
|
+
export function withTimeout<T>(promise: Promise<T>, ms: number, message: string): Promise<T> {
|
|
51
|
+
return withDeadline(promise, ms, message);
|
|
52
|
+
}
|