Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
A
aisbf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexlab
aisbf
Commits
f182fbd1
Commit
f182fbd1
authored
Apr 20, 2026
by
Your Name
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
All working but qwen-oauth2
parent
8b50a0ae
Changes
6
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
3945 additions
and
3030 deletions
+3945
-3030
package-lock.json
.kilo/package-lock.json
+115
-0
codex.py
aisbf/providers/codex.py
+100
-40
qwen.py
aisbf/providers/qwen.py
+73
-21
antani_sqlite_db_3f9c7e7f.sqlite3
antani_sqlite_db_3f9c7e7f.sqlite3
+0
-0
chatgpt-api-implementation-guide.md
chatgpt-api-implementation-guide.md
+1178
-1255
qwen-oauth2-analysis.md
qwen-oauth2-analysis.md
+2479
-1714
No files found.
.kilo/package-lock.json
0 → 100644
View file @
f182fbd1
{
"name"
:
".kilo"
,
"lockfileVersion"
:
3
,
"requires"
:
true
,
"packages"
:
{
""
:
{
"dependencies"
:
{
"@kilocode/plugin"
:
"7.2.14"
}
},
"node_modules/@kilocode/plugin"
:
{
"version"
:
"7.2.14"
,
"resolved"
:
"https://registry.npmjs.org/@kilocode/plugin/-/plugin-7.2.14.tgz"
,
"integrity"
:
"sha512-mS+WA9HZIBH2qQ9ARA+v0q4MdQTSdfOvKbe4AOSkjP+P5hVA70OM/UVM9DVcvmjSOxU+wuUxmOy+j/EQIrgFmw=="
,
"license"
:
"MIT"
,
"dependencies"
:
{
"@kilocode/sdk"
:
"7.2.14"
,
"zod"
:
"4.1.8"
},
"peerDependencies"
:
{
"@opentui/core"
:
">=0.1.97"
,
"@opentui/solid"
:
">=0.1.97"
},
"peerDependenciesMeta"
:
{
"@opentui/core"
:
{
"optional"
:
true
},
"@opentui/solid"
:
{
"optional"
:
true
}
}
},
"node_modules/@kilocode/sdk"
:
{
"version"
:
"7.2.14"
,
"resolved"
:
"https://registry.npmjs.org/@kilocode/sdk/-/sdk-7.2.14.tgz"
,
"integrity"
:
"sha512-Naz83lFrsbavuDp6UwxRuglOaSNvRBsZfcRNvb7RpWYAwbuJP0dBdhpXj6uO3ta5qxeQ2JzxKNC9Ffz+LCLLDg=="
,
"license"
:
"MIT"
,
"dependencies"
:
{
"cross-spawn"
:
"7.0.6"
}
},
"node_modules/cross-spawn"
:
{
"version"
:
"7.0.6"
,
"resolved"
:
"https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz"
,
"integrity"
:
"sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="
,
"license"
:
"MIT"
,
"dependencies"
:
{
"path-key"
:
"^3.1.0"
,
"shebang-command"
:
"^2.0.0"
,
"which"
:
"^2.0.1"
},
"engines"
:
{
"node"
:
">= 8"
}
},
"node_modules/isexe"
:
{
"version"
:
"2.0.0"
,
"resolved"
:
"https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
,
"integrity"
:
"sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
,
"license"
:
"ISC"
},
"node_modules/path-key"
:
{
"version"
:
"3.1.1"
,
"resolved"
:
"https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
,
"integrity"
:
"sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
,
"license"
:
"MIT"
,
"engines"
:
{
"node"
:
">=8"
}
},
"node_modules/shebang-command"
:
{
"version"
:
"2.0.0"
,
"resolved"
:
"https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
,
"integrity"
:
"sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="
,
"license"
:
"MIT"
,
"dependencies"
:
{
"shebang-regex"
:
"^3.0.0"
},
"engines"
:
{
"node"
:
">=8"
}
},
"node_modules/shebang-regex"
:
{
"version"
:
"3.0.0"
,
"resolved"
:
"https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz"
,
"integrity"
:
"sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
,
"license"
:
"MIT"
,
"engines"
:
{
"node"
:
">=8"
}
},
"node_modules/which"
:
{
"version"
:
"2.0.2"
,
"resolved"
:
"https://registry.npmjs.org/which/-/which-2.0.2.tgz"
,
"integrity"
:
"sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="
,
"license"
:
"ISC"
,
"dependencies"
:
{
"isexe"
:
"^2.0.0"
},
"bin"
:
{
"node-which"
:
"bin/node-which"
},
"engines"
:
{
"node"
:
">= 8"
}
},
"node_modules/zod"
:
{
"version"
:
"4.1.8"
,
"license"
:
"MIT"
,
"funding"
:
{
"url"
:
"https://github.com/sponsors/colinhacks"
}
}
}
}
aisbf/providers/codex.py
View file @
f182fbd1
...
@@ -25,7 +25,7 @@ import json
...
@@ -25,7 +25,7 @@ import json
import
logging
import
logging
import
time
import
time
import
uuid
import
uuid
from
typing
import
Dict
,
List
,
Optional
,
Union
,
AsyncIterator
from
typing
import
Dict
,
List
,
Optional
,
Union
,
AsyncIterator
,
Tuple
from
openai
import
OpenAI
from
openai
import
OpenAI
import
httpx
import
httpx
...
@@ -49,8 +49,8 @@ class CodexProviderHandler(BaseProviderHandler):
...
@@ -49,8 +49,8 @@ class CodexProviderHandler(BaseProviderHandler):
- Standard OpenAI protocol with Bearer token
- Standard OpenAI protocol with Bearer token
**OAuth2 Mode** (no api_key, OAuth2 credentials):
**OAuth2 Mode** (no api_key, OAuth2 credentials):
- Uses ChatGPT backend API: https://chatgpt.com/backend-api
/codex
- Uses ChatGPT backend API: https://chatgpt.com/backend-api
- Uses Responses API endpoint: /
v1
/responses
- Uses Responses API endpoint: /
codex
/responses
- ChatGPT-specific protocol with SSE streaming
- ChatGPT-specific protocol with SSE streaming
- Includes ChatGPT-Account-ID header
- Includes ChatGPT-Account-ID header
...
@@ -104,7 +104,7 @@ class CodexProviderHandler(BaseProviderHandler):
...
@@ -104,7 +104,7 @@ class CodexProviderHandler(BaseProviderHandler):
# OAuth2 Mode: Check if OAuth2 is authenticated
# OAuth2 Mode: Check if OAuth2 is authenticated
# If authenticated, use ChatGPT backend; otherwise use configured endpoint
# If authenticated, use ChatGPT backend; otherwise use configured endpoint
if
self
.
oauth2
.
is_authenticated
():
if
self
.
oauth2
.
is_authenticated
():
self
.
base_url
=
"https://chatgpt.com/backend-api
/codex
"
self
.
base_url
=
"https://chatgpt.com/backend-api"
logger
.
info
(
f
"CodexProviderHandler: Initialized in OAuth2 mode with ChatGPT backend: {self.base_url}"
)
logger
.
info
(
f
"CodexProviderHandler: Initialized in OAuth2 mode with ChatGPT backend: {self.base_url}"
)
else
:
else
:
# Not yet authenticated, keep configured endpoint
# Not yet authenticated, keep configured endpoint
...
@@ -160,8 +160,8 @@ class CodexProviderHandler(BaseProviderHandler):
...
@@ -160,8 +160,8 @@ class CodexProviderHandler(BaseProviderHandler):
self
.
_account_id
=
self
.
oauth2
.
credentials
[
'tokens'
]
.
get
(
'account_id'
)
self
.
_account_id
=
self
.
oauth2
.
credentials
[
'tokens'
]
.
get
(
'account_id'
)
# Switch to ChatGPT backend if OAuth2 is now authenticated
# Switch to ChatGPT backend if OAuth2 is now authenticated
if
not
self
.
_use_api_key_mode
and
self
.
base_url
!=
"https://chatgpt.com/backend-api
/codex
"
:
if
not
self
.
_use_api_key_mode
and
self
.
base_url
!=
"https://chatgpt.com/backend-api"
:
self
.
base_url
=
"https://chatgpt.com/backend-api
/codex
"
self
.
base_url
=
"https://chatgpt.com/backend-api"
logger
.
info
(
f
"CodexProviderHandler: Switched to ChatGPT backend after OAuth2 authentication: {self.base_url}"
)
logger
.
info
(
f
"CodexProviderHandler: Switched to ChatGPT backend after OAuth2 authentication: {self.base_url}"
)
# Update the configuration with the new endpoint
# Update the configuration with the new endpoint
...
@@ -257,19 +257,35 @@ class CodexProviderHandler(BaseProviderHandler):
...
@@ -257,19 +257,35 @@ class CodexProviderHandler(BaseProviderHandler):
# OAuth2 Mode Methods (ChatGPT Responses API)
# OAuth2 Mode Methods (ChatGPT Responses API)
# =========================================================================
# =========================================================================
def
_convert_messages_to_responses_format
(
self
,
messages
:
List
[
Dict
])
->
List
[
Dict
]:
def
_convert_messages_to_responses_format
(
self
,
messages
:
List
[
Dict
])
->
Tuple
[
List
[
Dict
],
Optional
[
str
]
]:
"""
"""
Convert OpenAI Chat Completions messages to Responses API format.
Convert OpenAI Chat Completions messages to Responses API format.
OpenAI format: {"role": "user", "content": "text"}
OpenAI format: {"role": "user", "content": "text"}
Responses format: {"type": "message", "role": "user", "content": [{"type": "input_text", "text": "text"}]}
Responses format: {"type": "message", "role": "user", "content": [{"type": "input_text", "text": "text"}]}
Returns:
tuple: (converted_messages, system_instruction)
- converted_messages: List of messages in Responses API format
- system_instruction: Combined system message content (if any)
"""
"""
result
=
[]
result
=
[]
system_instructions
=
[]
for
msg
in
messages
:
for
msg
in
messages
:
role
=
msg
.
get
(
"role"
,
"user"
)
role
=
msg
.
get
(
"role"
,
"user"
)
content
=
msg
.
get
(
"content"
,
""
)
content
=
msg
.
get
(
"content"
,
""
)
# Handle system messages - extract for instructions field
if
role
==
"system"
:
if
isinstance
(
content
,
str
):
system_instructions
.
append
(
content
)
elif
isinstance
(
content
,
list
):
for
item
in
content
:
if
isinstance
(
item
,
dict
)
and
item
.
get
(
"type"
)
==
"text"
:
system_instructions
.
append
(
item
.
get
(
"text"
,
""
))
continue
# Handle tool messages
# Handle tool messages
if
role
==
"tool"
:
if
role
==
"tool"
:
result
.
append
({
result
.
append
({
...
@@ -299,17 +315,17 @@ class CodexProviderHandler(BaseProviderHandler):
...
@@ -299,17 +315,17 @@ class CodexProviderHandler(BaseProviderHandler):
})
})
continue
continue
# Handle regular messages
# Handle regular messages
(user, developer, assistant)
content_items
=
[]
content_items
=
[]
if
isinstance
(
content
,
str
):
if
isinstance
(
content
,
str
):
content_type
=
"input_text"
if
role
in
[
"user"
,
"
system"
,
"
developer"
]
else
"output_text"
content_type
=
"input_text"
if
role
in
[
"user"
,
"developer"
]
else
"output_text"
content_items
.
append
({
"type"
:
content_type
,
"text"
:
content
})
content_items
.
append
({
"type"
:
content_type
,
"text"
:
content
})
elif
isinstance
(
content
,
list
):
elif
isinstance
(
content
,
list
):
# Handle multimodal content
# Handle multimodal content
for
item
in
content
:
for
item
in
content
:
if
isinstance
(
item
,
dict
):
if
isinstance
(
item
,
dict
):
if
item
.
get
(
"type"
)
==
"text"
:
if
item
.
get
(
"type"
)
==
"text"
:
content_type
=
"input_text"
if
role
in
[
"user"
,
"
system"
,
"
developer"
]
else
"output_text"
content_type
=
"input_text"
if
role
in
[
"user"
,
"developer"
]
else
"output_text"
content_items
.
append
({
"type"
:
content_type
,
"text"
:
item
.
get
(
"text"
,
""
)})
content_items
.
append
({
"type"
:
content_type
,
"text"
:
item
.
get
(
"text"
,
""
)})
elif
item
.
get
(
"type"
)
==
"image_url"
:
elif
item
.
get
(
"type"
)
==
"image_url"
:
content_items
.
append
({
content_items
.
append
({
...
@@ -324,7 +340,40 @@ class CodexProviderHandler(BaseProviderHandler):
...
@@ -324,7 +340,40 @@ class CodexProviderHandler(BaseProviderHandler):
"content"
:
content_items
"content"
:
content_items
})
})
return
result
# Combine system instructions
combined_system
=
" "
.
join
(
system_instructions
)
if
system_instructions
else
None
return
result
,
combined_system
def
_convert_tools_to_codex_format
(
self
,
tools
:
Optional
[
List
[
Dict
]])
->
List
[
Dict
]:
"""
Convert OpenAI tool format to Codex/ChatGPT format.
OpenAI format: {"type": "function", "function": {"name": "...", "description": "...", "parameters": {...}}}
Codex format: {"type": "function", "name": "...", "description": "...", "parameters": {...}}
Key difference: No nested "function" object in Codex format.
"""
if
not
tools
:
return
[]
converted_tools
=
[]
for
tool
in
tools
:
if
tool
.
get
(
"type"
)
==
"function"
and
"function"
in
tool
:
# OpenAI format - flatten it
func
=
tool
[
"function"
]
converted_tool
=
{
"type"
:
"function"
,
"name"
:
func
.
get
(
"name"
),
"description"
:
func
.
get
(
"description"
,
""
),
"parameters"
:
func
.
get
(
"parameters"
,
{}),
}
converted_tools
.
append
(
converted_tool
)
else
:
# Already in Codex format or other type
converted_tools
.
append
(
tool
)
return
converted_tools
def
_build_responses_request
(
def
_build_responses_request
(
self
,
self
,
...
@@ -336,29 +385,32 @@ class CodexProviderHandler(BaseProviderHandler):
...
@@ -336,29 +385,32 @@ class CodexProviderHandler(BaseProviderHandler):
tool_choice
:
Optional
[
Union
[
str
,
Dict
]]
=
None
,
tool_choice
:
Optional
[
Union
[
str
,
Dict
]]
=
None
,
)
->
Dict
:
)
->
Dict
:
"""Build a Responses API request payload."""
"""Build a Responses API request payload."""
# Convert messages to Responses format
# Convert messages to Responses format and extract system instructions
input_items
=
self
.
_convert_messages_to_responses_format
(
messages
)
input_items
,
system_instruction
=
self
.
_convert_messages_to_responses_format
(
messages
)
# Use system instruction from messages if available, otherwise use default
instructions
=
system_instruction
if
system_instruction
else
"You are Codex, a helpful AI assistant for coding tasks."
# Convert tools to Codex format (flatten the structure)
codex_tools
=
self
.
_convert_tools_to_codex_format
(
tools
)
# Build base request
# Build base request
request
=
{
request
=
{
"model"
:
model
,
"model"
:
model
,
"instructions"
:
"You are Codex, a helpful AI assistant for coding tasks."
,
"instructions"
:
instructions
,
"input"
:
input_items
,
"input"
:
input_items
,
"stream"
:
True
,
"stream"
:
True
,
"store"
:
False
,
"store"
:
False
,
"tools"
:
codex_tools
,
"tool_choice"
:
"auto"
,
"parallel_tool_calls"
:
True
,
}
}
# Add optional parameters
# Add optional parameters
if
max_tokens
is
not
None
:
# Note: temperature and max_tokens are not supported by /codex/responses endpoint
request
[
"max_tokens"
]
=
max_tokens
# They are handled internally by the model
if
temperature
is
not
None
:
request
[
"temperature"
]
=
temperature
if
tools
:
# Convert OpenAI tool format to Responses API format
request
[
"tools"
]
=
tools
# Override tool_choice if explicitly provided
if
tool_choice
:
if
tool_choice
:
request
[
"tool_choice"
]
=
tool_choice
if
isinstance
(
tool_choice
,
str
)
else
"auto"
request
[
"tool_choice"
]
=
tool_choice
if
isinstance
(
tool_choice
,
str
)
else
"auto"
...
@@ -506,16 +558,24 @@ class CodexProviderHandler(BaseProviderHandler):
...
@@ -506,16 +558,24 @@ class CodexProviderHandler(BaseProviderHandler):
headers
=
self
.
_build_headers
(
api_key
,
conversation_id
)
headers
=
self
.
_build_headers
(
api_key
,
conversation_id
)
# Make request to Responses API
# Make request to Responses API
url
=
f
"{self.base_url}/
v1
/responses"
url
=
f
"{self.base_url}/
codex
/responses"
logger
.
info
(
f
"CodexProviderHandler: Sending request to {url}"
)
logger
.
info
(
f
"CodexProviderHandler: Sending request to {url}"
)
if
AISBF_DEBUG
:
logger
.
info
(
f
"CodexProviderHandler: Request payload: {json.dumps(request_payload, indent=2)}"
)
logger
.
info
(
f
"CodexProviderHandler: Request headers: {json.dumps({k: v for k, v in headers.items() if k.lower() != 'authorization'}, indent=2)}"
)
async
with
httpx
.
AsyncClient
(
timeout
=
300.0
)
as
client
:
async
with
httpx
.
AsyncClient
(
timeout
=
300.0
)
as
client
:
response
=
await
client
.
post
(
async
with
client
.
stream
(
"POST"
,
url
,
url
,
headers
=
headers
,
headers
=
headers
,
json
=
request_payload
,
json
=
request_payload
,
)
)
as
response
:
if
response
.
status_code
>=
400
:
error_body
=
await
response
.
aread
()
logger
.
error
(
f
"CodexProviderHandler: Error response status: {response.status_code}"
)
logger
.
error
(
f
"CodexProviderHandler: Error response body: {error_body.decode('utf-8')}"
)
response
.
raise_for_status
()
response
.
raise_for_status
()
...
...
aisbf/providers/qwen.py
View file @
f182fbd1
...
@@ -25,6 +25,7 @@ import asyncio
...
@@ -25,6 +25,7 @@ import asyncio
import
time
import
time
import
json
import
json
import
platform
import
platform
import
uuid
from
typing
import
Dict
,
List
,
Optional
,
Union
from
typing
import
Dict
,
List
,
Optional
,
Union
from
openai
import
AsyncOpenAI
from
openai
import
AsyncOpenAI
from
..models
import
Model
from
..models
import
Model
...
@@ -130,19 +131,35 @@ class QwenProviderHandler(BaseProviderHandler):
...
@@ -130,19 +131,35 @@ class QwenProviderHandler(BaseProviderHandler):
logger
.
info
(
"QwenProviderHandler: Using OAuth2 authentication"
)
logger
.
info
(
"QwenProviderHandler: Using OAuth2 authentication"
)
auth_key
=
access_token
auth_key
=
access_token
#
Use provider configured endpoint for OAuth2 (fixed endpoints)
#
Get resource URL from auth and normalize it properly
base_url
=
self
.
provider_config
.
endpoint
base_url
=
self
.
auth
.
get_resource_url
()
# Normalize endpoint
# Normalize endpoint exactly as specified in documentation
if
not
base_url
.
startswith
(
"http"
):
if
not
base_url
.
startswith
(
"http"
):
base_url
=
f
"https://{base_url}"
base_url
=
f
"https://{base_url}"
# DashScope endpoint already includes /v1 so do not append again
if
not
base_url
.
endswith
(
"/v1"
):
base_url
=
f
"{base_url}/v1"
logger
.
info
(
f
"QwenProviderHandler: Final endpoint: {base_url}"
)
# Build required DashScope headers
import
uuid
user_agent
=
f
"QwenCode/1.0.0 ({platform.system().lower()}; {platform.machine()})"
default_headers
=
{
"Accept"
:
"application/json"
,
"X-DashScope-CacheControl"
:
"enable"
,
"X-DashScope-UserAgent"
:
user_agent
,
"X-DashScope-AuthType"
:
"qwen-oauth"
,
"x-request-id"
:
str
(
uuid
.
uuid4
()),
}
self
.
_sdk_client
=
AsyncOpenAI
(
self
.
_sdk_client
=
AsyncOpenAI
(
api_key
=
auth_key
,
api_key
=
auth_key
,
base_url
=
base_url
,
base_url
=
base_url
,
max_retries
=
3
,
max_retries
=
3
,
timeout
=
httpx
.
Timeout
(
300.0
,
connect
=
30.0
),
timeout
=
httpx
.
Timeout
(
300.0
,
connect
=
30.0
),
default_headers
=
default_headers
,
)
)
logger
.
info
(
f
"QwenProviderHandler: Created SDK client (endpoint: {base_url})"
)
logger
.
info
(
f
"QwenProviderHandler: Created SDK client (endpoint: {base_url})"
)
...
@@ -223,12 +240,22 @@ class QwenProviderHandler(BaseProviderHandler):
...
@@ -223,12 +240,22 @@ class QwenProviderHandler(BaseProviderHandler):
# Get SDK client with current OAuth token
# Get SDK client with current OAuth token
client
=
await
self
.
_get_sdk_client
()
client
=
await
self
.
_get_sdk_client
()
# Generate session tracking IDs
session_id
=
str
(
uuid
.
uuid4
())
prompt_id
=
str
(
uuid
.
uuid4
())
# Build request parameters
# Build request parameters
request_params
=
{
request_params
=
{
"model"
:
model
,
"model"
:
model
,
"messages"
:
messages
,
"messages"
:
messages
,
"max_tokens"
:
max_tokens
or
4096
,
"max_tokens"
:
max_tokens
or
4096
,
"stream"
:
stream
,
"stream"
:
stream
,
"extra_body"
:
{
"metadata"
:
{
"sessionId"
:
session_id
,
"promptId"
:
prompt_id
}
}
}
}
if
temperature
is
not
None
and
temperature
>
0
:
if
temperature
is
not
None
and
temperature
>
0
:
...
@@ -240,6 +267,10 @@ class QwenProviderHandler(BaseProviderHandler):
...
@@ -240,6 +267,10 @@ class QwenProviderHandler(BaseProviderHandler):
if
tool_choice
and
tools
:
if
tool_choice
and
tools
:
request_params
[
"tool_choice"
]
=
tool_choice
request_params
[
"tool_choice"
]
=
tool_choice
# Add stream_options for streaming requests
if
stream
:
request_params
[
"stream_options"
]
=
{
"include_usage"
:
True
}
try
:
try
:
if
stream
:
if
stream
:
logger
.
info
(
"QwenProviderHandler: Using streaming mode"
)
logger
.
info
(
"QwenProviderHandler: Using streaming mode"
)
...
@@ -440,16 +471,37 @@ class QwenProviderHandler(BaseProviderHandler):
...
@@ -440,16 +471,37 @@ class QwenProviderHandler(BaseProviderHandler):
using_api_key
=
qwen_config
and
isinstance
(
qwen_config
,
dict
)
and
qwen_config
.
get
(
'api_key'
)
using_api_key
=
qwen_config
and
isinstance
(
qwen_config
,
dict
)
and
qwen_config
.
get
(
'api_key'
)
if
not
using_api_key
:
if
not
using_api_key
:
# OAuth2 authentication: return f
ixed
model list
# OAuth2 authentication: return f
ull
model list
logger
.
info
(
"QwenProviderHandler: Using OAuth2 authentication, returning f
ixed
model list"
)
logger
.
info
(
"QwenProviderHandler: Using OAuth2 authentication, returning f
ull
model list"
)
return
[
return
[
Model
(
Model
(
id
=
"
coder-model
"
,
id
=
"
qwen-turbo
"
,
name
=
"
Coder Model
"
,
name
=
"
Qwen Turbo
"
,
provider_id
=
self
.
provider_id
,
provider_id
=
self
.
provider_id
,
context_size
=
1000000
,
context_size
=
32000
,
context_length
=
1000000
,
context_length
=
32000
,
)
),
Model
(
id
=
"qwen-plus"
,
name
=
"Qwen Plus"
,
provider_id
=
self
.
provider_id
,
context_size
=
128000
,
context_length
=
128000
,
),
Model
(
id
=
"qwen-max"
,
name
=
"Qwen Max"
,
provider_id
=
self
.
provider_id
,
context_size
=
128000
,
context_length
=
128000
,
),
Model
(
id
=
"qwen3-coder-plus"
,
name
=
"Qwen 3 Coder Plus"
,
provider_id
=
self
.
provider_id
,
context_size
=
128000
,
context_length
=
128000
,
),
]
]
# API token authentication: fetch from models endpoint
# API token authentication: fetch from models endpoint
...
@@ -502,10 +554,10 @@ class QwenProviderHandler(BaseProviderHandler):
...
@@ -502,10 +554,10 @@ class QwenProviderHandler(BaseProviderHandler):
# Fallback to static model list
# Fallback to static model list
logger
.
warning
(
"QwenProviderHandler: No models returned from API, using static list"
)
logger
.
warning
(
"QwenProviderHandler: No models returned from API, using static list"
)
models
=
[
models
=
[
Model
(
id
=
"qwen-
plus"
,
name
=
"Qwen Plus
"
,
provider_id
=
self
.
provider_id
,
context_size
=
32000
),
Model
(
id
=
"qwen-
turbo"
,
name
=
"Qwen Turbo
"
,
provider_id
=
self
.
provider_id
,
context_size
=
32000
),
Model
(
id
=
"qwen-
turbo"
,
name
=
"Qwen Turbo"
,
provider_id
=
self
.
provider_id
,
context_size
=
8000
),
Model
(
id
=
"qwen-
plus"
,
name
=
"Qwen Plus"
,
provider_id
=
self
.
provider_id
,
context_size
=
12
8000
),
Model
(
id
=
"qwen-max"
,
name
=
"Qwen Max"
,
provider_id
=
self
.
provider_id
,
context_size
=
8000
),
Model
(
id
=
"qwen-max"
,
name
=
"Qwen Max"
,
provider_id
=
self
.
provider_id
,
context_size
=
12
8000
),
Model
(
id
=
"
coder-model"
,
name
=
"Qwen Coder"
,
provider_id
=
self
.
provider_id
,
context_size
=
32
000
),
Model
(
id
=
"
qwen3-coder-plus"
,
name
=
"Qwen 3 Coder Plus"
,
provider_id
=
self
.
provider_id
,
context_size
=
128
000
),
]
]
logger
.
info
(
f
"QwenProviderHandler: Returning {len(models)} models"
)
logger
.
info
(
f
"QwenProviderHandler: Returning {len(models)} models"
)
...
@@ -517,8 +569,8 @@ class QwenProviderHandler(BaseProviderHandler):
...
@@ -517,8 +569,8 @@ class QwenProviderHandler(BaseProviderHandler):
# Return static fallback list
# Return static fallback list
logger
.
info
(
"QwenProviderHandler: Using static fallback model list"
)
logger
.
info
(
"QwenProviderHandler: Using static fallback model list"
)
return
[
return
[
Model
(
id
=
"qwen-
plus"
,
name
=
"Qwen Plus
"
,
provider_id
=
self
.
provider_id
,
context_size
=
32000
),
Model
(
id
=
"qwen-
turbo"
,
name
=
"Qwen Turbo
"
,
provider_id
=
self
.
provider_id
,
context_size
=
32000
),
Model
(
id
=
"qwen-
turbo"
,
name
=
"Qwen Turbo"
,
provider_id
=
self
.
provider_id
,
context_size
=
8000
),
Model
(
id
=
"qwen-
plus"
,
name
=
"Qwen Plus"
,
provider_id
=
self
.
provider_id
,
context_size
=
12
8000
),
Model
(
id
=
"qwen-max"
,
name
=
"Qwen Max"
,
provider_id
=
self
.
provider_id
,
context_size
=
8000
),
Model
(
id
=
"qwen-max"
,
name
=
"Qwen Max"
,
provider_id
=
self
.
provider_id
,
context_size
=
12
8000
),
Model
(
id
=
"
coder-model"
,
name
=
"Qwen Coder"
,
provider_id
=
self
.
provider_id
,
context_size
=
32
000
),
Model
(
id
=
"
qwen3-coder-plus"
,
name
=
"Qwen 3 Coder Plus"
,
provider_id
=
self
.
provider_id
,
context_size
=
128
000
),
]
]
antani_sqlite_db_3f9c7e7f.sqlite3
0 → 100644
View file @
f182fbd1
chatgpt-api-implementation-guide.md
View file @
f182fbd1
This diff is collapsed.
Click to expand it.
qwen-oauth2-analysis.md
View file @
f182fbd1
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment