deepagentsdk 0.9.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/LICENSE +21 -0
- package/README.md +159 -0
- package/package.json +95 -0
- package/src/agent.ts +1230 -0
- package/src/backends/composite.ts +273 -0
- package/src/backends/filesystem.ts +692 -0
- package/src/backends/index.ts +22 -0
- package/src/backends/local-sandbox.ts +175 -0
- package/src/backends/persistent.ts +593 -0
- package/src/backends/sandbox.ts +510 -0
- package/src/backends/state.ts +244 -0
- package/src/backends/utils.ts +287 -0
- package/src/checkpointer/file-saver.ts +98 -0
- package/src/checkpointer/index.ts +5 -0
- package/src/checkpointer/kv-saver.ts +82 -0
- package/src/checkpointer/memory-saver.ts +82 -0
- package/src/checkpointer/types.ts +125 -0
- package/src/cli/components/ApiKeyInput.tsx +300 -0
- package/src/cli/components/FilePreview.tsx +237 -0
- package/src/cli/components/Input.tsx +277 -0
- package/src/cli/components/Message.tsx +93 -0
- package/src/cli/components/ModelSelection.tsx +338 -0
- package/src/cli/components/SlashMenu.tsx +101 -0
- package/src/cli/components/StatusBar.tsx +89 -0
- package/src/cli/components/Subagent.tsx +91 -0
- package/src/cli/components/TodoList.tsx +133 -0
- package/src/cli/components/ToolApproval.tsx +70 -0
- package/src/cli/components/ToolCall.tsx +144 -0
- package/src/cli/components/ToolCallSummary.tsx +175 -0
- package/src/cli/components/Welcome.tsx +75 -0
- package/src/cli/components/index.ts +24 -0
- package/src/cli/hooks/index.ts +12 -0
- package/src/cli/hooks/useAgent.ts +933 -0
- package/src/cli/index.tsx +1066 -0
- package/src/cli/theme.ts +205 -0
- package/src/cli/utils/model-list.ts +365 -0
- package/src/constants/errors.ts +29 -0
- package/src/constants/limits.ts +195 -0
- package/src/index.ts +176 -0
- package/src/middleware/agent-memory.ts +330 -0
- package/src/prompts.ts +196 -0
- package/src/skills/index.ts +2 -0
- package/src/skills/load.ts +191 -0
- package/src/skills/types.ts +53 -0
- package/src/tools/execute.ts +167 -0
- package/src/tools/filesystem.ts +418 -0
- package/src/tools/index.ts +39 -0
- package/src/tools/subagent.ts +443 -0
- package/src/tools/todos.ts +101 -0
- package/src/tools/web.ts +567 -0
- package/src/types/backend.ts +177 -0
- package/src/types/core.ts +220 -0
- package/src/types/events.ts +429 -0
- package/src/types/index.ts +94 -0
- package/src/types/structured-output.ts +43 -0
- package/src/types/subagent.ts +96 -0
- package/src/types.ts +22 -0
- package/src/utils/approval.ts +213 -0
- package/src/utils/events.ts +416 -0
- package/src/utils/eviction.ts +181 -0
- package/src/utils/index.ts +34 -0
- package/src/utils/model-parser.ts +38 -0
- package/src/utils/patch-tool-calls.ts +233 -0
- package/src/utils/project-detection.ts +32 -0
- package/src/utils/summarization.ts +254 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for applying tool approval configuration.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { tool, type ToolSet } from "ai";
|
|
6
|
+
import type { InterruptOnConfig, DynamicApprovalConfig } from "../types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Callback type for requesting approval from the user.
|
|
10
|
+
*/
|
|
11
|
+
export type ApprovalCallback = (request: {
|
|
12
|
+
approvalId: string;
|
|
13
|
+
toolCallId: string;
|
|
14
|
+
toolName: string;
|
|
15
|
+
args: unknown;
|
|
16
|
+
}) => Promise<boolean>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Check if approval is needed based on config.
|
|
20
|
+
*/
|
|
21
|
+
async function checkNeedsApproval(
|
|
22
|
+
config: boolean | DynamicApprovalConfig,
|
|
23
|
+
args: unknown
|
|
24
|
+
): Promise<boolean> {
|
|
25
|
+
if (typeof config === "boolean") {
|
|
26
|
+
return config;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (config.shouldApprove) {
|
|
30
|
+
return config.shouldApprove(args);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Convert interruptOn config to needsApproval function for a tool.
|
|
38
|
+
*/
|
|
39
|
+
function configToNeedsApproval(
|
|
40
|
+
config: boolean | DynamicApprovalConfig
|
|
41
|
+
): boolean | ((args: unknown) => boolean | Promise<boolean>) {
|
|
42
|
+
if (typeof config === "boolean") {
|
|
43
|
+
return config;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (config.shouldApprove) {
|
|
47
|
+
return config.shouldApprove;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let approvalCounter = 0;
|
|
54
|
+
function generateApprovalId(): string {
|
|
55
|
+
return `approval-${Date.now()}-${++approvalCounter}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Apply interruptOn configuration to a toolset.
|
|
60
|
+
*
|
|
61
|
+
* This adds the `needsApproval` property to tools based on the config.
|
|
62
|
+
*
|
|
63
|
+
* @param tools - The original toolset
|
|
64
|
+
* @param interruptOn - Configuration mapping tool names to approval settings
|
|
65
|
+
* @returns New toolset with needsApproval applied
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const approvedTools = applyInterruptConfig(tools, {
|
|
70
|
+
* write_file: true,
|
|
71
|
+
* execute: { shouldApprove: (args) => args.command.includes('rm') },
|
|
72
|
+
* });
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export function applyInterruptConfig(
|
|
76
|
+
tools: ToolSet,
|
|
77
|
+
interruptOn?: InterruptOnConfig
|
|
78
|
+
): ToolSet {
|
|
79
|
+
if (!interruptOn) {
|
|
80
|
+
return tools;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const result: ToolSet = {};
|
|
84
|
+
|
|
85
|
+
for (const [name, tool] of Object.entries(tools)) {
|
|
86
|
+
const config = interruptOn[name];
|
|
87
|
+
|
|
88
|
+
if (config === undefined || config === false) {
|
|
89
|
+
// No approval needed - use tool as-is
|
|
90
|
+
result[name] = tool;
|
|
91
|
+
} else {
|
|
92
|
+
// Apply needsApproval
|
|
93
|
+
result[name] = {
|
|
94
|
+
...tool,
|
|
95
|
+
needsApproval: configToNeedsApproval(config),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Wrap tools with approval checking that intercepts execution.
|
|
105
|
+
*
|
|
106
|
+
* Unlike applyInterruptConfig which just sets needsApproval metadata,
|
|
107
|
+
* this actually wraps the execute function to request approval before running.
|
|
108
|
+
*
|
|
109
|
+
* If no approval callback is provided, tools requiring approval will be auto-denied.
|
|
110
|
+
*
|
|
111
|
+
* @param tools - The original toolset
|
|
112
|
+
* @param interruptOn - Configuration mapping tool names to approval settings
|
|
113
|
+
* @param onApprovalRequest - Callback to request approval from user (optional)
|
|
114
|
+
* @returns New toolset with wrapped execute functions
|
|
115
|
+
*/
|
|
116
|
+
export function wrapToolsWithApproval(
|
|
117
|
+
tools: ToolSet,
|
|
118
|
+
interruptOn: InterruptOnConfig | undefined,
|
|
119
|
+
onApprovalRequest: ApprovalCallback | undefined
|
|
120
|
+
): ToolSet {
|
|
121
|
+
if (!interruptOn) {
|
|
122
|
+
return tools;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const result: ToolSet = {};
|
|
126
|
+
|
|
127
|
+
for (const [name, existingTool] of Object.entries(tools)) {
|
|
128
|
+
const config = interruptOn[name];
|
|
129
|
+
|
|
130
|
+
if (config === undefined || config === false) {
|
|
131
|
+
// No approval needed - use tool as-is
|
|
132
|
+
result[name] = existingTool;
|
|
133
|
+
} else {
|
|
134
|
+
// Wrap the execute function with approval check
|
|
135
|
+
const originalExecute = existingTool.execute;
|
|
136
|
+
if (!originalExecute) {
|
|
137
|
+
// Tool has no execute function - skip wrapping
|
|
138
|
+
result[name] = existingTool;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Create a completely new tool using the AI SDK tool() function
|
|
143
|
+
// This ensures proper integration with AI SDK's execution mechanism
|
|
144
|
+
result[name] = tool({
|
|
145
|
+
description: existingTool.description,
|
|
146
|
+
inputSchema: existingTool.inputSchema,
|
|
147
|
+
execute: async (args, options) => {
|
|
148
|
+
// Check if this specific call needs approval
|
|
149
|
+
const needsApproval = await checkNeedsApproval(config, args);
|
|
150
|
+
|
|
151
|
+
if (needsApproval) {
|
|
152
|
+
// If no callback provided, auto-deny
|
|
153
|
+
if (!onApprovalRequest) {
|
|
154
|
+
return `Tool execution denied. No approval callback provided. The ${name} tool was not executed.`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Generate unique IDs for this approval request
|
|
158
|
+
const approvalId = generateApprovalId();
|
|
159
|
+
const toolCallId = options?.toolCallId || approvalId;
|
|
160
|
+
|
|
161
|
+
// Request approval from user
|
|
162
|
+
const approved = await onApprovalRequest({
|
|
163
|
+
approvalId,
|
|
164
|
+
toolCallId,
|
|
165
|
+
toolName: name,
|
|
166
|
+
args,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
if (!approved) {
|
|
170
|
+
// User denied - return an error message instead of executing
|
|
171
|
+
return `Tool execution denied by user. The ${name} tool was not executed.`;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Approved or no approval needed - execute the tool
|
|
176
|
+
return originalExecute(args, options);
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Check if a toolset has any tools requiring approval.
|
|
187
|
+
*/
|
|
188
|
+
export function hasApprovalTools(interruptOn?: InterruptOnConfig): boolean {
|
|
189
|
+
if (!interruptOn) return false;
|
|
190
|
+
return Object.values(interruptOn).some((v) => v !== false);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Create interrupt data for checkpoint when approval is requested.
|
|
195
|
+
*
|
|
196
|
+
* This is used to save checkpoint state when a tool requires approval,
|
|
197
|
+
* allowing the agent to resume from the interrupt point later.
|
|
198
|
+
*/
|
|
199
|
+
export function createInterruptData(
|
|
200
|
+
toolCallId: string,
|
|
201
|
+
toolName: string,
|
|
202
|
+
args: unknown,
|
|
203
|
+
step: number
|
|
204
|
+
): import("../checkpointer/types").InterruptData {
|
|
205
|
+
return {
|
|
206
|
+
toolCall: {
|
|
207
|
+
toolCallId,
|
|
208
|
+
toolName,
|
|
209
|
+
args,
|
|
210
|
+
},
|
|
211
|
+
step,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-safe event creation helpers for Deep Agent.
|
|
3
|
+
*
|
|
4
|
+
* These factory functions provide type-safe ways to create DeepAgentEvent objects,
|
|
5
|
+
* reducing duplication and ensuring event objects are correctly structured.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { createFileReadEvent, createToolCallEvent } from './utils/events';
|
|
10
|
+
*
|
|
11
|
+
* // Create events with type inference
|
|
12
|
+
* const fileEvent = createFileReadEvent('/path/to/file.ts', 100);
|
|
13
|
+
* const toolEvent = createToolCallEvent('read_file', { path: '/file.txt' }, 'call-123');
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type {
|
|
18
|
+
TextEvent,
|
|
19
|
+
StepStartEvent,
|
|
20
|
+
ToolCallEvent,
|
|
21
|
+
ToolResultEvent,
|
|
22
|
+
TodosChangedEvent,
|
|
23
|
+
FileWriteStartEvent,
|
|
24
|
+
FileWrittenEvent,
|
|
25
|
+
FileEditedEvent,
|
|
26
|
+
FileReadEvent,
|
|
27
|
+
LsEvent,
|
|
28
|
+
GlobEvent,
|
|
29
|
+
GrepEvent,
|
|
30
|
+
ExecuteStartEvent,
|
|
31
|
+
ExecuteFinishEvent,
|
|
32
|
+
WebSearchStartEvent,
|
|
33
|
+
WebSearchFinishEvent,
|
|
34
|
+
HttpRequestStartEvent,
|
|
35
|
+
HttpRequestFinishEvent,
|
|
36
|
+
FetchUrlStartEvent,
|
|
37
|
+
FetchUrlFinishEvent,
|
|
38
|
+
SubagentStartEvent,
|
|
39
|
+
SubagentFinishEvent,
|
|
40
|
+
SubagentStepEvent,
|
|
41
|
+
TextSegmentEvent,
|
|
42
|
+
UserMessageEvent,
|
|
43
|
+
DoneEvent,
|
|
44
|
+
ErrorEvent,
|
|
45
|
+
ApprovalRequestedEvent,
|
|
46
|
+
ApprovalResponseEvent,
|
|
47
|
+
CheckpointSavedEvent,
|
|
48
|
+
CheckpointLoadedEvent,
|
|
49
|
+
DeepAgentEvent,
|
|
50
|
+
DeepAgentState,
|
|
51
|
+
} from "../types";
|
|
52
|
+
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Basic Event Factories
|
|
55
|
+
// ============================================================================
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Create a text streaming event.
|
|
59
|
+
*/
|
|
60
|
+
export function createTextEvent(text: string): TextEvent {
|
|
61
|
+
return { type: "text", text };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create a step-start event.
|
|
66
|
+
*/
|
|
67
|
+
export function createStepStartEvent(stepNumber: number): StepStartEvent {
|
|
68
|
+
return { type: "step-start", stepNumber };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Create a tool-call event.
|
|
73
|
+
*/
|
|
74
|
+
export function createToolCallEvent(
|
|
75
|
+
toolName: string,
|
|
76
|
+
args: unknown,
|
|
77
|
+
toolCallId: string
|
|
78
|
+
): ToolCallEvent {
|
|
79
|
+
return { type: "tool-call", toolName, toolCallId, args };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Create a tool-result event.
|
|
84
|
+
*/
|
|
85
|
+
export function createToolResultEvent(
|
|
86
|
+
toolName: string,
|
|
87
|
+
toolCallId: string,
|
|
88
|
+
result: unknown
|
|
89
|
+
): ToolResultEvent {
|
|
90
|
+
return { type: "tool-result", toolName, toolCallId, result };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create a text-segment event (for CLI display).
|
|
95
|
+
*/
|
|
96
|
+
export function createTextSegmentEvent(text: string): TextSegmentEvent {
|
|
97
|
+
return { type: "text-segment", text };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Create a user-message event (for CLI history).
|
|
102
|
+
*/
|
|
103
|
+
export function createUserMessageEvent(content: string): UserMessageEvent {
|
|
104
|
+
return { type: "user-message", content };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Create a done event.
|
|
109
|
+
*/
|
|
110
|
+
export function createDoneEvent(
|
|
111
|
+
state: DeepAgentState,
|
|
112
|
+
options?: { text?: string; messages?: DoneEvent["messages"]; output?: DoneEvent["output"] }
|
|
113
|
+
): DoneEvent {
|
|
114
|
+
const event: DoneEvent = { type: "done", state, ...options };
|
|
115
|
+
return event;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Create an error event.
|
|
120
|
+
*/
|
|
121
|
+
export function createErrorEvent(error: Error): ErrorEvent {
|
|
122
|
+
return { type: "error", error };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ============================================================================
|
|
126
|
+
// Todo Event Factories
|
|
127
|
+
// ============================================================================
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Create a todos-changed event.
|
|
131
|
+
*/
|
|
132
|
+
export function createTodosChangedEvent(todos: TodosChangedEvent["todos"]): TodosChangedEvent {
|
|
133
|
+
return { type: "todos-changed", todos };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ============================================================================
|
|
137
|
+
// File Event Factories
|
|
138
|
+
// ============================================================================
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Create a file-write-start event (preview before write).
|
|
142
|
+
*/
|
|
143
|
+
export function createFileWriteStartEvent(
|
|
144
|
+
path: string,
|
|
145
|
+
content: string
|
|
146
|
+
): FileWriteStartEvent {
|
|
147
|
+
return { type: "file-write-start", path, content };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Create a file-written event (after successful write).
|
|
152
|
+
*/
|
|
153
|
+
export function createFileWrittenEvent(
|
|
154
|
+
path: string,
|
|
155
|
+
content: string
|
|
156
|
+
): FileWrittenEvent {
|
|
157
|
+
return { type: "file-written", path, content };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Create a file-edited event.
|
|
162
|
+
*/
|
|
163
|
+
export function createFileEditedEvent(
|
|
164
|
+
path: string,
|
|
165
|
+
occurrences: number
|
|
166
|
+
): FileEditedEvent {
|
|
167
|
+
return { type: "file-edited", path, occurrences };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Create a file-read event.
|
|
172
|
+
*/
|
|
173
|
+
export function createFileReadEvent(path: string, lines: number): FileReadEvent {
|
|
174
|
+
return { type: "file-read", path, lines };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ============================================================================
|
|
178
|
+
// Filesystem Operation Event Factories
|
|
179
|
+
// ============================================================================
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Create an ls (list) event.
|
|
183
|
+
*/
|
|
184
|
+
export function createLsEvent(path: string, count: number): LsEvent {
|
|
185
|
+
return { type: "ls", path, count };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Create a glob (pattern search) event.
|
|
190
|
+
*/
|
|
191
|
+
export function createGlobEvent(pattern: string, count: number): GlobEvent {
|
|
192
|
+
return { type: "glob", pattern, count };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Create a grep (content search) event.
|
|
197
|
+
*/
|
|
198
|
+
export function createGrepEvent(pattern: string, count: number): GrepEvent {
|
|
199
|
+
return { type: "grep", pattern, count };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ============================================================================
|
|
203
|
+
// Execute Event Factories
|
|
204
|
+
// ============================================================================
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Create an execute-start event.
|
|
208
|
+
*/
|
|
209
|
+
export function createExecuteStartEvent(
|
|
210
|
+
command: string,
|
|
211
|
+
sandboxId: string
|
|
212
|
+
): ExecuteStartEvent {
|
|
213
|
+
return { type: "execute-start", command, sandboxId };
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Create an execute-finish event.
|
|
218
|
+
*/
|
|
219
|
+
export function createExecuteFinishEvent(
|
|
220
|
+
command: string,
|
|
221
|
+
sandboxId: string,
|
|
222
|
+
exitCode: number | null,
|
|
223
|
+
truncated: boolean
|
|
224
|
+
): ExecuteFinishEvent {
|
|
225
|
+
return { type: "execute-finish", command, sandboxId, exitCode, truncated };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ============================================================================
|
|
229
|
+
// Web Event Factories
|
|
230
|
+
// ============================================================================
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Create a web-search-start event.
|
|
234
|
+
*/
|
|
235
|
+
export function createWebSearchStartEvent(query: string): WebSearchStartEvent {
|
|
236
|
+
return { type: "web-search-start", query };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Create a web-search-finish event.
|
|
241
|
+
*/
|
|
242
|
+
export function createWebSearchFinishEvent(
|
|
243
|
+
query: string,
|
|
244
|
+
resultCount: number
|
|
245
|
+
): WebSearchFinishEvent {
|
|
246
|
+
return { type: "web-search-finish", query, resultCount };
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Create an http-request-start event.
|
|
251
|
+
*/
|
|
252
|
+
export function createHttpRequestStartEvent(
|
|
253
|
+
url: string,
|
|
254
|
+
method: string
|
|
255
|
+
): HttpRequestStartEvent {
|
|
256
|
+
return { type: "http-request-start", url, method };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Create an http-request-finish event.
|
|
261
|
+
*/
|
|
262
|
+
export function createHttpRequestFinishEvent(
|
|
263
|
+
url: string,
|
|
264
|
+
statusCode: number
|
|
265
|
+
): HttpRequestFinishEvent {
|
|
266
|
+
return { type: "http-request-finish", url, statusCode };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Create a fetch-url-start event.
|
|
271
|
+
*/
|
|
272
|
+
export function createFetchUrlStartEvent(url: string): FetchUrlStartEvent {
|
|
273
|
+
return { type: "fetch-url-start", url };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Create a fetch-url-finish event.
|
|
278
|
+
*/
|
|
279
|
+
export function createFetchUrlFinishEvent(
|
|
280
|
+
url: string,
|
|
281
|
+
success: boolean
|
|
282
|
+
): FetchUrlFinishEvent {
|
|
283
|
+
return { type: "fetch-url-finish", url, success };
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ============================================================================
|
|
287
|
+
// Subagent Event Factories
|
|
288
|
+
// ============================================================================
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Create a subagent-start event.
|
|
292
|
+
*/
|
|
293
|
+
export function createSubagentStartEvent(
|
|
294
|
+
name: string,
|
|
295
|
+
task: string
|
|
296
|
+
): SubagentStartEvent {
|
|
297
|
+
return { type: "subagent-start", name, task };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Create a subagent-finish event.
|
|
302
|
+
*/
|
|
303
|
+
export function createSubagentFinishEvent(
|
|
304
|
+
name: string,
|
|
305
|
+
result: string
|
|
306
|
+
): SubagentFinishEvent {
|
|
307
|
+
return { type: "subagent-finish", name, result };
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Create a subagent-step event.
|
|
312
|
+
*/
|
|
313
|
+
export function createSubagentStepEvent(
|
|
314
|
+
stepIndex: number,
|
|
315
|
+
toolCalls: SubagentStepEvent["toolCalls"]
|
|
316
|
+
): SubagentStepEvent {
|
|
317
|
+
return { type: "subagent-step", stepIndex, toolCalls };
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// ============================================================================
|
|
321
|
+
// Approval Event Factories
|
|
322
|
+
// ============================================================================
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Create an approval-requested event.
|
|
326
|
+
*/
|
|
327
|
+
export function createApprovalRequestedEvent(
|
|
328
|
+
approvalId: string,
|
|
329
|
+
toolCallId: string,
|
|
330
|
+
toolName: string,
|
|
331
|
+
args: unknown
|
|
332
|
+
): ApprovalRequestedEvent {
|
|
333
|
+
return { type: "approval-requested", approvalId, toolCallId, toolName, args };
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Create an approval-response event.
|
|
338
|
+
*/
|
|
339
|
+
export function createApprovalResponseEvent(
|
|
340
|
+
approvalId: string,
|
|
341
|
+
approved: boolean
|
|
342
|
+
): ApprovalResponseEvent {
|
|
343
|
+
return { type: "approval-response", approvalId, approved };
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// ============================================================================
|
|
347
|
+
// Checkpoint Event Factories
|
|
348
|
+
// ============================================================================
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Create a checkpoint-saved event.
|
|
352
|
+
*/
|
|
353
|
+
export function createCheckpointSavedEvent(
|
|
354
|
+
threadId: string,
|
|
355
|
+
step: number
|
|
356
|
+
): CheckpointSavedEvent {
|
|
357
|
+
return { type: "checkpoint-saved", threadId, step };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Create a checkpoint-loaded event.
|
|
362
|
+
*/
|
|
363
|
+
export function createCheckpointLoadedEvent(
|
|
364
|
+
threadId: string,
|
|
365
|
+
step: number,
|
|
366
|
+
messagesCount: number
|
|
367
|
+
): CheckpointLoadedEvent {
|
|
368
|
+
return { type: "checkpoint-loaded", threadId, step, messagesCount };
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// ============================================================================
|
|
372
|
+
// Utility Functions
|
|
373
|
+
// ============================================================================
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Type guard to check if an event is a specific type.
|
|
377
|
+
* Useful for filtering or discriminating union types.
|
|
378
|
+
*
|
|
379
|
+
* @example
|
|
380
|
+
* ```typescript
|
|
381
|
+
* if (isEventType(event, "file-read")) {
|
|
382
|
+
* // TypeScript knows event is FileReadEvent here
|
|
383
|
+
* console.log(event.lines);
|
|
384
|
+
* }
|
|
385
|
+
* ```
|
|
386
|
+
*/
|
|
387
|
+
export function isEventType<T extends DeepAgentEvent["type"]>(
|
|
388
|
+
event: DeepAgentEvent,
|
|
389
|
+
type: T
|
|
390
|
+
): event is Extract<DeepAgentEvent, { type: T }> {
|
|
391
|
+
return event.type === type;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Get the event type as a string.
|
|
396
|
+
* Utility function for logging or debugging.
|
|
397
|
+
*/
|
|
398
|
+
export function getEventType(event: DeepAgentEvent): string {
|
|
399
|
+
return event.type;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Create a generic event object from a type and data.
|
|
404
|
+
* This is a more flexible but less type-safe alternative to the specific factories.
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* ```typescript
|
|
408
|
+
* const event = createEvent("file-read", { path: "/file.txt", lines: 100 });
|
|
409
|
+
* ```
|
|
410
|
+
*/
|
|
411
|
+
export function createEvent<T extends DeepAgentEvent>(
|
|
412
|
+
type: T["type"],
|
|
413
|
+
data: Omit<T, "type">
|
|
414
|
+
): T {
|
|
415
|
+
return { type, ...data } as T;
|
|
416
|
+
}
|