refactor: share streaming tool event normalization
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -92,6 +92,23 @@ def _allowed_tool_events(
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def _allowed_stream_tool_event(
|
||||||
|
event: Any,
|
||||||
|
*,
|
||||||
|
tool_config: dict[str, Any] | None,
|
||||||
|
forced_tool_name: str | None = None,
|
||||||
|
) -> dict[str, Any] | None:
|
||||||
|
if not isinstance(event, dict) or event.get("type") != "tool":
|
||||||
|
return None
|
||||||
|
tool = event.get("tool")
|
||||||
|
if not isinstance(tool, dict):
|
||||||
|
return None
|
||||||
|
tool_name = str(tool.get("name") or "")
|
||||||
|
if not _tool_event_allowed(tool_name, tool_config, forced_tool_name=forced_tool_name):
|
||||||
|
return None
|
||||||
|
return tool
|
||||||
|
|
||||||
|
|
||||||
def _openai_forced_tool_name(tool_choice: Any) -> str | None:
|
def _openai_forced_tool_name(tool_choice: Any) -> str | None:
|
||||||
if not isinstance(tool_choice, dict):
|
if not isinstance(tool_choice, dict):
|
||||||
return None
|
return None
|
||||||
|
|||||||
39
app/main.py
39
app/main.py
@@ -39,6 +39,7 @@ from .http.responses_adapter import (
|
|||||||
_sse_data,
|
_sse_data,
|
||||||
)
|
)
|
||||||
from .http.tool_bridge import (
|
from .http.tool_bridge import (
|
||||||
|
_allowed_stream_tool_event,
|
||||||
_allowed_tool_events,
|
_allowed_tool_events,
|
||||||
_anthropic_forced_tool_name,
|
_anthropic_forced_tool_name,
|
||||||
_anthropic_tool_name as _shared_anthropic_tool_name,
|
_anthropic_tool_name as _shared_anthropic_tool_name,
|
||||||
@@ -51,7 +52,6 @@ from .http.tool_bridge import (
|
|||||||
_openai_tool_call,
|
_openai_tool_call,
|
||||||
_openai_tool_name as _shared_openai_tool_name,
|
_openai_tool_name as _shared_openai_tool_name,
|
||||||
_tool_code_single_arg_name,
|
_tool_code_single_arg_name,
|
||||||
_tool_event_allowed,
|
|
||||||
)
|
)
|
||||||
from .lingma_pool import LingmaPool, PoolInstance
|
from .lingma_pool import LingmaPool, PoolInstance
|
||||||
from .logging_config import configure_logging, get_logger, request_id_var
|
from .logging_config import configure_logging, get_logger, request_id_var
|
||||||
@@ -551,14 +551,6 @@ def _stream_text(event: Any) -> str:
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def _stream_tool_event(event: Any) -> dict[str, Any] | None:
|
|
||||||
if isinstance(event, dict) and event.get("type") == "tool":
|
|
||||||
tool = event.get("tool")
|
|
||||||
if isinstance(tool, dict):
|
|
||||||
return tool
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/v1/chat/completions", dependencies=[Depends(auth_guard)])
|
@app.post("/v1/chat/completions", dependencies=[Depends(auth_guard)])
|
||||||
async def v1_chat_completions(req: ChatCompletionsRequest, request: Request):
|
async def v1_chat_completions(req: ChatCompletionsRequest, request: Request):
|
||||||
p = _require_pool()
|
p = _require_pool()
|
||||||
@@ -693,16 +685,12 @@ async def v1_chat_completions(req: ChatCompletionsRequest, request: Request):
|
|||||||
out_meta=_meta,
|
out_meta=_meta,
|
||||||
):
|
):
|
||||||
if _stream_event_type(chunk) == "tool":
|
if _stream_event_type(chunk) == "tool":
|
||||||
tool = _stream_tool_event(chunk)
|
tool = _allowed_stream_tool_event(
|
||||||
if not tool:
|
chunk,
|
||||||
continue
|
tool_config=tool_config,
|
||||||
|
|
||||||
tool_name = str(tool.get("name") or "")
|
|
||||||
if not _tool_event_allowed(
|
|
||||||
tool_name,
|
|
||||||
tool_config,
|
|
||||||
forced_tool_name=forced_tool_name,
|
forced_tool_name=forced_tool_name,
|
||||||
):
|
)
|
||||||
|
if not tool:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if buffered_text_parts:
|
if buffered_text_parts:
|
||||||
@@ -1430,6 +1418,7 @@ async def v1_messages(req: AnthropicMessagesRequest, request: Request):
|
|||||||
completion_tokens_holder = {"n": 0}
|
completion_tokens_holder = {"n": 0}
|
||||||
stream_meta: dict = {}
|
stream_meta: dict = {}
|
||||||
max_tokens = req.max_tokens
|
max_tokens = req.max_tokens
|
||||||
|
forced_tool_name = _anthropic_forced_tool_name(req.tool_choice)
|
||||||
|
|
||||||
async def event_stream(_ticket=ticket, _inst=inst, _meta=stream_meta):
|
async def event_stream(_ticket=ticket, _inst=inst, _meta=stream_meta):
|
||||||
success = False
|
success = False
|
||||||
@@ -1477,18 +1466,14 @@ async def v1_messages(req: AnthropicMessagesRequest, request: Request):
|
|||||||
block_index += 1
|
block_index += 1
|
||||||
text_block_open = False
|
text_block_open = False
|
||||||
|
|
||||||
tool = _stream_tool_event(chunk)
|
tool = _allowed_stream_tool_event(
|
||||||
|
chunk,
|
||||||
|
tool_config=tool_config,
|
||||||
|
forced_tool_name=forced_tool_name,
|
||||||
|
)
|
||||||
if not tool:
|
if not tool:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
tool_name = str(tool.get("name") or "")
|
|
||||||
if not _tool_event_allowed(
|
|
||||||
tool_name,
|
|
||||||
tool_config,
|
|
||||||
forced_tool_name=_anthropic_forced_tool_name(req.tool_choice),
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
|
|
||||||
tool_id = str(tool.get("id") or f"toolu_stream_{block_index}")
|
tool_id = str(tool.get("id") or f"toolu_stream_{block_index}")
|
||||||
|
|
||||||
tool_use_block = _anthropic_tool_use_block(tool, forced_id=tool_id)
|
tool_use_block = _anthropic_tool_use_block(tool, forced_id=tool_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user