ohwow 0.4.3 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +1 -1
- package/dist/index.js +702 -667
- package/dist/mcp-server/index.js +4 -4
- package/dist/migrations/069-rag-corpus-stats.sql +16 -0
- package/dist/migrations/070-connectors.sql +25 -0
- package/dist/migrations/071-embedding-columns.sql +9 -0
- package/dist/migrations/072-biological-org.sql +45 -0
- package/dist/migrations/072-document-processing-queue.sql +17 -0
- package/dist/migrations/073-knowledge-graph.sql +31 -0
- package/dist/migrations/074-peer-knowledge-count.sql +3 -0
- package/dist/migrations/075-bpp-wiring.sql +39 -0
- package/dist/web/assets/index-BvOfuQPF.js +100 -0
- package/dist/web/assets/index-C47z59TE.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +3 -3
- package/dist/web/assets/index-CzPQPzpE.js +0 -100
- package/dist/web/assets/index-D_dz8KjO.css +0 -1
package/dist/mcp-server/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire } from 'module'; const require = createRequire(import.meta.url);
|
|
2
|
-
import{McpServer as
|
|
2
|
+
import{McpServer as Z}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as tt}from"@modelcontextprotocol/sdk/server/stdio.js";import{readFileSync as f,existsSync as C}from"fs";import{join as x}from"path";import{homedir as H}from"os";var g=class n{constructor(o,t,e){this.baseUrl=`http://127.0.0.1:${o}`,this.token=t,this.tokenPath=e}static async create(){let o=x(H(),".ohwow"),t=x(o,"config.json"),e=x(o,"data","daemon.token"),r=7700;if(C(t))try{let c=f(t,"utf-8"),a=JSON.parse(c);a.port&&(r=a.port)}catch{}if(!C(e))throw new Error("OHWOW daemon is not running. Start it with: ohwow");let s=f(e,"utf-8").trim();if(!s)throw new Error("Couldn't authenticate with OHWOW daemon. Try: ohwow restart");let i=new n(r,s,e);try{await i.get("/health")}catch{throw new Error("OHWOW daemon is not running. Start it with: ohwow")}return i}refreshToken(){try{let o=f(this.tokenPath,"utf-8").trim();if(o&&o!==this.token)return this.token=o,!0}catch{}return!1}authHeaders(){return{Authorization:`Bearer ${this.token}`}}async fetchWithRetry(o,t){let e=await fetch(o,t);if(e.status===401&&this.refreshToken()){let r={...t.headers,...this.authHeaders()};e=await fetch(o,{...t,headers:r})}return e}async get(o){let t=await this.fetchWithRetry(`${this.baseUrl}${o}`,{headers:this.authHeaders()});if(!t.ok)throw new Error(`ohwow daemon error on GET ${o}: ${t.status}. Check daemon with: ohwow logs`);return t.json()}async post(o,t){let e=await this.fetchWithRetry(`${this.baseUrl}${o}`,{method:"POST",headers:{...this.authHeaders(),"Content-Type":"application/json"},body:JSON.stringify(t)});if(!e.ok)throw new Error(`ohwow daemon error on POST ${o}: ${e.status}. Check daemon with: ohwow logs`);return e.json()}async postSSE(o,t,e=12e4){let r=new AbortController,s=setTimeout(()=>r.abort(),e),i=[],c=async()=>fetch(`${this.baseUrl}${o}`,{method:"POST",headers:{...this.authHeaders(),"Content-Type":"application/json",Accept:"text/event-stream"},body:JSON.stringify(t),signal:r.signal});try{let a=await c();if(a.status===401&&this.refreshToken()&&(a=await c()),!a.ok)throw new Error(`Daemon API error: ${a.status} ${a.statusText}`);if(!a.body)throw new Error("No response body from daemon");let p=a.body.getReader(),b=new TextDecoder,m="";for(;;){let{done:w,value:L}=await p.read();if(w)break;m+=b.decode(L,{stream:!0});let R=m.split(`
|
|
3
3
|
`);m=R.pop()||"";for(let T of R){if(!T.startsWith("data: "))continue;let O=T.slice(6).trim();if(O!=="[DONE]")try{let u=JSON.parse(O);if(u.type==="text"&&u.content)i.push(u.content);else if(u.type==="tool_start")i.push(`
|
|
4
4
|
[Using tool: ${u.name}]
|
|
5
5
|
`);else if(u.type==="error")i.push(`
|
|
@@ -59,7 +59,7 @@ A2A protocol, PDF forms, media generation, automation creation, and
|
|
|
59
59
|
anything not listed above.
|
|
60
60
|
`;import{createServer as F}from"http";import{writeFileSync as G,unlinkSync as z,existsSync as K}from"fs";import{join as B}from"path";import{homedir as V}from"os";var S=B(V(),".ohwow","data","mcp-sampling.port");function J(n){let o=null,t=F(async(r,s)=>{if(r.method!=="POST"||r.url!=="/sampling"){s.writeHead(404),s.end("Not found");return}let i="";for await(let a of r)i+=a;let c;try{c=JSON.parse(i)}catch{s.writeHead(400),s.end(JSON.stringify({error:"Invalid JSON"}));return}if(!c.messages?.length){s.writeHead(400),s.end(JSON.stringify({error:"messages array is required"}));return}try{let a=c.messages.map(w=>({role:w.role,content:{type:"text",text:w.content}})),p=await n.server.createMessage({messages:a,systemPrompt:c.systemPrompt,maxTokens:c.maxTokens||4096,temperature:c.temperature}),m={content:Array.isArray(p.content)?p.content.filter(w=>w.type==="text").map(w=>w.text).join(""):typeof p.content=="object"&&"text"in p.content?p.content.text:String(p.content),model:p.model,stopReason:p.stopReason??void 0};s.writeHead(200,{"Content-Type":"application/json"}),s.end(JSON.stringify(m))}catch(a){let p=a instanceof Error?a.message:"Sampling failed";s.writeHead(500),s.end(JSON.stringify({error:p}))}});return o=t,t.listen(0,"127.0.0.1",()=>{let r=t.address();if(r&&typeof r=="object"){let s=r.port;try{G(S,String(s)),process.stderr.write(`[ohwow-mcp] Sampling bridge listening on port ${s}
|
|
61
61
|
`)}catch{process.stderr.write(`[ohwow-mcp] Could not write sampling port file
|
|
62
|
-
`)}}}),{cleanup:()=>{o&&(o.close(),o=null);try{K(S)&&z(S)}catch{}}}}var
|
|
63
|
-
`),process.exit(1)}let o=new
|
|
62
|
+
`)}}}),{cleanup:()=>{o&&(o.close(),o=null);try{K(S)&&z(S)}catch{}}}}import{createRequire as Q}from"module";var X=Q(import.meta.url),Y=X("../package.json"),E=Y.version;async function Ft(){let n;try{n=await g.create()}catch(s){process.stderr.write(`[ohwow-mcp] ${s instanceof Error?s.message:"Unknown error"}
|
|
63
|
+
`),process.exit(1)}let o=new Z({name:"ohwow",version:E});I(o,n),P(o,n);let t=new tt,e=null,r=async()=>{e?.();try{await o.close()}catch{}process.exit(0)};process.on("SIGTERM",r),process.on("SIGINT",r);try{await o.connect(t),process.stderr.write(`[ohwow-mcp] Connected (v${E})
|
|
64
64
|
`),e=J(o).cleanup}catch(s){process.stderr.write(`[ohwow-mcp] Failed to connect: ${s instanceof Error?s.message:"Unknown error"}
|
|
65
|
-
`),process.exit(1)}}export{
|
|
65
|
+
`),process.exit(1)}}export{Ft as startMcpServer};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- 069: RAG Corpus Statistics
|
|
3
|
+
--
|
|
4
|
+
-- Tracks per-term document frequency for IDF-aware BM25 scoring.
|
|
5
|
+
-- ============================================================================
|
|
6
|
+
|
|
7
|
+
CREATE TABLE IF NOT EXISTS rag_corpus_stats (
|
|
8
|
+
workspace_id TEXT NOT NULL,
|
|
9
|
+
term TEXT NOT NULL,
|
|
10
|
+
doc_frequency INTEGER NOT NULL DEFAULT 1,
|
|
11
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
12
|
+
PRIMARY KEY (workspace_id, term)
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_rag_corpus_stats_workspace
|
|
16
|
+
ON rag_corpus_stats(workspace_id);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- 070: Data Source Connectors
|
|
3
|
+
--
|
|
4
|
+
-- Configuration table for external data source connectors (GitHub, local
|
|
5
|
+
-- files, Google Drive, etc.) that feed documents into the knowledge base.
|
|
6
|
+
-- ============================================================================
|
|
7
|
+
|
|
8
|
+
CREATE TABLE IF NOT EXISTS data_source_connectors (
|
|
9
|
+
id TEXT PRIMARY KEY,
|
|
10
|
+
workspace_id TEXT NOT NULL,
|
|
11
|
+
type TEXT NOT NULL,
|
|
12
|
+
name TEXT NOT NULL,
|
|
13
|
+
settings TEXT NOT NULL DEFAULT '{}',
|
|
14
|
+
sync_interval_minutes INTEGER NOT NULL DEFAULT 30,
|
|
15
|
+
prune_interval_days INTEGER NOT NULL DEFAULT 30,
|
|
16
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
17
|
+
last_sync_at TEXT,
|
|
18
|
+
last_sync_status TEXT,
|
|
19
|
+
last_sync_error TEXT,
|
|
20
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
21
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_connectors_workspace
|
|
25
|
+
ON data_source_connectors(workspace_id, enabled);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- ============================================================================
|
|
2
|
+
-- 071: Embedding Columns for Knowledge Chunks
|
|
3
|
+
--
|
|
4
|
+
-- Adds vector embedding storage to enable hybrid BM25 + semantic search.
|
|
5
|
+
-- ============================================================================
|
|
6
|
+
|
|
7
|
+
ALTER TABLE agent_workforce_knowledge_chunks ADD COLUMN embedding BLOB;
|
|
8
|
+
|
|
9
|
+
ALTER TABLE agent_workforce_knowledge_documents ADD COLUMN embedding_model TEXT;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
-- =====================================================================
|
|
2
|
+
-- Migration 072: Biological Org Hierarchy + Budget Guard
|
|
3
|
+
-- Extends departments into organ systems with purpose and nesting.
|
|
4
|
+
-- Adds agent synapses for biological agent-to-agent connections.
|
|
5
|
+
-- =====================================================================
|
|
6
|
+
|
|
7
|
+
-- Organ system extensions: purpose, nesting, type classification
|
|
8
|
+
-- @statement
|
|
9
|
+
ALTER TABLE agent_workforce_departments ADD COLUMN telos TEXT;
|
|
10
|
+
-- @statement
|
|
11
|
+
ALTER TABLE agent_workforce_departments ADD COLUMN parent_id TEXT;
|
|
12
|
+
-- @statement
|
|
13
|
+
ALTER TABLE agent_workforce_departments ADD COLUMN system_type TEXT DEFAULT 'organ_system';
|
|
14
|
+
|
|
15
|
+
-- Agent-to-agent synaptic connections
|
|
16
|
+
-- Directed, typed, strength-decaying connections between agents.
|
|
17
|
+
-- Types:
|
|
18
|
+
-- coordination = bidirectional, fast (nervous system signal)
|
|
19
|
+
-- delegation = one-way task assignment (efferent signal)
|
|
20
|
+
-- nurture = mentor/mentee growth (growth hormone)
|
|
21
|
+
-- symbiotic = mutualistic, both benefit (emergent from collaboration)
|
|
22
|
+
-- immune = one monitors the other's outputs (watchdog)
|
|
23
|
+
-- @statement
|
|
24
|
+
CREATE TABLE IF NOT EXISTS agent_synapses (
|
|
25
|
+
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
|
|
26
|
+
workspace_id TEXT NOT NULL,
|
|
27
|
+
source_agent_id TEXT NOT NULL,
|
|
28
|
+
target_agent_id TEXT NOT NULL,
|
|
29
|
+
synapse_type TEXT NOT NULL CHECK (synapse_type IN ('coordination','delegation','nurture','symbiotic','immune')),
|
|
30
|
+
strength REAL DEFAULT 0.5,
|
|
31
|
+
origin TEXT DEFAULT 'configured' CHECK (origin IN ('configured','emergent','hybrid')),
|
|
32
|
+
evidence TEXT DEFAULT '[]',
|
|
33
|
+
last_activated TEXT,
|
|
34
|
+
activation_count INTEGER DEFAULT 0,
|
|
35
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
36
|
+
updated_at TEXT DEFAULT (datetime('now')),
|
|
37
|
+
UNIQUE(workspace_id, source_agent_id, target_agent_id, synapse_type)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
-- @statement
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_synapses_source ON agent_synapses(source_agent_id);
|
|
42
|
+
-- @statement
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_synapses_target ON agent_synapses(target_agent_id);
|
|
44
|
+
-- @statement
|
|
45
|
+
CREATE INDEX IF NOT EXISTS idx_synapses_workspace ON agent_synapses(workspace_id);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS document_processing_queue (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
workspace_id TEXT NOT NULL,
|
|
4
|
+
document_id TEXT NOT NULL,
|
|
5
|
+
status TEXT NOT NULL DEFAULT 'pending', -- pending, processing, done, failed
|
|
6
|
+
payload TEXT NOT NULL DEFAULT '{}', -- JSON: { source_type, file_path?, url?, ... }
|
|
7
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
8
|
+
started_at TEXT,
|
|
9
|
+
completed_at TEXT,
|
|
10
|
+
error TEXT
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE INDEX IF NOT EXISTS idx_doc_queue_status
|
|
14
|
+
ON document_processing_queue(status, created_at);
|
|
15
|
+
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_doc_queue_workspace
|
|
17
|
+
ON document_processing_queue(workspace_id);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
-- Entities extracted from knowledge chunks
|
|
2
|
+
CREATE TABLE IF NOT EXISTS knowledge_graph_entities (
|
|
3
|
+
id TEXT PRIMARY KEY,
|
|
4
|
+
workspace_id TEXT NOT NULL,
|
|
5
|
+
chunk_id TEXT NOT NULL,
|
|
6
|
+
entity_text TEXT NOT NULL,
|
|
7
|
+
entity_type TEXT NOT NULL,
|
|
8
|
+
confidence REAL NOT NULL DEFAULT 1.0,
|
|
9
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
CREATE INDEX IF NOT EXISTS idx_kg_entities_workspace ON knowledge_graph_entities(workspace_id);
|
|
13
|
+
CREATE INDEX IF NOT EXISTS idx_kg_entities_chunk ON knowledge_graph_entities(chunk_id);
|
|
14
|
+
CREATE INDEX IF NOT EXISTS idx_kg_entities_text ON knowledge_graph_entities(workspace_id, entity_text);
|
|
15
|
+
|
|
16
|
+
-- Relationships between entities
|
|
17
|
+
CREATE TABLE IF NOT EXISTS knowledge_graph_edges (
|
|
18
|
+
id TEXT PRIMARY KEY,
|
|
19
|
+
workspace_id TEXT NOT NULL,
|
|
20
|
+
source_entity_id TEXT NOT NULL,
|
|
21
|
+
target_entity_id TEXT NOT NULL,
|
|
22
|
+
relation TEXT NOT NULL,
|
|
23
|
+
source_chunk_id TEXT NOT NULL,
|
|
24
|
+
confidence REAL NOT NULL DEFAULT 1.0,
|
|
25
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_kg_edges_workspace ON knowledge_graph_edges(workspace_id);
|
|
29
|
+
CREATE INDEX IF NOT EXISTS idx_kg_edges_source ON knowledge_graph_edges(source_entity_id);
|
|
30
|
+
CREATE INDEX IF NOT EXISTS idx_kg_edges_target ON knowledge_graph_edges(target_entity_id);
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_kg_edges_chunk ON knowledge_graph_edges(source_chunk_id);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
-- BPP Wiring — Soul persistence, homeostasis action log, immune state transitions
|
|
2
|
+
-- Supports Phase 6 of the BPP hot-path integration.
|
|
3
|
+
|
|
4
|
+
-- Soul snapshots: periodic persistence of agent identity computation
|
|
5
|
+
CREATE TABLE IF NOT EXISTS soul_snapshots (
|
|
6
|
+
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
|
|
7
|
+
agent_id TEXT NOT NULL,
|
|
8
|
+
workspace_id TEXT NOT NULL,
|
|
9
|
+
soul TEXT NOT NULL, -- JSON: full AgentSoul object
|
|
10
|
+
confidence REAL NOT NULL DEFAULT 0,
|
|
11
|
+
emerging_identity TEXT,
|
|
12
|
+
computed_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
13
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
14
|
+
);
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_soul_snapshots_agent ON soul_snapshots(agent_id, workspace_id, computed_at);
|
|
16
|
+
|
|
17
|
+
-- Homeostasis action log: audit trail of corrective actions taken
|
|
18
|
+
CREATE TABLE IF NOT EXISTS homeostasis_action_log (
|
|
19
|
+
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
|
|
20
|
+
workspace_id TEXT NOT NULL,
|
|
21
|
+
metric TEXT NOT NULL,
|
|
22
|
+
action_type TEXT NOT NULL,
|
|
23
|
+
reason TEXT,
|
|
24
|
+
severity REAL NOT NULL DEFAULT 0,
|
|
25
|
+
outcome TEXT,
|
|
26
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
27
|
+
);
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_homeostasis_actions_ws ON homeostasis_action_log(workspace_id, created_at);
|
|
29
|
+
|
|
30
|
+
-- Immune state transitions: track alert level escalation/de-escalation
|
|
31
|
+
CREATE TABLE IF NOT EXISTS immune_state_transitions (
|
|
32
|
+
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
|
|
33
|
+
workspace_id TEXT NOT NULL,
|
|
34
|
+
from_level TEXT NOT NULL,
|
|
35
|
+
to_level TEXT NOT NULL,
|
|
36
|
+
trigger_incident_id TEXT,
|
|
37
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
38
|
+
);
|
|
39
|
+
CREATE INDEX IF NOT EXISTS idx_immune_transitions_ws ON immune_state_transitions(workspace_id, created_at);
|