OpenClaw for HIX

136 views
Skip to first unread message

antonio....@gmail.com

unread,
Feb 19, 2026, 2:12:36 PM (2 days ago) Feb 19
to Harbour Users
For those of you that want to have an OpenClaw built with Harbour using HIX:

HIX:

chat.prg
function main()
    local cHtml := ""
   
    cHtml += "<!DOCTYPE html>"
    cHtml += "<html lang='es'>"
    cHtml += "<head>"
    cHtml += "    <meta charset='UTF-8'>"
    cHtml += "    <meta name='viewport' content='width=device-width, initial-scale=1.0'>"
    cHtml += "    <title>AIOS 1.0</title>"
    cHtml += "    <link href='https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600&family=JetBrains+Mono&display=swap' rel='stylesheet'>"
    cHtml += "    <style>"
    cHtml += "        :root {"
    cHtml += "            --bg: #0a0b10;"
    cHtml += "            --glass: rgba(255, 255, 255, 0.05);"
    cHtml += "            --glass-border: rgba(255, 255, 255, 0.1);"
    cHtml += "            --accent: linear-gradient(135deg, #6366f1, #a855f7);"
    cHtml += "            --text: #e2e8f0;"
    cHtml += "            --bot-bubble: rgba(30, 41, 59, 0.7);"
    cHtml += "            --user-bubble: linear-gradient(135deg, #4f46e5, #7c3aed);"
    cHtml += "        }"
    cHtml += "        * { margin:0; padding:0; box-sizing: border-box; }"
    cHtml += "        body {"
    cHtml += "            font-family: 'Outfit', sans-serif;"
    cHtml += "            background: var(--bg);"
    cHtml += "            background-image: radial-gradient(circle at 20% 20%, rgba(99, 102, 241, 0.15) 0%, transparent 40%),"
    cHtml += "                              radial-gradient(circle at 80% 80%, rgba(168, 85, 247, 0.15) 0%, transparent 40%);"
    cHtml += "            color: var(--text);"
    cHtml += "            height: 100vh;"
    cHtml += "            display: flex;"
    cHtml += "            flex-direction: column;"
    cHtml += "            overflow: hidden;"
    cHtml += "        }"
    cHtml += "        header {"
    cHtml += "            padding: 1.5rem 2rem;"
    cHtml += "            background: var(--glass);"
    cHtml += "            backdrop-filter: blur(10px);"
    cHtml += "            border-bottom: 1px solid var(--glass-border);"
    cHtml += "            display: flex;"
    cHtml += "            justify-content: space-between;"
    cHtml += "            align-items: center;"
    cHtml += "            z-index: 10;"
    cHtml += "        }"
    cHtml += "        header h1 { font-size: 1.5rem; font-weight: 600; letter-spacing: -0.5px; }"
    cHtml += "        .version-badge { background: var(--accent); padding: 0.2rem 0.6rem; border-radius: 20px; font-size: 0.75rem; font-weight: bold; }"
    cHtml += "        #chat-container {"
    cHtml += "            flex: 1;"
    cHtml += "            overflow-y: auto;"
    cHtml += "            padding: 2rem;"
    cHtml += "            display: flex;"
    cHtml += "            flex-direction: column;"
    cHtml += "            gap: 1.5rem;"
    cHtml += "        }"
    cHtml += "        .message {"
    cHtml += "            max-width: 85%;"
    cHtml += "            padding: 1rem 1.25rem;"
    cHtml += "            border-radius: 1.2rem;"
    cHtml += "            line-height: 1.6;"
    cHtml += "            animation: fadeIn 0.3s ease-out;"
    cHtml += "        }"
    cHtml += "        @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }"
    cHtml += "        .user { align-self: flex-end; background: var(--user-bubble); color: white; border-bottom-right-radius: 0.2rem; }"
    cHtml += "        .bot { align-self: flex-start; background: var(--bot-bubble); backdrop-filter: blur(5px); border: 1px solid var(--glass-border); border-bottom-left-radius: 0.2rem; }"
    cHtml += "        .error { align-self: center; background: rgba(255,0,0,0.2); color: #ff8888; border: 1px solid #ff0000; padding: 0.5rem 1rem; border-radius: 10px; }"
    cHtml += "        pre { background: #1e1e1e; padding: 1rem; border-radius: 8px; overflow-x: auto; font-family: 'JetBrains Mono', monospace; }"
    cHtml += "        .input-wrapper { padding: 2rem; background: linear-gradient(to top, var(--bg), transparent); }"
    cHtml += "        .input-box {"
    cHtml += "            max-width: 900px; margin: 0 auto; background: var(--glass); backdrop-filter: blur(20px); border: 1px solid var(--glass-border);"
    cHtml += "            border-radius: 1.5rem; padding: 0.5rem; display: flex; align-items: center; gap: 0.5rem;"
    cHtml += "        }"
    cHtml += "        input { flex: 1; background: transparent; border: none; color: white; padding: 0.75rem 1rem; font-size: 1rem; outline: none; }"
    cHtml += "        button { background: var(--accent); border: none; color: white; padding: 0.75rem 1.5rem; border-radius: 1.1rem; font-weight: 600; cursor: pointer; }"
    cHtml += "        button:disabled { background: #444; }"
    cHtml += "        .typing { display: flex; gap: 4px; padding: 10px; }"
    cHtml += "        .dot { width: 8px; height: 8px; background: #6366f1; border-radius: 50%; animation: bounce 1.4s infinite ease-in-out; }"
    cHtml += "        @keyframes bounce { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } }"
    cHtml += "    </style>"
    cHtml += "</head>"
    cHtml += "<body>"
    cHtml += "<header>"
    cHtml += "    <h1>AIOS</h1>"
    cHtml += "    <button onclick='clearChat()'>Limpiar</button>"
    cHtml += "</header>"
    cHtml += "<div id='chat-container'></div>"
    cHtml += "<div class='input-wrapper'>"
    cHtml += "    <div class='input-box'>"
    cHtml += "        <input type='text' id='input' placeholder='Pregunta algo...' onkeydown='if(event.keyCode===13) sendMessage()'>"
    cHtml += "        <button id='send-btn' onclick='sendMessage()'>Enviar</button>"
    cHtml += "    </div>"
    cHtml += "</div>"
    cHtml += "<script>"
    cHtml += "    window.onerror = function(m, u, l) { alert('Error: ' + m + ' en ' + l); };"
    cHtml += "    var history_data = [];"
    cHtml += "    function addMessage(role, text) {"
    cHtml += "        var container = document.getElementById('chat-container');"
    cHtml += "        var div = document.createElement('div');"
    cHtml += "        div.className = 'message ' + role;"
    cHtml += "        div.innerHTML = text.split('\\n').join('<br>');"
    cHtml += "        container.appendChild(div);"
    cHtml += "        setTimeout(function() { container.scrollTop = container.scrollHeight; }, 50);"
    cHtml += "    }"
    cHtml += "    function addTyping() {"
    cHtml += "        var container = document.getElementById('chat-container');"
    cHtml += "        var div = document.createElement('div');"
    cHtml += "        div.id = 'typing-indicator';"
    cHtml += "        div.className = 'message bot typing';"
    cHtml += "        div.innerHTML = '⚙️ Pensando...';"
    cHtml += "        container.appendChild(div);"
    cHtml += "        container.scrollTop = container.scrollHeight;"
    cHtml += "    }"
    cHtml += "    function removeTyping() {"
    cHtml += "        var indicator = document.getElementById('typing-indicator');"
    cHtml += "        if(indicator) indicator.parentNode.removeChild(indicator);"
    cHtml += "    }"
    cHtml += "    function sendMessage() {"
    cHtml += "        var input = document.getElementById('input');"
    cHtml += "        var text = input.value.trim();"
    cHtml += "        var btn = document.getElementById('send-btn');"
    cHtml += "        if (!text) return;"
    cHtml += "        addMessage('user', text);"
    cHtml += "        input.value = '';"
    cHtml += "        addTyping();"
    cHtml += "        btn.disabled = true;"
    cHtml += "        var params = 'query=' + encodeURIComponent(text);"
    cHtml += "        if (history_data.length > 0) params += '&history=' + encodeURIComponent(JSON.stringify(history_data));"
    cHtml += "        console.log('SENDING:', params);"
    cHtml += "        var xhr = new XMLHttpRequest();"
    cHtml += "        xhr.open('POST', 'aios.prg', true);"
    cHtml += "        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');"
    cHtml += "        xhr.onreadystatechange = function() {"
    cHtml += "            if (xhr.status !== 200 && xhr.status !== 0) { addMessage('error', 'Status: ' + xhr.status); }"
    cHtml += "            if (xhr.readyState == 4) {"
    cHtml += "                removeTyping(); btn.disabled = false;"
    cHtml += "                if (xhr.status == 200) {"
    cHtml += "                    try {"
    cHtml += "                        var data = JSON.parse(xhr.responseText);"
    cHtml += "                        if (data.success) {"
    cHtml += "                            addMessage('bot', data.text);"
    cHtml += "                            history_data.push({role:'user', parts:[{text:text}]});"
    cHtml += "                            history_data.push({role:'model', parts:[{text:data.text}]});"
    cHtml += "                        } else { addMessage('error', 'Error: ' + data.error); }"
    cHtml += "                    } catch(e) { addMessage('error', 'JSON Error: ' + xhr.responseText.substring(0,100)); }"
    cHtml += "                } else if(xhr.status !== 0) { addMessage('error', 'Server Error: ' + xhr.status); }"
    cHtml += "            }"
    cHtml += "        };"
    cHtml += "        xhr.send(params);"
    cHtml += "    }"
    cHtml += "    function clearChat() {"
    cHtml += "        document.getElementById('chat-container').innerHTML = '';"
    cHtml += "        history_data = [];"
    cHtml += "    }"
    cHtml += "</script>"
    cHtml += "</body></html>"
   
    UWrite(cHtml)
