|
11 | 11 | from claude_agent_sdk import query, ClaudeAgentOptions |
12 | 12 | from claude_agent_sdk.types import AssistantMessage, ResultMessage, TextBlock |
13 | 13 |
|
14 | | -ROLE_PREFIXES = { |
15 | | - "system": "System", |
16 | | - "user": "Human", |
17 | | - "assistant": "Assistant", |
18 | | -} |
| 14 | +DEFAULT_SYSTEM_PROMPT = "You are a helpful assistant." |
| 15 | + |
| 16 | +ROLE_PREFIXES = {"user": "Human", "assistant": "Assistant"} |
19 | 17 |
|
20 | 18 |
|
21 | 19 | class ClaudeAgentSDKProvider(CustomLLM): |
22 | | - """LiteLLM provider that routes requests through the Claude Agent SDK.""" |
| 20 | + """LiteLLM provider that wraps the Claude Agent SDK as a plain model call.""" |
23 | 21 |
|
24 | 22 | def __init__(self): |
25 | 23 | super().__init__() |
26 | 24 | print("ClaudeAgentSDKProvider initialized") |
27 | 25 |
|
28 | 26 | @staticmethod |
29 | | - def _format_prompt(messages: List[Dict]) -> str: |
30 | | - parts = [] |
| 27 | + def _split_messages(messages: List[Dict]) -> Tuple[str, str]: |
| 28 | + """Separate system prompt from conversation turns. |
| 29 | +
|
| 30 | + Returns (system_prompt, conversation_prompt). |
| 31 | + """ |
| 32 | + system_parts = [] |
| 33 | + turn_parts = [] |
31 | 34 | for msg in messages: |
32 | | - prefix = ROLE_PREFIXES.get(msg.get("role", "user")) |
33 | | - if prefix: |
34 | | - parts.append(f"{prefix}: {msg.get('content', '')}") |
35 | | - return "\n\n".join(parts) |
| 35 | + role = msg.get("role", "user") |
| 36 | + content = msg.get("content", "") |
| 37 | + if role == "system": |
| 38 | + system_parts.append(content) |
| 39 | + else: |
| 40 | + prefix = ROLE_PREFIXES.get(role) |
| 41 | + if prefix: |
| 42 | + turn_parts.append(f"{prefix}: {content}") |
| 43 | + |
| 44 | + system_prompt = "\n\n".join(system_parts) if system_parts else DEFAULT_SYSTEM_PROMPT |
| 45 | + conversation = "\n\n".join(turn_parts) |
| 46 | + return system_prompt, conversation |
36 | 47 |
|
37 | 48 | @staticmethod |
38 | 49 | def _extract_model(model: str) -> str: |
@@ -90,8 +101,13 @@ def completion(self, model: str, messages: List[Dict], **kwargs) -> ModelRespons |
90 | 101 |
|
91 | 102 | async def acompletion(self, model: str, messages: List[Dict], **kwargs) -> ModelResponse: |
92 | 103 | """Async completion using Claude Agent SDK.""" |
93 | | - prompt = self._format_prompt(messages) |
94 | | - options = ClaudeAgentOptions(model=self._extract_model(model)) |
| 104 | + system_prompt, prompt = self._split_messages(messages) |
| 105 | + options = ClaudeAgentOptions( |
| 106 | + model=self._extract_model(model), |
| 107 | + system_prompt=system_prompt, |
| 108 | + allowed_tools=[], |
| 109 | + max_turns=1, |
| 110 | + ) |
95 | 111 |
|
96 | 112 | content = "" |
97 | 113 | prompt_tokens = 0 |
@@ -120,8 +136,13 @@ def streaming(self, model: str, messages: List[Dict], **kwargs) -> Iterator[Gene |
120 | 136 |
|
121 | 137 | async def astreaming(self, model: str, messages: List[Dict], **kwargs) -> AsyncIterator[GenericStreamingChunk]: |
122 | 138 | """Async streaming using Claude Agent SDK.""" |
123 | | - prompt = self._format_prompt(messages) |
124 | | - options = ClaudeAgentOptions(model=self._extract_model(model)) |
| 139 | + system_prompt, prompt = self._split_messages(messages) |
| 140 | + options = ClaudeAgentOptions( |
| 141 | + model=self._extract_model(model), |
| 142 | + system_prompt=system_prompt, |
| 143 | + allowed_tools=[], |
| 144 | + max_turns=1, |
| 145 | + ) |
125 | 146 |
|
126 | 147 | total_chars = 0 |
127 | 148 | prompt_tokens = 0 |
|
0 commit comments