hyperstack-core 1.0.0
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/LICENSE +21 -0
- package/README.md +154 -0
- package/SKILL.md +118 -0
- package/adapters/openclaw.js +221 -0
- package/cli.js +500 -0
- package/examples/before-after.js +110 -0
- package/examples/openclaw-multiagent.js +214 -0
- package/index.js +18 -0
- package/package.json +50 -0
- package/src/client.js +267 -0
- package/templates/openclaw-multiagent.json +98 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CascadeAI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# hyperstack-core
|
|
2
|
+
|
|
3
|
+
Typed graph memory for AI agents. Replace `GOALS.md` + `DECISIONS.md` with queryable cards and relations.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
npm i hyperstack-core
|
|
7
|
+
npx hyperstack-core init openclaw-multiagent
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## The Problem
|
|
11
|
+
|
|
12
|
+
OpenClaw multi-agent setups use markdown files for coordination:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
# DECISIONS.md (append-only)
|
|
16
|
+
- 2026-02-15: Use Clerk for auth (coder-agent)
|
|
17
|
+
- 2026-02-15: Deploy needs auth migration first (deploy-agent)
|
|
18
|
+
- 2026-02-16: Migration blocks production deploy (ops-agent)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Try answering: **"What blocks the production deploy?"**
|
|
22
|
+
|
|
23
|
+
With markdown: `grep -r "blocks.*deploy" *.md` — manual, fragile, returns text blobs.
|
|
24
|
+
|
|
25
|
+
## The Solution
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import { HyperStackClient } from "hyperstack-core";
|
|
29
|
+
|
|
30
|
+
const hs = new HyperStackClient({ apiKey: "hs_..." });
|
|
31
|
+
|
|
32
|
+
// Coder agent records a decision
|
|
33
|
+
await hs.decide({
|
|
34
|
+
slug: "use-clerk",
|
|
35
|
+
title: "Use Clerk for auth",
|
|
36
|
+
body: "Better DX, lower cost, native Next.js support",
|
|
37
|
+
decidedBy: "agent-coder",
|
|
38
|
+
affects: ["auth-api"],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Deploy agent records a blocker
|
|
42
|
+
await hs.store({
|
|
43
|
+
slug: "migration-23",
|
|
44
|
+
title: "Auth migration to Clerk",
|
|
45
|
+
cardType: "task",
|
|
46
|
+
links: [
|
|
47
|
+
{ target: "deploy-prod", relation: "blocks" },
|
|
48
|
+
{ target: "use-clerk", relation: "depends_on" },
|
|
49
|
+
],
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Ops agent asks: what blocks deploy?
|
|
53
|
+
const result = await hs.blockers("deploy-prod");
|
|
54
|
+
// → { blockers: [{ slug: "migration-23", title: "Auth migration to Clerk" }] }
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Typed relations, not text blobs.** `task→blocks→deploy` is queryable. A paragraph in DECISIONS.md is not.
|
|
58
|
+
|
|
59
|
+
## OpenClaw Integration
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import { createOpenClawAdapter } from "hyperstack-core/adapters/openclaw";
|
|
63
|
+
|
|
64
|
+
// Each agent gets its own adapter
|
|
65
|
+
const researcher = createOpenClawAdapter({ agentId: "researcher" });
|
|
66
|
+
const builder = createOpenClawAdapter({ agentId: "builder" });
|
|
67
|
+
|
|
68
|
+
// Register on session start
|
|
69
|
+
await researcher.onSessionStart({
|
|
70
|
+
agentName: "Research Agent",
|
|
71
|
+
agentRole: "Investigate questions, store findings as context cards",
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Use tools in agent logic
|
|
75
|
+
await researcher.tools.hs_store({
|
|
76
|
+
slug: "finding-clerk-pricing",
|
|
77
|
+
title: "Clerk pricing analysis",
|
|
78
|
+
body: "Free for 10K MAU, $0.02/MAU after. Cheaper than Auth0 at our scale.",
|
|
79
|
+
type: "context",
|
|
80
|
+
links: "use-clerk:related",
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Builder queries shared knowledge
|
|
84
|
+
const blockers = await builder.tools.hs_blockers({ slug: "deploy-prod" });
|
|
85
|
+
// → "1 blocker: [migration-23] Auth migration to Clerk"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## CLI
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Initialize with multi-agent template
|
|
92
|
+
npx hyperstack-core init openclaw-multiagent
|
|
93
|
+
|
|
94
|
+
# Store cards
|
|
95
|
+
npx hyperstack-core store --slug "use-clerk" --title "Use Clerk" --type decision
|
|
96
|
+
|
|
97
|
+
# Record decisions
|
|
98
|
+
npx hyperstack-core decide --slug "use-clerk" --title "Use Clerk" --rationale "Better DX"
|
|
99
|
+
|
|
100
|
+
# Check blockers
|
|
101
|
+
npx hyperstack-core blockers deploy-prod
|
|
102
|
+
|
|
103
|
+
# Traverse graph
|
|
104
|
+
npx hyperstack-core graph auth-api --depth 2
|
|
105
|
+
|
|
106
|
+
# Search
|
|
107
|
+
npx hyperstack-core search "authentication setup"
|
|
108
|
+
|
|
109
|
+
# List all cards
|
|
110
|
+
npx hyperstack-core list
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Why Not Mem0/Cognee?
|
|
114
|
+
|
|
115
|
+
| | hyperstack-core | Mem0 | Cognee |
|
|
116
|
+
|--|---|---|---|
|
|
117
|
+
| "What blocks deploy?" | Exact: 2 typed blockers | Fuzzy: 17 similar tasks | Generic entities |
|
|
118
|
+
| Relations | `task→blocks→deploy` (typed) | Auto-extracted (hallucinated) | Generic graph |
|
|
119
|
+
| Cost per op | **$0** (deterministic) | ~$0.002 (LLM extraction) | ~$0.002 |
|
|
120
|
+
| Multi-agent | Built-in agent tagging | Shared userId issues | No agent awareness |
|
|
121
|
+
| Setup | `npm i` + 1 env var | Docker + config | Docker + Neo4j |
|
|
122
|
+
|
|
123
|
+
Mem0 finds "similar" cards. HyperStack finds **exactly** what blocks task #42.
|
|
124
|
+
|
|
125
|
+
## How It Works
|
|
126
|
+
|
|
127
|
+
Cards are typed objects with explicit relations:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
[task:deploy-prod] "Deploy to production"
|
|
131
|
+
←blocks— [task:migration-23] "Auth migration to Clerk"
|
|
132
|
+
←blocks— [blocker:staging-tests] "Staging tests failing"
|
|
133
|
+
—assigned_to→ [agent:deploy-agent]
|
|
134
|
+
—depends_on→ [decision:use-clerk]
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Every card stores: slug, title, body, cardType, links (typed relations), keywords, meta.
|
|
138
|
+
Every relation is explicit — no LLM extraction, no hallucinated connections.
|
|
139
|
+
|
|
140
|
+
Backed by HyperStack API (Neon PostgreSQL + pgvector for hybrid search).
|
|
141
|
+
|
|
142
|
+
## Setup
|
|
143
|
+
|
|
144
|
+
1. Get a free API key: [cascadeai.dev/hyperstack](https://cascadeai.dev/hyperstack)
|
|
145
|
+
2. `export HYPERSTACK_API_KEY=hs_your_key`
|
|
146
|
+
3. `npm i hyperstack-core`
|
|
147
|
+
4. `npx hyperstack-core init openclaw-multiagent`
|
|
148
|
+
|
|
149
|
+
Free tier: 10 cards, keyword search.
|
|
150
|
+
Pro ($29/mo): 100 cards, graph traversal, time-travel, semantic search.
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
MIT
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hyperstack
|
|
3
|
+
description: "Typed graph memory for multi-agent coordination. Replace GOALS.md + DECISIONS.md with queryable cards and relations. Ask 'what blocks task X?' and get exact answers, not text blobs."
|
|
4
|
+
user-invocable: true
|
|
5
|
+
homepage: https://cascadeai.dev/hyperstack
|
|
6
|
+
metadata:
|
|
7
|
+
openclaw:
|
|
8
|
+
emoji: "🃏"
|
|
9
|
+
requires:
|
|
10
|
+
env:
|
|
11
|
+
- HYPERSTACK_API_KEY
|
|
12
|
+
primaryEnv: HYPERSTACK_API_KEY
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# HyperStack — Typed Graph Memory for Multi-Agent Coordination
|
|
16
|
+
|
|
17
|
+
## What this does
|
|
18
|
+
|
|
19
|
+
Replaces markdown-file coordination (GOALS.md, DECISIONS.md, WORKING.md) with a typed knowledge graph that any agent can query.
|
|
20
|
+
|
|
21
|
+
**Before** (current OpenClaw multi-agent):
|
|
22
|
+
```
|
|
23
|
+
# DECISIONS.md (append-only)
|
|
24
|
+
- 2026-02-15: Use Clerk for auth (coder-agent)
|
|
25
|
+
- 2026-02-16: Migration blocks production deploy (ops-agent)
|
|
26
|
+
```
|
|
27
|
+
"What blocks deploy?" → `grep -r "blocks.*deploy" *.md` → manual, fragile
|
|
28
|
+
|
|
29
|
+
**After** (HyperStack):
|
|
30
|
+
```
|
|
31
|
+
"What blocks deploy?" → hs_blockers deploy-prod → [migration-23] Auth migration to Clerk
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Typed relations. Exact answers. Zero LLM cost.
|
|
35
|
+
|
|
36
|
+
## Tools
|
|
37
|
+
|
|
38
|
+
### hs_search
|
|
39
|
+
Search the shared knowledge graph.
|
|
40
|
+
```
|
|
41
|
+
hs_search({ query: "authentication setup" })
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### hs_store
|
|
45
|
+
Store a card in the graph. Auto-tags with your agent ID.
|
|
46
|
+
```
|
|
47
|
+
hs_store({
|
|
48
|
+
slug: "use-clerk",
|
|
49
|
+
title: "Use Clerk for auth",
|
|
50
|
+
body: "Better DX, lower cost, native Next.js support",
|
|
51
|
+
type: "decision",
|
|
52
|
+
links: "auth-api:triggers,alice:decided"
|
|
53
|
+
})
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### hs_decide
|
|
57
|
+
Record a decision with full provenance — who decided, what it affects, what it blocks.
|
|
58
|
+
```
|
|
59
|
+
hs_decide({
|
|
60
|
+
slug: "use-clerk",
|
|
61
|
+
title: "Use Clerk for auth",
|
|
62
|
+
rationale: "Better DX, lower cost vs Auth0",
|
|
63
|
+
affects: "auth-api,user-service",
|
|
64
|
+
blocks: ""
|
|
65
|
+
})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### hs_blockers
|
|
69
|
+
Check what blocks a task/card. Returns exact typed blockers, not fuzzy search results.
|
|
70
|
+
```
|
|
71
|
+
hs_blockers({ slug: "deploy-prod" })
|
|
72
|
+
→ "1 blocker: [migration-23] Auth migration to Clerk"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### hs_graph
|
|
76
|
+
Traverse the knowledge graph from a starting card. See connections, ownership, dependencies.
|
|
77
|
+
```
|
|
78
|
+
hs_graph({ from: "auth-api", depth: 2 })
|
|
79
|
+
→ nodes: [auth-api, use-clerk, migration-23, alice]
|
|
80
|
+
→ edges: [auth-api→triggers→use-clerk, migration-23→blocks→deploy-prod]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### hs_my_cards
|
|
84
|
+
List all cards created by this agent.
|
|
85
|
+
```
|
|
86
|
+
hs_my_cards()
|
|
87
|
+
→ "3 cards by agent researcher: [finding-clerk-pricing] [finding-auth0-limits] [finding-nextauth-deprecated]"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Multi-Agent Setup
|
|
91
|
+
|
|
92
|
+
Each agent gets its own ID. Cards are auto-tagged so you can see who created what.
|
|
93
|
+
|
|
94
|
+
Recommended roles:
|
|
95
|
+
- **coordinator**: Routes tasks, monitors blockers (`hs_blockers`, `hs_graph`, `hs_decide`)
|
|
96
|
+
- **researcher**: Investigates, stores findings (`hs_search`, `hs_store`)
|
|
97
|
+
- **builder**: Implements, records tech decisions (`hs_store`, `hs_decide`, `hs_blockers`)
|
|
98
|
+
|
|
99
|
+
## Setup
|
|
100
|
+
|
|
101
|
+
1. Get free API key: https://cascadeai.dev/hyperstack
|
|
102
|
+
2. Set `HYPERSTACK_API_KEY=hs_your_key` in your OpenClaw env
|
|
103
|
+
3. Tools are available immediately
|
|
104
|
+
|
|
105
|
+
Free: 10 cards, keyword search.
|
|
106
|
+
Pro ($29/mo): 100 cards, graph traversal, semantic search, time-travel debugging.
|
|
107
|
+
|
|
108
|
+
## When to use
|
|
109
|
+
|
|
110
|
+
- **Start of session**: `hs_search` for relevant context
|
|
111
|
+
- **Decision made**: `hs_decide` with rationale and links
|
|
112
|
+
- **Task blocked**: `hs_store` with `blocks` relation
|
|
113
|
+
- **Before starting work**: `hs_blockers` to check dependencies
|
|
114
|
+
- **New finding**: `hs_store` as context card
|
|
115
|
+
|
|
116
|
+
## Data safety
|
|
117
|
+
|
|
118
|
+
NEVER store passwords, API keys, tokens, PII, or credentials. Cards should be safe in a data breach. Always confirm with user before storing.
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hyperstack-core/adapters/openclaw.js
|
|
3
|
+
*
|
|
4
|
+
* OpenClaw adapter for HyperStack.
|
|
5
|
+
* Replaces GOALS.md / DECISIONS.md with typed graph memory.
|
|
6
|
+
*
|
|
7
|
+
* Usage in OpenClaw config (openclaw.json):
|
|
8
|
+
* {
|
|
9
|
+
* "skills": ["hyperstack-core/adapters/openclaw"],
|
|
10
|
+
* "env": {
|
|
11
|
+
* "HYPERSTACK_API_KEY": "hs_your_key"
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* Or use programmatically:
|
|
16
|
+
* import { createOpenClawAdapter } from "hyperstack-core/adapters/openclaw";
|
|
17
|
+
* const adapter = createOpenClawAdapter({ agentId: "researcher" });
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { HyperStackClient } from "../src/client.js";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Create an OpenClaw-compatible adapter that provides tools
|
|
24
|
+
* for multi-agent coordination via HyperStack.
|
|
25
|
+
*
|
|
26
|
+
* @param {object} opts
|
|
27
|
+
* @param {string} opts.agentId — this agent's unique ID
|
|
28
|
+
* @param {string} [opts.apiKey] — HyperStack API key
|
|
29
|
+
* @param {string} [opts.workspace] — workspace slug
|
|
30
|
+
*/
|
|
31
|
+
function createOpenClawAdapter(opts = {}) {
|
|
32
|
+
const agentId = opts.agentId || process.env.OPENCLAW_AGENT_ID || "main";
|
|
33
|
+
|
|
34
|
+
const client = new HyperStackClient({
|
|
35
|
+
apiKey: opts.apiKey,
|
|
36
|
+
workspace: opts.workspace,
|
|
37
|
+
agentId,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
client,
|
|
42
|
+
agentId,
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Tools that get exposed to the OpenClaw agent.
|
|
46
|
+
* These can be called via OpenClaw's tool system.
|
|
47
|
+
*/
|
|
48
|
+
tools: {
|
|
49
|
+
/**
|
|
50
|
+
* Search the shared knowledge graph.
|
|
51
|
+
*/
|
|
52
|
+
async hs_search({ query }) {
|
|
53
|
+
const result = await client.search(query);
|
|
54
|
+
const cards = result.results || [];
|
|
55
|
+
if (!cards.length) return { text: "No matching cards found." };
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
text: cards.slice(0, 5).map(c => {
|
|
59
|
+
let line = `[${c.slug}] ${c.title} (${c.cardType || "general"})`;
|
|
60
|
+
if (c.body) line += `\n ${c.body.slice(0, 200)}`;
|
|
61
|
+
if (c.links?.length) {
|
|
62
|
+
line += `\n Links: ${c.links.map(l => `${l.relation}→${l.target}`).join(", ")}`;
|
|
63
|
+
}
|
|
64
|
+
return line;
|
|
65
|
+
}).join("\n\n"),
|
|
66
|
+
cards,
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Store a card in the shared graph. Auto-tags with agent ID.
|
|
72
|
+
*/
|
|
73
|
+
async hs_store({ slug, title, body, type, links, keywords }) {
|
|
74
|
+
const parsedLinks = [];
|
|
75
|
+
if (links) {
|
|
76
|
+
// Accept "target:relation,target:relation" format
|
|
77
|
+
for (const l of (typeof links === "string" ? links.split(",") : links)) {
|
|
78
|
+
if (typeof l === "string") {
|
|
79
|
+
const [target, relation] = l.trim().split(":");
|
|
80
|
+
parsedLinks.push({ target: target.trim(), relation: (relation || "related").trim() });
|
|
81
|
+
} else {
|
|
82
|
+
parsedLinks.push(l);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const result = await client.store({
|
|
88
|
+
slug,
|
|
89
|
+
title,
|
|
90
|
+
body: body || "",
|
|
91
|
+
cardType: type || "general",
|
|
92
|
+
keywords: typeof keywords === "string" ? keywords.split(",").map(k => k.trim()) : (keywords || []),
|
|
93
|
+
links: parsedLinks,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
text: `${result.updated ? "Updated" : "Created"} [${slug}]: ${title}`,
|
|
98
|
+
result,
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Record a decision with full provenance.
|
|
104
|
+
*/
|
|
105
|
+
async hs_decide({ slug, title, rationale, affects, blocks }) {
|
|
106
|
+
const result = await client.decide({
|
|
107
|
+
slug,
|
|
108
|
+
title,
|
|
109
|
+
body: rationale,
|
|
110
|
+
decidedBy: `agent-${agentId}`,
|
|
111
|
+
affects: affects ? (typeof affects === "string" ? affects.split(",").map(s => s.trim()) : affects) : [],
|
|
112
|
+
blocks: blocks ? (typeof blocks === "string" ? blocks.split(",").map(s => s.trim()) : blocks) : [],
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
text: `Decision recorded: [${slug}] ${title} (by ${agentId})`,
|
|
117
|
+
result,
|
|
118
|
+
};
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Check what blocks a task/card.
|
|
123
|
+
*/
|
|
124
|
+
async hs_blockers({ slug }) {
|
|
125
|
+
const result = await client.blockers(slug);
|
|
126
|
+
const blockers = result.blockers || [];
|
|
127
|
+
|
|
128
|
+
if (!blockers.length) {
|
|
129
|
+
return { text: `Nothing blocks [${slug}].`, blockers: [] };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
text: `${blockers.length} blocker(s) for [${slug}]:\n` +
|
|
134
|
+
blockers.map(b => ` [${b.slug}] ${b.title || "?"}`).join("\n"),
|
|
135
|
+
blockers,
|
|
136
|
+
};
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Traverse the graph from a card.
|
|
141
|
+
*/
|
|
142
|
+
async hs_graph({ from, depth, relation }) {
|
|
143
|
+
const result = await client.graph(from, {
|
|
144
|
+
depth: depth || 2,
|
|
145
|
+
relation: relation || undefined,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const nodes = result.nodes || [];
|
|
149
|
+
const edges = result.edges || [];
|
|
150
|
+
|
|
151
|
+
if (!nodes.length) {
|
|
152
|
+
return { text: `No graph found from [${from}].`, nodes: [], edges: [] };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let text = `Graph from [${from}]: ${nodes.length} nodes, ${edges.length} edges\n\n`;
|
|
156
|
+
text += "Nodes:\n" + nodes.map(n =>
|
|
157
|
+
` [${n.slug}] ${n.title || "?"} (${n.cardType || "?"})`
|
|
158
|
+
).join("\n");
|
|
159
|
+
text += "\n\nEdges:\n" + edges.map(e =>
|
|
160
|
+
` ${e.from} --${e.relation}--> ${e.to}`
|
|
161
|
+
).join("\n");
|
|
162
|
+
|
|
163
|
+
return { text, nodes, edges };
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* List all cards by this agent.
|
|
168
|
+
*/
|
|
169
|
+
async hs_my_cards() {
|
|
170
|
+
const result = await client.agentCards(agentId);
|
|
171
|
+
const cards = result.results || [];
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
text: `${cards.length} cards by agent "${agentId}":\n` +
|
|
175
|
+
cards.map(c => ` [${c.slug}] ${c.title}`).join("\n"),
|
|
176
|
+
cards,
|
|
177
|
+
};
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Hook: called when agent session starts.
|
|
183
|
+
* Registers the agent and loads relevant context.
|
|
184
|
+
*/
|
|
185
|
+
async onSessionStart({ agentName, agentRole }) {
|
|
186
|
+
// Register this agent in the graph
|
|
187
|
+
await client.registerAgent({
|
|
188
|
+
id: agentId,
|
|
189
|
+
name: agentName || agentId,
|
|
190
|
+
role: agentRole || "OpenClaw agent",
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Load recent context for this agent
|
|
194
|
+
const context = await client.search(`agent:${agentId}`);
|
|
195
|
+
return {
|
|
196
|
+
cards: context.results || [],
|
|
197
|
+
text: `HyperStack: ${(context.results || []).length} cards loaded for agent "${agentId}"`,
|
|
198
|
+
};
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Hook: called when agent session ends.
|
|
203
|
+
* Good place to save working state.
|
|
204
|
+
*/
|
|
205
|
+
async onSessionEnd({ summary }) {
|
|
206
|
+
if (summary) {
|
|
207
|
+
await client.store({
|
|
208
|
+
slug: `session-${agentId}-${Date.now()}`,
|
|
209
|
+
title: `Session summary (${agentId})`,
|
|
210
|
+
body: summary.slice(0, 500),
|
|
211
|
+
cardType: "event",
|
|
212
|
+
stack: "general",
|
|
213
|
+
keywords: ["session", "summary"],
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export { createOpenClawAdapter };
|
|
221
|
+
export default createOpenClawAdapter;
|