signalwire-agents 1.0.0__py3-none-any.whl → 1.0.2__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.
- signalwire_agents/__init__.py +1 -1
- signalwire_agents/agent_server.py +125 -12
- {signalwire_agents-1.0.0.dist-info → signalwire_agents-1.0.2.dist-info}/METADATA +1 -1
- {signalwire_agents-1.0.0.dist-info → signalwire_agents-1.0.2.dist-info}/RECORD +8 -8
- {signalwire_agents-1.0.0.dist-info → signalwire_agents-1.0.2.dist-info}/WHEEL +0 -0
- {signalwire_agents-1.0.0.dist-info → signalwire_agents-1.0.2.dist-info}/entry_points.txt +0 -0
- {signalwire_agents-1.0.0.dist-info → signalwire_agents-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {signalwire_agents-1.0.0.dist-info → signalwire_agents-1.0.2.dist-info}/top_level.txt +0 -0
signalwire_agents/__init__.py
CHANGED
|
@@ -18,7 +18,7 @@ A package for building AI agents using SignalWire's AI and SWML capabilities.
|
|
|
18
18
|
from .core.logging_config import configure_logging
|
|
19
19
|
configure_logging()
|
|
20
20
|
|
|
21
|
-
__version__ = "1.0.
|
|
21
|
+
__version__ = "1.0.2"
|
|
22
22
|
|
|
23
23
|
# Import core classes for easier access
|
|
24
24
|
from .core.agent_base import AgentBase
|
|
@@ -549,11 +549,11 @@ class AgentServer:
|
|
|
549
549
|
# This is a request to an agent's sub-path
|
|
550
550
|
relative_path = full_path[len(route.lstrip("/")):]
|
|
551
551
|
relative_path = relative_path.lstrip("/")
|
|
552
|
-
|
|
552
|
+
|
|
553
553
|
# Route to appropriate handler based on path
|
|
554
554
|
if not relative_path or relative_path == "/":
|
|
555
555
|
return await agent._handle_root_request(request)
|
|
556
|
-
|
|
556
|
+
|
|
557
557
|
clean_path = relative_path.rstrip("/")
|
|
558
558
|
if clean_path == "debug":
|
|
559
559
|
return await agent._handle_debug_request(request)
|
|
@@ -564,7 +564,7 @@ class AgentServer:
|
|
|
564
564
|
return await agent._handle_post_prompt_request(request)
|
|
565
565
|
elif clean_path == "check_for_input":
|
|
566
566
|
return await agent._handle_check_for_input_request(request)
|
|
567
|
-
|
|
567
|
+
|
|
568
568
|
# Check for custom routing callbacks
|
|
569
569
|
if hasattr(agent, '_routing_callbacks'):
|
|
570
570
|
for callback_path, callback_fn in agent._routing_callbacks.items():
|
|
@@ -572,9 +572,26 @@ class AgentServer:
|
|
|
572
572
|
if clean_path == cb_path_clean:
|
|
573
573
|
request.state.callback_path = callback_path
|
|
574
574
|
return await agent._handle_root_request(request)
|
|
575
|
-
|
|
576
|
-
# No matching agent
|
|
577
|
-
|
|
575
|
+
|
|
576
|
+
# No matching agent - check for static files
|
|
577
|
+
if hasattr(self, '_static_directories'):
|
|
578
|
+
# Check each static directory route
|
|
579
|
+
for static_route, static_dir in self._static_directories.items():
|
|
580
|
+
# For root static route, serve any unmatched path
|
|
581
|
+
if static_route == "" or static_route == "/":
|
|
582
|
+
response = self._serve_static_file(full_path, "")
|
|
583
|
+
if response:
|
|
584
|
+
return response
|
|
585
|
+
# For prefixed static routes, check if path matches
|
|
586
|
+
elif full_path.startswith(static_route.lstrip("/") + "/") or full_path == static_route.lstrip("/"):
|
|
587
|
+
relative_path = full_path[len(static_route.lstrip("/")):].lstrip("/")
|
|
588
|
+
response = self._serve_static_file(relative_path, static_route)
|
|
589
|
+
if response:
|
|
590
|
+
return response
|
|
591
|
+
|
|
592
|
+
# No matching agent or static file found
|
|
593
|
+
from fastapi import HTTPException
|
|
594
|
+
raise HTTPException(status_code=404, detail="Not Found")
|
|
578
595
|
|
|
579
596
|
# Set host and port
|
|
580
597
|
host = host or self.host
|
|
@@ -634,13 +651,13 @@ class AgentServer:
|
|
|
634
651
|
log_level=self.log_level
|
|
635
652
|
)
|
|
636
653
|
|
|
637
|
-
def register_global_routing_callback(self, callback_fn: Callable[[Request, Dict[str, Any]], Optional[str]],
|
|
654
|
+
def register_global_routing_callback(self, callback_fn: Callable[[Request, Dict[str, Any]], Optional[str]],
|
|
638
655
|
path: str) -> None:
|
|
639
656
|
"""
|
|
640
657
|
Register a routing callback across all agents
|
|
641
|
-
|
|
658
|
+
|
|
642
659
|
This allows you to add unified routing logic to all agents at the same path.
|
|
643
|
-
|
|
660
|
+
|
|
644
661
|
Args:
|
|
645
662
|
callback_fn: The callback function to register
|
|
646
663
|
path: The path to register the callback at
|
|
@@ -648,11 +665,107 @@ class AgentServer:
|
|
|
648
665
|
# Normalize the path
|
|
649
666
|
if not path.startswith("/"):
|
|
650
667
|
path = f"/{path}"
|
|
651
|
-
|
|
668
|
+
|
|
652
669
|
path = path.rstrip("/")
|
|
653
|
-
|
|
670
|
+
|
|
654
671
|
# Register with all existing agents
|
|
655
672
|
for agent in self.agents.values():
|
|
656
673
|
agent.register_routing_callback(callback_fn, path=path)
|
|
657
|
-
|
|
674
|
+
|
|
658
675
|
self.logger.info(f"Registered global routing callback at {path} on all agents")
|
|
676
|
+
|
|
677
|
+
def serve_static_files(self, directory: str, route: str = "/") -> None:
|
|
678
|
+
"""
|
|
679
|
+
Serve static files from a directory.
|
|
680
|
+
|
|
681
|
+
This method properly integrates static file serving with agent routes,
|
|
682
|
+
ensuring that agent routes take priority over static files.
|
|
683
|
+
|
|
684
|
+
Unlike using StaticFiles.mount("/", ...) directly on self.app, this method
|
|
685
|
+
uses explicit route handlers that work correctly with agent routes.
|
|
686
|
+
|
|
687
|
+
Args:
|
|
688
|
+
directory: Path to the directory containing static files
|
|
689
|
+
route: URL path prefix for static files (default: "/" for root)
|
|
690
|
+
|
|
691
|
+
Example:
|
|
692
|
+
server = AgentServer()
|
|
693
|
+
server.register(SupportAgent(), "/support")
|
|
694
|
+
server.serve_static_files("./web") # Serves at /
|
|
695
|
+
# /support -> SupportAgent
|
|
696
|
+
# /index.html -> ./web/index.html
|
|
697
|
+
# / -> ./web/index.html
|
|
698
|
+
"""
|
|
699
|
+
from pathlib import Path
|
|
700
|
+
from fastapi.responses import FileResponse
|
|
701
|
+
from fastapi import HTTPException
|
|
702
|
+
|
|
703
|
+
# Normalize directory path
|
|
704
|
+
static_dir = Path(directory).resolve()
|
|
705
|
+
|
|
706
|
+
if not static_dir.exists():
|
|
707
|
+
raise ValueError(f"Directory does not exist: {directory}")
|
|
708
|
+
|
|
709
|
+
if not static_dir.is_dir():
|
|
710
|
+
raise ValueError(f"Path is not a directory: {directory}")
|
|
711
|
+
|
|
712
|
+
# Normalize route
|
|
713
|
+
if not route.startswith("/"):
|
|
714
|
+
route = f"/{route}"
|
|
715
|
+
route = route.rstrip("/")
|
|
716
|
+
|
|
717
|
+
# Store static directory config for use by catch-all handler
|
|
718
|
+
if not hasattr(self, '_static_directories'):
|
|
719
|
+
self._static_directories = {}
|
|
720
|
+
|
|
721
|
+
self._static_directories[route] = static_dir
|
|
722
|
+
|
|
723
|
+
self.logger.info(f"Serving static files from '{directory}' at route '{route or '/'}'")
|
|
724
|
+
|
|
725
|
+
def _serve_static_file(self, file_path: str, route: str = "/") -> Optional[Response]:
|
|
726
|
+
"""
|
|
727
|
+
Internal method to serve a static file.
|
|
728
|
+
|
|
729
|
+
Args:
|
|
730
|
+
file_path: The requested file path
|
|
731
|
+
route: The route prefix
|
|
732
|
+
|
|
733
|
+
Returns:
|
|
734
|
+
FileResponse if file exists, None otherwise
|
|
735
|
+
"""
|
|
736
|
+
from pathlib import Path
|
|
737
|
+
from fastapi.responses import FileResponse
|
|
738
|
+
|
|
739
|
+
if not hasattr(self, '_static_directories'):
|
|
740
|
+
return None
|
|
741
|
+
|
|
742
|
+
static_dir = self._static_directories.get(route)
|
|
743
|
+
if not static_dir:
|
|
744
|
+
return None
|
|
745
|
+
|
|
746
|
+
# Default to index.html for empty path
|
|
747
|
+
if not file_path:
|
|
748
|
+
file_path = "index.html"
|
|
749
|
+
|
|
750
|
+
full_path = static_dir / file_path
|
|
751
|
+
|
|
752
|
+
# Security: prevent path traversal
|
|
753
|
+
try:
|
|
754
|
+
full_path = full_path.resolve()
|
|
755
|
+
if not str(full_path).startswith(str(static_dir)):
|
|
756
|
+
return None
|
|
757
|
+
except Exception:
|
|
758
|
+
return None
|
|
759
|
+
|
|
760
|
+
# Handle directory requests
|
|
761
|
+
if full_path.is_dir():
|
|
762
|
+
index_path = full_path / "index.html"
|
|
763
|
+
if index_path.exists():
|
|
764
|
+
full_path = index_path
|
|
765
|
+
else:
|
|
766
|
+
return None
|
|
767
|
+
|
|
768
|
+
if not full_path.exists():
|
|
769
|
+
return None
|
|
770
|
+
|
|
771
|
+
return FileResponse(full_path)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
signalwire_agents/__init__.py,sha256=
|
|
2
|
-
signalwire_agents/agent_server.py,sha256=
|
|
1
|
+
signalwire_agents/__init__.py,sha256=Ik9ySmfseOgGLIgBOsWq2kktOjpB1yNgdIh1yJL5Fn4,5030
|
|
2
|
+
signalwire_agents/agent_server.py,sha256=5GPt6XekVxep9esZY9s4MG6sOR-VF_m53U25r3WoML4,30964
|
|
3
3
|
signalwire_agents/schema.json,sha256=OSTe01OQW3WFnHGVnDP3dwIDBP1NWDFZkTJaeWi3f54,378569
|
|
4
4
|
signalwire_agents/agents/bedrock.py,sha256=J582gooNtxtep4xdVOfyDzRtHp_XrurPMS93xf2Xod0,10836
|
|
5
5
|
signalwire_agents/cli/__init__.py,sha256=XbxAQFaCIdGXIXJiriVBWoFPOJsC401u21588nO4TG8,388
|
|
@@ -130,9 +130,9 @@ signalwire_agents/utils/token_generators.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663
|
|
|
130
130
|
signalwire_agents/utils/validators.py,sha256=4Mr7baQ_xR_hfJ72YxQRAT_GFa663YjFX_PumJ35Xds,191
|
|
131
131
|
signalwire_agents/web/__init__.py,sha256=XE_pSTY9Aalzr7J7wqFth1Zr3cccQHPPcF5HWNrOpz8,383
|
|
132
132
|
signalwire_agents/web/web_service.py,sha256=a2PSHJgX1tlZr0Iz1A1UouZjXEePJAZL632evvLVM38,21071
|
|
133
|
-
signalwire_agents-1.0.
|
|
134
|
-
signalwire_agents-1.0.
|
|
135
|
-
signalwire_agents-1.0.
|
|
136
|
-
signalwire_agents-1.0.
|
|
137
|
-
signalwire_agents-1.0.
|
|
138
|
-
signalwire_agents-1.0.
|
|
133
|
+
signalwire_agents-1.0.2.dist-info/licenses/LICENSE,sha256=NYvAsB-rTcSvG9cqHt9EUHAWLiA9YzM4Qfz-mPdvDR0,1067
|
|
134
|
+
signalwire_agents-1.0.2.dist-info/METADATA,sha256=H-Zd7PV62-L5AvcGMdol8MUFYLpquNJgiZ71jL1t10Q,41595
|
|
135
|
+
signalwire_agents-1.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
136
|
+
signalwire_agents-1.0.2.dist-info/entry_points.txt,sha256=ZDT65zfTO_YyDzi_hwQbCxIhrUfu_t8RpNXMMXlUPWI,144
|
|
137
|
+
signalwire_agents-1.0.2.dist-info/top_level.txt,sha256=kDGS6ZYv84K9P5Kyg9_S8P_pbUXoHkso0On_DB5bbWc,18
|
|
138
|
+
signalwire_agents-1.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|