@shareai-lab/kode 1.0.71 → 1.0.75

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 (108) hide show
  1. package/README.md +160 -1
  2. package/README.zh-CN.md +65 -1
  3. package/cli.js +5 -10
  4. package/package.json +6 -2
  5. package/src/ProjectOnboarding.tsx +47 -29
  6. package/src/Tool.ts +33 -4
  7. package/src/commands/agents.tsx +3401 -0
  8. package/src/commands/help.tsx +2 -2
  9. package/src/commands/resume.tsx +2 -1
  10. package/src/commands/terminalSetup.ts +4 -4
  11. package/src/commands.ts +3 -0
  12. package/src/components/ApproveApiKey.tsx +1 -1
  13. package/src/components/Config.tsx +10 -6
  14. package/src/components/ConsoleOAuthFlow.tsx +5 -4
  15. package/src/components/CustomSelect/select-option.tsx +28 -2
  16. package/src/components/CustomSelect/select.tsx +14 -5
  17. package/src/components/CustomSelect/theme.ts +45 -0
  18. package/src/components/Help.tsx +4 -4
  19. package/src/components/InvalidConfigDialog.tsx +1 -1
  20. package/src/components/LogSelector.tsx +1 -1
  21. package/src/components/MCPServerApprovalDialog.tsx +1 -1
  22. package/src/components/Message.tsx +2 -0
  23. package/src/components/ModelListManager.tsx +10 -6
  24. package/src/components/ModelSelector.tsx +201 -23
  25. package/src/components/ModelStatusDisplay.tsx +7 -5
  26. package/src/components/PromptInput.tsx +146 -96
  27. package/src/components/SentryErrorBoundary.ts +9 -3
  28. package/src/components/StickerRequestForm.tsx +16 -0
  29. package/src/components/StructuredDiff.tsx +36 -29
  30. package/src/components/TextInput.tsx +13 -0
  31. package/src/components/TodoItem.tsx +47 -0
  32. package/src/components/TrustDialog.tsx +1 -1
  33. package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +5 -1
  34. package/src/components/messages/AssistantToolUseMessage.tsx +14 -4
  35. package/src/components/messages/TaskProgressMessage.tsx +32 -0
  36. package/src/components/messages/TaskToolMessage.tsx +58 -0
  37. package/src/components/permissions/FallbackPermissionRequest.tsx +2 -4
  38. package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +1 -1
  39. package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +5 -3
  40. package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +1 -1
  41. package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +5 -3
  42. package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +2 -4
  43. package/src/components/permissions/PermissionRequest.tsx +3 -5
  44. package/src/constants/macros.ts +2 -0
  45. package/src/constants/modelCapabilities.ts +179 -0
  46. package/src/constants/models.ts +90 -0
  47. package/src/constants/product.ts +1 -1
  48. package/src/context.ts +7 -7
  49. package/src/entrypoints/cli.tsx +23 -3
  50. package/src/entrypoints/mcp.ts +10 -10
  51. package/src/hooks/useCanUseTool.ts +1 -1
  52. package/src/hooks/useTextInput.ts +5 -2
  53. package/src/hooks/useUnifiedCompletion.ts +1405 -0
  54. package/src/messages.ts +1 -0
  55. package/src/query.ts +3 -0
  56. package/src/screens/ConfigureNpmPrefix.tsx +1 -1
  57. package/src/screens/Doctor.tsx +1 -1
  58. package/src/screens/REPL.tsx +11 -12
  59. package/src/services/adapters/base.ts +38 -0
  60. package/src/services/adapters/chatCompletions.ts +90 -0
  61. package/src/services/adapters/responsesAPI.ts +170 -0
  62. package/src/services/claude.ts +198 -62
  63. package/src/services/customCommands.ts +43 -22
  64. package/src/services/gpt5ConnectionTest.ts +340 -0
  65. package/src/services/mcpClient.ts +1 -1
  66. package/src/services/mentionProcessor.ts +273 -0
  67. package/src/services/modelAdapterFactory.ts +69 -0
  68. package/src/services/openai.ts +534 -14
  69. package/src/services/responseStateManager.ts +90 -0
  70. package/src/services/systemReminder.ts +113 -12
  71. package/src/test/testAdapters.ts +96 -0
  72. package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +120 -56
  73. package/src/tools/BashTool/BashTool.tsx +4 -31
  74. package/src/tools/BashTool/BashToolResultMessage.tsx +1 -1
  75. package/src/tools/BashTool/OutputLine.tsx +1 -0
  76. package/src/tools/FileEditTool/FileEditTool.tsx +4 -5
  77. package/src/tools/FileReadTool/FileReadTool.tsx +43 -10
  78. package/src/tools/MCPTool/MCPTool.tsx +2 -1
  79. package/src/tools/MultiEditTool/MultiEditTool.tsx +2 -2
  80. package/src/tools/NotebookReadTool/NotebookReadTool.tsx +15 -23
  81. package/src/tools/StickerRequestTool/StickerRequestTool.tsx +1 -1
  82. package/src/tools/TaskTool/TaskTool.tsx +170 -86
  83. package/src/tools/TaskTool/prompt.ts +61 -25
  84. package/src/tools/ThinkTool/ThinkTool.tsx +1 -3
  85. package/src/tools/TodoWriteTool/TodoWriteTool.tsx +65 -41
  86. package/src/tools/lsTool/lsTool.tsx +5 -2
  87. package/src/tools.ts +16 -16
  88. package/src/types/conversation.ts +51 -0
  89. package/src/types/logs.ts +58 -0
  90. package/src/types/modelCapabilities.ts +64 -0
  91. package/src/types/notebook.ts +87 -0
  92. package/src/utils/advancedFuzzyMatcher.ts +290 -0
  93. package/src/utils/agentLoader.ts +284 -0
  94. package/src/utils/ask.tsx +1 -0
  95. package/src/utils/commands.ts +1 -1
  96. package/src/utils/commonUnixCommands.ts +161 -0
  97. package/src/utils/config.ts +173 -2
  98. package/src/utils/conversationRecovery.ts +1 -0
  99. package/src/utils/debugLogger.ts +13 -13
  100. package/src/utils/exampleCommands.ts +1 -0
  101. package/src/utils/fuzzyMatcher.ts +328 -0
  102. package/src/utils/messages.tsx +6 -5
  103. package/src/utils/model.ts +120 -42
  104. package/src/utils/responseState.ts +23 -0
  105. package/src/utils/secureFile.ts +559 -0
  106. package/src/utils/terminal.ts +1 -0
  107. package/src/utils/theme.ts +11 -0
  108. package/src/hooks/useSlashCommandTypeahead.ts +0 -137