return ""


antonio....@gmail.com

unread,
Feb 19, 2026, 2:13:50 PM (2 days ago) Feb 19
to Harbour Users
aios.prg
#include "hbcurl.ch"

function main()
    local cQuery, cModel, cHistory, cSystemPrompt := "", cJsonRes
    local hResult := { "success" => .f. }, oErr, cOldMem, cSep, cMemPath, cBaseDir
   
    cBaseDir := hb_DirBase()
    cSep := "\" ; if !("\" $ cBaseDir) ; cSep := "/" ; endif
   
    cQuery   := UGet("query")
    cModel   := UGet("model")
    cHistory := UGet("history")
   
    if Empty(cQuery)   ; cQuery   := UPost("query")   ; endif
    if Empty(cModel)   ; cModel   := UPost("model")   ; endif
    if Empty(cHistory) ; cHistory := UPost("history") ; endif
   
    // Clean data
    if !Empty(cHistory) .and. "%" $ hb_ValToStr(cHistory) ; cHistory := Hix_UrlDecode(hb_ValToStr(cHistory)) ; endif
    if !Empty(cQuery)   .and. "%" $ hb_ValToStr(cQuery)   ; cQuery   := Hix_UrlDecode(hb_ValToStr(cQuery))   ; endif
   
    if cQuery == "ping" ; UWrite('{"success":true, "text":"pong"}') ; return "" ; endif
    if Empty(cQuery)   ; UWrite('{"success":false, "error":"No query provided"}') ; return "" ; endif

    cJsonRes := '{"success":false, "error":"Fatal Crash"}'

    BEGIN SEQUENCE WITH {|e| break(e)}
    if Empty(cModel) ; cModel := "gemini-2.0-flash" ; endif
       
    // System Prompt - FORCED PERSONALITY
    cSystemPrompt := "ERES HIX AIOS v1.7. ASISTENTE AVANZADO." + (Chr(13)+Chr(10))
    cSystemPrompt += "TIENES ACCESO A MEMORIA PERSISTENTE QUE SE TE PROPORCIONA A CONTINUACIÓN." + (Chr(13)+Chr(10))
    cSystemPrompt += "PROHIBIDO DECIR QUE NO TIENES MEMORIA." + (Chr(13)+Chr(10))
       
    // Load Identity & Soul
    if File(cBaseDir + "persona" + cSep + "IDENTITY.md")
        cSystemPrompt += "TU IDENTIDAD:" + (Chr(13)+Chr(10)) + hb_MemoRead(cBaseDir + "persona" + cSep + "IDENTITY.md") + (Chr(13)+Chr(10))
    endif
    if File(cBaseDir + "persona" + cSep + "SOUL.md")
        cSystemPrompt += "TU ALMA:" + (Chr(13)+Chr(10)) + hb_MemoRead(cBaseDir + "persona" + cSep + "SOUL.md") + (Chr(13)+Chr(10))
    endif
       
    // Load Memory (Last 8000 chars)
    cMemPath := cBaseDir + "persona" + cSep + "MEMORY.md"
    if File(cMemPath)
        cOldMem := hb_MemoRead(cMemPath)
        cSystemPrompt += "HISTORIAL DE CONVERSACIONES (MEMORIA):" + (Chr(13)+Chr(10)) + Right(cOldMem, 8000) + (Chr(13)+Chr(10))
    endif
       
    cSystemPrompt += "Si necesitas un chat_id para Telegram, BÚSCALO EN EL HISTORIAL ARRIBA." + (Chr(13)+Chr(10))
       
    LogTrace("REQ: " + cQuery + " | PromptLen: " + AllTrim(Str(Len(cSystemPrompt))))
       
    hResult := ExecuteReasoningLoop(cQuery, cModel, hb_ValToStr(cHistory), cSystemPrompt)
       
    // Save to Memory
    if ValType(hResult) == "H" .and. hb_HGetDef(hResult, 'success', .f.)
        if !hb_DirExists(cBaseDir + "persona") ; hb_DirCreate(cBaseDir + "persona") ; endif
            cOldMem := "" ; if File(cMemPath) ; cOldMem := hb_MemoRead(cMemPath) ; endif
            hb_MemoWrit(cMemPath, cOldMem + "[" + Time() + "] User: " + cQuery + (Chr(13)+Chr(10)) + "HIX: " + hb_ValToStr(hResult['text']) + (Chr(13)+Chr(10)) + (Chr(13)+Chr(10)))
        endif
       
        hResult["v"] := "1.7"
        cJsonRes := hb_jsonEncode(hResult)
       
        RECOVER USING oErr
        cJsonRes := '{"success":false, "error":"RTE: ' + hb_ValToStr(oErr:Description) + '", "v":"1.7-err"}'
    END
   
    UWrite(cJsonRes)
