|
@@ -1,3 +1,5 @@
|
|
|
|
|
+import asyncio
|
|
|
|
|
+import json
|
|
|
import unittest
|
|
import unittest
|
|
|
|
|
|
|
|
from pydantic import ValidationError
|
|
from pydantic import ValidationError
|
|
@@ -162,7 +164,6 @@ class ApplicationDeclarationTest(unittest.TestCase):
|
|
|
),
|
|
),
|
|
|
).application_ref.config_hash)
|
|
).application_ref.config_hash)
|
|
|
self.assertTrue(all(item != base for item in hashes))
|
|
self.assertTrue(all(item != base for item in hashes))
|
|
|
-
|
|
|
|
|
changed_schema = registry("base")
|
|
changed_schema = registry("base")
|
|
|
definition = changed_schema._tools["save"]
|
|
definition = changed_schema._tools["save"]
|
|
|
definition["schema"] = {
|
|
definition["schema"] = {
|
|
@@ -181,6 +182,51 @@ class ApplicationDeclarationTest(unittest.TestCase):
|
|
|
).application_ref.config_hash
|
|
).application_ref.config_hash
|
|
|
self.assertNotEqual(base, schema_hash)
|
|
self.assertNotEqual(base, schema_hash)
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+class ApplicationToolIsolationTest(unittest.IsolatedAsyncioTestCase):
|
|
|
|
|
+ async def test_same_named_tools_execute_in_private_registries_concurrently(self):
|
|
|
|
|
+ app_a = application()
|
|
|
|
|
+ app_b = app_a.model_copy(update={"application_id": "creative.other"})
|
|
|
|
|
+ binding_a = ApplicationRegistry().register(
|
|
|
|
|
+ app_a,
|
|
|
|
|
+ ApplicationServices(
|
|
|
|
|
+ tool_registry=registry("A"),
|
|
|
|
|
+ context_provider=object(),
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+ binding_b = ApplicationRegistry().register(
|
|
|
|
|
+ app_b,
|
|
|
|
|
+ ApplicationServices(
|
|
|
|
|
+ tool_registry=registry("B"),
|
|
|
|
|
+ context_provider=object(),
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ async def execute(binding, expected, index):
|
|
|
|
|
+ raw = await binding.tool_registry.execute(
|
|
|
|
|
+ "save",
|
|
|
|
|
+ {"value": str(index)},
|
|
|
|
|
+ uid="user",
|
|
|
|
|
+ allowed_tool_names={"save"},
|
|
|
|
|
+ )
|
|
|
|
|
+ payload = json.loads(raw) if isinstance(raw, str) else raw
|
|
|
|
|
+ self.assertEqual(expected, payload["application"])
|
|
|
|
|
+ self.assertEqual(str(index), payload["value"])
|
|
|
|
|
+
|
|
|
|
|
+ await asyncio.gather(*(
|
|
|
|
|
+ execute(binding, expected, index)
|
|
|
|
|
+ for binding, expected in ((binding_a, "A"), (binding_b, "B"))
|
|
|
|
|
+ for index in range(20)
|
|
|
|
|
+ ))
|
|
|
|
|
+ self.assertEqual(
|
|
|
|
|
+ 20,
|
|
|
|
|
+ binding_a.tool_registry.get_stats("save")["save"]["call_count"],
|
|
|
|
|
+ )
|
|
|
|
|
+ self.assertEqual(
|
|
|
|
|
+ 20,
|
|
|
|
|
+ binding_b.tool_registry.get_stats("save")["save"]["call_count"],
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
def test_runtime_service_identity_is_not_part_of_config_hash(self):
|
|
def test_runtime_service_identity_is_not_part_of_config_hash(self):
|
|
|
first = ApplicationRegistry().register(
|
|
first = ApplicationRegistry().register(
|
|
|
application(),
|
|
application(),
|