@chatcops/server 0.4.0 → 0.6.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 +35 -7
- package/dist/adapters/ai-sdk.d.ts +12 -0
- package/dist/adapters/ai-sdk.d.ts.map +1 -0
- package/dist/adapters/ai-sdk.js +27 -0
- package/dist/adapters/ai-sdk.js.map +1 -0
- package/dist/adapters/cloudflare.d.ts +3 -1
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +11 -58
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/express.d.ts +6 -2
- package/dist/adapters/express.d.ts.map +1 -1
- package/dist/adapters/express.js +109 -26
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/index.d.ts +1 -0
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +1 -0
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/vercel.d.ts.map +1 -1
- package/dist/adapters/vercel.js +7 -60
- package/dist/adapters/vercel.js.map +1 -1
- package/dist/client-ip.d.ts +36 -0
- package/dist/client-ip.d.ts.map +1 -0
- package/dist/client-ip.js +62 -0
- package/dist/client-ip.js.map +1 -0
- package/dist/config.d.ts +110 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -1
- package/dist/config.js.map +1 -1
- package/dist/handler.d.ts +53 -2
- package/dist/handler.d.ts.map +1 -1
- package/dist/handler.js +410 -127
- package/dist/handler.js.map +1 -1
- package/dist/http.d.ts +66 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +262 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/rate-limit.d.ts +5 -0
- package/dist/rate-limit.d.ts.map +1 -1
- package/dist/rate-limit.js +5 -0
- package/dist/rate-limit.js.map +1 -1
- package/dist/security/origin-policy.d.ts +19 -0
- package/dist/security/origin-policy.d.ts.map +1 -0
- package/dist/security/origin-policy.js +58 -0
- package/dist/security/origin-policy.js.map +1 -0
- package/dist/security/origin.d.ts +5 -0
- package/dist/security/origin.d.ts.map +1 -0
- package/dist/security/origin.js +47 -0
- package/dist/security/origin.js.map +1 -0
- package/dist/security/session-token.d.ts +65 -0
- package/dist/security/session-token.d.ts.map +1 -0
- package/dist/security/session-token.js +338 -0
- package/dist/security/session-token.js.map +1 -0
- package/dist/security/sessions.d.ts +49 -0
- package/dist/security/sessions.d.ts.map +1 -0
- package/dist/security/sessions.js +159 -0
- package/dist/security/sessions.js.map +1 -0
- package/dist/security/startup-checks.d.ts +44 -0
- package/dist/security/startup-checks.d.ts.map +1 -0
- package/dist/security/startup-checks.js +134 -0
- package/dist/security/startup-checks.js.map +1 -0
- package/dist/security/turnstile.d.ts +24 -0
- package/dist/security/turnstile.d.ts.map +1 -0
- package/dist/security/turnstile.js +93 -0
- package/dist/security/turnstile.js.map +1 -0
- package/dist/visitor-context.d.ts +20 -0
- package/dist/visitor-context.d.ts.map +1 -0
- package/dist/visitor-context.js +60 -0
- package/dist/visitor-context.js.map +1 -0
- package/dist/webhook.d.ts +48 -2
- package/dist/webhook.d.ts.map +1 -1
- package/dist/webhook.js +159 -31
- package/dist/webhook.js.map +1 -1
- package/package.json +22 -5
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The visitor's IP, for per-IP rate limits and budgets. Only headers a
|
|
3
|
+
* platform sets itself are read, never ones a visitor can send. When the IP
|
|
4
|
+
* can't be told, per-IP limits are skipped for that request (with one
|
|
5
|
+
* warning) instead of every visitor sharing one bucket.
|
|
6
|
+
*/
|
|
7
|
+
const DOCS = 'https://chat.codercops.com/server/fetch-runtimes/#the-visitors-ip';
|
|
8
|
+
// IPv4, IPv6 (including IPv4-mapped) and nothing else, so a header can't
|
|
9
|
+
// carry an arbitrary counter key.
|
|
10
|
+
const IP_PATTERN = /^[0-9A-Fa-f:.]{2,45}$/;
|
|
11
|
+
export function cleanIp(value) {
|
|
12
|
+
const ip = value?.split(',')[0]?.trim();
|
|
13
|
+
return ip && IP_PATTERN.test(ip) ? ip : undefined;
|
|
14
|
+
}
|
|
15
|
+
/** Vercel overwrites these headers, so a visitor can't set them there. */
|
|
16
|
+
export function onVercel() {
|
|
17
|
+
return typeof process !== 'undefined' && Boolean(process.env?.VERCEL);
|
|
18
|
+
}
|
|
19
|
+
const warned = new Set();
|
|
20
|
+
export function warnOnce(key, message) {
|
|
21
|
+
if (warned.has(key))
|
|
22
|
+
return;
|
|
23
|
+
warned.add(key);
|
|
24
|
+
console.warn(message);
|
|
25
|
+
}
|
|
26
|
+
/** For tests. */
|
|
27
|
+
export function resetClientIpWarnings() {
|
|
28
|
+
warned.clear();
|
|
29
|
+
}
|
|
30
|
+
/** The fetch handler for Vercel and other Fetch API runtimes. */
|
|
31
|
+
export function fetchClientIp(request, resolver) {
|
|
32
|
+
if (resolver)
|
|
33
|
+
return cleanIp(resolver(request));
|
|
34
|
+
if (onVercel()) {
|
|
35
|
+
const headers = request.headers;
|
|
36
|
+
return cleanIp(headers.get('x-vercel-forwarded-for')) ?? cleanIp(headers.get('x-real-ip')) ?? cleanIp(headers.get('x-forwarded-for'));
|
|
37
|
+
}
|
|
38
|
+
warnOnce('fetch', `[chatcops] Not running on Vercel, so the visitor's IP isn't read from X-Forwarded-For, which a visitor can set themselves. Per-IP rate limits and budgets are off until you set \`clientIp\`. See ${DOCS}`);
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
/** Cloudflare sets CF-Connecting-IP on every request that reaches a Worker. */
|
|
42
|
+
export function cloudflareClientIp(request, resolver) {
|
|
43
|
+
if (resolver)
|
|
44
|
+
return cleanIp(resolver(request));
|
|
45
|
+
const ip = cleanIp(request.headers.get('cf-connecting-ip'));
|
|
46
|
+
if (!ip) {
|
|
47
|
+
warnOnce('cloudflare', '[chatcops] A request had no CF-Connecting-IP header, so per-IP rate limits and budgets were skipped for it.');
|
|
48
|
+
}
|
|
49
|
+
return ip;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Express's `req.ip` follows its `trust proxy` setting. Behind a proxy with
|
|
53
|
+
* that setting off, every visitor gets the proxy's address and shares one
|
|
54
|
+
* rate limit and budget, so that case gets a warning.
|
|
55
|
+
*/
|
|
56
|
+
export function expressClientIp(req) {
|
|
57
|
+
if (req.headers?.['x-forwarded-for'] !== undefined && !req.app?.get?.('trust proxy')) {
|
|
58
|
+
warnOnce('express', "[chatcops] A request had X-Forwarded-For, but Express's `trust proxy` setting is off, so the connection's IP is used. Behind a proxy that means every visitor gets the proxy's IP and shares one rate limit and budget. With one proxy in front, call app.set('trust proxy', 1).");
|
|
59
|
+
}
|
|
60
|
+
return cleanIp(req.ip ?? req.socket?.remoteAddress);
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=client-ip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-ip.js","sourceRoot":"","sources":["../src/client-ip.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,IAAI,GAAG,mEAAmE,CAAC;AAEjF,yEAAyE;AACzE,kCAAkC;AAClC,MAAM,UAAU,GAAG,uBAAuB,CAAC;AAE3C,MAAM,UAAU,OAAO,CAAC,KAAgC;IACtD,MAAM,EAAE,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACxC,OAAO,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,QAAQ;IACtB,OAAO,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;AAEjC,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,OAAe;IACnD,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO;IAC5B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACxB,CAAC;AAED,iBAAiB;AACjB,MAAM,UAAU,qBAAqB;IACnC,MAAM,CAAC,KAAK,EAAE,CAAC;AACjB,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,aAAa,CAAC,OAAgB,EAAE,QAAsC;IACpF,IAAI,QAAQ;QAAE,OAAO,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAChD,IAAI,QAAQ,EAAE,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAChC,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACxI,CAAC;IACD,QAAQ,CACN,OAAO,EACP,qMAAqM,IAAI,EAAE,CAC5M,CAAC;IACF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,kBAAkB,CAAC,OAAgB,EAAE,QAAsC;IACzF,IAAI,QAAQ;QAAE,OAAO,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAChD,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAC5D,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,QAAQ,CAAC,YAAY,EAAE,6GAA6G,CAAC,CAAC;IACxI,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AASD;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAuB;IACrD,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC,iBAAiB,CAAC,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC;QACrF,QAAQ,CACN,SAAS,EACT,kRAAkR,CACnR,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AACtD,CAAC"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ClientIpResolver } from './client-ip.js';
|
|
3
|
+
import type { TurnstileConfig } from './security/turnstile.js';
|
|
4
|
+
import type { AIProvider, Budgets, ChatCopsStorage, ChatTool, ConversationStore, KnowledgeSource, LocaleStrings, ProviderConfig, WebhookConfig } from '@chatcops/core';
|
|
3
5
|
export interface ChatCopsServerConfig {
|
|
4
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Which model to use: a config like `{ type: 'claude', apiKey }`, or a
|
|
8
|
+
* provider object you built yourself (anything with `step()` or `chat()`).
|
|
9
|
+
*/
|
|
10
|
+
provider: ProviderConfig | AIProvider;
|
|
5
11
|
systemPrompt: string;
|
|
6
12
|
tools?: ChatTool[];
|
|
7
13
|
toolTimeoutMs?: number;
|
|
8
|
-
/** Most tokens in one reply. Defaults to
|
|
14
|
+
/** Most tokens in one reply. Defaults to 4096 (`DEFAULT_MAX_TOKENS` in @chatcops/core). */
|
|
9
15
|
maxTokens?: number;
|
|
10
16
|
/** Sampling temperature. Defaults to the provider's own; the allowed range depends on the provider. */
|
|
11
17
|
temperature?: number;
|
|
@@ -14,12 +20,94 @@ export interface ChatCopsServerConfig {
|
|
|
14
20
|
maxRequests: number;
|
|
15
21
|
windowMs: number;
|
|
16
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* Token, reply and dollar limits per conversation, per IP per day and
|
|
25
|
+
* overall per day, counted in `storage` so they hold across instances. A
|
|
26
|
+
* reply that would go over ends with an error instead of calling the model.
|
|
27
|
+
* On by default (`DEFAULT_BUDGETS`: 200 replies per conversation, 2M tokens
|
|
28
|
+
* per IP per day). A scope you set replaces its default, `false` turns a
|
|
29
|
+
* scope off, and `budgets: false` turns them all off.
|
|
30
|
+
*/
|
|
31
|
+
budgets?: Budgets | false;
|
|
32
|
+
/**
|
|
33
|
+
* The pre-chat form fields to keep (the `name`s in the widget's
|
|
34
|
+
* `preChatForm.fields`). Other fields a request sends are dropped. Unset
|
|
35
|
+
* keeps every field. Answers are stored with the conversation from its
|
|
36
|
+
* first message and can't change after that.
|
|
37
|
+
*/
|
|
38
|
+
preChatFields?: string[];
|
|
17
39
|
webhooks?: WebhookConfig[];
|
|
18
40
|
analytics?: boolean;
|
|
19
|
-
/**
|
|
41
|
+
/** Bearer token required to read the analytics endpoint. When unset, the endpoint is public. */
|
|
42
|
+
analyticsToken?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Where conversations (and, with stores that have them, counters, turn
|
|
45
|
+
* locks and events) live: `postgresStorage(...)`, `redisStorage(...)` and
|
|
46
|
+
* so on. Defaults to memory, which doesn't survive a restart and isn't
|
|
47
|
+
* shared between serverless instances.
|
|
48
|
+
*/
|
|
49
|
+
storage?: ChatCopsStorage;
|
|
50
|
+
/**
|
|
51
|
+
* @deprecated Use `storage`. A conversation store on its own, as in 0.4.
|
|
52
|
+
* Setting both is an error.
|
|
53
|
+
*/
|
|
20
54
|
conversationStore?: ConversationStore;
|
|
21
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* How long to keep conversations. `purge()` on the handler deletes older
|
|
57
|
+
* ones; call it on a schedule (a cron job, a Workers cron trigger).
|
|
58
|
+
*/
|
|
59
|
+
retention?: {
|
|
60
|
+
conversationsDays?: number;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* The sites that can use the chat: exact origins (`'https://acme.com'`) or
|
|
64
|
+
* subdomain wildcards (`'https://*.acme.com'`). A browser request from any
|
|
65
|
+
* other page gets 403 `origin_not_allowed` before the model is called.
|
|
66
|
+
* Requests without an `Origin` header (curl, your own server) pass: this
|
|
67
|
+
* stops other sites embedding your bot, not scripts. Defaults to `['*']`.
|
|
68
|
+
*/
|
|
69
|
+
allowedOrigins?: string[];
|
|
70
|
+
/** @deprecated Use `allowedOrigins`. Read as a one-item `allowedOrigins`. */
|
|
22
71
|
cors?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Reads the visitor's IP for per-IP rate limits and budgets, in the fetch
|
|
74
|
+
* handlers (`chatcopsVercelHandler`, `chatcopsCloudflareHandler`). Needed
|
|
75
|
+
* where the handler can't tell on its own: any host other than Vercel or
|
|
76
|
+
* Cloudflare. Read only a header your platform or proxy sets, never one a
|
|
77
|
+
* visitor can send. Return `undefined` to skip per-IP limits for a request.
|
|
78
|
+
* Express uses `req.ip`, which follows its `trust proxy` setting.
|
|
79
|
+
*/
|
|
80
|
+
clientIp?: ClientIpResolver;
|
|
81
|
+
/**
|
|
82
|
+
* Turns on session tokens. `POST <chat url>/session` gives the widget a
|
|
83
|
+
* token bound to its origin and one conversation, and chat requests send
|
|
84
|
+
* it as `Authorization: Bearer <token>`, so a guessed conversation id is
|
|
85
|
+
* useless. Sign with the first secret and verify with all of them, so a
|
|
86
|
+
* new secret goes first and the old one stays until its tokens expire.
|
|
87
|
+
* Each needs at least 32 bytes (`openssl rand -base64 32`). Keep them
|
|
88
|
+
* server side, never in a client bundle.
|
|
89
|
+
*/
|
|
90
|
+
sessionSecrets?: string[];
|
|
91
|
+
/** How long a session token lasts, in seconds. Defaults to 900. */
|
|
92
|
+
sessionTtlSec?: number;
|
|
93
|
+
/**
|
|
94
|
+
* Refuse chat requests without a session token (401 `session_required`).
|
|
95
|
+
* Defaults to true when `sessionSecrets` is set. Set false while widgets
|
|
96
|
+
* older than 0.6, which don't send tokens, are still out there.
|
|
97
|
+
*/
|
|
98
|
+
requireSession?: boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Cloudflare Turnstile when a session token is issued: `/session` needs a
|
|
101
|
+
* Turnstile token and checks it with Cloudflare before signing. Refreshing
|
|
102
|
+
* a session with its previous token skips it. Needs `sessionSecrets`, and
|
|
103
|
+
* the widget's `turnstileSiteKey`.
|
|
104
|
+
*/
|
|
105
|
+
turnstile?: TurnstileConfig;
|
|
106
|
+
/**
|
|
107
|
+
* Adds the reply's token usage to the `finish` part of protocol v1
|
|
108
|
+
* streams. Off by default, since visitors can read the stream.
|
|
109
|
+
*/
|
|
110
|
+
exposeUsage?: boolean;
|
|
23
111
|
/** @deprecated The server ignores this. Set the widget's text with its `strings` option. */
|
|
24
112
|
i18n?: {
|
|
25
113
|
defaultLocale: string;
|
|
@@ -34,7 +122,17 @@ export declare const chatRequestSchema: z.ZodObject<{
|
|
|
34
122
|
conversationId: z.ZodString;
|
|
35
123
|
message: z.ZodString;
|
|
36
124
|
messageId: z.ZodOptional<z.ZodString>;
|
|
37
|
-
|
|
125
|
+
/**
|
|
126
|
+
* `{ assistantMessageId }` replaces that reply. `true` (the 0.5 form)
|
|
127
|
+
* replaces the reply to `messageId`, or the latest one.
|
|
128
|
+
*/
|
|
129
|
+
regenerate: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodObject<{
|
|
130
|
+
assistantMessageId: z.ZodString;
|
|
131
|
+
}, "strip", z.ZodTypeAny, {
|
|
132
|
+
assistantMessageId: string;
|
|
133
|
+
}, {
|
|
134
|
+
assistantMessageId: string;
|
|
135
|
+
}>]>>;
|
|
38
136
|
pageContext: z.ZodOptional<z.ZodObject<{
|
|
39
137
|
url: z.ZodString;
|
|
40
138
|
title: z.ZodString;
|
|
@@ -57,7 +155,9 @@ export declare const chatRequestSchema: z.ZodObject<{
|
|
|
57
155
|
conversationId: string;
|
|
58
156
|
message: string;
|
|
59
157
|
messageId?: string | undefined;
|
|
60
|
-
regenerate?: boolean |
|
|
158
|
+
regenerate?: boolean | {
|
|
159
|
+
assistantMessageId: string;
|
|
160
|
+
} | undefined;
|
|
61
161
|
pageContext?: {
|
|
62
162
|
url: string;
|
|
63
163
|
title: string;
|
|
@@ -70,7 +170,9 @@ export declare const chatRequestSchema: z.ZodObject<{
|
|
|
70
170
|
conversationId: string;
|
|
71
171
|
message: string;
|
|
72
172
|
messageId?: string | undefined;
|
|
73
|
-
regenerate?: boolean |
|
|
173
|
+
regenerate?: boolean | {
|
|
174
|
+
assistantMessageId: string;
|
|
175
|
+
} | undefined;
|
|
74
176
|
pageContext?: {
|
|
75
177
|
url: string;
|
|
76
178
|
title: string;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EACV,UAAU,EACV,OAAO,EACP,eAAe,EACf,QAAQ,EACR,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,cAAc,EACd,aAAa,EACd,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,EAAE,cAAc,GAAG,UAAU,CAAC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2FAA2F;IAC3F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uGAAuG;IACvG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IAC1B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gGAAgG;IAChG,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC;;;OAGG;IACH,SAAS,CAAC,EAAE;QAAE,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4FAA4F;IAC5F,IAAI,CAAC,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;KAAE,CAAC;CAC1E;AAGD,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,eAAO,MAAM,iBAAiB;;;;IAI5B;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAeH,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -8,7 +8,11 @@ export const chatRequestSchema = z.object({
|
|
|
8
8
|
conversationId: z.string().min(1).max(128),
|
|
9
9
|
message: z.string().min(1).max(10000),
|
|
10
10
|
messageId: z.string().min(1).max(128).optional(),
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* `{ assistantMessageId }` replaces that reply. `true` (the 0.5 form)
|
|
13
|
+
* replaces the reply to `messageId`, or the latest one.
|
|
14
|
+
*/
|
|
15
|
+
regenerate: z.union([z.boolean(), z.object({ assistantMessageId: z.string().min(1).max(128) })]).optional(),
|
|
12
16
|
pageContext: z.object({
|
|
13
17
|
url: z.string().url(),
|
|
14
18
|
title: z.string().max(500),
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAwHxB,yFAAyF;AACzF,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAC5C,kFAAkF;AAClF,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAExC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;IACrC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAChD;;;OAGG;IACH,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC3G,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;QACrB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;QAC1B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;QAC5C,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;KAChD,CAAC,CAAC,QAAQ,EAAE;IACb,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;IACrC,QAAQ,EAAE,CAAC;SACR,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;SACrE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,oBAAoB,EAAE;QAClE,OAAO,EAAE,6BAA6B,oBAAoB,SAAS;KACpE,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC"}
|
package/dist/handler.d.ts
CHANGED
|
@@ -1,7 +1,58 @@
|
|
|
1
|
+
import { type AnalyticsStats, type BudgetScope, type Budgets, type LegacyChunk, type WireErrorBody, type WirePart } from '@chatcops/core';
|
|
1
2
|
import type { ChatCopsServerConfig } from './config.js';
|
|
2
3
|
export declare function createChatHandler(config: ChatCopsServerConfig): {
|
|
3
|
-
handleChat: (body: unknown, clientIp?: string
|
|
4
|
-
|
|
4
|
+
handleChat: (body: unknown, clientIp?: string, options?: {
|
|
5
|
+
signal?: AbortSignal;
|
|
6
|
+
}) => AsyncGenerator<string>;
|
|
7
|
+
startChat: (body: unknown, clientIp?: string, options?: StartChatOptions) => Promise<ChatStart>;
|
|
8
|
+
purge: (now?: number) => Promise<number | null>;
|
|
9
|
+
/** How many requests asked for each stream format, to tell when 0.5 widgets are gone. */
|
|
10
|
+
/** Answers `POST /session`, or `undefined` when session tokens are off. */
|
|
11
|
+
startSession: ((body: unknown, origin: string | null, clientIp?: string) => Promise<import("./security/sessions.js").SessionReply>) | undefined;
|
|
12
|
+
protocolStats: () => {
|
|
13
|
+
v1: number;
|
|
14
|
+
legacy: number;
|
|
15
|
+
"ai-sdk": number;
|
|
16
|
+
};
|
|
17
|
+
/** Stats from this process only. `analyticsStats()` reads the storage's event sink. */
|
|
18
|
+
getAnalytics: () => AnalyticsStats | null;
|
|
19
|
+
analyticsStats: (range?: {
|
|
20
|
+
from?: number;
|
|
21
|
+
to?: number;
|
|
22
|
+
}) => Promise<AnalyticsStats | null>;
|
|
5
23
|
cleanup: () => void;
|
|
6
24
|
};
|
|
25
|
+
/** The stream a caller writes: protocol v1, the 0.5 chunks, or the AI SDK's UI message stream. */
|
|
26
|
+
export type ChatFormat = 'v1' | 'legacy' | 'ai-sdk';
|
|
27
|
+
export interface StartChatOptions {
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
/** Which stream the caller writes, for `protocolStats()`. Defaults to `'v1'`. */
|
|
30
|
+
format?: ChatFormat;
|
|
31
|
+
/** The request's `Authorization` header, for session tokens. */
|
|
32
|
+
authorization?: string | null;
|
|
33
|
+
/** The request's `Origin` header, which a session token is bound to. */
|
|
34
|
+
origin?: string | null;
|
|
35
|
+
}
|
|
36
|
+
/** A request the handler won't answer, or the reply's parts. */
|
|
37
|
+
export type ChatStart = {
|
|
38
|
+
ok: true;
|
|
39
|
+
parts: AsyncGenerator<WirePart, void>;
|
|
40
|
+
} | {
|
|
41
|
+
ok: false;
|
|
42
|
+
/** The HTTP status protocol v1 answers with. */
|
|
43
|
+
status: number;
|
|
44
|
+
error: WireErrorBody['error'];
|
|
45
|
+
/** The chunk a 0.5 widget gets instead, inside a 200 stream. */
|
|
46
|
+
legacy: LegacyChunk & {
|
|
47
|
+
details?: unknown;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export type ChatHandler = ReturnType<typeof createChatHandler>;
|
|
51
|
+
/**
|
|
52
|
+
* Protocol v1 parts as 0.5 chunks (JSON strings). An error goes out last,
|
|
53
|
+
* after the turn has ended and lead webhooks have finished, as in 0.5.
|
|
54
|
+
*/
|
|
55
|
+
export declare function toLegacyStream(parts: AsyncIterable<WirePart>): AsyncGenerator<string>;
|
|
56
|
+
/** The startup line, so the limits in force are never a surprise. */
|
|
57
|
+
export declare function describeBudgets(budgets: Budgets, defaulted?: BudgetScope[]): string;
|
|
7
58
|
//# sourceMappingURL=handler.d.ts.map
|
package/dist/handler.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,cAAc,EAenB,KAAK,WAAW,EAChB,KAAK,OAAO,EAGZ,KAAK,WAAW,EAChB,KAAK,aAAa,EAElB,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,oBAAoB,EAAwB,MAAM,aAAa,CAAC;AAQ9E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,oBAAoB;uBAgLpD,OAAO,aACF,MAAM,YACR;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,KAChC,cAAc,CAAC,MAAM,CAAC;sBAlGM,OAAO,aAAa,MAAM,YAAW,gBAAgB,KAAQ,OAAO,CAAC,SAAS,CAAC;6BAwStE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAc5D,yFAAyF;IACzF,2EAA2E;0BAEhE,OAAO,UAAU,MAAM,GAAG,IAAI,aAAa,MAAM;;;;;;IAG5D,uFAAuF;;6BA3OnD;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,KAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;;EAgPtG;AAED,kGAAkG;AAClG,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEpD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,iFAAiF;IACjF,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,gEAAgE;AAChE,MAAM,MAAM,SAAS,GACjB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;CAAE,GACnD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9B,gEAAgE;IAChE,MAAM,EAAE,WAAW,GAAG;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC7C,CAAC;AAEN,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAU/D;;;GAGG;AACH,wBAAuB,cAAc,CAAC,KAAK,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAc5F;AA+CD,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,GAAE,WAAW,EAAO,GAAG,MAAM,CAkBvF"}
|