diff --git a/1-concept.md b/1-concept.md index e6b9dc4..9aadd1f 100644 --- a/1-concept.md +++ b/1-concept.md @@ -36,7 +36,9 @@ WIPではObjectを受動的なJSON recordとして扱わない。 本文を読む、metadataを取得する、検索する、状態を変更するといった行為はいずれもOperationとして表現する。例えばIssueであれば、`read_body()`、`get_metadata()`、`close(reason)`などを公開できる。 -Operationには、名前や型に加えて、用途を判断するための短いdescriptionを持たせる。長文documentationや大量のドメインデータをinterface metadataへ埋め込むことは想定しない。 +Operationには、名前や型に加えて、用途を判断するための短いdescriptionを持たせる。長文documentationや大量のドメインデータをInterfaceへ埋め込むことは想定しない。 + +ObjectはOperation定義を直接埋め込まず、WIP IDLで記述されたInterfaceを参照する。一つのInterfaceに宣言された関数の集合がOperation一覧となり、複数のObjectが同じInterfaceを共有できる。 ## 発見と既知世界 diff --git a/2-core-model.md b/2-core-model.md index 43f5b61..fb90f01 100644 --- a/2-core-model.md +++ b/2-core-model.md @@ -6,7 +6,7 @@ Worldspaceは、LLMが探索できる**ObjectのTree**として公開される WIPではObjectとエントリを別の構造として定義しない。**ObjectをWorldspaceのTree上の位置として扱うとき、そのObjectをエントリと呼ぶ。** -したがって、ObjectはTree上で親子関係を持ち得るし、途中のNodeもそのまま操作対象になってよい。例えば`articles`はCollection Objectとして`query`等を公開でき、その配下に個別Articleが配置され得る。 +したがって、ObjectはTree上で親子関係を持ち得るし、途中のNodeもそのまま操作対象になってよい。例えば`articles`はCollection Objectとして、そのInterfaceに`query`等を宣言し、配下に個別Articleを配置できる。 ## Object / エントリ @@ -20,6 +20,14 @@ Tree上の位置はpathで表される。Pathは恒久的なIdentityではなく 同じObjectが複数の位置に現れる場合、一つのObjectが複数のエントリとして観測され得る。 +## Interface + +ObjectはOperation定義を直接持たず、一つのInterfaceを参照する。 + +Interfaceの実体は一つのWIP IDL documentであり、document内に宣言された関数の集合が、そのInterfaceのOperation集合となる。複数のObjectが同じInterfaceを共有できる。 + +ObjectとInterfaceを分離することで、Collection内の多数の同種Objectに同じOperation定義を重複して持たせず、ClientがInterface定義を参照単位でcacheできる。 + ## `ref` Objectは必要に応じて`ref`を公開できる。 diff --git a/2.1-object-tree-schema.md b/2.1-object-tree-schema.md index c5dcaf1..8b4a625 100644 --- a/2.1-object-tree-schema.md +++ b/2.1-object-tree-schema.md @@ -20,16 +20,24 @@ ObjectがTree上に配置されることでエントリとなり、pathはその ## 2.1.3 公開情報 -Object / エントリが公開する情報は、Worldspaceを探索し、対象に対して何ができるかを理解するための**interface metadata**である。 +Object / エントリが公開する情報は、Worldspaceを探索し、対象に対して何ができるかを理解するための最小限のmetadataである。 現時点では、少なくとも次の情報を想定する。 - `name` — Objectの短い名前。Tree上ではエントリ名としても用いられる。 - `description` — Objectが何を表すかを説明する短い自然言語。長文documentationではなく、探索・判断に必要な最小限のsemantic metadataとする。 -- `operations` — Objectが公開するOperation。詳細は [2.2. Operation](2.2-operation.md) で定義する。 +- `interface` — Objectが実装するInterfaceへの参照。 - `children` — Tree上でindexableとして公開される子Object / エントリ。 - `ref` — 必要に応じて公開される、同一Objectを再参照するための外部Handle。 +Interfaceの実体は[WIP IDL](draft/wip-idl.md) documentである。IDL内に宣言された関数の集合が、そのInterfaceのOperation集合となる。ObjectはOperation定義を個別に埋め込まず、一つのInterface参照だけを持つ。 + +複数のObjectが同じInterfaceを参照できる。これにより、Collectionから多数の同種エントリを取得する場合でも、Operation名、documentation、parameter、return typeを各エントリへ重複して送る必要がない。 + +Interface参照は、HostがそのClientへ投影したInterfaceを識別する。同じObjectでも主体のroleや権限により異なるInterfaceを参照し得るが、頻繁に変化する実行可否を表すためには使用しない。 + +ClientはInterface参照をcacheと比較し、未知のInterfaceだけを`fetch_interface`で取得する。HostはClientのcache状態を推測せず、ObjectのresponseへInterface定義を先行同梱しない。複数のInterface取得はTransport Bindingでbatchできる。 + WIPではドメインデータそのものをpropertiesとして直接公開することを前提としない。本文、metadata、状態などを読む行為もOperationとして表現する。 ## 2.1.4 Tree diff --git a/2.2-operation.md b/2.2-operation.md index 903de5c..07d7173 100644 --- a/2.2-operation.md +++ b/2.2-operation.md @@ -2,49 +2,65 @@ ## 2.2.1 目的 -Operationは、Objectが外部へ公開する意味的な操作を表す。WIPではドメインデータをpropertiesとして常時露出するのではなく、読み取り・検索・更新を含む行為をOperationとして公開する。 +Operationは、Objectに対して実行できる操作を表す。 -## 2.2.2 基本形 +WIPでは、本文を読む、metadataを取得する、検索する、状態を変更するなど、Objectに対する行為をOperationとして公開する。 -Operationは少なくとも次の情報を持つ。 +## 2.2.2 Interface -- `name` — Operationを識別する名前。 -- `description` — 何を行う操作かを説明する短い自然言語。 -- `input` — 呼び出し時に受け取る入力の型。 -- `output` — 呼び出し結果の型。 +ObjectはOperation定義を直接持たず、一つのInterfaceを参照する。 -Operation名や型だけに意味を担わせず、`description`をinterface metadataの一部として扱う。長文documentationを埋め込むことは想定しない。 +Interfaceの定義は[WIP IDL](draft/wip-idl.md) documentそのものである。IDL documentに宣言された関数の集合が、そのInterfaceのOperation集合となる。Operation名、parameter、return type、短いdocumentationは一つの関数宣言としてまとめて定義し、別のOperation descriptorへ重複して記述しない。 -## 2.2.3 入出力型とWIP IDL +複数のObjectが同じInterfaceを参照できる。これにより、Collectionから多数の同種Objectを取得する場合でも、Operation定義を各Objectへ重複して埋め込む必要がない。 -Operationのinput / outputは、機械的に検証・解釈できる構造化された型として[WIP IDL](draft/wip-idl.md)で定義する。WIP IDLのsourceをschemaのcanonicalな交換形式とし、JSON SchemaやIDLを変換したJSON ASTはCore Protocol上の交換形式にしない。 +HostはInterfaceについて、参照、IDLのlanguage identifier、source、およびcacheや同一性確認に利用できるdigestをClientへ提供する。ObjectはInterface参照だけを持ち、Clientは未知のInterface定義だけを取得してcacheできる。 -Hostは公開するinterfaceについて、IDLのlanguage identifier、sourceまたはsourceへの参照、およびcacheや同一性確認に利用できるdigestをClientへ提供する。ClientはIDLをparseして内部表現を構築する。AI ToolやGUIへ投影する際にJSON Schema等へ変換することはClient実装の責務であり、その変換形式をWIP interfaceとしてHostへ要求しない。 +## 2.2.3 Operation declaration -WIP IDLは、Operation境界の値を記述するための小さな型システムとする。Primitive、record、list、optional field、enum、unionに加え、Worldspace内のエントリpathを示す`entry`型を表現する。任意のドメインデータをObjectのpropertiesとしてモデル化するための型システムではない。 +Operationは、WIP IDL内で関数形式により宣言する。 -Operationのinputは常に名前付きfieldを持つrecordとする。引数を持たないOperationのinputは空のrecordであり、位置引数は用いない。これにより、呼び出しの可読性を保ち、既存fieldの意味を変えずにoptional fieldを追加できる。 +```wip +/// Returns items related to this Object. +operation get_related_items( + relation: Relation, + limit?: integer, +) -> { + items: [entry], + next_cursor?: string, +}; +``` -Outputは任意のIDL型を返してよい。ただし、将来の拡張や付加情報の追加が想定されるOperationではrecordを基本とする。 +Parameterは常に名前付きとし、位置引数は用いない。引数を持たないOperationは空のparameter list `()`で宣言する。 + +```wip +operation refresh() -> unit; +``` + +Return typeには任意のWIP IDL型を使用できる。ただし、将来fieldを追加する可能性があるOperationではrecordを基本とする。 + +Operationの用途は`///` documentation commentで簡潔に説明する。長文documentationや大量のdomain dataをInterfaceへ埋め込むことは想定しない。 ## 2.2.4 可視性 -Hostは、主体の権限やrole / capabilityに基づいて、その主体へ公開するOperation集合を決定してよい。 +Hostは、主体の権限やrole / capabilityに基づいて、その主体へ公開するInterfaceを決定してよい。 -Operationの可視性は、頻繁に変化する実行可否やdomain stateを表すものではなく、**その主体に対してどのinterfaceを公開するか**というprojectionとして扱う。 +Operationの可視性は、頻繁に変化する実行可否やdomain stateを表すものではなく、**その主体に対してどのInterfaceを公開するか**というprojectionとして扱う。 -例えばread-only主体には読み取り系Operationのみを公開し、maintainerやadminには追加の更新・管理Operationを公開できる。 +同じObjectでも、主体ごとに異なるInterface参照を返してよい。 -WIPはOperationの`available` / `disabled`のような揮発的状態をinterface metadataとして同期することを前提としない。現在状態を判断する必要がある場合は、必要に応じてdomain固有のOperationで観測する。最終的なauthorizationと実行条件の判定は`call_operation`時にHostが行う。 +WIPはOperationの`available` / `disabled`のような揮発的状態をInterfaceへ同期することを前提としない。現在状態を判断する必要がある場合は、必要に応じてdomain固有のOperationで観測する。最終的なauthorizationと実行条件の判定は`call_operation`時にHostが行う。 ## 2.2.5 Operation Result -Operationの結果には、通常のdomain valueに加えて、WIP IDLの`entry`型として新しいエントリのpathが含まれ得る。 +`call_operation`は、対象ObjectのInterfaceに宣言されたOperation名と、parameter listに従う名前付きargumentsを受け取る。結果はOperationのreturn typeに従う型付きvalueとして返す。 -`entry`は同じWorldspace内のcanonical absolute pathであり、wire上では文字列として表現する。Clientはoutput schemaに従って`entry`型の位置を認識し、返されたpathを一時的な発見結果として扱う。通常の`string`や任意JSON値に含まれるpathらしい文字列を、エントリとして推測してはならない。 +Operation Resultには、WIP IDLの`entry`型として新しいエントリのpathが含まれ得る。 -Clientは発見したpathを必要に応じて`fetch`または`fetch_tree`する。複数pathのbatch取得や、invoke responseへのエントリ公開情報の同梱は、Operationのoutput型とは独立したprotocol上の最適化として扱う。 +`entry`は同じWorldspace内のcanonical absolute pathであり、wire上では文字列として表現する。Clientはreturn typeに従って`entry`型の位置を認識し、返されたpathを一時的な発見結果として扱う。通常の`string`や任意JSON値に含まれるpathらしい文字列を、エントリとして推測してはならない。 + +Clientは発見したpathを必要に応じて`fetch`または`fetch_tree`する。複数pathの取得は、それぞれ独立したCore操作をTransport Bindingでbatchする。Operation Resultへエントリ公開情報を先行同梱しない。 Operationの実行対象と、結果として発見されたエントリのTree上の位置は独立している。発見されたエントリは実行対象の子である必要はなく、親、兄弟、またはWorldspace内の任意の位置にあるエントリであってよい。 -Operationがエントリpathを返したこと自体から、実行対象との間に親子関係や意味的関係を推論してはならない。親子関係はTree上の配置で表し、非内包の意味的関係はOperation名、outputのfield名、またはdomain固有のrelation型で表現する。 +Operationがエントリpathを返したこと自体から、実行対象との間に親子関係や意味的関係を推論してはならない。親子関係はTree上の配置で表し、非内包の意味的関係はOperation名、resultのfield名、またはdomain固有のrelation型で表現する。 diff --git a/3-core-protocol.md b/3-core-protocol.md index 97483b0..dba6c85 100644 --- a/3-core-protocol.md +++ b/3-core-protocol.md @@ -10,7 +10,7 @@ WIP上の主要な登場主体は**Client**と**Host**である。 ClientはHostが提供するWorldspaceをユーザーまたはAIへ提示する。 -Hostから取得したエントリを既知の空間として保持・キャッシュし、`ref`によるObject同一性の追跡や、観測時と操作時の対応関係の検証を行う。 +Hostから取得したエントリとInterface定義を既知の空間として保持・キャッシュし、`ref`によるObject同一性の追跡や、観測時と操作時の対応関係の検証を行う。 GUI、AI用Tools、PTC / REPL向けAPIなどへの投影はClient実装の責務とする。 @@ -18,7 +18,7 @@ GUI、AI用Tools、PTC / REPL向けAPIなどへの投影はClient実装の責務 HostはClientに対して一つのWorldspaceを提供する。 -どのObject、エントリ、Operation、可視性を公開するかを決定し、そのClientから見えるWorldspaceを構成する。 +どのObject、エントリ、Interface、可視性を公開するかを決定し、そのClientから見えるWorldspaceを構成する。 Host内部でGitHub API、Database、Filesystem、RAG、他Agent、別プロトコルなどをどう接続・集約するかはWIPの規定対象外とする。 @@ -32,13 +32,14 @@ ClientとHostの境界は通信境界であると同時に、ある主体へど ## 3.3 基本操作 -現時点では次の3操作をCore Protocolの基本とする。 +現時点では次の4操作をCore Protocolの基本とする。 -- `fetch(entry)` — 1つのエントリにあるObjectの公開情報を取得する。 +- `fetch(entry)` — 1つのエントリにあるObjectの公開情報とInterface参照を取得する。 - `fetch_tree(entry, depth, limit)` — 指定エントリを起点に、indexableな子エントリを幅優先探索してエントリツリーとして取得する。 -- `call_operation(target, operation, input)` — Objectが公開するOperationを実行する。 +- `fetch_interface(interface)` — Interface参照からWIP IDL documentを取得する。 +- `call_operation(target, operation, arguments)` — Objectが参照するInterfaceに宣言されたOperationを実行する。 -Operationのinterfaceは[WIP IDL](draft/wip-idl.md)で定義する。`call_operation`の`input`はOperationが宣言したinput recordに従う名前付きの型付き値であり、引数がない場合も空のrecordを渡す。Core Protocolはこの値をJSONに限定せず、transport bindingが具体的なencodingを定める。 +Interfaceの定義は[WIP IDL](draft/wip-idl.md) documentそのものであり、そこに宣言された関数の集合がOperation一覧となる。`call_operation`の`arguments`は選択したOperationのparameter listに従う名前付きの型付き値であり、引数がない場合は空のrecordとする。Core Protocolはこの値をJSONに限定せず、Transport Bindingが具体的なencodingを定める。 ## 3.4 `fetch_tree` @@ -52,13 +53,15 @@ Operationのinterfaceは[WIP IDL](draft/wip-idl.md)で定義する。`call_opera ## 3.5 Operation実行と発見 -`call_operation`の結果はOperationのWIP IDL output型に従う型付き値である。Output schema上で`entry`として宣言された位置には、同じWorldspace内のエントリを指すcanonical absolute pathを返せる。 +`call_operation`の結果は、選択したOperationのWIP IDL return typeに従う型付き値である。Return type上で`entry`として宣言された位置には、同じWorldspace内のエントリを指すcanonical absolute pathを返せる。 -Clientはoutput schemaに従って`entry`型の位置を認識する。通常の`string`や任意JSONに含まれるpathらしい文字列を、エントリとして推測してはならない。 +Clientはreturn typeに従って`entry`型の位置を認識する。通常の`string`や任意JSONに含まれるpathらしい文字列を、エントリとして推測してはならない。 返されたエントリpathのTree上の位置はOperationの実行対象から独立しており、実行対象の子に限定されない。Operationの実行対象と返されたエントリの間に、暗黙の親子関係や意味的関係を作ってはならない。 -ClientはOperation結果として発見したpathを一時的に扱い、必要なものを`fetch`または`fetch_tree`して既知の空間へ統合できる。複数pathに対する`fetch`は意味上それぞれ独立しており、Transport Bindingは同じ意味を保ったまま一つのrequestへbatchしてよい。 +ClientはOperation結果として発見したpathを一時的に扱い、必要なものを`fetch`または`fetch_tree`して既知の空間へ統合できる。 + +複数の`fetch`または`fetch_interface`は、Core Protocol上ではそれぞれ独立した操作である。Transport Bindingは、個別に実行した場合と同じ意味を保ったまま、Clientが選択した複数の操作を一つのrequestへbatchしてよい。HostがClientの既知状態を推測して追加情報を先行同梱することはCore Protocolの一部としない。 ## 3.6 Transportとの分離 diff --git a/4-client.md b/4-client.md index 2520572..5e2f676 100644 --- a/4-client.md +++ b/4-client.md @@ -2,7 +2,7 @@ ## 役割 -Clientは、Hostが提供するWorldspaceをユーザーへ提示する実装主体である。WIPのCore Protocolを直接利用しつつ、用途に応じたViewやAPIへ投影する。 +Clientは、Hostが提供するWorldspaceをユーザーへ提示する実装主体である。WIPのCore Protocolを直接利用しつつ、Objectが参照するInterfaceを解決し、用途に応じたViewやAPIへ投影する。 ClientはHostから得た情報をそのまま一時表示するだけでなく、rootからindexable edgeを辿って構成したエントリツリーと、必要に応じて選択したエントリを保持し、ユーザーから見た**既知の空間**を構成する。 @@ -21,6 +21,14 @@ Operationを通して発見されたpathは、必ずしもKnown Spaceへ追加 既知エントリ間の移動や参照はClient側で処理できる。既知の空間を辿るたびにHostへ問い合わせる必要はない。 +## Interface cache + +Objectの公開情報はOperation定義を直接含まず、Interface参照を持つ。Clientは未知のInterface参照を`fetch_interface`で解決し、取得したWIP IDL documentを参照ごとにcacheする。 + +一つのInterface documentに宣言された関数の集合が、そのInterfaceのOperation一覧である。複数のObjectが同じInterfaceを参照する場合、ClientはIDLを一度だけ取得・parseすればよい。 + +ClientはInterface cacheとObjectのInterface参照を比較し、未知のInterfaceだけを取得する。複数の`fetch_interface`は、Transport Bindingが提供するbatchを利用してまとめてよい。 + ## Discoverable Space Clientは、Hostから`fetch_tree`で取得したindexableなエントリツリーをDiscoverable Spaceとして保持する。Discoverable Spaceとして扱う間、Clientはそのtreeの構造を保持する必要がある。 @@ -33,7 +41,7 @@ Operationを通して発見されたpathは、それだけではDiscoverable Spa ## 一時的な発見とpin -Clientは、Operation Resultの`entry`型として発見したpathを現在の結果として一時的に扱える。標準的なClientはoutput schemaからentry pathを抽出して重複を除去し、必要なpathの公開情報を取得する。Transportがbatch fetchやinvoke responseへの同梱を提供する場合は、それを利用してround tripを削減してよい。 +Clientは、Operation Resultの`entry`型として発見したpathを現在の結果として一時的に扱える。標準的なClientはOperationのreturn typeからentry pathを抽出して重複を除去し、Known Spaceと比較して必要なpathだけを取得する。複数の`fetch`はTransport Bindingが提供するbatchを利用してまとめてよい。 一時的に取得したエントリは、結果の利用が終わった時点で破棄してよい。 diff --git a/4.1-ai-tools-example.md b/4.1-ai-tools-example.md index 52f1f49..1321f4e 100644 --- a/4.1-ai-tools-example.md +++ b/4.1-ai-tools-example.md @@ -16,7 +16,7 @@ AI用Toolsは、WIP ClientがAIへ提供する想定インターフェースで ## `inspect` -`inspect(target)` は、対象エントリ / Objectについて**何ができるか**を把握するための操作である。 +`inspect(target)` は、対象エントリ / Objectについて**何ができるか**を把握するための操作である。ClientはObjectのInterface参照を解決し、WIP IDL documentに宣言されたOperationを提示する。 Objectのドメインデータをpropertiesとして直接公開することは前提としない。データを読む行為もOperationとして表現する。 @@ -27,13 +27,11 @@ Objectのドメインデータをpropertiesとして直接公開することは - `get_related_items()` — 関連Objectのentry pathを取得する。 - `close(reason: string)` — 理由を添えてIssueをクローズする。 -Operationはシグネチャだけでなく、AIが用途を判断できる短いdescriptionを持つ。長文ドキュメントを埋め込むことは想定しない。 - -Operationのinput / output schemaは[WIP IDL](draft/wip-idl.md)として取得する。ClientはIDLをparseし、利用するAI providerが要求するTool schemaへ変換する。JSON Schema等への変換はAI向けClient adapterの責務であり、HostがWIP interfaceとして提供する必要はない。 +Operationの関数宣言と短いdocumentationは、Objectが参照する[WIP IDL](draft/wip-idl.md) documentから取得する。ClientはIDLをparseし、利用するAI providerが要求するTool schemaへ変換する。JSON Schema等への変換はAI向けClient adapterの責務であり、HostがWIP Interfaceとして提供する必要はない。 ## `invoke` -`invoke(target, operation, input)` は、`inspect`によって発見したOperationを実行する。`input`はOperationのWIP IDLで定義された名前付きfieldを持つrecordであり、位置引数は用いない。引数を持たないOperationには空のrecordを渡す。 +`invoke(target, operation, arguments)` は、`inspect`によって発見したOperationを実行する。`arguments`はOperationのWIP IDL parameter listに従う名前付きfieldのrecordであり、位置引数は用いない。引数を持たないOperationには空のrecordを渡す。 PTC / REPL bindingでは、通常のメソッド呼び出しへ投影してよい。 @@ -57,4 +55,4 @@ ClientはOperation Resultからentry pathを抽出し、必要なpathを`fetch` 全文検索、semantic retrieval、外部API検索などはWIP固有のToolにはしない。 -検索能力を持つObjectが`query`や`search`などのOperationを公開し、AIはそれを`invoke`する。結果として`entry`型のpathが返された場合、Clientは必要なpathを取得し、一時的な発見結果として利用するかKnown Spaceへ保持できる。 \ No newline at end of file +検索能力を持つObjectのInterfaceが`query`や`search`などのOperationを宣言し、AIはそれを`invoke`する。結果として`entry`型のpathが返された場合、Clientは必要なpathを取得し、一時的な発見結果として利用するかKnown Spaceへ保持できる。 \ No newline at end of file diff --git a/draft/unresolved-issues.md b/draft/unresolved-issues.md index 513888c..e920dd3 100644 --- a/draft/unresolved-issues.md +++ b/draft/unresolved-issues.md @@ -6,29 +6,31 @@ 対象: [2.1. Object tree / Schema](../2.1-object-tree-schema.md) -- Object / エントリ公開情報の具体的なwire schema。 +- Object / エントリ公開情報とInterface参照の具体的なwire schema。 - `name`とpath segmentの関係。 - entry pathのcanonicalization規則。 -- `description`の長さや必須性をprotocol上でどこまで規定するか。 +- Object `description`の長さや必須性をprotocol上でどこまで規定するか。 ## 2.2. Operation / WIP IDL 対象: [2.2. Operation](../2.2-operation.md)、[WIP IDL](wip-idl.md) -- WIP IDL sourceのcanonicalization、digest algorithm、参照方法。 +- WIP IDL sourceのcanonicalization、digest algorithm、Interface参照の形式とscope。 - WIP IDLのversion間における互換性規則。 -- Sourceにdescriptionやdocumentation commentを含めるか。 - String length、numeric range、pattern等のconstraintを導入するか。 - Recursive named typeを許可するか。 - `i64`、`u64`、`bigint`、`decimal`等を追加するか。 -- `description`の必須性と長さ。 -- error型をOperation outputに含めるか、Protocol errorとして分離するか。 +- Operation documentationの必須性と長さ。 +- Effect annotationを採用するか、および構文と標準effectの集合。 +- `fail`を採用する場合のdomain failure表現。 +- domain errorをOperationのreturn typeに含めるか、Protocol errorとして分離するか。 ## WIP over HTTPS 対象: [WIP over HTTPS](wip-over-https.md) -- 複数の`fetch`をまとめるbatch request / responseのwire schema。 -- Invoke時に`included`を要求する方法と、Hostが自動同梱できる条件。 -- `included`のresponse size上限とtruncation表現。 -- `included`と個別の`fetch`で観測整合性情報をどう共有するか。 \ No newline at end of file +- `fetch_interface`のrequest / response wire schema。 +- Effect annotationを採用した場合に、副作用のない`call_operation`をbatch対象へ加えるか。 +- Batch件数、request / response byte size、timeoutの上限。 +- Batch envelope自体が不正な場合のHTTP statusとerror body。 +- Subrequest共通のProtocol error schema。 \ No newline at end of file diff --git a/draft/wip-idl.md b/draft/wip-idl.md index 602eadf..36320e5 100644 --- a/draft/wip-idl.md +++ b/draft/wip-idl.md @@ -1,16 +1,19 @@ # WIP IDL -WIP IDLは、Operationのinput / outputを記述するための小さなinterface definition languageである。 +WIP IDLは、Objectが実装するInterfaceを記述するための小さなinterface definition languageである。 -WIP IDLのsourceそのものをschemaのcanonicalな交換形式とする。HostとClientの間でJSON SchemaやIDLを変換したJSON ASTを交換することは前提としない。Clientはsourceをparseして内部表現を構築し、必要に応じてAI Tool schemaやGUI formへ投影する。 +一つのWIP IDL documentが一つのInterfaceを定義する。Documentに宣言された関数の集合が、そのInterfaceのOperation集合となる。Operation名、parameter、return type、documentationはIDL内の一つの宣言としてまとめ、別のOperation descriptorへ重複して記述しない。 + +WIP IDLのsourceそのものをInterface定義のcanonicalな交換形式とする。HostとClientの間でJSON SchemaやIDLを変換したJSON ASTを交換することは前提としない。Clientはsourceをparseして内部表現を構築し、必要に応じてAI Tool schemaやGUI formへ投影する。 この文書では、WIP IDLの初期文法と型を定義する。 ## 設計方針 -- Operation境界の型だけを表現する。 +- 一つのdocumentで一つのInterfaceを定義する。 +- Document内のOperation declarationを、そのInterfaceのOperation一覧とする。 +- Operationを関数として、parameterとreturn typeを一体で表現する。 - 文法を小さく保ち、一般的なschema validation languageにはしない。 -- Operationのinputは名前付きfieldを持つrecordとする。 - Wire上の値表現はTransport Bindingが定める。 - JSON SchemaはWIPの交換形式にせず、必要なClientが生成する。 - Worldspaceのエントリは、そのpathを表す`entry`型として扱う。 @@ -19,7 +22,16 @@ WIP IDLのsourceそのものをschemaのcanonicalな交換形式とする。Host WIP IDL sourceはUTF-8 textとする。ASCII space、tab、LFによる空白は、tokenを分離する場合を除いて意味を持たない。 -`//`から行末まではcommentとし、parserは無視する。 +`//`から行末までは通常のcommentとし、parserは無視する。 + +`///`から行末まではdocumentation commentとする。Operationまたはtype declarationの直前に連続するdocumentation commentは、そのdeclarationのdocumentationとしてparserが保持する。 + +```wip +/// Returns entries related to the target Object. +operation get_related_items() -> { + items: [entry], +}; +``` IdentifierはASCIIの英字または`_`で始まり、以降にASCIIの英数字または`_`を含められる。 @@ -29,7 +41,7 @@ identifier = (ALPHA | "_") { ALPHA | DIGIT | "_" }; Keyword、primitive type名、Worldspace固有型名はidentifierとして使用できない。 -Named typeにはUpperCamelCase、Operation、field、enum case、union caseにはsnake_caseを使用する。 +Named typeにはUpperCamelCase、Operation、parameter、field、enum case、union caseにはsnake_caseを使用する。 ## Grammar @@ -38,17 +50,21 @@ Named typeにはUpperCamelCase、Operation、field、enum case、union caseに ```ebnf document = { declaration } ; -declaration = type-declaration | operation-declaration ; +declaration = [ documentation ], + ( type-declaration | operation-declaration ) ; + +documentation = doc-comment, { doc-comment } ; type-declaration = "type", type-name, "=", type-definition, ";" ; type-definition = type-expression | enum-type | union-type ; operation-declaration = - "operation", identifier, "{", - "input", ":", type-expression, ";", - "output", ":", type-expression, ";", - "}" ; + "operation", identifier, + "(", [ parameter, { ",", parameter }, [ "," ] ], ")", + "->", type-expression, ";" ; + +parameter = identifier, [ "?" ], ":", type-expression ; type-expression = primitive-type @@ -86,13 +102,13 @@ worldspace-type = "entry" ; type-name = identifier ; ``` -同じdocument内でtype名またはOperation名を重複して宣言してはならない。Named typeは同じdocument内で宣言されたtypeを参照する。 +同じdocument内でtype名またはOperation名を重複して宣言してはならない。同じOperation内でparameter名を重複してはならない。Named typeは同じdocument内で宣言されたtypeを参照する。 ## Primitive types | Type | 意味 | WIP over HTTPSでの表現 | 制約 | | --- | --- | --- | --- | -| `unit` | 値を持たない | JSON `null` | Optional fieldの省略とは区別する | +| `unit` | 値を持たない | JSON `null` | Optional parameter / fieldの省略とは区別する | | `boolean` | 真偽値 | JSON boolean | — | | `integer` | 符号付き整数 | 小数部を持たないJSON number | `-9007199254740991`以上、`9007199254740991`以下 | | `number` | IEEE 754 binary64値 | JSON number | NaN、positive infinity、negative infinityは不可 | @@ -102,7 +118,7 @@ type-name = identifier ; `integer`の範囲は、異なる言語のClient間で正確に交換できる範囲に制限している。この範囲を超える整数は`integer`としてencodeしない。`i64`、`u64`、`bigint`等の追加型とlosslessなwire表現は将来の拡張として扱う。 -`json`は外部APIの応答など構造を事前に固定できない値のためのescape hatchであり、通常のOperation interfaceではより具体的な型を優先する。 +`json`は外部APIの応答など構造を事前に固定できない値のためのescape hatchであり、通常のOperationではより具体的な型を優先する。 ## Composite types @@ -119,13 +135,13 @@ type-name = identifier ; Recordは名前付きfieldの集合である。 ```wip -type Query = { - text: string, - limit?: integer, +type QueryResult = { + items: [entry], + next_cursor?: string, }; ``` -`?`を持たないfieldはrequired、`?`を持つfieldはoptionalである。Optionalはrecord fieldにのみ適用し、一般化しない。 +`?`を持たないfieldはrequired、`?`を持つfieldはoptionalである。Optionalはparameterまたはrecord fieldにのみ適用し、一般化しない。 WIP over HTTPSではrecordをJSON objectとしてencodeする。Optional fieldに値がない場合はfield自体を省略する。FieldをJSON `null`にすることは省略と同じ意味ではなく、そのfieldの型が`unit`または`json`として`null`を許す場合に限る。 @@ -210,7 +226,7 @@ Payloadを持たないcaseには`value`を含めない。 Wire上では通常の`string`と同じ表現だが、WIP IDL上で`entry`と宣言された位置にある値だけをClientがエントリとして認識する。通常の`string`やopaqueな`json`に含まれるpathらしい文字列を、Clientがエントリとして推測してはならない。 -Operation Resultから`entry`を発見したClientは、そのpathを一時的に利用し、必要に応じて`fetch`または`fetch_tree`する。複数のpathを効率的に取得するためのbatchingや、取得結果をinvoke responseへ同梱する最適化は、`entry`型のwire表現とは分離する。 +Operation Resultから`entry`を発見したClientは、そのpathを一時的に利用し、必要に応じて`fetch`または`fetch_tree`する。複数のpathを効率的に取得する場合は、Clientが必要なpathを選択した後、Transport Bindingが提供するbatchを利用する。Operation Resultへエントリ公開情報を先行同梱しない。 Operationが返したpathは、Operationの実行対象の子に限定されない。親、兄弟、関連Objectなど、Worldspace内の任意のエントリを指してよい。Operationの実行対象と返されたpathの間に、暗黙のTree edgeや意味的関係を推論してはならない。 @@ -218,7 +234,7 @@ Operationが返したpathは、Operationの実行対象の子に限定されな ## Operation declarations -Operationはinputとoutputをそれぞれ一つ宣言する。 +Operationは名前付きparameterとreturn typeを一つの関数宣言として定義する。 ```wip type Relation = enum { @@ -227,55 +243,93 @@ type Relation = enum { related, }; -operation get_related_item { - input: { - relation: Relation, - limit?: integer, - }; - - output: { - items: [entry], - next_cursor?: string, - }; -} +/// Returns entries related to the target Object. +operation get_related_items( + relation: Relation, + limit?: integer, +) -> { + items: [entry], + next_cursor?: string, +}; ``` -Operationのinputは、直接またはNamed typeを介してrecordへ解決されなければならない。位置引数は定義しない。 +Operationのparameterは、WIP over HTTPSでは一つのJSON objectへencodeする。Parameter名がobjectのfield名になる。位置引数は定義しない。 -引数を持たないOperationは空のrecordをinputにする。 +引数を持たないOperationは空のparameter listで宣言し、空のJSON objectをargumentsとして渡す。 ```wip -operation refresh { - input: {}; - output: unit; -} +operation refresh() -> unit; ``` -Outputには任意のtype expressionまたはNamed typeを使用できる。ただし、将来fieldを追加する可能性があるOperationではrecord outputを推奨する。 +Return typeには任意のtype expressionまたはNamed typeを使用できる。ただし、将来fieldを追加する可能性があるOperationではrecordを推奨する。 -Operationのnameやdescriptionなど、input / output型以外のinterface metadataとの対応付けは[Operation schema](../2.2-operation.md)で定義する。 +`///` documentation commentは、AIやユーザーがOperationの用途を判断するための短いdescriptionとして扱う。長文documentationをIDLへ埋め込むことは想定しない。 -## Schema exchange +## Effect annotation(検討案) -HostはOperation interfaceとともに、次のschema情報をClientへ提供する。 +Operationがdomain-levelな副作用や失敗を発生させ得ることを、関数宣言上のeffect rowとして表す案を検討する。この節は確定仕様ではなく、前掲のEBNFにもまだ含めない。 + +構文は、return typeの後に`! { ... }`を付ける形を候補とする。 + +```wip +operation get_item( + id: string, +) -> Item ! {}; + +operation update_item( + id: string, + value: Item, +) -> Item ! { + write, + fail, +}; +``` + +| Annotation | 意味の候補 | +| --- | --- | +| `! {}` | 宣言上、domain-levelな副作用およびfailureを持たない | +| `write` | 外部から観測可能な副作用を発生させ得る | +| `fail` | `E`型のdomain failureを返し得る | +| annotationなし | Effect情報が未指定 | + +Network error、authorization失敗、target消失、Protocol decode errorなど、すべてのremote callで起こり得るProtocol errorは`fail`に含めない。`fail`はOperation固有のdomain failureだけを表す候補とする。 + +Effect annotationは、ClientによるOperationの説明や、HTTP batchへ安全に含められるOperationの判定材料として利用できる可能性がある。ただし、具体的なbatch可否規則はまだ確定しない。 + +この案はKokaのeffect rowやUnisonのability requirementのように、関数が起こし得るeffectをsignatureへ表す記法を参考にしている。ただしWIP IDLへ導入するのは宣言上のannotationだけであり、effect handler、`perform`、continuation、resume、handlerへのnetwork転送、algebraic effect runtimeは導入しない。 + +## Interface identity and sharing + +一つのWIP IDL documentが一つのInterfaceを定義する。ObjectはOperation定義ではなく、そのInterfaceへの参照を持つ。 + +複数のObjectが同じInterface参照を共有できる。Clientは未知のInterfaceだけを`fetch_interface`で取得し、参照ごとにIDL sourceとparse済み表現をcacheできる。 + +Hostは主体のroleや権限に応じて異なるOperation集合を投影する場合、異なるWIP IDL documentとInterface参照を返してよい。Interfaceは頻繁に変化するOperationの実行可否を表すものではない。 + +Interface参照をcontent-addressed digestにすることが想定されるが、参照形式、sourceのcanonicalization、digest algorithmはTransport Bindingで定義する。 + +## Interface exchange + +HostはInterfaceについて、少なくとも次をClientへ提供する。 | 項目 | 内容 | | --- | --- | +| Interface reference | Objectが保持し、`fetch_interface`の対象となる参照 | | Language identifier | 初期versionは`wip-idl/1` | -| Source | WIP IDL source、またはsourceを取得するための参照 | +| Source | WIP IDL source | | Digest | Cacheと同一性確認に利用するdigest | -交換されるschemaの正本はWIP IDL sourceである。HostはJSON SchemaやIDL ASTを併記する必要はない。 +交換されるInterface定義の正本はWIP IDL sourceである。HostはJSON SchemaやIDL ASTを併記する必要はない。 ClientはIDLを内部ASTへparseし、必要に応じてAI provider用JSON Schema、GUI form、言語固有の型などを生成できる。 -Sourceのcanonicalization規則、digest algorithm、参照方法の詳細はTransport Bindingで定義する。 +ClientはObjectのInterface参照をcacheと比較し、未知のInterfaceだけを`fetch_interface`する。複数のInterface取得はTransport Bindingでbatchできる。HostはClientのcache状態を推測せず、ObjectのresponseへInterface定義を先行同梱しない。 ## 未解決事項 -- Sourceにdescriptionやdocumentation commentを含めるか。 +- Sourceのcanonicalizationとdigestの厳密な計算方法。 +- Interface参照の具体的な形式とscope。 - String length、numeric range、pattern等のconstraintを導入するか。 - Recursive named typeを許可するか。 - `i64`、`u64`、`bigint`、`decimal`等を追加するか。 -- Sourceのcanonicalizationとdigestの厳密な計算方法。 - `entry`が参照するpathのcanonicalization規則。 diff --git a/draft/wip-over-https.md b/draft/wip-over-https.md index 7f34ec9..e32e463 100644 --- a/draft/wip-over-https.md +++ b/draft/wip-over-https.md @@ -20,21 +20,24 @@ OperationがWebSocket等のendpointを通常のdomain valueとして返すこと - `fetch` - `fetch_tree` +- `fetch_interface` - `call_operation` 具体的なHTTP method、endpoint、content type、error mapping、認証方式、batch表現などは、このbinding仕様側で定義する。 -## WIP IDLの取得 +## Interfaceの取得 -Operationのinput / output schemaは[WIP IDL](wip-idl.md)のsourceとして交換する。HostはIDLのlanguage identifier、sourceまたはsourceを取得するための参照、およびcacheと同一性確認に利用できるdigestを公開する。 +Objectの公開情報はOperation定義を直接含まず、[WIP IDL](wip-idl.md) documentで定義されたInterfaceへの参照を持つ。`fetch_interface`は、その参照に対応するInterfaceのlanguage identifier、source、digestを返す。 HTTPS response全体をJSON envelopeにする場合、IDL sourceをJSON stringとして格納してよい。ただし、これはIDLをJSON ASTへ変換するものではない。BindingはIDL sourceを専用resourceおよびcontent typeで直接取得する方法を定義してもよい。 +ClientはObjectのInterface参照をcacheと比較し、未知のInterfaceだけを`fetch_interface`する。HostはClientのcache状態を推測せず、`fetch`や`fetch_tree`のresponseへInterface定義を先行同梱しない。複数のInterface取得はHTTP batchingでまとめられる。 + ## Operation valueのJSON encoding -WIP over HTTPSでは、`call_operation`のinputとoutputをWIP IDLに従うJSON valueとしてencodeする。JSONはHTTPS binding上の値表現であり、WIP Coreの型定義形式ではない。 +WIP over HTTPSでは、`call_operation`のargumentsとresultを、選択したOperation declarationに従うJSON valueとしてencodeする。JSONはHTTPS binding上の値表現であり、WIP CoreのInterface定義形式ではない。 -`input`は常に名前付きfieldを持つJSON objectとする。位置引数は用いず、引数を持たないOperationには空のobjectを渡す。 +`arguments`はOperationのparameter名をfield名とするJSON objectとする。位置引数は用いず、引数を持たないOperationには空のobjectを渡す。 概念的なrequest bodyは次の形になる。 @@ -42,7 +45,7 @@ WIP over HTTPSでは、`call_operation`のinputとoutputをWIP IDLに従うJSON { "target": "/items/current", "operation": "get_related_item", - "input": { + "arguments": { "relation": "sibling", "limit": 10 } @@ -52,7 +55,7 @@ WIP over HTTPSでは、`call_operation`のinputとoutputをWIP IDLに従うJSON IDL型からJSONへのmappingはbindingで一意に定める。少なくとも次の規則を持つ。 - `boolean`、`string`、`number`、record、listは対応するJSON valueで表す。 -- optionalなrecord fieldはfieldの省略で表し、`null`とは区別する。 +- optionalなparameterまたはrecord fieldはfieldの省略で表し、`null`とは区別する。 - unit形式のenumはstring、payloadを持つunionは明示的なdiscriminatorを持つobjectで表す。 - `bytes`はbase64でencodeしたstringとして表す。 - 通常のJSON numberで表す`integer`は相互運用可能な安全範囲に制限する。それを超える整数型を設ける場合はdecimal string等のlosslessな表現を定義する。 @@ -60,42 +63,90 @@ IDL型からJSONへのmappingはbindingで一意に定める。少なくとも ClientはWIP IDLに従ってvalueをdecodeし、IDL上で`entry`と宣言された位置にある文字列だけをエントリとして認識する。通常の`string`や任意JSON値に含まれるpathらしい文字列を、エントリとして推測してはならない。 -## Entry取得のbatching +## HTTP batching -Operation Resultに複数のentry pathが含まれる場合、Clientはそれらを抽出して重複を除去し、必要なpathを取得できる。 +WIP over HTTPSは、複数の独立したCore取得requestを一つのHTTP requestへまとめるbatch形式を提供する。Batchingは通信上のpackagingであり、Core Protocolへ新しい操作や意味論を追加しない。 -Core Protocol上では各`fetch`を独立した観測として扱う。WIP over HTTPSは、複数の`fetch`を一つのHTTP requestへまとめ、個別に実行した場合と同じ結果を返すbatch表現を定義してよい。Batchingは通信上の最適化であり、Core Protocolへ別の意味を追加しない。 +Clientは、Known SpaceとInterface cacheをもとに必要なrequestだけを選択してbatchを構成する。HostはClientの既知状態を推測して、要求されていないentry公開情報やInterface定義をresponseへ追加しない。 -## Invoke responseへの同梱 - -Hostは追加のround tripを避けるため、Operation Resultに含まれるentry pathの公開情報を、invoke responseの`included` sidecarへ同梱してよい。 +Batch endpointは概念的に`POST {wip-endpoint}/batch`とし、bodyに一意な`id`を持つsubrequestの配列を格納する。 ```json { - "output": { - "items": [ - "/items/123", - "/items/456" - ] - }, - "included": { - "/items/123": { - "type": "item", - "description": "First item", - "operations": [] + "requests": [ + { + "id": "entry-123", + "method": "fetch", + "arguments": { + "entry": "/items/123" + } }, - "/items/456": { - "type": "item", - "description": "Second item", - "operations": [] + { + "id": "entry-456", + "method": "fetch", + "arguments": { + "entry": "/items/456" + } + }, + { + "id": "item-interface", + "method": "fetch_interface", + "arguments": { + "interface": "sha256:item-interface" + } } - } + ] } ``` -`included`のkeyはOperation Resultに現れるcanonical entry path、valueは同じpathに対する通常の`fetch`結果と同じ観測とする。`included`はOperationのtyped outputには含まれず、Operationのoutput schemaを変更しない。 +Hostは各subrequestを、単独で受け取った場合と同じ規則で処理する。Responseは同じ`id`で対応付けたsubresponseの配列を返す。 -Clientは`included`をfetch済みの観測として利用しても、無視して改めて取得してもよい。Clientが同梱を要求する方法、Hostが自動的に同梱できる条件、response sizeの上限はbindingの詳細として定める。 +```json +{ + "responses": [ + { + "id": "entry-123", + "result": { + "name": "123", + "description": "First item", + "interface": "sha256:item-interface" + } + }, + { + "id": "entry-456", + "error": { + "code": "not_found", + "message": "Entry not found" + } + }, + { + "id": "item-interface", + "result": { + "interface": "sha256:item-interface", + "language": "wip-idl/1", + "digest": "sha256:item-interface", + "source": "..." + } + } + ] +} +``` + +Batchには次の規則を適用する。 + +- Request内の`id`は一意なstringとする。 +- Responseの順序に意味を持たせず、`id`でcorrelateする。 +- 各subrequestは独立して成功または失敗し、一つの失敗によって他のresultを破棄しない。 +- Batch全体はtransactionではなく、atomicity、共通snapshot、実行順序を保証しない。 +- Hostはsubrequestを直列または並列に実行してよい。 +- Subrequest間で、先行requestのresultを後続requestのargumentsとして参照できない。 +- 各`result`は対応するCore操作を単独で呼んだ場合と同じvalueとする。 +- 各`error`は通常のProtocol errorと同じschemaを使用する。 +- HostはClientが要求していないsubresponseを追加してはならない。 + +初期のbatch形式に格納できるのは`fetch`、`fetch_tree`、`fetch_interface`とし、`call_operation`は含めない。将来、WIP IDLのEffect annotationを採用する場合に、副作用を持たないと明示されたOperationをbatch対象へ加えるかを改めて検討する。 + +Batch件数、request / response byte size、timeoutの上限、およびbatch envelope自体が不正な場合のHTTP statusはbindingの詳細として定める。 ## 非目標