@kindgi/handler-runtime 0.0.0-bootstrap.0 → 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.
Files changed (68) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +218 -2
  3. package/dist/build-extensions.d.ts +75 -0
  4. package/dist/build-extensions.d.ts.map +1 -0
  5. package/dist/build-extensions.js +27 -0
  6. package/dist/build-extensions.js.map +1 -0
  7. package/dist/discovery.d.ts +19 -0
  8. package/dist/discovery.d.ts.map +1 -0
  9. package/dist/discovery.js +81 -0
  10. package/dist/discovery.js.map +1 -0
  11. package/dist/entrypoint.d.ts +10 -0
  12. package/dist/entrypoint.d.ts.map +1 -0
  13. package/dist/entrypoint.js +24 -0
  14. package/dist/entrypoint.js.map +1 -0
  15. package/dist/handler-runner.d.ts +127 -0
  16. package/dist/handler-runner.d.ts.map +1 -0
  17. package/dist/handler-runner.js +318 -0
  18. package/dist/handler-runner.js.map +1 -0
  19. package/dist/index.d.ts +8 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +7 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/kindgi-index-main.d.ts +2 -0
  24. package/dist/kindgi-index-main.d.ts.map +1 -0
  25. package/dist/kindgi-index-main.js +15 -0
  26. package/dist/kindgi-index-main.js.map +1 -0
  27. package/dist/kindgi-index.d.ts +316 -0
  28. package/dist/kindgi-index.d.ts.map +1 -0
  29. package/dist/kindgi-index.js +1201 -0
  30. package/dist/kindgi-index.js.map +1 -0
  31. package/dist/pack-env.d.ts +66 -0
  32. package/dist/pack-env.d.ts.map +1 -0
  33. package/dist/pack-env.js +97 -0
  34. package/dist/pack-env.js.map +1 -0
  35. package/dist/pack-service/index.d.ts +7 -0
  36. package/dist/pack-service/index.d.ts.map +1 -0
  37. package/dist/pack-service/index.js +6 -0
  38. package/dist/pack-service/index.js.map +1 -0
  39. package/dist/pack-service/main.d.ts +47 -0
  40. package/dist/pack-service/main.d.ts.map +1 -0
  41. package/dist/pack-service/main.js +201 -0
  42. package/dist/pack-service/main.js.map +1 -0
  43. package/dist/pack-service/service.d.ts +61 -0
  44. package/dist/pack-service/service.d.ts.map +1 -0
  45. package/dist/pack-service/service.js +341 -0
  46. package/dist/pack-service/service.js.map +1 -0
  47. package/dist/pack-service/supervisor.d.ts +138 -0
  48. package/dist/pack-service/supervisor.d.ts.map +1 -0
  49. package/dist/pack-service/supervisor.js +424 -0
  50. package/dist/pack-service/supervisor.js.map +1 -0
  51. package/dist/protocol.d.ts +104 -0
  52. package/dist/protocol.d.ts.map +1 -0
  53. package/dist/protocol.js +116 -0
  54. package/dist/protocol.js.map +1 -0
  55. package/package.json +87 -4
  56. package/src/build-extensions.ts +100 -0
  57. package/src/discovery.ts +89 -0
  58. package/src/entrypoint.ts +23 -0
  59. package/src/handler-runner.ts +500 -0
  60. package/src/index.ts +66 -0
  61. package/src/kindgi-index-main.ts +17 -0
  62. package/src/kindgi-index.ts +1605 -0
  63. package/src/pack-env.ts +148 -0
  64. package/src/pack-service/index.ts +17 -0
  65. package/src/pack-service/main.ts +246 -0
  66. package/src/pack-service/service.ts +478 -0
  67. package/src/pack-service/supervisor.ts +600 -0
  68. package/src/protocol.ts +214 -0
