@adecore/agents 0.31.4 → 0.31.6

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.
Files changed (45) hide show
  1. package/dist/chat/acp-backend.d.ts +7 -0
  2. package/dist/chat/acp-backend.js +87 -6
  3. package/dist/chat/acp-protocol.d.ts +6 -0
  4. package/dist/chat/acp-protocol.js +34 -9
  5. package/dist/providers/accounts/acp-account.d.ts +1 -0
  6. package/dist/providers/accounts/acp-account.js +25 -3
  7. package/dist/providers/acp-agent-state.d.ts +35 -0
  8. package/dist/providers/acp-agent-state.js +170 -0
  9. package/dist/providers/acp-provider.d.ts +2 -0
  10. package/dist/providers/acp-provider.js +29 -33
  11. package/dist/providers/catalog.d.ts +2 -0
  12. package/dist/providers/catalog.js +14 -4
  13. package/dist/providers/index.d.ts +1 -0
  14. package/dist/providers/index.js +1 -0
  15. package/dist/providers/provider.d.ts +1 -0
  16. package/dist/providers/registry.d.ts +1 -0
  17. package/dist/providers/registry.js +9 -0
  18. package/dist/testing/fake-acp.d.ts +3 -0
  19. package/dist/testing/fake-acp.js +11 -4
  20. package/dist/usage/aggregate.js +1 -1
  21. package/dist/usage/index-file.d.ts +2 -0
  22. package/dist/usage/index-file.js +19 -10
  23. package/dist/usage/pricing.d.ts +3 -2
  24. package/dist/usage/pricing.js +42 -8
  25. package/dist/usage/readers/codex.d.ts +9 -0
  26. package/dist/usage/readers/codex.js +75 -14
  27. package/dist/usage/record.d.ts +1 -0
  28. package/dist/usage/scanner.js +32 -8
  29. package/package.json +3 -3
  30. package/src/chat/acp-backend.ts +93 -5
  31. package/src/chat/acp-protocol.ts +41 -9
  32. package/src/providers/accounts/acp-account.ts +34 -3
  33. package/src/providers/acp-agent-state.ts +206 -0
  34. package/src/providers/acp-provider.ts +33 -37
  35. package/src/providers/catalog.ts +19 -5
  36. package/src/providers/index.ts +1 -0
  37. package/src/providers/provider.ts +2 -0
  38. package/src/providers/registry.ts +10 -0
  39. package/src/testing/fake-acp.ts +17 -4
  40. package/src/usage/aggregate.ts +1 -1
  41. package/src/usage/index-file.ts +25 -18
  42. package/src/usage/pricing.ts +46 -8
  43. package/src/usage/readers/codex.ts +86 -14
  44. package/src/usage/record.ts +1 -0
  45. package/src/usage/scanner.ts +35 -8
@@ -1,6 +1,7 @@
1
1
  import { createHash, type Hash } from 'node:crypto';
2
2
  import { mkdir, open, readFile, readdir, stat } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
+ import { zstdDecompressSync } from 'node:zlib';
4
5
  import type { UsageProvider, UsageRoot } from '@adecore/agent-contracts';
5
6
  import { errorText } from '../error-text.ts';
6
7
  import { isNotFound, writeAtomic } from '../fs.ts';
