proscenium 0.0.11__tar.gz → 0.0.12__tar.gz
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-0.0.11/src/proscenium.egg-info → proscenium-0.0.12}/PKG-INFO +2 -4
- {proscenium-0.0.11 → proscenium-0.0.12}/README.md +0 -2
- {proscenium-0.0.11 → proscenium-0.0.12}/pyproject.toml +2 -2
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/admin/__init__.py +6 -3
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/bin/bot.py +17 -3
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/interfaces/slack.py +73 -106
- {proscenium-0.0.11 → proscenium-0.0.12/src/proscenium.egg-info}/PKG-INFO +2 -4
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium.egg-info/SOURCES.txt +2 -1
- proscenium-0.0.12/tests/test_slack_echo.py +61 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/LICENSE +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/setup.cfg +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/__init__.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/bin/__init__.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/core/__init__.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/interfaces/__init__.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/patterns/__init__.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/patterns/graph_rag.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/patterns/rag.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/patterns/tools.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/util/__init__.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/verbs/__init__.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/verbs/complete.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/verbs/display/__init__.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/verbs/display/chat.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/verbs/display/tools.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/verbs/display.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/verbs/invoke.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium/verbs/remember.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium.egg-info/dependency_links.txt +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium.egg-info/entry_points.txt +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium.egg-info/requires.txt +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/src/proscenium.egg-info/top_level.txt +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/tests/test_demo_typer_help.py +0 -0
- {proscenium-0.0.11 → proscenium-0.0.12}/tests/test_display.py +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: proscenium
|
3
|
-
Version: 0.0.
|
4
|
-
Summary:
|
3
|
+
Version: 0.0.12
|
4
|
+
Summary: Declare AI Agent Scenes
|
5
5
|
Author-email: Adam Pingel <oss@pingel.org>
|
6
6
|
License-Expression: Apache-2.0
|
7
7
|
Requires-Python: >=3.11
|
@@ -33,8 +33,6 @@ Dynamic: license-file
|
|
33
33
|
|
34
34
|
Proscenium is a small, experimental library of composable glue that allows for succinct construction of enterprise AI applications. It was started in February 2025 and is still in early development.
|
35
35
|
|
36
|
-
Currently, proscenium development prioritizes support for domains where the creation and use of structured data is critical.
|
37
|
-
|
38
36
|
See the [website](https://the-ai-alliance.github.io/proscenium/) for quickstart info, goals, and other links.
|
39
37
|
|
40
38
|
To find the Proscenium community, see the [discussions](https://github.com/The-AI-Alliance/proscenium/discussions)
|
@@ -8,8 +8,6 @@
|
|
8
8
|
|
9
9
|
Proscenium is a small, experimental library of composable glue that allows for succinct construction of enterprise AI applications. It was started in February 2025 and is still in early development.
|
10
10
|
|
11
|
-
Currently, proscenium development prioritizes support for domains where the creation and use of structured data is critical.
|
12
|
-
|
13
11
|
See the [website](https://the-ai-alliance.github.io/proscenium/) for quickstart info, goals, and other links.
|
14
12
|
|
15
13
|
To find the Proscenium community, see the [discussions](https://github.com/The-AI-Alliance/proscenium/discussions)
|
@@ -7,8 +7,8 @@ build-backend = "setuptools.build_meta"
|
|
7
7
|
|
8
8
|
[project]
|
9
9
|
name = "proscenium"
|
10
|
-
version = "0.0.
|
11
|
-
description = "
|
10
|
+
version = "0.0.12"
|
11
|
+
description = "Declare AI Agent Scenes"
|
12
12
|
authors = [{ name = "Adam Pingel", email = "oss@pingel.org" }]
|
13
13
|
license = "Apache-2.0"
|
14
14
|
readme = "README.md"
|
@@ -24,9 +24,12 @@ def props(console: Optional[Console]) -> List[Prop]:
|
|
24
24
|
|
25
25
|
class Admin(Character):
|
26
26
|
|
27
|
-
def __init__(self,
|
28
|
-
super().__init__(
|
29
|
-
self.
|
27
|
+
def __init__(self, channel_id: str, channel: str):
|
28
|
+
super().__init__(channel_id)
|
29
|
+
self.channel_id = channel_id
|
30
|
+
self.channel = channel
|
31
|
+
|
32
|
+
log.info("Admin handler started %s %s.", self.channel, self.channel_id)
|
30
33
|
|
31
34
|
def wants_to_handle(self, channel_id: str, speaker_id: str, utterance: str) -> bool:
|
32
35
|
return False
|
@@ -1,15 +1,16 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
|
3
|
+
import typer
|
4
|
+
import time
|
3
5
|
import os
|
4
6
|
import sys
|
5
7
|
import logging
|
6
|
-
import typer
|
7
8
|
from pathlib import Path
|
8
9
|
from rich.console import Console
|
9
10
|
|
10
11
|
from proscenium.verbs.display import header
|
11
12
|
from proscenium.bin import production_from_config
|
12
|
-
from proscenium.interfaces.slack import
|
13
|
+
from proscenium.interfaces.slack import SlackProductionProcessor
|
13
14
|
|
14
15
|
logging.basicConfig(
|
15
16
|
stream=sys.stdout,
|
@@ -52,7 +53,20 @@ def start(
|
|
52
53
|
production.prepare_props()
|
53
54
|
console.print("Props are up-to-date.")
|
54
55
|
|
55
|
-
|
56
|
+
slack_admin_channel = config.get("slack", {}).get("admin_channel", None)
|
57
|
+
slack_production_processor = SlackProductionProcessor(
|
58
|
+
production,
|
59
|
+
slack_admin_channel,
|
60
|
+
console,
|
61
|
+
)
|
62
|
+
|
63
|
+
try:
|
64
|
+
while True:
|
65
|
+
time.sleep(1)
|
66
|
+
except KeyboardInterrupt:
|
67
|
+
console.print("Exiting...")
|
68
|
+
|
69
|
+
slack_production_processor.shutdown()
|
56
70
|
|
57
71
|
|
58
72
|
if __name__ == "__main__":
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from typing import Callable
|
2
2
|
from typing import Generator
|
3
|
+
from typing import Optional
|
3
4
|
|
4
|
-
import time
|
5
5
|
import logging
|
6
6
|
import os
|
7
7
|
from rich.console import Console
|
@@ -11,7 +11,6 @@ from slack_sdk.web import WebClient
|
|
11
11
|
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
|
-
from slack_sdk.socket_mode.listeners import SocketModeRequestListener
|
15
14
|
|
16
15
|
from proscenium.core import Production
|
17
16
|
from proscenium.core import Character
|
@@ -187,7 +186,7 @@ def channel_table(channels_by_id) -> Table:
|
|
187
186
|
return channel_table
|
188
187
|
|
189
188
|
|
190
|
-
def bot_user_id(socket_mode_client: SocketModeClient, console: Console):
|
189
|
+
def bot_user_id(socket_mode_client: SocketModeClient, console: Console) -> str:
|
191
190
|
|
192
191
|
auth_response = socket_mode_client.web_client.auth_test()
|
193
192
|
|
@@ -239,113 +238,81 @@ Curtain up.
|
|
239
238
|
)
|
240
239
|
|
241
240
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
user_id = bot_user_id(socket_mode_client, console)
|
294
|
-
console.print()
|
295
|
-
|
296
|
-
channels_by_id, channel_name_to_id = channel_maps(socket_mode_client)
|
297
|
-
console.print(channel_table(channels_by_id))
|
298
|
-
console.print()
|
299
|
-
|
300
|
-
slack_admin_channel = config.get("slack", {}).get("admin_channel", None)
|
301
|
-
|
302
|
-
if slack_admin_channel is None:
|
303
|
-
raise ValueError(
|
304
|
-
"slack.admin_channel is not set. "
|
305
|
-
"Please set it to the channel name of the Proscenium admin channel."
|
306
|
-
)
|
307
|
-
slack_admin_channel_id = channel_name_to_id.get(slack_admin_channel, None)
|
308
|
-
if slack_admin_channel_id is None:
|
309
|
-
raise ValueError(
|
310
|
-
f"Admin channel {slack_admin_channel} not found in subscribed channels."
|
241
|
+
class SlackProductionProcessor:
|
242
|
+
|
243
|
+
def __init__(
|
244
|
+
self,
|
245
|
+
production: Production,
|
246
|
+
slack_admin_channel: str,
|
247
|
+
console: Optional[Console] = None,
|
248
|
+
event_log: Optional[list[tuple[str, str]]] = None,
|
249
|
+
):
|
250
|
+
self.production = production
|
251
|
+
self.console = console
|
252
|
+
self.event_log = event_log
|
253
|
+
|
254
|
+
slack_app_token, slack_bot_token = get_slack_auth()
|
255
|
+
|
256
|
+
self.socket_mode_client = connect(slack_app_token, slack_bot_token)
|
257
|
+
|
258
|
+
user_id = bot_user_id(self.socket_mode_client, console)
|
259
|
+
console.print()
|
260
|
+
|
261
|
+
channels_by_id, channel_name_to_id = channel_maps(self.socket_mode_client)
|
262
|
+
console.print(channel_table(channels_by_id))
|
263
|
+
console.print()
|
264
|
+
|
265
|
+
if slack_admin_channel is None:
|
266
|
+
raise ValueError(
|
267
|
+
"slack.admin_channel is not set. "
|
268
|
+
"Please set it to the channel name of the Proscenium admin channel."
|
269
|
+
)
|
270
|
+
slack_admin_channel_id = channel_name_to_id.get(slack_admin_channel, None)
|
271
|
+
if slack_admin_channel_id is None:
|
272
|
+
raise ValueError(
|
273
|
+
f"Admin channel {slack_admin_channel} not found in subscribed channels."
|
274
|
+
)
|
275
|
+
|
276
|
+
self.admin = Admin(slack_admin_channel_id, slack_admin_channel)
|
277
|
+
|
278
|
+
log.info("Places, please!")
|
279
|
+
channel_id_to_character = production.places(channel_name_to_id)
|
280
|
+
channel_id_to_character[slack_admin_channel_id] = self.admin
|
281
|
+
|
282
|
+
console.print(places_table(channel_id_to_character, channels_by_id))
|
283
|
+
console.print()
|
284
|
+
|
285
|
+
self.slack_listener = make_slack_listener(
|
286
|
+
user_id,
|
287
|
+
slack_admin_channel_id,
|
288
|
+
channels_by_id,
|
289
|
+
channel_id_to_character,
|
290
|
+
console,
|
311
291
|
)
|
312
292
|
|
313
|
-
|
314
|
-
log.info(
|
315
|
-
"Admin handler started %s %s.", slack_admin_channel, slack_admin_channel_id
|
316
|
-
)
|
317
|
-
|
318
|
-
log.info("Places, please!")
|
319
|
-
channel_id_to_character = production.places(channel_name_to_id)
|
320
|
-
channel_id_to_character[slack_admin_channel_id] = admin
|
293
|
+
send_curtain_up(self.socket_mode_client, production, slack_admin_channel_id)
|
321
294
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
user_id,
|
327
|
-
slack_admin_channel_id,
|
328
|
-
channels_by_id,
|
329
|
-
channel_id_to_character,
|
330
|
-
console,
|
331
|
-
)
|
295
|
+
console.print("Starting the show. Listening for events...")
|
296
|
+
self.socket_mode_client.socket_mode_request_listeners.append(
|
297
|
+
self.slack_listener
|
298
|
+
)
|
332
299
|
|
333
|
-
|
300
|
+
def shutdown(
|
301
|
+
self,
|
302
|
+
):
|
303
|
+
self.socket_mode_client.web_client.chat_postMessage(
|
304
|
+
channel=self.admin.channel_id,
|
305
|
+
text="""Curtain down. We hope you enjoyed the show!""",
|
306
|
+
)
|
334
307
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
)
|
308
|
+
self.socket_mode_client.socket_mode_request_listeners.remove(
|
309
|
+
self.slack_listener
|
310
|
+
)
|
311
|
+
self.socket_mode_client.disconnect()
|
312
|
+
if self.console is not None:
|
313
|
+
self.console.print("Disconnected from Slack.")
|
342
314
|
|
343
|
-
|
315
|
+
self.production.curtain()
|
344
316
|
|
345
|
-
|
346
|
-
|
347
|
-
slack_listener,
|
348
|
-
user_id,
|
349
|
-
production,
|
350
|
-
console,
|
351
|
-
)
|
317
|
+
if self.console is not None:
|
318
|
+
self.console.print("Handlers stopped.")
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: proscenium
|
3
|
-
Version: 0.0.
|
4
|
-
Summary:
|
3
|
+
Version: 0.0.12
|
4
|
+
Summary: Declare AI Agent Scenes
|
5
5
|
Author-email: Adam Pingel <oss@pingel.org>
|
6
6
|
License-Expression: Apache-2.0
|
7
7
|
Requires-Python: >=3.11
|
@@ -33,8 +33,6 @@ Dynamic: license-file
|
|
33
33
|
|
34
34
|
Proscenium is a small, experimental library of composable glue that allows for succinct construction of enterprise AI applications. It was started in February 2025 and is still in early development.
|
35
35
|
|
36
|
-
Currently, proscenium development prioritizes support for domains where the creation and use of structured data is critical.
|
37
|
-
|
38
36
|
See the [website](https://the-ai-alliance.github.io/proscenium/) for quickstart info, goals, and other links.
|
39
37
|
|
40
38
|
To find the Proscenium community, see the [discussions](https://github.com/The-AI-Alliance/proscenium/discussions)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
import logging
|
4
|
+
import time
|
5
|
+
import pytest
|
6
|
+
from pathlib import Path
|
7
|
+
from rich.console import Console
|
8
|
+
|
9
|
+
from proscenium.bin import production_from_config
|
10
|
+
from proscenium.interfaces.slack import SlackProductionProcessor
|
11
|
+
|
12
|
+
logging.basicConfig(
|
13
|
+
stream=sys.stdout,
|
14
|
+
format="%(asctime)s %(levelname)-8s %(name)s: %(message)s",
|
15
|
+
level=logging.WARNING,
|
16
|
+
)
|
17
|
+
|
18
|
+
log = logging.getLogger(__name__)
|
19
|
+
log.setLevel(logging.INFO)
|
20
|
+
logging.getLogger("proscenium").setLevel(logging.INFO)
|
21
|
+
logging.getLogger("demo").setLevel(logging.INFO)
|
22
|
+
|
23
|
+
console = Console()
|
24
|
+
|
25
|
+
config_file = Path("tests/demo/tests.yml")
|
26
|
+
|
27
|
+
|
28
|
+
@pytest.fixture
|
29
|
+
def setup_slack():
|
30
|
+
|
31
|
+
print("\nSetting up Slack Processor...")
|
32
|
+
|
33
|
+
production, config = production_from_config(config_file, os.environ.get, console)
|
34
|
+
|
35
|
+
console.print("Preparing props...")
|
36
|
+
production.prepare_props()
|
37
|
+
console.print("Props are up-to-date.")
|
38
|
+
|
39
|
+
slack_admin_channel = config.get("slack", {}).get("admin_channel", None)
|
40
|
+
slack_production_processor = SlackProductionProcessor(
|
41
|
+
production,
|
42
|
+
slack_admin_channel,
|
43
|
+
console,
|
44
|
+
)
|
45
|
+
|
46
|
+
time.sleep(2)
|
47
|
+
|
48
|
+
yield slack_production_processor
|
49
|
+
|
50
|
+
print("\nTearing down resources...")
|
51
|
+
slack_production_processor.shutdown()
|
52
|
+
|
53
|
+
|
54
|
+
# TODO check for startup messages
|
55
|
+
|
56
|
+
|
57
|
+
def test_admin(setup_slack):
|
58
|
+
assert setup_slack.admin.channel == "deus-ex-machina", "Admin channel is set"
|
59
|
+
|
60
|
+
|
61
|
+
# TODO send message as another user and check that it is echoed back
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|