@posthog/agent 1.7.1 → 1.10.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.
Files changed (54) hide show
  1. package/README.md +8 -5
  2. package/dist/index.d.ts +5 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +2 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/src/adapters/claude/claude-adapter.d.ts +17 -0
  7. package/dist/src/adapters/claude/claude-adapter.d.ts.map +1 -0
  8. package/dist/src/{event-transformer.js → adapters/claude/claude-adapter.js} +34 -10
  9. package/dist/src/adapters/claude/claude-adapter.js.map +1 -0
  10. package/dist/src/adapters/claude/tool-mapper.d.ts +19 -0
  11. package/dist/src/adapters/claude/tool-mapper.d.ts.map +1 -0
  12. package/dist/src/adapters/claude/tool-mapper.js +44 -0
  13. package/dist/src/adapters/claude/tool-mapper.js.map +1 -0
  14. package/dist/src/adapters/types.d.ts +28 -0
  15. package/dist/src/adapters/types.d.ts.map +1 -0
  16. package/dist/src/agent.d.ts +1 -1
  17. package/dist/src/agent.d.ts.map +1 -1
  18. package/dist/src/agent.js +61 -44
  19. package/dist/src/agent.js.map +1 -1
  20. package/dist/src/posthog-api.d.ts +16 -57
  21. package/dist/src/posthog-api.d.ts.map +1 -1
  22. package/dist/src/posthog-api.js +38 -38
  23. package/dist/src/posthog-api.js.map +1 -1
  24. package/dist/src/stage-executor.d.ts +1 -1
  25. package/dist/src/stage-executor.d.ts.map +1 -1
  26. package/dist/src/stage-executor.js +7 -7
  27. package/dist/src/stage-executor.js.map +1 -1
  28. package/dist/src/task-progress-reporter.d.ts +2 -7
  29. package/dist/src/task-progress-reporter.d.ts.map +1 -1
  30. package/dist/src/task-progress-reporter.js +37 -55
  31. package/dist/src/task-progress-reporter.js.map +1 -1
  32. package/dist/src/tools/registry.d.ts +25 -0
  33. package/dist/src/tools/registry.d.ts.map +1 -0
  34. package/dist/src/tools/registry.js +120 -0
  35. package/dist/src/tools/registry.js.map +1 -0
  36. package/dist/src/tools/types.d.ts +80 -0
  37. package/dist/src/tools/types.d.ts.map +1 -0
  38. package/dist/src/types.d.ts +65 -15
  39. package/dist/src/types.d.ts.map +1 -1
  40. package/dist/src/types.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/{event-transformer.ts → adapters/claude/claude-adapter.ts} +40 -16
  43. package/src/adapters/claude/tool-mapper.ts +46 -0
  44. package/src/adapters/types.ts +31 -0
  45. package/src/agent.ts +64 -41
  46. package/src/posthog-api.ts +57 -92
  47. package/src/stage-executor.ts +11 -11
  48. package/src/task-progress-reporter.ts +38 -63
  49. package/src/tools/registry.ts +129 -0
  50. package/src/tools/types.ts +127 -0
  51. package/src/types.ts +73 -20
  52. package/dist/src/event-transformer.d.ts +0 -10
  53. package/dist/src/event-transformer.d.ts.map +0 -1
  54. package/dist/src/event-transformer.js.map +0 -1
@@ -1,11 +1,8 @@
1
1
  import type { Logger } from './utils/logger.js';
2
- import type { PostHogAPIClient, TaskProgressRecord, TaskProgressUpdate } from './posthog-api.js';
3
- import type { AgentEvent } from './types.js';
2
+ import type { PostHogAPIClient, TaskRunUpdate } from './posthog-api.js';
3
+ import type { AgentEvent, TaskRun } from './types.js';
4
4
 
5
5
  interface ProgressMetadata {
6
- workflowId?: string;
7
- workflowRunId?: string;
8
- activityId?: string;
9
6
  totalSteps?: number;
10
7
  }
11
8
 
