Single prompt tom (#89)

* Add TOM method switching

* Add system prompt and note on format

* Add persistence tweaks

* Specify format for each section of user representation

* Parse XML tags before saving representation metamessage

* Clean up

* Use Claude 3.5 Haiku and refine prompt

* Simplify message processing

* chore: update token limit on dialectic and model for deriver

* chore: Update to Contributing Docs and .env template

* Contributing Docs

* chore: Add Deriver Template Variables

* chore: Remove healthcheck endpoint

* chore: Changelog updates

---------

Co-authored-by: Daniel Balcells <dbalcells@gmail.com>
This commit is contained in:
Vineeth Voruganti 2025-02-24 19:12:31 -05:00 committed by GitHub
parent c2a1bb1796
commit e68aceaab2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 398 additions and 4625 deletions

View File

@ -2,20 +2,22 @@ CONNECTION_URI=postgresql+psycopg://testuser:testpwd@localhost:5432/honcho # sam
# CONNECTION_URI=postgresql+psycopg://testuser:testpwd@database:5432/honcho # sample for docker-compose database
OPENAI_API_KEY=
OPENAI_API_KEY= # Used for vector embeddings
ANTHROPIC_API_KEY= # Used for the deriver and dialectic API
# Logging
SENTRY_ENABLED=false # Set to true to enable Sentry logging and tracing
LOGFIRE_TOKEN= # optional logfire config
# Auth
USE_AUTH_SERVICE=false
AUTH_SERVICE_URL=http://localhost:8001
SECRET_KEY=
# Sentry
SENTRY_DSN=
# Deriver
DERIVER_WORKERS=1
TOM_METHOD="single_prompt"
USER_REPRESENTATION_METHOD="single_prompt"

2
.vscode/tasks.json vendored
View File

@ -4,7 +4,7 @@
{
"label": "start",
"type": "shell",
"command": "poetry install --no-root && poetry run uvicorn src.main:app --reload",
"command": "uv sync && uv run fastapi dev src/main.py",
"group": "none",
"presentation": {
"reveal": "always",

View File

@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.0.16]
## Changed
- Deriver to use a new cognitive architecture that only updates on user messages
and updates user representation to apply more confidence scores to its known
facts
- Dialectic API token cutoff from 150 tokens to 300
## Fixed
- Self-hosting documentation and README to mention `uv` instead of `poetry`
## [0.0.15]
### Added

View File

@ -3,7 +3,7 @@
This project is completely open source and welcomes any and all open source
contributions. The workflow for contributing is to make a fork of the
repository. You can claim an issue in the issues tab or start a new thread to
indicate a feature or bug fix you are working on.
indicate a feature or bug fix you are working on.
Once you have finished your contribution make a PR , and it will be reviewed by
a project manager. Feel free to join us in our
@ -22,15 +22,15 @@ Server.
### Prerequisites and Dependencies
Honcho is developed using [python](https://www.python.org/) and [poetry](https://python-poetry.org/).
Honcho is developed using [python](https://www.python.org/) and [uv](https://docs.astral.sh/uv/).
The minimum python version is `3.9`
The minimum poetry version is `1.4.1`
The minimum poetry version is `0.4.9`
### Setup
Once the dependencies are installed on the system run the following steps to get
the local project setup.
the local project setup.
1. Clone the repository
@ -41,28 +41,34 @@ git clone https://github.com/plastic-labs/honcho.git
2. Enter the repository and install the python dependencies
We recommend using a virtual environment to isolate the dependencies for Honcho
from other projects on the same system. With `poetry` a virtual environment can
be generated using the `poetry shell` command. Once the virtual environment is
created and activated install the dependencies with `poetry install`
from other projects on the same system. `uv` will create a virtual environment
when you sync your dependencies in the project.
Putting this together:
```bash
cd honcho
poetry shell
poetry install
uv sync
```
This will create a virtual environment and install the dependencies for Honcho.
The default virtual environment will be located at `honcho/.venv`. Activate the
virtual environment via:
```bash
source honcho/.venv/bin/activate
```
3. Set up a database
Honcho utilized [Postgres](https://www.postgresql.org/) for its database with
Honcho utilized [Postgres](https://www.postgresql.org/) for its database with
pgvector. An easy way to get started with a postgresdb is to create a project
with [Supabase](https://supabase.com/)
A `docker-compose` template is also available with a database configuration
available.
available.
4. Edit the environment variables.
4. Edit the environment variables.
Honcho uses a `.env` file for managing runtime environment variables. A
`.env.template` file is included for convenience. Several of the configurations
@ -73,18 +79,19 @@ Below are the required configurations
```env
CONNECTION_URI= # Connection uri for a postgres database
OPENAI_API_KEY= # API Key for OpenAI used for insights
OPENAI_API_KEY= # API Key for OpenAI used for embedding documents
ANTHROPIC_API_KEY= # API Key for Anthropic used for the deriver and dialectic API
```
> Note that the `CONNECTION_URI` must have the prefix `postgresql+psycopg` to
> function properly. This is a requirement brought by `sqlalchemy`
The template has the additional functionality disabled by default. To ensure
that they are disabled you can verify the following environment variables are
set to false.
set to false.
```env
USE_AUTH_SERVICE=false
OPENTELEMETRY_ENABLED=false
SENTRY_ENABLED=false
```
@ -95,8 +102,9 @@ and the environment variables setup you can now launch a local instance of
Honcho. The following command will launch the storage API for Honcho
```bash
python -m uvicorn src.main:app --reload --port 8000
fastapi dev src/main.py
```
This is a development server that will reload whenever code is changed. When
first launching the API with a connection the database it will provision the
necessary tables for Honcho to operate.
@ -105,10 +113,10 @@ necessary tables for Honcho to operate.
As mentioned earlier a `docker-compose` template is included for running Honcho.
As an alternative to running Honcho locally it can also be run with the compose
template.
template.
The docker-compose template is set to use an environment file called `.env`.
You can also copy the `.env.template` and fill with the appropriate values.
You can also copy the `.env.template` and fill with the appropriate values.
Copy the template and update the appropriate environment variables before
launching the service.
@ -116,7 +124,7 @@ launching the service.
```bash
cd honcho/api
cp .env.template .env
# update the file with openai key and other wanted environment variables
# update the file with openai key and other wanted environment variables
cp docker-compose.yml.example docker-compose.yml
docker compose up
```
@ -140,4 +148,3 @@ flyctl launch --no-deploy # Follow the prompts and edit as you see fit
cat .env | flyctl secrets import # Load in your secrets
flyctl deploy # Deploy with appropriate environment variables
```

View File

@ -1,21 +1,20 @@
# honcho-docs
# Honcho Docs
## Setting Up `honcho-docs` Locally
These docs are built using Next.js via mintlify.
## Setting Up Honcho's Docs Locally
1. Clone the repository:
```
git clone git@github.com:plastic-labs/honcho-docs.git
git clone git@github.com:plastic-labs/honcho.git
```
2. Navigate into the `honcho-docs` folder:
2. Navigate into the `docs` folder:
```
cd honcho-docs/
cd honcho/docs/
```
The docs folder contains the markdown files that make up the documentation. The majority of the files are in the pages directory. Some notable files in this folder include:
`index.mdx`: The main documentation file.
`_app.js`: This file is used to customize the default Next.js application shell.
`theme.config.jsx`: This file is for configuring the Nextra theme for the documentation.
3. Verify that you have Node.js and npm installed in your system. You can check by running:
```
@ -30,7 +29,7 @@ npm --version
npm install -g pnpm
```
6. Install the project dependencies using yarn:
6. Install the project dependencies using pnpm:
```
pnpm i
```

View File

@ -10,10 +10,10 @@ icon: 'cloud'
### Prerequisites and Dependencies
Honcho is developed using [python](https://www.python.org/) and [poetry](https://python-poetry.org/).
Honcho is developed using [python](https://www.python.org/) and [uv](https://docs.astral.sh/uv/).
The minimum python version is `3.9`
The minimum poetry version is `1.4.1`
The minimum poetry version is `0.4.9`
### Setup
@ -29,16 +29,22 @@ git clone https://github.com/plastic-labs/honcho.git
2. Enter the repository and install the python dependencies
We recommend using a virtual environment to isolate the dependencies for Honcho
from other projects on the same system. With `poetry` a virtual environment can
be generated using the `poetry shell` command. Once the virtual environment is
created and activated install the dependencies with `poetry install`
from other projects on the same system. `uv` will create a virtual environment
when you sync your dependencies in the project.
Putting this together:
```bash
cd honcho
poetry shell
poetry install
uv sync
```
This will create a virtual environment and install the dependencies for Honcho.
The default virtual environment will be located at `honcho/.venv`. Activate the
virtual environment via:
```bash
source honcho/.venv/bin/activate
```
3. Set up a database
@ -61,7 +67,8 @@ Below are the required configurations
```env
CONNECTION_URI= # Connection uri for a postgres database
OPENAI_API_KEY= # API Key for OpenAI used for insights
OPENAI_API_KEY= # API Key for OpenAI used for embedding documents
ANTHROPIC_API_KEY= # API Key for Anthropic used for the deriver and dialectic API
```
> Note that the `CONNECTION_URI` must have the prefix `postgresql+psycopg` to
> function properly. This is a requirement brought by `sqlalchemy`
@ -72,7 +79,6 @@ set to false.
```env
USE_AUTH_SERVICE=false
OPENTELEMETRY_ENABLED=false
SENTRY_ENABLED=false
```
@ -83,7 +89,7 @@ and the environment variables setup you can now launch a local instance of
Honcho. The following command will launch the storage API for Honcho
```bash
python -m uvicorn src.main:app --reload --port 8000
fastapi dev src/main.py
```
This is a development server that will reload whenever code is changed. When
first launching the API with a connection the database it will provision the

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,19 @@
---
title: 🫡 Welcome to Honcho
sidebarTitle: 'Overview'
description: 'Honcho is an open source platform for building personalized AI experiences.'
description: 'The identity layer for the agentic world'
icon: 'face-saluting'
---
<Snippet file="overview-shields.mdx" />
Honcho provides an simple API store data for AI applications in a user-centric
fashion and derive insights about users that improve the ability of
applications to quickly deliver value to the User.
Honcho is an infrastructure layer that empowers AI agents with social cognition and deeper understanding of their users.
Now you can focus on improving your service instead of spending
countless hours figuring out how to get it to scale and be personalized.
The API is built on two core concepts: *Storage* and *Insights*. The Storage API provides a flexible memory framework that can store both chat conversations and vector embeddings of user interactions. This forms the foundation for building more socially aware agents.
The Insights layer analyzes these stored interactions to build rich user profiles, which can be queried through a natural language dialectic endpoint. This allows agents to develop a nuanced understanding of users' preferences, behaviors, and needs over time.
By handling the complex infrastructure needed for memory and user understanding, Honcho lets you focus on building amazing AI experiences. No more worrying about how to scale personalization - we've got you covered.
To learn more about the project, check out our [blog
post](https://blog.plasticlabs.ai/blog/A-Simple-Honcho-Primer).

View File

@ -73,7 +73,7 @@ class Dialectic:
system=self.system_prompt,
messages=messages,
model=self.model,
max_tokens=150,
max_tokens=300,
)
return response.content

View File

@ -9,13 +9,16 @@ from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from .. import models
from .voe import tom_inference, user_representation
from .tom import get_tom_inference, get_user_representation
# Turn off SQLAlchemy Echo logging
logging.getLogger("sqlalchemy.engine.Engine").disabled = True
console = Console(markup=False)
TOM_METHOD = os.getenv("TOM_METHOD", "single_prompt")
USER_REPRESENTATION_METHOD = os.getenv("USER_REPRESENTATION_METHOD", "single_prompt")
# FIXME see if this is SAFE
async def add_metamessage(db, message_id, metamessage_type, content):
@ -34,6 +37,29 @@ def parse_xml_content(text, tag):
return match.group(1).strip() if match else ""
async def get_chat_history(db, session_id, message_id) -> str:
subquery = (
select(models.Message.id)
.where(models.Message.public_id == message_id)
.scalar_subquery()
)
messages_stmt = (
select(models.Message)
.where(models.Message.session_id == session_id)
.order_by(models.Message.id.desc())
.where(models.Message.id < subquery)
.limit(10)
)
result = await db.execute(messages_stmt)
messages = result.scalars().all()[::-1]
chat_history_str = "\n".join(
[f"human: {m.content}" if m.is_user else f"ai: {m.content}" for m in messages]
)
return chat_history_str
async def process_item(db: AsyncSession, payload: dict):
processing_args = [
payload["content"],
@ -65,54 +91,6 @@ async def process_ai_message(
"""
console.print(f"Processing AI message: {content}", style="bright_magenta")
subquery = (
select(models.Message.id)
.where(models.Message.public_id == message_id)
.scalar_subquery()
)
messages_stmt = (
select(models.Message)
.where(models.Message.session_id == session_id)
.order_by(models.Message.id.desc())
.where(models.Message.id < subquery)
.limit(10)
)
result = await db.execute(messages_stmt)
messages = result.scalars().all()[::-1]
chat_history_str = "\n".join(
[f"human: {m.content}" if m.is_user else f"ai: {m.content}" for m in messages]
)
# append current message to chat history
chat_history_str = f"{chat_history_str}\nai: {content}"
langfuse_context.update_current_trace(
session_id=session_id,
user_id=user_id,
release=os.getenv("SENTRY_RELEASE"),
metadata={"environment": os.getenv("SENTRY_ENVIRONMENT")},
)
tom_inference_response = await tom_inference(
chat_history_str, session_id=session_id
)
prediction = parse_xml_content(tom_inference_response, "prediction")
await add_metamessage(
db,
message_id,
"tom_inference",
prediction,
)
await db.commit()
console.print("Tom Inference:", style="blue")
content_lines = str(prediction)
console.print(content_lines, style="blue")
@sentry_sdk.trace
@observe()
@ -125,112 +103,88 @@ async def process_user_message(
db: AsyncSession,
):
"""
Process a user message. If there are revised user predictions to run VoE against, run it. Otherwise pass.
Process a user message by:
- Getting TOM inference
- Getting user representation
"""
console.print(f"Processing User Message: {content}", style="orange1")
subquery = (
select(models.Message.id)
.where(models.Message.public_id == message_id)
.scalar_subquery()
)
messages_stmt = (
select(models.Message)
.where(models.Message.session_id == session_id)
.where(models.Message.is_user == False)
.order_by(models.Message.id.desc())
.where(models.Message.id < subquery)
# Get chat history and append current message
chat_history_str = await get_chat_history(db, session_id, message_id)
chat_history_str = f"{chat_history_str}\nhuman: {content}"
# Get TOM inference, parse and save it
tom_inference_response = await get_tom_inference(
chat_history_str, session_id, method=TOM_METHOD
)
tom_inference = parse_xml_content(tom_inference_response, "prediction")
await add_metamessage(
db,
message_id,
"tom_inference",
tom_inference,
)
await db.commit()
# Fetch the latest user representation
user_representation_stmt = (
select(models.Metamessage)
.join(
models.Message,
models.Message.public_id == models.Metamessage.message_id,
)
.join(
models.Session,
models.Message.session_id == models.Session.public_id,
)
.join(models.User, models.User.public_id == models.Session.user_id)
.join(models.App, models.App.public_id == models.User.app_id)
.where(models.App.public_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Metamessage.metamessage_type == "user_representation")
.order_by(models.Metamessage.id.desc()) # get the most recent
.limit(1)
)
response = await db.execute(messages_stmt)
ai_message = response.scalar_one_or_none()
response = await db.execute(user_representation_stmt)
existing_representation = response.scalar_one_or_none()
if ai_message and ai_message.content:
console.print(f"AI Message: {ai_message.content}", style="bright_magenta")
existing_representation_content = (
existing_representation.content if existing_representation else "None"
)
print(f"Existing Representation: {existing_representation_content}")
# Fetch the tom_inference metamessage
tom_inference_stmt = (
select(models.Metamessage)
.where(models.Metamessage.message_id == ai_message.public_id)
.where(models.Metamessage.metamessage_type == "tom_inference")
.order_by(
models.Metamessage.id.asc()
) # Get the earliest tom inference on this message
.limit(1)
)
response = await db.execute(tom_inference_stmt)
tom_inference_metamessage = response.scalar_one_or_none()
langfuse_context.update_current_trace(
session_id=session_id,
user_id=user_id,
release=os.getenv("SENTRY_RELEASE"),
metadata={"environment": os.getenv("SENTRY_ENVIRONMENT")},
)
if tom_inference_metamessage and tom_inference_metamessage.content:
console.print(
f"Tom Inference: {tom_inference_metamessage.content}", style="blue"
)
# Call user_representation
user_representation_response = await get_user_representation(
chat_history=chat_history_str,
session_id=session_id,
user_representation=existing_representation_content,
tom_inference=tom_inference,
method=USER_REPRESENTATION_METHOD,
)
# Fetch the latest user representation
user_representation_stmt = (
select(models.Metamessage)
.join(
models.Message,
models.Message.public_id == models.Metamessage.message_id,
)
.join(
models.Session,
models.Message.session_id == models.Session.public_id,
)
.join(models.User, models.User.public_id == models.Session.user_id)
.join(models.App, models.App.public_id == models.User.app_id)
.where(models.App.public_id == app_id)
.where(models.User.public_id == user_id)
.where(models.Metamessage.metamessage_type == "user_representation")
.order_by(models.Metamessage.id.desc()) # get the most recent
.limit(1)
)
# parse the user_representation response
user_representation_response = parse_xml_content(
user_representation_response, "representation"
)
response = await db.execute(user_representation_stmt)
existing_representation = response.scalar_one_or_none()
# Store the user_representation response as a metamessage
await add_metamessage(
db,
message_id,
"user_representation",
user_representation_response,
)
await db.commit()
existing_representation_content = (
existing_representation.content if existing_representation else "None"
)
langfuse_context.update_current_trace(
session_id=session_id,
user_id=user_id,
release=os.getenv("SENTRY_RELEASE"),
metadata={"environment": os.getenv("SENTRY_ENVIRONMENT")},
)
# Call user_representation
user_representation_response = await user_representation(
chat_history=f"{ai_message.content}\nhuman: {content}",
session_id=session_id,
user_representation=existing_representation_content,
tom_inference=tom_inference_metamessage.content,
)
# Store the user_representation response as a metamessage
await add_metamessage(
db,
message_id,
"user_representation",
user_representation_response,
)
# parse the user_representation response
user_representation_response = parse_xml_content(
user_representation_response, "representation"
)
console.print(
f"User Representation:\n{user_representation_response}",
style="bright_green",
)
else:
raise Exception(
f"\033[91mTom Inference NOT READY YET on message {message_id}"
)
else:
console.print("No AI message before this user message", style="red")
return
console.print(
f"User Representation:\n{user_representation_response}",
style="bright_green",
)

View File

@ -0,0 +1,30 @@
from .conversational import get_tom_inference_conversational, get_user_representation_conversational
from .single_prompt import get_tom_inference_single_prompt, get_user_representation_single_prompt
async def get_tom_inference(chat_history: str,
session_id: str,
user_representation: str = "None",
method: str = "conversational",
**kwargs
) -> str:
if method == "conversational":
return await get_tom_inference_conversational(chat_history, session_id, user_representation, **kwargs)
elif method == "single_prompt":
return await get_tom_inference_single_prompt(chat_history, session_id, user_representation, **kwargs)
else:
raise ValueError(f"Invalid method: {method}")
async def get_user_representation(chat_history: str,
session_id: str,
user_representation: str = "None",
tom_inference: str = "None",
method: str = "conversational",
**kwargs
) -> str:
if method == "conversational":
return await get_user_representation_conversational(chat_history, session_id, user_representation, tom_inference, **kwargs)
elif method == "single_prompt":
return await get_user_representation_single_prompt(chat_history, session_id, user_representation, tom_inference, **kwargs)
else:
raise ValueError(f"Invalid method: {method}")

View File

@ -16,7 +16,7 @@ anthropic = Anthropic(
@ai_track("Tom Inference")
@observe(as_type="generation")
async def tom_inference(
async def get_tom_inference_conversational(
chat_history: str, session_id: str, user_representation: str = "None"
) -> str:
with sentry_sdk.start_transaction(op="tom-inference", name="ToM Inference"):
@ -82,7 +82,7 @@ async def tom_inference(
@ai_track("User Representation")
@observe(as_type="generation")
async def user_representation(
async def get_user_representation_conversational(
chat_history: str,
session_id: str,
user_representation: str = "None",

View File

@ -0,0 +1,187 @@
import os
import sentry_sdk
from anthropic import Anthropic
from langfuse.decorators import langfuse_context, observe
from sentry_sdk.ai.monitoring import ai_track
# Place the code below at the beginning of your application to initialize the tracer
# Initialize the Anthropic client
anthropic = Anthropic(
api_key=os.getenv("ANTHROPIC_API_KEY"),
max_retries=5,
)
ANTHROPIC_MODEL = "claude-3-5-haiku-20241022"
@ai_track("Tom Inference")
@observe(as_type="generation")
async def get_tom_inference_single_prompt(
chat_history: str, session_id: str, user_representation: str = "None", **kwargs
) -> str:
with sentry_sdk.start_transaction(op="tom-inference", name="ToM Inference"):
system_prompt = """You are a system for analyzing conversations to make evidence-based inferences about user mental states.
REQUIREMENTS:
1. Only make inferences that are directly supported by conversation evidence
2. For each inference, cite the specific message that supports it
3. Use uncertainty qualifiers (may, might, possibly) for speculative inferences
4. Do not make assumptions about demographics unless explicitly stated
5. Focus on current mental state and immediate context
6. Consider your own knowledge gaps and violations of expectations (what would surprise you)
7. Always wrap your prediction in <prediction> tags.
OUTPUT FORMAT:
<prediction>
CURRENT STATE:
- Immediate Context: User's current situation
- Active Goals: What user is trying to achieve
- Present Mood: Observable emotional state
SUPPORTED OBSERVATIONS:
- List only behaviors/preferences with direct evidence
- Format: "OBSERVATION: [detail] (SOURCE: [exact message])"
TENTATIVE INFERENCES:
- List possible but uncertain interpretations
- Format: "POSSIBLE: [interpretation] (BASIS: [supporting message])"
KNOWLEDGE GAPS:
- List important unknown information
- Format: "UNKNOWN: [topic/question]"
EXPECTATION VIOLATIONS:
- Based on the above information, if the next message were to surprise you, what could it contain?
- Format: "POTENTIAL SURPRISE: [possible content] [reason] [confidence level]"
- Include 3-5 possible surprises
</prediction>
"""
messages = [
{
"role": "user",
"content": f"Please analyze this conversation and provide a prediction following the format above:\n{chat_history}",
}
]
# Add existing user representation if available
if user_representation != "None":
messages.append(
{
"role": "user",
"content": f"Consider this existing user representation for context, but focus on current state:\n{user_representation}",
}
)
langfuse_context.update_current_observation(
input=messages, model=ANTHROPIC_MODEL
)
message = anthropic.messages.create(
model=ANTHROPIC_MODEL,
max_tokens=1000,
temperature=0,
messages=messages,
system=system_prompt,
)
print(f"tom_inference in single_prompt.py: {message.content[0].text=}")
message = message.content[0].text
return message
@ai_track("User Representation")
@observe(as_type="generation")
async def get_user_representation_single_prompt(
chat_history: str,
session_id: str,
user_representation: str = "None",
tom_inference: str = "None",
**kwargs,
) -> str:
with sentry_sdk.start_transaction(
op="user-representation-inference", name="User Representation"
):
system_prompt = """You are a system for maintaining factual user representations based on conversation history and theory of mind analysis.
Your job is to update the existing user representation (if provided) with the new information from the conversation history and theory of mind analysis.
Copy over information as-is from the existing user representation. Add new information as needed. Only remove content from this section if new information contradicts it. This is especially important for Persistent Information and Tentative Patterns.
If the existing user representation contains sources, copy them over to the new user representation.
Sometimes, especially at the beginning of a conversation, the user representation might contain information from previous conversations. In this case, preserve all previous information unless new information contradicts it, especially in regards to traits, interests, style, and other information about the user that is likely to be useful across conversations.
Always use the format below. If the existing user representation is in another format, convert it to the format below.
Always wrap your output in <representation> tags.
REQUIREMENTS:
1. Distinguish between temporary states and persistent patterns
2. Only incorporate verified information into core profile
3. Track certainty levels for all information
4. Maintain areas of uncertainty explicitly
5. Update representation incrementally
OUTPUT FORMAT:
<representation>
CURRENT STATE:
- ACTIVE CONTEXT: [detail on situation/activity/location] (SOURCE: [exact message]) # Current situation/activity/location
- TEMPORARY CONDITIONS: [detail on immediate circumstances] (SOURCE: [exact message]) # Immediate circumstances
- PRESENT MOOD/ACTIVITY: [what user is doing right now] (SOURCE: [exact message]) # What user is doing right now
PERSISTENT INFORMATION:
- STYLE: [pattern] (SOURCE: [exact message]) # Communication style: observed patterns in language use
- STATEMENT: [fact] (SOURCE: [exact message]) # Explicitly stated information
TENTATIVE PATTERNS:
- LIKELY PATTERN: [pattern] (SOURCE: [exact message]) # Patterns that are almost certain to be true
- POTENTIAL PATTERN: [pattern] (SOURCE: [exact message]) # Patterns that are possible but less likely
- SPECULATIVE PATTERN: [pattern] (SOURCE: [exact message]) # Patterns that are highly uncertain but remotely possible
KNOWLEDGE GAPS:
- List key missing information
- Note areas needing clarification
EXPECTATION VIOLATIONS:
- Based on the above information, if the next message were to surprise you, what could it contain?
- Format: "POTENTIAL SURPRISE: [possible content] [reason] [confidence level]"
- Include 3-5 possible surprises
UPDATES:
- New Information: Recent observations
- Changes: Modified interpretations
- Removals: Information no longer supported
</representation>
"""
messages = []
print(f"in single_prompt.py: chat_history: {chat_history}")
print(f"in single_prompt.py: user_representation: {user_representation}")
# Build the context message
context_str = f"CONVERSATION:\n{chat_history}\n\n"
if tom_inference != "None":
context_str += f"PREDICTION OF USER MENTAL STATE - MIGHT BE INCORRECT:\n{tom_inference}\n\n"
if user_representation != "None":
context_str += f"EXISTING USER REPRESENTATION - INCOMPLETE, TO BE UPDATED:\n{user_representation}"
messages.append(
{
"role": "user",
"content": f"Please analyze this information and provide an updated user representation:\n{context_str}",
}
)
langfuse_context.update_current_observation(
input=messages, model=ANTHROPIC_MODEL
)
message = anthropic.messages.create(
model=ANTHROPIC_MODEL,
max_tokens=1000,
temperature=0,
messages=messages,
system=system_prompt,
)
message = message.content[0].text
return message