iointel 1.3.3__tar.gz → 1.3.4__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 (82) hide show
  1. {iointel-1.3.3 → iointel-1.3.4}/.github/workflows/tests.yaml +18 -8
  2. {iointel-1.3.3 → iointel-1.3.4}/PKG-INFO +4 -2
  3. iointel-1.3.4/docker-compose.yml +33 -0
  4. {iointel-1.3.3 → iointel-1.3.4}/iointel/__init__.py +1 -1
  5. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/agents/tool_factory.py +6 -2
  6. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/data_models/datamodels.py +1 -1
  7. iointel-1.3.4/iointel/src/agent_methods/tools/agno/agentql.py +21 -0
  8. iointel-1.3.4/iointel/src/agent_methods/tools/agno/airflow.py +22 -0
  9. iointel-1.3.4/iointel/src/agent_methods/tools/agno/arxiv.py +27 -0
  10. iointel-1.3.4/iointel/src/agent_methods/tools/agno/aws_lambda.py +20 -0
  11. iointel-1.3.4/iointel/src/agent_methods/tools/agno/common.py +11 -0
  12. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/tools/duckduckgo.py +13 -1
  13. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/utilities/decorators.py +1 -1
  14. {iointel-1.3.3 → iointel-1.3.4}/pyproject.toml +3 -1
  15. iointel-1.3.4/tests/conftest.py +0 -0
  16. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_with_agents/test_basic_agent_tools.py +1 -1
  17. iointel-1.3.3/Makefile +0 -38
  18. {iointel-1.3.3 → iointel-1.3.4}/.gitattributes +0 -0
  19. {iointel-1.3.3 → iointel-1.3.4}/.github/workflows/codeql.yaml +0 -0
  20. {iointel-1.3.3 → iointel-1.3.4}/.github/workflows/linting.yaml +0 -0
  21. {iointel-1.3.3 → iointel-1.3.4}/.github/workflows/release.yaml +0 -0
  22. {iointel-1.3.3 → iointel-1.3.4}/.gitignore +0 -0
  23. {iointel-1.3.3 → iointel-1.3.4}/.pre-commit-config.yaml +0 -0
  24. {iointel-1.3.3 → iointel-1.3.4}/LICENSE +0 -0
  25. {iointel-1.3.3 → iointel-1.3.4}/README.md +0 -0
  26. {iointel-1.3.3 → iointel-1.3.4}/creds.env.example +0 -0
  27. {iointel-1.3.3 → iointel-1.3.4}/iointel/client/__init__.py +0 -0
  28. {iointel-1.3.3 → iointel-1.3.4}/iointel/client/client.py +0 -0
  29. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/__init__.py +0 -0
  30. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/__init__.py +0 -0
  31. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/agents/__init__.py +0 -0
  32. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/agents/agents_factory.py +0 -0
  33. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/data_models/__init__.py +0 -0
  34. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/prompts/__init__.py +0 -0
  35. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/prompts/instructions.py +0 -0
  36. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/tools/__init__.py +0 -0
  37. {iointel-1.3.3/iointel/src/code_parsers → iointel-1.3.4/iointel/src/agent_methods/tools/agno}/__init__.py +0 -0
  38. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/tools/coinmarketcap.py +0 -0
  39. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/tools/firecrawl.py +0 -0
  40. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/tools/r2r.py +0 -0
  41. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/tools/searxng.py +0 -0
  42. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/tools/solscan.py +0 -0
  43. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/tools/tools.py +0 -0
  44. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/tools/utils.py +0 -0
  45. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agent_methods/tools/wolfram.py +0 -0
  46. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/agents.py +0 -0
  47. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/chainables.py +0 -0
  48. /iointel-1.3.3/tests/conftest.py → /iointel-1.3.4/iointel/src/code_parsers/__init__.py +0 -0
  49. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/code_parsers/jscode_parser.py +0 -0
  50. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/code_parsers/pycode_parser.py +0 -0
  51. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/memory.py +0 -0
  52. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/task.py +0 -0
  53. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/utilities/constants.py +0 -0
  54. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/utilities/exceptions.py +0 -0
  55. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/utilities/func_metadata.py +0 -0
  56. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/utilities/graph_nodes.py +0 -0
  57. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/utilities/helpers.py +0 -0
  58. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/utilities/registries.py +0 -0
  59. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/utilities/rich.py +0 -0
  60. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/utilities/runners.py +0 -0
  61. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/utilities/stages.py +0 -0
  62. {iointel-1.3.3 → iointel-1.3.4}/iointel/src/workflow.py +0 -0
  63. {iointel-1.3.3 → iointel-1.3.4}/test-runner +0 -0
  64. {iointel-1.3.3 → iointel-1.3.4}/tests/test_agents.py +0 -0
  65. {iointel-1.3.3 → iointel-1.3.4}/tests/test_client.py +0 -0
  66. {iointel-1.3.3 → iointel-1.3.4}/tests/test_stages.py +0 -0
  67. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tasks.py +0 -0
  68. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_isolated/test_coinmarketcap.py +0 -0
  69. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_isolated/test_duckduckgo.py +0 -0
  70. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_isolated/test_firecrawl_tool.py +0 -0
  71. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_isolated/test_r2r.py +0 -0
  72. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_isolated/test_searxng.py +0 -0
  73. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_isolated/test_solscan.py +0 -0
  74. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_isolated/test_wolfram.py +0 -0
  75. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_with_agents/test_coinmarketcap_agent.py +0 -0
  76. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_with_agents/test_crawl_agent.py +0 -0
  77. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_with_agents/test_duckduckgo_agent.py +0 -0
  78. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_with_agents/test_searxng_agent.py +0 -0
  79. {iointel-1.3.3 → iointel-1.3.4}/tests/test_tools_with_agents/test_wolframalpha_agent.py +0 -0
  80. {iointel-1.3.3 → iointel-1.3.4}/tests/test_utilities.py +0 -0
  81. {iointel-1.3.3 → iointel-1.3.4}/tests/test_workflows.py +0 -0
  82. {iointel-1.3.3 → iointel-1.3.4}/uv.lock +0 -0