return ""

function LogTrace(cMsg)
    local nH
    nH := fOpen("aios_debug.log", 1)
    if nH < 0 ; nH := fCreate("aios_debug.log") ; endif
    if nH > 0
        fSeek(nH, 0, 2)
        fWrite(nH, "[" + DToC(Date()) + " " + Time() + "] v1.7: " + hb_ValToStr(cMsg) + (Chr(13)+Chr(10)))
        fClose(nH)
    endif
return nil

function ExecuteReasoningLoop(cQuery, cModel, cHistory, cSystemPrompt)
    local aFunctions := BuildAiosFunctions()
    local aMessages := {}, nStep := 0, hResult := { "success" => .f. }, hGeminiResult, hSkillResult, hMsg, aResponseParts, hPart, lHasFC
    local cFullText := ""
   
    if !Empty(cHistory) ; hb_jsonDecode(cHistory, @aMessages) ; endif
    if ValType(aMessages) != "A" ; aMessages := {} ; endif
   
    aAdd(aMessages, { "role" => "user", "parts" => { { "text" => cQuery } } })
   
    do while nStep < 10 // Increase steps for safety
        nStep++
        hGeminiResult := GeminiCallFC(aMessages, aFunctions, cModel, cSystemPrompt)
       
        if ValType(hGeminiResult) != "H" .or. !hb_HGetDef(hGeminiResult,"success",.f.)
            if nStep > 1 .and. !Empty(cFullText)
                // If it fails after Turn 1 but we have text, return it
                hResult['success'] := .t. ; hResult['text'] := cFullText ; hResult['model_used'] := cModel ; retu hResult
            endif
            hResult['success'] := .f. ; hResult['error'] := hb_ValToStr(hb_HGetDef(hGeminiResult, "error", "API Fail"))
            LogTrace("LOOP ERR: " + hResult['error'])
            retu hResult
        endif
       
        hMsg := { "role" => "model", "parts" => hGeminiResult["raw_parts"] }
        aAdd(aMessages, hMsg)
       
        // Accumulate text from this turn
        if !Empty(hGeminiResult['text'])
            cFullText += hGeminiResult['text']
        endif

        if hGeminiResult['type'] == "function_call"
            aResponseParts := {}
            for each hPart in hGeminiResult["raw_parts"]
                if ValType(hPart) == "H" .and. hb_HHasKey(hPart, "functionCall")
                    hSkillResult := ExecuteAiosSkill(hPart["functionCall"]["name"], hPart["functionCall"]["args"])
                    aAdd(aResponseParts, { "functionResponse" => { "name" => hPart["functionCall"]["name"], "response" => hSkillResult } } )
                endif
            next
            aAdd(aMessages, { "role" => "function", "parts" => aResponseParts })
        elseif hGeminiResult['type'] == "text"
            hResult['success'] := .t. ; hResult['text'] := cFullText ; hResult['model_used'] := cModel ; retu hResult
        else
            // Type is 'empty' or unknown, but if we have text, we are done
            hResult['success'] := .t. ; hResult['text'] := iif(Empty(cFullText), "OK", cFullText) ; hResult['model_used'] := cModel ; retu hResult
        endif
    enddo
