wave-agent-sdk 0.18.2 → 0.18.4

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 (53) hide show
  1. package/dist/agent.d.ts.map +1 -1
  2. package/dist/agent.js +0 -2
  3. package/dist/managers/MemoryRuleManager.d.ts +9 -0
  4. package/dist/managers/MemoryRuleManager.d.ts.map +1 -1
  5. package/dist/managers/MemoryRuleManager.js +18 -0
  6. package/dist/managers/aiManager.d.ts +1 -1
  7. package/dist/managers/aiManager.d.ts.map +1 -1
  8. package/dist/managers/aiManager.js +370 -345
  9. package/dist/managers/messageManager.d.ts +32 -13
  10. package/dist/managers/messageManager.d.ts.map +1 -1
  11. package/dist/managers/messageManager.js +82 -76
  12. package/dist/prompts/index.d.ts +10 -4
  13. package/dist/prompts/index.d.ts.map +1 -1
  14. package/dist/prompts/index.js +21 -20
  15. package/dist/services/aiService.d.ts +2 -1
  16. package/dist/services/aiService.d.ts.map +1 -1
  17. package/dist/services/aiService.js +37 -10
  18. package/dist/services/memory.d.ts +1 -0
  19. package/dist/services/memory.d.ts.map +1 -1
  20. package/dist/services/memory.js +35 -17
  21. package/dist/tools/agentTool.d.ts.map +1 -1
  22. package/dist/tools/agentTool.js +24 -2
  23. package/dist/tools/editTool.js +3 -3
  24. package/dist/tools/readTool.js +2 -2
  25. package/dist/tools/writeTool.js +2 -2
  26. package/dist/utils/containerSetup.d.ts.map +1 -1
  27. package/dist/utils/containerSetup.js +1 -0
  28. package/dist/utils/openaiClient.d.ts.map +1 -1
  29. package/dist/utils/openaiClient.js +28 -7
  30. package/dist/utils/taskReminder.d.ts +2 -3
  31. package/dist/utils/taskReminder.d.ts.map +1 -1
  32. package/dist/utils/taskReminder.js +7 -18
  33. package/package.json +1 -1
  34. package/scripts/install_ripgrep.js +21 -1
  35. package/src/agent.ts +0 -5
  36. package/src/managers/MemoryRuleManager.ts +23 -0
  37. package/src/managers/aiManager.ts +473 -434
  38. package/src/managers/messageManager.ts +99 -82
  39. package/src/prompts/index.ts +33 -24
  40. package/src/services/aiService.ts +39 -12
  41. package/src/services/memory.ts +34 -16
  42. package/src/tools/agentTool.ts +24 -2
  43. package/src/tools/editTool.ts +3 -3
  44. package/src/tools/readTool.ts +2 -2
  45. package/src/tools/writeTool.ts +2 -2
  46. package/src/utils/containerSetup.ts +1 -0
  47. package/src/utils/openaiClient.ts +35 -7
  48. package/src/utils/taskReminder.ts +7 -19
  49. package/vendor/ripgrep/linux-aarch64/rg +0 -0
  50. package/vendor/ripgrep/macos-aarch64/rg +0 -0
  51. package/vendor/ripgrep/macos-x86_64/rg +0 -0
  52. package/vendor/ripgrep/windows-aarch64/rg.exe +0 -0
  53. package/vendor/ripgrep/windows-x86_64/rg.exe +0 -0
@@ -109,13 +109,13 @@ Usage:
109
109
  };
110
110
  }
111
111
 
112
- // Touch file to track it in context
113
- context.messageManager?.touchFile(filePath);
112
+ // Trigger conditional rule loading for this file
113
+ context.messageManager?.triggerFileRead(filePath);
114
114
 
115
115
  // Enforce read-before-edit: the file must have been read first
116
116
  if (
117
117
  context.messageManager &&
118
- !context.messageManager.hasFileInContext(filePath)
118
+ !context.messageManager.hasFileBeenRead(filePath)
119
119
  ) {
120
120
  return {
121
121
  success: false,
@@ -195,8 +195,8 @@ Usage:
195
195
  };
196
196
  }