@@ -18,7 +15,7 @@ interface ProgressMetadata {
18
15
  export class TaskProgressReporter {
19
16
  private posthogAPI?: PostHogAPIClient;
20
17
  private logger: Logger;
21
- private progressRecord?: TaskProgressRecord;
18
+ private taskRun?: TaskRun;
22
19
  private taskId?: string;
23
20
  private outputLog: string[] = [];
24
21
  private totalSteps?: number;
@@ -29,8 +26,8 @@ export class TaskProgressReporter {
29
26
  this.logger = logger.child('TaskProgressReporter');
30
27
  }
31
28
 
32
- get progressId(): string | undefined {
33
- return this.progressRecord?.id;
29
+ get runId(): string | undefined {
30
+ return this.taskRun?.id;
34
31
  }
35
32
 
36
33
  async start(taskId: string, metadata: ProgressMetadata = {}): Promise<void> {
@@ -42,37 +39,27 @@ export class TaskProgressReporter {
42
39
  this.totalSteps = metadata.totalSteps;
43
40
 
44
41
  try {
45
- const record = await this.posthogAPI.createTaskProgress(taskId, {
42
+ const run = await this.posthogAPI.createTaskRun(taskId, {
46
43
  status: 'started',
47
- current_step: 'initializing',
48
- total_steps: metadata.totalSteps ?? 0,
49
- completed_steps: 0,
50
- workflow_id: metadata.workflowId,
51
- workflow_run_id: metadata.workflowRunId,
52
- activity_id: metadata.activityId,
53
- output_log: '',
44
+ log: [],
54
45
  });
55
- this.progressRecord = record;
56
- this.outputLog = record.output_log ? record.output_log.split('\n') : [];
57
- this.logger.debug('Created task progress record', { taskId, progressId: record.id });
46
+ this.taskRun = run;
47
+ this.outputLog = [];
48
+ this.logger.debug('Created task run', { taskId, runId: run.id });
58
49
  } catch (error) {
59
- this.logger.warn('Failed to create task progress record', { taskId, error: (error as Error).message });
50
+ this.logger.warn('Failed to create task run', { taskId, error: (error as Error).message });
60
51
  }
61
52
  }
62
53
 
63
54
  async stageStarted(stageKey: string, stageIndex: number): Promise<void> {
64
55
  await this.update({
65
56
  status: 'in_progress',
66
- current_step: stageKey,
67
- completed_steps: Math.min(stageIndex, this.totalSteps ?? stageIndex),
68
57
  }, `Stage started: ${stageKey}`);
69
58
  }
70
59
 
71
60
  async stageCompleted(stageKey: string, completedStages: number): Promise<void> {
72
61
  await this.update({
73
62
  status: 'in_progress',
74
- current_step: stageKey,
75
- completed_steps: Math.min(completedStages, this.totalSteps ?? completedStages),
76
63
  }, `Stage completed: ${stageKey}`);
77
64
  }
78
65
 
@@ -97,7 +84,7 @@ export class TaskProgressReporter {
97
84
  }
98
85
 
99
86
  async complete(): Promise<void> {
100
- await this.update({ status: 'completed', completed_steps: this.totalSteps }, 'Workflow execution completed');
87
+ await this.update({ status: 'completed' }, 'Workflow execution completed');
101
88
  }
102
89
 
103
90
  async fail(error: Error | string): Promise<void> {
@@ -110,7 +97,7 @@ export class TaskProgressReporter {
110
97
  }
111
98
 
112
99
  async recordEvent(event: AgentEvent): Promise<void> {
113
- if (!this.posthogAPI || !this.progressId || !this.taskId) {
100
+ if (!this.posthogAPI || !this.runId || !this.taskId) {
114
101
  return;
115
102
  }
116
103
 
@@ -144,14 +131,6 @@ export class TaskProgressReporter {
144
131
  return;
145
132
  }
146
133
 
147
- case 'file_write':
148
- await this.appendLog(this.formatFileWriteEvent(event));
149
- return;
150
-
151
- case 'diff':
152
- await this.appendLog(this.formatDiffEvent(event));
153
- return;
154
-
155
134
  case 'status':
156
135
  // Status events are covered by dedicated progress updates
157
136
  return;
@@ -186,32 +165,39 @@ export class TaskProgressReporter {
186
165
  }
187
166
  }
188
167
 
189
- private async update(update: TaskProgressUpdate, logLine?: string): Promise<void> {
190
- if (!this.posthogAPI || !this.progressId || !this.taskId) {
168
+ private async update(update: TaskRunUpdate, logLine?: string): Promise<void> {
169
+ if (!this.posthogAPI || !this.runId || !this.taskId) {
191
170
  return;
192
171
  }
193
172
 
194
- if (logLine) {
195
- if (logLine !== this.lastLogEntry) {
196
- this.outputLog.push(logLine);
173
+ // If there's a log line, append it separately using the append_log endpoint
174
+ if (logLine && logLine !== this.lastLogEntry) {
175
+ try {
176
+ await this.posthogAPI.appendTaskRunLog(this.taskId, this.runId, [
177
+ { type: 'info', message: logLine }
178
+ ]);
197
179
  this.lastLogEntry = logLine;
180
+ } catch (error) {
181
+ this.logger.warn('Failed to append log entry', {
182
+ taskId: this.taskId,
183
+ runId: this.runId,
184
+ error: (error as Error).message,
185
+ });
198
186
  }
199
- update.output_log = this.outputLog.join('\n');
200
187
  }
201
188
 
202
- try {
203
- const record = await this.posthogAPI.updateTaskProgress(this.taskId, this.progressId, update);
204
- // Sync local cache with server response to avoid drift if server modifies values
205
- this.progressRecord = record;
206
- if (record.output_log !== undefined && record.output_log !== null) {
207
- this.outputLog = record.output_log ? record.output_log.split('\n') : [];
189
+ // Update other fields if provided
190
+ if (Object.keys(update).length > 0) {
191
+ try {
192
+ const run = await this.posthogAPI.updateTaskRun(this.taskId, this.runId, update);
193
+ this.taskRun = run;
194
+ } catch (error) {
195
+ this.logger.warn('Failed to update task run', {
196
+ taskId: this.taskId,
197
+ runId: this.runId,
198
+ error: (error as Error).message,
199
+ });
208
200
  }
209
- } catch (error) {
210
- this.logger.warn('Failed to update task progress record', {
211
- taskId: this.taskId,
212
- progressId: this.progressId,
213
- error: (error as Error).message,
214
- });
215
201
  }
216
202
  }
217
203
 
@@ -280,17 +266,6 @@ export class TaskProgressReporter {
280
266
  return `[user] ${preview}`;
281
267
  }
282
268
 
283
- private formatFileWriteEvent(event: Extract<AgentEvent, { type: 'file_write' }>): string {
284
- const size = event.bytes !== undefined ? ` (${event.bytes} bytes)` : '';
285
- return `[file] wrote ${event.path}${size}`;
286
- }
287
-
288
- private formatDiffEvent(event: Extract<AgentEvent, { type: 'diff' }>): string {
289
- const summary = event.summary
290
- ? event.summary.trim()
291
- : this.truncateMultiline(event.patch ?? '', 160);
292
- return `[diff] ${event.file}${summary ? ` | ${summary}` : ''}`;
293
- }
294
269
 
295
270
  private truncateMultiline(text: string, max = 160): string {
296
271
  if (!text) {
@@ -0,0 +1,129 @@
1
+ import type { Tool } from './types.js';
2
+
3
+ /**
4
+ * Registry of all known tools with their metadata.
5
+ * Maps tool names to their definitions.
6
+ */
7
+ const TOOL_DEFINITIONS: Record<string, Tool> = {
8
+ // Filesystem tools
9
+ 'Read': {
10
+ name: 'Read',
11
+ category: 'filesystem',
12
+ description: 'Read file contents from the filesystem',
13
+ },
14
+ 'Write': {
15
+ name: 'Write',
16
+ category: 'filesystem',
17
+ description: 'Write content to a file',
18
+ },
19
+ 'Edit': {
20
+ name: 'Edit',
21
+ category: 'filesystem',
22
+ description: 'Edit file with find and replace operations',
23
+ },
24
+ 'Glob': {
25
+ name: 'Glob',
26
+ category: 'filesystem',
27
+ description: 'Find files matching a pattern',
28
+ },
29
+ 'NotebookEdit': {
30
+ name: 'NotebookEdit',
31
+ category: 'filesystem',
32
+ description: 'Edit Jupyter notebook cells',
33
+ },
34
+
35
+ // Shell tools
36
+ 'Bash': {
37
+ name: 'Bash',
38
+ category: 'shell',
39
+ description: 'Execute bash commands',
40
+ },
41
+ 'BashOutput': {
42
+ name: 'BashOutput',
43
+ category: 'shell',
44
+ description: 'Read output from a background bash process',
45
+ },
46
+ 'KillShell': {
47
+ name: 'KillShell',
48
+ category: 'shell',
49
+ description: 'Terminate a background bash process',
50
+ },
51
+
52
+ // Web tools
53
+ 'WebFetch': {
54
+ name: 'WebFetch',
55
+ category: 'web',
56
+ description: 'Fetch content from a URL',
57
+ },
58
+ 'WebSearch': {
59
+ name: 'WebSearch',
60
+ category: 'web',
61
+ description: 'Search the web',
62
+ },
63
+
64
+ // Search tools
65
+ 'Grep': {
66
+ name: 'Grep',
67
+ category: 'search',
68
+ description: 'Search file contents using patterns',
69
+ },
70
+
71
+ // Assistant tools
72
+ 'Task': {
73
+ name: 'Task',
74
+ category: 'assistant',
75
+ description: 'Launch a specialized agent for a sub-task',
76
+ },
77
+ 'TodoWrite': {
78
+ name: 'TodoWrite',
79
+ category: 'assistant',
80
+ description: 'Manage task list and track progress',
81
+ },
82
+ 'ExitPlanMode': {
83
+ name: 'ExitPlanMode',
84
+ category: 'assistant',
85
+ description: 'Exit plan mode and present plan to user',
86
+ },
87
+ 'SlashCommand': {
88
+ name: 'SlashCommand',
89
+ category: 'assistant',
90
+ description: 'Execute a slash command',
91
+ },
92
+ };
93
+
94
+ /**
95
+ * Tool registry for looking up tool definitions by name.
96
+ * Provides metadata about tools for UI consumption.
97
+ */
98
+ export class ToolRegistry {
99
+ /**
100
+ * Get tool definition by name.
101
+ * Returns undefined if tool is not recognized.
102
+ */
103
+ get(name: string): Tool | undefined {
104
+ return TOOL_DEFINITIONS[name];
105
+ }
106
+
107
+ /**
108
+ * Get all registered tools.
109
+ */
110
+ getAll(): Tool[] {
111
+ return Object.values(TOOL_DEFINITIONS);
112
+ }
113
+
114
+ /**
115
+ * Check if a tool name is registered.
116
+ */
117
+ has(name: string): boolean {
118
+ return name in TOOL_DEFINITIONS;
119
+ }
120
+
121
+ /**
122
+ * Get all tools in a specific category.
123
+ */
124
+ getByCategory(category: string): Tool[] {
125
+ return Object.values(TOOL_DEFINITIONS).filter(
126
+ (tool) => tool.category === category
127
+ );
128
+ }
129
+ }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Tool category classification for grouping related tools.
3
+ * Makes it easier for UIs to filter and display tools by function.
4
+ */
5
+ export type ToolCategory =
6
+ | 'filesystem' // File operations: Read, Write, Edit, Glob, NotebookEdit
7
+ | 'shell' // Shell operations: Bash, BashOutput, KillShell
8
+ | 'web' // Web operations: WebFetch, WebSearch
9
+ | 'assistant' // Assistant operations: Task, TodoWrite, ExitPlanMode
10
+ | 'search' // Search operations: Grep
11
+ | 'unknown'; // Unknown or unrecognized tools
12
+
13
+ /**
14
+ * Base tool interface representing a tool that can be called by the agent.
15
+ * Each tool has a name, category, and human-readable description.
16
+ */
17
+ export interface Tool {
18
+ name: string;
19
+ category: ToolCategory;
20
+ description: string;
21
+ }
22
+
23
+ // Filesystem tools
24
+
25
+ export interface ReadTool extends Tool {
26
+ name: 'Read';
27
+ category: 'filesystem';
28
+ }
29
+
30
+ export interface WriteTool extends Tool {
31
+ name: 'Write';
32
+ category: 'filesystem';
33
+ }
34
+
35
+ export interface EditTool extends Tool {
36
+ name: 'Edit';
37
+ category: 'filesystem';
38
+ }
39
+
40
+ export interface GlobTool extends Tool {
41
+ name: 'Glob';
42
+ category: 'filesystem';
43
+ }
44
+
45
+ export interface NotebookEditTool extends Tool {
46
+ name: 'NotebookEdit';
47
+ category: 'filesystem';
48
+ }
49
+
50
+ // Shell tools
51
+
52
+ export interface BashTool extends Tool {
53
+ name: 'Bash';
54
+ category: 'shell';
55
+ }
56
+
57
+ export interface BashOutputTool extends Tool {
58
+ name: 'BashOutput';
59
+ category: 'shell';
60
+ }
61
+
62
+ export interface KillShellTool extends Tool {
63
+ name: 'KillShell';
64
+ category: 'shell';
65
+ }
66
+
67
+ // Web tools
68
+
69
+ export interface WebFetchTool extends Tool {
70
+ name: 'WebFetch';
71
+ category: 'web';
72
+ }
73
+
74
+ export interface WebSearchTool extends Tool {
75
+ name: 'WebSearch';
76
+ category: 'web';
77
+ }
78
+
79
+ // Search tools
80
+
81
+ export interface GrepTool extends Tool {
82
+ name: 'Grep';
83
+ category: 'search';
84
+ }
85
+
86
+ // Assistant tools
87
+
88
+ export interface TaskTool extends Tool {
89
+ name: 'Task';
90
+ category: 'assistant';
91
+ }
92
+
93
+ export interface TodoWriteTool extends Tool {
94
+ name: 'TodoWrite';
95
+ category: 'assistant';
96
+ }
97
+
98
+ export interface ExitPlanModeTool extends Tool {
99
+ name: 'ExitPlanMode';
100
+ category: 'assistant';
101
+ }
102
+
103
+ export interface SlashCommandTool extends Tool {
104
+ name: 'SlashCommand';
105
+ category: 'assistant';
106
+ }
107
+
108
+ /**
109
+ * Union type of all known tool types.
110
+ * Useful for discriminated unions and type narrowing.
111
+ */
112
+ export type KnownTool =
113
+ | ReadTool
114
+ | WriteTool
115
+ | EditTool
116
+ | GlobTool
117
+ | NotebookEditTool
118
+ | BashTool
119
+ | BashOutputTool
120
+ | KillShellTool
121
+ | WebFetchTool
122
+ | WebSearchTool
123
+ | GrepTool
124
+ | TaskTool
125
+ | TodoWriteTool
126
+ | ExitPlanModeTool
127
+ | SlashCommandTool;
package/src/types.ts CHANGED
@@ -6,15 +6,43 @@ export interface Task {
6
6
  origin_product: 'error_tracking' | 'eval_clusters' | 'user_created' | 'support_queue' | 'session_summaries';
7
7
  position?: number;
8
8
  workflow?: string | null;
9
- current_stage?: string | null;
10
9
  github_integration?: number | null;
11
10
  repository_config?: unknown; // JSONField
12
11
  repository_list: string;
13
12
  primary_repository: string;
14
- github_branch: string | null;
15
- github_pr_url: string | null;
16
13
  created_at: string;
17
14
  updated_at: string;
15
+
16
+ // DEPRECATED: These fields have been moved to TaskRun
17
+ // Use task.latest_run instead
18
+ current_stage?: string | null;
19
+ github_branch?: string | null;
20
+ github_pr_url?: string | null;
21
+ latest_run?: TaskRun;
22
+ }
23
+
24
+ // Log entry structure for TaskRun.log
25
+ export interface LogEntry {
26
+ type: string; // e.g., "info", "warning", "error", "success", "debug"
27
+ message: string;
28
+ [key: string]: unknown; // Allow additional fields
29
+ }
30
+
31
+ // TaskRun model - represents individual execution runs of tasks
32
+ export interface TaskRun {
33
+ id: string;
34
+ task: string; // Task ID
35
+ team: number;
36
+ branch: string | null;
37
+ current_stage: string | null; // WorkflowStage ID
38
+ status: 'started' | 'in_progress' | 'completed' | 'failed';
39
+ log: LogEntry[]; // Array of log entry objects
40
+ error_message: string | null;
41
+ output: Record<string, unknown> | null; // Structured output (PR URL, commit SHA, etc.)
42
+ state: Record<string, unknown>; // Intermediate run state (defaults to {}, never null)
43
+ created_at: string;
44
+ updated_at: string;
45
+ completed_at: string | null;
18
46
  }
19
47
 
20
48
  export interface SupportingFile {
@@ -69,6 +97,10 @@ export interface ToolCallEvent extends BaseEvent {
69
97
  toolName: string;
70
98
  callId: string;
71
99
  args: Record<string, any>;
100
+ parentToolUseId?: string | null; // For nested tool calls (subagents)
101
+ // Tool metadata (enriched by adapter for UI consumption)
102
+ tool?: import('./tools/types.js').Tool;
103
+ category?: import('./tools/types.js').ToolCategory;
72
104
  }
73
105
 
74
106
  export interface ToolResultEvent extends BaseEvent {
@@ -76,6 +108,11 @@ export interface ToolResultEvent extends BaseEvent {
76
108
  toolName: string;
77
109
  callId: string;
78
110
  result: any;
111
+ isError?: boolean; // Whether the tool execution failed
112
+ parentToolUseId?: string | null; // For nested tool calls (subagents)
113
+ // Tool metadata (enriched by adapter for UI consumption)
114
+ tool?: import('./tools/types.js').Tool;
115
+ category?: import('./tools/types.js').ToolCategory;
79
116
  }
80
117
 
81
118
  // Message lifecycle events
@@ -109,7 +146,16 @@ export interface UserMessageEvent extends BaseEvent {
109
146
  export interface StatusEvent extends BaseEvent {
110
147
  type: 'status';
111
148
  phase: string;
112
- [key: string]: any;
149
+ // Common optional fields (varies by phase):
150
+ stage?: string; // Workflow stage (plan, code, complete)
151
+ kind?: string; // Kind of status (plan, implementation)
152
+ branch?: string; // Git branch name
153
+ prUrl?: string; // Pull request URL
154
+ workflowId?: string; // Workflow identifier
155
+ taskId?: string; // Task identifier
156
+ messageId?: string; // Claude message ID
157
+ model?: string; // Model name
158
+ [key: string]: any; // Allow additional fields
113
159
  }
114
160
 
115
161
  export interface InitEvent extends BaseEvent {
@@ -119,6 +165,10 @@ export interface InitEvent extends BaseEvent {
119
165
  permissionMode: string;
120
166
  cwd: string;
121
167
  apiKeySource: string;
168
+ agents?: string[];
169
+ slashCommands?: string[];
170
+ outputStyle?: string;
171
+ mcpServers?: Array<{ name: string; status: string }>;
122
172
  }
123
173
 
124
174
  export interface CompactBoundaryEvent extends BaseEvent {
@@ -130,10 +180,28 @@ export interface CompactBoundaryEvent extends BaseEvent {
130
180
  // Result events
131
181
  export interface DoneEvent extends BaseEvent {
132
182
  type: 'done';
183
+ result?: string; // Final summary text from Claude
133
184
  durationMs?: number;
185
+ durationApiMs?: number; // API-only duration (excluding local processing)
134
186
  numTurns?: number;
135
187
  totalCostUsd?: number;
136
188
  usage?: any;
189
+ modelUsage?: { // Per-model usage breakdown
190
+ [modelName: string]: {
191
+ inputTokens: number;
192
+ outputTokens: number;
193
+ cacheReadInputTokens: number;
194
+ cacheCreationInputTokens: number;
195
+ webSearchRequests: number;
196
+ costUSD: number;
197
+ contextWindow: number;
198
+ };
199
+ };
200
+ permissionDenials?: Array<{ // Tools that were denied by permissions
201
+ tool_name: string;
202
+ tool_use_id: string;
203
+ tool_input: Record<string, unknown>;
204
+ }>;
137
205
  }
138
206
 
139
207
  export interface ErrorEvent extends BaseEvent {
@@ -145,20 +213,7 @@ export interface ErrorEvent extends BaseEvent {
145
213
  sdkError?: any; // Original SDK error object
146
214
  }
147
215
 
148
- // Legacy events (keeping for backwards compatibility)
149
- export interface DiffEvent extends BaseEvent {
150
- type: 'diff';
151
- file: string;
152
- patch: string;
153
- summary?: string;
154
- }
155
-
156
- export interface FileWriteEvent extends BaseEvent {
157
- type: 'file_write';
158
- path: string;
159
- bytes: number;
160
- }
161
-
216
+ // Metric and artifact events (general purpose, not tool-specific)
162
217
  export interface MetricEvent extends BaseEvent {
163
218
  type: 'metric';
164
219
  key: string;
@@ -192,8 +247,6 @@ export type AgentEvent =
192
247
  | CompactBoundaryEvent
193
248
  | DoneEvent
194
249
  | ErrorEvent
195
- | DiffEvent
196
- | FileWriteEvent
197
250
  | MetricEvent
198
251
  | ArtifactEvent
199
252
  | RawSDKEvent;
@@ -1,10 +0,0 @@
1
- import type { AgentEvent } from './types.js';
2
- import type { SDKMessage } from '@anthropic-ai/claude-agent-sdk';
3
- export declare class EventTransformer {
4
- createRawSDKEvent(sdkMessage: any): AgentEvent;
5
- transform(sdkMessage: SDKMessage): AgentEvent | null;
6
- createStatusEvent(phase: string, additionalData?: any): AgentEvent;
7
- private extractUserContent;
8
- private extractFromObject;
9
- }
10
- //# sourceMappingURL=event-transformer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"event-transformer.d.ts","sourceRoot":"","sources":["../../src/event-transformer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAEjE,qBAAa,gBAAgB;IAC3B,iBAAiB,CAAC,UAAU,EAAE,GAAG,GAAG,UAAU;IAQ9C,SAAS,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI;IA2NpD,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,GAAG,GAAG,UAAU;IASlE,OAAO,CAAC,kBAAkB;IAkC1B,OAAO,CAAC,iBAAiB;CAoB1B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"event-transformer.js","sources":["../../src/event-transformer.ts"],"sourcesContent":["import type { AgentEvent } from './types.js';\nimport type { SDKMessage } from '@anthropic-ai/claude-agent-sdk';\n\nexport class EventTransformer {\n createRawSDKEvent(sdkMessage: any): AgentEvent {\n return {\n type: 'raw_sdk_event',\n ts: Date.now(),\n sdkMessage\n };\n }\n\n transform(sdkMessage: SDKMessage): AgentEvent | null {\n const baseEvent = { ts: Date.now() };\n\n // Handle stream events\n if (sdkMessage.type === 'stream_event') {\n const event = sdkMessage.event;\n\n switch (event.type) {\n case 'message_start':\n return {\n ...baseEvent,\n type: 'message_start',\n messageId: event.message?.id,\n model: event.message?.model\n };\n\n case 'content_block_start':\n const contentBlock = event.content_block;\n if (!contentBlock) return null;\n\n return {\n ...baseEvent,\n type: 'content_block_start',\n index: event.index,\n contentType: contentBlock.type as 'text' | 'tool_use' | 'thinking',\n toolName: contentBlock.type === 'tool_use' ? contentBlock.name : undefined,\n toolId: contentBlock.type === 'tool_use' ? contentBlock.id : undefined\n };\n\n case 'content_block_delta':\n const delta = event.delta;\n if (!delta) return null;\n\n if (delta.type === 'text_delta') {\n return {\n ...baseEvent,\n type: 'token',\n content: delta.text,\n contentType: 'text'\n };\n } else if (delta.type === 'input_json_delta') {\n return {\n ...baseEvent,\n type: 'token',\n content: delta.partial_json,\n contentType: 'tool_input'\n };\n } else if (delta.type === 'thinking_delta') {\n return {\n ...baseEvent,\n type: 'token',\n content: delta.thinking,\n contentType: 'thinking'\n };\n }\n return null;\n\n case 'content_block_stop':\n return {\n ...baseEvent,\n type: 'content_block_stop',\n index: event.index\n };\n\n case 'message_delta':\n return {\n ...baseEvent,\n type: 'message_delta',\n stopReason: event.delta?.stop_reason,\n stopSequence: event.delta?.stop_sequence,\n usage: event.usage ? {\n outputTokens: event.usage.output_tokens\n } : undefined\n };\n\n case 'message_stop':\n return {\n ...baseEvent,\n type: 'message_stop'\n };\n\n case 'ping':\n // Ignore ping events\n return null;\n\n case 'error':\n return {\n ...baseEvent,\n type: 'error',\n message: event.error?.message || 'Unknown error',\n error: event.error,\n errorType: event.error?.type || 'stream_error',\n context: event.error ? {\n type: event.error.type,\n code: event.error.code,\n } : undefined,\n sdkError: event.error\n };\n\n default:\n return null;\n }\n }\n\n // Handle assistant messages (full message, not streaming)\n if (sdkMessage.type === 'assistant') {\n const message = sdkMessage.message;\n \n // Extract tool calls from content blocks\n if (message.content && Array.isArray(message.content)) {\n for (const block of message.content) {\n if (block.type === 'tool_use') {\n // Return first tool_call event found\n return {\n ...baseEvent,\n type: 'tool_call',\n toolName: block.name,\n callId: block.id,\n args: block.input || {}\n };\n }\n }\n }\n \n // If no tool calls, emit status event\n return {\n ...baseEvent,\n type: 'status',\n phase: 'assistant_message',\n messageId: message.id,\n model: message.model\n };\n }\n\n // Handle user messages\n if (sdkMessage.type === 'user') {\n const message = sdkMessage.message;\n \n // Check for tool results in content blocks\n if (message?.content && Array.isArray(message.content)) {\n for (const block of message.content) {\n if (block.type === 'tool_result') {\n return {\n ...baseEvent,\n type: 'tool_result',\n toolName: block.tool_name || 'unknown',\n callId: block.tool_use_id || '',\n result: block.content\n };\n }\n }\n }\n \n // Otherwise extract text content\n const textContent = this.extractUserContent(message?.content);\n if (!textContent) {\n return null;\n }\n return {\n ...baseEvent,\n type: 'user_message',\n content: textContent,\n isSynthetic: sdkMessage.isSynthetic\n };\n }\n\n // Handle result messages\n if (sdkMessage.type === 'result') {\n if (sdkMessage.subtype === 'success') {\n return {\n ...baseEvent,\n type: 'done',\n durationMs: sdkMessage.duration_ms,\n numTurns: sdkMessage.num_turns,\n totalCostUsd: sdkMessage.total_cost_usd,\n usage: sdkMessage.usage\n };\n } else {\n return {\n ...baseEvent,\n type: 'error',\n message: `Execution failed: ${sdkMessage.subtype}`,\n error: { subtype: sdkMessage.subtype },\n errorType: sdkMessage.subtype || 'result_error',\n context: {\n subtype: sdkMessage.subtype,\n duration_ms: sdkMessage.duration_ms,\n num_turns: sdkMessage.num_turns\n },\n sdkError: sdkMessage\n };\n }\n }\n\n // Handle system messages\n if (sdkMessage.type === 'system') {\n if (sdkMessage.subtype === 'init') {\n return {\n ...baseEvent,\n type: 'init',\n model: sdkMessage.model,\n tools: sdkMessage.tools,\n permissionMode: sdkMessage.permissionMode,\n cwd: sdkMessage.cwd,\n apiKeySource: sdkMessage.apiKeySource\n };\n } else if (sdkMessage.subtype === 'compact_boundary') {\n return {\n ...baseEvent,\n type: 'compact_boundary',\n trigger: sdkMessage.compact_metadata.trigger,\n preTokens: sdkMessage.compact_metadata.pre_tokens\n };\n }\n }\n\n return null;\n }\n \n createStatusEvent(phase: string, additionalData?: any): AgentEvent {\n return {\n type: 'status',\n ts: Date.now(),\n phase,\n ...additionalData\n };\n }\n\n private extractUserContent(content: unknown): string | null {\n if (!content) {\n return null;\n }\n\n if (typeof content === 'string') {\n const trimmed = content.trim();\n return trimmed.length > 0 ? trimmed : null;\n }\n\n if (Array.isArray(content)) {\n const parts: string[] = [];\n for (const block of content) {\n const extracted = this.extractUserContent(block);\n if (extracted) {\n parts.push(extracted);\n } else if (block && typeof block === 'object') {\n const candidate = this.extractFromObject(block as Record<string, unknown>);\n if (candidate) {\n parts.push(candidate);\n }\n }\n }\n const text = parts.join('\\n').trim();\n return text.length > 0 ? text : null;\n }\n\n if (typeof content === 'object') {\n return this.extractFromObject(content as Record<string, unknown>);\n }\n\n return null;\n }\n\n private extractFromObject(value: Record<string, unknown>): string | null {\n const preferredKeys = ['text', 'input_text', 'input', 'markdown', 'content', 'message'];\n for (const key of preferredKeys) {\n if (typeof value[key] === 'string') {\n const trimmed = (value[key] as string).trim();\n if (trimmed.length > 0) {\n return trimmed;\n }\n }\n }\n\n for (const entry of Object.values(value)) {\n const extracted = this.extractUserContent(entry);\n if (extracted) {\n return extracted;\n }\n }\n\n return null;\n }\n}\n"],"names":[],"mappings":"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"}