return hResult

function GeminiCallFC(aMessages, aFunctions, cModel, cSystemPrompt)
    local cApiKey := GetAiosApiKey()
    local cUrl, cJson, hCurl, nError, cResponse := "", hResult := { "success" => .f. }
    local hPayload := { "contents" => aMessages, "tools" => { { "function_declarations" => aFunctions } } }
   
    if !Empty(cSystemPrompt) ; hPayload["system_instruction"] := { "parts" => { { "text" => cSystemPrompt } } } ; endif
   
    cUrl := "https://generativelanguage.googleapis.com/v1beta/models/" + cModel + ":generateContent?key=" + cApiKey
    cJson := hb_jsonEncode(hPayload)
   
    hCurl := curl_easy_init()
    if !Empty(hCurl)
    curl_easy_setopt(hCurl, HB_CURLOPT_POST, .T.)
    curl_easy_setopt(hCurl, HB_CURLOPT_URL, cUrl)
    curl_easy_setopt(hCurl, HB_CURLOPT_HTTPHEADER, { "Content-Type: application/json" })
    curl_easy_setopt(hCurl, HB_CURLOPT_SSL_VERIFYPEER, .F.)
    curl_easy_setopt(hCurl, HB_CURLOPT_POSTFIELDS, cJson)
    curl_easy_setopt(hCurl, HB_CURLOPT_DL_BUFF_SETUP)
       
    nError := curl_easy_perform(hCurl)
    if nError == HB_CURLE_OK
        cResponse := curl_easy_dl_buff_get(hCurl)
        LogTrace("RECV: " + Left(cResponse, 500) + " (len: " + AllTrim(Str(Len(cResponse))) + ")")
        hResult := ParseAiosFCResponse(cResponse)
        if !hResult['success'] ; LogTrace("PARSE ERR: " + hb_ValToStr(hResult['error'])) ; endif
        else
            hResult['error'] := "Curl error: " + hb_ValToStr(nError)
            LogTrace("CURL ERR: " + AllTrim(Str(nError)))
        endif
        curl_easy_cleanup(hCurl)
    else
        hResult['error'] := "Curl init failed"
    endif
