---
title: その他の言語 (ABI)
description: 任意の言語で Package を書くための ABI。
---

SDK は手間を省くためのもので、必須ではありません。**WASI preview 1** 向けの WebAssembly Module をビルドできる言語なら、**ABI 1** を直接実装して Function package を書けます。wasi-sdk を使った C や C++、Zig、AssemblyScript、TinyGo、Swift、自作の言語でもかまいません。

ABI 1 の仕様は小さなものです。Module は MCP の stdio transport で通信する [MCP](https://modelcontextprotocol.io) サーバーで、ステートレスなリビジョン `2026-07-28` を使います。HTTP 用には host module を 1 つ import できます。

## Module

| 要件 | |
| --- | --- |
| 種類 | WebAssembly の **core module** (component ではありません) |
| ターゲット | WASI preview 1。`wasm32-wasip1`、古いツールチェーンでは `wasm32-wasi` |
| Export | 引数も戻り値もない `_start` (WASI command) と、`memory` という名前の linear memory |
| Import | `wasi_snapshot_preview1` と `subako_http` からのみ |
| 機能 | GC なしの WebAssembly 2.0: bulk memory、reference types、multi-value、sign extension、non-trapping float-to-int、128-bit SIMD。threads、shared memory、exceptions、tail calls、memory64、multi-memory、relaxed SIMD は使えません。 |

アップロード時にはこれらがすべてチェックされ、拒否された場合はその理由が示されます。たとえば、Subako が提供しない import がある、export が足りない、Module ではなく component である、などです。

## 呼び出しの流れ

1. **Subako が Module を起動する**

    Subako は Module をインスタンス化し、要素が 1 つの `argv` を渡して、環境変数なしで `_start` を呼び出します。この時点で、最初のリクエストはすでに stdin で待っています。

2. **Module が各リクエストに応答する**

    リクエストは **stdin** に、1 行に 1 つの JSON-RPC 2.0 メッセージとして届きます。それぞれに対し、**stdout** へ `\n` で終わるコンパクトな JSON を 1 行書いて応答し、flush してください。Subako はリクエストを 1 つずつ送ります。stdin は最後のリクエストに応答するまで開いたままなので、入力の終わりを待たず、リクエストが届くたびに応答してください。

3. **Subako が stdin を閉じる**

    最後のリクエストに応答すると、stdin が end of file に達します。Module はその後 1 秒以内に、終了コード 0 で終了しなければなりません (`_start` から return するか、`proc_exit(0)` を呼びます)。

**stderr** はログに自由に使えます。stdout はプロトコル専用で、JSON-RPC メッセージでない行が 1 行でもあると呼び出しは失敗します。

## プロトコル

どのリクエストにも、`_meta` にプロトコルのリビジョンとクライアントの capabilities が含まれています。`initialize` によるハンドシェイクはありません。

```json
{"jsonrpc":"2.0","id":"call-0192f5c4","method":"tools/call","params":{"name":"greet","arguments":{"name":"Ada"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientInfo":{"name":"subako","version":"0.2.3"},"io.modelcontextprotocol/clientCapabilities":{}}}}
```

レスポンスには、リクエストの `id` をそのまま入れて返してください。id は文字列か数値で、中身に意味はなく、毎回異なります。

### Package をアップロードしたとき

Subako は Tool の一覧を得るために Module を一度実行します。このときは 10 秒以内に応答する必要があり、Volume もネットワークも使えず、マウントされるのは `/package` だけです。

1. `server/discover`: 対応しているリビジョンと、Tool を提供することを返します。

   ```json
   {"jsonrpc":"2.0","id":"discover-1","result":{"supportedVersions":["2026-07-28"],"capabilities":{"tools":{}}}}
   ```

2. `tools/list`: すべての Tool を返します。`nextCursor` を返すと、次のページを要求されます (最大 16 ページ)。

   ```json
   {"jsonrpc":"2.0","id":"tools-list-1","result":{"tools":[{"name":"greet","description":"Greet someone by name.","inputSchema":{"type":"object","properties":{"name":{"type":"string","description":"Who to greet."}},"required":["name"]}}]}}
   ```

3. stdin が閉じたら、終了コード 0 で終了します。

`tools/list` で返した内容が、次のバージョンまでその Package の提供するものになります。決まりは次のとおりです。

| | 決まり |
| --- | --- |
| Tool | 1 から 64 個。名前は重複不可 |
| `name` | 1 から 64 文字: `a`–`z`、`0`–`9`、`_`、`-` |
| `description` | 最大 1,024 文字。モデルが読みます。 |
| `inputSchema` | 最上位が `"type": "object"` の JSON Schema。最大 64 KiB |
| `outputSchema` | 任意。最大 64 KiB。モデルではなく人に表示されます。 |
| すべての Tool の合計 | 最大 256 KiB |

### Agent が Tool を呼び出したとき

Tool の `name` と、オブジェクト形式の `arguments` を持つ `tools/call` が 1 つ届きます。MCP の `CallToolResult` で応答してください。

```json
{"jsonrpc":"2.0","id":"call-0192f5c4","result":{"content":[{"type":"text","text":"{\"message\":\"Hello, Ada!\"}"}],"structuredContent":{"message":"Hello, Ada!"}}}
```

Subako は `arguments` を Schema に照らしてチェックしないので、Module の側で検証してください。モデルに読ませたい失敗は、JSON-RPC のエラーにせず、`isError` を付けた結果として返します。

```json
{"jsonrpc":"2.0","id":"call-0192f5c4","result":{"content":[{"type":"text","text":"name must not be empty"}],"isError":true}}
```

Subako が読む content block は次のとおりです。

| Block | モデルへの見せ方 |
| --- | --- |
| `{"type": "text", "text": ...}` | そのテキスト |
| `{"type": "image", "mimeType": "image/png", "data": "<base64>"}` | その画像。stdout の 1 MiB に含めて数えます |
| `{"type": "resource_link", "uri": "volume:///tmp/chart.png", "name": "chart.png"}` | `/volume/tmp/chart.png` の画像ファイル。Module の終了後に読み取ります |

`volume:///` の URI は `/volume` より下の Path を表し、各セグメントはパーセントエンコードします。画像は PNG、JPEG、GIF、WebP のいずれかです。これ以外の `resource_link` はリンク先を示す 1 行として、表にないそのほかの block は省略したことを伝える注記として表示されます。

### 呼び出しが失敗する場合

Module が次のいずれかに当てはまると、モデルには Function がクラッシュしたことが、stderr の最後の 4 KiB とともに伝えられます。

- JSON-RPC の `error` で応答した、または `resultType` が `complete` 以外だった
- stdout に JSON-RPC メッセージでない行を出力した、または要求されていない id に応答した
- 自分からリクエストを送った (ステートレスなサーバーはリクエストを送りません)
- 応答する前に終了した、0 以外の終了コードで終了した、または stdin が閉じてから 1 秒以内に終了しなかった
- trap した、またはメモリや実行時間を使い切った

通知 (`id` のないメッセージ) は無視されます。

## ファイル

[ファイルシステム](/ja/functions/runtime#ファイルシステム)は WASI の preopen として、`/volume/tmp`、`/volume/data` (Agent が有効にしている場合)、`/package` (Package に Asset がある場合)、`/skills` と各 `/skills/<name>` の順に渡されます。ファイルは絶対パスで開いてください。

`fd_allocate` は `ENOTSUP` を返します。ファイルへの書き込みが 1 回の呼び出しの上限 1 GiB を超えると、`EDQUOT` が返ります。`sock_*` 関数はリンクされていますが、ソケットが渡されることはありません。HTTP は `subako_http` を通して送ります。

## HTTP: `subako_http`

`subako_http` Module から import する関数は次の 2 つで、どちらも `i32` の値を扱います。

| Import | 動作 |
| --- | --- |
| `request(ptr, len) -> len` | `ptr` にある `len` バイトの JSON の**リクエスト**を読み取って送信し、返ってきた JSON の**応答**を保持して、その長さを返します。応答が届くまでブロックします。 |
| `read_response(ptr, len) -> 0` | 保持している応答を `ptr` にコピーします。`len` には `request` が返した値を渡します。0 を返し、保持していた応答を破棄します。 |

負の戻り値は ABI の使い方の誤りを表します。`-1` は Module のメモリ外の範囲を指定した、`-2` は保持している応答がない、`-3` は長さが一致しない、という意味です。

```c
__attribute__((import_module("subako_http"), import_name("request")))
int32_t subako_http_request(const uint8_t *ptr, int32_t len);

__attribute__((import_module("subako_http"), import_name("read_response")))
int32_t subako_http_read_response(uint8_t *ptr, int32_t len);
```

リクエストは最大 8 MiB で、次のフィールドだけを受け付けます。

```json
{
  "method": "POST",
  "url": "https://api.example.com/orders",
  "headers": { "accept": "application/json" },
  "body": { "type": "json", "json": { "order": 1042 } },
  "output": { "type": "inline" },
  "follow_redirects": true,
  "timeout_ms": 5000
}
```

| フィールド | |
| --- | --- |
| `method` | `GET` (既定)、`HEAD`、`POST`、`PUT`、`PATCH`、`DELETE`、`OPTIONS` のいずれか |
| `url` | 必須。`https` のみ。 |
| `headers` | 名前は小文字。`host` や `content-length` などの接続に関する Header は取り除かれます。 |
| `body` | `{"type": "text", "text": ...}`、`{"type": "json", "json": ...}`、`{"type": "file", "path": "/volume/tmp/in.bin"}` のいずれか |
| `output` | `{"type": "inline"}` (既定)、または本文を Volume に保存する `{"type": "file", "path": "/volume/tmp/out.bin"}` |
| `follow_redirects` | 既定は `true`。最大 10 ホップ |
| `timeout_ms` | リクエスト全体にかかる制限時間。指定の有無にかかわらず、呼び出し自体の Timeout も適用されます。 |

応答は `{"ok": ...}` か `{"error": ...}` です。

```json
{"ok":{"status":200,"headers":{"content-type":"application/json"},"body":{"type":"inline","text":"{\"status\":\"shipped\"}"}}}
{"ok":{"status":200,"headers":{},"body":{"type":"file","path":"/volume/tmp/out.bin","bytes":48211}}}
{"error":{"kind":"host_not_allowed","message":"api.example.com is not in this function's network allowlist"}}
```

インラインの本文は最大 256 KiB で、UTF-8 のテキストでなければなりません。そうでない場合、リクエストは `too_large` か `not_text` で失敗するので、本文はファイルに保存するようにしてください。エラーの種類は `invalid_request`、`host_not_allowed`、`forbidden_destination`、`credential_header`、`credential_unavailable`、`too_many_redirects`、`timeout`、`too_large`、`not_text`、`write_budget`、`bad_path`、`connection`、`abi` です。

## ローカルでのテスト

WASI preview 1 の command を実行できるランタイムなら、どれでも手元のマシンで Module を試せます。stdin にリクエストを 1 つ渡し、stdout から応答を読みます。

```bash
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}},"name":"greet","arguments":{"name":"Ada"}}}'
```

Module を読み込むには、ランタイムが `subako_http` を提供する必要があります。Rust と Go のテンプレートには、Module を別の Module にリンクできるランタイム向けに、すべてのリクエストを失敗させるスタブ `tests/subako_http_stub.wat` が含まれています。

```wat tests/subako_http_stub.wat
(module
  (func (export "request") (param i32 i32) (result i32) i32.const -1)
  (func (export "read_response") (param i32 i32) (result i32) i32.const -2))
```

## チェックリスト

1. `_start` と `memory` を export する WASI preview 1 の command module を、threads と exceptions なしでビルドします。
2. stdin を 1 行ずつ読み、end of file に達したら終了コード 0 で終了します。
3. `id` のないメッセージは無視します。
4. `server/discover` には `"supportedVersions": ["2026-07-28"]` と `tools` capability で応答します。
5. `tools/list` には、Tool の一覧と、それぞれのオブジェクト型の入力 Schema で応答します。
6. `tools/call` には `CallToolResult` で応答し、失敗には `isError` を使います。
7. 応答ごとにコンパクトな JSON を 1 行 stdout に書き、flush します。ログは stderr に書きます。
8. ファイルは `/volume/tmp`、`/volume/data`、`/package`、`/skills` の下で読み書きします。
9. HTTP は `subako_http` を通して送ります。

あとは、`abi` を `1` にした [`subako-package.json`](/ja/functions/packages#manifest) と `module.wasm` をまとめれば完成です。
