@kjerneverk/execution-openai 1.0.5-dev.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 (50) hide show
  1. package/.kodrdriv-test-cache.json +6 -0
  2. package/LICENSE +18 -0
  3. package/README.md +80 -0
  4. package/dist/index.d.ts +85 -0
  5. package/dist/index.js +103 -0
  6. package/dist/index.js.map +1 -0
  7. package/output/kodrdriv/.kodrdriv-parallel-context.json +589 -0
  8. package/output/kodrdriv/260110-1751-release-notes.md +39 -0
  9. package/output/kodrdriv/260112-2207-commit-message.md +1 -0
  10. package/output/kodrdriv/260112-2208-release-notes.md +36 -0
  11. package/output/kodrdriv/260112-2341-commit-message.md +1 -0
  12. package/output/kodrdriv/260113-0029-commit-message.md +1 -0
  13. package/output/kodrdriv/260113-0030-release-notes.md +5 -0
  14. package/output/kodrdriv/260114-0656-commit-message.md +6 -0
  15. package/output/kodrdriv/260115-0616-commit-message.md +1 -0
  16. package/output/kodrdriv/260115-0739-commit-message.md +1 -0
  17. package/output/kodrdriv/260126-0852-commit-message.md +1 -0
  18. package/output/kodrdriv/260126-0853-release-notes.md +47 -0
  19. package/output/kodrdriv/260126-0854-release-notes.md +50 -0
  20. package/output/kodrdriv/260128-0929-commit-message.md +1 -0
  21. package/output/kodrdriv/260128-0929-release-notes.md +24 -0
  22. package/output/kodrdriv/260128-0959-commit-message.md +6 -0
  23. package/output/kodrdriv/260128-1127-commit-message.md +1 -0
  24. package/output/kodrdriv/260128-1127-release-notes.md +30 -0
  25. package/output/kodrdriv/260130-1639-commit-message.md +5 -0
  26. package/output/kodrdriv/260130-1652-commit-message.md +1 -0
  27. package/output/kodrdriv/260130-1652-release-notes.md +27 -0
  28. package/output/kodrdriv/RELEASE_NOTES.md +25 -0
  29. package/output/kodrdriv/RELEASE_TITLE.md +1 -0
  30. package/output/kodrdriv/agentic-reflection-commit-2026-01-13T06-07-12-251Z.md +97 -0
  31. package/output/kodrdriv/agentic-reflection-commit-2026-01-13T07-41-08-151Z.md +97 -0
  32. package/output/kodrdriv/agentic-reflection-commit-2026-01-13T08-29-26-449Z.md +97 -0
  33. package/output/kodrdriv/agentic-reflection-commit-2026-01-14T14-56-03-314Z.md +102 -0
  34. package/output/kodrdriv/agentic-reflection-commit-2026-01-15T14-16-42-406Z.md +97 -0
  35. package/output/kodrdriv/agentic-reflection-commit-2026-01-15T15-39-56-545Z.md +114 -0
  36. package/output/kodrdriv/agentic-reflection-commit-2026-01-26T16-52-42-503Z.md +152 -0
  37. package/output/kodrdriv/agentic-reflection-commit-2026-01-28T17-59-30-913Z.md +204 -0
  38. package/output/kodrdriv/agentic-reflection-commit-2026-01-31T00-39-30-443Z.md +245 -0
  39. package/output/kodrdriv/agentic-reflection-commit-2026-01-31T00-52-07-165Z.md +152 -0
  40. package/output/kodrdriv/agentic-reflection-release-2026-01-11T01-51-19-115Z.md +277 -0
  41. package/output/kodrdriv/agentic-reflection-release-2026-01-13T06-08-15-507Z.md +289 -0
  42. package/output/kodrdriv/agentic-reflection-release-2026-01-13T08-30-05-728Z.md +312 -0
  43. package/output/kodrdriv/agentic-reflection-release-2026-01-26T16-53-34-128Z.md +417 -0
  44. package/output/kodrdriv/agentic-reflection-release-2026-01-26T16-53-55-634Z.md +391 -0
  45. package/output/kodrdriv/agentic-reflection-release-2026-01-26T16-54-13-700Z.md +456 -0
  46. package/output/kodrdriv/agentic-reflection-release-2026-01-26T16-54-22-655Z.md +496 -0
  47. package/output/kodrdriv/agentic-reflection-release-2026-01-26T16-54-32-261Z.md +490 -0
  48. package/output/kodrdriv/agentic-reflection-release-2026-01-31T00-52-29-053Z.md +334 -0
  49. package/package.json +58 -0
  50. package/package.json~ +57 -0