retu hResult

function ParseAiosFCResponse(cJSON)
    local hResult := { "success" => .f. }, hResponse := {=>}, aParts, nErr := 0, cW, nS, nE, hPart, lHasFC
    cW := AllTrim(StrTran(hb_ValToStr(cJSON), Chr(0), ""))
    nS := At("{", cW) ; nE := RAt("}", cW)
    if nS > 0 .and. nE > nS ; cW := SubStr(cW, nS, nE - nS + 1) ; endif
    if Empty(cW) ; hResult['error'] := "Empty response" ; return hResult ; endif
    nErr := hb_jsonDecode(cW, @hResponse)
    if (nErr == 0 .or. nErr == Len(cW)) .and. ValType(hResponse) == "H"
    if hb_HHasKey(hResponse, "candidates") .and. Len(hResponse["candidates"]) > 0
    aParts := hResponse["candidates"][1]["content"]["parts"]
    hResult['success'] := .t. ; hResult['raw_parts'] := aParts ; lHasFC := .f.
    hResult['text'] := ""
    hResult['type'] := 'unknown'
           
    for each hPart in aParts
        if ValType(hPart) == "H"
            if hb_HHasKey(hPart, "functionCall") ; lHasFC := .t. ; endif
            if hb_HHasKey(hPart, "text") ; hResult['text'] += hPart["text"] ; endif
            endif
        next
           
        if lHasFC
            hResult['type'] := 'function_call'
        elseif !Empty(hResult['text'])
            hResult['type'] := 'text'
        endif
    elseif hb_HHasKey(hResponse, "error")
        hResult['error'] := "API Error: " + hb_ValToStr(hResponse["error"]["message"])
    elseif hb_HHasKey(hResponse, "usageMetadata")
        // Valid response but empty of content (happens after tool turns sometimes)
        hResult['success'] := .t. ; hResult['type'] := 'empty' ; hResult['raw_parts'] := {} ; hResult['text'] := ""
    else
        hResult['error'] := "Invalid API Response Structure"
    endif
    else
    hResult['error'] := "JSON Parse Error (Code: " + AllTrim(Str(nErr)) + ")"
    endif
