Skip to content

Commit cbf624f

Browse files
authored
Tag ChatHistory blocks and files (#531)
We don't currently Tag ChatHistory files as being ChatHistory files. That means that the Web UI can't show a list of prior chats and let the user resume or browse one. This PR adds a tag constant for ChatHistory and tags new ChatHistory files with it when they are created. ### Along for the ride on this PR - Remove unused code from `experimental` - Consolidate duplicated `get_tag_value_key` methods into a single `tag_util.py` file. - Extract `build_chat_history_for_tool` function from `next_action` to enable testing on its own and possible resuse
1 parent 0045906 commit cbf624f

17 files changed

Lines changed: 115 additions & 49 deletions

File tree

src/steamship/agents/functional/functions_based.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ def __init__(self, tools: List[Tool], llm: ChatLLM, **kwargs):
2525
output_parser=FunctionsBasedOutputParser(tools=tools), llm=llm, tools=tools, **kwargs
2626
)
2727

28-
def next_action(self, context: AgentContext) -> Action:
29-
messages = []
28+
def build_chat_history_for_tool(self, context: AgentContext) -> List[Block]:
29+
messages: List[Block] = []
3030

31-
# get system messsage
31+
# get system message
3232
system_message = Block(text=self.PROMPT)
3333
system_message.set_chat_role(RoleTag.SYSTEM)
3434
messages.append(system_message)
@@ -72,7 +72,13 @@ def next_action(self, context: AgentContext) -> Action:
7272
for action in actions:
7373
messages.extend(action.to_chat_messages())
7474

75-
# call chat()
75+
return messages
76+
77+
def next_action(self, context: AgentContext) -> Action:
78+
# Build the Chat History that we'll provide as input to the action
79+
messages = self.build_chat_history_for_tool(context)
80+
81+
# Run the default LLM on those messages
7682
output_blocks = self.llm.chat(messages=messages, tools=self.tools)
7783

7884
return self.output_parser.parse(output_blocks[0].text, context)

src/steamship/agents/llms/openai.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from typing import List, Optional
22

3-
from steamship import Block, File, PluginInstance, Steamship
3+
from steamship import Block, File, PluginInstance, Steamship, Tag
44
from steamship.agents.schema import LLM, ChatLLM, Tool
5+
from steamship.data import TagKind
6+
from steamship.data.tags.tag_constants import GenerationTag
57

68
PLUGIN_HANDLE = "gpt-4"
79
DEFAULT_MAX_TOKENS = 256
@@ -80,7 +82,11 @@ def chat(self, messages: List[Block], tools: Optional[List[Tool]], **kwargs) ->
8082
- `max_tokens` (controls the size of LLM responses)
8183
"""
8284

83-
temp_file = File.create(client=self.client, blocks=messages)
85+
temp_file = File.create(
86+
client=self.client,
87+
blocks=messages,
88+
tags=[Tag(kind=TagKind.GENERATION, name=GenerationTag.PROMPT_COMPLETION)],
89+
)
8490

8591
options = {}
8692
if len(tools) > 0:
@@ -94,4 +100,5 @@ def chat(self, messages: List[Block], tools: Optional[List[Tool]], **kwargs) ->
94100

95101
tool_selection_task = self.generator.generate(input_file_id=temp_file.id, options=options)
96102
tool_selection_task.wait()
103+
97104
return tool_selection_task.output.blocks

src/steamship/agents/mixins/transports/slack.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ class SlackTransport(Transport):
244244
Interacting with the Bot on Slack will trigger a request/response loop in the Agent.
245245
"""
246246

247-
bot_token: str
247+
bot_token: Optional[str] = None
248248
agent_service: AgentService
249249
config: SlackTransportConfig
250250

src/steamship/agents/mixins/transports/telegram.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class TelegramTransportConfig(Config):
2525
class TelegramTransport(Transport):
2626
"""Experimental base class to encapsulate a Telegram communication channel."""
2727

28-
bot_token: Optional[str]
28+
bot_token: Optional[str] = None
2929
agent_service: AgentService
3030
config: TelegramTransportConfig
3131

@@ -292,7 +292,7 @@ def get_api_root(self) -> Optional[str]:
292292
api_base += "/"
293293

