proscenium 0.0.9__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.
Files changed (36) hide show
  1. proscenium-0.0.12/PKG-INFO +38 -0
  2. {proscenium-0.0.9 → proscenium-0.0.12}/README.md +0 -2
  3. proscenium-0.0.12/pyproject.toml +38 -0
  4. proscenium-0.0.12/setup.cfg +4 -0
  5. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/admin/__init__.py +6 -3
  6. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/bin/bot.py +17 -3
  7. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/interfaces/slack.py +73 -106
  8. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/patterns/rag.py +37 -3
  9. proscenium-0.0.12/src/proscenium.egg-info/PKG-INFO +38 -0
  10. proscenium-0.0.12/src/proscenium.egg-info/SOURCES.txt +32 -0
  11. proscenium-0.0.12/src/proscenium.egg-info/dependency_links.txt +1 -0
  12. proscenium-0.0.12/src/proscenium.egg-info/entry_points.txt +2 -0
  13. proscenium-0.0.12/src/proscenium.egg-info/requires.txt +15 -0
  14. proscenium-0.0.12/src/proscenium.egg-info/top_level.txt +1 -0
  15. proscenium-0.0.12/tests/test_demo_typer_help.py +32 -0
  16. proscenium-0.0.12/tests/test_display.py +7 -0
  17. proscenium-0.0.12/tests/test_slack_echo.py +61 -0
  18. proscenium-0.0.9/PKG-INFO +0 -49
  19. proscenium-0.0.9/pyproject.toml +0 -38
  20. {proscenium-0.0.9 → proscenium-0.0.12}/LICENSE +0 -0
  21. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/__init__.py +0 -0
  22. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/bin/__init__.py +0 -0
  23. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/core/__init__.py +0 -0
  24. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/interfaces/__init__.py +0 -0
  25. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/patterns/__init__.py +0 -0
  26. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/patterns/graph_rag.py +0 -0
  27. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/patterns/tools.py +0 -0
  28. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/util/__init__.py +0 -0
  29. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/verbs/__init__.py +0 -0
  30. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/verbs/complete.py +0 -0
  31. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/verbs/display/__init__.py +0 -0
  32. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/verbs/display/chat.py +0 -0
  33. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/verbs/display/tools.py +0 -0
  34. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/verbs/display.py +0 -0
  35. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/verbs/invoke.py +0 -0
  36. {proscenium-0.0.9 → proscenium-0.0.12/src}/proscenium/verbs/remember.py +0 -0