197
197
 
198
- // Touch file to track it in context
199
- context.messageManager?.touchFile(filePath);
198
+ // Trigger conditional rule loading for this file
199
+ context.messageManager?.triggerFileRead(filePath);
200
200
 
201
201
  // Check for binary document formats
202
202
  if (isBinaryDocument(filePath)) {
@@ -68,8 +68,8 @@ Usage:
68
68
  };
69
69
  }
70
70
 
71
- // Touch file to track it in context
72
- context.messageManager?.touchFile(filePath);
71
+ // Trigger conditional rule loading for this file
72
+ context.messageManager?.triggerFileRead(filePath);
73
73
 
74
74
  try {
75
75
  const resolvedPath = resolvePath(filePath, context.workdir);
@@ -117,6 +117,7 @@ export function setupAgentContainer(
117
117
  logger.error("Failed to sync task list with session:", error);
118
118
  });
119
119
  }
120
+ memoryService.clearCache();
120
121
  callbacks.onSessionIdChange?.(sessionId);
121
122
  },
122
123
  },
@@ -7,6 +7,28 @@ import {
7
7
  import { GatewayConfig } from "../types/config.js";
8
8
  import { logger } from "./globalLogger.js";
9
9
 
10
+ const MAX_RETRIES = 10;
11
+ const BASE_DELAY_MS = 500;
12
+ const MAX_DELAY_MS = 32000;
13
+
14
+ function getRetryDelay(
15
+ attempt: number,
16
+ retryAfterHeader: string | null,
17
+ ): number {
18
+ if (retryAfterHeader) {
19
+ const seconds = parseInt(retryAfterHeader, 10);
20
+ if (!isNaN(seconds)) {
21
+ return seconds * 1000;
22
+ }
23
+ }
24
+ const baseDelay = Math.min(
25
+ BASE_DELAY_MS * Math.pow(2, attempt - 1),
26
+ MAX_DELAY_MS,
27
+ );
28
+ const jitter = Math.random() * 0.25 * baseDelay;
29
+ return baseDelay + jitter;
30
+ }
31
+
10
32
  type CreateParams =
11
33
  | ChatCompletionCreateParamsNonStreaming
12
34
  | ChatCompletionCreateParamsStreaming;
@@ -88,12 +110,11 @@ export class OpenAIClient {
88
110
 
89
111
  const fetchFn = (customFetch as typeof fetch) || fetch;
90
112
  let lastError: (Error & { status?: number; body?: unknown }) | undefined;
91
- const maxRetries = 5;
92
- const initialDelay = 2000;
113
+ let lastRetryAfter: string | null = null;
93
114
 
94
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
115
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
95
116
  if (attempt > 0) {
96
- const delay = initialDelay * Math.pow(2, attempt - 1);
117
+ const delay = getRetryDelay(attempt, lastRetryAfter);
97
118
  await new Promise((resolve) => setTimeout(resolve, delay));
98
119
  }
99
120
 
@@ -110,12 +131,13 @@ export class OpenAIClient {
110
131
  if (e instanceof Error && e.name === "AbortError") {
111
132
  throw e;
112
133
  }
113
- if (attempt < maxRetries) {
134
+ if (attempt < MAX_RETRIES) {
114
135
  logger.warn("OpenAI API network error, retrying...", {
115
136
  attempt: attempt + 1,
116
137
  error: e,
117
138
  });
118
139
  lastError = e as Error;
140
+ lastRetryAfter = null;
119
141
  continue;
120
142
  }
121
143
  throw e;
@@ -179,10 +201,12 @@ export class OpenAIClient {
179
201
  const retryableStatus =
180
202
  response.status === 429 ||
181
203
  (response.status >= 500 && response.status !== 501);
182
- if (retryableStatus && attempt < maxRetries) {
204
+ if (retryableStatus && attempt < MAX_RETRIES) {
205
+ lastRetryAfter = response.headers.get("retry-after");
183
206
  logger.warn("OpenAI API error, retrying...", {
184
207
  attempt: attempt + 1,
185
208
  status: response.status,
209
+ retryAfter: lastRetryAfter,
186
210
  });
187
211
  lastError = error;
188
212
  continue;
@@ -222,12 +246,16 @@ export class OpenAIClient {
222
246
 
223
247
  const data = trimmedLine.slice(5).trim();
224
248
  if (data === "[DONE]") return;
249
+ if (!data) continue; // Skip empty data lines (keepalive heartbeats)
225
250
 
226
251
  try {
227
252
  const json = JSON.parse(data);
228
253
  yield json as ChatCompletionChunk;
229
254
  } catch (e) {
230
- logger.error("Failed to parse stream chunk", { error: e, data });
255
+ logger.error("Failed to parse stream chunk", {
256
+ error: e instanceof Error ? e.message : String(e),
257
+ data,
258
+ });
231
259
  }
232
260
  }
233
261
  }
@@ -1,18 +1,12 @@
1
1
  import type { Message } from "../types/messaging.js";
2
2
  import type { Task } from "../types/tasks.js";
3
- import type { ChatCompletionMessageParam } from "openai/resources.js";
4
3
 
5
4
  export const TASK_REMINDER_CONFIG = {
6
5
  TURNS_SINCE_WRITE: 10,
7
6
  TURNS_BETWEEN_REMINDERS: 10,
8
7
  };
9
8
 
10
- const TASK_MANAGEMENT_TOOLS = new Set([
11
- "TaskCreate",
12
- "TaskUpdate",
13
- "TaskList",
14
- "TaskGet",
15
- ]);
9
+ const TASK_MANAGEMENT_TOOLS = new Set(["TaskCreate", "TaskUpdate"]);
16
10
  const TASK_REMINDER_MARKER = "<!-- task-reminder -->";
17
11
 
18
12
  function isQualifyingAssistantMessage(message: Message): boolean {
@@ -66,43 +60,37 @@ export function getTaskReminderTurnCounts(messages: Message[]): {
66
60
  export function buildTaskReminderText(tasks: Task[]): string {
67
61
  let text = `${TASK_REMINDER_MARKER}\n`;
68
62
  text +=
69
- "Here is a gentle reminder about the task list. The user may not have explicitly asked for the following to be done, but you should check the task list to see if any tasks need attention.\n";
63
+ "The task tools haven't been used recently. If you're working on tasks that would benefit from tracking progress, consider using TaskCreate to add new tasks and TaskUpdate to update task status (set to in_progress when starting, completed when done). Also consider cleaning up the task list if it has become stale. Only use these if relevant to the current work. This is just a gentle reminder - ignore if not applicable. Make sure that you never mention this reminder to the user";
70
64
 
71
65
  if (tasks.length > 0) {
72
- text += "\n";
66
+ text += "\n\nHere are the existing tasks:\n";
73
67
  for (const task of tasks) {
74
68
  text += `#${task.id} [${task.status}] ${task.subject}\n`;
75
69
  }
76
- } else {
77
- text += "The task list is currently empty.\n";
78
70
  }
79
71
 
80
72
  return text;
81
73
  }
82
74
 
83
75
  export function maybeInjectTaskReminder(
84
- messages: ChatCompletionMessageParam[],
85
76
  turnCounts: {
86
77
  turnsSinceLastTaskManagement: number;
87
78
  turnsSinceLastReminder: number;
88
79
  },
89
80
  tasks: Task[],
90
- ): void {
81
+ ): string | null {
91
82
  if (
92
83
  turnCounts.turnsSinceLastTaskManagement <
93
84
  TASK_REMINDER_CONFIG.TURNS_SINCE_WRITE
94
85
  ) {
95
- return;
86
+ return null;
96
87
  }
97
88
  if (
98
89
  turnCounts.turnsSinceLastReminder <
99
90
  TASK_REMINDER_CONFIG.TURNS_BETWEEN_REMINDERS
100
91
  ) {
101
- return;
92
+ return null;
102
93
  }
103
94
 
104
- messages.push({
105
- role: "user",
106
- content: buildTaskReminderText(tasks),
107
- } as ChatCompletionMessageParam);
95
+ return buildTaskReminderText(tasks);
108
96
  }
Binary file
Binary file
Binary file