@holoscript/holoscript-agent 2.0.3 → 2.0.4
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/holomesh-client.d.ts +21 -1
- package/dist/holomesh-client.js +31 -0
- package/dist/holomesh-client.js.map +1 -1
- package/dist/index.js +149 -20
- package/dist/index.js.map +1 -1
- package/dist/runner.js +118 -20
- package/dist/runner.js.map +1 -1
- package/dist/supervisor.js +149 -20
- package/dist/supervisor.js.map +1 -1
- package/package.json +1 -1
|
@@ -45,6 +45,14 @@ interface TeamMessage {
|
|
|
45
45
|
messageType: string;
|
|
46
46
|
createdAt: string;
|
|
47
47
|
}
|
|
48
|
+
/** Minimal knowledge-entry shape returned by the mesh knowledge endpoints. */
|
|
49
|
+
interface KnowledgeEntry {
|
|
50
|
+
id: string;
|
|
51
|
+
content: string;
|
|
52
|
+
domain?: string;
|
|
53
|
+
type?: string;
|
|
54
|
+
createdAt?: string;
|
|
55
|
+
}
|
|
48
56
|
declare class HolomeshClient {
|
|
49
57
|
private readonly apiBase;
|
|
50
58
|
private readonly bearer;
|
|
@@ -104,6 +112,18 @@ declare class HolomeshClient {
|
|
|
104
112
|
deleteTask(taskId: string): Promise<unknown>;
|
|
105
113
|
/** Delegate a board task to another agent. */
|
|
106
114
|
delegateTask(taskId: string, toAgentId: string): Promise<unknown>;
|
|
115
|
+
/**
|
|
116
|
+
* Query the TEAM knowledge base (the `rag_query` cognitive verb). Bearer-only
|
|
117
|
+
* GET; `q` is the server-side search filter. Returns [] on any failure so a
|
|
118
|
+
* retrieval miss never breaks a tick.
|
|
119
|
+
*/
|
|
120
|
+
queryTeamKnowledge(query: string, limit?: number): Promise<KnowledgeEntry[]>;
|
|
121
|
+
/**
|
|
122
|
+
* Query this agent's PRIVATE workspace knowledge (the `recall` cognitive verb).
|
|
123
|
+
* The endpoint has no server-side search param, so the caller filters by query
|
|
124
|
+
* client-side. Returns [] on any failure.
|
|
125
|
+
*/
|
|
126
|
+
queryPrivateKnowledge(): Promise<KnowledgeEntry[]>;
|
|
107
127
|
private req;
|
|
108
128
|
}
|
|
109
129
|
/**
|
|
@@ -116,4 +136,4 @@ declare class HolomeshClient {
|
|
|
116
136
|
declare function deriveSurface(seatName: string | undefined): string;
|
|
117
137
|
declare function pickClaimableTask(tasks: BoardTask[], brainCapabilityTags: string[]): BoardTask | undefined;
|
|
118
138
|
|
|
119
|
-
export { HolomeshClient, type HolomeshClientOptions, type RequestSigner, type TeamMessage, deriveSurface, pickClaimableTask };
|
|
139
|
+
export { HolomeshClient, type HolomeshClientOptions, type KnowledgeEntry, type RequestSigner, type TeamMessage, deriveSurface, pickClaimableTask };
|
package/dist/holomesh-client.js
CHANGED
|
@@ -105,6 +105,37 @@ var HolomeshClient = class {
|
|
|
105
105
|
async delegateTask(taskId, toAgentId) {
|
|
106
106
|
return this.req("PATCH", `/team/${this.teamId}/board/${taskId}`, await this.signBody({ action: "delegate", toAgentId }));
|
|
107
107
|
}
|
|
108
|
+
// ── Cognitive-verb knowledge surface (Phase 2.2 — recall / rag_query) ────────
|
|
109
|
+
/**
|
|
110
|
+
* Query the TEAM knowledge base (the `rag_query` cognitive verb). Bearer-only
|
|
111
|
+
* GET; `q` is the server-side search filter. Returns [] on any failure so a
|
|
112
|
+
* retrieval miss never breaks a tick.
|
|
113
|
+
*/
|
|
114
|
+
async queryTeamKnowledge(query, limit = 5) {
|
|
115
|
+
const qs = new URLSearchParams({ q: query, limit: String(limit) }).toString();
|
|
116
|
+
try {
|
|
117
|
+
const data = await this.req(
|
|
118
|
+
"GET",
|
|
119
|
+
`/team/${this.teamId}/knowledge?${qs}`
|
|
120
|
+
);
|
|
121
|
+
return data.entries ?? [];
|
|
122
|
+
} catch {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Query this agent's PRIVATE workspace knowledge (the `recall` cognitive verb).
|
|
128
|
+
* The endpoint has no server-side search param, so the caller filters by query
|
|
129
|
+
* client-side. Returns [] on any failure.
|
|
130
|
+
*/
|
|
131
|
+
async queryPrivateKnowledge() {
|
|
132
|
+
try {
|
|
133
|
+
const data = await this.req("GET", `/knowledge/private`);
|
|
134
|
+
return data.entries ?? [];
|
|
135
|
+
} catch {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
}
|
|
108
139
|
async req(method, path, body) {
|
|
109
140
|
const url = `${this.apiBase}${path}`;
|
|
110
141
|
const res = await this.fetchImpl(url, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/holomesh-client.ts"],"sourcesContent":["import type { BoardTask } from './types.js';\nimport type { CaelAuditRecord } from './cael-builder.js';\n\n/** Wraps a request body in a signed envelope for strict-mode endpoints (e.g. /team/:id/join). */\nexport type RequestSigner = (\n body: Record<string, unknown>\n) => Promise<Record<string, unknown>>;\n\nexport interface HolomeshClientOptions {\n apiBase: string;\n bearer: string;\n teamId: string;\n fetchImpl?: typeof fetch;\n /** EIP-191 signing function. When present, used on strict endpoints like joinTeam(). */\n signer?: RequestSigner;\n}\n\nexport interface TeamMessage {\n id: string;\n fromAgentId: string;\n fromAgentName: string;\n content: string;\n messageType: string;\n createdAt: string;\n}\n\nexport class HolomeshClient {\n private readonly apiBase: string;\n private readonly bearer: string;\n private readonly teamId: string;\n private readonly fetchImpl: typeof fetch;\n private readonly signer?: RequestSigner;\n\n constructor(opts: HolomeshClientOptions) {\n this.apiBase = opts.apiBase.replace(/\\/$/, '');\n this.bearer = opts.bearer;\n this.teamId = opts.teamId;\n this.fetchImpl = opts.fetchImpl ?? fetch;\n this.signer = opts.signer;\n }\n\n /** Wrap body in a signed envelope when a signer is available (strict-mode endpoints). */\n private async signBody(body: Record<string, unknown>): Promise<Record<string, unknown>> {\n return this.signer ? await this.signer(body) : body;\n }\n\n async heartbeat(payload: { agentName: string; surface: string }): Promise<void> {\n await this.req('POST', `/team/${this.teamId}/presence`, await this.signBody(payload as Record<string, unknown>));\n }\n\n async getOpenTasks(): Promise<BoardTask[]> {\n const data = await this.req<{ tasks?: BoardTask[]; open?: BoardTask[] }>(\n 'GET',\n `/team/${this.teamId}/board`\n );\n return data.tasks ?? data.open ?? [];\n }\n\n async claim(taskId: string): Promise<BoardTask> {\n return this.req<BoardTask>('PATCH', `/team/${this.teamId}/board/${taskId}`, await this.signBody({ action: 'claim' }));\n }\n\n async joinTeam(): Promise<{ success: boolean; role?: string; members?: number }> {\n return this.req<{ success: boolean; role?: string; members?: number }>(\n 'POST',\n `/team/${this.teamId}/join`,\n await this.signBody({})\n );\n }\n\n async sendMessageOnTask(taskId: string, body: string): Promise<void> {\n await this.req('POST', `/team/${this.teamId}/message`, await this.signBody({\n to: 'team',\n subject: `task:${taskId}`,\n content: body,\n }));\n }\n\n async markDone(taskId: string, summary: string, commitHash?: string): Promise<void> {\n await this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, await this.signBody({\n action: 'done',\n summary,\n // verification_evidence required by server before task can be closed.\n verification_evidence: summary,\n // Exclude commitHash when undefined — JSON.stringify drops undefined but\n // canonicalizeSigning preserves it as the literal string \"undefined\",\n // causing a signature-mismatch vs what the server sees after JSON.parse.\n ...(commitHash !== undefined ? { commitHash } : {}),\n }));\n }\n\n // POST CAEL audit records for this agent. Server validator at\n // packages/mcp-server/src/holomesh/routes/core-routes.ts:472-533 requires\n // bearer == handle owner OR founder; the per-surface x402 bearer is the\n // handle owner so this resolves correctly. Records that fail shape\n // validation (layer_hashes != 7 elements, missing tick_iso/operation/\n // fnv1a_chain) are silently dropped server-side, not rejected as a batch.\n async postAuditRecords(\n handle: string,\n records: CaelAuditRecord[]\n ): Promise<{ appended: number; rejected: number }> {\n // Audit endpoint uses bearer-only auth — no signed envelope wrapper.\n return this.req<{ appended: number; rejected: number }>(\n 'POST',\n `/agent/${encodeURIComponent(handle)}/audit`,\n { records } as unknown as Record<string, unknown>\n );\n }\n\n async whoAmI(): Promise<{ agentId: string; surface: string; wallet?: string }> {\n // GET /api/holomesh/me returns { agentId, name, wallet, isFounder, teamId, teams, permissions }\n // (see packages/mcp-server/src/holomesh/routes/core-routes.ts §/me handler).\n // It does NOT return a `surface` field — derive it from the seat name on the\n // client side. Seat naming convention (set by the provisioning admin path):\n // claudecode-claude-x402 → claude-code\n // cursor-claude-x402 → claude-cursor\n // gemini-antigravity → gemini-antigravity\n // copilot-vscode → copilot-vscode\n // Founder → unknown (shared key, no surface attribution)\n const raw = await this.req<{\n agentId: string;\n name?: string;\n wallet?: string;\n }>('GET', '/me');\n return {\n agentId: raw.agentId,\n surface: deriveSurface(raw.name),\n wallet: raw.wallet,\n };\n }\n\n // ── Team Message Surface (E4 delegated-authority protocol) ───────────────────\n\n /** Read recent team messages. */\n async getTeamMessages(limit = 20): Promise<TeamMessage[]> {\n const data = await this.req<{ messages?: TeamMessage[]; success?: boolean }>(\n 'GET',\n `/team/${this.teamId}/messages?limit=${limit}`\n );\n return data.messages ?? [];\n }\n\n /** Post a message to the team feed. */\n async sendTeamMessage(content: string, messageType = 'text'): Promise<void> {\n await this.req('POST', `/team/${this.teamId}/message`, await this.signBody({ content, type: messageType }));\n }\n\n // ── Owner-op API wrappers (E4) ─────────────────────────────────────────────\n\n /** Switch team mode. Requires owner or founder role. */\n async setTeamMode(mode: string, reason?: string): Promise<{ mode: string; unchanged?: boolean }> {\n return this.req('POST', `/team/${this.teamId}/mode`, await this.signBody({ mode, reason } as Record<string, unknown>));\n }\n\n /** Update room preferences. Requires config:write permission. */\n async patchRoomPrefs(prefs: { communicationStyle?: string; objective?: string }): Promise<{\n communicationStyle: string;\n objective: string;\n }> {\n return this.req('PATCH', `/team/${this.teamId}/room`, await this.signBody(prefs as Record<string, unknown>));\n }\n\n /** Update a board task. */\n async updateTask(\n taskId: string,\n updates: {\n title?: string;\n description?: string;\n priority?: number;\n tags?: string[];\n }\n ): Promise<unknown> {\n return this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, await this.signBody({ action: 'update', ...updates } as Record<string, unknown>));\n }\n\n /** Delete a board task. */\n async deleteTask(taskId: string): Promise<unknown> {\n return this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, await this.signBody({ action: 'delete' }));\n }\n\n /** Delegate a board task to another agent. */\n async delegateTask(taskId: string, toAgentId: string): Promise<unknown> {\n return this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, await this.signBody({ action: 'delegate', toAgentId }));\n }\n\n private async req<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.apiBase}${path}`;\n // HoloMesh REST auth: server (packages/mcp-server/src/holomesh/auth-utils.ts\n // resolveRequestingAgent) accepts EITHER `Authorization: Bearer <token>`\n // (HTTP-standard, used here) OR `x-mcp-api-key: <token>` (orchestrator\n // convention). Both resolve through the same key-registry / agent-store /\n // env-fallback chain. Bearer is preferred for new code (W.087 vertex B,\n // task_1777073616424_klls).\n const res = await this.fetchImpl(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.bearer}`,\n 'content-type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n throw new Error(`HoloMesh ${method} ${path} ${res.status}: ${txt.slice(0, 300)}`);\n }\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n }\n}\n\n/**\n * Derive a surface tag from a seat name returned by /me. Mirrors the surface\n * detection in scripts/probe-surface-bearers.mjs and hooks/lib/holomesh-env.mjs\n * so a single agent's surface attribution is consistent across read and write\n * paths. Returns 'unknown' when the seat name doesn't encode a surface\n * (e.g. shared-key resolution to \"Founder\").\n */\nexport function deriveSurface(seatName: string | undefined): string {\n if (!seatName) return 'unknown';\n const n = seatName.toLowerCase();\n if (n.startsWith('claudecode')) return 'claude-code';\n if (n.startsWith('cursor')) return 'claude-cursor';\n if (n.startsWith('claudedesktop')) return 'claude-desktop';\n if (n.startsWith('vscode-claude') || n.startsWith('claude-vscode')) return 'claude-vscode';\n if (n.startsWith('gemini')) return 'gemini-antigravity';\n if (n.startsWith('copilot')) return 'copilot-vscode';\n return 'unknown';\n}\n\nexport function pickClaimableTask(\n tasks: BoardTask[],\n brainCapabilityTags: string[]\n): BoardTask | undefined {\n const wanted = new Set(brainCapabilityTags.map((t) => t.toLowerCase()));\n const open = tasks.filter((t) => t.status === 'open' && !t.claimedBy);\n const scored = open\n .map((t) => ({ task: t, score: scoreTask(t, wanted) }))\n .filter((s) => s.score > 0)\n .sort((a, b) => b.score - a.score || priority(a.task) - priority(b.task));\n return scored[0]?.task;\n}\n\nfunction scoreTask(task: BoardTask, wanted: Set<string>): number {\n const tags = (task.tags ?? []).map((t) => t.toLowerCase());\n const text = `${task.title} ${task.description ?? ''}`.toLowerCase();\n let score = 0;\n for (const tag of tags) if (wanted.has(tag)) score += 2;\n for (const w of wanted) if (text.includes(w)) score += 1;\n return score;\n}\n\nfunction priority(t: BoardTask): number {\n if (typeof t.priority === 'number') return t.priority;\n const map: Record<string, number> = { critical: 1, high: 2, medium: 4, low: 6 };\n return map[String(t.priority).toLowerCase()] ?? 5;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/holomesh-client.ts"],"sourcesContent":["import type { BoardTask } from './types.js';\nimport type { CaelAuditRecord } from './cael-builder.js';\n\n/** Wraps a request body in a signed envelope for strict-mode endpoints (e.g. /team/:id/join). */\nexport type RequestSigner = (\n body: Record<string, unknown>\n) => Promise<Record<string, unknown>>;\n\nexport interface HolomeshClientOptions {\n apiBase: string;\n bearer: string;\n teamId: string;\n fetchImpl?: typeof fetch;\n /** EIP-191 signing function. When present, used on strict endpoints like joinTeam(). */\n signer?: RequestSigner;\n}\n\nexport interface TeamMessage {\n id: string;\n fromAgentId: string;\n fromAgentName: string;\n content: string;\n messageType: string;\n createdAt: string;\n}\n\n/** Minimal knowledge-entry shape returned by the mesh knowledge endpoints. */\nexport interface KnowledgeEntry {\n id: string;\n content: string;\n domain?: string;\n type?: string;\n createdAt?: string;\n}\n\nexport class HolomeshClient {\n private readonly apiBase: string;\n private readonly bearer: string;\n private readonly teamId: string;\n private readonly fetchImpl: typeof fetch;\n private readonly signer?: RequestSigner;\n\n constructor(opts: HolomeshClientOptions) {\n this.apiBase = opts.apiBase.replace(/\\/$/, '');\n this.bearer = opts.bearer;\n this.teamId = opts.teamId;\n this.fetchImpl = opts.fetchImpl ?? fetch;\n this.signer = opts.signer;\n }\n\n /** Wrap body in a signed envelope when a signer is available (strict-mode endpoints). */\n private async signBody(body: Record<string, unknown>): Promise<Record<string, unknown>> {\n return this.signer ? await this.signer(body) : body;\n }\n\n async heartbeat(payload: { agentName: string; surface: string }): Promise<void> {\n await this.req('POST', `/team/${this.teamId}/presence`, await this.signBody(payload as Record<string, unknown>));\n }\n\n async getOpenTasks(): Promise<BoardTask[]> {\n const data = await this.req<{ tasks?: BoardTask[]; open?: BoardTask[] }>(\n 'GET',\n `/team/${this.teamId}/board`\n );\n return data.tasks ?? data.open ?? [];\n }\n\n async claim(taskId: string): Promise<BoardTask> {\n return this.req<BoardTask>('PATCH', `/team/${this.teamId}/board/${taskId}`, await this.signBody({ action: 'claim' }));\n }\n\n async joinTeam(): Promise<{ success: boolean; role?: string; members?: number }> {\n return this.req<{ success: boolean; role?: string; members?: number }>(\n 'POST',\n `/team/${this.teamId}/join`,\n await this.signBody({})\n );\n }\n\n async sendMessageOnTask(taskId: string, body: string): Promise<void> {\n await this.req('POST', `/team/${this.teamId}/message`, await this.signBody({\n to: 'team',\n subject: `task:${taskId}`,\n content: body,\n }));\n }\n\n async markDone(taskId: string, summary: string, commitHash?: string): Promise<void> {\n await this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, await this.signBody({\n action: 'done',\n summary,\n // verification_evidence required by server before task can be closed.\n verification_evidence: summary,\n // Exclude commitHash when undefined — JSON.stringify drops undefined but\n // canonicalizeSigning preserves it as the literal string \"undefined\",\n // causing a signature-mismatch vs what the server sees after JSON.parse.\n ...(commitHash !== undefined ? { commitHash } : {}),\n }));\n }\n\n // POST CAEL audit records for this agent. Server validator at\n // packages/mcp-server/src/holomesh/routes/core-routes.ts:472-533 requires\n // bearer == handle owner OR founder; the per-surface x402 bearer is the\n // handle owner so this resolves correctly. Records that fail shape\n // validation (layer_hashes != 7 elements, missing tick_iso/operation/\n // fnv1a_chain) are silently dropped server-side, not rejected as a batch.\n async postAuditRecords(\n handle: string,\n records: CaelAuditRecord[]\n ): Promise<{ appended: number; rejected: number }> {\n // Audit endpoint uses bearer-only auth — no signed envelope wrapper.\n return this.req<{ appended: number; rejected: number }>(\n 'POST',\n `/agent/${encodeURIComponent(handle)}/audit`,\n { records } as unknown as Record<string, unknown>\n );\n }\n\n async whoAmI(): Promise<{ agentId: string; surface: string; wallet?: string }> {\n // GET /api/holomesh/me returns { agentId, name, wallet, isFounder, teamId, teams, permissions }\n // (see packages/mcp-server/src/holomesh/routes/core-routes.ts §/me handler).\n // It does NOT return a `surface` field — derive it from the seat name on the\n // client side. Seat naming convention (set by the provisioning admin path):\n // claudecode-claude-x402 → claude-code\n // cursor-claude-x402 → claude-cursor\n // gemini-antigravity → gemini-antigravity\n // copilot-vscode → copilot-vscode\n // Founder → unknown (shared key, no surface attribution)\n const raw = await this.req<{\n agentId: string;\n name?: string;\n wallet?: string;\n }>('GET', '/me');\n return {\n agentId: raw.agentId,\n surface: deriveSurface(raw.name),\n wallet: raw.wallet,\n };\n }\n\n // ── Team Message Surface (E4 delegated-authority protocol) ───────────────────\n\n /** Read recent team messages. */\n async getTeamMessages(limit = 20): Promise<TeamMessage[]> {\n const data = await this.req<{ messages?: TeamMessage[]; success?: boolean }>(\n 'GET',\n `/team/${this.teamId}/messages?limit=${limit}`\n );\n return data.messages ?? [];\n }\n\n /** Post a message to the team feed. */\n async sendTeamMessage(content: string, messageType = 'text'): Promise<void> {\n await this.req('POST', `/team/${this.teamId}/message`, await this.signBody({ content, type: messageType }));\n }\n\n // ── Owner-op API wrappers (E4) ─────────────────────────────────────────────\n\n /** Switch team mode. Requires owner or founder role. */\n async setTeamMode(mode: string, reason?: string): Promise<{ mode: string; unchanged?: boolean }> {\n return this.req('POST', `/team/${this.teamId}/mode`, await this.signBody({ mode, reason } as Record<string, unknown>));\n }\n\n /** Update room preferences. Requires config:write permission. */\n async patchRoomPrefs(prefs: { communicationStyle?: string; objective?: string }): Promise<{\n communicationStyle: string;\n objective: string;\n }> {\n return this.req('PATCH', `/team/${this.teamId}/room`, await this.signBody(prefs as Record<string, unknown>));\n }\n\n /** Update a board task. */\n async updateTask(\n taskId: string,\n updates: {\n title?: string;\n description?: string;\n priority?: number;\n tags?: string[];\n }\n ): Promise<unknown> {\n return this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, await this.signBody({ action: 'update', ...updates } as Record<string, unknown>));\n }\n\n /** Delete a board task. */\n async deleteTask(taskId: string): Promise<unknown> {\n return this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, await this.signBody({ action: 'delete' }));\n }\n\n /** Delegate a board task to another agent. */\n async delegateTask(taskId: string, toAgentId: string): Promise<unknown> {\n return this.req('PATCH', `/team/${this.teamId}/board/${taskId}`, await this.signBody({ action: 'delegate', toAgentId }));\n }\n\n // ── Cognitive-verb knowledge surface (Phase 2.2 — recall / rag_query) ────────\n\n /**\n * Query the TEAM knowledge base (the `rag_query` cognitive verb). Bearer-only\n * GET; `q` is the server-side search filter. Returns [] on any failure so a\n * retrieval miss never breaks a tick.\n */\n async queryTeamKnowledge(query: string, limit = 5): Promise<KnowledgeEntry[]> {\n const qs = new URLSearchParams({ q: query, limit: String(limit) }).toString();\n try {\n const data = await this.req<{ entries?: KnowledgeEntry[] }>(\n 'GET',\n `/team/${this.teamId}/knowledge?${qs}`\n );\n return data.entries ?? [];\n } catch {\n return [];\n }\n }\n\n /**\n * Query this agent's PRIVATE workspace knowledge (the `recall` cognitive verb).\n * The endpoint has no server-side search param, so the caller filters by query\n * client-side. Returns [] on any failure.\n */\n async queryPrivateKnowledge(): Promise<KnowledgeEntry[]> {\n try {\n const data = await this.req<{ entries?: KnowledgeEntry[] }>('GET', `/knowledge/private`);\n return data.entries ?? [];\n } catch {\n return [];\n }\n }\n\n private async req<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.apiBase}${path}`;\n // HoloMesh REST auth: server (packages/mcp-server/src/holomesh/auth-utils.ts\n // resolveRequestingAgent) accepts EITHER `Authorization: Bearer <token>`\n // (HTTP-standard, used here) OR `x-mcp-api-key: <token>` (orchestrator\n // convention). Both resolve through the same key-registry / agent-store /\n // env-fallback chain. Bearer is preferred for new code (W.087 vertex B,\n // task_1777073616424_klls).\n const res = await this.fetchImpl(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.bearer}`,\n 'content-type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!res.ok) {\n const txt = await res.text().catch(() => '');\n throw new Error(`HoloMesh ${method} ${path} ${res.status}: ${txt.slice(0, 300)}`);\n }\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n }\n}\n\n/**\n * Derive a surface tag from a seat name returned by /me. Mirrors the surface\n * detection in scripts/probe-surface-bearers.mjs and hooks/lib/holomesh-env.mjs\n * so a single agent's surface attribution is consistent across read and write\n * paths. Returns 'unknown' when the seat name doesn't encode a surface\n * (e.g. shared-key resolution to \"Founder\").\n */\nexport function deriveSurface(seatName: string | undefined): string {\n if (!seatName) return 'unknown';\n const n = seatName.toLowerCase();\n if (n.startsWith('claudecode')) return 'claude-code';\n if (n.startsWith('cursor')) return 'claude-cursor';\n if (n.startsWith('claudedesktop')) return 'claude-desktop';\n if (n.startsWith('vscode-claude') || n.startsWith('claude-vscode')) return 'claude-vscode';\n if (n.startsWith('gemini')) return 'gemini-antigravity';\n if (n.startsWith('copilot')) return 'copilot-vscode';\n return 'unknown';\n}\n\nexport function pickClaimableTask(\n tasks: BoardTask[],\n brainCapabilityTags: string[]\n): BoardTask | undefined {\n const wanted = new Set(brainCapabilityTags.map((t) => t.toLowerCase()));\n const open = tasks.filter((t) => t.status === 'open' && !t.claimedBy);\n const scored = open\n .map((t) => ({ task: t, score: scoreTask(t, wanted) }))\n .filter((s) => s.score > 0)\n .sort((a, b) => b.score - a.score || priority(a.task) - priority(b.task));\n return scored[0]?.task;\n}\n\nfunction scoreTask(task: BoardTask, wanted: Set<string>): number {\n const tags = (task.tags ?? []).map((t) => t.toLowerCase());\n const text = `${task.title} ${task.description ?? ''}`.toLowerCase();\n let score = 0;\n for (const tag of tags) if (wanted.has(tag)) score += 2;\n for (const w of wanted) if (text.includes(w)) score += 1;\n return score;\n}\n\nfunction priority(t: BoardTask): number {\n if (typeof t.priority === 'number') return t.priority;\n const map: Record<string, number> = { critical: 1, high: 2, medium: 4, low: 6 };\n return map[String(t.priority).toLowerCase()] ?? 5;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -618,6 +618,37 @@ var HolomeshClient = class {
|
|
|
618
618
|
async delegateTask(taskId, toAgentId) {
|
|
619
619
|
return this.req("PATCH", `/team/${this.teamId}/board/${taskId}`, await this.signBody({ action: "delegate", toAgentId }));
|
|
620
620
|
}
|
|
621
|
+
// ── Cognitive-verb knowledge surface (Phase 2.2 — recall / rag_query) ────────
|
|
622
|
+
/**
|
|
623
|
+
* Query the TEAM knowledge base (the `rag_query` cognitive verb). Bearer-only
|
|
624
|
+
* GET; `q` is the server-side search filter. Returns [] on any failure so a
|
|
625
|
+
* retrieval miss never breaks a tick.
|
|
626
|
+
*/
|
|
627
|
+
async queryTeamKnowledge(query, limit = 5) {
|
|
628
|
+
const qs = new URLSearchParams({ q: query, limit: String(limit) }).toString();
|
|
629
|
+
try {
|
|
630
|
+
const data = await this.req(
|
|
631
|
+
"GET",
|
|
632
|
+
`/team/${this.teamId}/knowledge?${qs}`
|
|
633
|
+
);
|
|
634
|
+
return data.entries ?? [];
|
|
635
|
+
} catch {
|
|
636
|
+
return [];
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Query this agent's PRIVATE workspace knowledge (the `recall` cognitive verb).
|
|
641
|
+
* The endpoint has no server-side search param, so the caller filters by query
|
|
642
|
+
* client-side. Returns [] on any failure.
|
|
643
|
+
*/
|
|
644
|
+
async queryPrivateKnowledge() {
|
|
645
|
+
try {
|
|
646
|
+
const data = await this.req("GET", `/knowledge/private`);
|
|
647
|
+
return data.entries ?? [];
|
|
648
|
+
} catch {
|
|
649
|
+
return [];
|
|
650
|
+
}
|
|
651
|
+
}
|
|
621
652
|
async req(method, path, body) {
|
|
622
653
|
const url = `${this.apiBase}${path}`;
|
|
623
654
|
const res = await this.fetchImpl(url, {
|
|
@@ -1116,6 +1147,109 @@ function errResult(id, message) {
|
|
|
1116
1147
|
return { type: "tool_result", tool_use_id: id, content: message, is_error: true };
|
|
1117
1148
|
}
|
|
1118
1149
|
|
|
1150
|
+
// src/cognitive-verbs.ts
|
|
1151
|
+
var DEFAULT_LIMIT = 5;
|
|
1152
|
+
var MAX_ENTRY_CHARS = 320;
|
|
1153
|
+
var MAX_INJECTED_CHARS = 2400;
|
|
1154
|
+
function strField(config, ...keys) {
|
|
1155
|
+
for (const k of keys) {
|
|
1156
|
+
const v = config[k];
|
|
1157
|
+
if (typeof v === "string" && v.trim()) return v.trim();
|
|
1158
|
+
}
|
|
1159
|
+
return "";
|
|
1160
|
+
}
|
|
1161
|
+
function numField(config, key, fallback) {
|
|
1162
|
+
const v = config[key];
|
|
1163
|
+
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
1164
|
+
}
|
|
1165
|
+
function formatEntries(entries) {
|
|
1166
|
+
let out = "";
|
|
1167
|
+
for (const e of entries) {
|
|
1168
|
+
const line = `- ${(e.content ?? "").replace(/\s+/g, " ").trim().slice(0, MAX_ENTRY_CHARS)}`;
|
|
1169
|
+
if (out.length + line.length > MAX_INJECTED_CHARS) break;
|
|
1170
|
+
out += (out ? "\n" : "") + line;
|
|
1171
|
+
}
|
|
1172
|
+
return out;
|
|
1173
|
+
}
|
|
1174
|
+
async function augmentWithOnTaskCognition(deps) {
|
|
1175
|
+
let content = deps.systemPrompt;
|
|
1176
|
+
if (!deps.onTaskActions || deps.onTaskActions.length === 0) return content;
|
|
1177
|
+
for (const action of deps.onTaskActions) {
|
|
1178
|
+
try {
|
|
1179
|
+
switch (action.verb) {
|
|
1180
|
+
case "llm_call": {
|
|
1181
|
+
const prompt = strField(action.config, "prompt");
|
|
1182
|
+
if (prompt) {
|
|
1183
|
+
content += `
|
|
1184
|
+
|
|
1185
|
+
[Brain on_task directive]
|
|
1186
|
+
${prompt}`;
|
|
1187
|
+
deps.log({ ev: "on-task-llm-call", taskId: deps.task.id, promptLen: prompt.length });
|
|
1188
|
+
}
|
|
1189
|
+
break;
|
|
1190
|
+
}
|
|
1191
|
+
case "rag_query": {
|
|
1192
|
+
const query = strField(action.config, "query", "q") || deps.task.title;
|
|
1193
|
+
const limit = numField(action.config, "limit", DEFAULT_LIMIT);
|
|
1194
|
+
const entries = await deps.queryTeamKnowledge(query, limit);
|
|
1195
|
+
if (entries.length > 0) {
|
|
1196
|
+
content += `
|
|
1197
|
+
|
|
1198
|
+
[Retrieved knowledge for "${query}"]
|
|
1199
|
+
${formatEntries(entries)}`;
|
|
1200
|
+
}
|
|
1201
|
+
deps.log({ ev: "on-task-rag-query", taskId: deps.task.id, query, retrieved: entries.length });
|
|
1202
|
+
break;
|
|
1203
|
+
}
|
|
1204
|
+
case "recall": {
|
|
1205
|
+
const query = strField(action.config, "query", "q");
|
|
1206
|
+
const limit = numField(action.config, "limit", DEFAULT_LIMIT);
|
|
1207
|
+
const all = await deps.queryPrivateKnowledge();
|
|
1208
|
+
const needle = query.toLowerCase();
|
|
1209
|
+
const matched = (needle ? all.filter((e) => `${e.id ?? ""} ${e.content ?? ""}`.toLowerCase().includes(needle)) : all).slice(0, limit);
|
|
1210
|
+
if (matched.length > 0) {
|
|
1211
|
+
content += `
|
|
1212
|
+
|
|
1213
|
+
[Recalled memory${query ? ` for "${query}"` : ""}]
|
|
1214
|
+
${formatEntries(matched)}`;
|
|
1215
|
+
}
|
|
1216
|
+
deps.log({ ev: "on-task-recall", taskId: deps.task.id, query, recalled: matched.length });
|
|
1217
|
+
break;
|
|
1218
|
+
}
|
|
1219
|
+
case "plan": {
|
|
1220
|
+
if (!deps.plan) break;
|
|
1221
|
+
const goal = strField(action.config, "goal", "prompt", "of") || deps.task.title;
|
|
1222
|
+
const planText = await deps.plan(
|
|
1223
|
+
`Produce a short numbered plan (max 6 steps) to accomplish this task. Be concrete and specific to the goal; do not execute it.
|
|
1224
|
+
|
|
1225
|
+
Goal: ${goal}`
|
|
1226
|
+
);
|
|
1227
|
+
const trimmed = planText.trim().slice(0, MAX_INJECTED_CHARS);
|
|
1228
|
+
if (trimmed) {
|
|
1229
|
+
content += `
|
|
1230
|
+
|
|
1231
|
+
[Plan]
|
|
1232
|
+
${trimmed}`;
|
|
1233
|
+
deps.log({ ev: "on-task-plan", taskId: deps.task.id, planLen: trimmed.length });
|
|
1234
|
+
}
|
|
1235
|
+
break;
|
|
1236
|
+
}
|
|
1237
|
+
// `reflect` is handled post-artifact in runner.ts, not here.
|
|
1238
|
+
default:
|
|
1239
|
+
break;
|
|
1240
|
+
}
|
|
1241
|
+
} catch (err) {
|
|
1242
|
+
deps.log({
|
|
1243
|
+
ev: "on-task-verb-error",
|
|
1244
|
+
taskId: deps.task.id,
|
|
1245
|
+
verb: action.verb,
|
|
1246
|
+
message: err instanceof Error ? err.message : String(err)
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
return content;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1119
1253
|
// src/runner.ts
|
|
1120
1254
|
var RUNTIME_VERSION = "1.0.0";
|
|
1121
1255
|
var AgentRunner = class {
|
|
@@ -1198,26 +1332,21 @@ var AgentRunner = class {
|
|
|
1198
1332
|
log({ ev: "claim", taskId: target.id, title: target.title });
|
|
1199
1333
|
await mesh.claim(target.id);
|
|
1200
1334
|
const start = Date.now();
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
[Brain on_task directive]
|
|
1217
|
-
${llmCallAction.config.prompt}`;
|
|
1218
|
-
log({ ev: "on-task-llm-call", taskId: target.id, promptLen: llmCallAction.config.prompt.length });
|
|
1219
|
-
}
|
|
1220
|
-
}
|
|
1335
|
+
const systemContent = await augmentWithOnTaskCognition({
|
|
1336
|
+
systemPrompt: brain.systemPrompt,
|
|
1337
|
+
onTaskActions: brain.onTaskActions ?? [],
|
|
1338
|
+
task: { id: target.id, title: target.title },
|
|
1339
|
+
queryTeamKnowledge: (q, limit) => mesh.queryTeamKnowledge(q, limit),
|
|
1340
|
+
queryPrivateKnowledge: () => mesh.queryPrivateKnowledge(),
|
|
1341
|
+
plan: async (prompt) => {
|
|
1342
|
+
const resp = await provider.complete(
|
|
1343
|
+
{ messages: [{ role: "user", content: prompt }], maxTokens: 512, temperature: 0.3 },
|
|
1344
|
+
identity.llmModel
|
|
1345
|
+
);
|
|
1346
|
+
return resp.content;
|
|
1347
|
+
},
|
|
1348
|
+
log
|
|
1349
|
+
});
|
|
1221
1350
|
const messages = [
|
|
1222
1351
|
{ role: "system", content: systemContent },
|
|
1223
1352
|
{ role: "user", content: buildTaskPrompt(target) }
|