Files
HarborForge.PlexumPlugin/manifest.json
hzhang 9e43021ba5 feat(kb): dynamic-kb-* tool family + <kb-block> subblock provider
Implements the HF side of Plexum DESIGN-DYNAMIC-BLOCK.md Phase 2 — the
HarborForge knowledge-base block agents cache facts into per session.
Cross-runtime aligned with the ClawSkills workflow text (same tool
names + input schemas + return shapes will land on openclaw side later).

manifest.json:
  - 5 new dynamic-kb-* tool contracts (list-kbs / list-topics /
    list-facts / cache / evict)
  - dynamicSubblocks contract entry declaring this plugin owns
    the "kb-block" <dynamic-block> subblock

internal/kbblock/ (new):
  - Per-session storage at <PLEXUM_PROFILE_ROOT>/agents/<id>/sessions/
    <sid>/plugins/harbor-forge/kb-block.json
  - Entry carries ID (HF backend DB primary key) + KBCode + SourceTopic
    + Content + InsertSeq for §9 #4 cache-insertion-order rendering
  - Render emits <kb-fact id=N kb=<code> source=topic:<slug>>...
    </kb-fact> (no title/description per §9 #8; source attr omitted
    when empty)
  - Fade NOT applied in v1 — §9 #3 lock has fade params shared with
    memory but implementation deferred until prod data informs whether
    KB needs it; agent dynamic-kb-evict is the only eviction path
  - 11 unit tests

internal/kbclient/ (new):
  - Typed HTTP client for HarborForge.Backend KB routes verified
    against app/api/routers/knowledge.py
  - GET /knowledge-bases[?project=<code>] (list KBs)
  - GET /knowledge-bases/{kb_code}/topics (list topics)
  - GET /knowledge-bases/{kb_code}/tree (full hierarchy — ListFacts
    flattens this client-side filtered by topic ids; backend has no
    flat list-facts-in-topic route)
  - GET /knowledge-facts/{id} per fact (GetFacts batch loop)
  - Auth: plugin-level Bearer APIKey. Per-agent hf-token resolution
    is a TODO when SDK exposes secret-mgr access.

internal/tools/kb.go (new) + tools.go:
  - 5 tool functions hooked into Dispatch
  - KBDeps struct bundles Client + ProfileRoot + SessionFor + Turn
  - Cache/evict use SessionFor lookup populated by main.go's
    RenderDynamicSubblock (called per turn by host; carries sessionID)

cmd/plexum-harborforge-plugin/main.go:
  - kbClient field initialized when BackendURL + APIKey present
  - profileRoot cached for kbblock path resolution
  - agentSession sync.Map tracks agentID → sessionID; populated by
    RenderDynamicSubblock so subsequent tool calls in the same turn
    can resolve the per-session kb-block.json path
  - Implements sdkplugin.DynamicBlockProvider.RenderDynamicSubblock:
    opens kbblock for (agentID, sessionID) and returns its Render()
    body; host wraps in <kb-block>...</kb-block>

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-05 20:15:34 +01:00

84 lines
4.3 KiB
JSON

{
"name": "harbor-forge",
"version": "0.1.0",
"activation": "eager",
"executable": "plexum-harborforge-plugin",
"contracts": {
"tools": [
{
"name": "harborforge_status",
"description": "Return the plugin's resolved config + Monitor bridge health + Calendar scheduler status + telemetry snapshot.",
"inputSchema": {"type": "object"}
},
{
"name": "harborforge_telemetry",
"description": "Current system + agent telemetry (the same snapshot served to the local HarborForge.Monitor over the monitor_port).",
"inputSchema": {"type": "object"}
},
{
"name": "harborforge_monitor_telemetry",
"description": "Last telemetry payload the Monitor bridge fetched, with timing info — useful when diagnosing bridge connectivity.",
"inputSchema": {"type": "object"}
},
{
"name": "harborforge_calendar_status",
"description": "Active Calendar slot (if any) plus next-up + recent-history. Returns Calendar scheduler state when no slot is active.",
"inputSchema": {"type": "object"}
},
{
"name": "harborforge_calendar_complete",
"description": "Mark the agent's currently-active Calendar slot as completed and notify the backend.",
"inputSchema": {"type": "object", "properties": {"summary": {"type": "string"}}}
},
{
"name": "harborforge_calendar_abort",
"description": "Abort the agent's currently-active Calendar slot (e.g. unrecoverable error). Optionally include a reason.",
"inputSchema": {"type": "object", "properties": {"reason": {"type": "string"}}}
},
{
"name": "harborforge_calendar_pause",
"description": "Pause the agent's currently-active Calendar slot — heartbeat tracks paused state until resume/abort/complete.",
"inputSchema": {"type": "object", "properties": {"reason": {"type": "string"}}}
},
{
"name": "harborforge_calendar_resume",
"description": "Resume a paused Calendar slot for the agent.",
"inputSchema": {"type": "object"}
},
{
"name": "harborforge_restart_status",
"description": "Check whether a Plexum host restart is pending (backend-driven flag). Reports last poll time and pending flag.",
"inputSchema": {"type": "object"}
},
{
"name": "dynamic-kb-list-kbs",
"description": "List HarborForge Knowledge Bases the agent can access. Optional project-code filter (equivalent to `hf knowledge-base list [--project <code>]`). Returns code/title/description per KB. Browse — follow up with dynamic-kb-list-topics to drill into one.",
"inputSchema": {"type": "object", "properties": {"project-code": {"type": "string"}}}
},
{
"name": "dynamic-kb-list-topics",
"description": "List topics in one KB by code. Returns topic id/slug/description per row. Browse — follow up with dynamic-kb-list-facts.",
"inputSchema": {"type": "object", "properties": {"kb-code": {"type": "string"}}, "required": ["kb-code"]}
},
{
"name": "dynamic-kb-list-facts",
"description": "List facts in given topics. Returns lightweight previews (id/topic/title/snippet). Browse — feed into dynamic-kb-cache to commit selected facts to your kb-block.",
"inputSchema": {"type": "object", "properties": {"kb-code": {"type": "string"}, "topic-ids": {"type": "array", "items": {"type": "integer"}}}, "required": ["kb-code", "topic-ids"]}
},
{
"name": "dynamic-kb-cache",
"description": "Cache specific KB facts into your per-session kb-block (visible in System prompt next turn). Pass previous-dynamic-id to consume the matching list-facts browse output.",
"inputSchema": {"type": "object", "properties": {"kb-code": {"type": "string"}, "fact-ids": {"type": "array", "items": {"type": "integer"}}, "previous-dynamic-id": {"type": "string"}}, "required": ["kb-code", "fact-ids"]}
},
{
"name": "dynamic-kb-evict",
"description": "Remove cached facts from your kb-block (free ctx). Takes effect starting your next turn.",
"inputSchema": {"type": "object", "properties": {"fact-ids": {"type": "array", "items": {"type": "integer"}}}, "required": ["fact-ids"]}
}
],
"dynamicSubblocks": [
{"name": "kb-block"}
]
}
}