fix: complete 0.5.1 demo workflows
This commit is contained in:
@@ -6,7 +6,7 @@ import pytest
|
||||
|
||||
from app.config import BACKEND_DIR
|
||||
from app.container import build_container
|
||||
from app.contracts import ModelCapability, PluginCommandContext, ToolCall
|
||||
from app.contracts import ModelCapability, ToolCall
|
||||
from app.agent.tools import ToolExecutionContext
|
||||
from app.extensions.archive import install_zip
|
||||
|
||||
@@ -37,7 +37,7 @@ def test_analysis_ignores_metadata_and_code_and_keeps_line_numbers():
|
||||
assert many['truncated'] and many['summary']['tasks'] == 205 and len(many['tasks']) == 200
|
||||
|
||||
|
||||
def test_zip_install_real_mcp_tool_command_and_skill(tmp_path):
|
||||
def test_zip_install_real_declarative_tool_and_skill(tmp_path):
|
||||
builder = load(ROOT / 'build_packages.py')
|
||||
output = tmp_path / 'dist'
|
||||
catalog = builder.build(output)
|
||||
@@ -53,8 +53,6 @@ def test_zip_install_real_mcp_tool_command_and_skill(tmp_path):
|
||||
result = await runtime.tools.execute(ToolCall(tool_call_id='community-test', name='markdown-workbench.inspect_markdown', arguments={'text': sample}), ToolExecutionContext(run_id='community-test'))
|
||||
assert result.success, result.error_message
|
||||
assert result.output['summary']['issues'] == 2
|
||||
command = await runtime.plugins.execute_command('markdown-workbench.inspect-selection', {}, PluginCommandContext(selection=sample))
|
||||
assert '1 项未完成任务' in command.effect.payload.message
|
||||
assert runtime.skills.enable('note-reviewer').status == 'ready'
|
||||
config = runtime.skills.build_agent_configuration('note-reviewer', [ModelCapability.chat, ModelCapability.tool_calling])
|
||||
assert 'notes.read' in config.allowed_tools
|
||||
|
||||
@@ -149,6 +149,130 @@ def test_desktop_revision_conflict_recovers_marker_matched_note(monkeypatch):
|
||||
assert result is recovered
|
||||
|
||||
|
||||
def test_transcript_export_recovers_link_from_another_vault(monkeypatch):
|
||||
from app.contracts import TranscriptNoteRequest
|
||||
from app.services import note_service
|
||||
from app.services.media_notes import create_transcript_note
|
||||
|
||||
text_attachment()
|
||||
|
||||
async def scenario():
|
||||
job = await jobs.create_transcription("lecture.txt")
|
||||
options = TranscriptNoteRequest(title="跨库课程")
|
||||
original = await create_transcript_note(job.job_id, options)
|
||||
with closing(connect()) as conn:
|
||||
conn.execute(
|
||||
"UPDATE media_notes SET note_id=? WHERE job_id=?",
|
||||
("note-from-another-vault", job.job_id),
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
real_get_note = note_service.get_note
|
||||
|
||||
async def get_note(note_id):
|
||||
if note_id == "note-from-another-vault":
|
||||
return None
|
||||
return await real_get_note(note_id)
|
||||
|
||||
monkeypatch.setattr(note_service, "get_note", get_note)
|
||||
recovered = await create_transcript_note(job.job_id, options)
|
||||
assert recovered.note_id == original.note_id
|
||||
with closing(connect()) as conn:
|
||||
linked = conn.execute(
|
||||
"SELECT note_id FROM media_notes WHERE job_id=?",
|
||||
(job.job_id,),
|
||||
).fetchone()[0]
|
||||
assert linked == original.note_id
|
||||
|
||||
asyncio.run(scenario())
|
||||
|
||||
|
||||
def test_artifact_host_writes_use_distinct_child_operations(monkeypatch):
|
||||
from app import host_bridge
|
||||
from app.contracts import TranscriptArtifactsRequest
|
||||
from app.services import media_notes
|
||||
|
||||
operations = []
|
||||
text_attachment()
|
||||
job = asyncio.run(jobs.create_transcription("lecture.txt"))
|
||||
|
||||
async def transcript(_job_id, _options):
|
||||
operations.append(host_bridge.operation_id.get())
|
||||
return SimpleNamespace(note_id="transcript-note")
|
||||
|
||||
async def knowledge(*_args):
|
||||
return "<!-- knowledge-note:test -->\n# Knowledge"
|
||||
|
||||
async def create(*_args, **_kwargs):
|
||||
operations.append(host_bridge.operation_id.get())
|
||||
return SimpleNamespace(note_id="knowledge-note")
|
||||
|
||||
monkeypatch.setattr(media_notes, "create_transcript_note", transcript)
|
||||
monkeypatch.setattr(media_notes, "_knowledge_markdown", knowledge)
|
||||
monkeypatch.setattr(media_notes, "_create_note", create)
|
||||
|
||||
token = host_bridge.operation_id.set("11111111-1111-4111-8111-111111111111")
|
||||
try:
|
||||
result = asyncio.run(media_notes.create_transcript_artifacts(
|
||||
job.job_id,
|
||||
TranscriptArtifactsRequest(
|
||||
title="Transcript", knowledge_title="Knowledge",
|
||||
provider_id="mock", model="mock-1",
|
||||
),
|
||||
))
|
||||
finally:
|
||||
host_bridge.operation_id.reset(token)
|
||||
|
||||
assert result["transcript"].note_id == "transcript-note"
|
||||
assert result["knowledge_note"].note_id == "knowledge-note"
|
||||
assert len(operations) == 2
|
||||
assert operations[0] != operations[1]
|
||||
assert all(operation and operation != "11111111-1111-4111-8111-111111111111" for operation in operations)
|
||||
|
||||
|
||||
def test_course_note_blocks_are_recomposed_with_markdown_and_plot_tools(monkeypatch):
|
||||
from app.container import container
|
||||
from app.services.media_notes import _compose_course_blocks
|
||||
|
||||
names = []
|
||||
original = container.tools.execute
|
||||
|
||||
async def execute(call, context):
|
||||
names.append(call.name)
|
||||
return await original(call, context)
|
||||
|
||||
monkeypatch.setattr(container.tools, "execute", execute)
|
||||
markdown = """## 算法
|
||||
```python
|
||||
left += 1
|
||||
```
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A --> B
|
||||
```
|
||||
```function_plot
|
||||
domain: -4, 4
|
||||
range: -1, 8
|
||||
y = x^2
|
||||
```"""
|
||||
rendered = asyncio.run(_compose_course_blocks(markdown, "media-test"))
|
||||
assert names == ["markdown.compose", "markdown.compose", "function_plot.compose"]
|
||||
assert "```python\nleft += 1\n```" in rendered
|
||||
assert "```mermaid\nflowchart LR" in rendered
|
||||
assert "```function-plot\ndomain: -4, 4" in rendered
|
||||
|
||||
|
||||
def test_course_note_rejects_invalid_function_plot():
|
||||
from app.services.media_notes import _compose_course_blocks
|
||||
|
||||
with pytest.raises(ApiError) as invalid:
|
||||
asyncio.run(_compose_course_blocks(
|
||||
"```function-plot\ndomain: -4, 4\ny = __import__('os')\n```",
|
||||
"media-test",
|
||||
))
|
||||
assert invalid.value.code == "KNOWLEDGE_NOTE_VISUAL_INVALID"
|
||||
|
||||
|
||||
def test_local_only_export_and_rebuild_keep_local_embedding_policy(monkeypatch):
|
||||
from types import SimpleNamespace
|
||||
from app.contracts import TranscriptNoteRequest, IndexRebuildRequest
|
||||
|
||||
@@ -3,7 +3,7 @@ import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from pydantic import TypeAdapter, ValidationError
|
||||
from pydantic import BaseModel, TypeAdapter, ValidationError
|
||||
|
||||
from app.agent import ToolRegistry
|
||||
from app.config import BACKEND_DIR, get_settings
|
||||
@@ -91,6 +91,33 @@ def test_echo_command_returns_none_for_empty_message() -> None:
|
||||
assert populated.payload.message == "hello"
|
||||
|
||||
|
||||
def test_markdown_inspector_returns_line_based_findings() -> None:
|
||||
class Arguments(BaseModel):
|
||||
text: str
|
||||
|
||||
markdown = "# 课程\n### 跳级\n## 重复\n## 重复\n- [ ] 复习\n```python\nprint(1)"
|
||||
result = run(
|
||||
DeclarativePluginHost().execute(
|
||||
"inspect_markdown", Arguments(text=markdown), None
|
||||
)
|
||||
)
|
||||
|
||||
assert result["summary"] == {
|
||||
"lines": 7,
|
||||
"characters": len(markdown),
|
||||
"headings": 4,
|
||||
"tasks": 1,
|
||||
"open_tasks": 1,
|
||||
"issues": 3,
|
||||
}
|
||||
assert [issue["type"] for issue in result["issues"]] == [
|
||||
"heading_level_jump",
|
||||
"duplicate_heading",
|
||||
"unclosed_code_fence",
|
||||
]
|
||||
assert [issue["line"] for issue in result["issues"]] == [2, 4, 6]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("effect_type", "payload"),
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user