@holokai/neuron-sdk 0.5.1 → 0.7.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/README.md +24 -1
- package/dist/index.d.mts +25 -3
- package/dist/index.d.ts +25 -3
- package/dist/index.js +57 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +57 -18
- package/dist/index.mjs.map +1 -1
- package/dist/ipc.d.mts +1 -1
- package/dist/ipc.d.ts +1 -1
- package/dist/{transport-Ckcwj-Do.d.mts → transport-BhFVHvR7.d.mts} +138 -11
- package/dist/{transport-Ckcwj-Do.d.ts → transport-BhFVHvR7.d.ts} +138 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ pnpm add @holokai/neuron-sdk
|
|
|
21
21
|
|
|
22
22
|
Runs in **Node 20+** (uses the global `fetch` and `ReadableStream`) and **modern browsers** (Chromium, Firefox, Safari latest). The package has no `node:*` imports — Holokai Desktop / Electron and the in-browser neuron-tester both consume the same SDK build.
|
|
23
23
|
|
|
24
|
-
> **Gateway compatibility (protocol 1.
|
|
24
|
+
> **Gateway compatibility (protocol 1.2.0; HOL-2926, HOL-4326).** Since protocol
|
|
25
25
|
> 1.1.0 the SDK advertises each capability's contract (`description` +
|
|
26
26
|
> input/output JSON Schemas) on the register frame. The gateway validates
|
|
27
27
|
> register frames **strictly**, so a gateway older than HOL-2926 rejects
|
|
@@ -114,6 +114,29 @@ Examples:
|
|
|
114
114
|
- `desktop/mcp/drive.read` — user's Google Drive, scoped to that user
|
|
115
115
|
- `org/01HBQ8ZK/custom-tool` — org-specific capability
|
|
116
116
|
|
|
117
|
+
### Composing capabilities (`composes`)
|
|
118
|
+
|
|
119
|
+
A capability namespaced `skill/<name>/<id>` may declare `composes`: the other
|
|
120
|
+
capability types it draws on to carry out one recurring job. Set it on
|
|
121
|
+
`defineCapability(...)`, on `neuron.handle(def, opts, fn)`'s `opts`, or on the
|
|
122
|
+
legacy registration object — it is only valid on a `skill/*` type, must name
|
|
123
|
+
1 to 64 distinct capability types, and none of them may itself be `skill/*`.
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
const weeklyReport = defineCapability({
|
|
127
|
+
type: 'skill/weekly-report/01',
|
|
128
|
+
description: 'Pulls last week\'s issues and writes a summary.',
|
|
129
|
+
input: z.object({}),
|
|
130
|
+
output: z.object({ summary: z.string() }),
|
|
131
|
+
composes: ['mcp/linear/list_issues', 'holo/37bfe871'],
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`composes` is carried on the register frame's capability object (gateway
|
|
136
|
+
protocol 1.2.0, HOL-4326) — **the gateway must be running 1.2.0 or later
|
|
137
|
+
before deploying an SDK version that sends it**, or the gateway rejects the
|
|
138
|
+
register frame outright.
|
|
139
|
+
|
|
117
140
|
### Namespace authorization
|
|
118
141
|
|
|
119
142
|
The gateway enforces which identities may advertise which namespaces:
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { J as JsonSchema, C as Capability, a as CapabilityHandleOptions, S as ServerToNeuronFrame, N as NeuronLogger, T as Transport, A as AuthCallback, H as Handler, b as CapabilityRegistration, c as TransportCallbacks, d as ClientFrame, P as PostPath } from './transport-
|
|
2
|
-
export { e as HandlerContext, f as HeartbeatInFlightEntry, L as LeasePayload,
|
|
1
|
+
import { J as JsonSchema, C as Capability, a as CapabilityHandleOptions, S as ServerToNeuronFrame, N as NeuronLogger, T as Transport, A as AuthCallback, H as Handler, b as CapabilityRegistration, c as TransportCallbacks, d as ClientFrame, P as PostPath } from './transport-BhFVHvR7.mjs';
|
|
2
|
+
export { e as HandlerContext, f as HandlerFailureOptions, g as HeartbeatInFlightEntry, L as LeasePayload, h as TaskPayload } from './transport-BhFVHvR7.mjs';
|
|
3
3
|
import { EventEmitter } from 'eventemitter3';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { ErrorObject } from 'ajv';
|
|
@@ -48,6 +48,12 @@ interface CapabilityDefInit<TIn extends z.ZodTypeAny, TOut extends z.ZodTypeAny>
|
|
|
48
48
|
* Bounded `[1_000, 3_600_000]` (1s..1h) by `CapabilitySchema`.
|
|
49
49
|
*/
|
|
50
50
|
leaseTtlMs?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Capability types this `skill/*` capability composes (HOL-4326). Only
|
|
53
|
+
* valid when `type` is namespaced `skill/*` — enforced by
|
|
54
|
+
* `CapabilitySchema` on the gateway.
|
|
55
|
+
*/
|
|
56
|
+
composes?: readonly string[];
|
|
51
57
|
}
|
|
52
58
|
/**
|
|
53
59
|
* A typed capability definition. The phantom `_input` / `_output` fields
|
|
@@ -68,6 +74,8 @@ interface CapabilityDef<TIn = unknown, TOut = unknown> {
|
|
|
68
74
|
readonly concurrency?: number;
|
|
69
75
|
/** See {@link CapabilityDefInit.leaseTtlMs}. */
|
|
70
76
|
readonly leaseTtlMs?: number;
|
|
77
|
+
/** See {@link CapabilityDefInit.composes}. */
|
|
78
|
+
readonly composes?: readonly string[];
|
|
71
79
|
/** Original zod schemas — kept for runtime validation in handlers if needed. */
|
|
72
80
|
readonly _zod: {
|
|
73
81
|
input: z.ZodType<TIn>;
|
|
@@ -418,4 +426,18 @@ declare class SchemaValidator {
|
|
|
418
426
|
validate(schema: JsonSchema | undefined, data: unknown): ErrorObject[] | null;
|
|
419
427
|
}
|
|
420
428
|
|
|
421
|
-
|
|
429
|
+
/**
|
|
430
|
+
* The exception `ctx.fail()` throws to short-circuit the handler with a
|
|
431
|
+
* nack. Caught by the runner; consumers should not catch it. Exported so a
|
|
432
|
+
* wrapper around a handler can raise one for a refusal the handler answered
|
|
433
|
+
* as data.
|
|
434
|
+
*/
|
|
435
|
+
declare class HandlerFailure extends Error {
|
|
436
|
+
readonly reason: string;
|
|
437
|
+
readonly code?: string | undefined;
|
|
438
|
+
readonly details?: unknown | undefined;
|
|
439
|
+
readonly kind: 'terminal' | 'retryable';
|
|
440
|
+
constructor(reason: string, code?: string | undefined, details?: unknown | undefined, kind?: 'terminal' | 'retryable');
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export { AuthCallback, Capability, type CapabilityDef, type CapabilityDefInit, CapabilityHandleOptions, type CapabilityPlanShape, CapabilityRegistration, Handler, HandlerFailure, HttpTransport, type HttpTransportOptions, Neuron, type NeuronEvents, NeuronLogger, type NeuronOptions, SSE_EVENT_NAMES, SchemaValidator, ServerToNeuronFrame, ShutdownError, Transport, TransportCallbacks, TransportError, WorkerPool, defineCapability, toPlanShape, toRegistrationCapability };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { J as JsonSchema, C as Capability, a as CapabilityHandleOptions, S as ServerToNeuronFrame, N as NeuronLogger, T as Transport, A as AuthCallback, H as Handler, b as CapabilityRegistration, c as TransportCallbacks, d as ClientFrame, P as PostPath } from './transport-
|
|
2
|
-
export { e as HandlerContext, f as HeartbeatInFlightEntry, L as LeasePayload,
|
|
1
|
+
import { J as JsonSchema, C as Capability, a as CapabilityHandleOptions, S as ServerToNeuronFrame, N as NeuronLogger, T as Transport, A as AuthCallback, H as Handler, b as CapabilityRegistration, c as TransportCallbacks, d as ClientFrame, P as PostPath } from './transport-BhFVHvR7.js';
|
|
2
|
+
export { e as HandlerContext, f as HandlerFailureOptions, g as HeartbeatInFlightEntry, L as LeasePayload, h as TaskPayload } from './transport-BhFVHvR7.js';
|
|
3
3
|
import { EventEmitter } from 'eventemitter3';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { ErrorObject } from 'ajv';
|
|
@@ -48,6 +48,12 @@ interface CapabilityDefInit<TIn extends z.ZodTypeAny, TOut extends z.ZodTypeAny>
|
|
|
48
48
|
* Bounded `[1_000, 3_600_000]` (1s..1h) by `CapabilitySchema`.
|
|
49
49
|
*/
|
|
50
50
|
leaseTtlMs?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Capability types this `skill/*` capability composes (HOL-4326). Only
|
|
53
|
+
* valid when `type` is namespaced `skill/*` — enforced by
|
|
54
|
+
* `CapabilitySchema` on the gateway.
|
|
55
|
+
*/
|
|
56
|
+
composes?: readonly string[];
|
|
51
57
|
}
|
|
52
58
|
/**
|
|
53
59
|
* A typed capability definition. The phantom `_input` / `_output` fields
|
|
@@ -68,6 +74,8 @@ interface CapabilityDef<TIn = unknown, TOut = unknown> {
|
|
|
68
74
|
readonly concurrency?: number;
|
|
69
75
|
/** See {@link CapabilityDefInit.leaseTtlMs}. */
|
|
70
76
|
readonly leaseTtlMs?: number;
|
|
77
|
+
/** See {@link CapabilityDefInit.composes}. */
|
|
78
|
+
readonly composes?: readonly string[];
|
|
71
79
|
/** Original zod schemas — kept for runtime validation in handlers if needed. */
|
|
72
80
|
readonly _zod: {
|
|
73
81
|
input: z.ZodType<TIn>;
|
|
@@ -418,4 +426,18 @@ declare class SchemaValidator {
|
|
|
418
426
|
validate(schema: JsonSchema | undefined, data: unknown): ErrorObject[] | null;
|
|
419
427
|
}
|
|
420
428
|
|
|
421
|
-
|
|
429
|
+
/**
|
|
430
|
+
* The exception `ctx.fail()` throws to short-circuit the handler with a
|
|
431
|
+
* nack. Caught by the runner; consumers should not catch it. Exported so a
|
|
432
|
+
* wrapper around a handler can raise one for a refusal the handler answered
|
|
433
|
+
* as data.
|
|
434
|
+
*/
|
|
435
|
+
declare class HandlerFailure extends Error {
|
|
436
|
+
readonly reason: string;
|
|
437
|
+
readonly code?: string | undefined;
|
|
438
|
+
readonly details?: unknown | undefined;
|
|
439
|
+
readonly kind: 'terminal' | 'retryable';
|
|
440
|
+
constructor(reason: string, code?: string | undefined, details?: unknown | undefined, kind?: 'terminal' | 'retryable');
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export { AuthCallback, Capability, type CapabilityDef, type CapabilityDefInit, CapabilityHandleOptions, type CapabilityPlanShape, CapabilityRegistration, Handler, HandlerFailure, HttpTransport, type HttpTransportOptions, Neuron, type NeuronEvents, NeuronLogger, type NeuronOptions, SSE_EVENT_NAMES, SchemaValidator, ServerToNeuronFrame, ShutdownError, Transport, TransportCallbacks, TransportError, WorkerPool, defineCapability, toPlanShape, toRegistrationCapability };
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,11 @@ var CapabilityTypeSchema = zod.z.string().min(1).regex(
|
|
|
17
17
|
"capability type must be namespaced: {owner}/{package}[/{name}][.{variant}]"
|
|
18
18
|
);
|
|
19
19
|
var UserIdSchema = zod.z.string().min(1);
|
|
20
|
+
var SKILL_CAPABILITY_PREFIX = "skill/";
|
|
21
|
+
function isSkillCapabilityType(type) {
|
|
22
|
+
return type.startsWith(SKILL_CAPABILITY_PREFIX);
|
|
23
|
+
}
|
|
24
|
+
var MAX_COMPOSED_CAPABILITIES = 64;
|
|
20
25
|
var JsonSchemaSchema = zod.z.unknown();
|
|
21
26
|
var CapabilityScopeSchema = zod.z.union([
|
|
22
27
|
zod.z.literal("any"),
|
|
@@ -69,8 +74,29 @@ var CapabilitySchema = zod.z.object({
|
|
|
69
74
|
* heartbeat budget should be the limiter, not a single
|
|
70
75
|
* capability).
|
|
71
76
|
*/
|
|
72
|
-
leaseTtlMs: zod.z.number().int().min(1e3).max(60 * 60 * 1e3).optional()
|
|
73
|
-
|
|
77
|
+
leaseTtlMs: zod.z.number().int().min(1e3).max(60 * 60 * 1e3).optional(),
|
|
78
|
+
/**
|
|
79
|
+
* Capability types this `skill/*` capability composes (HOL-4326).
|
|
80
|
+
* Only valid on a `skill/*` type — enforced below, since a non-skill
|
|
81
|
+
* type carrying `composes` is a modeling error the gateway should
|
|
82
|
+
* reject rather than silently ignore.
|
|
83
|
+
*/
|
|
84
|
+
composes: zod.z.array(CapabilityTypeSchema).min(1).max(MAX_COMPOSED_CAPABILITIES).refine(
|
|
85
|
+
(types) => new Set(types).size === types.length,
|
|
86
|
+
"composes must not contain duplicate capability types"
|
|
87
|
+
).refine(
|
|
88
|
+
(types) => types.every((t) => !isSkillCapabilityType(t)),
|
|
89
|
+
"composes must not contain skill/* capability types"
|
|
90
|
+
).optional()
|
|
91
|
+
}).strict().superRefine((cap, ctx) => {
|
|
92
|
+
if (cap.composes !== void 0 && !isSkillCapabilityType(cap.type)) {
|
|
93
|
+
ctx.addIssue({
|
|
94
|
+
code: zod.z.ZodIssueCode.custom,
|
|
95
|
+
message: "composes is only valid on a skill/* capability type",
|
|
96
|
+
path: ["composes"]
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
});
|
|
74
100
|
var LeaseIdSchema = zod.z.string().min(1);
|
|
75
101
|
var TaskPayloadSchema = zod.z.object({
|
|
76
102
|
taskId: zod.z.string().min(1),
|
|
@@ -209,7 +235,7 @@ zod.z.discriminatedUnion("type", [
|
|
|
209
235
|
]);
|
|
210
236
|
|
|
211
237
|
// ../neuron-protocol/src/transport.ts
|
|
212
|
-
var PROTOCOL_VERSION = "1.
|
|
238
|
+
var PROTOCOL_VERSION = "1.2.0";
|
|
213
239
|
var SSE_PATH = "/neuron/events";
|
|
214
240
|
var SSE_EVENT = {
|
|
215
241
|
registered: "registered",
|
|
@@ -235,6 +261,7 @@ function defineCapability(init) {
|
|
|
235
261
|
scope: init.scope,
|
|
236
262
|
concurrency: init.concurrency,
|
|
237
263
|
leaseTtlMs: init.leaseTtlMs,
|
|
264
|
+
composes: init.composes,
|
|
238
265
|
_zod: { input: init.input, output: init.output }
|
|
239
266
|
};
|
|
240
267
|
}
|
|
@@ -260,6 +287,7 @@ function toRegistrationCapability(def, opts) {
|
|
|
260
287
|
);
|
|
261
288
|
}
|
|
262
289
|
const leaseTtlMs = opts?.leaseTtlMs ?? def.leaseTtlMs;
|
|
290
|
+
const composes = opts?.composes ?? def.composes;
|
|
263
291
|
return {
|
|
264
292
|
type: def.type,
|
|
265
293
|
scope,
|
|
@@ -270,7 +298,8 @@ function toRegistrationCapability(def, opts) {
|
|
|
270
298
|
description: opts?.description ?? def.description,
|
|
271
299
|
inputSchema: def.inputSchema,
|
|
272
300
|
outputSchema: def.outputSchema,
|
|
273
|
-
...typeof leaseTtlMs === "number" ? { leaseTtlMs } : {}
|
|
301
|
+
...typeof leaseTtlMs === "number" ? { leaseTtlMs } : {},
|
|
302
|
+
...composes !== void 0 ? { composes: [...composes] } : {}
|
|
274
303
|
};
|
|
275
304
|
}
|
|
276
305
|
|
|
@@ -550,13 +579,16 @@ var TransportError = class extends Error {
|
|
|
550
579
|
};
|
|
551
580
|
|
|
552
581
|
// src/lease-runner.ts
|
|
553
|
-
var
|
|
554
|
-
constructor(reason, code) {
|
|
582
|
+
var HandlerFailure = class extends Error {
|
|
583
|
+
constructor(reason, code, details, kind = "terminal") {
|
|
555
584
|
super(reason);
|
|
556
585
|
this.reason = reason;
|
|
557
586
|
this.code = code;
|
|
558
|
-
this.
|
|
587
|
+
this.details = details;
|
|
588
|
+
this.name = "HandlerFailure";
|
|
589
|
+
this.kind = kind;
|
|
559
590
|
}
|
|
591
|
+
kind;
|
|
560
592
|
};
|
|
561
593
|
var DEFAULT_PROGRESS_TIMEOUT_MS = 5e3;
|
|
562
594
|
function validateInput(zod, validator, jsonSchema, data) {
|
|
@@ -564,10 +596,7 @@ function validateInput(zod, validator, jsonSchema, data) {
|
|
|
564
596
|
const result = zod.safeParse(data);
|
|
565
597
|
return result.success ? { ok: true, value: result.data } : { ok: false, errors: result.error.issues };
|
|
566
598
|
}
|
|
567
|
-
const errors = validator.validate(
|
|
568
|
-
jsonSchema,
|
|
569
|
-
data
|
|
570
|
-
);
|
|
599
|
+
const errors = validator.validate(jsonSchema, data);
|
|
571
600
|
return errors === null ? { ok: true, value: data } : { ok: false, errors };
|
|
572
601
|
}
|
|
573
602
|
async function runLease(opts) {
|
|
@@ -597,7 +626,13 @@ async function runLease(opts) {
|
|
|
597
626
|
return;
|
|
598
627
|
}
|
|
599
628
|
const parsedInput = inputCheck.value;
|
|
600
|
-
const reporter = makeProgressReporter(
|
|
629
|
+
const reporter = makeProgressReporter(
|
|
630
|
+
transport,
|
|
631
|
+
lease.leaseId,
|
|
632
|
+
logger,
|
|
633
|
+
signal,
|
|
634
|
+
progressTimeoutMs
|
|
635
|
+
);
|
|
601
636
|
const ctx = {
|
|
602
637
|
task: lease.task,
|
|
603
638
|
leaseId: lease.leaseId,
|
|
@@ -605,7 +640,7 @@ async function runLease(opts) {
|
|
|
605
640
|
log: scopedLogger(logger, lease),
|
|
606
641
|
progress: reporter.progress,
|
|
607
642
|
fail: (reason, opts2) => {
|
|
608
|
-
throw new
|
|
643
|
+
throw new HandlerFailure(reason, opts2?.code, opts2?.details, opts2?.kind);
|
|
609
644
|
}
|
|
610
645
|
};
|
|
611
646
|
let output;
|
|
@@ -625,13 +660,16 @@ async function runLease(opts) {
|
|
|
625
660
|
);
|
|
626
661
|
return;
|
|
627
662
|
}
|
|
628
|
-
if (err instanceof
|
|
663
|
+
if (err instanceof HandlerFailure) {
|
|
629
664
|
await sendNack(
|
|
630
665
|
transport,
|
|
631
666
|
lease.leaseId,
|
|
632
|
-
|
|
667
|
+
err.kind,
|
|
633
668
|
err.reason,
|
|
634
|
-
{
|
|
669
|
+
{
|
|
670
|
+
code: err.code ?? (err.kind === "terminal" ? "HANDLER_TERMINAL" : "HANDLER_RETRYABLE"),
|
|
671
|
+
...err.details !== void 0 ? { details: err.details } : {}
|
|
672
|
+
},
|
|
635
673
|
logger
|
|
636
674
|
);
|
|
637
675
|
return;
|
|
@@ -979,7 +1017,8 @@ var Neuron = class extends eventemitter3.EventEmitter {
|
|
|
979
1017
|
...reg.description !== void 0 ? { description: reg.description } : {},
|
|
980
1018
|
...reg.inputSchema !== void 0 ? { inputSchema: reg.inputSchema } : {},
|
|
981
1019
|
...reg.outputSchema !== void 0 ? { outputSchema: reg.outputSchema } : {},
|
|
982
|
-
...typeof reg.leaseTtlMs === "number" ? { leaseTtlMs: reg.leaseTtlMs } : {}
|
|
1020
|
+
...typeof reg.leaseTtlMs === "number" ? { leaseTtlMs: reg.leaseTtlMs } : {},
|
|
1021
|
+
...reg.composes !== void 0 ? { composes: reg.composes } : {}
|
|
983
1022
|
};
|
|
984
1023
|
inputSchema = reg.inputSchema;
|
|
985
1024
|
outputSchema = reg.outputSchema;
|
|
@@ -1221,6 +1260,7 @@ var Neuron = class extends eventemitter3.EventEmitter {
|
|
|
1221
1260
|
};
|
|
1222
1261
|
var SSE_EVENT_NAMES = SSE_EVENT;
|
|
1223
1262
|
|
|
1263
|
+
exports.HandlerFailure = HandlerFailure;
|
|
1224
1264
|
exports.HttpTransport = HttpTransport;
|
|
1225
1265
|
exports.Neuron = Neuron;
|
|
1226
1266
|
exports.SSE_EVENT_NAMES = SSE_EVENT_NAMES;
|