@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.
- package/README.md +160 -1
- package/README.zh-CN.md +65 -1
- package/cli.js +5 -10
- package/package.json +6 -2
- package/src/ProjectOnboarding.tsx +47 -29
- package/src/Tool.ts +33 -4
- package/src/commands/agents.tsx +3401 -0
- package/src/commands/help.tsx +2 -2
- package/src/commands/resume.tsx +2 -1
- package/src/commands/terminalSetup.ts +4 -4
- package/src/commands.ts +3 -0
- package/src/components/ApproveApiKey.tsx +1 -1
- package/src/components/Config.tsx +10 -6
- package/src/components/ConsoleOAuthFlow.tsx +5 -4
- package/src/components/CustomSelect/select-option.tsx +28 -2
- package/src/components/CustomSelect/select.tsx +14 -5
- package/src/components/CustomSelect/theme.ts +45 -0
- package/src/components/Help.tsx +4 -4
- package/src/components/InvalidConfigDialog.tsx +1 -1
- package/src/components/LogSelector.tsx +1 -1
- package/src/components/MCPServerApprovalDialog.tsx +1 -1
- package/src/components/Message.tsx +2 -0
- package/src/components/ModelListManager.tsx +10 -6
- package/src/components/ModelSelector.tsx +201 -23
- package/src/components/ModelStatusDisplay.tsx +7 -5
- package/src/components/PromptInput.tsx +146 -96
- package/src/components/SentryErrorBoundary.ts +9 -3
- package/src/components/StickerRequestForm.tsx +16 -0
- package/src/components/StructuredDiff.tsx +36 -29
- package/src/components/TextInput.tsx +13 -0
- package/src/components/TodoItem.tsx +47 -0
- package/src/components/TrustDialog.tsx +1 -1
- package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +5 -1
- package/src/components/messages/AssistantToolUseMessage.tsx +14 -4
- package/src/components/messages/TaskProgressMessage.tsx +32 -0
- package/src/components/messages/TaskToolMessage.tsx +58 -0
- package/src/components/permissions/FallbackPermissionRequest.tsx +2 -4
- package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +1 -1
- package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +5 -3
- package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +1 -1
- package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +5 -3
- package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +2 -4
- package/src/components/permissions/PermissionRequest.tsx +3 -5
- package/src/constants/macros.ts +2 -0
- package/src/constants/modelCapabilities.ts +179 -0
- package/src/constants/models.ts +90 -0
- package/src/constants/product.ts +1 -1
- package/src/context.ts +7 -7
- package/src/entrypoints/cli.tsx +23 -3
- package/src/entrypoints/mcp.ts +10 -10
- package/src/hooks/useCanUseTool.ts +1 -1
- package/src/hooks/useTextInput.ts +5 -2
- package/src/hooks/useUnifiedCompletion.ts +1405 -0
- package/src/messages.ts +1 -0
- package/src/query.ts +3 -0
- package/src/screens/ConfigureNpmPrefix.tsx +1 -1
- package/src/screens/Doctor.tsx +1 -1
- package/src/screens/REPL.tsx +11 -12
- package/src/services/adapters/base.ts +38 -0
- package/src/services/adapters/chatCompletions.ts +90 -0
- package/src/services/adapters/responsesAPI.ts +170 -0
- package/src/services/claude.ts +198 -62
- package/src/services/customCommands.ts +43 -22
- package/src/services/gpt5ConnectionTest.ts +340 -0
- package/src/services/mcpClient.ts +1 -1
- package/src/services/mentionProcessor.ts +273 -0
- package/src/services/modelAdapterFactory.ts +69 -0
- package/src/services/openai.ts +534 -14
- package/src/services/responseStateManager.ts +90 -0
- package/src/services/systemReminder.ts +113 -12
- package/src/test/testAdapters.ts +96 -0
- package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +120 -56
- package/src/tools/BashTool/BashTool.tsx +4 -31
- package/src/tools/BashTool/BashToolResultMessage.tsx +1 -1
- package/src/tools/BashTool/OutputLine.tsx +1 -0
- package/src/tools/FileEditTool/FileEditTool.tsx +4 -5
- package/src/tools/FileReadTool/FileReadTool.tsx +43 -10
- package/src/tools/MCPTool/MCPTool.tsx +2 -1
- package/src/tools/MultiEditTool/MultiEditTool.tsx +2 -2
- package/src/tools/NotebookReadTool/NotebookReadTool.tsx +15 -23
- package/src/tools/StickerRequestTool/StickerRequestTool.tsx +1 -1
- package/src/tools/TaskTool/TaskTool.tsx +170 -86
- package/src/tools/TaskTool/prompt.ts +61 -25
- package/src/tools/ThinkTool/ThinkTool.tsx +1 -3
- package/src/tools/TodoWriteTool/TodoWriteTool.tsx +65 -41
- package/src/tools/lsTool/lsTool.tsx +5 -2
- package/src/tools.ts +16 -16
- package/src/types/conversation.ts +51 -0
- package/src/types/logs.ts +58 -0
- package/src/types/modelCapabilities.ts +64 -0
- package/src/types/notebook.ts +87 -0
- package/src/utils/advancedFuzzyMatcher.ts +290 -0
- package/src/utils/agentLoader.ts +284 -0
- package/src/utils/ask.tsx +1 -0
- package/src/utils/commands.ts +1 -1
- package/src/utils/commonUnixCommands.ts +161 -0
- package/src/utils/config.ts +173 -2
- package/src/utils/conversationRecovery.ts +1 -0
- package/src/utils/debugLogger.ts +13 -13
- package/src/utils/exampleCommands.ts +1 -0
- package/src/utils/fuzzyMatcher.ts +328 -0
- package/src/utils/messages.tsx +6 -5
- package/src/utils/model.ts +120 -42
- package/src/utils/responseState.ts +23 -0
- package/src/utils/secureFile.ts +559 -0
- package/src/utils/terminal.ts +1 -0
- package/src/utils/theme.ts +11 -0
- package/src/hooks/useSlashCommandTypeahead.ts +0 -137
package/src/messages.ts
CHANGED
package/src/query.ts
CHANGED
|
@@ -80,6 +80,7 @@ export type AssistantMessage = {
|
|
|
80
80
|
type: 'assistant'
|
|
81
81
|
uuid: UUID
|
|
82
82
|
isApiErrorMessage?: boolean
|
|
83
|
+
responseId?: string // For GPT-5 Responses API state management
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
export type BinaryFeedbackResult =
|
|
@@ -230,6 +231,7 @@ export async function* query(
|
|
|
230
231
|
safeMode: toolUseContext.options.safeMode ?? false,
|
|
231
232
|
model: toolUseContext.options.model || 'main',
|
|
232
233
|
prependCLISysprompt: true,
|
|
234
|
+
toolUseContext: toolUseContext,
|
|
233
235
|
},
|
|
234
236
|
)
|
|
235
237
|
}
|
|
@@ -408,6 +410,7 @@ export async function* runToolUse(
|
|
|
408
410
|
currentRequest?.id,
|
|
409
411
|
)
|
|
410
412
|
|
|
413
|
+
|
|
411
414
|
logEvent('tengu_tool_use_start', {
|
|
412
415
|
toolName: toolUse.name,
|
|
413
416
|
toolUseID: toolUse.id,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
2
|
import { Box, Text } from 'ink'
|
|
3
|
-
import { Select } from '
|
|
3
|
+
import { Select } from '../components/CustomSelect/select'
|
|
4
4
|
import TextInput from '../components/TextInput'
|
|
5
5
|
import { SimpleSpinner } from '../components/Spinner'
|
|
6
6
|
import { getTheme } from '../utils/theme'
|
package/src/screens/Doctor.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState } from 'react'
|
|
2
2
|
import { Box, Text, useInput } from 'ink'
|
|
3
|
-
import { Select } from '
|
|
3
|
+
import { Select } from '../components/CustomSelect/select'
|
|
4
4
|
import { getTheme } from '../utils/theme'
|
|
5
5
|
import { ConfigureNpmPrefix } from './ConfigureNpmPrefix.tsx'
|
|
6
6
|
import { platform } from 'process'
|
package/src/screens/REPL.tsx
CHANGED
|
@@ -171,17 +171,15 @@ export function REPL({
|
|
|
171
171
|
}>({})
|
|
172
172
|
|
|
173
173
|
const { status: apiKeyStatus, reverify } = useApiKeyVerification()
|
|
174
|
-
// 🔧 FIXED: Simple cancellation logic matching original claude-code
|
|
175
174
|
function onCancel() {
|
|
176
175
|
if (!isLoading) {
|
|
177
176
|
return
|
|
178
177
|
}
|
|
179
178
|
setIsLoading(false)
|
|
180
179
|
if (toolUseConfirm) {
|
|
181
|
-
// Tool use confirm handles the abort signal itself
|
|
182
180
|
toolUseConfirm.onAbort()
|
|
183
|
-
} else {
|
|
184
|
-
abortController
|
|
181
|
+
} else if (abortController && !abortController.signal.aborted) {
|
|
182
|
+
abortController.abort()
|
|
185
183
|
}
|
|
186
184
|
}
|
|
187
185
|
|
|
@@ -392,7 +390,7 @@ export function REPL({
|
|
|
392
390
|
}
|
|
393
391
|
|
|
394
392
|
// If this was a Koding request and we got an assistant message back,
|
|
395
|
-
// save it to
|
|
393
|
+
// save it to AGENTS.md (and CLAUDE.md if exists)
|
|
396
394
|
if (
|
|
397
395
|
isKodingRequest &&
|
|
398
396
|
lastAssistantMessage &&
|
|
@@ -407,7 +405,7 @@ export function REPL({
|
|
|
407
405
|
.map(block => (block.type === 'text' ? block.text : ''))
|
|
408
406
|
.join('\n')
|
|
409
407
|
|
|
410
|
-
// Add the content to
|
|
408
|
+
// Add the content to AGENTS.md (and CLAUDE.md if exists)
|
|
411
409
|
if (content && content.trim().length > 0) {
|
|
412
410
|
handleHashCommand(content)
|
|
413
411
|
}
|
|
@@ -605,12 +603,13 @@ export function REPL({
|
|
|
605
603
|
return (
|
|
606
604
|
<PermissionProvider isBypassPermissionsModeAvailable={!safeMode}>
|
|
607
605
|
<ModeIndicator />
|
|
608
|
-
<
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
606
|
+
<React.Fragment key={`static-messages-${forkNumber}`}>
|
|
607
|
+
<Static
|
|
608
|
+
items={messagesJSX.filter(_ => _.type === 'static')}
|
|
609
|
+
>
|
|
610
|
+
{_ => _.jsx}
|
|
611
|
+
</Static>
|
|
612
|
+
</React.Fragment>
|
|
614
613
|
{messagesJSX.filter(_ => _.type === 'transient').map(_ => _.jsx)}
|
|
615
614
|
<Box
|
|
616
615
|
borderColor="red"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ModelCapabilities, UnifiedRequestParams, UnifiedResponse } from '../../types/modelCapabilities'
|
|
2
|
+
import { ModelProfile } from '../../utils/config'
|
|
3
|
+
import { Tool } from '../../Tool'
|
|
4
|
+
|
|
5
|
+
export abstract class ModelAPIAdapter {
|
|
6
|
+
constructor(
|
|
7
|
+
protected capabilities: ModelCapabilities,
|
|
8
|
+
protected modelProfile: ModelProfile
|
|
9
|
+
) {}
|
|
10
|
+
|
|
11
|
+
// Subclasses must implement these methods
|
|
12
|
+
abstract createRequest(params: UnifiedRequestParams): any
|
|
13
|
+
abstract parseResponse(response: any): UnifiedResponse
|
|
14
|
+
abstract buildTools(tools: Tool[]): any
|
|
15
|
+
|
|
16
|
+
// Shared utility methods
|
|
17
|
+
protected getMaxTokensParam(): string {
|
|
18
|
+
return this.capabilities.parameters.maxTokensField
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
protected getTemperature(): number {
|
|
22
|
+
if (this.capabilities.parameters.temperatureMode === 'fixed_one') {
|
|
23
|
+
return 1
|
|
24
|
+
}
|
|
25
|
+
if (this.capabilities.parameters.temperatureMode === 'restricted') {
|
|
26
|
+
return Math.min(1, 0.7)
|
|
27
|
+
}
|
|
28
|
+
return 0.7
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
protected shouldIncludeReasoningEffort(): boolean {
|
|
32
|
+
return this.capabilities.parameters.supportsReasoningEffort
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
protected shouldIncludeVerbosity(): boolean {
|
|
36
|
+
return this.capabilities.parameters.supportsVerbosity
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { ModelAPIAdapter } from './base'
|
|
2
|
+
import { UnifiedRequestParams, UnifiedResponse } from '../../types/modelCapabilities'
|
|
3
|
+
import { Tool } from '../../Tool'
|
|
4
|
+
import { zodToJsonSchema } from 'zod-to-json-schema'
|
|
5
|
+
|
|
6
|
+
export class ChatCompletionsAdapter extends ModelAPIAdapter {
|
|
7
|
+
createRequest(params: UnifiedRequestParams): any {
|
|
8
|
+
const { messages, systemPrompt, tools, maxTokens, stream } = params
|
|
9
|
+
|
|
10
|
+
// Build complete message list (including system prompts)
|
|
11
|
+
const fullMessages = this.buildMessages(systemPrompt, messages)
|
|
12
|
+
|
|
13
|
+
// Build request
|
|
14
|
+
const request: any = {
|
|
15
|
+
model: this.modelProfile.modelName,
|
|
16
|
+
messages: fullMessages,
|
|
17
|
+
[this.getMaxTokensParam()]: maxTokens,
|
|
18
|
+
temperature: this.getTemperature()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Add tools
|
|
22
|
+
if (tools && tools.length > 0) {
|
|
23
|
+
request.tools = this.buildTools(tools)
|
|
24
|
+
request.tool_choice = 'auto'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Add reasoning effort for GPT-5 via Chat Completions
|
|
28
|
+
if (this.shouldIncludeReasoningEffort() && params.reasoningEffort) {
|
|
29
|
+
request.reasoning_effort = params.reasoningEffort // Chat Completions format
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Add verbosity for GPT-5 via Chat Completions
|
|
33
|
+
if (this.shouldIncludeVerbosity() && params.verbosity) {
|
|
34
|
+
request.verbosity = params.verbosity // Chat Completions format
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Add streaming options
|
|
38
|
+
if (stream) {
|
|
39
|
+
request.stream = true
|
|
40
|
+
request.stream_options = {
|
|
41
|
+
include_usage: true
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// O1 model special handling
|
|
46
|
+
if (this.modelProfile.modelName.startsWith('o1')) {
|
|
47
|
+
delete request.temperature // O1 doesn't support temperature
|
|
48
|
+
delete request.stream // O1 doesn't support streaming
|
|
49
|
+
delete request.stream_options
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return request
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
buildTools(tools: Tool[]): any[] {
|
|
56
|
+
// Chat Completions only supports traditional function calling
|
|
57
|
+
return tools.map(tool => ({
|
|
58
|
+
type: 'function',
|
|
59
|
+
function: {
|
|
60
|
+
name: tool.name,
|
|
61
|
+
description: tool.description || '',
|
|
62
|
+
parameters: tool.inputJSONSchema || zodToJsonSchema(tool.inputSchema)
|
|
63
|
+
}
|
|
64
|
+
}))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
parseResponse(response: any): UnifiedResponse {
|
|
68
|
+
const choice = response.choices?.[0]
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
id: response.id || `chatcmpl_${Date.now()}`,
|
|
72
|
+
content: choice?.message?.content || '',
|
|
73
|
+
toolCalls: choice?.message?.tool_calls || [],
|
|
74
|
+
usage: {
|
|
75
|
+
promptTokens: response.usage?.prompt_tokens || 0,
|
|
76
|
+
completionTokens: response.usage?.completion_tokens || 0
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private buildMessages(systemPrompt: string[], messages: any[]): any[] {
|
|
82
|
+
// Merge system prompts and messages
|
|
83
|
+
const systemMessages = systemPrompt.map(prompt => ({
|
|
84
|
+
role: 'system',
|
|
85
|
+
content: prompt
|
|
86
|
+
}))
|
|
87
|
+
|
|
88
|
+
return [...systemMessages, ...messages]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { ModelAPIAdapter } from './base'
|
|
2
|
+
import { UnifiedRequestParams, UnifiedResponse } from '../../types/modelCapabilities'
|
|
3
|
+
import { Tool } from '../../Tool'
|
|
4
|
+
import { zodToJsonSchema } from 'zod-to-json-schema'
|
|
5
|
+
|
|
6
|
+
export class ResponsesAPIAdapter extends ModelAPIAdapter {
|
|
7
|
+
createRequest(params: UnifiedRequestParams): any {
|
|
8
|
+
const { messages, systemPrompt, tools, maxTokens } = params
|
|
9
|
+
|
|
10
|
+
// Separate system messages and user messages
|
|
11
|
+
const systemMessages = messages.filter(m => m.role === 'system')
|
|
12
|
+
const nonSystemMessages = messages.filter(m => m.role !== 'system')
|
|
13
|
+
|
|
14
|
+
// Build base request
|
|
15
|
+
const request: any = {
|
|
16
|
+
model: this.modelProfile.modelName,
|
|
17
|
+
input: this.convertMessagesToInput(nonSystemMessages),
|
|
18
|
+
instructions: this.buildInstructions(systemPrompt, systemMessages)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Add token limit
|
|
22
|
+
request[this.getMaxTokensParam()] = maxTokens
|
|
23
|
+
|
|
24
|
+
// Add temperature (GPT-5 only supports 1)
|
|
25
|
+
if (this.getTemperature() === 1) {
|
|
26
|
+
request.temperature = 1
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Add reasoning control - correct format for Responses API
|
|
30
|
+
if (this.shouldIncludeReasoningEffort()) {
|
|
31
|
+
request.reasoning = {
|
|
32
|
+
effort: params.reasoningEffort || this.modelProfile.reasoningEffort || 'medium'
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Add verbosity control - correct format for Responses API
|
|
37
|
+
if (this.shouldIncludeVerbosity()) {
|
|
38
|
+
request.text = {
|
|
39
|
+
verbosity: params.verbosity || 'high' // High verbosity for coding tasks
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Add tools
|
|
44
|
+
if (tools && tools.length > 0) {
|
|
45
|
+
request.tools = this.buildTools(tools)
|
|
46
|
+
|
|
47
|
+
// Handle allowed_tools
|
|
48
|
+
if (params.allowedTools && this.capabilities.toolCalling.supportsAllowedTools) {
|
|
49
|
+
request.tool_choice = {
|
|
50
|
+
type: 'allowed_tools',
|
|
51
|
+
mode: 'auto',
|
|
52
|
+
tools: params.allowedTools
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Add state management
|
|
58
|
+
if (params.previousResponseId && this.capabilities.stateManagement.supportsPreviousResponseId) {
|
|
59
|
+
request.previous_response_id = params.previousResponseId
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return request
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
buildTools(tools: Tool[]): any[] {
|
|
66
|
+
// If freeform not supported, use traditional format
|
|
67
|
+
if (!this.capabilities.toolCalling.supportsFreeform) {
|
|
68
|
+
return tools.map(tool => ({
|
|
69
|
+
type: 'function',
|
|
70
|
+
function: {
|
|
71
|
+
name: tool.name,
|
|
72
|
+
description: tool.description || '',
|
|
73
|
+
parameters: tool.inputJSONSchema || zodToJsonSchema(tool.inputSchema)
|
|
74
|
+
}
|
|
75
|
+
}))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Custom tools format (GPT-5 feature)
|
|
79
|
+
return tools.map(tool => {
|
|
80
|
+
const hasSchema = tool.inputJSONSchema || tool.inputSchema
|
|
81
|
+
const isCustom = !hasSchema
|
|
82
|
+
|
|
83
|
+
if (isCustom) {
|
|
84
|
+
// Custom tool format
|
|
85
|
+
return {
|
|
86
|
+
type: 'custom',
|
|
87
|
+
name: tool.name,
|
|
88
|
+
description: tool.description || ''
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
// Traditional function format
|
|
92
|
+
return {
|
|
93
|
+
type: 'function',
|
|
94
|
+
function: {
|
|
95
|
+
name: tool.name,
|
|
96
|
+
description: tool.description || '',
|
|
97
|
+
parameters: tool.inputJSONSchema || zodToJsonSchema(tool.inputSchema)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
parseResponse(response: any): UnifiedResponse {
|
|
105
|
+
// Process basic text output
|
|
106
|
+
let content = response.output_text || ''
|
|
107
|
+
|
|
108
|
+
// Process structured output
|
|
109
|
+
if (response.output && Array.isArray(response.output)) {
|
|
110
|
+
const messageItems = response.output.filter(item => item.type === 'message')
|
|
111
|
+
if (messageItems.length > 0) {
|
|
112
|
+
content = messageItems
|
|
113
|
+
.map(item => {
|
|
114
|
+
if (item.content && Array.isArray(item.content)) {
|
|
115
|
+
return item.content
|
|
116
|
+
.filter(c => c.type === 'text')
|
|
117
|
+
.map(c => c.text)
|
|
118
|
+
.join('\n')
|
|
119
|
+
}
|
|
120
|
+
return item.content || ''
|
|
121
|
+
})
|
|
122
|
+
.filter(Boolean)
|
|
123
|
+
.join('\n\n')
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Parse tool calls
|
|
128
|
+
const toolCalls = this.parseToolCalls(response)
|
|
129
|
+
|
|
130
|
+
// Build unified response
|
|
131
|
+
return {
|
|
132
|
+
id: response.id || `resp_${Date.now()}`,
|
|
133
|
+
content,
|
|
134
|
+
toolCalls,
|
|
135
|
+
usage: {
|
|
136
|
+
promptTokens: response.usage?.input_tokens || 0,
|
|
137
|
+
completionTokens: response.usage?.output_tokens || 0,
|
|
138
|
+
reasoningTokens: response.usage?.output_tokens_details?.reasoning_tokens
|
|
139
|
+
},
|
|
140
|
+
responseId: response.id // Save for state management
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private convertMessagesToInput(messages: any[]): any {
|
|
145
|
+
// Convert messages to Responses API input format
|
|
146
|
+
// May need adjustment based on actual API specification
|
|
147
|
+
return messages
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private buildInstructions(systemPrompt: string[], systemMessages: any[]): string {
|
|
151
|
+
const systemContent = systemMessages.map(m => m.content).join('\n\n')
|
|
152
|
+
const promptContent = systemPrompt.join('\n\n')
|
|
153
|
+
return [systemContent, promptContent].filter(Boolean).join('\n\n')
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private parseToolCalls(response: any): any[] {
|
|
157
|
+
if (!response.output || !Array.isArray(response.output)) {
|
|
158
|
+
return []
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return response.output
|
|
162
|
+
.filter(item => item.type === 'tool_call')
|
|
163
|
+
.map(item => ({
|
|
164
|
+
id: item.id || `tool_${Date.now()}`,
|
|
165
|
+
type: 'tool_call',
|
|
166
|
+
name: item.name,
|
|
167
|
+
arguments: item.arguments // Can be text or JSON
|
|
168
|
+
}))
|
|
169
|
+
}
|
|
170
|
+
}
|