bashkit 0.3.1 → 0.3.2
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/dist/cloudflare/index.d.ts +20 -0
- package/dist/cloudflare/index.js +1251 -0
- package/dist/durable/durable-session.d.ts +220 -0
- package/dist/durable/index.d.ts +41 -0
- package/dist/durable/index.js +159 -0
- package/dist/durable/schema.d.ts +51 -0
- package/dist/durable/types.d.ts +208 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +619 -106
- package/dist/react/index.d.ts +42 -0
- package/dist/react/index.js +10 -0
- package/dist/react/types.d.ts +333 -0
- package/dist/react/use-agent.d.ts +33 -0
- package/dist/react/use-durable-chat.d.ts +39 -0
- package/dist/tools/task.d.ts +6 -4
- package/dist/utils/debug.d.ts +83 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/workflow.js +827 -234
- package/package.json +1 -1
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { Agent } from "agents";
|
|
2
|
+
import { AIChatAgent } from "agents/ai-chat-agent";
|
|
3
|
+
import type { Connection, ConnectionContext, WSMessage } from "agents";
|
|
4
|
+
import type { Sandbox } from "../sandbox/interface";
|
|
5
|
+
/**
|
|
6
|
+
* Configuration for creating a BashKit agent with sandbox support.
|
|
7
|
+
*/
|
|
8
|
+
export interface BashKitAgentConfig<TEnv = unknown> {
|
|
9
|
+
/**
|
|
10
|
+
* Sandbox lifecycle configuration.
|
|
11
|
+
*/
|
|
12
|
+
sandbox: {
|
|
13
|
+
/**
|
|
14
|
+
* Create a new sandbox instance.
|
|
15
|
+
*/
|
|
16
|
+
create: (env: TEnv) => Promise<Sandbox>;
|
|
17
|
+
/**
|
|
18
|
+
* Reconnect to an existing sandbox by ID.
|
|
19
|
+
*/
|
|
20
|
+
reconnect: (sandboxId: string, env: TEnv) => Promise<Sandbox>;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Base class for BashKit agents with sandbox support.
|
|
25
|
+
* Extends the Cloudflare Agents SDK Agent class.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* import { BashKitAgent } from 'bashkit/durable';
|
|
30
|
+
* import { createE2BSandbox } from 'bashkit';
|
|
31
|
+
*
|
|
32
|
+
* export class MyAgent extends BashKitAgent<Env> {
|
|
33
|
+
* getSandboxConfig() {
|
|
34
|
+
* return {
|
|
35
|
+
* create: () => createE2BSandbox({ apiKey: this.env.E2B_API_KEY }),
|
|
36
|
+
* reconnect: (id) => createE2BSandbox({ apiKey: this.env.E2B_API_KEY, sandboxId: id }),
|
|
37
|
+
* };
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* async onMessage(connection: Connection, message: WSMessage) {
|
|
41
|
+
* // Access sandbox via this.getSandbox()
|
|
42
|
+
* const sandbox = this.getSandbox();
|
|
43
|
+
* const result = await sandbox.commands.run('echo hello');
|
|
44
|
+
* connection.send(JSON.stringify({ output: result.stdout }));
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare abstract class BashKitAgent<TEnv = unknown, TState = unknown> extends Agent<TEnv, TState> {
|
|
50
|
+
/**
|
|
51
|
+
* Environment bindings (typed from generic).
|
|
52
|
+
* Exposed from parent class for TypeScript access.
|
|
53
|
+
*/
|
|
54
|
+
env: TEnv;
|
|
55
|
+
/**
|
|
56
|
+
* The sandbox instance. Available after onStart() completes.
|
|
57
|
+
*/
|
|
58
|
+
private _sandbox;
|
|
59
|
+
/**
|
|
60
|
+
* Override this to configure sandbox creation/reconnection.
|
|
61
|
+
* Called with access to this.env.
|
|
62
|
+
*/
|
|
63
|
+
protected abstract getSandboxConfig(): BashKitAgentConfig<TEnv>["sandbox"];
|
|
64
|
+
/**
|
|
65
|
+
* Called when the agent starts. Initializes the sandbox.
|
|
66
|
+
*/
|
|
67
|
+
onStart(): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Initialize or reconnect to sandbox.
|
|
70
|
+
*/
|
|
71
|
+
private initSandbox;
|
|
72
|
+
/**
|
|
73
|
+
* Create a new sandbox and persist its ID.
|
|
74
|
+
*/
|
|
75
|
+
private createNewSandbox;
|
|
76
|
+
/**
|
|
77
|
+
* Ensure schema exists. Called automatically in onStart.
|
|
78
|
+
*/
|
|
79
|
+
private ensureSchema;
|
|
80
|
+
/**
|
|
81
|
+
* Get the current sandbox, throwing if not initialized.
|
|
82
|
+
*/
|
|
83
|
+
protected getSandbox(): Sandbox;
|
|
84
|
+
/**
|
|
85
|
+
* Check if sandbox is initialized.
|
|
86
|
+
*/
|
|
87
|
+
protected hasSandbox(): boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Factory function to create a BashKit agent class with sandbox support.
|
|
91
|
+
* This is an alternative to extending BashKitAgent directly.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* import { createBashKitAgent } from 'bashkit/durable';
|
|
96
|
+
* import { createE2BSandbox } from 'bashkit';
|
|
97
|
+
*
|
|
98
|
+
* const BaseBashKitAgent = createBashKitAgent<Env>({
|
|
99
|
+
* sandbox: {
|
|
100
|
+
* create: (env) => createE2BSandbox({ apiKey: env.E2B_API_KEY }),
|
|
101
|
+
* reconnect: (id, env) => createE2BSandbox({ apiKey: env.E2B_API_KEY, sandboxId: id }),
|
|
102
|
+
* },
|
|
103
|
+
* });
|
|
104
|
+
*
|
|
105
|
+
* export class MyAgent extends BaseBashKitAgent {
|
|
106
|
+
* async onMessage(connection, message) {
|
|
107
|
+
* const sandbox = this.getSandbox();
|
|
108
|
+
* const result = await sandbox.commands.run('echo hello');
|
|
109
|
+
* connection.send(JSON.stringify({ output: result.stdout }));
|
|
110
|
+
* }
|
|
111
|
+
* }
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export declare function createBashKitAgent<TEnv = unknown, TState = unknown>(config: BashKitAgentConfig<TEnv>): typeof BashKitAgent<TEnv, TState>;
|
|
115
|
+
/**
|
|
116
|
+
* Base class for BashKit chat agents with sandbox support.
|
|
117
|
+
* Extends AIChatAgent for built-in chat handling + adds sandbox lifecycle management.
|
|
118
|
+
*
|
|
119
|
+
* Use this when building chat-based agents that need sandbox access.
|
|
120
|
+
* You get:
|
|
121
|
+
* - `this.messages` - automatic chat history
|
|
122
|
+
* - `onChatMessage()` - implement to handle chat, return streaming response
|
|
123
|
+
* - `getSandbox()` - access the E2B sandbox
|
|
124
|
+
* - Resumable streaming out of the box
|
|
125
|
+
* - Works with `useAgentChat` on the frontend
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* import { BashKitChatAgent } from 'bashkit/durable';
|
|
130
|
+
* import { createE2BSandbox, createAgentTools } from 'bashkit';
|
|
131
|
+
* import { streamText } from 'ai';
|
|
132
|
+
* import { anthropic } from '@ai-sdk/anthropic';
|
|
133
|
+
*
|
|
134
|
+
* export class MyChatAgent extends BashKitChatAgent<Env> {
|
|
135
|
+
* getSandboxConfig() {
|
|
136
|
+
* return {
|
|
137
|
+
* create: () => createE2BSandbox({ apiKey: this.env.E2B_API_KEY }),
|
|
138
|
+
* reconnect: (id) => createE2BSandbox({ apiKey: this.env.E2B_API_KEY, sandboxId: id }),
|
|
139
|
+
* };
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
* async onChatMessage() {
|
|
143
|
+
* const sandbox = this.getSandbox();
|
|
144
|
+
* const tools = createAgentTools(sandbox);
|
|
145
|
+
*
|
|
146
|
+
* return streamText({
|
|
147
|
+
* model: anthropic('claude-sonnet-4-20250514'),
|
|
148
|
+
* messages: this.messages,
|
|
149
|
+
* tools,
|
|
150
|
+
* }).toUIMessageStreamResponse();
|
|
151
|
+
* }
|
|
152
|
+
* }
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
export declare abstract class BashKitChatAgent<TEnv = unknown, TState = unknown> extends AIChatAgent<TEnv, TState> {
|
|
156
|
+
/**
|
|
157
|
+
* Environment bindings (typed from generic).
|
|
158
|
+
*/
|
|
159
|
+
env: TEnv;
|
|
160
|
+
/**
|
|
161
|
+
* The sandbox instance. Available after onStart() completes.
|
|
162
|
+
*/
|
|
163
|
+
private _sandbox;
|
|
164
|
+
/**
|
|
165
|
+
* Override this to configure sandbox creation/reconnection.
|
|
166
|
+
*/
|
|
167
|
+
protected abstract getSandboxConfig(): BashKitAgentConfig<TEnv>["sandbox"];
|
|
168
|
+
/**
|
|
169
|
+
* Called when the agent starts. Initializes the sandbox.
|
|
170
|
+
* If you override this, make sure to call super.onStart().
|
|
171
|
+
*/
|
|
172
|
+
onStart(): Promise<void>;
|
|
173
|
+
/**
|
|
174
|
+
* Initialize or reconnect to sandbox.
|
|
175
|
+
*/
|
|
176
|
+
private initSandbox;
|
|
177
|
+
/**
|
|
178
|
+
* Create a new sandbox and persist its ID.
|
|
179
|
+
*/
|
|
180
|
+
private createNewSandbox;
|
|
181
|
+
/**
|
|
182
|
+
* Ensure sandbox schema exists.
|
|
183
|
+
*/
|
|
184
|
+
private ensureSandboxSchema;
|
|
185
|
+
/**
|
|
186
|
+
* Get the current sandbox, throwing if not initialized.
|
|
187
|
+
*/
|
|
188
|
+
protected getSandbox(): Sandbox;
|
|
189
|
+
/**
|
|
190
|
+
* Check if sandbox is initialized.
|
|
191
|
+
*/
|
|
192
|
+
protected hasSandbox(): boolean;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Factory function to create a BashKit chat agent class with sandbox support.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```typescript
|
|
199
|
+
* import { createBashKitChatAgent } from 'bashkit/durable';
|
|
200
|
+
* import { createE2BSandbox, createAgentTools } from 'bashkit';
|
|
201
|
+
*
|
|
202
|
+
* const BaseChatAgent = createBashKitChatAgent<Env>({
|
|
203
|
+
* sandbox: {
|
|
204
|
+
* create: (env) => createE2BSandbox({ apiKey: env.E2B_API_KEY }),
|
|
205
|
+
* reconnect: (id, env) => createE2BSandbox({ apiKey: env.E2B_API_KEY, sandboxId: id }),
|
|
206
|
+
* },
|
|
207
|
+
* });
|
|
208
|
+
*
|
|
209
|
+
* export class MyChatAgent extends BaseChatAgent {
|
|
210
|
+
* async onChatMessage() {
|
|
211
|
+
* const tools = createAgentTools(this.getSandbox());
|
|
212
|
+
* return streamText({ ... }).toUIMessageStreamResponse();
|
|
213
|
+
* }
|
|
214
|
+
* }
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
export declare function createBashKitChatAgent<TEnv = unknown, TState = unknown>(config: BashKitAgentConfig<TEnv>): typeof BashKitChatAgent<TEnv, TState>;
|
|
218
|
+
export type { Connection, ConnectionContext, WSMessage };
|
|
219
|
+
export { Agent } from "agents";
|
|
220
|
+
export { AIChatAgent } from "agents/ai-chat-agent";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bashkit/durable - Durable agent sessions with Cloudflare Agents SDK
|
|
3
|
+
*
|
|
4
|
+
* This module provides sandbox-integrated agents built on the Cloudflare Agents SDK.
|
|
5
|
+
* It extends the Agent class with automatic sandbox lifecycle management.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { BashKitAgent, createBashKitAgent } from 'bashkit/durable';
|
|
10
|
+
* import { createE2BSandbox } from 'bashkit';
|
|
11
|
+
*
|
|
12
|
+
* // Option 1: Extend BashKitAgent directly
|
|
13
|
+
* export class MyAgent extends BashKitAgent<Env> {
|
|
14
|
+
* sandboxConfig = {
|
|
15
|
+
* create: () => createE2BSandbox({ apiKey: this.env.E2B_API_KEY }),
|
|
16
|
+
* reconnect: (id) => createE2BSandbox({ apiKey: this.env.E2B_API_KEY, sandboxId: id }),
|
|
17
|
+
* };
|
|
18
|
+
*
|
|
19
|
+
* async onMessage(connection, message) {
|
|
20
|
+
* const result = await this.sandbox.commands.run('echo hello');
|
|
21
|
+
* connection.send(JSON.stringify({ output: result.stdout }));
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* // Option 2: Use factory function
|
|
26
|
+
* const BaseBashKitAgent = createBashKitAgent({
|
|
27
|
+
* sandbox: {
|
|
28
|
+
* create: (env) => createE2BSandbox({ apiKey: env.E2B_API_KEY }),
|
|
29
|
+
* reconnect: (id, env) => createE2BSandbox({ apiKey: env.E2B_API_KEY, sandboxId: id }),
|
|
30
|
+
* },
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* export class MyAgent extends BaseBashKitAgent {
|
|
34
|
+
* async onMessage(connection, message) {
|
|
35
|
+
* // Your agent logic
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export { BashKitAgent, createBashKitAgent, BashKitChatAgent, createBashKitChatAgent, Agent, AIChatAgent, } from "./durable-session";
|
|
41
|
+
export type { BashKitAgentConfig, Connection, ConnectionContext, WSMessage, } from "./durable-session";
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// src/durable/durable-session.ts
|
|
2
|
+
import { Agent } from "agents";
|
|
3
|
+
import { AIChatAgent } from "agents/ai-chat-agent";
|
|
4
|
+
import { Agent as Agent2 } from "agents";
|
|
5
|
+
import { AIChatAgent as AIChatAgent2 } from "agents/ai-chat-agent";
|
|
6
|
+
|
|
7
|
+
class BashKitAgent extends Agent {
|
|
8
|
+
_sandbox = null;
|
|
9
|
+
async onStart() {
|
|
10
|
+
this.ensureSchema();
|
|
11
|
+
await this.initSandbox();
|
|
12
|
+
}
|
|
13
|
+
async initSandbox() {
|
|
14
|
+
const config = this.getSandboxConfig();
|
|
15
|
+
let existingSandboxId = null;
|
|
16
|
+
try {
|
|
17
|
+
const rows = this.sql`
|
|
18
|
+
SELECT sandbox_id FROM _bashkit_sandbox WHERE id = 1
|
|
19
|
+
`;
|
|
20
|
+
existingSandboxId = rows[0]?.sandbox_id ?? null;
|
|
21
|
+
} catch {}
|
|
22
|
+
if (existingSandboxId) {
|
|
23
|
+
try {
|
|
24
|
+
this._sandbox = await config.reconnect(existingSandboxId, this.env);
|
|
25
|
+
console.log(`[bashkit] Reconnected to sandbox: ${existingSandboxId}`);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.warn(`[bashkit] Failed to reconnect to sandbox ${existingSandboxId}, creating new:`, error);
|
|
28
|
+
await this.createNewSandbox(config);
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
await this.createNewSandbox(config);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async createNewSandbox(config) {
|
|
35
|
+
this._sandbox = await config.create(this.env);
|
|
36
|
+
if (this._sandbox.id) {
|
|
37
|
+
const now = Date.now();
|
|
38
|
+
const sandboxId = this._sandbox.id;
|
|
39
|
+
this.sql`
|
|
40
|
+
INSERT INTO _bashkit_sandbox (id, sandbox_id, status, created_at, updated_at)
|
|
41
|
+
VALUES (1, ${sandboxId}, 'active', ${now}, ${now})
|
|
42
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
43
|
+
sandbox_id = ${sandboxId},
|
|
44
|
+
updated_at = ${now}
|
|
45
|
+
`;
|
|
46
|
+
console.log(`[bashkit] Created new sandbox: ${this._sandbox.id}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
ensureSchema() {
|
|
50
|
+
this.sql`
|
|
51
|
+
CREATE TABLE IF NOT EXISTS _bashkit_sandbox (
|
|
52
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
53
|
+
sandbox_id TEXT,
|
|
54
|
+
status TEXT DEFAULT 'active',
|
|
55
|
+
created_at INTEGER,
|
|
56
|
+
updated_at INTEGER
|
|
57
|
+
)
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
60
|
+
getSandbox() {
|
|
61
|
+
if (!this._sandbox) {
|
|
62
|
+
throw new Error("Sandbox not initialized. Wait for onStart() to complete.");
|
|
63
|
+
}
|
|
64
|
+
return this._sandbox;
|
|
65
|
+
}
|
|
66
|
+
hasSandbox() {
|
|
67
|
+
return this._sandbox !== null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function createBashKitAgent(config) {
|
|
71
|
+
|
|
72
|
+
class ConfiguredBashKitAgent extends BashKitAgent {
|
|
73
|
+
getSandboxConfig() {
|
|
74
|
+
return config.sandbox;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return ConfiguredBashKitAgent;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
class BashKitChatAgent extends AIChatAgent {
|
|
81
|
+
_sandbox = null;
|
|
82
|
+
async onStart() {
|
|
83
|
+
this.ensureSandboxSchema();
|
|
84
|
+
await this.initSandbox();
|
|
85
|
+
}
|
|
86
|
+
async initSandbox() {
|
|
87
|
+
const config = this.getSandboxConfig();
|
|
88
|
+
let existingSandboxId = null;
|
|
89
|
+
try {
|
|
90
|
+
const rows = this.sql`
|
|
91
|
+
SELECT sandbox_id FROM _bashkit_sandbox WHERE id = 1
|
|
92
|
+
`;
|
|
93
|
+
existingSandboxId = rows[0]?.sandbox_id ?? null;
|
|
94
|
+
} catch {}
|
|
95
|
+
if (existingSandboxId) {
|
|
96
|
+
try {
|
|
97
|
+
this._sandbox = await config.reconnect(existingSandboxId, this.env);
|
|
98
|
+
console.log(`[bashkit] Reconnected to sandbox: ${existingSandboxId}`);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.warn(`[bashkit] Failed to reconnect to sandbox ${existingSandboxId}, creating new:`, error);
|
|
101
|
+
await this.createNewSandbox(config);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
await this.createNewSandbox(config);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async createNewSandbox(config) {
|
|
108
|
+
this._sandbox = await config.create(this.env);
|
|
109
|
+
if (this._sandbox.id) {
|
|
110
|
+
const now = Date.now();
|
|
111
|
+
const sandboxId = this._sandbox.id;
|
|
112
|
+
this.sql`
|
|
113
|
+
INSERT INTO _bashkit_sandbox (id, sandbox_id, status, created_at, updated_at)
|
|
114
|
+
VALUES (1, ${sandboxId}, 'active', ${now}, ${now})
|
|
115
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
116
|
+
sandbox_id = ${sandboxId},
|
|
117
|
+
updated_at = ${now}
|
|
118
|
+
`;
|
|
119
|
+
console.log(`[bashkit] Created new sandbox: ${this._sandbox.id}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
ensureSandboxSchema() {
|
|
123
|
+
this.sql`
|
|
124
|
+
CREATE TABLE IF NOT EXISTS _bashkit_sandbox (
|
|
125
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
126
|
+
sandbox_id TEXT,
|
|
127
|
+
status TEXT DEFAULT 'active',
|
|
128
|
+
created_at INTEGER,
|
|
129
|
+
updated_at INTEGER
|
|
130
|
+
)
|
|
131
|
+
`;
|
|
132
|
+
}
|
|
133
|
+
getSandbox() {
|
|
134
|
+
if (!this._sandbox) {
|
|
135
|
+
throw new Error("Sandbox not initialized. Wait for onStart() to complete.");
|
|
136
|
+
}
|
|
137
|
+
return this._sandbox;
|
|
138
|
+
}
|
|
139
|
+
hasSandbox() {
|
|
140
|
+
return this._sandbox !== null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function createBashKitChatAgent(config) {
|
|
144
|
+
|
|
145
|
+
class ConfiguredBashKitChatAgent extends BashKitChatAgent {
|
|
146
|
+
getSandboxConfig() {
|
|
147
|
+
return config.sandbox;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return ConfiguredBashKitChatAgent;
|
|
151
|
+
}
|
|
152
|
+
export {
|
|
153
|
+
createBashKitChatAgent,
|
|
154
|
+
createBashKitAgent,
|
|
155
|
+
BashKitChatAgent,
|
|
156
|
+
BashKitAgent,
|
|
157
|
+
Agent2 as Agent,
|
|
158
|
+
AIChatAgent2 as AIChatAgent
|
|
159
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { BashkitSessionRow, BashkitStreamBufferRow, SqlStorage, StreamBufferOptions } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Initialize the bashkit schema in the Durable Object's SQLite.
|
|
4
|
+
* Creates tables if they don't exist.
|
|
5
|
+
* Tables are prefixed with `_bashkit_` to avoid collisions with consumer tables.
|
|
6
|
+
*/
|
|
7
|
+
export declare function initSchema(sql: SqlStorage): void;
|
|
8
|
+
/**
|
|
9
|
+
* Get the stored sandbox ID from the session table.
|
|
10
|
+
* @returns The sandbox ID or null if no session exists.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getSandboxId(sql: SqlStorage): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Save or update the sandbox ID in the session table.
|
|
15
|
+
*/
|
|
16
|
+
export declare function saveSandboxId(sql: SqlStorage, sandboxId: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Update the session status.
|
|
19
|
+
*/
|
|
20
|
+
export declare function updateSessionStatus(sql: SqlStorage, status: "active" | "idle" | "disconnected"): void;
|
|
21
|
+
/**
|
|
22
|
+
* Get the current session row.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getSession(sql: SqlStorage): BashkitSessionRow | null;
|
|
25
|
+
/**
|
|
26
|
+
* Add a chunk to the stream buffer.
|
|
27
|
+
* Used to allow reconnecting clients to catch up on missed messages.
|
|
28
|
+
*/
|
|
29
|
+
export declare function addToStreamBuffer(sql: SqlStorage, chunk: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Get all buffered chunks, optionally since a specific timestamp.
|
|
32
|
+
* @param sinceTimestamp - Unix timestamp to get chunks after (exclusive)
|
|
33
|
+
*/
|
|
34
|
+
export declare function getStreamBuffer(sql: SqlStorage, sinceTimestamp?: number): BashkitStreamBufferRow[];
|
|
35
|
+
/**
|
|
36
|
+
* Get just the chunk strings from the buffer.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getBufferedChunks(sql: SqlStorage, sinceTimestamp?: number): string[];
|
|
39
|
+
/**
|
|
40
|
+
* Clear the stream buffer.
|
|
41
|
+
* Typically called after all clients have caught up.
|
|
42
|
+
*/
|
|
43
|
+
export declare function clearStreamBuffer(sql: SqlStorage): void;
|
|
44
|
+
/**
|
|
45
|
+
* Cleanup old chunks from the stream buffer based on options.
|
|
46
|
+
*/
|
|
47
|
+
export declare function cleanupStreamBuffer(sql: SqlStorage, options?: StreamBufferOptions): number;
|
|
48
|
+
/**
|
|
49
|
+
* Get the count of chunks in the stream buffer.
|
|
50
|
+
*/
|
|
51
|
+
export declare function getStreamBufferCount(sql: SqlStorage): number;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import type { Sandbox } from "../sandbox/interface";
|
|
2
|
+
/**
|
|
3
|
+
* Cloudflare Workers runtime types.
|
|
4
|
+
* These are minimal types to avoid requiring @cloudflare/workers-types as a hard dependency.
|
|
5
|
+
* Consumers using Cloudflare Workers will have full types from their own @cloudflare/workers-types.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* WebSocketPair for creating client/server WebSocket pairs.
|
|
9
|
+
* This is a Cloudflare Workers runtime global.
|
|
10
|
+
*/
|
|
11
|
+
export interface WebSocketPair {
|
|
12
|
+
0: WebSocket;
|
|
13
|
+
1: WebSocket;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Constructor for WebSocketPair.
|
|
17
|
+
*/
|
|
18
|
+
export interface WebSocketPairConstructor {
|
|
19
|
+
new (): WebSocketPair;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Extended ResponseInit that includes Cloudflare's webSocket property.
|
|
23
|
+
*/
|
|
24
|
+
export interface CloudflareResponseInit extends ResponseInit {
|
|
25
|
+
webSocket?: WebSocket;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Declare WebSocketPair on globalThis for Cloudflare Workers runtime.
|
|
29
|
+
*/
|
|
30
|
+
declare global {
|
|
31
|
+
var WebSocketPair: WebSocketPairConstructor | undefined;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Cloudflare Durable Object context types.
|
|
35
|
+
*/
|
|
36
|
+
export interface DurableObjectState {
|
|
37
|
+
id: DurableObjectId;
|
|
38
|
+
storage: DurableObjectStorage;
|
|
39
|
+
acceptWebSocket(ws: WebSocket): void;
|
|
40
|
+
getWebSockets(): WebSocket[];
|
|
41
|
+
}
|
|
42
|
+
export interface DurableObjectId {
|
|
43
|
+
toString(): string;
|
|
44
|
+
name?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface DurableObjectStorage {
|
|
47
|
+
sql: SqlStorage;
|
|
48
|
+
}
|
|
49
|
+
export interface SqlStorage {
|
|
50
|
+
exec<T = Record<string, unknown>>(query: string, ...params: unknown[]): SqlStorageCursor<T>;
|
|
51
|
+
}
|
|
52
|
+
export interface SqlStorageCursor<T = Record<string, unknown>> {
|
|
53
|
+
toArray(): T[];
|
|
54
|
+
one(): T | null;
|
|
55
|
+
raw(): unknown[][];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Configuration for creating a durable session.
|
|
59
|
+
* @template TContext - Custom context type that consumers can extend
|
|
60
|
+
*/
|
|
61
|
+
export interface DurableSessionConfig<TContext = unknown> {
|
|
62
|
+
/**
|
|
63
|
+
* Name of the durable session (used for identification/logging).
|
|
64
|
+
*/
|
|
65
|
+
name: string;
|
|
66
|
+
/**
|
|
67
|
+
* Sandbox lifecycle configuration.
|
|
68
|
+
*/
|
|
69
|
+
sandbox: {
|
|
70
|
+
/**
|
|
71
|
+
* Create a new sandbox instance.
|
|
72
|
+
* Called when no existing sandbox ID is found in storage.
|
|
73
|
+
*/
|
|
74
|
+
create: () => Promise<Sandbox>;
|
|
75
|
+
/**
|
|
76
|
+
* Reconnect to an existing sandbox by ID.
|
|
77
|
+
* Called when a sandbox ID is found in storage.
|
|
78
|
+
*/
|
|
79
|
+
reconnect: (sandboxId: string) => Promise<Sandbox>;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Called when a new session starts (first connection, no existing sandbox).
|
|
83
|
+
* Use this to hydrate the sandbox with files, setup environment, etc.
|
|
84
|
+
*/
|
|
85
|
+
onSessionStart?: (ctx: SessionContext<TContext>) => Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Called when a message is received from any connected client.
|
|
88
|
+
* This is where you implement your agent logic.
|
|
89
|
+
*/
|
|
90
|
+
onMessage: (ctx: MessageContext<TContext>) => Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Called when the last client disconnects.
|
|
93
|
+
* Use this for cleanup, snapshotting, etc.
|
|
94
|
+
*/
|
|
95
|
+
onDisconnect?: (ctx: SessionContext<TContext>) => Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Called when a client reconnects to an existing session.
|
|
98
|
+
* Use this to send catch-up data to the reconnecting client.
|
|
99
|
+
*/
|
|
100
|
+
onReconnect?: (ctx: ReconnectContext<TContext>) => Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* Optional context factory. Called once per session to create custom context.
|
|
103
|
+
*/
|
|
104
|
+
createContext?: (sessionId: string) => TContext | Promise<TContext>;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Base context available in all lifecycle hooks.
|
|
108
|
+
*/
|
|
109
|
+
export interface SessionContext<TContext = unknown> {
|
|
110
|
+
/**
|
|
111
|
+
* The sandbox instance (created or reconnected).
|
|
112
|
+
*/
|
|
113
|
+
sandbox: Sandbox;
|
|
114
|
+
/**
|
|
115
|
+
* Durable Object's SQLite storage for custom data.
|
|
116
|
+
* bashkit manages internal tables prefixed with `_bashkit_`.
|
|
117
|
+
*/
|
|
118
|
+
sql: SqlStorage;
|
|
119
|
+
/**
|
|
120
|
+
* Unique session identifier (Durable Object ID).
|
|
121
|
+
*/
|
|
122
|
+
sessionId: string;
|
|
123
|
+
/**
|
|
124
|
+
* Custom context created by `createContext` config.
|
|
125
|
+
*/
|
|
126
|
+
context: TContext;
|
|
127
|
+
/**
|
|
128
|
+
* Broadcast a message to all connected clients.
|
|
129
|
+
*/
|
|
130
|
+
broadcast: (message: unknown) => void;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Context available in the `onMessage` handler.
|
|
134
|
+
*/
|
|
135
|
+
export interface MessageContext<TContext = unknown> extends SessionContext<TContext> {
|
|
136
|
+
/**
|
|
137
|
+
* The message received from the client.
|
|
138
|
+
*/
|
|
139
|
+
message: unknown;
|
|
140
|
+
/**
|
|
141
|
+
* The WebSocket connection that sent the message.
|
|
142
|
+
*/
|
|
143
|
+
connection: WebSocket;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Context available in the `onReconnect` handler.
|
|
147
|
+
*/
|
|
148
|
+
export interface ReconnectContext<TContext = unknown> extends SessionContext<TContext> {
|
|
149
|
+
/**
|
|
150
|
+
* The WebSocket connection that is reconnecting.
|
|
151
|
+
*/
|
|
152
|
+
connection: WebSocket;
|
|
153
|
+
/**
|
|
154
|
+
* Buffered chunks from the stream buffer (if any).
|
|
155
|
+
* These are messages that were broadcast while this client was disconnected.
|
|
156
|
+
*/
|
|
157
|
+
bufferedChunks: string[];
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Internal session state stored in SQLite.
|
|
161
|
+
*/
|
|
162
|
+
export interface BashkitSessionRow {
|
|
163
|
+
id: number;
|
|
164
|
+
sandbox_id: string | null;
|
|
165
|
+
status: "active" | "idle" | "disconnected";
|
|
166
|
+
created_at: number;
|
|
167
|
+
updated_at: number;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Internal stream buffer row stored in SQLite.
|
|
171
|
+
*/
|
|
172
|
+
export interface BashkitStreamBufferRow {
|
|
173
|
+
id: number;
|
|
174
|
+
chunk: string;
|
|
175
|
+
created_at: number;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Options for buffering stream chunks.
|
|
179
|
+
*/
|
|
180
|
+
export interface StreamBufferOptions {
|
|
181
|
+
/**
|
|
182
|
+
* Maximum number of chunks to keep in the buffer.
|
|
183
|
+
* Older chunks are deleted when this limit is exceeded.
|
|
184
|
+
* @default 1000
|
|
185
|
+
*/
|
|
186
|
+
maxChunks?: number;
|
|
187
|
+
/**
|
|
188
|
+
* Maximum age of chunks in seconds.
|
|
189
|
+
* Chunks older than this are deleted on cleanup.
|
|
190
|
+
* @default 300 (5 minutes)
|
|
191
|
+
*/
|
|
192
|
+
maxAgeSeconds?: number;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* The generated Durable Object class type.
|
|
196
|
+
*/
|
|
197
|
+
export interface DurableSessionClass {
|
|
198
|
+
new (state: DurableObjectState, env: unknown): DurableSessionInstance;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Instance of a generated Durable Session.
|
|
202
|
+
*/
|
|
203
|
+
export interface DurableSessionInstance {
|
|
204
|
+
fetch(request: Request): Promise<Response>;
|
|
205
|
+
webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void>;
|
|
206
|
+
webSocketClose(ws: WebSocket, code: number, reason: string, wasClean: boolean): Promise<void>;
|
|
207
|
+
webSocketError(ws: WebSocket, error: unknown): void;
|
|
208
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,8 +9,8 @@ export type { AgentConfig, AskUserConfig, CacheConfig, SkillConfig, ToolConfig,
|
|
|
9
9
|
export { DEFAULT_CONFIG } from "./types";
|
|
10
10
|
export type { CachedTool, CacheEntry, CacheOptions, CacheStats, CacheStore, RedisCacheStoreOptions, RedisClient, } from "./cache";
|
|
11
11
|
export { cached, createRedisCacheStore, LRUCacheStore } from "./cache";
|
|
12
|
-
export type { CompactConversationConfig, CompactConversationResult, CompactConversationState, ContextMetrics, ContextStatus, ContextStatusConfig, ContextStatusLevel, ModelContextLimit, PruneMessagesConfig, } from "./utils";
|
|
13
|
-
export { compactConversation, contextNeedsAttention, contextNeedsCompaction, createCompactConfig, estimateMessagesTokens, estimateMessageTokens, estimateTokens, getContextStatus, MODEL_CONTEXT_LIMITS, pruneMessagesByTokens, } from "./utils";
|
|
12
|
+
export type { CompactConversationConfig, CompactConversationResult, CompactConversationState, ContextMetrics, ContextStatus, ContextStatusConfig, ContextStatusLevel, DebugEvent, ModelContextLimit, PruneMessagesConfig, } from "./utils";
|
|
13
|
+
export { clearDebugLogs, compactConversation, contextNeedsAttention, contextNeedsCompaction, createCompactConfig, estimateMessagesTokens, estimateMessageTokens, estimateTokens, getContextStatus, getDebugLogs, isDebugEnabled, MODEL_CONTEXT_LIMITS, pruneMessagesByTokens, reinitDebugMode, } from "./utils";
|
|
14
14
|
export type { DiscoverSkillsOptions, SkillBundle, SkillMetadata, } from "./skills";
|
|
15
15
|
export { discoverSkills, fetchSkill, fetchSkills, loadSkillBundle, loadSkillBundles, parseSkillMetadata, skillsToXml, } from "./skills";
|
|
16
16
|
export type { AgentEnvironmentConfig, SetupResult, SkillContent, } from "./setup";
|