solidb 1.0.1

A lightweight, high-performance structured database server written in Rust.
pub const MANAGED_AGENT_TEMPLATE: &str = r#"
-- Managed Agent: {{AGENT_NAME}}
-- Auto-generated by SoliDB

local AGENT_NAME = "{{AGENT_NAME}}"
local AGENT_TYPE = "{{AGENT_TYPE}}"
local AGENT_CAPS = {{AGENT_CAPS}}
local AGENT_KEY = "{{AGENT_KEY}}" -- Internal reference to agent document

-- Configuration
local LLM_API_URL = solidb.env.{{ENV_URL_KEY}}
local LLM_API_KEY = solidb.env.{{ENV_API_KEY}}

if not LLM_API_URL then error("LLM_API_URL not found in env: " .. "{{ENV_URL_KEY}}") end
if not LLM_API_KEY then error("LLM_API_KEY not found in env: " .. "{{ENV_API_KEY}}") end

-- Helper to call LLM
function ask_llm(user_prompt)
    local body = solidb.json_encode({
        model = "gpt-4o", -- Default model, can be adjusted
        messages = {
            { role = "user", content = user_prompt }
        }
    })

    print("🤖 " .. AGENT_NAME .. " calling AI Provider...")
    local response = solidb.fetch(LLM_API_URL, {
        method = "POST",
        headers = {
            ["Authorization"] = "Bearer " .. LLM_API_KEY,
            ["x-api-key"] = LLM_API_KEY, -- Redundant but covers Anthropic/others
            ["api-key"] = LLM_API_KEY, -- Azure
            ["content-type"] = "application/json"
        },
        body = body
    })

    if not response.ok then
        return nil, "API Error " .. response.status .. ": " .. response.body
    end

    local data = solidb.json_decode(response.body)

    -- Attempt to parse response from common formats
    if data.choices and data.choices[1] and data.choices[1].message then
        return data.choices[1].message.content -- OpenAI format
    elseif data.content and data.content[1] and data.content[1].text then
        return data.content[1].text -- Anthropic format
    elseif data.response then
        return data.response -- Ollama format
    else
        return solidb.json_encode(data) -- Fallback
    end
end

-- Main Loop
function run_agent_loop()
    print("🚀 Starting Managed Agent: " .. AGENT_NAME)

    -- Ensure agent is registered/active
    -- We assume the agent is already registered via the UI, but we can re-register to ensure caps
    local agent = solidb.ai.register_agent(AGENT_NAME, AGENT_TYPE, AGENT_CAPS)
    local agent_id = agent.id or agent._key

    local processed = 0
    local MAX_ITERATIONS = 50 -- Safety limit for one run execution

    for i = 1, MAX_ITERATIONS do
        solidb.ai.heartbeat(agent_id)

        local tasks = solidb.ai.get_pending_tasks({
            limit = 1,
            agent_type = AGENT_TYPE
        })

        if #tasks > 0 then
            local task = tasks[1]
            print("📥 " .. AGENT_NAME .. " found task: " .. task._key)

            if solidb.ai.claim_task(task._key, agent_id) then
                local prompt = "Please fulfill this request:\n\n" .. (task.data.description or "No description")

                local result, err = ask_llm(prompt)

                if result then
                    solidb.ai.complete_task(task._key, {
                        result = result,
                        agent = AGENT_NAME
                    })
                    print("✅ Task completed")
                    processed = processed + 1
                else
                    print("❌ Task failed: " .. tostring(err))
                    solidb.ai.fail_task(task._key, err or "Unknown error")
                end
            end
        else
            -- If running in a loop, sleep. If invoked via cron/event, maybe just exit.
            -- For this template, we'll exit if no tasks to avoid long-running processes blocking threads if not async
            print("💤 No tasks. Exiting loop.")
            break
        end
    end

    return "Agent " .. AGENT_NAME .. " processed " .. processed .. " tasks."
end
"#;