summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--agent.py45
-rw-r--r--agent.toml11
-rw-r--r--client.py44
-rw-r--r--context.py24
-rw-r--r--identity.py34
-rw-r--r--llm.py42
-rw-r--r--user.toml3
7 files changed, 175 insertions, 28 deletions
diff --git a/agent.py b/agent.py
new file mode 100644
index 0000000..51661fd
--- /dev/null
+++ b/agent.py
@@ -0,0 +1,45 @@
+from collections.abc import Iterator
+
+from context import ContextBuilder
+from identity import AgentIdentity, UserProfile
+from llm import LLM
+
+class Agent:
+ def __init__(
+ self,
+ llm: LLM,
+ agent_identity: AgentIdentity,
+ user_profile: UserProfile
+ ) -> None:
+ self.llm = llm
+
+ self.context = ContextBuilder(
+ agent_identity,
+ user_profile,
+ )
+
+ self.messages: list[dict[str, str]] = [
+ {
+ "role": "system",
+ "content": self.context.build_system_prompt(),
+ }
+ ]
+
+ def chat(self, user_input: str) -> Iterator[str]:
+ self.messages.append({
+ "role": "user",
+ "content": user_input,
+ })
+
+ answer_parts: list[str] = []
+
+ for chunk in self.llm.chat(self.messages):
+ yield chunk
+ answer_parts.append(chunk)
+
+ answer = "".join(answer_parts)
+
+ self.messages.append({
+ "role": "assistant",
+ "content": answer,
+ })
diff --git a/agent.toml b/agent.toml
new file mode 100644
index 0000000..87189cd
--- /dev/null
+++ b/agent.toml
@@ -0,0 +1,11 @@
+name = "Personal Agent"
+
+[personality]
+style = "casual, helpful, concise, conversational"
+
+[values]
+honesty = true
+directness = true
+
+[quirks]
+favorite_color = "purple and orange"
diff --git a/client.py b/client.py
index 0974650..c983db1 100644
--- a/client.py
+++ b/client.py
@@ -1,8 +1,17 @@
-import requests
+from agent import Agent
+from identity import load_agent_identity, load_user_profile
+from llm import LLM
-URL = "http://localhost:8080/v1/chat/completions"
+llm = LLM("http://localhost:8080/v1/chat/completions",)
-messages = []
+agent_identity = load_agent_identity("agent.toml")
+user_profile = load_user_profile("user.toml")
+
+agent = Agent(
+ llm,
+ agent_identity,
+ user_profile,
+)
while True:
user_input = input("You: ")
@@ -10,30 +19,9 @@ while True:
if user_input.lower() in {"exit", "quit"}:
break
- messages.append({
- "role": "user",
- "content": user_input
- })
-
- response = requests.post(
- URL,
- json={
- "messages": messages,
- "max_tokens": 256,
- "temperature": 0.7,
- }
- )
-
- if not response.ok:
- print("Server error: ", response.text)
- continue
-
- data = response.json()
- answer = data["choices"][0]["message"]["content"]
+ print("Agent: ", end="", flush=True)
- print(f"Agent: {answer}")
+ for chunk in agent.chat(user_input):
+ print(chunk, end="", flush=True)
- messages.append({
- "role": "assistant",
- "content": answer
- })
+ print()
diff --git a/context.py b/context.py
new file mode 100644
index 0000000..5006e3a
--- /dev/null
+++ b/context.py
@@ -0,0 +1,24 @@
+from identity import AgentIdentity, UserProfile
+
+class ContextBuilder:
+ def __init__(
+ self,
+ agent_identity: AgentIdentity,
+ user_profile: UserProfile,
+ ) -> None:
+ self.agent_identity = agent_identity
+ self.user_profile = user_profile
+
+ def build_system_prompt(self) -> str:
+ agent = self.agent_identity
+ user = self.user_profile
+
+ return (
+ f"You are {agent.name}, a personal AI assistant.\n"
+ f"Personality: {agent.personality['style']}.\n"
+ f"Honesty: {agent.values['honesty']}.\n"
+ f"Directness: {agent.values['directness']}.\n"
+ f"Favorite color: {agent.quirks['favorite_color']}.\n"
+ f"\n"
+ f"The user's name is {user.name}"
+ )
diff --git a/identity.py b/identity.py
new file mode 100644
index 0000000..9b4faa0
--- /dev/null
+++ b/identity.py
@@ -0,0 +1,34 @@
+from dataclasses import dataclass
+import tomllib
+
+@dataclass
+class AgentIdentity:
+ name: str
+ personality: dict[str, str]
+ values: dict[str, bool]
+ quirks: dict[str, str]
+
+@dataclass
+class UserProfile:
+ name: str
+ preferences: dict[str, str]
+
+def load_agent_identity(path: str) -> AgentIdentity:
+ with open(path, "rb") as file:
+ data = tomllib.load(file)
+
+ return AgentIdentity(
+ name=data["name"],
+ personality=data["personality"],
+ values=data["values"],
+ quirks=data["quirks"],
+ )
+
+def load_user_profile(path: str) -> UserProfile:
+ with open(path, "rb") as file:
+ data = tomllib.load(file)
+
+ return UserProfile(
+ name=data["name"],
+ preferences=data["preferences"],
+ )
diff --git a/llm.py b/llm.py
new file mode 100644
index 0000000..524f173
--- /dev/null
+++ b/llm.py
@@ -0,0 +1,42 @@
+import json
+from collections.abc import Iterator
+
+import requests
+
+class LLM:
+ def __init__(self, url: str) -> None:
+ self.url = url
+
+ def chat(self, messages: list[dict[str, str]], max_tokens: int = 256) -> Iterator[str]:
+ response = requests.post(
+ self.url,
+ json = {
+ "messages": messages,
+ "max_tokens": max_tokens,
+ "temperature": 0.7,
+ "stream": True,
+ },
+ stream=True,
+ )
+ response.raise_for_status()
+
+ for line in response.iter_lines():
+ if not line:
+ continue
+
+ if not line.startswith(b"data: "):
+ continue
+
+ data = line[6:]
+
+ if data == b"[DONE]":
+ break
+
+ chunk = json.loads(data)
+
+ delta = chunk["choices"][0]["delta"]
+ content = delta.get("content")
+
+ if content:
+ yield content
+
diff --git a/user.toml b/user.toml
new file mode 100644
index 0000000..fae9d85
--- /dev/null
+++ b/user.toml
@@ -0,0 +1,3 @@
+name = "User"
+
+[preferences]