@bcmyguest/openmem 0.0.0-stage → 0.8.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/.agents/skills/openmem/SKILL.md +34 -0
- package/LICENSE +190 -0
- package/README.md +140 -2
- package/bin/hindsight-project-index +530 -0
- package/cli/coding-agent/access-policy.mjs +38 -0
- package/cli/coding-agent/agents.mjs +34 -0
- package/cli/coding-agent/bank-from-cwd.mjs +140 -0
- package/cli/coding-agent/capabilities.mjs +34 -0
- package/cli/coding-agent/context-store.mjs +81 -0
- package/cli/coding-agent/context-trim.mjs +897 -0
- package/cli/coding-agent/file-io.mjs +72 -0
- package/cli/coding-agent/hook-harnesses.mjs +88 -0
- package/cli/coding-agent/hook-runner.mjs +284 -0
- package/cli/coding-agent/install-access.mjs +119 -0
- package/cli/coding-agent/install-context-proxy.mjs +333 -0
- package/cli/coding-agent/install-rtk.mjs +60 -0
- package/cli/coding-agent/install-shim.mjs +201 -0
- package/cli/coding-agent/opencode-config.mjs +107 -0
- package/cli/coding-agent/opencode-plugin.mjs +132 -0
- package/cli/coding-agent/opencode2-plugin/index.js +299 -0
- package/cli/coding-agent/recall-frame.mjs +29 -0
- package/cli/coding-agent/remove-upstream-access.mjs +122 -0
- package/cli/coding-agent/runtime.mjs +40 -0
- package/cli/coding-agent/session-db.mjs +626 -0
- package/cli/coding-agent/session-facade.mjs +86 -0
- package/cli/coding-agent/toml-edit.mjs +161 -0
- package/cli/cognee-mcp.mjs +260 -0
- package/cli/context-management.mjs +254 -0
- package/cli/feed-sync.mjs +27 -0
- package/cli/install-coding-agent.mjs +298 -0
- package/cli/install-memory-mcp.mjs +426 -0
- package/cli/is-main.mjs +18 -0
- package/cli/mcp/context-sql-runner.mjs +58 -0
- package/cli/mcp/context-store.mjs +670 -0
- package/cli/mcp/context.mjs +61 -0
- package/cli/mcp/export/cognee-dataset-name.mjs +12 -0
- package/cli/mcp/export/cognee.mjs +119 -0
- package/cli/mcp/export/hindsight.mjs +48 -0
- package/cli/mcp/export/index.mjs +26 -0
- package/cli/mcp/export/mem0.mjs +31 -0
- package/cli/mcp/knowledge.mjs +333 -0
- package/cli/mcp/llm-synthesize.mjs +50 -0
- package/cli/mcp/mem0-scope-id.mjs +22 -0
- package/cli/mcp/memory-facade.mjs +521 -0
- package/cli/mcp/memory-reflect-consolidate.mjs +120 -0
- package/cli/mcp/notebooklm-banks.mjs +21 -0
- package/cli/mcp/notebooklm-hindsight-rest.mjs +45 -0
- package/cli/mcp/notebooklm-provider.mjs +225 -0
- package/cli/mcp/pmm-records.mjs +23 -0
- package/cli/mcp/portability.mjs +158 -0
- package/cli/mcp/stdio.mjs +65 -0
- package/cli/mcp/unified-mcp-install.mjs +65 -0
- package/cli/mem0-mcp.mjs +108 -0
- package/cli/notebooklm-mcp.mjs +236 -0
- package/cli/openmem-mcp.mjs +38 -0
- package/cli/openmem.mjs +222 -0
- package/cli/roots.mjs +85 -0
- package/cli/schedule.mjs +176 -0
- package/cli/stack.mjs +438 -0
- package/cli/switch-memory-provider.mjs +358 -0
- package/cli/wiring-report.mjs +125 -0
- package/compose.bench.yaml +12 -0
- package/compose.yaml +227 -0
- package/config/coding-agent.json +13 -0
- package/config/hindsight.env.example +26 -0
- package/config/index.yml +54 -0
- package/config/litellm.lemond.yaml +40 -0
- package/config/litellm.ollama.yaml +33 -0
- package/config/notebooklm.yml +33 -0
- package/config/openmem.toml.example +124 -0
- package/docs/OPENMEM.md +23 -0
- package/docs/architecture.md +245 -0
- package/docs/assets/README.md +10 -0
- package/docs/assets/setup-demo.gif +0 -0
- package/docs/coding-agent-hooks.md +75 -0
- package/docs/coding-agent-scopes.md +22 -0
- package/docs/coding-agents.md +71 -0
- package/docs/cognee.md +37 -0
- package/docs/compatibility.md +80 -0
- package/docs/concepts.md +135 -0
- package/docs/context-management.md +255 -0
- package/docs/context-proxy.md +115 -0
- package/docs/context-research.md +215 -0
- package/docs/context-store.md +277 -0
- package/docs/hindsight.md +77 -0
- package/docs/index-sources-roadmap.md +38 -0
- package/docs/index-sources.md +39 -0
- package/docs/indexer-sinks.md +122 -0
- package/docs/indexing.md +57 -0
- package/docs/manual-stack-setup.md +74 -0
- package/docs/mcp-install-guide.md +4 -0
- package/docs/mcp-setup.md +104 -0
- package/docs/mem0.md +141 -0
- package/docs/memory-portability.md +73 -0
- package/docs/memory-providers.md +246 -0
- package/docs/meridian-litellm.md +198 -0
- package/docs/model-configuration.md +106 -0
- package/docs/notebooklm.md +83 -0
- package/docs/npx-install.md +172 -0
- package/docs/openmem-config.md +194 -0
- package/docs/provider-wizard-hooks.md +222 -0
- package/docs/quickstart.md +107 -0
- package/docs/setup-wizard.md +117 -0
- package/docs/sources-feeds.md +39 -0
- package/docs/sources-readwise.md +23 -0
- package/docs/sources-zotero.md +22 -0
- package/glama.json +4 -0
- package/indexer/Dockerfile +38 -0
- package/indexer/code_outline.py +146 -0
- package/indexer/feed_sync.py +107 -0
- package/indexer/index_config.py +290 -0
- package/indexer/pytest.ini +5 -0
- package/indexer/sinks/__init__.py +148 -0
- package/indexer/sinks/_http.py +44 -0
- package/indexer/sinks/cognee.py +329 -0
- package/indexer/sinks/hindsight.py +107 -0
- package/indexer/sinks/mem0.py +247 -0
- package/indexer/watch.py +240 -0
- package/package.json +96 -4
- package/providers/_template/compose.yaml +52 -0
- package/providers/cognee/OPERATOR.md +82 -0
- package/providers/cognee/compose.yaml +89 -0
- package/providers/cognee/lib/clack.mjs +157 -0
- package/providers/cognee/lib/coding-agent.mjs +26 -0
- package/providers/cognee/lib/cognee-mcp-install.mjs +153 -0
- package/providers/cognee/lib/config.mjs +98 -0
- package/providers/cognee/lib/env-file.mjs +194 -0
- package/providers/cognee/lib/env-setup.mjs +83 -0
- package/providers/cognee/lib/llm-env.mjs +382 -0
- package/providers/cognee/lib/ports.mjs +25 -0
- package/providers/cognee/lib/smoke.mjs +246 -0
- package/providers/cognee/lib/stack-env.mjs +134 -0
- package/providers/cognee/lib/state.mjs +101 -0
- package/providers/cognee/lib/summary.mjs +56 -0
- package/providers/cognee/lib/validate.mjs +97 -0
- package/providers/cognee/manifest.json +56 -0
- package/providers/cognee/wizard.mjs +134 -0
- package/providers/graphiti/manifest.json +15 -0
- package/providers/hindsight/lib/clack.mjs +347 -0
- package/providers/hindsight/lib/coding-agent.mjs +204 -0
- package/providers/hindsight/lib/config.mjs +79 -0
- package/providers/hindsight/lib/env-setup.mjs +72 -0
- package/providers/hindsight/lib/litellm-routes.mjs +196 -0
- package/providers/hindsight/lib/meridian.mjs +307 -0
- package/providers/hindsight/lib/model-backend.mjs +243 -0
- package/providers/hindsight/lib/notebooklm-mcp-install.mjs +127 -0
- package/providers/hindsight/lib/ollama-compose.mjs +51 -0
- package/providers/hindsight/lib/ports.mjs +30 -0
- package/providers/hindsight/lib/probe.mjs +54 -0
- package/providers/hindsight/lib/stack-env.mjs +125 -0
- package/providers/hindsight/lib/state.mjs +80 -0
- package/providers/hindsight/lib/summary.mjs +57 -0
- package/providers/hindsight/lib/validate.mjs +81 -0
- package/providers/hindsight/manifest.json +58 -0
- package/providers/hindsight/wizard.mjs +150 -0
- package/providers/letta/manifest.json +29 -0
- package/providers/mem0/OPERATOR.md +143 -0
- package/providers/mem0/compose.yaml +79 -0
- package/providers/mem0/lib/coding-agent.mjs +58 -0
- package/providers/mem0/lib/config.mjs +45 -0
- package/providers/mem0/lib/configure.mjs +201 -0
- package/providers/mem0/lib/dotenv.mjs +71 -0
- package/providers/mem0/lib/env-file.mjs +110 -0
- package/providers/mem0/lib/http.mjs +69 -0
- package/providers/mem0/lib/litellm.mjs +457 -0
- package/providers/mem0/lib/mcp-install.mjs +165 -0
- package/providers/mem0/lib/secret.mjs +30 -0
- package/providers/mem0/lib/smoke.mjs +179 -0
- package/providers/mem0/lib/stack-env.mjs +255 -0
- package/providers/mem0/lib/state.mjs +67 -0
- package/providers/mem0/lib/summary.mjs +88 -0
- package/providers/mem0/lib/url.mjs +106 -0
- package/providers/mem0/lib/validate.mjs +158 -0
- package/providers/mem0/manifest.json +47 -0
- package/providers/mem0/wizard.mjs +146 -0
- package/providers/zep/manifest.json +29 -0
- package/proxy/config.yaml +33 -0
- package/proxy/openmem_context/__init__.py +6 -0
- package/proxy/openmem_context/adapters.py +504 -0
- package/proxy/openmem_context/compress.py +53 -0
- package/proxy/openmem_context/core.py +606 -0
- package/proxy/openmem_context/embed.py +212 -0
- package/proxy/openmem_context/recall.py +49 -0
- package/proxy/openmem_context/session.py +70 -0
- package/proxy/openmem_context/sessiondb.py +276 -0
- package/proxy/openmem_context/settings.py +134 -0
- package/proxy/openmem_context/store.py +129 -0
- package/proxy/openmem_context/tokens.py +123 -0
- package/proxy/openmem_context/ttl.py +78 -0
- package/proxy/openmem_context_hook.py +34 -0
- package/scripts/check-pack.mjs +219 -0
- package/scripts/gen-masks.mjs +83 -0
- package/scripts/gen-masks.sh +4 -0
- package/scripts/promotion-provider-smoke.mjs +34 -0
- package/scripts/run-setup.sh +30 -0
- package/scripts/setup.mjs +107 -0
- package/scripts/setup.sh +5 -0
- package/scripts/spin-up.sh +45 -0
- package/scripts/wizard.sh +5 -0
- package/server.json +34 -0
- package/sync/Dockerfile +27 -0
- package/sync/memory_backend.py +87 -0
- package/sync/notebooklm_sync.py +664 -0
- package/wizard/bin/pm.mjs +97 -0
- package/wizard/bin/setup.mjs +33 -0
- package/wizard/lib/compose-version.mjs +32 -0
- package/wizard/lib/compose.mjs +70 -0
- package/wizard/lib/context-step.mjs +140 -0
- package/wizard/lib/curl.mjs +103 -0
- package/wizard/lib/docker-build.mjs +148 -0
- package/wizard/lib/exec.mjs +41 -0
- package/wizard/lib/indexer.mjs +6 -0
- package/wizard/lib/litellm-env.mjs +55 -0
- package/wizard/lib/load-machine-env.mjs +4 -0
- package/wizard/lib/log.mjs +32 -0
- package/wizard/lib/notebooklm-agent-access.mjs +92 -0
- package/wizard/lib/notebooklm.mjs +214 -0
- package/wizard/lib/parse-args.mjs +87 -0
- package/wizard/lib/paths.mjs +39 -0
- package/wizard/lib/pm-config.mjs +371 -0
- package/wizard/lib/ports.mjs +94 -0
- package/wizard/lib/prompts.mjs +85 -0
- package/wizard/lib/provider-wizard/helpers.mjs +98 -0
- package/wizard/lib/provider-wizard/run-steps.mjs +129 -0
- package/wizard/lib/providers/registry.mjs +262 -0
- package/wizard/lib/run-clack.mjs +108 -0
- package/wizard/lib/run-wizard.mjs +750 -0
- package/wizard/lib/validate-setup.mjs +62 -0
- package/wizard/lib/wizard-action.mjs +34 -0
- package/wizard/lib/wizard-conf.mjs +71 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "cognee",
|
|
3
|
+
"label": "Cognee",
|
|
4
|
+
"status": "supported",
|
|
5
|
+
"notes": "Self-hosted graph/RAG memory run as a pinned cognee/cognee image (single container, SQLite + LanceDB + Ladybug) on a loopback port in single-user mode (no authentication). Ingestion is asynchronous: the indexer adds documents, then requests cognify once per changed dataset, so a document is searchable only after the graph is built. Default cognify path is local GLiNER + FastEmbed (no API key); alternatives are LLM_PROVIDER=ollama or an OpenAI-compatible LLM_API_KEY. No coding-agent plugin — agents use the REST API on the loopback port (/docs).",
|
|
6
|
+
"settings": {
|
|
7
|
+
"nativeDocs": "https://docs.cognee.ai/",
|
|
8
|
+
"nativeConfigPaths": [
|
|
9
|
+
"~/.config/personal-memory/cognee.env",
|
|
10
|
+
"~/.config/personal-memory/cognee-indexer.env"
|
|
11
|
+
],
|
|
12
|
+
"wizardOwns": [
|
|
13
|
+
"compose profile 'cognee', the loopback host port (COGNEE_PORT, default 8766) and the stack .env entries",
|
|
14
|
+
"GRAPH_EXTRACTOR / EMBEDDING_* (default GLiNER + FastEmbed) and optional LLM_* settings in cognee.env (mode 600, outside the repo)",
|
|
15
|
+
"the smoke test (health, dataset, multipart add, list, delete; recall is skipped because ingestion is asynchronous)",
|
|
16
|
+
"index.yml sources (shared indexer)",
|
|
17
|
+
"Cognee dataset mapping from indexer banks (the indexer sink maps each bank to a dataset)"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"compose": {
|
|
21
|
+
"services": ["cognee", "indexer"],
|
|
22
|
+
"healthService": "cognee",
|
|
23
|
+
"logServices": ["cognee"],
|
|
24
|
+
"healthPath": "/health",
|
|
25
|
+
"hostPortEnv": "COGNEE_PORT",
|
|
26
|
+
"defaultHostPort": 8766,
|
|
27
|
+
"profile": "cognee",
|
|
28
|
+
"files": ["providers/cognee/compose.yaml"]
|
|
29
|
+
},
|
|
30
|
+
"indexer": {
|
|
31
|
+
"apiUrlEnv": "COGNEE_API_URL",
|
|
32
|
+
"sink": "cognee",
|
|
33
|
+
"sinkDriver": "cognee-rest"
|
|
34
|
+
},
|
|
35
|
+
"codingAgent": {
|
|
36
|
+
"pluginPackage": null,
|
|
37
|
+
"configTemplate": null,
|
|
38
|
+
"notes": "No plugin package. setupCodingAgent prints REST paths and registers the read-only Cognee MCP (cognee_health / cognee_search) in ~/.cursor/mcp.json."
|
|
39
|
+
},
|
|
40
|
+
"wizardHooks": {
|
|
41
|
+
"module": "wizard.mjs",
|
|
42
|
+
"delegates": {}
|
|
43
|
+
},
|
|
44
|
+
"wizard": {
|
|
45
|
+
"smokeBank": "wizard-smoke",
|
|
46
|
+
"retainMethod": "POST",
|
|
47
|
+
"retainPath": "/api/v1/add",
|
|
48
|
+
"retainBody": "multipart/form-data: datasetName=wizard_smoke, data=wizard-smoke.md (done by the smoke hook)",
|
|
49
|
+
"recallMethod": "POST",
|
|
50
|
+
"recallPath": "/api/v1/search",
|
|
51
|
+
"recallBody": "{\"searchType\":\"GRAPH_COMPLETION\",\"query\":\"What is the project codename?\",\"datasets\":[\"wizard_smoke\"]}",
|
|
52
|
+
"recallHint": "check {compose} logs cognee and cognify settings (GLiNER/FastEmbed, Ollama, or LLM_API_KEY)",
|
|
53
|
+
"deleteMethod": "DELETE",
|
|
54
|
+
"deletePath": "/api/v1/datasets/{bank}"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cognee sub-wizard (hook API v2). Cognee runs as a pinned docker service on a loopback
|
|
3
|
+
* port in single-user mode; its secrets (LLM_API_KEY) live in an operator env file outside
|
|
4
|
+
* the repo (default ~/.config/personal-memory/cognee.env), never in the stack .env,
|
|
5
|
+
* wizard.conf, config.toml, the summary or an error message. See lib/ for the
|
|
6
|
+
* implementations and docs/provider-wizard-hooks.md for the hook contract.
|
|
7
|
+
*
|
|
8
|
+
* This module must not import wizard/lib/run-wizard.mjs; it receives `helpers`.
|
|
9
|
+
*/
|
|
10
|
+
import { applyConfig, configToml as buildConfigToml } from "./lib/config.mjs";
|
|
11
|
+
import { clackSetup as askInClack } from "./lib/clack.mjs";
|
|
12
|
+
import { setupCodingAgent as printRestAgentHelp } from "./lib/coding-agent.mjs";
|
|
13
|
+
import { beforeStack as prepareEnvDirs, stackEnv as cogneeStackEnv } from "./lib/env-setup.mjs";
|
|
14
|
+
import { captureSecrets, configureLlm } from "./lib/llm-env.mjs";
|
|
15
|
+
import { resolvePorts as resolveCogneePorts } from "./lib/ports.mjs";
|
|
16
|
+
import { runSmoke } from "./lib/smoke.mjs";
|
|
17
|
+
import { ensureState } from "./lib/state.mjs";
|
|
18
|
+
import { summary as cogneeSummary } from "./lib/summary.mjs";
|
|
19
|
+
import { validateCognee } from "./lib/validate.mjs";
|
|
20
|
+
|
|
21
|
+
// Called by scripts/setup.mjs (the stack .env writer), not by the wizard.
|
|
22
|
+
export { prepareStackEnv, setupNotices } from "./lib/stack-env.mjs";
|
|
23
|
+
|
|
24
|
+
/** @typedef {import('../../wizard/lib/provider-wizard/helpers.mjs').ProviderWizardHelpers} Helpers */
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Quiet: fill Cognee's context fields, map the `[memory.cognee]` TOML table (port,
|
|
28
|
+
* env_file, indexer_env_file) into the environment when the environment did not set it, and
|
|
29
|
+
* take the secret answers (PM_COGNEE_LLM_API_KEY and friends) out of `process.env`. This
|
|
30
|
+
* runs before the wizard's first docker call, so no child process inherits a key.
|
|
31
|
+
* @param {Record<string, any>} ctx
|
|
32
|
+
* @param {Helpers} h
|
|
33
|
+
*/
|
|
34
|
+
export async function init(ctx, h) {
|
|
35
|
+
applyConfig(ctx, h);
|
|
36
|
+
captureSecrets(ctx);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Quiet: nothing to restore. The saved port is picked up in `resolvePorts`, which runs
|
|
41
|
+
* before this hook; nothing secret is saved anywhere.
|
|
42
|
+
* @param {Record<string, any>} ctx
|
|
43
|
+
*/
|
|
44
|
+
export async function hydrate(ctx) {
|
|
45
|
+
ensureState(ctx);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The single host port (COGNEE_PORT, default 8766). */
|
|
49
|
+
export const resolvePorts = resolveCogneePorts;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Step "LLM / embeddings": write cognify settings (default GLiNER + FastEmbed, or Ollama /
|
|
53
|
+
* OpenAI answers given as PM_COGNEE_<NAME>) into the operator env file. Never fails for a
|
|
54
|
+
* missing cloud key: the default local path is cognify-ready without one.
|
|
55
|
+
* @param {Record<string, any>} ctx
|
|
56
|
+
* @param {Helpers} h
|
|
57
|
+
*/
|
|
58
|
+
export async function configureModelRouting(ctx, h) {
|
|
59
|
+
await configureLlm(ctx, h);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Quiet: description and environment for the stack setup script (scripts/setup.mjs).
|
|
64
|
+
* @param {Record<string, any>} ctx
|
|
65
|
+
*/
|
|
66
|
+
export function stackEnv(ctx) {
|
|
67
|
+
return cogneeStackEnv(ctx);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Create the env directories (mode 700) before the stack setup masks them; warn about
|
|
72
|
+
* loose modes.
|
|
73
|
+
* @param {Record<string, any>} ctx
|
|
74
|
+
* @param {Helpers} h
|
|
75
|
+
*/
|
|
76
|
+
export async function beforeStack(ctx, h) {
|
|
77
|
+
await prepareEnvDirs(ctx, h);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Replaces the manifest smoke test: health, create dataset, multipart add, list, delete.
|
|
82
|
+
* Recall is not checked (ingestion is asynchronous).
|
|
83
|
+
* @param {Record<string, any>} ctx
|
|
84
|
+
* @param {Helpers} h
|
|
85
|
+
*/
|
|
86
|
+
export async function smoke(ctx, h) {
|
|
87
|
+
await runSmoke(ctx, h);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Appends to ctx.validationErrors / ctx.validationChecks after the shared checks.
|
|
92
|
+
* @param {Record<string, any>} ctx
|
|
93
|
+
* @param {Helpers} h
|
|
94
|
+
*/
|
|
95
|
+
export async function extendValidation(ctx, h) {
|
|
96
|
+
validateCognee(ctx, h);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Quiet: tables merged into config.toml (`[memory.cognee]`: port, env_file; no secrets).
|
|
101
|
+
* @param {Record<string, any>} ctx
|
|
102
|
+
*/
|
|
103
|
+
export function configToml(ctx) {
|
|
104
|
+
return buildConfigToml(ctx);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Quiet: lines for the closing summary.
|
|
109
|
+
* @param {Record<string, any>} ctx
|
|
110
|
+
*/
|
|
111
|
+
export function summary(ctx) {
|
|
112
|
+
return cogneeSummary(ctx);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Clack-only: choose OpenAI key vs Ollama; for OpenAI, ask with a hidden prompt. Answers
|
|
117
|
+
* reach the wizard as PM_COGNEE_* in its own process environment.
|
|
118
|
+
* @param {Record<string, any>} ctx
|
|
119
|
+
* @param {typeof import("@clack/prompts")} ui
|
|
120
|
+
* @param {Helpers} h
|
|
121
|
+
*/
|
|
122
|
+
export async function clackSetup(ctx, ui, h) {
|
|
123
|
+
return askInClack(ctx, ui, h);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* After the generic coding-agent step (skipped: no pluginPackage): print how agents talk
|
|
128
|
+
* to Cognee over REST on the loopback port.
|
|
129
|
+
* @param {Record<string, any>} ctx
|
|
130
|
+
* @param {Helpers} h
|
|
131
|
+
*/
|
|
132
|
+
export async function setupCodingAgent(ctx, h) {
|
|
133
|
+
await printRestAgentHelp(ctx, h);
|
|
134
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "graphiti",
|
|
3
|
+
"label": "Graphiti",
|
|
4
|
+
"status": "planned",
|
|
5
|
+
"notes": "Placeholder for Zep Graphiti temporal knowledge graph backend.",
|
|
6
|
+
"settings": {
|
|
7
|
+
"nativeDocs": "https://help.getzep.com/graphiti",
|
|
8
|
+
"nativeConfigPaths": [],
|
|
9
|
+
"wizardOwns": []
|
|
10
|
+
},
|
|
11
|
+
"compose": { "profile": "graphiti", "files": [], "services": [] },
|
|
12
|
+
"indexer": { "apiUrlEnv": "GRAPHITI_API_URL", "sink": "graphiti" },
|
|
13
|
+
"codingAgent": { "pluginPackage": null, "configTemplate": null },
|
|
14
|
+
"wizard": {}
|
|
15
|
+
}
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hindsight's questions for the Clack setup UI: model backend, models, reflect model
|
|
3
|
+
* (or, for Meridian, its URL, key and the two Claude models).
|
|
4
|
+
* The meta UI asks the provider-neutral questions (action, provider) and then calls
|
|
5
|
+
* clackSetup; the returned environment is handed to the wizard so it skips its own
|
|
6
|
+
* model prompts (WIZARD_SKIP_BACKEND_STEP).
|
|
7
|
+
*/
|
|
8
|
+
import { applyConfigEnv } from "./config.mjs";
|
|
9
|
+
import {
|
|
10
|
+
bridgeReport,
|
|
11
|
+
containerApiBase,
|
|
12
|
+
dockerBridgeIp,
|
|
13
|
+
existingMeridianKey,
|
|
14
|
+
MERIDIAN_DEFAULT_BASE,
|
|
15
|
+
MERIDIAN_GUIDE,
|
|
16
|
+
MERIDIAN_REFLECT_DEFAULT,
|
|
17
|
+
MERIDIAN_RETAIN_DEFAULT,
|
|
18
|
+
normalizeMeridianBase,
|
|
19
|
+
pickModel,
|
|
20
|
+
probeMeridian,
|
|
21
|
+
} from "./meridian.mjs";
|
|
22
|
+
import { fetchJson, normalizeOpenAiBase, ollamaModelNames, openAiModelIds } from "./probe.mjs";
|
|
23
|
+
import {
|
|
24
|
+
LEMOND_DEFAULT_MODEL,
|
|
25
|
+
OLLAMA_COMPOSE_API_BASE,
|
|
26
|
+
OLLAMA_DEFAULT_MODEL,
|
|
27
|
+
OLLAMA_HOST_API_BASE,
|
|
28
|
+
} from "./state.mjs";
|
|
29
|
+
|
|
30
|
+
/** @typedef {import("../../../wizard/lib/provider-wizard/helpers.mjs").ProviderWizardHelpers} Helpers */
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {{ repoRoot: string, home: string, wizardConf: string, pmMerged?: Record<string, unknown> }} ctx
|
|
34
|
+
* @param {typeof import("@clack/prompts")} ui the @clack/prompts module
|
|
35
|
+
* @param {Helpers} h
|
|
36
|
+
* @returns {Promise<Record<string, string>>} environment for the wizard process
|
|
37
|
+
*/
|
|
38
|
+
export async function clackSetup(ctx, ui, h) {
|
|
39
|
+
const wizardConf = ctx.wizardConf;
|
|
40
|
+
if (ctx.pmMerged) applyConfigEnv(ctx.pmMerged);
|
|
41
|
+
/** @type {Record<string, string>} */
|
|
42
|
+
const handoff = {};
|
|
43
|
+
|
|
44
|
+
const lemondBase = process.env.LEMOND_BASE || "http://127.0.0.1:13305";
|
|
45
|
+
handoff.LEMOND_BASE = lemondBase;
|
|
46
|
+
|
|
47
|
+
const backendDefault =
|
|
48
|
+
process.env.PM_BACKEND ||
|
|
49
|
+
h.envValue(wizardConf, "MEMORY_BACKEND") ||
|
|
50
|
+
"lemond";
|
|
51
|
+
|
|
52
|
+
const backend = await ui.select({
|
|
53
|
+
message: "Model backend",
|
|
54
|
+
options: [
|
|
55
|
+
{
|
|
56
|
+
value: "lemond",
|
|
57
|
+
label: "Lemonade (lemond)",
|
|
58
|
+
hint: "local GGUFs on this host",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
value: "ollama",
|
|
62
|
+
label: "Ollama",
|
|
63
|
+
hint: "local models on this host",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
value: "custom",
|
|
67
|
+
label: "OpenAI-compatible URL",
|
|
68
|
+
hint: "hosted API, other",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
value: "meridian",
|
|
72
|
+
label: "Claude subscription (Meridian)",
|
|
73
|
+
hint: "a Meridian proxy you already run on this host",
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
initialValue: ["lemond", "ollama", "custom", "meridian"].includes(backendDefault)
|
|
77
|
+
? backendDefault
|
|
78
|
+
: "lemond",
|
|
79
|
+
});
|
|
80
|
+
if (ui.isCancel(backend)) {
|
|
81
|
+
ui.cancel("Setup cancelled.");
|
|
82
|
+
process.exit(0);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let model = "";
|
|
86
|
+
let apiBase = "";
|
|
87
|
+
let reflectModel =
|
|
88
|
+
process.env.PM_REFLECT_MODEL ||
|
|
89
|
+
h.envValue(wizardConf, "MEMORY_REFLECT_MODEL") ||
|
|
90
|
+
"";
|
|
91
|
+
|
|
92
|
+
if (backend === "lemond") {
|
|
93
|
+
const spin = ui.spinner();
|
|
94
|
+
spin.start(`Checking lemond at ${lemondBase}`);
|
|
95
|
+
const body = await fetchJson(`${lemondBase}/v1/models`);
|
|
96
|
+
const ids = openAiModelIds(body);
|
|
97
|
+
spin.stop(
|
|
98
|
+
body ? `lemond answered (${ids.length} models)` : "lemond not reachable",
|
|
99
|
+
);
|
|
100
|
+
if (!body) {
|
|
101
|
+
ui.log.warn(
|
|
102
|
+
"Start lemonade (lemond) on this host, or pick custom / Ollama instead.",
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
const defaultModel =
|
|
106
|
+
h.envValue(wizardConf, "MEMORY_MODEL") ||
|
|
107
|
+
LEMOND_DEFAULT_MODEL;
|
|
108
|
+
if (ids.length > 0) {
|
|
109
|
+
const picked = await ui.select({
|
|
110
|
+
message: "Retain / consolidate model",
|
|
111
|
+
options: ids.map((id) => ({ value: id, label: id })),
|
|
112
|
+
initialValue: ids.includes(defaultModel) ? defaultModel : ids[0],
|
|
113
|
+
});
|
|
114
|
+
if (ui.isCancel(picked)) process.exit(0);
|
|
115
|
+
model = /** @type {string} */ (picked);
|
|
116
|
+
} else {
|
|
117
|
+
const typed = await ui.text({
|
|
118
|
+
message: "Retain / consolidate model id",
|
|
119
|
+
placeholder: defaultModel,
|
|
120
|
+
defaultValue: defaultModel,
|
|
121
|
+
});
|
|
122
|
+
if (ui.isCancel(typed)) process.exit(0);
|
|
123
|
+
model = /** @type {string} */ (typed);
|
|
124
|
+
}
|
|
125
|
+
apiBase = "http://host.docker.internal:13305/v1";
|
|
126
|
+
} else if (backend === "ollama") {
|
|
127
|
+
const ollamaBase = "http://127.0.0.1:11434";
|
|
128
|
+
const spin = ui.spinner();
|
|
129
|
+
spin.start(`Checking Ollama at ${ollamaBase}`);
|
|
130
|
+
const body = await fetchJson(`${ollamaBase}/api/tags`);
|
|
131
|
+
const names = ollamaModelNames(body);
|
|
132
|
+
spin.stop(
|
|
133
|
+
body ? `Ollama answered (${names.length} models)` : "Ollama not reachable",
|
|
134
|
+
);
|
|
135
|
+
let ollamaInCompose = false;
|
|
136
|
+
if (!body) {
|
|
137
|
+
const useDocker = await ui.confirm({
|
|
138
|
+
message: "Ollama is not on this host. Run it in Docker (compose profile ollama)?",
|
|
139
|
+
active: "yes",
|
|
140
|
+
inactive: "no",
|
|
141
|
+
initialValue: true,
|
|
142
|
+
});
|
|
143
|
+
if (ui.isCancel(useDocker)) process.exit(0);
|
|
144
|
+
ollamaInCompose = Boolean(useDocker);
|
|
145
|
+
if (ollamaInCompose) {
|
|
146
|
+
ui.log.info(
|
|
147
|
+
"LiteLLM will call http://ollama:11434; the wizard pulls the model after the stack starts.",
|
|
148
|
+
);
|
|
149
|
+
} else {
|
|
150
|
+
ui.log.warn(
|
|
151
|
+
"Start Ollama on this host (OLLAMA_HOST on the Docker bridge), or rerun and pick Docker.",
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const defaultModel =
|
|
156
|
+
h.envValue(wizardConf, "MEMORY_MODEL") ||
|
|
157
|
+
OLLAMA_DEFAULT_MODEL;
|
|
158
|
+
if (names.length > 0) {
|
|
159
|
+
const picked = await ui.select({
|
|
160
|
+
message: "Retain / consolidate model",
|
|
161
|
+
options: names.map((n) => ({ value: n, label: n })),
|
|
162
|
+
initialValue: names.includes(defaultModel) ? defaultModel : names[0],
|
|
163
|
+
});
|
|
164
|
+
if (ui.isCancel(picked)) process.exit(0);
|
|
165
|
+
model = /** @type {string} */ (picked);
|
|
166
|
+
} else {
|
|
167
|
+
const typed = await ui.text({
|
|
168
|
+
message: "Retain / consolidate model",
|
|
169
|
+
placeholder: defaultModel,
|
|
170
|
+
defaultValue: defaultModel,
|
|
171
|
+
});
|
|
172
|
+
if (ui.isCancel(typed)) process.exit(0);
|
|
173
|
+
model = /** @type {string} */ (typed);
|
|
174
|
+
}
|
|
175
|
+
apiBase = ollamaInCompose ? OLLAMA_COMPOSE_API_BASE : OLLAMA_HOST_API_BASE;
|
|
176
|
+
if (ollamaInCompose) handoff.MEMORY_OLLAMA_IN_COMPOSE = "1";
|
|
177
|
+
} else if (backend === "meridian") {
|
|
178
|
+
const m = await askMeridian(ctx, ui, h);
|
|
179
|
+
model = m.model;
|
|
180
|
+
reflectModel = m.reflectModel;
|
|
181
|
+
apiBase = m.apiBase;
|
|
182
|
+
Object.assign(handoff, m.env);
|
|
183
|
+
} else {
|
|
184
|
+
const defaultBase = "http://host.docker.internal:3456/v1";
|
|
185
|
+
const defaultModel =
|
|
186
|
+
h.envValue(wizardConf, "MEMORY_MODEL") ||
|
|
187
|
+
LEMOND_DEFAULT_MODEL;
|
|
188
|
+
const baseInput = await ui.text({
|
|
189
|
+
message: "OpenAI-compatible base URL (host.docker.internal from containers)",
|
|
190
|
+
placeholder: defaultBase,
|
|
191
|
+
defaultValue: defaultBase,
|
|
192
|
+
});
|
|
193
|
+
if (ui.isCancel(baseInput)) process.exit(0);
|
|
194
|
+
apiBase = normalizeOpenAiBase(/** @type {string} */ (baseInput));
|
|
195
|
+
|
|
196
|
+
const spin = ui.spinner();
|
|
197
|
+
spin.start("Listing models");
|
|
198
|
+
const body = await fetchJson(`${apiBase}/models`);
|
|
199
|
+
const ids = openAiModelIds(body);
|
|
200
|
+
spin.stop(
|
|
201
|
+
ids.length
|
|
202
|
+
? `Found ${ids.length} models`
|
|
203
|
+
: "Could not list models (enter id manually)",
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
if (ids.length > 0) {
|
|
207
|
+
const picked = await ui.select({
|
|
208
|
+
message: "Retain / consolidate model",
|
|
209
|
+
options: ids.map((id) => ({ value: id, label: id })),
|
|
210
|
+
initialValue: ids.includes(defaultModel) ? defaultModel : ids[0],
|
|
211
|
+
});
|
|
212
|
+
if (ui.isCancel(picked)) process.exit(0);
|
|
213
|
+
model = /** @type {string} */ (picked);
|
|
214
|
+
} else {
|
|
215
|
+
const typed = await ui.text({
|
|
216
|
+
message: "Retain / consolidate model id",
|
|
217
|
+
placeholder: defaultModel,
|
|
218
|
+
defaultValue: defaultModel,
|
|
219
|
+
});
|
|
220
|
+
if (ui.isCancel(typed)) process.exit(0);
|
|
221
|
+
model = /** @type {string} */ (typed);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (backend !== "meridian") reflectModel = await askReflect(ui, model, reflectModel);
|
|
226
|
+
|
|
227
|
+
ui.note("Next: Docker, secrets, indexing, and starting the stack.", "Backend configured");
|
|
228
|
+
|
|
229
|
+
handoff.WIZARD_SKIP_BACKEND_STEP = "1";
|
|
230
|
+
handoff.PM_BACKEND = /** @type {string} */ (backend);
|
|
231
|
+
handoff.PM_DEFAULT_MODEL = model;
|
|
232
|
+
handoff.MEMORY_API_BASE = apiBase;
|
|
233
|
+
handoff.PM_REFLECT_MODEL = reflectModel;
|
|
234
|
+
return handoff;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* @param {typeof import("@clack/prompts")} ui
|
|
239
|
+
* @param {string} model retain model
|
|
240
|
+
* @param {string} reflectModel stored or env reflect model
|
|
241
|
+
*/
|
|
242
|
+
async function askReflect(ui, model, reflectModel) {
|
|
243
|
+
const reflectChoice = await ui.select({
|
|
244
|
+
message: "Reflect model (needs tool calls; used for memory-reflect)",
|
|
245
|
+
options: [
|
|
246
|
+
{
|
|
247
|
+
value: "",
|
|
248
|
+
label: "Shipped default for this backend",
|
|
249
|
+
hint: "E4B route on lemond, etc.",
|
|
250
|
+
},
|
|
251
|
+
{ value: "same", label: "Same as retain model" },
|
|
252
|
+
{ value: "custom", label: "Pick another model id" },
|
|
253
|
+
],
|
|
254
|
+
initialValue: reflectModel ? "custom" : "",
|
|
255
|
+
});
|
|
256
|
+
if (ui.isCancel(reflectChoice)) process.exit(0);
|
|
257
|
+
|
|
258
|
+
if (reflectChoice === "same") {
|
|
259
|
+
reflectModel = model;
|
|
260
|
+
} else if (reflectChoice === "custom") {
|
|
261
|
+
const typed = await ui.text({
|
|
262
|
+
message: "Reflect model id",
|
|
263
|
+
placeholder: model,
|
|
264
|
+
defaultValue: reflectModel || model,
|
|
265
|
+
});
|
|
266
|
+
if (ui.isCancel(typed)) process.exit(0);
|
|
267
|
+
reflectModel = /** @type {string} */ (typed);
|
|
268
|
+
} else {
|
|
269
|
+
reflectModel = "";
|
|
270
|
+
}
|
|
271
|
+
return reflectModel;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Meridian URL, key and models. Detect only: Meridian must already run.
|
|
276
|
+
* @param {{ home: string, wizardConf: string }} ctx
|
|
277
|
+
* @param {typeof import("@clack/prompts")} ui
|
|
278
|
+
* @param {Helpers} h
|
|
279
|
+
*/
|
|
280
|
+
async function askMeridian(ctx, ui, h) {
|
|
281
|
+
ui.log.info(`The wizard does not install or start Meridian; see ${MERIDIAN_GUIDE}.`);
|
|
282
|
+
const stored =
|
|
283
|
+
h.envValue(ctx.wizardConf, "MEMORY_BACKEND") === "meridian"
|
|
284
|
+
? h.envValue(ctx.wizardConf, "MEMORY_MERIDIAN_URL")
|
|
285
|
+
: "";
|
|
286
|
+
const defaultBase = process.env.MERIDIAN_BASE || stored || MERIDIAN_DEFAULT_BASE;
|
|
287
|
+
const baseInput = await ui.text({
|
|
288
|
+
message: "Meridian URL from this host",
|
|
289
|
+
placeholder: defaultBase,
|
|
290
|
+
defaultValue: defaultBase,
|
|
291
|
+
});
|
|
292
|
+
if (ui.isCancel(baseInput)) process.exit(0);
|
|
293
|
+
const meridianBase = normalizeMeridianBase(/** @type {string} */ (baseInput));
|
|
294
|
+
const paths = {
|
|
295
|
+
meridianEnvFile: `${ctx.home}/.config/meridian/meridian.env`,
|
|
296
|
+
litellmEnv: `${ctx.home}/.config/hindsight/litellm.env`,
|
|
297
|
+
};
|
|
298
|
+
const existing = existingMeridianKey(paths, h);
|
|
299
|
+
const keyInput = await ui.password({
|
|
300
|
+
message: `MERIDIAN_API_KEY (blank uses ${existing.source || "no key"})`,
|
|
301
|
+
});
|
|
302
|
+
if (ui.isCancel(keyInput)) process.exit(0);
|
|
303
|
+
const typedKey = String(keyInput || "").trim();
|
|
304
|
+
const key = typedKey || existing.key;
|
|
305
|
+
|
|
306
|
+
const bridgeIp = dockerBridgeIp();
|
|
307
|
+
const spin = ui.spinner();
|
|
308
|
+
spin.start(`Checking Meridian at ${meridianBase}`);
|
|
309
|
+
const probe = await probeMeridian(meridianBase, key, bridgeIp);
|
|
310
|
+
spin.stop(
|
|
311
|
+
probe.answered ? `Meridian answered (${probe.ids.length} models)` : "Meridian not reachable",
|
|
312
|
+
);
|
|
313
|
+
if (!probe.answered) {
|
|
314
|
+
ui.log.warn(`Start Meridian first (${MERIDIAN_GUIDE}); the route uses the guide's default models.`);
|
|
315
|
+
} else if (probe.modelsStatus === 401 || probe.modelsStatus === 403) {
|
|
316
|
+
ui.log.warn(`Meridian rejected the key on /v1/models (HTTP ${probe.modelsStatus}).`);
|
|
317
|
+
}
|
|
318
|
+
const apiBase = containerApiBase(meridianBase);
|
|
319
|
+
const report = bridgeReport({ ...paths, meridianBase, apiBase, dockerBridgeIp: bridgeIp }, h.envValue, probe);
|
|
320
|
+
if (report) (report.level === "warn" ? ui.log.warn : ui.log.info)(report.text);
|
|
321
|
+
|
|
322
|
+
const choose = async (message, preferred, family, candidates) => {
|
|
323
|
+
const def = pickModel(probe.ids, preferred, family, candidates);
|
|
324
|
+
const picked = probe.ids.length
|
|
325
|
+
? await ui.select({
|
|
326
|
+
message,
|
|
327
|
+
options: probe.ids.map((id) => ({ value: id, label: id })),
|
|
328
|
+
initialValue: def,
|
|
329
|
+
})
|
|
330
|
+
: await ui.text({ message, placeholder: def, defaultValue: def });
|
|
331
|
+
if (ui.isCancel(picked)) process.exit(0);
|
|
332
|
+
return /** @type {string} */ (picked);
|
|
333
|
+
};
|
|
334
|
+
const sameBackend = h.envValue(ctx.wizardConf, "MEMORY_BACKEND") === "meridian";
|
|
335
|
+
const model = await choose("Retain / consolidate model", MERIDIAN_RETAIN_DEFAULT, /haiku/, [
|
|
336
|
+
process.env.PM_DEFAULT_MODEL,
|
|
337
|
+
sameBackend ? h.envValue(ctx.wizardConf, "MEMORY_MODEL") : "",
|
|
338
|
+
]);
|
|
339
|
+
const reflectModel = await choose("Reflect model (needs tool calls)", MERIDIAN_REFLECT_DEFAULT, /sonnet/, [
|
|
340
|
+
process.env.PM_REFLECT_MODEL,
|
|
341
|
+
sameBackend ? h.envValue(ctx.wizardConf, "MEMORY_REFLECT_MODEL") : "",
|
|
342
|
+
]);
|
|
343
|
+
/** @type {Record<string, string>} */
|
|
344
|
+
const env = { MERIDIAN_BASE: meridianBase };
|
|
345
|
+
if (typedKey) env.MERIDIAN_API_KEY = typedKey;
|
|
346
|
+
return { model, reflectModel, apiBase, env };
|
|
347
|
+
}
|