@legioncodeinc/honeycomb 0.1.6 → 0.1.8
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/bundle/cli.js +102 -7
- package/daemon/dashboard-app.js +10 -10
- package/daemon/index.js +2279 -241
- package/embeddings/embed-daemon.js +1 -1
- package/harnesses/claude-code/.claude-plugin/plugin.json +1 -1
- package/harnesses/claude-code/bundle/capture.js +56 -3
- package/harnesses/claude-code/bundle/index.js +56 -3
- package/harnesses/claude-code/bundle/pre-tool-use.js +56 -3
- package/harnesses/claude-code/bundle/session-end.js +56 -3
- package/harnesses/claude-code/bundle/session-start.js +56 -3
- package/harnesses/codex/bundle/capture.js +22 -2
- package/harnesses/codex/bundle/index.js +22 -2
- package/harnesses/codex/bundle/pre-tool-use.js +22 -2
- package/harnesses/codex/bundle/session-start.js +22 -2
- package/harnesses/codex/package.json +1 -1
- package/harnesses/cursor/bundle/capture.js +22 -2
- package/harnesses/cursor/bundle/index.js +22 -2
- package/harnesses/cursor/bundle/pre-tool-use.js +22 -2
- package/harnesses/cursor/bundle/session-end.js +22 -2
- package/harnesses/cursor/bundle/session-start.js +22 -2
- package/harnesses/openclaw/dist/index.js +1 -1
- package/harnesses/openclaw/openclaw.plugin.json +1 -1
- package/harnesses/openclaw/package.json +1 -1
- package/mcp/bundle/server.js +1 -1
- package/package.json +1 -1
package/daemon/index.js
CHANGED
|
@@ -7369,7 +7369,7 @@ var require_dist = __commonJS({
|
|
|
7369
7369
|
// dist/src/shared/constants.js
|
|
7370
7370
|
var DAEMON_PORT = 3850;
|
|
7371
7371
|
var DAEMON_HOST = "127.0.0.1";
|
|
7372
|
-
var HONEYCOMB_VERSION = true ? "0.1.
|
|
7372
|
+
var HONEYCOMB_VERSION = true ? "0.1.8" : "0.0.0-dev";
|
|
7373
7373
|
|
|
7374
7374
|
// node_modules/zod/v4/classic/external.js
|
|
7375
7375
|
var external_exports = {};
|
|
@@ -25673,6 +25673,28 @@ var SESSIONS_COLUMNS = Object.freeze([
|
|
|
25673
25673
|
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25674
25674
|
{ name: "agent_id", sql: "TEXT NOT NULL DEFAULT 'default'" },
|
|
25675
25675
|
{ name: "visibility", sql: "TEXT NOT NULL DEFAULT 'global'" },
|
|
25676
|
+
// ── PRD-060a (a-AC-3 / a-AC-6): per-turn token + cache usage ──────────────────
|
|
25677
|
+
// Additive columns, healed in via the SAME `ALTER TABLE ADD COLUMN` path the rest
|
|
25678
|
+
// of the catalog uses (the heal engine iterates THIS array; nothing else to wire).
|
|
25679
|
+
//
|
|
25680
|
+
// ZERO vs NULL (a-AC-1 / a-AC-6, the open-question ruling): these four counts are
|
|
25681
|
+
// NULLABLE BIGINT with NO `DEFAULT 0`. The distinction is load-bearing — a genuine
|
|
25682
|
+
// `cache_read_input_tokens = 0` (a real measurement: nothing read from cache) must
|
|
25683
|
+
// stay DISTINCT from "no usage data" (the count was never produced). A `DEFAULT 0`
|
|
25684
|
+
// would collapse "absent" into "measured zero", which a-AC-6 forbids, so absent is
|
|
25685
|
+
// encoded as SQL NULL and a measured zero as the integer 0. Nullable columns are
|
|
25686
|
+
// exempt from the NOT-NULL-needs-a-DEFAULT load guard (NULL is their implicit
|
|
25687
|
+
// default), so `ALTER TABLE ADD COLUMN … BIGINT` heals cleanly onto a populated
|
|
25688
|
+
// legacy table: existing rows read back NULL = "token data absent" (a-AC-4).
|
|
25689
|
+
{ name: "input_tokens", sql: "BIGINT" },
|
|
25690
|
+
{ name: "output_tokens", sql: "BIGINT" },
|
|
25691
|
+
{ name: "cache_read_input_tokens", sql: "BIGINT" },
|
|
25692
|
+
{ name: "cache_creation_input_tokens", sql: "BIGINT" },
|
|
25693
|
+
// The capture-source discriminant (a-AC-7): every Claude-Code row carries
|
|
25694
|
+
// `source_tool = 'claude-code'`, so 060b/060e can render a "Claude Code only"
|
|
25695
|
+
// partial state. NOT NULL DEFAULT '' (a discriminant always present; '' = unknown
|
|
25696
|
+
// source) — heal-safe on a populated table because the empty string backfills.
|
|
25697
|
+
{ name: "source_tool", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25676
25698
|
{ name: "creation_date", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25677
25699
|
{ name: "last_update_date", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
25678
25700
|
]);
|
|
@@ -25939,6 +25961,52 @@ var ROUTER_HISTORY_COLUMNS = Object.freeze([
|
|
|
25939
25961
|
{ name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25940
25962
|
{ name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
25941
25963
|
]);
|
|
25964
|
+
var ROI_METRICS_COLUMNS = Object.freeze([
|
|
25965
|
+
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25966
|
+
{ name: "session_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25967
|
+
{ name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25968
|
+
{ name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25969
|
+
{ name: "agent_id", sql: "TEXT NOT NULL DEFAULT 'default'" },
|
|
25970
|
+
{ name: "project_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25971
|
+
{ name: "team_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25972
|
+
// GATED: '' until a verified backend-token claim populates it (f-AC-6/f-AC-7).
|
|
25973
|
+
{ name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25974
|
+
{ name: "input_tokens", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
25975
|
+
{ name: "output_tokens", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
25976
|
+
{ name: "cache_read_tokens", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
25977
|
+
{ name: "cache_creation_tokens", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
25978
|
+
// MEASURED / MODELED / GROSS / INFRA money — BIGINT integer cents, never FLOAT (f-AC-4).
|
|
25979
|
+
{ name: "measured_cache_savings_cents", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
25980
|
+
{ name: "modeled_savings_cents", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
25981
|
+
{ name: "modeled_assumption_ref", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25982
|
+
{ name: "gross_cost_cents", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
25983
|
+
{ name: "infra_cost_cents", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
25984
|
+
// cost_basis ∈ {measured, allocated, none}; allocation_method '' unless allocated (f-AC-5).
|
|
25985
|
+
{ name: "cost_basis", sql: "TEXT NOT NULL DEFAULT 'none'" },
|
|
25986
|
+
{ name: "allocation_method", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25987
|
+
{ name: "price_ref", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25988
|
+
{ name: "period_start", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25989
|
+
{ name: "period_end", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25990
|
+
{ name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
25991
|
+
]);
|
|
25992
|
+
var ROI_COST_BASES = Object.freeze(["measured", "allocated", "none"]);
|
|
25993
|
+
var TEAMS_COLUMNS = Object.freeze([
|
|
25994
|
+
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25995
|
+
{ name: "team_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25996
|
+
{ name: "team_name", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
25997
|
+
// 'agent' rows work today; 'user' rows inert until user_id verified.
|
|
25998
|
+
{ name: "member_type", sql: "TEXT NOT NULL DEFAULT 'agent'" },
|
|
25999
|
+
{ name: "member_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
26000
|
+
{ name: "role", sql: "TEXT NOT NULL DEFAULT 'member'" },
|
|
26001
|
+
{ name: "active", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
26002
|
+
{ name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
26003
|
+
{ name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
26004
|
+
{ name: "version", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
26005
|
+
{ name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
26006
|
+
{ name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
26007
|
+
]);
|
|
26008
|
+
var TEAM_MEMBER_TYPES = Object.freeze(["agent", "user"]);
|
|
26009
|
+
var TEAM_ACTIVE = 1;
|
|
25942
26010
|
var TENANCY_TABLES = defineGroup([
|
|
25943
26011
|
{
|
|
25944
26012
|
name: "agents",
|
|
@@ -25977,6 +26045,25 @@ var TENANCY_TABLES = defineGroup([
|
|
|
25977
26045
|
pattern: "append-only",
|
|
25978
26046
|
embeddingColumns: [],
|
|
25979
26047
|
scope: "tenant"
|
|
26048
|
+
},
|
|
26049
|
+
{
|
|
26050
|
+
// PRD-060f (f-AC-1/f-AC-2): the shared spend ledger. APPEND-ONLY — one
|
|
26051
|
+
// immutable row per session, a re-price APPENDs a new row (new price_ref),
|
|
26052
|
+
// NEVER an in-place UPDATE; the canonical row is MAX(created_at) per session.
|
|
26053
|
+
name: "roi_metrics",
|
|
26054
|
+
columns: ROI_METRICS_COLUMNS,
|
|
26055
|
+
pattern: "append-only",
|
|
26056
|
+
embeddingColumns: [],
|
|
26057
|
+
scope: "tenant"
|
|
26058
|
+
},
|
|
26059
|
+
{
|
|
26060
|
+
// PRD-060f (f-AC-8): the roster. VERSION-BUMPED — one row per (team, member),
|
|
26061
|
+
// an edit APPENDs version N+1, read ORDER BY version DESC (same as api_keys).
|
|
26062
|
+
name: "teams",
|
|
26063
|
+
columns: TEAMS_COLUMNS,
|
|
26064
|
+
pattern: "version-bumped",
|
|
26065
|
+
embeddingColumns: [],
|
|
26066
|
+
scope: "tenant"
|
|
25980
26067
|
}
|
|
25981
26068
|
]);
|
|
25982
26069
|
function buildApiKeyLookupByIdSql(id) {
|
|
@@ -26904,6 +26991,36 @@ function appendOnlyInsert(client, target, scope, row) {
|
|
|
26904
26991
|
const sql = buildInsert(target.table, row);
|
|
26905
26992
|
return withHeal(client, target, scope, () => client.query(sql, scope));
|
|
26906
26993
|
}
|
|
26994
|
+
function buildInsertMany(table, rows) {
|
|
26995
|
+
if (rows.length === 0) {
|
|
26996
|
+
throw new Error("buildInsertMany: at least one row is required");
|
|
26997
|
+
}
|
|
26998
|
+
const tbl = sqlIdent(table);
|
|
26999
|
+
const first = rows[0];
|
|
27000
|
+
const colNames = first.map(([name]) => name);
|
|
27001
|
+
for (const row of rows)
|
|
27002
|
+
assertSameColumns(colNames, row);
|
|
27003
|
+
const cols = colNames.map((name) => sqlIdent(name)).join(", ");
|
|
27004
|
+
const vals = rows.map((row) => `(${row.map(([, v]) => renderValue(v)).join(", ")})`).join(", ");
|
|
27005
|
+
return `INSERT INTO "${tbl}" (${cols}) VALUES ${vals}`;
|
|
27006
|
+
}
|
|
27007
|
+
function assertSameColumns(expected, row) {
|
|
27008
|
+
if (row.length !== expected.length) {
|
|
27009
|
+
throw new Error(`buildInsertMany: row column count ${row.length} != expected ${expected.length}`);
|
|
27010
|
+
}
|
|
27011
|
+
for (let i = 0; i < expected.length; i++) {
|
|
27012
|
+
const actual = row[i][0];
|
|
27013
|
+
if (actual !== expected[i]) {
|
|
27014
|
+
throw new Error(`buildInsertMany: row column "${actual}" != expected "${expected[i]}" at index ${i}`);
|
|
27015
|
+
}
|
|
27016
|
+
}
|
|
27017
|
+
}
|
|
27018
|
+
function appendOnlyInsertMany(client, target, scope, rows, opts) {
|
|
27019
|
+
if (rows.length === 0)
|
|
27020
|
+
return Promise.resolve(ok([], 0));
|
|
27021
|
+
const sql = buildInsertMany(target.table, rows);
|
|
27022
|
+
return withHeal(client, target, scope, () => client.query(sql, scope, opts));
|
|
27023
|
+
}
|
|
26907
27024
|
async function readLatestVersion(client, target, scope, keyColumn, keyValue, selectColumns = "*") {
|
|
26908
27025
|
const tbl = sqlIdent(target.table);
|
|
26909
27026
|
const key = sqlIdent(keyColumn);
|
|
@@ -26988,6 +27105,8 @@ function resolveConfig(config2, ownerFallback) {
|
|
|
26988
27105
|
var RESOLVE_POLLS = 8;
|
|
26989
27106
|
var DISCOVER_POLLS = 8;
|
|
26990
27107
|
var LEASE_CANDIDATE_TRIES = 8;
|
|
27108
|
+
var SOURCE_LEASE = "poll-lease";
|
|
27109
|
+
var SOURCE_REAPER = "poll-reaper";
|
|
26991
27110
|
function defaultClock2() {
|
|
26992
27111
|
return {
|
|
26993
27112
|
now: () => Date.now(),
|
|
@@ -27164,7 +27283,7 @@ var DeepLakeJobQueueService = class {
|
|
|
27164
27283
|
]);
|
|
27165
27284
|
if (!wrote)
|
|
27166
27285
|
return null;
|
|
27167
|
-
const current = await this.resolveCurrent(candidate.id);
|
|
27286
|
+
const current = await this.resolveCurrent(candidate.id, SOURCE_LEASE);
|
|
27168
27287
|
if (current !== null && current.leaseOwner === owner && current.status === JOB_LEASED) {
|
|
27169
27288
|
return {
|
|
27170
27289
|
id: candidate.id,
|
|
@@ -27189,7 +27308,7 @@ var DeepLakeJobQueueService = class {
|
|
|
27189
27308
|
*/
|
|
27190
27309
|
async selectLeasable(exclude, kinds) {
|
|
27191
27310
|
const nowIso10 = this.nowIso();
|
|
27192
|
-
const states = await this.discoverIds();
|
|
27311
|
+
const states = await this.discoverIds(SOURCE_LEASE);
|
|
27193
27312
|
const leasable = states.filter((s) => !exclude.has(s.id) && (kinds === void 0 || kinds.includes(s.type)) && (s.status === JOB_QUEUED || s.status === JOB_FAILED) && s.nextRunAt !== "" && s.nextRunAt <= nowIso10);
|
|
27194
27313
|
if (leasable.length === 0)
|
|
27195
27314
|
return null;
|
|
@@ -27204,12 +27323,12 @@ var DeepLakeJobQueueService = class {
|
|
|
27204
27323
|
* growing. Then resolves each id's current state via {@link resolveCurrent}. The
|
|
27205
27324
|
* `__ensure__` sentinel row (see {@link ensureTable}) is filtered out.
|
|
27206
27325
|
*/
|
|
27207
|
-
async discoverIds() {
|
|
27326
|
+
async discoverIds(source) {
|
|
27208
27327
|
const ids = /* @__PURE__ */ new Set();
|
|
27209
27328
|
let lastSize = -1;
|
|
27210
27329
|
for (let poll = 0; poll < DISCOVER_POLLS; poll++) {
|
|
27211
27330
|
const sql = `SELECT DISTINCT ${sqlIdent("id")} FROM "${this.tbl()}"`;
|
|
27212
|
-
const res = await this.storage.query(sql, this.scope);
|
|
27331
|
+
const res = await this.storage.query(sql, this.scope, source !== void 0 ? { source } : {});
|
|
27213
27332
|
if (isOk(res)) {
|
|
27214
27333
|
for (const row of res.rows) {
|
|
27215
27334
|
const id = rowText(row, "id");
|
|
@@ -27223,7 +27342,7 @@ var DeepLakeJobQueueService = class {
|
|
|
27223
27342
|
}
|
|
27224
27343
|
const states = [];
|
|
27225
27344
|
for (const id of ids) {
|
|
27226
|
-
const state = await this.resolveCurrent(id);
|
|
27345
|
+
const state = await this.resolveCurrent(id, source);
|
|
27227
27346
|
if (state !== null)
|
|
27228
27347
|
states.push(state);
|
|
27229
27348
|
}
|
|
@@ -27239,11 +27358,11 @@ var DeepLakeJobQueueService = class {
|
|
|
27239
27358
|
* when the id has no row at all. Short-circuits once a max-version row is seen
|
|
27240
27359
|
* twice (the fake is decisive on the first read).
|
|
27241
27360
|
*/
|
|
27242
|
-
async resolveCurrent(id) {
|
|
27361
|
+
async resolveCurrent(id, source) {
|
|
27243
27362
|
let best = null;
|
|
27244
27363
|
let seenBestTwice = false;
|
|
27245
27364
|
for (let poll = 0; poll < RESOLVE_POLLS; poll++) {
|
|
27246
|
-
const row = await this.latestById(id);
|
|
27365
|
+
const row = await this.latestById(id, source);
|
|
27247
27366
|
if (row !== null) {
|
|
27248
27367
|
const state = toJobState(row);
|
|
27249
27368
|
if (best === null || state.version > best.version) {
|
|
@@ -27259,10 +27378,10 @@ var DeepLakeJobQueueService = class {
|
|
|
27259
27378
|
return best;
|
|
27260
27379
|
}
|
|
27261
27380
|
/** One highest-version by-id read of the full job row, or `null` when absent. */
|
|
27262
|
-
async latestById(id) {
|
|
27381
|
+
async latestById(id, source) {
|
|
27263
27382
|
const cols = STATE_COLUMNS.map((c) => sqlIdent(c)).join(", ");
|
|
27264
27383
|
const sql = `SELECT ${cols} FROM "${this.tbl()}" WHERE ${sqlIdent("id")} = ${sLiteral(id)} ORDER BY ${sqlIdent("version")} DESC LIMIT 1`;
|
|
27265
|
-
const res = await this.storage.query(sql, this.scope);
|
|
27384
|
+
const res = await this.storage.query(sql, this.scope, source !== void 0 ? { source } : {});
|
|
27266
27385
|
if (isOk(res) && res.rows.length > 0)
|
|
27267
27386
|
return res.rows[0];
|
|
27268
27387
|
return null;
|
|
@@ -27362,7 +27481,7 @@ var DeepLakeJobQueueService = class {
|
|
|
27362
27481
|
*/
|
|
27363
27482
|
async reapExpiredLeases() {
|
|
27364
27483
|
const nowIso10 = this.nowIso();
|
|
27365
|
-
const states = await this.discoverIds();
|
|
27484
|
+
const states = await this.discoverIds(SOURCE_REAPER);
|
|
27366
27485
|
const expired = states.filter((s) => s.status === JOB_LEASED && s.leaseExpiresAt !== "" && s.leaseExpiresAt <= nowIso10);
|
|
27367
27486
|
if (expired.length === 0)
|
|
27368
27487
|
return 0;
|
|
@@ -28464,7 +28583,7 @@ function buildAllowedProperties(input) {
|
|
|
28464
28583
|
}
|
|
28465
28584
|
var systemTelemetryClock = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
28466
28585
|
var DEFAULT_EMIT_TIMEOUT_MS = 2e3;
|
|
28467
|
-
var HONEYCOMB_VERSION2 = true ? "0.1.
|
|
28586
|
+
var HONEYCOMB_VERSION2 = true ? "0.1.8" : "0.0.0-dev";
|
|
28468
28587
|
async function emitTelemetry(event, opts, deps = {}) {
|
|
28469
28588
|
const env = deps.env ?? process.env;
|
|
28470
28589
|
const key = deps.posthogKey ?? POSTHOG_KEY;
|
|
@@ -31039,6 +31158,17 @@ function createSummaryJobWorker(deps) {
|
|
|
31039
31158
|
|
|
31040
31159
|
// dist/src/daemon/runtime/capture/event-contract.js
|
|
31041
31160
|
var nonEmpty = external_exports.string().trim().min(1);
|
|
31161
|
+
var tokenCount = external_exports.number().int().nonnegative();
|
|
31162
|
+
var TurnUsageSchema = external_exports.object({
|
|
31163
|
+
/** `input_tokens` — prompt tokens billed for this turn. */
|
|
31164
|
+
input: tokenCount.optional(),
|
|
31165
|
+
/** `output_tokens` — completion tokens billed for this turn. */
|
|
31166
|
+
output: tokenCount.optional(),
|
|
31167
|
+
/** `cache_read_input_tokens` — tokens served from the prompt cache (a real 0 ≠ absent). */
|
|
31168
|
+
cacheRead: tokenCount.optional(),
|
|
31169
|
+
/** `cache_creation_input_tokens` — tokens written into the prompt cache. */
|
|
31170
|
+
cacheCreation: tokenCount.optional()
|
|
31171
|
+
}).optional().transform((u) => u !== void 0 && (u.input !== void 0 || u.output !== void 0 || u.cacheRead !== void 0 || u.cacheCreation !== void 0) ? u : void 0);
|
|
31042
31172
|
var UserMessageEventSchema = external_exports.object({
|
|
31043
31173
|
kind: external_exports.literal("user_message"),
|
|
31044
31174
|
text: external_exports.string()
|
|
@@ -31051,7 +31181,9 @@ var ToolCallEventSchema = external_exports.object({
|
|
|
31051
31181
|
});
|
|
31052
31182
|
var AssistantMessageEventSchema = external_exports.object({
|
|
31053
31183
|
kind: external_exports.literal("assistant_message"),
|
|
31054
|
-
text: external_exports.string()
|
|
31184
|
+
text: external_exports.string(),
|
|
31185
|
+
/** PRD-060a: optional per-turn token + cache counts; absent when unavailable. */
|
|
31186
|
+
usage: TurnUsageSchema
|
|
31055
31187
|
});
|
|
31056
31188
|
var CaptureEventSchema = external_exports.discriminatedUnion("kind", [
|
|
31057
31189
|
UserMessageEventSchema,
|
|
@@ -31094,15 +31226,204 @@ function parseCaptureRequest(body) {
|
|
|
31094
31226
|
return { ok: false, error: issues };
|
|
31095
31227
|
}
|
|
31096
31228
|
|
|
31229
|
+
// dist/src/daemon/runtime/capture/capture-buffer.js
|
|
31230
|
+
var realBufferClock = {
|
|
31231
|
+
now: () => Date.now(),
|
|
31232
|
+
setTimer: (fn, ms) => {
|
|
31233
|
+
const t = setTimeout(fn, ms);
|
|
31234
|
+
if (typeof t === "object" && t !== null && "unref" in t && typeof t.unref === "function")
|
|
31235
|
+
t.unref();
|
|
31236
|
+
return t;
|
|
31237
|
+
},
|
|
31238
|
+
clearTimer: (handle) => clearTimeout(handle)
|
|
31239
|
+
};
|
|
31240
|
+
var DEFAULT_MAX_EVENTS = 25;
|
|
31241
|
+
var DEFAULT_WINDOW_MS = 1e3;
|
|
31242
|
+
var CaptureBuffer = class {
|
|
31243
|
+
maxEvents;
|
|
31244
|
+
windowMs;
|
|
31245
|
+
clock;
|
|
31246
|
+
flushFn;
|
|
31247
|
+
/** The current window's buffered items. */
|
|
31248
|
+
items = [];
|
|
31249
|
+
/** The pending time-flush timer, or null when the window is empty. */
|
|
31250
|
+
timer = null;
|
|
31251
|
+
/** The in-flight flush, so a second trigger awaits it rather than racing it. */
|
|
31252
|
+
inFlight = Promise.resolve();
|
|
31253
|
+
/** Set on `close()` so a late `add` after shutdown is rejected, not silently buffered-then-lost. */
|
|
31254
|
+
closed = false;
|
|
31255
|
+
constructor(flushFn, config2 = {}, clock = realBufferClock) {
|
|
31256
|
+
this.flushFn = flushFn;
|
|
31257
|
+
this.maxEvents = Math.max(1, config2.maxEvents ?? DEFAULT_MAX_EVENTS);
|
|
31258
|
+
this.windowMs = Math.max(1, config2.windowMs ?? DEFAULT_WINDOW_MS);
|
|
31259
|
+
this.clock = clock;
|
|
31260
|
+
}
|
|
31261
|
+
/** Number of items currently buffered (for assertions / diagnostics). */
|
|
31262
|
+
get size() {
|
|
31263
|
+
return this.items.length;
|
|
31264
|
+
}
|
|
31265
|
+
/**
|
|
31266
|
+
* Buffer one item. Starts the time window on the first item of an empty buffer,
|
|
31267
|
+
* and triggers an immediate flush when the size cap is reached. Returns a promise
|
|
31268
|
+
* that resolves when THIS item has been flushed (either by the size cap it just
|
|
31269
|
+
* tripped, or by a later time/force flush), so a caller that needs the durable
|
|
31270
|
+
* write before responding can await it; a caller that wants fire-and-forget
|
|
31271
|
+
* batching simply does not await.
|
|
31272
|
+
*/
|
|
31273
|
+
add(item) {
|
|
31274
|
+
if (this.closed) {
|
|
31275
|
+
return Promise.reject(new Error("CaptureBuffer.add after close"));
|
|
31276
|
+
}
|
|
31277
|
+
this.items.push(item);
|
|
31278
|
+
if (this.items.length === 1)
|
|
31279
|
+
this.startTimer();
|
|
31280
|
+
if (this.items.length >= this.maxEvents)
|
|
31281
|
+
return this.flushNow();
|
|
31282
|
+
return this.inFlight;
|
|
31283
|
+
}
|
|
31284
|
+
/**
|
|
31285
|
+
* Force a flush of the current window NOW (window close / shutdown drain). Cancels
|
|
31286
|
+
* the pending timer, swaps out the buffered batch, and appends it as one multi-row
|
|
31287
|
+
* write. Awaits any in-flight flush first so two flushes never overlap. A no-op
|
|
31288
|
+
* (resolved) when the buffer is empty.
|
|
31289
|
+
*/
|
|
31290
|
+
flushNow() {
|
|
31291
|
+
this.cancelTimer();
|
|
31292
|
+
if (this.items.length === 0)
|
|
31293
|
+
return this.inFlight;
|
|
31294
|
+
const batch = this.items;
|
|
31295
|
+
this.items = [];
|
|
31296
|
+
this.inFlight = this.inFlight.then(() => this.flushFn(batch));
|
|
31297
|
+
return this.inFlight;
|
|
31298
|
+
}
|
|
31299
|
+
/**
|
|
31300
|
+
* Drain + close (graceful shutdown, AC-5 / AC-62c.1.2). Flushes the remaining
|
|
31301
|
+
* window so nothing buffered is lost on a clean stop, then marks the buffer closed
|
|
31302
|
+
* so a late `add` is rejected rather than buffered into a buffer that will never
|
|
31303
|
+
* flush again. Idempotent.
|
|
31304
|
+
*/
|
|
31305
|
+
async close() {
|
|
31306
|
+
if (this.closed) {
|
|
31307
|
+
await this.inFlight;
|
|
31308
|
+
return;
|
|
31309
|
+
}
|
|
31310
|
+
const drained = this.flushNow();
|
|
31311
|
+
this.closed = true;
|
|
31312
|
+
await drained;
|
|
31313
|
+
}
|
|
31314
|
+
/** Start the time-flush timer for the current window (called on the first buffered item). */
|
|
31315
|
+
startTimer() {
|
|
31316
|
+
this.cancelTimer();
|
|
31317
|
+
this.timer = this.clock.setTimer(() => {
|
|
31318
|
+
this.timer = null;
|
|
31319
|
+
void this.flushNow();
|
|
31320
|
+
}, this.windowMs);
|
|
31321
|
+
}
|
|
31322
|
+
/** Cancel + clear the pending time-flush timer, if any. */
|
|
31323
|
+
cancelTimer() {
|
|
31324
|
+
if (this.timer !== null) {
|
|
31325
|
+
this.clock.clearTimer(this.timer);
|
|
31326
|
+
this.timer = null;
|
|
31327
|
+
}
|
|
31328
|
+
}
|
|
31329
|
+
};
|
|
31330
|
+
|
|
31331
|
+
// dist/src/daemon/runtime/capture/capture-config.js
|
|
31332
|
+
var DEFAULT_CAPTURE_WINDOW_MS = 1e3;
|
|
31333
|
+
var DEFAULT_CAPTURE_MAX_EVENTS = 25;
|
|
31334
|
+
var DEFAULT_CAPTURE_ENVELOPE_BUDGET_BYTES = 16384;
|
|
31335
|
+
var BoolFlag = external_exports.preprocess((raw2) => {
|
|
31336
|
+
if (typeof raw2 === "boolean")
|
|
31337
|
+
return raw2;
|
|
31338
|
+
return raw2 === "true" || raw2 === "1";
|
|
31339
|
+
}, external_exports.boolean());
|
|
31340
|
+
function ClampedInt(def, min = 0) {
|
|
31341
|
+
return external_exports.preprocess((raw2) => {
|
|
31342
|
+
const n = typeof raw2 === "number" ? raw2 : Number(raw2);
|
|
31343
|
+
if (!Number.isFinite(n))
|
|
31344
|
+
return def;
|
|
31345
|
+
return Math.max(min, Math.trunc(n));
|
|
31346
|
+
}, external_exports.number().int());
|
|
31347
|
+
}
|
|
31348
|
+
var CaptureConfigSchema = external_exports.object({
|
|
31349
|
+
/** Master switch for write batching; DEFAULT-ON (L-X1). Off ⇒ one INSERT per event. */
|
|
31350
|
+
batch: BoolFlag.default(true),
|
|
31351
|
+
/** Time-flush window in ms (AC-5). */
|
|
31352
|
+
windowMs: ClampedInt(DEFAULT_CAPTURE_WINDOW_MS, 1).default(DEFAULT_CAPTURE_WINDOW_MS),
|
|
31353
|
+
/** Size-flush cap in events (AC-5). */
|
|
31354
|
+
maxEvents: ClampedInt(DEFAULT_CAPTURE_MAX_EVENTS, 1).default(DEFAULT_CAPTURE_MAX_EVENTS),
|
|
31355
|
+
/** Per-field tool-I/O byte budget; `0` disables trimming (full envelope, pre-062c). */
|
|
31356
|
+
envelopeBudgetBytes: ClampedInt(DEFAULT_CAPTURE_ENVELOPE_BUDGET_BYTES, 0).default(DEFAULT_CAPTURE_ENVELOPE_BUDGET_BYTES)
|
|
31357
|
+
});
|
|
31358
|
+
var CAPTURE_ENV_KEYS = {
|
|
31359
|
+
batch: "HONEYCOMB_CAPTURE_BATCH",
|
|
31360
|
+
windowMs: "HONEYCOMB_CAPTURE_WINDOW_MS",
|
|
31361
|
+
maxEvents: "HONEYCOMB_CAPTURE_MAX_EVENTS",
|
|
31362
|
+
envelopeBudgetBytes: "HONEYCOMB_CAPTURE_ENVELOPE_BUDGET_BYTES"
|
|
31363
|
+
};
|
|
31364
|
+
function resolveCaptureConfig(env = process.env) {
|
|
31365
|
+
const parsed = CaptureConfigSchema.safeParse({
|
|
31366
|
+
batch: env[CAPTURE_ENV_KEYS.batch],
|
|
31367
|
+
windowMs: env[CAPTURE_ENV_KEYS.windowMs],
|
|
31368
|
+
maxEvents: env[CAPTURE_ENV_KEYS.maxEvents],
|
|
31369
|
+
envelopeBudgetBytes: env[CAPTURE_ENV_KEYS.envelopeBudgetBytes]
|
|
31370
|
+
});
|
|
31371
|
+
return parsed.success ? parsed.data : CaptureConfigSchema.parse({});
|
|
31372
|
+
}
|
|
31373
|
+
|
|
31374
|
+
// dist/src/daemon/runtime/capture/budgeted-stringify.js
|
|
31375
|
+
var DEFAULT_ENVELOPE_BUDGET_BYTES = 16384;
|
|
31376
|
+
function truncationMarker(originalBytes) {
|
|
31377
|
+
return `\u2026[truncated ${originalBytes} bytes]`;
|
|
31378
|
+
}
|
|
31379
|
+
function byteLength(value) {
|
|
31380
|
+
return Buffer.byteLength(value, "utf8");
|
|
31381
|
+
}
|
|
31382
|
+
function capToolField(value, budgetBytes) {
|
|
31383
|
+
if (value === void 0)
|
|
31384
|
+
return void 0;
|
|
31385
|
+
let serialized;
|
|
31386
|
+
try {
|
|
31387
|
+
serialized = JSON.stringify(value);
|
|
31388
|
+
} catch {
|
|
31389
|
+
return void 0;
|
|
31390
|
+
}
|
|
31391
|
+
if (serialized === void 0)
|
|
31392
|
+
return void 0;
|
|
31393
|
+
if (byteLength(serialized) <= budgetBytes)
|
|
31394
|
+
return value;
|
|
31395
|
+
return truncationMarker(byteLength(serialized));
|
|
31396
|
+
}
|
|
31397
|
+
function trimEvent(event, budgetBytes) {
|
|
31398
|
+
if (event.kind !== "tool_call")
|
|
31399
|
+
return event;
|
|
31400
|
+
const cappedInput = capToolField(event.input, budgetBytes);
|
|
31401
|
+
const cappedResponse = capToolField(event.response, budgetBytes);
|
|
31402
|
+
if (cappedInput === event.input && cappedResponse === event.response)
|
|
31403
|
+
return event;
|
|
31404
|
+
return {
|
|
31405
|
+
kind: "tool_call",
|
|
31406
|
+
tool: event.tool,
|
|
31407
|
+
...cappedInput !== void 0 ? { input: cappedInput } : {},
|
|
31408
|
+
...cappedResponse !== void 0 ? { response: cappedResponse } : {}
|
|
31409
|
+
};
|
|
31410
|
+
}
|
|
31411
|
+
function budgetedStringify(event, metadata, budgetBytes = DEFAULT_ENVELOPE_BUDGET_BYTES) {
|
|
31412
|
+
const trimmedEvent = trimEvent(event, budgetBytes);
|
|
31413
|
+
return JSON.stringify({ event: trimmedEvent, metadata });
|
|
31414
|
+
}
|
|
31415
|
+
|
|
31097
31416
|
// dist/src/daemon/runtime/capture/capture-handler.js
|
|
31098
31417
|
var HOOKS_GROUP = "/api/hooks";
|
|
31418
|
+
var CAPTURE_WRITE_SOURCE = "capture-write";
|
|
31099
31419
|
var CAPTURE_PATH = "/capture";
|
|
31100
31420
|
var CONVERSATION_PATH = "/conversation";
|
|
31101
31421
|
function createCaptureHandler(deps) {
|
|
31102
31422
|
const counters = deps.counters ?? new TurnCounters(deps.counterConfig);
|
|
31103
31423
|
const embed = deps.embed ?? noopEmbedAttachment;
|
|
31104
31424
|
const now = deps.now ?? (() => Date.now());
|
|
31105
|
-
const
|
|
31425
|
+
const config2 = deps.captureConfig ?? resolveCaptureConfig();
|
|
31426
|
+
const handler = new CaptureRouteHandler(deps, counters, embed, now, config2);
|
|
31106
31427
|
return {
|
|
31107
31428
|
register(daemon) {
|
|
31108
31429
|
const group = daemon.group(HOOKS_GROUP);
|
|
@@ -31112,7 +31433,8 @@ function createCaptureHandler(deps) {
|
|
|
31112
31433
|
group.post(CAPTURE_PATH, (c) => handler.handleCapture(c));
|
|
31113
31434
|
group.get(CONVERSATION_PATH, (c) => handler.handleConversation(c));
|
|
31114
31435
|
},
|
|
31115
|
-
counters
|
|
31436
|
+
counters,
|
|
31437
|
+
flush: () => handler.flush()
|
|
31116
31438
|
};
|
|
31117
31439
|
}
|
|
31118
31440
|
var CaptureRouteHandler = class {
|
|
@@ -31120,11 +31442,19 @@ var CaptureRouteHandler = class {
|
|
|
31120
31442
|
counters;
|
|
31121
31443
|
embed;
|
|
31122
31444
|
now;
|
|
31123
|
-
|
|
31445
|
+
config;
|
|
31446
|
+
/**
|
|
31447
|
+
* PRD-062c (L-C1): the capture write buffer. NULL when batching is off — the handler
|
|
31448
|
+
* then does one append-only INSERT per event (the pre-062c path). Lazily created on the
|
|
31449
|
+
* first buffered write so a flag-off handler allocates nothing.
|
|
31450
|
+
*/
|
|
31451
|
+
buffer = null;
|
|
31452
|
+
constructor(deps, counters, embed, now, config2) {
|
|
31124
31453
|
this.deps = deps;
|
|
31125
31454
|
this.counters = counters;
|
|
31126
31455
|
this.embed = embed;
|
|
31127
31456
|
this.now = now;
|
|
31457
|
+
this.config = config2;
|
|
31128
31458
|
}
|
|
31129
31459
|
/**
|
|
31130
31460
|
* POST /api/hooks/capture (FR-1..5, FR-7..9 / a-AC-1..5).
|
|
@@ -31153,10 +31483,16 @@ var CaptureRouteHandler = class {
|
|
|
31153
31483
|
const nowIso10 = new Date(this.now()).toISOString();
|
|
31154
31484
|
const projectId = this.resolveCaptureProjectId(metadata);
|
|
31155
31485
|
const row = this.buildRow(id, event, metadata, nowIso10, projectId);
|
|
31156
|
-
|
|
31157
|
-
|
|
31158
|
-
|
|
31159
|
-
|
|
31486
|
+
if (this.config.batch) {
|
|
31487
|
+
this.bufferRow(id, row, scope);
|
|
31488
|
+
} else {
|
|
31489
|
+
const result = await appendOnlyInsertMany(this.deps.storage, this.deps.sessionsTarget, scope, [row], {
|
|
31490
|
+
source: CAPTURE_WRITE_SOURCE
|
|
31491
|
+
});
|
|
31492
|
+
if (!isOk(result)) {
|
|
31493
|
+
this.deps.logger?.event("capture.insert.failed", { id, kind: result.kind });
|
|
31494
|
+
return c.json({ error: "capture_failed", reason: "could not write the session row" }, 502);
|
|
31495
|
+
}
|
|
31160
31496
|
}
|
|
31161
31497
|
const cues = this.bumpCounters(metadata);
|
|
31162
31498
|
await this.enqueueCues(cues);
|
|
@@ -31189,6 +31525,67 @@ var CaptureRouteHandler = class {
|
|
|
31189
31525
|
}
|
|
31190
31526
|
return c.json({ path: path4.trim(), rows: result.rows });
|
|
31191
31527
|
}
|
|
31528
|
+
/**
|
|
31529
|
+
* Buffer one built row for batched flushing (PRD-062c L-C1). Lazily creates the
|
|
31530
|
+
* buffer on first use (a flag-off handler never allocates one). The per-item flush
|
|
31531
|
+
* promise the buffer returns is observed fire-and-forget: a flush failure is logged
|
|
31532
|
+
* here (never swallowed) but does NOT fail the captured turn — the row is committed
|
|
31533
|
+
* to the in-memory window, which the buffer GUARANTEES to flush (window / size /
|
|
31534
|
+
* shutdown). This is the documented trade: worst-case loss is one window on a hard
|
|
31535
|
+
* crash (see {@link CaptureBuffer}); a graceful stop drains the buffer.
|
|
31536
|
+
*/
|
|
31537
|
+
bufferRow(id, row, scope) {
|
|
31538
|
+
const buffer = this.ensureBuffer();
|
|
31539
|
+
void buffer.add({ row, scope }).catch((err) => {
|
|
31540
|
+
this.deps.logger?.event("capture.flush.failed", {
|
|
31541
|
+
id,
|
|
31542
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
31543
|
+
});
|
|
31544
|
+
});
|
|
31545
|
+
}
|
|
31546
|
+
/** Lazily build the capture write buffer from the resolved config + the flush callback. */
|
|
31547
|
+
ensureBuffer() {
|
|
31548
|
+
if (this.buffer === null) {
|
|
31549
|
+
const cfg = { maxEvents: this.config.maxEvents, windowMs: this.config.windowMs };
|
|
31550
|
+
this.buffer = this.deps.bufferClock !== void 0 ? new CaptureBuffer((batch) => this.flushBatch(batch), cfg, this.deps.bufferClock) : new CaptureBuffer((batch) => this.flushBatch(batch), cfg);
|
|
31551
|
+
}
|
|
31552
|
+
return this.buffer;
|
|
31553
|
+
}
|
|
31554
|
+
/**
|
|
31555
|
+
* Flush a buffered batch as multi-row append(s) (PRD-062c L-C1 / AC-5). Rows that
|
|
31556
|
+
* share a tenancy scope are grouped and written with ONE `appendOnlyInsertMany`, so N
|
|
31557
|
+
* within-window same-scope events become ONE DeepLake write (AC-62c.1.1). Different
|
|
31558
|
+
* scopes (the rare cross-tenant interleave within a window) each get their own append —
|
|
31559
|
+
* a multi-row INSERT cannot span partitions. Every append threads the `capture-write`
|
|
31560
|
+
* 062a meter source. A failed append rejects so the awaiter ({@link bufferRow}) logs it.
|
|
31561
|
+
*/
|
|
31562
|
+
async flushBatch(batch) {
|
|
31563
|
+
for (const [scope, rows] of groupRowsByScope(batch)) {
|
|
31564
|
+
const result = await appendOnlyInsertMany(this.deps.storage, this.deps.sessionsTarget, scope, rows, {
|
|
31565
|
+
source: CAPTURE_WRITE_SOURCE
|
|
31566
|
+
});
|
|
31567
|
+
if (!isOk(result)) {
|
|
31568
|
+
this.deps.logger?.event("capture.batch_insert.failed", { count: rows.length, kind: result.kind });
|
|
31569
|
+
throw new Error(`capture batch append failed: ${result.kind}`);
|
|
31570
|
+
}
|
|
31571
|
+
}
|
|
31572
|
+
}
|
|
31573
|
+
/**
|
|
31574
|
+
* Force-flush + close the buffer on shutdown (PRD-062c AC-5 / AC-62c.1.2). Drains the
|
|
31575
|
+
* remaining window so nothing buffered is lost on a clean stop. A no-op when batching is
|
|
31576
|
+
* off (no buffer). Never throws — a flush failure on shutdown is logged, not surfaced.
|
|
31577
|
+
*/
|
|
31578
|
+
async flush() {
|
|
31579
|
+
if (this.buffer === null)
|
|
31580
|
+
return;
|
|
31581
|
+
try {
|
|
31582
|
+
await this.buffer.close();
|
|
31583
|
+
} catch (err) {
|
|
31584
|
+
this.deps.logger?.event("capture.flush.failed", {
|
|
31585
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
31586
|
+
});
|
|
31587
|
+
}
|
|
31588
|
+
}
|
|
31192
31589
|
/**
|
|
31193
31590
|
* Build the single `sessions` row's ordered column values (FR-4 / FR-5).
|
|
31194
31591
|
*
|
|
@@ -31205,8 +31602,8 @@ var CaptureRouteHandler = class {
|
|
|
31205
31602
|
* org/workspace scope the partition.
|
|
31206
31603
|
*/
|
|
31207
31604
|
buildRow(id, event, meta3, nowIso10, projectId) {
|
|
31208
|
-
const message = JSON.stringify({ event, metadata: meta3 });
|
|
31209
|
-
|
|
31605
|
+
const message = this.config.envelopeBudgetBytes > 0 ? budgetedStringify(event, meta3, this.config.envelopeBudgetBytes) : JSON.stringify({ event, metadata: meta3 });
|
|
31606
|
+
const row = [
|
|
31210
31607
|
["id", val.str(id)],
|
|
31211
31608
|
["path", val.str(meta3.path)],
|
|
31212
31609
|
["filename", val.str(meta3.hookEventName)],
|
|
@@ -31220,9 +31617,17 @@ var CaptureRouteHandler = class {
|
|
|
31220
31617
|
["project_id", val.str(projectId)],
|
|
31221
31618
|
["plugin_version", val.str(meta3.pluginVersion)],
|
|
31222
31619
|
["agent_id", val.str(meta3.agentId)],
|
|
31620
|
+
// PRD-060a (a-AC-7): the capture-source discriminant. `metadata.agent` is the
|
|
31621
|
+
// canonical harness token the shim stamps (`claude-code` for the reference
|
|
31622
|
+
// shim), so every Claude-Code-captured row carries `source_tool='claude-code'`.
|
|
31623
|
+
["source_tool", val.str(meta3.agent)],
|
|
31223
31624
|
["creation_date", val.str(nowIso10)],
|
|
31224
31625
|
["last_update_date", val.str(nowIso10)]
|
|
31225
31626
|
];
|
|
31627
|
+
for (const [col, value] of usageColumns(event)) {
|
|
31628
|
+
row.push([col, val.num(value)]);
|
|
31629
|
+
}
|
|
31630
|
+
return row;
|
|
31226
31631
|
}
|
|
31227
31632
|
/**
|
|
31228
31633
|
* Resolve the capture row's `project_id` from the session cwd (PRD-049b 49b-AC-1 / 49b-AC-3).
|
|
@@ -31365,6 +31770,36 @@ function embedTextFor(event) {
|
|
|
31365
31770
|
return [event.tool, serialize(event.input), serialize(event.response)].filter((s) => s.length > 0).join("\n");
|
|
31366
31771
|
}
|
|
31367
31772
|
}
|
|
31773
|
+
function usageColumns(event) {
|
|
31774
|
+
if (event.kind !== "assistant_message" || event.usage === void 0)
|
|
31775
|
+
return [];
|
|
31776
|
+
const u = event.usage;
|
|
31777
|
+
const cols = [];
|
|
31778
|
+
if (u.input !== void 0)
|
|
31779
|
+
cols.push(["input_tokens", u.input]);
|
|
31780
|
+
if (u.output !== void 0)
|
|
31781
|
+
cols.push(["output_tokens", u.output]);
|
|
31782
|
+
if (u.cacheRead !== void 0)
|
|
31783
|
+
cols.push(["cache_read_input_tokens", u.cacheRead]);
|
|
31784
|
+
if (u.cacheCreation !== void 0)
|
|
31785
|
+
cols.push(["cache_creation_input_tokens", u.cacheCreation]);
|
|
31786
|
+
return cols;
|
|
31787
|
+
}
|
|
31788
|
+
function groupRowsByScope(batch) {
|
|
31789
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
31790
|
+
for (const item of batch) {
|
|
31791
|
+
const key = JSON.stringify([item.scope.org, item.scope.workspace ?? ""]);
|
|
31792
|
+
const bucket = byKey.get(key);
|
|
31793
|
+
if (bucket === void 0)
|
|
31794
|
+
byKey.set(key, { scope: item.scope, rows: [item.row] });
|
|
31795
|
+
else
|
|
31796
|
+
bucket.rows.push(item.row);
|
|
31797
|
+
}
|
|
31798
|
+
const out = /* @__PURE__ */ new Map();
|
|
31799
|
+
for (const { scope, rows } of byKey.values())
|
|
31800
|
+
out.set(scope, rows);
|
|
31801
|
+
return out;
|
|
31802
|
+
}
|
|
31368
31803
|
function serialize(value) {
|
|
31369
31804
|
if (value === void 0 || value === null)
|
|
31370
31805
|
return "";
|
|
@@ -31389,7 +31824,9 @@ function attachHooksHandlers(daemon, options) {
|
|
|
31389
31824
|
...options.enqueuePipelineEntry !== void 0 ? { enqueuePipelineEntry: options.enqueuePipelineEntry } : {},
|
|
31390
31825
|
...options.firstRunGate !== void 0 ? { firstRunGate: options.firstRunGate } : {},
|
|
31391
31826
|
...options.projectsDir !== void 0 ? { projectsDir: options.projectsDir } : {},
|
|
31392
|
-
...options.logger !== void 0 ? { logger: options.logger } : {}
|
|
31827
|
+
...options.logger !== void 0 ? { logger: options.logger } : {},
|
|
31828
|
+
...options.captureConfig !== void 0 ? { captureConfig: options.captureConfig } : {},
|
|
31829
|
+
...options.bufferClock !== void 0 ? { bufferClock: options.bufferClock } : {}
|
|
31393
31830
|
});
|
|
31394
31831
|
handler.register(daemon);
|
|
31395
31832
|
const group = daemon.group(HOOKS_GROUP);
|
|
@@ -32426,9 +32863,9 @@ async function loadGrammar(language, tsx) {
|
|
|
32426
32863
|
const base = GRAMMAR_WASM[language];
|
|
32427
32864
|
const wasm = language === "typescript" && tsx ? "tree-sitter-tsx" : base;
|
|
32428
32865
|
const key = wasm;
|
|
32429
|
-
const
|
|
32430
|
-
if (
|
|
32431
|
-
return
|
|
32866
|
+
const cached3 = grammarCache.get(key);
|
|
32867
|
+
if (cached3)
|
|
32868
|
+
return cached3;
|
|
32432
32869
|
const promise2 = (async () => {
|
|
32433
32870
|
const Parser = await parserModule();
|
|
32434
32871
|
return Parser.Language.load(`${grammarDir()}${wasm}.wasm`);
|
|
@@ -34945,6 +35382,37 @@ function mountSkillPropagationApi(daemon, options) {
|
|
|
34945
35382
|
}
|
|
34946
35383
|
}
|
|
34947
35384
|
|
|
35385
|
+
// dist/src/dashboard/contracts.js
|
|
35386
|
+
var EMPTY_DASHBOARD_DATA = Object.freeze({
|
|
35387
|
+
kpis: { memoryCount: 0, sessionCount: 0, turnCount: 0, estimatedSavings: 0, teamSkillCount: 0 },
|
|
35388
|
+
sessions: { sessions: [] },
|
|
35389
|
+
settings: { orgId: "", orgName: "", workspace: "", settings: {} },
|
|
35390
|
+
graph: { built: false, nodes: [], edges: [] },
|
|
35391
|
+
rules: { rules: [] },
|
|
35392
|
+
skillSync: { skills: [] }
|
|
35393
|
+
});
|
|
35394
|
+
var EMPTY_ROI_VIEW = Object.freeze({
|
|
35395
|
+
savings: {
|
|
35396
|
+
status: "absent",
|
|
35397
|
+
measuredCents: 0,
|
|
35398
|
+
modeledCents: 0,
|
|
35399
|
+
assumption: { kind: "", assumptionText: "", signedOff: false },
|
|
35400
|
+
blendedCentsPerMtok: null
|
|
35401
|
+
},
|
|
35402
|
+
infra: { status: "absent", cents: 0, costBasis: "none" },
|
|
35403
|
+
pollination: { status: "absent", cents: 0, lines: [] },
|
|
35404
|
+
net: { status: "absent", computed: false, netCents: 0, modeled: true, costBasis: "none" },
|
|
35405
|
+
rollups: [],
|
|
35406
|
+
perUserAvailable: false,
|
|
35407
|
+
scopedAcrossDevices: false,
|
|
35408
|
+
ratesAsOf: ""
|
|
35409
|
+
});
|
|
35410
|
+
var EMPTY_ROI_TREND = Object.freeze({
|
|
35411
|
+
status: "absent",
|
|
35412
|
+
series: [],
|
|
35413
|
+
startedAt: ""
|
|
35414
|
+
});
|
|
35415
|
+
|
|
34948
35416
|
// dist/src/daemon/runtime/dashboard/installed-assets.js
|
|
34949
35417
|
import { homedir as homedir11 } from "node:os";
|
|
34950
35418
|
import { join as join16 } from "node:path";
|
|
@@ -35103,6 +35571,548 @@ function sanitizeName(name) {
|
|
|
35103
35571
|
return name.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
35104
35572
|
}
|
|
35105
35573
|
|
|
35574
|
+
// dist/src/daemon/runtime/dashboard/roi-rates.js
|
|
35575
|
+
var ANTHROPIC_CACHE_READ_MULTIPLIER = 0.1;
|
|
35576
|
+
var ANTHROPIC_CACHE_WRITE_MULTIPLIER = 1.25;
|
|
35577
|
+
function anthropicCacheRate(inputCentsPerMtok, multiplier) {
|
|
35578
|
+
return Math.round(inputCentsPerMtok * multiplier);
|
|
35579
|
+
}
|
|
35580
|
+
var RATES_AS_OF = "2026-06-26";
|
|
35581
|
+
var RATE_TABLE = Object.freeze([
|
|
35582
|
+
Object.freeze({
|
|
35583
|
+
provider: "anthropic",
|
|
35584
|
+
model: "claude-sonnet-4-6",
|
|
35585
|
+
input_cents_per_mtok: 300,
|
|
35586
|
+
output_cents_per_mtok: 1500,
|
|
35587
|
+
cache_read_cents_per_mtok: anthropicCacheRate(300, ANTHROPIC_CACHE_READ_MULTIPLIER),
|
|
35588
|
+
cache_write_cents_per_mtok: anthropicCacheRate(300, ANTHROPIC_CACHE_WRITE_MULTIPLIER)
|
|
35589
|
+
}),
|
|
35590
|
+
Object.freeze({
|
|
35591
|
+
provider: "anthropic",
|
|
35592
|
+
model: "claude-opus-4-8",
|
|
35593
|
+
input_cents_per_mtok: 1500,
|
|
35594
|
+
output_cents_per_mtok: 7500,
|
|
35595
|
+
cache_read_cents_per_mtok: anthropicCacheRate(1500, ANTHROPIC_CACHE_READ_MULTIPLIER),
|
|
35596
|
+
cache_write_cents_per_mtok: anthropicCacheRate(1500, ANTHROPIC_CACHE_WRITE_MULTIPLIER)
|
|
35597
|
+
}),
|
|
35598
|
+
// Finding (haiku-rate): the skillify gate runs `claude-haiku-4-5` (roi-pollination.ts
|
|
35599
|
+
// SKILLIFY_HAIKU_MODEL). Without its own row, `priceHaikuTokens` fell back to the Sonnet default and
|
|
35600
|
+
// MIS-priced Honeycomb's own-inference cost. Anthropic Haiku per-Mtok: $1 in / $5 out; the cache
|
|
35601
|
+
// columns are derived from input via the SAME 0.1x / 1.25x multipliers (the invariant a test asserts).
|
|
35602
|
+
Object.freeze({
|
|
35603
|
+
provider: "anthropic",
|
|
35604
|
+
model: "claude-haiku-4-5",
|
|
35605
|
+
input_cents_per_mtok: 100,
|
|
35606
|
+
output_cents_per_mtok: 500,
|
|
35607
|
+
cache_read_cents_per_mtok: anthropicCacheRate(100, ANTHROPIC_CACHE_READ_MULTIPLIER),
|
|
35608
|
+
cache_write_cents_per_mtok: anthropicCacheRate(100, ANTHROPIC_CACHE_WRITE_MULTIPLIER)
|
|
35609
|
+
})
|
|
35610
|
+
]);
|
|
35611
|
+
var DEFAULT_RATE_PROVIDER = "anthropic";
|
|
35612
|
+
var DEFAULT_RATE_MODEL = "claude-sonnet-4-6";
|
|
35613
|
+
function rateRowFor(provider, model) {
|
|
35614
|
+
return RATE_TABLE.find((r) => r.provider === provider && r.model === model);
|
|
35615
|
+
}
|
|
35616
|
+
function defaultRateRow() {
|
|
35617
|
+
const row = rateRowFor(DEFAULT_RATE_PROVIDER, DEFAULT_RATE_MODEL);
|
|
35618
|
+
if (row === void 0) {
|
|
35619
|
+
throw new Error("roi-rates: the default rate row must exist in RATE_TABLE");
|
|
35620
|
+
}
|
|
35621
|
+
return row;
|
|
35622
|
+
}
|
|
35623
|
+
function resolveRate(provider, model) {
|
|
35624
|
+
if (provider === void 0 || model === void 0 || provider.length === 0 || model.length === 0) {
|
|
35625
|
+
return defaultRateRow();
|
|
35626
|
+
}
|
|
35627
|
+
return rateRowFor(provider, model) ?? defaultRateRow();
|
|
35628
|
+
}
|
|
35629
|
+
|
|
35630
|
+
// dist/src/daemon/runtime/dashboard/roi-savings.js
|
|
35631
|
+
function measured(value) {
|
|
35632
|
+
return { tag: "measured", value };
|
|
35633
|
+
}
|
|
35634
|
+
function modeled(value, assumption) {
|
|
35635
|
+
return { tag: "modeled", value, assumption };
|
|
35636
|
+
}
|
|
35637
|
+
function tokensAtRate(tokens, centsPerMtok) {
|
|
35638
|
+
return Math.round(tokens * centsPerMtok / 1e6);
|
|
35639
|
+
}
|
|
35640
|
+
function measuredCacheSavings(turns) {
|
|
35641
|
+
let savingsCents = 0;
|
|
35642
|
+
let measuredTurns = 0;
|
|
35643
|
+
for (const turn of turns) {
|
|
35644
|
+
if (turn.cache_read_input_tokens === null)
|
|
35645
|
+
continue;
|
|
35646
|
+
measuredTurns += 1;
|
|
35647
|
+
const rate = resolveRate(turn.provider, turn.model);
|
|
35648
|
+
const deltaCentsPerMtok = rate.input_cents_per_mtok - rate.cache_read_cents_per_mtok;
|
|
35649
|
+
savingsCents += tokensAtRate(turn.cache_read_input_tokens, deltaCentsPerMtok);
|
|
35650
|
+
}
|
|
35651
|
+
const totalTurns = turns.length;
|
|
35652
|
+
const status = totalTurns === 0 || measuredTurns === 0 ? "absent" : measuredTurns < totalTurns ? "partial" : "measured";
|
|
35653
|
+
return measured({ savingsCents, measuredTurns, totalTurns, status });
|
|
35654
|
+
}
|
|
35655
|
+
function blendedCentsPerMtok(turns) {
|
|
35656
|
+
let totalCents = 0;
|
|
35657
|
+
let totalTokens = 0;
|
|
35658
|
+
for (const turn of turns) {
|
|
35659
|
+
const rate = resolveRate(turn.provider, turn.model);
|
|
35660
|
+
if (turn.input_tokens !== null) {
|
|
35661
|
+
totalCents += tokensAtRate(turn.input_tokens, rate.input_cents_per_mtok);
|
|
35662
|
+
totalTokens += turn.input_tokens;
|
|
35663
|
+
}
|
|
35664
|
+
if (turn.output_tokens !== null) {
|
|
35665
|
+
totalCents += tokensAtRate(turn.output_tokens, rate.output_cents_per_mtok);
|
|
35666
|
+
totalTokens += turn.output_tokens;
|
|
35667
|
+
}
|
|
35668
|
+
if (turn.cache_read_input_tokens !== null) {
|
|
35669
|
+
totalCents += tokensAtRate(turn.cache_read_input_tokens, rate.cache_read_cents_per_mtok);
|
|
35670
|
+
totalTokens += turn.cache_read_input_tokens;
|
|
35671
|
+
}
|
|
35672
|
+
if (turn.cache_creation_input_tokens !== null) {
|
|
35673
|
+
totalCents += tokensAtRate(turn.cache_creation_input_tokens, rate.cache_write_cents_per_mtok);
|
|
35674
|
+
totalTokens += turn.cache_creation_input_tokens;
|
|
35675
|
+
}
|
|
35676
|
+
}
|
|
35677
|
+
if (totalTokens === 0)
|
|
35678
|
+
return null;
|
|
35679
|
+
return Math.round(totalCents / totalTokens * 1e6);
|
|
35680
|
+
}
|
|
35681
|
+
var MEMORY_INJECTION_ASSUMPTION = Object.freeze({
|
|
35682
|
+
kind: "turns-saved-per-session",
|
|
35683
|
+
turnsSavedPerSession: 2,
|
|
35684
|
+
avgTokensPerSavedTurn: 4e3,
|
|
35685
|
+
includesOutputTokens: false,
|
|
35686
|
+
signedOff: false,
|
|
35687
|
+
assumptionText: "PLACEHOLDER (pending operator sign-off): estimates that injecting memory saves ~2 turns of re-explaining per session, at ~4,000 input tokens per saved turn, priced at the session's input rate. Output-token savings are NOT yet claimed. This is a model, not a billed figure."
|
|
35688
|
+
});
|
|
35689
|
+
function modeledMemoryInjectionSavings(sessions, rate = resolveRate(void 0, void 0), assumption = MEMORY_INJECTION_ASSUMPTION) {
|
|
35690
|
+
const savedTokens = Math.max(0, sessions) * assumption.turnsSavedPerSession * assumption.avgTokensPerSavedTurn;
|
|
35691
|
+
let estimatedCents = tokensAtRate(savedTokens, rate.input_cents_per_mtok);
|
|
35692
|
+
if (assumption.includesOutputTokens) {
|
|
35693
|
+
estimatedCents += tokensAtRate(savedTokens, rate.output_cents_per_mtok);
|
|
35694
|
+
}
|
|
35695
|
+
return modeled({ estimatedCents, sessions: Math.max(0, sessions) }, assumption);
|
|
35696
|
+
}
|
|
35697
|
+
|
|
35698
|
+
// dist/src/daemon/runtime/dashboard/roi-billing.js
|
|
35699
|
+
var realSleeper3 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
35700
|
+
var systemBillingClock = {
|
|
35701
|
+
now() {
|
|
35702
|
+
return Date.now();
|
|
35703
|
+
}
|
|
35704
|
+
};
|
|
35705
|
+
var DEFAULT_MAX_RETRIES2 = 3;
|
|
35706
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
35707
|
+
var DEFAULT_TTL_MS2 = 5 * 6e4;
|
|
35708
|
+
var DEEPLAKE_CLIENT_HEADER2 = "X-Deeplake-Client";
|
|
35709
|
+
var DEEPLAKE_ORG_HEADER2 = "X-Activeloop-Org-Id";
|
|
35710
|
+
var DEEPLAKE_CLIENT_VALUE2 = "honeycomb";
|
|
35711
|
+
var centsField = external_exports.number().int().catch(0);
|
|
35712
|
+
var numberField = external_exports.number().catch(0);
|
|
35713
|
+
var ComputeTierSchema = external_exports.object({
|
|
35714
|
+
tier: external_exports.string().catch(""),
|
|
35715
|
+
hours: numberField,
|
|
35716
|
+
cost_cents: centsField,
|
|
35717
|
+
unit_price_cents: centsField
|
|
35718
|
+
});
|
|
35719
|
+
var BillingComparisonSchema = external_exports.object({
|
|
35720
|
+
compute_cost_previous: centsField,
|
|
35721
|
+
total_cost_previous: centsField,
|
|
35722
|
+
delta_pct: numberField
|
|
35723
|
+
});
|
|
35724
|
+
var BillingComputeSchema = external_exports.object({
|
|
35725
|
+
total_cost_cents: centsField,
|
|
35726
|
+
total_pod_hours: numberField,
|
|
35727
|
+
by_tier: external_exports.array(ComputeTierSchema).catch([])
|
|
35728
|
+
});
|
|
35729
|
+
var BillingSummarySchema = external_exports.object({
|
|
35730
|
+
balance_cents: centsField,
|
|
35731
|
+
period_start: external_exports.string().catch(""),
|
|
35732
|
+
period_end: external_exports.string().catch(""),
|
|
35733
|
+
total_cost_cents: centsField,
|
|
35734
|
+
storage_cost_cents: centsField,
|
|
35735
|
+
transfer_cost_cents: centsField,
|
|
35736
|
+
projected_end_of_period_cents: centsField,
|
|
35737
|
+
compute: BillingComputeSchema,
|
|
35738
|
+
comparison: BillingComparisonSchema
|
|
35739
|
+
});
|
|
35740
|
+
var SESSION_TYPES = ["query", "embedding", "ingestion"];
|
|
35741
|
+
var SessionTypeSchema = external_exports.enum(SESSION_TYPES);
|
|
35742
|
+
var ComputeSessionSchema = external_exports.object({
|
|
35743
|
+
session_type: SessionTypeSchema,
|
|
35744
|
+
gpu_hours: numberField,
|
|
35745
|
+
gpu_units: numberField,
|
|
35746
|
+
price_cents_per_gpu_hour: centsField,
|
|
35747
|
+
// Finding (billing-zero): keep `total_cost_cents` OPTIONAL/nullish so a MISSING field (absent on the
|
|
35748
|
+
// wire) stays `undefined` and is distinguishable from a legitimate explicit `0` (a free session). The
|
|
35749
|
+
// `.catch(undefined)` keeps a present-but-malformed value from throwing while NOT collapsing it to 0
|
|
35750
|
+
// -- `buildSessionTypeBreakdown` derives a cost ONLY when the field is truly absent, never over an
|
|
35751
|
+
// explicit 0 (which would overwrite a legitimately-free session with gpu_hours x price).
|
|
35752
|
+
total_cost_cents: centsField.optional().nullable().catch(void 0)
|
|
35753
|
+
});
|
|
35754
|
+
var ComputeUsageSchema = external_exports.object({
|
|
35755
|
+
total_cost_cents: centsField,
|
|
35756
|
+
total_gpu_hours: numberField,
|
|
35757
|
+
sessions: external_exports.array(ComputeSessionSchema).catch([])
|
|
35758
|
+
});
|
|
35759
|
+
function sessionTypeTotalCents(lines) {
|
|
35760
|
+
return lines.reduce((sum, line) => sum + line.cost_cents, 0);
|
|
35761
|
+
}
|
|
35762
|
+
function isRetryable2(status) {
|
|
35763
|
+
return status === 429 || status >= 500 && status <= 599;
|
|
35764
|
+
}
|
|
35765
|
+
function billingHeaders(creds) {
|
|
35766
|
+
const headers = {
|
|
35767
|
+
Authorization: `Bearer ${creds.token}`,
|
|
35768
|
+
"Content-Type": "application/json",
|
|
35769
|
+
[DEEPLAKE_CLIENT_HEADER2]: DEEPLAKE_CLIENT_VALUE2
|
|
35770
|
+
};
|
|
35771
|
+
if (creds.orgId.length > 0)
|
|
35772
|
+
headers[DEEPLAKE_ORG_HEADER2] = creds.orgId;
|
|
35773
|
+
return headers;
|
|
35774
|
+
}
|
|
35775
|
+
function resolveBillingApiUrl(creds) {
|
|
35776
|
+
const base = creds.apiUrl !== void 0 && creds.apiUrl.length > 0 ? creds.apiUrl : DEFAULT_DEEPLAKE_API_URL;
|
|
35777
|
+
return base.replace(/\/+$/, "");
|
|
35778
|
+
}
|
|
35779
|
+
function buildSessionTypeBreakdown(usage) {
|
|
35780
|
+
return usage.sessions.map((s) => {
|
|
35781
|
+
const derived = Math.round(s.gpu_hours * s.price_cents_per_gpu_hour);
|
|
35782
|
+
const cost_cents = s.total_cost_cents !== void 0 && s.total_cost_cents !== null ? s.total_cost_cents : derived;
|
|
35783
|
+
return {
|
|
35784
|
+
session_type: s.session_type,
|
|
35785
|
+
gpu_hours: s.gpu_hours,
|
|
35786
|
+
price_cents_per_gpu_hour: s.price_cents_per_gpu_hour,
|
|
35787
|
+
cost_cents
|
|
35788
|
+
};
|
|
35789
|
+
});
|
|
35790
|
+
}
|
|
35791
|
+
function createInfraCostReadModel(options = {}) {
|
|
35792
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
35793
|
+
const sleep2 = options.sleep ?? realSleeper3;
|
|
35794
|
+
const clock = options.clock ?? systemBillingClock;
|
|
35795
|
+
const dir = options.dir;
|
|
35796
|
+
const loadCreds = options.creds ?? (() => loadDiskCredentials(dir));
|
|
35797
|
+
const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES2;
|
|
35798
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
35799
|
+
const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS2;
|
|
35800
|
+
let cached3;
|
|
35801
|
+
async function getJson(apiUrl, path4, headers) {
|
|
35802
|
+
for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
|
|
35803
|
+
const controller = new AbortController();
|
|
35804
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
35805
|
+
try {
|
|
35806
|
+
const resp = await doFetch(`${apiUrl}${path4}`, { method: "GET", headers, signal: controller.signal });
|
|
35807
|
+
if (resp.ok) {
|
|
35808
|
+
return await resp.json().catch(() => null);
|
|
35809
|
+
}
|
|
35810
|
+
if (isRetryable2(resp.status) && attempt < maxRetries) {
|
|
35811
|
+
clearTimeout(timer);
|
|
35812
|
+
await sleep2(250 * 2 ** attempt);
|
|
35813
|
+
continue;
|
|
35814
|
+
}
|
|
35815
|
+
return null;
|
|
35816
|
+
} catch {
|
|
35817
|
+
if (attempt < maxRetries) {
|
|
35818
|
+
clearTimeout(timer);
|
|
35819
|
+
await sleep2(250 * 2 ** attempt);
|
|
35820
|
+
continue;
|
|
35821
|
+
}
|
|
35822
|
+
return null;
|
|
35823
|
+
} finally {
|
|
35824
|
+
clearTimeout(timer);
|
|
35825
|
+
}
|
|
35826
|
+
}
|
|
35827
|
+
return null;
|
|
35828
|
+
}
|
|
35829
|
+
function parseOrMissing(raw2, schema) {
|
|
35830
|
+
if (raw2 === null || raw2 === void 0)
|
|
35831
|
+
return void 0;
|
|
35832
|
+
const result = schema.safeParse(raw2);
|
|
35833
|
+
return result.success ? result.data : void 0;
|
|
35834
|
+
}
|
|
35835
|
+
async function fetchSnapshot() {
|
|
35836
|
+
const creds = loadCreds();
|
|
35837
|
+
if (creds === null || creds.token.length === 0) {
|
|
35838
|
+
return { status: "unauthenticated", missing: [], sessionTypes: [], fetchedAt: clock.now() };
|
|
35839
|
+
}
|
|
35840
|
+
const apiUrl = resolveBillingApiUrl(creds);
|
|
35841
|
+
const headers = billingHeaders(creds);
|
|
35842
|
+
const [summaryRaw, computeRaw] = await Promise.all([
|
|
35843
|
+
getJson(apiUrl, "/billing/summary", headers),
|
|
35844
|
+
getJson(apiUrl, "/billing/usage/compute", headers)
|
|
35845
|
+
]);
|
|
35846
|
+
const summary = parseOrMissing(summaryRaw, BillingSummarySchema);
|
|
35847
|
+
const compute = parseOrMissing(computeRaw, ComputeUsageSchema);
|
|
35848
|
+
const missing = [];
|
|
35849
|
+
if (summary === void 0)
|
|
35850
|
+
missing.push("/billing/summary");
|
|
35851
|
+
if (compute === void 0)
|
|
35852
|
+
missing.push("/billing/usage/compute");
|
|
35853
|
+
const okCount = (summary !== void 0 ? 1 : 0) + (compute !== void 0 ? 1 : 0);
|
|
35854
|
+
const status = okCount === 0 ? "unreachable" : okCount === 2 ? "ok" : "partial";
|
|
35855
|
+
const sessionTypes = compute !== void 0 ? buildSessionTypeBreakdown(compute) : [];
|
|
35856
|
+
return {
|
|
35857
|
+
status,
|
|
35858
|
+
missing,
|
|
35859
|
+
...summary !== void 0 ? { summary } : {},
|
|
35860
|
+
...compute !== void 0 ? { compute } : {},
|
|
35861
|
+
sessionTypes,
|
|
35862
|
+
fetchedAt: clock.now()
|
|
35863
|
+
};
|
|
35864
|
+
}
|
|
35865
|
+
return {
|
|
35866
|
+
async read() {
|
|
35867
|
+
const now = clock.now();
|
|
35868
|
+
if (cached3 !== void 0 && now - cached3.fetchedAt < ttlMs) {
|
|
35869
|
+
return cached3;
|
|
35870
|
+
}
|
|
35871
|
+
const snapshot = await fetchSnapshot();
|
|
35872
|
+
cached3 = snapshot;
|
|
35873
|
+
return snapshot;
|
|
35874
|
+
},
|
|
35875
|
+
invalidate() {
|
|
35876
|
+
cached3 = void 0;
|
|
35877
|
+
}
|
|
35878
|
+
};
|
|
35879
|
+
}
|
|
35880
|
+
|
|
35881
|
+
// dist/src/daemon/runtime/dashboard/roi-pollination.js
|
|
35882
|
+
var SKILLIFY_PROVIDER = "anthropic";
|
|
35883
|
+
var SKILLIFY_HAIKU_MODEL = "claude-haiku-4-5";
|
|
35884
|
+
function tokensAtRate2(tokens, centsPerMtok) {
|
|
35885
|
+
return Math.round(tokens * centsPerMtok / 1e6);
|
|
35886
|
+
}
|
|
35887
|
+
function priceHaikuTokens(snapshot) {
|
|
35888
|
+
if (snapshot.perModel !== void 0 && snapshot.perModel.length > 0) {
|
|
35889
|
+
return snapshot.perModel.reduce((sum, b) => sum + priceBucket(b), 0);
|
|
35890
|
+
}
|
|
35891
|
+
const rate = resolveRate(SKILLIFY_PROVIDER, snapshot.model ?? SKILLIFY_HAIKU_MODEL);
|
|
35892
|
+
return tokensAtRate2(snapshot.inputTokens, rate.input_cents_per_mtok) + tokensAtRate2(snapshot.outputTokens, rate.output_cents_per_mtok) + tokensAtRate2(snapshot.cacheReadInputTokens, rate.cache_read_cents_per_mtok) + tokensAtRate2(snapshot.cacheCreationInputTokens, rate.cache_write_cents_per_mtok);
|
|
35893
|
+
}
|
|
35894
|
+
function priceBucket(b) {
|
|
35895
|
+
const rate = resolveRate(SKILLIFY_PROVIDER, b.model.length > 0 ? b.model : SKILLIFY_HAIKU_MODEL);
|
|
35896
|
+
return tokensAtRate2(b.inputTokens, rate.input_cents_per_mtok) + tokensAtRate2(b.outputTokens, rate.output_cents_per_mtok) + tokensAtRate2(b.cacheReadInputTokens, rate.cache_read_cents_per_mtok) + tokensAtRate2(b.cacheCreationInputTokens, rate.cache_write_cents_per_mtok);
|
|
35897
|
+
}
|
|
35898
|
+
function composeHaikuContribution(snapshot) {
|
|
35899
|
+
const buckets = snapshot.perModel;
|
|
35900
|
+
const model = buckets !== void 0 && buckets.length > 1 ? "mixed" : buckets !== void 0 && buckets.length === 1 ? buckets[0].model : snapshot.model ?? SKILLIFY_HAIKU_MODEL;
|
|
35901
|
+
if (snapshot.recorded === 0) {
|
|
35902
|
+
return {
|
|
35903
|
+
status: "absent",
|
|
35904
|
+
cents: 0,
|
|
35905
|
+
recorded: 0,
|
|
35906
|
+
inputTokens: 0,
|
|
35907
|
+
outputTokens: 0,
|
|
35908
|
+
cacheReadInputTokens: 0,
|
|
35909
|
+
cacheCreationInputTokens: 0,
|
|
35910
|
+
model
|
|
35911
|
+
};
|
|
35912
|
+
}
|
|
35913
|
+
return {
|
|
35914
|
+
status: "measured",
|
|
35915
|
+
cents: priceHaikuTokens(snapshot),
|
|
35916
|
+
recorded: snapshot.recorded,
|
|
35917
|
+
inputTokens: snapshot.inputTokens,
|
|
35918
|
+
outputTokens: snapshot.outputTokens,
|
|
35919
|
+
cacheReadInputTokens: snapshot.cacheReadInputTokens,
|
|
35920
|
+
cacheCreationInputTokens: snapshot.cacheCreationInputTokens,
|
|
35921
|
+
model
|
|
35922
|
+
};
|
|
35923
|
+
}
|
|
35924
|
+
function emptyPerType() {
|
|
35925
|
+
return { query: 0, embedding: 0, ingestion: 0 };
|
|
35926
|
+
}
|
|
35927
|
+
function composeDeeplakeContribution(infra) {
|
|
35928
|
+
const perTypeCents = emptyPerType();
|
|
35929
|
+
for (const line of infra.sessionTypes) {
|
|
35930
|
+
perTypeCents[line.session_type] += line.cost_cents;
|
|
35931
|
+
}
|
|
35932
|
+
return {
|
|
35933
|
+
status: infra.status,
|
|
35934
|
+
cents: sessionTypeTotalCents(infra.sessionTypes),
|
|
35935
|
+
bySessionType: infra.sessionTypes,
|
|
35936
|
+
perTypeCents
|
|
35937
|
+
};
|
|
35938
|
+
}
|
|
35939
|
+
var STATUS_SEVERITY = Object.freeze({
|
|
35940
|
+
unauthenticated: 0,
|
|
35941
|
+
// worst — no credentials, no figure.
|
|
35942
|
+
unreachable: 1,
|
|
35943
|
+
// billing could not be read.
|
|
35944
|
+
absent: 2,
|
|
35945
|
+
// Haiku has no data yet.
|
|
35946
|
+
partial: 3,
|
|
35947
|
+
// billing partially read.
|
|
35948
|
+
measured: 4,
|
|
35949
|
+
// Haiku ok (a real token figure).
|
|
35950
|
+
ok: 5
|
|
35951
|
+
// best — billing fully read.
|
|
35952
|
+
});
|
|
35953
|
+
function worstPollinationStatus(haiku, deeplake) {
|
|
35954
|
+
if (haiku === "measured" && deeplake === "ok")
|
|
35955
|
+
return "ok";
|
|
35956
|
+
const haikuStatus = haiku;
|
|
35957
|
+
const deeplakeStatus = deeplake;
|
|
35958
|
+
return STATUS_SEVERITY[haikuStatus] <= STATUS_SEVERITY[deeplakeStatus] ? haikuStatus : deeplakeStatus;
|
|
35959
|
+
}
|
|
35960
|
+
function composePollinationCost(usage, infra) {
|
|
35961
|
+
const haiku = composeHaikuContribution(usage.snapshot());
|
|
35962
|
+
const deeplake = composeDeeplakeContribution(infra);
|
|
35963
|
+
return {
|
|
35964
|
+
pollinationCents: haiku.cents + deeplake.cents,
|
|
35965
|
+
status: worstPollinationStatus(haiku.status, deeplake.status),
|
|
35966
|
+
haiku,
|
|
35967
|
+
deeplake
|
|
35968
|
+
};
|
|
35969
|
+
}
|
|
35970
|
+
|
|
35971
|
+
// dist/src/daemon/runtime/dashboard/roi-skillify-meter.js
|
|
35972
|
+
function emptySnapshot() {
|
|
35973
|
+
return {
|
|
35974
|
+
recorded: 0,
|
|
35975
|
+
inputTokens: 0,
|
|
35976
|
+
outputTokens: 0,
|
|
35977
|
+
cacheReadInputTokens: 0,
|
|
35978
|
+
cacheCreationInputTokens: 0
|
|
35979
|
+
};
|
|
35980
|
+
}
|
|
35981
|
+
function snapshotSource(snapshot) {
|
|
35982
|
+
return { snapshot: () => snapshot };
|
|
35983
|
+
}
|
|
35984
|
+
var emptyUsageSource = snapshotSource(emptySnapshot());
|
|
35985
|
+
|
|
35986
|
+
// dist/src/daemon/runtime/recall/scope-clause.js
|
|
35987
|
+
var PROJECT_ID_COLUMN = "project_id";
|
|
35988
|
+
var PROJECT_ID_UNSET = "";
|
|
35989
|
+
var CROSS_PROJECT_ADMITTED = Object.freeze(["user", "workspace"]);
|
|
35990
|
+
var SCOPE_READ_POLICIES = Object.freeze(["isolated", "shared", "group"]);
|
|
35991
|
+
function asReadPolicy(raw2) {
|
|
35992
|
+
return SCOPE_READ_POLICIES.includes(raw2) ? raw2 : null;
|
|
35993
|
+
}
|
|
35994
|
+
function buildProjectScopeClause(input) {
|
|
35995
|
+
const projectColumn = input.projectColumn ?? PROJECT_ID_COLUMN;
|
|
35996
|
+
const rawId = input.projectId ?? "";
|
|
35997
|
+
const isInbox = rawId.trim() === "" || rawId === UNSORTED_PROJECT_ID;
|
|
35998
|
+
const bound = input.bound ?? !isInbox;
|
|
35999
|
+
const col = sqlIdent(projectColumn);
|
|
36000
|
+
const primaryId = bound ? rawId : UNSORTED_PROJECT_ID;
|
|
36001
|
+
const admitted = primaryId === PROJECT_ID_UNSET ? [PROJECT_ID_UNSET] : [primaryId, PROJECT_ID_UNSET];
|
|
36002
|
+
const disjuncts = admitted.map((id) => `${col} = ${sLiteral(id)}`);
|
|
36003
|
+
const values = [...admitted];
|
|
36004
|
+
if (input.promotionColumn !== void 0 && input.promotionColumn !== "") {
|
|
36005
|
+
const promoCol = sqlIdent(input.promotionColumn);
|
|
36006
|
+
for (const reach of CROSS_PROJECT_ADMITTED) {
|
|
36007
|
+
disjuncts.push(`${promoCol} = ${sLiteral(reach)}`);
|
|
36008
|
+
values.push(reach);
|
|
36009
|
+
}
|
|
36010
|
+
}
|
|
36011
|
+
const sql = `(${disjuncts.join(" OR ")})`;
|
|
36012
|
+
return { sql, values, bound };
|
|
36013
|
+
}
|
|
36014
|
+
function buildProjectScopeConjunct(input) {
|
|
36015
|
+
return ` AND ${buildProjectScopeClause(input).sql}`;
|
|
36016
|
+
}
|
|
36017
|
+
|
|
36018
|
+
// dist/src/daemon/runtime/dashboard/roi-ledger.js
|
|
36019
|
+
var BACKEND_TOKEN_SOURCE = "backend-token";
|
|
36020
|
+
function resolveGatedUserId(verifiedClaim) {
|
|
36021
|
+
if (verifiedClaim !== void 0 && verifiedClaim.source === BACKEND_TOKEN_SOURCE) {
|
|
36022
|
+
return verifiedClaim.userId;
|
|
36023
|
+
}
|
|
36024
|
+
return "";
|
|
36025
|
+
}
|
|
36026
|
+
async function resolveTeamId(client, scope, agentId) {
|
|
36027
|
+
const tbl = sqlIdent("teams");
|
|
36028
|
+
const memberType = sqlIdent("member_type");
|
|
36029
|
+
const memberId = sqlIdent("member_id");
|
|
36030
|
+
const activeCol = sqlIdent("active");
|
|
36031
|
+
const versionCol = sqlIdent("version");
|
|
36032
|
+
const sql = `SELECT team_id FROM "${tbl}" AS t WHERE ${memberType} = ${sLiteral("agent")} AND ${memberId} = ${sLiteral(agentId)} AND ${activeCol} = ${TEAM_ACTIVE} AND ${versionCol} = (SELECT MAX(${versionCol}) FROM "${tbl}" AS u WHERE u.${memberType} = ${sLiteral("agent")} AND u.${memberId} = ${sLiteral(agentId)}) LIMIT 1`;
|
|
36033
|
+
let res;
|
|
36034
|
+
try {
|
|
36035
|
+
res = await client.query(sql, scope);
|
|
36036
|
+
} catch {
|
|
36037
|
+
return "";
|
|
36038
|
+
}
|
|
36039
|
+
if (!isOk(res) || res.rows.length === 0)
|
|
36040
|
+
return "";
|
|
36041
|
+
const raw2 = res.rows[0].team_id;
|
|
36042
|
+
return typeof raw2 === "string" ? raw2 : "";
|
|
36043
|
+
}
|
|
36044
|
+
function toInt(n) {
|
|
36045
|
+
if (n === void 0 || !Number.isFinite(n))
|
|
36046
|
+
return 0;
|
|
36047
|
+
return Math.trunc(n);
|
|
36048
|
+
}
|
|
36049
|
+
function asCostBasis(raw2) {
|
|
36050
|
+
return raw2 !== void 0 && ROI_COST_BASES.includes(raw2) ? raw2 : "none";
|
|
36051
|
+
}
|
|
36052
|
+
async function appendRoiMetric(client, scope, input) {
|
|
36053
|
+
const agentId = input.agentId.trim() === "" ? "default" : input.agentId;
|
|
36054
|
+
const teamId = await resolveTeamId(client, scope, agentId);
|
|
36055
|
+
const userId = resolveGatedUserId(input.verifiedClaim);
|
|
36056
|
+
const costBasis = asCostBasis(input.costBasis);
|
|
36057
|
+
const row = [
|
|
36058
|
+
["id", val.str(input.id)],
|
|
36059
|
+
["session_id", val.str(input.sessionId)],
|
|
36060
|
+
["org_id", val.str(scope.org)],
|
|
36061
|
+
["workspace_id", val.str(scope.workspace ?? "")],
|
|
36062
|
+
["agent_id", val.str(agentId)],
|
|
36063
|
+
["project_id", val.str(input.projectId ?? "")],
|
|
36064
|
+
["team_id", val.str(teamId)],
|
|
36065
|
+
["user_id", val.str(userId)],
|
|
36066
|
+
["input_tokens", val.num(toInt(input.inputTokens))],
|
|
36067
|
+
["output_tokens", val.num(toInt(input.outputTokens))],
|
|
36068
|
+
["cache_read_tokens", val.num(toInt(input.cacheReadTokens))],
|
|
36069
|
+
["cache_creation_tokens", val.num(toInt(input.cacheCreationTokens))],
|
|
36070
|
+
["measured_cache_savings_cents", val.num(toInt(input.measuredCacheSavingsCents))],
|
|
36071
|
+
["modeled_savings_cents", val.num(toInt(input.modeledSavingsCents))],
|
|
36072
|
+
["modeled_assumption_ref", val.str(input.modeledAssumptionRef ?? "")],
|
|
36073
|
+
["gross_cost_cents", val.num(toInt(input.grossCostCents))],
|
|
36074
|
+
["infra_cost_cents", val.num(toInt(input.infraCostCents))],
|
|
36075
|
+
["cost_basis", val.str(costBasis)],
|
|
36076
|
+
["allocation_method", val.str(input.allocationMethod ?? "")],
|
|
36077
|
+
["price_ref", val.str(input.priceRef ?? "")],
|
|
36078
|
+
["period_start", val.str(input.periodStart ?? "")],
|
|
36079
|
+
["period_end", val.str(input.periodEnd ?? "")],
|
|
36080
|
+
["created_at", val.str(input.createdAt)]
|
|
36081
|
+
];
|
|
36082
|
+
const result = await appendOnlyInsert(client, healTargetFor("roi_metrics"), scope, row);
|
|
36083
|
+
return { result, teamId, userId };
|
|
36084
|
+
}
|
|
36085
|
+
function buildRoiReadScopeSql(input, tableAlias) {
|
|
36086
|
+
const agentCol = tableAlias !== void 0 ? `${sqlIdent(tableAlias)}.${sqlIdent("agent_id")}` : sqlIdent("agent_id");
|
|
36087
|
+
const ownSql = `${agentCol} = ${sLiteral(input.agentId)}`;
|
|
36088
|
+
const noRows = `(${sLiteral("1")} = ${sLiteral("0")})`;
|
|
36089
|
+
const policy = asReadPolicy(input.readPolicy);
|
|
36090
|
+
if (input.agentId.trim() === "" || policy === null || policy === "isolated") {
|
|
36091
|
+
const ownClause = input.agentId.trim() === "" ? noRows : ownSql;
|
|
36092
|
+
return { sql: `(${ownClause})`, policyApplied: "isolated" };
|
|
36093
|
+
}
|
|
36094
|
+
if (policy === "shared") {
|
|
36095
|
+
return { sql: `(${sLiteral("1")} = ${sLiteral("1")})`, policyApplied: "shared" };
|
|
36096
|
+
}
|
|
36097
|
+
return { sql: `(${ownSql})`, policyApplied: "group" };
|
|
36098
|
+
}
|
|
36099
|
+
async function readRoiMetrics(client, scope, input) {
|
|
36100
|
+
const tbl = sqlIdent("roi_metrics");
|
|
36101
|
+
const { sql: scopeSql } = buildRoiReadScopeSql(input, "m");
|
|
36102
|
+
const projectClause = input.projectId !== void 0 && input.projectId.trim() !== "" ? ` AND ${sqlIdent("m")}.${sqlIdent("project_id")} = ${sLiteral(input.projectId.trim())}` : "";
|
|
36103
|
+
const sql = `SELECT m.* FROM "${tbl}" AS m WHERE ${scopeSql}${projectClause} AND NOT EXISTS (SELECT 1 FROM "${tbl}" AS n WHERE n.session_id = m.session_id AND (n.created_at > m.created_at OR (n.created_at = m.created_at AND n.id > m.id)))`;
|
|
36104
|
+
let res;
|
|
36105
|
+
try {
|
|
36106
|
+
res = await client.query(sql, scope);
|
|
36107
|
+
} catch (err) {
|
|
36108
|
+
return { status: "shared-ledger-absent", reason: err instanceof Error ? err.message : "query threw" };
|
|
36109
|
+
}
|
|
36110
|
+
if (!isOk(res)) {
|
|
36111
|
+
return { status: "shared-ledger-absent", reason: res.kind === "query_error" ? res.message : res.kind };
|
|
36112
|
+
}
|
|
36113
|
+
return { status: "ok", rows: res.rows };
|
|
36114
|
+
}
|
|
36115
|
+
|
|
35106
36116
|
// dist/src/daemon/runtime/dashboard/api.js
|
|
35107
36117
|
var DASHBOARD_GROUPS = Object.freeze({
|
|
35108
36118
|
/**
|
|
@@ -35147,7 +36157,14 @@ var DASHBOARD_GROUPS = Object.freeze({
|
|
|
35147
36157
|
* READ-ONLY filesystem walk; tenancy-independent (no org header required). PRD-036b calls
|
|
35148
36158
|
* the underlying `scanInstalledAssets` IN-PROCESS, not over this HTTP surface.
|
|
35149
36159
|
*/
|
|
35150
|
-
installedAssets: "/api/diagnostics"
|
|
36160
|
+
installedAssets: "/api/diagnostics",
|
|
36161
|
+
/**
|
|
36162
|
+
* ROI composite read-model (PRD-060e) — served off the diagnostics group at `/roi` + `/roi/trend`
|
|
36163
|
+
* (full paths `/api/diagnostics/roi` + `/api/diagnostics/roi/trend`). Local-mode-only loopback like
|
|
36164
|
+
* every other dashboard view-model; attached under the already-mounted, protected diagnostics group
|
|
36165
|
+
* (no new group, no `server.ts` edit). The page is a PURE function of the `RoiView` this returns.
|
|
36166
|
+
*/
|
|
36167
|
+
roi: "/api/diagnostics"
|
|
35151
36168
|
});
|
|
35152
36169
|
function toNum2(value) {
|
|
35153
36170
|
const n = typeof value === "number" ? value : Number(value ?? 0);
|
|
@@ -35331,6 +36348,176 @@ async function fetchSkillSyncView(storage, scope, scan = scanInstalledAssets) {
|
|
|
35331
36348
|
}
|
|
35332
36349
|
return { skills: [...merged.values()] };
|
|
35333
36350
|
}
|
|
36351
|
+
var DEFAULT_ROI_READ_POLICY = "shared";
|
|
36352
|
+
function roiSectionStatusFor(status) {
|
|
36353
|
+
if (status === "measured")
|
|
36354
|
+
return "ok";
|
|
36355
|
+
return status;
|
|
36356
|
+
}
|
|
36357
|
+
function tokenCountOrNull(value) {
|
|
36358
|
+
if (value === null || value === void 0)
|
|
36359
|
+
return null;
|
|
36360
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
36361
|
+
return Number.isFinite(n) ? Math.trunc(n) : null;
|
|
36362
|
+
}
|
|
36363
|
+
function rowToCapturedTurn(r) {
|
|
36364
|
+
const sourceTool = toStr2(r.source_tool);
|
|
36365
|
+
return {
|
|
36366
|
+
input_tokens: tokenCountOrNull(r.input_tokens),
|
|
36367
|
+
output_tokens: tokenCountOrNull(r.output_tokens),
|
|
36368
|
+
cache_read_input_tokens: tokenCountOrNull(r.cache_read_input_tokens),
|
|
36369
|
+
cache_creation_input_tokens: tokenCountOrNull(r.cache_creation_input_tokens),
|
|
36370
|
+
...sourceTool !== "" ? { sourceTool } : {}
|
|
36371
|
+
};
|
|
36372
|
+
}
|
|
36373
|
+
var ROI_SESSIONS_LIMIT = 5e3;
|
|
36374
|
+
async function readCapturedTurns(storage, scope, projectId) {
|
|
36375
|
+
const tbl = sqlIdent("sessions");
|
|
36376
|
+
const dateCol = sqlIdent("creation_date");
|
|
36377
|
+
const idCol = sqlIdent("id");
|
|
36378
|
+
const projClause = projectId !== void 0 && projectId !== "" ? ` WHERE ${sqlIdent("project_id")} = ${sLiteral(projectId)}` : "";
|
|
36379
|
+
const sql = `SELECT ${sqlIdent("input_tokens")}, ${sqlIdent("output_tokens")}, ${sqlIdent("cache_read_input_tokens")}, ${sqlIdent("cache_creation_input_tokens")}, ${sqlIdent("source_tool")} FROM "${tbl}"${projClause} ORDER BY ${dateCol} DESC, ${idCol} DESC LIMIT ${ROI_SESSIONS_LIMIT}`;
|
|
36380
|
+
const rows = await selectRows2(storage, sql, scope);
|
|
36381
|
+
return rows.map(rowToCapturedTurn);
|
|
36382
|
+
}
|
|
36383
|
+
var ROLLUP_DIMENSIONS = Object.freeze([
|
|
36384
|
+
{ dimension: "org", column: "org_id" },
|
|
36385
|
+
{ dimension: "team", column: "team_id" },
|
|
36386
|
+
{ dimension: "agent", column: "agent_id" },
|
|
36387
|
+
{ dimension: "project", column: "project_id" }
|
|
36388
|
+
]);
|
|
36389
|
+
function asCostBasisTag(raw2) {
|
|
36390
|
+
const s = toStr2(raw2);
|
|
36391
|
+
return s === "measured" || s === "allocated" || s === "none" ? s : "none";
|
|
36392
|
+
}
|
|
36393
|
+
function computeRollups(rows) {
|
|
36394
|
+
return ROLLUP_DIMENSIONS.map(({ dimension, column }) => {
|
|
36395
|
+
const groups = /* @__PURE__ */ new Map();
|
|
36396
|
+
const allBases = /* @__PURE__ */ new Set();
|
|
36397
|
+
for (const r of rows) {
|
|
36398
|
+
const key = toStr2(r[column]);
|
|
36399
|
+
const measured2 = toNum2(r.measured_cache_savings_cents);
|
|
36400
|
+
const modeled2 = toNum2(r.modeled_savings_cents);
|
|
36401
|
+
const infra = toNum2(r.infra_cost_cents);
|
|
36402
|
+
const gross = toNum2(r.gross_cost_cents);
|
|
36403
|
+
const basis = asCostBasisTag(r.cost_basis);
|
|
36404
|
+
allBases.add(basis);
|
|
36405
|
+
const g = groups.get(key) ?? { measured: 0, net: 0, infra: 0, sessions: 0, bases: /* @__PURE__ */ new Set() };
|
|
36406
|
+
g.measured += measured2;
|
|
36407
|
+
g.net += measured2 + modeled2 - (infra + gross);
|
|
36408
|
+
g.infra += infra;
|
|
36409
|
+
g.sessions += 1;
|
|
36410
|
+
g.bases.add(basis);
|
|
36411
|
+
groups.set(key, g);
|
|
36412
|
+
}
|
|
36413
|
+
const rollupRows = [...groups.entries()].map(([key, g]) => ({
|
|
36414
|
+
key,
|
|
36415
|
+
label: key,
|
|
36416
|
+
measuredSavingsCents: g.measured,
|
|
36417
|
+
netCents: g.net,
|
|
36418
|
+
infraCostCents: g.infra,
|
|
36419
|
+
// A row whose own group mixes bases is flagged `allocated` (the more-cautious tag); a single
|
|
36420
|
+
// basis carries through verbatim, so a measured-only row stays `measured`.
|
|
36421
|
+
costBasis: g.bases.size > 1 ? "allocated" : [...g.bases][0] ?? "none",
|
|
36422
|
+
sessions: g.sessions
|
|
36423
|
+
}));
|
|
36424
|
+
return { dimension, rows: rollupRows, mixedBasis: allBases.size > 1 };
|
|
36425
|
+
});
|
|
36426
|
+
}
|
|
36427
|
+
async function fetchRoiView(storage, scope, options = {}) {
|
|
36428
|
+
const agentId = options.agentId !== void 0 && options.agentId.trim() !== "" ? options.agentId.trim() : "";
|
|
36429
|
+
const readPolicy = options.readPolicy ?? DEFAULT_ROI_READ_POLICY;
|
|
36430
|
+
const infraModel = options.infra ?? createInfraCostReadModel();
|
|
36431
|
+
const usage = options.usage ?? emptyUsageSource;
|
|
36432
|
+
const projectId = options.projectId !== void 0 && options.projectId.trim() !== "" ? options.projectId.trim() : void 0;
|
|
36433
|
+
try {
|
|
36434
|
+
const [turns, infra, ledger] = await Promise.all([
|
|
36435
|
+
readCapturedTurns(storage, scope, projectId),
|
|
36436
|
+
infraModel.read(),
|
|
36437
|
+
readRoiMetrics(storage, scope, { agentId, readPolicy, ...projectId !== void 0 ? { projectId } : {} })
|
|
36438
|
+
]);
|
|
36439
|
+
return assembleRoiView({ turns, infra, usage, ledger, readPolicy });
|
|
36440
|
+
} catch {
|
|
36441
|
+
return EMPTY_ROI_VIEW;
|
|
36442
|
+
}
|
|
36443
|
+
}
|
|
36444
|
+
function assembleRoiView(input) {
|
|
36445
|
+
const { turns, infra, usage, ledger, readPolicy } = input;
|
|
36446
|
+
const measured2 = measuredCacheSavings(turns);
|
|
36447
|
+
const modeled2 = modeledMemoryInjectionSavings(turns.length);
|
|
36448
|
+
const blended = blendedCentsPerMtok(turns);
|
|
36449
|
+
const captureStatus = measured2.value.status;
|
|
36450
|
+
const savingsStatus = captureStatus === "measured" ? "ok" : captureStatus;
|
|
36451
|
+
const savings = {
|
|
36452
|
+
status: savingsStatus,
|
|
36453
|
+
measuredCents: measured2.value.savingsCents,
|
|
36454
|
+
modeledCents: modeled2.value.estimatedCents,
|
|
36455
|
+
assumption: {
|
|
36456
|
+
kind: modeled2.assumption.kind,
|
|
36457
|
+
assumptionText: modeled2.assumption.assumptionText,
|
|
36458
|
+
signedOff: modeled2.assumption.signedOff
|
|
36459
|
+
},
|
|
36460
|
+
blendedCentsPerMtok: blended
|
|
36461
|
+
};
|
|
36462
|
+
const infraStatus = roiSectionStatusFor(infra.status);
|
|
36463
|
+
const infraCents = infra.summary !== void 0 ? infra.summary.total_cost_cents : 0;
|
|
36464
|
+
const infraSection = {
|
|
36465
|
+
status: infraStatus,
|
|
36466
|
+
cents: infraCents,
|
|
36467
|
+
// Org/workspace infra read from billing is a MEASURED fact when present; otherwise no line.
|
|
36468
|
+
costBasis: infra.status === "ok" || infra.status === "partial" ? "measured" : "none"
|
|
36469
|
+
};
|
|
36470
|
+
const pollination = composePollinationCost(usage, infra);
|
|
36471
|
+
const pollinationLines = [
|
|
36472
|
+
{ label: "haiku-skillify", cents: pollination.haiku.cents },
|
|
36473
|
+
...pollination.deeplake.bySessionType.map((s) => ({ label: `deeplake-${s.session_type}`, cents: s.cost_cents }))
|
|
36474
|
+
];
|
|
36475
|
+
const pollinationSection = {
|
|
36476
|
+
status: roiSectionStatusFor(pollination.status),
|
|
36477
|
+
cents: pollination.pollinationCents,
|
|
36478
|
+
lines: pollinationLines
|
|
36479
|
+
};
|
|
36480
|
+
const savingsPresent = savingsStatus === "ok";
|
|
36481
|
+
const infraConfident = infraStatus === "ok";
|
|
36482
|
+
const pollinationConfident = pollinationSection.status === "ok";
|
|
36483
|
+
const netComputable = savingsPresent && infraConfident && pollinationConfident;
|
|
36484
|
+
let netSection;
|
|
36485
|
+
if (netComputable) {
|
|
36486
|
+
const netCents = measured2.value.savingsCents + modeled2.value.estimatedCents - (infraCents + pollination.pollinationCents);
|
|
36487
|
+
netSection = {
|
|
36488
|
+
status: "ok",
|
|
36489
|
+
computed: true,
|
|
36490
|
+
netCents,
|
|
36491
|
+
modeled: true,
|
|
36492
|
+
// the net folds a modeled term → ALWAYS `est.` (e-AC-3 net-hero inheritance).
|
|
36493
|
+
costBasis: infraSection.costBasis
|
|
36494
|
+
};
|
|
36495
|
+
} else {
|
|
36496
|
+
const reason = !savingsPresent ? savingsStatus : !infraConfident ? infraStatus : pollinationSection.status;
|
|
36497
|
+
netSection = { status: reason, computed: false, netCents: 0, modeled: true, costBasis: "none" };
|
|
36498
|
+
}
|
|
36499
|
+
const ledgerRows = ledger.status === "ok" ? ledger.rows : [];
|
|
36500
|
+
const rollups = computeRollups(ledgerRows);
|
|
36501
|
+
return {
|
|
36502
|
+
savings,
|
|
36503
|
+
infra: infraSection,
|
|
36504
|
+
pollination: pollinationSection,
|
|
36505
|
+
net: netSection,
|
|
36506
|
+
rollups,
|
|
36507
|
+
// PER-USER GATE (e-AC-14): there is no verified backend user-claim today, so per-user is NEVER
|
|
36508
|
+
// available — the page shows the "per-user requires verified login" empty state, never a $0/name.
|
|
36509
|
+
perUserAvailable: false,
|
|
36510
|
+
// ACROSS-DEVICE (e-AC-12): a `shared` read returned workspace-wide rows (across devices); an
|
|
36511
|
+
// `isolated` read returned only this machine's. The page captions the scope from this.
|
|
36512
|
+
scopedAcrossDevices: readPolicy === "shared",
|
|
36513
|
+
ratesAsOf: RATES_AS_OF
|
|
36514
|
+
};
|
|
36515
|
+
}
|
|
36516
|
+
async function fetchRoiTrendView(storage, scope, _range, _options = {}) {
|
|
36517
|
+
void storage;
|
|
36518
|
+
void scope;
|
|
36519
|
+
return EMPTY_ROI_TREND;
|
|
36520
|
+
}
|
|
35334
36521
|
var NO_ORG_BODY4 = { error: "bad_request", reason: "x-honeycomb-org header is required" };
|
|
35335
36522
|
function mountDashboardApi(daemon, options) {
|
|
35336
36523
|
const storage = options.storage;
|
|
@@ -35398,16 +36585,44 @@ function mountDashboardApi(daemon, options) {
|
|
|
35398
36585
|
return c.json(await inventoryCache());
|
|
35399
36586
|
});
|
|
35400
36587
|
}
|
|
36588
|
+
const roi = daemon.group(DASHBOARD_GROUPS.roi);
|
|
36589
|
+
if (roi !== void 0) {
|
|
36590
|
+
const roiOptions = (c, scope) => {
|
|
36591
|
+
const project = resolveRequestProject(c, scope);
|
|
36592
|
+
return {
|
|
36593
|
+
...options.roiInfra !== void 0 ? { infra: options.roiInfra } : {},
|
|
36594
|
+
...options.roiUsage !== void 0 ? { usage: options.roiUsage } : {},
|
|
36595
|
+
readPolicy: resolveRoiReadPolicy(c.req.query("policy")),
|
|
36596
|
+
...!project.degraded ? { projectId: project.projectId } : {}
|
|
36597
|
+
};
|
|
36598
|
+
};
|
|
36599
|
+
roi.get("/roi", async (c) => {
|
|
36600
|
+
const scope = resolveScope5(c);
|
|
36601
|
+
if (scope === null)
|
|
36602
|
+
return c.json(NO_ORG_BODY4, 400);
|
|
36603
|
+
return c.json(await fetchRoiView(storage, scope, roiOptions(c, scope)));
|
|
36604
|
+
});
|
|
36605
|
+
roi.get("/roi/trend", async (c) => {
|
|
36606
|
+
const scope = resolveScope5(c);
|
|
36607
|
+
if (scope === null)
|
|
36608
|
+
return c.json(NO_ORG_BODY4, 400);
|
|
36609
|
+
const range = c.req.query("range") ?? "";
|
|
36610
|
+
return c.json(await fetchRoiTrendView(storage, scope, range, roiOptions(c, scope)));
|
|
36611
|
+
});
|
|
36612
|
+
}
|
|
36613
|
+
}
|
|
36614
|
+
function resolveRoiReadPolicy(raw2) {
|
|
36615
|
+
return raw2 === "isolated" || raw2 === "shared" || raw2 === "group" ? raw2 : DEFAULT_ROI_READ_POLICY;
|
|
35401
36616
|
}
|
|
35402
36617
|
var INSTALLED_ASSETS_TTL_MS = 5e3;
|
|
35403
36618
|
function createInventoryCache() {
|
|
35404
|
-
let
|
|
36619
|
+
let cached3;
|
|
35405
36620
|
return async () => {
|
|
35406
36621
|
const now = Date.now();
|
|
35407
|
-
if (
|
|
35408
|
-
return
|
|
36622
|
+
if (cached3 !== void 0 && now - cached3.at < INSTALLED_ASSETS_TTL_MS)
|
|
36623
|
+
return cached3.value;
|
|
35409
36624
|
const value = await scanInstalledAssets();
|
|
35410
|
-
|
|
36625
|
+
cached3 = { value, at: now };
|
|
35411
36626
|
return value;
|
|
35412
36627
|
};
|
|
35413
36628
|
}
|
|
@@ -35693,8 +36908,61 @@ function nestedString(raw2, a, b) {
|
|
|
35693
36908
|
function userMessageData(text) {
|
|
35694
36909
|
return { kind: "user_message", text };
|
|
35695
36910
|
}
|
|
35696
|
-
function assistantMessageData(text) {
|
|
35697
|
-
|
|
36911
|
+
function assistantMessageData(text, usage) {
|
|
36912
|
+
const normalized = usage !== void 0 ? compactUsage(usage) : void 0;
|
|
36913
|
+
return {
|
|
36914
|
+
kind: "assistant_message",
|
|
36915
|
+
text,
|
|
36916
|
+
...normalized !== void 0 ? { usage: normalized } : {}
|
|
36917
|
+
};
|
|
36918
|
+
}
|
|
36919
|
+
function compactUsage(usage) {
|
|
36920
|
+
const out = {};
|
|
36921
|
+
if (isCount(usage.input))
|
|
36922
|
+
out.input = usage.input;
|
|
36923
|
+
if (isCount(usage.output))
|
|
36924
|
+
out.output = usage.output;
|
|
36925
|
+
if (isCount(usage.cacheRead))
|
|
36926
|
+
out.cacheRead = usage.cacheRead;
|
|
36927
|
+
if (isCount(usage.cacheCreation))
|
|
36928
|
+
out.cacheCreation = usage.cacheCreation;
|
|
36929
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
36930
|
+
}
|
|
36931
|
+
function isCount(n) {
|
|
36932
|
+
return typeof n === "number" && Number.isInteger(n) && n >= 0;
|
|
36933
|
+
}
|
|
36934
|
+
function extractTurnUsage(raw2) {
|
|
36935
|
+
const block = usageBlock(raw2);
|
|
36936
|
+
if (block === void 0)
|
|
36937
|
+
return void 0;
|
|
36938
|
+
const usage = {
|
|
36939
|
+
...readCount(block, "input_tokens") !== void 0 ? { input: readCount(block, "input_tokens") } : {},
|
|
36940
|
+
...readCount(block, "output_tokens") !== void 0 ? { output: readCount(block, "output_tokens") } : {},
|
|
36941
|
+
...readCount(block, "cache_read_input_tokens") !== void 0 ? { cacheRead: readCount(block, "cache_read_input_tokens") } : {},
|
|
36942
|
+
...readCount(block, "cache_creation_input_tokens") !== void 0 ? { cacheCreation: readCount(block, "cache_creation_input_tokens") } : {}
|
|
36943
|
+
};
|
|
36944
|
+
return compactUsage(usage);
|
|
36945
|
+
}
|
|
36946
|
+
function usageBlock(raw2) {
|
|
36947
|
+
const top = nested(raw2, "usage");
|
|
36948
|
+
if (top !== null && typeof top === "object")
|
|
36949
|
+
return top;
|
|
36950
|
+
const inner = nestedRecord(nested(raw2, "message"), "usage");
|
|
36951
|
+
return inner;
|
|
36952
|
+
}
|
|
36953
|
+
function nestedRecord(obj, key) {
|
|
36954
|
+
if (obj !== null && typeof obj === "object") {
|
|
36955
|
+
const value = obj[key];
|
|
36956
|
+
if (value !== null && typeof value === "object")
|
|
36957
|
+
return value;
|
|
36958
|
+
}
|
|
36959
|
+
return void 0;
|
|
36960
|
+
}
|
|
36961
|
+
function readCount(block, key) {
|
|
36962
|
+
const value = block[key];
|
|
36963
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0)
|
|
36964
|
+
return void 0;
|
|
36965
|
+
return value;
|
|
35698
36966
|
}
|
|
35699
36967
|
function toolCallData(tool, input, response) {
|
|
35700
36968
|
return { kind: "tool_call", tool, input, response };
|
|
@@ -35744,7 +37012,7 @@ function claudeCodeExtractData(raw2, logical) {
|
|
|
35744
37012
|
case "tool_call":
|
|
35745
37013
|
return toolCallData(pickString(raw2, "tool_name", "tool"), nested(raw2, "tool_input"), nested(raw2, "tool_response"));
|
|
35746
37014
|
case "assistant_message":
|
|
35747
|
-
return assistantMessageData(pickString(raw2, "text", "message"));
|
|
37015
|
+
return assistantMessageData(pickString(raw2, "text", "message"), extractTurnUsage(raw2));
|
|
35748
37016
|
case "session-end":
|
|
35749
37017
|
return sessionEndData(pickString(raw2, "reason") || "Stop");
|
|
35750
37018
|
default:
|
|
@@ -36162,7 +37430,17 @@ var StorageConfigSchema = external_exports.object({
|
|
|
36162
37430
|
/** Per-statement timeout, clamped non-negative. */
|
|
36163
37431
|
queryTimeoutMs: QueryTimeoutMs.default(DEFAULT_QUERY_TIMEOUT_MS),
|
|
36164
37432
|
/** SQL tracing gate (FR-6). Evaluated at call time, see client.ts. */
|
|
36165
|
-
traceSql: external_exports.boolean().default(false)
|
|
37433
|
+
traceSql: external_exports.boolean().default(false),
|
|
37434
|
+
/**
|
|
37435
|
+
* Query-meter persistence gate (PRD-062a). RESERVED, NOT YET IMPLEMENTED. The
|
|
37436
|
+
* query meter's default posture is in-memory + structured-log only and adds
|
|
37437
|
+
* ZERO DeepLake queries; persisting per-source counts to the existing
|
|
37438
|
+
* `telemetry_counters` tenant group is a later, separate concern and would add
|
|
37439
|
+
* write cost, so it is gated behind this flag. Today the flag is parsed and
|
|
37440
|
+
* carried but nothing reads it for behavior — wiring persistence is out of
|
|
37441
|
+
* scope for this sub-PRD (it must not make the meter itself a write-cost driver).
|
|
37442
|
+
*/
|
|
37443
|
+
queryMeterPersist: external_exports.boolean().default(false)
|
|
36166
37444
|
});
|
|
36167
37445
|
var StorageConfigError = class extends Error {
|
|
36168
37446
|
issues;
|
|
@@ -36181,7 +37459,8 @@ function envCredentialProvider(env = process.env) {
|
|
|
36181
37459
|
org: env.HONEYCOMB_DEEPLAKE_ORG,
|
|
36182
37460
|
workspace: env.HONEYCOMB_DEEPLAKE_WORKSPACE,
|
|
36183
37461
|
queryTimeoutMs: env.HONEYCOMB_QUERY_TIMEOUT_MS,
|
|
36184
|
-
traceSql: env.HONEYCOMB_TRACE_SQL === "1" || env.HONEYCOMB_TRACE_SQL === "true"
|
|
37462
|
+
traceSql: env.HONEYCOMB_TRACE_SQL === "1" || env.HONEYCOMB_TRACE_SQL === "true",
|
|
37463
|
+
queryMeterPersist: env.HONEYCOMB_QUERY_METER_PERSIST === "1" || env.HONEYCOMB_QUERY_METER_PERSIST === "true"
|
|
36185
37464
|
};
|
|
36186
37465
|
}
|
|
36187
37466
|
};
|
|
@@ -36233,7 +37512,8 @@ function defaultCredentialProvider(options = {}) {
|
|
|
36233
37512
|
orgName: fromFile.orgName,
|
|
36234
37513
|
// Tuning knobs are env-only (the file carries none).
|
|
36235
37514
|
queryTimeoutMs: fromEnv.queryTimeoutMs,
|
|
36236
|
-
traceSql: fromEnv.traceSql
|
|
37515
|
+
traceSql: fromEnv.traceSql,
|
|
37516
|
+
queryMeterPersist: fromEnv.queryMeterPersist
|
|
36237
37517
|
};
|
|
36238
37518
|
}
|
|
36239
37519
|
};
|
|
@@ -37583,12 +38863,12 @@ function mountSetupMigrate(daemon, options = {}) {
|
|
|
37583
38863
|
// dist/src/daemon/runtime/pollinating/config.js
|
|
37584
38864
|
var DEFAULT_TOKEN_THRESHOLD = 1e5;
|
|
37585
38865
|
var DEFAULT_MAX_INPUT_TOKENS = 128e3;
|
|
37586
|
-
var
|
|
38866
|
+
var BoolFlag2 = external_exports.preprocess((raw2) => {
|
|
37587
38867
|
if (typeof raw2 === "boolean")
|
|
37588
38868
|
return raw2;
|
|
37589
38869
|
return raw2 === "true" || raw2 === "1";
|
|
37590
38870
|
}, external_exports.boolean());
|
|
37591
|
-
function
|
|
38871
|
+
function ClampedInt2(def, min = 1) {
|
|
37592
38872
|
return external_exports.preprocess((raw2) => {
|
|
37593
38873
|
const n = typeof raw2 === "number" ? raw2 : Number(raw2);
|
|
37594
38874
|
if (!Number.isFinite(n))
|
|
@@ -37598,13 +38878,13 @@ function ClampedInt(def, min = 1) {
|
|
|
37598
38878
|
}
|
|
37599
38879
|
var PollinatingConfigSchema = external_exports.object({
|
|
37600
38880
|
/** Master switch; off → counter still grows but no job is queued (FR-7 / a-AC-4). */
|
|
37601
|
-
enabled:
|
|
38881
|
+
enabled: BoolFlag2.default(false),
|
|
37602
38882
|
/** Tokens-since-last-pass that queues a pass; reset SUBTRACTS this (FR-3 / FR-5). */
|
|
37603
|
-
tokenThreshold:
|
|
38883
|
+
tokenThreshold: ClampedInt2(DEFAULT_TOKEN_THRESHOLD).default(DEFAULT_TOKEN_THRESHOLD),
|
|
37604
38884
|
/** Input-token budget a pass's payload must fit under (D-2 / 009c). */
|
|
37605
|
-
maxInputTokens:
|
|
38885
|
+
maxInputTokens: ClampedInt2(DEFAULT_MAX_INPUT_TOKENS).default(DEFAULT_MAX_INPUT_TOKENS),
|
|
37606
38886
|
/** First run with no prior pass enters compaction, not incremental (D-4 / c-AC-1). */
|
|
37607
|
-
backfillOnFirstRun:
|
|
38887
|
+
backfillOnFirstRun: BoolFlag2.default(true)
|
|
37608
38888
|
});
|
|
37609
38889
|
var PollinatingConfigError = class extends Error {
|
|
37610
38890
|
issues;
|
|
@@ -38632,7 +39912,7 @@ var DEFAULT_KEEP_LATEST_N = 5;
|
|
|
38632
39912
|
var DEFAULT_WINDOW_DAYS = 30;
|
|
38633
39913
|
var DEFAULT_TIMESTAMP_COLUMN = "updated_at";
|
|
38634
39914
|
var DEFAULT_VERSION_COLUMN = "version";
|
|
38635
|
-
function
|
|
39915
|
+
function ClampedInt3(def, min) {
|
|
38636
39916
|
return external_exports.preprocess((raw2) => {
|
|
38637
39917
|
const n = typeof raw2 === "number" ? raw2 : Number(raw2);
|
|
38638
39918
|
if (!Number.isFinite(n))
|
|
@@ -38649,9 +39929,9 @@ function IdentColumn(def) {
|
|
|
38649
39929
|
}
|
|
38650
39930
|
var CompactionRetentionSchema = external_exports.object({
|
|
38651
39931
|
/** Keep the most-recent N versions below the highest (D-1). Clamp `>= 1`. */
|
|
38652
|
-
keepLatestN:
|
|
39932
|
+
keepLatestN: ClampedInt3(DEFAULT_KEEP_LATEST_N, 1).default(DEFAULT_KEEP_LATEST_N),
|
|
38653
39933
|
/** Keep any version newer than now − windowDays (D-1). Clamp `>= 0` (0 = off). */
|
|
38654
|
-
windowDays:
|
|
39934
|
+
windowDays: ClampedInt3(DEFAULT_WINDOW_DAYS, 0).default(DEFAULT_WINDOW_DAYS),
|
|
38655
39935
|
/** The timestamp column the window is measured on. Default `updated_at`. */
|
|
38656
39936
|
timestampColumn: IdentColumn(DEFAULT_TIMESTAMP_COLUMN).default(DEFAULT_TIMESTAMP_COLUMN),
|
|
38657
39937
|
/** The version column. Default `version` (mirrors `appendVersionBumped`). */
|
|
@@ -39055,35 +40335,6 @@ async function readBody4(c) {
|
|
|
39055
40335
|
}
|
|
39056
40336
|
}
|
|
39057
40337
|
|
|
39058
|
-
// dist/src/daemon/runtime/recall/scope-clause.js
|
|
39059
|
-
var PROJECT_ID_COLUMN = "project_id";
|
|
39060
|
-
var PROJECT_ID_UNSET = "";
|
|
39061
|
-
var CROSS_PROJECT_ADMITTED = Object.freeze(["user", "workspace"]);
|
|
39062
|
-
var SCOPE_READ_POLICIES = Object.freeze(["isolated", "shared", "group"]);
|
|
39063
|
-
function buildProjectScopeClause(input) {
|
|
39064
|
-
const projectColumn = input.projectColumn ?? PROJECT_ID_COLUMN;
|
|
39065
|
-
const rawId = input.projectId ?? "";
|
|
39066
|
-
const isInbox = rawId.trim() === "" || rawId === UNSORTED_PROJECT_ID;
|
|
39067
|
-
const bound = input.bound ?? !isInbox;
|
|
39068
|
-
const col = sqlIdent(projectColumn);
|
|
39069
|
-
const primaryId = bound ? rawId : UNSORTED_PROJECT_ID;
|
|
39070
|
-
const admitted = primaryId === PROJECT_ID_UNSET ? [PROJECT_ID_UNSET] : [primaryId, PROJECT_ID_UNSET];
|
|
39071
|
-
const disjuncts = admitted.map((id) => `${col} = ${sLiteral(id)}`);
|
|
39072
|
-
const values = [...admitted];
|
|
39073
|
-
if (input.promotionColumn !== void 0 && input.promotionColumn !== "") {
|
|
39074
|
-
const promoCol = sqlIdent(input.promotionColumn);
|
|
39075
|
-
for (const reach of CROSS_PROJECT_ADMITTED) {
|
|
39076
|
-
disjuncts.push(`${promoCol} = ${sLiteral(reach)}`);
|
|
39077
|
-
values.push(reach);
|
|
39078
|
-
}
|
|
39079
|
-
}
|
|
39080
|
-
const sql = `(${disjuncts.join(" OR ")})`;
|
|
39081
|
-
return { sql, values, bound };
|
|
39082
|
-
}
|
|
39083
|
-
function buildProjectScopeConjunct(input) {
|
|
39084
|
-
return ` AND ${buildProjectScopeClause(input).sql}`;
|
|
39085
|
-
}
|
|
39086
|
-
|
|
39087
40338
|
// dist/src/daemon/runtime/memories/reads.js
|
|
39088
40339
|
var DEFAULT_LIST_LIMIT = 50;
|
|
39089
40340
|
var MAX_LIST_LIMIT = 500;
|
|
@@ -40382,12 +41633,12 @@ var DEFAULT_REHEARSAL_BOOST = 1.1;
|
|
|
40382
41633
|
var DEFAULT_REHEARSAL_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
40383
41634
|
var DEFAULT_MIN_INJECTION_SCORE = 0.6;
|
|
40384
41635
|
var RERANKER_STRATEGIES = Object.freeze(["embedding-cosine", "llm", "none"]);
|
|
40385
|
-
var
|
|
41636
|
+
var BoolFlag3 = external_exports.preprocess((raw2) => {
|
|
40386
41637
|
if (typeof raw2 === "boolean")
|
|
40387
41638
|
return raw2;
|
|
40388
41639
|
return raw2 === "true" || raw2 === "1";
|
|
40389
41640
|
}, external_exports.boolean());
|
|
40390
|
-
function
|
|
41641
|
+
function ClampedInt4(def, min = 0) {
|
|
40391
41642
|
return external_exports.preprocess((raw2) => {
|
|
40392
41643
|
const n = typeof raw2 === "number" ? raw2 : Number(raw2);
|
|
40393
41644
|
if (!Number.isFinite(n))
|
|
@@ -40423,29 +41674,29 @@ function OptionalClampedHalfLifeDays(min) {
|
|
|
40423
41674
|
}
|
|
40424
41675
|
var TraversalConfigSchema = external_exports.object({
|
|
40425
41676
|
/** Max aspects per focal entity. */
|
|
40426
|
-
aspectsPerEntity:
|
|
41677
|
+
aspectsPerEntity: ClampedInt4(DEFAULT_TRAVERSAL_ASPECTS_PER_ENTITY, 1).default(DEFAULT_TRAVERSAL_ASPECTS_PER_ENTITY),
|
|
40427
41678
|
/** Max attributes per aspect. */
|
|
40428
|
-
attrsPerAspect:
|
|
41679
|
+
attrsPerAspect: ClampedInt4(DEFAULT_TRAVERSAL_ATTRS_PER_ASPECT, 1).default(DEFAULT_TRAVERSAL_ATTRS_PER_ASPECT),
|
|
40429
41680
|
/** Max branching factor per node. */
|
|
40430
|
-
branching:
|
|
41681
|
+
branching: ClampedInt4(DEFAULT_TRAVERSAL_BRANCHING, 1).default(DEFAULT_TRAVERSAL_BRANCHING),
|
|
40431
41682
|
/** Hard cap on total IDs the walk may collect. */
|
|
40432
|
-
totalIds:
|
|
41683
|
+
totalIds: ClampedInt4(DEFAULT_TRAVERSAL_TOTAL_IDS, 1).default(DEFAULT_TRAVERSAL_TOTAL_IDS),
|
|
40433
41684
|
/** Minimum edge strength×confidence to follow an edge. */
|
|
40434
41685
|
minEdgeWeight: ClampedFloat(DEFAULT_TRAVERSAL_MIN_EDGE_WEIGHT).default(DEFAULT_TRAVERSAL_MIN_EDGE_WEIGHT),
|
|
40435
41686
|
/** Hard traversal timeout in ms. */
|
|
40436
|
-
timeoutMs:
|
|
41687
|
+
timeoutMs: ClampedInt4(DEFAULT_TRAVERSAL_TIMEOUT_MS, 1).default(DEFAULT_TRAVERSAL_TIMEOUT_MS)
|
|
40437
41688
|
});
|
|
40438
41689
|
var RerankerConfigSchema = external_exports.object({
|
|
40439
41690
|
/** The reranker strategy (D-4). */
|
|
40440
41691
|
strategy: external_exports.enum(RERANKER_STRATEGIES).default(DEFAULT_RERANKER),
|
|
40441
41692
|
/** Reranker timeout in ms; on timeout keep the original order (d-AC-2 / b-AC-2). */
|
|
40442
|
-
timeoutMs:
|
|
41693
|
+
timeoutMs: ClampedInt4(DEFAULT_RERANKER_TIMEOUT_MS, 1).default(DEFAULT_RERANKER_TIMEOUT_MS),
|
|
40443
41694
|
/** Rerank window N: how many fused top-N candidates to re-score (PRD-047b). */
|
|
40444
|
-
window:
|
|
41695
|
+
window: ClampedInt4(DEFAULT_RERANKER_WINDOW, 1).default(DEFAULT_RERANKER_WINDOW)
|
|
40445
41696
|
});
|
|
40446
41697
|
var DedupConfigSchema = external_exports.object({
|
|
40447
41698
|
/** Whether semantic near-duplicate dedup runs; ON by default (PRD-047c / c-AC-3). */
|
|
40448
|
-
enabled:
|
|
41699
|
+
enabled: BoolFlag3.default(DEFAULT_DEDUP_ENABLED),
|
|
40449
41700
|
/** The cosine-similarity collapse threshold in `[0,1]` (PRD-047c / c-AC-1). */
|
|
40450
41701
|
similarityThreshold: ClampedFloat(DEFAULT_DEDUP_SIMILARITY_THRESHOLD).default(DEFAULT_DEDUP_SIMILARITY_THRESHOLD)
|
|
40451
41702
|
});
|
|
@@ -40484,21 +41735,21 @@ var DampeningConfigSchema = external_exports.object({
|
|
|
40484
41735
|
/** Bounded rehearsal boost for a recently-accessed memory. Ceiling 4. */
|
|
40485
41736
|
rehearsalBoost: ClampedFloat(DEFAULT_REHEARSAL_BOOST, 4).default(DEFAULT_REHEARSAL_BOOST),
|
|
40486
41737
|
/** "Recent" window for the rehearsal boost in ms (7d). */
|
|
40487
|
-
rehearsalWindowMs:
|
|
41738
|
+
rehearsalWindowMs: ClampedInt4(DEFAULT_REHEARSAL_WINDOW_MS, 1).default(DEFAULT_REHEARSAL_WINDOW_MS)
|
|
40488
41739
|
});
|
|
40489
41740
|
var RecallConfigSchema = external_exports.object({
|
|
40490
41741
|
/** Over-fetch multiplier for scoped vector recalls (D-1 / a-AC-2 / FR-5). */
|
|
40491
|
-
overFetchMultiplier:
|
|
41742
|
+
overFetchMultiplier: ClampedInt4(DEFAULT_OVER_FETCH_MULTIPLIER, 1).default(DEFAULT_OVER_FETCH_MULTIPLIER),
|
|
40492
41743
|
/** Base per-channel candidate limit (FTS/vector base, pre over-fetch). */
|
|
40493
|
-
channelLimit:
|
|
41744
|
+
channelLimit: ClampedInt4(DEFAULT_CHANNEL_LIMIT, 1).default(DEFAULT_CHANNEL_LIMIT),
|
|
40494
41745
|
/** Hint cap so a memory can't ride in on hints alone (D-2 / a-AC-4 / FR-7). */
|
|
40495
|
-
hintCap:
|
|
41746
|
+
hintCap: ClampedInt4(DEFAULT_HINT_CAP, 0).default(DEFAULT_HINT_CAP),
|
|
40496
41747
|
/** Keyword expansion for the LEXICAL path only; OFF by default (D-2 / FR-2). */
|
|
40497
|
-
keywordExpansion:
|
|
41748
|
+
keywordExpansion: BoolFlag3.default(false),
|
|
40498
41749
|
/** Minimum calibrated injection score (D-6 / e-AC-1); per-agent tunable. */
|
|
40499
41750
|
minInjectionScore: ClampedFloat(DEFAULT_MIN_INJECTION_SCORE).default(DEFAULT_MIN_INJECTION_SCORE),
|
|
40500
41751
|
/** Master graph switch for the traversal channel/phase (007b). */
|
|
40501
|
-
graphEnabled:
|
|
41752
|
+
graphEnabled: BoolFlag3.default(false),
|
|
40502
41753
|
/** D-3 traversal budgets (007b). */
|
|
40503
41754
|
traversal: TraversalConfigSchema.default(() => TraversalConfigSchema.parse({})),
|
|
40504
41755
|
/** D-4 reranker config (007d). */
|
|
@@ -40581,6 +41832,129 @@ function resolveRecallConfig(provider = envRecallConfigProvider()) {
|
|
|
40581
41832
|
return parsed.data;
|
|
40582
41833
|
}
|
|
40583
41834
|
|
|
41835
|
+
// dist/src/daemon/runtime/memories/bounded-pool.js
|
|
41836
|
+
var Semaphore = class {
|
|
41837
|
+
/** The maximum permits (in-flight tasks) allowed at once. Always `>= 1`. */
|
|
41838
|
+
max;
|
|
41839
|
+
/** Permits currently held (tasks running). Never exceeds {@link max}. */
|
|
41840
|
+
held = 0;
|
|
41841
|
+
/** FIFO queue of waiters parked because all permits were held at acquire time. */
|
|
41842
|
+
waiters = [];
|
|
41843
|
+
constructor(max) {
|
|
41844
|
+
this.max = Number.isFinite(max) && max >= 1 ? Math.trunc(max) : 1;
|
|
41845
|
+
}
|
|
41846
|
+
/** Permits currently held (the live in-flight count). Test-observable for the cap assertion. */
|
|
41847
|
+
get inFlight() {
|
|
41848
|
+
return this.held;
|
|
41849
|
+
}
|
|
41850
|
+
/** Number of tasks parked waiting for a permit (test-observable). */
|
|
41851
|
+
get waiting() {
|
|
41852
|
+
return this.waiters.length;
|
|
41853
|
+
}
|
|
41854
|
+
/**
|
|
41855
|
+
* Acquire one permit. Resolves immediately when a permit is free; otherwise parks
|
|
41856
|
+
* FIFO and resolves when {@link release} hands a permit forward. Each acquire MUST
|
|
41857
|
+
* be paired with exactly one {@link release} (use {@link run} to guarantee it).
|
|
41858
|
+
*/
|
|
41859
|
+
acquire() {
|
|
41860
|
+
if (this.held < this.max) {
|
|
41861
|
+
this.held += 1;
|
|
41862
|
+
return Promise.resolve();
|
|
41863
|
+
}
|
|
41864
|
+
return new Promise((resolve6) => {
|
|
41865
|
+
this.waiters.push(() => {
|
|
41866
|
+
this.held += 1;
|
|
41867
|
+
resolve6();
|
|
41868
|
+
});
|
|
41869
|
+
});
|
|
41870
|
+
}
|
|
41871
|
+
/**
|
|
41872
|
+
* Release one permit. If a waiter is parked, hand the permit STRAIGHT to it (the
|
|
41873
|
+
* held count stays balanced — the waiter's resolver re-increments), otherwise drop
|
|
41874
|
+
* the held count. Releasing with no permit held is a no-op (defensive — a double
|
|
41875
|
+
* release never drives the count negative).
|
|
41876
|
+
*/
|
|
41877
|
+
release() {
|
|
41878
|
+
const next = this.waiters.shift();
|
|
41879
|
+
if (next !== void 0) {
|
|
41880
|
+
this.held -= 1;
|
|
41881
|
+
next();
|
|
41882
|
+
return;
|
|
41883
|
+
}
|
|
41884
|
+
if (this.held > 0)
|
|
41885
|
+
this.held -= 1;
|
|
41886
|
+
}
|
|
41887
|
+
/**
|
|
41888
|
+
* Run `fn` under one permit: acquire, run, and ALWAYS release (even when `fn`
|
|
41889
|
+
* throws/rejects), then re-throw the original error. The safe wrapper — a task
|
|
41890
|
+
* that throws never leaks a permit and wedges the pool.
|
|
41891
|
+
*/
|
|
41892
|
+
async run(fn) {
|
|
41893
|
+
await this.acquire();
|
|
41894
|
+
try {
|
|
41895
|
+
return await fn();
|
|
41896
|
+
} finally {
|
|
41897
|
+
this.release();
|
|
41898
|
+
}
|
|
41899
|
+
}
|
|
41900
|
+
};
|
|
41901
|
+
|
|
41902
|
+
// dist/src/daemon/runtime/memories/amplification-config.js
|
|
41903
|
+
var DEFAULT_FANOUT_BATCH = true;
|
|
41904
|
+
var DEFAULT_RECALL_MAX_CONCURRENCY = 6;
|
|
41905
|
+
var MIN_RECALL_MAX_CONCURRENCY = 1;
|
|
41906
|
+
var OnByDefaultFlag = external_exports.preprocess((raw2) => {
|
|
41907
|
+
if (typeof raw2 === "boolean")
|
|
41908
|
+
return raw2;
|
|
41909
|
+
if (raw2 === void 0 || raw2 === null || raw2 === "")
|
|
41910
|
+
return true;
|
|
41911
|
+
return !(raw2 === "false" || raw2 === "0");
|
|
41912
|
+
}, external_exports.boolean());
|
|
41913
|
+
var ConcurrencyKnob = external_exports.preprocess((raw2) => {
|
|
41914
|
+
const n = typeof raw2 === "number" ? raw2 : Number(raw2);
|
|
41915
|
+
if (!Number.isFinite(n))
|
|
41916
|
+
return DEFAULT_RECALL_MAX_CONCURRENCY;
|
|
41917
|
+
return Math.max(MIN_RECALL_MAX_CONCURRENCY, Math.trunc(n));
|
|
41918
|
+
}, external_exports.number().int());
|
|
41919
|
+
var AmplificationConfigSchema = external_exports.object({
|
|
41920
|
+
/** `HONEYCOMB_FANOUT_BATCH` — batched fan-out enqueue; ON by default (AC-62d.1.1 / AC-9). */
|
|
41921
|
+
fanoutBatch: OnByDefaultFlag.default(DEFAULT_FANOUT_BATCH),
|
|
41922
|
+
/** `HONEYCOMB_RECALL_MAX_CONCURRENCY` — in-flight DeepLake-query ceiling; 6 by default (AC-62d.2.1). */
|
|
41923
|
+
recallMaxConcurrency: ConcurrencyKnob.default(DEFAULT_RECALL_MAX_CONCURRENCY)
|
|
41924
|
+
});
|
|
41925
|
+
var AmplificationConfigError = class extends Error {
|
|
41926
|
+
issues;
|
|
41927
|
+
constructor(issues) {
|
|
41928
|
+
super(`Invalid amplification config: ${issues.join("; ")}`);
|
|
41929
|
+
this.name = "AmplificationConfigError";
|
|
41930
|
+
this.issues = issues;
|
|
41931
|
+
}
|
|
41932
|
+
};
|
|
41933
|
+
function envAmplificationConfigProvider(env = process.env) {
|
|
41934
|
+
return {
|
|
41935
|
+
read() {
|
|
41936
|
+
return {
|
|
41937
|
+
fanoutBatch: env.HONEYCOMB_FANOUT_BATCH,
|
|
41938
|
+
recallMaxConcurrency: env.HONEYCOMB_RECALL_MAX_CONCURRENCY
|
|
41939
|
+
};
|
|
41940
|
+
}
|
|
41941
|
+
};
|
|
41942
|
+
}
|
|
41943
|
+
function resolveAmplificationConfig(provider = envAmplificationConfigProvider()) {
|
|
41944
|
+
const parsed = AmplificationConfigSchema.safeParse(provider.read());
|
|
41945
|
+
if (!parsed.success) {
|
|
41946
|
+
const issues = parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`);
|
|
41947
|
+
throw new AmplificationConfigError(issues);
|
|
41948
|
+
}
|
|
41949
|
+
return parsed.data;
|
|
41950
|
+
}
|
|
41951
|
+
var cached2;
|
|
41952
|
+
function amplificationConfig() {
|
|
41953
|
+
if (cached2 === void 0)
|
|
41954
|
+
cached2 = resolveAmplificationConfig();
|
|
41955
|
+
return cached2;
|
|
41956
|
+
}
|
|
41957
|
+
|
|
40584
41958
|
// dist/src/daemon/runtime/memories/activation.js
|
|
40585
41959
|
var DEFAULT_ACTR_DECAY = 0.5;
|
|
40586
41960
|
var DEFAULT_ACTR_A_MIN = 0.05;
|
|
@@ -40695,6 +42069,15 @@ function deserializeModel(blob) {
|
|
|
40695
42069
|
}
|
|
40696
42070
|
|
|
40697
42071
|
// dist/src/daemon/runtime/memories/recall.js
|
|
42072
|
+
var SOURCE_RECALL_ARM = "recall-arm";
|
|
42073
|
+
var sharedRecallPool;
|
|
42074
|
+
function resolveRecallPool(deps) {
|
|
42075
|
+
if (deps.recallPool !== void 0)
|
|
42076
|
+
return deps.recallPool;
|
|
42077
|
+
if (sharedRecallPool === void 0)
|
|
42078
|
+
sharedRecallPool = new Semaphore(amplificationConfig().recallMaxConcurrency);
|
|
42079
|
+
return sharedRecallPool;
|
|
42080
|
+
}
|
|
40698
42081
|
var DEFAULT_RECALL_LIMIT = 20;
|
|
40699
42082
|
var MAX_RECALL_LIMIT = 200;
|
|
40700
42083
|
var RRF_K = 60;
|
|
@@ -40826,7 +42209,8 @@ function projectConjunctFor(request) {
|
|
|
40826
42209
|
});
|
|
40827
42210
|
}
|
|
40828
42211
|
async function runArm(sql, request, deps) {
|
|
40829
|
-
const
|
|
42212
|
+
const pool = resolveRecallPool(deps);
|
|
42213
|
+
const result = await pool.run(() => deps.storage.query(sql, request.scope, { source: SOURCE_RECALL_ARM }));
|
|
40830
42214
|
return isOk(result) ? result.rows : [];
|
|
40831
42215
|
}
|
|
40832
42216
|
var SEMANTIC_ARMS = [
|
|
@@ -40866,7 +42250,8 @@ async function runSemanticArm(spec, queryVector, request, deps, limit) {
|
|
|
40866
42250
|
const projectClause = projectConjunctFor(request);
|
|
40867
42251
|
let scored;
|
|
40868
42252
|
try {
|
|
40869
|
-
const
|
|
42253
|
+
const pool = resolveRecallPool(deps);
|
|
42254
|
+
const recall = await pool.run(() => vectorSearch(deps.storage, request.scope, {
|
|
40870
42255
|
table: spec.table,
|
|
40871
42256
|
idColumn: spec.idColumn,
|
|
40872
42257
|
embeddingColumn: spec.embeddingColumn,
|
|
@@ -40874,7 +42259,7 @@ async function runSemanticArm(spec, queryVector, request, deps, limit) {
|
|
|
40874
42259
|
scope: {},
|
|
40875
42260
|
limit,
|
|
40876
42261
|
...projectClause !== "" ? { extraClause: projectClause } : {}
|
|
40877
|
-
});
|
|
42262
|
+
}));
|
|
40878
42263
|
scored = recall.ids;
|
|
40879
42264
|
} catch {
|
|
40880
42265
|
return [];
|
|
@@ -41388,6 +42773,19 @@ async function recallMemories(request, deps) {
|
|
|
41388
42773
|
}
|
|
41389
42774
|
|
|
41390
42775
|
// dist/src/daemon/runtime/secrets/api.js
|
|
42776
|
+
function localDefaultScopeResolver(mode, defaultScope) {
|
|
42777
|
+
return {
|
|
42778
|
+
resolve(c) {
|
|
42779
|
+
const fromHeader = headerScopeResolver2.resolve(c);
|
|
42780
|
+
if (fromHeader !== null)
|
|
42781
|
+
return fromHeader;
|
|
42782
|
+
if (mode === "local" && defaultScope !== void 0) {
|
|
42783
|
+
return { org: defaultScope.org, workspace: defaultScope.workspace ?? "default" };
|
|
42784
|
+
}
|
|
42785
|
+
return null;
|
|
42786
|
+
}
|
|
42787
|
+
};
|
|
42788
|
+
}
|
|
41391
42789
|
var headerScopeResolver2 = {
|
|
41392
42790
|
resolve(c) {
|
|
41393
42791
|
const org = c.req.header("x-honeycomb-org");
|
|
@@ -41911,12 +43309,12 @@ var DEFAULT_DEAD_JOB_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
|
41911
43309
|
var DEFAULT_HISTORY_RETENTION_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
41912
43310
|
var DEFAULT_TOMBSTONE_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
41913
43311
|
var EXTRACTION_PROVIDER_NONE = "none";
|
|
41914
|
-
var
|
|
43312
|
+
var BoolFlag4 = external_exports.preprocess((raw2) => {
|
|
41915
43313
|
if (typeof raw2 === "boolean")
|
|
41916
43314
|
return raw2;
|
|
41917
43315
|
return raw2 === "true" || raw2 === "1";
|
|
41918
43316
|
}, external_exports.boolean());
|
|
41919
|
-
function
|
|
43317
|
+
function ClampedInt5(def, min = 1) {
|
|
41920
43318
|
return external_exports.preprocess((raw2) => {
|
|
41921
43319
|
const n = typeof raw2 === "number" ? raw2 : Number(raw2);
|
|
41922
43320
|
if (!Number.isFinite(n))
|
|
@@ -41932,49 +43330,49 @@ var Confidence = external_exports.preprocess((raw2) => {
|
|
|
41932
43330
|
}, external_exports.number());
|
|
41933
43331
|
var AutonomousConfigSchema = external_exports.object({
|
|
41934
43332
|
/** Master switch for retention/autonomous mutation; off → retention does not run (006e e-AC-4). */
|
|
41935
|
-
enabled:
|
|
43333
|
+
enabled: BoolFlag4.default(false),
|
|
41936
43334
|
/** Halt switch: set → no further purges even when enabled (006e e-AC-5). */
|
|
41937
|
-
frozen:
|
|
43335
|
+
frozen: BoolFlag4.default(false),
|
|
41938
43336
|
/** Gate for UPDATE/DELETE proposals being applied (006c c-AC-3 / D-7). */
|
|
41939
|
-
allowUpdateDelete:
|
|
43337
|
+
allowUpdateDelete: BoolFlag4.default(false)
|
|
41940
43338
|
});
|
|
41941
43339
|
var GraphConfigSchema = external_exports.object({
|
|
41942
43340
|
/** Master graph switch; off → no graph rows written (006d d-AC-4). */
|
|
41943
|
-
enabled:
|
|
43341
|
+
enabled: BoolFlag4.default(false),
|
|
41944
43342
|
/** Whether extraction-derived triples are persisted to the graph (006d d-AC-4). */
|
|
41945
|
-
extractionWritesEnabled:
|
|
43343
|
+
extractionWritesEnabled: BoolFlag4.default(false)
|
|
41946
43344
|
});
|
|
41947
43345
|
var ExtractionConfigSchema = external_exports.object({
|
|
41948
43346
|
/** Input char cap before the model call (a-AC-2 / FR-6). */
|
|
41949
|
-
inputCharCap:
|
|
43347
|
+
inputCharCap: ClampedInt5(DEFAULT_INPUT_CHAR_CAP).default(DEFAULT_INPUT_CHAR_CAP),
|
|
41950
43348
|
/** Max facts kept (a-AC-3 / FR-7). */
|
|
41951
|
-
maxFacts:
|
|
43349
|
+
maxFacts: ClampedInt5(DEFAULT_MAX_FACTS).default(DEFAULT_MAX_FACTS),
|
|
41952
43350
|
/** Max entity triples kept (a-AC-3 / FR-7). */
|
|
41953
|
-
maxEntities:
|
|
43351
|
+
maxEntities: ClampedInt5(DEFAULT_MAX_ENTITIES).default(DEFAULT_MAX_ENTITIES),
|
|
41954
43352
|
/** Per-fact content length cap (a-AC-3 / FR-7). */
|
|
41955
|
-
maxFactChars:
|
|
43353
|
+
maxFactChars: ClampedInt5(DEFAULT_MAX_FACT_CHARS).default(DEFAULT_MAX_FACT_CHARS)
|
|
41956
43354
|
});
|
|
41957
43355
|
var RetentionConfigSchema = external_exports.object({
|
|
41958
43356
|
/** Per-run row batch cap (e-AC-1 / e-AC-6). */
|
|
41959
|
-
batchLimit:
|
|
43357
|
+
batchLimit: ClampedInt5(DEFAULT_RETENTION_BATCH_LIMIT).default(DEFAULT_RETENTION_BATCH_LIMIT),
|
|
41960
43358
|
/** Completed-jobs window in ms. */
|
|
41961
|
-
completedJobMs:
|
|
43359
|
+
completedJobMs: ClampedInt5(DEFAULT_COMPLETED_JOB_RETENTION_MS).default(DEFAULT_COMPLETED_JOB_RETENTION_MS),
|
|
41962
43360
|
/** Dead-jobs window in ms. */
|
|
41963
|
-
deadJobMs:
|
|
43361
|
+
deadJobMs: ClampedInt5(DEFAULT_DEAD_JOB_RETENTION_MS).default(DEFAULT_DEAD_JOB_RETENTION_MS),
|
|
41964
43362
|
/** History window in ms. */
|
|
41965
|
-
historyMs:
|
|
43363
|
+
historyMs: ClampedInt5(DEFAULT_HISTORY_RETENTION_MS).default(DEFAULT_HISTORY_RETENTION_MS),
|
|
41966
43364
|
/** Tombstone window in ms. */
|
|
41967
|
-
tombstoneMs:
|
|
43365
|
+
tombstoneMs: ClampedInt5(DEFAULT_TOMBSTONE_RETENTION_MS).default(DEFAULT_TOMBSTONE_RETENTION_MS)
|
|
41968
43366
|
});
|
|
41969
43367
|
var PipelineConfigSchema = external_exports.object({
|
|
41970
43368
|
/** Master switch; off → no stage runs (a-AC-5 / FR-9). */
|
|
41971
|
-
enabled:
|
|
43369
|
+
enabled: BoolFlag4.default(false),
|
|
41972
43370
|
/** Router-selection token; `'none'` disables extraction (a-AC-5 / FR-9). */
|
|
41973
43371
|
extractionProvider: external_exports.string().trim().min(1).default(EXTRACTION_PROVIDER_NONE),
|
|
41974
43372
|
/** Shadow mode: proposals logged, no memory written (006c c-AC-4). */
|
|
41975
|
-
shadowMode:
|
|
43373
|
+
shadowMode: BoolFlag4.default(false),
|
|
41976
43374
|
/** Frozen: nothing written even if shadow off; supersedes shadow (006c c-AC-5). */
|
|
41977
|
-
mutationsFrozen:
|
|
43375
|
+
mutationsFrozen: BoolFlag4.default(false),
|
|
41978
43376
|
/** ADD confidence gate (D-1 / 006c c-AC-1). */
|
|
41979
43377
|
minFactConfidenceForWrite: Confidence.default(DEFAULT_MIN_FACT_CONFIDENCE),
|
|
41980
43378
|
/** Autonomous brakes (retention + UPDATE/DELETE). */
|
|
@@ -42125,6 +43523,7 @@ function normalizeProposalKeys(candidate) {
|
|
|
42125
43523
|
// dist/src/daemon/runtime/pipeline/controlled-writes.js
|
|
42126
43524
|
var silentLogger4 = { event() {
|
|
42127
43525
|
} };
|
|
43526
|
+
var CONTROLLED_WRITE_BATCH_KEY = "proposals";
|
|
42128
43527
|
var MEMORIES_VERSION_COLUMN = Object.freeze({
|
|
42129
43528
|
name: "version",
|
|
42130
43529
|
sql: "BIGINT NOT NULL DEFAULT 1"
|
|
@@ -42474,33 +43873,66 @@ var noopControlledWriteHandler = async (_job) => {
|
|
|
42474
43873
|
function createControlledWriteHandler(deps) {
|
|
42475
43874
|
if (deps === void 0)
|
|
42476
43875
|
return noopControlledWriteHandler;
|
|
43876
|
+
const handlerDeps = deps;
|
|
42477
43877
|
const logger = deps.logger ?? silentLogger4;
|
|
42478
43878
|
return async (job) => {
|
|
42479
|
-
const
|
|
42480
|
-
if (
|
|
42481
|
-
|
|
43879
|
+
const batch = readBatchPayloads(job.payload);
|
|
43880
|
+
if (batch !== null) {
|
|
43881
|
+
for (const factPayload of batch) {
|
|
43882
|
+
const merged = { ...envelopeOf(job.payload), ...factPayload };
|
|
43883
|
+
const factJob = { ...job, payload: merged };
|
|
43884
|
+
await applyOneControlledWrite(factJob, handlerDeps, logger);
|
|
43885
|
+
}
|
|
42482
43886
|
return;
|
|
42483
43887
|
}
|
|
42484
|
-
|
|
42485
|
-
|
|
42486
|
-
|
|
42487
|
-
|
|
42488
|
-
|
|
42489
|
-
|
|
42490
|
-
if (
|
|
42491
|
-
|
|
42492
|
-
|
|
42493
|
-
|
|
42494
|
-
|
|
42495
|
-
|
|
42496
|
-
|
|
42497
|
-
|
|
42498
|
-
|
|
42499
|
-
|
|
42500
|
-
|
|
42501
|
-
|
|
43888
|
+
await applyOneControlledWrite(job, handlerDeps, logger);
|
|
43889
|
+
};
|
|
43890
|
+
}
|
|
43891
|
+
function envelopeOf(payload) {
|
|
43892
|
+
const out = {};
|
|
43893
|
+
for (const key of ["org", "workspace", "agent_id", "project_id"]) {
|
|
43894
|
+
if (typeof payload[key] === "string")
|
|
43895
|
+
out[key] = payload[key];
|
|
43896
|
+
}
|
|
43897
|
+
return out;
|
|
43898
|
+
}
|
|
43899
|
+
function readBatchPayloads(payload) {
|
|
43900
|
+
const raw2 = payload[CONTROLLED_WRITE_BATCH_KEY];
|
|
43901
|
+
if (!Array.isArray(raw2) || raw2.length === 0)
|
|
43902
|
+
return null;
|
|
43903
|
+
const out = [];
|
|
43904
|
+
for (const item of raw2) {
|
|
43905
|
+
if (item !== null && typeof item === "object" && !Array.isArray(item)) {
|
|
43906
|
+
out.push(item);
|
|
42502
43907
|
}
|
|
43908
|
+
}
|
|
43909
|
+
return out.length > 0 ? out : null;
|
|
43910
|
+
}
|
|
43911
|
+
async function applyOneControlledWrite(job, deps, logger) {
|
|
43912
|
+
const parsed = readControlledWriteInput(job.payload);
|
|
43913
|
+
if (parsed === null) {
|
|
43914
|
+
logger.event("controlled_write.unparseable_payload", { id: job.id });
|
|
43915
|
+
return;
|
|
43916
|
+
}
|
|
43917
|
+
const input = {
|
|
43918
|
+
...parsed,
|
|
43919
|
+
agentId: parsed.agentId ?? job.scope.agentId
|
|
42503
43920
|
};
|
|
43921
|
+
const scope = { org: job.scope.org, workspace: job.scope.workspace };
|
|
43922
|
+
const outcome = await applyControlledWrite(input, scope, deps);
|
|
43923
|
+
if (deps.onOutcome) {
|
|
43924
|
+
try {
|
|
43925
|
+
await deps.onOutcome(job, outcome);
|
|
43926
|
+
} catch (err) {
|
|
43927
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
43928
|
+
logger.event("controlled_write.fan_out_failed", {
|
|
43929
|
+
id: job.id,
|
|
43930
|
+
action: outcome.action,
|
|
43931
|
+
memoryId: outcome.memoryId,
|
|
43932
|
+
reason
|
|
43933
|
+
});
|
|
43934
|
+
}
|
|
43935
|
+
}
|
|
42504
43936
|
}
|
|
42505
43937
|
|
|
42506
43938
|
// dist/src/daemon/runtime/memories/store.js
|
|
@@ -43609,7 +45041,7 @@ var DEFAULT_OPEN_CONFLICT_SUPPRESSION = DEFAULT_RHO;
|
|
|
43609
45041
|
var DEFAULT_CONFLICT_AUTO_RESOLVE = false;
|
|
43610
45042
|
var STALE_REF_POSTURES = Object.freeze(["observe", "execute"]);
|
|
43611
45043
|
var DEFAULT_STALE_REF_POSTURE = "observe";
|
|
43612
|
-
var
|
|
45044
|
+
var BoolFlag5 = external_exports.preprocess((raw2) => {
|
|
43613
45045
|
if (typeof raw2 === "boolean")
|
|
43614
45046
|
return raw2;
|
|
43615
45047
|
return raw2 === "true" || raw2 === "1";
|
|
@@ -43664,7 +45096,7 @@ var LifecycleConfigSchema = external_exports.object({
|
|
|
43664
45096
|
/** Open-conflict suppression `ρ` (058b); `0` default (fully suppress, reversible), clamped into `[0,1]`. */
|
|
43665
45097
|
openConflictSuppression: ClampedFloat2(DEFAULT_OPEN_CONFLICT_SUPPRESSION, 1).default(DEFAULT_OPEN_CONFLICT_SUPPRESSION),
|
|
43666
45098
|
/** Conflict auto-resolve (058b); OFF by default (detect + queue only, human-in-the-loop). */
|
|
43667
|
-
conflictAutoResolve:
|
|
45099
|
+
conflictAutoResolve: BoolFlag5.default(DEFAULT_CONFLICT_AUTO_RESOLVE),
|
|
43668
45100
|
/** Stale-ref posture (058c); `observe` by default (`s = 0`, inert). */
|
|
43669
45101
|
staleRefPosture: PostureFlag.default(DEFAULT_STALE_REF_POSTURE)
|
|
43670
45102
|
});
|
|
@@ -46179,8 +47611,8 @@ function realDiscordProvider(cfg, transport) {
|
|
|
46179
47611
|
}
|
|
46180
47612
|
}
|
|
46181
47613
|
async function* indexDesktopCache() {
|
|
46182
|
-
const
|
|
46183
|
-
for (const m of
|
|
47614
|
+
const cached3 = await transport.readDesktopCache();
|
|
47615
|
+
for (const m of cached3) {
|
|
46184
47616
|
yield messageArtifact(cfg, m);
|
|
46185
47617
|
}
|
|
46186
47618
|
}
|
|
@@ -48850,12 +50282,34 @@ var RouterModelClient = class {
|
|
|
48850
50282
|
var ANTHROPIC_MESSAGES_URL = "https://api.anthropic.com/v1/messages";
|
|
48851
50283
|
var ANTHROPIC_VERSION = "2023-06-01";
|
|
48852
50284
|
var DEFAULT_MAX_TOKENS = 4096;
|
|
50285
|
+
var noopUsageSink = {
|
|
50286
|
+
record() {
|
|
50287
|
+
}
|
|
50288
|
+
};
|
|
48853
50289
|
var AnthropicContentBlockSchema = external_exports.object({
|
|
48854
50290
|
type: external_exports.string(),
|
|
48855
50291
|
text: external_exports.string().optional()
|
|
48856
50292
|
});
|
|
50293
|
+
var AnthropicUsageSchema = external_exports.object({
|
|
50294
|
+
input_tokens: external_exports.number().int().nonnegative().catch(0).default(0),
|
|
50295
|
+
output_tokens: external_exports.number().int().nonnegative().catch(0).default(0),
|
|
50296
|
+
cache_read_input_tokens: external_exports.number().int().nonnegative().catch(0).default(0),
|
|
50297
|
+
cache_creation_input_tokens: external_exports.number().int().nonnegative().catch(0).default(0)
|
|
50298
|
+
});
|
|
50299
|
+
var ZERO_USAGE = {
|
|
50300
|
+
input_tokens: 0,
|
|
50301
|
+
output_tokens: 0,
|
|
50302
|
+
cache_read_input_tokens: 0,
|
|
50303
|
+
cache_creation_input_tokens: 0
|
|
50304
|
+
};
|
|
48857
50305
|
var AnthropicMessagesResponseSchema = external_exports.object({
|
|
48858
|
-
content: external_exports.array(AnthropicContentBlockSchema).default([])
|
|
50306
|
+
content: external_exports.array(AnthropicContentBlockSchema).default([]),
|
|
50307
|
+
// Finding (usage-failsoft): `.default(ZERO_USAGE)` only covers `usage === undefined`. A response with
|
|
50308
|
+
// `usage: null` or a malformed `usage` object would FAIL the object parse and -- because this field is
|
|
50309
|
+
// part of the whole-response schema -- bubble up to a 502 that DROPS an otherwise-valid completion.
|
|
50310
|
+
// `.catch(ZERO_USAGE)` makes ANY invalid value (null, a string, a malformed object) fall back to
|
|
50311
|
+
// zero-usage so a valid completion is NEVER dropped over its (side-channel) usage block.
|
|
50312
|
+
usage: AnthropicUsageSchema.default(ZERO_USAGE).catch(ZERO_USAGE)
|
|
48859
50313
|
});
|
|
48860
50314
|
function toAnthropicBody(call, defaultMaxTokens) {
|
|
48861
50315
|
const systemParts = [];
|
|
@@ -48883,6 +50337,7 @@ function createAnthropicTransport(deps = {}) {
|
|
|
48883
50337
|
const doFetch = deps.fetch ?? globalThis.fetch;
|
|
48884
50338
|
const url2 = deps.baseUrl ?? ANTHROPIC_MESSAGES_URL;
|
|
48885
50339
|
const defaultMaxTokens = deps.defaultMaxTokens ?? DEFAULT_MAX_TOKENS;
|
|
50340
|
+
const usageSink = deps.usageSink ?? noopUsageSink;
|
|
48886
50341
|
async function post(call) {
|
|
48887
50342
|
const body = toAnthropicBody(call, defaultMaxTokens);
|
|
48888
50343
|
let res;
|
|
@@ -48908,16 +50363,33 @@ function createAnthropicTransport(deps = {}) {
|
|
|
48908
50363
|
if (!parsed.success) {
|
|
48909
50364
|
throw new ProviderError(502, "anthropic transport: malformed provider response");
|
|
48910
50365
|
}
|
|
48911
|
-
|
|
50366
|
+
const u = parsed.data.usage;
|
|
50367
|
+
const usage = {
|
|
50368
|
+
model: call.target.model,
|
|
50369
|
+
workload: call.request.workload,
|
|
50370
|
+
inputTokens: u.input_tokens,
|
|
50371
|
+
outputTokens: u.output_tokens,
|
|
50372
|
+
cacheReadInputTokens: u.cache_read_input_tokens,
|
|
50373
|
+
cacheCreationInputTokens: u.cache_creation_input_tokens
|
|
50374
|
+
};
|
|
50375
|
+
return { output: joinContentText(parsed.data.content), usage };
|
|
50376
|
+
}
|
|
50377
|
+
function reportUsage(usage) {
|
|
50378
|
+
try {
|
|
50379
|
+
usageSink.record(usage);
|
|
50380
|
+
} catch {
|
|
50381
|
+
}
|
|
48912
50382
|
}
|
|
48913
50383
|
return {
|
|
48914
50384
|
async execute(call) {
|
|
48915
|
-
const output = await post(call);
|
|
50385
|
+
const { output, usage } = await post(call);
|
|
50386
|
+
reportUsage(usage);
|
|
48916
50387
|
return { output };
|
|
48917
50388
|
},
|
|
48918
50389
|
stream(call) {
|
|
48919
50390
|
async function* gen() {
|
|
48920
|
-
const output = await post(call);
|
|
50391
|
+
const { output, usage } = await post(call);
|
|
50392
|
+
reportUsage(usage);
|
|
48921
50393
|
yield { delta: output };
|
|
48922
50394
|
}
|
|
48923
50395
|
return gen();
|
|
@@ -48962,7 +50434,7 @@ async function buildInferenceModelClient(deps) {
|
|
|
48962
50434
|
}
|
|
48963
50435
|
const effectiveConfig = deps.providerModelOverride !== void 0 ? applyProviderModelOverride(config2, deps.providerModelOverride) : config2;
|
|
48964
50436
|
const secrets = createSecretResolver(deps.secretsStore, deps.scope);
|
|
48965
|
-
const transport = createAnthropicTransport();
|
|
50437
|
+
const transport = createAnthropicTransport(deps.usageSink !== void 0 ? { usageSink: deps.usageSink } : {});
|
|
48966
50438
|
const router = createInferenceRouter({
|
|
48967
50439
|
config: effectiveConfig,
|
|
48968
50440
|
transport,
|
|
@@ -48972,6 +50444,216 @@ async function buildInferenceModelClient(deps) {
|
|
|
48972
50444
|
return new RouterModelClient(router);
|
|
48973
50445
|
}
|
|
48974
50446
|
|
|
50447
|
+
// dist/src/daemon/runtime/services/poll-backoff.js
|
|
50448
|
+
var DEFAULT_POLL_BACKOFF_FLOOR_MS = 1e3;
|
|
50449
|
+
var DEFAULT_POLL_BACKOFF_CEILING_MS = 3e4;
|
|
50450
|
+
var DEFAULT_POLL_BACKOFF_JITTER = 0.1;
|
|
50451
|
+
var BoolFlag6 = external_exports.preprocess((raw2) => {
|
|
50452
|
+
if (typeof raw2 === "boolean")
|
|
50453
|
+
return raw2;
|
|
50454
|
+
return raw2 === "true" || raw2 === "1";
|
|
50455
|
+
}, external_exports.boolean());
|
|
50456
|
+
function ClampedInt6(def, min = 1) {
|
|
50457
|
+
return external_exports.preprocess((raw2) => {
|
|
50458
|
+
const n = typeof raw2 === "number" ? raw2 : Number(raw2);
|
|
50459
|
+
if (!Number.isFinite(n))
|
|
50460
|
+
return def;
|
|
50461
|
+
return Math.max(min, Math.trunc(n));
|
|
50462
|
+
}, external_exports.number().int());
|
|
50463
|
+
}
|
|
50464
|
+
function ClampedFraction(def) {
|
|
50465
|
+
return external_exports.preprocess((raw2) => {
|
|
50466
|
+
const n = typeof raw2 === "number" ? raw2 : Number(raw2);
|
|
50467
|
+
if (!Number.isFinite(n))
|
|
50468
|
+
return def;
|
|
50469
|
+
return Math.min(1, Math.max(0, n));
|
|
50470
|
+
}, external_exports.number());
|
|
50471
|
+
}
|
|
50472
|
+
var PollBackoffConfigSchema = external_exports.object({
|
|
50473
|
+
/** Master switch; off → flat `floorMs`, the exact pre-PRD cadence (AC-9). */
|
|
50474
|
+
enabled: BoolFlag6.default(false),
|
|
50475
|
+
/** Fast floor the backoff starts at and resets to on any lease (AC-3). */
|
|
50476
|
+
floorMs: ClampedInt6(DEFAULT_POLL_BACKOFF_FLOOR_MS).default(DEFAULT_POLL_BACKOFF_FLOOR_MS),
|
|
50477
|
+
/** Ceiling the backoff doubles toward while the queue stays empty (AC-2). */
|
|
50478
|
+
ceilingMs: ClampedInt6(DEFAULT_POLL_BACKOFF_CEILING_MS).default(DEFAULT_POLL_BACKOFF_CEILING_MS),
|
|
50479
|
+
/** +/- jitter fraction of the current step, anti-thundering-herd. */
|
|
50480
|
+
jitter: ClampedFraction(DEFAULT_POLL_BACKOFF_JITTER).default(DEFAULT_POLL_BACKOFF_JITTER)
|
|
50481
|
+
});
|
|
50482
|
+
var PollBackoffConfigError = class extends Error {
|
|
50483
|
+
issues;
|
|
50484
|
+
constructor(issues) {
|
|
50485
|
+
super(`Invalid poll-backoff config: ${issues.join("; ")}`);
|
|
50486
|
+
this.name = "PollBackoffConfigError";
|
|
50487
|
+
this.issues = issues;
|
|
50488
|
+
}
|
|
50489
|
+
};
|
|
50490
|
+
function envPollBackoffConfigProvider(env = process.env) {
|
|
50491
|
+
return {
|
|
50492
|
+
read() {
|
|
50493
|
+
const raw2 = env.HONEYCOMB_POLL_BACKOFF_ENABLED;
|
|
50494
|
+
const enabled = raw2 === void 0 ? true : raw2;
|
|
50495
|
+
return {
|
|
50496
|
+
enabled,
|
|
50497
|
+
floorMs: env.HONEYCOMB_POLL_BACKOFF_FLOOR_MS,
|
|
50498
|
+
ceilingMs: env.HONEYCOMB_POLL_BACKOFF_CEILING_MS,
|
|
50499
|
+
jitter: env.HONEYCOMB_POLL_BACKOFF_JITTER
|
|
50500
|
+
};
|
|
50501
|
+
}
|
|
50502
|
+
};
|
|
50503
|
+
}
|
|
50504
|
+
function resolvePollBackoffConfig(provider = envPollBackoffConfigProvider()) {
|
|
50505
|
+
const parsed = PollBackoffConfigSchema.safeParse(provider.read());
|
|
50506
|
+
if (!parsed.success) {
|
|
50507
|
+
const issues = parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`);
|
|
50508
|
+
throw new PollBackoffConfigError(issues);
|
|
50509
|
+
}
|
|
50510
|
+
const cfg = parsed.data;
|
|
50511
|
+
return cfg.ceilingMs < cfg.floorMs ? { ...cfg, ceilingMs: cfg.floorMs } : cfg;
|
|
50512
|
+
}
|
|
50513
|
+
var defaultJitterSource = () => Math.random() * 2 - 1;
|
|
50514
|
+
var PollBackoff = class {
|
|
50515
|
+
floorMs;
|
|
50516
|
+
ceilingMs;
|
|
50517
|
+
jitter;
|
|
50518
|
+
jitterSource;
|
|
50519
|
+
/** The current un-jittered step. Starts at the floor; doubles toward the ceiling. */
|
|
50520
|
+
stepMs;
|
|
50521
|
+
/**
|
|
50522
|
+
* @param config the resolved bounds + jitter fraction. The state machine is only
|
|
50523
|
+
* ever CONSTRUCTED when backoff is active; a loop with `config.enabled === false`
|
|
50524
|
+
* does not build one (it keeps its flat legacy interval), so this class need not
|
|
50525
|
+
* re-check the flag.
|
|
50526
|
+
* @param jitterSource injectable `[-1, 1]` source — a test pins it to 0 to assert
|
|
50527
|
+
* the exact geometric schedule; production uses the uniform random default.
|
|
50528
|
+
*/
|
|
50529
|
+
constructor(config2, jitterSource = defaultJitterSource) {
|
|
50530
|
+
this.floorMs = config2.floorMs;
|
|
50531
|
+
this.ceilingMs = Math.max(config2.floorMs, config2.ceilingMs);
|
|
50532
|
+
this.jitter = config2.jitter;
|
|
50533
|
+
this.jitterSource = jitterSource;
|
|
50534
|
+
this.stepMs = this.floorMs;
|
|
50535
|
+
}
|
|
50536
|
+
/**
|
|
50537
|
+
* Step the delay toward the ceiling after an EMPTY lease (no job this tick):
|
|
50538
|
+
* double the current step, capped at the ceiling. Idempotent at the ceiling (a
|
|
50539
|
+
* fully-idle daemon stays there until a job arrives).
|
|
50540
|
+
*/
|
|
50541
|
+
onEmptyLease() {
|
|
50542
|
+
this.stepMs = Math.min(this.stepMs * 2, this.ceilingMs);
|
|
50543
|
+
}
|
|
50544
|
+
/**
|
|
50545
|
+
* Reset the delay to the floor after a SUCCESSFUL lease (AC-3): the first real
|
|
50546
|
+
* job snaps the cadence back to fast so an active session is unchanged.
|
|
50547
|
+
*/
|
|
50548
|
+
onLease() {
|
|
50549
|
+
this.stepMs = this.floorMs;
|
|
50550
|
+
}
|
|
50551
|
+
/** The current un-jittered step (for assertions on the geometric schedule). */
|
|
50552
|
+
currentStepMs() {
|
|
50553
|
+
return this.stepMs;
|
|
50554
|
+
}
|
|
50555
|
+
/**
|
|
50556
|
+
* The ms to wait before the next tick: the current step plus a bounded jitter.
|
|
50557
|
+
* The jitter is a fraction of the step (`jitter * step`), so it scales with the
|
|
50558
|
+
* step; the result is clamped to `[floorMs, ceilingMs]` so jitter never pushes
|
|
50559
|
+
* the cadence below the fast floor (which would defeat the cost cut) or above the
|
|
50560
|
+
* ceiling (which would blow the worst-case pickup-latency budget).
|
|
50561
|
+
*/
|
|
50562
|
+
nextDelayMs() {
|
|
50563
|
+
const offset = this.jitterSource() * this.jitter * this.stepMs;
|
|
50564
|
+
const delayed = this.stepMs + offset;
|
|
50565
|
+
return Math.min(this.ceilingMs, Math.max(this.floorMs, Math.round(delayed)));
|
|
50566
|
+
}
|
|
50567
|
+
};
|
|
50568
|
+
|
|
50569
|
+
// dist/src/daemon/runtime/services/poll-loop.js
|
|
50570
|
+
var AdaptivePollLoop = class {
|
|
50571
|
+
tick;
|
|
50572
|
+
backoffEnabled;
|
|
50573
|
+
flatIntervalMs;
|
|
50574
|
+
timers;
|
|
50575
|
+
backoff;
|
|
50576
|
+
handle;
|
|
50577
|
+
stopped = false;
|
|
50578
|
+
/** Guards against overlapping ticks on the poll loop (the workers' `running` flag). */
|
|
50579
|
+
running = false;
|
|
50580
|
+
constructor(deps) {
|
|
50581
|
+
this.tick = deps.tick;
|
|
50582
|
+
this.backoffEnabled = deps.backoff.enabled;
|
|
50583
|
+
this.flatIntervalMs = deps.flatIntervalMs;
|
|
50584
|
+
this.timers = deps.timers;
|
|
50585
|
+
this.backoff = deps.backoff.enabled ? new PollBackoff(deps.backoff) : null;
|
|
50586
|
+
}
|
|
50587
|
+
start() {
|
|
50588
|
+
this.stopped = false;
|
|
50589
|
+
if (this.backoff === null) {
|
|
50590
|
+
this.handle = this.timers.setTimer(() => {
|
|
50591
|
+
this.fireGuarded(null);
|
|
50592
|
+
}, this.flatIntervalMs);
|
|
50593
|
+
return;
|
|
50594
|
+
}
|
|
50595
|
+
this.scheduleNext(this.backoff.nextDelayMs());
|
|
50596
|
+
}
|
|
50597
|
+
/** Arm the next one-shot tick (adaptive path only). */
|
|
50598
|
+
scheduleNext(ms) {
|
|
50599
|
+
if (this.stopped)
|
|
50600
|
+
return;
|
|
50601
|
+
this.handle = this.timers.setTimer(() => {
|
|
50602
|
+
this.fireGuarded(this.backoff);
|
|
50603
|
+
}, ms);
|
|
50604
|
+
}
|
|
50605
|
+
/**
|
|
50606
|
+
* One guarded tick. Skips if a previous run is still in flight (never overlap).
|
|
50607
|
+
* On the adaptive path, feeds the lease outcome to the state machine and re-arms
|
|
50608
|
+
* the next tick; on the flat path, the repeating interval re-fires on its own.
|
|
50609
|
+
*/
|
|
50610
|
+
fireGuarded(backoff) {
|
|
50611
|
+
if (this.running)
|
|
50612
|
+
return;
|
|
50613
|
+
this.running = true;
|
|
50614
|
+
void this.tick().then((processed) => {
|
|
50615
|
+
if (backoff === null)
|
|
50616
|
+
return;
|
|
50617
|
+
if (processed)
|
|
50618
|
+
backoff.onLease();
|
|
50619
|
+
else
|
|
50620
|
+
backoff.onEmptyLease();
|
|
50621
|
+
}).finally(() => {
|
|
50622
|
+
this.running = false;
|
|
50623
|
+
if (backoff !== null)
|
|
50624
|
+
this.scheduleNext(backoff.nextDelayMs());
|
|
50625
|
+
});
|
|
50626
|
+
}
|
|
50627
|
+
stop() {
|
|
50628
|
+
this.stopped = true;
|
|
50629
|
+
if (this.handle !== void 0) {
|
|
50630
|
+
this.timers.clearTimer(this.handle);
|
|
50631
|
+
this.handle = void 0;
|
|
50632
|
+
}
|
|
50633
|
+
}
|
|
50634
|
+
};
|
|
50635
|
+
function createPollLoop(deps) {
|
|
50636
|
+
return new AdaptivePollLoop(deps);
|
|
50637
|
+
}
|
|
50638
|
+
function buildWorkerPollLoop(options) {
|
|
50639
|
+
const setTimer = options.setTimer ?? ((cb, ms) => {
|
|
50640
|
+
const t = setInterval(cb, ms);
|
|
50641
|
+
if (typeof t === "object" && t !== null && "unref" in t && typeof t.unref === "function")
|
|
50642
|
+
t.unref();
|
|
50643
|
+
return t;
|
|
50644
|
+
});
|
|
50645
|
+
const clearTimer = options.clearTimer ?? ((handle) => {
|
|
50646
|
+
if (handle !== void 0)
|
|
50647
|
+
clearInterval(handle);
|
|
50648
|
+
});
|
|
50649
|
+
return createPollLoop({
|
|
50650
|
+
tick: options.tick,
|
|
50651
|
+
backoff: options.backoff ?? PollBackoffConfigSchema.parse({}),
|
|
50652
|
+
flatIntervalMs: options.flatIntervalMs,
|
|
50653
|
+
timers: { setTimer, clearTimer }
|
|
50654
|
+
});
|
|
50655
|
+
}
|
|
50656
|
+
|
|
48975
50657
|
// dist/src/daemon/runtime/pipeline/stage-worker.js
|
|
48976
50658
|
var PIPELINE_JOB_KINDS = Object.freeze([
|
|
48977
50659
|
"memory_extraction",
|
|
@@ -48999,33 +50681,42 @@ var PipelineStageWorker = class {
|
|
|
48999
50681
|
queue;
|
|
49000
50682
|
handlers;
|
|
49001
50683
|
logger;
|
|
50684
|
+
/** Public for the lease coordinator's union (the kinds this participant owns). */
|
|
49002
50685
|
leaseKinds;
|
|
49003
|
-
|
|
49004
|
-
setTimer;
|
|
49005
|
-
clearTimer;
|
|
49006
|
-
handle;
|
|
49007
|
-
/** Guards against overlapping `runOnce` invocations on the poll loop. */
|
|
49008
|
-
running = false;
|
|
50686
|
+
loop;
|
|
49009
50687
|
constructor(deps) {
|
|
49010
50688
|
this.queue = deps.queue;
|
|
49011
50689
|
this.handlers = deps.handlers;
|
|
49012
50690
|
this.logger = deps.logger;
|
|
49013
50691
|
this.leaseKinds = deps.leaseKinds ?? PIPELINE_JOB_KINDS;
|
|
49014
|
-
this.
|
|
49015
|
-
|
|
49016
|
-
|
|
49017
|
-
|
|
49018
|
-
|
|
50692
|
+
this.loop = buildWorkerPollLoop({
|
|
50693
|
+
tick: () => this.runOnce(),
|
|
50694
|
+
flatIntervalMs: deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2,
|
|
50695
|
+
backoff: deps.backoff,
|
|
50696
|
+
setTimer: deps.setTimer,
|
|
50697
|
+
clearTimer: deps.clearTimer
|
|
49019
50698
|
});
|
|
49020
50699
|
}
|
|
49021
50700
|
async runOnce() {
|
|
49022
50701
|
const leased = await this.queue.lease(this.leaseKinds);
|
|
49023
50702
|
if (leased === null)
|
|
49024
50703
|
return false;
|
|
50704
|
+
await this.processLeased(leased);
|
|
50705
|
+
return true;
|
|
50706
|
+
}
|
|
50707
|
+
/**
|
|
50708
|
+
* PRD-062b (AC-4): process ONE already-leased pipeline job — route it by kind, run
|
|
50709
|
+
* the handler, and complete/fail it. Split out of {@link runOnce} so the single
|
|
50710
|
+
* combined lease coordinator can dispatch a job IT leased (over the union of kinds)
|
|
50711
|
+
* to this participant without a second lease. The standalone `runOnce` leases then
|
|
50712
|
+
* calls this; both paths share the identical route+run+complete/fail body, so kind
|
|
50713
|
+
* isolation and the no-swallowed-error contract hold whether consolidation is on or off.
|
|
50714
|
+
*/
|
|
50715
|
+
async processLeased(leased) {
|
|
49025
50716
|
if (!isPipelineJobKind(leased.kind)) {
|
|
49026
50717
|
this.logger?.event("stage.unknown_kind", { id: leased.id, kind: leased.kind });
|
|
49027
50718
|
await this.queue.fail(leased.id, `unknown pipeline job kind: ${leased.kind}`);
|
|
49028
|
-
return
|
|
50719
|
+
return;
|
|
49029
50720
|
}
|
|
49030
50721
|
const job = toStageJob(leased, leased.kind);
|
|
49031
50722
|
const handler = this.handlers[leased.kind];
|
|
@@ -49038,23 +50729,12 @@ var PipelineStageWorker = class {
|
|
|
49038
50729
|
this.logger?.event("stage.failed", { id: job.id, kind: job.kind, attempt: job.attempt, reason });
|
|
49039
50730
|
await this.queue.fail(job.id, reason);
|
|
49040
50731
|
}
|
|
49041
|
-
return true;
|
|
49042
50732
|
}
|
|
49043
50733
|
start() {
|
|
49044
|
-
this.
|
|
49045
|
-
if (this.running)
|
|
49046
|
-
return;
|
|
49047
|
-
this.running = true;
|
|
49048
|
-
void this.runOnce().finally(() => {
|
|
49049
|
-
this.running = false;
|
|
49050
|
-
});
|
|
49051
|
-
}, this.pollIntervalMs);
|
|
50734
|
+
this.loop.start();
|
|
49052
50735
|
}
|
|
49053
50736
|
stop() {
|
|
49054
|
-
|
|
49055
|
-
this.clearTimer(this.handle);
|
|
49056
|
-
this.handle = void 0;
|
|
49057
|
-
}
|
|
50737
|
+
this.loop.stop();
|
|
49058
50738
|
}
|
|
49059
50739
|
};
|
|
49060
50740
|
function createStageWorker(deps) {
|
|
@@ -49894,34 +51574,45 @@ function extractionFanOut(queue) {
|
|
|
49894
51574
|
});
|
|
49895
51575
|
};
|
|
49896
51576
|
}
|
|
49897
|
-
function
|
|
51577
|
+
function buildControlledWritePayload(decision, entities) {
|
|
51578
|
+
const proposal = {
|
|
51579
|
+
action: decision.proposal.action,
|
|
51580
|
+
confidence: decision.proposal.confidence,
|
|
51581
|
+
reason: decision.proposal.reason
|
|
51582
|
+
};
|
|
51583
|
+
if (decision.proposal.targetId !== void 0 && decision.proposal.targetId !== "") {
|
|
51584
|
+
proposal.target_id = decision.proposal.targetId;
|
|
51585
|
+
}
|
|
51586
|
+
const targetId = decision.proposal.targetId;
|
|
51587
|
+
const candidates = decision.candidates.filter((c) => c.id !== "" && c.id !== targetId && typeof c.content === "string" && c.content !== "").map((c) => ({ id: c.id, content: c.content }));
|
|
51588
|
+
return {
|
|
51589
|
+
proposal,
|
|
51590
|
+
content: decision.fact.content,
|
|
51591
|
+
normalized_content: decision.fact.content,
|
|
51592
|
+
fact_confidence: decision.fact.confidence,
|
|
51593
|
+
fact_type: decision.fact.type,
|
|
51594
|
+
entities: serializeEntities(entities),
|
|
51595
|
+
...candidates.length > 0 ? { candidates } : {}
|
|
51596
|
+
};
|
|
51597
|
+
}
|
|
51598
|
+
function decisionFanOut(queue, config2 = amplificationConfig()) {
|
|
49898
51599
|
return async (job, decisions) => {
|
|
49899
51600
|
const entities = readForwardedEntities(job.payload);
|
|
49900
|
-
|
|
49901
|
-
|
|
49902
|
-
|
|
49903
|
-
|
|
49904
|
-
|
|
49905
|
-
confidence: decision.proposal.confidence,
|
|
49906
|
-
reason: decision.proposal.reason
|
|
49907
|
-
};
|
|
49908
|
-
if (decision.proposal.targetId !== void 0 && decision.proposal.targetId !== "") {
|
|
49909
|
-
proposal.target_id = decision.proposal.targetId;
|
|
49910
|
-
}
|
|
49911
|
-
const targetId = decision.proposal.targetId;
|
|
49912
|
-
const candidates = decision.candidates.filter((c) => c.id !== "" && c.id !== targetId && typeof c.content === "string" && c.content !== "").map((c) => ({ id: c.id, content: c.content }));
|
|
51601
|
+
const envelope = scopeEnvelope(job.scope);
|
|
51602
|
+
const facts = decisions.filter((d) => d.proposal.action !== "none").map((d) => buildControlledWritePayload(d, entities));
|
|
51603
|
+
if (facts.length === 0)
|
|
51604
|
+
return;
|
|
51605
|
+
if (config2.fanoutBatch) {
|
|
49913
51606
|
await queue.enqueue({
|
|
49914
51607
|
kind: "memory_controlled_write",
|
|
49915
|
-
payload: {
|
|
49916
|
-
|
|
49917
|
-
|
|
49918
|
-
|
|
49919
|
-
|
|
49920
|
-
|
|
49921
|
-
|
|
49922
|
-
|
|
49923
|
-
...candidates.length > 0 ? { candidates } : {}
|
|
49924
|
-
}
|
|
51608
|
+
payload: { ...envelope, [CONTROLLED_WRITE_BATCH_KEY]: facts }
|
|
51609
|
+
});
|
|
51610
|
+
return;
|
|
51611
|
+
}
|
|
51612
|
+
for (const fact of facts) {
|
|
51613
|
+
await queue.enqueue({
|
|
51614
|
+
kind: "memory_controlled_write",
|
|
51615
|
+
payload: { ...envelope, ...fact }
|
|
49925
51616
|
});
|
|
49926
51617
|
}
|
|
49927
51618
|
};
|
|
@@ -50463,6 +52154,8 @@ function stateUpdaterFromTrigger(trigger) {
|
|
|
50463
52154
|
};
|
|
50464
52155
|
}
|
|
50465
52156
|
var PollinatingJobWorkerImpl = class {
|
|
52157
|
+
/** Public for the lease coordinator's union — the single `pollinating` kind. */
|
|
52158
|
+
leaseKinds = LEASE_KINDS2;
|
|
50466
52159
|
queue;
|
|
50467
52160
|
storage;
|
|
50468
52161
|
scope;
|
|
@@ -50472,12 +52165,7 @@ var PollinatingJobWorkerImpl = class {
|
|
|
50472
52165
|
stateUpdater;
|
|
50473
52166
|
logger;
|
|
50474
52167
|
clock;
|
|
50475
|
-
|
|
50476
|
-
setTimer;
|
|
50477
|
-
clearTimer;
|
|
50478
|
-
handle;
|
|
50479
|
-
/** Guards against overlapping `runOnce` invocations on the poll loop. */
|
|
50480
|
-
running = false;
|
|
52168
|
+
loop;
|
|
50481
52169
|
constructor(deps) {
|
|
50482
52170
|
this.queue = deps.queue;
|
|
50483
52171
|
this.storage = deps.storage;
|
|
@@ -50488,22 +52176,36 @@ var PollinatingJobWorkerImpl = class {
|
|
|
50488
52176
|
this.stateUpdater = deps.stateUpdater ?? stateUpdaterFromTrigger(deps.trigger);
|
|
50489
52177
|
this.logger = deps.logger;
|
|
50490
52178
|
this.clock = deps.clock ?? { now: () => Date.now() };
|
|
50491
|
-
this.
|
|
50492
|
-
|
|
50493
|
-
|
|
50494
|
-
|
|
50495
|
-
|
|
52179
|
+
this.loop = buildWorkerPollLoop({
|
|
52180
|
+
tick: () => this.runOnce(),
|
|
52181
|
+
flatIntervalMs: deps.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS3,
|
|
52182
|
+
backoff: deps.backoff,
|
|
52183
|
+
setTimer: deps.setTimer,
|
|
52184
|
+
clearTimer: deps.clearTimer
|
|
50496
52185
|
});
|
|
50497
52186
|
}
|
|
50498
52187
|
async runOnce() {
|
|
50499
|
-
const leased = await this.queue.lease(
|
|
52188
|
+
const leased = await this.queue.lease(this.leaseKinds);
|
|
50500
52189
|
if (leased === null)
|
|
50501
52190
|
return false;
|
|
52191
|
+
await this.processLeased(leased);
|
|
52192
|
+
return true;
|
|
52193
|
+
}
|
|
52194
|
+
/**
|
|
52195
|
+
* PRD-062b (AC-4): process ONE already-leased `pollinating` job — parse it, select
|
|
52196
|
+
* the strategy, run the pass, and complete/fail it. Split out of {@link runOnce} so
|
|
52197
|
+
* the single combined lease coordinator can dispatch a job IT leased (over the
|
|
52198
|
+
* union of kinds) to this participant without a second lease. The standalone
|
|
52199
|
+
* `runOnce` leases then calls this; both share the identical parse+run+complete/fail
|
|
52200
|
+
* body, so kind isolation and the no-swallowed-error contract hold whether
|
|
52201
|
+
* consolidation is on or off.
|
|
52202
|
+
*/
|
|
52203
|
+
async processLeased(leased) {
|
|
50502
52204
|
const job = parsePollinatingJobPayload(leased.payload);
|
|
50503
52205
|
if (job === null) {
|
|
50504
52206
|
this.logger?.event("pollinating.worker.bad_payload", { id: leased.id });
|
|
50505
52207
|
await this.queue.fail(leased.id, "malformed pollinating job payload");
|
|
50506
|
-
return
|
|
52208
|
+
return;
|
|
50507
52209
|
}
|
|
50508
52210
|
try {
|
|
50509
52211
|
const strategy = await this.selectStrategy(job);
|
|
@@ -50527,7 +52229,6 @@ var PollinatingJobWorkerImpl = class {
|
|
|
50527
52229
|
this.logger?.event("pollinating.worker.failed", { id: leased.id, attempt: leased.attempt, reason });
|
|
50528
52230
|
await this.queue.fail(leased.id, reason);
|
|
50529
52231
|
}
|
|
50530
|
-
return true;
|
|
50531
52232
|
}
|
|
50532
52233
|
/**
|
|
50533
52234
|
* Select the payload strategy for a job by mode (D-4). Compaction when the payload
|
|
@@ -50555,26 +52256,105 @@ var PollinatingJobWorkerImpl = class {
|
|
|
50555
52256
|
return shouldEnterCompaction(this.config, state.lastPassAt);
|
|
50556
52257
|
}
|
|
50557
52258
|
start() {
|
|
50558
|
-
this.
|
|
50559
|
-
if (this.running)
|
|
50560
|
-
return;
|
|
50561
|
-
this.running = true;
|
|
50562
|
-
void this.runOnce().finally(() => {
|
|
50563
|
-
this.running = false;
|
|
50564
|
-
});
|
|
50565
|
-
}, this.pollIntervalMs);
|
|
52259
|
+
this.loop.start();
|
|
50566
52260
|
}
|
|
50567
52261
|
stop() {
|
|
50568
|
-
|
|
50569
|
-
this.clearTimer(this.handle);
|
|
50570
|
-
this.handle = void 0;
|
|
50571
|
-
}
|
|
52262
|
+
this.loop.stop();
|
|
50572
52263
|
}
|
|
50573
52264
|
};
|
|
50574
52265
|
function createPollinatingWorker(deps) {
|
|
50575
52266
|
return new PollinatingJobWorkerImpl(deps);
|
|
50576
52267
|
}
|
|
50577
52268
|
|
|
52269
|
+
// dist/src/daemon/runtime/services/lease-coordinator.js
|
|
52270
|
+
var CombinedLeaseCoordinator = class {
|
|
52271
|
+
queue;
|
|
52272
|
+
participants;
|
|
52273
|
+
logger;
|
|
52274
|
+
unionKinds;
|
|
52275
|
+
/** `kind` → the participant that owns it (built once; one owner per kind). */
|
|
52276
|
+
routes;
|
|
52277
|
+
loop;
|
|
52278
|
+
constructor(deps) {
|
|
52279
|
+
this.queue = deps.queue;
|
|
52280
|
+
this.participants = deps.participants;
|
|
52281
|
+
this.logger = deps.logger;
|
|
52282
|
+
this.routes = /* @__PURE__ */ new Map();
|
|
52283
|
+
const union2 = [];
|
|
52284
|
+
for (const participant of deps.participants) {
|
|
52285
|
+
for (const kind of participant.leaseKinds) {
|
|
52286
|
+
if (this.routes.has(kind)) {
|
|
52287
|
+
this.logger?.event("lease.coordinator.duplicate_kind", { kind });
|
|
52288
|
+
continue;
|
|
52289
|
+
}
|
|
52290
|
+
this.routes.set(kind, participant);
|
|
52291
|
+
union2.push(kind);
|
|
52292
|
+
}
|
|
52293
|
+
}
|
|
52294
|
+
this.unionKinds = union2;
|
|
52295
|
+
const timers = deps.timers ?? {
|
|
52296
|
+
setTimer: (cb, ms) => {
|
|
52297
|
+
const t = setInterval(cb, ms);
|
|
52298
|
+
if (typeof t === "object" && t !== null && "unref" in t && typeof t.unref === "function")
|
|
52299
|
+
t.unref();
|
|
52300
|
+
return t;
|
|
52301
|
+
},
|
|
52302
|
+
clearTimer: (handle) => {
|
|
52303
|
+
if (handle !== void 0)
|
|
52304
|
+
clearInterval(handle);
|
|
52305
|
+
}
|
|
52306
|
+
};
|
|
52307
|
+
this.loop = createPollLoop({
|
|
52308
|
+
tick: () => this.runOnce(),
|
|
52309
|
+
backoff: deps.backoff,
|
|
52310
|
+
flatIntervalMs: deps.flatIntervalMs,
|
|
52311
|
+
timers
|
|
52312
|
+
});
|
|
52313
|
+
}
|
|
52314
|
+
async runOnce() {
|
|
52315
|
+
const leased = await this.queue.lease(this.unionKinds);
|
|
52316
|
+
if (leased === null)
|
|
52317
|
+
return false;
|
|
52318
|
+
const participant = this.routes.get(leased.kind);
|
|
52319
|
+
if (participant === void 0) {
|
|
52320
|
+
this.logger?.event("lease.coordinator.unknown_kind", { id: leased.id, kind: leased.kind });
|
|
52321
|
+
await this.queue.fail(leased.id, `no participant owns leased kind: ${leased.kind}`);
|
|
52322
|
+
return true;
|
|
52323
|
+
}
|
|
52324
|
+
await participant.processLeased(leased);
|
|
52325
|
+
return true;
|
|
52326
|
+
}
|
|
52327
|
+
start() {
|
|
52328
|
+
this.loop.start();
|
|
52329
|
+
}
|
|
52330
|
+
stop() {
|
|
52331
|
+
this.loop.stop();
|
|
52332
|
+
}
|
|
52333
|
+
};
|
|
52334
|
+
function createLeaseCoordinator(deps) {
|
|
52335
|
+
return new CombinedLeaseCoordinator(deps);
|
|
52336
|
+
}
|
|
52337
|
+
var BoolFlag7 = external_exports.preprocess((raw2) => {
|
|
52338
|
+
if (typeof raw2 === "boolean")
|
|
52339
|
+
return raw2;
|
|
52340
|
+
return raw2 === "true" || raw2 === "1";
|
|
52341
|
+
}, external_exports.boolean());
|
|
52342
|
+
var PollConsolidateConfigSchema = external_exports.object({
|
|
52343
|
+
/** Master switch; off → two independent lease passes, the pre-PRD path (AC-9). */
|
|
52344
|
+
enabled: BoolFlag7.default(false)
|
|
52345
|
+
});
|
|
52346
|
+
function envPollConsolidateConfigProvider(env = process.env) {
|
|
52347
|
+
return {
|
|
52348
|
+
read() {
|
|
52349
|
+
const raw2 = env.HONEYCOMB_POLL_CONSOLIDATE;
|
|
52350
|
+
return { enabled: raw2 === void 0 ? true : raw2 };
|
|
52351
|
+
}
|
|
52352
|
+
};
|
|
52353
|
+
}
|
|
52354
|
+
function resolvePollConsolidateConfig(provider = envPollConsolidateConfigProvider()) {
|
|
52355
|
+
return PollConsolidateConfigSchema.parse(provider.read());
|
|
52356
|
+
}
|
|
52357
|
+
|
|
50578
52358
|
// dist/src/daemon/runtime/skillify/worker.js
|
|
50579
52359
|
import { homedir as homedir24 } from "node:os";
|
|
50580
52360
|
import { join as join31 } from "node:path";
|
|
@@ -50668,6 +52448,95 @@ function sanitizeSegment5(projectKey) {
|
|
|
50668
52448
|
return cleaned === "" ? "default" : cleaned;
|
|
50669
52449
|
}
|
|
50670
52450
|
|
|
52451
|
+
// dist/src/daemon/runtime/dashboard/roi-session-writer.js
|
|
52452
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
52453
|
+
var SESSION_TURNS_LIMIT = 2e3;
|
|
52454
|
+
function tokenCountOrNull2(value) {
|
|
52455
|
+
if (value === null || value === void 0)
|
|
52456
|
+
return null;
|
|
52457
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
52458
|
+
return Number.isFinite(n) ? Math.trunc(n) : null;
|
|
52459
|
+
}
|
|
52460
|
+
function rowToCapturedTurn2(r) {
|
|
52461
|
+
const sourceTool = typeof r.source_tool === "string" ? r.source_tool : "";
|
|
52462
|
+
return {
|
|
52463
|
+
input_tokens: tokenCountOrNull2(r.input_tokens),
|
|
52464
|
+
output_tokens: tokenCountOrNull2(r.output_tokens),
|
|
52465
|
+
cache_read_input_tokens: tokenCountOrNull2(r.cache_read_input_tokens),
|
|
52466
|
+
cache_creation_input_tokens: tokenCountOrNull2(r.cache_creation_input_tokens),
|
|
52467
|
+
...sourceTool !== "" ? { sourceTool } : {}
|
|
52468
|
+
};
|
|
52469
|
+
}
|
|
52470
|
+
async function readSessionTurns(storage, scope, path4) {
|
|
52471
|
+
const tbl = sqlIdent("sessions");
|
|
52472
|
+
const pathCol = sqlIdent("path");
|
|
52473
|
+
const sql = `SELECT ${sqlIdent("input_tokens")}, ${sqlIdent("output_tokens")}, ${sqlIdent("cache_read_input_tokens")}, ${sqlIdent("cache_creation_input_tokens")}, ${sqlIdent("source_tool")} FROM "${tbl}" WHERE ${pathCol} = ${sLiteral(path4)} LIMIT ${SESSION_TURNS_LIMIT}`;
|
|
52474
|
+
let result;
|
|
52475
|
+
try {
|
|
52476
|
+
result = await storage.query(sql, scope);
|
|
52477
|
+
} catch {
|
|
52478
|
+
return [];
|
|
52479
|
+
}
|
|
52480
|
+
return isOk(result) ? result.rows.map(rowToCapturedTurn2) : [];
|
|
52481
|
+
}
|
|
52482
|
+
function createRoiSessionWriter(deps) {
|
|
52483
|
+
const clock = deps.clock ?? { now: () => Date.now() };
|
|
52484
|
+
return {
|
|
52485
|
+
async writeForSession(input) {
|
|
52486
|
+
try {
|
|
52487
|
+
if (input.path.trim() === "") {
|
|
52488
|
+
deps.logger?.event("roi.write.skipped", { reason: "blank path", sessionId: input.sessionId });
|
|
52489
|
+
return;
|
|
52490
|
+
}
|
|
52491
|
+
const turns = await readSessionTurns(deps.storage, deps.scope, input.path);
|
|
52492
|
+
const measured2 = measuredCacheSavings(turns);
|
|
52493
|
+
const modeled2 = modeledMemoryInjectionSavings(1);
|
|
52494
|
+
let inputTokens = 0;
|
|
52495
|
+
let outputTokens = 0;
|
|
52496
|
+
let cacheReadTokens = 0;
|
|
52497
|
+
let cacheCreationTokens = 0;
|
|
52498
|
+
for (const t of turns) {
|
|
52499
|
+
inputTokens += t.input_tokens ?? 0;
|
|
52500
|
+
outputTokens += t.output_tokens ?? 0;
|
|
52501
|
+
cacheReadTokens += t.cache_read_input_tokens ?? 0;
|
|
52502
|
+
cacheCreationTokens += t.cache_creation_input_tokens ?? 0;
|
|
52503
|
+
}
|
|
52504
|
+
const createdAt = new Date(clock.now()).toISOString();
|
|
52505
|
+
const { teamId, userId } = await appendRoiMetric(deps.storage, deps.scope, {
|
|
52506
|
+
id: randomUUID7(),
|
|
52507
|
+
sessionId: input.sessionId,
|
|
52508
|
+
agentId: input.agentId,
|
|
52509
|
+
...input.projectId !== void 0 ? { projectId: input.projectId } : {},
|
|
52510
|
+
inputTokens,
|
|
52511
|
+
outputTokens,
|
|
52512
|
+
cacheReadTokens,
|
|
52513
|
+
cacheCreationTokens,
|
|
52514
|
+
measuredCacheSavingsCents: measured2.value.savingsCents,
|
|
52515
|
+
modeledSavingsCents: modeled2.value.estimatedCents,
|
|
52516
|
+
modeledAssumptionRef: modeled2.assumption.kind,
|
|
52517
|
+
grossCostCents: 0,
|
|
52518
|
+
infraCostCents: 0,
|
|
52519
|
+
costBasis: "none",
|
|
52520
|
+
allocationMethod: "",
|
|
52521
|
+
createdAt
|
|
52522
|
+
});
|
|
52523
|
+
deps.logger?.event("roi.write.appended", {
|
|
52524
|
+
sessionId: input.sessionId,
|
|
52525
|
+
measuredCents: measured2.value.savingsCents,
|
|
52526
|
+
teamId,
|
|
52527
|
+
// user_id is gated to '' today — surface that it stayed gated (never a leaked identity).
|
|
52528
|
+
userGated: userId === ""
|
|
52529
|
+
});
|
|
52530
|
+
} catch (err) {
|
|
52531
|
+
deps.logger?.event("roi.write.failed", {
|
|
52532
|
+
sessionId: input.sessionId,
|
|
52533
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
52534
|
+
});
|
|
52535
|
+
}
|
|
52536
|
+
}
|
|
52537
|
+
};
|
|
52538
|
+
}
|
|
52539
|
+
|
|
50671
52540
|
// dist/src/daemon/runtime/skillify/worker.js
|
|
50672
52541
|
var SKILLIFY_JOB_KIND = "skillify";
|
|
50673
52542
|
var DEFAULT_POLL_INTERVAL_MS4 = 1e3;
|
|
@@ -50710,6 +52579,8 @@ var SkillifyJobWorkerImpl = class {
|
|
|
50710
52579
|
gateOverride;
|
|
50711
52580
|
fetcherOverride;
|
|
50712
52581
|
storeOverride;
|
|
52582
|
+
/** PRD-060e/060f — the per-session ROI writer fired once at completion (fail-soft). */
|
|
52583
|
+
roiWriter;
|
|
50713
52584
|
handle;
|
|
50714
52585
|
/** Guards against overlapping `runOnce` invocations on the poll loop. */
|
|
50715
52586
|
running = false;
|
|
@@ -50735,6 +52606,7 @@ var SkillifyJobWorkerImpl = class {
|
|
|
50735
52606
|
this.gateOverride = deps.gateOverride;
|
|
50736
52607
|
this.fetcherOverride = deps.fetcherOverride;
|
|
50737
52608
|
this.storeOverride = deps.storeOverride;
|
|
52609
|
+
this.roiWriter = deps.roiWriter ?? createRoiSessionWriter({ storage: this.storage, scope: this.scope });
|
|
50738
52610
|
}
|
|
50739
52611
|
async runOnce() {
|
|
50740
52612
|
let leased;
|
|
@@ -50775,6 +52647,19 @@ var SkillifyJobWorkerImpl = class {
|
|
|
50775
52647
|
const outcome = await writeSkill(result.outcome.verdict, { store, install, author: this.author, projectId }, result.outcome.minedSessionIds, "global");
|
|
50776
52648
|
const sessionDates = result.outcome.pairs.map((p) => p.sessionDate);
|
|
50777
52649
|
this.watermarkStore.advance(projectKey, sessionDates);
|
|
52650
|
+
try {
|
|
52651
|
+
await this.roiWriter.writeForSession({
|
|
52652
|
+
sessionId: payload.sessionId,
|
|
52653
|
+
path: payload.path,
|
|
52654
|
+
agentId: this.author,
|
|
52655
|
+
projectId
|
|
52656
|
+
});
|
|
52657
|
+
} catch (roiErr) {
|
|
52658
|
+
this.logger?.event("skillify.worker.roi_write_failed", {
|
|
52659
|
+
id: job.id,
|
|
52660
|
+
reason: roiErr instanceof Error ? roiErr.message : String(roiErr)
|
|
52661
|
+
});
|
|
52662
|
+
}
|
|
50778
52663
|
await this.queue.complete(job.id);
|
|
50779
52664
|
this.logger?.event("skillify.worker.completed", {
|
|
50780
52665
|
id: job.id,
|
|
@@ -50841,6 +52726,86 @@ function createSkillifyJobWorker(deps) {
|
|
|
50841
52726
|
// dist/src/daemon/storage/client.js
|
|
50842
52727
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
50843
52728
|
|
|
52729
|
+
// dist/src/daemon/storage/query-meter.js
|
|
52730
|
+
var QUERY_SOURCES = [
|
|
52731
|
+
"poll-lease",
|
|
52732
|
+
"poll-reaper",
|
|
52733
|
+
"capture-write",
|
|
52734
|
+
"fan-out-enqueue",
|
|
52735
|
+
"controlled-write",
|
|
52736
|
+
"recall-arm",
|
|
52737
|
+
"embedding",
|
|
52738
|
+
"other"
|
|
52739
|
+
];
|
|
52740
|
+
var DEFAULT_QUERY_SOURCE = "other";
|
|
52741
|
+
var QueryMeter = class {
|
|
52742
|
+
/** `source` → {reads, writes}. Lazily populated on first hit per source. */
|
|
52743
|
+
counts = /* @__PURE__ */ new Map();
|
|
52744
|
+
/**
|
|
52745
|
+
* Record ONE metered operation against a `source`.
|
|
52746
|
+
*
|
|
52747
|
+
* @param source the attribution label. Callers that have not threaded a label
|
|
52748
|
+
* pass nothing and the operation is counted under {@link DEFAULT_QUERY_SOURCE}
|
|
52749
|
+
* (`"other"`), so it is visibly "unlabeled" rather than dropped.
|
|
52750
|
+
* @param isWrite `true` for a write statement (INSERT/UPDATE/DELETE/DDL),
|
|
52751
|
+
* `false` for a read (SELECT / read-only WITH). The storage client classifies
|
|
52752
|
+
* this from the statement shape so the split is consistent with the retry
|
|
52753
|
+
* layer's read/write tag, not guessed per call site.
|
|
52754
|
+
*/
|
|
52755
|
+
record(source = DEFAULT_QUERY_SOURCE, isWrite = false) {
|
|
52756
|
+
const entry = this.counts.get(source) ?? { reads: 0, writes: 0 };
|
|
52757
|
+
if (isWrite)
|
|
52758
|
+
entry.writes += 1;
|
|
52759
|
+
else
|
|
52760
|
+
entry.reads += 1;
|
|
52761
|
+
this.counts.set(source, entry);
|
|
52762
|
+
}
|
|
52763
|
+
/**
|
|
52764
|
+
* Take an immutable snapshot of the current per-source counts and rollup
|
|
52765
|
+
* totals. Sources that have never been hit are omitted from `perSource` (a
|
|
52766
|
+
* zero-traffic source contributes nothing), but the entries that ARE present
|
|
52767
|
+
* are emitted in the canonical {@link QUERY_SOURCES} order for stable output.
|
|
52768
|
+
*/
|
|
52769
|
+
snapshot() {
|
|
52770
|
+
const perSource = [];
|
|
52771
|
+
let totalReads = 0;
|
|
52772
|
+
let totalWrites = 0;
|
|
52773
|
+
for (const source of QUERY_SOURCES) {
|
|
52774
|
+
const entry = this.counts.get(source);
|
|
52775
|
+
if (entry === void 0)
|
|
52776
|
+
continue;
|
|
52777
|
+
perSource.push({ source, reads: entry.reads, writes: entry.writes });
|
|
52778
|
+
totalReads += entry.reads;
|
|
52779
|
+
totalWrites += entry.writes;
|
|
52780
|
+
}
|
|
52781
|
+
return { perSource, totalReads, totalWrites };
|
|
52782
|
+
}
|
|
52783
|
+
/**
|
|
52784
|
+
* Reset every counter to zero. Used by the idle-baseline harness to start a
|
|
52785
|
+
* clean measurement window, and available if a future caller flushes the meter
|
|
52786
|
+
* per period.
|
|
52787
|
+
*/
|
|
52788
|
+
reset() {
|
|
52789
|
+
this.counts.clear();
|
|
52790
|
+
}
|
|
52791
|
+
/**
|
|
52792
|
+
* Render the current snapshot as a single structured log line for the periodic
|
|
52793
|
+
* diagnostic surface (AC-62a.1.3). The shape is `key=value` pairs so it greps
|
|
52794
|
+
* cleanly and parses without a schema:
|
|
52795
|
+
*
|
|
52796
|
+
* [query-meter] total_reads=42 total_writes=7 poll-lease=r:30/w:0 capture-write=r:0/w:5 other=r:12/w:2
|
|
52797
|
+
*
|
|
52798
|
+
* A meter with no traffic yet renders the header with zero totals and no
|
|
52799
|
+
* per-source segments, so an idle window is still an explicit, loggable fact.
|
|
52800
|
+
*/
|
|
52801
|
+
formatLogLine() {
|
|
52802
|
+
const snap = this.snapshot();
|
|
52803
|
+
const segments = snap.perSource.map((e) => `${e.source}=r:${e.reads}/w:${e.writes}`);
|
|
52804
|
+
const header = `[query-meter] total_reads=${snap.totalReads} total_writes=${snap.totalWrites}`;
|
|
52805
|
+
return segments.length === 0 ? header : `${header} ${segments.join(" ")}`;
|
|
52806
|
+
}
|
|
52807
|
+
};
|
|
52808
|
+
|
|
50844
52809
|
// dist/src/daemon/storage/transport.js
|
|
50845
52810
|
var TransportError = class extends Error {
|
|
50846
52811
|
kind;
|
|
@@ -50853,8 +52818,8 @@ var TransportError = class extends Error {
|
|
|
50853
52818
|
this.status = status;
|
|
50854
52819
|
}
|
|
50855
52820
|
};
|
|
50856
|
-
var
|
|
50857
|
-
var
|
|
52821
|
+
var DEEPLAKE_CLIENT_HEADER3 = "X-Deeplake-Client";
|
|
52822
|
+
var DEEPLAKE_ORG_HEADER3 = "X-Activeloop-Org-Id";
|
|
50858
52823
|
var HttpDeepLakeTransport = class {
|
|
50859
52824
|
endpoint;
|
|
50860
52825
|
token;
|
|
@@ -50870,8 +52835,8 @@ var HttpDeepLakeTransport = class {
|
|
|
50870
52835
|
headers: {
|
|
50871
52836
|
Authorization: `Bearer ${this.token}`,
|
|
50872
52837
|
"Content-Type": "application/json",
|
|
50873
|
-
[
|
|
50874
|
-
[
|
|
52838
|
+
[DEEPLAKE_ORG_HEADER3]: req.org,
|
|
52839
|
+
[DEEPLAKE_CLIENT_HEADER3]: "honeycomb"
|
|
50875
52840
|
},
|
|
50876
52841
|
signal: req.signal,
|
|
50877
52842
|
body: JSON.stringify({ query: req.sql })
|
|
@@ -51015,15 +52980,39 @@ var StorageClient = class {
|
|
|
51015
52980
|
* the real timer; a test injects a no-op so the bounded backoff costs zero
|
|
51016
52981
|
* wall-clock time and the retry count stays deterministic.
|
|
51017
52982
|
*/
|
|
51018
|
-
|
|
52983
|
+
/** Per-source DeepLake query meter (PRD-062a). Always present; default mode is in-memory + log only. */
|
|
52984
|
+
meter;
|
|
52985
|
+
/**
|
|
52986
|
+
* @param sleep injectable backoff clock for the read-retry layer. Defaults to
|
|
52987
|
+
* the real timer; a test injects a no-op so the bounded backoff costs zero
|
|
52988
|
+
* wall-clock time and the retry count stays deterministic.
|
|
52989
|
+
* @param meter injectable query meter (PRD-062a). Defaults to a fresh in-memory
|
|
52990
|
+
* {@link QueryMeter}; the daemon may inject a shared one so diagnostics and a
|
|
52991
|
+
* later persistence path observe the SAME counts. The meter is a pure observer:
|
|
52992
|
+
* supplying it never changes any query's behavior or result.
|
|
52993
|
+
*/
|
|
52994
|
+
constructor(transport, config2, sleep2 = realSleep2, meter = new QueryMeter()) {
|
|
51019
52995
|
this.transport = transport;
|
|
51020
52996
|
this.config = config2;
|
|
51021
52997
|
this.sleep = sleep2;
|
|
52998
|
+
this.meter = meter;
|
|
51022
52999
|
}
|
|
51023
53000
|
/** The endpoint the client is bound to (for diagnostics; no secrets). */
|
|
51024
53001
|
get endpoint() {
|
|
51025
53002
|
return this.config.endpoint;
|
|
51026
53003
|
}
|
|
53004
|
+
/**
|
|
53005
|
+
* Snapshot the per-source query counts (PRD-062a, AC-62a.1.3). The diagnostic
|
|
53006
|
+
* surface and the idle-baseline harness read the meter through here without
|
|
53007
|
+
* touching the live counter, so a snapshot is stable even as traffic continues.
|
|
53008
|
+
*/
|
|
53009
|
+
meterSnapshot() {
|
|
53010
|
+
return this.meter.snapshot();
|
|
53011
|
+
}
|
|
53012
|
+
/** Render the current per-source counts as one structured log line (PRD-062a). */
|
|
53013
|
+
meterLogLine() {
|
|
53014
|
+
return this.meter.formatLogLine();
|
|
53015
|
+
}
|
|
51027
53016
|
/**
|
|
51028
53017
|
* Liveness check (a-AC-1): "connects" against the fake transport means a
|
|
51029
53018
|
* trivial statement succeeds. Returns a typed result so a caller branches on
|
|
@@ -51056,7 +53045,9 @@ var StorageClient = class {
|
|
|
51056
53045
|
* from the per-statement timeout: each attempt gets its own fresh timeout/abort.
|
|
51057
53046
|
*/
|
|
51058
53047
|
async query(sql, scope, opts = {}) {
|
|
51059
|
-
|
|
53048
|
+
const retryability = statementRetryability(sql);
|
|
53049
|
+
this.meter.record(opts.source, retryability !== "read");
|
|
53050
|
+
if (retryability === "unsafe-write")
|
|
51060
53051
|
return this.attemptOnce(sql, scope, opts);
|
|
51061
53052
|
let last;
|
|
51062
53053
|
for (let attempt = 1; attempt <= RETRY_ATTEMPTS; attempt++) {
|
|
@@ -51141,7 +53132,7 @@ function createStorageClient(options = {}) {
|
|
|
51141
53132
|
const provider = options.provider ?? defaultCredentialProvider();
|
|
51142
53133
|
const config2 = resolveStorageConfig(provider);
|
|
51143
53134
|
const transport = options.transport ?? new HttpDeepLakeTransport(config2.endpoint, config2.token);
|
|
51144
|
-
return new StorageClient(transport, config2, options.sleep);
|
|
53135
|
+
return new StorageClient(transport, config2, options.sleep, options.meter);
|
|
51145
53136
|
}
|
|
51146
53137
|
function createLazyStorageClient(options = {}) {
|
|
51147
53138
|
let built = null;
|
|
@@ -51291,7 +53282,7 @@ function authForMode(mode, storage, scope) {
|
|
|
51291
53282
|
return { authenticator: composeAuthenticator(storage, scope), policy: defaultDenyPolicy };
|
|
51292
53283
|
}
|
|
51293
53284
|
function assembleSeams(daemon, storage, defaultScope, orgName, embed, healthDetail, workspaceDir, installedHarnesses, logStore, seams = defaultSeamFns, vault) {
|
|
51294
|
-
seams.attachHooks(daemon, {
|
|
53285
|
+
const captureHandler = seams.attachHooks(daemon, {
|
|
51295
53286
|
storage,
|
|
51296
53287
|
queue: daemon.services.queue,
|
|
51297
53288
|
embed,
|
|
@@ -51347,7 +53338,7 @@ function assembleSeams(daemon, storage, defaultScope, orgName, embed, healthDeta
|
|
|
51347
53338
|
seams.mountMemoriesPrime(daemon, { storage, defaultScope });
|
|
51348
53339
|
}
|
|
51349
53340
|
seams.mountVfs(daemon, { storage, defaultScope });
|
|
51350
|
-
seams.mountProductData(daemon, resolveProductDataDeps(storage, defaultScope, daemon.services.queue, embed.client));
|
|
53341
|
+
seams.mountProductData(daemon, resolveProductDataDeps(storage, defaultScope, daemon.services.queue, embed.client, daemon.config.mode));
|
|
51351
53342
|
seams.mountPollinate(daemon, { storage, defaultScope, enqueuer: daemon.services.queue });
|
|
51352
53343
|
try {
|
|
51353
53344
|
seams.mountProjectsSync(daemon, { storage, defaultScope });
|
|
@@ -51416,11 +53407,16 @@ function assembleSeams(daemon, storage, defaultScope, orgName, embed, healthDeta
|
|
|
51416
53407
|
`);
|
|
51417
53408
|
}
|
|
51418
53409
|
}
|
|
53410
|
+
return captureHandler;
|
|
51419
53411
|
}
|
|
51420
|
-
function resolveProductDataDeps(storage, defaultScope, queue, embed) {
|
|
53412
|
+
function resolveProductDataDeps(storage, defaultScope, queue, embed, mode) {
|
|
51421
53413
|
const baseDir = process.env.HONEYCOMB_WORKSPACE ?? process.cwd();
|
|
51422
53414
|
const secrets = {
|
|
51423
|
-
store: new SecretsStore({ baseDir, machineKey: createMachineKeyProvider() })
|
|
53415
|
+
store: new SecretsStore({ baseDir, machineKey: createMachineKeyProvider() }),
|
|
53416
|
+
// PRD-022 local-mode default: the dashboard's `GET /api/secrets` (names-only) carries no
|
|
53417
|
+
// `x-honeycomb-org` header, so resolve the daemon's single local tenant instead of 400ing.
|
|
53418
|
+
// Team/hybrid stay fail-closed (a missing org still 400s) — cross-tenant access is rejected.
|
|
53419
|
+
scope: localDefaultScopeResolver(mode, defaultScope)
|
|
51424
53420
|
};
|
|
51425
53421
|
let sources;
|
|
51426
53422
|
try {
|
|
@@ -51502,7 +53498,7 @@ function coerceSettingBool(value) {
|
|
|
51502
53498
|
return value === "true" || value === "1";
|
|
51503
53499
|
return false;
|
|
51504
53500
|
}
|
|
51505
|
-
async function buildGatedPollinatingWorker(options, storage, scope, queue, vault) {
|
|
53501
|
+
async function buildGatedPollinatingWorker(options, storage, scope, queue, vault, backoff) {
|
|
51506
53502
|
let config2;
|
|
51507
53503
|
try {
|
|
51508
53504
|
config2 = resolvePollinatingConfig(options.pollinatingConfigProvider);
|
|
@@ -51529,7 +53525,7 @@ async function buildGatedPollinatingWorker(options, storage, scope, queue, vault
|
|
|
51529
53525
|
...providerModelOverride !== void 0 ? { providerModelOverride } : {}
|
|
51530
53526
|
});
|
|
51531
53527
|
const trigger = createPollinatingTrigger({ storage, scope, config: config2, enqueuer: queue });
|
|
51532
|
-
return createPollinatingWorker({ queue, storage, scope, config: config2, model, trigger });
|
|
53528
|
+
return createPollinatingWorker({ queue, storage, scope, config: config2, model, trigger, backoff });
|
|
51533
53529
|
}
|
|
51534
53530
|
function buildSummaryWorker(storage, scope, queue, embed) {
|
|
51535
53531
|
return createSummaryJobWorker({ queue, storage, scope, embed: embed.client });
|
|
@@ -51550,7 +53546,7 @@ function makePipelineEntryEnqueuer(queue) {
|
|
|
51550
53546
|
});
|
|
51551
53547
|
};
|
|
51552
53548
|
}
|
|
51553
|
-
async function buildPipelineWorker(options, storage, scope, queue, embed) {
|
|
53549
|
+
async function buildPipelineWorker(options, storage, scope, queue, embed, backoff) {
|
|
51554
53550
|
let config2;
|
|
51555
53551
|
try {
|
|
51556
53552
|
config2 = resolvePipelineConfig();
|
|
@@ -51580,7 +53576,7 @@ async function buildPipelineWorker(options, storage, scope, queue, embed) {
|
|
|
51580
53576
|
graphPersist: { storage, scope: queryScope, config: config2 },
|
|
51581
53577
|
retention: { storage, scope: queryScope, config: config2 }
|
|
51582
53578
|
});
|
|
51583
|
-
return createStageWorker({ queue, handlers });
|
|
53579
|
+
return createStageWorker({ queue, handlers, backoff });
|
|
51584
53580
|
}
|
|
51585
53581
|
function buildSkillifyWorker(storage, scope, queue) {
|
|
51586
53582
|
return createSkillifyJobWorker({
|
|
@@ -51635,10 +53631,10 @@ function assembleDaemon(options = {}) {
|
|
|
51635
53631
|
const embed = options.embed ?? createEmbedAttachment({ storage });
|
|
51636
53632
|
const installedHarnesses = options.installedHarnesses ?? (options.harnessTargets !== void 0 && options.harnessTargets.length > 0 ? new Set(options.harnessTargets.map((t) => t.name)) : options.storage === void 0 ? detectInstalledHarnesses() : /* @__PURE__ */ new Set());
|
|
51637
53633
|
const vault = options.vault ?? (options.storage === void 0 ? buildVaultStore() : void 0);
|
|
51638
|
-
assembleSeams(daemon, storage, scope, daemonOrgName, embed, healthDetail, options.workspaceDir ?? process.cwd(), installedHarnesses, logStore, options.seams ?? defaultSeamFns, vault);
|
|
53634
|
+
const captureHandler = assembleSeams(daemon, storage, scope, daemonOrgName, embed, healthDetail, options.workspaceDir ?? process.cwd(), installedHarnesses, logStore, options.seams ?? defaultSeamFns, vault);
|
|
51639
53635
|
if (vault !== void 0 && vault instanceof VaultStore) {
|
|
51640
53636
|
try {
|
|
51641
|
-
mountSettingsApi(daemon, { store: vault });
|
|
53637
|
+
mountSettingsApi(daemon, { store: vault, scope: localDefaultScopeResolver(daemon.config.mode, scope) });
|
|
51642
53638
|
} catch (err) {
|
|
51643
53639
|
const reason = err instanceof Error ? err.message : String(err);
|
|
51644
53640
|
process.stderr.write(`honeycomb: settings API mount failed (non-fatal): ${reason}
|
|
@@ -51705,6 +53701,7 @@ function assembleDaemon(options = {}) {
|
|
|
51705
53701
|
let pollinatingWorker = null;
|
|
51706
53702
|
let summaryWorker = null;
|
|
51707
53703
|
let pipelineWorker = null;
|
|
53704
|
+
let leaseCoordinator = null;
|
|
51708
53705
|
let skillifyWorker = null;
|
|
51709
53706
|
return {
|
|
51710
53707
|
daemon,
|
|
@@ -51724,6 +53721,18 @@ function assembleDaemon(options = {}) {
|
|
|
51724
53721
|
probeTimer.unref();
|
|
51725
53722
|
}
|
|
51726
53723
|
await daemon.startServices();
|
|
53724
|
+
let pollBackoff;
|
|
53725
|
+
try {
|
|
53726
|
+
pollBackoff = resolvePollBackoffConfig();
|
|
53727
|
+
} catch {
|
|
53728
|
+
pollBackoff = resolvePollBackoffConfig({ read: () => ({}) });
|
|
53729
|
+
}
|
|
53730
|
+
let consolidatePoll = false;
|
|
53731
|
+
try {
|
|
53732
|
+
consolidatePoll = resolvePollConsolidateConfig().enabled;
|
|
53733
|
+
} catch {
|
|
53734
|
+
consolidatePoll = false;
|
|
53735
|
+
}
|
|
51727
53736
|
try {
|
|
51728
53737
|
summaryWorker = buildSummaryWorker(storage, scope, daemon.services.queue, embed);
|
|
51729
53738
|
summaryWorker.start();
|
|
@@ -51734,8 +53743,9 @@ function assembleDaemon(options = {}) {
|
|
|
51734
53743
|
summaryWorker = null;
|
|
51735
53744
|
}
|
|
51736
53745
|
try {
|
|
51737
|
-
pipelineWorker = await buildPipelineWorker(options, storage, scope, daemon.services.queue, embed);
|
|
51738
|
-
|
|
53746
|
+
pipelineWorker = await buildPipelineWorker(options, storage, scope, daemon.services.queue, embed, pollBackoff);
|
|
53747
|
+
if (!consolidatePoll)
|
|
53748
|
+
pipelineWorker.start();
|
|
51739
53749
|
} catch (err) {
|
|
51740
53750
|
const reason = err instanceof Error ? err.message : String(err);
|
|
51741
53751
|
process.stderr.write(`honeycomb: memory-pipeline worker start failed (non-fatal): ${reason}
|
|
@@ -51765,16 +53775,41 @@ function assembleDaemon(options = {}) {
|
|
|
51765
53775
|
}
|
|
51766
53776
|
}
|
|
51767
53777
|
try {
|
|
51768
|
-
pollinatingWorker = await buildGatedPollinatingWorker(options, storage, scope, daemon.services.queue, vault);
|
|
51769
|
-
pollinatingWorker
|
|
53778
|
+
pollinatingWorker = await buildGatedPollinatingWorker(options, storage, scope, daemon.services.queue, vault, pollBackoff);
|
|
53779
|
+
const pollinatingInjected = options.pollinatingWorker !== void 0;
|
|
53780
|
+
if (consolidatePoll && !pollinatingInjected) {
|
|
53781
|
+
const participants = [pipelineWorker, pollinatingWorker].filter((p) => p !== null);
|
|
53782
|
+
if (participants.length > 0) {
|
|
53783
|
+
leaseCoordinator = createLeaseCoordinator({
|
|
53784
|
+
queue: daemon.services.queue,
|
|
53785
|
+
participants,
|
|
53786
|
+
backoff: pollBackoff,
|
|
53787
|
+
flatIntervalMs: 1e3
|
|
53788
|
+
});
|
|
53789
|
+
leaseCoordinator.start();
|
|
53790
|
+
}
|
|
53791
|
+
} else {
|
|
53792
|
+
pollinatingWorker?.start();
|
|
53793
|
+
if (consolidatePoll && pollinatingInjected && pipelineWorker !== null) {
|
|
53794
|
+
pipelineWorker.start();
|
|
53795
|
+
}
|
|
53796
|
+
}
|
|
51770
53797
|
} catch (err) {
|
|
51771
53798
|
const reason = err instanceof Error ? err.message : String(err);
|
|
51772
53799
|
process.stderr.write(`honeycomb: pollinating worker start failed (non-fatal): ${reason}
|
|
51773
53800
|
`);
|
|
51774
53801
|
pollinatingWorker = null;
|
|
53802
|
+
if (consolidatePoll && leaseCoordinator === null && pipelineWorker !== null) {
|
|
53803
|
+
pipelineWorker.start();
|
|
53804
|
+
}
|
|
51775
53805
|
}
|
|
51776
53806
|
},
|
|
51777
53807
|
async shutdown() {
|
|
53808
|
+
await captureHandler.flush?.();
|
|
53809
|
+
if (leaseCoordinator !== null) {
|
|
53810
|
+
leaseCoordinator.stop();
|
|
53811
|
+
leaseCoordinator = null;
|
|
53812
|
+
}
|
|
51778
53813
|
if (pollinatingWorker !== null) {
|
|
51779
53814
|
pollinatingWorker.stop();
|
|
51780
53815
|
pollinatingWorker = null;
|
|
@@ -51897,9 +53932,9 @@ export {
|
|
|
51897
53932
|
CompactionConfigError,
|
|
51898
53933
|
CompactionRefusedError,
|
|
51899
53934
|
CompactionRetentionSchema,
|
|
51900
|
-
|
|
53935
|
+
DEEPLAKE_CLIENT_HEADER3 as DEEPLAKE_CLIENT_HEADER,
|
|
51901
53936
|
DEFAULT_MAX_POLLS as DEEPLAKE_DEFAULT_MAX_POLLS,
|
|
51902
|
-
|
|
53937
|
+
DEEPLAKE_ORG_HEADER3 as DEEPLAKE_ORG_HEADER,
|
|
51903
53938
|
DEFAULT_CONVERGE_BACKOFF_BASE_MS,
|
|
51904
53939
|
DEFAULT_CONVERGE_BACKOFF_CAP_MS,
|
|
51905
53940
|
DEFAULT_CONVERGE_BUDGET,
|
|
@@ -51911,6 +53946,7 @@ export {
|
|
|
51911
53946
|
DEFAULT_MAX_POLLS2 as DEFAULT_MAX_POLLS,
|
|
51912
53947
|
DEFAULT_MAX_RETRIES,
|
|
51913
53948
|
DEFAULT_OVERFETCH_MULTIPLIER,
|
|
53949
|
+
DEFAULT_QUERY_SOURCE,
|
|
51914
53950
|
DEFAULT_QUERY_TIMEOUT_MS,
|
|
51915
53951
|
DEFAULT_TIMESTAMP_COLUMN,
|
|
51916
53952
|
DEFAULT_VERSION_COLUMN,
|
|
@@ -51935,6 +53971,8 @@ export {
|
|
|
51935
53971
|
LEGACY_CREDENTIALS_DIR_NAME,
|
|
51936
53972
|
LOCK_FILE_NAME,
|
|
51937
53973
|
PID_FILE_NAME,
|
|
53974
|
+
QUERY_SOURCES,
|
|
53975
|
+
QueryMeter,
|
|
51938
53976
|
ROLES,
|
|
51939
53977
|
RuntimeConfigError,
|
|
51940
53978
|
RuntimeConfigSchema,
|