@techwavedev/agi-agent-kit 1.1.7 → 1.2.1
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.
Potentially problematic release.
This version of @techwavedev/agi-agent-kit might be problematic. Click here for more details.
- package/CHANGELOG.md +82 -1
- package/README.md +190 -12
- package/bin/init.js +30 -2
- package/package.json +6 -3
- package/templates/base/AGENTS.md +54 -23
- package/templates/base/README.md +325 -0
- package/templates/base/directives/memory_integration.md +95 -0
- package/templates/base/execution/memory_manager.py +309 -0
- package/templates/base/execution/session_boot.py +218 -0
- package/templates/base/execution/session_init.py +320 -0
- package/templates/base/skill-creator/SKILL_skillcreator.md +23 -36
- package/templates/base/skill-creator/scripts/init_skill.py +18 -135
- package/templates/skills/ec/README.md +31 -0
- package/templates/skills/ec/aws/SKILL.md +1020 -0
- package/templates/skills/ec/aws/defaults.yaml +13 -0
- package/templates/skills/ec/aws/references/common_patterns.md +80 -0
- package/templates/skills/ec/aws/references/mcp_servers.md +98 -0
- package/templates/skills/ec/aws-terraform/SKILL.md +349 -0
- package/templates/skills/ec/aws-terraform/references/best_practices.md +394 -0
- package/templates/skills/ec/aws-terraform/references/checkov_reference.md +337 -0
- package/templates/skills/ec/aws-terraform/scripts/configure_mcp.py +150 -0
- package/templates/skills/ec/confluent-kafka/SKILL.md +655 -0
- package/templates/skills/ec/confluent-kafka/references/ansible_playbooks.md +792 -0
- package/templates/skills/ec/confluent-kafka/references/ec_deployment.md +579 -0
- package/templates/skills/ec/confluent-kafka/references/kraft_migration.md +490 -0
- package/templates/skills/ec/confluent-kafka/references/troubleshooting.md +778 -0
- package/templates/skills/ec/confluent-kafka/references/upgrade_7x_to_8x.md +488 -0
- package/templates/skills/ec/confluent-kafka/scripts/kafka_health_check.py +435 -0
- package/templates/skills/ec/confluent-kafka/scripts/upgrade_preflight.py +568 -0
- package/templates/skills/ec/confluent-kafka/scripts/validate_config.py +455 -0
- package/templates/skills/ec/consul/SKILL.md +427 -0
- package/templates/skills/ec/consul/references/acl_setup.md +168 -0
- package/templates/skills/ec/consul/references/ha_config.md +196 -0
- package/templates/skills/ec/consul/references/troubleshooting.md +267 -0
- package/templates/skills/ec/consul/references/upgrades.md +213 -0
- package/templates/skills/ec/consul/scripts/consul_health_report.py +530 -0
- package/templates/skills/ec/consul/scripts/consul_status.py +264 -0
- package/templates/skills/ec/consul/scripts/generate_values.py +170 -0
- package/templates/skills/ec/documentation/SKILL.md +351 -0
- package/templates/skills/ec/documentation/references/best_practices.md +201 -0
- package/templates/skills/ec/documentation/scripts/analyze_code.py +307 -0
- package/templates/skills/ec/documentation/scripts/detect_changes.py +460 -0
- package/templates/skills/ec/documentation/scripts/generate_changelog.py +312 -0
- package/templates/skills/ec/documentation/scripts/sync_docs.py +272 -0
- package/templates/skills/ec/documentation/scripts/update_skill_docs.py +366 -0
- package/templates/skills/ec/gitlab/SKILL.md +529 -0
- package/templates/skills/ec/gitlab/references/agent_installation.md +416 -0
- package/templates/skills/ec/gitlab/references/api_reference.md +508 -0
- package/templates/skills/ec/gitlab/references/gitops_flux.md +465 -0
- package/templates/skills/ec/gitlab/references/troubleshooting.md +518 -0
- package/templates/skills/ec/gitlab/scripts/generate_agent_values.py +329 -0
- package/templates/skills/ec/gitlab/scripts/gitlab_agent_status.py +414 -0
- package/templates/skills/ec/jira/SKILL.md +484 -0
- package/templates/skills/ec/jira/references/jql_reference.md +148 -0
- package/templates/skills/ec/jira/scripts/add_comment.py +91 -0
- package/templates/skills/ec/jira/scripts/bulk_log_work.py +124 -0
- package/templates/skills/ec/jira/scripts/create_ticket.py +162 -0
- package/templates/skills/ec/jira/scripts/get_ticket.py +191 -0
- package/templates/skills/ec/jira/scripts/jira_client.py +383 -0
- package/templates/skills/ec/jira/scripts/log_work.py +154 -0
- package/templates/skills/ec/jira/scripts/search_tickets.py +104 -0
- package/templates/skills/ec/jira/scripts/update_comment.py +67 -0
- package/templates/skills/ec/jira/scripts/update_ticket.py +161 -0
- package/templates/skills/ec/karpenter/SKILL.md +301 -0
- package/templates/skills/ec/karpenter/references/ec2nodeclasses.md +421 -0
- package/templates/skills/ec/karpenter/references/migration.md +396 -0
- package/templates/skills/ec/karpenter/references/nodepools.md +400 -0
- package/templates/skills/ec/karpenter/references/troubleshooting.md +359 -0
- package/templates/skills/ec/karpenter/scripts/generate_ec2nodeclass.py +187 -0
- package/templates/skills/ec/karpenter/scripts/generate_nodepool.py +245 -0
- package/templates/skills/ec/karpenter/scripts/karpenter_status.py +359 -0
- package/templates/skills/ec/opensearch/SKILL.md +720 -0
- package/templates/skills/ec/opensearch/references/ml_neural_search.md +576 -0
- package/templates/skills/ec/opensearch/references/operator.md +532 -0
- package/templates/skills/ec/opensearch/references/query_dsl.md +532 -0
- package/templates/skills/ec/opensearch/scripts/configure_mcp.py +148 -0
- package/templates/skills/ec/victoriametrics/SKILL.md +598 -0
- package/templates/skills/ec/victoriametrics/references/kubernetes.md +531 -0
- package/templates/skills/ec/victoriametrics/references/prometheus_migration.md +333 -0
- package/templates/skills/ec/victoriametrics/references/troubleshooting.md +442 -0
- package/templates/skills/knowledge/SKILLS_CATALOG.md +274 -4
- package/templates/skills/knowledge/intelligent-routing/SKILL.md +237 -164
- package/templates/skills/knowledge/parallel-agents/SKILL.md +345 -73
- package/templates/skills/knowledge/plugin-discovery/SKILL.md +582 -0
- package/templates/skills/knowledge/plugin-discovery/scripts/platform_setup.py +1083 -0
- package/templates/skills/knowledge/design-md/README.md +0 -34
- package/templates/skills/knowledge/design-md/SKILL.md +0 -193
- package/templates/skills/knowledge/design-md/examples/DESIGN.md +0 -154
- package/templates/skills/knowledge/notebooklm-mcp/SKILL.md +0 -71
- package/templates/skills/knowledge/notebooklm-mcp/assets/example_asset.txt +0 -24
- package/templates/skills/knowledge/notebooklm-mcp/references/api_reference.md +0 -34
- package/templates/skills/knowledge/notebooklm-mcp/scripts/example.py +0 -19
- package/templates/skills/knowledge/react-components/README.md +0 -36
- package/templates/skills/knowledge/react-components/SKILL.md +0 -53
- package/templates/skills/knowledge/react-components/examples/gold-standard-card.tsx +0 -80
- package/templates/skills/knowledge/react-components/package-lock.json +0 -231
- package/templates/skills/knowledge/react-components/package.json +0 -16
- package/templates/skills/knowledge/react-components/resources/architecture-checklist.md +0 -15
- package/templates/skills/knowledge/react-components/resources/component-template.tsx +0 -37
- package/templates/skills/knowledge/react-components/resources/stitch-api-reference.md +0 -14
- package/templates/skills/knowledge/react-components/resources/style-guide.json +0 -27
- package/templates/skills/knowledge/react-components/scripts/fetch-stitch.sh +0 -30
- package/templates/skills/knowledge/react-components/scripts/validate.js +0 -68
- package/templates/skills/knowledge/self-update/SKILL.md +0 -60
- package/templates/skills/knowledge/self-update/scripts/update_kit.py +0 -103
- package/templates/skills/knowledge/stitch-loop/README.md +0 -54
- package/templates/skills/knowledge/stitch-loop/SKILL.md +0 -235
- package/templates/skills/knowledge/stitch-loop/examples/SITE.md +0 -73
- package/templates/skills/knowledge/stitch-loop/examples/next-prompt.md +0 -25
- package/templates/skills/knowledge/stitch-loop/resources/baton-schema.md +0 -61
- package/templates/skills/knowledge/stitch-loop/resources/site-template.md +0 -104
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Script: memory_manager.py
|
|
4
|
+
Purpose: Unified memory management wrapper for all qdrant-memory operations.
|
|
5
|
+
Provides a single entry point for agents across any AI environment.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
# Auto-decide: check cache first, then retrieve context
|
|
9
|
+
python3 execution/memory_manager.py auto --query "How to set up auth middleware?"
|
|
10
|
+
|
|
11
|
+
# Explicit store (decision, code, error, technical, conversation)
|
|
12
|
+
python3 execution/memory_manager.py store --content "Chose PostgreSQL for relational model" --type decision --project myapp
|
|
13
|
+
|
|
14
|
+
# Retrieve context only
|
|
15
|
+
python3 execution/memory_manager.py retrieve --query "database architecture" --top-k 5
|
|
16
|
+
|
|
17
|
+
# Cache a response
|
|
18
|
+
python3 execution/memory_manager.py cache-store --query "How to X?" --response "Do Y..."
|
|
19
|
+
|
|
20
|
+
# Health check (Qdrant + Ollama)
|
|
21
|
+
python3 execution/memory_manager.py health
|
|
22
|
+
|
|
23
|
+
Environment Variables:
|
|
24
|
+
EMBEDDING_PROVIDER - "ollama" (default), "openai", or "bedrock"
|
|
25
|
+
OLLAMA_URL - Ollama server URL (default: http://localhost:11434)
|
|
26
|
+
QDRANT_URL - Qdrant server URL (default: http://localhost:6333)
|
|
27
|
+
MEMORY_COLLECTION - Memory collection name (default: agent_memory)
|
|
28
|
+
CACHE_COLLECTION - Cache collection name (default: semantic_cache)
|
|
29
|
+
|
|
30
|
+
Exit Codes:
|
|
31
|
+
0 - Success
|
|
32
|
+
1 - No results / cache miss
|
|
33
|
+
2 - Connection error (Qdrant or embedding service down)
|
|
34
|
+
3 - Operation error
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
import argparse
|
|
38
|
+
import json
|
|
39
|
+
import os
|
|
40
|
+
import sys
|
|
41
|
+
from urllib.request import Request, urlopen
|
|
42
|
+
from urllib.error import URLError
|
|
43
|
+
|
|
44
|
+
# Resolve path to qdrant-memory scripts
|
|
45
|
+
SKILL_SCRIPTS_DIR = os.path.join(
|
|
46
|
+
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
|
47
|
+
"skills",
|
|
48
|
+
"qdrant-memory",
|
|
49
|
+
"scripts",
|
|
50
|
+
)
|
|
51
|
+
sys.path.insert(0, SKILL_SCRIPTS_DIR)
|
|
52
|
+
|
|
53
|
+
from embedding_utils import check_embedding_service, get_embedding_dimension
|
|
54
|
+
from semantic_cache import check_cache, store_response, clear_cache
|
|
55
|
+
from memory_retrieval import retrieve_context, store_memory, list_memories, build_filter
|
|
56
|
+
|
|
57
|
+
# Configuration
|
|
58
|
+
QDRANT_URL = os.environ.get("QDRANT_URL", "http://localhost:6333")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def health_check() -> dict:
|
|
62
|
+
"""Check Qdrant connectivity and embedding service status."""
|
|
63
|
+
result = {"qdrant": "unknown", "embeddings": "unknown", "collections": []}
|
|
64
|
+
|
|
65
|
+
# Check Qdrant
|
|
66
|
+
try:
|
|
67
|
+
req = Request(f"{QDRANT_URL}/collections", method="GET")
|
|
68
|
+
with urlopen(req, timeout=10) as response:
|
|
69
|
+
data = json.loads(response.read().decode())
|
|
70
|
+
collections = [
|
|
71
|
+
c["name"] for c in data.get("result", {}).get("collections", [])
|
|
72
|
+
]
|
|
73
|
+
result["qdrant"] = "ok"
|
|
74
|
+
result["collections"] = collections
|
|
75
|
+
except Exception as e:
|
|
76
|
+
result["qdrant"] = f"error: {e}"
|
|
77
|
+
|
|
78
|
+
# Check embedding service
|
|
79
|
+
embed_status = check_embedding_service()
|
|
80
|
+
result["embeddings"] = embed_status
|
|
81
|
+
|
|
82
|
+
# Check expected collections
|
|
83
|
+
expected = ["agent_memory", "semantic_cache"]
|
|
84
|
+
result["missing_collections"] = [
|
|
85
|
+
c for c in expected if c not in result.get("collections", [])
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
# Overall status
|
|
89
|
+
result["ready"] = (
|
|
90
|
+
result["qdrant"] == "ok"
|
|
91
|
+
and embed_status.get("status") == "ok"
|
|
92
|
+
and len(result["missing_collections"]) == 0
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
return result
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def auto_query(query: str, project: str = None, threshold: float = 0.92) -> dict:
|
|
99
|
+
"""
|
|
100
|
+
Smart query: check cache first, then retrieve context.
|
|
101
|
+
This is the primary entry point for agents.
|
|
102
|
+
|
|
103
|
+
Flow:
|
|
104
|
+
1. Check semantic cache (exact match saves 100% tokens)
|
|
105
|
+
2. If miss, retrieve relevant memories (saves 80-95% tokens)
|
|
106
|
+
3. Return combined result with token savings estimate
|
|
107
|
+
"""
|
|
108
|
+
result = {
|
|
109
|
+
"source": "none",
|
|
110
|
+
"cache_hit": False,
|
|
111
|
+
"context_chunks": [],
|
|
112
|
+
"tokens_saved_estimate": 0,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# Step 1: Semantic cache check
|
|
116
|
+
try:
|
|
117
|
+
cached = check_cache(query, threshold)
|
|
118
|
+
if cached and cached.get("cache_hit"):
|
|
119
|
+
result["source"] = "cache"
|
|
120
|
+
result["cache_hit"] = True
|
|
121
|
+
result["cached_response"] = cached.get("response", "")
|
|
122
|
+
result["cache_score"] = cached.get("score", 0)
|
|
123
|
+
result["tokens_saved_estimate"] = cached.get("tokens_saved", 0)
|
|
124
|
+
return result
|
|
125
|
+
except Exception:
|
|
126
|
+
pass # Cache miss or error, continue to retrieval
|
|
127
|
+
|
|
128
|
+
# Step 2: Context retrieval
|
|
129
|
+
try:
|
|
130
|
+
filters = None
|
|
131
|
+
if project:
|
|
132
|
+
filters = {"must": [{"key": "project", "match": {"value": project}}]}
|
|
133
|
+
|
|
134
|
+
context = retrieve_context(query, filters=filters, top_k=5, score_threshold=0.7)
|
|
135
|
+
if context.get("total_chunks", 0) > 0:
|
|
136
|
+
result["source"] = "memory"
|
|
137
|
+
result["context_chunks"] = context.get("chunks", [])
|
|
138
|
+
result["total_chunks"] = context.get("total_chunks", 0)
|
|
139
|
+
result["tokens_saved_estimate"] = context.get("total_tokens_estimate", 0)
|
|
140
|
+
except Exception:
|
|
141
|
+
pass # No context available
|
|
142
|
+
|
|
143
|
+
return result
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def main():
|
|
147
|
+
parser = argparse.ArgumentParser(
|
|
148
|
+
description="Unified memory manager for AI agents",
|
|
149
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
150
|
+
epilog="""
|
|
151
|
+
Examples:
|
|
152
|
+
# Smart auto-query (cache + context retrieval)
|
|
153
|
+
python3 execution/memory_manager.py auto --query "How to handle JWT refresh?"
|
|
154
|
+
|
|
155
|
+
# Store a key decision
|
|
156
|
+
python3 execution/memory_manager.py store --content "Chose Supabase for auth" --type decision
|
|
157
|
+
|
|
158
|
+
# Health check
|
|
159
|
+
python3 execution/memory_manager.py health
|
|
160
|
+
""",
|
|
161
|
+
)
|
|
162
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
163
|
+
|
|
164
|
+
# Auto command (primary entry point)
|
|
165
|
+
auto_parser = subparsers.add_parser(
|
|
166
|
+
"auto", help="Smart query: cache check + context retrieval"
|
|
167
|
+
)
|
|
168
|
+
auto_parser.add_argument("--query", required=True, help="Natural language query")
|
|
169
|
+
auto_parser.add_argument("--project", help="Filter by project name")
|
|
170
|
+
auto_parser.add_argument(
|
|
171
|
+
"--threshold", type=float, default=0.92, help="Cache similarity threshold"
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Store command
|
|
175
|
+
store_parser = subparsers.add_parser(
|
|
176
|
+
"store", help="Store memory (decision, code, error, technical, conversation)"
|
|
177
|
+
)
|
|
178
|
+
store_parser.add_argument("--content", required=True, help="Memory content")
|
|
179
|
+
store_parser.add_argument(
|
|
180
|
+
"--type",
|
|
181
|
+
required=True,
|
|
182
|
+
choices=["decision", "code", "error", "conversation", "technical"],
|
|
183
|
+
help="Memory type",
|
|
184
|
+
)
|
|
185
|
+
store_parser.add_argument("--project", help="Project name")
|
|
186
|
+
store_parser.add_argument("--tags", nargs="+", help="Tags for the memory")
|
|
187
|
+
|
|
188
|
+
# Retrieve command
|
|
189
|
+
retrieve_parser = subparsers.add_parser(
|
|
190
|
+
"retrieve", help="Retrieve relevant context"
|
|
191
|
+
)
|
|
192
|
+
retrieve_parser.add_argument("--query", required=True, help="Search query")
|
|
193
|
+
retrieve_parser.add_argument("--type", help="Filter by memory type")
|
|
194
|
+
retrieve_parser.add_argument("--project", help="Filter by project")
|
|
195
|
+
retrieve_parser.add_argument(
|
|
196
|
+
"--top-k", type=int, default=5, help="Number of results"
|
|
197
|
+
)
|
|
198
|
+
retrieve_parser.add_argument(
|
|
199
|
+
"--threshold", type=float, default=0.7, help="Score threshold"
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# Cache store command
|
|
203
|
+
cache_parser = subparsers.add_parser(
|
|
204
|
+
"cache-store", help="Store query-response in semantic cache"
|
|
205
|
+
)
|
|
206
|
+
cache_parser.add_argument("--query", required=True, help="Original query")
|
|
207
|
+
cache_parser.add_argument("--response", required=True, help="LLM response to cache")
|
|
208
|
+
cache_parser.add_argument("--model", default="agent", help="Model identifier")
|
|
209
|
+
cache_parser.add_argument("--project", help="Project name")
|
|
210
|
+
|
|
211
|
+
# List command
|
|
212
|
+
list_parser = subparsers.add_parser("list", help="List stored memories")
|
|
213
|
+
list_parser.add_argument("--type", help="Filter by memory type")
|
|
214
|
+
list_parser.add_argument("--project", help="Filter by project")
|
|
215
|
+
list_parser.add_argument("--limit", type=int, default=20, help="Max results")
|
|
216
|
+
|
|
217
|
+
# Health command
|
|
218
|
+
subparsers.add_parser("health", help="Check Qdrant + embedding service health")
|
|
219
|
+
|
|
220
|
+
# Cache clear command
|
|
221
|
+
clear_parser = subparsers.add_parser("cache-clear", help="Clear old cache entries")
|
|
222
|
+
clear_parser.add_argument(
|
|
223
|
+
"--older-than", type=int, default=7, help="Delete entries older than N days"
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
args = parser.parse_args()
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
if args.command == "auto":
|
|
230
|
+
result = auto_query(args.query, args.project, args.threshold)
|
|
231
|
+
print(json.dumps(result, indent=2))
|
|
232
|
+
sys.exit(0 if result["source"] != "none" else 1)
|
|
233
|
+
|
|
234
|
+
elif args.command == "store":
|
|
235
|
+
metadata = {}
|
|
236
|
+
if args.project:
|
|
237
|
+
metadata["project"] = args.project
|
|
238
|
+
if args.tags:
|
|
239
|
+
metadata["tags"] = args.tags
|
|
240
|
+
result = store_memory(args.content, args.type, metadata)
|
|
241
|
+
print(json.dumps(result, indent=2))
|
|
242
|
+
sys.exit(0)
|
|
243
|
+
|
|
244
|
+
elif args.command == "retrieve":
|
|
245
|
+
filters = build_filter(
|
|
246
|
+
type_filter=getattr(args, "type", None), project=args.project
|
|
247
|
+
)
|
|
248
|
+
result = retrieve_context(
|
|
249
|
+
args.query,
|
|
250
|
+
filters={"must": filters["must"]} if filters else None,
|
|
251
|
+
top_k=args.top_k,
|
|
252
|
+
score_threshold=args.threshold,
|
|
253
|
+
)
|
|
254
|
+
print(json.dumps(result, indent=2))
|
|
255
|
+
sys.exit(0 if result.get("total_chunks", 0) > 0 else 1)
|
|
256
|
+
|
|
257
|
+
elif args.command == "cache-store":
|
|
258
|
+
metadata = {"model": args.model}
|
|
259
|
+
if args.project:
|
|
260
|
+
metadata["project"] = args.project
|
|
261
|
+
result = store_response(args.query, args.response, metadata)
|
|
262
|
+
print(json.dumps(result, indent=2))
|
|
263
|
+
sys.exit(0)
|
|
264
|
+
|
|
265
|
+
elif args.command == "list":
|
|
266
|
+
filters = build_filter(
|
|
267
|
+
type_filter=getattr(args, "type", None), project=args.project
|
|
268
|
+
)
|
|
269
|
+
result = list_memories(
|
|
270
|
+
filters={"must": filters["must"]} if filters else None, limit=args.limit
|
|
271
|
+
)
|
|
272
|
+
print(json.dumps(result, indent=2))
|
|
273
|
+
sys.exit(0)
|
|
274
|
+
|
|
275
|
+
elif args.command == "health":
|
|
276
|
+
result = health_check()
|
|
277
|
+
print(json.dumps(result, indent=2))
|
|
278
|
+
sys.exit(0 if result["ready"] else 2)
|
|
279
|
+
|
|
280
|
+
elif args.command == "cache-clear":
|
|
281
|
+
result = clear_cache(args.older_than)
|
|
282
|
+
print(json.dumps(result, indent=2))
|
|
283
|
+
sys.exit(0)
|
|
284
|
+
|
|
285
|
+
except URLError as e:
|
|
286
|
+
print(
|
|
287
|
+
json.dumps(
|
|
288
|
+
{
|
|
289
|
+
"status": "error",
|
|
290
|
+
"type": "connection_error",
|
|
291
|
+
"message": str(e),
|
|
292
|
+
"hint": "Is Qdrant running? Try: docker run -p 6333:6333 qdrant/qdrant",
|
|
293
|
+
}
|
|
294
|
+
),
|
|
295
|
+
file=sys.stderr,
|
|
296
|
+
)
|
|
297
|
+
sys.exit(2)
|
|
298
|
+
except Exception as e:
|
|
299
|
+
print(
|
|
300
|
+
json.dumps(
|
|
301
|
+
{"status": "error", "type": type(e).__name__, "message": str(e)}
|
|
302
|
+
),
|
|
303
|
+
file=sys.stderr,
|
|
304
|
+
)
|
|
305
|
+
sys.exit(3)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
if __name__ == "__main__":
|
|
309
|
+
main()
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Script: session_boot.py
|
|
4
|
+
Purpose: Single entry point for session initialization. Checks memory system,
|
|
5
|
+
initializes if needed, and returns a combined status report.
|
|
6
|
+
|
|
7
|
+
This is the FIRST script an agent should run at session start.
|
|
8
|
+
Combines: health check + session_init + platform detection.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
python3 execution/session_boot.py
|
|
12
|
+
python3 execution/session_boot.py --json
|
|
13
|
+
python3 execution/session_boot.py --auto-fix
|
|
14
|
+
|
|
15
|
+
Arguments:
|
|
16
|
+
--json Output JSON only (for programmatic use)
|
|
17
|
+
--auto-fix Automatically fix issues (pull model, create collections)
|
|
18
|
+
|
|
19
|
+
Exit Codes:
|
|
20
|
+
0 - Memory system ready
|
|
21
|
+
1 - Memory available but degraded (missing model, empty collections)
|
|
22
|
+
2 - Memory unavailable (Qdrant or Ollama not running)
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import argparse
|
|
26
|
+
import json
|
|
27
|
+
import os
|
|
28
|
+
import subprocess
|
|
29
|
+
import sys
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
from urllib.request import Request, urlopen
|
|
32
|
+
from urllib.error import URLError, HTTPError
|
|
33
|
+
|
|
34
|
+
# Configuration
|
|
35
|
+
QDRANT_URL = os.environ.get("QDRANT_URL", "http://localhost:6333")
|
|
36
|
+
OLLAMA_URL = os.environ.get("OLLAMA_URL", "http://localhost:11434")
|
|
37
|
+
EMBEDDING_MODEL = "nomic-embed-text"
|
|
38
|
+
PROJECT_DIR = Path(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def check_qdrant() -> dict:
|
|
42
|
+
"""Check Qdrant connectivity and collection status."""
|
|
43
|
+
result = {"status": "not_running", "collections": {}, "url": QDRANT_URL}
|
|
44
|
+
try:
|
|
45
|
+
req = Request(f"{QDRANT_URL}/collections", method="GET")
|
|
46
|
+
with urlopen(req, timeout=5) as response:
|
|
47
|
+
data = json.loads(response.read().decode())
|
|
48
|
+
names = [c["name"] for c in data.get("result", {}).get("collections", [])]
|
|
49
|
+
result["status"] = "ok"
|
|
50
|
+
|
|
51
|
+
for col_name in ["agent_memory", "semantic_cache"]:
|
|
52
|
+
if col_name in names:
|
|
53
|
+
try:
|
|
54
|
+
col_req = Request(f"{QDRANT_URL}/collections/{col_name}", method="GET")
|
|
55
|
+
with urlopen(col_req, timeout=5) as col_resp:
|
|
56
|
+
col_data = json.loads(col_resp.read().decode())
|
|
57
|
+
points = col_data.get("result", {}).get("points_count", 0)
|
|
58
|
+
result["collections"][col_name] = {"exists": True, "points": points}
|
|
59
|
+
except Exception:
|
|
60
|
+
result["collections"][col_name] = {"exists": True, "points": -1}
|
|
61
|
+
else:
|
|
62
|
+
result["collections"][col_name] = {"exists": False, "points": 0}
|
|
63
|
+
except (URLError, HTTPError, Exception):
|
|
64
|
+
pass
|
|
65
|
+
return result
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def check_ollama() -> dict:
|
|
69
|
+
"""Check Ollama connectivity and embedding model."""
|
|
70
|
+
result = {"status": "not_running", "has_model": False, "url": OLLAMA_URL}
|
|
71
|
+
try:
|
|
72
|
+
req = Request(f"{OLLAMA_URL}/api/tags", method="GET")
|
|
73
|
+
with urlopen(req, timeout=5) as response:
|
|
74
|
+
data = json.loads(response.read().decode())
|
|
75
|
+
models = [m["name"] for m in data.get("models", [])]
|
|
76
|
+
result["status"] = "ok"
|
|
77
|
+
result["models"] = models
|
|
78
|
+
result["has_model"] = any(EMBEDDING_MODEL in m for m in models)
|
|
79
|
+
except (URLError, HTTPError, Exception):
|
|
80
|
+
pass
|
|
81
|
+
return result
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def run_session_init() -> bool:
|
|
85
|
+
"""Run session_init.py to create collections."""
|
|
86
|
+
init_script = PROJECT_DIR / "execution" / "session_init.py"
|
|
87
|
+
if not init_script.exists():
|
|
88
|
+
return False
|
|
89
|
+
try:
|
|
90
|
+
proc = subprocess.run(
|
|
91
|
+
["python3", str(init_script)],
|
|
92
|
+
capture_output=True, text=True, timeout=30,
|
|
93
|
+
cwd=str(PROJECT_DIR),
|
|
94
|
+
)
|
|
95
|
+
return proc.returncode == 0
|
|
96
|
+
except Exception:
|
|
97
|
+
return False
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def pull_model() -> bool:
|
|
101
|
+
"""Pull the embedding model via Ollama."""
|
|
102
|
+
try:
|
|
103
|
+
proc = subprocess.run(
|
|
104
|
+
["ollama", "pull", EMBEDDING_MODEL],
|
|
105
|
+
capture_output=True, text=True, timeout=120,
|
|
106
|
+
)
|
|
107
|
+
return proc.returncode == 0
|
|
108
|
+
except Exception:
|
|
109
|
+
return False
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def main():
|
|
113
|
+
parser = argparse.ArgumentParser(
|
|
114
|
+
description="Session boot: check + initialize memory system"
|
|
115
|
+
)
|
|
116
|
+
parser.add_argument("--json", action="store_true", dest="json_output",
|
|
117
|
+
help="JSON output only")
|
|
118
|
+
parser.add_argument("--auto-fix", action="store_true",
|
|
119
|
+
help="Auto-fix issues (pull model, create collections)")
|
|
120
|
+
args = parser.parse_args()
|
|
121
|
+
|
|
122
|
+
report = {
|
|
123
|
+
"qdrant": {},
|
|
124
|
+
"ollama": {},
|
|
125
|
+
"memory_ready": False,
|
|
126
|
+
"actions_taken": [],
|
|
127
|
+
"issues": [],
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
# Step 1: Check Qdrant
|
|
131
|
+
qdrant = check_qdrant()
|
|
132
|
+
report["qdrant"] = qdrant
|
|
133
|
+
|
|
134
|
+
if qdrant["status"] != "ok":
|
|
135
|
+
report["issues"].append("Qdrant not running. Start with: docker run -d -p 6333:6333 -v qdrant_storage:/qdrant/storage qdrant/qdrant")
|
|
136
|
+
|
|
137
|
+
# Step 2: Check Ollama
|
|
138
|
+
ollama = check_ollama()
|
|
139
|
+
report["ollama"] = ollama
|
|
140
|
+
|
|
141
|
+
if ollama["status"] != "ok":
|
|
142
|
+
report["issues"].append("Ollama not running. Start with: ollama serve")
|
|
143
|
+
elif not ollama["has_model"]:
|
|
144
|
+
if args.auto_fix:
|
|
145
|
+
if not args.json_output:
|
|
146
|
+
print(f"⏳ Pulling {EMBEDDING_MODEL}...")
|
|
147
|
+
if pull_model():
|
|
148
|
+
report["actions_taken"].append(f"Pulled {EMBEDDING_MODEL}")
|
|
149
|
+
ollama["has_model"] = True
|
|
150
|
+
else:
|
|
151
|
+
report["issues"].append(f"Failed to pull {EMBEDDING_MODEL}")
|
|
152
|
+
else:
|
|
153
|
+
report["issues"].append(f"Embedding model missing. Run: ollama pull {EMBEDDING_MODEL}")
|
|
154
|
+
|
|
155
|
+
# Step 3: Initialize collections if needed
|
|
156
|
+
if qdrant["status"] == "ok" and ollama["status"] == "ok" and ollama["has_model"]:
|
|
157
|
+
agent_mem = qdrant["collections"].get("agent_memory", {})
|
|
158
|
+
sem_cache = qdrant["collections"].get("semantic_cache", {})
|
|
159
|
+
|
|
160
|
+
if not agent_mem.get("exists") or not sem_cache.get("exists"):
|
|
161
|
+
if args.auto_fix:
|
|
162
|
+
if not args.json_output:
|
|
163
|
+
print("⏳ Initializing collections...")
|
|
164
|
+
if run_session_init():
|
|
165
|
+
report["actions_taken"].append("Created collections via session_init.py")
|
|
166
|
+
# Re-check
|
|
167
|
+
qdrant = check_qdrant()
|
|
168
|
+
report["qdrant"] = qdrant
|
|
169
|
+
else:
|
|
170
|
+
report["issues"].append("Failed to initialize collections")
|
|
171
|
+
else:
|
|
172
|
+
report["issues"].append("Collections missing. Run: python3 execution/session_init.py")
|
|
173
|
+
|
|
174
|
+
# Final readiness
|
|
175
|
+
qdrant = report["qdrant"]
|
|
176
|
+
ollama = report["ollama"]
|
|
177
|
+
agent_mem = qdrant.get("collections", {}).get("agent_memory", {})
|
|
178
|
+
sem_cache = qdrant.get("collections", {}).get("semantic_cache", {})
|
|
179
|
+
|
|
180
|
+
report["memory_ready"] = (
|
|
181
|
+
qdrant.get("status") == "ok"
|
|
182
|
+
and ollama.get("status") == "ok"
|
|
183
|
+
and ollama.get("has_model", False)
|
|
184
|
+
and agent_mem.get("exists", False)
|
|
185
|
+
and sem_cache.get("exists", False)
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# Summary
|
|
189
|
+
total_points = (
|
|
190
|
+
agent_mem.get("points", 0) + sem_cache.get("points", 0)
|
|
191
|
+
)
|
|
192
|
+
report["summary"] = {
|
|
193
|
+
"ready": report["memory_ready"],
|
|
194
|
+
"total_memories": agent_mem.get("points", 0),
|
|
195
|
+
"total_cached": sem_cache.get("points", 0),
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if args.json_output:
|
|
199
|
+
print(json.dumps(report, indent=2))
|
|
200
|
+
else:
|
|
201
|
+
if report["memory_ready"]:
|
|
202
|
+
mem_pts = agent_mem.get("points", 0)
|
|
203
|
+
cache_pts = sem_cache.get("points", 0)
|
|
204
|
+
print(f"✅ Memory system ready — {mem_pts} memories, {cache_pts} cached responses")
|
|
205
|
+
else:
|
|
206
|
+
print("❌ Memory system not ready:")
|
|
207
|
+
for issue in report["issues"]:
|
|
208
|
+
print(f" • {issue}")
|
|
209
|
+
|
|
210
|
+
if report["actions_taken"]:
|
|
211
|
+
for action in report["actions_taken"]:
|
|
212
|
+
print(f" ✅ {action}")
|
|
213
|
+
|
|
214
|
+
sys.exit(0 if report["memory_ready"] else (1 if qdrant.get("status") == "ok" else 2))
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
if __name__ == "__main__":
|
|
218
|
+
main()
|