maka-agent 0.2.0-dev.22.20260905 → 0.2.0-dev.23.20260906
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/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
- package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
- package/node_modules/@maka/core/dist/bot-events.js +18 -63
- package/node_modules/@maka/core/dist/model-call-attempt.js +0 -82
- package/node_modules/@maka/core/dist/model-call-usage-projection.js +0 -186
- package/node_modules/@maka/core/dist/record-schema.js +13 -0
- package/node_modules/@maka/core/dist/redaction.js +41 -58
- package/node_modules/@maka/core/dist/session-trace.js +5 -1
- package/node_modules/@maka/core/dist/usage-ledger-merge.js +7 -9
- package/node_modules/@maka/core/dist/workhub-creation-intent.js +34 -20
- package/node_modules/@maka/eval/harbor/egress-proxy/entrypoint.sh +2 -1
- package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +51 -24
- package/node_modules/@maka/runtime/dist/bots/base-adapter.js +17 -0
- package/node_modules/@maka/runtime/dist/bots/bot-test.js +38 -22
- package/node_modules/@maka/runtime/dist/bots/dingtalk-bridge.js +7 -5
- package/node_modules/@maka/runtime/dist/bots/discord-bridge.js +4 -4
- package/node_modules/@maka/runtime/dist/bots/feishu-bridge.js +4 -5
- package/node_modules/@maka/runtime/dist/bots/qq-bridge.js +6 -4
- package/node_modules/@maka/runtime/dist/bots/slack-bridge.js +3 -4
- package/node_modules/@maka/runtime/dist/bots/telegram-bridge.js +4 -5
- package/node_modules/@maka/runtime/dist/bots/wechat-bridge.js +17 -19
- package/node_modules/@maka/runtime/dist/bots/wecom-bridge.js +5 -6
- package/node_modules/@maka/runtime/dist/bots/ws-bridge-base.js +2 -3
- package/node_modules/@maka/runtime/dist/session-trace-projection.js +3 -30
- package/node_modules/@maka/runtime-host/dist/candidate-entry.js +4 -1
- package/node_modules/@maka/runtime-host/dist/client/index.js +1 -1
- package/node_modules/@maka/runtime-host/dist/client/peer-client.js +13 -0
- package/node_modules/@maka/runtime-host/dist/client/registered-host-termination.js +0 -59
- package/node_modules/@maka/runtime-host/dist/peer-mesh/node.js +28 -16
- package/node_modules/@maka/runtime-host/dist/protocol/external-session.js +4 -0
- package/node_modules/@maka/runtime-host/dist/protocol/host-status.js +8 -0
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +13 -1
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +1 -0
- package/node_modules/@maka/runtime-host/dist/protocol/session-collaboration.js +28 -1
- package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +33 -0
- package/node_modules/@maka/runtime-host/dist/server/access-authority.js +26 -1
- package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +5 -1
- package/node_modules/@maka/runtime-host/dist/server/canonical-usage-reader.js +24 -11
- package/node_modules/@maka/runtime-host/dist/server/daily-review-coordinator.js +7 -4
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +70 -6
- package/node_modules/@maka/runtime-host/dist/server/external-session-coordinator.js +6 -3
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +12 -6
- package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +9 -2
- package/node_modules/@maka/runtime-host/dist/server/root-admission-owner.js +7 -0
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +21 -0
- package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +151 -5
- package/node_modules/@maka/runtime-host/dist/server/usage-pricing-coordinator.js +4 -11
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +44 -15
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +6 -1
- package/node_modules/@maka/storage/dist/agent-run-store.js +44 -0
- package/node_modules/@maka/storage/dist/conversation-operational-state.js +4 -0
- package/node_modules/@maka/storage/dist/execution-stores.js +2 -0
- package/node_modules/@maka/storage/dist/model-call-ledger.js +199 -32
- package/node_modules/@maka/storage/dist/model-call-usage-sql.js +136 -0
- package/node_modules/@maka/storage/dist/operational-state-store-public.js +1 -1
- package/node_modules/@maka/storage/dist/operational-state-store.js +5 -3
- package/node_modules/@maka/storage/dist/sqlite-core-execution-schema.js +11 -1
- package/node_modules/@maka/storage/dist/sqlite-usage-schema.js +200 -20
- package/node_modules/@maka/storage/dist/usage-stores.js +6 -2
- package/package.json +1 -1
|
@@ -16,7 +16,132 @@
|
|
|
16
16
|
* specific language governing permissions and limitations
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
|
-
export const SQLITE_USAGE_SCHEMA_VERSION =
|
|
19
|
+
export const SQLITE_USAGE_SCHEMA_VERSION = 7;
|
|
20
|
+
/**
|
|
21
|
+
* The canonical ledger's columns, in the order every statement binds them.
|
|
22
|
+
*
|
|
23
|
+
* Ordered so `attempt_id, completed_at, session_id` — the three a damaged row
|
|
24
|
+
* keeps — come first, and the pricing columns follow.
|
|
25
|
+
*/
|
|
26
|
+
export const MODEL_CALL_COLUMNS = [
|
|
27
|
+
'attempt_id',
|
|
28
|
+
'completed_at',
|
|
29
|
+
'session_id',
|
|
30
|
+
'logical_call_id',
|
|
31
|
+
'turn_id',
|
|
32
|
+
'call_kind',
|
|
33
|
+
'connection_slug',
|
|
34
|
+
'provider_id',
|
|
35
|
+
'model_id',
|
|
36
|
+
'latency_ms',
|
|
37
|
+
'status',
|
|
38
|
+
'error_class',
|
|
39
|
+
'usage_basis',
|
|
40
|
+
'input_tokens',
|
|
41
|
+
'output_tokens',
|
|
42
|
+
'cache_read_input_tokens',
|
|
43
|
+
'cache_miss_input_tokens',
|
|
44
|
+
'cache_write_input_tokens',
|
|
45
|
+
'reasoning_tokens',
|
|
46
|
+
'cost_basis',
|
|
47
|
+
'cost_usd',
|
|
48
|
+
];
|
|
49
|
+
/**
|
|
50
|
+
* The JSON path each pricing column was read from before the columns existed,
|
|
51
|
+
* used once by the migration that converted the rows.
|
|
52
|
+
*/
|
|
53
|
+
const MODEL_CALL_COLUMN_SOURCES = [
|
|
54
|
+
['logical_call_id', '$.logicalCallId'],
|
|
55
|
+
['turn_id', '$.turnId'],
|
|
56
|
+
['call_kind', '$.callKind'],
|
|
57
|
+
['connection_slug', '$.connectionSlug'],
|
|
58
|
+
['provider_id', '$.providerId'],
|
|
59
|
+
['model_id', '$.modelId'],
|
|
60
|
+
['latency_ms', '$.latencyMs'],
|
|
61
|
+
['status', '$.status'],
|
|
62
|
+
['error_class', '$.errorClass'],
|
|
63
|
+
['usage_basis', '$.usageBasis'],
|
|
64
|
+
['input_tokens', '$.inputTokens'],
|
|
65
|
+
['output_tokens', '$.outputTokens'],
|
|
66
|
+
['cache_read_input_tokens', '$.cacheReadInputTokens'],
|
|
67
|
+
['cache_miss_input_tokens', '$.cacheMissInputTokens'],
|
|
68
|
+
['cache_write_input_tokens', '$.cacheWriteInputTokens'],
|
|
69
|
+
['reasoning_tokens', '$.reasoningTokens'],
|
|
70
|
+
['cost_basis', '$.costBasis'],
|
|
71
|
+
['cost_usd', '$.costUsd'],
|
|
72
|
+
];
|
|
73
|
+
/** The columns that are present together or not at all. See the table's CHECK. */
|
|
74
|
+
const MODEL_CALL_REQUIRED_COLUMNS = [
|
|
75
|
+
'logical_call_id',
|
|
76
|
+
'turn_id',
|
|
77
|
+
'call_kind',
|
|
78
|
+
'provider_id',
|
|
79
|
+
'model_id',
|
|
80
|
+
'latency_ms',
|
|
81
|
+
'status',
|
|
82
|
+
'usage_basis',
|
|
83
|
+
'cost_basis',
|
|
84
|
+
];
|
|
85
|
+
const MODEL_CALL_TOKEN_COLUMNS = [
|
|
86
|
+
'input_tokens',
|
|
87
|
+
'output_tokens',
|
|
88
|
+
'cache_read_input_tokens',
|
|
89
|
+
'cache_miss_input_tokens',
|
|
90
|
+
'cache_write_input_tokens',
|
|
91
|
+
'reasoning_tokens',
|
|
92
|
+
];
|
|
93
|
+
const NO_TOKENS = MODEL_CALL_TOKEN_COLUMNS.map((column) => `${column} IS NULL`).join(' AND ');
|
|
94
|
+
/**
|
|
95
|
+
* Canonical model-call accounting ledger (#1679).
|
|
96
|
+
*
|
|
97
|
+
* One column per field a cost answer reads, so the totals are a `SUM` the
|
|
98
|
+
* database can compute rather than every row of a workspace's history parsed
|
|
99
|
+
* into memory first.
|
|
100
|
+
*
|
|
101
|
+
* A row is either a complete pricing record or a tombstone that kept only the
|
|
102
|
+
* identity and timestamp of a call whose stored form was damaged. Never half of
|
|
103
|
+
* each — which is what makes `cost_basis IS NOT NULL` a sound test for "this row
|
|
104
|
+
* can be counted", and its negation the count a read reports as unreadable.
|
|
105
|
+
*
|
|
106
|
+
* The vocabularies (`status`, `call_kind`) are deliberately not constrained
|
|
107
|
+
* here. They are already validated where a record is decoded, and a CHECK on
|
|
108
|
+
* them would turn one damaged row into a failed migration for the whole
|
|
109
|
+
* workspace.
|
|
110
|
+
*/
|
|
111
|
+
const MODEL_CALL_TABLE = `
|
|
112
|
+
CREATE TABLE IF NOT EXISTS %TABLE% (
|
|
113
|
+
attempt_id TEXT PRIMARY KEY,
|
|
114
|
+
completed_at INTEGER NOT NULL CHECK (completed_at >= 0),
|
|
115
|
+
session_id TEXT,
|
|
116
|
+
logical_call_id TEXT,
|
|
117
|
+
turn_id TEXT,
|
|
118
|
+
call_kind TEXT,
|
|
119
|
+
connection_slug TEXT,
|
|
120
|
+
provider_id TEXT,
|
|
121
|
+
model_id TEXT,
|
|
122
|
+
latency_ms INTEGER,
|
|
123
|
+
status TEXT,
|
|
124
|
+
error_class TEXT,
|
|
125
|
+
usage_basis TEXT,
|
|
126
|
+
input_tokens INTEGER,
|
|
127
|
+
output_tokens INTEGER,
|
|
128
|
+
cache_read_input_tokens INTEGER,
|
|
129
|
+
cache_miss_input_tokens INTEGER,
|
|
130
|
+
cache_write_input_tokens INTEGER,
|
|
131
|
+
reasoning_tokens INTEGER,
|
|
132
|
+
cost_basis TEXT,
|
|
133
|
+
cost_usd REAL,
|
|
134
|
+
CHECK (${MODEL_CALL_REQUIRED_COLUMNS.map((column) => `(${column} IS NULL) = (cost_basis IS NULL)`).join(' AND ')}),
|
|
135
|
+
-- A price that could not be resolved must never surface as an amount, and a
|
|
136
|
+
-- priced call must carry one. Zero stays legal: it is the only way to say a
|
|
137
|
+
-- call was genuinely free.
|
|
138
|
+
CHECK (cost_basis IS NOT 'priced' OR cost_usd IS NOT NULL),
|
|
139
|
+
CHECK (cost_basis IS NOT 'unpriced' OR cost_usd IS NULL),
|
|
140
|
+
-- "The provider reported no usage" and "it reported zero" are different
|
|
141
|
+
-- facts, so a missing-usage row carries no token counts at all.
|
|
142
|
+
CHECK (usage_basis IS NOT 'missing' OR (${NO_TOKENS}))
|
|
143
|
+
)
|
|
144
|
+
`;
|
|
20
145
|
export function migrateSqliteUsageDatabase(db) {
|
|
21
146
|
db.exec(`
|
|
22
147
|
CREATE TABLE IF NOT EXISTS usage_llm_calls (
|
|
@@ -40,18 +165,7 @@ export function migrateSqliteUsageDatabase(db) {
|
|
|
40
165
|
CREATE INDEX IF NOT EXISTS usage_tool_invocations_ts
|
|
41
166
|
ON usage_tool_invocations(ts DESC, id);
|
|
42
167
|
|
|
43
|
-
|
|
44
|
-
-- usage_llm_calls, which is a frozen historical projection: these rows carry
|
|
45
|
-
-- usageBasis/costBasis, which that schema cannot express.
|
|
46
|
-
CREATE TABLE IF NOT EXISTS usage_model_call_attempts (
|
|
47
|
-
attempt_id TEXT PRIMARY KEY,
|
|
48
|
-
completed_at INTEGER NOT NULL CHECK (completed_at >= 0),
|
|
49
|
-
record_json TEXT NOT NULL,
|
|
50
|
-
session_id TEXT
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
CREATE INDEX IF NOT EXISTS usage_model_call_attempts_completed_at
|
|
54
|
-
ON usage_model_call_attempts(completed_at DESC, attempt_id);
|
|
168
|
+
${MODEL_CALL_TABLE.replace('%TABLE%', 'usage_model_call_attempts')};
|
|
55
169
|
|
|
56
170
|
-- The AgentRun sequence is the projection's sole progress authority. A run
|
|
57
171
|
-- is behind exactly when its latest model-call event is newer than this
|
|
@@ -82,26 +196,92 @@ export function migrateSqliteUsageDatabase(db) {
|
|
|
82
196
|
`);
|
|
83
197
|
db.exec('DROP TABLE IF EXISTS usage_model_call_reprojection');
|
|
84
198
|
ensureColumn(db, 'usage_llm_calls', 'session_id', 'TEXT');
|
|
85
|
-
ensureColumn(db, 'usage_model_call_attempts', 'session_id', 'TEXT');
|
|
86
199
|
db.exec(`
|
|
87
200
|
UPDATE usage_llm_calls
|
|
88
201
|
SET session_id = json_extract(record_json, '$.sessionId')
|
|
89
202
|
WHERE session_id IS NULL AND json_valid(record_json);
|
|
90
203
|
|
|
91
|
-
UPDATE usage_model_call_attempts
|
|
92
|
-
SET session_id = json_extract(record_json, '$.sessionId')
|
|
93
|
-
WHERE session_id IS NULL AND json_valid(record_json);
|
|
94
|
-
|
|
95
204
|
CREATE INDEX IF NOT EXISTS usage_llm_calls_session_ts
|
|
96
205
|
ON usage_llm_calls(session_id, ts DESC, id);
|
|
206
|
+
`);
|
|
207
|
+
// A ledger old enough to predate Session attribution has no column to carry
|
|
208
|
+
// through, and the conversion below reads one.
|
|
209
|
+
ensureColumn(db, 'usage_model_call_attempts', 'session_id', 'TEXT');
|
|
210
|
+
spreadModelCallRecordJson(db);
|
|
211
|
+
db.exec(`
|
|
212
|
+
CREATE INDEX IF NOT EXISTS usage_model_call_attempts_completed_at
|
|
213
|
+
ON usage_model_call_attempts(completed_at DESC, attempt_id);
|
|
97
214
|
|
|
98
215
|
CREATE INDEX IF NOT EXISTS usage_model_call_attempts_session_completed_at
|
|
99
216
|
ON usage_model_call_attempts(session_id, completed_at DESC, attempt_id);
|
|
100
217
|
`);
|
|
101
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* Converts rows that stored the record as one JSON blob into the columns.
|
|
221
|
+
*
|
|
222
|
+
* Not rebuilt from the AgentRun authority, the usual move for a read model:
|
|
223
|
+
* deleting a Session drops its runs and cascades their events while these rows
|
|
224
|
+
* are kept on purpose, so for those calls this table is the last copy and a
|
|
225
|
+
* wipe-and-replay would erase their spend. See the header of
|
|
226
|
+
* `model-call-ledger.ts`.
|
|
227
|
+
*
|
|
228
|
+
* A blob that does not yield a whole record — damaged text, or a row some other
|
|
229
|
+
* schema left behind — keeps its identity and timestamp and loses the rest. That
|
|
230
|
+
* is the same claim the old JSON reader made by counting it as unreadable, and
|
|
231
|
+
* it is why the conversion is all-or-nothing per row: a half-filled row would
|
|
232
|
+
* make the table's own CHECK unsatisfiable and take the whole migration with it.
|
|
233
|
+
*/
|
|
234
|
+
function spreadModelCallRecordJson(db) {
|
|
235
|
+
if (!hasColumn(db, 'usage_model_call_attempts', 'record_json'))
|
|
236
|
+
return;
|
|
237
|
+
const extracted = MODEL_CALL_COLUMN_SOURCES.map(([column, path]) => `CASE WHEN json_valid(record_json) THEN json_extract(record_json, '${path}') END AS ${column}`).join(',\n ');
|
|
238
|
+
const readable = [
|
|
239
|
+
...MODEL_CALL_REQUIRED_COLUMNS.map((column) => `${column} IS NOT NULL`),
|
|
240
|
+
"(cost_basis IS NOT 'priced' OR cost_usd IS NOT NULL)",
|
|
241
|
+
"(cost_basis IS NOT 'unpriced' OR cost_usd IS NULL)",
|
|
242
|
+
`(usage_basis IS NOT 'missing' OR (${NO_TOKENS}))`,
|
|
243
|
+
].join('\n AND ');
|
|
244
|
+
const pricing = MODEL_CALL_COLUMN_SOURCES.map(([column]) => `CASE WHEN readable THEN ${column} END`).join(',\n ');
|
|
245
|
+
// The old table moves aside so the new one is created under its final name:
|
|
246
|
+
// a table renamed into place keeps a rewritten `CREATE` statement, and the
|
|
247
|
+
// schema guard compares those texts.
|
|
248
|
+
db.exec(`
|
|
249
|
+
ALTER TABLE usage_model_call_attempts RENAME TO usage_model_call_attempts_blob;
|
|
250
|
+
|
|
251
|
+
${MODEL_CALL_TABLE.replace('%TABLE%', 'usage_model_call_attempts')};
|
|
252
|
+
|
|
253
|
+
INSERT INTO usage_model_call_attempts(${MODEL_CALL_COLUMNS.join(', ')})
|
|
254
|
+
WITH extracted AS (
|
|
255
|
+
SELECT
|
|
256
|
+
attempt_id,
|
|
257
|
+
completed_at,
|
|
258
|
+
-- A tombstone keeps its Session: the row still says a call happened here.
|
|
259
|
+
COALESCE(
|
|
260
|
+
session_id,
|
|
261
|
+
CASE WHEN json_valid(record_json) THEN json_extract(record_json, '$.sessionId') END
|
|
262
|
+
) AS session_id,
|
|
263
|
+
${extracted}
|
|
264
|
+
FROM usage_model_call_attempts_blob
|
|
265
|
+
),
|
|
266
|
+
classified AS (
|
|
267
|
+
SELECT *, (${readable}) AS readable FROM extracted
|
|
268
|
+
)
|
|
269
|
+
SELECT
|
|
270
|
+
attempt_id,
|
|
271
|
+
completed_at,
|
|
272
|
+
session_id,
|
|
273
|
+
${pricing}
|
|
274
|
+
FROM classified;
|
|
275
|
+
|
|
276
|
+
DROP TABLE usage_model_call_attempts_blob;
|
|
277
|
+
`);
|
|
278
|
+
}
|
|
102
279
|
function ensureColumn(db, table, column, definition) {
|
|
103
|
-
|
|
104
|
-
if (columns.some((candidate) => candidate.name === column))
|
|
280
|
+
if (hasColumn(db, table, column))
|
|
105
281
|
return;
|
|
106
282
|
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
|
|
107
283
|
}
|
|
284
|
+
function hasColumn(db, table, column) {
|
|
285
|
+
const columns = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
286
|
+
return columns.some((candidate) => candidate.name === column);
|
|
287
|
+
}
|
|
@@ -291,7 +291,9 @@ function createWriterFacade(lease, telemetry, modelCalls, pricing) {
|
|
|
291
291
|
recordToolInvocation: (record) => admitSessionUsageMutation(record.sessionId, () => telemetry.insertToolInvocation(record)),
|
|
292
292
|
},
|
|
293
293
|
modelCalls: {
|
|
294
|
-
|
|
294
|
+
modelCallSummary: (query, now) => read(() => modelCalls.summary(query, now)),
|
|
295
|
+
modelCallBuckets: (query, groupBy, now) => read(() => modelCalls.buckets(query, groupBy, now)),
|
|
296
|
+
modelCallLogs: (query, now, offset, limit) => read(() => modelCalls.logs(query, now, offset, limit)),
|
|
295
297
|
catchUpModelCallProjection: admitModelCallProjectionCatchUp,
|
|
296
298
|
},
|
|
297
299
|
pricing: {
|
|
@@ -323,7 +325,9 @@ function telemetryReader(repo, run) {
|
|
|
323
325
|
}
|
|
324
326
|
function modelCallReader(ledger, run) {
|
|
325
327
|
return Object.freeze({
|
|
326
|
-
|
|
328
|
+
modelCallSummary: (query, now) => run(() => ledger.summary(query, now)),
|
|
329
|
+
modelCallBuckets: (query, groupBy, now) => run(() => ledger.buckets(query, groupBy, now)),
|
|
330
|
+
modelCallLogs: (query, now, offset, limit) => run(() => ledger.logs(query, now, offset, limit)),
|
|
327
331
|
});
|
|
328
332
|
}
|
|
329
333
|
function pricingReader(store, run) {
|