@legioncodeinc/honeycomb 0.1.7 → 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 +87 -2
- package/daemon/dashboard-app.js +10 -10
- package/daemon/index.js +1139 -52
- 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) {
|
|
@@ -28496,7 +28583,7 @@ function buildAllowedProperties(input) {
|
|
|
28496
28583
|
}
|
|
28497
28584
|
var systemTelemetryClock = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
28498
28585
|
var DEFAULT_EMIT_TIMEOUT_MS = 2e3;
|
|
28499
|
-
var HONEYCOMB_VERSION2 = true ? "0.1.
|
|
28586
|
+
var HONEYCOMB_VERSION2 = true ? "0.1.8" : "0.0.0-dev";
|
|
28500
28587
|
async function emitTelemetry(event, opts, deps = {}) {
|
|
28501
28588
|
const env = deps.env ?? process.env;
|
|
28502
28589
|
const key = deps.posthogKey ?? POSTHOG_KEY;
|
|
@@ -31071,6 +31158,17 @@ function createSummaryJobWorker(deps) {
|
|
|
31071
31158
|
|
|
31072
31159
|
// dist/src/daemon/runtime/capture/event-contract.js
|
|
31073
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);
|
|
31074
31172
|
var UserMessageEventSchema = external_exports.object({
|
|
31075
31173
|
kind: external_exports.literal("user_message"),
|
|
31076
31174
|
text: external_exports.string()
|
|
@@ -31083,7 +31181,9 @@ var ToolCallEventSchema = external_exports.object({
|
|
|
31083
31181
|
});
|
|
31084
31182
|
var AssistantMessageEventSchema = external_exports.object({
|
|
31085
31183
|
kind: external_exports.literal("assistant_message"),
|
|
31086
|
-
text: external_exports.string()
|
|
31184
|
+
text: external_exports.string(),
|
|
31185
|
+
/** PRD-060a: optional per-turn token + cache counts; absent when unavailable. */
|
|
31186
|
+
usage: TurnUsageSchema
|
|
31087
31187
|
});
|
|
31088
31188
|
var CaptureEventSchema = external_exports.discriminatedUnion("kind", [
|
|
31089
31189
|
UserMessageEventSchema,
|
|
@@ -31503,7 +31603,7 @@ var CaptureRouteHandler = class {
|
|
|
31503
31603
|
*/
|
|
31504
31604
|
buildRow(id, event, meta3, nowIso10, projectId) {
|
|
31505
31605
|
const message = this.config.envelopeBudgetBytes > 0 ? budgetedStringify(event, meta3, this.config.envelopeBudgetBytes) : JSON.stringify({ event, metadata: meta3 });
|
|
31506
|
-
|
|
31606
|
+
const row = [
|
|
31507
31607
|
["id", val.str(id)],
|
|
31508
31608
|
["path", val.str(meta3.path)],
|
|
31509
31609
|
["filename", val.str(meta3.hookEventName)],
|
|
@@ -31517,9 +31617,17 @@ var CaptureRouteHandler = class {
|
|
|
31517
31617
|
["project_id", val.str(projectId)],
|
|
31518
31618
|
["plugin_version", val.str(meta3.pluginVersion)],
|
|
31519
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)],
|
|
31520
31624
|
["creation_date", val.str(nowIso10)],
|
|
31521
31625
|
["last_update_date", val.str(nowIso10)]
|
|
31522
31626
|
];
|
|
31627
|
+
for (const [col, value] of usageColumns(event)) {
|
|
31628
|
+
row.push([col, val.num(value)]);
|
|
31629
|
+
}
|
|
31630
|
+
return row;
|
|
31523
31631
|
}
|
|
31524
31632
|
/**
|
|
31525
31633
|
* Resolve the capture row's `project_id` from the session cwd (PRD-049b 49b-AC-1 / 49b-AC-3).
|
|
@@ -31662,6 +31770,21 @@ function embedTextFor(event) {
|
|
|
31662
31770
|
return [event.tool, serialize(event.input), serialize(event.response)].filter((s) => s.length > 0).join("\n");
|
|
31663
31771
|
}
|
|
31664
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
|
+
}
|
|
31665
31788
|
function groupRowsByScope(batch) {
|
|
31666
31789
|
const byKey = /* @__PURE__ */ new Map();
|
|
31667
31790
|
for (const item of batch) {
|
|
@@ -35259,6 +35382,37 @@ function mountSkillPropagationApi(daemon, options) {
|
|
|
35259
35382
|
}
|
|
35260
35383
|
}
|
|
35261
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
|
+
|
|
35262
35416
|
// dist/src/daemon/runtime/dashboard/installed-assets.js
|
|
35263
35417
|
import { homedir as homedir11 } from "node:os";
|
|
35264
35418
|
import { join as join16 } from "node:path";
|
|
@@ -35417,6 +35571,548 @@ function sanitizeName(name) {
|
|
|
35417
35571
|
return name.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
35418
35572
|
}
|
|
35419
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
|
+
|
|
35420
36116
|
// dist/src/daemon/runtime/dashboard/api.js
|
|
35421
36117
|
var DASHBOARD_GROUPS = Object.freeze({
|
|
35422
36118
|
/**
|
|
@@ -35461,7 +36157,14 @@ var DASHBOARD_GROUPS = Object.freeze({
|
|
|
35461
36157
|
* READ-ONLY filesystem walk; tenancy-independent (no org header required). PRD-036b calls
|
|
35462
36158
|
* the underlying `scanInstalledAssets` IN-PROCESS, not over this HTTP surface.
|
|
35463
36159
|
*/
|
|
35464
|
-
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"
|
|
35465
36168
|
});
|
|
35466
36169
|
function toNum2(value) {
|
|
35467
36170
|
const n = typeof value === "number" ? value : Number(value ?? 0);
|
|
@@ -35645,6 +36348,176 @@ async function fetchSkillSyncView(storage, scope, scan = scanInstalledAssets) {
|
|
|
35645
36348
|
}
|
|
35646
36349
|
return { skills: [...merged.values()] };
|
|
35647
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
|
+
}
|
|
35648
36521
|
var NO_ORG_BODY4 = { error: "bad_request", reason: "x-honeycomb-org header is required" };
|
|
35649
36522
|
function mountDashboardApi(daemon, options) {
|
|
35650
36523
|
const storage = options.storage;
|
|
@@ -35712,6 +36585,34 @@ function mountDashboardApi(daemon, options) {
|
|
|
35712
36585
|
return c.json(await inventoryCache());
|
|
35713
36586
|
});
|
|
35714
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;
|
|
35715
36616
|
}
|
|
35716
36617
|
var INSTALLED_ASSETS_TTL_MS = 5e3;
|
|
35717
36618
|
function createInventoryCache() {
|
|
@@ -36007,8 +36908,61 @@ function nestedString(raw2, a, b) {
|
|
|
36007
36908
|
function userMessageData(text) {
|
|
36008
36909
|
return { kind: "user_message", text };
|
|
36009
36910
|
}
|
|
36010
|
-
function assistantMessageData(text) {
|
|
36011
|
-
|
|
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;
|
|
36012
36966
|
}
|
|
36013
36967
|
function toolCallData(tool, input, response) {
|
|
36014
36968
|
return { kind: "tool_call", tool, input, response };
|
|
@@ -36058,7 +37012,7 @@ function claudeCodeExtractData(raw2, logical) {
|
|
|
36058
37012
|
case "tool_call":
|
|
36059
37013
|
return toolCallData(pickString(raw2, "tool_name", "tool"), nested(raw2, "tool_input"), nested(raw2, "tool_response"));
|
|
36060
37014
|
case "assistant_message":
|
|
36061
|
-
return assistantMessageData(pickString(raw2, "text", "message"));
|
|
37015
|
+
return assistantMessageData(pickString(raw2, "text", "message"), extractTurnUsage(raw2));
|
|
36062
37016
|
case "session-end":
|
|
36063
37017
|
return sessionEndData(pickString(raw2, "reason") || "Stop");
|
|
36064
37018
|
default:
|
|
@@ -39381,35 +40335,6 @@ async function readBody4(c) {
|
|
|
39381
40335
|
}
|
|
39382
40336
|
}
|
|
39383
40337
|
|
|
39384
|
-
// dist/src/daemon/runtime/recall/scope-clause.js
|
|
39385
|
-
var PROJECT_ID_COLUMN = "project_id";
|
|
39386
|
-
var PROJECT_ID_UNSET = "";
|
|
39387
|
-
var CROSS_PROJECT_ADMITTED = Object.freeze(["user", "workspace"]);
|
|
39388
|
-
var SCOPE_READ_POLICIES = Object.freeze(["isolated", "shared", "group"]);
|
|
39389
|
-
function buildProjectScopeClause(input) {
|
|
39390
|
-
const projectColumn = input.projectColumn ?? PROJECT_ID_COLUMN;
|
|
39391
|
-
const rawId = input.projectId ?? "";
|
|
39392
|
-
const isInbox = rawId.trim() === "" || rawId === UNSORTED_PROJECT_ID;
|
|
39393
|
-
const bound = input.bound ?? !isInbox;
|
|
39394
|
-
const col = sqlIdent(projectColumn);
|
|
39395
|
-
const primaryId = bound ? rawId : UNSORTED_PROJECT_ID;
|
|
39396
|
-
const admitted = primaryId === PROJECT_ID_UNSET ? [PROJECT_ID_UNSET] : [primaryId, PROJECT_ID_UNSET];
|
|
39397
|
-
const disjuncts = admitted.map((id) => `${col} = ${sLiteral(id)}`);
|
|
39398
|
-
const values = [...admitted];
|
|
39399
|
-
if (input.promotionColumn !== void 0 && input.promotionColumn !== "") {
|
|
39400
|
-
const promoCol = sqlIdent(input.promotionColumn);
|
|
39401
|
-
for (const reach of CROSS_PROJECT_ADMITTED) {
|
|
39402
|
-
disjuncts.push(`${promoCol} = ${sLiteral(reach)}`);
|
|
39403
|
-
values.push(reach);
|
|
39404
|
-
}
|
|
39405
|
-
}
|
|
39406
|
-
const sql = `(${disjuncts.join(" OR ")})`;
|
|
39407
|
-
return { sql, values, bound };
|
|
39408
|
-
}
|
|
39409
|
-
function buildProjectScopeConjunct(input) {
|
|
39410
|
-
return ` AND ${buildProjectScopeClause(input).sql}`;
|
|
39411
|
-
}
|
|
39412
|
-
|
|
39413
40338
|
// dist/src/daemon/runtime/memories/reads.js
|
|
39414
40339
|
var DEFAULT_LIST_LIMIT = 50;
|
|
39415
40340
|
var MAX_LIST_LIMIT = 500;
|
|
@@ -41848,6 +42773,19 @@ async function recallMemories(request, deps) {
|
|
|
41848
42773
|
}
|
|
41849
42774
|
|
|
41850
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
|
+
}
|
|
41851
42789
|
var headerScopeResolver2 = {
|
|
41852
42790
|
resolve(c) {
|
|
41853
42791
|
const org = c.req.header("x-honeycomb-org");
|
|
@@ -49344,12 +50282,34 @@ var RouterModelClient = class {
|
|
|
49344
50282
|
var ANTHROPIC_MESSAGES_URL = "https://api.anthropic.com/v1/messages";
|
|
49345
50283
|
var ANTHROPIC_VERSION = "2023-06-01";
|
|
49346
50284
|
var DEFAULT_MAX_TOKENS = 4096;
|
|
50285
|
+
var noopUsageSink = {
|
|
50286
|
+
record() {
|
|
50287
|
+
}
|
|
50288
|
+
};
|
|
49347
50289
|
var AnthropicContentBlockSchema = external_exports.object({
|
|
49348
50290
|
type: external_exports.string(),
|
|
49349
50291
|
text: external_exports.string().optional()
|
|
49350
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
|
+
};
|
|
49351
50305
|
var AnthropicMessagesResponseSchema = external_exports.object({
|
|
49352
|
-
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)
|
|
49353
50313
|
});
|
|
49354
50314
|
function toAnthropicBody(call, defaultMaxTokens) {
|
|
49355
50315
|
const systemParts = [];
|
|
@@ -49377,6 +50337,7 @@ function createAnthropicTransport(deps = {}) {
|
|
|
49377
50337
|
const doFetch = deps.fetch ?? globalThis.fetch;
|
|
49378
50338
|
const url2 = deps.baseUrl ?? ANTHROPIC_MESSAGES_URL;
|
|
49379
50339
|
const defaultMaxTokens = deps.defaultMaxTokens ?? DEFAULT_MAX_TOKENS;
|
|
50340
|
+
const usageSink = deps.usageSink ?? noopUsageSink;
|
|
49380
50341
|
async function post(call) {
|
|
49381
50342
|
const body = toAnthropicBody(call, defaultMaxTokens);
|
|
49382
50343
|
let res;
|
|
@@ -49402,16 +50363,33 @@ function createAnthropicTransport(deps = {}) {
|
|
|
49402
50363
|
if (!parsed.success) {
|
|
49403
50364
|
throw new ProviderError(502, "anthropic transport: malformed provider response");
|
|
49404
50365
|
}
|
|
49405
|
-
|
|
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
|
+
}
|
|
49406
50382
|
}
|
|
49407
50383
|
return {
|
|
49408
50384
|
async execute(call) {
|
|
49409
|
-
const output = await post(call);
|
|
50385
|
+
const { output, usage } = await post(call);
|
|
50386
|
+
reportUsage(usage);
|
|
49410
50387
|
return { output };
|
|
49411
50388
|
},
|
|
49412
50389
|
stream(call) {
|
|
49413
50390
|
async function* gen() {
|
|
49414
|
-
const output = await post(call);
|
|
50391
|
+
const { output, usage } = await post(call);
|
|
50392
|
+
reportUsage(usage);
|
|
49415
50393
|
yield { delta: output };
|
|
49416
50394
|
}
|
|
49417
50395
|
return gen();
|
|
@@ -49456,7 +50434,7 @@ async function buildInferenceModelClient(deps) {
|
|
|
49456
50434
|
}
|
|
49457
50435
|
const effectiveConfig = deps.providerModelOverride !== void 0 ? applyProviderModelOverride(config2, deps.providerModelOverride) : config2;
|
|
49458
50436
|
const secrets = createSecretResolver(deps.secretsStore, deps.scope);
|
|
49459
|
-
const transport = createAnthropicTransport();
|
|
50437
|
+
const transport = createAnthropicTransport(deps.usageSink !== void 0 ? { usageSink: deps.usageSink } : {});
|
|
49460
50438
|
const router = createInferenceRouter({
|
|
49461
50439
|
config: effectiveConfig,
|
|
49462
50440
|
transport,
|
|
@@ -51470,6 +52448,95 @@ function sanitizeSegment5(projectKey) {
|
|
|
51470
52448
|
return cleaned === "" ? "default" : cleaned;
|
|
51471
52449
|
}
|
|
51472
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
|
+
|
|
51473
52540
|
// dist/src/daemon/runtime/skillify/worker.js
|
|
51474
52541
|
var SKILLIFY_JOB_KIND = "skillify";
|
|
51475
52542
|
var DEFAULT_POLL_INTERVAL_MS4 = 1e3;
|
|
@@ -51512,6 +52579,8 @@ var SkillifyJobWorkerImpl = class {
|
|
|
51512
52579
|
gateOverride;
|
|
51513
52580
|
fetcherOverride;
|
|
51514
52581
|
storeOverride;
|
|
52582
|
+
/** PRD-060e/060f — the per-session ROI writer fired once at completion (fail-soft). */
|
|
52583
|
+
roiWriter;
|
|
51515
52584
|
handle;
|
|
51516
52585
|
/** Guards against overlapping `runOnce` invocations on the poll loop. */
|
|
51517
52586
|
running = false;
|
|
@@ -51537,6 +52606,7 @@ var SkillifyJobWorkerImpl = class {
|
|
|
51537
52606
|
this.gateOverride = deps.gateOverride;
|
|
51538
52607
|
this.fetcherOverride = deps.fetcherOverride;
|
|
51539
52608
|
this.storeOverride = deps.storeOverride;
|
|
52609
|
+
this.roiWriter = deps.roiWriter ?? createRoiSessionWriter({ storage: this.storage, scope: this.scope });
|
|
51540
52610
|
}
|
|
51541
52611
|
async runOnce() {
|
|
51542
52612
|
let leased;
|
|
@@ -51577,6 +52647,19 @@ var SkillifyJobWorkerImpl = class {
|
|
|
51577
52647
|
const outcome = await writeSkill(result.outcome.verdict, { store, install, author: this.author, projectId }, result.outcome.minedSessionIds, "global");
|
|
51578
52648
|
const sessionDates = result.outcome.pairs.map((p) => p.sessionDate);
|
|
51579
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
|
+
}
|
|
51580
52663
|
await this.queue.complete(job.id);
|
|
51581
52664
|
this.logger?.event("skillify.worker.completed", {
|
|
51582
52665
|
id: job.id,
|
|
@@ -51735,8 +52818,8 @@ var TransportError = class extends Error {
|
|
|
51735
52818
|
this.status = status;
|
|
51736
52819
|
}
|
|
51737
52820
|
};
|
|
51738
|
-
var
|
|
51739
|
-
var
|
|
52821
|
+
var DEEPLAKE_CLIENT_HEADER3 = "X-Deeplake-Client";
|
|
52822
|
+
var DEEPLAKE_ORG_HEADER3 = "X-Activeloop-Org-Id";
|
|
51740
52823
|
var HttpDeepLakeTransport = class {
|
|
51741
52824
|
endpoint;
|
|
51742
52825
|
token;
|
|
@@ -51752,8 +52835,8 @@ var HttpDeepLakeTransport = class {
|
|
|
51752
52835
|
headers: {
|
|
51753
52836
|
Authorization: `Bearer ${this.token}`,
|
|
51754
52837
|
"Content-Type": "application/json",
|
|
51755
|
-
[
|
|
51756
|
-
[
|
|
52838
|
+
[DEEPLAKE_ORG_HEADER3]: req.org,
|
|
52839
|
+
[DEEPLAKE_CLIENT_HEADER3]: "honeycomb"
|
|
51757
52840
|
},
|
|
51758
52841
|
signal: req.signal,
|
|
51759
52842
|
body: JSON.stringify({ query: req.sql })
|
|
@@ -52255,7 +53338,7 @@ function assembleSeams(daemon, storage, defaultScope, orgName, embed, healthDeta
|
|
|
52255
53338
|
seams.mountMemoriesPrime(daemon, { storage, defaultScope });
|
|
52256
53339
|
}
|
|
52257
53340
|
seams.mountVfs(daemon, { storage, defaultScope });
|
|
52258
|
-
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));
|
|
52259
53342
|
seams.mountPollinate(daemon, { storage, defaultScope, enqueuer: daemon.services.queue });
|
|
52260
53343
|
try {
|
|
52261
53344
|
seams.mountProjectsSync(daemon, { storage, defaultScope });
|
|
@@ -52326,10 +53409,14 @@ function assembleSeams(daemon, storage, defaultScope, orgName, embed, healthDeta
|
|
|
52326
53409
|
}
|
|
52327
53410
|
return captureHandler;
|
|
52328
53411
|
}
|
|
52329
|
-
function resolveProductDataDeps(storage, defaultScope, queue, embed) {
|
|
53412
|
+
function resolveProductDataDeps(storage, defaultScope, queue, embed, mode) {
|
|
52330
53413
|
const baseDir = process.env.HONEYCOMB_WORKSPACE ?? process.cwd();
|
|
52331
53414
|
const secrets = {
|
|
52332
|
-
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)
|
|
52333
53420
|
};
|
|
52334
53421
|
let sources;
|
|
52335
53422
|
try {
|
|
@@ -52547,7 +53634,7 @@ function assembleDaemon(options = {}) {
|
|
|
52547
53634
|
const captureHandler = assembleSeams(daemon, storage, scope, daemonOrgName, embed, healthDetail, options.workspaceDir ?? process.cwd(), installedHarnesses, logStore, options.seams ?? defaultSeamFns, vault);
|
|
52548
53635
|
if (vault !== void 0 && vault instanceof VaultStore) {
|
|
52549
53636
|
try {
|
|
52550
|
-
mountSettingsApi(daemon, { store: vault });
|
|
53637
|
+
mountSettingsApi(daemon, { store: vault, scope: localDefaultScopeResolver(daemon.config.mode, scope) });
|
|
52551
53638
|
} catch (err) {
|
|
52552
53639
|
const reason = err instanceof Error ? err.message : String(err);
|
|
52553
53640
|
process.stderr.write(`honeycomb: settings API mount failed (non-fatal): ${reason}
|
|
@@ -52845,9 +53932,9 @@ export {
|
|
|
52845
53932
|
CompactionConfigError,
|
|
52846
53933
|
CompactionRefusedError,
|
|
52847
53934
|
CompactionRetentionSchema,
|
|
52848
|
-
|
|
53935
|
+
DEEPLAKE_CLIENT_HEADER3 as DEEPLAKE_CLIENT_HEADER,
|
|
52849
53936
|
DEFAULT_MAX_POLLS as DEEPLAKE_DEFAULT_MAX_POLLS,
|
|
52850
|
-
|
|
53937
|
+
DEEPLAKE_ORG_HEADER3 as DEEPLAKE_ORG_HEADER,
|
|
52851
53938
|
DEFAULT_CONVERGE_BACKOFF_BASE_MS,
|
|
52852
53939
|
DEFAULT_CONVERGE_BACKOFF_CAP_MS,
|
|
52853
53940
|
DEFAULT_CONVERGE_BUDGET,
|