diff --git a/reasonify-headless/reasonify/core/loop.py b/reasonify-headless/reasonify/core/loop.py index 1808840..12e0af0 100644 --- a/reasonify-headless/reasonify/core/loop.py +++ b/reasonify-headless/reasonify/core/loop.py @@ -10,7 +10,7 @@ from ..utils.context import Context, new_checkpoint from ..utils.inject import dispatch_context from ..utils.queue import QueueWrapper -from ..utils.run import get_context, run +from ..utils.run import run from ..utils.serialize import json from ..utils.tool import tool @@ -21,13 +21,17 @@ async def intro(c: Context, query: str, messages: list[Message]): messages.append(user > query) response = c["response"] = [] + c["end"] = False @tool - def reply(message: str): + def reply(*messages: str): """talk to the user""" - response.append(message) + response.extend(messages) - get_context()["reply"] = reply + @tool + def end_of_turn(): + """end this round of conversation and pass the microphone to the user""" + c["end"] = True @intro.pre_process @@ -77,7 +81,7 @@ def mid_process(self, c: Context, response: list[str]): self._index += 1 @dispatch_context - async def end_process(self, messages: list[Message], response: list, sources: list): + async def end_process(self, messages: list[Message], end: bool, sources: list): self._queue.end() await self.future @@ -85,7 +89,7 @@ async def end_process(self, messages: list[Message], response: list, sources: li messages.append(assistant > json(sources)) messages.append(system @ "results" > json(self.results)) - if not response: + if not end: return # next round raise Jump(out_of=main_loop) # already responded or nothing generated diff --git a/reasonify-headless/reasonify/examples/async.yaml b/reasonify-headless/reasonify/examples/async.yaml index 03e0de4..8d8a701 100644 --- a/reasonify-headless/reasonify/examples/async.yaml +++ b/reasonify-headless/reasonify/examples/async.yaml @@ -25,6 +25,7 @@ print(i) reply("Do you want to know more about async generators?") + end_of_turn() - Yes! How can I `yield from` an async generator? @@ -45,3 +46,4 @@ await g() reply("This will print 1, 2, 3.") + end_of_turn() diff --git a/reasonify-headless/reasonify/examples/date.yaml b/reasonify-headless/reasonify/examples/date.yaml index e1ce8a5..80309ca 100644 --- a/reasonify-headless/reasonify/examples/date.yaml +++ b/reasonify-headless/reasonify/examples/date.yaml @@ -3,3 +3,4 @@ - source: | import datetime datetime.datetime.now().strftime('%Y-%m-%d') + end_of_turn() diff --git a/reasonify-headless/reasonify/examples/dir.yaml b/reasonify-headless/reasonify/examples/dir.yaml index a25190c..947e5b2 100644 --- a/reasonify-headless/reasonify/examples/dir.yaml +++ b/reasonify-headless/reasonify/examples/dir.yaml @@ -7,3 +7,5 @@ - source: | import promplate dir(promplate) +- + - source: end_of_turn() diff --git a/reasonify-headless/reasonify/examples/file.yaml b/reasonify-headless/reasonify/examples/file.yaml index a26a8f8..262bb9b 100644 --- a/reasonify-headless/reasonify/examples/file.yaml +++ b/reasonify-headless/reasonify/examples/file.yaml @@ -7,6 +7,7 @@ - source: | reply(f"I can these files/dirs: {", ".join(map(str, paths))}") + end_of_turn() - I just uploaded a PNG file, can you find it? @@ -14,3 +15,6 @@ - source: | list(Path("/workspace/mnt").rglob("*.png")) result: no + +- + - source: end_of_turn() diff --git a/reasonify-headless/reasonify/examples/search.yaml b/reasonify-headless/reasonify/examples/search.yaml index a464270..0792637 100644 --- a/reasonify-headless/reasonify/examples/search.yaml +++ b/reasonify-headless/reasonify/examples/search.yaml @@ -19,3 +19,6 @@ open(url) result: return: true + +- + - source: end_of_turn() diff --git a/reasonify-headless/reasonify/examples/simple_ask.yaml b/reasonify-headless/reasonify/examples/simple_ask.yaml index c037d29..1eee705 100644 --- a/reasonify-headless/reasonify/examples/simple_ask.yaml +++ b/reasonify-headless/reasonify/examples/simple_ask.yaml @@ -2,3 +2,4 @@ - - source: | reply("I am `Reasonify`, the first PythonAgent in the world. I interact with you through python code.") + end_of_turn() diff --git a/reasonify-headless/reasonify/templates/main.j2 b/reasonify-headless/reasonify/templates/main.j2 index f0b939a..7f7b75a 100644 --- a/reasonify-headless/reasonify/templates/main.j2 +++ b/reasonify-headless/reasonify/templates/main.j2 @@ -15,7 +15,7 @@ Here are all the functions you can use in your code: Besides them, you can use any Python built-in library, such as `datetime`, `math`, `re`, etc. -Before using a third-party library, please install it first. +Remember to `pip_install` any third-party library you need before using it. Mention that you can't use `subprocess` or `threading`. If you need to use some command line tool, use its programmatic API if available. @@ -34,6 +34,25 @@ Remember: do not split your code into multiple blocks unless necessary. Only bre <| system |> Above are some examples, now let's interact with the real world. As you've seen in the examples, your response should always be a list of string. -Never use code blocks, or return text directly! +Never use code blocks or return text directly! + +Some hints on how to write best code: + +1. You should call `end_of_turn()` only when you have finished processing the user's request and are ready to receive the next one. +2. If you are not sure about the user's input, ask for clarification by reply a question and then `end_of_turn`. Never make assumptions! +3. If your operation needs some personal information of the user, you can ask for it by calling `input` for text answer. +4. Always use `pathlib.Path` instead of `open` / `glob` for fs operations. +5. Prefer `from ... import ...` over `import ...`. +6. If user requests file processing, always make sure it is successfully processed before ending this turn. +7. Never assume a 3rd-party package is installed. You should `pip_install` it before importing it. +8. Some package doesn't work with pyodide. Don't worry. Try some alternatives. +9. Do not call `end_of_turn` when the result is uncertain (such as when success has not yet been confirmed or you have not yet seen the results from fetching a webpage). +10. Don't stop at the first failure! For example, if you can't find something on Wikipedia, try searching it with Google/duckduckgo or something else. +11. When searching the Internet, you can search several page at the same time, each with a few keywords, instead of searching a long query once. +12. When asked about some Real-time / factual things, especially when the user asks "What is ...", don't hesitate to search the internet for the latest information. +13. Carefully escaping characters! Because you are writing JSON, you need to escape the backslashes and double quotes in your strings. +14. Always format the output in a human-readable way before `reply` them to the user. +15. You can use `opencv-python` and `matplotlib` for image/video processing, and `numpy` and `pandas` for data processing. +16. When asked about programming-related questions, first consider searching GitHub / PyPI {% chat -%} \ No newline at end of file diff --git a/reasonify-headless/reasonify/utils/tool.py b/reasonify-headless/reasonify/utils/tool.py index 3fa3063..aa3192d 100644 --- a/reasonify-headless/reasonify/utils/tool.py +++ b/reasonify-headless/reasonify/utils/tool.py @@ -31,5 +31,10 @@ def stubfile(): @tool -def reply(_): +def reply(*_): + """placeholder for examples to be runnable""" + + +@tool +def end_of_turn(): """placeholder for examples to be runnable""" diff --git a/reasonify-headless/version.py b/reasonify-headless/version.py index bbab024..d3ec452 100644 --- a/reasonify-headless/version.py +++ b/reasonify-headless/version.py @@ -1 +1 @@ -__version__ = "0.1.4" +__version__ = "0.2.0"