294294
if bot_token:
295-
if ".steamship.run/" in api_base:
295+
if ".steamship.run/" in api_base or ".apps.staging.steamship.com" in api_base:
296296
# This is a special case for our testing pipeline -- it contains a mock Telegram server.
297297
return api_base
298298
else:

src/steamship/agents/schema/chathistory.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ def get_or_create(
9393
if file is None:
9494
tags = tags or []
9595
index_handle = str(uuid.uuid4())
96-
tags.append(Tag(kind=TagKind.DOCUMENT, name=DocTag.CHAT))
96+
tags.append(Tag(kind=TagKind.DOCUMENT, name=DocTag.CHAT)) # This is a Chat-related tag
97+
tags.append(Tag(kind=TagKind.CHAT, name=ChatTag.HISTORY)) # This is a ChatHistory file
9798
tags.append(Tag(kind=TagKind.CHAT, name=ChatTag.CONTEXT_KEYS, value=context_keys))
9899
tags.append(
99100
Tag(
@@ -133,6 +134,7 @@ def append_message_with_role(
133134
tags.append(
134135
Tag(kind=TagKind.CHAT, name=ChatTag.ROLE, value={TagValueKey.STRING_VALUE: role})
135136
)
137+
tags.append(Tag(kind=TagKind.CHAT, name=ChatTag.MESSAGE))
136138
block = self.file.append_block(
137139
text=text, tags=tags, content=content, url=url, mime_type=mime_type
138140
)

src/steamship/agents/tools/search/search.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from steamship.agents.schema import AgentContext, Tool
99
from steamship.agents.utils import with_llm
1010
from steamship.data import TagValueKey
11-
from steamship.experimental.easy.tags import get_tag_value_key
11+
from steamship.data.tags.tag_utils import get_tag_value_key
1212
from steamship.utils.kv_store import KeyValueStore
1313
from steamship.utils.repl import ToolREPL
1414

src/steamship/data/block.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from steamship.base.response import Response
1414
from steamship.data.tags.tag import Tag
1515
from steamship.data.tags.tag_constants import ChatTag, DocTag, RoleTag, TagValueKey
16+
from steamship.data.tags.tag_utils import get_tag_value_key
1617

1718

1819
class BlockQueryRequest(Request):
@@ -26,16 +27,6 @@ class BlockUploadType(str, Enum):
2627
NONE = "none" # No upload; plain text only.
2728

2829

29-
def get_tag_value_key(
30-
tags: Optional[List[Tag]], key: str, kind: Optional[str] = None, name: Optional[str] = None
31-
) -> Optional[any]:
32-
"""Iterates through a list of tags and returns the first that contains the provided Kind/Name/ValueKey."""
33-
for tag in tags or []:
34-
if (kind is None or tag.kind == kind) and (name is None or tag.name == name):
35-
return (tag.value or {}).get(key)
36-
return None
37-
38-
3930
class Block(CamelModel):
4031
"""A Block is a chunk of content within a File. It can be plain text content, image content,
4132
video content, etc. If the content is not text, the text value may be the empty string

src/steamship/data/tags/tag_constants.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,9 @@ class ChatTag(str, Enum):
284284

285285
# A chunk of text for indexing
286286
CHUNK = "chunk"
287+
288+
# A chat history should be marked as kind=CHAT/name=HISTORY
289+
HISTORY = "history"
290+
291+
# A message should be marked as kind=CHAT/name=MESSAGE
292+
MESSAGE = "message"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from typing import List, Optional
2+
3+
from steamship.data.tags.tag import Tag
4+
5+
6+
def get_tag(
7+
tags: Optional[List[Tag]], kind: Optional[str] = None, name: Optional[str] = None
8+
) -> Optional[Tag]:
9+
"""Return the first tag of a list with the provided kind & name."""
10+
for tag in tags or []:
11+
if (kind is None or tag.kind == kind) and (name is None or tag.name == name):
12+
return tag
13+
return None
14+
15+
16+
def get_tag_value_key(
17+
tags: Optional[List[Tag]], key: str, kind: Optional[str] = None, name: Optional[str] = None
18+
) -> Optional[any]:
19+
"""Return the value key from the first tag of a list with the provided kind & name."""
20+
if tag := get_tag(tags, kind=kind, name=name):
21+
return (tag.value or {}).get(key)
22+
return None

src/steamship/experimental/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)