@@ -13,6 +14,7 @@ import { cloneCodexState, codexMightCarryUsage, createCodexState, parseCodexLine
13
14
  import { usageRoots, type UsageRootPath } from './roots.ts';
14
15
 
15
16
  const HASH_CHUNK_BYTES = 65536;
17
+ const CODEX_PARSER_VERSION = 2;
16
18
 
17
19
  interface HashedRead {
18
20
  /* Everything from `from` to the end of the file, as it is at the read. */
@@ -82,7 +84,7 @@ function readsWhole(provider: UsageProvider): boolean {
82
84
  }
83
85
 
84
86
  function isUsageFile(provider: UsageProvider, name: string): boolean {
85
- return readsWhole(provider) ? name === GROK_USAGE_FILE : name.endsWith('.jsonl');
87
+ return readsWhole(provider) ? name === GROK_USAGE_FILE : name.endsWith('.jsonl') || (provider === 'codex' && name.endsWith('.jsonl.zst'));
86
88
  }
87
89
 
88
90
  async function listUsageFiles(dir: string, provider: UsageProvider, out: string[] = []): Promise<string[]> {
@@ -255,7 +257,12 @@ export class UsageScanner {
255
257
  }
256
258
  let failure: string | null = null;
257
259
  const accountOf = accountResolver(root, sessionAccounts);
258
- for (const path of await listUsageFiles(root.path, root.provider)) {
260
+ const paths = await listUsageFiles(root.path, root.provider);
261
+ const plain = new Set(paths);
262
+ for (const path of paths) {
263
+ if (root.provider === 'codex' && path.endsWith('.jsonl.zst') && plain.has(path.slice(0, -4))) {
264
+ continue;
265
+ }
259
266
  files += 1;
260
267
  try {
261
268
  if (await this.readFileInto(path, root.provider, accountOf)) {
@@ -288,15 +295,34 @@ export class UsageScanner {
288
295
 
289
296
  private async readFileInto(path: string, provider: UsageProvider, accountOf: AccountOf): Promise<boolean> {
290
297
  const info = await stat(path);
291
- const known = this.index.get(path);
292
- if (known !== undefined && known.provider === provider && known.size === info.size && known.mtimeMs === info.mtimeMs) {
298
+ const compressed = provider === 'codex' && path.endsWith('.jsonl.zst');
299
+ const key = compressed ? path.slice(0, -4) : path;
300
+ const known = this.index.get(key);
301
+ const currentParser = provider !== 'codex' || known?.parserVersion === CODEX_PARSER_VERSION;
302
+ if (
303
+ currentParser &&
304
+ known !== undefined &&
305
+ known.provider === provider &&
306
+ (known.compressed ?? false) === compressed &&
307
+ known.size === info.size &&
308
+ known.mtimeMs === info.mtimeMs
309
+ ) {
293
310
  return false;
294
311
  }
295
312
  if (readsWhole(provider)) {
296
313
  return this.readWholeInto(path, provider, accountOf, info);
297
314
  }
298
- const appended = known !== undefined && known.provider === provider && info.size > known.size && known.head?.startsWith('sha256:') === true;
299
- let read = await readHashed(path, appended ? known.offset : 0);
315
+ const appended =
316
+ !compressed &&
317
+ currentParser &&
318
+ known?.compressed !== true &&
319
+ known !== undefined &&
320
+ known.provider === provider &&
321
+ info.size > known.size &&
322
+ known.head?.startsWith('sha256:') === true;
323
+ let read = compressed
324
+ ? { bytes: zstdDecompressSync(await readFile(path)), hash: createHash('sha256') }
325
+ : await readHashed(path, appended ? known.offset : 0);
300
326
  // A file only counts as grown while it starts the way it did; one rewritten larger is read again from the start.
301
327
  const grown = appended && headOf(read.hash) === known.head;
302
328
  if (appended && !grown) {
@@ -315,9 +341,10 @@ export class UsageScanner {
315
341
  records: foldByKey([...before, ...withAccount(parsed.records, accountOf)]),
316
342
  tail: withAccount(parsed.tail, accountOf),
317
343
  codex: parsed.codex,
318
- head: headOf(read.hash)
344
+ head: headOf(read.hash),
345
+ ...(provider === 'codex' ? { parserVersion: CODEX_PARSER_VERSION, compressed } : {})
319
346
  };
320
- this.index.set(path, entry);
347
+ this.index.set(key, entry);
321
348
  this.dirty = true;
322
349
  return true;
323
350
  }