Skip to content

Commit 270d351

Browse files
committed
chore: add sandbox for oai responses api
1 parent 376920c commit 270d351

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

sandbox/server-oai-web-search.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
"""
2+
Example server for the ReDel web interface.
3+
4+
Environment Variables:
5+
- OPENAI_API_KEY
6+
- ANTHROPIC_API_KEY (optional)
7+
8+
Configuration:
9+
- root engine: gpt-4o
10+
- delegate engine: gpt-4o
11+
- tools:
12+
- Browsing (always included in delegates)
13+
- long engine: claude-3-opus (for summarizing long webpages, if ANTHROPIC_API_KEY is set)
14+
"""
15+
16+
import logging
17+
18+
from kani import AIFunction, ChatMessage
19+
from kani.engines import Completion
20+
from kani.engines.openai import OpenAIEngine
21+
from kani.engines.openai.translation import translate_functions, translate_messages
22+
from openai.types.responses import ResponseOutputItem, WebSearchToolParam
23+
24+
from redel import AUTOGENERATE_TITLE, ReDel
25+
from redel.delegation import DelegateOne
26+
from redel.server import VizServer
27+
28+
29+
# openai responses engine, basic impl
30+
class OpenAIResponsesEngine(OpenAIEngine):
31+
def __init__(self, *args, web_search_config: WebSearchToolParam = None, **kwargs):
32+
super().__init__(*args, **kwargs)
33+
self.web_search_config = web_search_config
34+
35+
async def predict(
36+
self, messages: list[ChatMessage], functions: list[AIFunction] | None = None, **hyperparams
37+
) -> Completion:
38+
if functions:
39+
tool_specs = translate_functions(functions)
40+
else:
41+
tool_specs = []
42+
if self.web_search_config:
43+
tool_specs.append(self.web_search_config)
44+
45+
if not tool_specs:
46+
tool_specs = None
47+
# translate to openai spec - group any tool messages together and ensure all free ToolCall IDs are bound
48+
translated_messages = translate_messages(messages)
49+
# make API call
50+
completion = await self.client.responses.create(
51+
model=self.model, input=translated_messages, tools=tool_specs, **self.hyperparams, **hyperparams
52+
)
53+
# translate into Kani spec and return
54+
cmpl = Completion(
55+
message=openai_response_to_kani_cm(completion.output),
56+
prompt_tokens=completion.usage.input_tokens,
57+
completion_tokens=completion.usage.output_tokens,
58+
)
59+
self.set_cached_message_len(cmpl.message, cmpl.completion_tokens)
60+
return cmpl
61+
62+
63+
def openai_response_to_kani_cm(output_items: list[ResponseOutputItem]) -> ChatMessage:
64+
"""Translate an OpenAI ChatCompletionMessage into a kani ChatMessage."""
65+
texts = []
66+
for output in output_items:
67+
if output.type == "message":
68+
for content in output.content:
69+
if content.type == "output_text":
70+
text = content.text
71+
for annotation in sorted(content.annotations, key=lambda a: a.end_index, reverse=True):
72+
text = (
73+
text[: annotation.end_index + 1]
74+
+ f" ({annotation.url}) "
75+
+ text[annotation.end_index + 1 :]
76+
)
77+
texts.append(text)
78+
79+
content = "".join(texts)
80+
return ChatMessage.assistant(content)
81+
82+
83+
# Define the engines
84+
engine = OpenAIResponsesEngine(web_search_config={"type": "web_search_preview"}, temperature=0.8, top_p=0.95)
85+
86+
# Define the configuration for each interactive session
87+
ai = ReDel(
88+
root_engine=engine,
89+
delegate_engine=engine,
90+
delegation_scheme=DelegateOne,
91+
title=AUTOGENERATE_TITLE,
92+
tool_configs={},
93+
)
94+
95+
# configure and start the server
96+
server = VizServer(ai)
97+
98+
if __name__ == "__main__":
99+
logging.basicConfig(level=logging.INFO)
100+
server.serve()

0 commit comments

Comments
 (0)