@bike4mind/cli 0.2.29-cli-resume-command.18763 → 0.2.29-feature-b4m-pi.18846

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/index.js CHANGED
@@ -5,7 +5,8 @@ import {
5
5
  getEffectiveApiKey,
6
6
  getOpenWeatherKey,
7
7
  getSerperKey
8
- } from "./chunk-VGYTNJXN.js";
8
+ } from "./chunk-SZRU4SFM.js";
9
+ import "./chunk-NHP3UPYU.js";
9
10
  import {
10
11
  ConfigStore
11
12
  } from "./chunk-23T2XGSZ.js";
@@ -13,8 +14,8 @@ import {
13
14
  selectActiveBackgroundAgents,
14
15
  useCliStore
15
16
  } from "./chunk-TVW4ZESU.js";
16
- import "./chunk-JJBDHUGY.js";
17
- import "./chunk-ZEMWV6IR.js";
17
+ import "./chunk-MUWN5G77.js";
18
+ import "./chunk-2UFCM2T4.js";
18
19
  import {
19
20
  BFLImageService,
20
21
  BaseStorage,
@@ -26,7 +27,7 @@ import {
26
27
  OpenAIBackend,
27
28
  OpenAIImageService,
28
29
  XAIImageService
29
- } from "./chunk-UNOJBVD2.js";
30
+ } from "./chunk-A3HXNIIZ.js";
30
31
  import {
31
32
  AiEvents,
32
33
  ApiKeyEvents,
@@ -82,7 +83,7 @@ import {
82
83
  XAI_IMAGE_MODELS,
83
84
  b4mLLMTools,
84
85
  getMcpProviderMetadata
85
- } from "./chunk-XJRPAAUS.js";
86
+ } from "./chunk-WVQTZODT.js";
86
87
  import {
87
88
  Logger
88
89
  } from "./chunk-OCYRD7D6.js";
@@ -551,9 +552,8 @@ var COMMANDS = [
551
552
  args: "<name>"
552
553
  },
553
554
  {
554
- name: "resume",
555
- description: "List and resume saved sessions",
556
- aliases: ["sessions"]
555
+ name: "sessions",
556
+ description: "List saved sessions"
557
557
  },
