@artinet/fleet 0.1.0 → 0.1.5
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 +35 -2
- package/dist/default.js +1 -1
- package/dist/routes/create/index.d.ts +4 -4
- package/dist/routes/index.d.ts +1 -0
- package/dist/routes/index.js +1 -0
- package/dist/routes/intercept.d.ts +16 -0
- package/dist/routes/intercept.js +31 -0
- package/dist/routes/request/implementation/invoke.js +13 -1
- package/dist/routes/request/implementation/load.js +1 -0
- package/dist/routes/request/request.d.ts +1 -1
- package/dist/routes/request/request.js +4 -3
- package/dist/routes/request/types/definitions.d.ts +10 -7
- package/dist/server/express/agent-request.d.ts +3 -3
- package/dist/server/express/agent-request.js +8 -5
- package/dist/server/express/deploy-request.js +3 -2
- package/dist/server/express/server.d.ts +59 -0
- package/dist/server/express/server.js +37 -1
- package/dist/server/hono/agent-request.d.ts +3 -3
- package/dist/server/hono/agent-request.js +5 -4
- package/dist/server/hono/deploy-request.js +2 -1
- package/dist/server/hono/server.d.ts +68 -0
- package/dist/server/hono/server.js +46 -1
- package/dist/settings.d.ts +24 -0
- package/dist/ship.d.ts +45 -1
- package/dist/ship.js +46 -1
- package/dist/storage/in-memory.d.ts +2 -2
- package/dist/storage/in-memory.js +2 -2
- package/dist/types.d.ts +37 -0
- package/package.json +21 -22
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<a href="https://artinet.io"><img src="https://img.shields.io/badge/website-artinet.io-black" alt="Website"></a>
|
|
3
|
-
<a href="https://www.npmjs.com/package/@artinet/fleet"><img src="https://img.shields.io/npm/v/@artinet/fleet?color=black" alt="
|
|
3
|
+
<a href="https://www.npmjs.com/package/@artinet/fleet"><img src="https://img.shields.io/npm/v/@artinet/fleet?color=black" alt="Version"></a>
|
|
4
|
+
<a href="https://www.npmjs.com/package/@artinet/fleet"><img src="https://img.shields.io/npm/dt/@artinet/fleet?color=black" alt="Downloads"></a>
|
|
4
5
|
<a><img src="https://img.shields.io/badge/License-Apache_2.0-black.svg" alt="License"></a>
|
|
5
6
|
<a href="https://snyk.io/test/npm/@artinet/fleet"><img src="https://snyk.io/test/npm/@artinet/fleet/badge.svg" alt="Known Vulnerabilities"></a>
|
|
6
7
|
</p>
|
|
@@ -8,7 +9,7 @@
|
|
|
8
9
|
|
|
9
10
|
Deploy AI agents on any infrastructure.
|
|
10
11
|
|
|
11
|
-
Fleet is a lightweight server framework for hosting
|
|
12
|
+
Fleet is a lightweight server framework for hosting agents with built-in orchestration, tool integration (MCP), and Agent2Agent communication.
|
|
12
13
|
|
|
13
14
|
## Installation
|
|
14
15
|
|
|
@@ -220,6 +221,37 @@ configure({
|
|
|
220
221
|
});
|
|
221
222
|
```
|
|
222
223
|
|
|
224
|
+
### Middleware
|
|
225
|
+
|
|
226
|
+
Intercept and transform agent requests and responses by adding `Middleware`:
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import { fleet } from "@artinet/fleet/express";
|
|
230
|
+
import { Middleware } from "@artinet/fleet";
|
|
231
|
+
|
|
232
|
+
fleet({
|
|
233
|
+
middleware: new Middleware()
|
|
234
|
+
.request(async ({ request, context }) => {
|
|
235
|
+
// Inspect or transform incoming requests
|
|
236
|
+
console.log("Incoming request:", request);
|
|
237
|
+
return request;
|
|
238
|
+
})
|
|
239
|
+
.response(
|
|
240
|
+
async ({ response, context }) => {
|
|
241
|
+
// Inspect or transform outgoing responses
|
|
242
|
+
console.log("Outgoing response:", response);
|
|
243
|
+
return response;
|
|
244
|
+
},
|
|
245
|
+
// Use a trigger function to determine if the middleware should fire (defaults to `true` for every request/response)
|
|
246
|
+
({ response, context }) => {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
),
|
|
250
|
+
}).launch(3000);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
The middleware chain is composable & sequential; add multiple `request` or `response` handlers as needed. Each handler receives the current request/response and context, and must return the (optionally modified) value.
|
|
254
|
+
|
|
223
255
|
## [Docker Configuration](https://github.com/the-artinet-project/artinet/blob/main/fleet/dockerfile)
|
|
224
256
|
|
|
225
257
|
Build the docker image:
|
|
@@ -290,6 +322,7 @@ app.listen(3000);
|
|
|
290
322
|
| `testPath` | `string` | `"/test"` | Test endpoint |
|
|
291
323
|
| `inferenceProviderUrl` | `string` | `undefined` | An OpenAI API compatible endpoint |
|
|
292
324
|
| `load` | `function` | `loadAgent` | Returns an A2A Protocol compliant agent wrapped in the [`@artinet/sdk`](<(https://github.com/the-artinet-project/artinet-sdk)>) |
|
|
325
|
+
| `middleware` | `Middleware` | `undefined` | Request/response interceptors for the agent route |
|
|
293
326
|
|
|
294
327
|
## API Reference
|
|
295
328
|
|
package/dist/default.js
CHANGED
|
@@ -801,7 +801,7 @@ export declare const CreateAgentRequestSchema: import("zod/v4").ZodObject<{
|
|
|
801
801
|
instructions: import("zod/v4").ZodString;
|
|
802
802
|
services: import("zod/v4").ZodDefault<import("zod/v4").ZodArray<import("zod/v4").ZodUnion<readonly [import("zod/v4").ZodUnion<readonly [import("zod/v4").ZodObject<{
|
|
803
803
|
id: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
804
|
-
url: import("zod/v4").
|
|
804
|
+
url: import("zod/v4").ZodURL;
|
|
805
805
|
headers: import("zod/v4").ZodOptional<import("zod/v4").ZodRecord<import("zod/v4").ZodString, import("zod/v4").ZodString>>;
|
|
806
806
|
authToken: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
807
807
|
parameters: import("zod/v4").ZodOptional<import("zod/v4").ZodRecord<import("zod/v4").ZodString, import("zod/v4").ZodUnknown>>;
|
|
@@ -916,7 +916,7 @@ export declare const CreateAgentRequestSchema: import("zod/v4").ZodObject<{
|
|
|
916
916
|
}, import("zod/v4/core").$strip>;
|
|
917
917
|
}, import("zod/v4/core").$strip>, import("zod/v4").ZodObject<{
|
|
918
918
|
id: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
919
|
-
url: import("zod/v4").ZodOptional<import("zod/v4").
|
|
919
|
+
url: import("zod/v4").ZodOptional<import("zod/v4").ZodURL>;
|
|
920
920
|
headers: import("zod/v4").ZodOptional<import("zod/v4").ZodOptional<import("zod/v4").ZodRecord<import("zod/v4").ZodString, import("zod/v4").ZodString>>>;
|
|
921
921
|
authToken: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
922
922
|
parameters: import("zod/v4").ZodOptional<import("zod/v4").ZodRecord<import("zod/v4").ZodString, import("zod/v4").ZodUnknown>>;
|
|
@@ -1031,7 +1031,7 @@ export declare const CreateAgentRequestSchema: import("zod/v4").ZodObject<{
|
|
|
1031
1031
|
}, import("zod/v4/core").$strip>;
|
|
1032
1032
|
}, import("zod/v4/core").$strip>]>, import("zod/v4").ZodUnion<readonly [import("zod/v4").ZodObject<{
|
|
1033
1033
|
id: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
1034
|
-
url: import("zod/v4").
|
|
1034
|
+
url: import("zod/v4").ZodURL;
|
|
1035
1035
|
headers: import("zod/v4").ZodOptional<import("zod/v4").ZodRecord<import("zod/v4").ZodString, import("zod/v4").ZodString>>;
|
|
1036
1036
|
authToken: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
1037
1037
|
parameters: import("zod/v4").ZodOptional<import("zod/v4").ZodRecord<import("zod/v4").ZodString, import("zod/v4").ZodUnknown>>;
|
|
@@ -1168,7 +1168,7 @@ export declare const CreateAgentRequestSchema: import("zod/v4").ZodObject<{
|
|
|
1168
1168
|
}, import("zod/v4/core").$strip>;
|
|
1169
1169
|
}, import("zod/v4/core").$strip>, import("zod/v4").ZodObject<{
|
|
1170
1170
|
id: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
1171
|
-
url: import("zod/v4").ZodOptional<import("zod/v4").
|
|
1171
|
+
url: import("zod/v4").ZodOptional<import("zod/v4").ZodURL>;
|
|
1172
1172
|
headers: import("zod/v4").ZodOptional<import("zod/v4").ZodOptional<import("zod/v4").ZodRecord<import("zod/v4").ZodString, import("zod/v4").ZodString>>>;
|
|
1173
1173
|
authToken: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
1174
1174
|
parameters: import("zod/v4").ZodOptional<import("zod/v4").ZodRecord<import("zod/v4").ZodString, import("zod/v4").ZodUnknown>>;
|
package/dist/routes/index.d.ts
CHANGED
package/dist/routes/index.js
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 The Artinet Project
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import * as armada from "@artinet/armada";
|
|
6
|
+
import { RequestAgentRoute } from "./request/types/definitions.js";
|
|
7
|
+
import { API } from "@artinet/types";
|
|
8
|
+
export declare class InterceptBuilder<Req extends API.APIRequest = RequestAgentRoute["request"], Res extends API.APIResponse = RequestAgentRoute["response"], Context extends armada.BaseContext = RequestAgentRoute["context"]> {
|
|
9
|
+
private readonly intercepts;
|
|
10
|
+
constructor(intercepts?: armada.Intercept<Req, Res, Req | Res, Context>[]);
|
|
11
|
+
build(): armada.Intercept<Req, Res, Req | Res, Context>[];
|
|
12
|
+
request(action: armada.Intercept<Req, Res, Req, Context>["action"], trigger?: armada.Intercept<Req, Res, Req, Context>["trigger"]): InterceptBuilder<Req, Res, Context>;
|
|
13
|
+
response(action: armada.Intercept<Req, Res, Res, Context>["action"], trigger?: armada.Intercept<Req, Res, Res, Context>["trigger"]): InterceptBuilder<Req, Res, Context>;
|
|
14
|
+
}
|
|
15
|
+
export type Middleware = InterceptBuilder;
|
|
16
|
+
export declare const Middleware: typeof InterceptBuilder;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 The Artinet Project
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import * as armada from "@artinet/armada";
|
|
6
|
+
export class InterceptBuilder {
|
|
7
|
+
intercepts;
|
|
8
|
+
constructor(intercepts = []) {
|
|
9
|
+
this.intercepts = intercepts;
|
|
10
|
+
}
|
|
11
|
+
build() {
|
|
12
|
+
return this.intercepts;
|
|
13
|
+
}
|
|
14
|
+
request(action, trigger) {
|
|
15
|
+
this.intercepts.push({
|
|
16
|
+
action,
|
|
17
|
+
trigger: trigger ?? true,
|
|
18
|
+
phase: armada.Phase.REQUEST,
|
|
19
|
+
});
|
|
20
|
+
return new InterceptBuilder(this.intercepts);
|
|
21
|
+
}
|
|
22
|
+
response(action, trigger) {
|
|
23
|
+
this.intercepts.push({
|
|
24
|
+
action,
|
|
25
|
+
trigger: trigger ?? true,
|
|
26
|
+
phase: armada.Phase.RESPONSE,
|
|
27
|
+
});
|
|
28
|
+
return new InterceptBuilder(this.intercepts);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export const Middleware = InterceptBuilder;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as sdk from "@artinet/sdk";
|
|
6
6
|
import { assert } from "console";
|
|
7
|
+
import { A2AError } from "@a2a-js/sdk/server";
|
|
7
8
|
function isAgentMessenger(agent) {
|
|
8
9
|
return agent instanceof sdk.AgentMessenger;
|
|
9
10
|
}
|
|
@@ -17,9 +18,20 @@ export const invoke = async (type, request, invocable) => {
|
|
|
17
18
|
}
|
|
18
19
|
catch (error) {
|
|
19
20
|
sdk.logger.error(`invocation error:${request.method}:error:${JSON.stringify(error, null, 2)}`, { error });
|
|
21
|
+
let jsonRPCError;
|
|
22
|
+
if (error instanceof A2AError || error instanceof sdk.SystemError) {
|
|
23
|
+
jsonRPCError = {
|
|
24
|
+
code: error.code,
|
|
25
|
+
message: error.message,
|
|
26
|
+
data: error.data,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
jsonRPCError = A2AError.internalError(error?.message ?? "Internal error", { cause: error?.stack }).toJSONRPCError();
|
|
31
|
+
}
|
|
20
32
|
return {
|
|
21
33
|
type: "error",
|
|
22
|
-
error:
|
|
34
|
+
error: jsonRPCError,
|
|
23
35
|
};
|
|
24
36
|
}
|
|
25
37
|
if (!result) {
|
|
@@ -33,6 +33,7 @@ export const loadAgent = async (config, context, provider = process.env.OPENAI_A
|
|
|
33
33
|
context.defaultInstructions ??
|
|
34
34
|
DEFAULT_INSTRUCTIONS,
|
|
35
35
|
provider,
|
|
36
|
+
tasks: context.tasks,
|
|
36
37
|
});
|
|
37
38
|
if (requiredAgentsNotLoaded(config, context)) {
|
|
38
39
|
throw sdk.INTERNAL_ERROR({
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { RequestAgentRoute, TestAgentRoute } from "./types/definitions.js";
|
|
6
|
-
export declare const requestAgent: (request: RequestAgentRoute["request"], context: RequestAgentRoute["context"], requestFn?: RequestAgentRoute["implementation"]) => Promise<RequestAgentRoute["response"]>;
|
|
6
|
+
export declare const requestAgent: (request: RequestAgentRoute["request"], context: RequestAgentRoute["context"], requestFn?: RequestAgentRoute["implementation"], intercepts?: RequestAgentRoute["intercept"][]) => Promise<RequestAgentRoute["response"]>;
|
|
7
7
|
export declare const RequestAgent: RequestAgentRoute["implementation"];
|
|
8
8
|
/**
|
|
9
9
|
* Test agent implementation.
|
|
@@ -6,13 +6,14 @@ import * as armada from "@artinet/armada";
|
|
|
6
6
|
import { FetchAgent } from "./interceptors/fetch-agent.js";
|
|
7
7
|
import { GetAgents } from "./interceptors/get-agents.js";
|
|
8
8
|
import { requestImplementation } from "./implementation/request.js";
|
|
9
|
-
|
|
9
|
+
const DEFAULT_INTERCEPTS = [FetchAgent, GetAgents];
|
|
10
|
+
export const requestAgent = (request, context, requestFn = requestImplementation, intercepts = []) => armada.entry({
|
|
10
11
|
request,
|
|
11
12
|
implementation: requestFn,
|
|
12
|
-
intercepts: [
|
|
13
|
+
intercepts: [...DEFAULT_INTERCEPTS, ...intercepts],
|
|
13
14
|
context,
|
|
14
15
|
});
|
|
15
|
-
export const RequestAgent = (request, context) => requestAgent(request, context, requestImplementation);
|
|
16
|
+
export const RequestAgent = (request, context, intercepts = []) => requestAgent(request, context, requestImplementation, intercepts);
|
|
16
17
|
/**
|
|
17
18
|
* Test agent implementation.
|
|
18
19
|
* @note Similar to RequestAgent, but skips the FetchAgent intercept and uses the testInvoke function that returns a stream of updates.
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
import * as armada from "@artinet/armada";
|
|
6
6
|
import { AgentConfiguration } from "agent-def";
|
|
7
7
|
import * as sdk from "@artinet/sdk";
|
|
8
|
+
import { API } from "@artinet/types";
|
|
8
9
|
import { z } from "zod/v4";
|
|
9
10
|
import { ResultOrError } from "../../../types.js";
|
|
10
|
-
export type AgentRequest = {
|
|
11
|
+
export type AgentRequest = API.APIRequest & {
|
|
11
12
|
method: string;
|
|
12
13
|
params: sdk.A2A.RequestParam;
|
|
13
14
|
};
|
|
@@ -16,11 +17,13 @@ export type AgentError = {
|
|
|
16
17
|
message: string;
|
|
17
18
|
data?: unknown;
|
|
18
19
|
};
|
|
19
|
-
export type AgentResponse = ResultOrError<sdk.A2A.ResponseResult | sdk.A2A.AgentCard, AgentError, sdk.A2A.Update>;
|
|
20
|
+
export type AgentResponse = API.APIResponse & ResultOrError<sdk.A2A.ResponseResult | sdk.A2A.AgentCard, AgentError, sdk.A2A.Update>;
|
|
20
21
|
export type Agent = sdk.Agent | sdk.AgentMessenger;
|
|
21
22
|
export type loadFunction = (config: AgentConfiguration, context?: RequestContext) => Promise<Agent | undefined>;
|
|
22
23
|
export type invokeFunction = <Req extends AgentRequest = AgentRequest>(request: Req, agent: Agent, context?: RequestContext) => Promise<AgentResponse | null>;
|
|
23
|
-
export interface RequestContext extends armada.StorageContext<typeof armada.StoredAgentSchema>, armada.FindContext<typeof armada.StoredAgentSchema
|
|
24
|
+
export interface RequestContext extends armada.StorageContext<typeof armada.StoredAgentSchema>, armada.FindContext<typeof armada.StoredAgentSchema>,
|
|
25
|
+
/**If passing `contexts` to the `orc8` loader, be aware that it requires a Monitored Context Manager */
|
|
26
|
+
Pick<sdk.CreateAgentParams, "contexts" | "tasks"> {
|
|
24
27
|
agentId: string;
|
|
25
28
|
headers?: Record<string, string>;
|
|
26
29
|
agents?: Record<string, Agent>;
|
|
@@ -167,7 +170,7 @@ export declare const TestRequestSchema: z.ZodObject<{
|
|
|
167
170
|
instructions: z.ZodString;
|
|
168
171
|
services: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodObject<{
|
|
169
172
|
id: z.ZodOptional<z.ZodString>;
|
|
170
|
-
url: z.
|
|
173
|
+
url: z.ZodURL;
|
|
171
174
|
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
172
175
|
authToken: z.ZodOptional<z.ZodString>;
|
|
173
176
|
parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -282,7 +285,7 @@ export declare const TestRequestSchema: z.ZodObject<{
|
|
|
282
285
|
}, z.core.$strip>;
|
|
283
286
|
}, z.core.$strip>, z.ZodObject<{
|
|
284
287
|
id: z.ZodOptional<z.ZodString>;
|
|
285
|
-
url: z.ZodOptional<z.
|
|
288
|
+
url: z.ZodOptional<z.ZodURL>;
|
|
286
289
|
headers: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
|
|
287
290
|
authToken: z.ZodOptional<z.ZodString>;
|
|
288
291
|
parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -397,7 +400,7 @@ export declare const TestRequestSchema: z.ZodObject<{
|
|
|
397
400
|
}, z.core.$strip>;
|
|
398
401
|
}, z.core.$strip>]>, z.ZodUnion<readonly [z.ZodObject<{
|
|
399
402
|
id: z.ZodOptional<z.ZodString>;
|
|
400
|
-
url: z.
|
|
403
|
+
url: z.ZodURL;
|
|
401
404
|
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
402
405
|
authToken: z.ZodOptional<z.ZodString>;
|
|
403
406
|
parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -534,7 +537,7 @@ export declare const TestRequestSchema: z.ZodObject<{
|
|
|
534
537
|
}, z.core.$strip>;
|
|
535
538
|
}, z.core.$strip>, z.ZodObject<{
|
|
536
539
|
id: z.ZodOptional<z.ZodString>;
|
|
537
|
-
url: z.ZodOptional<z.
|
|
540
|
+
url: z.ZodOptional<z.ZodURL>;
|
|
538
541
|
headers: z.ZodOptional<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
|
|
539
542
|
authToken: z.ZodOptional<z.ZodString>;
|
|
540
543
|
parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
import express from "express";
|
|
6
6
|
import { RequestAgentRoute, RequestContext } from "../../routes/request/index.js";
|
|
7
7
|
export declare const AGENT_FIELD_NAME = "agentId";
|
|
8
|
-
export type handler = (req: express.Request, res: express.Response, next: express.NextFunction, context: RequestContext, request?: RequestAgentRoute["implementation"]) => Promise<void>;
|
|
9
|
-
export declare function handle(req: express.Request, res: express.Response, _next: express.NextFunction, context: RequestContext, request?: RequestAgentRoute["implementation"]): Promise<void>;
|
|
10
|
-
export declare const factory: (request?: RequestAgentRoute["implementation"]) => handler;
|
|
8
|
+
export type handler = (req: express.Request, res: express.Response, next: express.NextFunction, context: RequestContext, request?: RequestAgentRoute["implementation"], intercepts?: RequestAgentRoute["intercept"][]) => Promise<void>;
|
|
9
|
+
export declare function handle(req: express.Request, res: express.Response, _next: express.NextFunction, context: RequestContext, request?: RequestAgentRoute["implementation"], intercepts?: RequestAgentRoute["intercept"][]): Promise<void>;
|
|
10
|
+
export declare const factory: (request?: RequestAgentRoute["implementation"], intercepts?: RequestAgentRoute["intercept"][]) => handler;
|
|
11
11
|
/**
|
|
12
12
|
* Handler utilities for agent HTTP requests.
|
|
13
13
|
*
|
|
@@ -8,7 +8,7 @@ import * as sdk from "@artinet/sdk";
|
|
|
8
8
|
import { handleJSONRPCResponse } from "./rpc.js";
|
|
9
9
|
import { generateRequestId } from "./utils.js";
|
|
10
10
|
export const AGENT_FIELD_NAME = "agentId";
|
|
11
|
-
export async function handle(req, res, _next, context, request = RequestAgent) {
|
|
11
|
+
export async function handle(req, res, _next, context, request = RequestAgent, intercepts) {
|
|
12
12
|
const requestId = generateRequestId(context, req);
|
|
13
13
|
let parsed;
|
|
14
14
|
if (req?.path?.endsWith("agent-card.json") ||
|
|
@@ -28,13 +28,16 @@ export async function handle(req, res, _next, context, request = RequestAgent) {
|
|
|
28
28
|
method: parsed.method,
|
|
29
29
|
params: params,
|
|
30
30
|
};
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
sdk.logger.info(`handle agent request received:${parsed.method}:params:${sdk.formatJson(agentRequest)}`);
|
|
32
|
+
const response = await request(agentRequest, context, intercepts);
|
|
33
|
+
sdk.logger.info(`handle agent request completed:${parsed.method}:response:${sdk.formatJson(response)}`);
|
|
33
34
|
await handleJSONRPCResponse(res, requestId, parsed.method, response);
|
|
34
35
|
}
|
|
35
|
-
export const factory = (request = RequestAgent) => async (req, res, next, context) => await handle(req, res, next, context, request);
|
|
36
|
+
export const factory = (request = RequestAgent, intercepts) => async (req, res, next, context) => await handle(req, res, next, context, request, intercepts);
|
|
36
37
|
export async function request({ request: req, response: res, next, context, handler = handle, user, }) {
|
|
37
|
-
const agentId = req?.params?.[AGENT_FIELD_NAME]
|
|
38
|
+
const agentId = Array.isArray(req?.params?.[AGENT_FIELD_NAME])
|
|
39
|
+
? req?.params?.[AGENT_FIELD_NAME][0]
|
|
40
|
+
: req?.params?.[AGENT_FIELD_NAME];
|
|
38
41
|
if (!agentId) {
|
|
39
42
|
return next(INVALID_REQUEST({ message: `${AGENT_FIELD_NAME} is required` }));
|
|
40
43
|
}
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { CreateAgent, CreateAgentRequestSchema, } from "../../routes/create/index.js";
|
|
6
6
|
import { generateRequestId, generateRegistrationId } from "./utils.js";
|
|
7
|
-
import { logger, validateSchema } from "@artinet/sdk";
|
|
7
|
+
import { logger, validateSchema, formatJson } from "@artinet/sdk";
|
|
8
8
|
export async function handle(req, res, _next, context, deploy = CreateAgent) {
|
|
9
|
-
logger.warn(`handle deploy request with body: ${JSON.stringify(req.body)}`);
|
|
10
9
|
const request = await validateSchema(CreateAgentRequestSchema, req?.body ?? {});
|
|
10
|
+
logger.info(`deploying agent: ${request.config.name}`);
|
|
11
|
+
logger.debug(`deploying agent: ${formatJson(request)}`);
|
|
11
12
|
context.registrationId = generateRegistrationId(request.config.uri);
|
|
12
13
|
const result = await deploy(request, context);
|
|
13
14
|
res.json(result);
|
|
@@ -9,18 +9,77 @@ import { Settings as FleetSettings } from "../../settings.js";
|
|
|
9
9
|
import * as agent from "./agent-request.js";
|
|
10
10
|
import * as testing from "./test-request.js";
|
|
11
11
|
import * as deployment from "./deploy-request.js";
|
|
12
|
+
/**
|
|
13
|
+
* Extended settings for the Express Fleet server.
|
|
14
|
+
*
|
|
15
|
+
* Combines base {@link FleetSettings} with Express-specific handlers for
|
|
16
|
+
* authentication, user resolution, and request processing.
|
|
17
|
+
*
|
|
18
|
+
* @see {@link https://expressjs.com/en/guide/using-middleware.html Express Middleware}
|
|
19
|
+
*/
|
|
12
20
|
export type Settings = FleetSettings & {
|
|
21
|
+
/** Extracts the user ID from an incoming request. Used for multi-tenant agent isolation. */
|
|
13
22
|
user?: (req: express.Request) => Promise<string>;
|
|
23
|
+
/** Handler for agent retrieval requests. Generated via {@link agent.factory}. */
|
|
14
24
|
retrieve?: agent.handler;
|
|
25
|
+
/** Handler for agent deployment requests. Generated via {@link deployment.factory}. */
|
|
15
26
|
deploy?: deployment.handler;
|
|
27
|
+
/** Handler for agent test/evaluation requests. Generated via {@link testing.factory}. */
|
|
16
28
|
evaluate?: testing.handler;
|
|
29
|
+
/**
|
|
30
|
+
* Authentication middleware applied to protected routes.
|
|
31
|
+
* @see {@link https://expressjs.com/en/guide/writing-middleware.html Writing Middleware}
|
|
32
|
+
*/
|
|
17
33
|
auth?: (req: express.Request, res: express.Response, next: express.NextFunction) => Promise<void>;
|
|
18
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Options for configuring the Fleet server instance.
|
|
37
|
+
*
|
|
38
|
+
* Allows injection of a pre-configured Express app for integration with
|
|
39
|
+
* existing servers or custom middleware stacks.
|
|
40
|
+
*/
|
|
19
41
|
export interface Options {
|
|
42
|
+
/** Pre-configured Express application. Defaults to a new `express()` instance. */
|
|
20
43
|
app?: express.Application;
|
|
44
|
+
/** Apply auth middleware to agent retrieval routes. Defaults to `false`. */
|
|
21
45
|
authOnRetrieve?: boolean;
|
|
46
|
+
/** Expose the test endpoint for agent evaluation. Defaults to `true`. */
|
|
22
47
|
enableTesting?: boolean;
|
|
23
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Creates and configures a Fleet server instance using Express.
|
|
51
|
+
*
|
|
52
|
+
* This function implements the **Factory Pattern** combined with **Dependency Injection**
|
|
53
|
+
* to provide a flexible, testable, and configurable server setup. The pattern allows
|
|
54
|
+
* consumers to override defaults while maintaining sensible out-of-the-box behavior.
|
|
55
|
+
*
|
|
56
|
+
* @param settings - Partial configuration merged with defaults. Supports custom
|
|
57
|
+
* handlers for `get`, `set`, `test`, and middleware composition.
|
|
58
|
+
* @param options - Server instantiation options
|
|
59
|
+
* @param options.app - Pre-configured Express application instance. Useful for
|
|
60
|
+
* adding custom middleware or integrating with existing servers.
|
|
61
|
+
* @param options.authOnRetrieve - When `true`, applies auth middleware to agent
|
|
62
|
+
* retrieval routes. Defaults to `false` for development convenience.
|
|
63
|
+
* @param options.enableTesting - When `true`, exposes the test endpoint for
|
|
64
|
+
* agent evaluation. Disable in production if not needed.
|
|
65
|
+
*
|
|
66
|
+
* @returns Object containing:
|
|
67
|
+
* - `app`: The configured Express application
|
|
68
|
+
* - `launch`: Function to start the HTTP server on a specified port
|
|
69
|
+
* - `ship`: Async function to deploy agents and return a launchable server
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* // Basic usage with defaults
|
|
74
|
+
* const { app, launch } = fleet();
|
|
75
|
+
* launch(3000);
|
|
76
|
+
*
|
|
77
|
+
* // With custom configuration
|
|
78
|
+
* const { ship } = fleet({ userId: 'admin' }, { authOnRetrieve: true });
|
|
79
|
+
* const server = await ship([agentConfig]);
|
|
80
|
+
* server.launch(8080);
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
24
83
|
export declare function fleet(settings?: Partial<Settings>, { app, authOnRetrieve, enableTesting, }?: Options): {
|
|
25
84
|
app: express.Application;
|
|
26
85
|
launch: (port: number) => Server;
|
|
@@ -13,7 +13,9 @@ const createContext = (settings) => {
|
|
|
13
13
|
const _settings = {
|
|
14
14
|
...DEFAULTS,
|
|
15
15
|
...settings,
|
|
16
|
-
retrieve: agent.factory(settings.get ?? DEFAULTS.get
|
|
16
|
+
retrieve: agent.factory(settings.get ?? DEFAULTS.get,
|
|
17
|
+
/**Middleware addons are currently only supported on the agent request route */
|
|
18
|
+
settings.middleware?.build() ?? []),
|
|
17
19
|
deploy: deployment.factory(settings.set ?? DEFAULTS.set),
|
|
18
20
|
evaluate: testing.factory(settings.test ?? DEFAULTS.test),
|
|
19
21
|
user: settings.user
|
|
@@ -38,6 +40,40 @@ const createRequestContext = (context) => {
|
|
|
38
40
|
timestamp: undefined,
|
|
39
41
|
};
|
|
40
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Creates and configures a Fleet server instance using Express.
|
|
45
|
+
*
|
|
46
|
+
* This function implements the **Factory Pattern** combined with **Dependency Injection**
|
|
47
|
+
* to provide a flexible, testable, and configurable server setup. The pattern allows
|
|
48
|
+
* consumers to override defaults while maintaining sensible out-of-the-box behavior.
|
|
49
|
+
*
|
|
50
|
+
* @param settings - Partial configuration merged with defaults. Supports custom
|
|
51
|
+
* handlers for `get`, `set`, `test`, and middleware composition.
|
|
52
|
+
* @param options - Server instantiation options
|
|
53
|
+
* @param options.app - Pre-configured Express application instance. Useful for
|
|
54
|
+
* adding custom middleware or integrating with existing servers.
|
|
55
|
+
* @param options.authOnRetrieve - When `true`, applies auth middleware to agent
|
|
56
|
+
* retrieval routes. Defaults to `false` for development convenience.
|
|
57
|
+
* @param options.enableTesting - When `true`, exposes the test endpoint for
|
|
58
|
+
* agent evaluation. Disable in production if not needed.
|
|
59
|
+
*
|
|
60
|
+
* @returns Object containing:
|
|
61
|
+
* - `app`: The configured Express application
|
|
62
|
+
* - `launch`: Function to start the HTTP server on a specified port
|
|
63
|
+
* - `ship`: Async function to deploy agents and return a launchable server
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* // Basic usage with defaults
|
|
68
|
+
* const { app, launch } = fleet();
|
|
69
|
+
* launch(3000);
|
|
70
|
+
*
|
|
71
|
+
* // With custom configuration
|
|
72
|
+
* const { ship } = fleet({ userId: 'admin' }, { authOnRetrieve: true });
|
|
73
|
+
* const server = await ship([agentConfig]);
|
|
74
|
+
* server.launch(8080);
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
41
77
|
export function fleet(settings = DEFAULTS, { app = express(), authOnRetrieve = false, enableTesting = true, } = {}) {
|
|
42
78
|
const context = createContext(settings);
|
|
43
79
|
const { basePath, agentPath, fallbackPath, deploymentPath, testPath, auth, user, evaluate, deploy, retrieve, set, } = context;
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
import * as hono from "hono";
|
|
6
6
|
import { RequestAgentRoute, RequestContext } from "../../routes/request/index.js";
|
|
7
7
|
export declare const AGENT_FIELD_NAME = "agentId";
|
|
8
|
-
export type handler = (ctx: hono.Context, next: hono.Next, context: RequestContext, request?: RequestAgentRoute["implementation"]) => Promise<void>;
|
|
9
|
-
export declare function handle(ctx: hono.Context, _next: hono.Next, context: RequestContext, request?: RequestAgentRoute["implementation"]): Promise<void>;
|
|
10
|
-
export declare const factory: (request?: RequestAgentRoute["implementation"]) => handler;
|
|
8
|
+
export type handler = (ctx: hono.Context, next: hono.Next, context: RequestContext, request?: RequestAgentRoute["implementation"], intercepts?: RequestAgentRoute["intercept"][]) => Promise<void>;
|
|
9
|
+
export declare function handle(ctx: hono.Context, _next: hono.Next, context: RequestContext, request?: RequestAgentRoute["implementation"], intercepts?: RequestAgentRoute["intercept"][]): Promise<void>;
|
|
10
|
+
export declare const factory: (request?: RequestAgentRoute["implementation"], intercepts?: RequestAgentRoute["intercept"][]) => handler;
|
|
11
11
|
/**
|
|
12
12
|
* Handler utilities for agent HTTP requests.
|
|
13
13
|
*
|
|
@@ -8,7 +8,7 @@ import * as sdk from "@artinet/sdk";
|
|
|
8
8
|
import { handleJSONRPCResponse } from "./rpc.js";
|
|
9
9
|
import { generateRequestId } from "./utils.js";
|
|
10
10
|
export const AGENT_FIELD_NAME = "agentId";
|
|
11
|
-
export async function handle(ctx, _next, context, request = RequestAgent) {
|
|
11
|
+
export async function handle(ctx, _next, context, request = RequestAgent, intercepts) {
|
|
12
12
|
/* hono.Context.req uses a raw JSON.parse() so we prefer to use the text() and our own safeParse() */
|
|
13
13
|
const body = sdk.safeParse(await ctx.req.text());
|
|
14
14
|
const requestId = generateRequestId(context, ctx.req.header("x-request-id") ?? body?.id);
|
|
@@ -30,11 +30,12 @@ export async function handle(ctx, _next, context, request = RequestAgent) {
|
|
|
30
30
|
method: parsed.method,
|
|
31
31
|
params: params,
|
|
32
32
|
};
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
sdk.logger.info(`handle agent request received:${parsed.method}:params:${sdk.formatJson(agentRequest)}`);
|
|
34
|
+
const response = await request(agentRequest, context, intercepts);
|
|
35
|
+
sdk.logger.info(`handle agent request completed:${parsed.method}:response:${sdk.formatJson(response)}`);
|
|
35
36
|
await handleJSONRPCResponse(ctx, requestId, parsed.method, response);
|
|
36
37
|
}
|
|
37
|
-
export const factory = (request = RequestAgent) => async (ctx, next, context) => await handle(ctx, next, context, request);
|
|
38
|
+
export const factory = (request = RequestAgent, intercepts) => async (ctx, next, context) => await handle(ctx, next, context, request, intercepts);
|
|
38
39
|
export async function request({ ctx, next, context, handler = handle, user, }) {
|
|
39
40
|
const agentId = ctx.req.param(AGENT_FIELD_NAME);
|
|
40
41
|
if (!agentId) {
|
|
@@ -8,8 +8,9 @@ import { generateRequestId, generateRegistrationId } from "./utils.js";
|
|
|
8
8
|
export async function handle(ctx, _next, context, deploy = CreateAgent) {
|
|
9
9
|
/* hono.Context.req uses a raw JSON.parse() so we prefer to use the text() and our own safeParse() */
|
|
10
10
|
const req = sdk.safeParse(await ctx.req.text());
|
|
11
|
-
sdk.logger.warn(`handle deploy request with body: ${JSON.stringify(req)}`);
|
|
12
11
|
const request = await sdk.validateSchema(CreateAgentRequestSchema, req);
|
|
12
|
+
sdk.logger.info(`deploying agent: ${request.config.name}`);
|
|
13
|
+
sdk.logger.debug(`deploying agent: ${sdk.formatJson(request)}`);
|
|
13
14
|
context.registrationId = generateRegistrationId(request.config.uri);
|
|
14
15
|
const result = await deploy(request, context);
|
|
15
16
|
ctx.res = ctx.json(result);
|
|
@@ -9,18 +9,86 @@ import { Settings as FleetSettings } from "../../settings.js";
|
|
|
9
9
|
import * as agent from "./agent-request.js";
|
|
10
10
|
import * as testing from "./test-request.js";
|
|
11
11
|
import * as deployment from "./deploy-request.js";
|
|
12
|
+
/**
|
|
13
|
+
* Extended settings for the Hono Fleet server.
|
|
14
|
+
*
|
|
15
|
+
* Combines base {@link FleetSettings} with Hono-specific handlers for
|
|
16
|
+
* authentication, user resolution, and request processing.
|
|
17
|
+
*
|
|
18
|
+
* @see {@link https://hono.dev/docs/guides/middleware Hono Middleware Guide}
|
|
19
|
+
*/
|
|
12
20
|
export type Settings = FleetSettings & {
|
|
21
|
+
/** Extracts the user ID from the Hono context. Used for multi-tenant agent isolation. */
|
|
13
22
|
user?: (ctx: hono.Context) => Promise<string>;
|
|
23
|
+
/** Handler for agent retrieval requests. Generated via {@link agent.factory}. */
|
|
14
24
|
retrieve?: agent.handler;
|
|
25
|
+
/** Handler for agent deployment requests. Generated via {@link deployment.factory}. */
|
|
15
26
|
deploy?: deployment.handler;
|
|
27
|
+
/** Handler for agent test/evaluation requests. Generated via {@link testing.factory}. */
|
|
16
28
|
evaluate?: testing.handler;
|
|
29
|
+
/**
|
|
30
|
+
* Authentication middleware applied to protected routes.
|
|
31
|
+
* @see {@link https://hono.dev/docs/guides/middleware#middleware-argument Middleware Guide}
|
|
32
|
+
*/
|
|
17
33
|
auth?: (ctx: hono.Context, next: hono.Next) => Promise<void>;
|
|
18
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Options for configuring the Fleet server instance.
|
|
37
|
+
*
|
|
38
|
+
* Allows injection of a pre-configured Hono app for integration with
|
|
39
|
+
* existing servers or edge runtime deployments.
|
|
40
|
+
*/
|
|
19
41
|
export interface Options {
|
|
42
|
+
/** Pre-configured Hono application. Defaults to a new `Hono()` instance. */
|
|
20
43
|
app?: hono.Hono;
|
|
44
|
+
/** Apply auth middleware to agent retrieval routes. Defaults to `false`. */
|
|
21
45
|
authOnRetrieve?: boolean;
|
|
46
|
+
/** Expose the test endpoint for agent evaluation. Defaults to `true`. */
|
|
22
47
|
enableTesting?: boolean;
|
|
23
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Creates and configures a Fleet server instance using Hono.
|
|
51
|
+
*
|
|
52
|
+
* This function implements the **Factory Pattern** combined with **Dependency Injection**
|
|
53
|
+
* to provide a flexible, testable, and configurable server setup. Hono is chosen for its
|
|
54
|
+
* ultrafast performance, edge-runtime compatibility, and minimal footprint.
|
|
55
|
+
*
|
|
56
|
+
* @see {@link https://hono.dev/docs/ Hono Documentation}
|
|
57
|
+
* @see {@link https://hono.dev/docs/concepts/routers Hono Routers}
|
|
58
|
+
* @see {@link https://hono.dev/docs/guides/middleware Hono Middleware Guide}
|
|
59
|
+
*
|
|
60
|
+
* ## Security Considerations
|
|
61
|
+
*
|
|
62
|
+
* - Authentication middleware is applied conditionally via `auth` setting
|
|
63
|
+
* - `authOnRetrieve` flag controls whether agent retrieval requires authentication
|
|
64
|
+
* - Consider enabling `authOnRetrieve` in production environments
|
|
65
|
+
*
|
|
66
|
+
* @param settings - Partial configuration merged with defaults. Supports custom
|
|
67
|
+
* handlers for `get`, `set`, `test`, and middleware composition.
|
|
68
|
+
* @param options - Server instantiation options
|
|
69
|
+
* @param options.app - Pre-configured Hono application instance. Useful for
|
|
70
|
+
* adding custom middleware or integrating with existing servers.
|
|
71
|
+
* @param options.authOnRetrieve - When `true`, applies auth middleware to agent
|
|
72
|
+
* retrieval routes. Defaults to `false` for development convenience.
|
|
73
|
+
* @param options.enableTesting - When `true`, exposes the test endpoint for
|
|
74
|
+
* agent evaluation. Disable in production if not needed.
|
|
75
|
+
*
|
|
76
|
+
* @returns Object containing:
|
|
77
|
+
* - `app`: The configured Hono application
|
|
78
|
+
* - `launch`: Function to start the HTTP server on a specified port
|
|
79
|
+
* - `ship`: Async function to deploy agents and return a launchable server
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* // Basic usage with defaults
|
|
84
|
+
* const { app, launch } = fleet();
|
|
85
|
+
* launch(3000);
|
|
86
|
+
*
|
|
87
|
+
* // With custom configuration and edge deployment
|
|
88
|
+
* const { app } = fleet({ userId: 'admin' }, { authOnRetrieve: true });
|
|
89
|
+
* export default app; // For Cloudflare Workers
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
24
92
|
export declare function fleet(settings?: Partial<Settings>, { app, authOnRetrieve, enableTesting, }?: Options): {
|
|
25
93
|
app: hono.Hono;
|
|
26
94
|
launch: (port: number) => ServerType;
|
|
@@ -15,7 +15,9 @@ const createContext = (settings) => {
|
|
|
15
15
|
const _settings = {
|
|
16
16
|
...DEFAULTS,
|
|
17
17
|
...settings,
|
|
18
|
-
retrieve: agent.factory(settings.get ?? DEFAULTS.get
|
|
18
|
+
retrieve: agent.factory(settings.get ?? DEFAULTS.get,
|
|
19
|
+
/**Middleware addons are currently only supported on the agent request route */
|
|
20
|
+
settings.middleware?.build() ?? []),
|
|
19
21
|
deploy: deployment.factory(settings.set ?? DEFAULTS.set),
|
|
20
22
|
evaluate: testing.factory(settings.test ?? DEFAULTS.test),
|
|
21
23
|
user: settings.user
|
|
@@ -40,6 +42,49 @@ const createRequestContext = (context) => {
|
|
|
40
42
|
timestamp: undefined,
|
|
41
43
|
};
|
|
42
44
|
};
|
|
45
|
+
/**
|
|
46
|
+
* Creates and configures a Fleet server instance using Hono.
|
|
47
|
+
*
|
|
48
|
+
* This function implements the **Factory Pattern** combined with **Dependency Injection**
|
|
49
|
+
* to provide a flexible, testable, and configurable server setup. Hono is chosen for its
|
|
50
|
+
* ultrafast performance, edge-runtime compatibility, and minimal footprint.
|
|
51
|
+
*
|
|
52
|
+
* @see {@link https://hono.dev/docs/ Hono Documentation}
|
|
53
|
+
* @see {@link https://hono.dev/docs/concepts/routers Hono Routers}
|
|
54
|
+
* @see {@link https://hono.dev/docs/guides/middleware Hono Middleware Guide}
|
|
55
|
+
*
|
|
56
|
+
* ## Security Considerations
|
|
57
|
+
*
|
|
58
|
+
* - Authentication middleware is applied conditionally via `auth` setting
|
|
59
|
+
* - `authOnRetrieve` flag controls whether agent retrieval requires authentication
|
|
60
|
+
* - Consider enabling `authOnRetrieve` in production environments
|
|
61
|
+
*
|
|
62
|
+
* @param settings - Partial configuration merged with defaults. Supports custom
|
|
63
|
+
* handlers for `get`, `set`, `test`, and middleware composition.
|
|
64
|
+
* @param options - Server instantiation options
|
|
65
|
+
* @param options.app - Pre-configured Hono application instance. Useful for
|
|
66
|
+
* adding custom middleware or integrating with existing servers.
|
|
67
|
+
* @param options.authOnRetrieve - When `true`, applies auth middleware to agent
|
|
68
|
+
* retrieval routes. Defaults to `false` for development convenience.
|
|
69
|
+
* @param options.enableTesting - When `true`, exposes the test endpoint for
|
|
70
|
+
* agent evaluation. Disable in production if not needed.
|
|
71
|
+
*
|
|
72
|
+
* @returns Object containing:
|
|
73
|
+
* - `app`: The configured Hono application
|
|
74
|
+
* - `launch`: Function to start the HTTP server on a specified port
|
|
75
|
+
* - `ship`: Async function to deploy agents and return a launchable server
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* // Basic usage with defaults
|
|
80
|
+
* const { app, launch } = fleet();
|
|
81
|
+
* launch(3000);
|
|
82
|
+
*
|
|
83
|
+
* // With custom configuration and edge deployment
|
|
84
|
+
* const { app } = fleet({ userId: 'admin' }, { authOnRetrieve: true });
|
|
85
|
+
* export default app; // For Cloudflare Workers
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
43
88
|
export function fleet(settings = DEFAULTS, { app = new hono.Hono(), authOnRetrieve = false, enableTesting = true, } = {}) {
|
|
44
89
|
const context = createContext(settings);
|
|
45
90
|
const { basePath, agentPath, fallbackPath, deploymentPath, testPath, auth, user, evaluate, deploy, retrieve, set, } = context;
|
package/dist/settings.d.ts
CHANGED
|
@@ -5,14 +5,38 @@
|
|
|
5
5
|
import { RequestAgentRoute, TestAgentRoute } from "./routes/index.js";
|
|
6
6
|
import { CreateAgentRoute } from "./routes/create/index.js";
|
|
7
7
|
import { Configuration } from "./types.js";
|
|
8
|
+
import { Middleware } from "./routes/intercept.js";
|
|
9
|
+
/**
|
|
10
|
+
* Route path configuration parameters for the Fleet server.
|
|
11
|
+
*
|
|
12
|
+
* Extends {@link Configuration} with customizable URL paths for each endpoint,
|
|
13
|
+
* allowing flexible integration with existing API structures.
|
|
14
|
+
*/
|
|
8
15
|
export interface Params extends Configuration {
|
|
16
|
+
/** Base path prefix for all Fleet routes. Defaults to `/`. */
|
|
9
17
|
basePath?: string;
|
|
18
|
+
/** Fallback path for agent requests. Defaults to `/.well-known/agent`. */
|
|
10
19
|
fallbackPath?: string;
|
|
20
|
+
/** Path for agent deployment requests. Defaults to `/deploy`. */
|
|
11
21
|
deploymentPath?: string;
|
|
22
|
+
/** Path for agent test/evaluation requests. Defaults to `/test`. */
|
|
12
23
|
testPath?: string;
|
|
24
|
+
/** Middleware addons are currently only supported on the Request Agent route. */
|
|
25
|
+
middleware?: Middleware;
|
|
13
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Complete settings combining route paths with handler implementations.
|
|
29
|
+
*
|
|
30
|
+
* Defines the core operations for agent management:
|
|
31
|
+
* - `get`: Retrieve and execute agent requests
|
|
32
|
+
* - `set`: Deploy new agents or update existing ones
|
|
33
|
+
* - `test`: Evaluate agent behavior (optional)
|
|
34
|
+
*/
|
|
14
35
|
export interface Settings extends Params {
|
|
36
|
+
/** Implementation for retrieving and processing agent requests. */
|
|
15
37
|
get: RequestAgentRoute["implementation"];
|
|
38
|
+
/** Implementation for deploying or updating agents. */
|
|
16
39
|
set: CreateAgentRoute["implementation"];
|
|
40
|
+
/** Implementation for testing/evaluating agents. Optional. */
|
|
17
41
|
test?: TestAgentRoute["implementation"];
|
|
18
42
|
}
|
package/dist/ship.d.ts
CHANGED
|
@@ -3,4 +3,48 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { CreateAgentRoute } from "./routes/create/index.js";
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Deploys an agent configuration to a remote Fleet server.
|
|
8
|
+
*
|
|
9
|
+
* This function serves as a client for agent deployment,
|
|
10
|
+
* implementing schema validation on both request and response to ensure type safety
|
|
11
|
+
* and data integrity across network boundaries.
|
|
12
|
+
*
|
|
13
|
+
* @see {@link https://zod.dev/ Zod Schema Validation}
|
|
14
|
+
*
|
|
15
|
+
* Schema validation will throw if the request or response doesn't match the expected
|
|
16
|
+
* structure. Network errors from `fetch` will propagate as-is.
|
|
17
|
+
*
|
|
18
|
+
* @template T - The agent request type, constrained to `CreateAgentRoute["request"]`
|
|
19
|
+
*
|
|
20
|
+
* @param fleetUrl - Base URL of the Fleet server. Defaults to `http://localhost:3000`
|
|
21
|
+
* for local development. In production, use environment variables.
|
|
22
|
+
* @param request - Agent configuration to deploy. Must conform to {@link armada.CreateAgentRequestSchema}.
|
|
23
|
+
* @param headers - Optional custom HTTP headers to include with the request. Useful for authentication tokens, correlation IDs, or distributed tracing headers.
|
|
24
|
+
*
|
|
25
|
+
* @returns Promise resolving to the deployment response, validated against {@link API.CreateAgentResponseSchema}.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* // Deploy to local development server
|
|
30
|
+
* const result = await ship("http://localhost:3000", {
|
|
31
|
+
* config: {
|
|
32
|
+
* schemaVersion: "0.1.0",
|
|
33
|
+
* uri: "my-agent",
|
|
34
|
+
* name: "My Agent",
|
|
35
|
+
* description: "A helpful assistant",
|
|
36
|
+
* modelId: "gpt-4",
|
|
37
|
+
* instructions: "You are a helpful assistant.",
|
|
38
|
+
* version: "1.0.0",
|
|
39
|
+
* },
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* // Deploy with authentication header
|
|
43
|
+
* const authResult = await ship(
|
|
44
|
+
* process.env.FLEET_URL!,
|
|
45
|
+
* agentConfig,
|
|
46
|
+
* { Authorization: `Bearer ${token}` }
|
|
47
|
+
* );
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function ship<T extends CreateAgentRoute["request"]>(fleetUrl: string | undefined, request: T, headers?: Record<string, string>): Promise<CreateAgentRoute["response"]>;
|
package/dist/ship.js
CHANGED
|
@@ -5,13 +5,58 @@
|
|
|
5
5
|
import * as sdk from "@artinet/sdk";
|
|
6
6
|
import * as armada from "@artinet/armada";
|
|
7
7
|
import { API } from "@artinet/types";
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Deploys an agent configuration to a remote Fleet server.
|
|
10
|
+
*
|
|
11
|
+
* This function serves as a client for agent deployment,
|
|
12
|
+
* implementing schema validation on both request and response to ensure type safety
|
|
13
|
+
* and data integrity across network boundaries.
|
|
14
|
+
*
|
|
15
|
+
* @see {@link https://zod.dev/ Zod Schema Validation}
|
|
16
|
+
*
|
|
17
|
+
* Schema validation will throw if the request or response doesn't match the expected
|
|
18
|
+
* structure. Network errors from `fetch` will propagate as-is.
|
|
19
|
+
*
|
|
20
|
+
* @template T - The agent request type, constrained to `CreateAgentRoute["request"]`
|
|
21
|
+
*
|
|
22
|
+
* @param fleetUrl - Base URL of the Fleet server. Defaults to `http://localhost:3000`
|
|
23
|
+
* for local development. In production, use environment variables.
|
|
24
|
+
* @param request - Agent configuration to deploy. Must conform to {@link armada.CreateAgentRequestSchema}.
|
|
25
|
+
* @param headers - Optional custom HTTP headers to include with the request. Useful for authentication tokens, correlation IDs, or distributed tracing headers.
|
|
26
|
+
*
|
|
27
|
+
* @returns Promise resolving to the deployment response, validated against {@link API.CreateAgentResponseSchema}.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* // Deploy to local development server
|
|
32
|
+
* const result = await ship("http://localhost:3000", {
|
|
33
|
+
* config: {
|
|
34
|
+
* schemaVersion: "0.1.0",
|
|
35
|
+
* uri: "my-agent",
|
|
36
|
+
* name: "My Agent",
|
|
37
|
+
* description: "A helpful assistant",
|
|
38
|
+
* modelId: "gpt-4",
|
|
39
|
+
* instructions: "You are a helpful assistant.",
|
|
40
|
+
* version: "1.0.0",
|
|
41
|
+
* },
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* // Deploy with authentication header
|
|
45
|
+
* const authResult = await ship(
|
|
46
|
+
* process.env.FLEET_URL!,
|
|
47
|
+
* agentConfig,
|
|
48
|
+
* { Authorization: `Bearer ${token}` }
|
|
49
|
+
* );
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export async function ship(fleetUrl = "http://localhost:3000", request, headers = {}) {
|
|
9
53
|
const requestBody = await sdk.validateSchema(armada.CreateAgentRequestSchema, request);
|
|
10
54
|
sdk.logger.debug(`deployAgent request:`, { requestBody });
|
|
11
55
|
const response = await fetch(`${fleetUrl}/deploy`, {
|
|
12
56
|
method: "POST",
|
|
13
57
|
headers: {
|
|
14
58
|
"Content-Type": "application/json",
|
|
59
|
+
...headers,
|
|
15
60
|
},
|
|
16
61
|
body: JSON.stringify(requestBody),
|
|
17
62
|
});
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import * as armada from "@artinet/armada";
|
|
6
|
-
import * as
|
|
7
|
-
export declare class InMemoryStore extends
|
|
6
|
+
import * as sdk from "@artinet/sdk";
|
|
7
|
+
export declare class InMemoryStore extends sdk.Manager<armada.StoredAgent> implements armada.IDataStore<armada.StoredAgent> {
|
|
8
8
|
search(query: string): Promise<armada.StoredAgent[]>;
|
|
9
9
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Copyright 2025 The Artinet Project
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
import * as
|
|
6
|
-
export class InMemoryStore extends
|
|
5
|
+
import * as sdk from "@artinet/sdk";
|
|
6
|
+
export class InMemoryStore extends sdk.Manager {
|
|
7
7
|
async search(query) {
|
|
8
8
|
return Array.from(this.data.values()).filter((value) => value.uri.includes(query) ||
|
|
9
9
|
value.name.includes(query) ||
|
package/dist/types.d.ts
CHANGED
|
@@ -4,8 +4,45 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { RequestAgentRoute, TestAgentRoute } from "./routes/index.js";
|
|
6
6
|
import { CreateAgentRoute } from "./routes/create/index.js";
|
|
7
|
+
/**
|
|
8
|
+
* Combined context type for all route handlers.
|
|
9
|
+
*
|
|
10
|
+
* Represents the intersection of context requirements across agent request,
|
|
11
|
+
* creation, and testing routes. Used internally for handler type safety.
|
|
12
|
+
*/
|
|
7
13
|
export type Config = RequestAgentRoute["context"] & CreateAgentRoute["context"] & TestAgentRoute["context"];
|
|
14
|
+
/**
|
|
15
|
+
* Configuration type without agent-specific identifiers.
|
|
16
|
+
*
|
|
17
|
+
* Omits `agentId` from {@link Config} for use in settings and initialization
|
|
18
|
+
* where the agent ID is not yet known.
|
|
19
|
+
*/
|
|
8
20
|
export type Configuration = Omit<Config, "agentId">;
|
|
21
|
+
/**
|
|
22
|
+
* Discriminated union for operation results.
|
|
23
|
+
*
|
|
24
|
+
* Provides a type-safe way to represent three possible outcomes:
|
|
25
|
+
* - `success`: Operation completed with a result
|
|
26
|
+
* - `error`: Operation failed with an error
|
|
27
|
+
* - `stream`: Operation returns an async iterable stream
|
|
28
|
+
*
|
|
29
|
+
* @see {@link https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions Discriminated Unions}
|
|
30
|
+
*
|
|
31
|
+
* @template Result - Type of successful result. Defaults to `unknown`.
|
|
32
|
+
* @template Error - Type of error payload. Defaults to `unknown`.
|
|
33
|
+
* @template Stream - Type of streamed items. Defaults to `unknown`.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* function handle(result: ResultOrError<User, ApiError, Chunk>) {
|
|
38
|
+
* switch (result.type) {
|
|
39
|
+
* case "success": return result.result; // User
|
|
40
|
+
* case "error": throw result.error; // ApiError
|
|
41
|
+
* case "stream": return result.stream; // AsyncIterable<Chunk>
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
9
46
|
export type ResultOrError<Result = unknown, Error = unknown, Stream = unknown> = {
|
|
10
47
|
type: "success";
|
|
11
48
|
result: Result;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@artinet/fleet",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "A an agentic orchestration server for on premise deployment.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -62,53 +62,52 @@
|
|
|
62
62
|
],
|
|
63
63
|
"rootDir": ".",
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@artinet/armada": "^0.1.
|
|
66
|
-
"@artinet/sdk": "^0.6.
|
|
67
|
-
"@artinet/types": "^0.
|
|
65
|
+
"@artinet/armada": "^0.1.4",
|
|
66
|
+
"@artinet/sdk": "^0.6.4",
|
|
67
|
+
"@artinet/types": "^0.1.4",
|
|
68
68
|
"@sindresorhus/slugify": "^3.0.0",
|
|
69
|
-
"agent-def": "^0.1.
|
|
70
|
-
"orc8": "^0.1.
|
|
69
|
+
"agent-def": "^0.1.4",
|
|
70
|
+
"orc8": "^0.1.4",
|
|
71
71
|
"zod": "^3.25"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
74
|
"@a2a-js/sdk": "^0.3.7",
|
|
75
75
|
"@modelcontextprotocol/sdk": "^1.24.3",
|
|
76
76
|
"@opentelemetry/api": "^1.9.0",
|
|
77
|
+
"drizzle-orm": "^0.45.1",
|
|
77
78
|
"express": "^5.2.1",
|
|
78
79
|
"hono": "^4.11.3",
|
|
79
80
|
"openai": "^6.15.0",
|
|
80
|
-
"pino": "^10.1.0"
|
|
81
|
-
"drizzle-orm": "^0.45.1"
|
|
81
|
+
"pino": "^10.1.0"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@a2a-js/sdk": "^0.3.7",
|
|
85
|
-
"@
|
|
86
|
-
"@eslint/js": "^9.25.1",
|
|
85
|
+
"@eslint/js": "^9.39.2",
|
|
87
86
|
"@modelcontextprotocol/sdk": "^1.24.3",
|
|
88
87
|
"@types/better-sqlite3": "^7.6.13",
|
|
89
|
-
"@types/express": "^5.0.
|
|
88
|
+
"@types/express": "^5.0.6",
|
|
90
89
|
"@types/jest": "^29.5.14",
|
|
91
|
-
"@types/node": "^
|
|
90
|
+
"@types/node": "^25.0.9",
|
|
92
91
|
"@types/supertest": "^6.0.3",
|
|
93
92
|
"autocannon": "^8.0.0",
|
|
94
93
|
"better-sqlite3": "^12.5.0",
|
|
95
94
|
"drizzle-orm": "^0.45.1",
|
|
96
|
-
"eslint": "^9.
|
|
95
|
+
"eslint": "^9.39.2",
|
|
97
96
|
"express": "^5.2.1",
|
|
98
|
-
"globals": "^
|
|
99
|
-
"hono": "^4.11.
|
|
100
|
-
"jest": "
|
|
101
|
-
"pino": "^10.
|
|
97
|
+
"globals": "^17.0.0",
|
|
98
|
+
"hono": "^4.11.4",
|
|
99
|
+
"jest": "29.7.0",
|
|
100
|
+
"pino": "^10.2.0",
|
|
102
101
|
"pm2": "^6.0.14",
|
|
103
|
-
"rimraf": "^
|
|
102
|
+
"rimraf": "^6.1.2",
|
|
104
103
|
"supertest": "latest",
|
|
105
|
-
"ts-jest": "^29.
|
|
104
|
+
"ts-jest": "^29.4.6",
|
|
106
105
|
"ts-node": "^10.9.2",
|
|
107
|
-
"typescript": "^5.
|
|
108
|
-
"typescript-eslint": "^8.
|
|
106
|
+
"typescript": "^5.9.3",
|
|
107
|
+
"typescript-eslint": "^8.53.0",
|
|
109
108
|
"undici": "^5.29.0"
|
|
110
109
|
},
|
|
111
110
|
"engines": {
|
|
112
|
-
"node": ">=
|
|
111
|
+
"node": ">=20.0.0"
|
|
113
112
|
}
|
|
114
113
|
}
|