bashkit 0.3.0 → 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.
@@ -0,0 +1,42 @@
1
+ /**
2
+ * bashkit/react - React hooks for connecting to BashKit agents
3
+ *
4
+ * This module re-exports hooks from the Cloudflare Agents SDK for connecting
5
+ * to agents from React applications.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { useAgent, useAgentChat } from 'bashkit/react';
10
+ *
11
+ * function Chat() {
12
+ * // Connect to the agent
13
+ * const agent = useAgent({
14
+ * agent: 'my-agent',
15
+ * name: sessionId,
16
+ * });
17
+ *
18
+ * // Use the chat hook for AI conversations
19
+ * const { messages, input, handleSubmit, handleInputChange } = useAgentChat({
20
+ * agent,
21
+ * });
22
+ *
23
+ * return (
24
+ * <div>
25
+ * {messages.map((msg, i) => (
26
+ * <div key={i}>
27
+ * <strong>{msg.role}:</strong> {msg.content}
28
+ * </div>
29
+ * ))}
30
+ * <form onSubmit={handleSubmit}>
31
+ * <input value={input} onChange={handleInputChange} />
32
+ * <button type="submit">Send</button>
33
+ * </form>
34
+ * </div>
35
+ * );
36
+ * }
37
+ * ```
38
+ */
39
+ export { useAgent } from "agents/react";
40
+ export { useAgentChat } from "agents/ai-react";
41
+ export { AgentClient, agentFetch } from "agents/client";
42
+ export type { UseAgentOptions } from "agents/react";
@@ -0,0 +1,10 @@
1
+ // src/react/index.ts
2
+ import { useAgent } from "agents/react";
3
+ import { useAgentChat } from "agents/ai-react";
4
+ import { AgentClient, agentFetch } from "agents/client";
5
+ export {
6
+ useAgentChat,
7
+ useAgent,
8
+ agentFetch,
9
+ AgentClient
10
+ };
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Connection status for the agent WebSocket.
3
+ */
4
+ export type ConnectionStatus = "connecting" | "connected" | "disconnected" | "reconnecting";
5
+ /**
6
+ * Configuration for the useAgent hook.
7
+ */
8
+ export interface UseAgentConfig<TMessage = unknown> {
9
+ /**
10
+ * The WebSocket URL to connect to.
11
+ * Should be your Cloudflare Worker URL.
12
+ */
13
+ url: string;
14
+ /**
15
+ * The session ID to connect to.
16
+ * Each session ID maps to a separate Durable Object.
17
+ */
18
+ sessionId: string;
19
+ /**
20
+ * Called when a message is received from the server.
21
+ */
22
+ onMessage?: (message: TMessage) => void;
23
+ /**
24
+ * Called when the connection is established.
25
+ */
26
+ onConnect?: () => void;
27
+ /**
28
+ * Called when the connection is closed.
29
+ */
30
+ onDisconnect?: (event: CloseEvent) => void;
31
+ /**
32
+ * Called when an error occurs.
33
+ */
34
+ onError?: (error: Event) => void;
35
+ /**
36
+ * Called when reconnecting with buffered content.
37
+ * The buffered content is sent by the server's onReconnect handler.
38
+ */
39
+ onReconnect?: (bufferedChunks: string[]) => void;
40
+ /**
41
+ * Whether to automatically reconnect on disconnect.
42
+ * @default true
43
+ */
44
+ autoReconnect?: boolean;
45
+ /**
46
+ * Delay in milliseconds before attempting to reconnect.
47
+ * @default 1000
48
+ */
49
+ reconnectDelay?: number;
50
+ /**
51
+ * Maximum number of reconnection attempts.
52
+ * @default 5
53
+ */
54
+ maxReconnectAttempts?: number;
55
+ /**
56
+ * Whether the hook should connect immediately.
57
+ * Set to false to manually control connection via `connect()`.
58
+ * @default true
59
+ */
60
+ enabled?: boolean;
61
+ }
62
+ /**
63
+ * Return type of the useAgent hook.
64
+ */
65
+ export interface UseAgentReturn<TMessage = unknown> {
66
+ /**
67
+ * Current connection status.
68
+ */
69
+ status: ConnectionStatus;
70
+ /**
71
+ * Whether the WebSocket is currently connected.
72
+ */
73
+ isConnected: boolean;
74
+ /**
75
+ * Accumulated messages received from the server.
76
+ */
77
+ messages: TMessage[];
78
+ /**
79
+ * Send a message to the server.
80
+ */
81
+ sendMessage: (message: unknown) => void;
82
+ /**
83
+ * Manually connect to the server.
84
+ * Only needed if `enabled: false` was passed.
85
+ */
86
+ connect: () => void;
87
+ /**
88
+ * Manually disconnect from the server.
89
+ */
90
+ disconnect: () => void;
91
+ /**
92
+ * Clear all accumulated messages.
93
+ */
94
+ clearMessages: () => void;
95
+ /**
96
+ * The raw WebSocket instance (for advanced use).
97
+ */
98
+ socket: WebSocket | null;
99
+ /**
100
+ * Number of reconnection attempts made.
101
+ */
102
+ reconnectAttempts: number;
103
+ /**
104
+ * Any error that occurred during connection.
105
+ */
106
+ error: Event | null;
107
+ }
108
+ /**
109
+ * Options for individual message sending.
110
+ */
111
+ export interface SendMessageOptions {
112
+ /**
113
+ * Whether to wait for connection before sending.
114
+ * If true, the message will be queued and sent when connected.
115
+ * @default false
116
+ */
117
+ queue?: boolean;
118
+ }
119
+ /**
120
+ * Message types commonly sent between client and server.
121
+ */
122
+ export interface AgentMessage<T = unknown> {
123
+ type: string;
124
+ data?: T;
125
+ timestamp?: number;
126
+ }
127
+ /**
128
+ * Common message types for agent communication.
129
+ */
130
+ export interface ChunkMessage {
131
+ type: "chunk";
132
+ text: string;
133
+ }
134
+ export interface StatusMessage {
135
+ type: "status";
136
+ status: "thinking" | "executing" | "idle";
137
+ }
138
+ export interface ErrorMessage {
139
+ type: "error";
140
+ error: string;
141
+ message?: string;
142
+ }
143
+ export interface ReconnectMessage {
144
+ type: "reconnect";
145
+ bufferedChunks: string[];
146
+ }
147
+ export interface StateMessage<T = unknown> {
148
+ type: "state";
149
+ data: T;
150
+ }
151
+ /**
152
+ * Union of common message types.
153
+ */
154
+ export type CommonAgentMessage<T = unknown> = ChunkMessage | StatusMessage | ErrorMessage | ReconnectMessage | StateMessage<T>;
155
+ /**
156
+ * Status of the chat generation.
157
+ * Matches Vercel AI SDK useChat status values.
158
+ */
159
+ export type DurableChatStatus = "ready" | "submitted" | "streaming" | "error";
160
+ /**
161
+ * A part of a chat message (text, tool call, or tool result).
162
+ * Matches Vercel AI SDK UIMessagePart structure.
163
+ */
164
+ export type DurableChatPart = {
165
+ type: "text";
166
+ text: string;
167
+ } | {
168
+ type: "tool-call";
169
+ toolCallId: string;
170
+ toolName: string;
171
+ args: unknown;
172
+ } | {
173
+ type: "tool-result";
174
+ toolCallId: string;
175
+ toolName: string;
176
+ result: unknown;
177
+ };
178
+ /**
179
+ * A chat message with parts.
180
+ * Matches Vercel AI SDK UIMessage structure.
181
+ */
182
+ export interface DurableChatMessage {
183
+ id: string;
184
+ role: "user" | "assistant" | "system";
185
+ parts: DurableChatPart[];
186
+ createdAt?: Date;
187
+ metadata?: unknown;
188
+ }
189
+ /**
190
+ * Server-to-client message types for streaming chat.
191
+ */
192
+ export type ServerMessage = {
193
+ type: "message-start";
194
+ id: string;
195
+ role: "assistant" | "system";
196
+ } | {
197
+ type: "text-delta";
198
+ text: string;
199
+ } | {
200
+ type: "tool-call";
201
+ toolCallId: string;
202
+ toolName: string;
203
+ args: unknown;
204
+ } | {
205
+ type: "tool-result";
206
+ toolCallId: string;
207
+ toolName: string;
208
+ result: unknown;
209
+ } | {
210
+ type: "message-end";
211
+ } | {
212
+ type: "error";
213
+ error: string;
214
+ } | {
215
+ type: "aborted";
216
+ };
217
+ /**
218
+ * Client-to-server message types.
219
+ */
220
+ export type ClientMessage = {
221
+ type: "chat";
222
+ content: string;
223
+ metadata?: unknown;
224
+ [key: string]: unknown;
225
+ } | {
226
+ type: "abort";
227
+ } | {
228
+ type: "regenerate";
229
+ messageId?: string;
230
+ };
231
+ /**
232
+ * Configuration for the useDurableChat hook.
233
+ */
234
+ export interface UseDurableChatConfig {
235
+ /**
236
+ * The WebSocket URL to connect to.
237
+ */
238
+ url: string;
239
+ /**
240
+ * The session ID for the chat.
241
+ */
242
+ sessionId: string;
243
+ /**
244
+ * Called when any server message is received.
245
+ */
246
+ onMessage?: (message: ServerMessage) => void;
247
+ /**
248
+ * Called when an assistant message is complete.
249
+ */
250
+ onFinish?: (message: DurableChatMessage) => void;
251
+ /**
252
+ * Called when an error occurs.
253
+ */
254
+ onError?: (error: Error) => void;
255
+ /**
256
+ * Whether the hook should connect immediately.
257
+ * @default true
258
+ */
259
+ enabled?: boolean;
260
+ }
261
+ /**
262
+ * Return type of the useDurableChat hook.
263
+ * API mirrors Vercel AI SDK useChat for familiarity.
264
+ */
265
+ export interface UseDurableChatReturn {
266
+ /**
267
+ * The array of chat messages.
268
+ */
269
+ messages: DurableChatMessage[];
270
+ /**
271
+ * Current status of the chat generation.
272
+ */
273
+ status: DurableChatStatus;
274
+ /**
275
+ * Error if one occurred.
276
+ */
277
+ error: Error | null;
278
+ /**
279
+ * Whether the assistant is currently streaming a response.
280
+ */
281
+ isStreaming: boolean;
282
+ /**
283
+ * Whether a request is in progress (submitted or streaming).
284
+ */
285
+ isLoading: boolean;
286
+ /**
287
+ * Send a message to the chat.
288
+ */
289
+ sendMessage: (content: string | {
290
+ text: string;
291
+ [key: string]: unknown;
292
+ }, options?: {
293
+ body?: Record<string, unknown>;
294
+ }) => void;
295
+ /**
296
+ * Stop/abort the current generation.
297
+ */
298
+ stop: () => void;
299
+ /**
300
+ * Regenerate the last assistant message or a specific message.
301
+ */
302
+ regenerate: (options?: {
303
+ messageId?: string;
304
+ }) => void;
305
+ /**
306
+ * Update messages locally without sending to server.
307
+ */
308
+ setMessages: React.Dispatch<React.SetStateAction<DurableChatMessage[]>>;
309
+ /**
310
+ * Clear all messages.
311
+ */
312
+ clearMessages: () => void;
313
+ /**
314
+ * Clear the error state.
315
+ */
316
+ clearError: () => void;
317
+ /**
318
+ * WebSocket connection status.
319
+ */
320
+ connectionStatus: ConnectionStatus;
321
+ /**
322
+ * Whether the WebSocket is connected.
323
+ */
324
+ isConnected: boolean;
325
+ /**
326
+ * Manually connect to the server.
327
+ */
328
+ connect: () => void;
329
+ /**
330
+ * Manually disconnect from the server.
331
+ */
332
+ disconnect: () => void;
333
+ }
@@ -0,0 +1,33 @@
1
+ import type { UseAgentConfig, UseAgentReturn } from "./types";
2
+ /**
3
+ * React hook for connecting to a bashkit durable agent session.
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * import { useAgent } from 'bashkit/react';
8
+ *
9
+ * function ChatUI() {
10
+ * const {
11
+ * status,
12
+ * messages,
13
+ * sendMessage,
14
+ * isConnected,
15
+ * } = useAgent({
16
+ * url: 'https://my-agent.workers.dev',
17
+ * sessionId: 'conversation-123',
18
+ * onMessage: (msg) => console.log('Received:', msg),
19
+ * });
20
+ *
21
+ * return (
22
+ * <div>
23
+ * <p>Status: {status}</p>
24
+ * {messages.map((msg, i) => <div key={i}>{JSON.stringify(msg)}</div>)}
25
+ * <button onClick={() => sendMessage({ type: 'chat', text: 'Hello!' })}>
26
+ * Send
27
+ * </button>
28
+ * </div>
29
+ * );
30
+ * }
31
+ * ```
32
+ */
33
+ export declare function useAgent<TMessage = unknown>(config: UseAgentConfig<TMessage>): UseAgentReturn<TMessage>;
@@ -0,0 +1,39 @@
1
+ import type { UseDurableChatConfig, UseDurableChatReturn } from "./types";
2
+ /**
3
+ * React hook for durable chat sessions with streaming support.
4
+ * Provides a similar API to Vercel AI SDK's useChat but over WebSockets
5
+ * with durable session support.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { useDurableChat } from 'bashkit/react';
10
+ *
11
+ * function Chat() {
12
+ * const {
13
+ * messages,
14
+ * status,
15
+ * sendMessage,
16
+ * stop,
17
+ * isStreaming,
18
+ * } = useDurableChat({
19
+ * url: 'https://my-agent.workers.dev',
20
+ * sessionId: 'conversation-123',
21
+ * });
22
+ *
23
+ * return (
24
+ * <div>
25
+ * {messages.map(msg => (
26
+ * <div key={msg.id}>
27
+ * <strong>{msg.role}:</strong>
28
+ * {msg.parts.map((part, i) => (
29
+ * part.type === 'text' ? <span key={i}>{part.text}</span> : null
30
+ * ))}
31
+ * </div>
32
+ * ))}
33
+ * <button onClick={stop} disabled={!isStreaming}>Stop</button>
34
+ * </div>
35
+ * );
36
+ * }
37
+ * ```
38
+ */
39
+ export declare function useDurableChat(config: UseDurableChatConfig): UseDurableChatReturn;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Dynamically imports @vscode/ripgrep to get the bundled binary path.
3
+ * Returns undefined if the package is not installed.
4
+ */
5
+ export declare function getBundledRgPath(): Promise<string | undefined>;
6
+ /**
7
+ * Synchronously gets the bundled ripgrep path using require.
8
+ * For use in synchronous contexts (e.g., LocalSandbox).
9
+ * Returns undefined if the package is not installed.
10
+ */
11
+ export declare function getBundledRgPathSync(): string | undefined;
@@ -43,8 +43,10 @@ export interface SubagentTypeConfig {
43
43
  systemPrompt?: string;
44
44
  /** Tool names this subagent can use (filters from parent tools) */
45
45
  tools?: string[];
46
- /** Stop condition for this subagent (default: stepCountIs(15)) */
47
- stopWhen?: StopCondition<ToolSet>;
46
+ /** Additional tools only this subagent can use (merged with filtered tools) */
47
+ additionalTools?: ToolSet;
48
+ /** Stop condition(s) for this subagent (default: stepCountIs(15)). Can be a single condition or array - stops when ANY condition is met. */
49
+ stopWhen?: StopCondition<ToolSet> | StopCondition<ToolSet>[];
48
50
  /** Prepare step callback for dynamic control per step */
49
51
  prepareStep?: PrepareStepFunction<ToolSet>;
50
52
  /** Callback for each step this subagent takes */
@@ -57,8 +59,8 @@ export interface TaskToolConfig {
57
59
  tools: ToolSet;
58
60
  /** Configuration for each subagent type */
59
61
  subagentTypes?: Record<string, SubagentTypeConfig>;
60
- /** Default stop condition for subagents (default: stepCountIs(15)) */
61
- defaultStopWhen?: StopCondition<ToolSet>;
62
+ /** Default stop condition(s) for subagents (default: stepCountIs(15)). Can be a single condition or array - stops when ANY condition is met. */
63
+ defaultStopWhen?: StopCondition<ToolSet> | StopCondition<ToolSet>[];
62
64
  /** Default callback for each step any subagent takes */
63
65
  defaultOnStepFinish?: (event: SubagentStepEvent) => void | Promise<void>;
64
66
  /** Optional stream writer for real-time subagent activity (uses streamText instead of generateText) */
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Debug logging utilities for bashkit tools.
3
+ *
4
+ * Enable debug logging via environment variable:
5
+ * - BASHKIT_DEBUG=1 or BASHKIT_DEBUG=stderr - Human readable output to stderr
6
+ * - BASHKIT_DEBUG=json - JSON lines to stderr
7
+ * - BASHKIT_DEBUG=memory - In-memory array (retrieve via getDebugLogs())
8
+ * - BASHKIT_DEBUG=file:/path/to/trace.jsonl - Write to file
9
+ */
10
+ /** Debug event structure for tool execution tracing */
11
+ export interface DebugEvent {
12
+ /** Unique ID to correlate start/end events (e.g., "grep-1") */
13
+ id: string;
14
+ /** Timestamp in milliseconds */
15
+ ts: number;
16
+ /** Tool name */
17
+ tool: string;
18
+ /** Event type */
19
+ event: "start" | "end" | "error";
20
+ /** Input parameters (start events only, summarized) */
21
+ input?: unknown;
22
+ /** Output data (end events only, summarized) */
23
+ output?: unknown;
24
+ /** Key metrics like exitCode, matchCount, etc. */
25
+ summary?: Record<string, unknown>;
26
+ /** Duration in milliseconds (end events only) */
27
+ duration_ms?: number;
28
+ /** Parent event ID for nested tool calls (e.g., task → subagent tools) */
29
+ parent?: string;
30
+ /** Error message (error events only) */
31
+ error?: string;
32
+ }
33
+ /**
34
+ * Checks if debug mode is enabled (any mode except "off").
35
+ */
36
+ export declare function isDebugEnabled(): boolean;
37
+ /**
38
+ * Summarize data for debug output.
39
+ * - Truncates strings to 1000 chars
40
+ * - Limits arrays to 10 items
41
+ * - Recursively summarizes nested objects
42
+ */
43
+ export declare function summarize(data: unknown, depth?: number): unknown;
44
+ /**
45
+ * Record the start of a tool execution.
46
+ * @returns Event ID to correlate with debugEnd/debugError
47
+ */
48
+ export declare function debugStart(tool: string, input?: Record<string, unknown>): string;
49
+ /**
50
+ * Record the successful end of a tool execution.
51
+ */
52
+ export declare function debugEnd(id: string, tool: string, options: {
53
+ output?: unknown;
54
+ summary?: Record<string, unknown>;
55
+ duration_ms: number;
56
+ }): void;
57
+ /**
58
+ * Record an error during tool execution.
59
+ */
60
+ export declare function debugError(id: string, tool: string, error: string | Error): void;
61
+ /**
62
+ * Push a parent context for nested tool calls (e.g., when Task starts a subagent).
63
+ */
64
+ export declare function pushParent(id: string): void;
65
+ /**
66
+ * Pop the current parent context.
67
+ */
68
+ export declare function popParent(): void;
69
+ /**
70
+ * Get all debug logs (memory mode only).
71
+ * @returns Array of debug events, or empty array if not in memory mode
72
+ */
73
+ export declare function getDebugLogs(): DebugEvent[];
74
+ /**
75
+ * Clear all debug logs (memory mode).
76
+ * Call this between agent runs to reset the trace.
77
+ */
78
+ export declare function clearDebugLogs(): void;
79
+ /**
80
+ * Force re-initialization of debug mode from environment.
81
+ * Useful for testing or when environment changes.
82
+ */
83
+ export declare function reinitDebugMode(): void;
@@ -1,3 +1,4 @@
1
1
  export { type CompactConversationConfig, type CompactConversationResult, type CompactConversationState, compactConversation, createCompactConfig, MODEL_CONTEXT_LIMITS, type ModelContextLimit, } from "./compact-conversation";
2
2
  export { type ContextMetrics, type ContextStatus, type ContextStatusConfig, type ContextStatusLevel, contextNeedsAttention, contextNeedsCompaction, getContextStatus, } from "./context-status";
3
+ export { type DebugEvent, clearDebugLogs, getDebugLogs, isDebugEnabled, reinitDebugMode, } from "./debug";
3
4
  export { estimateMessagesTokens, estimateMessageTokens, estimateTokens, type PruneMessagesConfig, pruneMessagesByTokens, } from "./prune-messages";
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Bashkit Workflow Integration
3
+ *
4
+ * Durable agent tools for Vercel's Workflow DevKit.
5
+ * Each tool execution is wrapped with "use step" for automatic
6
+ * durability, retries, and checkpointing.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { createDurableAgentTools } from 'bashkit/workflow';
11
+ * import { DurableAgent } from '@workflow/ai/agent';
12
+ *
13
+ * export async function generateReport(sandboxId: string) {
14
+ * "use workflow";
15
+ *
16
+ * const { tools } = createDurableAgentTools(sandboxId);
17
+ *
18
+ * const agent = new DurableAgent({
19
+ * model: "anthropic/claude-sonnet-4-20250514",
20
+ * tools,
21
+ * });
22
+ *
23
+ * await agent.run({ prompt: "Generate the report" });
24
+ * }
25
+ * ```
26
+ */
27
+ import { type ToolSet } from "ai";
28
+ import type { AgentConfig } from "./types";
29
+ export interface DurableAgentConfig extends Omit<AgentConfig, "cache"> {
30
+ /**
31
+ * E2B API key (optional, uses ANTHROPIC_API_KEY env var by default)
32
+ */
33
+ apiKey?: string;
34
+ }
35
+ export interface DurableAgentToolsResult {
36
+ tools: ToolSet;
37
+ }
38
+ /**
39
+ * Creates durable agent tools for Workflow DevKit.
40
+ *
41
+ * Each tool execution:
42
+ * 1. Is wrapped with "use step" for durability
43
+ * 2. Reconnects to the E2B sandbox via sandboxId
44
+ * 3. Can retry independently on failure
45
+ * 4. Works with parallel tool calls (each gets own correlationId)
46
+ *
47
+ * @param sandboxId - E2B sandbox ID to reconnect to
48
+ * @param config - Optional tool configuration
49
+ */
50
+ export declare function createDurableAgentTools(sandboxId: string, config?: DurableAgentConfig): DurableAgentToolsResult;
51
+ export type { Sandbox } from "./sandbox/interface";
52
+ export type { ToolConfig, AgentConfig } from "./types";