@skein-js/fastify 0.8.0 → 0.9.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 +18 -0
- package/dist/index.d.ts +22 -4
- package/dist/index.js +42 -2
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -46,6 +46,22 @@ await app.listen({ port: 3000 });
|
|
|
46
46
|
// the Agent Protocol is now served under /agent/*
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
## Graphs as plain endpoints (non-chat)
|
|
50
|
+
|
|
51
|
+
For workloads that aren't chat — a classifier, an extractor, a workflow another service calls — there
|
|
52
|
+
is a smaller surface: every graph mounted as `POST /invoke/:graph_id`, where the request body **is**
|
|
53
|
+
the graph input and the response **is** the final state. No threads, assistants, or runs.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { skeinInvokePlugin } from "@skein-js/fastify";
|
|
57
|
+
|
|
58
|
+
await app.register(skeinInvokePlugin, { prefix: "/agent", deps });
|
|
59
|
+
// → POST /agent/invoke/:graph_id
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Send `Accept: text/event-stream` to stream the steps instead. See
|
|
63
|
+
[docs/serving-a-single-graph.md](../../docs/serving-a-single-graph.md).
|
|
64
|
+
|
|
49
65
|
## Streaming
|
|
50
66
|
|
|
51
67
|
SSE responses take over the raw Node response (`reply.hijack()` + `reply.raw`) and stream the
|
|
@@ -56,6 +72,8 @@ pre-serialized frames the engine produced, tearing the run's subscription down o
|
|
|
56
72
|
- **`createFastifyServer(options): Promise<SkeinFastifyServer>`** — a standalone server;
|
|
57
73
|
`SkeinFastifyServer` = `{ app, runtime, listen(port?, host?), close() }`. `listen` defaults to port
|
|
58
74
|
`2024`, host `"localhost"`; `close()` stops the run worker then the HTTP server.
|
|
75
|
+
- **`skeinInvokePlugin`** — the simplified serving surface (`POST /invoke/:graph_id`, body-in /
|
|
76
|
+
final-state-out). Options add `invokePrefix` (default `/invoke`) and `streamMode`.
|
|
59
77
|
- **`skeinPlugin`** — a Fastify plugin: `await app.register(skeinPlugin, { prefix, ...options })`
|
|
60
78
|
mounts the protocol under `prefix`. Encapsulated, so skein's routes + CORS stay isolated from the
|
|
61
79
|
host app. Options: `SkeinPluginOptions` (an alias of `SkeinRuntimeOptions`); `prefix` is Fastify's
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Server } from 'node:http';
|
|
2
|
-
import { ProtocolRuntime, Logger, ProtocolHandlers, ProtocolRequest, ProtocolResponse } from '@skein-js/agent-protocol';
|
|
2
|
+
import { ProtocolRuntime, Logger, ProtocolHandlers, GraphInvokeOptions, ProtocolRequest, ProtocolResponse } from '@skein-js/agent-protocol';
|
|
3
3
|
export { skeinRoutes } from '@skein-js/agent-protocol';
|
|
4
4
|
import { SkeinRuntimeOptions, CorsOptions } from '@skein-js/server-kit';
|
|
5
5
|
export { SkeinRuntimeOptions } from '@skein-js/server-kit';
|
|
@@ -33,8 +33,7 @@ interface HandlerRoutesOptions {
|
|
|
33
33
|
/**
|
|
34
34
|
* Bind the Agent Protocol route table to a handler table on a Fastify instance — the pure shim. It
|
|
35
35
|
* assembles no runtime and knows no storage driver, so a caller with custom `ProtocolDeps` can mount
|
|
36
|
-
* it over any `ProtocolHandlers`.
|
|
37
|
-
* `Access-Control-Allow-*` headers cover every route, including the SSE streams.
|
|
36
|
+
* it over any `ProtocolHandlers`.
|
|
38
37
|
*/
|
|
39
38
|
declare function registerSkeinHandlers(fastify: FastifyInstance, handlers: ProtocolHandlers, options?: HandlerRoutesOptions): Promise<void>;
|
|
40
39
|
/**
|
|
@@ -49,6 +48,25 @@ declare function registerSkeinHandlers(fastify: FastifyInstance, handlers: Proto
|
|
|
49
48
|
*/
|
|
50
49
|
declare const skeinPlugin: FastifyPluginAsync<SkeinPluginOptions>;
|
|
51
50
|
|
|
51
|
+
type SkeinInvokePluginOptions = SkeinRuntimeOptions & GraphInvokeOptions & {
|
|
52
|
+
/**
|
|
53
|
+
* Path prefix *inside* this plugin, appended to any Fastify `prefix` it is registered under.
|
|
54
|
+
* Defaults to `/invoke`; pass `"/"` to serve `:graph_id` directly at the registration prefix.
|
|
55
|
+
*/
|
|
56
|
+
invokePrefix?: string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* A Fastify plugin serving `POST <invokePrefix>/:graph_id`. Resolves deps from the shared
|
|
60
|
+
* `{ config } | { deps }` seam; seeds no assistants and starts no background run worker, since an
|
|
61
|
+
* invoke-only service needs neither.
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* await app.register(skeinInvokePlugin, { prefix: "/api", deps });
|
|
65
|
+
* // → POST /api/invoke/:graph_id
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
declare const skeinInvokePlugin: FastifyPluginAsync<SkeinInvokePluginOptions>;
|
|
69
|
+
|
|
52
70
|
/** Translate a Fastify `FastifyRequest` into the normalized `ProtocolRequest` the handler table reads. */
|
|
53
71
|
declare function toProtocolRequest(req: FastifyRequest): ProtocolRequest;
|
|
54
72
|
|
|
@@ -58,4 +76,4 @@ declare function sendProtocolResponse(response: ProtocolResponse, reply: Fastify
|
|
|
58
76
|
/** Serialize a caught error onto `reply`, using the protocol status when the error carries one. */
|
|
59
77
|
declare function sendErrorResponse(error: unknown, reply: FastifyReply, logger?: Logger): void;
|
|
60
78
|
|
|
61
|
-
export { type HandlerRoutesOptions, type SkeinFastifyServer, type SkeinPluginOptions, createFastifyServer, registerSkeinHandlers, sendErrorResponse, sendProtocolResponse, skeinPlugin, toProtocolRequest };
|
|
79
|
+
export { type HandlerRoutesOptions, type SkeinFastifyServer, type SkeinInvokePluginOptions, type SkeinPluginOptions, createFastifyServer, registerSkeinHandlers, sendErrorResponse, sendProtocolResponse, skeinInvokePlugin, skeinPlugin, toProtocolRequest };
|
package/dist/index.js
CHANGED
|
@@ -106,7 +106,7 @@ var HTTP_METHOD_TO_FASTIFY = {
|
|
|
106
106
|
patch: "PATCH",
|
|
107
107
|
delete: "DELETE"
|
|
108
108
|
};
|
|
109
|
-
async function
|
|
109
|
+
async function prepareSkeinContext(fastify, options = {}) {
|
|
110
110
|
if (options.cors) {
|
|
111
111
|
let fastifyCors;
|
|
112
112
|
try {
|
|
@@ -121,7 +121,10 @@ async function registerSkeinHandlers(fastify, handlers, options = {}) {
|
|
|
121
121
|
options.cors === true ? { origin: true } : options.cors
|
|
122
122
|
);
|
|
123
123
|
}
|
|
124
|
-
|
|
124
|
+
try {
|
|
125
|
+
fastify.removeContentTypeParser("application/json");
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
125
128
|
fastify.addContentTypeParser("application/json", { parseAs: "string" }, (_req, body, done) => {
|
|
126
129
|
const text = (typeof body === "string" ? body : body.toString()).trim();
|
|
127
130
|
if (text === "") {
|
|
@@ -134,6 +137,9 @@ async function registerSkeinHandlers(fastify, handlers, options = {}) {
|
|
|
134
137
|
done(error);
|
|
135
138
|
}
|
|
136
139
|
});
|
|
140
|
+
}
|
|
141
|
+
async function registerSkeinHandlers(fastify, handlers, options = {}) {
|
|
142
|
+
await prepareSkeinContext(fastify, options);
|
|
137
143
|
for (const binding of skeinRoutes) {
|
|
138
144
|
const invoke = handlers[binding.handler];
|
|
139
145
|
fastify.route({
|
|
@@ -195,6 +201,39 @@ async function createFastifyServer(options) {
|
|
|
195
201
|
};
|
|
196
202
|
}
|
|
197
203
|
|
|
204
|
+
// src/skein-invoke-plugin.ts
|
|
205
|
+
import {
|
|
206
|
+
createGraphInvokeHandler,
|
|
207
|
+
graphInvokeRoutes
|
|
208
|
+
} from "@skein-js/agent-protocol";
|
|
209
|
+
import { resolveRuntimeDeps } from "@skein-js/server-kit";
|
|
210
|
+
var skeinInvokePlugin = async (fastify, options) => {
|
|
211
|
+
const { deps, cors } = await resolveRuntimeDeps(options);
|
|
212
|
+
const invoke = createGraphInvokeHandler(deps, { streamMode: options.streamMode });
|
|
213
|
+
await prepareSkeinContext(fastify, {
|
|
214
|
+
logger: options.logger,
|
|
215
|
+
// Explicit option wins; otherwise fall back to the config's `http.cors`, else off.
|
|
216
|
+
cors: options.cors ?? cors ?? false
|
|
217
|
+
});
|
|
218
|
+
for (const binding of graphInvokeRoutes(options.invokePrefix)) {
|
|
219
|
+
fastify.route({
|
|
220
|
+
method: HTTP_METHOD_TO_FASTIFY[binding.method],
|
|
221
|
+
url: binding.path,
|
|
222
|
+
handler: async (req, reply) => {
|
|
223
|
+
const disconnected = new AbortController();
|
|
224
|
+
reply.raw.once("close", () => disconnected.abort(new Error("client disconnected")));
|
|
225
|
+
try {
|
|
226
|
+
const request = { ...toProtocolRequest(req), signal: disconnected.signal };
|
|
227
|
+
await sendProtocolResponse(await invoke(request), reply);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
sendErrorResponse(error, reply, options.logger);
|
|
230
|
+
}
|
|
231
|
+
return reply;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
198
237
|
// src/index.ts
|
|
199
238
|
import { skeinRoutes as skeinRoutes2 } from "@skein-js/agent-protocol";
|
|
200
239
|
export {
|
|
@@ -202,6 +241,7 @@ export {
|
|
|
202
241
|
registerSkeinHandlers,
|
|
203
242
|
sendErrorResponse,
|
|
204
243
|
sendProtocolResponse,
|
|
244
|
+
skeinInvokePlugin,
|
|
205
245
|
skeinPlugin,
|
|
206
246
|
skeinRoutes2 as skeinRoutes,
|
|
207
247
|
toProtocolRequest
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skein-js/fastify",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Fastify adapter for skein-js — mount the Agent Protocol as a Fastify plugin.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Maina Wycliffe <wmmaina7@gmail.com>",
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"node": ">=20"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@skein-js/
|
|
44
|
-
"@skein-js/
|
|
45
|
-
"@skein-js/
|
|
43
|
+
"@skein-js/agent-protocol": "0.9.0",
|
|
44
|
+
"@skein-js/server-kit": "0.9.0",
|
|
45
|
+
"@skein-js/core": "0.9.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@fastify/cors": ">=8.0.0",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"@langchain/core": "^1.2.0",
|
|
60
60
|
"@langchain/langgraph": "^1.4.0",
|
|
61
61
|
"fastify": "^5.2.0",
|
|
62
|
-
"@skein-js/storage-memory": "0.
|
|
62
|
+
"@skein-js/storage-memory": "0.9.0"
|
|
63
63
|
},
|
|
64
64
|
"publishConfig": {
|
|
65
65
|
"access": "public"
|