wave-agent-sdk 0.14.4 → 0.15.1
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/builtin/skills/settings/SKILLS.md +31 -6
- package/dist/agent.d.ts +4 -5
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +10 -15
- package/dist/constants/toolLimits.d.ts +10 -0
- package/dist/constants/toolLimits.d.ts.map +1 -0
- package/dist/constants/toolLimits.js +9 -0
- package/dist/managers/aiManager.d.ts +0 -5
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +0 -22
- package/dist/managers/hookManager.d.ts +0 -4
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +0 -25
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +7 -6
- package/dist/managers/permissionManager.d.ts +1 -1
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +5 -5
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +16 -4
- package/dist/managers/subagentManager.d.ts +6 -1
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +17 -18
- package/dist/prompts/index.d.ts +1 -3
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +3 -6
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +10 -8
- package/dist/services/hook.d.ts +0 -4
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +0 -10
- package/dist/services/jsonlHandler.d.ts +4 -4
- package/dist/services/jsonlHandler.d.ts.map +1 -1
- package/dist/services/jsonlHandler.js +4 -13
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +7 -13
- package/dist/tools/agentTool.d.ts.map +1 -1
- package/dist/tools/agentTool.js +16 -4
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +4 -50
- package/dist/tools/editTool.js +1 -1
- package/dist/tools/skillTool.d.ts.map +1 -1
- package/dist/tools/skillTool.js +16 -4
- package/dist/tools/types.d.ts +0 -3
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/agent.d.ts +0 -1
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/hooks.d.ts +1 -5
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +0 -1
- package/dist/types/messaging.d.ts +1 -0
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/session.d.ts +0 -4
- package/dist/types/session.d.ts.map +1 -1
- package/dist/utils/editUtils.d.ts +5 -2
- package/dist/utils/editUtils.d.ts.map +1 -1
- package/dist/utils/editUtils.js +3 -57
- package/dist/utils/markdownParser.d.ts +8 -1
- package/dist/utils/markdownParser.d.ts.map +1 -1
- package/dist/utils/markdownParser.js +64 -11
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +5 -0
- package/dist/utils/openaiClient.d.ts.map +1 -1
- package/dist/utils/openaiClient.js +0 -11
- package/package.json +1 -1
- package/src/agent.ts +12 -17
- package/src/constants/toolLimits.ts +12 -0
- package/src/managers/aiManager.ts +0 -38
- package/src/managers/hookManager.ts +0 -32
- package/src/managers/messageManager.ts +7 -8
- package/src/managers/permissionManager.ts +6 -6
- package/src/managers/slashCommandManager.ts +24 -5
- package/src/managers/subagentManager.ts +28 -23
- package/src/prompts/index.ts +3 -8
- package/src/services/aiService.ts +10 -12
- package/src/services/hook.ts +0 -15
- package/src/services/jsonlHandler.ts +12 -24
- package/src/services/session.ts +9 -15
- package/src/tools/agentTool.ts +24 -5
- package/src/tools/bashTool.ts +4 -56
- package/src/tools/editTool.ts +1 -1
- package/src/tools/skillTool.ts +24 -4
- package/src/tools/types.ts +0 -3
- package/src/types/agent.ts +0 -1
- package/src/types/hooks.ts +1 -7
- package/src/types/messaging.ts +1 -0
- package/src/types/session.ts +0 -8
- package/src/utils/editUtils.ts +3 -73
- package/src/utils/markdownParser.ts +85 -11
- package/src/utils/messageOperations.ts +5 -0
- package/src/utils/openaiClient.ts +0 -11
package/src/types/agent.ts
CHANGED
|
@@ -98,6 +98,5 @@ export interface AgentCallbacks
|
|
|
98
98
|
onConfiguredModelsChange?: (models: string[]) => void;
|
|
99
99
|
onLoadingChange?: (loading: boolean) => void;
|
|
100
100
|
onCommandRunningChange?: (running: boolean) => void;
|
|
101
|
-
onWorkdirChange?: (newCwd: string) => void;
|
|
102
101
|
onQueuedMessagesChange?: (messages: QueuedMessage[]) => void;
|
|
103
102
|
}
|
package/src/types/hooks.ts
CHANGED
|
@@ -21,7 +21,6 @@ export type HookEvent =
|
|
|
21
21
|
| "SubagentStop"
|
|
22
22
|
| "PermissionRequest"
|
|
23
23
|
| "WorktreeCreate"
|
|
24
|
-
| "CwdChanged"
|
|
25
24
|
| "SessionStart"
|
|
26
25
|
| "SessionEnd";
|
|
27
26
|
|
|
@@ -110,7 +109,6 @@ export function isValidHookEvent(event: string): event is HookEvent {
|
|
|
110
109
|
"SubagentStop",
|
|
111
110
|
"PermissionRequest",
|
|
112
111
|
"WorktreeCreate",
|
|
113
|
-
"CwdChanged",
|
|
114
112
|
"SessionStart",
|
|
115
113
|
"SessionEnd",
|
|
116
114
|
].includes(event);
|
|
@@ -169,7 +167,7 @@ export interface HookJsonInput {
|
|
|
169
167
|
session_id: string; // Format: "wave_session_{uuid}_{shortId}"
|
|
170
168
|
transcript_path: string; // Format: "~/.wave/sessions/session_{shortId}.json"
|
|
171
169
|
cwd: string; // Absolute path to current working directory
|
|
172
|
-
hook_event_name: HookEvent; // "PreToolUse" | "PostToolUse" | "UserPromptSubmit" | "Stop" | "SubagentStop" | "PermissionRequest" | "WorktreeCreate" | "
|
|
170
|
+
hook_event_name: HookEvent; // "PreToolUse" | "PostToolUse" | "UserPromptSubmit" | "Stop" | "SubagentStop" | "PermissionRequest" | "WorktreeCreate" | "SessionStart"
|
|
173
171
|
|
|
174
172
|
// Optional fields based on event type
|
|
175
173
|
tool_name?: string; // Present for PreToolUse, PostToolUse, PermissionRequest
|
|
@@ -178,8 +176,6 @@ export interface HookJsonInput {
|
|
|
178
176
|
user_prompt?: string; // Present for UserPromptSubmit only
|
|
179
177
|
subagent_type?: string; // Present when hook is executed by a subagent
|
|
180
178
|
name?: string; // Present for WorktreeCreate events
|
|
181
|
-
old_cwd?: string; // Present for CwdChanged events
|
|
182
|
-
new_cwd?: string; // Present for CwdChanged events
|
|
183
179
|
source?: SessionStartSource; // Present for SessionStart events
|
|
184
180
|
agent_type?: string; // Present for SessionStart events
|
|
185
181
|
end_source?: SessionEndSource; // Present for SessionEnd events
|
|
@@ -196,8 +192,6 @@ export interface ExtendedHookExecutionContext extends HookExecutionContext {
|
|
|
196
192
|
userPrompt?: string; // User prompt text (UserPromptSubmit only)
|
|
197
193
|
subagentType?: string; // Subagent type when hook is executed by a subagent
|
|
198
194
|
worktreeName?: string; // Worktree name (WorktreeCreate only)
|
|
199
|
-
oldCwd?: string; // Previous working directory (CwdChanged only)
|
|
200
|
-
newCwd?: string; // New working directory (CwdChanged only)
|
|
201
195
|
source?: SessionStartSource; // Session start source (SessionStart only)
|
|
202
196
|
agentType?: string; // Agent type identifier (SessionStart only)
|
|
203
197
|
endSource?: SessionEndSource; // Session end source (SessionEnd only)
|
package/src/types/messaging.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface Message {
|
|
|
14
14
|
id: string; // Unique identifier for the message
|
|
15
15
|
role: "user" | "assistant";
|
|
16
16
|
blocks: MessageBlock[];
|
|
17
|
+
timestamp: string; // ISO 8601 timestamp, assigned at creation
|
|
17
18
|
usage?: Usage; // Usage data for this message's AI operation (assistant messages only)
|
|
18
19
|
additionalFields?: Record<string, unknown>; // Additional metadata from AI responses
|
|
19
20
|
isMeta?: boolean; // Whether the message is a meta message (hidden from UI)
|
package/src/types/session.ts
CHANGED
|
@@ -5,14 +5,6 @@
|
|
|
5
5
|
* SIMPLIFIED: Removed unused interfaces to focus on core functionality
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { Message } from "./messaging.js";
|
|
9
|
-
|
|
10
|
-
// Enhanced message interface for JSONL storage (extends existing Message)
|
|
11
|
-
export interface SessionMessage extends Message {
|
|
12
|
-
timestamp: string; // ISO 8601 - added for JSONL format
|
|
13
|
-
// Inherits: role: "user" | "assistant", blocks: MessageBlock[], usage?, additionalFields?
|
|
14
|
-
}
|
|
15
|
-
|
|
16
8
|
// Session filename structure for simple filename-based metadata
|
|
17
9
|
export interface SessionFilename {
|
|
18
10
|
sessionId: string;
|
package/src/utils/editUtils.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Utility functions for file editing tools
|
|
3
3
|
*/
|
|
4
|
-
import { formatLineNumberPrefix } from "./stringUtils.js";
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Escape regular expression special characters
|
|
@@ -11,77 +10,8 @@ export function escapeRegExp(string: string): string {
|
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
|
-
*
|
|
13
|
+
* Returns a generic error message when old_string is not found.
|
|
15
14
|
*/
|
|
16
|
-
export function analyzeEditMismatch(
|
|
17
|
-
|
|
18
|
-
searchString: string,
|
|
19
|
-
): string {
|
|
20
|
-
const contentLines = content.split("\n");
|
|
21
|
-
const searchLines = searchString.split("\n");
|
|
22
|
-
|
|
23
|
-
if (searchLines.length === 0 || contentLines.length === 0) {
|
|
24
|
-
return "old_string not found in file (empty search or content)";
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
let bestMatchIndex = -1;
|
|
28
|
-
let bestMatchScore = -1;
|
|
29
|
-
|
|
30
|
-
// Sliding window to find the best partial match
|
|
31
|
-
for (let i = 0; i <= contentLines.length - searchLines.length; i++) {
|
|
32
|
-
let currentScore = 0;
|
|
33
|
-
for (let j = 0; j < searchLines.length; j++) {
|
|
34
|
-
if (contentLines[i + j] === searchLines[j]) {
|
|
35
|
-
currentScore++;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Heuristic: prioritize matches where first or last lines match
|
|
40
|
-
if (contentLines[i] === searchLines[0]) currentScore += 0.5;
|
|
41
|
-
if (
|
|
42
|
-
contentLines[i + searchLines.length - 1] ===
|
|
43
|
-
searchLines[searchLines.length - 1]
|
|
44
|
-
)
|
|
45
|
-
currentScore += 0.5;
|
|
46
|
-
|
|
47
|
-
// Also consider trimmed matches to catch indentation issues
|
|
48
|
-
for (let j = 0; j < searchLines.length; j++) {
|
|
49
|
-
if (
|
|
50
|
-
contentLines[i + j].trim() === searchLines[j].trim() &&
|
|
51
|
-
contentLines[i + j] !== searchLines[j]
|
|
52
|
-
) {
|
|
53
|
-
currentScore += 0.1;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (currentScore > bestMatchScore) {
|
|
58
|
-
bestMatchScore = currentScore;
|
|
59
|
-
bestMatchIndex = i;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// If no decent match found (score <= 0), return generic message
|
|
64
|
-
if (bestMatchScore <= 0) {
|
|
65
|
-
return "old_string not found in file (no similar block found)";
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Generate detailed report
|
|
69
|
-
const reportLines: string[] = [
|
|
70
|
-
`old_string not found in file. Best partial match found at line ${bestMatchIndex + 1}:`,
|
|
71
|
-
];
|
|
72
|
-
|
|
73
|
-
for (let j = 0; j < searchLines.length; j++) {
|
|
74
|
-
const lineNum = bestMatchIndex + j + 1;
|
|
75
|
-
const actualLine = contentLines[bestMatchIndex + j];
|
|
76
|
-
const expectedLine = searchLines[j];
|
|
77
|
-
|
|
78
|
-
if (actualLine === expectedLine) {
|
|
79
|
-
reportLines.push(`${formatLineNumberPrefix(lineNum)}${actualLine}`);
|
|
80
|
-
} else {
|
|
81
|
-
reportLines.push(`${formatLineNumberPrefix(lineNum)}- ${expectedLine}`);
|
|
82
|
-
reportLines.push(`${formatLineNumberPrefix(lineNum)}+ ${actualLine}`);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return reportLines.join("\n");
|
|
15
|
+
export function analyzeEditMismatch(): string {
|
|
16
|
+
return "old_string not found in file";
|
|
87
17
|
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
2
2
|
import { exec } from "child_process";
|
|
3
3
|
import { promisify } from "util";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { tmpdir } from "os";
|
|
4
6
|
import type { CustomSlashCommandConfig } from "../types/index.js";
|
|
7
|
+
import {
|
|
8
|
+
SKILL_BASH_MAX_OUTPUT_CHARS,
|
|
9
|
+
PREVIEW_SIZE_BYTES,
|
|
10
|
+
} from "../constants/toolLimits.js";
|
|
5
11
|
|
|
6
12
|
const execAsync = promisify(exec);
|
|
7
13
|
|
|
@@ -138,17 +144,52 @@ export interface BashCommandResult {
|
|
|
138
144
|
exitCode: number;
|
|
139
145
|
}
|
|
140
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Block syntax pattern: ```! command ```
|
|
149
|
+
*/
|
|
150
|
+
const BLOCK_BASH_REGEX = /```!\s*\n?([\s\S]*?)\n?```/g;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Inline syntax pattern: !`command`
|
|
154
|
+
*/
|
|
155
|
+
const INLINE_BASH_REGEX = /!`([^`]+)`/g;
|
|
156
|
+
|
|
141
157
|
export function parseBashCommands(content: string): {
|
|
142
158
|
commands: string[];
|
|
143
159
|
processedContent: string;
|
|
144
160
|
} {
|
|
145
|
-
|
|
161
|
+
// Performance gate: skip expensive regex if no bash pattern exists
|
|
162
|
+
// Covers the common case where 93% of skills have no bash substitution
|
|
163
|
+
if (!content.includes("!`") && !content.includes("```!")) {
|
|
164
|
+
return { commands: [], processedContent: content };
|
|
165
|
+
}
|
|
166
|
+
|
|
146
167
|
const commands: string[] = [];
|
|
147
|
-
let match;
|
|
148
168
|
|
|
149
|
-
// Extract
|
|
150
|
-
|
|
151
|
-
|
|
169
|
+
// Extract block commands
|
|
170
|
+
let blockMatch;
|
|
171
|
+
const blockRegex = new RegExp(
|
|
172
|
+
BLOCK_BASH_REGEX.source,
|
|
173
|
+
BLOCK_BASH_REGEX.flags,
|
|
174
|
+
);
|
|
175
|
+
while ((blockMatch = blockRegex.exec(content)) !== null) {
|
|
176
|
+
const cmd = blockMatch[1].trim();
|
|
177
|
+
if (cmd) {
|
|
178
|
+
commands.push(cmd);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Extract inline commands
|
|
183
|
+
let inlineMatch;
|
|
184
|
+
const inlineRegex = new RegExp(
|
|
185
|
+
INLINE_BASH_REGEX.source,
|
|
186
|
+
INLINE_BASH_REGEX.flags,
|
|
187
|
+
);
|
|
188
|
+
while ((inlineMatch = inlineRegex.exec(content)) !== null) {
|
|
189
|
+
const cmd = inlineMatch[1].trim();
|
|
190
|
+
if (cmd) {
|
|
191
|
+
commands.push(cmd);
|
|
192
|
+
}
|
|
152
193
|
}
|
|
153
194
|
|
|
154
195
|
// For now, return the content as-is. The actual command execution
|
|
@@ -160,22 +201,55 @@ export function parseBashCommands(content: string): {
|
|
|
160
201
|
}
|
|
161
202
|
|
|
162
203
|
/**
|
|
163
|
-
*
|
|
204
|
+
* Truncate output if it exceeds the size limit.
|
|
205
|
+
* Writes to a temp file and returns a preview + file path if truncated.
|
|
206
|
+
*/
|
|
207
|
+
export function truncateOutput(output: string): string {
|
|
208
|
+
if (output.length <= SKILL_BASH_MAX_OUTPUT_CHARS) {
|
|
209
|
+
return output;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const preview = output.slice(0, PREVIEW_SIZE_BYTES);
|
|
213
|
+
const tempDir = join(tmpdir(), "wave-skill-bash");
|
|
214
|
+
mkdirSync(tempDir, { recursive: true });
|
|
215
|
+
|
|
216
|
+
const tempFile = join(
|
|
217
|
+
tempDir,
|
|
218
|
+
`output-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.txt`,
|
|
219
|
+
);
|
|
220
|
+
writeFileSync(tempFile, output, "utf-8");
|
|
221
|
+
|
|
222
|
+
return `${preview}\n\n[Output truncated (${output.length} chars). Full output saved to: ${tempFile}]`;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Replace bash command placeholders with their outputs.
|
|
227
|
+
* Uses function replacer to avoid $$, $&, $' corruption in shell output.
|
|
228
|
+
* Handles both inline (!`cmd`) and block (```! cmd ```) syntax.
|
|
164
229
|
*/
|
|
165
230
|
export function replaceBashCommandsWithOutput(
|
|
166
231
|
content: string,
|
|
167
232
|
results: BashCommandResult[],
|
|
168
233
|
): string {
|
|
169
|
-
const bashCommandRegex = /!`([^`]+)`/g;
|
|
170
234
|
let processedContent = content;
|
|
171
235
|
let commandIndex = 0;
|
|
172
236
|
|
|
173
|
-
|
|
237
|
+
// Replace block syntax first: ```! command ```
|
|
238
|
+
processedContent = processedContent.replace(BLOCK_BASH_REGEX, () => {
|
|
239
|
+
if (commandIndex < results.length) {
|
|
240
|
+
const result = results[commandIndex++];
|
|
241
|
+
return truncateOutput(result.output);
|
|
242
|
+
}
|
|
243
|
+
return "";
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Replace inline syntax: !`command`
|
|
247
|
+
processedContent = processedContent.replace(INLINE_BASH_REGEX, () => {
|
|
174
248
|
if (commandIndex < results.length) {
|
|
175
249
|
const result = results[commandIndex++];
|
|
176
|
-
return result.output;
|
|
250
|
+
return truncateOutput(result.output);
|
|
177
251
|
}
|
|
178
|
-
return
|
|
252
|
+
return "";
|
|
179
253
|
});
|
|
180
254
|
|
|
181
255
|
return processedContent;
|
|
@@ -160,6 +160,7 @@ export const addUserMessageToMessages = ({
|
|
|
160
160
|
id: id || generateMessageId(),
|
|
161
161
|
role: "user",
|
|
162
162
|
blocks,
|
|
163
|
+
timestamp: new Date().toISOString(),
|
|
163
164
|
...(isMeta !== undefined && { isMeta }),
|
|
164
165
|
};
|
|
165
166
|
return [...messages, userMessage];
|
|
@@ -231,6 +232,7 @@ export const addAssistantMessageToMessages = (
|
|
|
231
232
|
id: generateMessageId(),
|
|
232
233
|
role: "assistant",
|
|
233
234
|
blocks,
|
|
235
|
+
timestamp: new Date().toISOString(),
|
|
234
236
|
usage, // Include usage data if provided
|
|
235
237
|
...(additionalFields ? { additionalFields: { ...additionalFields } } : {}),
|
|
236
238
|
};
|
|
@@ -407,6 +409,7 @@ export const addErrorBlockToMessage = ({
|
|
|
407
409
|
content: error,
|
|
408
410
|
},
|
|
409
411
|
],
|
|
412
|
+
timestamp: new Date().toISOString(),
|
|
410
413
|
});
|
|
411
414
|
}
|
|
412
415
|
|
|
@@ -430,6 +433,7 @@ export const addBangMessage = ({
|
|
|
430
433
|
exitCode: null,
|
|
431
434
|
},
|
|
432
435
|
],
|
|
436
|
+
timestamp: new Date().toISOString(),
|
|
433
437
|
};
|
|
434
438
|
|
|
435
439
|
return [...messages, outputMessage];
|
|
@@ -620,6 +624,7 @@ export const addNotificationMessageToMessages = ({
|
|
|
620
624
|
id: generateMessageId(),
|
|
621
625
|
role: "user",
|
|
622
626
|
blocks: [block],
|
|
627
|
+
timestamp: new Date().toISOString(),
|
|
623
628
|
};
|
|
624
629
|
|
|
625
630
|
return [...messages, notificationMessage];
|
|
@@ -177,28 +177,17 @@ export class OpenAIClient {
|
|
|
177
177
|
error.body = errorBody;
|
|
178
178
|
|
|
179
179
|
if (response.status === 429 && attempt < maxRetries) {
|
|
180
|
-
const responseHeaders: Record<string, string> = {};
|
|
181
|
-
response.headers.forEach((value, key) => {
|
|
182
|
-
responseHeaders[key] = value;
|
|
183
|
-
});
|
|
184
180
|
logger.warn("OpenAI API 429 Too Many Requests, retrying...", {
|
|
185
181
|
attempt: attempt + 1,
|
|
186
182
|
status: response.status,
|
|
187
|
-
responseHeaders,
|
|
188
183
|
});
|
|
189
184
|
lastError = error;
|
|
190
185
|
continue;
|
|
191
186
|
}
|
|
192
187
|
|
|
193
|
-
const responseHeaders: Record<string, string> = {};
|
|
194
|
-
response.headers.forEach((value, key) => {
|
|
195
|
-
responseHeaders[key] = value;
|
|
196
|
-
});
|
|
197
188
|
logger.error("OpenAI API Error:", {
|
|
198
189
|
status: response.status,
|
|
199
190
|
statusText: response.statusText,
|
|
200
|
-
requestHeaders: headers,
|
|
201
|
-
responseHeaders,
|
|
202
191
|
errorBody,
|
|
203
192
|
});
|
|
204
193
|
throw error;
|