@@ -52,21 +52,31 @@ jobs:
52
52
  uses: actions/setup-python@v5
53
53
  with:
54
54
  python-version: ${{ matrix.python-version }}
55
-
55
+
56
56
  - name: download uv
57
57
  run: curl -LsSf https://astral.sh/uv/install.sh | sh
58
-
58
+
59
59
  - name: Install dependencies
60
60
  run: uv pip install --system -e ".[dev]"
61
+
62
+ - name: Check readme anchors
63
+ run: |
64
+ pip install pipx
65
+ pipx run hatch-fancy-pypi-readme | grep -vq 'MISSING ANCHOR'
66
+
67
+ - name: Set up Docker Compose
68
+ uses: docker/setup-buildx-action@v3
61
69
 
62
- - name: Prepare for tests
63
- run: make prepare_for_tests
70
+ - name: Start services
71
+ run: |
72
+ docker compose up -d
73
+ # Wait for searxng to be healthy by checking the health endpoint directly
74
+ timeout 60s bash -c 'until curl -s -f http://localhost:8080/healthz > /dev/null; do sleep 2; done'
64
75
 
65
76
  - name: Run tests
66
77
  run: pytest -vv tests/ --retries 2 --retry-delay 5
67
78
  if: ${{ !(github.event.pull_request.head.repo.fork) }}
68
79
 
69
- - name: Check readme anchors
70
- run: |
71
- pip install pipx
72
- pipx run hatch-fancy-pypi-readme | grep -vq 'MISSING ANCHOR'
80
+ - name: Remove containers
81
+ if: always() # This ensures cleanup happens even if tests fail
82
+ run: docker compose down -v
@@ -1,12 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iointel
3
- Version: 1.3.3
3
+ Version: 1.3.4
4
4
  Summary: A framework to create agents, tasks, and workflows.
5
5
  License-File: LICENSE
6
6
  Keywords: AI,Agents,LLM,framework,tools
7
7
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
8
8
  Requires-Python: >=3.10
9
- Requires-Dist: duckduckgo-search==8.0.0
9
+ Requires-Dist: agno[tools]==1.5.5
10
+ Requires-Dist: backoff==2.2.1
11
+ Requires-Dist: duckduckgo-search==8.0.2
10
12
  Requires-Dist: firecrawl-py>=2.2.0
11
13
  Requires-Dist: firecrawl>=2.2.0
12
14
  Requires-Dist: httpx
