mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-09 07:16:04 +00:00
feat(agent-runner): align protocol adapter terminology
This commit is contained in:
@@ -182,8 +182,8 @@ class TestDefaultPipelineConfig:
|
||||
assert config['ai']['runner_config'] == {}
|
||||
|
||||
|
||||
class TestResolveRunnerIdBackwardCompat:
|
||||
"""Tests for backward compatibility in resolve_runner_id."""
|
||||
class TestResolveRunnerIdAliases:
|
||||
"""Tests for runner id alias resolution."""
|
||||
|
||||
def test_resolve_new_format_id(self):
|
||||
"""resolve_runner_id should work with new format."""
|
||||
|
||||
@@ -420,12 +420,12 @@ class TestBuildParamsInContext:
|
||||
|
||||
context = await builder.build_context(query, descriptor, resources)
|
||||
|
||||
# Protocol v1: params is in compatibility.extra
|
||||
assert 'compatibility' in context
|
||||
assert 'extra' in context['compatibility']
|
||||
assert 'params' in context['compatibility']['extra']
|
||||
assert context['compatibility']['extra']['params']['public_param'] == 'value'
|
||||
assert '_private' not in context['compatibility']['extra']['params']
|
||||
# Protocol v1: params is in adapter.extra
|
||||
assert 'adapter' in context
|
||||
assert 'extra' in context['adapter']
|
||||
assert 'params' in context['adapter']['extra']
|
||||
assert context['adapter']['extra']['params']['public_param'] == 'value'
|
||||
assert '_private' not in context['adapter']['extra']['params']
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_params_and_state_both_present(self):
|
||||
@@ -457,12 +457,12 @@ class TestBuildParamsInContext:
|
||||
|
||||
context = await builder.build_context(query, descriptor, resources)
|
||||
|
||||
# Protocol v1: params is in compatibility.extra
|
||||
assert 'compatibility' in context
|
||||
assert 'extra' in context['compatibility']
|
||||
assert 'params' in context['compatibility']['extra']
|
||||
assert context['compatibility']['extra']['params']['workflow_input'] == 'user_question'
|
||||
assert context['compatibility']['extra']['params']['sender_name'] == 'John'
|
||||
# Protocol v1: params is in adapter.extra
|
||||
assert 'adapter' in context
|
||||
assert 'extra' in context['adapter']
|
||||
assert 'params' in context['adapter']['extra']
|
||||
assert context['adapter']['extra']['params']['workflow_input'] == 'user_question'
|
||||
assert context['adapter']['extra']['params']['sender_name'] == 'John'
|
||||
|
||||
# state should have seeded conversation_id
|
||||
assert 'state' in context
|
||||
@@ -495,10 +495,10 @@ class TestBuildParamsInContext:
|
||||
|
||||
context = await builder.build_context(query, descriptor, resources)
|
||||
|
||||
# Protocol v1: prompt is in compatibility.extra
|
||||
assert 'compatibility' in context
|
||||
assert 'extra' in context['compatibility']
|
||||
assert 'prompt' in context['compatibility']['extra']
|
||||
assert context['compatibility']['extra']['prompt'][0]['content'] == 'Effective prompt'
|
||||
# Protocol v1: prompt is in adapter.extra
|
||||
assert 'adapter' in context
|
||||
assert 'extra' in context['adapter']
|
||||
assert 'prompt' in context['adapter']['extra']
|
||||
assert context['adapter']['extra']['prompt'][0]['content'] == 'Effective prompt'
|
||||
assert context['runtime']['metadata']['streaming_supported'] is True
|
||||
assert context['runtime']['metadata']['remove_think'] is True
|
||||
|
||||
@@ -200,7 +200,7 @@ class TestContextValidation:
|
||||
assert 'delivery' in context_dict, "delivery is REQUIRED in Protocol v1"
|
||||
assert 'context' in context_dict, "context (ContextAccess) is REQUIRED in Protocol v1"
|
||||
assert 'bootstrap' in context_dict, "bootstrap should exist (can be None)"
|
||||
assert 'compatibility' in context_dict, "compatibility should exist"
|
||||
assert 'adapter' in context_dict, "adapter should exist"
|
||||
assert 'metadata' in context_dict, "metadata should exist"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"""Tests for event-first Protocol v1 entities and Pipeline compatibility adapter.
|
||||
"""Tests for event-first Protocol v1 entities and Pipeline adapter.
|
||||
|
||||
Tests cover:
|
||||
1. Pipeline Query -> AgentEventEnvelope conversion
|
||||
2. Pipeline config -> AgentBinding conversion
|
||||
3. AgentRunContext not inlining full history by default
|
||||
4. Legacy max-round only affecting bootstrap/compat adapter
|
||||
4. Pipeline max-round only affecting bootstrap/adapter context
|
||||
5. Event-first run() entry point
|
||||
"""
|
||||
from __future__ import annotations
|
||||
@@ -49,7 +49,7 @@ from langbot.pkg.agent.runner.host_models import (
|
||||
StatePolicy,
|
||||
DeliveryPolicy,
|
||||
)
|
||||
from langbot.pkg.agent.runner.pipeline_compat_adapter import PipelineCompatAdapter
|
||||
from langbot.pkg.agent.runner.pipeline_adapter import PipelineAdapter
|
||||
|
||||
|
||||
class TestPipelineQueryToEventEnvelope:
|
||||
@@ -57,24 +57,24 @@ class TestPipelineQueryToEventEnvelope:
|
||||
|
||||
def test_query_to_event_basic_fields(self, mock_query):
|
||||
"""Test basic field conversion from Query to Event envelope."""
|
||||
event = PipelineCompatAdapter.query_to_event(mock_query)
|
||||
event = PipelineAdapter.query_to_event(mock_query)
|
||||
|
||||
assert event.event_type == "message.received"
|
||||
assert event.source == "pipeline_compat"
|
||||
assert event.source == "pipeline_adapter"
|
||||
assert event.bot_id == mock_query.bot_uuid
|
||||
assert event.actor is not None
|
||||
assert event.actor.actor_type == "user"
|
||||
|
||||
def test_query_to_event_input(self, mock_query):
|
||||
"""Test input conversion from Query."""
|
||||
event = PipelineCompatAdapter.query_to_event(mock_query)
|
||||
event = PipelineAdapter.query_to_event(mock_query)
|
||||
|
||||
assert event.input is not None
|
||||
assert event.input.text == "Hello world"
|
||||
|
||||
def test_query_to_event_conversation(self, mock_query):
|
||||
"""Test conversation context extraction."""
|
||||
event = PipelineCompatAdapter.query_to_event(mock_query)
|
||||
event = PipelineAdapter.query_to_event(mock_query)
|
||||
|
||||
# Conversation may be None if no session
|
||||
if event.conversation_id:
|
||||
@@ -82,7 +82,7 @@ class TestPipelineQueryToEventEnvelope:
|
||||
|
||||
def test_query_to_event_delivery_context(self, mock_query):
|
||||
"""Test delivery context extraction."""
|
||||
event = PipelineCompatAdapter.query_to_event(mock_query)
|
||||
event = PipelineAdapter.query_to_event(mock_query)
|
||||
|
||||
assert event.delivery is not None
|
||||
assert event.delivery.surface == "platform"
|
||||
@@ -94,7 +94,7 @@ class TestPipelineConfigToBinding:
|
||||
|
||||
def test_config_to_binding_runner_id(self, mock_query):
|
||||
"""Test binding runner_id extraction."""
|
||||
binding = PipelineCompatAdapter.pipeline_config_to_binding(
|
||||
binding = PipelineAdapter.pipeline_config_to_binding(
|
||||
mock_query, "plugin:author/plugin/runner"
|
||||
)
|
||||
|
||||
@@ -102,7 +102,7 @@ class TestPipelineConfigToBinding:
|
||||
|
||||
def test_config_to_binding_scope(self, mock_query):
|
||||
"""Test binding scope extraction."""
|
||||
binding = PipelineCompatAdapter.pipeline_config_to_binding(
|
||||
binding = PipelineAdapter.pipeline_config_to_binding(
|
||||
mock_query, "plugin:test/plugin/runner"
|
||||
)
|
||||
|
||||
@@ -110,8 +110,8 @@ class TestPipelineConfigToBinding:
|
||||
assert binding.scope.scope_id == mock_query.pipeline_uuid
|
||||
|
||||
def test_config_to_binding_max_round(self, mock_query_with_max_round):
|
||||
"""Test max_round extraction for compatibility adapter."""
|
||||
binding = PipelineCompatAdapter.pipeline_config_to_binding(
|
||||
"""Test max_round extraction for Pipeline adapter."""
|
||||
binding = PipelineAdapter.pipeline_config_to_binding(
|
||||
mock_query_with_max_round, "plugin:test/plugin/runner"
|
||||
)
|
||||
|
||||
@@ -120,7 +120,7 @@ class TestPipelineConfigToBinding:
|
||||
|
||||
def test_config_to_binding_no_max_round(self, mock_query):
|
||||
"""Test binding without max_round."""
|
||||
binding = PipelineCompatAdapter.pipeline_config_to_binding(
|
||||
binding = PipelineAdapter.pipeline_config_to_binding(
|
||||
mock_query, "plugin:test/plugin/runner"
|
||||
)
|
||||
|
||||
@@ -210,8 +210,8 @@ class TestAgentRunContextProtocolV1:
|
||||
assert ctx.bootstrap is None or isinstance(ctx.bootstrap.messages, list)
|
||||
|
||||
|
||||
class TestLegacyMaxRoundNotInProtocol:
|
||||
"""Test that legacy max-round only affects compat adapter, not Protocol v1."""
|
||||
class TestMaxRoundNotInProtocol:
|
||||
"""Test that Pipeline max-round only affects adapter context, not Protocol v1."""
|
||||
|
||||
def test_max_round_not_in_sdk_context(self):
|
||||
"""Test max-round is not a field in SDK AgentRunContext."""
|
||||
@@ -221,8 +221,8 @@ class TestLegacyMaxRoundNotInProtocol:
|
||||
assert "max_round" not in ctx_fields
|
||||
assert "maxRound" not in ctx_fields
|
||||
|
||||
def test_max_round_in_compatibility_context(self):
|
||||
"""Test max_round is in compatibility context, not main context."""
|
||||
def test_max_round_in_adapter_context(self):
|
||||
"""Test max_round is in adapter context, not main context."""
|
||||
trigger = AgentTrigger(type="message.received")
|
||||
event = AgentEventContext(
|
||||
event_id="evt_1",
|
||||
@@ -233,9 +233,9 @@ class TestLegacyMaxRoundNotInProtocol:
|
||||
from langbot_plugin.api.entities.builtin.agent_runner.resources import AgentResources
|
||||
from langbot_plugin.api.entities.builtin.agent_runner.runtime import AgentRuntimeContext
|
||||
from langbot_plugin.api.entities.builtin.agent_runner.delivery import DeliveryContext
|
||||
from langbot_plugin.api.entities.builtin.agent_runner.context import CompatibilityContext
|
||||
from langbot_plugin.api.entities.builtin.agent_runner.context import AdapterContext
|
||||
|
||||
compat = CompatibilityContext(max_round=10)
|
||||
adapter = AdapterContext(max_round=10)
|
||||
|
||||
ctx = AgentRunContext(
|
||||
run_id="run_1",
|
||||
@@ -245,20 +245,20 @@ class TestLegacyMaxRoundNotInProtocol:
|
||||
delivery=DeliveryContext(surface="platform"),
|
||||
resources=AgentResources(),
|
||||
runtime=AgentRuntimeContext(),
|
||||
compatibility=compat,
|
||||
adapter=adapter,
|
||||
)
|
||||
|
||||
# max_round is in compatibility context, not main context
|
||||
assert ctx.compatibility is not None
|
||||
assert ctx.compatibility.max_round == 10
|
||||
# max_round is in adapter context, not main context
|
||||
assert ctx.adapter is not None
|
||||
assert ctx.adapter.max_round == 10
|
||||
|
||||
def test_binding_max_round_for_adapter_only(self, mock_query_with_max_round):
|
||||
"""Test max_round in binding is for adapter use, not Protocol v1."""
|
||||
binding = PipelineCompatAdapter.pipeline_config_to_binding(
|
||||
binding = PipelineAdapter.pipeline_config_to_binding(
|
||||
mock_query_with_max_round, "plugin:test/plugin/runner"
|
||||
)
|
||||
|
||||
# max_round is in binding (Host-internal) for compat adapter
|
||||
# max_round is in binding (Host-internal) for Pipeline adapter
|
||||
assert binding.max_round == 10
|
||||
|
||||
# But SDK entities don't have it
|
||||
|
||||
@@ -8,7 +8,7 @@ Tests focus on:
|
||||
|
||||
Authorization paths:
|
||||
1. AgentRunner calls: has run_id, validates against session_registry
|
||||
2. Regular plugin calls: no run_id, unrestricted (backward compatibility)
|
||||
2. Regular plugin calls: no run_id, unscoped plugin action path
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -220,7 +220,7 @@ class TestInvokeLLMAuthorization:
|
||||
async def test_invoke_llm_no_run_id_unrestricted(self):
|
||||
"""INVOKE_LLM: no run_id should be unrestricted (backward compat)."""
|
||||
# When no run_id is provided, the authorization check is skipped
|
||||
# This is the backward compatibility path for regular plugin calls
|
||||
# This is the unscoped path for regular plugin calls
|
||||
|
||||
# Simulate: if not run_id, skip authorization
|
||||
run_id = None
|
||||
@@ -404,7 +404,7 @@ class TestRetrieveKnowledgeBaseAuthorization:
|
||||
async def test_retrieve_knowledge_base_no_run_id_pipeline_check(self):
|
||||
"""RETRIEVE_KNOWLEDGE_BASE: no run_id checks pipeline config."""
|
||||
# When no run_id, the handler checks against pipeline's configured KBs
|
||||
# This is the backward compatibility path for regular plugin calls
|
||||
# This is the unscoped path for regular plugin calls
|
||||
|
||||
from langbot.pkg.agent.runner.config_migration import ConfigMigration
|
||||
|
||||
@@ -899,7 +899,7 @@ class TestSDKAgentRunAPIProxyFieldConsistency:
|
||||
|
||||
|
||||
class TestNoRunIdBackwardCompatPath:
|
||||
"""Tests for backward compatibility path when no run_id is provided.
|
||||
"""Tests for unscoped plugin action path when no run_id is provided.
|
||||
|
||||
Regular plugins (non-AgentRunner) don't have run_id and should
|
||||
have unrestricted access to certain APIs.
|
||||
@@ -1965,7 +1965,7 @@ class TestCallerPluginIdentityValidation:
|
||||
@pytest.mark.asyncio
|
||||
async def test_no_caller_identity_allowed(self):
|
||||
"""_validate_run_authorization allows when caller_plugin_identity not provided."""
|
||||
# Backward compatibility: if caller_plugin_identity is None, skip identity check
|
||||
# Unscoped plugin path: if caller_plugin_identity is None, skip identity check
|
||||
from langbot.pkg.agent.runner.session_registry import get_session_registry
|
||||
registry = get_session_registry()
|
||||
resources = make_resources(models=[{'model_id': 'model_001'}])
|
||||
@@ -2000,7 +2000,7 @@ class TestCallerPluginIdentityValidation:
|
||||
|
||||
|
||||
class TestBackwardCompatStorageNoRunId:
|
||||
"""Tests for backward compatibility: storage actions without run_id.
|
||||
"""Tests for unscoped storage actions without run_id.
|
||||
|
||||
Regular plugins (non-AgentRunner) don't have run_id and should
|
||||
have unrestricted access to storage APIs.
|
||||
|
||||
@@ -317,8 +317,8 @@ async def test_orchestrator_runs_fake_plugin_with_authorized_context(clean_agent
|
||||
context = plugin_connector.contexts[0]
|
||||
assert context["config"]["timeout"] == 30
|
||||
assert context["runtime"]["deadline_at"] is not None
|
||||
# Protocol v1: params is in compatibility.extra
|
||||
assert context["compatibility"]["extra"]["params"] == {"public_param": "visible"}
|
||||
# Protocol v1: params is in adapter.extra
|
||||
assert context["adapter"]["extra"]["params"] == {"public_param": "visible"}
|
||||
assert context["event"]["event_type"] == "message.received"
|
||||
# Note: source_event_type is in event.source_event_type, not event.data
|
||||
# (event.data contains the raw event payload, not metadata)
|
||||
@@ -341,8 +341,8 @@ async def test_orchestrator_runs_fake_plugin_with_authorized_context(clean_agent
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_orchestrator_packages_legacy_max_round_without_mutating_query(clean_agent_state):
|
||||
"""Test that legacy max-round is packaged without mutating original query."""
|
||||
async def test_orchestrator_packages_max_round_without_mutating_query(clean_agent_state):
|
||||
"""Test that max-round is packaged without mutating original query."""
|
||||
db_engine = clean_agent_state
|
||||
descriptor = make_descriptor()
|
||||
plugin_connector = FakePluginConnector(
|
||||
@@ -370,7 +370,7 @@ async def test_orchestrator_packages_legacy_max_round_without_mutating_query(cle
|
||||
|
||||
assert len(messages) == 1
|
||||
context = plugin_connector.contexts[0]
|
||||
# Protocol v1: legacy messages are in bootstrap.messages
|
||||
# Protocol v1: messages are in bootstrap.messages
|
||||
assert context["bootstrap"] is not None
|
||||
assert [message["content"] for message in context["bootstrap"]["messages"]] == [
|
||||
"message 2",
|
||||
@@ -378,8 +378,8 @@ async def test_orchestrator_packages_legacy_max_round_without_mutating_query(cle
|
||||
"message 3",
|
||||
"response 3",
|
||||
]
|
||||
# Also in compatibility.legacy_messages for legacy runners
|
||||
assert [message["content"] for message in context["compatibility"]["legacy_messages"]] == [
|
||||
# Also in adapter.adapter_messages for transition runners
|
||||
assert [message["content"] for message in context["adapter"]["adapter_messages"]] == [
|
||||
"message 2",
|
||||
"response 2",
|
||||
"message 3",
|
||||
@@ -395,7 +395,7 @@ async def test_orchestrator_packages_legacy_max_round_without_mutating_query(cle
|
||||
]
|
||||
assert context["runtime"]["metadata"]["context_packaging"] == {
|
||||
"policy": {
|
||||
"mode": "legacy_max_round",
|
||||
"mode": "max_round",
|
||||
"max_round": 2,
|
||||
},
|
||||
"history": {
|
||||
@@ -592,12 +592,12 @@ class TestPipelineCompatibilityQueryIdInSession:
|
||||
assert session_during_run["query_id"] is None
|
||||
|
||||
|
||||
class TestPipelineCompatibilityPromptAndParams:
|
||||
"""Tests for prompt and params handling in Pipeline compatibility."""
|
||||
class TestPipelineAdapterPromptAndParams:
|
||||
"""Tests for prompt and params handling in Pipeline adapter."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_prompt_in_compatibility_extra(self, clean_agent_state):
|
||||
"""Pipeline prompt is placed in compatibility.extra.prompt."""
|
||||
async def test_prompt_in_adapter_extra(self, clean_agent_state):
|
||||
"""Pipeline prompt is placed in adapter.extra.prompt."""
|
||||
from langbot_plugin.api.entities.builtin.provider import prompt as provider_prompt
|
||||
|
||||
db_engine = clean_agent_state
|
||||
@@ -625,10 +625,10 @@ class TestPipelineCompatibilityPromptAndParams:
|
||||
messages = [message async for message in orchestrator.run_from_query(query)]
|
||||
|
||||
context = plugin_connector.contexts[0]
|
||||
# Prompt should be in compatibility.extra
|
||||
assert "prompt" in context["compatibility"]["extra"]
|
||||
assert len(context["compatibility"]["extra"]["prompt"]) == 1
|
||||
assert context["compatibility"]["extra"]["prompt"][0]["role"] == "system"
|
||||
# Prompt should be in adapter.extra
|
||||
assert "prompt" in context["adapter"]["extra"]
|
||||
assert len(context["adapter"]["extra"]["prompt"]) == 1
|
||||
assert context["adapter"]["extra"]["prompt"][0]["role"] == "system"
|
||||
# Top-level should NOT have prompt
|
||||
assert "prompt" not in context
|
||||
|
||||
@@ -656,7 +656,7 @@ class TestPipelineCompatibilityPromptAndParams:
|
||||
messages = [message async for message in orchestrator.run_from_query(query)]
|
||||
|
||||
context = plugin_connector.contexts[0]
|
||||
assert context["compatibility"]["extra"]["params"] == {
|
||||
assert context["adapter"]["extra"]["params"] == {
|
||||
"public_param": "visible",
|
||||
"another_param": 123,
|
||||
}
|
||||
@@ -686,7 +686,7 @@ class TestPipelineCompatibilityPromptAndParams:
|
||||
messages = [message async for message in orchestrator.run_from_query(query)]
|
||||
|
||||
context = plugin_connector.contexts[0]
|
||||
params = context["compatibility"]["extra"]["params"]
|
||||
params = context["adapter"]["extra"]["params"]
|
||||
assert "public_param" in params
|
||||
assert "_internal_var" not in params
|
||||
assert "_pipeline_bound_plugins" not in params
|
||||
@@ -718,7 +718,7 @@ class TestPipelineCompatibilityPromptAndParams:
|
||||
messages = [message async for message in orchestrator.run_from_query(query)]
|
||||
|
||||
context = plugin_connector.contexts[0]
|
||||
params = context["compatibility"]["extra"]["params"]
|
||||
params = context["adapter"]["extra"]["params"]
|
||||
assert "public_param" in params
|
||||
assert "api_token" not in params
|
||||
assert "secret_key" not in params
|
||||
@@ -750,14 +750,14 @@ class TestPipelineCompatibilityPromptAndParams:
|
||||
messages = [message async for message in orchestrator.run_from_query(query)]
|
||||
|
||||
context = plugin_connector.contexts[0]
|
||||
params = context["compatibility"]["extra"]["params"]
|
||||
params = context["adapter"]["extra"]["params"]
|
||||
assert "public_param" in params
|
||||
assert "a_set" not in params
|
||||
assert "a_lambda" not in params
|
||||
|
||||
|
||||
class TestPipelineCompatibilityHostCapabilities:
|
||||
"""Tests for event-first host capabilities via Pipeline compatibility path."""
|
||||
class TestPipelineAdapterHostCapabilities:
|
||||
"""Tests for event-first host capabilities via Pipeline adapter path."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_state_updated_writes_to_persistent_store(self, clean_agent_state):
|
||||
@@ -795,9 +795,9 @@ class TestPipelineCompatibilityHostCapabilities:
|
||||
persistent_store = get_persistent_state_store(db_engine)
|
||||
# Build snapshot to check if state was written
|
||||
# Note: We need to rebuild the event and binding to query the store
|
||||
from langbot.pkg.agent.runner.pipeline_compat_adapter import PipelineCompatAdapter
|
||||
event = PipelineCompatAdapter.query_to_event(query)
|
||||
binding = PipelineCompatAdapter.pipeline_config_to_binding(query, RUNNER_ID)
|
||||
from langbot.pkg.agent.runner.pipeline_adapter import PipelineAdapter
|
||||
event = PipelineAdapter.query_to_event(query)
|
||||
binding = PipelineAdapter.pipeline_config_to_binding(query, RUNNER_ID)
|
||||
|
||||
snapshot = await persistent_store.build_snapshot_from_event(event, binding, descriptor)
|
||||
assert snapshot["conversation"]["external.test_key"] == "test_value"
|
||||
|
||||
@@ -6,7 +6,7 @@ from langbot.pkg.agent.runner.state_store import (
|
||||
get_state_store,
|
||||
reset_state_store,
|
||||
VALID_STATE_SCOPES,
|
||||
LEGACY_KEY_MAPPING,
|
||||
STATE_KEY_ALIASES,
|
||||
)
|
||||
from langbot.pkg.agent.runner.descriptor import AgentRunnerDescriptor
|
||||
from langbot.pkg.agent.runner.host_models import AgentBinding, BindingScope, StatePolicy
|
||||
@@ -219,8 +219,8 @@ class TestStateStoreApplyUpdate:
|
||||
assert len(logger.warnings) == 1
|
||||
assert 'invalid scope' in logger.warnings[0]
|
||||
|
||||
def test_apply_update_legacy_key_mapping(self):
|
||||
"""Legacy key conversation_id should be mapped to external.conversation_id."""
|
||||
def test_apply_update_state_key_alias(self):
|
||||
"""Alias key conversation_id should be mapped to external.conversation_id."""
|
||||
store = RunnerScopedStateStore()
|
||||
descriptor = make_descriptor()
|
||||
query = FakeQuery()
|
||||
@@ -481,9 +481,9 @@ class TestConstants:
|
||||
"""VALID_STATE_SCOPES should have four scopes."""
|
||||
assert VALID_STATE_SCOPES == ('conversation', 'actor', 'subject', 'runner')
|
||||
|
||||
def test_legacy_key_mapping(self):
|
||||
"""LEGACY_KEY_MAPPING should map conversation_id."""
|
||||
assert LEGACY_KEY_MAPPING == {'conversation_id': 'external.conversation_id'}
|
||||
def test_state_key_aliases(self):
|
||||
"""STATE_KEY_ALIASES should map conversation_id."""
|
||||
assert STATE_KEY_ALIASES == {'conversation_id': 'external.conversation_id'}
|
||||
|
||||
|
||||
# ========== Event-first Protocol v1 tests ==========
|
||||
@@ -781,8 +781,8 @@ class TestStateStoreEventFirstApplyUpdate:
|
||||
assert len(logger.warnings) == 1
|
||||
assert 'missing identity' in logger.warnings[0]
|
||||
|
||||
def test_apply_update_legacy_key_mapping(self):
|
||||
"""Legacy key conversation_id should be mapped to external.conversation_id."""
|
||||
def test_apply_update_state_key_alias(self):
|
||||
"""Alias key conversation_id should be mapped to external.conversation_id."""
|
||||
store = RunnerScopedStateStore()
|
||||
descriptor = make_descriptor()
|
||||
event = FakeEventEnvelope(conversation_id='conv_001')
|
||||
@@ -1371,4 +1371,4 @@ class TestPersistentStateStore:
|
||||
|
||||
# Delete non-existent should return False
|
||||
deleted_again = await persistent_store.state_delete(scope_key, 'key')
|
||||
assert deleted_again is False
|
||||
assert deleted_again is False
|
||||
|
||||
Reference in New Issue
Block a user