@@ -0,0 +1,490 @@
1
+ # Agentic Workflow - Self-Reflection Report
2
+
3
+ Generated: 2026-01-26T16:54:32.262Z
4
+
5
+ ## Execution Summary
6
+
7
+ - **Iterations**: 7
8
+ - **Tool Calls**: 22
9
+ - **Unique Tools**: 11
10
+
11
+ ## Tool Effectiveness Analysis
12
+
13
+ | Tool | Calls | Success | Failures | Success Rate | Avg Duration |
14
+ |------|-------|---------|----------|--------------|--------------|
15
+ | get_file_content | 7 | 7 | 0 | 100.0% | 1ms |
16
+ | search_codebase | 4 | 4 | 0 | 100.0% | 14ms |
17
+ | get_file_history | 3 | 3 | 0 | 100.0% | 18ms |
18
+ | get_release_stats | 1 | 1 | 0 | 100.0% | 49ms |
19
+ | get_tag_history | 1 | 1 | 0 | 100.0% | 72ms |
20
+ | analyze_commit_patterns | 1 | 1 | 0 | 100.0% | 11ms |
21
+ | get_breaking_changes | 1 | 1 | 0 | 100.0% | 28ms |
22
+ | group_files_by_concern | 1 | 1 | 0 | 100.0% | 0ms |
23
+ | get_file_dependencies | 1 | 1 | 0 | 100.0% | 21ms |
24
+ | compare_previous_release | 1 | 1 | 0 | 100.0% | 36ms |
25
+ | get_related_tests | 1 | 1 | 0 | 100.0% | 0ms |
26
+
27
+ ### Tool Performance Insights
28
+
29
+ **Most Frequently Used:**
30
+ - get_release_stats: 1 calls
31
+ - get_tag_history: 1 calls
32
+ - analyze_commit_patterns: 1 calls
33
+
34
+ ## Recommendations for Improvement
35
+
36
+ - **Underutilized Tools**: Many tools were called only once. Consider whether all tools are necessary or if the agent needs better guidance on when to use them.
37
+
38
+ ## Detailed Execution Timeline
39
+
40
+ | Time | Iteration | Tool | Result | Duration |
41
+ |------|-----------|------|--------|----------|
42
+ | 8:52:48 AM | 1 | get_release_stats | ✅ Success | 49ms |
43
+ | 8:52:48 AM | 1 | get_tag_history | ✅ Success | 72ms |
44
+ | 8:52:48 AM | 1 | analyze_commit_patterns | ✅ Success | 11ms |
45
+ | 8:52:48 AM | 1 | get_breaking_changes | ✅ Success | 28ms |
46
+ | 8:52:55 AM | 2 | group_files_by_concern | ✅ Success | 0ms |
47
+ | 8:52:55 AM | 2 | get_file_content | ✅ Success | 1ms |
48
+ | 8:52:55 AM | 2 | get_file_content | ✅ Success | 0ms |
49
+ | 8:52:55 AM | 2 | get_file_content | ✅ Success | 0ms |
50
+ | 8:52:55 AM | 2 | get_file_content | ✅ Success | 1ms |
51
+ | 8:52:55 AM | 2 | get_file_content | ✅ Success | 0ms |
52
+ | 8:52:55 AM | 2 | get_file_dependencies | ✅ Success | 21ms |
53
+ | 8:52:55 AM | 2 | search_codebase | ✅ Success | 12ms |
54
+ | 8:52:55 AM | 2 | search_codebase | ✅ Success | 12ms |
55
+ | 8:52:55 AM | 2 | compare_previous_release | ✅ Success | 36ms |
56
+ | 8:53:06 AM | 3 | get_file_history | ✅ Success | 27ms |
57
+ | 8:53:06 AM | 3 | get_file_history | ✅ Success | 15ms |
58
+ | 8:53:06 AM | 3 | get_file_history | ✅ Success | 11ms |
59
+ | 8:53:06 AM | 3 | get_file_content | ✅ Success | 1ms |
60
+ | 8:53:06 AM | 3 | get_related_tests | ✅ Success | 0ms |
61
+ | 8:53:30 AM | 4 | search_codebase | ✅ Success | 17ms |
62
+ | 8:53:32 AM | 5 | search_codebase | ✅ Success | 14ms |
63
+ | 8:53:48 AM | 6 | get_file_content | ✅ Success | 1ms |
64
+
65
+ ## Conversation History
66
+
67
+ <details>
68
+ <summary>Click to expand full agentic interaction</summary>
69
+
70
+ ```json
71
+ [
72
+ {
73
+ "role": "system",
74
+ "content": "You are a professional software engineer writing release notes for your team and users.\n\n## Available Tools\n\nYou have access to tools to investigate the release:\n- `get_tag_history` - Understand release patterns\n- `get_release_stats` - Quantify scope of changes\n- `compare_previous_release` - See how this compares to previous releases\n- `group_files_by_concern` - Identify themes in changes\n- `analyze_commit_patterns` - Detect patterns in commits\n- `get_file_content` - Read file contents or diffs\n- `analyze_diff_section` - Expand unclear changes\n- `get_file_history` - Understand how code evolved\n- `get_file_dependencies` - Assess impact and reach\n- `search_codebase` - Find usage patterns\n- `get_related_tests` - Understand behavior changes\n- `get_breaking_changes` - Identify breaking changes (always use this)\n\nUse these tools to investigate the changes rather than asking for information upfront.\n\n## Your Task\n\nWrite release notes that clearly explain what's in this release and why it matters. Your notes should help users and developers understand what changed without needing to read every commit.\n\nFocus on:\n- What problems does this release solve?\n- What new capabilities does it add?\n- What's the impact on users and developers?\n- Are there breaking changes or important considerations?\n\nUse the available tools to investigate the changes. The more you understand, the better your notes will be.\n\n**Important**: If additional context is provided (from context files or other sources), use your judgment:\n- If the context is relevant to this specific package/release, incorporate it appropriately\n- If the context describes changes in other packages or unrelated work, ignore it\n- Don't fabricate connections between this package and unrelated context\n- Be honest about what changed - only mention what actually happened in this release\n- Context is supplemental information, not a requirement to include\n\n## Investigation Approach\n\nUse tools based on what you need to know:\n\n**Context:**\n- get_tag_history - understand release patterns\n- get_release_stats - quantify scope\n- compare_previous_release - see how this compares\n\n**Understanding:**\n- group_files_by_concern - identify themes\n- analyze_commit_patterns - detect patterns\n- get_file_content - see full context\n- analyze_diff_section - expand unclear changes\n- get_file_history - understand evolution\n\n**Impact:**\n- get_file_dependencies - assess reach\n- search_codebase - find usage patterns\n- get_related_tests - understand behavior changes\n- get_breaking_changes - identify breaking changes (always use)\n\n## Writing Style\n\nWrite naturally and directly:\n- Use plain language that users can understand\n- Be specific about what changed and why\n- Avoid marketing speak and buzzwords\n- No emojis or excessive punctuation\n- No phrases like \"we're excited to announce\"\n- No meta-commentary about the release itself\n- Focus on facts and implications, not enthusiasm\n\nStructure your notes logically:\n- Start with the most important changes\n- Group related changes together\n- Explain breaking changes clearly\n- Include practical examples when helpful\n\n## Output Format\n\nWhen ready, output your release notes in this exact format:\n\nRELEASE_TITLE:\n[A clear, factual title describing the main changes]\n\nRELEASE_BODY:\n[Detailed release notes in Markdown format]\n\nDo not include any JSON, code blocks, or wrapper syntax. Output plain text and markdown only.\nNo conversational remarks or follow-up offers."
75
+ },
76
+ {
77
+ "role": "user",
78
+ "content": "I need comprehensive release notes for changes from main to HEAD.\n\n**CRITICAL VERSION INSTRUCTION: This is a release for version 1.0.0. You MUST use EXACTLY \"1.0.0\" in your release title. DO NOT use any development/prerelease version numbers you may see in the diff (like 1.0.0-dev.0 or similar). The release version is 1.0.0.**\n\n## Your Analysis Task\n\nUse your tools to investigate the changes between main and HEAD:\n1. Use `get_release_stats` to understand the scope of changes\n2. Use `get_tag_history` or `compare_previous_release` to see release patterns\n3. Use `analyze_commit_patterns` to detect themes\n4. Use `group_files_by_concern` to identify logical groupings\n5. Use `get_breaking_changes` to identify breaking changes (always check this)\n6. Use `get_file_content` or `analyze_diff_section` to understand specific changes\n7. Use `get_file_dependencies` and `search_codebase` to assess impact\n\nWrite clear release notes that answer:\n- What's the main story of this release?\n- What problems does it solve?\n- What's the impact on users and developers?\n- Are there breaking changes?\n\nIf context information is provided, use it only if relevant to this specific package.\nDon't force connections that don't exist - if context describes changes in other packages\nor unrelated features, simply ignore it and focus on what actually changed in this release.\n\nStart by gathering statistics and understanding the scope, then investigate specific changes as needed."
79
+ },
80
+ {
81
+ "role": "assistant",
82
+ "content": null,
83
+ "tool_calls": [
84
+ {
85
+ "id": "call_rB9d71g39EX3i4FbpOMUKCZ3",
86
+ "type": "function",
87
+ "function": {
88
+ "name": "get_release_stats",
89
+ "arguments": "{\"fromRef\": \"main\", \"toRef\": \"HEAD\"}"
90
+ }
91
+ },
92
+ {
93
+ "id": "call_XIX7F1m2Z3Ji2xBD8Q9Ktnht",
94
+ "type": "function",
95
+ "function": {
96
+ "name": "get_tag_history",
97
+ "arguments": "{\"limit\": 20, \"pattern\": \"v*\"}"
98
+ }
99
+ },
100
+ {
101
+ "id": "call_nocZ4HmD2yHXWldbTnJhWwoK",
102
+ "type": "function",
103
+ "function": {
104
+ "name": "analyze_commit_patterns",
105
+ "arguments": "{\"fromRef\": \"main\", \"toRef\": \"HEAD\"}"
106
+ }
107
+ },
108
+ {
109
+ "id": "call_6qgh5VXoFVumUtMtbiP9Denw",
110
+ "type": "function",
111
+ "function": {
112
+ "name": "get_breaking_changes",
113
+ "arguments": "{\"fromRef\": \"main\", \"toRef\": \"HEAD\"}"
114
+ }
115
+ }
116
+ ]
117
+ },
118
+ {
119
+ "role": "tool",
120
+ "tool_call_id": "call_rB9d71g39EX3i4FbpOMUKCZ3",
121
+ "content": "Total commits: 6\n\nContributors:\n 6\tTim O'Brien\n\n\nFile changes: 5 files changed, 116 insertions(+), 50 deletions(-)\n\nTop 10 most changed files:\n vite.config.ts | 9 +++-\n src/index.ts | 148 +++++++++++++++++++++++++++++++++++++++------------------\n package.json | 6 ++-\n README.md | 2 +\n 5 files changed, 116 insertions(+), 50 deletions(-)\n .gitignore | 1 +\n",
122
+ "name": "get_release_stats"
123
+ },
124
+ {
125
+ "role": "tool",
126
+ "tool_call_id": "call_XIX7F1m2Z3Ji2xBD8Q9Ktnht",
127
+ "content": "Recent release tags:\nv0.0.4: 2026-01-13 00:30:54 -0800 - chore(release): bump @riotprompt/execution-openai to 0.0.4 (#7)\nv0.0.3: 2026-01-12 22:09:39 -0800 - chore(release): bump @riotprompt/execution-openai to 0.0.3 (#6)\nv0.0.3-dev.0: tag v0.0.3-dev.0\nTagger: Tim O'Brien <tobrien@discursive.com>\n\n0.0.3-dev.0\n2026-01-10 17:54:34 -0800 - 0.0.3-dev.0\nv0.0.2: 2026-01-10 17:51:23 -0800 - Updated and separated tests (#5)\nv0.0.2-dev.0: tag v0.0.2-dev.0\nTagger: Tim O'Brien <tobrien@discursive.com>\n\n0.0.2-dev.0\n2026-01-10 11:22:13 -0800 - 0.0.2-dev.0",
128
+ "name": "get_tag_history"
129
+ },
130
+ {
131
+ "role": "tool",
132
+ "tool_call_id": "call_nocZ4HmD2yHXWldbTnJhWwoK",
133
+ "content": "Commit types:\n chore: 5\n feat: 1\n\nTop keywords in commits:\n chore: 5\n release: 2\n openai: 2\n kodrdriv: 2\n riotprompt: 1\n execution: 1\n gitignore: 1\n pattern: 1\n ignore: 1\n internal: 1\n files: 1\n build: 1\n precommit: 1\n script: 1\n validate: 1",
134
+ "name": "analyze_commit_patterns"
135
+ },
136
+ {
137
+ "role": "tool",
138
+ "tool_call_id": "call_6qgh5VXoFVumUtMtbiP9Denw",
139
+ "content": "No obvious breaking changes detected. Manual review recommended for API changes.",
140
+ "name": "get_breaking_changes"
141
+ },
142
+ {
143
+ "role": "assistant",
144
+ "content": null,
145
+ "tool_calls": [
146
+ {
147
+ "id": "call_DJkQMZ757anGMgEB4GIwxdwX",
148
+ "type": "function",
149
+ "function": {
150
+ "name": "group_files_by_concern",
151
+ "arguments": "{\"filePaths\": [\"vite.config.ts\", \"src/index.ts\", \"package.json\", \"README.md\", \".gitignore\"]}"
152
+ }
153
+ },
154
+ {
155
+ "id": "call_M4003mslc9XjjOYz6k27a7Wi",
156
+ "type": "function",
157
+ "function": {
158
+ "name": "get_file_content",
159
+ "arguments": "{\"filePath\": \"src/index.ts\", \"includeLineNumbers\": true}"
160
+ }
161
+ },
162
+ {
163
+ "id": "call_SYdY6uYDrNsh8LcELHl7JDi1",
164
+ "type": "function",
165
+ "function": {
166
+ "name": "get_file_content",
167
+ "arguments": "{\"filePath\": \"package.json\", \"includeLineNumbers\": true}"
168
+ }
169
+ },
170
+ {
171
+ "id": "call_uzBgYMaCUCjreF9zJknAnQxp",
172
+ "type": "function",
173
+ "function": {
174
+ "name": "get_file_content",
175
+ "arguments": "{\"filePath\": \"vite.config.ts\", \"includeLineNumbers\": true}"
176
+ }
177
+ },
178
+ {
179
+ "id": "call_Be37iIrmhmr41hCI3hTtTvCu",
180
+ "type": "function",
181
+ "function": {
182
+ "name": "get_file_content",
183
+ "arguments": "{\"filePath\": \"README.md\", \"includeLineNumbers\": true}"
184
+ }
185
+ },
186
+ {
187
+ "id": "call_2gOGHhEDL11DeaWiZYg0XDZq",
188
+ "type": "function",
189
+ "function": {
190
+ "name": "get_file_content",
191
+ "arguments": "{\"filePath\": \".gitignore\", \"includeLineNumbers\": true}"
192
+ }
193
+ },
194
+ {
195
+ "id": "call_O4rzDDpxETJYuEFWdck1Dn5Z",
196
+ "type": "function",
197
+ "function": {
198
+ "name": "get_file_dependencies",
199
+ "arguments": "{\"filePaths\": [\"src/index.ts\", \"vite.config.ts\"]}"
200
+ }
201
+ },
202
+ {
203
+ "id": "call_I3xknHMN1HF070EvEZMuEjmW",
204
+ "type": "function",
205
+ "function": {
206
+ "name": "search_codebase",
207
+ "arguments": "{\"query\": \"execution-openai\", \"contextLines\": 2}"
208
+ }
209
+ },
210
+ {
211
+ "id": "call_KlJPHyTSPthDTtlgFdWioeHN",
212
+ "type": "function",
213
+ "function": {
214
+ "name": "search_codebase",
215
+ "arguments": "{\"query\": \"OpenAI\", \"contextLines\": 2}"
216
+ }
217
+ },
218
+ {
219
+ "id": "call_liRKr27bWq9jKBk8tsN445rU",
220
+ "type": "function",
221
+ "function": {
222
+ "name": "compare_previous_release",
223
+ "arguments": "{\"previousTag\": \"v0.0.4\", \"currentRef\": \"HEAD\", \"statsOnly\": false}"
224
+ }
225
+ }
226
+ ]
227
+ },
228
+ {
229
+ "role": "tool",
230
+ "tool_call_id": "call_DJkQMZ757anGMgEB4GIwxdwX",
231
+ "content": "other (2 files):\n - vite.config.ts\n - .gitignore\n\nsource:src (1 files):\n - src/index.ts\n\ndependencies (1 files):\n - package.json\n\ndocumentation (1 files):\n - README.md\n\nSuggestion: These 4 groups represent different concerns in the release.",
232
+ "name": "group_files_by_concern"
233
+ },
234
+ {
235
+ "role": "tool",
236
+ "tool_call_id": "call_M4003mslc9XjjOYz6k27a7Wi",
237
+ "content": "1: /**\n2: * Execution OpenAI Package\n3: *\n4: * OpenAI provider implementation for LLM execution.\n5: *\n6: * @packageDocumentation\n7: */\n8: \n9: import OpenAI from 'openai';\n10: import { getRedactor } from '@theunwalked/offrecord';\n11: import { \n12: createSafeError, \n13: configureErrorSanitizer,\n14: configureSecretGuard,\n15: } from '@theunwalked/spotclean';\n16: \n17: // Register OpenAI API key patterns on module load\n18: const redactor = getRedactor();\n19: redactor.register({\n20: name: 'openai',\n21: patterns: [\n22: /sk-[a-zA-Z0-9]{20,}/g,\n23: /sk-proj-[a-zA-Z0-9_-]+/g,\n24: ],\n25: validator: (key: string) => /^sk-(proj-)?[a-zA-Z0-9_-]{20,}$/.test(key),\n26: envVar: 'OPENAI_API_KEY',\n27: description: 'OpenAI API keys',\n28: });\n29: \n30: // Configure spotclean for error sanitization\n31: configureErrorSanitizer({\n32: enabled: true,\n33: environment: process.env.NODE_ENV === 'production' ? 'production' : 'development',\n34: includeCorrelationId: true,\n35: sanitizeStackTraces: process.env.NODE_ENV === 'production',\n36: maxMessageLength: 500,\n37: });\n38: \n39: configureSecretGuard({\n40: enabled: true,\n41: redactionText: '[REDACTED]',\n42: preservePartial: false,\n43: preserveLength: 0,\n44: customPatterns: [\n45: { name: 'openai', pattern: /sk-[a-zA-Z0-9]{20,}/g, description: 'OpenAI API key' },\n46: { name: 'openai-proj', pattern: /sk-proj-[a-zA-Z0-9_-]+/g, description: 'OpenAI project key' },\n47: ],\n48: });\n49: \n50: // ===== INLINE TYPES (from 'execution' package) =====\n51: // These types are duplicated here for build independence.\n52: // When 'execution' is published, these can be imported from there.\n53: \n54: export type Model = string;\n55: \n56: export interface Message {\n57: role: 'user' | 'assistant' | 'system' | 'developer' | 'tool';\n58: content: string | string[] | null;\n59: name?: string;\n60: }\n61: \n62: export interface Request {\n63: messages: Message[];\n64: model: Model;\n65: responseFormat?: any;\n66: validator?: any;\n67: addMessage(message: Message): void;\n68: }\n69: \n70: export interface ProviderResponse {\n71: content: string;\n72: model: string;\n73: usage?: {\n74: inputTokens: number;\n75: outputTokens: number;\n76: };\n77: toolCalls?: Array<{\n78: id: string;\n79: type: 'function';\n80: function: {\n81: name: string;\n82: arguments: string;\n83: };\n84: }>;\n85: }\n86: \n87: export interface ExecutionOptions {\n88: apiKey?: string;\n89: model?: string;\n90: temperature?: number;\n91: maxTokens?: number;\n92: timeout?: number;\n93: retries?: number;\n94: }\n95: \n96: export interface Provider {\n97: readonly name: string;\n98: execute(request: Request, options?: ExecutionOptions): Promise<ProviderResponse>;\n99: supportsModel?(model: Model): boolean;\n100: }\n101: \n102: /**\n103: * OpenAI Provider implementation\n104: */\n105: export class OpenAIProvider implements Provider {\n106: readonly name = 'openai';\n107: \n108: /**\n109: * Check if this provider supports a given model\n110: */\n111: supportsModel(model: Model): boolean {\n112: if (!model) return true; // Default to OpenAI\n113: return (\n114: model.startsWith('gpt') ||\n115: model.startsWith('o1') ||\n116: model.startsWith('o3') ||\n117: model.startsWith('o4')\n118: );\n119: }\n120: \n121: /**\n122: * Execute a request against OpenAI\n123: */\n124: async execute(\n125: request: Request,\n126: options: ExecutionOptions = {}\n127: ): Promise<ProviderResponse> {\n128: const apiKey = options.apiKey || process.env.OPENAI_API_KEY;\n129: \n130: if (!apiKey) {\n131: throw new Error('OpenAI API key is required. Set OPENAI_API_KEY environment variable.');\n132: }\n133: \n134: // Validate key format\n135: const validation = redactor.validateKey(apiKey, 'openai');\n136: if (!validation.valid) {\n137: throw new Error('Invalid OpenAI API key format');\n138: }\n139: \n140: try {\n141: const client = new OpenAI({ apiKey });\n142: \n143: const model = options.model || request.model || 'gpt-4';\n144: \n145: // Convert messages to OpenAI format\n146: const messages = request.messages.map((msg) => {\n147: const role =\n148: msg.role === 'developer' ? 'system' : msg.role;\n149: \n150: return {\n151: role: role,\n152: content:\n153: typeof msg.content === 'string'\n154: ? msg.content\n155: : JSON.stringify(msg.content),\n156: name: msg.name,\n157: } as any;\n158: });\n159: \n160: const response = await client.chat.completions.create({\n161: model: model,\n162: messages: messages,\n163: temperature: options.temperature,\n164: max_tokens: options.maxTokens,\n165: response_format: request.responseFormat,\n166: });\n167: \n168: const choice = response.choices[0];\n169: \n170: return {\n171: content: choice.message.content || '',\n172: model: response.model,\n173: usage: response.usage\n174: ? {\n175: inputTokens: response.usage.prompt_tokens,\n176: outputTokens: response.usage.completion_tokens,\n177: }\n178: : undefined,\n179: toolCalls: choice.message.tool_calls?.map((tc) => ({\n180: id: tc.id,\n181: type: 'function' as const,\n182: function: {\n183: name: tc.function.name,\n184: arguments: tc.function.arguments,\n185: },\n186: })),\n187: };\n188: } catch (error) {\n189: // Sanitize error to remove any API keys from error messages\n190: // Use spotclean for comprehensive error sanitization\n191: throw createSafeError(error as Error, { provider: 'openai' });\n192: }\n193: }\n194: }\n195: \n196: /**\n197: * Create a new OpenAI provider instance\n198: */\n199: export function createOpenAIProvider(): OpenAIProvider {\n200: return new OpenAIProvider();\n201: }\n202: \n203: /**\n204: * Package version\n205: */\n206: export const VERSION = '0.0.1';\n207: \n208: export default OpenAIProvider;\n209: ",
238
+ "name": "get_file_content"
239
+ },
240
+ {
241
+ "role": "tool",
242
+ "tool_call_id": "call_SYdY6uYDrNsh8LcELHl7JDi1",
243
+ "content": "1: {\n2: \"name\": \"@riotprompt/execution-openai\",\n3: \"version\": \"1.0.0\",\n4: \"description\": \"OpenAI provider for execution - implements Provider interface\",\n5: \"type\": \"module\",\n6: \"main\": \"./dist/index.js\",\n7: \"types\": \"./dist/index.d.ts\",\n8: \"exports\": {\n9: \".\": {\n10: \"types\": \"./dist/index.d.ts\",\n11: \"import\": \"./dist/index.js\"\n12: }\n13: },\n14: \"engines\": {\n15: \"node\": \">=24.0.0\"\n16: },\n17: \"scripts\": {\n18: \"clean\": \"rm -rf dist\",\n19: \"build\": \"vite build\",\n20: \"test\": \"vitest run --coverage\",\n21: \"test:coverage\": \"vitest run --coverage\",\n22: \"lint\": \"eslint src\",\n23: \"precommit\": \"npm run build && npm run lint && npm run test\",\n24: \"prepublishOnly\": \"npm run clean && npm run build\"\n25: },\n26: \"keywords\": [\n27: \"llm\",\n28: \"openai\",\n29: \"gpt\",\n30: \"execution\",\n31: \"provider\"\n32: ],\n33: \"author\": \"Tim O'Brien <tobrien@discursive.com>\",\n34: \"license\": \"Apache-2.0\",\n35: \"repository\": {\n36: \"type\": \"git\",\n37: \"url\": \"https://github.com/kjerneverk/execution-openai\"\n38: },\n39: \"dependencies\": {\n40: \"@theunwalked/offrecord\": \"^0.0.1\",\n41: \"@theunwalked/spotclean\": \"^0.0.3\",\n42: \"openai\": \"^4.103.0\",\n43: \"tiktoken\": \"^1.0.21\"\n44: },\n45: \"devDependencies\": {\n46: \"@types/node\": \"^25.0.6\",\n47: \"@typescript-eslint/eslint-plugin\": \"^8.33.1\",\n48: \"@typescript-eslint/parser\": \"^8.33.1\",\n49: \"@vitest/coverage-v8\": \"^3.2.4\",\n50: \"eslint\": \"^9.28.0\",\n51: \"globals\": \"^16.2.0\",\n52: \"typescript\": \"^5.8.3\",\n53: \"vite\": \"^7.0.4\",\n54: \"vite-plugin-dts\": \"^4.5.4\",\n55: \"vitest\": \"^3.2.4\"\n56: }\n57: }\n58: ",
244
+ "name": "get_file_content"
245
+ },
246
+ {
247
+ "role": "tool",
248
+ "tool_call_id": "call_uzBgYMaCUCjreF9zJknAnQxp",
249
+ "content": "1: import { defineConfig } from \"vite\";\n2: import dts from \"vite-plugin-dts\";\n3: \n4: export default defineConfig({\n5: build: {\n6: lib: {\n7: entry: \"src/index.ts\",\n8: name: \"execution-openai\",\n9: fileName: () => \"index.js\",\n10: formats: [\"es\"],\n11: },\n12: rollupOptions: {\n13: external: [\n14: \"openai\",\n15: \"tiktoken\",\n16: \"execution\",\n17: \"@theunwalked/offrecord\",\n18: \"@theunwalked/spotclean\",\n19: \"node:crypto\",\n20: ],\n21: },\n22: sourcemap: true,\n23: minify: false,\n24: },\n25: plugins: [dts({ rollupTypes: true })],\n26: });\n27: ",
250
+ "name": "get_file_content"
251
+ },
252
+ {
253
+ "role": "tool",
254
+ "tool_call_id": "call_Be37iIrmhmr41hCI3hTtTvCu",
255
+ "content": "1: # execution-openai\n2: \n3: OpenAI provider implementation for LLM execution. Implements the `Provider` interface from the `execution` package.\n4: \n5: ## Installation\n6: \n7: ```bash\n8: npm install execution-openai openai\n9: ```\n10: \n11: ## Usage\n12: \n13: ```typescript\n14: import { OpenAIProvider, createOpenAIProvider } from 'execution-openai';\n15: \n16: // Create provider\n17: const provider = createOpenAIProvider();\n18: \n19: // Or use the class directly\n20: const provider = new OpenAIProvider();\n21: \n22: // Execute a request\n23: const response = await provider.execute(\n24: {\n25: model: 'gpt-4o',\n26: messages: [\n27: { role: 'system', content: 'You are helpful.' },\n28: { role: 'user', content: 'Hello!' }\n29: ],\n30: addMessage: () => {},\n31: },\n32: {\n33: apiKey: process.env.OPENAI_API_KEY,\n34: temperature: 0.7,\n35: maxTokens: 1000,\n36: }\n37: );\n38: \n39: console.log(response.content);\n40: console.log(response.usage); // { inputTokens: X, outputTokens: Y }\n41: ```\n42: \n43: ## Supported Models\n44: \n45: The provider supports all OpenAI models:\n46: - GPT-4 family (gpt-4, gpt-4o, gpt-4-turbo, etc.)\n47: - O-series (o1, o1-preview, o1-mini, o3, etc.)\n48: - GPT-3.5 family\n49: \n50: ## API Key\n51: \n52: Set via:\n53: 1. `options.apiKey` parameter\n54: 2. `OPENAI_API_KEY` environment variable\n55: \n56: ## Response Format\n57: \n58: ```typescript\n59: interface ProviderResponse {\n60: content: string;\n61: model: string;\n62: usage?: {\n63: inputTokens: number;\n64: outputTokens: number;\n65: };\n66: toolCalls?: ToolCall[];\n67: }\n68: ```\n69: \n70: ## Related Packages\n71: \n72: - `execution` - Core interfaces (no SDK dependencies)\n73: - `execution-anthropic` - Anthropic provider\n74: - `execution-gemini` - Google Gemini provider\n75: \n76: ## License\n77: \n78: Apache-2.0\n79: \n80: <!-- v1.0.0 -->\n81: ",
256
+ "name": "get_file_content"
257
+ },
258
+ {
259
+ "role": "tool",
260
+ "tool_call_id": "call_2gOGHhEDL11DeaWiZYg0XDZq",
261
+ "content": "1: *~\n2: .env \n3: dist\n4: node_modules\n5: *.log\n6: .vscode\n7: coverage/\n8: **/.DS_Store\n9: package-lock.json\n10: \n11: output/\n12: .kodrdriv*\n13: ",
262
+ "name": "get_file_content"
263
+ },
264
+ {
265
+ "role": "tool",
266
+ "tool_call_id": "call_O4rzDDpxETJYuEFWdck1Dn5Z",
267
+ "content": "No files found that import the specified files",
268
+ "name": "get_file_dependencies"
269
+ },
270
+ {
271
+ "role": "tool",
272
+ "tool_call_id": "call_I3xknHMN1HF070EvEZMuEjmW",
273
+ "content": ".kodrdriv-test-cache.json-1-{\n.kodrdriv-test-cache.json:2: \"/Users/tobrien/gitw/kjerneverk/execution-openai\": {\n.kodrdriv-test-cache.json-3- \"lastTestRun\": 1768074156142,\n.kodrdriv-test-cache.json-4- \"lastCommitHash\": \"7948ae0dfcf8860fcbcc9965dff01f047e52a5c2\"\n--\nREADME.md:1:# execution-openai\nREADME.md-2-\nREADME.md-3-OpenAI provider implementation for LLM execution. Implements the `Provider` interface from the `execution` package.\n--\nREADME.md-6-\nREADME.md-7-```bash\nREADME.md:8:npm install execution-openai openai\nREADME.md-9-```\nREADME.md-10-\n--\nREADME.md-12-\nREADME.md-13-```typescript\nREADME.md:14:import { OpenAIProvider, createOpenAIProvider } from 'execution-openai';\nREADME.md-15-\nREADME.md-16-// Create provider\n--\nguide/index.md:1:# AI Agent Guide: execution-openai\nguide/index.md-2-\nguide/index.md-3-OpenAI provider for the `execution` interface.\n--\nguide/index.md-6-\nguide/index.md-7-```typescript\nguide/index.md:8:import { OpenAIProvider } from 'execution-openai';\nguide/index.md-9-\nguide/index.md-10-const provider = new OpenAIProvider({\n--\nguide/index.md-41-\nguide/index.md-42-```typescript\nguide/index.md:43:import { countTokens, getEncoding } from 'execution-openai';\nguide/index.md-44-\nguide/index.md-45-const tokens = countTokens('Hello!', 'gpt-4o');\n--\npackage.json-1-{\npackage.json:2: \"name\": \"@riotprompt/execution-openai\",\npackage.json-3- \"version\": \"1.0.0\",\npackage.json-4- \"description\": \"OpenAI provider for execution - implements Provider interface\",\n--\npackage.json-35- \"repository\": {\npackage.json-36- \"type\": \"git\",\npackage.json:37: \"url\": \"https://github.com/kjerneverk/execution-openai\"\npackage.json-38- },\npackage.json-39- \"dependencies\": {\n--\ntests/index.test.ts-1-/**\ntests/index.test.ts:2: * Tests for execution-openai package\ntests/index.test.ts-3- */\ntests/index.test.ts-4-\n--\nvite.config.ts-6- lib: {\nvite.config.ts-7- entry: \"src/index.ts\",\nvite.config.ts:8: name: \"execution-openai\",\nvite.config.ts-9- fileName: () => \"index.js\",\nvite.config.ts-10- formats: [\"es\"],\n",
274
+ "name": "search_codebase"
275
+ },
276
+ {
277
+ "role": "tool",
278
+ "tool_call_id": "call_KlJPHyTSPthDTtlgFdWioeHN",
279
+ "content": "README.md-1-# execution-openai\nREADME.md-2-\nREADME.md:3:OpenAI provider implementation for LLM execution. Implements the `Provider` interface from the `execution` package.\nREADME.md-4-\nREADME.md-5-## Installation\n--\nREADME.md-12-\nREADME.md-13-```typescript\nREADME.md:14:import { OpenAIProvider, createOpenAIProvider } from 'execution-openai';\nREADME.md-15-\nREADME.md-16-// Create provider\nREADME.md:17:const provider = createOpenAIProvider();\nREADME.md-18-\nREADME.md-19-// Or use the class directly\nREADME.md:20:const provider = new OpenAIProvider();\nREADME.md-21-\nREADME.md-22-// Execute a request\n--\nREADME.md-43-## Supported Models\nREADME.md-44-\nREADME.md:45:The provider supports all OpenAI models:\nREADME.md-46-- GPT-4 family (gpt-4, gpt-4o, gpt-4-turbo, etc.)\nREADME.md-47-- O-series (o1, o1-preview, o1-mini, o3, etc.)\n--\nguide/index.md-1-# AI Agent Guide: execution-openai\nguide/index.md-2-\nguide/index.md:3:OpenAI provider for the `execution` interface.\nguide/index.md-4-\nguide/index.md-5-## Quick Start\nguide/index.md-6-\nguide/index.md-7-```typescript\nguide/index.md:8:import { OpenAIProvider } from 'execution-openai';\nguide/index.md-9-\nguide/index.md:10:const provider = new OpenAIProvider({\nguide/index.md-11- apiKey: process.env.OPENAI_API_KEY\nguide/index.md-12-});\n--\nguide/index.md-20-\nguide/index.md-21-```typescript\nguide/index.md:22:new OpenAIProvider({\nguide/index.md-23- apiKey: 'sk-...', // Or use OPENAI_API_KEY env var\nguide/index.md-24- baseURL: '...', // Custom endpoint\n--\npackage.json-2- \"name\": \"@riotprompt/execution-openai\",\npackage.json-3- \"version\": \"1.0.0\",\npackage.json:4: \"description\": \"OpenAI provider for execution - implements Provider interface\",\npackage.json-5- \"type\": \"module\",\npackage.json-6- \"main\": \"./dist/index.js\",\n--\nsrc/index.ts-1-/**\nsrc/index.ts:2: * Execution OpenAI Package\nsrc/index.ts-3- *\nsrc/index.ts:4: * OpenAI provider implementation for LLM execution.\nsrc/index.ts-5- *\nsrc/index.ts-6- * @packageDocumentation\nsrc/index.ts-7- */\nsrc/index.ts-8-\nsrc/index.ts:9:import OpenAI from 'openai';\nsrc/index.ts-10-import { getRedactor } from '@theunwalked/offrecord';\nsrc/index.ts-11-import { \n--\nsrc/index.ts-15-} from '@theunwalked/spotclean';\nsrc/index.ts-16-\nsrc/index.ts:17:// Register OpenAI API key patterns on module load\nsrc/index.ts-18-const redactor = getRedactor();\nsrc/index.ts-19-redactor.register({\n--\nsrc/index.ts-25- validator: (key: string) => /^sk-(proj-)?[a-zA-Z0-9_-]{20,}$/.test(key),\nsrc/index.ts-26- envVar: 'OPENAI_API_KEY',\nsrc/index.ts:27: description: 'OpenAI API keys',\nsrc/index.ts-28-});\nsrc/index.ts-29-\n--\nsrc/index.ts-43- preserveLength: 0,\nsrc/index.ts-44- customPatterns: [\nsrc/index.ts:45: { name: 'openai', pattern: /sk-[a-zA-Z0-9]{20,}/g, description: 'OpenAI API key' },\nsrc/index.ts:46: { name: 'openai-proj', pattern: /sk-proj-[a-zA-Z0-9_-]+/g, description: 'OpenAI project key' },\nsrc/index.ts-47- ],\nsrc/index.ts-48-});\n--\nsrc/index.ts-101-\nsrc/index.ts-102-/**\nsrc/index.ts:103: * OpenAI Provider implementation\nsrc/index.ts-104- */\nsrc/index.ts:105:export class OpenAIProvider implements Provider {\nsrc/index.ts-106- readonly name = 'openai';\nsrc/index.ts-107-\n--\nsrc/index.ts-110- */\nsrc/index.ts-111- supportsModel(model: Model): boolean {\nsrc/index.ts:112: if (!model) return true; // Default to OpenAI\nsrc/index.ts-113- return (\nsrc/index.ts-114- model.startsWith('gpt') ||\n--\nsrc/index.ts-120-\nsrc/index.ts-121- /**\nsrc/index.ts:122: * Execute a request against OpenAI\nsrc/index.ts-123- */\nsrc/index.ts-124- async execute(\n--\nsrc/index.ts-129- \nsrc/index.ts-130- if (!apiKey) {\nsrc/index.ts:131: throw new Error('OpenAI API key is required. Set OPENAI_API_KEY environment variable.');\nsrc/index.ts-132- }\nsrc/index.ts-133-\n--\nsrc/index.ts-135- const validation = redactor.validateKey(apiKey, 'openai');\nsrc/index.ts-136- if (!validation.valid) {\nsrc/index.ts:137: throw new Error('Invalid OpenAI API key format');\nsrc/index.ts-138- }\nsrc/index.ts-139-\nsrc/index.ts-140- try {\nsrc/index.ts:141: const client = new OpenAI({ apiKey });\nsrc/index.ts-142-\nsrc/index.ts-143- const model = options.model || request.model || 'gpt-4';\nsrc/index.ts-144-\nsrc/index.ts:145: // Convert messages to OpenAI format\nsrc/index.ts-146- const messages = request.messages.map((msg) => {\nsrc/index.ts-147- const role =\n--\nsrc/index.ts-195-\nsrc/index.ts-196-/**\nsrc/index.ts:197: * Create a new OpenAI provider instance\nsrc/index.ts-198- */\nsrc/index.ts:199:export function createOpenAIProvider(): OpenAIProvider {\nsrc/index.ts:200: return new OpenAIProvider();\nsrc/index.ts-201-}\nsrc/index.ts-202-\n--\nsrc/index.ts-206-export const VERSION = '0.0.1';\nsrc/index.ts-207-\nsrc/index.ts:208:export default OpenAIProvider;\n--\ntests/index.test.ts-5-import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';\ntests/index.test.ts-6-import {\ntests/index.test.ts:7: OpenAIProvider,\ntests/index.test.ts:8: createOpenAIProvider,\ntests/index.test.ts-9- VERSION,\ntests/index.test.ts-10- type Message,\n--\ntests/index.test.ts-15-} from '../src/index.js';\ntests/index.test.ts-16-\ntests/index.test.ts:17:describe('OpenAIProvider', () => {\ntests/index.test.ts:18: let provider: OpenAIProvider;\ntests/index.test.ts-19-\ntests/index.test.ts-20- beforeEach(() => {\ntests/index.test.ts:21: provider = new OpenAIProvider();\ntests/index.test.ts-22- });\ntests/index.test.ts-23-\n--\ntests/index.test.ts-53- });\ntests/index.test.ts-54-\ntests/index.test.ts:55: it('should return true for empty/undefined model (default to OpenAI)', () => {\ntests/index.test.ts-56- expect(provider.supportsModel('')).toBe(true);\ntests/index.test.ts-57- });\n--\ntests/index.test.ts-78-\ntests/index.test.ts-79- await expect(provider.execute(request)).rejects.toThrow(\ntests/index.test.ts:80: 'OpenAI API key is required'\ntests/index.test.ts-81- );\ntests/index.test.ts-82- });\n--\ntests/index.test.ts-90-\ntests/index.test.ts-91- await expect(provider.execute(request, { apiKey: '' })).rejects.toThrow(\ntests/index.test.ts:92: 'OpenAI API key is required'\ntests/index.test.ts-93- );\ntests/index.test.ts-94- });\n--\ntests/index.test.ts-105-});\ntests/index.test.ts-106-\ntests/index.test.ts:107:describe('createOpenAIProvider', () => {\ntests/index.test.ts:108: it('should create a new OpenAIProvider instance', () => {\ntests/index.test.ts:109: const provider = createOpenAIProvider();\ntests/index.test.ts:110: expect(provider).toBeInstanceOf(OpenAIProvider);\ntests/index.test.ts-111- expect(provider.name).toBe('openai');\ntests/index.test.ts-112- });\n",
280
+ "name": "search_codebase"
281
+ },
282
+ {
283
+ "role": "tool",
284
+ "tool_call_id": "call_liRKr27bWq9jKBk8tsN445rU",
285
+ "content": "Comparison between v0.0.4 and HEAD:\n\nCommits: 6\n\nFile changes:\n .gitignore | 1 +\n README.md | 2 +\n package.json | 6 ++-\n src/index.ts | 148 +++++++++++++++++++++++++++++++++++++++------------------\n vite.config.ts | 9 +++-\n 5 files changed, 116 insertions(+), 50 deletions(-)\n\n\nCommit summary:\ndbca41c chore(release): bump @riotprompt/execution-openai to 1.0.0\n8ff7fa9 chore(gitignore): add .kodrdriv* pattern to ignore kodrdriv internal files\n3019c9a chore: run build in precommit script\n117b7a5 chore(release): bump to 1.0.0-dev.0\neea6bd7 feat(openai): validate API key and sanitize errors with offrecord/spotclean\nc4e9149 chore: bump to 0.0.4-dev.0\n",
286
+ "name": "compare_previous_release"
287
+ },
288
+ {
289
+ "role": "assistant",
290
+ "content": null,
291
+ "tool_calls": [
292
+ {
293
+ "id": "call_quLcMJXqrhrIWgdGIEHONYPl",
294
+ "type": "function",
295
+ "function": {
296
+ "name": "get_file_history",
297
+ "arguments": "{\"filePaths\": [\"src/index.ts\"], \"limit\": 20, \"format\": \"summary\"}"
298
+ }
299
+ },
300
+ {
301
+ "id": "call_rw5xzvvOqIsIOQgBRHz45H5f",
302
+ "type": "function",
303
+ "function": {
304
+ "name": "get_file_history",
305
+ "arguments": "{\"filePaths\": [\"package.json\"], \"limit\": 20, \"format\": \"summary\"}"
306
+ }
307
+ },
308
+ {
309
+ "id": "call_czvYKERodeGdFxuJD9HubmWS",
310
+ "type": "function",
311
+ "function": {
312
+ "name": "get_file_history",
313
+ "arguments": "{\"filePaths\": [\"vite.config.ts\"], \"limit\": 20, \"format\": \"summary\"}"
314
+ }
315
+ },
316
+ {
317
+ "id": "call_2j5va6UhMj8SwW19nlSwjEVu",
318
+ "type": "function",
319
+ "function": {
320
+ "name": "get_file_content",
321
+ "arguments": "{\"filePath\": \"guide/index.md\", \"includeLineNumbers\": true}"
322
+ }
323
+ },
324
+ {
325
+ "id": "call_Y8xO2HhGkYcnjU52u3pwAyLY",
326
+ "type": "function",
327
+ "function": {
328
+ "name": "get_related_tests",
329
+ "arguments": "{\"filePaths\": [\"src/index.ts\"]}"
330
+ }
331
+ }
332
+ ]
333
+ },
334
+ {
335
+ "role": "tool",
336
+ "tool_call_id": "call_quLcMJXqrhrIWgdGIEHONYPl",
337
+ "content": "eea6bd7 - feat(openai): validate API key and sanitize errors with offrecord/spotclean (Tim O'Brien, 12 days ago)\n52ade08 - First commit (Tim O'Brien, 2 weeks ago)\n",
338
+ "name": "get_file_history"
339
+ },
340
+ {
341
+ "role": "tool",
342
+ "tool_call_id": "call_rw5xzvvOqIsIOQgBRHz45H5f",
343
+ "content": "dbca41c - chore(release): bump @riotprompt/execution-openai to 1.0.0 (Tim O'Brien, 24 seconds ago)\n3019c9a - chore: run build in precommit script (Tim O'Brien, 11 days ago)\n117b7a5 - chore(release): bump to 1.0.0-dev.0 (Tim O'Brien, 11 days ago)\neea6bd7 - feat(openai): validate API key and sanitize errors with offrecord/spotclean (Tim O'Brien, 12 days ago)\nc4e9149 - chore: bump to 0.0.4-dev.0 (Tim O'Brien, 13 days ago)\n2f6afb3 - chore(release): bump @riotprompt/execution-openai to 0.0.4 (#7) (Tim O'Brien, 13 days ago)\n77c696f - chore(release): bump @riotprompt/execution-openai to 0.0.3 (#6) (Tim O'Brien, 13 days ago)\nd3ddebd - Updated and separated tests (#5) (Tim O'Brien, 2 weeks ago)\n52ade08 - First commit (Tim O'Brien, 2 weeks ago)\n",
344
+ "name": "get_file_history"
345
+ },
346
+ {
347
+ "role": "tool",
348
+ "tool_call_id": "call_czvYKERodeGdFxuJD9HubmWS",
349
+ "content": "eea6bd7 - feat(openai): validate API key and sanitize errors with offrecord/spotclean (Tim O'Brien, 12 days ago)\n2f6afb3 - chore(release): bump @riotprompt/execution-openai to 0.0.4 (#7) (Tim O'Brien, 13 days ago)\n52ade08 - First commit (Tim O'Brien, 2 weeks ago)\n",
350
+ "name": "get_file_history"
351
+ },
352
+ {
353
+ "role": "tool",
354
+ "tool_call_id": "call_2j5va6UhMj8SwW19nlSwjEVu",
355
+ "content": "1: # AI Agent Guide: execution-openai\n2: \n3: OpenAI provider for the `execution` interface.\n4: \n5: ## Quick Start\n6: \n7: ```typescript\n8: import { OpenAIProvider } from 'execution-openai';\n9: \n10: const provider = new OpenAIProvider({\n11: apiKey: process.env.OPENAI_API_KEY\n12: });\n13: \n14: const response = await provider.execute(messages, {\n15: model: 'gpt-4o'\n16: });\n17: ```\n18: \n19: ## Configuration\n20: \n21: ```typescript\n22: new OpenAIProvider({\n23: apiKey: 'sk-...', // Or use OPENAI_API_KEY env var\n24: baseURL: '...', // Custom endpoint\n25: organization: '...', // Org ID\n26: timeout: 30000 // Request timeout\n27: });\n28: ```\n29: \n30: ## Supported Models\n31: \n32: | Model | Vision | Tools | Notes |\n33: |-------|--------|-------|-------|\n34: | gpt-4o | ✅ | ✅ | Recommended |\n35: | gpt-4o-mini | ✅ | ✅ | Cheaper |\n36: | gpt-4-turbo | ✅ | ✅ | |\n37: | o1 | ❌ | ❌ | Reasoning, uses 'developer' role |\n38: | o1-mini | ❌ | ❌ | Faster reasoning |\n39: \n40: ## Token Counting\n41: \n42: ```typescript\n43: import { countTokens, getEncoding } from 'execution-openai';\n44: \n45: const tokens = countTokens('Hello!', 'gpt-4o');\n46: ```\n47: \n48: ## Dependencies\n49: \n50: - `openai` - Official SDK\n51: - `tiktoken` - Token counting\n52: - `execution` - Interface definitions (peer)\n53: \n54: ",
356
+ "name": "get_file_content"
357
+ },
358
+ {
359
+ "role": "tool",
360
+ "tool_call_id": "call_Y8xO2HhGkYcnjU52u3pwAyLY",
361
+ "content": "Found related test files:\nsrc/index.ts",
362
+ "name": "get_related_tests"
363
+ },
364
+ {
365
+ "role": "assistant",
366
+ "content": null,
367
+ "tool_calls": [
368
+ {
369
+ "id": "call_i0cjcL7W593ZVcs3CdHqh9ph",
370
+ "type": "function",
371
+ "function": {
372
+ "name": "search_codebase",
373
+ "arguments": "{\"query\":\"countTokens\",\"contextLines\":2}"
374
+ }
375
+ }
376
+ ]
377
+ },
378
+ {
379
+ "role": "tool",
380
+ "tool_call_id": "call_i0cjcL7W593ZVcs3CdHqh9ph",
381
+ "content": "guide/index.md-41-\nguide/index.md-42-```typescript\nguide/index.md:43:import { countTokens, getEncoding } from 'execution-openai';\nguide/index.md-44-\nguide/index.md:45:const tokens = countTokens('Hello!', 'gpt-4o');\nguide/index.md-46-```\nguide/index.md-47-\n",
382
+ "name": "search_codebase"
383
+ },
384
+ {
385
+ "role": "assistant",
386
+ "content": null,
387
+ "tool_calls": [
388
+ {
389
+ "id": "call_ZYaJzuqxjWgp51QmqZ1ZVxnq",
390
+ "type": "function",
391
+ "function": {
392
+ "name": "search_codebase",
393
+ "arguments": "{\"query\":\"getEncoding\",\"contextLines\":2}"
394
+ }
395
+ }
396
+ ]
397
+ },
398
+ {
399
+ "role": "tool",
400
+ "tool_call_id": "call_ZYaJzuqxjWgp51QmqZ1ZVxnq",
401
+ "content": "guide/index.md-41-\nguide/index.md-42-```typescript\nguide/index.md:43:import { countTokens, getEncoding } from 'execution-openai';\nguide/index.md-44-\nguide/index.md-45-const tokens = countTokens('Hello!', 'gpt-4o');\n",
402
+ "name": "search_codebase"
403
+ },
404
+ {
405
+ "role": "assistant",
406
+ "content": null,
407
+ "tool_calls": [
408
+ {
409
+ "id": "call_HxxCRlwQ9m0cE2FhGjBbjktQ",
410
+ "type": "function",
411
+ "function": {
412
+ "name": "get_file_content",
413
+ "arguments": "{\"filePath\":\"tests/index.test.ts\",\"includeLineNumbers\":true}"
414
+ }
415
+ }
416
+ ]
417
+ },
418
+ {
419
+ "role": "tool",
420
+ "tool_call_id": "call_HxxCRlwQ9m0cE2FhGjBbjktQ",
421
+ "content": "1: /**\n2: * Tests for execution-openai package\n3: */\n4: \n5: import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';\n6: import {\n7: OpenAIProvider,\n8: createOpenAIProvider,\n9: VERSION,\n10: type Message,\n11: type Request,\n12: type ExecutionOptions,\n13: type ProviderResponse,\n14: type Provider,\n15: } from '../src/index.js';\n16: \n17: describe('OpenAIProvider', () => {\n18: let provider: OpenAIProvider;\n19: \n20: beforeEach(() => {\n21: provider = new OpenAIProvider();\n22: });\n23: \n24: describe('name', () => {\n25: it('should have name \"openai\"', () => {\n26: expect(provider.name).toBe('openai');\n27: });\n28: });\n29: \n30: describe('supportsModel', () => {\n31: it('should support GPT models', () => {\n32: expect(provider.supportsModel('gpt-4')).toBe(true);\n33: expect(provider.supportsModel('gpt-4o')).toBe(true);\n34: expect(provider.supportsModel('gpt-4-turbo')).toBe(true);\n35: expect(provider.supportsModel('gpt-3.5-turbo')).toBe(true);\n36: });\n37: \n38: it('should support O1/O3/O4 models', () => {\n39: expect(provider.supportsModel('o1-preview')).toBe(true);\n40: expect(provider.supportsModel('o1-mini')).toBe(true);\n41: expect(provider.supportsModel('o3-mini')).toBe(true);\n42: expect(provider.supportsModel('o4-mini')).toBe(true);\n43: });\n44: \n45: it('should not support Claude models', () => {\n46: expect(provider.supportsModel('claude-3-opus-20240229')).toBe(false);\n47: expect(provider.supportsModel('claude-3-sonnet-20240229')).toBe(false);\n48: });\n49: \n50: it('should not support Gemini models', () => {\n51: expect(provider.supportsModel('gemini-1.5-pro')).toBe(false);\n52: expect(provider.supportsModel('gemini-1.5-flash')).toBe(false);\n53: });\n54: \n55: it('should return true for empty/undefined model (default to OpenAI)', () => {\n56: expect(provider.supportsModel('')).toBe(true);\n57: });\n58: });\n59: \n60: describe('execute', () => {\n61: const originalEnv = process.env;\n62: \n63: beforeEach(() => {\n64: process.env = { ...originalEnv };\n65: delete process.env.OPENAI_API_KEY;\n66: });\n67: \n68: afterEach(() => {\n69: process.env = originalEnv;\n70: });\n71: \n72: it('should throw error when no API key is provided', async () => {\n73: const request: Request = {\n74: messages: [{ role: 'user', content: 'Hello' }],\n75: model: 'gpt-4',\n76: addMessage: vi.fn(),\n77: };\n78: \n79: await expect(provider.execute(request)).rejects.toThrow(\n80: 'OpenAI API key is required'\n81: );\n82: });\n83: \n84: it('should throw error when API key is empty string', async () => {\n85: const request: Request = {\n86: messages: [{ role: 'user', content: 'Hello' }],\n87: model: 'gpt-4',\n88: addMessage: vi.fn(),\n89: };\n90: \n91: await expect(provider.execute(request, { apiKey: '' })).rejects.toThrow(\n92: 'OpenAI API key is required'\n93: );\n94: });\n95: });\n96: \n97: describe('implements Provider interface', () => {\n98: it('should satisfy Provider interface', () => {\n99: const p: Provider = provider;\n100: expect(p.name).toBe('openai');\n101: expect(typeof p.execute).toBe('function');\n102: expect(typeof p.supportsModel).toBe('function');\n103: });\n104: });\n105: });\n106: \n107: describe('createOpenAIProvider', () => {\n108: it('should create a new OpenAIProvider instance', () => {\n109: const provider = createOpenAIProvider();\n110: expect(provider).toBeInstanceOf(OpenAIProvider);\n111: expect(provider.name).toBe('openai');\n112: });\n113: });\n114: \n115: describe('VERSION', () => {\n116: it('should export version string', () => {\n117: expect(VERSION).toBe('0.0.1');\n118: });\n119: });\n120: \n121: describe('Type exports', () => {\n122: it('should export Message type', () => {\n123: const msg: Message = {\n124: role: 'user',\n125: content: 'Hello',\n126: };\n127: expect(msg.role).toBe('user');\n128: expect(msg.content).toBe('Hello');\n129: });\n130: \n131: it('should support all message roles', () => {\n132: const roles: Message['role'][] = ['user', 'assistant', 'system', 'developer', 'tool'];\n133: roles.forEach(role => {\n134: const msg: Message = { role, content: 'test' };\n135: expect(msg.role).toBe(role);\n136: });\n137: });\n138: \n139: it('should support array content', () => {\n140: const msg: Message = {\n141: role: 'user',\n142: content: ['Hello', 'World'],\n143: };\n144: expect(Array.isArray(msg.content)).toBe(true);\n145: });\n146: \n147: it('should support null content', () => {\n148: const msg: Message = {\n149: role: 'assistant',\n150: content: null,\n151: };\n152: expect(msg.content).toBeNull();\n153: });\n154: \n155: it('should export ExecutionOptions type', () => {\n156: const opts: ExecutionOptions = {\n157: apiKey: 'test-key',\n158: model: 'gpt-4',\n159: temperature: 0.7,\n160: maxTokens: 1000,\n161: timeout: 30000,\n162: retries: 3,\n163: };\n164: expect(opts.apiKey).toBe('test-key');\n165: expect(opts.temperature).toBe(0.7);\n166: });\n167: \n168: it('should export ProviderResponse type', () => {\n169: const response: ProviderResponse = {\n170: content: 'Hello!',\n171: model: 'gpt-4',\n172: usage: {\n173: inputTokens: 10,\n174: outputTokens: 5,\n175: },\n176: };\n177: expect(response.content).toBe('Hello!');\n178: expect(response.usage?.inputTokens).toBe(10);\n179: });\n180: \n181: it('should support toolCalls in ProviderResponse', () => {\n182: const response: ProviderResponse = {\n183: content: '',\n184: model: 'gpt-4',\n185: toolCalls: [\n186: {\n187: id: 'call_123',\n188: type: 'function',\n189: function: {\n190: name: 'get_weather',\n191: arguments: '{\"location\": \"NYC\"}',\n192: },\n193: },\n194: ],\n195: };\n196: expect(response.toolCalls).toHaveLength(1);\n197: expect(response.toolCalls?.[0].function.name).toBe('get_weather');\n198: });\n199: });\n200: \n201: ",
422
+ "name": "get_file_content"
423
+ },
424
+ {
425
+ "role": "assistant",
426
+ "content": "RELEASE_TITLE:\nexecution-openai 1.0.0\n\nRELEASE_BODY:\n## Main story\n\nThis release hardens the OpenAI provider for production use by **validating API keys up front** and **sanitizing/redacting secrets from errors**. It also tightens up release hygiene (precommit build, ignored internal files) as part of the 1.0.0 cut.\n\n## Security & reliability improvements\n\n### API key validation (fail fast)\n- `OpenAIProvider.execute()` now requires an API key from either:\n - `options.apiKey`, or\n - `OPENAI_API_KEY`\n- Keys are validated against known OpenAI key formats (including `sk-...` and `sk-proj-...`). Invalid formats throw a clear error before any API call is made.\n\nImpact:\n- Misconfiguration is caught earlier and more consistently.\n- If you previously passed non-standard key strings, they may now be rejected.\n\n### Error sanitization / secret redaction\n- The package now configures `@theunwalked/offrecord` and `@theunwalked/spotclean` on module load to:\n - register OpenAI key patterns for redaction, and\n - sanitize thrown errors via `createSafeError(...)` to reduce the chance of leaking secrets in logs.\n\nImpact:\n- Error messages and stack traces may look different than before (especially in production where stack sanitization is enabled).\n- If you were matching exact error strings or depending on raw upstream SDK error output, update those assumptions.\n\n## API surface and typings\n\n- The package includes and exports “inline” versions of the core execution interfaces/types (`Provider`, `Request`, `Message`, `ExecutionOptions`, `ProviderResponse`) to avoid requiring the separate `execution` package at build time.\n\n## Build / repo hygiene\n\n- `precommit` now runs `build` in addition to lint/tests (`npm run build && npm run lint && npm run test`).\n- `.gitignore` now ignores `.kodrdriv*` internal files.\n- Vite/Rollup config continues to externalize runtime dependencies like `openai`, `tiktoken`, `@theunwalked/offrecord`, and `@theunwalked/spotclean`.\n\n## Documentation\n\n- README includes a release marker update for this version.\n\n## Breaking changes\n\nNo explicit breaking changes were detected by automated scanning, but note these behavior changes that may affect consumers:\n- **Invalid/empty API keys now error earlier** due to format validation.\n- **Errors are now sanitized** (message/stack content may differ), which can break tests or log parsing that relied on previous error output.\n\n## Known considerations\n\n- `src/index.ts` exports `VERSION = '0.0.1'` even though the package version is 1.0.0. If you display or assert `VERSION`, be aware it does not currently reflect the published package version."
427
+ }
428
+ ]
429
+ ```
430
+
431
+ </details>
432
+
433
+ ## Generated Release Notes
434
+
435
+ ### Title
436
+ ```
437
+ execution-openai 1.0.0
438
+ ```
439
+
440
+ ### Body
441
+ ```markdown
442
+ ## Main story
443
+
444
+ This release hardens the OpenAI provider for production use by **validating API keys up front** and **sanitizing/redacting secrets from errors**. It also tightens up release hygiene (precommit build, ignored internal files) as part of the 1.0.0 cut.
445
+
446
+ ## Security & reliability improvements
447
+
448
+ ### API key validation (fail fast)
449
+ - `OpenAIProvider.execute()` now requires an API key from either:
450
+ - `options.apiKey`, or
451
+ - `OPENAI_API_KEY`
452
+ - Keys are validated against known OpenAI key formats (including `sk-...` and `sk-proj-...`). Invalid formats throw a clear error before any API call is made.
453
+
454
+ Impact:
455
+ - Misconfiguration is caught earlier and more consistently.
456
+ - If you previously passed non-standard key strings, they may now be rejected.
457
+
458
+ ### Error sanitization / secret redaction
459
+ - The package now configures `@theunwalked/offrecord` and `@theunwalked/spotclean` on module load to:
460
+ - register OpenAI key patterns for redaction, and
461
+ - sanitize thrown errors via `createSafeError(...)` to reduce the chance of leaking secrets in logs.
462
+
463
+ Impact:
464
+ - Error messages and stack traces may look different than before (especially in production where stack sanitization is enabled).
465
+ - If you were matching exact error strings or depending on raw upstream SDK error output, update those assumptions.
466
+
467
+ ## API surface and typings
468
+
469
+ - The package includes and exports “inline” versions of the core execution interfaces/types (`Provider`, `Request`, `Message`, `ExecutionOptions`, `ProviderResponse`) to avoid requiring the separate `execution` package at build time.
470
+
471
+ ## Build / repo hygiene
472
+
473
+ - `precommit` now runs `build` in addition to lint/tests (`npm run build && npm run lint && npm run test`).
474
+ - `.gitignore` now ignores `.kodrdriv*` internal files.
475
+ - Vite/Rollup config continues to externalize runtime dependencies like `openai`, `tiktoken`, `@theunwalked/offrecord`, and `@theunwalked/spotclean`.
476
+
477
+ ## Documentation
478
+
479
+ - README includes a release marker update for this version.
480
+
481
+ ## Breaking changes
482
+
483
+ No explicit breaking changes were detected by automated scanning, but note these behavior changes that may affect consumers:
484
+ - **Invalid/empty API keys now error earlier** due to format validation.
485
+ - **Errors are now sanitized** (message/stack content may differ), which can break tests or log parsing that relied on previous error output.
486
+
487
+ ## Known considerations
488
+
489
+ - `src/index.ts` exports `VERSION = '0.0.1'` even though the package version is 1.0.0. If you display or assert `VERSION`, be aware it does not currently reflect the published package version.
490
+ ```