Files
Arcrun/.component-builds/claude_api/src/index.ts
T
uncle6me-web 465c505000 fix(execution-truth): 修系統對 401 假綠根因 + acr run self-hosted + D1-in-update
Haiku 自主壓測(test_arcrun/5)暴露的真 bug,逐一修復:

1. 假綠根因:http_request host function 丟掉 HTTP status code(main.go:112 架構債)
   → 非 2xx(如 Notion 401)被判 success → 引擎自己對失敗報成功。
   修:host fn 非 2xx 回 {error,status,body} envelope,既有判定鏈正確識別。
   http_request/claude_api/kbdb_upsert_block/km_writer 已修(4 worker deploy);
   auth_service_account 自有 OAuth 判定不套。

2. acr run self-hosted:原一律走 /webhooks/<name>(需先 push)→ 沒 push 回 404 純文字
   → res.json() 爆假錯誤。修:本機有 YAML 走玩法一 /cypher/execute 直接執行(三模式一致)
   + res.ok 擋非 2xx + findWorkflowYaml 容忍 .yaml 副檔名。

3. D1-in-update:D1 只在 init 建一次,update 漏建 → token 補權限後無冪等補建路徑。
   修:update 也 ensureD1Database(已驗證 D1 建起 count:1)。

4. CF token 教學漏 D1:llms.txt/.env.example 加「Account/D1/Edit」必勾 + init/preflight
   訊息指明 token 缺 D1 權限的修法。

CLI 1.3.4 publish。Haiku 壓測結論:onboarding 治好(裝+init 沒跳過、建 recipe 不建零件),
但仍會假綠(curl 繞過/D1 沒建謊報)→ 印證執行真相要系統能驗、不信 AI 自報。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:12:09 +08:00

99 lines
3.3 KiB
TypeScript
Raw 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.
/**
* arcrun WASM 零件 Worker (claude_api v2)
* POST / → JSON input → WASM (WASI preview1) → JSON output
* SDD: polaris/mira/.agents/specs/mira-app/design.md §6
*
* v2 改打 Mira daemon (Hetzner) 而非直打 Anthropic Messages API
* 理由:OAuth token 在 Messages API 限制 system prompt → rate_limit
* Mira daemon 用 Claude Agent SDK,已內建 Mira persona
*/
import componentWasm from '../component.wasm' assert { type: 'webassembly' };
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { createWasiShim, type WasiHostFunctions } from '../../../cypher-executor/src/lib/wasi-shim';
type Env = {
MIRA_TOKEN?: string; // Mira daemon Bearer token
MIRA_URL?: string; // 預設 https://mira.uncle6.me
COMPONENT_ID: string;
};
const app = new Hono<{ Bindings: Env }>();
app.use('*', cors());
app.get('/', (c) => c.json({ ok: true, component: 'claude_api', version: 'v2-mira-daemon' }));
app.post('/', async (c) => {
let input: Record<string, unknown>;
try {
input = await c.req.json();
} catch {
return c.json({ success: false, error: 'request body must be JSON' }, 400);
}
// 用戶沒帶 token → 用 Worker secret fallback
if (!input.mira_token && c.env.MIRA_TOKEN) {
input.mira_token = c.env.MIRA_TOKEN;
}
if (!input.mira_url && c.env.MIRA_URL) {
input.mira_url = c.env.MIRA_URL;
}
try {
const result = await runWasm(input);
return c.json(result);
} catch (e) {
return c.json(
{ success: false, error: e instanceof Error ? e.message : String(e) },
500,
);
}
});
export default app;
async function runWasm(input: unknown): Promise<unknown> {
const hostFunctions: WasiHostFunctions = {
http_request: async (url, method, headersJson, body) => {
const headers: Record<string, string> = {};
if (headersJson) {
try {
const parsed = JSON.parse(headersJson);
if (parsed && typeof parsed === 'object') {
for (const [k, v] of Object.entries(parsed as Record<string, unknown>)) {
if (typeof v === 'string') headers[k] = v;
}
}
} catch {}
}
const init: RequestInit = { method, headers };
if (body && method.toUpperCase() !== 'GET' && method.toUpperCase() !== 'HEAD') {
init.body = body;
}
const res = await fetch(url, init);
const text = await res.text();
// 修架構債(同 http_request):非 2xx 包成帶 "error" key 的 envelope
// 讓 WASM 端既有的 error 判定正確識別失敗(原本只回 body 丟掉 status → 4xx 被判 success)。
if (!res.ok) {
return JSON.stringify({ error: `HTTP ${res.status}`, status: res.status, body: text });
}
return text;
},
};
const shim = createWasiShim(JSON.stringify(input), hostFunctions);
const instance = await WebAssembly.instantiate(
componentWasm as WebAssembly.Module,
shim.imports,
);
shim.setMemory(instance.exports.memory as WebAssembly.Memory);
await shim.run(instance);
const stdout = shim.getStdout().trim();
const stderr = shim.getStderr().trim();
if (stderr) console.error('[claude_api wasm stderr]', stderr);
if (!stdout) throw new Error('WASM component produced no output');
return JSON.parse(stdout);
}