Skip to content

Commit 99557bb

Browse files
authored
Merge pull request #1348 from OpenInterpreter/development
Server tests
2 parents 18728f2 + d7d428c commit 99557bb

File tree

5 files changed

+798
-421
lines changed

5 files changed

+798
-421
lines changed

docs/server/usage.mdx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,79 @@ docker run -p 8000:8000 open-interpreter
232232

233233
This will expose the server on port 8000 of your host machine.
234234

235+
## Acknowledgment Feature
236+
237+
When the `INTERPRETER_REQUIRE_ACKNOWLEDGE` environment variable is set to `"True"`, the server requires clients to acknowledge each message received. This feature ensures reliable message delivery in environments where network stability might be a concern.
238+
239+
### How it works
240+
241+
1. When this feature is enabled, each message sent by the server will include an `id` field.
242+
2. The client must send an acknowledgment message back to the server for each received message.
243+
3. The server will wait for this acknowledgment before sending the next message.
244+
245+
### Client Implementation
246+
247+
To implement this on the client side:
248+
249+
1. Check if each received message contains an `id` field.
250+
2. If an `id` is present, send an acknowledgment message back to the server.
251+
252+
Here's an example of how to handle this in your WebSocket client:
253+
254+
```python
255+
import json
256+
import websockets
257+
258+
async def handle_messages(websocket):
259+
async for message in websocket:
260+
data = json.loads(message)
261+
262+
# Process the message as usual
263+
print(f"Received: {data}")
264+
265+
# Check if the message has an ID that needs to be acknowledged
266+
if "id" in data:
267+
ack_message = {
268+
"ack": data["id"]
269+
}
270+
await websocket.send(json.dumps(ack_message))
271+
print(f"Sent acknowledgment for message {data['id']}")
272+
273+
async def main():
274+
uri = "ws://localhost:8000"
275+
async with websockets.connect(uri) as websocket:
276+
await handle_messages(websocket)
277+
278+
# Run the async function
279+
import asyncio
280+
asyncio.run(main())
281+
```
282+
283+
### Server Behavior
284+
285+
- If the server doesn't receive an acknowledgment within a certain timeframe, it will attempt to resend the message.
286+
- The server will make multiple attempts to send a message before considering it failed.
287+
288+
### Enabling the Feature
289+
290+
To enable this feature, set the `INTERPRETER_REQUIRE_ACKNOWLEDGE` environment variable to `"True"` before starting the server:
291+
292+
```bash
293+
export INTERPRETER_REQUIRE_ACKNOWLEDGE="True"
294+
interpreter --server
295+
```
296+
297+
Or in Python:
298+
299+
```python
300+
import os
301+
os.environ["INTERPRETER_REQUIRE_ACKNOWLEDGE"] = "True"
302+
303+
from interpreter import AsyncInterpreter
304+
async_interpreter = AsyncInterpreter()
305+
async_interpreter.server.run()
306+
```
307+
235308
## Advanced Usage: Accessing the FastAPI App Directly
236309

237310
The FastAPI app is exposed at `async_interpreter.server.app`. This allows you to add custom routes or host the app using Uvicorn directly.

interpreter/core/async_core.py

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,6 @@ def accumulate(self, chunk):
198198
chunk_copy["content"] = ""
199199
self.messages.append(chunk_copy)
200200

201-
print("ADDED CHUNK:", chunk)
202-
print("MESSAGES IS NOW:", self.messages)
203-
# time.sleep(5)
204-
205201
elif type(chunk) == bytes:
206202
if self.messages[-1]["content"] == "": # We initialize as an empty string ^
207203
self.messages[-1]["content"] = b"" # But it actually should be bytes
@@ -282,7 +278,7 @@ async def home():
282278
} else {
283279
var startMessageBlock = {
284280
"role": "user",
285-
"type": "message",
281+
//"type": "message",
286282
"start": true
287283
};
288284
ws.send(JSON.stringify(startMessageBlock));
@@ -296,7 +292,7 @@ async def home():
296292
297293
var endMessageBlock = {
298294
"role": "user",
299-
"type": "message",
295+
//"type": "message",
300296
"end": true
301297
};
302298
ws.send(JSON.stringify(endMessageBlock));
@@ -649,21 +645,38 @@ async def chat_completion(request: ChatCompletionRequest):
649645

650646

651647
class Server:
652-
def __init__(self, async_interpreter, host=host, port=port):
648+
def __init__(self, async_interpreter, host="127.0.0.1", port=8000):
653649
self.app = FastAPI()
654650
router = create_router(async_interpreter)
655651
self.app.include_router(router)
656-
self.host = host
657-
self.port = port
658-
659-
def run(self, retries=5, *args, **kwargs):
660-
if "host" in kwargs:
661-
self.host = kwargs.pop("host")
662-
if "port" in kwargs:
663-
self.port = kwargs.pop("port")
664-
if "app" in kwargs:
665-
self.app = kwargs.pop("app")
666-
652+
self.config = uvicorn.Config(app=self.app, host=host, port=port)
653+
self.uvicorn_server = uvicorn.Server(self.config)
654+
655+
@property
656+
def host(self):
657+
return self.config.host
658+
659+
@host.setter
660+
def host(self, value):
661+
self.config.host = value
662+
self.uvicorn_server = uvicorn.Server(self.config)
663+
664+
@property
665+
def port(self):
666+
return self.config.port
667+
668+
@port.setter
669+
def port(self, value):
670+
self.config.port = value
671+
self.uvicorn_server = uvicorn.Server(self.config)
672+
673+
def run(self, host=None, port=None, retries=5):
674+
if host is not None:
675+
self.host = host
676+
if port is not None:
677+
self.port = port
678+
679+
# Print server information
667680
if self.host == "0.0.0.0":
668681
print(
669682
"Warning: Using host `0.0.0.0` will expose Open Interpreter over your local network."
@@ -672,12 +685,12 @@ def run(self, retries=5, *args, **kwargs):
672685
s.connect(("8.8.8.8", 80)) # Google's public DNS server
673686
print(f"Server will run at http://{s.getsockname()[0]}:{self.port}")
674687
s.close()
688+
else:
689+
print(f"Server will run at http://{self.host}:{self.port}")
675690

676691
for _ in range(retries):
677692
try:
678-
uvicorn.run(
679-
app=self.app, host=self.host, port=self.port, *args, **kwargs
680-
)
693+
self.uvicorn_server.run()
681694
break
682695
except KeyboardInterrupt:
683696
break

0 commit comments

Comments
 (0)