importBundle method

Future<BundleImportSummary> importBundle(
  1. McpBundle bundle, {
  2. String workspaceId = 'default',
})

Import the two FlowBrain-owned operational sections from a loaded mcp_bundle. Other knowledge sections (skill / profile / fact / knowledge) are imported by OpsFacade.loadBundle on ops; callers typically invoke that first, then this method, when wiring a bundle into a live system.

  • bundle.philosophy → each Philosophy becomes an EthosRecord on ethosStore (when wired). Activation policy is left to the host — entries land inactive.
  • bundle.agents → each AgentDefinition is registered on the Agent Subsystem registry under workspaceId. The four-axis bindings (profileIds / skillIds / factSourceIds / philosophyIds) are preserved on Agent.tags as comma-separated id lists under bind.<axis>Ids keys, so downstream tools can resolve them at instantiation time.

No-op for missing sections / missing infra (silent skip). Returns a summary with counts for diagnostics. Duplicate agent ids inside a workspace are skipped (no throw) so re-import is idempotent.

Implementation

Future<BundleImportSummary> importBundle(
  mb.McpBundle bundle, {
  String workspaceId = 'default',
}) async {
  var philosophiesAdded = 0;
  var agentsAdded = 0;
  var agentsSkipped = 0;

  final philosophy = bundle.philosophy;
  final store = _infraPorts.ethosStore;
  if (philosophy != null && store != null) {
    for (final p in philosophy.philosophies) {
      await store.putEthos(mb.EthosRecord(
        id: p.id,
        name: p.name,
        version: '1.0.0',
        payload: p.toJson(),
        createdAt: DateTime.now().toUtc(),
        active: false,
      ));
      philosophiesAdded++;
    }
  }

  final agentsSection = bundle.agents;
  final registry = _agentRegistry;
  if (agentsSection != null && registry != null) {
    for (final def in agentsSection.agents) {
      final role = _parseAgentRole(def.role);
      final cfg = def.model;
      final model = cfg != null
          ? ModelSpec(
              provider: cfg.provider ?? 'unknown',
              model: cfg.model ?? 'unknown',
              maxTokens: cfg.maxTokens,
              temperature: cfg.temperature,
            )
          : ModelSpec.stub();
      final tags = <String, String>{
        if (def.profileIds.isNotEmpty)
          'bind.profileIds': def.profileIds.join(','),
        if (def.skillIds.isNotEmpty)
          'bind.skillIds': def.skillIds.join(','),
        if (def.factSourceIds.isNotEmpty)
          'bind.factSourceIds': def.factSourceIds.join(','),
        if (def.philosophyIds.isNotEmpty)
          'bind.philosophyIds': def.philosophyIds.join(','),
      };
      try {
        await registry.create(
          id: def.id,
          displayName: def.name,
          role: role,
          model: model,
          workspaceId: workspaceId,
          systemPrompt: def.systemPrompt,
          tags: tags,
        );
        agentsAdded++;
      } on StateError {
        // Duplicate id under the same workspace — re-import idempotent.
        agentsSkipped++;
      }
    }
  }

  return BundleImportSummary(
    philosophiesAdded: philosophiesAdded,
    agentsAdded: agentsAdded,
    agentsSkipped: agentsSkipped,
  );
}