@@ -0,0 +1,214 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ /**
5
+ * Pack protocol v2 — the messages a runtime exchanges with a pack
6
+ * service (`./pack-service`) to run pack code: tool handlers and
7
+ * guardrail checks.
8
+ *
9
+ * A request names a tool or check by id; the pack service resolves it
10
+ * from its own `index.json`. The caller never chooses which module is
11
+ * imported, and the schemas that validate input and output are the
12
+ * ones the pack was built with.
13
+ *
14
+ * One request, one response. Every outcome of running pack code —
15
+ * success, a validation failure, a throw, a deadline, an unknown tool —
16
+ * is a response message. Transport problems (auth, overload, draining)
17
+ * are HTTP statuses, never messages.
18
+ */
19
+
20
+ /** Wire version of every v2 message. */
21
+ export const PACK_PROTOCOL_VERSION = 2 as const;
22
+ export type PackProtocolVersion = typeof PACK_PROTOCOL_VERSION;
23
+
24
+ /** Per-call context a handler receives (serializable; no functions). */
25
+ export interface PackCallContext {
26
+ readonly tenantId: string;
27
+ /** The kernel run this call belongs to. */
28
+ readonly runId: string;
29
+ /** The individual call — e.g. the model's tool-call id. */
30
+ readonly requestId?: string;
31
+ readonly env?: Readonly<Record<string, unknown>>;
32
+ readonly secrets?: Readonly<Record<string, unknown>>;
33
+ readonly config?: Readonly<Record<string, unknown>>;
34
+ }
35
+
36
+ export interface ToolRef {
37
+ readonly id: string;
38
+ /** When set, the pack service refuses a different indexed version. */
39
+ readonly version?: string;
40
+ }
41
+
42
+ export interface CheckRef {
43
+ /** Guardrail check id (the indexed guardrail's `checkId`). */
44
+ readonly id: string;
45
+ }
46
+
47
+ export interface ToolInvokeMessage {
48
+ readonly v: PackProtocolVersion;
49
+ readonly kind: 'invoke';
50
+ readonly tool: ToolRef;
51
+ readonly input: unknown;
52
+ readonly ctx: PackCallContext;
53
+ }
54
+
55
+ export interface CheckInvokeMessage {
56
+ readonly v: PackProtocolVersion;
57
+ readonly kind: 'check-invoke';
58
+ readonly check: CheckRef;
59
+ readonly config: Readonly<Record<string, unknown>>;
60
+ readonly trace: unknown;
61
+ }
62
+
63
+ export interface ToolResultMessage {
64
+ readonly v: PackProtocolVersion;
65
+ readonly kind: 'result';
66
+ readonly output: unknown;
67
+ }
68
+
69
+ export interface CheckResultMessage {
70
+ readonly v: PackProtocolVersion;
71
+ readonly kind: 'check-result';
72
+ readonly result: unknown;
73
+ }
74
+
75
+ export type PackErrorCode =
76
+ | 'input-validation-failed'
77
+ | 'output-validation-failed'
78
+ | 'handler-import-failed'
79
+ | 'handler-shape-invalid'
80
+ | 'handler-throw'
81
+ | 'check-shape-invalid'
82
+ | 'malformed-message'
83
+ | 'unknown-protocol-version'
84
+ | 'unexpected-message-kind'
85
+ | 'tool-not-in-pack'
86
+ | 'check-not-in-pack'
87
+ | 'tool-version-mismatch'
88
+ | 'deadline-exceeded'
89
+ | 'cancelled';
90
+
91
+ export interface PackErrorMessage {
92
+ readonly v: PackProtocolVersion;
93
+ readonly kind: 'error';
94
+ readonly code: PackErrorCode;
95
+ readonly message: string;
96
+ readonly toolId?: string;
97
+ readonly checkId?: string;
98
+ readonly cause?: unknown;
99
+ /** Schema-validation issues (Ajv-style), for the validation codes. */
100
+ readonly issues?: readonly unknown[];
101
+ }
102
+
103
+ export type PackRequest = ToolInvokeMessage | CheckInvokeMessage;
104
+ export type PackResponse = ToolResultMessage | CheckResultMessage | PackErrorMessage;
105
+
106
+ export type ParseOutcome<T> =
107
+ | { readonly kind: 'ok'; readonly value: T }
108
+ | { readonly kind: 'err'; readonly error: PackErrorMessage };
109
+
110
+ export function packError(
111
+ code: PackErrorCode,
112
+ message: string,
113
+ extra: Omit<Partial<PackErrorMessage>, 'v' | 'kind' | 'code' | 'message'> = {},
114
+ ): PackErrorMessage {
115
+ return { v: PACK_PROTOCOL_VERSION, kind: 'error', code, message, ...extra };
116
+ }
117
+
118
+ function isRecord(value: unknown): value is Record<string, unknown> {
119
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
120
+ }
121
+
122
+ function checkEnvelope(value: unknown): ParseOutcome<Record<string, unknown>> {
123
+ if (!isRecord(value)) {
124
+ return { kind: 'err', error: packError('malformed-message', 'Message must be a JSON object') };
125
+ }
126
+ if (value.v !== PACK_PROTOCOL_VERSION) {
127
+ return {
128
+ kind: 'err',
129
+ error: packError(
130
+ 'unknown-protocol-version',
131
+ `Expected protocol v${PACK_PROTOCOL_VERSION}, got ${JSON.stringify(value.v)}`,
132
+ ),
133
+ };
134
+ }
135
+ return { kind: 'ok', value };
136
+ }
137
+
138
+ function parseContext(raw: unknown): PackCallContext | undefined {
139
+ if (!isRecord(raw)) return undefined;
140
+ if (typeof raw.tenantId !== 'string' || typeof raw.runId !== 'string') return undefined;
141
+ return raw as unknown as PackCallContext;
142
+ }
143
+
144
+ /** Parse a request body (already JSON-decoded) into a v2 request. */
145
+ export function parsePackRequest(value: unknown): ParseOutcome<PackRequest> {
146
+ const env = checkEnvelope(value);
147
+ if (env.kind === 'err') return env;
148
+ const m = env.value;
149
+ if (m.kind === 'invoke') return parseToolInvoke(m);
150
+ if (m.kind === 'check-invoke') return parseCheckInvoke(m);
151
+ return {
152
+ kind: 'err',
153
+ error: packError('unexpected-message-kind', `Unknown request kind ${JSON.stringify(m.kind)}`),
154
+ };
155
+ }
156
+
157
+ function malformed(message: string): ParseOutcome<never> {
158
+ return { kind: 'err', error: packError('malformed-message', message) };
159
+ }
160
+
161
+ function parseToolInvoke(m: Record<string, unknown>): ParseOutcome<ToolInvokeMessage> {
162
+ const tool = m.tool;
163
+ if (!isRecord(tool) || typeof tool.id !== 'string' || tool.id.length === 0) {
164
+ return malformed('`tool.id` is required');
165
+ }
166
+ if (tool.version !== undefined && typeof tool.version !== 'string') {
167
+ return malformed('`tool.version` must be a string');
168
+ }
169
+ if (parseContext(m.ctx) === undefined)
170
+ return malformed('`ctx` needs string `tenantId` and `runId`');
171
+ return { kind: 'ok', value: m as unknown as ToolInvokeMessage };
172
+ }
173
+
174
+ function parseCheckInvoke(m: Record<string, unknown>): ParseOutcome<CheckInvokeMessage> {
175
+ const check = m.check;
176
+ if (!isRecord(check) || typeof check.id !== 'string' || check.id.length === 0) {
177
+ return malformed('`check.id` is required');
178
+ }
179
+ if (!isRecord(m.config)) return malformed('`config` must be an object');
180
+ return { kind: 'ok', value: m as unknown as CheckInvokeMessage };
181
+ }
182
+
183
+ /** Parse a response body (already JSON-decoded) into a v2 response. */
184
+ export function parsePackResponse(value: unknown): ParseOutcome<PackResponse> {
185
+ const env = checkEnvelope(value);
186
+ if (env.kind === 'err') return env;
187
+ const m = env.value;
188
+ if (m.kind === 'result' || m.kind === 'check-result') {
189
+ return { kind: 'ok', value: m as unknown as PackResponse };
190
+ }
191
+ if (m.kind === 'error' && typeof m.code === 'string' && typeof m.message === 'string') {
192
+ return { kind: 'ok', value: m as unknown as PackErrorMessage };
193
+ }
194
+ return {
195
+ kind: 'err',
196
+ error: packError('unexpected-message-kind', `Unknown response kind ${JSON.stringify(m.kind)}`),
197
+ };
198
+ }
199
+
200
+ /**
201
+ * HTTP headers of the v2 transport. `Authorization` is deliberately not
202
+ * used: on platforms like Cloud Run it carries the platform's identity
203
+ * token, so the pack token travels separately.
204
+ */
205
+ export const PACK_HEADERS = {
206
+ protocol: 'kindgi-protocol',
207
+ token: 'kindgi-pack-token',
208
+ /** Relative deadline for the call, in milliseconds. */
209
+ timeoutMs: 'kindgi-timeout-ms',
210
+ runId: 'kindgi-run-id',
211
+ requestId: 'kindgi-request-id',
212
+ artifactVersion: 'kindgi-artifact-version',
213
+ durationMs: 'kindgi-duration-ms',
214
+ } as const;