@bike4mind/cli 0.2.1-epic-lattice.17015 → 0.2.1-feat-cli-usage-command.16999
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/dist/{artifactExtractor-LFD46Z57.js → artifactExtractor-GXQ5YZF7.js} +1 -1
- package/dist/{chunk-HHHI5KKC.js → chunk-F3ETXO5N.js} +2 -2
- package/dist/{chunk-FMXGH4KC.js → chunk-LZMRYJ3B.js} +2 -2
- package/dist/{chunk-GSXZOOWP.js → chunk-QXGU6KYI.js} +2 -2
- package/dist/{chunk-7JFN4F7V.js → chunk-U3GPYBTD.js} +2 -4
- package/dist/{chunk-ZMZK7YVU.js → chunk-WR6YZRQV.js} +187 -722
- package/dist/{create-H4NTHQFV.js → create-YUYXTEIS.js} +3 -3
- package/dist/index.js +124 -647
- package/dist/{llmMarkdownGenerator-MCARYCM6.js → llmMarkdownGenerator-4ZR3FLEQ.js} +1 -1
- package/dist/{markdownGenerator-SVLZNXRS.js → markdownGenerator-7WE7WKME.js} +1 -1
- package/dist/{mementoService-6AL37G2J.js → mementoService-2BDIT6PH.js} +3 -3
- package/dist/{src-4TOZJYKI.js → src-6J6LFPZ6.js} +1 -125
- package/dist/{src-5NAH3LYJ.js → src-VLP2EHKE.js} +2 -2
- package/dist/{subtractCredits-762T4S77.js → subtractCredits-NNYIS5XZ.js} +3 -3
- package/package.json +6 -6
- package/dist/HydrationEngine-TIB3IU6D.js +0 -10
- package/dist/chunk-NHP3UPYU.js +0 -765
package/dist/index.js
CHANGED
|
@@ -4,10 +4,9 @@ import {
|
|
|
4
4
|
getEffectiveApiKey,
|
|
5
5
|
getOpenWeatherKey,
|
|
6
6
|
getSerperKey
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-HHHI5KKC.js";
|
|
7
|
+
} from "./chunk-QXGU6KYI.js";
|
|
8
|
+
import "./chunk-LZMRYJ3B.js";
|
|
9
|
+
import "./chunk-F3ETXO5N.js";
|
|
11
10
|
import {
|
|
12
11
|
BFLImageService,
|
|
13
12
|
BaseStorage,
|
|
@@ -16,7 +15,7 @@ import {
|
|
|
16
15
|
OpenAIBackend,
|
|
17
16
|
OpenAIImageService,
|
|
18
17
|
XAIImageService
|
|
19
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-U3GPYBTD.js";
|
|
20
19
|
import {
|
|
21
20
|
Logger
|
|
22
21
|
} from "./chunk-AMDXHL6S.js";
|
|
@@ -30,6 +29,7 @@ import {
|
|
|
30
29
|
AuthEvents,
|
|
31
30
|
BFL_IMAGE_MODELS,
|
|
32
31
|
BFL_SAFETY_TOLERANCE,
|
|
32
|
+
CREDIT_DEDUCT_TRANSACTION_TYPES,
|
|
33
33
|
ChatCompletionCreateInputSchema,
|
|
34
34
|
ChatModels,
|
|
35
35
|
CollectionType,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
XAI_IMAGE_MODELS,
|
|
74
74
|
b4mLLMTools,
|
|
75
75
|
getMcpProviderMetadata
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-WR6YZRQV.js";
|
|
77
77
|
import {
|
|
78
78
|
__require
|
|
79
79
|
} from "./chunk-PDX44BCA.js";
|
|
@@ -178,6 +178,10 @@ var COMMANDS = [
|
|
|
178
178
|
{
|
|
179
179
|
name: "trusted",
|
|
180
180
|
description: "List all trusted tools"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: "usage",
|
|
184
|
+
description: "Show credit usage and balance"
|
|
181
185
|
}
|
|
182
186
|
];
|
|
183
187
|
|
|
@@ -7239,632 +7243,6 @@ var deleteFileTool = {
|
|
|
7239
7243
|
})
|
|
7240
7244
|
};
|
|
7241
7245
|
|
|
7242
|
-
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/lattice/index.js
|
|
7243
|
-
function createModelData(name, modelType, userId, description, sessionId) {
|
|
7244
|
-
const now = /* @__PURE__ */ new Date();
|
|
7245
|
-
return {
|
|
7246
|
-
name,
|
|
7247
|
-
description: description || "",
|
|
7248
|
-
modelType,
|
|
7249
|
-
userId,
|
|
7250
|
-
sessionId,
|
|
7251
|
-
data: { entities: [], relationships: [] },
|
|
7252
|
-
rules: { rules: [], rulesets: [] },
|
|
7253
|
-
views: { views: [] },
|
|
7254
|
-
settings: {
|
|
7255
|
-
currency: "USD",
|
|
7256
|
-
fiscalYearStart: "01-01",
|
|
7257
|
-
periodGrain: "quarter",
|
|
7258
|
-
defaultDecimalPlaces: 2,
|
|
7259
|
-
negativeFormat: "parentheses"
|
|
7260
|
-
},
|
|
7261
|
-
scenarios: [],
|
|
7262
|
-
operations: [],
|
|
7263
|
-
operationIndex: -1,
|
|
7264
|
-
version: 1,
|
|
7265
|
-
createdAt: now,
|
|
7266
|
-
updatedAt: now
|
|
7267
|
-
};
|
|
7268
|
-
}
|
|
7269
|
-
var latticeCreateModelTool = {
|
|
7270
|
-
name: "lattice_create_model",
|
|
7271
|
-
implementation: (context) => ({
|
|
7272
|
-
toolFn: async (params) => {
|
|
7273
|
-
const { name, description, modelType = "custom" } = params;
|
|
7274
|
-
const modelData = createModelData(name, modelType, context.userId, description);
|
|
7275
|
-
let model;
|
|
7276
|
-
if (context.db.latticeModels) {
|
|
7277
|
-
try {
|
|
7278
|
-
model = await context.db.latticeModels.create(modelData);
|
|
7279
|
-
context.logger.info(`[Lattice] Created model ${model.id} in database`);
|
|
7280
|
-
} catch (error) {
|
|
7281
|
-
context.logger.error(`[Lattice] Failed to persist model to database:`, error);
|
|
7282
|
-
model = {
|
|
7283
|
-
...modelData,
|
|
7284
|
-
id: `lattice_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
|
7285
|
-
};
|
|
7286
|
-
}
|
|
7287
|
-
} else {
|
|
7288
|
-
context.logger.warn("[Lattice] No database adapter available, creating in-memory model");
|
|
7289
|
-
model = {
|
|
7290
|
-
...modelData,
|
|
7291
|
-
id: `lattice_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
|
7292
|
-
};
|
|
7293
|
-
}
|
|
7294
|
-
const artifactData = {
|
|
7295
|
-
type: "lattice",
|
|
7296
|
-
id: model.id,
|
|
7297
|
-
title: name,
|
|
7298
|
-
content: JSON.stringify(model),
|
|
7299
|
-
metadata: {
|
|
7300
|
-
modelType,
|
|
7301
|
-
periodGrain: model.settings?.periodGrain || "quarter",
|
|
7302
|
-
currency: model.settings?.currency || "USD",
|
|
7303
|
-
entityCount: model.data?.entities?.length || 0,
|
|
7304
|
-
ruleCount: model.rules?.rules?.length || 0
|
|
7305
|
-
},
|
|
7306
|
-
createdAt: model.createdAt?.toISOString?.() || (/* @__PURE__ */ new Date()).toISOString(),
|
|
7307
|
-
updatedAt: model.updatedAt?.toISOString?.() || (/* @__PURE__ */ new Date()).toISOString()
|
|
7308
|
-
};
|
|
7309
|
-
return `I've created a new ${modelType} financial model called "${name}".
|
|
7310
|
-
|
|
7311
|
-
<artifact identifier="${model.id}" type="application/vnd.b4m.lattice" title="${name}">
|
|
7312
|
-
${JSON.stringify(artifactData, null, 2)}
|
|
7313
|
-
</artifact>
|
|
7314
|
-
|
|
7315
|
-
You can now add line items, set values, and create formulas. Try saying:
|
|
7316
|
-
- "Add Revenue and COGS line items"
|
|
7317
|
-
- "Set Q1 Revenue to 100,000"
|
|
7318
|
-
- "Gross Profit equals Revenue minus COGS"`;
|
|
7319
|
-
},
|
|
7320
|
-
toolSchema: {
|
|
7321
|
-
name: "lattice_create_model",
|
|
7322
|
-
description: `Create a new Lattice financial model. This is the first step when building a pro-forma or financial analysis.
|
|
7323
|
-
|
|
7324
|
-
**When to use:** When the user wants to:
|
|
7325
|
-
- Create a new financial model, spreadsheet, or pro-forma
|
|
7326
|
-
- Start building an income statement, balance sheet, or cash flow
|
|
7327
|
-
- Set up a SaaS metrics dashboard
|
|
7328
|
-
- Begin any structured numerical analysis
|
|
7329
|
-
|
|
7330
|
-
**Model types:**
|
|
7331
|
-
- income_statement: P&L with revenue, expenses, profits
|
|
7332
|
-
- balance_sheet: Assets, liabilities, equity
|
|
7333
|
-
- cashflow: Operating, investing, financing cash flows
|
|
7334
|
-
- saas_metrics: MRR, ARR, churn, CAC, LTV
|
|
7335
|
-
- custom: Any other structured model
|
|
7336
|
-
|
|
7337
|
-
After creating a model, add entities with \`lattice_add_entity\` and define formulas with \`lattice_create_rule\`.`,
|
|
7338
|
-
parameters: {
|
|
7339
|
-
type: "object",
|
|
7340
|
-
properties: {
|
|
7341
|
-
name: {
|
|
7342
|
-
type: "string",
|
|
7343
|
-
description: 'Name of the model (e.g., "2024 Budget", "Q1 Forecast")'
|
|
7344
|
-
},
|
|
7345
|
-
description: {
|
|
7346
|
-
type: "string",
|
|
7347
|
-
description: "Optional description of what this model represents"
|
|
7348
|
-
},
|
|
7349
|
-
modelType: {
|
|
7350
|
-
type: "string",
|
|
7351
|
-
enum: ["income_statement", "balance_sheet", "cashflow", "saas_metrics", "custom"],
|
|
7352
|
-
description: "Type of financial model to create"
|
|
7353
|
-
}
|
|
7354
|
-
},
|
|
7355
|
-
required: ["name"]
|
|
7356
|
-
}
|
|
7357
|
-
}
|
|
7358
|
-
})
|
|
7359
|
-
};
|
|
7360
|
-
var latticeAddEntityTool = {
|
|
7361
|
-
name: "lattice_add_entity",
|
|
7362
|
-
implementation: (context) => ({
|
|
7363
|
-
toolFn: async (params) => {
|
|
7364
|
-
const { modelId, name, type, displayName, initialValues = [] } = params;
|
|
7365
|
-
const entityId = name.toLowerCase().replace(/\s+/g, "_");
|
|
7366
|
-
const entityData = {
|
|
7367
|
-
id: entityId,
|
|
7368
|
-
type,
|
|
7369
|
-
name,
|
|
7370
|
-
displayName: displayName || name,
|
|
7371
|
-
attributes: initialValues.map((v) => ({
|
|
7372
|
-
key: v.key,
|
|
7373
|
-
value: v.value,
|
|
7374
|
-
dataType: v.dataType || (typeof v.value === "number" ? "number" : "string"),
|
|
7375
|
-
isComputed: false
|
|
7376
|
-
})),
|
|
7377
|
-
metadata: {},
|
|
7378
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
7379
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
7380
|
-
};
|
|
7381
|
-
if (context.db.latticeModels && modelId && /^[a-f0-9]{24}$/.test(modelId)) {
|
|
7382
|
-
try {
|
|
7383
|
-
const model = await context.db.latticeModels.findById(modelId);
|
|
7384
|
-
if (model) {
|
|
7385
|
-
const existingIndex = model.data.entities.findIndex((e) => e.id === entityId);
|
|
7386
|
-
if (existingIndex >= 0) {
|
|
7387
|
-
model.data.entities[existingIndex] = entityData;
|
|
7388
|
-
} else {
|
|
7389
|
-
model.data.entities.push(entityData);
|
|
7390
|
-
}
|
|
7391
|
-
await context.db.latticeModels.update({
|
|
7392
|
-
id: modelId,
|
|
7393
|
-
data: model.data,
|
|
7394
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
7395
|
-
});
|
|
7396
|
-
context.logger.info(`[Lattice] Added entity ${entityId} to model ${modelId}`);
|
|
7397
|
-
} else {
|
|
7398
|
-
context.logger.warn(`[Lattice] Model ${modelId} not found in database`);
|
|
7399
|
-
}
|
|
7400
|
-
} catch (error) {
|
|
7401
|
-
context.logger.error(`[Lattice] Failed to persist entity to database:`, error);
|
|
7402
|
-
}
|
|
7403
|
-
}
|
|
7404
|
-
return JSON.stringify({
|
|
7405
|
-
success: true,
|
|
7406
|
-
action: "ADD_ENTITY",
|
|
7407
|
-
modelId,
|
|
7408
|
-
entityId,
|
|
7409
|
-
data: entityData,
|
|
7410
|
-
message: `Added ${type} "${displayName || name}" to model. ${initialValues.length > 0 ? `Set initial values: ${initialValues.map((v) => `${v.key}=${v.value}`).join(", ")}` : "No initial values set."}`
|
|
7411
|
-
});
|
|
7412
|
-
},
|
|
7413
|
-
toolSchema: {
|
|
7414
|
-
name: "lattice_add_entity",
|
|
7415
|
-
description: `Add a line item, account, period, or other entity to a Lattice model.
|
|
7416
|
-
|
|
7417
|
-
**When to use:** When the user mentions:
|
|
7418
|
-
- Adding a revenue line, expense category, or account
|
|
7419
|
-
- Creating periods (Q1, Q2, Jan, Feb, etc.)
|
|
7420
|
-
- Adding any measurable item to their model
|
|
7421
|
-
|
|
7422
|
-
**Entity types:**
|
|
7423
|
-
- line_item: Revenue streams, expense lines, KPIs
|
|
7424
|
-
- account: Cash, AR, AP, inventory, etc.
|
|
7425
|
-
- period: Q1 2024, Jan, FY2025, etc.
|
|
7426
|
-
- category: Groups of line items (Operating Expenses)
|
|
7427
|
-
- scenario: Base case, upside, downside
|
|
7428
|
-
- custom: Any other structured element
|
|
7429
|
-
|
|
7430
|
-
**Examples:**
|
|
7431
|
-
- "Add Revenue" \u2192 line_item named "Revenue"
|
|
7432
|
-
- "Create a Marketing Expenses category" \u2192 category named "Marketing Expenses"
|
|
7433
|
-
- "Add quarters Q1 through Q4" \u2192 4 period entities`,
|
|
7434
|
-
parameters: {
|
|
7435
|
-
type: "object",
|
|
7436
|
-
properties: {
|
|
7437
|
-
modelId: {
|
|
7438
|
-
type: "string",
|
|
7439
|
-
description: "ID of the model to add the entity to"
|
|
7440
|
-
},
|
|
7441
|
-
name: {
|
|
7442
|
-
type: "string",
|
|
7443
|
-
description: "Internal name for the entity (used in formulas)"
|
|
7444
|
-
},
|
|
7445
|
-
type: {
|
|
7446
|
-
type: "string",
|
|
7447
|
-
enum: ["line_item", "account", "period", "category", "scenario", "custom"],
|
|
7448
|
-
description: "Type of entity"
|
|
7449
|
-
},
|
|
7450
|
-
displayName: {
|
|
7451
|
-
type: "string",
|
|
7452
|
-
description: "Human-readable display name (defaults to name)"
|
|
7453
|
-
},
|
|
7454
|
-
initialValues: {
|
|
7455
|
-
type: "array",
|
|
7456
|
-
items: {
|
|
7457
|
-
type: "object",
|
|
7458
|
-
properties: {
|
|
7459
|
-
key: { type: "string", description: 'Period or attribute key (e.g., "Q1_2024")' },
|
|
7460
|
-
value: { type: "string", description: "The value (number or string)" },
|
|
7461
|
-
dataType: {
|
|
7462
|
-
type: "string",
|
|
7463
|
-
enum: ["number", "currency", "percentage", "string"],
|
|
7464
|
-
description: "Data type for the value"
|
|
7465
|
-
}
|
|
7466
|
-
},
|
|
7467
|
-
required: ["key", "value"]
|
|
7468
|
-
},
|
|
7469
|
-
description: "Optional initial values for this entity"
|
|
7470
|
-
}
|
|
7471
|
-
},
|
|
7472
|
-
required: ["modelId", "name", "type"]
|
|
7473
|
-
}
|
|
7474
|
-
}
|
|
7475
|
-
})
|
|
7476
|
-
};
|
|
7477
|
-
var latticeSetValueTool = {
|
|
7478
|
-
name: "lattice_set_value",
|
|
7479
|
-
implementation: (context) => ({
|
|
7480
|
-
toolFn: async (params) => {
|
|
7481
|
-
const { modelId, entityName, attributeKey, value: rawValue } = params;
|
|
7482
|
-
let value = rawValue;
|
|
7483
|
-
const numValue = parseFloat(rawValue);
|
|
7484
|
-
if (!isNaN(numValue)) {
|
|
7485
|
-
value = numValue;
|
|
7486
|
-
} else if (rawValue.toLowerCase() === "true") {
|
|
7487
|
-
value = true;
|
|
7488
|
-
} else if (rawValue.toLowerCase() === "false") {
|
|
7489
|
-
value = false;
|
|
7490
|
-
}
|
|
7491
|
-
const entityId = entityName.toLowerCase().replace(/\s+/g, "_");
|
|
7492
|
-
if (context.db.latticeModels && modelId && /^[a-f0-9]{24}$/.test(modelId)) {
|
|
7493
|
-
try {
|
|
7494
|
-
const model = await context.db.latticeModels.findById(modelId);
|
|
7495
|
-
if (model) {
|
|
7496
|
-
const entity = model.data.entities.find((e) => e.id === entityId || e.name === entityName);
|
|
7497
|
-
if (entity) {
|
|
7498
|
-
const attrIndex = entity.attributes.findIndex((a) => a.key === attributeKey);
|
|
7499
|
-
const dataType = typeof value === "number" ? "number" : typeof value === "boolean" ? "boolean" : "string";
|
|
7500
|
-
const attributeData = {
|
|
7501
|
-
key: attributeKey,
|
|
7502
|
-
value,
|
|
7503
|
-
dataType,
|
|
7504
|
-
isComputed: false
|
|
7505
|
-
};
|
|
7506
|
-
if (attrIndex >= 0) {
|
|
7507
|
-
entity.attributes[attrIndex] = attributeData;
|
|
7508
|
-
} else {
|
|
7509
|
-
entity.attributes.push(attributeData);
|
|
7510
|
-
}
|
|
7511
|
-
entity.updatedAt = /* @__PURE__ */ new Date();
|
|
7512
|
-
await context.db.latticeModels.update({
|
|
7513
|
-
id: modelId,
|
|
7514
|
-
data: model.data,
|
|
7515
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
7516
|
-
});
|
|
7517
|
-
context.logger.info(`[Lattice] Set ${entityId}.${attributeKey} = ${value} in model ${modelId}`);
|
|
7518
|
-
} else {
|
|
7519
|
-
context.logger.warn(`[Lattice] Entity ${entityName} not found in model ${modelId}`);
|
|
7520
|
-
}
|
|
7521
|
-
} else {
|
|
7522
|
-
context.logger.warn(`[Lattice] Model ${modelId} not found in database`);
|
|
7523
|
-
}
|
|
7524
|
-
} catch (error) {
|
|
7525
|
-
context.logger.error(`[Lattice] Failed to persist value to database:`, error);
|
|
7526
|
-
}
|
|
7527
|
-
}
|
|
7528
|
-
return JSON.stringify({
|
|
7529
|
-
success: true,
|
|
7530
|
-
action: "SET_VALUE",
|
|
7531
|
-
modelId,
|
|
7532
|
-
data: {
|
|
7533
|
-
entityName,
|
|
7534
|
-
attributeKey,
|
|
7535
|
-
value
|
|
7536
|
-
},
|
|
7537
|
-
message: `Set ${entityName}.${attributeKey} = ${value}`
|
|
7538
|
-
});
|
|
7539
|
-
},
|
|
7540
|
-
toolSchema: {
|
|
7541
|
-
name: "lattice_set_value",
|
|
7542
|
-
description: `Set a specific value in a Lattice model.
|
|
7543
|
-
|
|
7544
|
-
**When to use:** When the user provides a specific number:
|
|
7545
|
-
- "Revenue in Q1 is 150,000"
|
|
7546
|
-
- "Set marketing spend to 50k for January"
|
|
7547
|
-
- "COGS is 40% of revenue" (use lattice_create_rule for formulas)
|
|
7548
|
-
|
|
7549
|
-
**Important:** This tool is for setting raw input values. For calculated values (formulas), use \`lattice_create_rule\` instead.
|
|
7550
|
-
|
|
7551
|
-
**Examples:**
|
|
7552
|
-
- "Q1 revenue is $100,000" \u2192 entityName="Revenue", attributeKey="Q1", value=100000
|
|
7553
|
-
- "Set headcount to 25" \u2192 entityName="Headcount", attributeKey="current", value=25`,
|
|
7554
|
-
parameters: {
|
|
7555
|
-
type: "object",
|
|
7556
|
-
properties: {
|
|
7557
|
-
modelId: {
|
|
7558
|
-
type: "string",
|
|
7559
|
-
description: "ID of the model"
|
|
7560
|
-
},
|
|
7561
|
-
entityName: {
|
|
7562
|
-
type: "string",
|
|
7563
|
-
description: "Name of the entity (line item, account, etc.)"
|
|
7564
|
-
},
|
|
7565
|
-
attributeKey: {
|
|
7566
|
-
type: "string",
|
|
7567
|
-
description: 'Period or attribute key (e.g., "Q1_2024", "current", "budget")'
|
|
7568
|
-
},
|
|
7569
|
-
value: {
|
|
7570
|
-
type: "string",
|
|
7571
|
-
description: "The value to set (will be parsed as number if numeric)"
|
|
7572
|
-
}
|
|
7573
|
-
},
|
|
7574
|
-
required: ["modelId", "entityName", "attributeKey", "value"]
|
|
7575
|
-
}
|
|
7576
|
-
}
|
|
7577
|
-
})
|
|
7578
|
-
};
|
|
7579
|
-
var latticeCreateRuleTool = {
|
|
7580
|
-
name: "lattice_create_rule",
|
|
7581
|
-
implementation: (context) => ({
|
|
7582
|
-
toolFn: async (params) => {
|
|
7583
|
-
const { modelId, name, description, formula } = params;
|
|
7584
|
-
const parsedRule = parseFormula(formula);
|
|
7585
|
-
const ruleId = `rule_${Date.now()}`;
|
|
7586
|
-
const ruleData = {
|
|
7587
|
-
id: ruleId,
|
|
7588
|
-
name,
|
|
7589
|
-
description: description || formula,
|
|
7590
|
-
type: "formula",
|
|
7591
|
-
definition: {
|
|
7592
|
-
operation: parsedRule.operation,
|
|
7593
|
-
inputs: parsedRule.inputs.map((ref) => ({
|
|
7594
|
-
type: "entity",
|
|
7595
|
-
ref
|
|
7596
|
-
})),
|
|
7597
|
-
output: {
|
|
7598
|
-
targetEntityId: parsedRule.outputEntity.toLowerCase().replace(/\s+/g, "_"),
|
|
7599
|
-
targetAttribute: "computed",
|
|
7600
|
-
dataType: "number"
|
|
7601
|
-
}
|
|
7602
|
-
},
|
|
7603
|
-
dependencies: parsedRule.inputs.map((i) => i.toLowerCase().replace(/\s+/g, "_")),
|
|
7604
|
-
priority: 0,
|
|
7605
|
-
enabled: true,
|
|
7606
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
7607
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
7608
|
-
};
|
|
7609
|
-
if (context.db.latticeModels && modelId && /^[a-f0-9]{24}$/.test(modelId)) {
|
|
7610
|
-
try {
|
|
7611
|
-
const model = await context.db.latticeModels.findById(modelId);
|
|
7612
|
-
if (model) {
|
|
7613
|
-
const existingIndex = model.rules.rules.findIndex((r) => r.id === ruleId || r.name === name);
|
|
7614
|
-
if (existingIndex >= 0) {
|
|
7615
|
-
model.rules.rules[existingIndex] = ruleData;
|
|
7616
|
-
} else {
|
|
7617
|
-
model.rules.rules.push(ruleData);
|
|
7618
|
-
}
|
|
7619
|
-
await context.db.latticeModels.update({
|
|
7620
|
-
id: modelId,
|
|
7621
|
-
rules: model.rules,
|
|
7622
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
7623
|
-
});
|
|
7624
|
-
context.logger.info(`[Lattice] Created rule ${ruleId} in model ${modelId}`);
|
|
7625
|
-
} else {
|
|
7626
|
-
context.logger.warn(`[Lattice] Model ${modelId} not found in database`);
|
|
7627
|
-
}
|
|
7628
|
-
} catch (error) {
|
|
7629
|
-
context.logger.error(`[Lattice] Failed to persist rule to database:`, error);
|
|
7630
|
-
}
|
|
7631
|
-
}
|
|
7632
|
-
return JSON.stringify({
|
|
7633
|
-
success: true,
|
|
7634
|
-
action: "CREATE_RULE",
|
|
7635
|
-
modelId,
|
|
7636
|
-
ruleId,
|
|
7637
|
-
data: {
|
|
7638
|
-
name,
|
|
7639
|
-
description,
|
|
7640
|
-
formula,
|
|
7641
|
-
parsed: parsedRule
|
|
7642
|
-
},
|
|
7643
|
-
message: `Created rule "${name}": ${formula}`
|
|
7644
|
-
});
|
|
7645
|
-
},
|
|
7646
|
-
toolSchema: {
|
|
7647
|
-
name: "lattice_create_rule",
|
|
7648
|
-
description: `Create a formula or calculation rule in a Lattice model.
|
|
7649
|
-
|
|
7650
|
-
**When to use:** When the user defines a calculation:
|
|
7651
|
-
- "Gross profit equals revenue minus COGS"
|
|
7652
|
-
- "Net margin is net income divided by revenue times 100"
|
|
7653
|
-
- "Total expenses is the sum of all expense line items"
|
|
7654
|
-
|
|
7655
|
-
**Formula syntax (natural language):**
|
|
7656
|
-
- Arithmetic: "X equals Y plus Z", "A minus B", "C times D"
|
|
7657
|
-
- Aggregation: "sum of", "average of", "total"
|
|
7658
|
-
- Percentage: "X percent of Y", "as a percentage"
|
|
7659
|
-
- Comparison: "if X is greater than Y then A else B"
|
|
7660
|
-
|
|
7661
|
-
**Examples:**
|
|
7662
|
-
- "Gross Profit = Revenue - COGS"
|
|
7663
|
-
- "Gross Margin = Gross Profit / Revenue * 100"
|
|
7664
|
-
- "Total OpEx = sum of all Operating Expenses"
|
|
7665
|
-
- "YoY Growth = (Current Year - Prior Year) / Prior Year * 100"`,
|
|
7666
|
-
parameters: {
|
|
7667
|
-
type: "object",
|
|
7668
|
-
properties: {
|
|
7669
|
-
modelId: {
|
|
7670
|
-
type: "string",
|
|
7671
|
-
description: "ID of the model"
|
|
7672
|
-
},
|
|
7673
|
-
name: {
|
|
7674
|
-
type: "string",
|
|
7675
|
-
description: 'Name for this rule (e.g., "Gross Profit Calculation")'
|
|
7676
|
-
},
|
|
7677
|
-
description: {
|
|
7678
|
-
type: "string",
|
|
7679
|
-
description: "Optional description of what this rule calculates"
|
|
7680
|
-
},
|
|
7681
|
-
formula: {
|
|
7682
|
-
type: "string",
|
|
7683
|
-
description: "The formula in natural language or equation format"
|
|
7684
|
-
}
|
|
7685
|
-
},
|
|
7686
|
-
required: ["modelId", "name", "formula"]
|
|
7687
|
-
}
|
|
7688
|
-
}
|
|
7689
|
-
})
|
|
7690
|
-
};
|
|
7691
|
-
var latticeQueryTool = {
|
|
7692
|
-
name: "lattice_query",
|
|
7693
|
-
implementation: () => ({
|
|
7694
|
-
toolFn: async (params) => {
|
|
7695
|
-
const { modelId, query } = params;
|
|
7696
|
-
const parsedQuery = parseQuery(query);
|
|
7697
|
-
return JSON.stringify({
|
|
7698
|
-
success: true,
|
|
7699
|
-
action: "QUERY",
|
|
7700
|
-
modelId,
|
|
7701
|
-
data: {
|
|
7702
|
-
query,
|
|
7703
|
-
parsed: parsedQuery
|
|
7704
|
-
},
|
|
7705
|
-
message: `Querying model for: ${query}`
|
|
7706
|
-
});
|
|
7707
|
-
},
|
|
7708
|
-
toolSchema: {
|
|
7709
|
-
name: "lattice_query",
|
|
7710
|
-
description: `Query a Lattice model for specific values or aggregations.
|
|
7711
|
-
|
|
7712
|
-
**When to use:** When the user asks about values in the model:
|
|
7713
|
-
- "What's Q1 gross margin?"
|
|
7714
|
-
- "Show me total revenue for 2024"
|
|
7715
|
-
- "What are all the expense categories?"
|
|
7716
|
-
- "Compare Q1 vs Q2 performance"
|
|
7717
|
-
|
|
7718
|
-
**Query types:**
|
|
7719
|
-
- Single value: "What is [entity] for [period]?"
|
|
7720
|
-
- Aggregation: "Total [entity] for [range]"
|
|
7721
|
-
- Comparison: "Compare [entity] across [periods]"
|
|
7722
|
-
- List: "Show all [entity type]"
|
|
7723
|
-
|
|
7724
|
-
**Examples:**
|
|
7725
|
-
- "What's Q2 revenue?" \u2192 Returns specific value
|
|
7726
|
-
- "Total revenue for 2024" \u2192 Sums Q1-Q4
|
|
7727
|
-
- "Compare gross margin Q1 vs Q2" \u2192 Side-by-side comparison`,
|
|
7728
|
-
parameters: {
|
|
7729
|
-
type: "object",
|
|
7730
|
-
properties: {
|
|
7731
|
-
modelId: {
|
|
7732
|
-
type: "string",
|
|
7733
|
-
description: "ID of the model to query"
|
|
7734
|
-
},
|
|
7735
|
-
query: {
|
|
7736
|
-
type: "string",
|
|
7737
|
-
description: "Natural language query about the model"
|
|
7738
|
-
}
|
|
7739
|
-
},
|
|
7740
|
-
required: ["modelId", "query"]
|
|
7741
|
-
}
|
|
7742
|
-
}
|
|
7743
|
-
})
|
|
7744
|
-
};
|
|
7745
|
-
var latticeExplainTool = {
|
|
7746
|
-
name: "lattice_explain",
|
|
7747
|
-
implementation: () => ({
|
|
7748
|
-
toolFn: async (params) => {
|
|
7749
|
-
const { modelId, entityName, attributeKey } = params;
|
|
7750
|
-
return JSON.stringify({
|
|
7751
|
-
success: true,
|
|
7752
|
-
action: "EXPLAIN",
|
|
7753
|
-
modelId,
|
|
7754
|
-
data: {
|
|
7755
|
-
entityName,
|
|
7756
|
-
attributeKey
|
|
7757
|
-
},
|
|
7758
|
-
message: `Explaining calculation for ${entityName}.${attributeKey}`
|
|
7759
|
-
});
|
|
7760
|
-
},
|
|
7761
|
-
toolSchema: {
|
|
7762
|
-
name: "lattice_explain",
|
|
7763
|
-
description: `Explain how a value in a Lattice model was calculated.
|
|
7764
|
-
|
|
7765
|
-
**When to use:** When the user wants to understand a calculation:
|
|
7766
|
-
- "How did you calculate gross profit?"
|
|
7767
|
-
- "Explain the Q2 margin number"
|
|
7768
|
-
- "Show me the formula for total expenses"
|
|
7769
|
-
- "Why is this number so high?"
|
|
7770
|
-
|
|
7771
|
-
This tool traces the calculation chain from the target value back through all its inputs and rules, providing a step-by-step explanation.`,
|
|
7772
|
-
parameters: {
|
|
7773
|
-
type: "object",
|
|
7774
|
-
properties: {
|
|
7775
|
-
modelId: {
|
|
7776
|
-
type: "string",
|
|
7777
|
-
description: "ID of the model"
|
|
7778
|
-
},
|
|
7779
|
-
entityName: {
|
|
7780
|
-
type: "string",
|
|
7781
|
-
description: "Name of the entity containing the value to explain"
|
|
7782
|
-
},
|
|
7783
|
-
attributeKey: {
|
|
7784
|
-
type: "string",
|
|
7785
|
-
description: "Period or attribute key of the value to explain"
|
|
7786
|
-
}
|
|
7787
|
-
},
|
|
7788
|
-
required: ["modelId", "entityName", "attributeKey"]
|
|
7789
|
-
}
|
|
7790
|
-
}
|
|
7791
|
-
})
|
|
7792
|
-
};
|
|
7793
|
-
function parseFormula(formula) {
|
|
7794
|
-
const normalized = formula.toLowerCase().trim();
|
|
7795
|
-
const equalsMatch = normalized.match(/^(\w+)\s*(?:=|equals?)\s*(.+)$/i);
|
|
7796
|
-
if (equalsMatch) {
|
|
7797
|
-
const [, output, expression] = equalsMatch;
|
|
7798
|
-
if (expression.includes("+") || expression.includes("plus")) {
|
|
7799
|
-
return {
|
|
7800
|
-
operation: "ADD",
|
|
7801
|
-
outputEntity: output,
|
|
7802
|
-
inputs: expression.split(/[+]|plus/i).map((s) => s.trim())
|
|
7803
|
-
};
|
|
7804
|
-
}
|
|
7805
|
-
if (expression.includes("-") || expression.includes("minus")) {
|
|
7806
|
-
return {
|
|
7807
|
-
operation: "SUBTRACT",
|
|
7808
|
-
outputEntity: output,
|
|
7809
|
-
inputs: expression.split(/[-]|minus/i).map((s) => s.trim())
|
|
7810
|
-
};
|
|
7811
|
-
}
|
|
7812
|
-
if (expression.includes("*") || expression.includes("times") || expression.includes("x")) {
|
|
7813
|
-
return {
|
|
7814
|
-
operation: "MULTIPLY",
|
|
7815
|
-
outputEntity: output,
|
|
7816
|
-
inputs: expression.split(/[*x]|times/i).map((s) => s.trim())
|
|
7817
|
-
};
|
|
7818
|
-
}
|
|
7819
|
-
if (expression.includes("/") || expression.includes("divided")) {
|
|
7820
|
-
return {
|
|
7821
|
-
operation: "DIVIDE",
|
|
7822
|
-
outputEntity: output,
|
|
7823
|
-
inputs: expression.split(/[/]|divided by/i).map((s) => s.trim())
|
|
7824
|
-
};
|
|
7825
|
-
}
|
|
7826
|
-
if (expression.includes("sum")) {
|
|
7827
|
-
return {
|
|
7828
|
-
operation: "SUM",
|
|
7829
|
-
outputEntity: output,
|
|
7830
|
-
inputs: [expression.replace(/sum of/i, "").trim()]
|
|
7831
|
-
};
|
|
7832
|
-
}
|
|
7833
|
-
}
|
|
7834
|
-
return {
|
|
7835
|
-
operation: "REFERENCE",
|
|
7836
|
-
outputEntity: "unknown",
|
|
7837
|
-
inputs: [formula]
|
|
7838
|
-
};
|
|
7839
|
-
}
|
|
7840
|
-
function parseQuery(query) {
|
|
7841
|
-
const normalized = query.toLowerCase();
|
|
7842
|
-
let type = "single_value";
|
|
7843
|
-
if (normalized.includes("total") || normalized.includes("sum")) {
|
|
7844
|
-
type = "aggregation";
|
|
7845
|
-
} else if (normalized.includes("compare") || normalized.includes("vs")) {
|
|
7846
|
-
type = "comparison";
|
|
7847
|
-
} else if (normalized.includes("list") || normalized.includes("show all")) {
|
|
7848
|
-
type = "list";
|
|
7849
|
-
}
|
|
7850
|
-
const entities = [];
|
|
7851
|
-
const periods = [];
|
|
7852
|
-
const periodPatterns = [/q[1-4]/gi, /\d{4}/g, /jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/gi];
|
|
7853
|
-
for (const pattern of periodPatterns) {
|
|
7854
|
-
const matches = query.match(pattern);
|
|
7855
|
-
if (matches) {
|
|
7856
|
-
periods.push(...matches);
|
|
7857
|
-
}
|
|
7858
|
-
}
|
|
7859
|
-
const commonEntities = ["revenue", "expenses", "profit", "margin", "income", "cost", "cogs", "ebitda"];
|
|
7860
|
-
for (const entity of commonEntities) {
|
|
7861
|
-
if (normalized.includes(entity)) {
|
|
7862
|
-
entities.push(entity);
|
|
7863
|
-
}
|
|
7864
|
-
}
|
|
7865
|
-
return { type, entities, periods };
|
|
7866
|
-
}
|
|
7867
|
-
|
|
7868
7246
|
// ../../b4m-core/packages/services/dist/src/llm/tools/index.js
|
|
7869
7247
|
var tools = {
|
|
7870
7248
|
dice_roll: diceRollTool,
|
|
@@ -7892,14 +7270,7 @@ var tools = {
|
|
|
7892
7270
|
create_file: createFileTool,
|
|
7893
7271
|
glob_files: globFilesTool,
|
|
7894
7272
|
grep_search: grepSearchTool,
|
|
7895
|
-
delete_file: deleteFileTool
|
|
7896
|
-
// Lattice financial modeling tools
|
|
7897
|
-
lattice_create_model: latticeCreateModelTool,
|
|
7898
|
-
lattice_add_entity: latticeAddEntityTool,
|
|
7899
|
-
lattice_set_value: latticeSetValueTool,
|
|
7900
|
-
lattice_create_rule: latticeCreateRuleTool,
|
|
7901
|
-
lattice_query: latticeQueryTool,
|
|
7902
|
-
lattice_explain: latticeExplainTool
|
|
7273
|
+
delete_file: deleteFileTool
|
|
7903
7274
|
};
|
|
7904
7275
|
var generateTools = (userId, user, logger2, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model) => {
|
|
7905
7276
|
const context = {
|
|
@@ -8029,7 +7400,6 @@ var QuestStartBodySchema = z137.object({
|
|
|
8029
7400
|
enableMementos: z137.boolean().optional(),
|
|
8030
7401
|
enableArtifacts: z137.boolean().optional(),
|
|
8031
7402
|
enableAgents: z137.boolean().optional(),
|
|
8032
|
-
enableLattice: z137.boolean().optional(),
|
|
8033
7403
|
promptMeta: PromptMetaZodSchema,
|
|
8034
7404
|
tools: z137.array(z137.union([b4mLLMTools, z137.string()])).optional(),
|
|
8035
7405
|
mcpServers: z137.array(z137.string()).optional(),
|
|
@@ -9390,10 +8760,13 @@ var ApiClient = class {
|
|
|
9390
8760
|
}
|
|
9391
8761
|
};
|
|
9392
8762
|
|
|
8763
|
+
// src/index.tsx
|
|
8764
|
+
import { isAxiosError as isAxiosError2 } from "axios";
|
|
8765
|
+
|
|
9393
8766
|
// package.json
|
|
9394
8767
|
var package_default = {
|
|
9395
8768
|
name: "@bike4mind/cli",
|
|
9396
|
-
version: "0.2.1-
|
|
8769
|
+
version: "0.2.1-feat-cli-usage-command.16999+815cdcd08",
|
|
9397
8770
|
type: "module",
|
|
9398
8771
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
9399
8772
|
license: "UNLICENSED",
|
|
@@ -9490,10 +8863,10 @@ var package_default = {
|
|
|
9490
8863
|
},
|
|
9491
8864
|
devDependencies: {
|
|
9492
8865
|
"@bike4mind/agents": "0.1.0",
|
|
9493
|
-
"@bike4mind/common": "2.36.1-
|
|
9494
|
-
"@bike4mind/mcp": "1.19.4-
|
|
9495
|
-
"@bike4mind/services": "2.29.1-
|
|
9496
|
-
"@bike4mind/utils": "2.0.3-
|
|
8866
|
+
"@bike4mind/common": "2.36.1-feat-cli-usage-command.16999+815cdcd08",
|
|
8867
|
+
"@bike4mind/mcp": "1.19.4-feat-cli-usage-command.16999+815cdcd08",
|
|
8868
|
+
"@bike4mind/services": "2.29.1-feat-cli-usage-command.16999+815cdcd08",
|
|
8869
|
+
"@bike4mind/utils": "2.0.3-feat-cli-usage-command.16999+815cdcd08",
|
|
9497
8870
|
"@types/diff": "^5.0.9",
|
|
9498
8871
|
"@types/jsonwebtoken": "^9.0.4",
|
|
9499
8872
|
"@types/node": "^22.9.0",
|
|
@@ -9504,9 +8877,14 @@ var package_default = {
|
|
|
9504
8877
|
tsx: "^4.21.0",
|
|
9505
8878
|
typescript: "^5.9.3"
|
|
9506
8879
|
},
|
|
9507
|
-
gitHead: "
|
|
8880
|
+
gitHead: "815cdcd0897c92e3713ce3e04c930b70332cb318"
|
|
9508
8881
|
};
|
|
9509
8882
|
|
|
8883
|
+
// src/config/constants.ts
|
|
8884
|
+
var USAGE_DAYS = 30;
|
|
8885
|
+
var MODEL_NAME_COLUMN_WIDTH = 18;
|
|
8886
|
+
var USAGE_CACHE_TTL = 5 * 60 * 1e3;
|
|
8887
|
+
|
|
9510
8888
|
// src/index.tsx
|
|
9511
8889
|
process.removeAllListeners("warning");
|
|
9512
8890
|
process.on("warning", (warning) => {
|
|
@@ -9517,6 +8895,7 @@ process.on("warning", (warning) => {
|
|
|
9517
8895
|
});
|
|
9518
8896
|
var exitTimestamp = null;
|
|
9519
8897
|
var EXIT_TIMEOUT_MS = 2e3;
|
|
8898
|
+
var usageCache = null;
|
|
9520
8899
|
function CliApp() {
|
|
9521
8900
|
const { exit } = useApp();
|
|
9522
8901
|
const [state, setState] = useState3({
|
|
@@ -9881,6 +9260,7 @@ Available commands:
|
|
|
9881
9260
|
/login - Authenticate with your B4M account
|
|
9882
9261
|
/logout - Clear authentication and sign out
|
|
9883
9262
|
/whoami - Show current authenticated user
|
|
9263
|
+
/usage - Show credit usage and balance
|
|
9884
9264
|
/save <name> - Save current session
|
|
9885
9265
|
/sessions - List saved sessions
|
|
9886
9266
|
/config - Show configuration
|
|
@@ -10051,6 +9431,103 @@ Tool Permissions:
|
|
|
10051
9431
|
console.log(`Expires: ${new Date(authTokens.expiresAt).toLocaleString()}`);
|
|
10052
9432
|
console.log("");
|
|
10053
9433
|
break;
|
|
9434
|
+
case "usage": {
|
|
9435
|
+
const usageAuthTokens = await state.configStore.getAuthTokens();
|
|
9436
|
+
if (!usageAuthTokens || new Date(usageAuthTokens.expiresAt) <= /* @__PURE__ */ new Date()) {
|
|
9437
|
+
console.log("\nNot authenticated. Run /login to authenticate.\n");
|
|
9438
|
+
return;
|
|
9439
|
+
}
|
|
9440
|
+
console.log("\nFetching usage data...");
|
|
9441
|
+
const now = Date.now();
|
|
9442
|
+
let currentCredits;
|
|
9443
|
+
let transactions;
|
|
9444
|
+
if (usageCache && now - usageCache.timestamp < USAGE_CACHE_TTL) {
|
|
9445
|
+
currentCredits = usageCache.data.currentCredits;
|
|
9446
|
+
transactions = usageCache.data.transactions;
|
|
9447
|
+
console.log("(using cached data)\n");
|
|
9448
|
+
} else {
|
|
9449
|
+
try {
|
|
9450
|
+
const config = await state.configStore.get();
|
|
9451
|
+
const apiBaseURL = getApiUrl(config.apiConfig);
|
|
9452
|
+
const apiClient = new ApiClient(apiBaseURL, state.configStore);
|
|
9453
|
+
const [identifyResponse, transactionsResponse] = await Promise.all([
|
|
9454
|
+
apiClient.get("/api/identify"),
|
|
9455
|
+
apiClient.get(`/api/credits/transactions?days=${USAGE_DAYS}`)
|
|
9456
|
+
]);
|
|
9457
|
+
currentCredits = identifyResponse.user.currentCredits;
|
|
9458
|
+
transactions = transactionsResponse || [];
|
|
9459
|
+
usageCache = {
|
|
9460
|
+
data: { currentCredits, transactions },
|
|
9461
|
+
timestamp: now
|
|
9462
|
+
};
|
|
9463
|
+
} catch (error) {
|
|
9464
|
+
if (isAxiosError2(error)) {
|
|
9465
|
+
if (error.response?.status === 401) {
|
|
9466
|
+
console.log("\n\u274C Authentication failed. Run /login to re-authenticate.\n");
|
|
9467
|
+
} else if (error.response?.status === 403) {
|
|
9468
|
+
console.log("\n\u274C Access denied. You may not have permission to view usage data.\n");
|
|
9469
|
+
} else if (error.response?.status === 404) {
|
|
9470
|
+
console.log("\n\u274C Usage endpoint not available on this server.\n");
|
|
9471
|
+
} else if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND") {
|
|
9472
|
+
console.log("\n\u274C Cannot connect to server. Check your API configuration with /api-info\n");
|
|
9473
|
+
} else {
|
|
9474
|
+
console.log(`
|
|
9475
|
+
\u274C Error fetching usage data: ${error.message}
|
|
9476
|
+
`);
|
|
9477
|
+
}
|
|
9478
|
+
} else if (error instanceof Error) {
|
|
9479
|
+
console.log(`
|
|
9480
|
+
\u274C Error: ${error.message}
|
|
9481
|
+
`);
|
|
9482
|
+
} else {
|
|
9483
|
+
console.log("\n\u274C Unexpected error fetching usage data. Please try again.\n");
|
|
9484
|
+
}
|
|
9485
|
+
break;
|
|
9486
|
+
}
|
|
9487
|
+
}
|
|
9488
|
+
const deductTransactions = transactions.filter(
|
|
9489
|
+
(t) => CREDIT_DEDUCT_TRANSACTION_TYPES.includes(t.type)
|
|
9490
|
+
);
|
|
9491
|
+
const totalCreditsUsed = deductTransactions.reduce((sum2, t) => sum2 + Math.abs(t.credits), 0);
|
|
9492
|
+
const dailyBurnRate = Math.round(totalCreditsUsed / USAGE_DAYS);
|
|
9493
|
+
let daysRemainingStr;
|
|
9494
|
+
if (dailyBurnRate === 0) {
|
|
9495
|
+
daysRemainingStr = "N/A (no usage)";
|
|
9496
|
+
} else {
|
|
9497
|
+
const daysRemaining = Math.floor(currentCredits / dailyBurnRate);
|
|
9498
|
+
daysRemainingStr = `~${daysRemaining.toLocaleString()} days`;
|
|
9499
|
+
}
|
|
9500
|
+
const usageByModel = {};
|
|
9501
|
+
for (const t of deductTransactions) {
|
|
9502
|
+
const modelName = t.metadata?.modelName || ("model" in t ? t.model : null) || "Unknown";
|
|
9503
|
+
usageByModel[modelName] = (usageByModel[modelName] || 0) + Math.abs(t.credits);
|
|
9504
|
+
}
|
|
9505
|
+
const sortedModels = Object.entries(usageByModel).sort((a, b) => b[1] - a[1]);
|
|
9506
|
+
console.log("\n Credit Usage Summary");
|
|
9507
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n");
|
|
9508
|
+
console.log(`Credits Balance: ${currentCredits.toLocaleString()}`);
|
|
9509
|
+
console.log(`Daily Burn Rate: ${dailyBurnRate.toLocaleString()} credits/day`);
|
|
9510
|
+
console.log(`Days Remaining: ${daysRemainingStr}`);
|
|
9511
|
+
if (currentCredits === 0) {
|
|
9512
|
+
console.log("\n\u26A0\uFE0F You have no credits remaining.");
|
|
9513
|
+
console.log("\u{1F4A1} Visit bike4mind.io to purchase more credits.\n");
|
|
9514
|
+
break;
|
|
9515
|
+
}
|
|
9516
|
+
if (sortedModels.length > 0) {
|
|
9517
|
+
console.log(`
|
|
9518
|
+
Usage by Model (Last ${USAGE_DAYS} days):`);
|
|
9519
|
+
for (const [model, credits] of sortedModels) {
|
|
9520
|
+
const percentage = totalCreditsUsed > 0 ? Math.round(credits / totalCreditsUsed * 100) : 0;
|
|
9521
|
+
const paddedModel = model.padEnd(MODEL_NAME_COLUMN_WIDTH);
|
|
9522
|
+
console.log(` ${paddedModel}${credits.toLocaleString()} credits (${percentage}%)`);
|
|
9523
|
+
}
|
|
9524
|
+
} else {
|
|
9525
|
+
console.log(`
|
|
9526
|
+
No usage data available for the last ${USAGE_DAYS} days.`);
|
|
9527
|
+
}
|
|
9528
|
+
console.log("");
|
|
9529
|
+
break;
|
|
9530
|
+
}
|
|
10054
9531
|
default:
|
|
10055
9532
|
console.log(`Unknown command: /${command}`);
|
|
10056
9533
|
console.log("Type /help for available commands");
|