Files
Arcrun/registry/components/claude_api/main.go
uncle6me-web 922a57fe34 arcrun — AI workflow execution engine (clean history)
Self-hosted 開源:WASM 零件 + recipe + cypher-executor,跑在你自己的 Cloudflare。

此為重建的乾淨歷史起點(移除曾誤 commit 的 GCP SA 金鑰,舊歷史保留在
richblack/arcrun 與本地 backup 分支)。含:
- acr init --self-hosted installer(建 KV/R2 + codeload 拉預編譯 wasm + wrangler deploy + seed recipe)
- recipe push 把關(資料外流提醒 + 打通檢查)
- 19 個正當零件預編譯 wasm(claude_api/km_writer/kbdb_upsert_block 排除:違反 DECISIONS §1)
- CLI / cypher-executor / registry / 完整 SDD

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 15:52:38 +08:00

181 lines
4.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// claude_api — 呼叫 Mira daemonHetzner 上跑的 Claude Agent SDK 服務)
//
// 架構決策(2026-05-06):
// 不直打 Anthropic Messages APIOAuth token 限制 system prompt 角色 → rate_limit_error
// 改透過已部署的 cloud-cto Mira daemon (https://mira.uncle6.me/mira/execute)
// 該 daemon 用 Claude Agent SDK,已內建 Mira persona,可長執行任務
//
// SDD: polaris/mira/.agents/specs/mira-app/design.md §6(五個 P0 零件)
//
//go:build tinygo
package main
import (
"encoding/json"
"io"
"os"
"unsafe"
)
//go:wasmimport u6u http_request
func hostHttpRequest(
urlPtr uintptr, urlLen uint32,
methodPtr uintptr, methodLen uint32,
headersPtr uintptr, headersLen uint32,
bodyPtr uintptr, bodyLen uint32,
outPtr uintptr, outLenPtr uintptr,
) uint32
type Input struct {
MiraURL string `json:"mira_url"` // 預設 https://mira.uncle6.me
MiraToken string `json:"mira_token"` // Mira daemon Bearer token
Prompt string `json:"prompt"` // 必填:要傳給 Mira 的訊息
TimeoutMS int `json:"timeout_ms"` // 預設 25000daemon 協商模式上限)
Model string `json:"model"` // 'haiku' / 'sonnet' / 'opus',預設 haikudaemon 端)
CallbackURL string `json:"callback_url"` // optionaldaemon 完成 task 時 POST 此 URL 通知(Resumable workflowSDD: resumable-workflow
}
var dummy [1]byte
func safePtr(b []byte) (uintptr, uint32) {
if len(b) == 0 {
return uintptr(unsafe.Pointer(&dummy[0])), 0
}
return uintptr(unsafe.Pointer(&b[0])), uint32(len(b))
}
func main() {
raw, err := io.ReadAll(os.Stdin)
if err != nil {
writeError("failed to read stdin: " + err.Error())
return
}
var input Input
if err := json.Unmarshal(raw, &input); err != nil {
writeError("invalid input JSON: " + err.Error())
return
}
if input.MiraToken == "" {
writeError("mira_token 必填(Mira daemon Bearer token")
return
}
if input.Prompt == "" {
writeError("prompt 必填")
return
}
miraURL := input.MiraURL
if miraURL == "" {
miraURL = "https://mira.uncle6.me"
}
timeoutMS := input.TimeoutMS
if timeoutMS <= 0 {
// 預設 120sdaemon 協商期會在 25s 切非同步 + callback
// callback_url 存在時,timeout 上限不重要(daemon 會 fire callback 不論多久)
timeoutMS = 120000
}
// Mira daemon /execute 介面
body := map[string]interface{}{
"prompt": input.Prompt,
"timeout_ms": timeoutMS,
}
if input.Model != "" {
body["model"] = input.Model
}
if input.CallbackURL != "" {
body["callback_url"] = input.CallbackURL
}
bodyBytes, _ := json.Marshal(body)
headers := map[string]string{
"Content-Type": "application/json",
"Authorization": "Bearer " + input.MiraToken,
}
headersBytes, _ := json.Marshal(headers)
url := miraURL + "/mira/execute"
urlBytes := []byte(url)
methodBytes := []byte("POST")
outBuf := make([]byte, 1024*1024) // 1MB
var outLen uint32
urlPtr, urlLen := safePtr(urlBytes)
methodPtr, methodLen := safePtr(methodBytes)
headersPtr, headersLen := safePtr(headersBytes)
bodyPtr, bodyLenU := safePtr(bodyBytes)
result := hostHttpRequest(
urlPtr, urlLen,
methodPtr, methodLen,
headersPtr, headersLen,
bodyPtr, bodyLenU,
uintptr(unsafe.Pointer(&outBuf[0])), uintptr(unsafe.Pointer(&outLen)),
)
if result != 0 {
writeError("Mira daemon request failed (host_http_request returned non-zero)")
return
}
respStr := string(outBuf[:outLen])
var resp map[string]interface{}
if err := json.Unmarshal([]byte(respStr), &resp); err != nil {
writeError("Mira returned non-JSON: " + respStr)
return
}
// 偵測錯誤回應
if errObj, hasErr := resp["error"]; hasErr {
errBytes, _ := json.Marshal(errObj)
writeError("Mira error: " + string(errBytes))
return
}
// daemon 回應格式:
// 同步完成: {"task_id":"...","status":"done","output":"...","model":"..."}
// 非同步: {"task_id":"...","status":"running","estimated_seconds":N}
status, _ := resp["status"].(string)
if status == "running" {
// 還沒完成,回傳 task_id 給 caller 自己 polling
out, _ := json.Marshal(map[string]interface{}{
"success": true,
"pending": true,
"task_id": resp["task_id"],
"estimated_seconds": resp["estimated_seconds"],
"poll_url": miraURL + "/mira/execute/" + toString(resp["task_id"]),
})
os.Stdout.Write(out)
return
}
// status == "done" 的場景
out := map[string]interface{}{
"success": true,
"data": map[string]interface{}{
"text": resp["output"],
"task_id": resp["task_id"],
"model": resp["model"],
},
}
outJSON, _ := json.Marshal(out)
os.Stdout.Write(outJSON)
}
func toString(v interface{}) string {
if s, ok := v.(string); ok {
return s
}
return ""
}
func writeError(msg string) {
out, _ := json.Marshal(map[string]interface{}{"success": false, "error": msg})
os.Stdout.Write(out)
}