retu hResult

function BuildAiosFunctions()
    local aFuncs := {}
    aAdd(aFuncs, { "name" => "filesystem_search", "description" => "Search files.", "parameters" => { "type" => "object", "properties" => { "pattern" => { "type" => "string" }, "path" => { "type" => "string" } }, "required" => {"pattern", "path"} } })
    aAdd(aFuncs, { "name" => "identity_get_context", "description" => "Identity info.", "parameters" => { "type" => "object", "properties" => {=>}, "required" => {} } })
    aAdd(aFuncs, { "name" => "telegram_send_message", "description" => "Send Telegram Msg.", "parameters" => { "type" => "object", "properties" => { "chat_id" => { "type" => "string" }, "text" => { "type" => "string" } }, "required" => {"chat_id", "text"} } })
    aAdd(aFuncs, { "name" => "telegram_get_updates", "description" => "Read incoming Telegram messages.", "parameters" => { "type" => "object", "properties" => {=>}, "required" => {} } })
    aAdd(aFuncs, { "name" => "config_set", "description" => "Save key-value pair.", "parameters" => { "type" => "object", "properties" => { "key" => { "type" => "string" }, "value" => { "type" => "string" } }, "required" => {"key", "value"} } })
    aAdd(aFuncs, { "name" => "config_get", "description" => "Get saved info.", "parameters" => { "type" => "object", "properties" => { "key" => { "type" => "string", "description" => "Optional key" } }, "required" => {} } })
    aAdd(aFuncs, { "name" => "memory_summarize", "description" => "Optimize/Summarize conversation history.", "parameters" => { "type" => "object", "properties" => { "summary" => { "type" => "string" } }, "required" => {"summary"} } })
    aAdd(aFuncs, { "name" => "filesystem_get_datetime", "description" => "Get current date, time and day of week.", "parameters" => { "type" => "object", "properties" => {=>}, "required" => {} } })
    aAdd(aFuncs, { "name" => "identity_update", "description" => "Update IDENTITY.md content.", "parameters" => { "type" => "object", "properties" => { "content" => { "type" => "string" } }, "required" => {"content"} } })
    aAdd(aFuncs, { "name" => "soul_update", "description" => "Update SOUL.md content.", "parameters" => { "type" => "object", "properties" => { "content" => { "type" => "string" } }, "required" => {"content"} } })
    aAdd(aFuncs, { "name" => "cron_add_reminder", "description" => "Schedule a reminder message.", "parameters" => { "type" => "object", "properties" => { "message" => { "type" => "string" }, "minutes" => { "type" => "number" }, "chat_id" => { "type" => "string" } }, "required" => {"message", "minutes"} } })
retu aFuncs

function ExecuteAiosSkill(cName, hArgs)
    local hRes := { "success" => .f. }
    do case
        case cName == 'filesystem_search' ; hRes := Aios_FileSystem(cName, hArgs)
        case cName == 'identity_get_context' ; hRes := Aios_Identity()
        case cName == 'telegram_send_message' ; hRes := Aios_Telegram(cName, hArgs)
        case cName == 'telegram_get_updates' ; hRes := Aios_Telegram(cName, hArgs)
        case cName == 'config_set' ; hRes := Aios_Config('config_set', hArgs)
        case cName == 'config_get' ; hRes := Aios_Config('config_get', hArgs)
        case cName == 'memory_summarize' ; hRes := Aios_MemorySummarize(hArgs)
        case cName == 'filesystem_get_datetime' ; hRes := Aios_FileSystem(cName, hArgs)
        case cName == 'identity_update' ; hRes := Aios_PersonaUpdate('identity', hArgs)
        case cName == 'soul_update' ; hRes := Aios_PersonaUpdate('soul', hArgs)
        case cName == 'cron_add_reminder' ; hRes := Aios_Cron(cName, hArgs)
    endcase
retu hRes

#include "skills\identity\identity.prg"
#include "skills\filesystem\hix_filesystem.prg"
#include "skills\telegram\telegram.prg"
#include "skills\config\config_skill.prg"
#include "skills\cron\cron_skill.prg"

function GetAiosApiKey()
    local cKey := GetEnv("GEMINI_API_KEY"), hCfg := {=>}
    if Empty(cKey) .and. File("gemini_config.json")
    hb_jsonDecode(hb_MemoRead("gemini_config.json"), @hCfg)
    if ValType(hCfg) == "H" ; cKey := hb_HGetDef(hCfg, "api_key", "") ; endif
    endif
