@openagentsy/ledger 0.0.0-stage → 0.2.0
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 +674 -0
- package/README.md +20 -2
- package/data/pricing/litellm.json +8882 -0
- package/data/pricing/models.dev.json +12151 -0
- package/data/pricing/openrouter.json +1017 -0
- package/dist/db.d.ts +44 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +97 -0
- package/dist/db.js.map +1 -0
- package/dist/export.d.ts +71 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +78 -0
- package/dist/export.js.map +1 -0
- package/dist/footprint.d.ts +24 -0
- package/dist/footprint.d.ts.map +1 -0
- package/dist/footprint.js +33 -0
- package/dist/footprint.js.map +1 -0
- package/dist/git.d.ts +44 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +126 -0
- package/dist/git.js.map +1 -0
- package/dist/git.test.d.ts +2 -0
- package/dist/git.test.d.ts.map +1 -0
- package/dist/git.test.js +101 -0
- package/dist/git.test.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest.d.ts +133 -0
- package/dist/ingest.d.ts.map +1 -0
- package/dist/ingest.js +324 -0
- package/dist/ingest.js.map +1 -0
- package/dist/ingest.test.d.ts +2 -0
- package/dist/ingest.test.d.ts.map +1 -0
- package/dist/ingest.test.js +245 -0
- package/dist/ingest.test.js.map +1 -0
- package/dist/outcomes.d.ts +81 -0
- package/dist/outcomes.d.ts.map +1 -0
- package/dist/outcomes.js +85 -0
- package/dist/outcomes.js.map +1 -0
- package/dist/outcomes.test.d.ts +2 -0
- package/dist/outcomes.test.d.ts.map +1 -0
- package/dist/outcomes.test.js +160 -0
- package/dist/outcomes.test.js.map +1 -0
- package/dist/policy.d.ts +48 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +99 -0
- package/dist/policy.js.map +1 -0
- package/dist/policy.test.d.ts +2 -0
- package/dist/policy.test.d.ts.map +1 -0
- package/dist/policy.test.js +126 -0
- package/dist/policy.test.js.map +1 -0
- package/dist/pricing.d.ts +92 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +341 -0
- package/dist/pricing.js.map +1 -0
- package/dist/pricing.test.d.ts +2 -0
- package/dist/pricing.test.d.ts.map +1 -0
- package/dist/pricing.test.js +167 -0
- package/dist/pricing.test.js.map +1 -0
- package/dist/query.d.ts +134 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +247 -0
- package/dist/query.js.map +1 -0
- package/dist/query.test.d.ts +2 -0
- package/dist/query.test.d.ts.map +1 -0
- package/dist/query.test.js +242 -0
- package/dist/query.test.js.map +1 -0
- package/dist/schema.d.ts +33 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +139 -0
- package/dist/schema.js.map +1 -0
- package/dist/schema.test.d.ts +2 -0
- package/dist/schema.test.d.ts.map +1 -0
- package/dist/schema.test.js +129 -0
- package/dist/schema.test.js.map +1 -0
- package/dist/waste.d.ts +116 -0
- package/dist/waste.d.ts.map +1 -0
- package/dist/waste.js +553 -0
- package/dist/waste.js.map +1 -0
- package/dist/waste.test.d.ts +2 -0
- package/dist/waste.test.d.ts.map +1 -0
- package/dist/waste.test.js +278 -0
- package/dist/waste.test.js.map +1 -0
- package/package.json +52 -4
package/dist/git.test.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { runGit } from './git.js';
|
|
6
|
+
let root;
|
|
7
|
+
beforeEach(async () => {
|
|
8
|
+
root = await mkdtemp(join(tmpdir(), 'openagentsy-git-'));
|
|
9
|
+
});
|
|
10
|
+
afterEach(async () => {
|
|
11
|
+
await rm(root, { recursive: true, force: true });
|
|
12
|
+
});
|
|
13
|
+
/**
|
|
14
|
+
* The variables that point a git command at a repository.
|
|
15
|
+
*
|
|
16
|
+
* A git that runs a hook sets them in the environment of the hook, and a
|
|
17
|
+
* command spawned inside that hook inherits them. The runner has to take
|
|
18
|
+
* them away, or the child writes to the repository of the hook.
|
|
19
|
+
*/
|
|
20
|
+
const REPOSITORY_VARS = [
|
|
21
|
+
'GIT_DIR',
|
|
22
|
+
'GIT_WORK_TREE',
|
|
23
|
+
'GIT_INDEX_FILE',
|
|
24
|
+
'GIT_COMMON_DIR',
|
|
25
|
+
'GIT_OBJECT_DIRECTORY',
|
|
26
|
+
'GIT_ALTERNATE_OBJECT_DIRECTORIES',
|
|
27
|
+
'GIT_CEILING_DIRECTORIES',
|
|
28
|
+
'GIT_PREFIX',
|
|
29
|
+
'GIT_NAMESPACE',
|
|
30
|
+
];
|
|
31
|
+
/** The environment as it was before the test touched it. */
|
|
32
|
+
const saved = new Map();
|
|
33
|
+
function setVar(name, value) {
|
|
34
|
+
if (!saved.has(name))
|
|
35
|
+
saved.set(name, process.env[name]);
|
|
36
|
+
process.env[name] = value;
|
|
37
|
+
}
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
for (const [name, value] of saved) {
|
|
40
|
+
if (value === undefined)
|
|
41
|
+
delete process.env[name];
|
|
42
|
+
else
|
|
43
|
+
process.env[name] = value;
|
|
44
|
+
}
|
|
45
|
+
saved.clear();
|
|
46
|
+
});
|
|
47
|
+
/** A repository with one commit in it. */
|
|
48
|
+
async function seedRepo() {
|
|
49
|
+
const repo = await mkdtemp(join(tmpdir(), 'openagentsy-repo-'));
|
|
50
|
+
const git = (...args) => {
|
|
51
|
+
const result = runGit(repo, [
|
|
52
|
+
'-c',
|
|
53
|
+
'user.email=test@example.com',
|
|
54
|
+
'-c',
|
|
55
|
+
'user.name=Test',
|
|
56
|
+
'-c',
|
|
57
|
+
'commit.gpgsign=false',
|
|
58
|
+
...args,
|
|
59
|
+
]);
|
|
60
|
+
if (!result.ok)
|
|
61
|
+
throw new Error(result.stderr);
|
|
62
|
+
};
|
|
63
|
+
git('init', '-q');
|
|
64
|
+
await writeFile(join(repo, 'a.txt'), 'one\n');
|
|
65
|
+
git('add', 'a.txt');
|
|
66
|
+
git('commit', '-q', '-m', 'feat: add');
|
|
67
|
+
return repo;
|
|
68
|
+
}
|
|
69
|
+
describe('the git runner', () => {
|
|
70
|
+
it('takes the repository variables away from the child', async () => {
|
|
71
|
+
const repo = await seedRepo();
|
|
72
|
+
for (const name of REPOSITORY_VARS)
|
|
73
|
+
setVar(name, `oa-sentinel-${name}`);
|
|
74
|
+
// A git alias that is a shell command runs in the environment of the
|
|
75
|
+
// child, so it shows what the child was given.
|
|
76
|
+
const dumped = runGit(repo, ['-c', 'alias.dumpenv=!env', 'dumpenv']);
|
|
77
|
+
expect(dumped.ok).toBe(true);
|
|
78
|
+
expect(dumped.stdout).not.toContain('oa-sentinel');
|
|
79
|
+
// Git sets a few of its own for the alias it runs; the ones it does
|
|
80
|
+
// not set have to be gone from the child entirely.
|
|
81
|
+
for (const name of REPOSITORY_VARS.filter((entry) => entry !== 'GIT_PREFIX')) {
|
|
82
|
+
expect(dumped.stdout).not.toContain(`${name}=`);
|
|
83
|
+
}
|
|
84
|
+
expect(dumped.stdout).toContain('PATH=');
|
|
85
|
+
});
|
|
86
|
+
it('reads the repository the caller named, not the one the environment names', async () => {
|
|
87
|
+
const repo = await seedRepo();
|
|
88
|
+
for (const name of REPOSITORY_VARS)
|
|
89
|
+
setVar(name, '/nonexistent');
|
|
90
|
+
const result = runGit(repo, ['log', '--oneline']);
|
|
91
|
+
expect(result.ok).toBe(true);
|
|
92
|
+
expect(result.stderr).toBe('');
|
|
93
|
+
expect(result.stdout).toContain('feat: add');
|
|
94
|
+
});
|
|
95
|
+
it('says what went wrong instead of throwing', async () => {
|
|
96
|
+
const result = runGit(root, ['not-a-command']);
|
|
97
|
+
expect(result.ok).toBe(false);
|
|
98
|
+
expect(result.stderr.length).toBeGreaterThan(0);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=git.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.test.js","sourceRoot":"","sources":["../src/git.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openagentsy/ledger — the numbers-only usage ledger (§6).
|
|
3
|
+
*
|
|
4
|
+
* Tokens, cost, waste, outcomes and footprint per message. The ledger holds
|
|
5
|
+
* no prompt, no completion and no code: those stay in OpenCode's own
|
|
6
|
+
* storage, and everything here is a number.
|
|
7
|
+
*/
|
|
8
|
+
export * from './db.js';
|
|
9
|
+
export * from './export.js';
|
|
10
|
+
export * from './footprint.js';
|
|
11
|
+
export * from './git.js';
|
|
12
|
+
export * from './ingest.js';
|
|
13
|
+
export * from './outcomes.js';
|
|
14
|
+
export * from './policy.js';
|
|
15
|
+
export * from './pricing.js';
|
|
16
|
+
export * from './query.js';
|
|
17
|
+
export * from './schema.js';
|
|
18
|
+
export * from './waste.js';
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openagentsy/ledger — the numbers-only usage ledger (§6).
|
|
3
|
+
*
|
|
4
|
+
* Tokens, cost, waste, outcomes and footprint per message. The ledger holds
|
|
5
|
+
* no prompt, no completion and no code: those stay in OpenCode's own
|
|
6
|
+
* storage, and everything here is a number.
|
|
7
|
+
*/
|
|
8
|
+
export * from './db.js';
|
|
9
|
+
export * from './export.js';
|
|
10
|
+
export * from './footprint.js';
|
|
11
|
+
export * from './git.js';
|
|
12
|
+
export * from './ingest.js';
|
|
13
|
+
export * from './outcomes.js';
|
|
14
|
+
export * from './policy.js';
|
|
15
|
+
export * from './pricing.js';
|
|
16
|
+
export * from './query.js';
|
|
17
|
+
export * from './schema.js';
|
|
18
|
+
export * from './waste.js';
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
|
package/dist/ingest.d.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import type { WasteKind } from './schema.js';
|
|
4
|
+
/**
|
|
5
|
+
* The ingest path (§6.2).
|
|
6
|
+
*
|
|
7
|
+
* The role arrives already resolved: the adapter's resolver turns an agent
|
|
8
|
+
* id into a role key before the message is written, so the ledger never sees
|
|
9
|
+
* `agentsy` where it means `lead`. The ledger stores the role it is given,
|
|
10
|
+
* verbatim, and never resolves one. The contract is in `SCHEMA.md`.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* The providers that fold the reasoning tokens into the output count.
|
|
14
|
+
*
|
|
15
|
+
* OpenCode reports reasoning separately from output, and some providers
|
|
16
|
+
* count it twice. The Codex family does, so the reasoning is subtracted
|
|
17
|
+
* before the row is written and the tokens are counted once.
|
|
18
|
+
*/
|
|
19
|
+
export declare const REASONING_IN_OUTPUT: ReadonlySet<string>;
|
|
20
|
+
/** The token counts of one message. */
|
|
21
|
+
export declare const messageTokensSchema: z.ZodObject<{
|
|
22
|
+
input: z.ZodOptional<z.ZodNumber>;
|
|
23
|
+
output: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
reasoning: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
cache: z.ZodOptional<z.ZodObject<{
|
|
26
|
+
read: z.ZodOptional<z.ZodNumber>;
|
|
27
|
+
write: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
}, z.core.$strip>>;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
/** The normalized shape the ledger stores. */
|
|
31
|
+
export declare const assistantMessageSchema: z.ZodObject<{
|
|
32
|
+
id: z.ZodString;
|
|
33
|
+
sessionID: z.ZodString;
|
|
34
|
+
providerID: z.ZodString;
|
|
35
|
+
modelID: z.ZodString;
|
|
36
|
+
tokens: z.ZodOptional<z.ZodObject<{
|
|
37
|
+
input: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
output: z.ZodOptional<z.ZodNumber>;
|
|
39
|
+
reasoning: z.ZodOptional<z.ZodNumber>;
|
|
40
|
+
cache: z.ZodOptional<z.ZodObject<{
|
|
41
|
+
read: z.ZodOptional<z.ZodNumber>;
|
|
42
|
+
write: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
}, z.core.$strip>>;
|
|
44
|
+
}, z.core.$strip>>;
|
|
45
|
+
cost: z.ZodOptional<z.ZodNumber>;
|
|
46
|
+
}, z.core.$strip>;
|
|
47
|
+
/** What the caller knows and the message does not. */
|
|
48
|
+
export declare const ingestCtxSchema: z.ZodObject<{
|
|
49
|
+
rootSessionId: z.ZodString;
|
|
50
|
+
role: z.ZodString;
|
|
51
|
+
latencyMs: z.ZodOptional<z.ZodNumber>;
|
|
52
|
+
activeTaskId: z.ZodOptional<z.ZodString>;
|
|
53
|
+
ts: z.ZodString;
|
|
54
|
+
}, z.core.$strip>;
|
|
55
|
+
export type MessageTokens = z.infer<typeof messageTokensSchema>;
|
|
56
|
+
export type AssistantMessage = z.infer<typeof assistantMessageSchema>;
|
|
57
|
+
export type IngestCtx = z.infer<typeof ingestCtxSchema>;
|
|
58
|
+
/**
|
|
59
|
+
* Normalize a message from OpenCode.
|
|
60
|
+
*
|
|
61
|
+
* The host nests the model under `message.model` on V2 and names it flat on
|
|
62
|
+
* V1, and the plan asks for both to work, so the reader is written
|
|
63
|
+
* tolerantly: every name it knows is tried, and a name it does not know
|
|
64
|
+
* leaves the field empty rather than throwing. Only a message without an id
|
|
65
|
+
* is refused, because the id is the dedup key.
|
|
66
|
+
*/
|
|
67
|
+
export declare function normalizeOcMessage(raw: unknown): AssistantMessage;
|
|
68
|
+
/**
|
|
69
|
+
* Record one assistant message.
|
|
70
|
+
*
|
|
71
|
+
* The row is written once: the message id is the dedup key, so replaying a
|
|
72
|
+
* session does not change the totals. A reported cost is stored only when it
|
|
73
|
+
* is a real positive number, and a message without one leaves
|
|
74
|
+
* `cost_reported` empty — the pricing chain fills `cost_estimated` later, and
|
|
75
|
+
* an unpriced model stays empty rather than becoming zero.
|
|
76
|
+
*/
|
|
77
|
+
export declare function recordAssistantMessage(db: Database, message: AssistantMessage, ctx: IngestCtx): void;
|
|
78
|
+
/**
|
|
79
|
+
* Record a waste signal (§6.4).
|
|
80
|
+
*
|
|
81
|
+
* The detail is free text, so it goes through the redaction first: a secret
|
|
82
|
+
* that reached a waste row would be a secret on disk.
|
|
83
|
+
*/
|
|
84
|
+
export declare function recordWaste(db: Database, waste: {
|
|
85
|
+
rootSessionId?: string | undefined;
|
|
86
|
+
messageId?: string | undefined;
|
|
87
|
+
kind: WasteKind;
|
|
88
|
+
tokens: number;
|
|
89
|
+
detail?: string | undefined;
|
|
90
|
+
ts: string;
|
|
91
|
+
}): void;
|
|
92
|
+
/** A backfill that cannot trust the shape of the file it was pointed at. */
|
|
93
|
+
export declare class BackfillError extends Error {
|
|
94
|
+
constructor(message: string);
|
|
95
|
+
}
|
|
96
|
+
export type BackfillOptions = {
|
|
97
|
+
/** Off by default: a backfill reads another program's database. */
|
|
98
|
+
enabled?: boolean;
|
|
99
|
+
/** Where OpenCode keeps its storage. */
|
|
100
|
+
dataDir?: string;
|
|
101
|
+
/** The newest rows to import. */
|
|
102
|
+
limit?: number;
|
|
103
|
+
};
|
|
104
|
+
export type BackfillResult = {
|
|
105
|
+
enabled: boolean;
|
|
106
|
+
imported: number;
|
|
107
|
+
files: string[];
|
|
108
|
+
errors: string[];
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* The database files of a storage directory, without the sidecars.
|
|
112
|
+
*
|
|
113
|
+
* The name is the one the OpenCode storage uses, and the sidecar files of a
|
|
114
|
+
* database are not databases: a reader that opened one would find an empty
|
|
115
|
+
* file.
|
|
116
|
+
*/
|
|
117
|
+
export declare function listOpencodeDatabases(dataDir: string): string[];
|
|
118
|
+
/** The columns of a table, as the file has them. */
|
|
119
|
+
export declare function tableColumns(source: Database, table: string): Set<string>;
|
|
120
|
+
/** The tables of a file. */
|
|
121
|
+
export declare function tableNames(source: Database): Set<string>;
|
|
122
|
+
/** The JSON of a storage row, or null when it is not JSON. */
|
|
123
|
+
export declare function parseJson(text: unknown): Record<string, unknown> | null;
|
|
124
|
+
/**
|
|
125
|
+
* Import the past messages of an OpenCode storage.
|
|
126
|
+
*
|
|
127
|
+
* The role cannot be resolved for an imported message: the raw agent id is
|
|
128
|
+
* all that is there, so it lands in `role_raw` and the row is left out of
|
|
129
|
+
* the per-role reports rather than mis-attributed. The import is off unless
|
|
130
|
+
* it is asked for, and it never writes to the file it reads.
|
|
131
|
+
*/
|
|
132
|
+
export declare function backfillFromOpencode(db: Database, options?: BackfillOptions): BackfillResult;
|
|
133
|
+
//# sourceMappingURL=ingest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest.d.ts","sourceRoot":"","sources":["../src/ingest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKtC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;;;GAOG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,MAAM,CAIlD,CAAC;AAEH,uCAAuC;AACvC,eAAO,MAAM,mBAAmB;;;;;;;;iBAK9B,CAAC;AAEH,8CAA8C;AAC9C,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;iBAOjC,CAAC;AAEH,sDAAsD;AACtD,eAAO,MAAM,eAAe;;;;;;iBAM1B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAsCxD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,CA+BjE;AAoBD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,QAAQ,EACZ,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,SAAS,GACb,IAAI,CA4BN;AAMD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE;IACL,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,EAAE,EAAE,MAAM,CAAC;CACZ,GACA,IAAI,CAYN;AAED,4EAA4E;AAC5E,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAY/D;AAED,oDAAoD;AACpD,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAGzE;AAED,4BAA4B;AAC5B,wBAAgB,UAAU,CAAC,MAAM,EAAE,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,CAKxD;AAsDD,8DAA8D;AAC9D,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAOvE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,GAAE,eAAoB,GAAG,cAAc,CAoBhG"}
|
package/dist/ingest.js
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
import { readdirSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { redact } from '@openagentsy/core';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { withBusyRetry } from './db.js';
|
|
8
|
+
/**
|
|
9
|
+
* The ingest path (§6.2).
|
|
10
|
+
*
|
|
11
|
+
* The role arrives already resolved: the adapter's resolver turns an agent
|
|
12
|
+
* id into a role key before the message is written, so the ledger never sees
|
|
13
|
+
* `agentsy` where it means `lead`. The ledger stores the role it is given,
|
|
14
|
+
* verbatim, and never resolves one. The contract is in `SCHEMA.md`.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* The providers that fold the reasoning tokens into the output count.
|
|
18
|
+
*
|
|
19
|
+
* OpenCode reports reasoning separately from output, and some providers
|
|
20
|
+
* count it twice. The Codex family does, so the reasoning is subtracted
|
|
21
|
+
* before the row is written and the tokens are counted once.
|
|
22
|
+
*/
|
|
23
|
+
export const REASONING_IN_OUTPUT = new Set([
|
|
24
|
+
'codex',
|
|
25
|
+
'openai-codex',
|
|
26
|
+
'openai-codex-mini',
|
|
27
|
+
]);
|
|
28
|
+
/** The token counts of one message. */
|
|
29
|
+
export const messageTokensSchema = z.object({
|
|
30
|
+
input: z.number().optional(),
|
|
31
|
+
output: z.number().optional(),
|
|
32
|
+
reasoning: z.number().optional(),
|
|
33
|
+
cache: z.object({ read: z.number().optional(), write: z.number().optional() }).optional(),
|
|
34
|
+
});
|
|
35
|
+
/** The normalized shape the ledger stores. */
|
|
36
|
+
export const assistantMessageSchema = z.object({
|
|
37
|
+
id: z.string().min(1),
|
|
38
|
+
sessionID: z.string(),
|
|
39
|
+
providerID: z.string(),
|
|
40
|
+
modelID: z.string(),
|
|
41
|
+
tokens: messageTokensSchema.optional(),
|
|
42
|
+
cost: z.number().optional(),
|
|
43
|
+
});
|
|
44
|
+
/** What the caller knows and the message does not. */
|
|
45
|
+
export const ingestCtxSchema = z.object({
|
|
46
|
+
rootSessionId: z.string().min(1),
|
|
47
|
+
role: z.string().min(1),
|
|
48
|
+
latencyMs: z.number().int().nonnegative().optional(),
|
|
49
|
+
activeTaskId: z.string().min(1).optional(),
|
|
50
|
+
ts: z.string().min(1),
|
|
51
|
+
});
|
|
52
|
+
/** A number, or zero. A token count is never a guess. */
|
|
53
|
+
function n(value) {
|
|
54
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : 0;
|
|
55
|
+
}
|
|
56
|
+
function record(value) {
|
|
57
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
58
|
+
? value
|
|
59
|
+
: {};
|
|
60
|
+
}
|
|
61
|
+
function readString(value) {
|
|
62
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
63
|
+
}
|
|
64
|
+
/** The first of the names that carries a non-empty string. */
|
|
65
|
+
function firstString(source, names) {
|
|
66
|
+
for (const name of names) {
|
|
67
|
+
const value = readString(source[name]);
|
|
68
|
+
if (value !== undefined)
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
/** The provider of a message, under either shape the host uses. */
|
|
74
|
+
function providerOf(message, model) {
|
|
75
|
+
return (firstString(message, ['providerID', 'providerId', 'provider']) ??
|
|
76
|
+
firstString(model, ['providerID', 'provider']) ??
|
|
77
|
+
'');
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Normalize a message from OpenCode.
|
|
81
|
+
*
|
|
82
|
+
* The host nests the model under `message.model` on V2 and names it flat on
|
|
83
|
+
* V1, and the plan asks for both to work, so the reader is written
|
|
84
|
+
* tolerantly: every name it knows is tried, and a name it does not know
|
|
85
|
+
* leaves the field empty rather than throwing. Only a message without an id
|
|
86
|
+
* is refused, because the id is the dedup key.
|
|
87
|
+
*/
|
|
88
|
+
export function normalizeOcMessage(raw) {
|
|
89
|
+
const outer = record(raw);
|
|
90
|
+
const inner = record(outer.message);
|
|
91
|
+
// The host hands the message over on V2, and the message itself on V1.
|
|
92
|
+
const message = readString(inner.id) === undefined ? outer : inner;
|
|
93
|
+
const model = record(message.model);
|
|
94
|
+
const tokens = record(message.tokens);
|
|
95
|
+
const cache = record(tokens.cache);
|
|
96
|
+
const id = firstString(message, ['id', 'messageID', 'message_id']);
|
|
97
|
+
if (id === undefined) {
|
|
98
|
+
throw new Error('the message has no id, so it cannot be deduplicated');
|
|
99
|
+
}
|
|
100
|
+
const cost = typeof message.cost === 'number' && Number.isFinite(message.cost) ? message.cost : undefined;
|
|
101
|
+
return {
|
|
102
|
+
id,
|
|
103
|
+
sessionID: firstString(message, ['sessionID', 'sessionId', 'session_id']) ?? '',
|
|
104
|
+
providerID: providerOf(message, model),
|
|
105
|
+
modelID: firstString(message, ['modelID', 'modelId']) ?? firstString(model, ['id', 'modelID']) ?? '',
|
|
106
|
+
tokens: {
|
|
107
|
+
input: n(tokens.input),
|
|
108
|
+
output: n(tokens.output),
|
|
109
|
+
reasoning: n(tokens.reasoning),
|
|
110
|
+
cache: { read: n(cache.read), write: n(cache.write) },
|
|
111
|
+
},
|
|
112
|
+
...(cost !== undefined ? { cost } : {}),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The output tokens of a message, with the reasoning counted once.
|
|
117
|
+
*
|
|
118
|
+
* The live path and the backfill both go through here, so a message that
|
|
119
|
+
* was counted once cannot be counted twice by the other path.
|
|
120
|
+
*/
|
|
121
|
+
function outputTokens(provider, tokens) {
|
|
122
|
+
const reasoning = n(tokens.reasoning);
|
|
123
|
+
return REASONING_IN_OUTPUT.has(provider.toLowerCase())
|
|
124
|
+
? Math.max(0, n(tokens.output) - reasoning)
|
|
125
|
+
: n(tokens.output);
|
|
126
|
+
}
|
|
127
|
+
const USAGE_INSERT = `INSERT OR IGNORE INTO usage
|
|
128
|
+
(message_id, session_id, root_session_id, role, provider, model, input, output, reasoning,
|
|
129
|
+
cache_read, cache_write, cost_reported, latency_ms, task_id, ts)
|
|
130
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`;
|
|
131
|
+
/**
|
|
132
|
+
* Record one assistant message.
|
|
133
|
+
*
|
|
134
|
+
* The row is written once: the message id is the dedup key, so replaying a
|
|
135
|
+
* session does not change the totals. A reported cost is stored only when it
|
|
136
|
+
* is a real positive number, and a message without one leaves
|
|
137
|
+
* `cost_reported` empty — the pricing chain fills `cost_estimated` later, and
|
|
138
|
+
* an unpriced model stays empty rather than becoming zero.
|
|
139
|
+
*/
|
|
140
|
+
export function recordAssistantMessage(db, message, ctx) {
|
|
141
|
+
// The row is written from what the schemas accept, so a number that is not
|
|
142
|
+
// a number stops here instead of in a report.
|
|
143
|
+
const m = assistantMessageSchema.parse(message);
|
|
144
|
+
const context = ingestCtxSchema.parse(ctx);
|
|
145
|
+
const tokens = m.tokens ?? {};
|
|
146
|
+
const reasoning = n(tokens.reasoning);
|
|
147
|
+
const output = outputTokens(m.providerID, tokens);
|
|
148
|
+
withBusyRetry(() => {
|
|
149
|
+
db.query(USAGE_INSERT).run(m.id, m.sessionID, context.rootSessionId, context.role, m.providerID, m.modelID, n(tokens.input), output, reasoning, n(tokens.cache?.read), n(tokens.cache?.write), typeof m.cost === 'number' && m.cost > 0 ? m.cost : null, context.latencyMs ?? null, context.activeTaskId ?? null, context.ts);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const WASTE_INSERT = `INSERT INTO waste
|
|
153
|
+
(root_session_id, message_id, kind, tokens, detail, ts)
|
|
154
|
+
VALUES (?,?,?,?,?,?)`;
|
|
155
|
+
/**
|
|
156
|
+
* Record a waste signal (§6.4).
|
|
157
|
+
*
|
|
158
|
+
* The detail is free text, so it goes through the redaction first: a secret
|
|
159
|
+
* that reached a waste row would be a secret on disk.
|
|
160
|
+
*/
|
|
161
|
+
export function recordWaste(db, waste) {
|
|
162
|
+
const detail = waste.detail === undefined ? null : redact(waste.detail).text;
|
|
163
|
+
withBusyRetry(() => {
|
|
164
|
+
db.query(WASTE_INSERT).run(waste.rootSessionId ?? null, waste.messageId ?? null, waste.kind, waste.tokens, detail, waste.ts);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/** A backfill that cannot trust the shape of the file it was pointed at. */
|
|
168
|
+
export class BackfillError extends Error {
|
|
169
|
+
constructor(message) {
|
|
170
|
+
super(message);
|
|
171
|
+
this.name = 'BackfillError';
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* The database files of a storage directory, without the sidecars.
|
|
176
|
+
*
|
|
177
|
+
* The name is the one the OpenCode storage uses, and the sidecar files of a
|
|
178
|
+
* database are not databases: a reader that opened one would find an empty
|
|
179
|
+
* file.
|
|
180
|
+
*/
|
|
181
|
+
export function listOpencodeDatabases(dataDir) {
|
|
182
|
+
let names;
|
|
183
|
+
try {
|
|
184
|
+
names = readdirSync(dataDir);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
return names
|
|
190
|
+
.filter((name) => name.startsWith('opencode') && name.endsWith('.db'))
|
|
191
|
+
.filter((name) => !name.endsWith('-wal') && !name.endsWith('-shm'))
|
|
192
|
+
.sort()
|
|
193
|
+
.map((name) => join(dataDir, name));
|
|
194
|
+
}
|
|
195
|
+
/** The columns of a table, as the file has them. */
|
|
196
|
+
export function tableColumns(source, table) {
|
|
197
|
+
const rows = source.query(`PRAGMA table_info(${table})`).all();
|
|
198
|
+
return new Set(rows.map((row) => row.name));
|
|
199
|
+
}
|
|
200
|
+
/** The tables of a file. */
|
|
201
|
+
export function tableNames(source) {
|
|
202
|
+
const rows = source.query("SELECT name FROM sqlite_master WHERE type = 'table'").all();
|
|
203
|
+
return new Set(rows.map((row) => row.name));
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Check the shape of the file before it is read.
|
|
207
|
+
*
|
|
208
|
+
* The OpenCode storage is internal and changes between versions, so the
|
|
209
|
+
* columns this backfill needs are checked and a file that does not carry
|
|
210
|
+
* them is refused with what it does carry. Guessing would import garbage.
|
|
211
|
+
*/
|
|
212
|
+
function verifySchema(source, path) {
|
|
213
|
+
const tables = tableNames(source);
|
|
214
|
+
if (!tables.has('message')) {
|
|
215
|
+
const found = [...tables].sort().join(', ') || 'no tables';
|
|
216
|
+
throw new BackfillError(`${path}: there is no "message" table; this OpenCode version has ${found}`);
|
|
217
|
+
}
|
|
218
|
+
const columns = tableColumns(source, 'message');
|
|
219
|
+
const missing = ['id', 'session_id', 'time_created', 'data'].filter((column) => !columns.has(column));
|
|
220
|
+
if (missing.length > 0) {
|
|
221
|
+
throw new BackfillError(`${path}: the "message" table has no ${missing.join(', ')} column; this OpenCode version has ${[...columns].join(', ')}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/** The parent of every session, when the file records one. */
|
|
225
|
+
function sessionParents(source) {
|
|
226
|
+
const parents = new Map();
|
|
227
|
+
if (!tableNames(source).has('session'))
|
|
228
|
+
return parents;
|
|
229
|
+
if (!tableColumns(source, 'session').has('parent_id'))
|
|
230
|
+
return parents;
|
|
231
|
+
const rows = source.query('SELECT id, parent_id FROM session').all();
|
|
232
|
+
for (const row of rows) {
|
|
233
|
+
parents.set(row.id, row.parent_id ?? undefined);
|
|
234
|
+
}
|
|
235
|
+
return parents;
|
|
236
|
+
}
|
|
237
|
+
/** The session at the top of the chain, with a bound on the walk. */
|
|
238
|
+
function rootSessionOf(parents, sessionId) {
|
|
239
|
+
let current = sessionId;
|
|
240
|
+
for (let depth = 0; depth < 64; depth += 1) {
|
|
241
|
+
const parent = parents.get(current);
|
|
242
|
+
if (parent === undefined || parent === current)
|
|
243
|
+
return current;
|
|
244
|
+
current = parent;
|
|
245
|
+
}
|
|
246
|
+
return current;
|
|
247
|
+
}
|
|
248
|
+
/** The JSON of a storage row, or null when it is not JSON. */
|
|
249
|
+
export function parseJson(text) {
|
|
250
|
+
if (typeof text !== 'string')
|
|
251
|
+
return null;
|
|
252
|
+
try {
|
|
253
|
+
return record(JSON.parse(text));
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Import the past messages of an OpenCode storage.
|
|
261
|
+
*
|
|
262
|
+
* The role cannot be resolved for an imported message: the raw agent id is
|
|
263
|
+
* all that is there, so it lands in `role_raw` and the row is left out of
|
|
264
|
+
* the per-role reports rather than mis-attributed. The import is off unless
|
|
265
|
+
* it is asked for, and it never writes to the file it reads.
|
|
266
|
+
*/
|
|
267
|
+
export function backfillFromOpencode(db, options = {}) {
|
|
268
|
+
if (options.enabled !== true) {
|
|
269
|
+
return { enabled: false, imported: 0, files: [], errors: [] };
|
|
270
|
+
}
|
|
271
|
+
const dataDir = options.dataDir ?? join(homedir(), '.local', 'share', 'opencode');
|
|
272
|
+
const limit = options.limit ?? 10_000;
|
|
273
|
+
const files = listOpencodeDatabases(dataDir);
|
|
274
|
+
let imported = 0;
|
|
275
|
+
const errors = [];
|
|
276
|
+
for (const file of files) {
|
|
277
|
+
try {
|
|
278
|
+
imported += importFile(db, file, limit);
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
errors.push(`${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return { enabled: true, imported, files, errors };
|
|
285
|
+
}
|
|
286
|
+
/** Import one storage file. */
|
|
287
|
+
function importFile(db, path, limit) {
|
|
288
|
+
const source = new Database(path, { readonly: true });
|
|
289
|
+
try {
|
|
290
|
+
verifySchema(source, path);
|
|
291
|
+
const parents = sessionParents(source);
|
|
292
|
+
const rows = source
|
|
293
|
+
.query('SELECT id, session_id, time_created, data FROM message ORDER BY time_created DESC LIMIT ?')
|
|
294
|
+
.all(limit);
|
|
295
|
+
let imported = 0;
|
|
296
|
+
for (const row of rows) {
|
|
297
|
+
const data = parseJson(row.data);
|
|
298
|
+
if (data === null)
|
|
299
|
+
continue;
|
|
300
|
+
if (readString(data.role) !== 'assistant')
|
|
301
|
+
continue;
|
|
302
|
+
const message = normalizeOcMessage({ ...data, id: row.id, sessionID: row.session_id });
|
|
303
|
+
const agent = readString(data.agent) ?? readString(data.mode) ?? null;
|
|
304
|
+
const created = Number(row.time_created);
|
|
305
|
+
const ts = Number.isFinite(created)
|
|
306
|
+
? new Date(created).toISOString()
|
|
307
|
+
: new Date(0).toISOString();
|
|
308
|
+
const result = withBusyRetry(() => {
|
|
309
|
+
return db
|
|
310
|
+
.query(`INSERT OR IGNORE INTO usage
|
|
311
|
+
(message_id, session_id, root_session_id, role, role_raw, provider, model, input, output,
|
|
312
|
+
reasoning, cache_read, cache_write, cost_reported, ts)
|
|
313
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)
|
|
314
|
+
.run(message.id, row.session_id, rootSessionOf(parents, row.session_id), null, agent, message.providerID, message.modelID, n(message.tokens?.input), outputTokens(message.providerID, message.tokens ?? {}), n(message.tokens?.reasoning), n(message.tokens?.cache?.read), n(message.tokens?.cache?.write), typeof message.cost === 'number' && message.cost > 0 ? message.cost : null, ts);
|
|
315
|
+
});
|
|
316
|
+
imported += result.changes;
|
|
317
|
+
}
|
|
318
|
+
return imported;
|
|
319
|
+
}
|
|
320
|
+
finally {
|
|
321
|
+
source.close();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
//# sourceMappingURL=ingest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest.js","sourceRoot":"","sources":["../src/ingest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingest.test.d.ts","sourceRoot":"","sources":["../src/ingest.test.ts"],"names":[],"mappings":""}
|