@oratis/lisa 0.9.0 → 0.11.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.
- package/README.md +123 -16
- package/README.zh-CN.md +101 -15
- package/completions/_lisa +56 -0
- package/completions/lisa.bash +35 -1
- package/completions/lisa.fish +18 -1
- package/dist/advisor/engine.d.ts +7 -0
- package/dist/advisor/engine.d.ts.map +1 -1
- package/dist/advisor/engine.js +12 -0
- package/dist/advisor/engine.js.map +1 -1
- package/dist/agent.d.ts +14 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +58 -7
- package/dist/agent.js.map +1 -1
- package/dist/agents/managed.d.ts +108 -0
- package/dist/agents/managed.d.ts.map +1 -0
- package/dist/agents/managed.js +241 -0
- package/dist/agents/managed.js.map +1 -0
- package/dist/agents/pty.d.ts +155 -0
- package/dist/agents/pty.d.ts.map +1 -0
- package/dist/agents/pty.js +299 -0
- package/dist/agents/pty.js.map +1 -0
- package/dist/approval.d.ts +13 -0
- package/dist/approval.d.ts.map +1 -1
- package/dist/approval.js +25 -2
- package/dist/approval.js.map +1 -1
- package/dist/autonomy/runs.d.ts +33 -0
- package/dist/autonomy/runs.d.ts.map +1 -0
- package/dist/autonomy/runs.js +106 -0
- package/dist/autonomy/runs.js.map +1 -0
- package/dist/channels/feishu.d.ts.map +1 -1
- package/dist/channels/feishu.js +65 -0
- package/dist/channels/feishu.js.map +1 -1
- package/dist/channels/router.d.ts +7 -0
- package/dist/channels/router.d.ts.map +1 -1
- package/dist/channels/router.js +1 -1
- package/dist/channels/router.js.map +1 -1
- package/dist/cli/agents-pty.d.ts +18 -0
- package/dist/cli/agents-pty.d.ts.map +1 -0
- package/dist/cli/agents-pty.js +182 -0
- package/dist/cli/agents-pty.js.map +1 -0
- package/dist/cli/agents.d.ts +2 -0
- package/dist/cli/agents.d.ts.map +1 -0
- package/dist/cli/agents.js +65 -0
- package/dist/cli/agents.js.map +1 -0
- package/dist/cli/consent.d.ts +2 -0
- package/dist/cli/consent.d.ts.map +1 -0
- package/dist/cli/consent.js +57 -0
- package/dist/cli/consent.js.map +1 -0
- package/dist/cli/model.d.ts +2 -0
- package/dist/cli/model.d.ts.map +1 -0
- package/dist/cli/model.js +121 -0
- package/dist/cli/model.js.map +1 -0
- package/dist/cli/sense.d.ts +2 -0
- package/dist/cli/sense.d.ts.map +1 -0
- package/dist/cli/sense.js +36 -0
- package/dist/cli/sense.js.map +1 -0
- package/dist/cli.js +117 -12
- package/dist/cli.js.map +1 -1
- package/dist/consent/blacklist.d.ts +28 -0
- package/dist/consent/blacklist.d.ts.map +1 -0
- package/dist/consent/blacklist.js +78 -0
- package/dist/consent/blacklist.js.map +1 -0
- package/dist/consent/store.d.ts +45 -0
- package/dist/consent/store.d.ts.map +1 -0
- package/dist/consent/store.js +126 -0
- package/dist/consent/store.js.map +1 -0
- package/dist/control/policy.d.ts +13 -0
- package/dist/control/policy.d.ts.map +1 -0
- package/dist/control/policy.js +57 -0
- package/dist/control/policy.js.map +1 -0
- package/dist/heartbeat/runner.d.ts.map +1 -1
- package/dist/heartbeat/runner.js +70 -14
- package/dist/heartbeat/runner.js.map +1 -1
- package/dist/idle/runner.d.ts.map +1 -1
- package/dist/idle/runner.js +87 -17
- package/dist/idle/runner.js.map +1 -1
- package/dist/integrations/aider/observer.d.ts +21 -1
- package/dist/integrations/aider/observer.d.ts.map +1 -1
- package/dist/integrations/aider/observer.js +110 -1
- package/dist/integrations/aider/observer.js.map +1 -1
- package/dist/integrations/claude-code/liveness.d.ts +10 -0
- package/dist/integrations/claude-code/liveness.d.ts.map +1 -0
- package/dist/integrations/claude-code/liveness.js +62 -0
- package/dist/integrations/claude-code/liveness.js.map +1 -0
- package/dist/integrations/claude-code/watcher.d.ts +39 -4
- package/dist/integrations/claude-code/watcher.d.ts.map +1 -1
- package/dist/integrations/claude-code/watcher.js +94 -57
- package/dist/integrations/claude-code/watcher.js.map +1 -1
- package/dist/integrations/codex/observer.d.ts +19 -6
- package/dist/integrations/codex/observer.d.ts.map +1 -1
- package/dist/integrations/codex/observer.js +228 -4
- package/dist/integrations/codex/observer.js.map +1 -1
- package/dist/integrations/dispatch-ledger.d.ts +30 -1
- package/dist/integrations/dispatch-ledger.d.ts.map +1 -1
- package/dist/integrations/dispatch-ledger.js +75 -9
- package/dist/integrations/dispatch-ledger.js.map +1 -1
- package/dist/integrations/git/branch.d.ts +11 -0
- package/dist/integrations/git/branch.d.ts.map +1 -0
- package/dist/integrations/git/branch.js +49 -0
- package/dist/integrations/git/branch.js.map +1 -0
- package/dist/integrations/git/observer.d.ts +39 -0
- package/dist/integrations/git/observer.d.ts.map +1 -0
- package/dist/integrations/git/observer.js +252 -0
- package/dist/integrations/git/observer.js.map +1 -0
- package/dist/integrations/github-pr/observer.d.ts.map +1 -1
- package/dist/integrations/github-pr/observer.js +7 -2
- package/dist/integrations/github-pr/observer.js.map +1 -1
- package/dist/integrations/hub.d.ts +8 -0
- package/dist/integrations/hub.d.ts.map +1 -1
- package/dist/integrations/hub.js +39 -1
- package/dist/integrations/hub.js.map +1 -1
- package/dist/integrations/managed/observer.d.ts +17 -0
- package/dist/integrations/managed/observer.d.ts.map +1 -0
- package/dist/integrations/managed/observer.js +46 -0
- package/dist/integrations/managed/observer.js.map +1 -0
- package/dist/integrations/opencode/observer.d.ts +53 -5
- package/dist/integrations/opencode/observer.d.ts.map +1 -1
- package/dist/integrations/opencode/observer.js +242 -20
- package/dist/integrations/opencode/observer.js.map +1 -1
- package/dist/integrations/pty/observer.d.ts +25 -0
- package/dist/integrations/pty/observer.d.ts.map +1 -0
- package/dist/integrations/pty/observer.js +48 -0
- package/dist/integrations/pty/observer.js.map +1 -0
- package/dist/integrations/registry.d.ts.map +1 -1
- package/dist/integrations/registry.js +5 -0
- package/dist/integrations/registry.js.map +1 -1
- package/dist/integrations/shell/observer.d.ts +33 -0
- package/dist/integrations/shell/observer.d.ts.map +1 -0
- package/dist/integrations/shell/observer.js +223 -0
- package/dist/integrations/shell/observer.js.map +1 -0
- package/dist/integrations/takoapi/a2a.d.ts +38 -0
- package/dist/integrations/takoapi/a2a.d.ts.map +1 -0
- package/dist/integrations/takoapi/a2a.js +70 -0
- package/dist/integrations/takoapi/a2a.js.map +1 -0
- package/dist/integrations/takoapi/ledger.d.ts +32 -0
- package/dist/integrations/takoapi/ledger.d.ts.map +1 -0
- package/dist/integrations/takoapi/ledger.js +96 -0
- package/dist/integrations/takoapi/ledger.js.map +1 -0
- package/dist/integrations/takoapi/observer.d.ts +39 -0
- package/dist/integrations/takoapi/observer.d.ts.map +1 -0
- package/dist/integrations/takoapi/observer.js +102 -0
- package/dist/integrations/takoapi/observer.js.map +1 -0
- package/dist/integrations/types.d.ts +17 -0
- package/dist/integrations/types.d.ts.map +1 -1
- package/dist/mcp/client.d.ts +5 -0
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/mcp/client.js +1 -1
- package/dist/mcp/client.js.map +1 -1
- package/dist/memory/embedding.d.ts +45 -0
- package/dist/memory/embedding.d.ts.map +1 -0
- package/dist/memory/embedding.js +139 -0
- package/dist/memory/embedding.js.map +1 -0
- package/dist/memory/search_tool.d.ts.map +1 -1
- package/dist/memory/search_tool.js +6 -2
- package/dist/memory/search_tool.js.map +1 -1
- package/dist/memory/vector.d.ts +14 -3
- package/dist/memory/vector.d.ts.map +1 -1
- package/dist/memory/vector.js +50 -0
- package/dist/memory/vector.js.map +1 -1
- package/dist/model/local.d.ts +43 -0
- package/dist/model/local.d.ts.map +1 -0
- package/dist/model/local.js +118 -0
- package/dist/model/local.js.map +1 -0
- package/dist/model/plan-usage.d.ts +41 -0
- package/dist/model/plan-usage.d.ts.map +1 -0
- package/dist/model/plan-usage.js +168 -0
- package/dist/model/plan-usage.js.map +1 -0
- package/dist/model/plans.d.ts +73 -0
- package/dist/model/plans.d.ts.map +1 -0
- package/dist/model/plans.js +246 -0
- package/dist/model/plans.js.map +1 -0
- package/dist/orchestrator/recent-recap.d.ts +2 -0
- package/dist/orchestrator/recent-recap.d.ts.map +1 -0
- package/dist/orchestrator/recent-recap.js +20 -0
- package/dist/orchestrator/recent-recap.js.map +1 -0
- package/dist/providers/anthropic.d.ts +1 -0
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +10 -2
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/fallback.d.ts +23 -0
- package/dist/providers/fallback.d.ts.map +1 -0
- package/dist/providers/fallback.js +29 -0
- package/dist/providers/fallback.js.map +1 -0
- package/dist/providers/gemini.d.ts +2 -0
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +24 -10
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +4 -1
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/registry.d.ts +18 -2
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +56 -9
- package/dist/providers/registry.js.map +1 -1
- package/dist/reflect.d.ts +55 -0
- package/dist/reflect.d.ts.map +1 -1
- package/dist/reflect.js +148 -54
- package/dist/reflect.js.map +1 -1
- package/dist/sense/log.d.ts +9 -0
- package/dist/sense/log.d.ts.map +1 -0
- package/dist/sense/log.js +63 -0
- package/dist/sense/log.js.map +1 -0
- package/dist/sense/screen.d.ts +43 -0
- package/dist/sense/screen.d.ts.map +1 -0
- package/dist/sense/screen.js +107 -0
- package/dist/sense/screen.js.map +1 -0
- package/dist/sense/service.d.ts +16 -0
- package/dist/sense/service.d.ts.map +1 -0
- package/dist/sense/service.js +33 -0
- package/dist/sense/service.js.map +1 -0
- package/dist/sense/types.d.ts +35 -0
- package/dist/sense/types.d.ts.map +1 -0
- package/dist/sense/types.js +11 -0
- package/dist/sense/types.js.map +1 -0
- package/dist/sense/voice.d.ts +28 -0
- package/dist/sense/voice.d.ts.map +1 -0
- package/dist/sense/voice.js +64 -0
- package/dist/sense/voice.js.map +1 -0
- package/dist/soul/git.d.ts.map +1 -1
- package/dist/soul/git.js +35 -16
- package/dist/soul/git.js.map +1 -1
- package/dist/soul/store.d.ts +22 -0
- package/dist/soul/store.d.ts.map +1 -1
- package/dist/soul/store.js +69 -14
- package/dist/soul/store.js.map +1 -1
- package/dist/soul/summary.d.ts +10 -0
- package/dist/soul/summary.d.ts.map +1 -0
- package/dist/soul/summary.js +57 -0
- package/dist/soul/summary.js.map +1 -0
- package/dist/soul/tools.d.ts.map +1 -1
- package/dist/soul/tools.js +13 -24
- package/dist/soul/tools.js.map +1 -1
- package/dist/soul/types.d.ts +9 -0
- package/dist/soul/types.d.ts.map +1 -1
- package/dist/soul/types.js.map +1 -1
- package/dist/subagent.d.ts +7 -0
- package/dist/subagent.d.ts.map +1 -1
- package/dist/subagent.js +3 -1
- package/dist/subagent.js.map +1 -1
- package/dist/tools/dispatch_agent.d.ts +13 -1
- package/dist/tools/dispatch_agent.d.ts.map +1 -1
- package/dist/tools/dispatch_agent.js +56 -12
- package/dist/tools/dispatch_agent.js.map +1 -1
- package/dist/tools/dispatch_status.d.ts +22 -0
- package/dist/tools/dispatch_status.d.ts.map +1 -0
- package/dist/tools/dispatch_status.js +57 -0
- package/dist/tools/dispatch_status.js.map +1 -0
- package/dist/tools/registry.d.ts +29 -0
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +67 -0
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/run_on_plan.d.ts +46 -0
- package/dist/tools/run_on_plan.d.ts.map +1 -0
- package/dist/tools/run_on_plan.js +89 -0
- package/dist/tools/run_on_plan.js.map +1 -0
- package/dist/tools/takoapi.d.ts +60 -0
- package/dist/tools/takoapi.d.ts.map +1 -0
- package/dist/tools/takoapi.js +181 -0
- package/dist/tools/takoapi.js.map +1 -0
- package/dist/tools/validate.d.ts +22 -0
- package/dist/tools/validate.d.ts.map +1 -0
- package/dist/tools/validate.js +50 -0
- package/dist/tools/validate.js.map +1 -0
- package/dist/web/agent-roster.d.ts +56 -0
- package/dist/web/agent-roster.d.ts.map +1 -0
- package/dist/web/agent-roster.js +109 -0
- package/dist/web/agent-roster.js.map +1 -0
- package/dist/web/devices.d.ts +27 -0
- package/dist/web/devices.d.ts.map +1 -0
- package/dist/web/devices.js +113 -0
- package/dist/web/devices.js.map +1 -0
- package/dist/web/island.d.ts +5 -1
- package/dist/web/island.d.ts.map +1 -1
- package/dist/web/island.js +410 -63
- package/dist/web/island.js.map +1 -1
- package/dist/web/lisa-client.d.ts +20 -0
- package/dist/web/lisa-client.d.ts.map +1 -0
- package/dist/web/lisa-client.js +1358 -0
- package/dist/web/lisa-client.js.map +1 -0
- package/dist/web/lisa-css.d.ts +13 -0
- package/dist/web/lisa-css.d.ts.map +1 -0
- package/dist/web/lisa-css.js +1163 -0
- package/dist/web/lisa-css.js.map +1 -0
- package/dist/web/lisa-html.d.ts +1 -1
- package/dist/web/lisa-html.d.ts.map +1 -1
- package/dist/web/lisa-html.js +15 -2136
- package/dist/web/lisa-html.js.map +1 -1
- package/dist/web/push.d.ts +76 -0
- package/dist/web/push.d.ts.map +1 -0
- package/dist/web/push.js +163 -0
- package/dist/web/push.js.map +1 -0
- package/dist/web/server.d.ts +19 -0
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +878 -64
- package/dist/web/server.js.map +1 -1
- package/package.json +5 -2
|
@@ -58,6 +58,23 @@ export interface AgentSession {
|
|
|
58
58
|
lastMtime: number;
|
|
59
59
|
/** L2 activity, present when the adapter runs at tier ≥ "activity". */
|
|
60
60
|
activity?: SessionActivity;
|
|
61
|
+
/**
|
|
62
|
+
* If LISA can CONTROL this session (not just observe it), which control-endpoint
|
|
63
|
+
* family drives it: POST /api/agents/<controllable>/<sessionId>/{send,cancel,…}.
|
|
64
|
+
* - "managed" — LISA runs the agent loop itself (send/cancel/approve).
|
|
65
|
+
* - "pty" — a real CLI LISA spawned under a pseudo-terminal (send/cancel).
|
|
66
|
+
* Absent ⇒ observe-only (an externally-started CLI; no control channel).
|
|
67
|
+
*/
|
|
68
|
+
controllable?: "managed" | "pty";
|
|
69
|
+
/**
|
|
70
|
+
* Observe-only claude session that LISA can ADOPT — it's idle (its process is
|
|
71
|
+
* gone), so `claude --resume <sessionId>` can safely continue it under LISA's
|
|
72
|
+
* control. Set by the API layer for claude-code sessions not currently live.
|
|
73
|
+
*/
|
|
74
|
+
resumable?: boolean;
|
|
75
|
+
/** When a controllable PTY is a resume-adopt, the real claude sessionId it
|
|
76
|
+
* continues — lets the roster drop the observe-only duplicate of that session. */
|
|
77
|
+
adoptedSessionId?: string;
|
|
61
78
|
}
|
|
62
79
|
/** Visibility tier — how deeply LISA may inspect a session. See plan §3. */
|
|
63
80
|
export type VisibilityTier = "off" | "metadata" | "activity" | "intent";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/integrations/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;gDACgD;AAChD,MAAM,MAAM,SAAS,GACjB,aAAa,GACb,OAAO,GACP,UAAU,GACV,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,KAAK,GACL,MAAM,GACN,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB;mEACmE;AACnE,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,SAAS,GACT,OAAO,GACP,MAAM,GACN,MAAM,GACN,SAAS,CAAC;AAEd;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,sEAAsE;IACtE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mFAAmF;IACnF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,SAAS,CAAC;IACjB,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,iBAAiB,CAAC;IACzB,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/integrations/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;gDACgD;AAChD,MAAM,MAAM,SAAS,GACjB,aAAa,GACb,OAAO,GACP,UAAU,GACV,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,KAAK,GACL,MAAM,GACN,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB;mEACmE;AACnE,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,SAAS,GACT,OAAO,GACP,MAAM,GACN,MAAM,GACN,SAAS,CAAC;AAEd;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,sEAAsE;IACtE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mFAAmF;IACnF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,SAAS,CAAC;IACjB,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,iBAAiB,CAAC;IACzB,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IACjC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;uFACmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,4EAA4E;AAC5E,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,CAAC;AAExE,uDAAuD;AACvD,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,0CAA0C;IAC1C,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,qEAAqE;IACrE,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,2CAA2C;IAC3C,IAAI,IAAI,YAAY,EAAE,CAAC;IACvB,6CAA6C;IAC7C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,MAAM,MAAM,oBAAoB,GAAG,CACjC,GAAG,EAAE,sBAAsB,KACxB,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC"}
|
package/dist/mcp/client.d.ts
CHANGED
|
@@ -8,4 +8,9 @@ export interface ConnectedMcpServer {
|
|
|
8
8
|
close(): Promise<void>;
|
|
9
9
|
}
|
|
10
10
|
export declare function connectMcpServers(specs: McpServerSpec[], log?: (msg: string) => void): Promise<ConnectedMcpServer[]>;
|
|
11
|
+
export declare function mcpToolToLisaTool(serverName: string, client: Client, mcpTool: {
|
|
12
|
+
name: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
inputSchema?: object;
|
|
15
|
+
}, log: (msg: string) => void): ToolDefinition;
|
|
11
16
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/mcp/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/mcp/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAEnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,aAAa,EAAE,EACtB,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAe,GACpC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAa/B"}
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/mcp/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAEnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,aAAa,EAAE,EACtB,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAe,GACpC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAa/B;AA8BD,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EACrE,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GACzB,cAAc,CA0BhB"}
|
package/dist/mcp/client.js
CHANGED
|
@@ -38,7 +38,7 @@ async function connectOne(spec, log) {
|
|
|
38
38
|
},
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
function mcpToolToLisaTool(serverName, client, mcpTool, log) {
|
|
41
|
+
export function mcpToolToLisaTool(serverName, client, mcpTool, log) {
|
|
42
42
|
const name = `mcp__${serverName}__${mcpTool.name}`;
|
|
43
43
|
const description = mcpTool.description
|
|
44
44
|
? `[mcp:${serverName}] ${mcpTool.description}`
|
package/dist/mcp/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/mcp/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAWjF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAsB,EACtB,MAA6B,GAAG,EAAE,GAAE,CAAC;IAErC,MAAM,GAAG,GAAyB,EAAE,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK;YAAE,SAAS;QACrC,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC9C,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACpB,GAAG,CAAC,SAAS,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,SAAS,IAAI,CAAC,IAAI,yBAA0B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,IAAmB,EACnB,GAA0B;IAE1B,MAAM,SAAS,GAAG,IAAI,oBAAoB,CAAC;QACzC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE;QACrB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,EAA4B;KACvE,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,EAClC,EAAE,YAAY,EAAE,EAAE,EAAE,CACrB,CAAC;IACF,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;IACtC,MAAM,KAAK,GAAqB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IACpG,OAAO;QACL,IAAI;QACJ,MAAM;QACN,KAAK;QACL,KAAK,CAAC,KAAK;YACT,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/mcp/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface Embedder {
|
|
2
|
+
/** Stable id, e.g. "ollama:nomic-embed-text" — used to cache doc vectors. */
|
|
3
|
+
readonly id: string;
|
|
4
|
+
/** Embed each text into a dense vector. Throws if the backend is unreachable. */
|
|
5
|
+
embed(texts: string[]): Promise<number[][]>;
|
|
6
|
+
}
|
|
7
|
+
/** Cosine similarity in [-1, 1]; 0 for a zero or empty vector. Pure. */
|
|
8
|
+
export declare function cosineSimilarity(a: number[], b: number[]): number;
|
|
9
|
+
export type PostJson = (url: string, body: unknown) => Promise<{
|
|
10
|
+
ok: boolean;
|
|
11
|
+
status: number;
|
|
12
|
+
body: string;
|
|
13
|
+
}>;
|
|
14
|
+
/** Parse Ollama's /api/embeddings response. Pure. */
|
|
15
|
+
export declare function parseOllamaEmbedding(body: string): number[] | null;
|
|
16
|
+
export declare class OllamaEmbedder implements Embedder {
|
|
17
|
+
private model;
|
|
18
|
+
private post;
|
|
19
|
+
readonly id: string;
|
|
20
|
+
private host;
|
|
21
|
+
constructor(model: string, host?: string, post?: PostJson);
|
|
22
|
+
embed(texts: string[]): Promise<number[][]>;
|
|
23
|
+
}
|
|
24
|
+
/** The embedder configured via LISA_EMBED_MODEL, or null (→ TF-IDF default). */
|
|
25
|
+
export declare function getConfiguredEmbedder(): Embedder | null;
|
|
26
|
+
export type EmbeddingCache = Record<string, number[]>;
|
|
27
|
+
/** Stable content key for a doc text (truncated sha256). Pure. */
|
|
28
|
+
export declare function docHash(text: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Embed `texts`, reusing `cache` for unchanged content and calling the embedder
|
|
31
|
+
* only for misses (one batched call). Returns vectors in input order, an
|
|
32
|
+
* `updated` cache pruned to just the current texts (no unbounded growth), and
|
|
33
|
+
* the miss count. Does not mutate `cache`. Pure modulo the embedder call; the
|
|
34
|
+
* caller falls back to TF-IDF if the embedder throws.
|
|
35
|
+
*/
|
|
36
|
+
export declare function embedWithCache(texts: string[], embedder: Embedder, cache: EmbeddingCache): Promise<{
|
|
37
|
+
vectors: number[][];
|
|
38
|
+
updated: EmbeddingCache;
|
|
39
|
+
misses: number;
|
|
40
|
+
}>;
|
|
41
|
+
/** Load the on-disk cache for an embedder; {} if missing/corrupt. */
|
|
42
|
+
export declare function loadEmbeddingCache(embedderId: string): Promise<EmbeddingCache>;
|
|
43
|
+
/** Persist the cache for an embedder. Best-effort (never throws). */
|
|
44
|
+
export declare function saveEmbeddingCache(embedderId: string, cache: EmbeddingCache): Promise<void>;
|
|
45
|
+
//# sourceMappingURL=embedding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../src/memory/embedding.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,QAAQ;IACvB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;CAC7C;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAYjE;AAED,MAAM,MAAM,QAAQ,GAAG,CACrB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,OAAO,KACV,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAe5D,qDAAqD;AACrD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CASlE;AAED,qBAAa,cAAe,YAAW,QAAQ;IAI3C,OAAO,CAAC,KAAK;IAEb,OAAO,CAAC,IAAI;IALd,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,IAAI,CAAS;gBAEX,KAAK,EAAE,MAAM,EACrB,IAAI,GAAE,MAAqC,EACnC,IAAI,GAAE,QAA0B;IAKpC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;CAYlD;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,IAAI,QAAQ,GAAG,IAAI,CAGvD;AAQD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AAEtD,kEAAkE;AAClE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EAAE,EACf,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;IAAC,OAAO,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAiB3E;AAOD,qEAAqE;AACrE,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAMpF;AAED,qEAAqE;AACrE,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAOjG"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedding abstraction for semantic memory search (PLAN_MODEL_v1.0 M2).
|
|
3
|
+
*
|
|
4
|
+
* TF-IDF (vector.ts) stays the zero-dependency default. When LISA_EMBED_MODEL
|
|
5
|
+
* is set, an Embedder provides dense vectors so search can match paraphrases
|
|
6
|
+
* ("connection failed" ↔ "network error") that share no literal tokens.
|
|
7
|
+
*
|
|
8
|
+
* The HTTP POST is injectable so the logic is unit-testable without a running
|
|
9
|
+
* embedding backend.
|
|
10
|
+
*/
|
|
11
|
+
import crypto from "node:crypto";
|
|
12
|
+
import fs from "node:fs/promises";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import { LISA_HOME } from "../paths.js";
|
|
15
|
+
import { localEndpoint } from "../model/local.js";
|
|
16
|
+
/** Cosine similarity in [-1, 1]; 0 for a zero or empty vector. Pure. */
|
|
17
|
+
export function cosineSimilarity(a, b) {
|
|
18
|
+
const n = Math.min(a.length, b.length);
|
|
19
|
+
let dot = 0;
|
|
20
|
+
let na = 0;
|
|
21
|
+
let nb = 0;
|
|
22
|
+
for (let i = 0; i < n; i++) {
|
|
23
|
+
dot += a[i] * b[i];
|
|
24
|
+
na += a[i] * a[i];
|
|
25
|
+
nb += b[i] * b[i];
|
|
26
|
+
}
|
|
27
|
+
if (na === 0 || nb === 0)
|
|
28
|
+
return 0;
|
|
29
|
+
return dot / (Math.sqrt(na) * Math.sqrt(nb));
|
|
30
|
+
}
|
|
31
|
+
const defaultPostJson = async (url, body) => {
|
|
32
|
+
try {
|
|
33
|
+
const res = await fetch(url, {
|
|
34
|
+
method: "POST",
|
|
35
|
+
headers: { "content-type": "application/json" },
|
|
36
|
+
body: JSON.stringify(body),
|
|
37
|
+
});
|
|
38
|
+
return { ok: res.ok, status: res.status, body: await res.text() };
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return { ok: false, status: 0, body: "" };
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
/** Parse Ollama's /api/embeddings response. Pure. */
|
|
45
|
+
export function parseOllamaEmbedding(body) {
|
|
46
|
+
try {
|
|
47
|
+
const j = JSON.parse(body);
|
|
48
|
+
return Array.isArray(j.embedding) && j.embedding.every((x) => typeof x === "number")
|
|
49
|
+
? j.embedding
|
|
50
|
+
: null;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export class OllamaEmbedder {
|
|
57
|
+
model;
|
|
58
|
+
post;
|
|
59
|
+
id;
|
|
60
|
+
host;
|
|
61
|
+
constructor(model, host = localEndpoint("ollama").host, post = defaultPostJson) {
|
|
62
|
+
this.model = model;
|
|
63
|
+
this.post = post;
|
|
64
|
+
this.host = host.replace(/\/$/, "");
|
|
65
|
+
this.id = `ollama:${model}`;
|
|
66
|
+
}
|
|
67
|
+
async embed(texts) {
|
|
68
|
+
const out = [];
|
|
69
|
+
for (const t of texts) {
|
|
70
|
+
const res = await this.post(`${this.host}/api/embeddings`, { model: this.model, prompt: t });
|
|
71
|
+
const emb = res.ok ? parseOllamaEmbedding(res.body) : null;
|
|
72
|
+
if (!emb) {
|
|
73
|
+
throw new Error(`ollama embedding failed for "${this.model}" (status ${res.status || "unreachable"})`);
|
|
74
|
+
}
|
|
75
|
+
out.push(emb);
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** The embedder configured via LISA_EMBED_MODEL, or null (→ TF-IDF default). */
|
|
81
|
+
export function getConfiguredEmbedder() {
|
|
82
|
+
const model = process.env.LISA_EMBED_MODEL?.trim();
|
|
83
|
+
return model ? new OllamaEmbedder(model) : null;
|
|
84
|
+
}
|
|
85
|
+
/** Stable content key for a doc text (truncated sha256). Pure. */
|
|
86
|
+
export function docHash(text) {
|
|
87
|
+
return crypto.createHash("sha256").update(text).digest("hex").slice(0, 32);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Embed `texts`, reusing `cache` for unchanged content and calling the embedder
|
|
91
|
+
* only for misses (one batched call). Returns vectors in input order, an
|
|
92
|
+
* `updated` cache pruned to just the current texts (no unbounded growth), and
|
|
93
|
+
* the miss count. Does not mutate `cache`. Pure modulo the embedder call; the
|
|
94
|
+
* caller falls back to TF-IDF if the embedder throws.
|
|
95
|
+
*/
|
|
96
|
+
export async function embedWithCache(texts, embedder, cache) {
|
|
97
|
+
const hashes = texts.map(docHash);
|
|
98
|
+
const missIdx = [];
|
|
99
|
+
for (let i = 0; i < texts.length; i++)
|
|
100
|
+
if (!cache[hashes[i]])
|
|
101
|
+
missIdx.push(i);
|
|
102
|
+
const missVecs = missIdx.length ? await embedder.embed(missIdx.map((i) => texts[i])) : [];
|
|
103
|
+
const fresh = {};
|
|
104
|
+
missIdx.forEach((i, k) => {
|
|
105
|
+
fresh[hashes[i]] = missVecs[k] ?? [];
|
|
106
|
+
});
|
|
107
|
+
const vectors = new Array(texts.length);
|
|
108
|
+
const updated = {};
|
|
109
|
+
for (let i = 0; i < texts.length; i++) {
|
|
110
|
+
const v = fresh[hashes[i]] ?? cache[hashes[i]] ?? [];
|
|
111
|
+
vectors[i] = v;
|
|
112
|
+
updated[hashes[i]] = v; // prune: keep only hashes for the current doc set
|
|
113
|
+
}
|
|
114
|
+
return { vectors, updated, misses: missIdx.length };
|
|
115
|
+
}
|
|
116
|
+
const EMBED_CACHE_DIR = path.join(LISA_HOME, "embeddings");
|
|
117
|
+
function embedCacheFile(embedderId) {
|
|
118
|
+
return path.join(EMBED_CACHE_DIR, `${embedderId.replace(/[^a-zA-Z0-9._-]/g, "_")}.json`);
|
|
119
|
+
}
|
|
120
|
+
/** Load the on-disk cache for an embedder; {} if missing/corrupt. */
|
|
121
|
+
export async function loadEmbeddingCache(embedderId) {
|
|
122
|
+
try {
|
|
123
|
+
return JSON.parse(await fs.readFile(embedCacheFile(embedderId), "utf8"));
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return {};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** Persist the cache for an embedder. Best-effort (never throws). */
|
|
130
|
+
export async function saveEmbeddingCache(embedderId, cache) {
|
|
131
|
+
try {
|
|
132
|
+
await fs.mkdir(EMBED_CACHE_DIR, { recursive: true });
|
|
133
|
+
await fs.writeFile(embedCacheFile(embedderId), JSON.stringify(cache));
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// best-effort; a missing cache just means more re-embedding next time
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=embedding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.js","sourceRoot":"","sources":["../../src/memory/embedding.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search_tool.d.ts","sourceRoot":"","sources":["../../src/memory/search_tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"search_tool.d.ts","sourceRoot":"","sources":["../../src/memory/search_tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,gBAAgB,EAAE,cAAc,CAAC,WAAW,EAAE,MAAM,CA6BhE,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { buildIndex, search } from "./vector.js";
|
|
1
|
+
import { buildIndex, search, semanticSearch } from "./vector.js";
|
|
2
|
+
import { getConfiguredEmbedder } from "./embedding.js";
|
|
2
3
|
export const memorySearchTool = {
|
|
3
4
|
name: "memory_search",
|
|
4
5
|
description: "Full-text search over the transcripts of all your past sessions (TF-IDF ranked). " +
|
|
@@ -15,7 +16,10 @@ export const memorySearchTool = {
|
|
|
15
16
|
},
|
|
16
17
|
async execute(input) {
|
|
17
18
|
const index = await buildIndex();
|
|
18
|
-
const
|
|
19
|
+
const embedder = getConfiguredEmbedder();
|
|
20
|
+
const hits = embedder
|
|
21
|
+
? await semanticSearch(index, input.query, embedder, input.limit ?? 5)
|
|
22
|
+
: search(index, input.query, input.limit ?? 5);
|
|
19
23
|
if (hits.length === 0)
|
|
20
24
|
return "(no matches)";
|
|
21
25
|
return hits
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search_tool.js","sourceRoot":"","sources":["../../src/memory/search_tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"search_tool.js","sourceRoot":"","sources":["../../src/memory/search_tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAOvD,MAAM,CAAC,MAAM,gBAAgB,GAAwC;IACnE,IAAI,EAAE,eAAe;IACrB,WAAW,EACT,mFAAmF;QACnF,0FAA0F;QAC1F,iFAAiF;QACjF,yEAAyE;IAC3E,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACzB,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE;SAChE;QACD,QAAQ,EAAE,CAAC,OAAO,CAAC;KACpB;IACD,KAAK,CAAC,OAAO,CAAC,KAAK;QACjB,MAAM,KAAK,GAAG,MAAM,UAAU,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,QAAQ;YACnB,CAAC,CAAC,MAAM,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;YACtE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;QACjD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,cAAc,CAAC;QAC7C,OAAO,IAAI;aACR,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CACJ,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,WAAW,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAClF;aACA,IAAI,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;CACF,CAAC"}
|
package/dist/memory/vector.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
|
-
|
|
3
|
+
import { type Embedder } from "./embedding.js";
|
|
4
|
+
export interface Document {
|
|
4
5
|
sessionId: string;
|
|
5
6
|
startedAt: string;
|
|
6
7
|
text: string;
|
|
@@ -8,9 +9,12 @@ interface Document {
|
|
|
8
9
|
tokenSet: Set<string>;
|
|
9
10
|
termFreq: Map<string, number>;
|
|
10
11
|
}
|
|
11
|
-
interface Index {
|
|
12
|
+
export interface Index {
|
|
12
13
|
docs: Document[];
|
|
13
14
|
idf: Map<string, number>;
|
|
15
|
+
/** Lazily-populated dense doc vectors (M2), keyed by sessionId; cached per embedderId. */
|
|
16
|
+
embeddings?: Map<string, number[]>;
|
|
17
|
+
embedderId?: string;
|
|
14
18
|
}
|
|
15
19
|
/** Drop the cached index (test hook / explicit invalidation). */
|
|
16
20
|
export declare function clearIndexCache(): void;
|
|
@@ -24,6 +28,13 @@ export interface SearchHit {
|
|
|
24
28
|
excerpt: string;
|
|
25
29
|
}
|
|
26
30
|
export declare function search(index: Index, query: string, k?: number): SearchHit[];
|
|
31
|
+
/**
|
|
32
|
+
* Semantic search: rank docs by cosine similarity to the query embedding, so
|
|
33
|
+
* paraphrases TF-IDF misses ("connection failed" ↔ "network error") still
|
|
34
|
+
* match. Doc vectors are computed once and cached on the (fingerprint-cached)
|
|
35
|
+
* index, so steady-state cost is one query embedding per search. Falls back to
|
|
36
|
+
* TF-IDF if the embedding backend is unreachable — memory_search never breaks.
|
|
37
|
+
*/
|
|
38
|
+
export declare function semanticSearch(index: Index, query: string, embedder: Embedder, k?: number): Promise<SearchHit[]>;
|
|
27
39
|
export declare const _unused_for_typecheck: typeof path | typeof fs | undefined;
|
|
28
|
-
export {};
|
|
29
40
|
//# sourceMappingURL=vector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector.d.ts","sourceRoot":"","sources":["../../src/memory/vector.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"vector.d.ts","sourceRoot":"","sources":["../../src/memory/vector.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAIlC,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzB,0FAA0F;IAC1F,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA4CD,iEAAiE;AACjE,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAED,wBAAsB,UAAU,CAAC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAW/E;AAsCD,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,SAAI,GAAG,SAAS,EAAE,CAuBtE;AAmBD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,EAClB,CAAC,SAAI,GACJ,OAAO,CAAC,SAAS,EAAE,CAAC,CAqBtB;AA2BD,eAAO,MAAM,qBAAqB,EAAE,OAAO,IAAI,GAAG,OAAO,EAAE,GAAG,SAAqB,CAAC"}
|
package/dist/memory/vector.js
CHANGED
|
@@ -3,6 +3,7 @@ import fs from "node:fs/promises";
|
|
|
3
3
|
import { listSessionsOnDisk, loadSessionMessages } from "../sessions/list.js";
|
|
4
4
|
import { SESSIONS_DIR } from "../paths.js";
|
|
5
5
|
import { extractTextFromContent } from "../agent.js";
|
|
6
|
+
import { cosineSimilarity, embedWithCache, loadEmbeddingCache, saveEmbeddingCache, } from "./embedding.js";
|
|
6
7
|
const STOPWORDS = new Set([
|
|
7
8
|
"the", "a", "an", "of", "to", "in", "and", "or", "for", "is", "it",
|
|
8
9
|
"this", "that", "be", "are", "was", "were", "with", "on", "as", "at",
|
|
@@ -130,6 +131,55 @@ export function search(index, query, k = 5) {
|
|
|
130
131
|
excerpt: excerptAround(s.doc.text, qTokens, 200),
|
|
131
132
|
}));
|
|
132
133
|
}
|
|
134
|
+
const SEMANTIC_DOC_CHARS = 2000;
|
|
135
|
+
/** Populate (and cache on the index) a dense vector per doc, once per embedder. */
|
|
136
|
+
async function ensureEmbeddings(index, embedder) {
|
|
137
|
+
if (index.embedderId === embedder.id && index.embeddings)
|
|
138
|
+
return;
|
|
139
|
+
const texts = index.docs.map((d) => d.text.slice(0, SEMANTIC_DOC_CHARS));
|
|
140
|
+
// Reuse the persistent cache so a rebuild (triggered by ANY session change)
|
|
141
|
+
// only re-embeds docs whose content actually changed, not all of them.
|
|
142
|
+
const cache = await loadEmbeddingCache(embedder.id);
|
|
143
|
+
const { vectors, updated, misses } = await embedWithCache(texts, embedder, cache);
|
|
144
|
+
if (misses > 0)
|
|
145
|
+
await saveEmbeddingCache(embedder.id, updated);
|
|
146
|
+
const map = new Map();
|
|
147
|
+
index.docs.forEach((d, i) => map.set(d.sessionId, vectors[i] ?? []));
|
|
148
|
+
index.embeddings = map;
|
|
149
|
+
index.embedderId = embedder.id;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Semantic search: rank docs by cosine similarity to the query embedding, so
|
|
153
|
+
* paraphrases TF-IDF misses ("connection failed" ↔ "network error") still
|
|
154
|
+
* match. Doc vectors are computed once and cached on the (fingerprint-cached)
|
|
155
|
+
* index, so steady-state cost is one query embedding per search. Falls back to
|
|
156
|
+
* TF-IDF if the embedding backend is unreachable — memory_search never breaks.
|
|
157
|
+
*/
|
|
158
|
+
export async function semanticSearch(index, query, embedder, k = 5) {
|
|
159
|
+
if (index.docs.length === 0 || !query.trim())
|
|
160
|
+
return [];
|
|
161
|
+
try {
|
|
162
|
+
await ensureEmbeddings(index, embedder);
|
|
163
|
+
const [qv] = await embedder.embed([query]);
|
|
164
|
+
if (!qv)
|
|
165
|
+
return search(index, query, k);
|
|
166
|
+
const qTokens = tokenize(query);
|
|
167
|
+
const scored = index.docs.map((d) => ({
|
|
168
|
+
doc: d,
|
|
169
|
+
score: cosineSimilarity(qv, index.embeddings.get(d.sessionId) ?? []),
|
|
170
|
+
}));
|
|
171
|
+
scored.sort((a, b) => b.score - a.score);
|
|
172
|
+
return scored.slice(0, k).map((s) => ({
|
|
173
|
+
sessionId: s.doc.sessionId,
|
|
174
|
+
startedAt: s.doc.startedAt,
|
|
175
|
+
score: s.score,
|
|
176
|
+
excerpt: excerptAround(s.doc.text, qTokens, 200),
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return search(index, query, k);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
133
183
|
function tokenize(text) {
|
|
134
184
|
return text
|
|
135
185
|
.toLowerCase()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector.js","sourceRoot":"","sources":["../../src/memory/vector.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"vector.js","sourceRoot":"","sources":["../../src/memory/vector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface LocalModelInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
sizeBytes?: number;
|
|
4
|
+
}
|
|
5
|
+
export interface LocalRuntime {
|
|
6
|
+
/** Run a command; stream stdout/stderr lines to onLine. Never rejects. */
|
|
7
|
+
exec(cmd: string, args: string[], onLine?: (line: string) => void): Promise<{
|
|
8
|
+
code: number;
|
|
9
|
+
stdout: string;
|
|
10
|
+
stderr: string;
|
|
11
|
+
}>;
|
|
12
|
+
/** GET a URL. Never rejects — a network error resolves to { ok:false }. */
|
|
13
|
+
httpGet(url: string): Promise<{
|
|
14
|
+
ok: boolean;
|
|
15
|
+
status: number;
|
|
16
|
+
body: string;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
export declare const defaultRuntime: LocalRuntime;
|
|
20
|
+
/** Default OpenAI-compatible endpoints per local backend. Pure. */
|
|
21
|
+
export declare function localEndpoint(backend: string): {
|
|
22
|
+
host: string;
|
|
23
|
+
baseURL: string;
|
|
24
|
+
apiKey: string;
|
|
25
|
+
};
|
|
26
|
+
/** Parse a `local://[backend/]model` reference. Pure. */
|
|
27
|
+
export declare function parseLocalRef(ref: string): {
|
|
28
|
+
backend: string;
|
|
29
|
+
model: string;
|
|
30
|
+
} | null;
|
|
31
|
+
/** Parse Ollama's /api/tags JSON into model infos. Pure. */
|
|
32
|
+
export declare function parseOllamaTags(body: string): LocalModelInfo[];
|
|
33
|
+
/** The Ollama backend: install / list / health via its CLI + HTTP API. */
|
|
34
|
+
export declare class OllamaBackend {
|
|
35
|
+
private runtime;
|
|
36
|
+
readonly name = "ollama";
|
|
37
|
+
readonly host: string;
|
|
38
|
+
constructor(runtime?: LocalRuntime, host?: string);
|
|
39
|
+
health(): Promise<"up" | "down">;
|
|
40
|
+
listInstalled(): Promise<LocalModelInfo[]>;
|
|
41
|
+
install(model: string, onLine?: (line: string) => void): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/model/local.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,0EAA0E;IAC1E,IAAI,CACF,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC9B,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7D,2EAA2E;IAC3E,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9E;AAED,eAAO,MAAM,cAAc,EAAE,YAgC5B,CAAC;AAEF,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAShG;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAWpF;AAED,4DAA4D;AAC5D,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAS9D;AAED,0EAA0E;AAC1E,qBAAa,aAAa;IAItB,OAAO,CAAC,OAAO;IAHjB,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEZ,OAAO,GAAE,YAA6B,EAC9C,IAAI,GAAE,MAAqC;IAKvC,MAAM,IAAI,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC;IAKhC,aAAa,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAK1C,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAS7E"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local-model lifecycle (PLAN_MODEL_v1.0 M1).
|
|
3
|
+
*
|
|
4
|
+
* Before this, "local models" meant: the user installs Ollama themselves, runs
|
|
5
|
+
* `ollama serve`, and hand-edits LISA_BASE_URL in config.env. This module makes
|
|
6
|
+
* it a first-class option — install / list / health / switch — while still
|
|
7
|
+
* routing through the existing OpenAI-compatible provider (Ollama et al. speak
|
|
8
|
+
* the OpenAI API), so no provider code changes.
|
|
9
|
+
*
|
|
10
|
+
* The runtime (process exec + HTTP) is injectable so the logic is unit-testable
|
|
11
|
+
* without a real Ollama install.
|
|
12
|
+
*/
|
|
13
|
+
import { spawn } from "node:child_process";
|
|
14
|
+
export const defaultRuntime = {
|
|
15
|
+
exec(cmd, args, onLine) {
|
|
16
|
+
return new Promise((resolve) => {
|
|
17
|
+
let stdout = "";
|
|
18
|
+
let stderr = "";
|
|
19
|
+
let child;
|
|
20
|
+
try {
|
|
21
|
+
child = spawn(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
resolve({ code: 127, stdout: "", stderr: err.message });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const pump = (chunk, sink) => {
|
|
28
|
+
const s = chunk.toString();
|
|
29
|
+
if (sink === "out")
|
|
30
|
+
stdout += s;
|
|
31
|
+
else
|
|
32
|
+
stderr += s;
|
|
33
|
+
if (onLine)
|
|
34
|
+
for (const line of s.split("\n"))
|
|
35
|
+
if (line.trim())
|
|
36
|
+
onLine(line.trim());
|
|
37
|
+
};
|
|
38
|
+
child.stdout?.on("data", (c) => pump(c, "out"));
|
|
39
|
+
child.stderr?.on("data", (c) => pump(c, "err")); // ollama writes pull progress to stderr
|
|
40
|
+
child.on("error", (err) => resolve({ code: 127, stdout, stderr: stderr + err.message }));
|
|
41
|
+
child.on("close", (code) => resolve({ code: code ?? 0, stdout, stderr }));
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
async httpGet(url) {
|
|
45
|
+
try {
|
|
46
|
+
const res = await fetch(url);
|
|
47
|
+
return { ok: res.ok, status: res.status, body: await res.text() };
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return { ok: false, status: 0, body: "" };
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
/** Default OpenAI-compatible endpoints per local backend. Pure. */
|
|
55
|
+
export function localEndpoint(backend) {
|
|
56
|
+
const hosts = {
|
|
57
|
+
ollama: "http://localhost:11434",
|
|
58
|
+
lmstudio: "http://localhost:1234",
|
|
59
|
+
llamacpp: "http://localhost:8080",
|
|
60
|
+
};
|
|
61
|
+
const envHost = backend === "ollama" ? process.env.OLLAMA_HOST : undefined;
|
|
62
|
+
const host = (envHost || hosts[backend] || hosts.ollama).replace(/\/$/, "");
|
|
63
|
+
return { host, baseURL: `${host}/v1`, apiKey: backend };
|
|
64
|
+
}
|
|
65
|
+
/** Parse a `local://[backend/]model` reference. Pure. */
|
|
66
|
+
export function parseLocalRef(ref) {
|
|
67
|
+
const m = ref.match(/^local:\/\/(.+)$/);
|
|
68
|
+
if (!m)
|
|
69
|
+
return null;
|
|
70
|
+
const rest = m[1].trim();
|
|
71
|
+
if (!rest)
|
|
72
|
+
return null;
|
|
73
|
+
const known = new Set(["ollama", "lmstudio", "llamacpp"]);
|
|
74
|
+
const slash = rest.indexOf("/");
|
|
75
|
+
if (slash > 0 && known.has(rest.slice(0, slash))) {
|
|
76
|
+
return { backend: rest.slice(0, slash), model: rest.slice(slash + 1) };
|
|
77
|
+
}
|
|
78
|
+
return { backend: "ollama", model: rest };
|
|
79
|
+
}
|
|
80
|
+
/** Parse Ollama's /api/tags JSON into model infos. Pure. */
|
|
81
|
+
export function parseOllamaTags(body) {
|
|
82
|
+
try {
|
|
83
|
+
const json = JSON.parse(body);
|
|
84
|
+
return (json.models ?? [])
|
|
85
|
+
.filter((m) => typeof m.name === "string")
|
|
86
|
+
.map((m) => ({ name: m.name, sizeBytes: typeof m.size === "number" ? m.size : undefined }));
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** The Ollama backend: install / list / health via its CLI + HTTP API. */
|
|
93
|
+
export class OllamaBackend {
|
|
94
|
+
runtime;
|
|
95
|
+
name = "ollama";
|
|
96
|
+
host;
|
|
97
|
+
constructor(runtime = defaultRuntime, host = localEndpoint("ollama").host) {
|
|
98
|
+
this.runtime = runtime;
|
|
99
|
+
this.host = host.replace(/\/$/, "");
|
|
100
|
+
}
|
|
101
|
+
async health() {
|
|
102
|
+
const res = await this.runtime.httpGet(`${this.host}/api/tags`);
|
|
103
|
+
return res.ok ? "up" : "down";
|
|
104
|
+
}
|
|
105
|
+
async listInstalled() {
|
|
106
|
+
const res = await this.runtime.httpGet(`${this.host}/api/tags`);
|
|
107
|
+
return res.ok ? parseOllamaTags(res.body) : [];
|
|
108
|
+
}
|
|
109
|
+
async install(model, onLine) {
|
|
110
|
+
const { code, stderr } = await this.runtime.exec("ollama", ["pull", model], onLine);
|
|
111
|
+
if (code === 0)
|
|
112
|
+
return;
|
|
113
|
+
throw new Error(code === 127
|
|
114
|
+
? "ollama CLI not found — install it from https://ollama.com, then retry"
|
|
115
|
+
: `\`ollama pull ${model}\` failed: ${stderr.trim().slice(-200) || `exit ${code}`}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/model/local.ts"],"names":[],"mappings":"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"}
|