release: OpenNexus 0.5.1-alpha

This commit is contained in:
2026-09-18 00:56:54 +08:00
parent f7d441bd92
commit 01ceae6fc6
32 changed files with 496 additions and 33 deletions
+70
View File
@@ -59,8 +59,78 @@ def test_zip_install_real_mcp_tool_command_and_skill(tmp_path):
config = runtime.skills.build_agent_configuration('note-reviewer', [ModelCapability.chat, ModelCapability.tool_calling])
assert 'notes.read' in config.allowed_tools
assert '不得改变用户指定的检查范围' in config.system_prompt
rewrite_skill = install_zip((output / 'course-note-rewriter-1.0.0.zip').read_bytes(), 'skill', tmp_path / 'installed', runtime.skills.install)
assert not rewrite_skill.missing_dependencies
assert runtime.skills.enable('course-note-rewriter').status == 'ready'
rewrite_config = runtime.skills.build_agent_configuration('course-note-rewriter', [ModelCapability.chat, ModelCapability.tool_calling])
assert 'notes.create' in rewrite_config.allowed_tools
assert 'markdown-workbench.inspect_markdown' in rewrite_config.allowed_tools
assert '三道自测题' in rewrite_config.system_prompt
runtime.plugins.disable('markdown-workbench')
assert runtime.skills.get('note-reviewer').status == 'dependency_missing'
assert runtime.skills.get('course-note-rewriter').status == 'dependency_missing'
try:
asyncio.run(run())
finally:
runtime.plugins.shutdown()
def test_study_plan_plugin_and_adaptive_skill_are_real_local_packages(tmp_path):
builder = load(ROOT / 'build_packages.py')
output = tmp_path / 'dist'
catalog = builder.build(output)
assert [item['id'] for item in catalog['packages'] if item['kind'] == 'plugin'] == [
'markdown-workbench', 'study-plan-kit'
]
assert {'course-note-rewriter', 'adaptive-study-coach'} <= {
item['id'] for item in catalog['packages'] if item['kind'] == 'skill'
}
runtime = build_container()
async def run():
plugin = install_zip(
(output / 'study-plan-kit-1.0.0.zip').read_bytes(),
'plugin',
tmp_path / 'installed',
runtime.plugins.install,
)
assert not plugin.enabled
skill = install_zip(
(output / 'adaptive-study-coach-1.0.0.zip').read_bytes(),
'skill',
tmp_path / 'installed',
runtime.skills.install,
)
assert 'study-plan-kit.build_sprint' in skill.missing_dependencies
assert runtime.plugins.enable('study-plan-kit').status == 'ready'
result = await runtime.tools.execute(
ToolCall(
tool_call_id='study-plan-test',
name='study-plan-kit.build_sprint',
arguments={
'topic': '三数和与头尾双指针',
'days': 7,
'daily_minutes': 45,
'confidence': 2,
'weak_points': '去重和指针移动条件',
},
),
ToolExecutionContext(run_id='study-plan-test'),
)
assert result.success, result.error_message
assert result.output['constraints']['total_minutes'] == 315
assert len(result.output['schedule']) == 7
assert sum(result.output['phases'].values()) == 7
assert result.output['constraints']['weak_points'] == '去重和指针移动条件'
assert runtime.skills.enable('adaptive-study-coach').status == 'ready'
config = runtime.skills.build_agent_configuration(
'adaptive-study-coach', [ModelCapability.chat, ModelCapability.tool_calling]
)
assert 'tasks.create' in config.allowed_tools
assert '严格保持工具返回的总分钟数' in config.system_prompt
runtime.plugins.disable('study-plan-kit')
assert runtime.skills.get('adaptive-study-coach').status == 'dependency_missing'
try:
asyncio.run(run())
finally:
+33
View File
@@ -1,6 +1,7 @@
"""无需模型下载的耐久性、取消和乐观编辑。"""
import asyncio
from contextlib import closing
from types import SimpleNamespace
import pytest
from fastapi.testclient import TestClient
@@ -116,6 +117,38 @@ def test_terminology_export_and_privacy_cleanup():
assert client.get('/api/media/attachments/lecture.txt').status_code == 404
def test_media_note_links_do_not_depend_on_rebuildable_note_projection():
with closing(connect()) as conn:
foreign_tables = {row[2] for row in conn.execute("PRAGMA foreign_key_list(media_notes)")}
assert foreign_tables == {"media_jobs"}
def test_desktop_revision_conflict_recovers_marker_matched_note(monkeypatch):
from app.services import note_service
from app.services.media_notes import _create_note
marker = "<!-- transcription:job:1:hash -->"
recovered = SimpleNamespace(note_id="stable-note", title="Generated", markdown=f"{marker}\nbody")
async def conflict(**_kwargs):
raise ApiError(409, "REVISION_CONFLICT", "already written")
monkeypatch.setattr(note_service, "create_note", conflict)
monkeypatch.setattr(
note_service, "list_notes",
lambda **_kwargs: ([SimpleNamespace(note_id="stable-note", title="Generated")], 1),
)
async def get_note(note_id):
return recovered if note_id == "stable-note" else None
monkeypatch.setattr(note_service, "get_note", get_note)
result = asyncio.run(_create_note(
"Generated", recovered.markdown, SimpleNamespace(folder=""), marker
))
assert result is recovered
def test_local_only_export_and_rebuild_keep_local_embedding_policy(monkeypatch):
from types import SimpleNamespace
from app.contracts import TranscriptNoteRequest, IndexRebuildRequest