@byok-sdk/protocol 0.1.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 +21 -0
- package/README.md +10 -0
- package/dist/agent-event.d.ts +146 -0
- package/dist/blob.d.ts +24 -0
- package/dist/codec.d.ts +116 -0
- package/dist/envelope.d.ts +333 -0
- package/dist/errors.d.ts +25 -0
- package/dist/http-api.d.ts +725 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +432 -0
- package/dist/index.js.map +1 -0
- package/dist/messages.d.ts +646 -0
- package/dist/permission.d.ts +39 -0
- package/dist/task-state.d.ts +21 -0
- package/dist/version.d.ts +70 -0
- package/package.json +49 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const TASK_STATES: readonly ['Offered', 'Claimed', 'Running', 'AwaitApproval', 'Complete', 'Failed', 'Cancelled'];
|
|
2
|
+
export type TaskState = (typeof TASK_STATES)[number];
|
|
3
|
+
/**
|
|
4
|
+
* Legal state transitions for a task. `Complete` / `Failed` / `Cancelled` are
|
|
5
|
+
* terminal (no outgoing edges). `Running` and `AwaitApproval` form a loop:
|
|
6
|
+
* the daemon can request approval mid-run and resume once the server
|
|
7
|
+
* approves (or fail/cancel out of the approval wait).
|
|
8
|
+
*
|
|
9
|
+
* `Offered -> Failed` (M1 gap #5, "Declined vs. Failed"): a daemon that
|
|
10
|
+
* declines an offer pre-claim (`task.decline`) reports it through the
|
|
11
|
+
* existing `Failed` state rather than a new `Declined` state. A decline and
|
|
12
|
+
* a post-claim failure are the same outcome from the dispatcher's point of
|
|
13
|
+
* view — this attempt produced no result, `reason`/`retryable` say why and
|
|
14
|
+
* whether retrying elsewhere makes sense — so reusing `Failed` keeps the
|
|
15
|
+
* state machine minimal instead of forking every terminal-state consumer
|
|
16
|
+
* into "Failed or Declined, handle both". See docs/protocol.md for the full
|
|
17
|
+
* writeup.
|
|
18
|
+
*/
|
|
19
|
+
export declare const TASK_TRANSITIONS: Readonly<Record<TaskState, readonly TaskState[]>>;
|
|
20
|
+
/** Whether `from -> to` is a legal transition per {@link TASK_TRANSITIONS}. */
|
|
21
|
+
export declare function canTransition(from: TaskState, to: TaskState): boolean;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire protocol version. Bump on breaking (non-additive) changes to the envelope
|
|
3
|
+
* or message shapes. Additive changes (new optional fields, new message types)
|
|
4
|
+
* do not require a bump — servers negotiate the highest common version and
|
|
5
|
+
* daemons/servers must ignore unknown fields and unknown message types.
|
|
6
|
+
*
|
|
7
|
+
* FROZEN v1 (end of M2 — see docs/protocol.md "Freeze rule"): the pi, claude,
|
|
8
|
+
* and codex runtime adapters have all exercised the wire, and every M1/M2
|
|
9
|
+
* protocol gap has been closed. `PROTOCOL_VERSION` stays `1` from here
|
|
10
|
+
* forward; it does not bump for additive changes (new optional fields, new
|
|
11
|
+
* message types, new `AgentEvent` variants, new capability flags) — only for
|
|
12
|
+
* a breaking one (changing, removing, or retyping anything that already
|
|
13
|
+
* exists).
|
|
14
|
+
*
|
|
15
|
+
* IMPORTANT: changing this constant, or changing/removing/retyping any
|
|
16
|
+
* already-frozen schema in this package, requires a DELIBERATE update to the
|
|
17
|
+
* committed golden fixtures in `src/__tests__/golden/` (`v1.frozen.json`,
|
|
18
|
+
* `v1.envelopes.ndjson`) — see `src/__tests__/freeze-guard.test.ts`, which
|
|
19
|
+
* fails loudly on exactly that kind of drift. A passing freeze-guard run
|
|
20
|
+
* after such a change means either (a) the change was genuinely additive and
|
|
21
|
+
* the golden was regenerated with justification, or (b) this constant was
|
|
22
|
+
* bumped alongside a new golden generation for the new version — never a
|
|
23
|
+
* silent edit to either file to make the test pass.
|
|
24
|
+
*/
|
|
25
|
+
export declare const PROTOCOL_VERSION = 1;
|
|
26
|
+
/**
|
|
27
|
+
* Capability flags exchanged during the connection handshake (`conn.hello` /
|
|
28
|
+
* `conn.ack`). Additional flags may be introduced without a protocol version
|
|
29
|
+
* bump; unrecognized flags must be ignored by both sides.
|
|
30
|
+
*
|
|
31
|
+
* `interactive-approval` is RESERVED as of this addition: it gates the
|
|
32
|
+
* (currently unexercised) approval seam — a server must not route an
|
|
33
|
+
* approval-requiring policy to a daemon that hasn't advertised this flag. No
|
|
34
|
+
* bundled runtime adapter emits it yet; that's expected until interactive
|
|
35
|
+
* approval is actually wired up in a later wave.
|
|
36
|
+
*
|
|
37
|
+
* `approval_resolved` (additive-minor): a SERVER-advertised flag meaning
|
|
38
|
+
* "I understand the `task.approval_resolved` message" (`messages.ts`). This
|
|
39
|
+
* is the N/N-1 answer for that new daemon -> server message: an old server's
|
|
40
|
+
* `CAPABILITY_FLAGS`/`conn.ack.capabilities` never includes it, so a new
|
|
41
|
+
* daemon talking to an old server never sends `task.approval_resolved` at
|
|
42
|
+
* all (see `packages/client`'s `task-runner.ts`) and falls back to the
|
|
43
|
+
* pre-existing implicit-resume inference
|
|
44
|
+
* (`ConnectionHub.resumeIfImplicitlyApproved`, `packages/server/src/hub.ts`)
|
|
45
|
+
* unconditionally, exactly as before this flag existed. Unlike
|
|
46
|
+
* `interactive-approval`, this one IS exercised the moment both sides
|
|
47
|
+
* support it — there is no reserved/dormant period for it.
|
|
48
|
+
*/
|
|
49
|
+
/**
|
|
50
|
+
* `approval-targeting` (M5, additive-minor): unlike `approval_resolved`
|
|
51
|
+
* above, this flag is purely INFORMATIONAL/semantic, not a functional gate.
|
|
52
|
+
* `task.await_approval`/`task.approve`/`task.reject` all carry their new
|
|
53
|
+
* `approvalId` field UNCONDITIONALLY on both sides once each peer is
|
|
54
|
+
* upgraded -- the wire is tolerant (a plain, non-`.strict()` `z.object()`
|
|
55
|
+
* field, `messages.ts`), so no version/capability negotiation is needed just
|
|
56
|
+
* to send it safely; an older peer that doesn't recognize the field simply
|
|
57
|
+
* never reads it. Receivers decide whether to apply exact-match targeting
|
|
58
|
+
* by FIELD PRESENCE on the specific message at hand (does this particular
|
|
59
|
+
* `task.approve`/`task.reject`/`onApprovalResolved` payload carry an
|
|
60
|
+
* `approvalId`, and does a stored one exist to compare it against?), never
|
|
61
|
+
* by checking this flag -- see `ConnectionHub.approveTask`/`rejectTask`/
|
|
62
|
+
* `onApprovalResolved` and `TaskRunner.handleApprove`/`handleReject`
|
|
63
|
+
* (`packages/client`'s `task-runner.ts`). This flag exists only so each side
|
|
64
|
+
* can advertise, and an embedder/operator can observe (`ConnectionHub.
|
|
65
|
+
* getDeviceCapabilities`), whether the OTHER side is new enough to
|
|
66
|
+
* participate in targeting at all -- the same N/N-1-safe shape as every
|
|
67
|
+
* other flag here, just consumed for observability instead of gating.
|
|
68
|
+
*/
|
|
69
|
+
export declare const CAPABILITY_FLAGS: readonly ['steer', 'blob-upload', 'interactive-approval', 'approval_resolved', 'approval-targeting'];
|
|
70
|
+
export type CapabilityFlag = (typeof CAPABILITY_FLAGS)[number];
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@byok-sdk/protocol",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "BYOK SDK wire protocol: envelope schema, message types, and codec helpers",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Ancienttwo/byok-sdk.git",
|
|
10
|
+
"directory": "packages/protocol"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/Ancienttwo/byok-sdk/issues"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/Ancienttwo/byok-sdk#readme",
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=20"
|
|
18
|
+
},
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"module": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./package.json": "./package.json"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"zod": "^4.4.3"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsup && tsc -p tsconfig.build.json",
|
|
43
|
+
"dev": "tsup --watch",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"test:watch": "vitest",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"clean": "rm -rf dist"
|
|
48
|
+
}
|
|
49
|
+
}
|