{
  "description": "Mibo Trace Sender — Custom JS Function for Flowise that posts canonical Custom API traces to Mibo. Drop this into any chatflow or agentflow after your final answer node.",
  "framework": ["Langchain"],
  "usecases": ["Observability"],
  "nodes": [
    {
      "id": "customFunction_mibo_trace_sender",
      "position": { "x": 600, "y": 240 },
      "type": "customNode",
      "data": {
        "id": "customFunction_mibo_trace_sender",
        "label": "Mibo Trace Sender",
        "version": 3,
        "name": "customFunction",
        "type": "CustomFunction",
        "baseClasses": ["CustomFunction", "Utilities"],
        "category": "Utilities",
        "description": "Posts the chatflow's final response to Mibo as a canonical Custom API trace. Identity flows via the x-request-id header. Add extra spans by populating $flow.state.miboSpans before this node runs.",
        "inputParams": [
          {
            "label": "Input Variables",
            "name": "functionInputVariables",
            "description": "Input variables can be used in the function with prefix $. For example: $miboApiKey",
            "type": "json",
            "optional": true,
            "acceptVariable": true,
            "list": true
          },
          {
            "label": "Javascript Function",
            "name": "javascriptFunction",
            "type": "code",
            "default": "const API_KEY = $vars.MIBO_API_KEY;\nconst MIBO_URL = $vars.MIBO_TRACES_URL || 'https://api.mibo-ai.com/public/traces';\n\nif (!API_KEY) {\n  return $input;\n}\n\nconst now = BigInt(Date.now()) * 1000000n;\nconst startNano = ($flow.state && $flow.state.miboStartNano)\n  ? BigInt($flow.state.miboStartNano)\n  : now;\n\nconst rid = () => {\n  if (typeof crypto !== 'undefined' && crypto.randomUUID) return crypto.randomUUID();\n  return 'span-' + Math.random().toString(36).slice(2, 18);\n};\n\nconst responseText = (typeof $input === 'string')\n  ? $input\n  : ($input && typeof $input === 'object' && typeof $input.text === 'string')\n    ? $input.text\n    : JSON.stringify($input);\n\nconst rootSpan = {\n  span_id: rid(),\n  parent_span_id: null,\n  name: $flow.chatflowName || 'Chatflow',\n  start_time_unix_nano: startNano.toString(),\n  end_time_unix_nano: now.toString(),\n  attributes: {\n    'gen_ai.response.text': responseText,\n    'gen_ai.output.messages': [{ role: 'assistant', parts: [{ type: 'text', content: responseText }] }],\n    'flowise.component.type': 'chatflow',\n    'flowise.component.status': 'success',\n    'flowise.chatflow.id': $flow.chatflowId,\n    'flowise.session.id': $flow.sessionId\n  },\n  status: { code: 1 }\n};\n\nconst extraSpans = Array.isArray($flow.state && $flow.state.miboSpans)\n  ? $flow.state.miboSpans.map(s => ({\n      span_id: s.span_id || rid(),\n      parent_span_id: s.parent_span_id || rootSpan.span_id,\n      name: s.name,\n      start_time_unix_nano: s.start_time_unix_nano,\n      end_time_unix_nano: s.end_time_unix_nano,\n      attributes: s.attributes || {},\n      status: s.status || { code: 1 }\n    }))\n  : [];\n\nconst payload = {\n  spans: [rootSpan, ...extraSpans],\n  metadata: {\n    chatflowId: $flow.chatflowId,\n    sessionId: $flow.sessionId,\n    chatId: $flow.chatId\n  }\n};\n\nconst headers = {\n  'Content-Type': 'application/json',\n  'x-api-key': API_KEY,\n  'x-request-id': $flow.chatId || $flow.sessionId || rid()\n};\n\ntry {\n  await fetch(MIBO_URL, {\n    method: 'POST',\n    headers,\n    body: JSON.stringify(payload)\n  });\n} catch (e) {\n  console.warn('[mibo] trace POST failed:', e && e.message);\n}\n\nreturn $input;\n"
          }
        ],
        "inputAnchors": [],
        "inputs": {
          "functionInputVariables": "",
          "javascriptFunction": ""
        },
        "outputAnchors": [
          {
            "id": "customFunction_mibo_trace_sender-output-customFunction-CustomFunction|Utilities",
            "name": "customFunction",
            "label": "Output",
            "type": "CustomFunction | Utilities"
          }
        ],
        "outputs": {},
        "selected": false
      },
      "width": 340,
      "height": 520,
      "selected": false,
      "dragging": false
    }
  ],
  "edges": []
}
