@vincemakes/kiso-protocol 0.41.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kiso contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # @vincemakes/kiso-protocol
2
+
3
+ The wire contract between a hosted kiso session and its clients: request
4
+ envelopes, wire events, the session snapshot, one error shape, a version.
5
+ Zero runtime dependencies — a browser client imports this and nothing
6
+ else from kiso.
7
+
8
+ **A wire event is a projection, never the durable event.** The runtime's
9
+ 27-variant Event union answers "what became a fact" and is frozen by
10
+ ADR-0051; the wire answers "how two processes talk". `DURABLE_TO_WIRE`
11
+ names the durable types that reach the wire (and the one rename:
12
+ `model_output_abandoned` is `draft_voided` on the wire), `NOT_ON_WIRE`
13
+ names the ones that do not, and `WIRE_FIELDS` is the allowlist of fields
14
+ per wire type — a field absent there never reaches the wire, whatever the
15
+ durable event holds. The projection itself (`toWireEvent`) lives in
16
+ `@vincemakes/kiso-server`, which knows the durable types; this package
17
+ only says what comes out.
18
+
19
+ Off the wire by decision: `usage` (a product bills through its own
20
+ frames — `WireFrame`), `stop` and the assistant / compaction boundaries
21
+ (control facts that render nothing), `tool_call_input_delta` (the end
22
+ carries the input). `thinking` is on the table but the projection exposes
23
+ it only when asked.
24
+
25
+ See the repository README for the framework overview.
@@ -0,0 +1,272 @@
1
+ /**
2
+ * @vincemakes/kiso-protocol — the wire contract.
3
+ *
4
+ * What a client and a hosted kiso session say to each other: request
5
+ * envelopes, wire events, the session snapshot, one error shape, a version.
6
+ *
7
+ * Two contracts, kept apart. The runtime's durable Event union answers
8
+ * "what became a fact" and is frozen by ADR-0051. The wire answers "how two
9
+ * processes talk". A wire event is a PROJECTION of a durable event — a
10
+ * curated subset of types, an allowlist of fields per type, tool arguments
11
+ * sanitized — and never the durable type itself, even where the shapes
12
+ * coincide today. So the persistence contract and the transport contract
13
+ * move on their own.
14
+ *
15
+ * This package imports nothing at runtime and nothing from the runtime:
16
+ * the content-block and approval shapes below are the wire's own
17
+ * structural copies, so a browser client never pulls kiso-runtime.
18
+ */
19
+ export declare const PROTOCOL_VERSION: 1;
20
+ export interface WireTextBlock {
21
+ readonly type: "text";
22
+ readonly text: string;
23
+ }
24
+ export interface WireImageBlock {
25
+ readonly type: "image";
26
+ readonly sourceType: "url" | "base64";
27
+ readonly url?: string;
28
+ readonly data?: string;
29
+ readonly mediaType?: "image/png" | "image/jpeg" | "image/webp" | "image/gif";
30
+ }
31
+ export type WireContentBlock = WireTextBlock | WireImageBlock;
32
+ export type WireInput = string | readonly WireContentBlock[];
33
+ /** Where a user line came from — mirrors the runtime's MessageSource. */
34
+ export type WireSource = "user" | "suggestion" | "tool_result";
35
+ export interface WireApproval {
36
+ readonly decisionId: string;
37
+ readonly callId: string;
38
+ readonly name: string;
39
+ readonly input: Readonly<Record<string, unknown>>;
40
+ }
41
+ export interface WireUncertain {
42
+ readonly executionId: string;
43
+ readonly callId: string;
44
+ readonly name: string;
45
+ }
46
+ export interface RunRequest {
47
+ readonly sessionId: string;
48
+ readonly input: WireInput;
49
+ readonly source?: WireSource;
50
+ /** The log holds an open run from a previous process: resume it first. */
51
+ readonly resumeFirst?: boolean;
52
+ }
53
+ export interface ResumeRequest {
54
+ readonly sessionId: string;
55
+ }
56
+ export interface AbortRequest {
57
+ readonly sessionId: string;
58
+ readonly force?: boolean;
59
+ }
60
+ export interface ApproveRequest {
61
+ readonly sessionId: string;
62
+ readonly decisionId: string;
63
+ readonly allow: boolean;
64
+ readonly reason?: string;
65
+ }
66
+ export interface ResolveUncertainRequest {
67
+ readonly sessionId: string;
68
+ readonly executionId: string;
69
+ readonly resolution: "rerun" | "abandoned";
70
+ }
71
+ export interface SubscribeRequest {
72
+ readonly sessionId: string;
73
+ /** The last seq the client saw; −1 for everything. */
74
+ readonly after: number;
75
+ }
76
+ export interface RunReply {
77
+ readonly runId: string;
78
+ }
79
+ export interface ApproveReply {
80
+ /** No run was live to consume the answer: the decision is durable, and
81
+ * a resume is what makes the run continue. */
82
+ readonly needsResume: boolean;
83
+ }
84
+ export interface ResolveUncertainReply {
85
+ readonly remaining: number;
86
+ }
87
+ export type AbortReply = {
88
+ readonly kind: "idle";
89
+ } | {
90
+ readonly kind: "parked";
91
+ readonly runId: string;
92
+ readonly approvals: readonly WireApproval[];
93
+ readonly reasons: readonly string[];
94
+ } | {
95
+ readonly kind: "stopped";
96
+ readonly runId: string;
97
+ };
98
+ /** What a client asks for on (re)connect, beside the stream. */
99
+ export interface SessionState {
100
+ readonly sessionId: string;
101
+ readonly running: boolean;
102
+ /** The highest seq on the log; the client subscribes from here. */
103
+ readonly highWater: number;
104
+ /** A run a previous process left without a terminal, or null. */
105
+ readonly openRun: string | null;
106
+ readonly pendingApprovals: readonly WireApproval[];
107
+ readonly uncertain: readonly WireUncertain[];
108
+ }
109
+ export type WireErrorCode = "in_flight" | "open_run" | "draining" | "not_found" | "bad_request" | "forbidden" | "internal";
110
+ export interface WireError {
111
+ readonly code: WireErrorCode;
112
+ readonly message: string;
113
+ /** `in_flight` and `open_run` name the run. */
114
+ readonly runId?: string;
115
+ }
116
+ /** The durable types that reach the wire, and the wire name of each. The
117
+ * one rename: the void marker is `draft_voided` on the wire — a client
118
+ * drops everything after `voidFromSeq`; "model_output_abandoned" is the
119
+ * kernel's name for the same fact. */
120
+ export declare const DURABLE_TO_WIRE: {
121
+ readonly user_input: "user_input";
122
+ readonly user_input_replaced: "user_input_replaced";
123
+ readonly text_start: "text_start";
124
+ readonly text_delta: "text_delta";
125
+ readonly text_end: "text_end";
126
+ readonly thinking: "thinking";
127
+ readonly tool_call_start: "tool_call_start";
128
+ readonly tool_call_end: "tool_call_end";
129
+ readonly tool_result: "tool_result";
130
+ readonly tool_execution_started: "tool_execution_started";
131
+ readonly tool_execution_succeeded: "tool_execution_succeeded";
132
+ readonly tool_execution_failed: "tool_execution_failed";
133
+ readonly tool_execution_resolved: "tool_execution_resolved";
134
+ readonly permission_requested: "permission_requested";
135
+ readonly permission_decided: "permission_decided";
136
+ readonly permission_expired: "permission_expired";
137
+ readonly uncertain_pending: "uncertain_pending";
138
+ readonly model_output_abandoned: "draft_voided";
139
+ readonly summarized: "summarized";
140
+ readonly terminal: "terminal";
141
+ };
142
+ export type DurableTypeOnWire = keyof typeof DURABLE_TO_WIRE;
143
+ export type WireEventType = (typeof DURABLE_TO_WIRE)[DurableTypeOnWire];
144
+ /** Off the wire, by decision: usage (a product bills through its own
145
+ * frames), stop and the assistant/compaction boundaries (control facts
146
+ * that render nothing), tool_call_input_delta (the end carries the input). */
147
+ export declare const NOT_ON_WIRE: readonly ["usage", "stop", "assistant_start", "assistant_end", "compacted", "microcompacted", "tool_call_input_delta"];
148
+ /** The allowlist: the fields a wire event MAY carry, per wire type. A
149
+ * field absent here never reaches the wire, whatever the durable event
150
+ * holds — leakage by omission is impossible. `seq` and `type` are
151
+ * implicit on every event. */
152
+ export declare const WIRE_FIELDS: Readonly<Record<WireEventType, readonly string[]>>;
153
+ /** The fields that are sanitized when they carry tool arguments. */
154
+ export declare const SANITIZED_FIELDS: ReadonlySet<string>;
155
+ export interface WireEventBase {
156
+ readonly seq: number;
157
+ readonly type: WireEventType;
158
+ }
159
+ export type WireEvent = (WireEventBase & {
160
+ readonly type: "user_input";
161
+ readonly content: WireInput;
162
+ readonly source?: WireSource;
163
+ }) | (WireEventBase & {
164
+ readonly type: "user_input_replaced";
165
+ readonly replaces: number;
166
+ readonly content: WireInput | null;
167
+ readonly source?: WireSource;
168
+ }) | (WireEventBase & {
169
+ readonly type: "text_start";
170
+ }) | (WireEventBase & {
171
+ readonly type: "text_delta";
172
+ readonly text: string;
173
+ }) | (WireEventBase & {
174
+ readonly type: "text_end";
175
+ }) | (WireEventBase & {
176
+ readonly type: "thinking";
177
+ readonly text: string;
178
+ }) | (WireEventBase & {
179
+ readonly type: "tool_call_start";
180
+ readonly callId: string;
181
+ readonly name: string;
182
+ }) | (WireEventBase & {
183
+ readonly type: "tool_call_end";
184
+ readonly callId: string;
185
+ readonly name: string;
186
+ readonly input: Readonly<Record<string, unknown>> | null;
187
+ }) | (WireEventBase & {
188
+ readonly type: "tool_result";
189
+ readonly callId: string;
190
+ readonly isError: boolean;
191
+ readonly errorKind?: string;
192
+ }) | (WireEventBase & {
193
+ readonly type: "tool_execution_started";
194
+ readonly executionId: string;
195
+ readonly callId: string;
196
+ readonly name: string;
197
+ }) | (WireEventBase & {
198
+ readonly type: "tool_execution_succeeded";
199
+ readonly executionId: string;
200
+ readonly callId: string;
201
+ }) | (WireEventBase & {
202
+ readonly type: "tool_execution_failed";
203
+ readonly executionId: string;
204
+ readonly callId: string;
205
+ readonly error: string;
206
+ readonly errorKind?: string;
207
+ readonly safeToRetry: boolean;
208
+ }) | (WireEventBase & {
209
+ readonly type: "tool_execution_resolved";
210
+ readonly executionId: string;
211
+ readonly callId: string;
212
+ readonly resolution: "rerun" | "abandoned";
213
+ }) | (WireEventBase & {
214
+ readonly type: "permission_requested";
215
+ readonly decisionId: string;
216
+ readonly callId: string;
217
+ readonly name: string;
218
+ readonly input: Readonly<Record<string, unknown>>;
219
+ }) | (WireEventBase & {
220
+ readonly type: "permission_decided";
221
+ readonly decisionId: string;
222
+ readonly decision: "approved" | "denied";
223
+ }) | (WireEventBase & {
224
+ readonly type: "permission_expired";
225
+ readonly decisionId: string;
226
+ readonly reason: string;
227
+ }) | (WireEventBase & {
228
+ readonly type: "uncertain_pending";
229
+ readonly executionId: string;
230
+ readonly callId: string;
231
+ readonly name: string;
232
+ readonly error: string;
233
+ }) | (WireEventBase & {
234
+ readonly type: "draft_voided";
235
+ readonly voidFromSeq: number;
236
+ readonly reason: string;
237
+ }) | (WireEventBase & {
238
+ readonly type: "summarized";
239
+ readonly coversToSeq: number;
240
+ readonly summary: string;
241
+ }) | (WireEventBase & {
242
+ readonly type: "terminal";
243
+ readonly outcome: WireTerminal;
244
+ });
245
+ export type WireTerminal = {
246
+ readonly kind: "completed";
247
+ } | {
248
+ readonly kind: "max_tokens";
249
+ } | {
250
+ readonly kind: "max_turns";
251
+ readonly turns: number;
252
+ } | {
253
+ readonly kind: "error";
254
+ readonly error: {
255
+ readonly code: string;
256
+ readonly message: string;
257
+ readonly retryable: boolean;
258
+ };
259
+ } | {
260
+ readonly kind: "aborted";
261
+ readonly by: "user" | "parent";
262
+ } | {
263
+ readonly kind: "hook_stopped";
264
+ readonly hook: string;
265
+ };
266
+ /** A frame a product adds beside the wire events (billing, an estimate, a
267
+ * courier's payload). Its `event` name is the product's; the transport
268
+ * carries it on the same connection and never reads it. */
269
+ export interface WireFrame {
270
+ readonly event: string;
271
+ readonly data: unknown;
272
+ }
package/dist/index.js ADDED
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @vincemakes/kiso-protocol — the wire contract.
3
+ *
4
+ * What a client and a hosted kiso session say to each other: request
5
+ * envelopes, wire events, the session snapshot, one error shape, a version.
6
+ *
7
+ * Two contracts, kept apart. The runtime's durable Event union answers
8
+ * "what became a fact" and is frozen by ADR-0051. The wire answers "how two
9
+ * processes talk". A wire event is a PROJECTION of a durable event — a
10
+ * curated subset of types, an allowlist of fields per type, tool arguments
11
+ * sanitized — and never the durable type itself, even where the shapes
12
+ * coincide today. So the persistence contract and the transport contract
13
+ * move on their own.
14
+ *
15
+ * This package imports nothing at runtime and nothing from the runtime:
16
+ * the content-block and approval shapes below are the wire's own
17
+ * structural copies, so a browser client never pulls kiso-runtime.
18
+ */
19
+ export const PROTOCOL_VERSION = 1;
20
+ // ---- wire events: the projection -------------------------------------------------
21
+ /** The durable types that reach the wire, and the wire name of each. The
22
+ * one rename: the void marker is `draft_voided` on the wire — a client
23
+ * drops everything after `voidFromSeq`; "model_output_abandoned" is the
24
+ * kernel's name for the same fact. */
25
+ export const DURABLE_TO_WIRE = {
26
+ user_input: "user_input",
27
+ user_input_replaced: "user_input_replaced",
28
+ text_start: "text_start",
29
+ text_delta: "text_delta",
30
+ text_end: "text_end",
31
+ thinking: "thinking",
32
+ tool_call_start: "tool_call_start",
33
+ tool_call_end: "tool_call_end",
34
+ tool_result: "tool_result",
35
+ tool_execution_started: "tool_execution_started",
36
+ tool_execution_succeeded: "tool_execution_succeeded",
37
+ tool_execution_failed: "tool_execution_failed",
38
+ tool_execution_resolved: "tool_execution_resolved",
39
+ permission_requested: "permission_requested",
40
+ permission_decided: "permission_decided",
41
+ permission_expired: "permission_expired",
42
+ uncertain_pending: "uncertain_pending",
43
+ model_output_abandoned: "draft_voided",
44
+ summarized: "summarized",
45
+ terminal: "terminal",
46
+ };
47
+ /** Off the wire, by decision: usage (a product bills through its own
48
+ * frames), stop and the assistant/compaction boundaries (control facts
49
+ * that render nothing), tool_call_input_delta (the end carries the input). */
50
+ export const NOT_ON_WIRE = ["usage", "stop", "assistant_start", "assistant_end", "compacted", "microcompacted", "tool_call_input_delta"];
51
+ /** The allowlist: the fields a wire event MAY carry, per wire type. A
52
+ * field absent here never reaches the wire, whatever the durable event
53
+ * holds — leakage by omission is impossible. `seq` and `type` are
54
+ * implicit on every event. */
55
+ export const WIRE_FIELDS = {
56
+ user_input: ["content", "source"],
57
+ user_input_replaced: ["replaces", "content", "source"],
58
+ text_start: [],
59
+ text_delta: ["text"],
60
+ text_end: [],
61
+ thinking: ["text"],
62
+ tool_call_start: ["callId", "name"],
63
+ tool_call_end: ["callId", "name", "input"],
64
+ tool_result: ["callId", "isError", "errorKind"],
65
+ tool_execution_started: ["executionId", "callId", "name"],
66
+ tool_execution_succeeded: ["executionId", "callId"],
67
+ tool_execution_failed: ["executionId", "callId", "error", "errorKind", "safeToRetry"],
68
+ tool_execution_resolved: ["executionId", "callId", "resolution"],
69
+ permission_requested: ["decisionId", "callId", "name", "input"],
70
+ permission_decided: ["decisionId", "decision"],
71
+ permission_expired: ["decisionId", "reason"],
72
+ uncertain_pending: ["executionId", "callId", "name", "error"],
73
+ draft_voided: ["voidFromSeq", "reason"],
74
+ summarized: ["coversToSeq", "summary"],
75
+ terminal: ["outcome"],
76
+ };
77
+ /** The fields that are sanitized when they carry tool arguments. */
78
+ export const SANITIZED_FIELDS = new Set(["input"]);
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@vincemakes/kiso-protocol",
3
+ "version": "0.41.0",
4
+ "description": "kiso protocol — the wire contract between a hosted kiso session and its clients: request envelopes, wire events (a projection of the durable stream, never the stream itself), the session snapshot, one error shape, a version. Zero runtime dependencies.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc -p tsconfig.build.json",
20
+ "typecheck": "tsc -p tsconfig.json",
21
+ "test": "vitest run"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^26.1.2",
25
+ "typescript": "^5.7.2",
26
+ "vitest": "^3.0.0"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/vincemakes/kiso.git",
31
+ "directory": "packages/protocol"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/vincemakes/kiso/issues"
35
+ },
36
+ "homepage": "https://github.com/vincemakes/kiso/tree/main/packages/protocol#readme"
37
+ }