proscenium 0.0.13__py3-none-any.whl → 0.0.14__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- proscenium/__init__.py +179 -0
- proscenium/admin/__init__.py +2 -2
- proscenium/bin/__init__.py +1 -1
- proscenium/bin/bot.py +1 -1
- proscenium/complete.py +97 -0
- proscenium/{verbs/display/chat.py → history.py} +14 -0
- proscenium/interfaces/slack.py +2 -2
- proscenium/patterns/rag.py +1 -1
- proscenium/patterns/tools.py +182 -7
- {proscenium-0.0.13.dist-info → proscenium-0.0.14.dist-info}/METADATA +6 -4
- proscenium-0.0.14.dist-info/RECORD +19 -0
- proscenium/core/__init__.py +0 -172
- proscenium/verbs/__init__.py +0 -3
- proscenium/verbs/complete.py +0 -209
- proscenium/verbs/display/__init__.py +0 -9
- proscenium/verbs/display/tools.py +0 -64
- proscenium/verbs/display.py +0 -13
- proscenium/verbs/invoke.py +0 -11
- proscenium/verbs/remember.py +0 -13
- proscenium-0.0.13.dist-info/RECORD +0 -26
- {proscenium-0.0.13.dist-info → proscenium-0.0.14.dist-info}/WHEEL +0 -0
- {proscenium-0.0.13.dist-info → proscenium-0.0.14.dist-info}/entry_points.txt +0 -0
- {proscenium-0.0.13.dist-info → proscenium-0.0.14.dist-info}/licenses/LICENSE +0 -0
- {proscenium-0.0.13.dist-info → proscenium-0.0.14.dist-info}/top_level.txt +0 -0
proscenium/__init__.py
CHANGED
@@ -1,3 +1,182 @@
|
|
1
|
+
from typing import Generator
|
2
|
+
from typing import Optional
|
1
3
|
import logging
|
2
4
|
|
5
|
+
from pydantic import BaseModel, Field
|
6
|
+
from rich.text import Text
|
7
|
+
from rich.console import Console
|
8
|
+
|
3
9
|
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
10
|
+
|
11
|
+
log = logging.getLogger(__name__)
|
12
|
+
|
13
|
+
|
14
|
+
def header() -> Text:
|
15
|
+
text = Text()
|
16
|
+
text.append("Proscenium 🎭\n", style="bold")
|
17
|
+
text.append("https://the-ai-alliance.github.io/proscenium/\n")
|
18
|
+
# TODO version, timestamp, ...
|
19
|
+
return text
|
20
|
+
|
21
|
+
|
22
|
+
control_flow_system_prompt = """
|
23
|
+
You control the workflow of an AI assistant. You evaluate user-posted messages and decide what the next step is.
|
24
|
+
"""
|
25
|
+
|
26
|
+
|
27
|
+
class WantsToHandleResponse(BaseModel):
|
28
|
+
"""
|
29
|
+
The response to whether the Character wants to handle the provided utterance.
|
30
|
+
"""
|
31
|
+
|
32
|
+
wants_to_handle: bool = Field(
|
33
|
+
description="A boolean indicating whether the Character wants to handle the provided utterance.",
|
34
|
+
)
|
35
|
+
|
36
|
+
|
37
|
+
class Prop:
|
38
|
+
"""
|
39
|
+
A `Prop` is a resource available to the `Character`s in a `Scene`.
|
40
|
+
"""
|
41
|
+
|
42
|
+
def __init__(
|
43
|
+
self,
|
44
|
+
console: Optional[Console] = None,
|
45
|
+
):
|
46
|
+
self.console = console
|
47
|
+
|
48
|
+
def name(self) -> str:
|
49
|
+
return self.__class__.__name__
|
50
|
+
|
51
|
+
def description(self) -> str:
|
52
|
+
return self.__doc__ or ""
|
53
|
+
|
54
|
+
def curtain_up_message(self) -> str:
|
55
|
+
return f"- {self.name()}, {self.description().strip()}"
|
56
|
+
|
57
|
+
def already_built(self) -> bool:
|
58
|
+
return False
|
59
|
+
|
60
|
+
def build(self) -> None:
|
61
|
+
pass
|
62
|
+
|
63
|
+
|
64
|
+
class Character:
|
65
|
+
"""
|
66
|
+
A `Character` is a participant in a `Scene` that `handle`s utterances from the
|
67
|
+
scene by producing its own utterances."""
|
68
|
+
|
69
|
+
def __init__(self, admin_channel_id: str):
|
70
|
+
self.admin_channel_id = admin_channel_id
|
71
|
+
|
72
|
+
def name(self) -> str:
|
73
|
+
return self.__class__.__name__
|
74
|
+
|
75
|
+
def description(self) -> str:
|
76
|
+
return self.__doc__ or ""
|
77
|
+
|
78
|
+
def curtain_up_message(self) -> str:
|
79
|
+
return f"- {self.name()}, {self.description().strip()}"
|
80
|
+
|
81
|
+
def wants_to_handle(self, channel_id: str, speaker_id: str, utterance: str) -> bool:
|
82
|
+
return False
|
83
|
+
|
84
|
+
def handle(
|
85
|
+
channel_id: str, speaker_id: str, utterance: str
|
86
|
+
) -> Generator[tuple[str, str], None, None]:
|
87
|
+
pass
|
88
|
+
|
89
|
+
|
90
|
+
class Scene:
|
91
|
+
"""
|
92
|
+
A `Scene` is a setting in which `Character`s interact with each other and
|
93
|
+
with `Prop`s. It is a container for `Character`s and `Prop`s.
|
94
|
+
"""
|
95
|
+
|
96
|
+
def __init__(self):
|
97
|
+
pass
|
98
|
+
|
99
|
+
def name(self) -> str:
|
100
|
+
return self.__class__.__name__
|
101
|
+
|
102
|
+
def description(self) -> str:
|
103
|
+
return self.__doc__ or ""
|
104
|
+
|
105
|
+
def curtain_up_message(self) -> str:
|
106
|
+
|
107
|
+
characters_msg = "\n".join(
|
108
|
+
[character.curtain_up_message() for character in self.characters()]
|
109
|
+
)
|
110
|
+
|
111
|
+
props_msg = "\n".join([prop.curtain_up_message() for prop in self.props()])
|
112
|
+
|
113
|
+
return f"""
|
114
|
+
Scene: {self.name()}, {self.description().strip()}
|
115
|
+
|
116
|
+
Characters:
|
117
|
+
{characters_msg}
|
118
|
+
|
119
|
+
Props:
|
120
|
+
{props_msg}
|
121
|
+
"""
|
122
|
+
|
123
|
+
def props(self) -> list[Prop]:
|
124
|
+
return []
|
125
|
+
|
126
|
+
def prepare_props(self, force_rebuild: bool = False) -> None:
|
127
|
+
for prop in self.props():
|
128
|
+
if force_rebuild:
|
129
|
+
prop.build()
|
130
|
+
elif not prop.already_built():
|
131
|
+
log.info("Prop %s not built. Building it now.", prop.name())
|
132
|
+
prop.build()
|
133
|
+
|
134
|
+
def characters(self) -> list[Character]:
|
135
|
+
return []
|
136
|
+
|
137
|
+
def places(self) -> dict[str, Character]:
|
138
|
+
pass
|
139
|
+
|
140
|
+
def curtain(self) -> None:
|
141
|
+
pass
|
142
|
+
|
143
|
+
|
144
|
+
class Production:
|
145
|
+
"""
|
146
|
+
A `Production` is a collection of `Scene`s."""
|
147
|
+
|
148
|
+
def __init__(self, admin_channel_id: str, console: Optional[Console] = None):
|
149
|
+
self.admin_channel_id = admin_channel_id
|
150
|
+
self.console = console
|
151
|
+
|
152
|
+
def name(self) -> str:
|
153
|
+
return self.__class__.__name__
|
154
|
+
|
155
|
+
def description(self) -> str:
|
156
|
+
return self.__doc__ or ""
|
157
|
+
|
158
|
+
def prepare_props(self, force_rebuild: bool = False) -> None:
|
159
|
+
if force_rebuild:
|
160
|
+
log.info("Forcing rebuild of all props.")
|
161
|
+
else:
|
162
|
+
log.info("Building any missing props...")
|
163
|
+
|
164
|
+
for scene in self.scenes():
|
165
|
+
scene.prepare_props(force_rebuild=force_rebuild)
|
166
|
+
|
167
|
+
def curtain_up_message(self) -> str:
|
168
|
+
|
169
|
+
scenes_msg = "\n\n".join(
|
170
|
+
[scene.curtain_up_message() for scene in self.scenes()]
|
171
|
+
)
|
172
|
+
|
173
|
+
return f"""Production: {self.name()}, {self.description().strip()}
|
174
|
+
|
175
|
+
{scenes_msg}"""
|
176
|
+
|
177
|
+
def scenes(self) -> list[Scene]:
|
178
|
+
return []
|
179
|
+
|
180
|
+
def curtain(self) -> None:
|
181
|
+
for scene in self.scenes():
|
182
|
+
scene.curtain()
|
proscenium/admin/__init__.py
CHANGED
@@ -4,8 +4,8 @@ from typing import Optional
|
|
4
4
|
|
5
5
|
import logging
|
6
6
|
|
7
|
-
from proscenium
|
8
|
-
from proscenium
|
7
|
+
from proscenium import Prop
|
8
|
+
from proscenium import Character
|
9
9
|
from rich.console import Console
|
10
10
|
|
11
11
|
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
proscenium/bin/__init__.py
CHANGED
proscenium/bin/bot.py
CHANGED
@@ -8,7 +8,7 @@ import logging
|
|
8
8
|
from pathlib import Path
|
9
9
|
from rich.console import Console
|
10
10
|
|
11
|
-
from proscenium
|
11
|
+
from proscenium import header
|
12
12
|
from proscenium.bin import production_from_config
|
13
13
|
from proscenium.interfaces.slack import SlackProductionProcessor
|
14
14
|
|
proscenium/complete.py
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
"""
|
2
|
+
This module uses the [`aisuite`](https://github.com/andrewyng/aisuite) library
|
3
|
+
to interact with various LLM inference providers.
|
4
|
+
|
5
|
+
It provides functions to complete a simple chat prompt, evaluate a tool call,
|
6
|
+
and apply a list of tool calls to a chat prompt.
|
7
|
+
|
8
|
+
Providers tested with Proscenium include:
|
9
|
+
|
10
|
+
# AWS
|
11
|
+
|
12
|
+
Environment: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`
|
13
|
+
|
14
|
+
Valid model ids:
|
15
|
+
- `aws:meta.llama3-1-8b-instruct-v1:0`
|
16
|
+
|
17
|
+
# Anthropic
|
18
|
+
|
19
|
+
Environment: `ANTHROPIC_API_KEY`
|
20
|
+
|
21
|
+
Valid model ids:
|
22
|
+
- `anthropic:claude-3-5-sonnet-20240620`
|
23
|
+
|
24
|
+
# OpenAI
|
25
|
+
|
26
|
+
Environment: `OPENAI_API_KEY`
|
27
|
+
|
28
|
+
Valid model ids:
|
29
|
+
- `openai:gpt-4o`
|
30
|
+
|
31
|
+
# Ollama
|
32
|
+
|
33
|
+
Command line, eg `ollama run llama3.2 --keepalive 2h`
|
34
|
+
|
35
|
+
Valid model ids:
|
36
|
+
- `ollama:llama3.2`
|
37
|
+
- `ollama:granite3.1-dense:2b`
|
38
|
+
"""
|
39
|
+
|
40
|
+
import logging
|
41
|
+
|
42
|
+
from rich.console import Group
|
43
|
+
from rich.panel import Panel
|
44
|
+
from rich.table import Table
|
45
|
+
from rich.text import Text
|
46
|
+
|
47
|
+
from aisuite import Client as AISuiteClient
|
48
|
+
|
49
|
+
log = logging.getLogger(__name__)
|
50
|
+
|
51
|
+
|
52
|
+
def complete_simple(
|
53
|
+
chat_completion_client: AISuiteClient,
|
54
|
+
model_id: str,
|
55
|
+
system_prompt: str,
|
56
|
+
user_prompt: str,
|
57
|
+
**kwargs,
|
58
|
+
) -> str:
|
59
|
+
|
60
|
+
console = kwargs.pop("console", None)
|
61
|
+
|
62
|
+
messages = [
|
63
|
+
{"role": "system", "content": system_prompt},
|
64
|
+
{"role": "user", "content": user_prompt},
|
65
|
+
]
|
66
|
+
|
67
|
+
if console is not None:
|
68
|
+
|
69
|
+
kwargs_text = "\n".join([str(k) + ": " + str(v) for k, v in kwargs.items()])
|
70
|
+
|
71
|
+
params_text = Text(
|
72
|
+
f"""
|
73
|
+
model_id: {model_id}
|
74
|
+
{kwargs_text}
|
75
|
+
"""
|
76
|
+
)
|
77
|
+
|
78
|
+
messages_table = Table(title="Messages", show_lines=True)
|
79
|
+
messages_table.add_column("Role", justify="left")
|
80
|
+
messages_table.add_column("Content", justify="left") # style="green"
|
81
|
+
for message in messages:
|
82
|
+
messages_table.add_row(message["role"], message["content"])
|
83
|
+
|
84
|
+
call_panel = Panel(
|
85
|
+
Group(params_text, messages_table), title="complete_simple call"
|
86
|
+
)
|
87
|
+
console.print(call_panel)
|
88
|
+
|
89
|
+
response = chat_completion_client.chat.completions.create(
|
90
|
+
model=model_id, messages=messages, **kwargs
|
91
|
+
)
|
92
|
+
response = response.choices[0].message.content
|
93
|
+
|
94
|
+
if console is not None:
|
95
|
+
console.print(Panel(response, title="Response"))
|
96
|
+
|
97
|
+
return response
|
@@ -1,5 +1,19 @@
|
|
1
|
+
import logging
|
2
|
+
|
1
3
|
from rich.table import Table
|
2
4
|
|
5
|
+
log = logging.getLogger(__name__)
|
6
|
+
|
7
|
+
|
8
|
+
def format_chat_history(chat_history) -> str:
|
9
|
+
delimiter = "-" * 80 + "\n"
|
10
|
+
return delimiter.join(
|
11
|
+
[
|
12
|
+
f"{msg['sender']} to {msg['receiver']}:\n\n{msg['content']}\n\n"
|
13
|
+
for msg in chat_history
|
14
|
+
]
|
15
|
+
)
|
16
|
+
|
3
17
|
|
4
18
|
def messages_table(messages: list) -> Table:
|
5
19
|
|
proscenium/interfaces/slack.py
CHANGED
@@ -12,8 +12,8 @@ from slack_sdk.socket_mode import SocketModeClient
|
|
12
12
|
from slack_sdk.socket_mode.request import SocketModeRequest
|
13
13
|
from slack_sdk.socket_mode.response import SocketModeResponse
|
14
14
|
|
15
|
-
from proscenium
|
16
|
-
from proscenium
|
15
|
+
from proscenium import Production
|
16
|
+
from proscenium import Character
|
17
17
|
from proscenium.admin import Admin
|
18
18
|
|
19
19
|
log = logging.getLogger(__name__)
|
proscenium/patterns/rag.py
CHANGED
proscenium/patterns/tools.py
CHANGED
@@ -1,19 +1,194 @@
|
|
1
1
|
from typing import Optional
|
2
|
+
from typing import Any
|
2
3
|
import logging
|
4
|
+
import json
|
3
5
|
|
4
|
-
from rich.console import
|
5
|
-
from rich.
|
6
|
+
from rich.console import Group
|
7
|
+
from rich.table import Table
|
6
8
|
from rich.text import Text
|
9
|
+
from rich.panel import Panel
|
10
|
+
from rich.console import Console
|
11
|
+
|
12
|
+
from aisuite import Client as AISuiteClient
|
13
|
+
from aisuite.framework.message import ChatCompletionMessageToolCall
|
7
14
|
|
8
|
-
from
|
9
|
-
|
10
|
-
|
11
|
-
complete_with_tool_results,
|
12
|
-
)
|
15
|
+
from gofannon.base import BaseTool
|
16
|
+
|
17
|
+
from proscenium.history import messages_table
|
13
18
|
|
14
19
|
log = logging.getLogger(__name__)
|
15
20
|
|
16
21
|
|
22
|
+
def evaluate_tool_call(tool_map: dict, tool_call: ChatCompletionMessageToolCall) -> Any:
|
23
|
+
|
24
|
+
function_name = tool_call.function.name
|
25
|
+
# TODO validate the arguments?
|
26
|
+
function_args = json.loads(tool_call.function.arguments)
|
27
|
+
|
28
|
+
log.info(f"Evaluating tool call: {function_name} with args {function_args}")
|
29
|
+
|
30
|
+
function_response = tool_map[function_name](**function_args)
|
31
|
+
|
32
|
+
log.info(f" Response: {function_response}")
|
33
|
+
|
34
|
+
return function_response
|
35
|
+
|
36
|
+
|
37
|
+
def tool_response_message(
|
38
|
+
tool_call: ChatCompletionMessageToolCall, tool_result: Any
|
39
|
+
) -> dict:
|
40
|
+
|
41
|
+
return {
|
42
|
+
"role": "tool",
|
43
|
+
"tool_call_id": tool_call.id,
|
44
|
+
"name": tool_call.function.name,
|
45
|
+
"content": json.dumps(tool_result),
|
46
|
+
}
|
47
|
+
|
48
|
+
|
49
|
+
def evaluate_tool_calls(tool_call_message, tool_map: dict) -> list[dict]:
|
50
|
+
|
51
|
+
tool_call: ChatCompletionMessageToolCall
|
52
|
+
|
53
|
+
log.info("Evaluating tool calls")
|
54
|
+
|
55
|
+
new_messages: list[dict] = []
|
56
|
+
|
57
|
+
for tool_call in tool_call_message.tool_calls:
|
58
|
+
function_response = evaluate_tool_call(tool_map, tool_call)
|
59
|
+
new_messages.append(tool_response_message(tool_call, function_response))
|
60
|
+
|
61
|
+
log.info("Tool calls evaluated")
|
62
|
+
|
63
|
+
return new_messages
|
64
|
+
|
65
|
+
|
66
|
+
def complete_for_tool_applications(
|
67
|
+
chat_completion_client: AISuiteClient,
|
68
|
+
model_id: str,
|
69
|
+
messages: list,
|
70
|
+
tool_desc_list: list,
|
71
|
+
temperature: float,
|
72
|
+
console: Optional[Console] = None,
|
73
|
+
):
|
74
|
+
|
75
|
+
if console is not None:
|
76
|
+
panel = complete_with_tools_panel(
|
77
|
+
"complete for tool applications",
|
78
|
+
model_id,
|
79
|
+
tool_desc_list,
|
80
|
+
messages,
|
81
|
+
temperature,
|
82
|
+
)
|
83
|
+
console.print(panel)
|
84
|
+
|
85
|
+
response = chat_completion_client.chat.completions.create(
|
86
|
+
model=model_id,
|
87
|
+
messages=messages,
|
88
|
+
temperature=temperature,
|
89
|
+
tools=tool_desc_list, # tool_choice="auto",
|
90
|
+
)
|
91
|
+
|
92
|
+
return response
|
93
|
+
|
94
|
+
|
95
|
+
def complete_with_tool_results(
|
96
|
+
chat_completion_client: AISuiteClient,
|
97
|
+
model_id: str,
|
98
|
+
messages: list,
|
99
|
+
tool_call_message: dict,
|
100
|
+
tool_evaluation_messages: list[dict],
|
101
|
+
tool_desc_list: list,
|
102
|
+
temperature: float,
|
103
|
+
console: Optional[Console] = None,
|
104
|
+
):
|
105
|
+
|
106
|
+
messages.append(tool_call_message)
|
107
|
+
messages.extend(tool_evaluation_messages)
|
108
|
+
|
109
|
+
if console is not None:
|
110
|
+
panel = complete_with_tools_panel(
|
111
|
+
"complete call with tool results",
|
112
|
+
model_id,
|
113
|
+
tool_desc_list,
|
114
|
+
messages,
|
115
|
+
temperature,
|
116
|
+
)
|
117
|
+
console.print(panel)
|
118
|
+
|
119
|
+
response = chat_completion_client.chat.completions.create(
|
120
|
+
model=model_id,
|
121
|
+
messages=messages,
|
122
|
+
)
|
123
|
+
|
124
|
+
return response.choices[0].message.content
|
125
|
+
|
126
|
+
|
127
|
+
def process_tools(tools: list[BaseTool]) -> tuple[dict, list]:
|
128
|
+
applied_tools = [F() for F in tools]
|
129
|
+
tool_map = {f.name: f.fn for f in applied_tools}
|
130
|
+
tool_desc_list = [f.definition for f in applied_tools]
|
131
|
+
return tool_map, tool_desc_list
|
132
|
+
|
133
|
+
|
134
|
+
def parameters_table(parameters: list[dict]) -> Table:
|
135
|
+
|
136
|
+
table = Table(title="Parameters", show_lines=False, box=None)
|
137
|
+
table.add_column("name", justify="right")
|
138
|
+
table.add_column("type", justify="left")
|
139
|
+
table.add_column("description", justify="left")
|
140
|
+
|
141
|
+
for name, props in parameters["properties"].items():
|
142
|
+
table.add_row(name, props["type"], props["description"])
|
143
|
+
|
144
|
+
# TODO denote required params
|
145
|
+
|
146
|
+
return table
|
147
|
+
|
148
|
+
|
149
|
+
def function_description_panel(fd: dict) -> Panel:
|
150
|
+
|
151
|
+
fn = fd["function"]
|
152
|
+
|
153
|
+
text = Text(f"{fd['type']} {fn['name']}: {fn['description']}\n")
|
154
|
+
|
155
|
+
pt = parameters_table(fn["parameters"])
|
156
|
+
|
157
|
+
panel = Panel(Group(text, pt))
|
158
|
+
|
159
|
+
return panel
|
160
|
+
|
161
|
+
|
162
|
+
def function_descriptions_panel(function_descriptions: list[dict]) -> Panel:
|
163
|
+
|
164
|
+
sub_panels = [function_description_panel(fd) for fd in function_descriptions]
|
165
|
+
|
166
|
+
panel = Panel(Group(*sub_panels), title="Function Descriptions")
|
167
|
+
|
168
|
+
return panel
|
169
|
+
|
170
|
+
|
171
|
+
def complete_with_tools_panel(
|
172
|
+
title: str, model_id: str, tool_desc_list: list, messages: list, temperature: float
|
173
|
+
) -> Panel:
|
174
|
+
|
175
|
+
text = Text(
|
176
|
+
f"""
|
177
|
+
model_id: {model_id}
|
178
|
+
temperature: {temperature}
|
179
|
+
"""
|
180
|
+
)
|
181
|
+
|
182
|
+
panel = Panel(
|
183
|
+
Group(
|
184
|
+
text, function_descriptions_panel(tool_desc_list), messages_table(messages)
|
185
|
+
),
|
186
|
+
title=title,
|
187
|
+
)
|
188
|
+
|
189
|
+
return panel
|
190
|
+
|
191
|
+
|
17
192
|
def apply_tools(
|
18
193
|
model_id: str,
|
19
194
|
system_message: str,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: proscenium
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.14
|
4
4
|
Summary: Declare Collaborative, Asynchronous Human To Agent Interactions
|
5
5
|
Author-email: Adam Pingel <oss@pingel.org>
|
6
6
|
License-Expression: Apache-2.0
|
@@ -25,15 +25,17 @@ Dynamic: license-file
|
|
25
25
|
|
26
26
|
# Proscenium
|
27
27
|
|
28
|
-
[](https://pypi.org/project/proscenium/)
|
29
29
|
[](https://pypi.org/project/proscenium/)
|
30
30
|
[](https://github.com/The-AI-Alliance/proscenium/actions/workflows/pytest.yml)
|
31
|
-
[](https://pypi.org/project/proscenium/)
|
32
31
|
[](https://github.com/The-AI-Alliance/proscenium/tree/main?tab=Apache-2.0-1-ov-file#readme)
|
33
32
|
[](https://github.com/The-AI-Alliance/proscenium/issues)
|
34
33
|
[](https://github.com/The-AI-Alliance/proscenium/stargazers)
|
35
34
|
|
36
|
-
Proscenium is a small, experimental library
|
35
|
+
Proscenium is a small, experimental library for
|
36
|
+
declaring collaborative, asynchronous human to agent interactions
|
37
|
+
in enterprise AI applications.
|
38
|
+
It was started in February 2025 and is still in early development.
|
37
39
|
|
38
40
|
See the [website](https://the-ai-alliance.github.io/proscenium/) for quickstart info, goals, and other links.
|
39
41
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
proscenium/__init__.py,sha256=n6X5CqhlDL3lagVL0756myyNwVxHyGokngxkbRzRkxA,4574
|
2
|
+
proscenium/complete.py,sha256=WVp-WB420jzikuUmPYVRQ0wI3bgRGZO_-ZCBBX_yJbw,2239
|
3
|
+
proscenium/history.py,sha256=AzLfn-raqlDNEJrKQYUJNN8kMogr08evfjOi9Mzwlqo,1445
|
4
|
+
proscenium/admin/__init__.py,sha256=5ENOL6CqlZJilCZFt3O6gwbHSvFMFcxEf9f8e2QmcTM,1016
|
5
|
+
proscenium/bin/__init__.py,sha256=RcD50sEH58LMEayUez9uugTigG7XnFB6kdILvro_xzg,1155
|
6
|
+
proscenium/bin/bot.py,sha256=IaQP33AOCTBcNtx4gb7kCwa2aXTR8XuKuLAfYwPJtE4,1699
|
7
|
+
proscenium/interfaces/__init__.py,sha256=nDWNd6_TSf4vDQuHVBoAf4QfZCB3ZUFQ0M7XvifNJ-g,78
|
8
|
+
proscenium/interfaces/slack.py,sha256=ebx3oc2CJuzbCJ9eYyCRyhtbojaCaWsgfscmwVv8I3E,10195
|
9
|
+
proscenium/patterns/__init__.py,sha256=nDWNd6_TSf4vDQuHVBoAf4QfZCB3ZUFQ0M7XvifNJ-g,78
|
10
|
+
proscenium/patterns/graph_rag.py,sha256=1HH1xdlAA6ypvYdP4dWFm-KXrGPUmm0T4qIdAU8mgvE,1763
|
11
|
+
proscenium/patterns/rag.py,sha256=HJzLYIqcxhAZNQ0JXhfHe9JV1rr41m9iFQGSxjryGBg,2304
|
12
|
+
proscenium/patterns/tools.py,sha256=CjVSySlWqd308ToYiwVSZG-NKnvUlWIGYfh-GY5BXMk,6164
|
13
|
+
proscenium/util/__init__.py,sha256=FC1hjA37VvmVpF9-OlYNp9TjArH6etr6KiAvF9t_6lI,679
|
14
|
+
proscenium-0.0.14.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
15
|
+
proscenium-0.0.14.dist-info/METADATA,sha256=6SRKhXXMTp7Zpt0Q5kQ7KtwBHF2pJ8dDdiJFr31yxRE,2148
|
16
|
+
proscenium-0.0.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
17
|
+
proscenium-0.0.14.dist-info/entry_points.txt,sha256=bbrDWv4WKIx9UROGXcyH0eo40F8SNpDQKvXxoE8BTHI,58
|
18
|
+
proscenium-0.0.14.dist-info/top_level.txt,sha256=aiTgQy73e21wnSSxM5iICXmXT3zldN8cFKeXpvJ5Xx4,11
|
19
|
+
proscenium-0.0.14.dist-info/RECORD,,
|
proscenium/core/__init__.py
DELETED
@@ -1,172 +0,0 @@
|
|
1
|
-
from typing import Generator
|
2
|
-
from typing import Optional
|
3
|
-
import logging
|
4
|
-
|
5
|
-
from pydantic import BaseModel, Field
|
6
|
-
from rich.console import Console
|
7
|
-
|
8
|
-
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
9
|
-
|
10
|
-
log = logging.getLogger(__name__)
|
11
|
-
|
12
|
-
control_flow_system_prompt = """
|
13
|
-
You control the workflow of an AI assistant. You evaluate user-posted messages and decide what the next step is.
|
14
|
-
"""
|
15
|
-
|
16
|
-
|
17
|
-
class WantsToHandleResponse(BaseModel):
|
18
|
-
"""
|
19
|
-
The response to whether the Character wants to handle the provided utterance.
|
20
|
-
"""
|
21
|
-
|
22
|
-
wants_to_handle: bool = Field(
|
23
|
-
description="A boolean indicating whether the Character wants to handle the provided utterance.",
|
24
|
-
)
|
25
|
-
|
26
|
-
|
27
|
-
class Prop:
|
28
|
-
"""
|
29
|
-
A `Prop` is a resource available to the `Character`s in a `Scene`.
|
30
|
-
"""
|
31
|
-
|
32
|
-
def __init__(
|
33
|
-
self,
|
34
|
-
console: Optional[Console] = None,
|
35
|
-
):
|
36
|
-
self.console = console
|
37
|
-
|
38
|
-
def name(self) -> str:
|
39
|
-
return self.__class__.__name__
|
40
|
-
|
41
|
-
def description(self) -> str:
|
42
|
-
return self.__doc__ or ""
|
43
|
-
|
44
|
-
def curtain_up_message(self) -> str:
|
45
|
-
return f"- {self.name()}, {self.description().strip()}"
|
46
|
-
|
47
|
-
def already_built(self) -> bool:
|
48
|
-
return False
|
49
|
-
|
50
|
-
def build(self) -> None:
|
51
|
-
pass
|
52
|
-
|
53
|
-
|
54
|
-
class Character:
|
55
|
-
"""
|
56
|
-
A `Character` is a participant in a `Scene` that `handle`s utterances from the
|
57
|
-
scene by producing its own utterances."""
|
58
|
-
|
59
|
-
def __init__(self, admin_channel_id: str):
|
60
|
-
self.admin_channel_id = admin_channel_id
|
61
|
-
|
62
|
-
def name(self) -> str:
|
63
|
-
return self.__class__.__name__
|
64
|
-
|
65
|
-
def description(self) -> str:
|
66
|
-
return self.__doc__ or ""
|
67
|
-
|
68
|
-
def curtain_up_message(self) -> str:
|
69
|
-
return f"- {self.name()}, {self.description().strip()}"
|
70
|
-
|
71
|
-
def wants_to_handle(self, channel_id: str, speaker_id: str, utterance: str) -> bool:
|
72
|
-
return False
|
73
|
-
|
74
|
-
def handle(
|
75
|
-
channel_id: str, speaker_id: str, utterance: str
|
76
|
-
) -> Generator[tuple[str, str], None, None]:
|
77
|
-
pass
|
78
|
-
|
79
|
-
|
80
|
-
class Scene:
|
81
|
-
"""
|
82
|
-
A `Scene` is a setting in which `Character`s interact with each other and
|
83
|
-
with `Prop`s. It is a container for `Character`s and `Prop`s.
|
84
|
-
"""
|
85
|
-
|
86
|
-
def __init__(self):
|
87
|
-
pass
|
88
|
-
|
89
|
-
def name(self) -> str:
|
90
|
-
return self.__class__.__name__
|
91
|
-
|
92
|
-
def description(self) -> str:
|
93
|
-
return self.__doc__ or ""
|
94
|
-
|
95
|
-
def curtain_up_message(self) -> str:
|
96
|
-
|
97
|
-
characters_msg = "\n".join(
|
98
|
-
[character.curtain_up_message() for character in self.characters()]
|
99
|
-
)
|
100
|
-
|
101
|
-
props_msg = "\n".join([prop.curtain_up_message() for prop in self.props()])
|
102
|
-
|
103
|
-
return f"""
|
104
|
-
Scene: {self.name()}, {self.description().strip()}
|
105
|
-
|
106
|
-
Characters:
|
107
|
-
{characters_msg}
|
108
|
-
|
109
|
-
Props:
|
110
|
-
{props_msg}
|
111
|
-
"""
|
112
|
-
|
113
|
-
def props(self) -> list[Prop]:
|
114
|
-
return []
|
115
|
-
|
116
|
-
def prepare_props(self, force_rebuild: bool = False) -> None:
|
117
|
-
for prop in self.props():
|
118
|
-
if force_rebuild:
|
119
|
-
prop.build()
|
120
|
-
elif not prop.already_built():
|
121
|
-
log.info("Prop %s not built. Building it now.", prop.name())
|
122
|
-
prop.build()
|
123
|
-
|
124
|
-
def characters(self) -> list[Character]:
|
125
|
-
return []
|
126
|
-
|
127
|
-
def places(self) -> dict[str, Character]:
|
128
|
-
pass
|
129
|
-
|
130
|
-
def curtain(self) -> None:
|
131
|
-
pass
|
132
|
-
|
133
|
-
|
134
|
-
class Production:
|
135
|
-
"""
|
136
|
-
A `Production` is a collection of `Scene`s."""
|
137
|
-
|
138
|
-
def __init__(self, admin_channel_id: str, console: Optional[Console] = None):
|
139
|
-
self.admin_channel_id = admin_channel_id
|
140
|
-
self.console = console
|
141
|
-
|
142
|
-
def name(self) -> str:
|
143
|
-
return self.__class__.__name__
|
144
|
-
|
145
|
-
def description(self) -> str:
|
146
|
-
return self.__doc__ or ""
|
147
|
-
|
148
|
-
def prepare_props(self, force_rebuild: bool = False) -> None:
|
149
|
-
if force_rebuild:
|
150
|
-
log.info("Forcing rebuild of all props.")
|
151
|
-
else:
|
152
|
-
log.info("Building any missing props...")
|
153
|
-
|
154
|
-
for scene in self.scenes():
|
155
|
-
scene.prepare_props(force_rebuild=force_rebuild)
|
156
|
-
|
157
|
-
def curtain_up_message(self) -> str:
|
158
|
-
|
159
|
-
scenes_msg = "\n\n".join(
|
160
|
-
[scene.curtain_up_message() for scene in self.scenes()]
|
161
|
-
)
|
162
|
-
|
163
|
-
return f"""Production: {self.name()}, {self.description().strip()}
|
164
|
-
|
165
|
-
{scenes_msg}"""
|
166
|
-
|
167
|
-
def scenes(self) -> list[Scene]:
|
168
|
-
return []
|
169
|
-
|
170
|
-
def curtain(self) -> None:
|
171
|
-
for scene in self.scenes():
|
172
|
-
scene.curtain()
|
proscenium/verbs/__init__.py
DELETED
proscenium/verbs/complete.py
DELETED
@@ -1,209 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
This module uses the [`aisuite`](https://github.com/andrewyng/aisuite) library
|
3
|
-
to interact with various LLM inference providers.
|
4
|
-
|
5
|
-
It provides functions to complete a simple chat prompt, evaluate a tool call,
|
6
|
-
and apply a list of tool calls to a chat prompt.
|
7
|
-
|
8
|
-
Providers tested with Proscenium include:
|
9
|
-
|
10
|
-
# AWS
|
11
|
-
|
12
|
-
Environment: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`
|
13
|
-
|
14
|
-
Valid model ids:
|
15
|
-
- `aws:meta.llama3-1-8b-instruct-v1:0`
|
16
|
-
|
17
|
-
# Anthropic
|
18
|
-
|
19
|
-
Environment: `ANTHROPIC_API_KEY`
|
20
|
-
|
21
|
-
Valid model ids:
|
22
|
-
- `anthropic:claude-3-5-sonnet-20240620`
|
23
|
-
|
24
|
-
# OpenAI
|
25
|
-
|
26
|
-
Environment: `OPENAI_API_KEY`
|
27
|
-
|
28
|
-
Valid model ids:
|
29
|
-
- `openai:gpt-4o`
|
30
|
-
|
31
|
-
# Ollama
|
32
|
-
|
33
|
-
Command line, eg `ollama run llama3.2 --keepalive 2h`
|
34
|
-
|
35
|
-
Valid model ids:
|
36
|
-
- `ollama:llama3.2`
|
37
|
-
- `ollama:granite3.1-dense:2b`
|
38
|
-
"""
|
39
|
-
|
40
|
-
from typing import Optional
|
41
|
-
from typing import Any
|
42
|
-
import logging
|
43
|
-
import json
|
44
|
-
|
45
|
-
from rich.console import Console
|
46
|
-
from rich.console import Group
|
47
|
-
from rich.panel import Panel
|
48
|
-
from rich.table import Table
|
49
|
-
from rich.text import Text
|
50
|
-
|
51
|
-
from aisuite import Client as AISuiteClient
|
52
|
-
from aisuite.framework.message import ChatCompletionMessageToolCall
|
53
|
-
|
54
|
-
from proscenium.verbs.display.tools import complete_with_tools_panel
|
55
|
-
|
56
|
-
log = logging.getLogger(__name__)
|
57
|
-
|
58
|
-
|
59
|
-
def complete_simple(
|
60
|
-
chat_completion_client: AISuiteClient,
|
61
|
-
model_id: str,
|
62
|
-
system_prompt: str,
|
63
|
-
user_prompt: str,
|
64
|
-
**kwargs,
|
65
|
-
) -> str:
|
66
|
-
|
67
|
-
console = kwargs.pop("console", None)
|
68
|
-
|
69
|
-
messages = [
|
70
|
-
{"role": "system", "content": system_prompt},
|
71
|
-
{"role": "user", "content": user_prompt},
|
72
|
-
]
|
73
|
-
|
74
|
-
if console is not None:
|
75
|
-
|
76
|
-
kwargs_text = "\n".join([str(k) + ": " + str(v) for k, v in kwargs.items()])
|
77
|
-
|
78
|
-
params_text = Text(
|
79
|
-
f"""
|
80
|
-
model_id: {model_id}
|
81
|
-
{kwargs_text}
|
82
|
-
"""
|
83
|
-
)
|
84
|
-
|
85
|
-
messages_table = Table(title="Messages", show_lines=True)
|
86
|
-
messages_table.add_column("Role", justify="left")
|
87
|
-
messages_table.add_column("Content", justify="left") # style="green"
|
88
|
-
for message in messages:
|
89
|
-
messages_table.add_row(message["role"], message["content"])
|
90
|
-
|
91
|
-
call_panel = Panel(
|
92
|
-
Group(params_text, messages_table), title="complete_simple call"
|
93
|
-
)
|
94
|
-
console.print(call_panel)
|
95
|
-
|
96
|
-
response = chat_completion_client.chat.completions.create(
|
97
|
-
model=model_id, messages=messages, **kwargs
|
98
|
-
)
|
99
|
-
response = response.choices[0].message.content
|
100
|
-
|
101
|
-
if console is not None:
|
102
|
-
console.print(Panel(response, title="Response"))
|
103
|
-
|
104
|
-
return response
|
105
|
-
|
106
|
-
|
107
|
-
def evaluate_tool_call(tool_map: dict, tool_call: ChatCompletionMessageToolCall) -> Any:
|
108
|
-
|
109
|
-
function_name = tool_call.function.name
|
110
|
-
# TODO validate the arguments?
|
111
|
-
function_args = json.loads(tool_call.function.arguments)
|
112
|
-
|
113
|
-
log.info(f"Evaluating tool call: {function_name} with args {function_args}")
|
114
|
-
|
115
|
-
function_response = tool_map[function_name](**function_args)
|
116
|
-
|
117
|
-
log.info(f" Response: {function_response}")
|
118
|
-
|
119
|
-
return function_response
|
120
|
-
|
121
|
-
|
122
|
-
def tool_response_message(
|
123
|
-
tool_call: ChatCompletionMessageToolCall, tool_result: Any
|
124
|
-
) -> dict:
|
125
|
-
|
126
|
-
return {
|
127
|
-
"role": "tool",
|
128
|
-
"tool_call_id": tool_call.id,
|
129
|
-
"name": tool_call.function.name,
|
130
|
-
"content": json.dumps(tool_result),
|
131
|
-
}
|
132
|
-
|
133
|
-
|
134
|
-
def evaluate_tool_calls(tool_call_message, tool_map: dict) -> list[dict]:
|
135
|
-
|
136
|
-
tool_call: ChatCompletionMessageToolCall
|
137
|
-
|
138
|
-
log.info("Evaluating tool calls")
|
139
|
-
|
140
|
-
new_messages: list[dict] = []
|
141
|
-
|
142
|
-
for tool_call in tool_call_message.tool_calls:
|
143
|
-
function_response = evaluate_tool_call(tool_map, tool_call)
|
144
|
-
new_messages.append(tool_response_message(tool_call, function_response))
|
145
|
-
|
146
|
-
log.info("Tool calls evaluated")
|
147
|
-
|
148
|
-
return new_messages
|
149
|
-
|
150
|
-
|
151
|
-
def complete_for_tool_applications(
|
152
|
-
chat_completion_client: AISuiteClient,
|
153
|
-
model_id: str,
|
154
|
-
messages: list,
|
155
|
-
tool_desc_list: list,
|
156
|
-
temperature: float,
|
157
|
-
console: Optional[Console] = None,
|
158
|
-
):
|
159
|
-
|
160
|
-
if console is not None:
|
161
|
-
panel = complete_with_tools_panel(
|
162
|
-
"complete for tool applications",
|
163
|
-
model_id,
|
164
|
-
tool_desc_list,
|
165
|
-
messages,
|
166
|
-
temperature,
|
167
|
-
)
|
168
|
-
console.print(panel)
|
169
|
-
|
170
|
-
response = chat_completion_client.chat.completions.create(
|
171
|
-
model=model_id,
|
172
|
-
messages=messages,
|
173
|
-
temperature=temperature,
|
174
|
-
tools=tool_desc_list, # tool_choice="auto",
|
175
|
-
)
|
176
|
-
|
177
|
-
return response
|
178
|
-
|
179
|
-
|
180
|
-
def complete_with_tool_results(
|
181
|
-
chat_completion_client: AISuiteClient,
|
182
|
-
model_id: str,
|
183
|
-
messages: list,
|
184
|
-
tool_call_message: dict,
|
185
|
-
tool_evaluation_messages: list[dict],
|
186
|
-
tool_desc_list: list,
|
187
|
-
temperature: float,
|
188
|
-
console: Optional[Console] = None,
|
189
|
-
):
|
190
|
-
|
191
|
-
messages.append(tool_call_message)
|
192
|
-
messages.extend(tool_evaluation_messages)
|
193
|
-
|
194
|
-
if console is not None:
|
195
|
-
panel = complete_with_tools_panel(
|
196
|
-
"complete call with tool results",
|
197
|
-
model_id,
|
198
|
-
tool_desc_list,
|
199
|
-
messages,
|
200
|
-
temperature,
|
201
|
-
)
|
202
|
-
console.print(panel)
|
203
|
-
|
204
|
-
response = chat_completion_client.chat.completions.create(
|
205
|
-
model=model_id,
|
206
|
-
messages=messages,
|
207
|
-
)
|
208
|
-
|
209
|
-
return response.choices[0].message.content
|
@@ -1,64 +0,0 @@
|
|
1
|
-
from rich.console import Group
|
2
|
-
from rich.table import Table
|
3
|
-
from rich.text import Text
|
4
|
-
from rich.panel import Panel
|
5
|
-
|
6
|
-
from .chat import messages_table
|
7
|
-
|
8
|
-
|
9
|
-
def parameters_table(parameters: list[dict]) -> Table:
|
10
|
-
|
11
|
-
table = Table(title="Parameters", show_lines=False, box=None)
|
12
|
-
table.add_column("name", justify="right")
|
13
|
-
table.add_column("type", justify="left")
|
14
|
-
table.add_column("description", justify="left")
|
15
|
-
|
16
|
-
for name, props in parameters["properties"].items():
|
17
|
-
table.add_row(name, props["type"], props["description"])
|
18
|
-
|
19
|
-
# TODO denote required params
|
20
|
-
|
21
|
-
return table
|
22
|
-
|
23
|
-
|
24
|
-
def function_description_panel(fd: dict) -> Panel:
|
25
|
-
|
26
|
-
fn = fd["function"]
|
27
|
-
|
28
|
-
text = Text(f"{fd['type']} {fn['name']}: {fn['description']}\n")
|
29
|
-
|
30
|
-
pt = parameters_table(fn["parameters"])
|
31
|
-
|
32
|
-
panel = Panel(Group(text, pt))
|
33
|
-
|
34
|
-
return panel
|
35
|
-
|
36
|
-
|
37
|
-
def function_descriptions_panel(function_descriptions: list[dict]) -> Panel:
|
38
|
-
|
39
|
-
sub_panels = [function_description_panel(fd) for fd in function_descriptions]
|
40
|
-
|
41
|
-
panel = Panel(Group(*sub_panels), title="Function Descriptions")
|
42
|
-
|
43
|
-
return panel
|
44
|
-
|
45
|
-
|
46
|
-
def complete_with_tools_panel(
|
47
|
-
title: str, model_id: str, tool_desc_list: list, messages: list, temperature: float
|
48
|
-
) -> Panel:
|
49
|
-
|
50
|
-
text = Text(
|
51
|
-
f"""
|
52
|
-
model_id: {model_id}
|
53
|
-
temperature: {temperature}
|
54
|
-
"""
|
55
|
-
)
|
56
|
-
|
57
|
-
panel = Panel(
|
58
|
-
Group(
|
59
|
-
text, function_descriptions_panel(tool_desc_list), messages_table(messages)
|
60
|
-
),
|
61
|
-
title=title,
|
62
|
-
)
|
63
|
-
|
64
|
-
return panel
|
proscenium/verbs/display.py
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
from rich.text import Text
|
3
|
-
|
4
|
-
log = logging.getLogger(__name__)
|
5
|
-
|
6
|
-
|
7
|
-
def header() -> Text:
|
8
|
-
text = Text(
|
9
|
-
"""[bold]Proscenium[/bold] :performing_arts:
|
10
|
-
[bold]The AI Alliance[/bold]"""
|
11
|
-
)
|
12
|
-
# TODO version, timestamp, ...
|
13
|
-
return text
|
proscenium/verbs/invoke.py
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
from gofannon.base import BaseTool
|
3
|
-
|
4
|
-
log = logging.getLogger(__name__)
|
5
|
-
|
6
|
-
|
7
|
-
def process_tools(tools: list[BaseTool]) -> tuple[dict, list]:
|
8
|
-
applied_tools = [F() for F in tools]
|
9
|
-
tool_map = {f.name: f.fn for f in applied_tools}
|
10
|
-
tool_desc_list = [f.definition for f in applied_tools]
|
11
|
-
return tool_map, tool_desc_list
|
proscenium/verbs/remember.py
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
|
3
|
-
log = logging.getLogger(__name__)
|
4
|
-
|
5
|
-
|
6
|
-
def format_chat_history(chat_history) -> str:
|
7
|
-
delimiter = "-" * 80 + "\n"
|
8
|
-
return delimiter.join(
|
9
|
-
[
|
10
|
-
f"{msg['sender']} to {msg['receiver']}:\n\n{msg['content']}\n\n"
|
11
|
-
for msg in chat_history
|
12
|
-
]
|
13
|
-
)
|
@@ -1,26 +0,0 @@
|
|
1
|
-
proscenium/__init__.py,sha256=nDWNd6_TSf4vDQuHVBoAf4QfZCB3ZUFQ0M7XvifNJ-g,78
|
2
|
-
proscenium/admin/__init__.py,sha256=31XUp83v7oCEXTeJb-GgnIitfs2EWovr3QJOewZ0zSg,1026
|
3
|
-
proscenium/bin/__init__.py,sha256=ThVsDG6BmnZ86gYaZLGMDcNmR6fVwBLJG3k_JawfzOY,1160
|
4
|
-
proscenium/bin/bot.py,sha256=cuHj2-ldPXGRf75Ts_J_y4WfDgTB49iN3sNmnoKKFus,1713
|
5
|
-
proscenium/core/__init__.py,sha256=aSUqPMn2LjZ0C_l9Tx6yqqlfCzM7oSljZxHosJyjlLU,4335
|
6
|
-
proscenium/interfaces/__init__.py,sha256=nDWNd6_TSf4vDQuHVBoAf4QfZCB3ZUFQ0M7XvifNJ-g,78
|
7
|
-
proscenium/interfaces/slack.py,sha256=zfj1D4O6ucVdw6HFnBIMGAbZUb5XK17c-57une42C48,10205
|
8
|
-
proscenium/patterns/__init__.py,sha256=nDWNd6_TSf4vDQuHVBoAf4QfZCB3ZUFQ0M7XvifNJ-g,78
|
9
|
-
proscenium/patterns/graph_rag.py,sha256=1HH1xdlAA6ypvYdP4dWFm-KXrGPUmm0T4qIdAU8mgvE,1763
|
10
|
-
proscenium/patterns/rag.py,sha256=iNPL7i8zfhEGIZAI7FjAs5yKgN1iV_E-PcJiQFrm7lE,2310
|
11
|
-
proscenium/patterns/tools.py,sha256=f2CD6f7CYiSs0Tm1Ff1sOL5Ti6DqJ5HQvMI7NmIgqNs,1740
|
12
|
-
proscenium/util/__init__.py,sha256=FC1hjA37VvmVpF9-OlYNp9TjArH6etr6KiAvF9t_6lI,679
|
13
|
-
proscenium/verbs/__init__.py,sha256=nDWNd6_TSf4vDQuHVBoAf4QfZCB3ZUFQ0M7XvifNJ-g,78
|
14
|
-
proscenium/verbs/complete.py,sha256=oRvIt6NR9yhzEHpT1BRKAmf05hVXI91v83A-7OSo-zs,5147
|
15
|
-
proscenium/verbs/display.py,sha256=hHFmktyJtjYLi4I1-8HUfmsuoMTIxc6JFfczASBsCbI,260
|
16
|
-
proscenium/verbs/invoke.py,sha256=-Bk7Pp0EEwRTS0MJUlViZeUNo8wxnDKJj5q78KU4CdM,339
|
17
|
-
proscenium/verbs/remember.py,sha256=Hh9BDRAYf7MGeMD4MzU73p6Q28KrSiLWPx4GjTW1amQ,296
|
18
|
-
proscenium/verbs/display/__init__.py,sha256=GXuvaMld8tzfJGngHdwVT-YLnuRmW2G0pMdti9Vj53s,238
|
19
|
-
proscenium/verbs/display/chat.py,sha256=2THBUdhG3cIIVZOnJ_AMYL4nWXKFG2cuSkX6wkm48yQ,1148
|
20
|
-
proscenium/verbs/display/tools.py,sha256=eR5g-r7MGKFZY0qg-ndkW3p0mfbupV0UaAUFqJPfnNM,1491
|
21
|
-
proscenium-0.0.13.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
22
|
-
proscenium-0.0.13.dist-info/METADATA,sha256=50Uqw56v2u2hdl8onbJWYfXSqPMgSdK_0Y6djW68OrA,2229
|
23
|
-
proscenium-0.0.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
24
|
-
proscenium-0.0.13.dist-info/entry_points.txt,sha256=bbrDWv4WKIx9UROGXcyH0eo40F8SNpDQKvXxoE8BTHI,58
|
25
|
-
proscenium-0.0.13.dist-info/top_level.txt,sha256=aiTgQy73e21wnSSxM5iICXmXT3zldN8cFKeXpvJ5Xx4,11
|
26
|
-
proscenium-0.0.13.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|