@skyold/protocol-engine 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +466 -0
- package/README.zh-CN.md +309 -0
- package/dist/contracts.d.ts +84 -0
- package/dist/contracts.js +1 -0
- package/dist/engine.d.ts +4 -0
- package/dist/engine.js +352 -0
- package/dist/errors.d.ts +38 -0
- package/dist/errors.js +68 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/target-binding.d.ts +12 -0
- package/dist/target-binding.js +29 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright 2026 TokenForge Contributors
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
# TokenForge Protocol Engine
|
|
2
|
+
|
|
3
|
+
[简体中文](./README.zh-CN.md) | English
|
|
4
|
+
|
|
5
|
+
> **New to the Engine?** Start with the practical
|
|
6
|
+
> [Protocol Engine usage guide](../../docs/guides/PROTOCOL_ENGINE.md) (Simplified
|
|
7
|
+
> Chinese). It includes the supported/unsupported matrix, annotated sync,
|
|
8
|
+
> stream, and async examples, architecture diagrams, and the request sequence.
|
|
9
|
+
> This manual remains the complete API and evidence-boundary reference.
|
|
10
|
+
|
|
11
|
+
`@skyold/protocol-engine` is a Host-neutral execution kernel for AI model
|
|
12
|
+
aggregation. Any application, service, or library that implements the V1 port
|
|
13
|
+
contract can embed it. The Engine neither recognizes nor enumerates external
|
|
14
|
+
application types, and does not import a caller's HTTP framework, database,
|
|
15
|
+
identity model, credentials, pricing, usage store, or settlement policy.
|
|
16
|
+
|
|
17
|
+
In this manual, **Host** means only the abstract role that embeds and calls the
|
|
18
|
+
Engine. It does not identify a particular product or deployment shape.
|
|
19
|
+
|
|
20
|
+
## Module status
|
|
21
|
+
|
|
22
|
+
The Engine is an independent workspace package with one package-root ESM API,
|
|
23
|
+
its own TypeScript build, its own test command, and one runtime dependency:
|
|
24
|
+
`@skyold/model-protocol`. It does not depend on any embedding Host,
|
|
25
|
+
concrete Provider Adapters, storage, HTTP frameworks, credential stores, or
|
|
26
|
+
network clients.
|
|
27
|
+
|
|
28
|
+
The package and its normalized-contract dependency are configured for public
|
|
29
|
+
npm access, but no registry release has been made yet. Therefore:
|
|
30
|
+
|
|
31
|
+
- it is independently embeddable and testable by packages in this repository;
|
|
32
|
+
- its packed runtime surface is independently inspectable;
|
|
33
|
+
- packed tarballs can be installed and exercised by an isolated external
|
|
34
|
+
consumer;
|
|
35
|
+
- public registry availability, a versioned release, and provenance signing are
|
|
36
|
+
not claimed until the release gate completes.
|
|
37
|
+
|
|
38
|
+
The local V1 core implementation is complete against its frozen execution
|
|
39
|
+
boundary. Overall rollout certification is still incomplete: fixture-backed
|
|
40
|
+
conformance is green for all nine built-in protocol families, while current
|
|
41
|
+
real-Provider success evidence covers seven. `openai-embeddings/v1` and
|
|
42
|
+
`openai-images/v1` still require successful real-Provider certification.
|
|
43
|
+
Public release, exact-SHA CI, and deployment are separate delivery gates, not
|
|
44
|
+
reasons to add Host business logic to the Engine.
|
|
45
|
+
|
|
46
|
+
Run its complete package-local gate from the repository root or package
|
|
47
|
+
directory:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pnpm --dir packages/protocol-engine check
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Embed V1
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import {
|
|
57
|
+
createProtocolEngineTargetBindingV1,
|
|
58
|
+
createProtocolEngineV1,
|
|
59
|
+
isProtocolEngineErrorV1,
|
|
60
|
+
type ProtocolEngineAdapterRegistryPortV1,
|
|
61
|
+
} from '@skyold/protocol-engine';
|
|
62
|
+
|
|
63
|
+
const registry: ProtocolEngineAdapterRegistryPortV1 = createMyRegistry();
|
|
64
|
+
const binding = createProtocolEngineTargetBindingV1({
|
|
65
|
+
target: resolvedTarget,
|
|
66
|
+
bindTransport: (signal) => bindCredentialTransport(resolvedTarget, signal),
|
|
67
|
+
});
|
|
68
|
+
const engine = createProtocolEngineV1({ registry });
|
|
69
|
+
const execution = await engine.execute({ binding, task, signal });
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Hosts construct the request-bound execution binding with
|
|
73
|
+
`createProtocolEngineTargetBindingV1({ target, bindTransport })`. The factory
|
|
74
|
+
checks the Engine-requested `connectionRef` against the resolved target before
|
|
75
|
+
delegating credential-bound Transport creation, preventing a target from being
|
|
76
|
+
executed with another connection.
|
|
77
|
+
|
|
78
|
+
Every V1 Registry exposes `listProtocolFamilies()`. The Engine snapshots that
|
|
79
|
+
inventory as the sorted, immutable `engine.protocolFamilies` view, so embedded
|
|
80
|
+
Hosts, conformance tooling, and certification use the same extension contract.
|
|
81
|
+
The snapshot is also the dispatch authority: execute and async-job operations
|
|
82
|
+
reject undeclared families, and a returned Factory must declare exactly the
|
|
83
|
+
requested family before Transport binding.
|
|
84
|
+
|
|
85
|
+
The Host resolves identity, policy, target, and credentials before constructing
|
|
86
|
+
the binding; authenticated Host context never enters the Engine API. Host
|
|
87
|
+
governance runs before the Engine call, while usage, audit, and settlement
|
|
88
|
+
consume its returned normalized facts afterwards.
|
|
89
|
+
|
|
90
|
+
“Unified” means that every embedding consumer uses this same execution lifecycle
|
|
91
|
+
and public contract. It does not merge external application orchestration or move
|
|
92
|
+
identity, routing, credential, governance, usage, or settlement responsibilities
|
|
93
|
+
into the Engine. Consumers may resolve targets differently; after resolution,
|
|
94
|
+
each supplies the same narrow task, target binding, Registry, and Transport ports.
|
|
95
|
+
|
|
96
|
+
The target's `provider` value is opaque compatibility identity data, not Engine
|
|
97
|
+
dispatch authority. Engine core may carry it into protocol capability
|
|
98
|
+
validation, but must never select behavior by Provider name. This distinction
|
|
99
|
+
matters for semantic facts such as embedding compatibility spaces, where two
|
|
100
|
+
otherwise similar models can produce incompatible vectors. Adding another
|
|
101
|
+
Provider for an existing protocol therefore requires no Engine change; adding
|
|
102
|
+
another model usually changes only Host catalog/capability facts; adding a new
|
|
103
|
+
protocol adds its Codec, Adapter, Registry declaration, and conformance cases
|
|
104
|
+
without adding a Provider or Host branch to Engine core.
|
|
105
|
+
|
|
106
|
+
The binding exposes only the dispatch fields the Engine uses: Provider, model,
|
|
107
|
+
connection reference, and protocol/model capability. Host-only `sourceId` and
|
|
108
|
+
`capabilityId` remain beside the call in the Host. Engine execution and job
|
|
109
|
+
results do not echo the target back.
|
|
110
|
+
|
|
111
|
+
## Public API reference
|
|
112
|
+
|
|
113
|
+
Import every API from the package root. Source and `dist` subpaths are private.
|
|
114
|
+
|
|
115
|
+
### Runtime exports
|
|
116
|
+
|
|
117
|
+
| Export | Purpose |
|
|
118
|
+
| -------------------------------------------- | ----------------------------------------------------------------------- |
|
|
119
|
+
| `PROTOCOL_ENGINE_API_VERSION` | Exact V1 identifier: `tokenforge-protocol-engine/v1`. |
|
|
120
|
+
| `PROTOCOL_ENGINE_ERROR_CODES_V1` | Frozen inventory of stable V1 Engine failure codes. |
|
|
121
|
+
| `ProtocolEngineErrorV1` | Versioned error class for Engine operation failures. |
|
|
122
|
+
| `isProtocolEngineErrorV1(error)` | Cross-realm-safe guard for the public V1 error shape. |
|
|
123
|
+
| `createProtocolEngineV1({ registry })` | Creates an immutable Engine view over one Adapter Registry inventory. |
|
|
124
|
+
| `createProtocolEngineTargetBindingV1(input)` | Binds one resolved target to one request-scoped Host Transport factory. |
|
|
125
|
+
|
|
126
|
+
### Exported types
|
|
127
|
+
|
|
128
|
+
| Type group | Exports |
|
|
129
|
+
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
130
|
+
| Engine | `ProtocolEngineV1`, `ProtocolEngineApiVersion`, `ProtocolEngineAdapterRegistryPortV1` |
|
|
131
|
+
| Execute input | `ProtocolEngineExecuteInputV1`, `ProtocolEngineDispatchTargetV1`, `ProtocolEngineTargetBindingV1`, `CreateProtocolEngineTargetBindingInputV1` |
|
|
132
|
+
| Execute output | `ProtocolEngineExecutionV1`, `ProtocolEngineResponseV1`, `ProtocolEngineStreamV1`, `ProtocolEngineAcceptedJobV1`, `ProtocolEngineRejectedV1` |
|
|
133
|
+
| Async jobs | `ProtocolEngineAsyncJobsV1`, `ProtocolEngineAsyncJobInputV1`, `ProtocolEngineAsyncJobListRequestV1`, `ProtocolEngineAsyncJobObservationV1`, `ProtocolEngineAsyncJobListResultV1`, `ProtocolEngineAsyncJobCancellationV1` |
|
|
134
|
+
| Errors | `ProtocolEngineErrorV1`, `ProtocolEngineErrorCodeV1`, `ProtocolEngineErrorPhaseV1`, `ProtocolEngineErrorOptionsV1` |
|
|
135
|
+
|
|
136
|
+
Normalized task, capability, Adapter, Transport, result, stream-event, usage,
|
|
137
|
+
and job-snapshot types come from `@skyold/model-protocol`; the Engine does
|
|
138
|
+
not duplicate those contracts.
|
|
139
|
+
|
|
140
|
+
### `createProtocolEngineV1`
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const engine = createProtocolEngineV1({ registry });
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The injected Registry implements:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
interface ProtocolEngineAdapterRegistryPortV1 {
|
|
150
|
+
listProtocolFamilies(): readonly ProtocolFamily[];
|
|
151
|
+
require(protocolFamily: ProtocolFamily): ProviderAdapterFactory;
|
|
152
|
+
requireAsync?(protocolFamily: ProtocolFamily): ProviderAsyncJobAdapterFactory;
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Construction snapshots, sorts, validates, and freezes the protocol inventory.
|
|
157
|
+
Duplicate or malformed families fail immediately. `require()` handles sync and
|
|
158
|
+
stream execution. `requireAsync()` is required only for asynchronous job
|
|
159
|
+
families.
|
|
160
|
+
|
|
161
|
+
TokenForge Hosts normally obtain the Registry from the coherent built-in suite:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
import { createBuiltinTokenForgeProtocolSuiteV1 } from '@skyold/provider-adapters';
|
|
165
|
+
import { createProtocolEngineV1 } from '@skyold/protocol-engine';
|
|
166
|
+
|
|
167
|
+
const suite = createBuiltinTokenForgeProtocolSuiteV1();
|
|
168
|
+
const engine = createProtocolEngineV1({ registry: suite.registry });
|
|
169
|
+
console.log(engine.apiVersion);
|
|
170
|
+
console.log(engine.protocolFamilies);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`engine.protocolFamilies` is the authoritative runtime inventory; do not copy a
|
|
174
|
+
separate protocol allowlist into a Host.
|
|
175
|
+
|
|
176
|
+
### Target binding
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
const binding = createProtocolEngineTargetBindingV1({
|
|
180
|
+
target: {
|
|
181
|
+
provider: 'opaque-provider-identity',
|
|
182
|
+
providerModel: 'resolved-provider-model',
|
|
183
|
+
connectionRef: 'host-owned-connection-reference',
|
|
184
|
+
capability: resolvedProtocolCapability,
|
|
185
|
+
},
|
|
186
|
+
bindTransport: (signal) => createCredentialBoundTransport({ resolvedConnection, signal }),
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The Host must finish authentication, routing, target selection, credential
|
|
191
|
+
lookup, URL safety policy, and governance before creating this binding. The
|
|
192
|
+
binding rejects connection-reference substitution before credentials or
|
|
193
|
+
network access are possible. Never store a tenant/account-specific Transport
|
|
194
|
+
inside a shared Registry or Engine.
|
|
195
|
+
|
|
196
|
+
### `engine.execute`
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
const execution = await engine.execute({
|
|
200
|
+
binding,
|
|
201
|
+
task,
|
|
202
|
+
signal,
|
|
203
|
+
// preparedMedia, // optional image-edit media prepared by the Host
|
|
204
|
+
// providerCallbackUrl, // optional async Provider callback selected by the Host
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
| Input | Meaning |
|
|
209
|
+
| --------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
210
|
+
| `binding` | Resolved target plus request-bound Transport binder. |
|
|
211
|
+
| `task` | Normalized `TaskEnvelopeV2`; raw HTTP requests do not enter the Engine. |
|
|
212
|
+
| `signal` | Request cancellation signal propagated to Transport and stream/async start. |
|
|
213
|
+
| `preparedMedia` | Optional bounded, validated media streams used by protocols such as image editing. |
|
|
214
|
+
| `providerCallbackUrl` | Optional async-job callback URL; lifecycle persistence and callback handling remain Host responsibilities. |
|
|
215
|
+
|
|
216
|
+
Handle the complete discriminated union rather than assuming every model is a
|
|
217
|
+
synchronous Chat model:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
switch (execution.kind) {
|
|
221
|
+
case 'response': {
|
|
222
|
+
consumeTerminal(execution.terminal);
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
case 'stream': {
|
|
226
|
+
try {
|
|
227
|
+
for await (const event of execution.events) consumeNormalizedEvent(event);
|
|
228
|
+
consumeTerminal(await execution.terminal);
|
|
229
|
+
} catch (error) {
|
|
230
|
+
execution.abort(error);
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
case 'accepted-job': {
|
|
236
|
+
persistAcceptedJob(execution.providerJobId);
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
case 'rejected': {
|
|
240
|
+
recordRejectedStart(execution.failureCode, execution.acceptance.state);
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
`response` and `stream` terminal facts are already normalized and runtime
|
|
247
|
+
validated. `accepted-job` means the Provider durably accepted the job.
|
|
248
|
+
`rejected` includes both known rejection and acceptance-unknown; a Host must not
|
|
249
|
+
blindly retry an acceptance-unknown create because that can duplicate work.
|
|
250
|
+
|
|
251
|
+
### `engine.jobs`
|
|
252
|
+
|
|
253
|
+
Use the same target binding for the Provider job that was previously accepted:
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
const observation = await engine.jobs.get({ binding, providerJobId, signal });
|
|
257
|
+
|
|
258
|
+
const page = await engine.jobs.list({
|
|
259
|
+
binding,
|
|
260
|
+
pageNum: 1,
|
|
261
|
+
pageSize: 20,
|
|
262
|
+
signal,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
await engine.jobs.cancel({ binding, providerJobId, signal });
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
The Engine validates returned snapshots and lists. Job ownership, persistence,
|
|
269
|
+
polling schedules, callback reconciliation, result materialization, usage, and
|
|
270
|
+
settlement remain Host-owned.
|
|
271
|
+
|
|
272
|
+
### Failure behavior
|
|
273
|
+
|
|
274
|
+
Invalid Registry inventories, target/task mismatches, unsupported capabilities,
|
|
275
|
+
connection substitution, malformed Adapter output, and Transport binding
|
|
276
|
+
failures reject the operation before unsafe facts reach the Host. Every Engine
|
|
277
|
+
operation failure uses `ProtocolEngineErrorV1` with the same
|
|
278
|
+
`tokenforge-protocol-engine/v1` API version, a stable `code`, and one structural
|
|
279
|
+
phase: `configuration`, `input`, `transport`, `adapter`, or `lifecycle`.
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
try {
|
|
283
|
+
await engine.execute({ binding, task, signal });
|
|
284
|
+
} catch (error) {
|
|
285
|
+
if (!isProtocolEngineErrorV1(error)) throw error;
|
|
286
|
+
hostMapEngineFailure(error.code, error.phase);
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
`cause` is diagnostic-only and can contain Host Transport or Adapter details;
|
|
291
|
+
never serialize it or a raw exception message to clients. The enumerable public
|
|
292
|
+
classification does not include Provider payloads, credentials, retry policy,
|
|
293
|
+
HTTP status, tenant facts, usage, pricing, or settlement decisions. Hosts own
|
|
294
|
+
those mappings. Historical fixed-runtime messages remain temporarily compatible,
|
|
295
|
+
but new integrations must switch on `code`, never `message`.
|
|
296
|
+
|
|
297
|
+
The Engine validates the normalized task against the resolved capability,
|
|
298
|
+
selects the protocol Adapter, and returns one versioned execution start:
|
|
299
|
+
|
|
300
|
+
- `response` for synchronous terminal execution;
|
|
301
|
+
- `stream` for normalized events, a terminal promise, and cancellation;
|
|
302
|
+
- `accepted-job` for durable asynchronous Provider acceptance;
|
|
303
|
+
- `rejected` for not-accepted or acceptance-unknown asynchronous starts.
|
|
304
|
+
|
|
305
|
+
Use `engine.jobs.get`, `engine.jobs.list`, and `engine.jobs.cancel` for later
|
|
306
|
+
async-job operations. Persistence, polling, callbacks, materialization, usage,
|
|
307
|
+
and settlement remain Host responsibilities.
|
|
308
|
+
|
|
309
|
+
An async Adapter factory declares its supported follow-up operations with
|
|
310
|
+
`jobOperations`. The Engine rejects an undeclared operation with
|
|
311
|
+
`PROTOCOL_ENGINE_CAPABILITY_UNSUPPORTED` before binding a Transport. Protocols
|
|
312
|
+
therefore keep their real lifecycle differences: for example, a protocol may
|
|
313
|
+
support `get` without pretending to support `list` or `cancel`.
|
|
314
|
+
|
|
315
|
+
### Provider response compatibility
|
|
316
|
+
|
|
317
|
+
Provider wire responses are an open-world boundary. An Adapter validates and
|
|
318
|
+
extracts the fields understood by its protocol version, ignores additive fields
|
|
319
|
+
in synchronous bodies and known stream frames, and never retains those unknown
|
|
320
|
+
fields in normalized output. This lets a Provider add response metadata without
|
|
321
|
+
breaking an otherwise compatible protocol implementation.
|
|
322
|
+
|
|
323
|
+
Compatibility does not turn malformed known facts into success. Missing,
|
|
324
|
+
mistyped, conflicting, duplicated, unsafe, or semantically invalid known fields
|
|
325
|
+
still fail. An unknown stream event kind can alter lifecycle semantics, so it is
|
|
326
|
+
not treated as a harmless additive field and fails unless the protocol Adapter
|
|
327
|
+
explicitly supports it. Parser depth, body-size, URL, base64, index, usage, and
|
|
328
|
+
terminal-consistency limits remain enforced.
|
|
329
|
+
|
|
330
|
+
The Engine then validates Adapter outputs before exposing them to a Host. This
|
|
331
|
+
includes sync/stream acceptance, terminal structure and consistency, every
|
|
332
|
+
normalized stream event, plus async start, snapshot, and list result structure.
|
|
333
|
+
Normalized event, metadata, terminal, result, usage, Responses, and async-job
|
|
334
|
+
objects are closed schemas: undeclared fields are rejected. Raw Provider
|
|
335
|
+
extensions therefore cannot leak through an Adapter to Host egress, usage, or
|
|
336
|
+
settlement.
|
|
337
|
+
|
|
338
|
+
Terminal results must match the requested Task kind, and duplicate result,
|
|
339
|
+
terminal, and Responses usage facts must agree when present. A custom Adapter
|
|
340
|
+
therefore cannot rely on TypeScript casts to bypass the V1 runtime contract or
|
|
341
|
+
make Host egress and settlement observe different facts.
|
|
342
|
+
|
|
343
|
+
## Extension rule
|
|
344
|
+
|
|
345
|
+
A new protocol implements the shared ingress/egress Codec and Adapter factory
|
|
346
|
+
contracts, registers Host Transport metadata, and includes them in one coherent
|
|
347
|
+
Protocol Suite. Engine core must not gain Provider-name, model-name, tenant, or
|
|
348
|
+
Host-framework branches. Embedded consumers may inject a custom Registry;
|
|
349
|
+
The TokenForge repository provides `createBuiltinTokenForgeProtocolSuiteV1()`
|
|
350
|
+
from `@skyold/provider-adapters` as its built-in implementation. Custom suites use
|
|
351
|
+
`createTokenForgeProtocolSuiteV1()`, which validates Adapter/Transport and
|
|
352
|
+
direct Ingress/Egress inventories before an Engine can consume the Registry.
|
|
353
|
+
TokenForge's built-in composition additionally declares direct-HTTP
|
|
354
|
+
participation beside each Adapter/Transport entry and rejects a declaration /
|
|
355
|
+
Codec inventory mismatch. Every embedding integration performs only Registry
|
|
356
|
+
lookup; a new protocol must not add an application-type or Host protocol-family
|
|
357
|
+
branch.
|
|
358
|
+
|
|
359
|
+
Consumers import only the `@skyold/protocol-engine` package root. Internal
|
|
360
|
+
source or build subpaths are not part of V1 and are rejected by the repository
|
|
361
|
+
architecture gate. The packed artifact allowlists only the five production
|
|
362
|
+
modules behind that root plus the English and Simplified Chinese manuals; tests
|
|
363
|
+
and other repository internals are not shipped.
|
|
364
|
+
|
|
365
|
+
The stable contract identifier is `tokenforge-protocol-engine/v1`. Breaking
|
|
366
|
+
contract changes require a new API version rather than changing V1 semantics.
|
|
367
|
+
|
|
368
|
+
## Testing and proof levels
|
|
369
|
+
|
|
370
|
+
No test suite can mathematically guarantee all future Engine functionality.
|
|
371
|
+
TokenForge uses separate proof layers so a narrow unit test is not mistaken for
|
|
372
|
+
complete proxy evidence.
|
|
373
|
+
|
|
374
|
+
| Layer | Command | What it proves | What it does not prove |
|
|
375
|
+
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
|
376
|
+
| Engine package | `pnpm --dir packages/protocol-engine check` | Independent build plus core Registry, binding, sync, stream, async-job, validation and Host-equivalence tests. | Concrete Adapter wire formats, Host persistence, live network. |
|
|
377
|
+
| Built-in conformance | `pnpm --filter @skyold/provider-adapters test -- src/conformance/runtime-conformance.test.ts` | Every registered built-in family executes through public Engine API with fixture Transports. | Provider credentials or current remote behavior. |
|
|
378
|
+
| Architecture boundary | `pnpm --filter @tokenforge/acceptance test -- src/L1-kernel/import-boundary.test.ts` | Engine dependency isolation, package surface, no raw-forward/direct Adapter bypass, Host neutrality. | Runtime semantic correctness by itself. |
|
|
379
|
+
| Host integration | Targeted suites for each embedding application and repository `pnpm check` | Caller-specific context binding, streams, media persistence, usage and settlement compatibility. | Exact deployed SHA or live Provider availability. |
|
|
380
|
+
| Real Provider certification | `pnpm certify:protocol-engine-real --manifest /protected/path/suite.json --run --env-file .env --ack-real-provider-calls I_AUTHORIZE_REAL_PROVIDER_CALLS` | Current authenticated Provider behavior for every successful evidence shard. | Deployment, billing correctness, or a missing family. |
|
|
381
|
+
|
|
382
|
+
For a local Engine change, the minimum independent gate is the Engine package
|
|
383
|
+
command. A protocol or Adapter change must also pass built-in conformance. A
|
|
384
|
+
Host integration change must additionally pass the affected Host suites. The
|
|
385
|
+
full goal is not complete until the Registry inventory has successful real
|
|
386
|
+
Provider evidence and the exact delivered SHA passes its CI and deployment
|
|
387
|
+
gates.
|
|
388
|
+
|
|
389
|
+
## Real-Provider certification
|
|
390
|
+
|
|
391
|
+
The repository's opt-in certification Host drives this public Engine API and
|
|
392
|
+
the built-in Adapter Registry directly; it does not enter through any product
|
|
393
|
+
application route. A versioned JSON manifest supplies one or more cases for every
|
|
394
|
+
protocol family returned by `engine.protocolFamilies`, with resolved target and
|
|
395
|
+
capability facts, normalized tasks, secret environment-variable names, exact
|
|
396
|
+
Provider domains, and suite request/time ceilings. Pricing and Provider billing
|
|
397
|
+
are deliberately absent from both the Engine contract and certification facts.
|
|
398
|
+
|
|
399
|
+
Validation is offline and is the default:
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
pnpm certify:protocol-engine-real --manifest /protected/path/suite.json
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Real execution additionally requires `--run`, an environment file, and the
|
|
406
|
+
exact CLI authorization
|
|
407
|
+
`--ack-real-provider-calls I_AUTHORIZE_REAL_PROVIDER_CALLS`. The CLI derives the
|
|
408
|
+
runtime domain allowlist from the already validated manifest and loads every
|
|
409
|
+
named key through its environment reference. The runner rejects private or
|
|
410
|
+
metadata network targets, cross-origin redirects, incomplete protocol
|
|
411
|
+
coverage, and request/time ceiling violations. It never prints prompts, keys,
|
|
412
|
+
Provider request IDs, job IDs, Provider names, or model names; durable evidence
|
|
413
|
+
is mode `0600` and contains only protocol facts, terminal state, numeric usage,
|
|
414
|
+
counts, and truncated SHA-256 fingerprints.
|
|
415
|
+
Generated manifests set the request ceiling to the exact worst case derived
|
|
416
|
+
from their cases. CLI summaries report execution starts separately from async
|
|
417
|
+
job list/get observation requests; neither field is a price, rate card, or
|
|
418
|
+
settlement input.
|
|
419
|
+
Cancellation is intentionally absent because it can destroy an externally
|
|
420
|
+
created job; it remains a separately authorized Provider lifecycle check.
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
pnpm certify:protocol-engine-real --manifest /protected/path/suite.json --run \
|
|
424
|
+
--env-file .env \
|
|
425
|
+
--ack-real-provider-calls I_AUTHORIZE_REAL_PROVIDER_CALLS
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Passing local validation proves that the suite is structurally ready, not that
|
|
429
|
+
any Provider was called. Only a completed `--run` artifact is real-Provider
|
|
430
|
+
evidence.
|
|
431
|
+
|
|
432
|
+
For a list-capable async target that has already been accepted, the Acceptance
|
|
433
|
+
Host can perform a one-request, read-only diagnostic through `engine.jobs.list`
|
|
434
|
+
without creating another task:
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
pnpm --filter @tokenforge/acceptance diagnose:protocol-engine-real-async \
|
|
438
|
+
--manifest /protected/path/async-shard.json \
|
|
439
|
+
--env-file /protected/path/provider.env \
|
|
440
|
+
--created-after 2026-08-18T03:00:00.000Z \
|
|
441
|
+
--ack-real-provider-calls I_AUTHORIZE_REAL_PROVIDER_CALLS
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
The diagnostic reports only protocol family, matching count, normalized status
|
|
445
|
+
counts and bounded Provider error codes. It never emits Provider job IDs,
|
|
446
|
+
models, URLs, response messages or bodies and cannot satisfy a certification
|
|
447
|
+
gate.
|
|
448
|
+
|
|
449
|
+
When a list-capable asynchronous shard stopped only because bounded polling was
|
|
450
|
+
exhausted after the Provider had accepted the task, recover that exact submitted
|
|
451
|
+
task without creating another one:
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
pnpm --filter @tokenforge/acceptance recover:protocol-engine-real-shard \
|
|
455
|
+
--manifest /protected/path/async-shard.json \
|
|
456
|
+
--failure-evidence /protected/path/polling-exhausted.json \
|
|
457
|
+
--env-file /protected/path/provider.env \
|
|
458
|
+
--output /protected/path/recovered-success.json \
|
|
459
|
+
--ack-real-provider-calls I_AUTHORIZE_REAL_PROVIDER_CALLS
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
Recovery accepts only matching polling-exhaustion evidence, performs one
|
|
463
|
+
read-only `engine.jobs.list`, and requires exactly one matching job inside the
|
|
464
|
+
original submission window. It never resubmits the task or emits raw job IDs.
|
|
465
|
+
Only a normalized `succeeded` snapshot produces standard success evidence;
|
|
466
|
+
other states remain non-success evidence.
|