@@ -0,0 +1,33 @@
1
+ version: '3.8'
2
+
3
+ services:
4
+ searxng:
5
+ image: searxng/searxng
6
+ container_name: iointel-searxng
7
+ ports:
8
+ - "8080:8080"
9
+ volumes:
10
+ - searxng_config:/etc/searxng
11
+ environment:
12
+ - BASE_URL=http://localhost:8080/
13
+ - INSTANCE_NAME=my-instance
14
+ healthcheck:
15
+ test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"]
16
+ interval: 30s
17
+ timeout: 10s
18
+ retries: 3
19
+ start_period: 5s
20
+ restart: unless-stopped
21
+
22
+ # Service to modify settings.yml
23
+ setup:
24
+ image: python:3-slim
25
+ volumes:
26
+ - searxng_config:/etc/searxng
27
+ command: ["bash", "-c", "pip install pyyaml && python3 -c 'import yaml; f=\"/etc/searxng/settings.yml\"; d=yaml.safe_load(open(f)); d.setdefault(\"search\",{}).setdefault(\"formats\",[]).append(\"json\"); open(f,\"w\").write(yaml.safe_dump(d))'"]
28
+ depends_on:
29
+ - searxng
30
+
31
+ volumes:
32
+ searxng_config:
33
+ name: iointel-searxng-config
@@ -45,4 +45,4 @@ __all__ = [
45
45
  ]
46
46
 
47
47
 
