@sisu-ai/server 7.0.1 → 7.0.3
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 +81 -0
- package/dist/index.d.ts +28 -23
- package/dist/index.js +75 -36
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
<div align="right">
|
|
2
|
+
<a href="https://github.com/finger-gun/sisu"><img src="https://github.com/finger-gun/sisu/raw/main/sisu-light.svg" alt="ProjectSpecs" width="100" /></a>
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
1
7
|
# @sisu-ai/server
|
|
2
8
|
|
|
3
9
|
Standalone HTTP/HTTPS adapter for Sisu agents. Spin up an HTTP server or attach to an existing one while keeping the small core philosophy.
|
|
@@ -104,3 +110,78 @@ Discover what you can do through examples or documentation. Check it out at http
|
|
|
104
110
|
- [License](https://github.com/finger-gun/sisu/blob/main/LICENSE)
|
|
105
111
|
- [Report a Bug](https://github.com/finger-gun/sisu/issues/new?template=bug_report.md)
|
|
106
112
|
- [Request a Feature](https://github.com/finger-gun/sisu/issues/new?template=feature_request.md)
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Documentation
|
|
117
|
+
|
|
118
|
+
**Core** — [Package docs](packages/core/README.md) · [Error types](packages/core/ERROR_TYPES.md)
|
|
119
|
+
|
|
120
|
+
**Adapters** — [OpenAI](packages/adapters/openai/README.md) · [Anthropic](packages/adapters/anthropic/README.md) · [Ollama](packages/adapters/ollama/README.md)
|
|
121
|
+
|
|
122
|
+
<details>
|
|
123
|
+
<summary>All middleware packages</summary>
|
|
124
|
+
|
|
125
|
+
- [@sisu-ai/mw-agent-run-api](packages/middleware/agent-run-api/README.md)
|
|
126
|
+
- [@sisu-ai/mw-context-compressor](packages/middleware/context-compressor/README.md)
|
|
127
|
+
- [@sisu-ai/mw-control-flow](packages/middleware/control-flow/README.md)
|
|
128
|
+
- [@sisu-ai/mw-conversation-buffer](packages/middleware/conversation-buffer/README.md)
|
|
129
|
+
- [@sisu-ai/mw-cors](packages/middleware/cors/README.md)
|
|
130
|
+
- [@sisu-ai/mw-error-boundary](packages/middleware/error-boundary/README.md)
|
|
131
|
+
- [@sisu-ai/mw-guardrails](packages/middleware/guardrails/README.md)
|
|
132
|
+
- [@sisu-ai/mw-invariants](packages/middleware/invariants/README.md)
|
|
133
|
+
- [@sisu-ai/mw-orchestration](packages/middleware/orchestration/README.md)
|
|
134
|
+
- [@sisu-ai/mw-rag](packages/middleware/rag/README.md)
|
|
135
|
+
- [@sisu-ai/mw-react-parser](packages/middleware/react-parser/README.md)
|
|
136
|
+
- [@sisu-ai/mw-register-tools](packages/middleware/register-tools/README.md)
|
|
137
|
+
- [@sisu-ai/mw-tool-calling](packages/middleware/tool-calling/README.md)
|
|
138
|
+
- [@sisu-ai/mw-trace-viewer](packages/middleware/trace-viewer/README.md)
|
|
139
|
+
- [@sisu-ai/mw-usage-tracker](packages/middleware/usage-tracker/README.md)
|
|
140
|
+
</details>
|
|
141
|
+
|
|
142
|
+
<details>
|
|
143
|
+
<summary>All tool packages</summary>
|
|
144
|
+
|
|
145
|
+
- [@sisu-ai/tool-aws-s3](packages/tools/aws-s3/README.md)
|
|
146
|
+
- [@sisu-ai/tool-azure-blob](packages/tools/azure-blob/README.md)
|
|
147
|
+
- [@sisu-ai/tool-extract-urls](packages/tools/extract-urls/README.md)
|
|
148
|
+
- [@sisu-ai/tool-github-projects](packages/tools/github-projects/README.md)
|
|
149
|
+
- [@sisu-ai/tool-summarize-text](packages/tools/summarize-text/README.md)
|
|
150
|
+
- [@sisu-ai/tool-terminal](packages/tools/terminal/README.md)
|
|
151
|
+
- [@sisu-ai/tool-vec-chroma](packages/tools/vec-chroma/README.md)
|
|
152
|
+
- [@sisu-ai/tool-web-fetch](packages/tools/web-fetch/README.md)
|
|
153
|
+
- [@sisu-ai/tool-web-search-duckduckgo](packages/tools/web-search-duckduckgo/README.md)
|
|
154
|
+
- [@sisu-ai/tool-web-search-google](packages/tools/web-search-google/README.md)
|
|
155
|
+
- [@sisu-ai/tool-web-search-openai](packages/tools/web-search-openai/README.md)
|
|
156
|
+
- [@sisu-ai/tool-wikipedia](packages/tools/wikipedia/README.md)
|
|
157
|
+
</details>
|
|
158
|
+
|
|
159
|
+
<details>
|
|
160
|
+
<summary>All examples</summary>
|
|
161
|
+
|
|
162
|
+
**Anthropic** — [hello](examples/anthropic-hello/README.md) · [control-flow](examples/anthropic-control-flow/README.md) · [stream](examples/anthropic-stream/README.md) · [weather](examples/anthropic-weather/README.md)
|
|
163
|
+
|
|
164
|
+
**Ollama** — [hello](examples/ollama-hello/README.md) · [stream](examples/ollama-stream/README.md) · [vision](examples/ollama-vision/README.md) · [weather](examples/ollama-weather/README.md) · [web-search](examples/ollama-web-search/README.md)
|
|
165
|
+
|
|
166
|
+
**OpenAI** — [hello](examples/openai-hello/README.md) · [weather](examples/openai-weather/README.md) · [stream](examples/openai-stream/README.md) · [vision](examples/openai-vision/README.md) · [reasoning](examples/openai-reasoning/README.md) · [react](examples/openai-react/README.md) · [control-flow](examples/openai-control-flow/README.md) · [branch](examples/openai-branch/README.md) · [parallel](examples/openai-parallel/README.md) · [graph](examples/openai-graph/README.md) · [orchestration](examples/openai-orchestration/README.md) · [orchestration-adaptive](examples/openai-orchestration-adaptive/README.md) · [guardrails](examples/openai-guardrails/README.md) · [error-handling](examples/openai-error-handling/README.md) · [rag-chroma](examples/openai-rag-chroma/README.md) · [web-search](examples/openai-web-search/README.md) · [web-fetch](examples/openai-web-fetch/README.md) · [wikipedia](examples/openai-wikipedia/README.md) · [terminal](examples/openai-terminal/README.md) · [github-projects](examples/openai-github-projects/README.md) · [server](examples/openai-server/README.md) · [aws-s3](examples/openai-aws-s3/README.md) · [azure-blob](examples/openai-azure-blob/README.md)
|
|
167
|
+
</details>
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Contributing
|
|
172
|
+
|
|
173
|
+
We build Sisu in the open. Contributions welcome.
|
|
174
|
+
|
|
175
|
+
[Contributing Guide](CONTRIBUTING.md) · [Report a Bug](https://github.com/finger-gun/sisu/issues/new?template=bug_report.md) · [Request a Feature](https://github.com/finger-gun/sisu/issues/new?template=feature_request.md) · [Code of Conduct](CODE_OF_CONDUCT.md)
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
<div align="center">
|
|
180
|
+
|
|
181
|
+
**[Star on GitHub](https://github.com/finger-gun/sisu)** if Sisu helps you build better agents.
|
|
182
|
+
|
|
183
|
+
*Quiet, determined, relentlessly useful.*
|
|
184
|
+
|
|
185
|
+
[Apache 2.0 License](LICENSE)
|
|
186
|
+
|
|
187
|
+
</div>
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import http, { type IncomingMessage, type ServerResponse } from
|
|
2
|
-
import https from
|
|
3
|
-
import type { Agent, Logger } from
|
|
4
|
-
import type { AddressInfo } from
|
|
5
|
-
export { matchRoute } from
|
|
1
|
+
import http, { type IncomingMessage, type ServerResponse } from "http";
|
|
2
|
+
import https from "https";
|
|
3
|
+
import type { Agent, Logger, Ctx } from "@sisu-ai/core";
|
|
4
|
+
import type { AddressInfo } from "net";
|
|
5
|
+
export { matchRoute } from "./router.js";
|
|
6
6
|
export interface ListenOptions<Ctx> {
|
|
7
7
|
tls?: https.ServerOptions;
|
|
8
8
|
port?: number;
|
|
@@ -15,10 +15,15 @@ export interface ListenOptions<Ctx> {
|
|
|
15
15
|
logBanner?: boolean;
|
|
16
16
|
bannerEndpoints?: string[];
|
|
17
17
|
logger?: Logger;
|
|
18
|
-
logLevel?:
|
|
18
|
+
logLevel?: "debug" | "info" | "warn" | "error";
|
|
19
19
|
redactLogKeys?: string[];
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
type HttpEnvelope<CtxT extends Ctx> = {
|
|
22
|
+
req?: IncomingMessage;
|
|
23
|
+
res?: ServerResponse;
|
|
24
|
+
agent?: Agent<CtxT>;
|
|
25
|
+
};
|
|
26
|
+
export declare class Server<CtxT extends Ctx & HttpEnvelope<CtxT>> {
|
|
22
27
|
private agent;
|
|
23
28
|
private opts;
|
|
24
29
|
private server?;
|
|
@@ -26,59 +31,59 @@ export declare class Server<Ctx = any> {
|
|
|
26
31
|
private healthPath;
|
|
27
32
|
private createCtx;
|
|
28
33
|
private emitter;
|
|
29
|
-
constructor(agent: Agent<
|
|
34
|
+
constructor(agent: Agent<CtxT>, opts?: ListenOptions<CtxT>);
|
|
30
35
|
private handle;
|
|
31
36
|
listener(): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
32
37
|
listen(cb?: () => void): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | https.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
|
|
33
38
|
attach(server: http.Server | https.Server): void;
|
|
34
39
|
close(cb?: (err?: Error) => void): void;
|
|
35
40
|
address(): string | AddressInfo | null | undefined;
|
|
36
|
-
on(event:
|
|
41
|
+
on(event: "listening", handler: (e: {
|
|
37
42
|
url: string;
|
|
38
43
|
address: string | AddressInfo | null | undefined;
|
|
39
44
|
}) => void): this;
|
|
40
|
-
on(event:
|
|
45
|
+
on(event: "request", handler: (e: {
|
|
41
46
|
method: string;
|
|
42
47
|
url: string;
|
|
43
48
|
}) => void): this;
|
|
44
|
-
on(event:
|
|
49
|
+
on(event: "response", handler: (e: {
|
|
45
50
|
method: string;
|
|
46
51
|
url: string;
|
|
47
52
|
status: number;
|
|
48
53
|
duration_ms: number;
|
|
49
54
|
}) => void): this;
|
|
50
|
-
on(event:
|
|
51
|
-
on(event:
|
|
52
|
-
once(event:
|
|
55
|
+
on(event: "error", handler: (err: Error) => void): this;
|
|
56
|
+
on(event: "close", handler: () => void): this;
|
|
57
|
+
once(event: "listening", handler: (e: {
|
|
53
58
|
url: string;
|
|
54
59
|
address: string | AddressInfo | null | undefined;
|
|
55
60
|
}) => void): this;
|
|
56
|
-
once(event:
|
|
61
|
+
once(event: "request", handler: (e: {
|
|
57
62
|
method: string;
|
|
58
63
|
url: string;
|
|
59
64
|
}) => void): this;
|
|
60
|
-
once(event:
|
|
65
|
+
once(event: "response", handler: (e: {
|
|
61
66
|
method: string;
|
|
62
67
|
url: string;
|
|
63
68
|
status: number;
|
|
64
69
|
duration_ms: number;
|
|
65
70
|
}) => void): this;
|
|
66
|
-
once(event:
|
|
67
|
-
once(event:
|
|
68
|
-
off(event:
|
|
71
|
+
once(event: "error", handler: (err: Error) => void): this;
|
|
72
|
+
once(event: "close", handler: () => void): this;
|
|
73
|
+
off(event: "listening", handler: (e: {
|
|
69
74
|
url: string;
|
|
70
75
|
address: string | AddressInfo | null | undefined;
|
|
71
76
|
}) => void): this;
|
|
72
|
-
off(event:
|
|
77
|
+
off(event: "request", handler: (e: {
|
|
73
78
|
method: string;
|
|
74
79
|
url: string;
|
|
75
80
|
}) => void): this;
|
|
76
|
-
off(event:
|
|
81
|
+
off(event: "response", handler: (e: {
|
|
77
82
|
method: string;
|
|
78
83
|
url: string;
|
|
79
84
|
status: number;
|
|
80
85
|
duration_ms: number;
|
|
81
86
|
}) => void): this;
|
|
82
|
-
off(event:
|
|
83
|
-
off(event:
|
|
87
|
+
off(event: "error", handler: (err: Error) => void): this;
|
|
88
|
+
off(event: "close", handler: () => void): this;
|
|
84
89
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,33 +1,50 @@
|
|
|
1
|
-
import http from
|
|
2
|
-
import https from
|
|
3
|
-
import { createConsoleLogger, createRedactingLogger } from
|
|
4
|
-
import { EventEmitter } from
|
|
5
|
-
export { matchRoute } from
|
|
1
|
+
import http from "http";
|
|
2
|
+
import https from "https";
|
|
3
|
+
import { createConsoleLogger, createRedactingLogger } from "@sisu-ai/core";
|
|
4
|
+
import { EventEmitter } from "events";
|
|
5
|
+
export { matchRoute } from "./router.js";
|
|
6
6
|
export class Server {
|
|
7
7
|
constructor(agent, opts = {}) {
|
|
8
8
|
this.agent = agent;
|
|
9
9
|
this.opts = opts;
|
|
10
10
|
this.emitter = new EventEmitter();
|
|
11
|
-
this.basePath = opts.basePath ??
|
|
12
|
-
this.healthPath = opts.healthPath ??
|
|
13
|
-
this.createCtx =
|
|
11
|
+
this.basePath = opts.basePath ?? "/api";
|
|
12
|
+
this.healthPath = opts.healthPath ?? "/health";
|
|
13
|
+
this.createCtx =
|
|
14
|
+
opts.createCtx ?? ((req, res) => ({ req, res }));
|
|
14
15
|
}
|
|
15
16
|
async handle(req, res) {
|
|
16
17
|
// Set up server-level request logging (independent of ctx)
|
|
17
|
-
const baseLogger = this.opts.logger ??
|
|
18
|
-
|
|
18
|
+
const baseLogger = this.opts.logger ??
|
|
19
|
+
createConsoleLogger({
|
|
20
|
+
level: this.opts.logLevel,
|
|
21
|
+
timestamps: true,
|
|
22
|
+
});
|
|
23
|
+
const srvLogger = createRedactingLogger(baseLogger, {
|
|
24
|
+
keys: this.opts.redactLogKeys,
|
|
25
|
+
});
|
|
19
26
|
const started = Date.now();
|
|
20
|
-
const { method =
|
|
21
|
-
srvLogger.info?.(
|
|
22
|
-
res.once?.(
|
|
27
|
+
const { method = "GET", url = "" } = req;
|
|
28
|
+
srvLogger.info?.("[server] request", { method, url });
|
|
29
|
+
res.once?.("finish", () => {
|
|
23
30
|
const ms = Date.now() - started;
|
|
24
|
-
srvLogger.info?.(
|
|
25
|
-
|
|
31
|
+
srvLogger.info?.("[server] response", {
|
|
32
|
+
method,
|
|
33
|
+
url,
|
|
34
|
+
status: res.statusCode,
|
|
35
|
+
duration_ms: ms,
|
|
36
|
+
});
|
|
37
|
+
this.emitter.emit("response", {
|
|
38
|
+
method,
|
|
39
|
+
url,
|
|
40
|
+
status: res.statusCode,
|
|
41
|
+
duration_ms: ms,
|
|
42
|
+
});
|
|
26
43
|
});
|
|
27
|
-
this.emitter.emit(
|
|
44
|
+
this.emitter.emit("request", { method, url });
|
|
28
45
|
if (this.healthPath && req.url === this.healthPath) {
|
|
29
46
|
res.statusCode = 200;
|
|
30
|
-
res.end(
|
|
47
|
+
res.end("ok");
|
|
31
48
|
return;
|
|
32
49
|
}
|
|
33
50
|
if (!req.url || !req.url.startsWith(this.basePath)) {
|
|
@@ -44,16 +61,24 @@ export class Server {
|
|
|
44
61
|
// Mark this context as an HTTP transport envelope and capture minimal request meta
|
|
45
62
|
const headers = req.headers || {};
|
|
46
63
|
const httpMeta = {
|
|
47
|
-
method: req.method ||
|
|
48
|
-
url: req.url ||
|
|
49
|
-
ip: (req.socket && (req.socket.remoteAddress ||
|
|
64
|
+
method: req.method || "GET",
|
|
65
|
+
url: req.url || "",
|
|
66
|
+
ip: (req.socket && (req.socket.remoteAddress || "")) || "",
|
|
50
67
|
headers: {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
68
|
+
"user-agent": typeof headers["user-agent"] === "string"
|
|
69
|
+
? headers["user-agent"]
|
|
70
|
+
: undefined,
|
|
71
|
+
accept: typeof headers["accept"] === "string" ? headers["accept"] : undefined,
|
|
72
|
+
"content-type": typeof headers["content-type"] === "string"
|
|
73
|
+
? headers["content-type"]
|
|
74
|
+
: undefined,
|
|
54
75
|
},
|
|
55
76
|
};
|
|
56
|
-
ctx.state = {
|
|
77
|
+
ctx.state = {
|
|
78
|
+
...(ctx.state ?? {}),
|
|
79
|
+
_transport: { type: "http" },
|
|
80
|
+
_http: httpMeta,
|
|
81
|
+
};
|
|
57
82
|
const handler = this.agent.handler();
|
|
58
83
|
await handler(ctx);
|
|
59
84
|
// Only synthesize a 404 when nothing has been written at all.
|
|
@@ -77,17 +102,19 @@ export class Server {
|
|
|
77
102
|
else {
|
|
78
103
|
this.server.listen(this.opts.port ?? 0, this.opts.host, this.opts.backlog, cb);
|
|
79
104
|
}
|
|
80
|
-
this.server.on(
|
|
81
|
-
this.server.on(
|
|
105
|
+
this.server.on("error", (err) => this.emitter.emit("error", err));
|
|
106
|
+
this.server.on("close", () => this.emitter.emit("close"));
|
|
82
107
|
const printBanner = this.opts.logBanner !== false;
|
|
83
108
|
if (printBanner) {
|
|
84
109
|
const addr = this.server.address();
|
|
85
|
-
let url =
|
|
86
|
-
if (typeof addr ===
|
|
87
|
-
const host = this.opts.host && this.opts.host !==
|
|
110
|
+
let url = "";
|
|
111
|
+
if (typeof addr === "object" && addr && "port" in addr) {
|
|
112
|
+
const host = this.opts.host && this.opts.host !== "0.0.0.0"
|
|
113
|
+
? this.opts.host
|
|
114
|
+
: "localhost";
|
|
88
115
|
url = `http://${host}:${addr.port}`;
|
|
89
116
|
}
|
|
90
|
-
else if (typeof addr ===
|
|
117
|
+
else if (typeof addr === "string") {
|
|
91
118
|
url = addr;
|
|
92
119
|
}
|
|
93
120
|
if (url)
|
|
@@ -97,16 +124,19 @@ export class Server {
|
|
|
97
124
|
if (this.basePath)
|
|
98
125
|
console.log(`[server] basePath: ${this.basePath}`);
|
|
99
126
|
if (this.opts.bannerEndpoints?.length) {
|
|
100
|
-
console.log(
|
|
127
|
+
console.log("[server] endpoints:");
|
|
101
128
|
for (const ep of this.opts.bannerEndpoints)
|
|
102
129
|
console.log(` ${ep}`);
|
|
103
130
|
}
|
|
104
|
-
this.emitter.emit(
|
|
131
|
+
this.emitter.emit("listening", {
|
|
132
|
+
url,
|
|
133
|
+
address: addr,
|
|
134
|
+
});
|
|
105
135
|
}
|
|
106
136
|
return this.server;
|
|
107
137
|
}
|
|
108
138
|
attach(server) {
|
|
109
|
-
server.on(
|
|
139
|
+
server.on("request", this.listener());
|
|
110
140
|
this.server = server;
|
|
111
141
|
}
|
|
112
142
|
close(cb) {
|
|
@@ -115,7 +145,16 @@ export class Server {
|
|
|
115
145
|
address() {
|
|
116
146
|
return this.server?.address();
|
|
117
147
|
}
|
|
118
|
-
on(event, handler) {
|
|
119
|
-
|
|
120
|
-
|
|
148
|
+
on(event, handler) {
|
|
149
|
+
this.emitter.on(event, handler);
|
|
150
|
+
return this;
|
|
151
|
+
}
|
|
152
|
+
once(event, handler) {
|
|
153
|
+
this.emitter.once(event, handler);
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
off(event, handler) {
|
|
157
|
+
this.emitter.off(event, handler);
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
121
160
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sisu-ai/server",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"access": "public"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"@sisu-ai/core": "^2.3.
|
|
15
|
+
"@sisu-ai/core": "^2.3.2"
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|