retu cKey

function Hix_UrlDecode( cT )
    local cR := "", n := 1, cX
    if Empty(cT) ; return "" ; endif
    cT := StrTran( cT, "+", " " )
    do while n <= Len( cT )
    if SubStr( cT, n, 1 ) == "%"
        cX := SubStr( cT, n + 1, 2 ) ; cR += Chr( Hix_HexToNum( cX ) ) ; n += 3
    else ; cR += SubStr( cT, n, 1 ) ; n++ ; endif
    enddo
retu cR

function Hix_HexToNum( cX )
    local n := 0, i, cC, nV
    cX := Upper( cX )
    for i := 1 to Len( cX )
    cC := SubStr( cX, i, 1 ) ; nV := At( cC, "0123456789ABCDEF" ) - 1
    if nV >= 0 ; n := n * 16 + nV ; endif
    next
retu n


antonio....@gmail.com

unread,
Feb 19, 2026, 2:16:18 PM (2 days ago) Feb 19
to Harbour Users
skills\identity\identity.prg
function Aios_Identity()
    local hR := { "success" => .t. }, cId := "", cSoul := "", cMem := "", cBaseDir := hb_DirBase()
    local cSep := "\" ; if !("\" $ cBaseDir) ; cSep := "/" ; endif

    if File(cBaseDir + "persona" + cSep + "IDENTITY.md") ; cId := hb_MemoRead(cBaseDir + "persona" + cSep + "IDENTITY.md") ; endif
    if File(cBaseDir + "persona" + cSep + "SOUL.md")     ; cSoul := hb_MemoRead(cBaseDir + "persona" + cSep + "SOUL.md")     ; endif
    if File(cBaseDir + "persona" + cSep + "MEMORY.md")   ; cMem := Right(hb_MemoRead(cBaseDir + "persona" + cSep + "MEMORY.md"), 2000) ; endif
   
    hR['identity'] := cId
    hR['soul'] := cSoul
    hR['recent_memory'] := cMem
   
    if Empty(cId) .and. Empty(cSoul) ; hR['success'] := .f. ; hR['error'] := "Identity files not found" ; endif
retu hR

function Aios_MemorySummarize(hArgs)
    local hR := { "success" => .f. }, cSummary, cBaseDir, cSep, cPath
    cSummary := hb_HGetDef(hArgs, "summary", "")
    if Empty(cSummary) ; hR['error'] := "Summary content is empty" ; retu hR ; endif
   
    cBaseDir := hb_DirBase()
    cSep := "\" ; if !("\" $ cBaseDir) ; cSep := "/" ; endif
    cPath := cBaseDir + "persona" + cSep + "MEMORY.md"
   
    if !hb_DirExists(cBaseDir + "persona") ; hb_DirCreate(cBaseDir + "persona") ; endif
   
    if hb_MemoWrit(cPath, "[OPTIMIZED MEMORY " + DToC(Date()) + "]" + (Chr(13)+Chr(10)) + cSummary + (Chr(13)+Chr(10)) + (Chr(13)+Chr(10)))
        hR['success'] := .t.
        hR['message'] := "Memory reorganized successfully"
    else
        hR['error'] := "Could not write memory file"
    endif
retu hR

function Aios_PersonaUpdate(cType, hArgs)
    local hR := { "success" => .f. }, cContent, cFile, cBaseDir, cSep, cPath
    cContent := hb_HGetDef(hArgs, "content", "")
    if Empty(cContent) ; hR['error'] := "Content is empty" ; retu hR ; endif
   
    cBaseDir := hb_DirBase()
    cSep := "\" ; if !("\" $ cBaseDir) ; cSep := "/" ; endif
    cFile := iif(cType == "identity", "IDENTITY.md", "SOUL.md")
    cPath := cBaseDir + "persona" + cSep + cFile
   
    if !hb_DirExists(cBaseDir + "persona") ; hb_DirCreate(cBaseDir + "persona") ; endif
   
    if hb_MemoWrit(cPath, cContent)
        hR['success'] := .t.
        hR['message'] := "Persona (" + cType + ") updated successfully"
    else
        hR['error'] := "Could not write " + cFile
    endif
retu hR


antonio....@gmail.com

unread,
Feb 19, 2026, 2:17:53 PM (2 days ago) Feb 19
to Harbour Users
skills\telegram\telegram.prg
#include "hbcurl.ch"

