feat(viking): archive full ACP traces and add MCP tool namespacing - #382
Conversation
- New wiki_build.py defines WikiBuildConfig/WikiBuildCapability/RoleFilter, lazily importing xeno_adp_agentic WikiBuildTools at runtime to keep the framework dependency-free - Tools are exposed as FunctionToolset (or RoleFilteredToolset) with a RunContext-injected wrapper preserving the real tool signature - Team task list (mine_only) shows owned subtasks under another member's parent; team mode prompt guides workers to list owned tasks by ID - mypy: allow missing imports for xeno_adp_agentic/xeno_adp_harness
Extend wiki build tool registry with find_wiki and the OPS/OPL worker tool set (create_ops/get_ops, create_opl/get_opls, op_flow_status). Define dedicated wiki_opa_worker / wiki_ops_worker / wiki_opl_worker role permissions and register them in WIKI_AGENT_ROLES.
…enhancements - Add viking/wiki_index.py + wiki_build tools (batch entity, index inject, service entrypoint) - MCP manager.py: PrefixedToolset monkey-patch for tool name conflict resolution - mcp_server_cap: disabled_tools support - team_comm_capability: team member role lookup - compaction: message count compaction support - DCP: fallback nested model config, team state directory propagation - run.py: session controller run improvements - Add tests for all new features
Add the generic layered `browse` tool and `browse_chapters` to ALL_WIKI_TOOLS, _HELPER_TOOL_NAMES, and _READ_TOOLS so conductor/extraction/relation/opa/ops workers can drill down over any raw-root URI without the full tree listing. Previously browse_chapters was gated as a helper but absent from _READ_TOOLS, so role filtering made it unreachable.
…rden distillation JSON
- event_mapper: handle duplicated concatenated JSON + invalid JSON args
(vLLM glm47/SGLang GLM streaming corruption); invalid args become {} so
raw garbage never reaches model requests or tool execution
- turn.py: sanitize inbound restored history before first model request
- dcp/tools.py: cap distillation at 4000 chars to keep arguments valid JSON
- wiki_build: allow rebuild_all_backlinks for file_op/finalize roles
ExternalOPCapability exposes three tools (submit_external_opa, submit_external_ops, apply_external_opl) letting an external expert feed OPA→OPS→OPL feedback into the wiki OP flow. Supports revise-by-URI: passing ops_uri/opl_uri updates the existing record in place so an expert can iterate on one opinion until accepted. sync_after_apply optionally pushes the patched page and OPL to remote Viking.
Extract tool functions to wiki_build_tools.py (matching tools.py pattern), slim WikiBuildCapability to config+lifecycle+delegate, merge ExternalOPCapability into wiki_external_expert role. Delete external_op.py. - wiki_build_tools.py: ALL_WIKI_TOOLS, ROLE_TOOLS, RoleFilter, build_tools(cap), _build_method_wrappers, _build_external_op_fns, _sync_entity_to_remote, get_instructions(role) - wiki_build.py: WikiBuildConfig (+sync_after_apply, +include_external_ops), WikiBuildCapability (config/tools properties, delegates get_toolset to build_tools) - external_op.py: deleted (3 OP closures moved to wiki_build_tools.py) - wiki_external_expert role: 3 OP tools + browse/read/search/get_opas/get_ops/get_opls - docstrings: viking:// URI format + discovery guidance for agent perception
Add refine_opa_reason_code and ops_dispatch_plan to ALL_WIKI_TOOLS. Expand wiki_ops_worker role with _OPA_REFINE_TOOLS, _OPA_RESOLVE_TOOLS, and _OPS_RESOLVE_WRITE_TOOLS (patch_entity + rebuild_backlinks) so the OPS resolver can close relation_missed gaps. Add _OPS_DISPATCH_TOOLS to wiki_conductor so it can drive deterministic OPS dispatch. Entity materialization tools (write_entity/merge_entity) remain excluded from ops_worker — that stays with file_operator.
…l link_relations - viking_upload_tree: single add_resource call (semantic+vectors, wait=True), temp strict-dir copy, 200-byte filename guard, skip index/source_packets - viking_link_relations: aggregate relations by from_uri, link each node at most once per direction (multi-target single call) to dodge the server-side relations lock bug; resolve local X.md URIs to the server md wrapper X/X.md; best-effort with backoff, reports linked/failed/skipped - viking_add_resource: optional processing_mode + wait params - unit tests for URI resolution + aggregated link semantics; live E2E manual test verified against real server (upload embeddings 0 errors, linked=3)
Replace the external OP closures in wiki_build_tools.py with a ticket-based capability (ticket.py): create_opa_ticket / create_ops_ticket / create_opl_ticket / apply_opl_ticket / get_ticket_status / submit_eval_payload. wiki_external_expert role now routes to the ticket toolset; sync_after_apply pushes patched wiki pages to remote Viking.
…l-worker-tools Integrate upstream #364/#356/#368/#372/#374/#375/#367 changes. Resolved: - pyproject/uv.lock: openviking-sdk 0.1.8 (keep local; image download_bytes comment) - mcp_server_cap.py: keep fork's self._tool_prefix logic - viking/tools.py: combine imports (PurePosixPath + json/Path/shutil/tempfile) - test_viking*.py: accept upload_tree (local wiki feature), 4→5 / 12→13
- wiki_build.py: FunctionTool used at runtime (FunctionTool.from_callable), import outside TYPE_CHECKING to avoid latent NameError (ruff TC004). - test_live_e2e_manual.py: break combined assertion into per-edge checks (ruff PT018).
…orage config Companion work that was pending on the branch: - team_state/team_comm: lease-token task claim + automatic renewal, member subtask creation permission, lease TTL config - model_configs: model capability additions + tests - storage: config hardening + storage tests - viking wiki_build_tools: extraction worker read-tool restriction (drop read_chapters_batch from extraction lane) - serve_opencode: CLI wiring
Allow StringModelConfig to disable OpenAI strict tool definitions (\"strict\": true) for backends that reject them (e.g. sglang/vLLM speculative decoding with grammar constraints). When set to False, pydantic-ai skips sending strict on tool schemas.
…wiki_read_resource - WikiBuildCapability now implements ResourceAccess/ResourceTemplateAccess: OPA/OPS/OPL tickets surface as MCP resources (list_resources, @-completion, URI templates). - Rename agent-facing tool read_resource -> wiki_read_resource to avoid a name clash with the generic ResourceCapability's read_resource when a native agent hosts both toolsets. - The bound method stays read_resource (ResourceAccess protocol); the tool wrapper name is mapped in wiki_build_tools._build_method_wrappers.
Allow StringModelConfig to disable forced tool choice (tool_choice='required') for backends that reject it when it conflicts with their grammar constraints (e.g. sglang/vLLM speculative decoding DFLASH). When set to False, pydantic-ai falls back to tool_choice='auto'. Fixes structured outputs (output_type) on dspark which error with 'DFLASH speculative decoding does not support grammar-constrained decoding yet' when tool_choice is forced.
…oice_required The dspark (sglang DFLASH) backend keeps rejecting grammar-constrained decoding regardless of these client-side switches; strict and forced tool_choice flags did not help. Revert them to keep model config as before.
…iking-ops-opl-worker-tools # Conflicts: # src/wolfharness/capabilities/viking/tools.py
…fixes - ticket: add update_ops_ticket (in-place OPS patch with status transitions) - wiki_build_tools: register BOM enrichment + chapter planning tools - file_team_state: count active (non-terminal) tasks for capacity, unify create lock between single and batch dispatch - team_comm: task_list active_only filter - mcp_server: drop redundant unconditional PrefixedToolset wrapping (mcp_server_cap conditional prefixing already covers it); fixes test_function_model_discovers_mcp_tools_through_acp_transport - dcp/tools: extract _DISTILLATION_MAX_CHARS constant (PLR2004) - tests: add resource protocol test; ruff format + import fixes
test_live_upload_tree_then_link_relations requires a real OpenViking configuration (~/.openviking/ovcli.conf). Mark it real_mcp so the core CI job (which excludes real_mcp) does not collect it.
team_add_member now accepts initial_task or initial_task_id; the task is persisted and assigned before the member receives its first message, so dynamic workers never observe an empty mine_only task view and exit early. Recovery can bind a released pending/blocked task to a replacement member without duplicate task IDs. Includes related resource_capability and viking ticket/build-tools updates plus tests.
…-worker-tools # Conflicts: # src/wolfharness/capabilities/viking/__init__.py # src/wolfharness_config/capabilities.py
P2 concurrency: - materialization.py: wave cap 8→12 to match max_parallel_members - team_comm_capability.py: enforce max_parallel_members in team_add_member (count non-lead members with live runs, reject when cap hit) - ops_dispatch_plan (opa.py + ticket_engine.py): add max_parallel_shards param, group items by target_class into _entity_batch_limit()-sized shards with shard_id/worker_role/opa_ids/task_description, wave-cap + remaining_count P3 cleanup + OPA quality: - _mark_merge_conflict (entities.py): entity name in title, readable opa_id slug, human-readable finding prefix - discover_opa (opa.py + ticket_engine.py): prepend entity name to title; low-value filter skips relation_missed, frontmatter:* (unless content_missing/fact_conflict), Procedure/DTC/Part with relation_missed/extraction_missed; skipped_low_value counter in return - wiki_conductor.j2: action cap ≤3→≤6; OPS dispatch via sharded ops_dispatch_plan(max_parallel_shards=N) - wiki-team.yaml: removed stale write_text_atomic reference - Deleted orphan prompts: wiki_opl_worker.j2, wiki_ticket_reviewer.j2
…tch optimization Component template (template_materializer.py): - Branch on concept==Component: emit 总成概览 + 工作机理 (from causal_chain.normal_function) + optional 组成零件 + 来源 - Drop 规格参数/关键事实/步骤/因果链 for Component pages - Non-Component path unchanged Finalize gate (finalize.py): - Replace gap_category whitelist with _CORE_PATH_BLOCKER_CODES frozenset - Only block on: Component.working_mechanism, Fault.failure_mechanism, Device.critical_components, DTC.related_faults - Removed SymptomProfile.device_refs (schema-optional, no body fallback, closure defers it — stale as blocker in body-first design) - All other errors log warning and proceed to finalize Batch optimization (materialization.py): - Raise template shard cap 12→50 - Conductor merges all template shard URIs into one materialize_template_batch call per wave
Conductor's audit_wiki cache was never invalidated because conductor has no write tools — worker invalidations only affect their own instances. Added force_refresh param for explicit bypass, plus automatic entity-count staleness check (cheap list_entities call) that catches adds/deletes without reading file contents.
…source refs Template: - Add Fault branch: emit 失效描述 + 失效机理 (from causal_chain) + 影响范围 - Remove ## 来源 section from all concept templates (raw refs only on Device) - Remove 来源 from schema body_sections for all concepts Audit: - Strip confirmation_requirements to 4 core-path checks only: Component.working_mechanism, Fault.failure_mechanism, Device.critical_components, DTC.related_faults - Unregister LightweightMaterializationHook, BodyEvidenceHook, SourceReferenceHook from ENTITY_VALIDATION_HOOKS Also includes prior uncommitted fixes: - storage.py: object_name byte-clip for long filenames - opa.py/ticket_engine.py: repair_only disposition converts to gap OPA instead of silently skipping
When remote_sync fails, checkpoint is set to remote_sync_pending. On the next finalize_wiki call, instead of re-running audit (which would activate strict hooks on already-promoted confirmed entities and self-lock the gate), skip audit + promotion and retry only the remote upload via _retry_remote_sync.
…ice fuzzy lookup - finalize.py: entities param defaults to None; store auto-discovers - team_workflow_guard.py: accept finalized_local as valid receipt status - migration.py: fuzzy fallback for device_id → object_name mismatch
Truncated/stale source URIs in frontmatter sources are reference-quality issues, not data-integrity blockers. Hard rejection blocked finalize promotion writes when an entity had a bad source URI written via write_entities_batch (which skips this check). Now logs a warning instead.
finalize_wiki calls _current_source_snapshot_id() which raised ValueError on any unresolvable source URI. But audit_wiki drops unresolvable sources from its hash instead of raising — so the two snapshots disagreed. Now both sides skip unresolvable sources, matching hashes.
1. patch_entities_batch: add preloaded_contents param to skip double-read in build_relation_closure (content already read by ThreadPoolExecutor) 2. materialize_template_batch: skip overwriting confirmed/published entities (respect expert content during incremental ingestion) 3. plan_materialization_work: LLM shard task_description now includes existing_entity_check=mandatory instruction
- tickets/opa.py: feedback category never dedupes/merges — every submission mints a fresh record via uuid4 fragment on generated ids, so the same problem reported again (possibly by another expert) stays a separate OPA; explicit opa_id/opa_uri revisions still update in place - tickets/ticket.py: drop the pending-OPA reuse shortcut that silently discarded new content when any pending OPA existed for the target - carry in-progress wiki build batch (storage backends, quality, planning, hooks, templates) that the pipeline has been running against
…ing-mem-diag' into feature/wh/merge-to-chenbin
Same principle as the feedback-OPA fix: one external submission = one record. Blind consume/merge surfaces removed: - ingest_external_ops: auto id now carries a fresh random fragment, so same-parent/same-title submissions with different solution/analysis create distinct OPS records instead of being silently discarded as idempotent; explicit ops_uri revisions still rewrite in place - create_ops: source_type=external_expert skips the pipeline worker consolidation (retrieval_query dedupe) and mints a fresh record; pipeline default unchanged (concurrent workers still consolidate) - create_opl: source_type=external_expert skips the ops-set dedupe and mints a fresh record per snapshot; pipeline default unchanged Regression tests (xeno workspace): distinct records for repeated external OPS/OPL submissions, in-place revision via explicit URIs, and pipeline consolidation preserved.
Feature/wh/merge to chenbin
- Relax _validate_opa_uris to accept any viking://resources/ URI across namespaces, not just the wiki store namespace - Update VikingCapability tools and instructions for cross-namespace ticket references - Add ticket reference scope tests - Align capabilities config for broader URI handling
- Run ruff format on all wiki/ and viking/ re-export files - Run ruff check --fix --unsafe-fixes for auto-fixable lint issues - Add per-directory ruff ignores for wiki/ (CJK unicode, complex methods, magic values, import ordering — inherited from xeno-adp-agentic codebase) - Exclude wiki/ from mypy strict checking (841 type errors from copied code) - Restore backward-compat re-exports in viking/wiki_build.py, viking/ticket.py, viking/wiki_index.py (ruff auto-fix had removed explicit re-exports of underscore-prefixed names that tests depend on) - Fix test_resource_protocol.py wiki_cap fixture: directly inject FakeWikiBuildTools instead of mocking xeno_adp_agentic imports (_ensure_tools now imports from internal wolfharness.capabilities.wiki)
…quest Import was 'wolfharness.capabilities.wiki.index' (non-existent) instead of 'wolfharness.capabilities.wiki.tickets.index'. The ModuleNotFoundError was silently caught by the except Exception block, causing index injection to be skipped — WikiBuildIndex tests expected 2 messages but got 1.
- Fix _format_index_block import in build.py: was importing from non-existent wolfharness.capabilities.wiki.index, corrected to wolfharness.capabilities.wiki.tickets.index - Fix mypy attr-defined error in viking/wiki_build.py re-export: place type: ignore comment before noqa for correct mypy parsing
- mcp_server_cap.py: take wolf1069b/main tool filtering (before imports) - resource_capability.py: take wolf1069b/main MCP Resource refactor (3 tools: list_mcp_resources, list_mcp_resource_templates, read_mcp_resource) - manager.py: take wolf1069b/main supports_resources() negotiation, remove lazy mode, restore tool_prefix fallback - test_resource_capability.py: take wolf1069b/main test assertions - test_pool_skills.py: update _FakeClient with connected + supports_resources for compatibility with wolf1069b/main setup_server
_ticket_evidence() blindly merged cited_references[].uri with every evidence entry. evidence is a free-form user expression that may carry provider URIs or plain audit text (e.g. 'QuotedText: ...'), which the TicketEngine's _validate_opa_uris rejects as invalid evidence URIs and fails the whole OPA/OPS ticket submission. Extract the engine's OPA/OPS URI format rule into is_valid_op_uri (shared by _validate_opa_uris) on OPAMixin and TicketEngine. Ticket closures capture that predicate and pass it to _ticket_evidence, which keeps cited_references[].uri verbatim and only admits evidence entries that pass. Engines without the predicate keep the historical blind merge. Regression tests cover text rejection, URI extraction, and back-compat.
…ools The tool_prefix config was not applied in the get_capabilities() path — MCPToolset was never wrapped in PrefixedToolset and allowed_tools were not prefixed. This caused test_tool_prefix_namespaces_mcp_tools to fail. Fix: wrap MCPToolset in PrefixedToolset when tool_prefix is set (matching the McpServerCap provider path, RFC-0058) and prefix enabled_tools for the allowed_tools advertisement.
Code Review — PR #382 (APC/Viking archive + Wiki knowledge-base subsystem)Scope: 152 files, +40,654 / −2,001. Core framework changes + a new Verdict: Needs work — do not merge as-is. The framework-side design is solid in places, but three of the headline reliability guarantees are actually broken in practice, and the new wiki subsystem contains two already-diverged ~3K-line ticket engines with essentially no test coverage. Per the project convention that all changes be tested, this PR is not in a mergeable state. 🔴 Critical (must fix before merge)1. DCP non-native fallback discards the compaction result (
2. ACP archive retry-on-failure defeated by an over-narrow exception tuple (
3. Auto-ingest retry reuses the same The failed batch retains the original 4. Model tool-call args are a JSON string; cutting at a byte offset yields invalid JSON. Downstream 5. Two ~3K-line ticket engines have already diverged semantically ( The files are ~87% character-identical, but the divergence is semantic, not cosmetic:
🟠 Major (recommend fixing before merge)Framework / Viking side:
Wiki subsystem:
🧪 Test coverage
Other test-quality notes: Most concerning gaps: entity planning/relation-closure, finalize/audit, 🏗️ Architecture assessmentThe storage layer is genuinely well-engineered: clean The dominant architectural debt is duplication at the worst possible scale: two 90%-identical ticket engines that have already drifted semantically, plus the god-mixin bundle ( Positives: the lease handshake + session-cached tokens, the shared ✅ Recommendations
Note: review performed statically via |
No description provided.