48
- __version__ = "1.3.3"
48
+ __version__ = "1.3.4"
@@ -63,7 +63,11 @@ def resolve_tools(params: AgentParams) -> List[Optional[Callable]]:
63
63
  """
64
64
  resolved_tools = []
65
65
  for tool_data in params.tools:
66
- if isinstance(tool_data, dict):
66
+ if isinstance(tool_data, str):
67
+ logger.debug(f"Looking up the registry for tool `{tool_data}`")
68
+ if not (tool_obj := TOOLS_REGISTRY.get(tool_data)):
69
+ raise ValueError(f"Tool {tool_data} is not known")
70
+ elif isinstance(tool_data, dict):
67
71
  logger.debug(f"Rehydrating tool from dict: {tool_data}")
68
72
  tool_obj = Tool.model_validate(tool_data)
69
73
  if "body" in tool_data:
@@ -82,7 +86,7 @@ def resolve_tools(params: AgentParams) -> List[Optional[Callable]]:
82
86
  tool_obj = Tool.from_function(tool_data)
83
87
  else:
84
88
  raise ValueError(
85
- "Unexpected type for tool_data; expected dict, Tool instance, or callable."
89
+ "Unexpected type for tool_data; expected str, dict, Tool instance, or callable."
86
90
  )
87
91
 
88
92
  registered_tool_name, registered_tool = next(
@@ -400,7 +400,7 @@ class AgentParams(BaseModel):
400
400
  base_url: Optional[str] = Field(
401
401
  None, description="Base URL for the model, if required."
402
402
  )
403
- tools: Optional[List[dict | Tool | Callable]] = Field(default_factory=list)
403
+ tools: Optional[List[str | dict | Tool | Callable]] = Field(default_factory=list)
404
404
  context: Optional[Dict[str, Any]] = Field(
405
405
  None,
406
406
  description="Context to be passed to the agent.",
@@ -0,0 +1,21 @@
1
+ from functools import wraps
2
+ from typing import Optional
3
+ from agno.tools.agentql import AgentQLTools as AgnoAgentQLTools
4
+
5
+ from ..utils import register_tool
6
+ from .common import DisableAgnoRegistryMixin
7
+
8
+
9
+ class AgentQL(DisableAgnoRegistryMixin, AgnoAgentQLTools):
10
+ def __init__(self, api_key: Optional[str] = None, agentql_query: str = ""):
11
+ super().__init__(api_key=api_key, scrape=True, agentql_query=agentql_query)
12
+
13
+ @register_tool(name="agentql_scrape_website")
14
+ @wraps(AgnoAgentQLTools.scrape_website)
15
+ def scrape_website(self, url: str) -> str:
16
+ return super().scrape_website(url)
17
+
18
+ @register_tool(name="agentql_custom_scrape_website")
19
+ @wraps(AgnoAgentQLTools.custom_scrape_website)
20
+ def custom_scrape_website(self, url: str) -> str:
21
+ return super().custom_scrape_website(url)
@@ -0,0 +1,22 @@
1
+ from pathlib import Path
2
+ from typing import Optional, Union
3
+ from functools import wraps
4
+ from agno.tools.airflow import AirflowTools as AgnoAirflowTools
5
+
6
+ from ..utils import register_tool
7
+ from .common import DisableAgnoRegistryMixin
8
+
9
+
10
+ class Airflow(DisableAgnoRegistryMixin, AgnoAirflowTools):
11
+ def __init__(self, dags_dir: Optional[Union[Path, str]] = None):
12
+ super().__init__(dags_dir=dags_dir, save_dag=True, read_dag=True)
13
+
14
+ @register_tool(name="airflow_save_dag_file")
15
+ @wraps(AgnoAirflowTools.save_dag_file)
16
+ def save_dag_file(self, contents: str, dag_file: str) -> str:
17
+ return super().save_dag_file(contents=contents, dag_file=dag_file)
18
+
19
+ @register_tool(name="airflow_read_dag_file")
20
+ @wraps(AgnoAirflowTools.read_dag_file)
21
+ def read_dag_file(self, dag_file: str) -> str:
22
+ return super().read_dag_file(dag_file=dag_file)
@@ -0,0 +1,27 @@
1
+ from pathlib import Path
2
+ from typing import Optional
3
+ from functools import wraps
4
+ from agno.tools.arxiv import ArxivTools as AgnoArxivTools
5
+
6
+ from ..utils import register_tool
7
+ from .common import DisableAgnoRegistryMixin
8
+
9
+
10
+ class Arxiv(DisableAgnoRegistryMixin, AgnoArxivTools):
11
+ def __init__(self, download_dir: Optional[Path] = None):
12
+ # TODO: define a better default option for downloading pdfs, agno arxiv has a weird choice
13
+ super().__init__(download_dir=download_dir)
14
+
15
+ @register_tool(name="arxiv_search")
16
+ @wraps(AgnoArxivTools.search_arxiv_and_return_articles)
17
+ def search_arxiv_and_return_articles(
18
+ self, query: str, num_articles: int = 10
19
+ ) -> str:
20
+ return super().search_arxiv_and_return_articles(query, num_articles)
21
+
22
+ @register_tool(name="arxiv_read_papers")
23
+ @wraps(AgnoArxivTools.read_arxiv_papers)
24
+ def read_arxiv_papers(
25
+ self, id_list: list[str], pages_to_read: Optional[int] = None
26
+ ) -> str:
27
+ return super().read_arxiv_papers(id_list, pages_to_read)
@@ -0,0 +1,20 @@
1
+ from functools import wraps
2
+ from agno.tools.aws_lambda import AWSLambdaTools as AgnoAWSLambdaTools
3
+
4
+ from ..utils import register_tool
5
+ from .common import DisableAgnoRegistryMixin
6
+
7
+
8
+ class AWSLambda(DisableAgnoRegistryMixin, AgnoAWSLambdaTools):
9
+ def __init__(self, region_name: str = "us-east-1"):
10
+ super().__init__(region_name=region_name)
11
+
12
+ @register_tool(name="aws_lambda_list_functions")
13
+ @wraps(AgnoAWSLambdaTools.list_functions)
14
+ def list_functions(self) -> str:
15
+ return super().list_functions()
16
+
17
+ @register_tool(name="aws_lambda_invoke_function")
18
+ @wraps(AgnoAWSLambdaTools.invoke_function)
19
+ def invoke_function(self, function_name: str, payload: str = "{}") -> str:
20
+ return super().invoke_function(function_name=function_name, payload=payload)
@@ -0,0 +1,11 @@
1
+ class DisableAgnoRegistryMixin:
2
+ """
3
+ Put this as first parent class when inheriting
4
+ from Agno tool to disable Agno registry,
5
+ because we only care about our own registry."""
6
+
7
+ def _register_tools(self):
8
+ """Disabled in favour of iointel registry."""
9
+
10
+ def register(self, function, name=None):
11
+ """Disabled in favour of iointel registry."""
@@ -1,5 +1,11 @@
1
1
  import asyncio
2
2
  from typing import Any, Dict, List, Optional
3
+ import backoff
4
+
5
+ try:
6
+ from duckduckgo import DuckDuckGoSearchException
7
+ except ImportError:
8
+ DuckDuckGoSearchException = Exception
3
9
 
4
10
  from iointel.src.utilities.decorators import register_tool
5
11
  from pydantic import BaseModel, ConfigDict, model_validator
@@ -24,7 +30,7 @@ class DuckDuckGoSearchAPIWrapper(BaseModel):
24
30
  Options: d, w, m, y
25
31
  """
26
32
  max_results: int = 5
