TOpenCode (OpenCode Zen)

Fonte: source/classes/topencode.prg

TOpenCode usa a API de chat OpenCode Zen (https://opencode.ai/zen/v1/chat/completions) com Authorization: Bearer public. Sem chave API. Modelos gratuitos (mimo-v2.6-flash-free, space-bunny-free, big-pickle, beam-free, glm-5.3-flash-free, deepseek-v4.1-flash-free; verificado em 2026-10-17). SendAsync exige a VM Harbour MT (build_new.bat <sample> hb32 mt).

Transporte: hbcurl sobre um libcurl estático (Schannel): não é preciso distribuir o libcurl.dll. Os fontes do curl e os scripts de build estão em 3rdparty/ (saídas: lib/libcurl_static*.{lib,a} para bcc32/bcc64/msvc32/msvc64/gcc).

Métodos

MétodoDescrição
New( cModel )Um handle curl por instância (vários agentes em paralelo).
Send( cPrompt ) / SendWithSystem()Síncrono; em rate limit tenta outro modelo free.
SendAsync() / SendWithSystemAsync()Retorna já. Consultar IsRunning(); se a thread terminar sem resultado retorna .F. e GetValue() informa o erro.
GetValue()Texto do assistente (UTF-8 → ACP).
lVerifySSLVerifica o certificado do servidor (padrão .T.). Deixe ativado.
SetServer( cBaseUrl [, cProviderID [, cModel ]] )Usa um servidor local opencode serve em vez do Zen (URL vazia = voltar ao Zen).
SessionStart() / SessionEnd()Gerencia a sessão do servidor manualmente (automático em Send() / End()).
SetTimeout( nMs )Timeout de cada requisição em milissegundos (nTimeout, padrão 90000).
ClearMessages()Esquece a conversa; no modo servidor o próximo Send() abre uma sessão nova.

Async grava oc_<ms>_<seq>.json via .part + rename: três SendAsync() no mesmo tick não colidem.

Melhor esforço: o nível gratuito do OpenCode Zen só responde a pedidos que parecem vir do cliente OpenCode, e o TOpenCode envia os cabeçalhos e a lista de ferramentas que esse nível espera. O Zen pode mudar isso, ou a lista de modelos gratuitos, a qualquer momento; se um modelo deixar de responder, use SetModel() com outro modelo gratuito.

Modo servidor local (opencode serve)

Com SetServer() a classe fala com um opencode serve local (padrão http://127.0.0.1:4096) em vez do OpenCode Zen. Ela mantém uma sessão persistente (POST /session), então o servidor lembra de toda a conversa, e qualquer provedor/modelo configurado no opencode pode ser usado (cProviderID + cModel; vazios = modelo padrão do servidor). Se a sessão se perde (HTTP 404), ela é recriada uma vez automaticamente, e End() a apaga (DELETE /session/{id}). Suporta autenticação básica com cServerUser / cServerPass (OPENCODE_SERVER_PASSWORD). Nesse modo o SendAsync() funciona de forma síncrona. Este backend segue a abordagem da classe TOpenCode de Charly 9000 (licença MIT).

o := TOpenCode():New()
o:SetServer( "http://127.0.0.1:4096" )
o:Send( "Olá" )
o:Send( "O que eu acabei de dizer?" )   // o servidor lembra
o:End()

Histórico de conversa

Por padrão (lHistory := .T.) cada Send()/SendWithSystem() bem-sucedido adiciona o turno a aMessages e a próxima requisição leva toda a conversa: o modelo tem memória. ClearMessages() começa uma conversa nova; lHistory := .F. volta a requisições sem estado.

Samples

cd samples\ai
build_new.bat opencode2 hb32 mt

Executar a partir de samples\ai para achar libcurl.dll.

Ver também