hyperforge-static-string 1.0.0.post22__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.
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: hyperforge_static_string
3
+ Version: 1.0.0.post22
4
+ Summary: A Hyperforge agent that always returns a fixed string
5
+ License: MIT License
6
+ Project-URL: Homepage, https://progress.com
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.10
11
+ Requires-Dist: hyperforge
@@ -0,0 +1,33 @@
1
+ [project]
2
+ dependencies = ["hyperforge"]
3
+
4
+ name = "hyperforge_static_string"
5
+ version = "1.0.0.post22"
6
+ authors = []
7
+ description = "A Hyperforge agent that always returns a fixed string"
8
+ requires-python = ">=3.10"
9
+ classifiers = [
10
+ "Programming Language :: Python :: 3",
11
+ "License :: OSI Approved :: MIT License",
12
+ "Operating System :: OS Independent",
13
+ ]
14
+ license = { text = "MIT License" }
15
+
16
+ [tool.uv]
17
+ required-version = ">=0.10"
18
+ managed = true
19
+ default-groups = "all"
20
+ keyring-provider = "subprocess"
21
+ package = true
22
+
23
+ [project.urls]
24
+ Homepage = "https://progress.com"
25
+
26
+ [tool.pytest.ini_options]
27
+ asyncio_mode = "auto"
28
+
29
+ [dependency-groups]
30
+ dev = [
31
+ "pytest",
32
+ "pytest-asyncio",
33
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ from .agent import StaticStringAgent
2
+
3
+ AGENTS = {"static_string": StaticStringAgent}
@@ -0,0 +1,78 @@
1
+ from time import time
2
+ from typing import Any, ClassVar, Dict, Optional
3
+
4
+ from hyperforge.agent import Agent
5
+ from hyperforge.configure import agent
6
+ from hyperforge.context.agent import ContextAgent
7
+ from hyperforge.context.config import ContextAgentConfig
8
+ from hyperforge.definition import FunctionDefinition
9
+ from hyperforge.manager import Manager
10
+ from hyperforge.memory import Chunk, Context, QuestionMemory
11
+ from pydantic import Field
12
+
13
+
14
+ class StaticStringAgentConfig(ContextAgentConfig):
15
+ context: str = Field(description="Data to add to the context")
16
+
17
+
18
+ @agent(
19
+ id="static_string",
20
+ agent_type="context",
21
+ title="Static String",
22
+ description="Use a static string to provide context for answering questions.",
23
+ config_schema=StaticStringAgentConfig,
24
+ )
25
+ class StaticStringAgent(ContextAgent, Agent[StaticStringAgentConfig]):
26
+ __published_functions__: ClassVar[Dict[str, FunctionDefinition]] = {
27
+ "static_string": FunctionDefinition(
28
+ name="static_string",
29
+ description="Returns a static string to provide context for answering questions.",
30
+ parameters={},
31
+ )
32
+ }
33
+
34
+ def static_string(self) -> str:
35
+ return self.config.context
36
+
37
+ async def _get_question_context(
38
+ self,
39
+ memory: QuestionMemory,
40
+ manager: Manager,
41
+ question_uuid: str,
42
+ question: str,
43
+ flow_id: str,
44
+ extra_context: Optional[Dict[str, Any]] = None,
45
+ ) -> list[tuple[str, str]]:
46
+ error = None
47
+ t0 = time()
48
+ missing = await self.save_ctx_and_return_missing(
49
+ memory=memory,
50
+ context=Context(
51
+ original_question_uuid=memory.original_question_uuid,
52
+ actual_question_uuid=question_uuid,
53
+ question=question,
54
+ chunks=[
55
+ Chunk(
56
+ chunk_id="static_string",
57
+ text=self.static_string(),
58
+ origin_agent=self.config.module,
59
+ )
60
+ ],
61
+ source=f"/context/{self.agent_id}",
62
+ agent=self.config.module,
63
+ ),
64
+ question=question,
65
+ manager=manager,
66
+ flow_id=flow_id,
67
+ )
68
+ await memory.add_step(
69
+ step_module=self.config.module,
70
+ step_title=self.step_title("Search results"),
71
+ step_agent_path=f"/context/{self.agent_id}",
72
+ step_value="String done",
73
+ timeit=time() - t0,
74
+ input_nuclia_tokens=0.5,
75
+ output_nuclia_tokens=0.5,
76
+ error=error,
77
+ )
78
+ return [missing] if missing is not None else []
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: hyperforge_static_string
3
+ Version: 1.0.0.post22
4
+ Summary: A Hyperforge agent that always returns a fixed string
5
+ License: MIT License
6
+ Project-URL: Homepage, https://progress.com
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.10
11
+ Requires-Dist: hyperforge
@@ -0,0 +1,10 @@
1
+ pyproject.toml
2
+ src/hyperforge_static_string/__init__.py
3
+ src/hyperforge_static_string/agent.py
4
+ src/hyperforge_static_string/py.typed
5
+ src/hyperforge_static_string.egg-info/PKG-INFO
6
+ src/hyperforge_static_string.egg-info/SOURCES.txt
7
+ src/hyperforge_static_string.egg-info/dependency_links.txt
8
+ src/hyperforge_static_string.egg-info/requires.txt
9
+ src/hyperforge_static_string.egg-info/top_level.txt
10
+ tests/test_static_string.py
@@ -0,0 +1,115 @@
1
+ from unittest.mock import MagicMock
2
+ from uuid import uuid4
3
+
4
+ import pytest
5
+ from hyperforge.manager import Manager
6
+ from hyperforge.memory.memory import EphemeralSessionMemory
7
+ from hyperforge.models import MemoryConfig, Rules
8
+ from hyperforge_static_string.agent import StaticStringAgent, StaticStringAgentConfig
9
+
10
+ pytestmark = pytest.mark.asyncio
11
+
12
+
13
+ def make_config(**kwargs) -> StaticStringAgentConfig:
14
+ """Helper to create a StaticStringAgentConfig with sensible test defaults."""
15
+ defaults = dict(
16
+ id="test-static-string",
17
+ title="Static String",
18
+ module="static_string",
19
+ prune_context=False, # Disable validation so no LLM calls are needed
20
+ )
21
+ defaults.update(kwargs)
22
+ return StaticStringAgentConfig(**defaults)
23
+
24
+
25
+ def make_session() -> EphemeralSessionMemory:
26
+ session = EphemeralSessionMemory.from_config(
27
+ config=MemoryConfig(), agent_id="test", workflow_id="test", rules=Rules()
28
+ )
29
+ session.init("test-session")
30
+ return session
31
+
32
+
33
+ async def test_static_string_returns_context_string():
34
+ """static_string() returns exactly the configured context string."""
35
+ config = make_config(context="Hello, world!")
36
+ agent = StaticStringAgent(config=config)
37
+ assert agent.static_string() == "Hello, world!"
38
+
39
+
40
+ async def test_get_question_context_saves_context_to_memory():
41
+ """_get_question_context saves a Context with the correct chunk to memory."""
42
+ manager = MagicMock(spec=Manager)
43
+ config = make_config(context="Some static context text.")
44
+ agent = StaticStringAgent(config=config)
45
+
46
+ memory = make_session().start_question("What is the answer?")
47
+ flow_id = uuid4().hex
48
+
49
+ missing = await agent._get_question_context(
50
+ memory=memory,
51
+ manager=manager,
52
+ question_uuid=memory.original_question_uuid,
53
+ question="What is the answer?",
54
+ flow_id=flow_id,
55
+ )
56
+
57
+ # No missing context — everything was provided
58
+ assert missing == []
59
+
60
+ # Context was saved with the correct chunk.
61
+ # Note: StaticStringAgent does not set agent_id on the Context object,
62
+ # so contexts are stored under the empty-string key.
63
+ saved = memory.get_agent_contexts(flow_id=flow_id, agent_id="")
64
+ assert len(saved) == 1
65
+ assert saved[0].chunks[0].chunk_id == "static_string"
66
+ assert saved[0].chunks[0].text == "Some static context text."
67
+ assert saved[0].chunks[0].origin_agent == config.module
68
+
69
+
70
+ async def test_get_question_context_records_step():
71
+ """_get_question_context adds exactly one step with correct metadata."""
72
+ manager = MagicMock(spec=Manager)
73
+ config = make_config(context="Step test context.")
74
+ agent = StaticStringAgent(config=config)
75
+
76
+ memory = make_session().start_question("Any question?")
77
+ flow_id = uuid4().hex
78
+
79
+ await agent._get_question_context(
80
+ memory=memory,
81
+ manager=manager,
82
+ question_uuid=memory.original_question_uuid,
83
+ question="Any question?",
84
+ flow_id=flow_id,
85
+ )
86
+
87
+ assert len(memory.steps) == 1
88
+ step = memory.steps[0]
89
+ assert step.module == "static_string"
90
+ assert "Search results" in step.title
91
+ assert step.value == "String done"
92
+
93
+
94
+ async def test_get_question_context_different_flow_ids():
95
+ """Contexts are scoped to their flow_id and do not bleed across flows."""
96
+ manager = MagicMock(spec=Manager)
97
+ config = make_config(context="Flow-isolated context.")
98
+ agent = StaticStringAgent(config=config)
99
+
100
+ memory = make_session().start_question("Question?")
101
+ flow_id_a = uuid4().hex
102
+ flow_id_b = uuid4().hex
103
+
104
+ await agent._get_question_context(
105
+ memory=memory,
106
+ manager=manager,
107
+ question_uuid=memory.original_question_uuid,
108
+ question="Question?",
109
+ flow_id=flow_id_a,
110
+ )
111
+
112
+ saved_a = memory.get_agent_contexts(flow_id=flow_id_a, agent_id="")
113
+ saved_b = memory.get_agent_contexts(flow_id=flow_id_b, agent_id="")
114
+ assert len(saved_a) == 1
115
+ assert len(saved_b) == 0