27
- backend: str = "auto"
33
+ backend: str = "html"
28
34
  """
29
35
  Options: auto, html, lite
30
36
  """
@@ -46,6 +52,12 @@ class DuckDuckGoSearchAPIWrapper(BaseModel):
46
52
  ) from e
47
53
  return values
48
54
 
55
+ @backoff.on_exception(
56
+ backoff.expo,
57
+ exception=(DuckDuckGoSearchException,),
58
+ max_tries=5,
59
+ jitter=backoff.random_jitter,
60
+ )
49
61
  def _ddgs(
50
62
  self, query: str, max_results: Optional[int] = None
51
63
  ) -> List[Dict[str, str]]:
@@ -97,7 +97,7 @@ def register_tool(_fn=None, name: Optional[str] = None):
97
97
  logger.debug(f"Tool '{tool_name}' is already safely registered.")
98
98
  return executor_fn
99
99
 
100
- TOOLS_REGISTRY[tool_name] = Tool.from_function(executor_fn)
100
+ TOOLS_REGISTRY[tool_name] = Tool.from_function(executor_fn, name=tool_name)
101
101
  logger.debug(f"Registered tool '{tool_name}' safely.")
102
102
  return executor_fn
103
103
 
@@ -10,7 +10,7 @@ dependencies = [
10
10
  "python-multipart>=0.0.20",
11
11
  "pydantic-ai>=0.1.0",
12
12
  "pyyaml>=6.0.2",
13
- "duckduckgo-search==8.0.0",
13
+ "duckduckgo-search==8.0.2",
14
14
  "pgvector>=0.4.0",
15
15
  "sqlalchemy-utils>=0.41.2",
16
16
  "sqlalchemy>=2.0.36",
@@ -18,6 +18,8 @@ dependencies = [
18
18
  # For some reason both firecrawl-py and firecrawl are necessary
19
19
  "firecrawl-py>=2.2.0",
20
20
  "firecrawl>=2.2.0",
21
+ "backoff==2.2.1",
22
+ "agno[tools]==1.5.5",
21
23
  ]
22
24
  keywords = ["Agents", "LLM", "framework", "AI", "tools"]
23
25
  classifiers = [
File without changes
@@ -34,7 +34,7 @@ async def test_basic_tools():
34
34
  Complete tasks to the best of your ability by using the appropriate tool. Follow all instructions carefully.
35
35
  When you need to add numbers, call the tool and use its result.
36
36
  """,
37
- tools=[add_two_numbers, get_current_datetime],
37
+ tools=["add_two_numbers", get_current_datetime],
38
38
  )
39
39
  numbers = [22122837493142, 159864395786239452]
40
40
 
iointel-1.3.3/Makefile DELETED
@@ -1,38 +0,0 @@
1
- prepare_for_tests:
2
- export PORT=8080
3
- docker pull searxng/searxng
4
- docker stop iointel-searxng || true
5
-
6
- # Run searxng to generate default settings.yml
7
- # Then edit settings.yml to support json format in the output, and restart docker with updated settings
8
- docker run --rm -d \
9
- -p ${PORT}:8080 \
10
- -v "${PWD}/searxng:/etc/searxng" \
11
- -e "BASE_URL=http://localhost:${PORT}/" \
12
- -e "INSTANCE_NAME=my-instance" \
13
- --name iointel-searxng \
14
- searxng/searxng
15
- sleep 5
16
- docker stop iointel-searxng || true
17
-
18
- sudo python3 -c "import yaml; f='searxng/settings.yml'; d=yaml.safe_load(open(f)); d.setdefault('search',{}).setdefault('formats',[]).append('json'); open(f,'w').write(yaml.safe_dump(d))"
19
-
20
- docker run --rm -d \
21
- -p ${PORT}:8080 \
22
- -v "${PWD}/searxng:/etc/searxng" \
23
- -e "BASE_URL=http://localhost:${PORT}/" \
24
- -e "INSTANCE_NAME=my-instance" \
25
- --name iointel-searxng \
26
- searxng/searxng
27
- sleep 5
28
- # # Retrieve the response from localhost:8080 silently.
29
- # @response=$$(curl -s localhost:8080) ; \
30
- # if [ -n "$$response" ]; then \
31
- # echo "Success: Server returned output."; \
32
- # else \
33
- # echo "Error: No output received from server."; \
34
- # exit 1; \
35
- # fi
36
-
37
-
38
- .PHONY: prepare_for_tests
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