feat: 添加MinIO文件系统支持并优化外部连接器功能
- 添加MinIO用户文件系统配置选项(BEAVER_MINIO_ROOT_USER等) - 更新外部连接器配置结构,包括BASE_URL和认证令牌设置 - 改进connector provider支持更多类型(official, feishu_bot等) - 实现Mistral模型推理模式支持reasoning_effort参数 - 增强外部连接器策略配置和运行时配置管理 - 添加connector bridge事件验证和安全保护机制 - 优化任务路由逻辑,区分simple_chat和new_task场景 - 更新初始技能工具提示配置,分离authoring admin功能
This commit is contained in:
@ -99,6 +99,191 @@ def test_task_run_records_evidence_and_waits_for_acceptance(tmp_path: Path) -> N
|
||||
assert "validated" not in event_types
|
||||
|
||||
|
||||
def test_unrelated_simple_chat_auto_accepts_active_task(tmp_path: Path) -> None:
|
||||
service = AgentService(
|
||||
loader=EngineLoader(
|
||||
workspace=tmp_path,
|
||||
task_execution_planner=StubTaskExecutionPlanner(),
|
||||
)
|
||||
)
|
||||
first = asyncio.run(
|
||||
service.process_direct(
|
||||
"recommend food in Hengqin",
|
||||
session_id="web:new-topic-chat",
|
||||
provider_bundle=_bundle("Food recommendations"),
|
||||
)
|
||||
)
|
||||
|
||||
second = asyncio.run(
|
||||
service.process_direct(
|
||||
"have you eaten?",
|
||||
session_id="web:new-topic-chat",
|
||||
provider_bundle=_bundle("I do not eat.", route_action="simple_chat"),
|
||||
)
|
||||
)
|
||||
|
||||
task_service = service.create_loop().boot().task_service
|
||||
assert task_service is not None
|
||||
previous = task_service.get_task(first.task_id or "")
|
||||
assert previous is not None
|
||||
assert previous.status == "closed"
|
||||
assert previous.run_ids == [first.run_id]
|
||||
assert previous.feedback[-1]["acceptance_type"] == "accept"
|
||||
assert previous.metadata["final_accepted_run_id"] == first.run_id
|
||||
assert second.task_id is None
|
||||
|
||||
|
||||
def test_unrelated_new_task_auto_accepts_previous_task(tmp_path: Path) -> None:
|
||||
service = AgentService(
|
||||
loader=EngineLoader(
|
||||
workspace=tmp_path,
|
||||
task_execution_planner=StubTaskExecutionPlanner(),
|
||||
)
|
||||
)
|
||||
first = asyncio.run(
|
||||
service.process_direct(
|
||||
"recommend food in Hengqin",
|
||||
session_id="web:new-topic-task",
|
||||
provider_bundle=_bundle("Food recommendations"),
|
||||
)
|
||||
)
|
||||
|
||||
second = asyncio.run(
|
||||
service.process_direct(
|
||||
"check today's weather in Iceland",
|
||||
session_id="web:new-topic-task",
|
||||
provider_bundle=_bundle("Weather result", route_action="new_task"),
|
||||
)
|
||||
)
|
||||
|
||||
task_service = service.create_loop().boot().task_service
|
||||
assert task_service is not None
|
||||
previous = task_service.get_task(first.task_id or "")
|
||||
current = task_service.get_task(second.task_id or "")
|
||||
assert previous is not None
|
||||
assert current is not None
|
||||
assert previous.status == "closed"
|
||||
assert previous.run_ids == [first.run_id]
|
||||
assert previous.feedback[-1]["acceptance_type"] == "accept"
|
||||
assert current.task_id != previous.task_id
|
||||
assert current.status == "awaiting_acceptance"
|
||||
assert current.run_ids == [second.run_id]
|
||||
|
||||
|
||||
def test_related_follow_up_continues_active_task_without_accepting_it(tmp_path: Path) -> None:
|
||||
service = AgentService(
|
||||
loader=EngineLoader(
|
||||
workspace=tmp_path,
|
||||
task_execution_planner=StubTaskExecutionPlanner(),
|
||||
)
|
||||
)
|
||||
first = asyncio.run(
|
||||
service.process_direct(
|
||||
"recommend food in Hengqin",
|
||||
session_id="web:continue-topic",
|
||||
provider_bundle=_bundle("Food recommendations"),
|
||||
)
|
||||
)
|
||||
|
||||
second = asyncio.run(
|
||||
service.process_direct(
|
||||
"include restaurants near the port",
|
||||
session_id="web:continue-topic",
|
||||
provider_bundle=_bundle("More recommendations", route_action="continue_task"),
|
||||
)
|
||||
)
|
||||
|
||||
task_service = service.create_loop().boot().task_service
|
||||
assert task_service is not None
|
||||
task = task_service.get_task(first.task_id or "")
|
||||
assert task is not None
|
||||
assert second.task_id == first.task_id
|
||||
assert task.status == "awaiting_acceptance"
|
||||
assert task.run_ids == [first.run_id, second.run_id]
|
||||
assert task.feedback == []
|
||||
|
||||
|
||||
def test_requested_revision_keeps_active_task_without_accepting_it(tmp_path: Path) -> None:
|
||||
service = AgentService(
|
||||
loader=EngineLoader(
|
||||
workspace=tmp_path,
|
||||
task_execution_planner=StubTaskExecutionPlanner(),
|
||||
)
|
||||
)
|
||||
first = asyncio.run(
|
||||
service.process_direct(
|
||||
"recommend food in Hengqin",
|
||||
session_id="web:revise-topic",
|
||||
provider_bundle=_bundle("Food recommendations"),
|
||||
)
|
||||
)
|
||||
|
||||
second = asyncio.run(
|
||||
service.process_direct(
|
||||
"remove expensive restaurants",
|
||||
session_id="web:revise-topic",
|
||||
provider_bundle=_bundle("Revised recommendations", route_action="revise_task"),
|
||||
)
|
||||
)
|
||||
|
||||
task_service = service.create_loop().boot().task_service
|
||||
assert task_service is not None
|
||||
task = task_service.get_task(first.task_id or "")
|
||||
assert task is not None
|
||||
assert second.task_id == first.task_id
|
||||
assert task.status == "awaiting_acceptance"
|
||||
assert task.run_ids == [first.run_id, second.run_id]
|
||||
assert [item["acceptance_type"] for item in task.feedback] == ["revise"]
|
||||
|
||||
|
||||
def test_router_failure_fallback_does_not_auto_accept_active_task(tmp_path: Path) -> None:
|
||||
service = AgentService(
|
||||
loader=EngineLoader(
|
||||
workspace=tmp_path,
|
||||
task_execution_planner=StubTaskExecutionPlanner(),
|
||||
)
|
||||
)
|
||||
first = asyncio.run(
|
||||
service.process_direct(
|
||||
"recommend food in Hengqin",
|
||||
session_id="web:router-fallback",
|
||||
provider_bundle=_bundle("Food recommendations"),
|
||||
)
|
||||
)
|
||||
fallback_bundle = ProviderBundle(
|
||||
main_runtime=SimpleNamespace(model="stub-model", provider_name="stub"),
|
||||
main_provider=StubProvider(
|
||||
[
|
||||
LLMResponse(
|
||||
content="Continued response",
|
||||
finish_reason="stop",
|
||||
provider_name="stub",
|
||||
model="stub-model",
|
||||
)
|
||||
]
|
||||
),
|
||||
auxiliary_runtime=SimpleNamespace(model="stub-model", provider_name="stub"),
|
||||
auxiliary_provider=StubProvider([]),
|
||||
)
|
||||
|
||||
second = asyncio.run(
|
||||
service.process_direct(
|
||||
"continue after router failure",
|
||||
session_id="web:router-fallback",
|
||||
provider_bundle=fallback_bundle,
|
||||
)
|
||||
)
|
||||
|
||||
task_service = service.create_loop().boot().task_service
|
||||
assert task_service is not None
|
||||
task = task_service.get_task(first.task_id or "")
|
||||
assert task is not None
|
||||
assert second.task_id == first.task_id
|
||||
assert task.status == "awaiting_acceptance"
|
||||
assert task.run_ids == [first.run_id, second.run_id]
|
||||
assert task.feedback == []
|
||||
|
||||
|
||||
def test_acceptance_closes_task_and_triggers_learning(tmp_path: Path) -> None:
|
||||
service = AgentService(
|
||||
loader=EngineLoader(
|
||||
|
||||
Reference in New Issue
Block a user