@@ -3,7 +3,7 @@ import { getGlobalConfig, GlobalConfig } from '../utils/config'
3
3
  import { ProxyAgent, fetch, Response } from 'undici'
4
4
  import { setSessionState, getSessionState } from '../utils/sessionState'
5
5
  import { logEvent } from '../services/statsig'
6
- import { debug as debugLogger } from '../utils/debugLogger'
6
+ import { debug as debugLogger, getCurrentRequest } from '../utils/debugLogger'
7
7
 
8
8
  // Helper function to calculate retry delay with exponential backoff
9
9
  function getRetryDelay(attempt: number, retryAfter?: string | null): number {
@@ -53,6 +53,7 @@ function abortableDelay(delayMs: number, signal?: AbortSignal): Promise<void> {
53
53
  enum ModelErrorType {
54
54
  MaxLength = '1024',
55
55
  MaxCompletionTokens = 'max_completion_tokens',
56
+ TemperatureRestriction = 'temperature_restriction',
56
57
  StreamOptions = 'stream_options',
57
58
  Citations = 'citations',
58
59
  RateLimit = 'rate_limit',
@@ -98,6 +99,49 @@ interface ErrorHandler {
98
99
  fix: ErrorFixer
99
100
  }
100
101
 
102
+ // GPT-5 specific error handlers with enhanced detection patterns
103
+ const GPT5_ERROR_HANDLERS: ErrorHandler[] = [
104
+ {
105
+ type: ModelErrorType.MaxCompletionTokens,
106
+ detect: errMsg => {
107
+ const lowerMsg = errMsg.toLowerCase()
108
+ return (
109
+ // Exact OpenAI GPT-5 error message
110
+ (lowerMsg.includes("unsupported parameter: 'max_tokens'") && lowerMsg.includes("'max_completion_tokens'")) ||
111
+ // Generic max_tokens error patterns
112
+ (lowerMsg.includes("max_tokens") && lowerMsg.includes("max_completion_tokens")) ||
113
+ (lowerMsg.includes("max_tokens") && lowerMsg.includes("not supported")) ||
114
+ (lowerMsg.includes("max_tokens") && lowerMsg.includes("use max_completion_tokens")) ||
115
+ // Additional patterns for various providers
116
+ (lowerMsg.includes("invalid parameter") && lowerMsg.includes("max_tokens")) ||
117
+ (lowerMsg.includes("parameter error") && lowerMsg.includes("max_tokens"))
118
+ )
119
+ },
120
+ fix: async opts => {
121
+ console.log(`🔧 GPT-5 Fix: Converting max_tokens (${opts.max_tokens}) to max_completion_tokens`)
122
+ if ('max_tokens' in opts) {
123
+ opts.max_completion_tokens = opts.max_tokens
124
+ delete opts.max_tokens
125
+ }
126
+ },
127
+ },
128
+ {
129
+ type: ModelErrorType.TemperatureRestriction,
130
+ detect: errMsg => {
131
+ const lowerMsg = errMsg.toLowerCase()
132
+ return (
133
+ lowerMsg.includes("temperature") &&
134
+ (lowerMsg.includes("only supports") || lowerMsg.includes("must be 1") || lowerMsg.includes("invalid temperature"))
135
+ )
136
+ },
137
+ fix: async opts => {
138
+ console.log(`🔧 GPT-5 Fix: Adjusting temperature from ${opts.temperature} to 1`)
139
+ opts.temperature = 1
140
+ },
141
+ },
142
+ // Add more GPT-5 specific handlers as needed
143
+ ]
144
+
101
145
  // Standard error handlers
102
146
  const ERROR_HANDLERS: ErrorHandler[] = [
103
147
  {
@@ -210,6 +254,11 @@ function isRateLimitError(errMsg: string): boolean {
210
254
  // Model-specific feature flags - can be extended with more properties as needed
211
255
  interface ModelFeatures {
212
256
  usesMaxCompletionTokens: boolean
257
+ supportsResponsesAPI?: boolean
258
+ requiresTemperatureOne?: boolean
259
+ supportsVerbosityControl?: boolean
260
+ supportsCustomTools?: boolean
261
+ supportsAllowedTools?: boolean
213
262
  }
214
263
 
215
264
  // Map of model identifiers to their specific features
@@ -220,16 +269,63 @@ const MODEL_FEATURES: Record<string, ModelFeatures> = {
220
269
  'o1-mini': { usesMaxCompletionTokens: true },
221
270
  'o1-pro': { usesMaxCompletionTokens: true },
222
271
  'o3-mini': { usesMaxCompletionTokens: true },
272
+ // GPT-5 models
273
+ 'gpt-5': {
274
+ usesMaxCompletionTokens: true,
275
+ supportsResponsesAPI: true,
276
+ requiresTemperatureOne: true,
277
+ supportsVerbosityControl: true,
278
+ supportsCustomTools: true,
279
+ supportsAllowedTools: true,
280
+ },
281
+ 'gpt-5-mini': {
282
+ usesMaxCompletionTokens: true,
283
+ supportsResponsesAPI: true,
284
+ requiresTemperatureOne: true,
285
+ supportsVerbosityControl: true,
286
+ supportsCustomTools: true,
287
+ supportsAllowedTools: true,
288
+ },
289
+ 'gpt-5-nano': {
290
+ usesMaxCompletionTokens: true,
291
+ supportsResponsesAPI: true,
292
+ requiresTemperatureOne: true,
293
+ supportsVerbosityControl: true,
294
+ supportsCustomTools: true,
295
+ supportsAllowedTools: true,
296
+ },
297
+ 'gpt-5-chat-latest': {
298
+ usesMaxCompletionTokens: true,
299
+ supportsResponsesAPI: false, // Uses Chat Completions only
300
+ requiresTemperatureOne: true,
301
+ supportsVerbosityControl: true,
302
+ },
223
303
  }
224
304
 
225
305
  // Helper to get model features based on model ID/name
226
306
  function getModelFeatures(modelName: string): ModelFeatures {
227
- // Check for exact matches first
307
+ if (!modelName || typeof modelName !== 'string') {
308
+ return { usesMaxCompletionTokens: false }
309
+ }
310
+
311
+ // Check for exact matches first (highest priority)
228
312
  if (MODEL_FEATURES[modelName]) {
229
313
  return MODEL_FEATURES[modelName]
230
314
  }
231
315
 
232
- // Check for partial matches (e.g., if modelName contains a known model ID)
316
+ // Simple GPT-5 detection: any model name containing 'gpt-5'
317
+ if (modelName.toLowerCase().includes('gpt-5')) {
318
+ return {
319
+ usesMaxCompletionTokens: true,
320
+ supportsResponsesAPI: true,
321
+ requiresTemperatureOne: true,
322
+ supportsVerbosityControl: true,
323
+ supportsCustomTools: true,
324
+ supportsAllowedTools: true,
325
+ }
326
+ }
327
+
328
+ // Check for partial matches (e.g., other reasoning models)
233
329
  for (const [key, features] of Object.entries(MODEL_FEATURES)) {
234
330
  if (modelName.includes(key)) {
235
331
  return features
@@ -249,15 +345,53 @@ function applyModelSpecificTransformations(
249
345
  }
250
346
 
251
347
  const features = getModelFeatures(opts.model)
348
+ const isGPT5 = opts.model.toLowerCase().includes('gpt-5')
252
349
 
253
- // Apply transformations based on features
254
- if (
255
- features.usesMaxCompletionTokens &&
256
- 'max_tokens' in opts &&
257
- !('max_completion_tokens' in opts)
258
- ) {
259
- opts.max_completion_tokens = opts.max_tokens
260
- delete opts.max_tokens
350
+ // 🔥 Enhanced GPT-5 Detection and Transformation
351
+ if (isGPT5 || features.usesMaxCompletionTokens) {
352
+ // Force max_completion_tokens for all GPT-5 models
353
+ if ('max_tokens' in opts && !('max_completion_tokens' in opts)) {
354
+ console.log(`🔧 Transforming max_tokens (${opts.max_tokens}) to max_completion_tokens for ${opts.model}`)
355
+ opts.max_completion_tokens = opts.max_tokens
356
+ delete opts.max_tokens
357
+ }
358
+
359
+ // Force temperature = 1 for GPT-5 models
360
+ if (features.requiresTemperatureOne && 'temperature' in opts) {
361
+ if (opts.temperature !== 1 && opts.temperature !== undefined) {
362
+ console.log(
363
+ `🔧 GPT-5 temperature constraint: Adjusting temperature from ${opts.temperature} to 1 for ${opts.model}`
364
+ )
365
+ opts.temperature = 1
366
+ }
367
+ }
368
+
369
+ // Remove unsupported parameters for GPT-5
370
+ if (isGPT5) {
371
+ // Remove parameters that may not be supported by GPT-5
372
+ delete opts.frequency_penalty
373
+ delete opts.presence_penalty
374
+ delete opts.logit_bias
375
+ delete opts.user
376
+
377
+ // Add reasoning_effort if not present and model supports it
378
+ if (!opts.reasoning_effort && features.supportsVerbosityControl) {
379
+ opts.reasoning_effort = 'medium' // Default reasoning effort for coding tasks
380
+ }
381
+ }
382
+ }
383
+
384
+ // Apply transformations for non-GPT-5 models
385
+ else {
386
+ // Standard max_tokens to max_completion_tokens conversion for other reasoning models
387
+ if (
388
+ features.usesMaxCompletionTokens &&
389
+ 'max_tokens' in opts &&
390
+ !('max_completion_tokens' in opts)
391
+ ) {
392
+ opts.max_completion_tokens = opts.max_tokens
393
+ delete opts.max_tokens
394
+ }
261
395
  }
262
396
 
263
397
  // Add more transformations here as needed
@@ -267,7 +401,10 @@ async function applyModelErrorFixes(
267
401
  opts: OpenAI.ChatCompletionCreateParams,
268
402
  baseURL: string,
269
403
  ) {
270
- for (const handler of ERROR_HANDLERS) {
404
+ const isGPT5 = opts.model.startsWith('gpt-5')
405
+ const handlers = isGPT5 ? [...GPT5_ERROR_HANDLERS, ...ERROR_HANDLERS] : ERROR_HANDLERS
406
+
407
+ for (const handler of handlers) {
271
408
  if (hasModelError(baseURL, opts.model, handler.type)) {
272
409
  await handler.fix(opts)
273
410
  return
@@ -333,6 +470,9 @@ async function tryWithEndpointFallback(
333
470
  throw lastError || new Error('All endpoints failed')
334
471
  }
335
472
 
473
+ // Export shared utilities for GPT-5 compatibility
474
+ export { getGPT5CompletionWithProfile, getModelFeatures, applyModelSpecificTransformations }
475
+
336
476
  export async function getCompletionWithProfile(
337
477
  modelProfile: any,
338
478
  opts: OpenAI.ChatCompletionCreateParams,
@@ -465,6 +605,43 @@ export async function getCompletionWithProfile(
465
605
  throw new Error('Request cancelled by user')
466
606
  }
467
607
 
608
+ // 🔥 NEW: Parse error message to detect and handle specific API errors
609
+ try {
610
+ const errorData = await response.json()
611
+ const errorMessage = errorData?.error?.message || errorData?.message || `HTTP ${response.status}`
612
+
613
+ // Check if this is a parameter error that we can fix
614
+ const isGPT5 = opts.model.startsWith('gpt-5')
615
+ const handlers = isGPT5 ? [...GPT5_ERROR_HANDLERS, ...ERROR_HANDLERS] : ERROR_HANDLERS
616
+
617
+ for (const handler of handlers) {
618
+ if (handler.detect(errorMessage)) {
619
+ console.log(`🔧 Detected ${handler.type} error for ${opts.model}: ${errorMessage}`)
620
+
621
+ // Store this error for future requests
622
+ setModelError(baseURL || '', opts.model, handler.type, errorMessage)
623
+
624
+ // Apply the fix and retry immediately
625
+ await handler.fix(opts)
626
+ console.log(`🔧 Applied fix for ${handler.type}, retrying...`)
627
+
628
+ return getCompletionWithProfile(
629
+ modelProfile,
630
+ opts,
631
+ attempt + 1,
632
+ maxAttempts,
633
+ signal,
634
+ )
635
+ }
636
+ }
637
+
638
+ // If no specific handler found, log the error for debugging
639
+ console.log(`⚠️ Unhandled API error (${response.status}): ${errorMessage}`)
640
+ } catch (parseError) {
641
+ // If we can't parse the error, fall back to generic retry
642
+ console.log(`⚠️ Could not parse error response (${response.status})`)
643
+ }
644
+
468
645
  const delayMs = getRetryDelay(attempt)
469
646
  console.log(
470
647
  ` ⎿ API error (${response.status}), retrying in ${Math.round(delayMs / 1000)}s... (attempt ${attempt + 1}/${maxAttempts})`,
@@ -487,7 +664,7 @@ export async function getCompletionWithProfile(
487
664
  )
488
665
  }
489
666
 
490
- const stream = createStreamProcessor(response.body as any)
667
+ const stream = createStreamProcessor(response.body as any, signal)
491
668
  return stream
492
669
  }
493
670
 
@@ -538,6 +715,43 @@ export async function getCompletionWithProfile(
538
715
  throw new Error('Request cancelled by user')
539
716
  }
540
717
 
718
+ // 🔥 NEW: Parse error message to detect and handle specific API errors
719
+ try {
720
+ const errorData = await response.json()
721
+ const errorMessage = errorData?.error?.message || errorData?.message || `HTTP ${response.status}`
722
+
723
+ // Check if this is a parameter error that we can fix
724
+ const isGPT5 = opts.model.startsWith('gpt-5')
725
+ const handlers = isGPT5 ? [...GPT5_ERROR_HANDLERS, ...ERROR_HANDLERS] : ERROR_HANDLERS
726
+
727
+ for (const handler of handlers) {
728
+ if (handler.detect(errorMessage)) {
729
+ console.log(`🔧 Detected ${handler.type} error for ${opts.model}: ${errorMessage}`)
730
+
731
+ // Store this error for future requests
732
+ setModelError(baseURL || '', opts.model, handler.type, errorMessage)
733
+
734
+ // Apply the fix and retry immediately
735
+ await handler.fix(opts)
736
+ console.log(`🔧 Applied fix for ${handler.type}, retrying...`)
737
+
738
+ return getCompletionWithProfile(
739
+ modelProfile,
740
+ opts,
741
+ attempt + 1,
742
+ maxAttempts,
743
+ signal,
744
+ )
745
+ }
746
+ }
747
+
748
+ // If no specific handler found, log the error for debugging
749
+ console.log(`⚠️ Unhandled API error (${response.status}): ${errorMessage}`)
750
+ } catch (parseError) {
751
+ // If we can't parse the error, fall back to generic retry
752
+ console.log(`⚠️ Could not parse error response (${response.status})`)
753
+ }
754
+
541
755
  const delayMs = getRetryDelay(attempt)
542
756
  console.log(
543
757
  ` ⎿ API error (${response.status}), retrying in ${Math.round(delayMs / 1000)}s... (attempt ${attempt + 1}/${maxAttempts})`,
@@ -601,6 +815,7 @@ export async function getCompletionWithProfile(
601
815
 
602
816
  export function createStreamProcessor(
603
817
  stream: any,
818
+ signal?: AbortSignal,
604
819
  ): AsyncGenerator<OpenAI.ChatCompletionChunk, void, unknown> {
605
820
  if (!stream) {
606
821
  throw new Error('Stream is null or undefined')
@@ -613,10 +828,19 @@ export function createStreamProcessor(
613
828
 
614
829
  try {
615
830
  while (true) {
831
+ // Check for cancellation before attempting to read
832
+ if (signal?.aborted) {
833
+ break
834
+ }
835
+
616
836
  let readResult
617
837
  try {
618
838
  readResult = await reader.read()
619
839
  } catch (e) {
840
+ // If signal is aborted, this is user cancellation - exit silently
841
+ if (signal?.aborted) {
842
+ break
843
+ }
620
844
  console.error('Error reading from stream:', e)
621
845
  break
622
846
  }
@@ -685,8 +909,304 @@ export function createStreamProcessor(
685
909
 
686
910
  export function streamCompletion(
687
911
  stream: any,
912
+ signal?: AbortSignal,
688
913
  ): AsyncGenerator<OpenAI.ChatCompletionChunk, void, unknown> {
689
- return createStreamProcessor(stream)
914
+ return createStreamProcessor(stream, signal)
915
+ }
916
+
917
+ /**
918
+ * Call GPT-5 Responses API with proper parameter handling
919
+ */
920
+ export async function callGPT5ResponsesAPI(
921
+ modelProfile: any,
922
+ opts: any, // Using 'any' for Responses API params which differ from ChatCompletionCreateParams
923
+ signal?: AbortSignal,
924
+ ): Promise<any> {
925
+ const baseURL = modelProfile?.baseURL || 'https://api.openai.com/v1'
926
+ const apiKey = modelProfile?.apiKey
927
+ const proxy = getGlobalConfig().proxy
928
+ ? new ProxyAgent(getGlobalConfig().proxy)
929
+ : undefined
930
+
931
+ const headers: Record<string, string> = {
932
+ 'Content-Type': 'application/json',
933
+ Authorization: `Bearer ${apiKey}`,
934
+ }
935
+
936
+ // 🔥 Enhanced Responses API Parameter Mapping for GPT-5
937
+ const responsesParams: any = {
938
+ model: opts.model,
939
+ input: opts.messages, // Responses API uses 'input' instead of 'messages'
940
+ }
941
+
942
+ // 🔧 GPT-5 Token Configuration
943
+ if (opts.max_completion_tokens) {
944
+ responsesParams.max_completion_tokens = opts.max_completion_tokens
945
+ } else if (opts.max_tokens) {
946
+ // Fallback conversion if max_tokens is still present
947
+ responsesParams.max_completion_tokens = opts.max_tokens
948
+ }
949
+
950
+ // 🔧 GPT-5 Temperature Handling (only 1 or undefined)
951
+ if (opts.temperature === 1) {
952
+ responsesParams.temperature = 1
953
+ }
954
+ // Note: Do not pass temperature if it's not 1, GPT-5 will use default
955
+
956
+ // 🔧 GPT-5 Reasoning Configuration
957
+ const reasoningEffort = opts.reasoning_effort || 'medium'
958
+ responsesParams.reasoning = {
959
+ effort: reasoningEffort,
960
+ // 🚀 Enable reasoning summaries for transparency in coding tasks
961
+ generate_summary: true,
962
+ }
963
+
964
+ // 🔧 GPT-5 Tools Support
965
+ if (opts.tools && opts.tools.length > 0) {
966
+ responsesParams.tools = opts.tools
967
+
968
+ // 🚀 GPT-5 Tool Choice Configuration
969
+ if (opts.tool_choice) {
970
+ responsesParams.tool_choice = opts.tool_choice
971
+ }
972
+ }
973
+
974
+ // 🔧 GPT-5 System Instructions (separate from messages)
975
+ const systemMessages = opts.messages.filter(msg => msg.role === 'system')
976
+ const nonSystemMessages = opts.messages.filter(msg => msg.role !== 'system')
977
+
978
+ if (systemMessages.length > 0) {
979
+ responsesParams.instructions = systemMessages.map(msg => msg.content).join('\n\n')
980
+ responsesParams.input = nonSystemMessages
981
+ }
982
+
983
+ // Handle verbosity (if supported) - optimized for coding tasks
984
+ const features = getModelFeatures(opts.model)
985
+ if (features.supportsVerbosityControl) {
986
+ // High verbosity for coding tasks to get detailed explanations and structured code
987
+ // Based on GPT-5 best practices for agent-like coding environments
988
+ responsesParams.text = {
989
+ verbosity: 'high',
990
+ }
991
+ }
992
+
993
+ // Apply GPT-5 coding optimizations
994
+ if (opts.model.startsWith('gpt-5')) {
995
+ // Set reasoning effort based on task complexity
996
+ if (!responsesParams.reasoning) {
997
+ responsesParams.reasoning = {
998
+ effort: 'medium', // Balanced for most coding tasks
999
+ }
1000
+ }
1001
+
1002
+ // Add instructions parameter for coding-specific guidance
1003
+ if (!responsesParams.instructions) {
1004
+ responsesParams.instructions = `You are an expert programmer working in a terminal-based coding environment. Follow these guidelines:
1005
+ - Provide clear, concise code solutions
1006
+ - Use proper error handling and validation
1007
+ - Follow coding best practices and patterns
1008
+ - Explain complex logic when necessary
1009
+ - Focus on maintainable, readable code`
1010
+ }
1011
+ }
1012
+
1013
+ try {
1014
+ const response = await fetch(`${baseURL}/responses`, {
1015
+ method: 'POST',
1016
+ headers,
1017
+ body: JSON.stringify(responsesParams),
1018
+ dispatcher: proxy,
1019
+ signal: signal,
1020
+ })
1021
+
1022
+ if (!response.ok) {
1023
+ throw new Error(`GPT-5 Responses API error: ${response.status} ${response.statusText}`)
1024
+ }
1025
+
1026
+ const responseData = await response.json()
1027
+
1028
+ // Convert Responses API response back to Chat Completion format for compatibility
1029
+ return convertResponsesAPIToChatCompletion(responseData)
1030
+ } catch (error) {
1031
+ if (signal?.aborted) {
1032
+ throw new Error('Request cancelled by user')
1033
+ }
1034
+ throw error
1035
+ }
1036
+ }
1037
+
1038
+ /**
1039
+ * Convert Responses API response to Chat Completion format for compatibility
1040
+ * 🔥 Enhanced for GPT-5 with reasoning summary support
1041
+ */
1042
+ function convertResponsesAPIToChatCompletion(responsesData: any): any {
1043
+ // Extract content from Responses API format
1044
+ let outputText = responsesData.output_text || ''
1045
+ const usage = responsesData.usage || {}
1046
+
1047
+ // 🚀 GPT-5 Reasoning Summary Integration
1048
+ // If reasoning summary is available, prepend it to the output for transparency
1049
+ if (responsesData.output && Array.isArray(responsesData.output)) {
1050
+ const reasoningItems = responsesData.output.filter(item => item.type === 'reasoning' && item.summary)
1051
+ const messageItems = responsesData.output.filter(item => item.type === 'message')
1052
+
1053
+ if (reasoningItems.length > 0 && messageItems.length > 0) {
1054
+ const reasoningSummary = reasoningItems
1055
+ .map(item => item.summary?.map(s => s.text).join('\n'))
1056
+ .filter(Boolean)
1057
+ .join('\n\n')
1058
+
1059
+ const mainContent = messageItems
1060
+ .map(item => item.content?.map(c => c.text).join('\n'))
1061
+ .filter(Boolean)
1062
+ .join('\n\n')
1063
+
1064
+ if (reasoningSummary) {
1065
+ outputText = `**🧠 Reasoning Process:**\n${reasoningSummary}\n\n**📝 Response:**\n${mainContent}`
1066
+ } else {
1067
+ outputText = mainContent
1068
+ }
1069
+ }
1070
+ }
1071
+
1072
+ return {
1073
+ id: responsesData.id || `chatcmpl-${Date.now()}`,
1074
+ object: 'chat.completion',
1075
+ created: Math.floor(Date.now() / 1000),
1076
+ model: responsesData.model || '',
1077
+ choices: [
1078
+ {
1079
+ index: 0,
1080
+ message: {
1081
+ role: 'assistant',
1082
+ content: outputText,
1083
+ // 🚀 Include reasoning metadata if available
1084
+ ...(responsesData.reasoning && {
1085
+ reasoning: {
1086
+ effort: responsesData.reasoning.effort,
1087
+ summary: responsesData.reasoning.summary,
1088
+ },
1089
+ }),
1090
+ },
1091
+ finish_reason: responsesData.status === 'completed' ? 'stop' : 'length',
1092
+ },
1093
+ ],
1094
+ usage: {
1095
+ prompt_tokens: usage.input_tokens || 0,
1096
+ completion_tokens: usage.output_tokens || 0,
1097
+ total_tokens: (usage.input_tokens || 0) + (usage.output_tokens || 0),
1098
+ // 🔧 GPT-5 Enhanced Usage Details
1099
+ prompt_tokens_details: {
1100
+ cached_tokens: usage.input_tokens_details?.cached_tokens || 0,
1101
+ },
1102
+ completion_tokens_details: {
1103
+ reasoning_tokens: usage.output_tokens_details?.reasoning_tokens || 0,
1104
+ },
1105
+ },
1106
+ }
1107
+ }
1108
+
1109
+ /**
1110
+ * Enhanced getCompletionWithProfile that supports GPT-5 Responses API
1111
+ * 🔥 Optimized for both official OpenAI and third-party GPT-5 providers
1112
+ */
1113
+ async function getGPT5CompletionWithProfile(
1114
+ modelProfile: any,
1115
+ opts: OpenAI.ChatCompletionCreateParams,
1116
+ attempt: number = 0,
1117
+ maxAttempts: number = 10,
1118
+ signal?: AbortSignal,
1119
+ ): Promise<OpenAI.ChatCompletion | AsyncIterable<OpenAI.ChatCompletionChunk>> {
1120
+ const features = getModelFeatures(opts.model)
1121
+ const isOfficialOpenAI = !modelProfile.baseURL ||
1122
+ modelProfile.baseURL.includes('api.openai.com')
1123
+
1124
+ // 🚀 Try Responses API for official OpenAI non-streaming requests
1125
+ if (features.supportsResponsesAPI && !opts.stream && isOfficialOpenAI) {
1126
+ try {
1127
+ debugLogger.api('ATTEMPTING_GPT5_RESPONSES_API', {
1128
+ model: opts.model,
1129
+ baseURL: modelProfile.baseURL || 'official',
1130
+ provider: modelProfile.provider,
1131
+ stream: opts.stream,
1132
+ requestId: getCurrentRequest()?.id,
1133
+ })
1134
+
1135
+ const result = await callGPT5ResponsesAPI(modelProfile, opts, signal)
1136
+
1137
+ debugLogger.api('GPT5_RESPONSES_API_SUCCESS', {
1138
+ model: opts.model,
1139
+ baseURL: modelProfile.baseURL || 'official',
1140
+ requestId: getCurrentRequest()?.id,
1141
+ })
1142
+
1143
+ return result
1144
+ } catch (error) {
1145
+ debugLogger.api('GPT5_RESPONSES_API_FALLBACK', {
1146
+ model: opts.model,
1147
+ error: error.message,
1148
+ baseURL: modelProfile.baseURL || 'official',
1149
+ requestId: getCurrentRequest()?.id,
1150
+ })
1151
+
1152
+ console.warn(
1153
+ `🔄 GPT-5 Responses API failed, falling back to Chat Completions: ${error.message}`
1154
+ )
1155
+ // Fall through to Chat Completions API
1156
+ }
1157
+ }
1158
+
1159
+ // 🌐 Handle third-party GPT-5 providers with enhanced compatibility
1160
+ else if (!isOfficialOpenAI) {
1161
+ debugLogger.api('GPT5_THIRD_PARTY_PROVIDER', {
1162
+ model: opts.model,
1163
+ baseURL: modelProfile.baseURL,
1164
+ provider: modelProfile.provider,
1165
+ supportsResponsesAPI: features.supportsResponsesAPI,
1166
+ requestId: getCurrentRequest()?.id,
1167
+ })
1168
+
1169
+ // 🔧 Apply enhanced parameter optimization for third-party providers
1170
+ console.log(`🌐 Using GPT-5 via third-party provider: ${modelProfile.provider} (${modelProfile.baseURL})`)
1171
+
1172
+ // Some third-party providers may need additional parameter adjustments
1173
+ if (modelProfile.provider === 'azure') {
1174
+ // Azure OpenAI specific adjustments
1175
+ delete opts.reasoning_effort // Azure may not support this yet
1176
+ } else if (modelProfile.provider === 'custom-openai') {
1177
+ // Generic OpenAI-compatible provider optimizations
1178
+ console.log(`🔧 Applying OpenAI-compatible optimizations for custom provider`)
1179
+ }
1180
+ }
1181
+
1182
+ // 📡 Handle streaming requests (Responses API doesn't support streaming yet)
1183
+ else if (opts.stream) {
1184
+ debugLogger.api('GPT5_STREAMING_MODE', {
1185
+ model: opts.model,
1186
+ baseURL: modelProfile.baseURL || 'official',
1187
+ reason: 'responses_api_no_streaming',
1188
+ requestId: getCurrentRequest()?.id,
1189
+ })
1190
+
1191
+ console.log(`🔄 Using Chat Completions for streaming (Responses API streaming not available)`)
1192
+ }
1193
+
1194
+ // 🔧 Enhanced Chat Completions fallback with GPT-5 optimizations
1195
+ debugLogger.api('USING_CHAT_COMPLETIONS_FOR_GPT5', {
1196
+ model: opts.model,
1197
+ baseURL: modelProfile.baseURL || 'official',
1198
+ provider: modelProfile.provider,
1199
+ reason: isOfficialOpenAI ? 'streaming_or_fallback' : 'third_party_provider',
1200
+ requestId: getCurrentRequest()?.id,
1201
+ })
1202
+
1203
+ return await getCompletionWithProfile(
1204
+ modelProfile,
1205
+ opts,
1206
+ attempt,
1207
+ maxAttempts,
1208
+ signal,
1209
+ )
690
1210
  }
691
1211
 
692
1212
  /**