@@ -0,0 +1,38 @@
1
+ Metadata-Version: 2.4
2
+ Name: proscenium
3
+ Version: 0.0.12
4
+ Summary: Declare AI Agent Scenes
5
+ Author-email: Adam Pingel <oss@pingel.org>
6
+ License-Expression: Apache-2.0
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: aisuite>=0.1.10
11
+ Requires-Dist: docstring_parser>=0.16
12
+ Requires-Dist: pydantic>=2.10.6
13
+ Requires-Dist: rich>=13.9.4
14
+ Requires-Dist: slack_sdk>=3.35.0
15
+ Provides-Extra: test
16
+ Requires-Dist: pytest<9,>=8; extra == "test"
17
+ Requires-Dist: pytest-cov<6,>=5; extra == "test"
18
+ Requires-Dist: typer>=0.15.2; extra == "test"
19
+ Requires-Dist: click>=8.2.0; extra == "test"
20
+ Requires-Dist: pytest>=8.3.5; extra == "test"
21
+ Requires-Dist: neo4j>=5.28.1; extra == "test"
22
+ Requires-Dist: gofannon>=0.25.13; extra == "test"
23
+ Requires-Dist: lapidarist>=0.0.2; extra == "test"
24
+ Dynamic: license-file
25
+
26
+ # Proscenium
27
+
28
+ [![CI](https://github.com/The-AI-Alliance/proscenium/actions/workflows/pytest.yml/badge.svg)](https://github.com/The-AI-Alliance/proscenium/actions/workflows/pytest.yml)
29
+ [![PyPI](https://img.shields.io/pypi/v/proscenium)](https://pypi.org/project/proscenium/)
30
+ [![License](https://img.shields.io/github/license/The-AI-Alliance/proscenium)](https://github.com/The-AI-Alliance/proscenium/tree/main?tab=Apache-2.0-1-ov-file#readme)
31
+ [![Issues](https://img.shields.io/github/issues/The-AI-Alliance/proscenium)](https://github.com/The-AI-Alliance/proscenium/issues)
32
+ [![GitHub stars](https://img.shields.io/github/stars/The-AI-Alliance/proscenium?style=social)](https://github.com/The-AI-Alliance/proscenium/stargazers)
33
+
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
+
36
+ See the [website](https://the-ai-alliance.github.io/proscenium/) for quickstart info, goals, and other links.
37
+
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)
@@ -0,0 +1,38 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools>=68",
4
+ "wheel"
5
+ ]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [project]
9
+ name = "proscenium"
10
+ version = "0.0.12"
11
+ description = "Declare AI Agent Scenes"
12
+ authors = [{ name = "Adam Pingel", email = "oss@pingel.org" }]
13
+ license = "Apache-2.0"
14
+ readme = "README.md"
15
+ requires-python = ">=3.11"
16
+
17
+ dependencies = [
18
+ "aisuite>=0.1.10",
19
+ "docstring_parser>=0.16",
20
+ "pydantic>=2.10.6",
21
+ "rich>=13.9.4",
22
+ "slack_sdk>=3.35.0"
23
+ ]
24
+
25
+ [project.optional-dependencies]
26
+ test = [
27
+ "pytest>=8,<9",
28
+ "pytest-cov>=5,<6",
29
+ "typer>=0.15.2",
30
+ "click>=8.2.0",
31
+ "pytest>=8.3.5",
32
+ "neo4j>=5.28.1",
33
+ "gofannon>=0.25.13",
34
+ "lapidarist>=0.0.2"
35
+ ]
36
+
37
+ [project.scripts]
38
+ proscenium-bot = "proscenium.bin.bot:app"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -24,9 +24,12 @@ def props(console: Optional[Console]) -> List[Prop]:
24
24
 
25
25
  class Admin(Character):
26
26
 
27
- def __init__(self, admin_channel_id: str):
28
- super().__init__(admin_channel_id)
29
- self.admin_channel_id = admin_channel_id
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 slack_main
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
- slack_main(production, config, console)
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
- def listen(
243
- socket_mode_client: SocketModeClient,
244
- slack_listener: SocketModeRequestListener,
245
- user_id: str,
246
- console: Console,
247
- ):
248
- socket_mode_client.socket_mode_request_listeners.append(slack_listener)
249
-
250
- try:
251
- while True:
252
- time.sleep(1)
253
- except KeyboardInterrupt:
254
- console.print("Exiting...")
255
-
256
-
257
- def send_curtain_down(
258
- socket_mode_client: SocketModeClient, slack_admin_channel_id: str
259
- ) -> None:
260
- socket_mode_client.web_client.chat_postMessage(
261
- channel=slack_admin_channel_id,
262
- text="""Curtain down. We hope you enjoyed the show!""",
263
- )
264
-
265
-
266
- def shutdown(
267
- socket_mode_client: SocketModeClient,
268
- slack_listener: SocketModeRequestListener,
269
- user_id: str,
270
- production: Production,
271
- console: Console,
272
- ):
273
-
274
- socket_mode_client.socket_mode_request_listeners.remove(slack_listener)
275
- socket_mode_client.disconnect()
276
- console.print("Disconnected from Slack.")
277
-
278
- production.curtain()
279
-
280
- console.print("Handlers stopped.")
281
-
282
-
283
- def slack_main(
284
- production: Production,
285
- config: dict,
286
- console: Console,
287
- ) -> None:
288
-
289
- slack_app_token, slack_bot_token = get_slack_auth()
290
-
291
- socket_mode_client = connect(slack_app_token, slack_bot_token)
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
- admin = Admin(slack_admin_channel_id)
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
- console.print(places_table(channel_id_to_character, channels_by_id))
323
- console.print()
324
-
325
- slack_listener = make_slack_listener(
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
- send_curtain_up(socket_mode_client, production, slack_admin_channel_id)
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
- console.print("Starting the show. Listening for events...")
336
- listen(
337
- socket_mode_client,
338
- slack_listener,
339
- user_id,
340
- console,
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
- send_curtain_down(socket_mode_client, slack_admin_channel_id)
315
+ self.production.curtain()
344
316
 
345
- shutdown(
346
- socket_mode_client,
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,12 +1,11 @@
1
1
  from typing import List, Dict
2
+
2
3
  import logging
4
+ from rich.table import Table
3
5
 
4
6
  from pymilvus import MilvusClient
5
7
  from pymilvus import model
6
8
 
7
- from lapidarist.verbs.display.milvus import chunk_hits_table
8
- from lapidarist.verbs.vector_database import closest_chunks
9
-
10
9
  from proscenium.verbs.complete import complete_simple
11
10
 
12
11
  log = logging.getLogger(__name__)
@@ -38,6 +37,41 @@ def rag_prompt(chunks: List[Dict], query: str) -> str:
38
37
  return rag_prompt_template.format(context=context, query=query)
39
38
 
40
39
 
40
+ def closest_chunks(
41
+ client: MilvusClient,
42
+ embedding_fn: model.dense.SentenceTransformerEmbeddingFunction,
43
+ query: str,
44
+ collection_name: str,
45
+ k: int = 4,
46
+ ) -> List[Dict]:
47
+
48
+ client.load_collection(collection_name)
49
+
50
+ result = client.search(
51
+ collection_name=collection_name,
52
+ data=embedding_fn.encode_queries([query]),
53
+ anns_field="vector",
54
+ search_params={"metric": "IP", "offset": 0},
55
+ output_fields=["text"],
56
+ limit=k,
57
+ )
58
+
59
+ hits = result[0]
60
+
61
+ return hits
62
+
63
+
64
+ def chunk_hits_table(chunks: list[dict]) -> Table:
65
+
66
+ table = Table(title="Closest Chunks", show_lines=True)
67
+ table.add_column("id", justify="right")
68
+ table.add_column("distance")
69
+ table.add_column("entity.text", justify="right")
70
+ for chunk in chunks:
71
+ table.add_row(str(chunk["id"]), str(chunk["distance"]), chunk["entity"]["text"])
72
+ return table
73
+
74
+
41
75
  def answer_question(
42
76
  query: str,
43
77
  model_id: str,
@@ -0,0 +1,38 @@
1
+ Metadata-Version: 2.4
2
+ Name: proscenium
3
+ Version: 0.0.12
4
+ Summary: Declare AI Agent Scenes
5
+ Author-email: Adam Pingel <oss@pingel.org>
6
+ License-Expression: Apache-2.0
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: aisuite>=0.1.10
11
+ Requires-Dist: docstring_parser>=0.16
12
+ Requires-Dist: pydantic>=2.10.6
13
+ Requires-Dist: rich>=13.9.4
14
+ Requires-Dist: slack_sdk>=3.35.0
15
+ Provides-Extra: test
16
+ Requires-Dist: pytest<9,>=8; extra == "test"
17
+ Requires-Dist: pytest-cov<6,>=5; extra == "test"
18
+ Requires-Dist: typer>=0.15.2; extra == "test"
19
+ Requires-Dist: click>=8.2.0; extra == "test"
20
+ Requires-Dist: pytest>=8.3.5; extra == "test"
21
+ Requires-Dist: neo4j>=5.28.1; extra == "test"
22
+ Requires-Dist: gofannon>=0.25.13; extra == "test"
23
+ Requires-Dist: lapidarist>=0.0.2; extra == "test"
24
+ Dynamic: license-file
25
+
26
+ # Proscenium
27
+
28
+ [![CI](https://github.com/The-AI-Alliance/proscenium/actions/workflows/pytest.yml/badge.svg)](https://github.com/The-AI-Alliance/proscenium/actions/workflows/pytest.yml)
29
+ [![PyPI](https://img.shields.io/pypi/v/proscenium)](https://pypi.org/project/proscenium/)
30
+ [![License](https://img.shields.io/github/license/The-AI-Alliance/proscenium)](https://github.com/The-AI-Alliance/proscenium/tree/main?tab=Apache-2.0-1-ov-file#readme)
31
+ [![Issues](https://img.shields.io/github/issues/The-AI-Alliance/proscenium)](https://github.com/The-AI-Alliance/proscenium/issues)
32
+ [![GitHub stars](https://img.shields.io/github/stars/The-AI-Alliance/proscenium?style=social)](https://github.com/The-AI-Alliance/proscenium/stargazers)
33
+
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
+
36
+ See the [website](https://the-ai-alliance.github.io/proscenium/) for quickstart info, goals, and other links.
37
+
38
+ To find the Proscenium community, see the [discussions](https://github.com/The-AI-Alliance/proscenium/discussions)
@@ -0,0 +1,32 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/proscenium/__init__.py
5
+ src/proscenium.egg-info/PKG-INFO
6
+ src/proscenium.egg-info/SOURCES.txt
7
+ src/proscenium.egg-info/dependency_links.txt
8
+ src/proscenium.egg-info/entry_points.txt
9
+ src/proscenium.egg-info/requires.txt
10
+ src/proscenium.egg-info/top_level.txt
11
+ src/proscenium/admin/__init__.py
12
+ src/proscenium/bin/__init__.py
13
+ src/proscenium/bin/bot.py
14
+ src/proscenium/core/__init__.py
15
+ src/proscenium/interfaces/__init__.py
16
+ src/proscenium/interfaces/slack.py
17
+ src/proscenium/patterns/__init__.py
18
+ src/proscenium/patterns/graph_rag.py
19
+ src/proscenium/patterns/rag.py
20
+ src/proscenium/patterns/tools.py
21
+ src/proscenium/util/__init__.py
22
+ src/proscenium/verbs/__init__.py
23
+ src/proscenium/verbs/complete.py
24
+ src/proscenium/verbs/display.py
25
+ src/proscenium/verbs/invoke.py
26
+ src/proscenium/verbs/remember.py
27
+ src/proscenium/verbs/display/__init__.py
28
+ src/proscenium/verbs/display/chat.py
29
+ src/proscenium/verbs/display/tools.py
30
+ tests/test_demo_typer_help.py
31
+ tests/test_display.py
32
+ tests/test_slack_echo.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ proscenium-bot = proscenium.bin.bot:app
@@ -0,0 +1,15 @@
1
+ aisuite>=0.1.10
2
+ docstring_parser>=0.16
3
+ pydantic>=2.10.6
4
+ rich>=13.9.4
5
+ slack_sdk>=3.35.0
6
+
7
+ [test]
8
+ pytest<9,>=8
9
+ pytest-cov<6,>=5
10
+ typer>=0.15.2
11
+ click>=8.2.0
12
+ pytest>=8.3.5
13
+ neo4j>=5.28.1
14
+ gofannon>=0.25.13
15
+ lapidarist>=0.0.2
@@ -0,0 +1 @@
1
+ proscenium
@@ -0,0 +1,32 @@
1
+ import pytest
2
+
3
+ from click import Command
4
+ from typer.main import get_command
5
+
6
+ from demo.cli import app
7
+
8
+
9
+ def _check_help_on_command(command: Command):
10
+ """
11
+ Check that this command (and any subcommands) has a non-empty help string.
12
+ """
13
+
14
+ assert (
15
+ command.help is not None and command.help.strip() != ""
16
+ ), f"Command '{command.name}' is missing a help string"
17
+
18
+ # recurse into subcommands
19
+ if hasattr(command, "commands"):
20
+ for subcommand_name, subcommand in command.commands.items():
21
+ _check_help_on_command(subcommand)
22
+
23
+
24
+ @pytest.mark.parametrize("command_name", list(get_command(app).commands.keys()))
25
+ def test_command_has_help(command_name: str):
26
+ """
27
+ Test each top-level command in the demo typer app to ensure
28
+ it (and any subcommands) have help strings.
29
+ """
30
+ root_command: Command = get_command(app)
31
+ command = root_command.commands[command_name]
32
+ _check_help_on_command(command)
@@ -0,0 +1,7 @@
1
+ from rich import print
2
+ from proscenium.verbs.display import header
3
+
4
+
5
+ def test_header():
6
+ print(header())
7
+ assert True, "Printed header"
@@ -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
proscenium-0.0.9/PKG-INFO DELETED
@@ -1,49 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: proscenium
3
- Version: 0.0.9
4
- Summary: Frame AI Agents
5
- License: ASFv2
6
- Author: Adam Pingel
7
- Author-email: oss@pingel.org
8
- Requires-Python: >=3.11,<4.0
9
- Classifier: License :: Other/Proprietary License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.11
12
- Classifier: Programming Language :: Python :: 3.12
13
- Classifier: Programming Language :: Python :: 3.13
14
- Provides-Extra: testing
15
- Requires-Dist: aisuite[openai,anthropic] (>=0.1.10,<0.2.0)
16
- Requires-Dist: datasets (>=3.3.2,<4.0.0)
17
- Requires-Dist: docstring_parser (>=0.16,<0.17)
18
- Requires-Dist: gofannon (>=0.25.13,<0.26.0)
19
- Requires-Dist: langchain-community (>=0.3.18,<0.4.0)
20
- Requires-Dist: langchain-huggingface (>=0.1.2,<0.2.0)
21
- Requires-Dist: lapidarist (>=0.0.1,<0.0.2)
22
- Requires-Dist: neo4j (>=5.28.1,<6.0.0)
23
- Requires-Dist: pydantic (>=2.10.6,<3.0.0)
24
- Requires-Dist: pymilvus (>=2.5.4,<3.0.0)
25
- Requires-Dist: pymilvus_model (>=0.3.1,<0.4.0)
26
- Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
27
- Requires-Dist: rich (>=13.9.4,<14.0.0)
28
- Requires-Dist: slack_sdk (>=3.35.0,<4.0.0)
29
- Requires-Dist: stringcase (>=1.2.0,<2.0.0)
30
- Requires-Dist: tiktoken (>=0.9.0,<0.10.0)
31
- Requires-Dist: typer (>=0.15.2,<0.16.0)
32
- Description-Content-Type: text/markdown
33
-
34
- # Proscenium
35
-
36
- [![CI](https://github.com/The-AI-Alliance/proscenium/actions/workflows/pytest.yml/badge.svg)](https://github.com/The-AI-Alliance/proscenium/actions/workflows/pytest.yml)
37
- [![PyPI](https://img.shields.io/pypi/v/proscenium)](https://pypi.org/project/proscenium/)
38
- [![License](https://img.shields.io/github/license/The-AI-Alliance/proscenium)](https://github.com/The-AI-Alliance/proscenium/tree/main?tab=Apache-2.0-1-ov-file#readme)
39
- [![Issues](https://img.shields.io/github/issues/The-AI-Alliance/proscenium)](https://github.com/The-AI-Alliance/proscenium/issues)
40
- [![GitHub stars](https://img.shields.io/github/stars/The-AI-Alliance/proscenium?style=social)](https://github.com/The-AI-Alliance/proscenium/stargazers)
41
-
42
- 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.
43
-
44
- Currently, proscenium development prioritizes support for domains where the creation and use of structured data is critical.
45
-
46
- See the [website](https://the-ai-alliance.github.io/proscenium/) for quickstart info, goals, and other links.
47
-
48
- To find the Proscenium community, see the [discussions](https://github.com/The-AI-Alliance/proscenium/discussions)
49
-
@@ -1,38 +0,0 @@
1
- [tool.poetry]
2
- name = "proscenium"
3
- version = "0.0.9"
4
- description = "Frame AI Agents"
5
- authors = ["Adam Pingel <oss@pingel.org>"]
6
- license = "ASFv2"
7
- readme = "README.md"
8
- packages = [{include = "proscenium"}]
9
-
10
- [tool.poetry.dependencies]
11
- python = "^3.11"
12
- lapidarist = "^0.0.1"
13
- aisuite = {extras = ["openai,anthropic"], version = "^0.1.10"}
14
- rich = "^13.9.4"
15
- typer = "^0.15.2"
16
- python-dotenv = "^1.0.1"
17
- pydantic = "^2.10.6"
18
- stringcase = "^1.2.0"
19
- docstring_parser = "^0.16"
20
- pymilvus = {version = "^2.5.4"}
21
- pymilvus_model = {version = "^0.3.1"}
22
- datasets = "^3.3.2"
23
- tiktoken = "^0.9.0"
24
- neo4j = "^5.28.1"
25
- gofannon = "^0.25.13"
26
- langchain-community = "^0.3.18"
27
- langchain-huggingface = "^0.1.2"
28
- slack_sdk = "^3.35.0"
29
-
30
- [tool.poetry.extras]
31
- testing = ["pytest"]
32
-
33
- [tool.poetry.scripts]
34
- proscenium-bot = "proscenium.bin.bot:app"
35
-
36
- [build-system]
37
- requires = ["poetry-core"]
38
- build-backend = "poetry.core.masonry.api"
File without changes