function Aios_Telegram(cAct, hP)
    local hR := { "success" => .t. }
    do case
        case cAct == 'telegram_send_message'
            hR := Telegram_SendMessage(hb_HGetDef(hP, "chat_id", ""), hb_HGetDef(hP, "text", ""))
        case cAct == 'telegram_get_updates'
            hR := Telegram_GetUpdates()
            otherwise
            hR := { "success" => .f., "error" => "Telegram action not supported: " + cAct }
    endcase
retu hR

function Telegram_SendMessage(cChatId, cText)
    local hR := { "success" => .f. }, cToken := GetTelegramToken()
    local cUrl, cPayload, hCurl, nError, cResponse := ""
   
    if Empty(cToken) ; hR['error'] := "Token not found" ; retu hR ; endif
    if Empty(cChatId) ; hR['error'] := "Chat ID required" ; retu hR ; endif
   
    cUrl := "https://api.telegram.org/bot" + cToken + "/sendMessage"
    cPayload := hb_jsonEncode({ "chat_id" => cChatId, "text" => cText })
   
    hCurl := curl_easy_init()
    if !Empty(hCurl)
        curl_easy_setopt(hCurl, HB_CURLOPT_POST, .T.)
        curl_easy_setopt(hCurl, HB_CURLOPT_URL, cUrl)
        curl_easy_setopt(hCurl, HB_CURLOPT_HTTPHEADER, { "Content-Type: application/json" })
        curl_easy_setopt(hCurl, HB_CURLOPT_SSL_VERIFYPEER, .F.)
        curl_easy_setopt(hCurl, HB_CURLOPT_POSTFIELDS, cPayload)
        curl_easy_setopt(hCurl, HB_CURLOPT_DL_BUFF_SETUP)
       
        nError := curl_easy_perform(hCurl)
        if nError == HB_CURLE_OK
            cResponse := curl_easy_dl_buff_get(hCurl)
            hR['success'] := .t. ; hR['raw_response'] := cResponse
        else
            hR['error'] := "Curl error: " + hb_ValToStr(nError)
        endif
        curl_easy_cleanup(hCurl)
    else
        hR['error'] := "Curl init failed"
    endif
retu hR

function Telegram_GetUpdates()
    local hR := { "success" => .f. }, cToken := GetTelegramToken()
    local cUrl, hCurl, nError, cResponse := "", hResp := {=>}
   
    if Empty(cToken) ; hR['error'] := "Token not found" ; retu hR ; endif
   
    cUrl := "https://api.telegram.org/bot" + cToken + "/getUpdates"
   
    hCurl := curl_easy_init()
    if !Empty(hCurl)
        curl_easy_setopt(hCurl, HB_CURLOPT_URL, cUrl)
        curl_easy_setopt(hCurl, HB_CURLOPT_SSL_VERIFYPEER, .F.)
        curl_easy_setopt(hCurl, HB_CURLOPT_DL_BUFF_SETUP)
       
        nError := curl_easy_perform(hCurl)
        if nError == HB_CURLE_OK
            cResponse := curl_easy_dl_buff_get(hCurl)
            hb_jsonDecode(cResponse, @hResp)
            hR['success'] := .t.
            if ValType(hResp) == "H" .and. hb_HHasKey(hResp, "result")
                hR['updates'] := hResp["result"]
            else
                hR['updates'] := cResponse
            endif
        else
            hR['error'] := "Curl error: " + hb_ValToStr(nError)
        endif
        curl_easy_cleanup(hCurl)
    else
        hR['error'] := "Curl init failed"
    endif
retu hR

function GetTelegramToken()
    local cKey := GetEnv("TELEGRAM_BOT_TOKEN"), hCfg := {=>}
    if Empty(cKey) .and. File("telegram_config.json")
    hb_jsonDecode(hb_MemoRead("telegram_config.json"), @hCfg)
    if ValType(hCfg) == "H" ; cKey := hb_HGetDef(hCfg, "bot_token", "") ; endif
    endif
retu cKey


antonio....@gmail.com

unread,
Feb 19, 2026, 2:21:51 PM (2 days ago) Feb 19
to Harbour Users
aios.jpg

antonio....@gmail.com

unread,
Feb 20, 2026, 7:52:24 AM (yesterday) Feb 20
to Harbour Users

antonio....@gmail.com

unread,
Feb 20, 2026, 8:02:09 AM (yesterday) Feb 20
to Harbour Users
The future belongs to Agents. Apps are the past...
Reply all
Reply to author
Forward
0 new messages