sideagent 0.0.0-stage → 0.2.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 +175 -2
- package/dist/index.d.ts +97 -0
- package/dist/index.js +759 -0
- package/dist/protocol.d.ts +87 -0
- package/dist/protocol.js +0 -0
- package/dist/server/browser.d.ts +2 -0
- package/dist/server/browser.js +4 -0
- package/dist/server/index.d.ts +260 -0
- package/dist/server/index.js +1160 -0
- package/dist/testing/mock-llm.d.ts +7 -0
- package/dist/testing/mock-llm.js +84 -0
- package/dist/workers-ai/index.d.ts +56 -0
- package/dist/workers-ai/index.js +241 -0
- package/package.json +79 -4
- package/skills/sideagent/SKILL.md +60 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** Events streamed from server to client over SSE. Shared with the client as types only. */
|
|
2
|
+
type AgentEvent = {
|
|
3
|
+
type: "turn.start";
|
|
4
|
+
threadId: string;
|
|
5
|
+
} | {
|
|
6
|
+
type: "text.delta";
|
|
7
|
+
text: string;
|
|
8
|
+
} | {
|
|
9
|
+
type: "tool.start";
|
|
10
|
+
callId: string;
|
|
11
|
+
operationId: string;
|
|
12
|
+
} | {
|
|
13
|
+
type: "approval.request";
|
|
14
|
+
callId: string;
|
|
15
|
+
operationId: string;
|
|
16
|
+
method: string;
|
|
17
|
+
path: string;
|
|
18
|
+
args: unknown;
|
|
19
|
+
token: string;
|
|
20
|
+
expiresAt: number;
|
|
21
|
+
} | {
|
|
22
|
+
type: "tool.complete";
|
|
23
|
+
callId: string;
|
|
24
|
+
operationId: string;
|
|
25
|
+
status: number;
|
|
26
|
+
args: unknown;
|
|
27
|
+
result: unknown;
|
|
28
|
+
invalidates: string[];
|
|
29
|
+
} | {
|
|
30
|
+
type: "tool.rejected";
|
|
31
|
+
callId: string;
|
|
32
|
+
operationId: string;
|
|
33
|
+
} | {
|
|
34
|
+
type: "error";
|
|
35
|
+
code: string;
|
|
36
|
+
message: string;
|
|
37
|
+
} | {
|
|
38
|
+
type: "turn.end";
|
|
39
|
+
};
|
|
40
|
+
type ChatRequest = {
|
|
41
|
+
threadId?: string;
|
|
42
|
+
message: string;
|
|
43
|
+
context?: unknown;
|
|
44
|
+
} | {
|
|
45
|
+
threadId: string;
|
|
46
|
+
approval: {
|
|
47
|
+
token: string;
|
|
48
|
+
decision: "approve" | "reject";
|
|
49
|
+
};
|
|
50
|
+
} | {
|
|
51
|
+
action: "threads.list";
|
|
52
|
+
} | {
|
|
53
|
+
action: "threads.get";
|
|
54
|
+
threadId: string;
|
|
55
|
+
} | {
|
|
56
|
+
action: "threads.delete";
|
|
57
|
+
threadId: string;
|
|
58
|
+
};
|
|
59
|
+
interface ThreadMeta {
|
|
60
|
+
id: string;
|
|
61
|
+
/** First user message, truncated. Never model output. */
|
|
62
|
+
title: string;
|
|
63
|
+
updatedAt: number;
|
|
64
|
+
}
|
|
65
|
+
type HistoryPart = {
|
|
66
|
+
type: "text";
|
|
67
|
+
text: string;
|
|
68
|
+
} | {
|
|
69
|
+
type: "tool";
|
|
70
|
+
callId: string;
|
|
71
|
+
operationId: string;
|
|
72
|
+
args: unknown;
|
|
73
|
+
result?: unknown;
|
|
74
|
+
};
|
|
75
|
+
interface HistoryMessage {
|
|
76
|
+
role: "user" | "assistant";
|
|
77
|
+
parts: HistoryPart[];
|
|
78
|
+
}
|
|
79
|
+
interface ThreadResponse {
|
|
80
|
+
messages: HistoryMessage[];
|
|
81
|
+
/** Set when the thread is waiting for an approval decision. */
|
|
82
|
+
pending?: Extract<AgentEvent, {
|
|
83
|
+
type: "approval.request";
|
|
84
|
+
}>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export type { AgentEvent, ChatRequest, HistoryMessage, HistoryPart, ThreadMeta, ThreadResponse };
|
package/dist/protocol.js
ADDED
|
File without changes
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { ThreadMeta } from '../protocol.js';
|
|
2
|
+
export { AgentEvent, ChatRequest } from '../protocol.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { BaseCheckpointSaver } from '@langchain/langgraph';
|
|
5
|
+
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
6
|
+
|
|
7
|
+
declare const configSchema: z.ZodObject<{
|
|
8
|
+
spec: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
|
|
9
|
+
baseUrl: z.ZodString;
|
|
10
|
+
llm: z.ZodOptional<z.ZodObject<{
|
|
11
|
+
baseUrl: z.ZodString;
|
|
12
|
+
apiKey: z.ZodString;
|
|
13
|
+
model: z.ZodString;
|
|
14
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
15
|
+
}, z.core.$strip>>;
|
|
16
|
+
allow: z.ZodArray<z.ZodString>;
|
|
17
|
+
allowedOrigins: z.ZodArray<z.ZodString>;
|
|
18
|
+
anonymous: z.ZodOptional<z.ZodBoolean>;
|
|
19
|
+
allowPrivateNetworks: z.ZodOptional<z.ZodBoolean>;
|
|
20
|
+
approvalSecret: z.ZodOptional<z.ZodString>;
|
|
21
|
+
instructions: z.ZodOptional<z.ZodString>;
|
|
22
|
+
knowledge: z.ZodOptional<z.ZodObject<{
|
|
23
|
+
sources: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
24
|
+
id: z.ZodString;
|
|
25
|
+
title: z.ZodString;
|
|
26
|
+
content: z.ZodString;
|
|
27
|
+
}, z.core.$strip>>>;
|
|
28
|
+
urls: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
29
|
+
url: z.ZodString;
|
|
30
|
+
title: z.ZodOptional<z.ZodString>;
|
|
31
|
+
}, z.core.$strip>]>>>;
|
|
32
|
+
embeddings: z.ZodOptional<z.ZodObject<{
|
|
33
|
+
model: z.ZodString;
|
|
34
|
+
baseUrl: z.ZodOptional<z.ZodString>;
|
|
35
|
+
apiKey: z.ZodOptional<z.ZodString>;
|
|
36
|
+
}, z.core.$strip>>;
|
|
37
|
+
topK: z.ZodDefault<z.ZodNumber>;
|
|
38
|
+
ttlMs: z.ZodDefault<z.ZodNumber>;
|
|
39
|
+
maxSourceBytes: z.ZodDefault<z.ZodNumber>;
|
|
40
|
+
maxChunks: z.ZodDefault<z.ZodNumber>;
|
|
41
|
+
chunkSize: z.ZodDefault<z.ZodNumber>;
|
|
42
|
+
}, z.core.$strict>>;
|
|
43
|
+
limits: z.ZodDefault<z.ZodObject<{
|
|
44
|
+
maxSteps: z.ZodDefault<z.ZodNumber>;
|
|
45
|
+
callTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
46
|
+
maxResultBytes: z.ZodDefault<z.ZodNumber>;
|
|
47
|
+
turnTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
48
|
+
maxConcurrentTurnsPerUser: z.ZodDefault<z.ZodNumber>;
|
|
49
|
+
maxTools: z.ZodDefault<z.ZodNumber>;
|
|
50
|
+
}, z.core.$strip>>;
|
|
51
|
+
}, z.core.$strict>;
|
|
52
|
+
type AgentConfigInput = z.input<typeof configSchema>;
|
|
53
|
+
type AgentConfig = z.output<typeof configSchema>;
|
|
54
|
+
/** Validates config; also requires getAuth or anonymous:true (checked by caller with the function in hand). */
|
|
55
|
+
declare function parseConfig(input: unknown, hasGetAuth: boolean, injected?: {
|
|
56
|
+
model?: boolean;
|
|
57
|
+
embeddings?: boolean;
|
|
58
|
+
}): AgentConfig;
|
|
59
|
+
|
|
60
|
+
interface UrlGuardOptions {
|
|
61
|
+
/** Pinned origin from config. Requests may only go here. */
|
|
62
|
+
baseUrl: string;
|
|
63
|
+
allowPrivateNetworks?: boolean;
|
|
64
|
+
}
|
|
65
|
+
/** Throws unless `url` is safe to call under the pinned config. */
|
|
66
|
+
declare function assertAllowedUrl(url: string, opts: UrlGuardOptions): URL;
|
|
67
|
+
|
|
68
|
+
interface KnowledgeSourceInput {
|
|
69
|
+
id: string;
|
|
70
|
+
title: string;
|
|
71
|
+
content: string;
|
|
72
|
+
}
|
|
73
|
+
interface KnowledgeUrlInput {
|
|
74
|
+
url: string;
|
|
75
|
+
title?: string;
|
|
76
|
+
}
|
|
77
|
+
interface KnowledgeOptions {
|
|
78
|
+
sources: KnowledgeSourceInput[];
|
|
79
|
+
urls: (string | KnowledgeUrlInput)[];
|
|
80
|
+
topK: number;
|
|
81
|
+
ttlMs: number;
|
|
82
|
+
maxSourceBytes: number;
|
|
83
|
+
maxChunks: number;
|
|
84
|
+
chunkSize: number;
|
|
85
|
+
}
|
|
86
|
+
interface ChunkMeta {
|
|
87
|
+
sourceId: string;
|
|
88
|
+
title: string;
|
|
89
|
+
/** Only set for sources that came from a URL listed in config. */
|
|
90
|
+
url?: string;
|
|
91
|
+
}
|
|
92
|
+
interface StoredChunk {
|
|
93
|
+
text: string;
|
|
94
|
+
vector: number[];
|
|
95
|
+
meta: ChunkMeta;
|
|
96
|
+
}
|
|
97
|
+
interface Hit {
|
|
98
|
+
text: string;
|
|
99
|
+
score: number;
|
|
100
|
+
meta: ChunkMeta;
|
|
101
|
+
}
|
|
102
|
+
/** Plug in your own (pgvector, Vectorize, …). The default is an in-memory cosine store. */
|
|
103
|
+
interface VectorStore {
|
|
104
|
+
replace(sourceId: string, chunks: StoredChunk[]): Promise<void>;
|
|
105
|
+
search(vector: number[], k: number): Promise<Hit[]>;
|
|
106
|
+
}
|
|
107
|
+
declare class MemoryVectorStore implements VectorStore {
|
|
108
|
+
private bySource;
|
|
109
|
+
replace(sourceId: string, chunks: StoredChunk[]): Promise<void>;
|
|
110
|
+
search(vector: number[], k: number): Promise<Hit[]>;
|
|
111
|
+
}
|
|
112
|
+
/** Splits markdown/plain text into chunks of roughly `size` chars, keeping the nearest heading as context. */
|
|
113
|
+
declare function chunkText(content: string, size: number): string[];
|
|
114
|
+
/** Dependency-free HTML to text/markdown-ish conversion. Plain text out; never HTML. */
|
|
115
|
+
declare function htmlToText(html: string): {
|
|
116
|
+
title?: string;
|
|
117
|
+
text: string;
|
|
118
|
+
};
|
|
119
|
+
interface SourceStatus {
|
|
120
|
+
id: string;
|
|
121
|
+
title: string;
|
|
122
|
+
url?: string;
|
|
123
|
+
chunks: number;
|
|
124
|
+
loadedAt?: number;
|
|
125
|
+
error?: string;
|
|
126
|
+
}
|
|
127
|
+
interface KnowledgeDeps {
|
|
128
|
+
embedDocuments(texts: string[]): Promise<number[][]>;
|
|
129
|
+
embedQuery(text: string): Promise<number[]>;
|
|
130
|
+
store?: VectorStore;
|
|
131
|
+
allowPrivateNetworks?: boolean;
|
|
132
|
+
fetch?: typeof fetch;
|
|
133
|
+
now?: () => number;
|
|
134
|
+
}
|
|
135
|
+
declare class KnowledgeBase {
|
|
136
|
+
private opts;
|
|
137
|
+
private deps;
|
|
138
|
+
readonly store: VectorStore;
|
|
139
|
+
private statuses;
|
|
140
|
+
private refreshing;
|
|
141
|
+
private lastRefresh;
|
|
142
|
+
private totalChunks;
|
|
143
|
+
constructor(opts: KnowledgeOptions, deps: KnowledgeDeps);
|
|
144
|
+
private now;
|
|
145
|
+
status(): SourceStatus[];
|
|
146
|
+
/** Loads every source. Failures are recorded per source and never throw. */
|
|
147
|
+
load(): Promise<void>;
|
|
148
|
+
private loadUrls;
|
|
149
|
+
private ingest;
|
|
150
|
+
private fetchPage;
|
|
151
|
+
/** Re-fetches URL sources. Keeps the old data for any source that fails. Concurrent calls share one run. */
|
|
152
|
+
refresh(): Promise<void>;
|
|
153
|
+
search(query: string): Promise<Hit[]>;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
interface AuditEvent {
|
|
157
|
+
at: number;
|
|
158
|
+
userId: string;
|
|
159
|
+
threadId: string;
|
|
160
|
+
operationId: string;
|
|
161
|
+
callId: string;
|
|
162
|
+
args: unknown;
|
|
163
|
+
status: "executed" | "rejected" | "denied" | "error";
|
|
164
|
+
httpStatus?: number;
|
|
165
|
+
approval: "auto" | "approved" | "rejected";
|
|
166
|
+
durationMs?: number;
|
|
167
|
+
error?: string;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Index of a user's conversations. The messages themselves live in the LangGraph checkpointer. */
|
|
171
|
+
interface ThreadStore {
|
|
172
|
+
list(userId: string): Promise<ThreadMeta[]>;
|
|
173
|
+
has(userId: string, threadId: string): Promise<boolean>;
|
|
174
|
+
/** Creates the thread with `title` if new, otherwise only bumps `updatedAt`. */
|
|
175
|
+
touch(userId: string, threadId: string, title: string): Promise<void>;
|
|
176
|
+
delete(userId: string, threadId: string): Promise<void>;
|
|
177
|
+
}
|
|
178
|
+
/** Per-process store. Use a persistent implementation (SQL, KV, Redis) in production. */
|
|
179
|
+
declare class MemoryThreadStore implements ThreadStore {
|
|
180
|
+
private users;
|
|
181
|
+
private of;
|
|
182
|
+
list(userId: string): Promise<ThreadMeta[]>;
|
|
183
|
+
has(userId: string, threadId: string): Promise<boolean>;
|
|
184
|
+
touch(userId: string, threadId: string, title: string): Promise<void>;
|
|
185
|
+
delete(userId: string, threadId: string): Promise<void>;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
interface AuthResult {
|
|
189
|
+
/** Stable identity of the signed-in user. Threads are bound to it. */
|
|
190
|
+
userId: string;
|
|
191
|
+
/** Headers forwarded to your API (e.g. Authorization, Cookie). Never shown to the LLM. */
|
|
192
|
+
headers?: Record<string, string>;
|
|
193
|
+
}
|
|
194
|
+
/** Same shape as LangChain's Embeddings, minimal so any adapter fits. */
|
|
195
|
+
interface EmbeddingsLike {
|
|
196
|
+
embedDocuments(texts: string[]): Promise<number[][]>;
|
|
197
|
+
embedQuery(text: string): Promise<number[]>;
|
|
198
|
+
}
|
|
199
|
+
interface CreateAgentOptions extends AgentConfigInput {
|
|
200
|
+
/** Your own chat model (e.g. workersAiChatModel from sideagent/workers-ai). Use instead of `llm`, never with it. It must support bindTools(). */
|
|
201
|
+
model?: BaseChatModel;
|
|
202
|
+
/** Your own embeddings, used instead of knowledge.embeddings. */
|
|
203
|
+
embeddings?: EmbeddingsLike;
|
|
204
|
+
getAuth?: (request: Request) => AuthResult | Promise<AuthResult>;
|
|
205
|
+
/** Throw to reject a turn (rate limiting, quota). */
|
|
206
|
+
beforeTurn?: (ctx: {
|
|
207
|
+
request: Request;
|
|
208
|
+
userId: string;
|
|
209
|
+
}) => void | Promise<void>;
|
|
210
|
+
onAudit?: (event: AuditEvent) => void | Promise<void>;
|
|
211
|
+
checkpointer?: BaseCheckpointSaver;
|
|
212
|
+
/** Index of each user's conversations (history list). Defaults to in-memory. */
|
|
213
|
+
threadStore?: ThreadStore;
|
|
214
|
+
/** Where knowledge embeddings live. Defaults to in-memory (re-embedded on every start). */
|
|
215
|
+
vectorStore?: VectorStore;
|
|
216
|
+
}
|
|
217
|
+
interface DoctorReport {
|
|
218
|
+
ok: boolean;
|
|
219
|
+
checks: {
|
|
220
|
+
name: string;
|
|
221
|
+
ok: boolean;
|
|
222
|
+
detail: string;
|
|
223
|
+
}[];
|
|
224
|
+
tools: {
|
|
225
|
+
operationId: string;
|
|
226
|
+
method: string;
|
|
227
|
+
path: string;
|
|
228
|
+
approval: "required" | "auto";
|
|
229
|
+
}[];
|
|
230
|
+
knowledge?: {
|
|
231
|
+
id: string;
|
|
232
|
+
title: string;
|
|
233
|
+
url?: string;
|
|
234
|
+
chunks: number;
|
|
235
|
+
error?: string;
|
|
236
|
+
}[];
|
|
237
|
+
}
|
|
238
|
+
declare function createAgent(options: CreateAgentOptions): Promise<{
|
|
239
|
+
handler: (request: Request) => Promise<Response>;
|
|
240
|
+
doctor: () => Promise<DoctorReport>;
|
|
241
|
+
tools: string[];
|
|
242
|
+
knowledge: KnowledgeBase | undefined;
|
|
243
|
+
}>;
|
|
244
|
+
type Agent = Awaited<ReturnType<typeof createAgent>>;
|
|
245
|
+
|
|
246
|
+
/** Next.js App Router: `export const { POST } = nextRoute(agent)` */
|
|
247
|
+
declare function nextRoute(agent: Agent): {
|
|
248
|
+
POST: (req: Request) => Promise<Response>;
|
|
249
|
+
OPTIONS: (req: Request) => Promise<Response>;
|
|
250
|
+
};
|
|
251
|
+
/** Hono: `app.on(["POST", "OPTIONS"], "/agent", honoHandler(agent))` */
|
|
252
|
+
declare function honoHandler(agent: Agent): (c: {
|
|
253
|
+
req: {
|
|
254
|
+
raw: Request;
|
|
255
|
+
};
|
|
256
|
+
}) => Promise<Response>;
|
|
257
|
+
/** Express (use express.json() before it): `app.post("/agent", expressHandler(agent))` and `app.options("/agent", expressHandler(agent))` */
|
|
258
|
+
declare function expressHandler(agent: Agent): (req: any, res: any) => Promise<any>;
|
|
259
|
+
|
|
260
|
+
export { type Agent, type AgentConfig, type AgentConfigInput, type AuditEvent, type AuthResult, type CreateAgentOptions, type DoctorReport, type EmbeddingsLike, KnowledgeBase, type KnowledgeSourceInput, MemoryThreadStore, MemoryVectorStore, type ThreadStore, type VectorStore, assertAllowedUrl, chunkText, configSchema, createAgent, expressHandler, honoHandler, htmlToText, nextRoute, parseConfig };
|