558
558
  {
559
559
  name: "config",
@@ -3718,23 +3718,18 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
3718
3718
  async executeToolWithQueueFallback(toolUse) {
3719
3719
  const queuedObs = this.observationQueue.find((obs) => obs.toolId === getToolId(toolUse));
3720
3720
  if (queuedObs) {
3721
- const result = queuedObs.result;
3721
+ const result2 = queuedObs.result;
3722
3722
  const index = this.observationQueue.indexOf(queuedObs);
3723
3723
  this.observationQueue.splice(index, 1);
3724
- return typeof result === "string" ? result : JSON.stringify(result);
3724
+ return typeof result2 === "string" ? result2 : JSON.stringify(result2);
3725
3725
  }
3726
3726
  const tool = this.context.tools.find((t) => t.toolSchema.name === toolUse.name);
3727
3727
  if (!tool) {
3728
- return `Error: Tool ${toolUse.name} not found in agent context`;
3729
- }
3730
- try {
3731
- const params = this.parseToolArguments(toolUse.arguments);
3732
- const result = await tool.toolFn(params);
3733
- return typeof result === "string" ? result : JSON.stringify(result);
3734
- } catch (error) {
3735
- const message = error instanceof Error ? error.message : String(error);
3736
- return `Error: ${message}`;
3728
+ throw new Error(`Tool ${toolUse.name} not found in agent context`);
3737
3729
  }
3730
+ const params = this.parseToolArguments(toolUse.arguments);
3731
+ const result = await tool.toolFn(params);
3732
+ return typeof result === "string" ? result : JSON.stringify(result);
3738
3733
  }
3739
3734
  /**
3740
3735
  * Build and append tool call/result messages for the conversation history
@@ -5756,7 +5751,19 @@ import { z as z129 } from "zod";
5756
5751
  var createArtifactSchema = z129.object({
5757
5752
  id: z129.string().optional(),
5758
5753
  // Allow custom ID for AI-generated artifacts
5759
- type: z129.enum(["mermaid", "recharts", "python", "react", "html", "svg", "code", "quest", "file", "questmaster"]),
5754
+ type: z129.enum([
5755
+ "mermaid",
5756
+ "recharts",
5757
+ "python",
5758
+ "react",
5759
+ "html",
5760
+ "svg",
5761
+ "code",
5762
+ "quest",
5763
+ "file",
5764
+ "questmaster",
5765
+ "lattice"
5766
+ ]),
5760
5767
  title: z129.string().min(1).max(255),
5761
5768
  description: z129.string().max(1e3).optional(),
5762
5769
  content: z129.string().min(1),
@@ -10364,6 +10371,819 @@ BLOCKED OPERATIONS:
10364
10371
  })
10365
10372
  };
10366
10373
 
10374
+ // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/lattice/index.js
10375
+ function createModelData(name, modelType, userId, description, sessionId) {
10376
+ const now = /* @__PURE__ */ new Date();
10377
+ return {
10378
+ name,
10379
+ description: description || "",
10380
+ modelType,
10381
+ userId,
10382
+ sessionId,
10383
+ data: { entities: [], relationships: [] },
10384
+ rules: { rules: [], rulesets: [] },
10385
+ views: { views: [] },
10386
+ settings: {
10387
+ currency: "USD",
10388
+ fiscalYearStart: "01-01",
10389
+ periodGrain: "quarter",
10390
+ defaultDecimalPlaces: 2,
10391
+ negativeFormat: "parentheses"
10392
+ },
10393
+ scenarios: [],
10394
+ operations: [],
10395
+ operationIndex: -1,
10396
+ version: 1,
10397
+ createdAt: now,
10398
+ updatedAt: now
10399
+ };
10400
+ }
10401
+ var latticeCreateModelTool = {
10402
+ name: "lattice_create_model",
10403
+ implementation: (context) => ({
10404
+ toolFn: async (params) => {
10405
+ const { name, description, modelType = "custom", initialData } = params;
10406
+ console.log("[LATTICE DEBUG] \u{1F3D7}\uFE0F lattice_create_model called:", {
10407
+ name,
10408
+ description,
10409
+ modelType,
10410
+ hasInitialData: !!initialData,
10411
+ entityCount: initialData?.entities?.length || 0,
10412
+ ruleCount: initialData?.rules?.length || 0
10413
+ });
10414
+ const modelData = createModelData(name, modelType, context.userId, description);
10415
+ if (initialData?.entities && modelData.data) {
10416
+ const now = /* @__PURE__ */ new Date();
10417
+ for (const entityDef of initialData.entities) {
10418
+ const entityId = entityDef.name.toLowerCase().replace(/\s+/g, "_");
10419
+ const attributes = [];
10420
+ if (entityDef.values) {
10421
+ for (const val of entityDef.values) {
10422
+ attributes.push({
10423
+ key: "period",
10424
+ value: val.period,
10425
+ dataType: "string",
10426
+ isComputed: false
10427
+ });
10428
+ attributes.push({
10429
+ key: "value",
10430
+ value: val.value,
10431
+ dataType: "currency",
10432
+ isComputed: false
10433
+ });
10434
+ attributes.push({
10435
+ key: "category",
10436
+ value: entityDef.name,
10437
+ dataType: "string",
10438
+ isComputed: false
10439
+ });
10440
+ modelData.data.entities.push({
10441
+ id: `${entityId}_${val.period.toLowerCase().replace(/\s+/g, "_")}`,
10442
+ type: entityDef.type || "line_item",
10443
+ name: `${entityDef.name} ${val.period}`,
10444
+ displayName: `${entityDef.name} ${val.period}`,
10445
+ attributes: [
10446
+ { key: "period", value: val.period, dataType: "string", isComputed: false },
10447
+ { key: "value", value: val.value, dataType: "currency", isComputed: false },
10448
+ { key: "category", value: entityDef.name, dataType: "string", isComputed: false }
10449
+ ],
10450
+ metadata: {},
10451
+ createdAt: now,
10452
+ updatedAt: now
10453
+ });
10454
+ }
10455
+ }
10456
+ console.log(`[LATTICE DEBUG] \u2795 Created entity: ${entityDef.name} with ${entityDef.values?.length || 0} period values`);
10457
+ }
10458
+ }
10459
+ if (initialData?.rules && modelData.rules) {
10460
+ const now = /* @__PURE__ */ new Date();
10461
+ for (const ruleDef of initialData.rules) {
10462
+ const ruleId = `rule_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`;
10463
+ const parsedRule = parseFormula(ruleDef.formula);
10464
+ modelData.rules.rules.push({
10465
+ id: ruleId,
10466
+ name: ruleDef.name,
10467
+ description: ruleDef.formula,
10468
+ type: "formula",
10469
+ definition: {
10470
+ operation: parsedRule.operation,
10471
+ inputs: parsedRule.inputs.map((ref) => ({ type: "entity", ref })),
10472
+ output: {
10473
+ targetEntityId: parsedRule.outputEntity.toLowerCase().replace(/\s+/g, "_"),
10474
+ targetAttribute: "computed",
10475
+ dataType: "number"
10476
+ }
10477
+ },
10478
+ dependencies: parsedRule.inputs.map((i) => i.toLowerCase().replace(/\s+/g, "_")),
10479
+ priority: 0,
10480
+ enabled: true,
10481
+ createdAt: now,
10482
+ updatedAt: now
10483
+ });
10484
+ console.log(`[LATTICE DEBUG] \u{1F4D0} Created rule: ${ruleDef.name} = ${ruleDef.formula}`);
10485
+ }
10486
+ }
10487
+ let model;
10488
+ let persistenceStatus = "unknown";
10489
+ const dbKeys = Object.keys(context.db || {});
10490
+ const hasLatticeModels = !!context.db?.latticeModels;
10491
+ if (context.db.latticeModels) {
10492
+ try {
10493
+ model = await context.db.latticeModels.create(modelData);
10494
+ persistenceStatus = `PERSISTED to MongoDB (id: ${model.id})`;
10495
+ context.logger.info(`[Lattice] Created model ${model.id} in database`);
10496
+ } catch (error) {
10497
+ persistenceStatus = `FAILED: ${error instanceof Error ? error.message : String(error)}`;
10498
+ context.logger.error(`[Lattice] Failed to persist model to database:`, error);
10499
+ model = {
10500
+ ...modelData,
10501
+ id: `lattice_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
10502
+ };
10503
+ }
10504
+ } else {
10505
+ persistenceStatus = `IN-MEMORY (no latticeModels adapter). DB keys: [${dbKeys.join(", ")}]`;
10506
+ context.logger.warn("[Lattice] No database adapter available, creating in-memory model");
10507
+ model = {
10508
+ ...modelData,
10509
+ id: `lattice_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
10510
+ };
10511
+ }
10512
+ const artifactData = {
10513
+ type: "lattice",
10514
+ id: model.id,
10515
+ title: name,
10516
+ content: JSON.stringify(model),
10517
+ metadata: {
10518
+ modelType,
10519
+ periodGrain: model.settings?.periodGrain || "quarter",
10520
+ currency: model.settings?.currency || "USD",
10521
+ entityCount: model.data?.entities?.length || 0,
10522
+ ruleCount: model.rules?.rules?.length || 0,
10523
+ // DEBUG: Include persistence info in metadata
10524
+ _debug: {
10525
+ persistenceStatus,
10526
+ hasLatticeModels,
10527
+ dbKeys
10528
+ }
10529
+ },
10530
+ createdAt: model.createdAt?.toISOString?.() || (/* @__PURE__ */ new Date()).toISOString(),
10531
+ updatedAt: model.updatedAt?.toISOString?.() || (/* @__PURE__ */ new Date()).toISOString()
10532
+ };
10533
+ const entityCount = model.data?.entities?.length || 0;
10534
+ const ruleCount = model.rules?.rules?.length || 0;
10535
+ return `Created "${name}" model with ${entityCount} entities and ${ruleCount} rules.
10536
+
10537
+ <artifact identifier="${model.id}" type="application/vnd.b4m.lattice" title="${name}">
10538
+ ${JSON.stringify(artifactData, null, 2)}
10539
+ </artifact>
10540
+
10541
+ The model is ready for viewing. You can add more data by asking to add line items or create formulas.`;
10542
+ },
10543
+ toolSchema: {
10544
+ name: "lattice_create_model",
10545
+ description: `Create a new Lattice financial model with optional initial data. Use initialData to populate entities and rules in ONE call.
10546
+
10547
+ **IMPORTANT**: Always include initialData when the user provides specific values! This creates a fully populated model immediately.
10548
+
10549
+ **When to use:** When the user wants to:
10550
+ - Create a new financial model, spreadsheet, or pro-forma
10551
+ - Start building an income statement, balance sheet, or cash flow
10552
+ - Set up a SaaS metrics dashboard
10553
+
10554
+ **Example with initialData:**
10555
+ User: "Create income statement with $100K revenue and $60K costs for Q1"
10556
+ Call: lattice_create_model with:
10557
+ - name: "Income Statement"
10558
+ - modelType: "income_statement"
10559
+ - initialData: {
10560
+ entities: [
10561
+ { name: "Revenue", values: [{ period: "Q1", value: 100000 }] },
10562
+ { name: "Costs", values: [{ period: "Q1", value: 60000 }] }
10563
+ ],
10564
+ rules: [
10565
+ { name: "Gross Profit", formula: "Gross Profit = Revenue - Costs" }
10566
+ ]
10567
+ }`,
10568
+ parameters: {
10569
+ type: "object",
10570
+ properties: {
10571
+ name: {
10572
+ type: "string",
10573
+ description: 'Name of the model (e.g., "2024 Budget", "Q1 Forecast")'
10574
+ },
10575
+ description: {
10576
+ type: "string",
10577
+ description: "Optional description of what this model represents"
10578
+ },
10579
+ modelType: {
10580
+ type: "string",
10581
+ enum: ["income_statement", "balance_sheet", "cashflow", "saas_metrics", "custom"],
10582
+ description: "Type of financial model to create"
10583
+ },
10584
+ initialData: {
10585
+ type: "object",
10586
+ description: "Initial entities and rules to populate the model. ALWAYS use this when user provides data!",
10587
+ properties: {
10588
+ entities: {
10589
+ type: "array",
10590
+ description: "Line items with their period values",
10591
+ items: {
10592
+ type: "object",
10593
+ properties: {
10594
+ name: { type: "string", description: 'Entity name (e.g., "Revenue", "COGS")' },
10595
+ type: { type: "string", description: "Entity type (default: line_item)" },
10596
+ values: {
10597
+ type: "array",
10598
+ description: "Period-value pairs",
10599
+ items: {
10600
+ type: "object",
10601
+ properties: {
10602
+ period: { type: "string", description: 'Period name (e.g., "Q1", "Jan", "2024")' },
10603
+ value: { type: "number", description: "Numeric value" }
10604
+ },
10605
+ required: ["period", "value"]
10606
+ }
10607
+ }
10608
+ },
10609
+ required: ["name"]
10610
+ }
10611
+ },
10612
+ rules: {
10613
+ type: "array",
10614
+ description: "Formulas/calculations to create",
10615
+ items: {
10616
+ type: "object",
10617
+ properties: {
10618
+ name: { type: "string", description: 'Rule name (e.g., "Gross Profit Calculation")' },
10619
+ formula: {
10620
+ type: "string",
10621
+ description: 'Natural language formula (e.g., "Gross Profit = Revenue - Costs")'
10622
+ }
10623
+ },
10624
+ required: ["name", "formula"]
10625
+ }
10626
+ }
10627
+ }
10628
+ }
10629
+ },
10630
+ required: ["name"]
10631
+ }
10632
+ }
10633
+ })
10634
+ };
10635
+ var latticeAddEntityTool = {
10636
+ name: "lattice_add_entity",
10637
+ implementation: (context) => ({
10638
+ toolFn: async (params) => {
10639
+ const { modelId, name, type, displayName, initialValues = [] } = params;
10640
+ console.log("[LATTICE DEBUG] \u2795 lattice_add_entity called:", { modelId, name, type, initialValues });
10641
+ const entityId = name.toLowerCase().replace(/\s+/g, "_");
10642
+ const entityData = {
10643
+ id: entityId,
10644
+ type,
10645
+ name,
10646
+ displayName: displayName || name,
10647
+ attributes: initialValues.map((v) => ({
10648
+ key: v.key,
10649
+ value: v.value,
10650
+ dataType: v.dataType || (typeof v.value === "number" ? "number" : "string"),
10651
+ isComputed: false
10652
+ })),
10653
+ metadata: {},
10654
+ createdAt: /* @__PURE__ */ new Date(),
10655
+ updatedAt: /* @__PURE__ */ new Date()
10656
+ };
10657
+ if (context.db.latticeModels && modelId && /^[a-f0-9]{24}$/.test(modelId)) {
10658
+ try {
10659
+ const model = await context.db.latticeModels.findById(modelId);
10660
+ if (model) {
10661
+ const existingIndex = model.data.entities.findIndex((e) => e.id === entityId);
10662
+ if (existingIndex >= 0) {
10663
+ model.data.entities[existingIndex] = entityData;
10664
+ } else {
10665
+ model.data.entities.push(entityData);
10666
+ }
10667
+ await context.db.latticeModels.update({
10668
+ id: modelId,
10669
+ data: model.data,
10670
+ updatedAt: /* @__PURE__ */ new Date()
10671
+ });
10672
+ context.logger.info(`[Lattice] Added entity ${entityId} to model ${modelId}`);
10673
+ } else {
10674
+ context.logger.warn(`[Lattice] Model ${modelId} not found in database`);
10675
+ }
10676
+ } catch (error) {
10677
+ context.logger.error(`[Lattice] Failed to persist entity to database:`, error);
10678
+ }
10679
+ }
10680
+ return JSON.stringify({
10681
+ success: true,
10682
+ action: "ADD_ENTITY",
10683
+ modelId,
10684
+ entityId,
10685
+ data: entityData,
10686
+ 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."}`
10687
+ });
10688
+ },
10689
+ toolSchema: {
10690
+ name: "lattice_add_entity",
10691
+ description: `Add a line item, account, period, or other entity to a Lattice model.
10692
+
10693
+ **When to use:** When the user mentions:
10694
+ - Adding a revenue line, expense category, or account
10695
+ - Creating periods (Q1, Q2, Jan, Feb, etc.)
10696
+ - Adding any measurable item to their model
10697
+
10698
+ **Entity types:**
10699
+ - line_item: Revenue streams, expense lines, KPIs
10700
+ - account: Cash, AR, AP, inventory, etc.
10701
+ - period: Q1 2024, Jan, FY2025, etc.
10702
+ - category: Groups of line items (Operating Expenses)
10703
+ - scenario: Base case, upside, downside
10704
+ - custom: Any other structured element
10705
+
10706
+ **Examples:**
10707
+ - "Add Revenue" \u2192 line_item named "Revenue"
10708
+ - "Create a Marketing Expenses category" \u2192 category named "Marketing Expenses"
10709
+ - "Add quarters Q1 through Q4" \u2192 4 period entities`,
10710
+ parameters: {
10711
+ type: "object",
10712
+ properties: {
10713
+ modelId: {
10714
+ type: "string",
10715
+ description: "ID of the model to add the entity to"
10716
+ },
10717
+ name: {
10718
+ type: "string",
10719
+ description: "Internal name for the entity (used in formulas)"
10720
+ },
10721
+ type: {
10722
+ type: "string",
10723
+ enum: ["line_item", "account", "period", "category", "scenario", "custom"],
10724
+ description: "Type of entity"
10725
+ },
10726
+ displayName: {
10727
+ type: "string",
10728
+ description: "Human-readable display name (defaults to name)"
10729
+ },
10730
+ initialValues: {
10731
+ type: "array",
10732
+ items: {
10733
+ type: "object",
10734
+ properties: {
10735
+ key: { type: "string", description: 'Period or attribute key (e.g., "Q1_2024")' },
10736
+ value: { type: "string", description: "The value (number or string)" },
10737
+ dataType: {
10738
+ type: "string",
10739
+ enum: ["number", "currency", "percentage", "string"],
10740
+ description: "Data type for the value"
10741
+ }
10742
+ },
10743
+ required: ["key", "value"]
10744
+ },
10745
+ description: "Optional initial values for this entity"
10746
+ }
10747
+ },
10748
+ required: ["modelId", "name", "type"]
10749
+ }
10750
+ }
10751
+ })
10752
+ };
10753
+ var latticeSetValueTool = {
10754
+ name: "lattice_set_value",
10755
+ implementation: (context) => ({
10756
+ toolFn: async (params) => {
10757
+ const { modelId, entityName, attributeKey, value: rawValue } = params;
10758
+ console.log("[LATTICE DEBUG] \u{1F4DD} lattice_set_value called:", { modelId, entityName, attributeKey, rawValue });
10759
+ let value = rawValue;
10760
+ const numValue = parseFloat(rawValue);
10761
+ if (!isNaN(numValue)) {
10762
+ value = numValue;
10763
+ } else if (rawValue.toLowerCase() === "true") {
10764
+ value = true;
10765
+ } else if (rawValue.toLowerCase() === "false") {
10766
+ value = false;
10767
+ }
10768
+ const entityId = entityName.toLowerCase().replace(/\s+/g, "_");
10769
+ if (context.db.latticeModels && modelId && /^[a-f0-9]{24}$/.test(modelId)) {
10770
+ try {
10771
+ const model = await context.db.latticeModels.findById(modelId);
10772
+ if (model) {
10773
+ const entity = model.data.entities.find((e) => e.id === entityId || e.name === entityName);
10774
+ if (entity) {
10775
+ const attrIndex = entity.attributes.findIndex((a) => a.key === attributeKey);
10776
+ const dataType = typeof value === "number" ? "number" : typeof value === "boolean" ? "boolean" : "string";
10777
+ const attributeData = {
10778
+ key: attributeKey,
10779
+ value,
10780
+ dataType,
10781
+ isComputed: false
10782
+ };
10783
+ if (attrIndex >= 0) {
10784
+ entity.attributes[attrIndex] = attributeData;
10785
+ } else {
10786
+ entity.attributes.push(attributeData);
10787
+ }
10788
+ entity.updatedAt = /* @__PURE__ */ new Date();
10789
+ await context.db.latticeModels.update({
10790
+ id: modelId,
10791
+ data: model.data,
10792
+ updatedAt: /* @__PURE__ */ new Date()
10793
+ });
10794
+ context.logger.info(`[Lattice] Set ${entityId}.${attributeKey} = ${value} in model ${modelId}`);
10795
+ } else {
10796
+ context.logger.warn(`[Lattice] Entity ${entityName} not found in model ${modelId}`);
10797
+ }
10798
+ } else {
10799
+ context.logger.warn(`[Lattice] Model ${modelId} not found in database`);
10800
+ }
10801
+ } catch (error) {
10802
+ context.logger.error(`[Lattice] Failed to persist value to database:`, error);
10803
+ }
10804
+ }
10805
+ return JSON.stringify({
10806
+ success: true,
10807
+ action: "SET_VALUE",
10808
+ modelId,
10809
+ data: {
10810
+ entityName,
10811
+ attributeKey,
10812
+ value
10813
+ },
10814
+ message: `Set ${entityName}.${attributeKey} = ${value}`
10815
+ });
10816
+ },
10817
+ toolSchema: {
10818
+ name: "lattice_set_value",
10819
+ description: `Set a specific value in a Lattice model.
10820
+
10821
+ **When to use:** When the user provides a specific number:
10822
+ - "Revenue in Q1 is 150,000"
10823
+ - "Set marketing spend to 50k for January"
10824
+ - "COGS is 40% of revenue" (use lattice_create_rule for formulas)
10825
+
10826
+ **Important:** This tool is for setting raw input values. For calculated values (formulas), use \`lattice_create_rule\` instead.
10827
+
10828
+ **Examples:**
10829
+ - "Q1 revenue is $100,000" \u2192 entityName="Revenue", attributeKey="Q1", value=100000
10830
+ - "Set headcount to 25" \u2192 entityName="Headcount", attributeKey="current", value=25`,
10831
+ parameters: {
10832
+ type: "object",
10833
+ properties: {
10834
+ modelId: {
10835
+ type: "string",
10836
+ description: "ID of the model"
10837
+ },
10838
+ entityName: {
10839
+ type: "string",
10840
+ description: "Name of the entity (line item, account, etc.)"
10841
+ },
10842
+ attributeKey: {
10843
+ type: "string",
10844
+ description: 'Period or attribute key (e.g., "Q1_2024", "current", "budget")'
10845
+ },
10846
+ value: {
10847
+ type: "string",
10848
+ description: "The value to set (will be parsed as number if numeric)"
10849
+ }
10850
+ },
10851
+ required: ["modelId", "entityName", "attributeKey", "value"]
10852
+ }
10853
+ }
10854
+ })
10855
+ };
10856
+ var latticeCreateRuleTool = {
10857
+ name: "lattice_create_rule",
10858
+ implementation: (context) => ({
10859
+ toolFn: async (params) => {
10860
+ const { modelId, name, description, formula } = params;
10861
+ console.log("[LATTICE DEBUG] \u{1F4D0} lattice_create_rule called:", { modelId, name, formula });
10862
+ const parsedRule = parseFormula(formula);
10863
+ const ruleId = `rule_${Date.now()}`;
10864
+ const ruleData = {
10865
+ id: ruleId,
10866
+ name,
10867
+ description: description || formula,
10868
+ type: "formula",
10869
+ definition: {
10870
+ operation: parsedRule.operation,
10871
+ inputs: parsedRule.inputs.map((ref) => ({
10872
+ type: "entity",
10873
+ ref
10874
+ })),
10875
+ output: {
10876
+ targetEntityId: parsedRule.outputEntity.toLowerCase().replace(/\s+/g, "_"),
10877
+ targetAttribute: "computed",
10878
+ dataType: "number"
10879
+ }
10880
+ },
10881
+ dependencies: parsedRule.inputs.map((i) => i.toLowerCase().replace(/\s+/g, "_")),
10882
+ priority: 0,
10883
+ enabled: true,
10884
+ createdAt: /* @__PURE__ */ new Date(),
10885
+ updatedAt: /* @__PURE__ */ new Date()
10886
+ };
10887
+ const outputEntityId = parsedRule.outputEntity.toLowerCase().replace(/\s+/g, "_");
10888
+ let entityCreatedMessage = "";
10889
+ if (context.db.latticeModels && modelId && /^[a-f0-9]{24}$/.test(modelId)) {
10890
+ try {
10891
+ const model = await context.db.latticeModels.findById(modelId);
10892
+ if (model) {
10893
+ const outputEntityExists = model.data.entities.some((e) => e.id === outputEntityId || e.name.toLowerCase() === parsedRule.outputEntity.toLowerCase());
10894
+ if (!outputEntityExists && parsedRule.outputEntity !== "unknown") {
10895
+ const now = /* @__PURE__ */ new Date();
10896
+ const newEntity = {
10897
+ id: outputEntityId,
10898
+ type: "line_item",
10899
+ name: parsedRule.outputEntity,
10900
+ displayName: parsedRule.outputEntity,
10901
+ attributes: [
10902
+ {
10903
+ key: "value",
10904
+ value: 0,
10905
+ dataType: "currency",
10906
+ isComputed: true
10907
+ },
10908
+ {
10909
+ key: "category",
10910
+ value: "Computed",
10911
+ dataType: "string",
10912
+ isComputed: false
10913
+ }
10914
+ ],
10915
+ metadata: { isComputed: true },
10916
+ createdAt: now,
10917
+ updatedAt: now
10918
+ };
10919
+ model.data.entities.push(newEntity);
10920
+ entityCreatedMessage = ` Created output entity "${parsedRule.outputEntity}".`;
10921
+ context.logger.info(`[Lattice] Auto-created output entity ${outputEntityId} for rule ${ruleId}`);
10922
+ }
10923
+ const existingIndex = model.rules.rules.findIndex((r) => r.id === ruleId || r.name === name);
10924
+ if (existingIndex >= 0) {
10925
+ model.rules.rules[existingIndex] = ruleData;
10926
+ } else {
10927
+ model.rules.rules.push(ruleData);
10928
+ }
10929
+ await context.db.latticeModels.update({
10930
+ id: modelId,
10931
+ data: model.data,
10932
+ rules: model.rules,
10933
+ updatedAt: /* @__PURE__ */ new Date()
10934
+ });
10935
+ context.logger.info(`[Lattice] Created rule ${ruleId} in model ${modelId}`);
10936
+ } else {
10937
+ context.logger.warn(`[Lattice] Model ${modelId} not found in database`);
10938
+ }
10939
+ } catch (error) {
10940
+ context.logger.error(`[Lattice] Failed to persist rule to database:`, error);
10941
+ }
10942
+ }
10943
+ return JSON.stringify({
10944
+ success: true,
10945
+ action: "CREATE_RULE",
10946
+ modelId,
10947
+ ruleId,
10948
+ data: {
10949
+ name,
10950
+ description,
10951
+ formula,
10952
+ parsed: parsedRule,
10953
+ outputEntityCreated: entityCreatedMessage !== ""
10954
+ },
10955
+ message: `Created rule "${name}": ${formula}.${entityCreatedMessage}`
10956
+ });
10957
+ },
10958
+ toolSchema: {
10959
+ name: "lattice_create_rule",
10960
+ description: `Create a formula or calculation rule in a Lattice model.
10961
+
10962
+ **When to use:** When the user defines a calculation:
10963
+ - "Gross profit equals revenue minus COGS"
10964
+ - "Net margin is net income divided by revenue times 100"
10965
+ - "Total expenses is the sum of all expense line items"
10966
+
10967
+ **IMPORTANT: For per-period calculations like "calculate X for each quarter", you MUST call this tool ONCE for EACH period.** For example, if asked to "calculate gross margin for each quarter", call this tool 4 times:
10968
+ 1. lattice_create_rule with formula "Q1 Gross Margin = Q1 Revenue - Q1 COGS"
10969
+ 2. lattice_create_rule with formula "Q2 Gross Margin = Q2 Revenue - Q2 COGS"
10970
+ 3. lattice_create_rule with formula "Q3 Gross Margin = Q3 Revenue - Q3 COGS"
10971
+ 4. lattice_create_rule with formula "Q4 Gross Margin = Q4 Revenue - Q4 COGS"
10972
+
10973
+ **Formula syntax (natural language):**
10974
+ - Arithmetic: "X equals Y plus Z", "A minus B", "C times D"
10975
+ - Aggregation: "sum of", "average of", "total"
10976
+ - Percentage: "X percent of Y", "as a percentage"
10977
+ - Comparison: "if X is greater than Y then A else B"
10978
+
10979
+ **Examples:**
10980
+ - "Gross Profit = Revenue - COGS"
10981
+ - "Gross Margin = Gross Profit / Revenue * 100"
10982
+ - "Total OpEx = sum of all Operating Expenses"
10983
+ - "YoY Growth = (Current Year - Prior Year) / Prior Year * 100"
10984
+ - "Q1 Gross Margin = Q1 Revenue - Q1 COGS" (per-period)`,
10985
+ parameters: {
10986
+ type: "object",
10987
+ properties: {
10988
+ modelId: {
10989
+ type: "string",
10990
+ description: "ID of the model"
10991
+ },
10992
+ name: {
10993
+ type: "string",
10994
+ description: 'Name for this rule (e.g., "Gross Profit Calculation")'
10995
+ },
10996
+ description: {
10997
+ type: "string",
10998
+ description: "Optional description of what this rule calculates"
10999
+ },
11000
+ formula: {
11001
+ type: "string",
11002
+ description: "The formula in natural language or equation format"
11003
+ }
11004
+ },
11005
+ required: ["modelId", "name", "formula"]
11006
+ }
11007
+ }
11008
+ })
11009
+ };
11010
+ var latticeQueryTool = {
11011
+ name: "lattice_query",
11012
+ implementation: () => ({
11013
+ toolFn: async (params) => {
11014
+ const { modelId, query } = params;
11015
+ const parsedQuery = parseQuery(query);
11016
+ return JSON.stringify({
11017
+ success: true,
11018
+ action: "QUERY",
11019
+ modelId,
11020
+ data: {
11021
+ query,
11022
+ parsed: parsedQuery
11023
+ },
11024
+ message: `Querying model for: ${query}`
11025
+ });
11026
+ },
11027
+ toolSchema: {
11028
+ name: "lattice_query",
11029
+ description: `Query a Lattice model for specific values or aggregations.
11030
+
11031
+ **When to use:** When the user asks about values in the model:
11032
+ - "What's Q1 gross margin?"
11033
+ - "Show me total revenue for 2024"
11034
+ - "What are all the expense categories?"
11035
+ - "Compare Q1 vs Q2 performance"
11036
+
11037
+ **Query types:**
11038
+ - Single value: "What is [entity] for [period]?"
11039
+ - Aggregation: "Total [entity] for [range]"
11040
+ - Comparison: "Compare [entity] across [periods]"
11041
+ - List: "Show all [entity type]"
11042
+
11043
+ **Examples:**
11044
+ - "What's Q2 revenue?" \u2192 Returns specific value
11045
+ - "Total revenue for 2024" \u2192 Sums Q1-Q4
11046
+ - "Compare gross margin Q1 vs Q2" \u2192 Side-by-side comparison`,
11047
+ parameters: {
11048
+ type: "object",
11049
+ properties: {
11050
+ modelId: {
11051
+ type: "string",
11052
+ description: "ID of the model to query"
11053
+ },
11054
+ query: {
11055
+ type: "string",
11056
+ description: "Natural language query about the model"
11057
+ }
11058
+ },
11059
+ required: ["modelId", "query"]
11060
+ }
11061
+ }
11062
+ })
11063
+ };
11064
+ var latticeExplainTool = {
11065
+ name: "lattice_explain",
11066
+ implementation: () => ({
11067
+ toolFn: async (params) => {
11068
+ const { modelId, entityName, attributeKey } = params;
11069
+ return JSON.stringify({
11070
+ success: true,
11071
+ action: "EXPLAIN",
11072
+ modelId,
11073
+ data: {
11074
+ entityName,
11075
+ attributeKey
11076
+ },
11077
+ message: `Explaining calculation for ${entityName}.${attributeKey}`
11078
+ });
11079
+ },
11080
+ toolSchema: {
11081
+ name: "lattice_explain",
11082
+ description: `Explain how a value in a Lattice model was calculated.
11083
+
11084
+ **When to use:** When the user wants to understand a calculation:
11085
+ - "How did you calculate gross profit?"
11086
+ - "Explain the Q2 margin number"
11087
+ - "Show me the formula for total expenses"
11088
+ - "Why is this number so high?"
11089
+
11090
+ This tool traces the calculation chain from the target value back through all its inputs and rules, providing a step-by-step explanation.`,
11091
+ parameters: {
11092
+ type: "object",
11093
+ properties: {
11094
+ modelId: {
11095
+ type: "string",
11096
+ description: "ID of the model"
11097
+ },
11098
+ entityName: {
11099
+ type: "string",
11100
+ description: "Name of the entity containing the value to explain"
11101
+ },
11102
+ attributeKey: {
11103
+ type: "string",
11104
+ description: "Period or attribute key of the value to explain"
11105
+ }
11106
+ },
11107
+ required: ["modelId", "entityName", "attributeKey"]
11108
+ }
11109
+ }
11110
+ })
11111
+ };
11112
+ function parseFormula(formula) {
11113
+ const normalized = formula.toLowerCase().trim();
11114
+ const equalsMatch = normalized.match(/^(.+?)\s*(?:=|equals?)\s*(.+)$/i);
11115
+ if (equalsMatch) {
11116
+ const [, output, expression] = equalsMatch;
11117
+ if (expression.includes("+") || expression.includes("plus")) {
11118
+ return {
11119
+ operation: "ADD",
11120
+ outputEntity: output,
11121
+ inputs: expression.split(/[+]|plus/i).map((s) => s.trim())
11122
+ };
11123
+ }
11124
+ if (expression.includes("-") || expression.includes("minus")) {
11125
+ return {
11126
+ operation: "SUBTRACT",
11127
+ outputEntity: output,
11128
+ inputs: expression.split(/[-]|minus/i).map((s) => s.trim())
11129
+ };
11130
+ }
11131
+ if (expression.includes("*") || expression.includes("times") || expression.includes("x")) {
11132
+ return {
11133
+ operation: "MULTIPLY",
11134
+ outputEntity: output,
11135
+ inputs: expression.split(/[*x]|times/i).map((s) => s.trim())
11136
+ };
11137
+ }
11138
+ if (expression.includes("/") || expression.includes("divided")) {
11139
+ return {
11140
+ operation: "DIVIDE",
11141
+ outputEntity: output,
11142
+ inputs: expression.split(/[/]|divided by/i).map((s) => s.trim())
11143
+ };
11144
+ }
11145
+ if (expression.includes("sum")) {
11146
+ return {
11147
+ operation: "SUM",
11148
+ outputEntity: output,
11149
+ inputs: [expression.replace(/sum of/i, "").trim()]
11150
+ };
11151
+ }
11152
+ }
11153
+ return {
11154
+ operation: "REFERENCE",
11155
+ outputEntity: "unknown",
11156
+ inputs: [formula]
11157
+ };
11158
+ }
11159
+ function parseQuery(query) {
11160
+ const normalized = query.toLowerCase();
11161
+ let type = "single_value";
11162
+ if (normalized.includes("total") || normalized.includes("sum")) {
11163
+ type = "aggregation";
11164
+ } else if (normalized.includes("compare") || normalized.includes("vs")) {
11165
+ type = "comparison";
11166
+ } else if (normalized.includes("list") || normalized.includes("show all")) {
11167
+ type = "list";
11168
+ }
11169
+ const entities = [];
11170
+ const periods = [];
11171
+ const periodPatterns = [/q[1-4]/gi, /\d{4}/g, /jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/gi];
11172
+ for (const pattern of periodPatterns) {
11173
+ const matches = query.match(pattern);
11174
+ if (matches) {
11175
+ periods.push(...matches);
11176
+ }
11177
+ }
11178
+ const commonEntities = ["revenue", "expenses", "profit", "margin", "income", "cost", "cogs", "ebitda"];
11179
+ for (const entity of commonEntities) {
11180
+ if (normalized.includes(entity)) {
11181
+ entities.push(entity);
11182
+ }
11183
+ }
11184
+ return { type, entities, periods };
11185
+ }
11186
+
10367
11187
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/editLocalFile/index.js
10368
11188
  import { promises as fs11 } from "fs";
10369
11189
  import { existsSync as existsSync6 } from "fs";
@@ -10835,7 +11655,14 @@ var cliOnlyTools = {
10835
11655
  // Shell execution
10836
11656
  bash_execute: bashExecuteTool,
10837
11657
  // Git operations
10838
- recent_changes: recentChangesTool
11658
+ recent_changes: recentChangesTool,
11659
+ // Lattice financial modeling tools
11660
+ lattice_create_model: latticeCreateModelTool,
11661
+ lattice_add_entity: latticeAddEntityTool,
11662
+ lattice_set_value: latticeSetValueTool,
11663
+ lattice_create_rule: latticeCreateRuleTool,
11664
+ lattice_query: latticeQueryTool,
11665
+ lattice_explain: latticeExplainTool
10839
11666
  };
10840
11667
  var generateTools = (userId, user, logger2, { db }, storage, imageGenerateStorage, statusUpdate, onStart, onFinish, llm, config, model, imageProcessorLambdaName, tools = b4mTools) => {
10841
11668
  const context = {
@@ -10961,6 +11788,7 @@ var QuestStartBodySchema = z139.object({
10961
11788
  enableMementos: z139.boolean().optional(),
10962
11789
  enableArtifacts: z139.boolean().optional(),
10963
11790
  enableAgents: z139.boolean().optional(),
11791
+ enableLattice: z139.boolean().optional(),
10964
11792
  promptMeta: PromptMetaZodSchema,
10965
11793
  tools: z139.array(z139.union([b4mLLMTools, z139.string()])).optional(),
10966
11794
  mcpServers: z139.array(z139.string()).optional(),
@@ -13807,7 +14635,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
13807
14635
  // package.json
13808
14636
  var package_default = {
13809
14637
  name: "@bike4mind/cli",
13810
- version: "0.2.29-cli-resume-command.18763+9e3ccc640",
14638
+ version: "0.2.29-feature-b4m-pi.18846+9859d25d9",
13811
14639
  type: "module",
13812
14640
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
13813
14641
  license: "UNLICENSED",
@@ -13915,10 +14743,10 @@ var package_default = {
13915
14743
  },
13916
14744
  devDependencies: {
13917
14745
  "@bike4mind/agents": "0.1.0",
13918
- "@bike4mind/common": "2.50.1-cli-resume-command.18763+9e3ccc640",
13919
- "@bike4mind/mcp": "1.29.1-cli-resume-command.18763+9e3ccc640",
13920
- "@bike4mind/services": "2.48.1-cli-resume-command.18763+9e3ccc640",
13921
- "@bike4mind/utils": "2.5.1-cli-resume-command.18763+9e3ccc640",
14746
+ "@bike4mind/common": "2.50.1-feature-b4m-pi.18846+9859d25d9",
14747
+ "@bike4mind/mcp": "1.29.1-feature-b4m-pi.18846+9859d25d9",
14748
+ "@bike4mind/services": "2.48.1-feature-b4m-pi.18846+9859d25d9",
14749
+ "@bike4mind/utils": "2.5.1-feature-b4m-pi.18846+9859d25d9",
13922
14750
  "@types/better-sqlite3": "^7.6.13",
13923
14751
  "@types/diff": "^5.0.9",
13924
14752
  "@types/jsonwebtoken": "^9.0.4",
@@ -13935,7 +14763,7 @@ var package_default = {
13935
14763
  optionalDependencies: {
13936
14764
  "@vscode/ripgrep": "^1.17.0"
13937
14765
  },
13938
- gitHead: "9e3ccc640da244f7528fa1a479d00e8b40b415a4"
14766
+ gitHead: "9859d25d9a50e23c155ed70c318a3edfe9573f2a"
13939
14767
  };
13940
14768
 
13941
14769
  // src/config/constants.ts
@@ -16681,7 +17509,7 @@ Available commands:
16681
17509
  /whoami - Show current authenticated user
16682
17510
  /usage - Show credit usage and balance
16683
17511
  /save <name> - Save current session
16684
- /resume - List and resume saved sessions
17512
+ /sessions - List saved sessions
16685
17513
  /config - Show configuration
16686
17514
 
16687
17515
  API Configuration:
@@ -16730,7 +17558,6 @@ Custom Commands:
16730
17558
  console.log(`\u2705 Session saved as "${sessionName}"`);
16731
17559
  break;
16732
17560
  }
16733
- case "resume":
16734
17561
  case "sessions": {
16735
17562
  const sessions = await state.sessionStore.list(20);
16736
17563
  if (sessions.length === 0) {