oh-my-opencode-kikokikok 2.15.0 → 2.15.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/dist/cli/index.js CHANGED
@@ -2253,7 +2253,7 @@ var require_picocolors = __commonJS((exports, module) => {
2253
2253
  var require_package = __commonJS((exports, module) => {
2254
2254
  module.exports = {
2255
2255
  name: "oh-my-opencode-kikokikok",
2256
- version: "2.15.0",
2256
+ version: "2.15.1",
2257
2257
  description: "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
2258
2258
  main: "dist/index.js",
2259
2259
  types: "dist/index.d.ts",
@@ -22646,6 +22646,21 @@ var Mem0ConfigSchema = exports_external.object({
22646
22646
  autoRehydrate: exports_external.boolean().default(true),
22647
22647
  rehydrateLayers: exports_external.array(MemoryLayerSchema).default(["user", "project", "team"])
22648
22648
  });
22649
+ var LettaConfigSchema = exports_external.object({
22650
+ enabled: exports_external.boolean().default(false),
22651
+ endpoint: exports_external.string().url().optional().describe("Letta server endpoint (default: http://localhost:8283)"),
22652
+ apiKey: exports_external.string().optional().describe("Optional API key for cloud Letta (not needed for self-hosted)"),
22653
+ userId: exports_external.string().optional(),
22654
+ projectId: exports_external.string().optional(),
22655
+ teamId: exports_external.string().optional(),
22656
+ orgId: exports_external.string().optional(),
22657
+ companyId: exports_external.string().optional(),
22658
+ agentPrefix: exports_external.string().optional().describe("Agent name prefix (default: opencode)"),
22659
+ llmModel: exports_external.string().optional().describe("LLM model for agent (e.g., openai/gpt-4.1)"),
22660
+ embeddingModel: exports_external.string().optional().describe("Embedding model for semantic search"),
22661
+ autoRehydrate: exports_external.boolean().default(true),
22662
+ rehydrateLayers: exports_external.array(MemoryLayerSchema).default(["user", "project", "team"])
22663
+ });
22649
22664
  var CentralHubConfigSchema = exports_external.object({
22650
22665
  url: exports_external.string().url(),
22651
22666
  branch: exports_external.string().default("main"),
@@ -22749,7 +22764,7 @@ var OhMyOpenCodeConfigSchema = exports_external.object({
22749
22764
  skills: SkillsConfigSchema.optional(),
22750
22765
  ralph_loop: RalphLoopConfigSchema.optional(),
22751
22766
  mem0: Mem0ConfigSchema.optional(),
22752
- letta: Mem0ConfigSchema.optional(),
22767
+ letta: LettaConfigSchema.optional(),
22753
22768
  knowledge_repo: KnowledgeRepoConfigSchema.optional(),
22754
22769
  knowledge_provider: KnowledgeProviderConfigSchema.optional(),
22755
22770
  openspec: OpenSpecConfigSchema.optional()
@@ -1455,6 +1455,29 @@ export declare const Mem0ConfigSchema: z.ZodObject<{
1455
1455
  company: "company";
1456
1456
  }>>>;
1457
1457
  }, z.core.$strip>;
1458
+ export declare const LettaConfigSchema: z.ZodObject<{
1459
+ enabled: z.ZodDefault<z.ZodBoolean>;
1460
+ endpoint: z.ZodOptional<z.ZodString>;
1461
+ apiKey: z.ZodOptional<z.ZodString>;
1462
+ userId: z.ZodOptional<z.ZodString>;
1463
+ projectId: z.ZodOptional<z.ZodString>;
1464
+ teamId: z.ZodOptional<z.ZodString>;
1465
+ orgId: z.ZodOptional<z.ZodString>;
1466
+ companyId: z.ZodOptional<z.ZodString>;
1467
+ agentPrefix: z.ZodOptional<z.ZodString>;
1468
+ llmModel: z.ZodOptional<z.ZodString>;
1469
+ embeddingModel: z.ZodOptional<z.ZodString>;
1470
+ autoRehydrate: z.ZodDefault<z.ZodBoolean>;
1471
+ rehydrateLayers: z.ZodDefault<z.ZodArray<z.ZodEnum<{
1472
+ user: "user";
1473
+ agent: "agent";
1474
+ session: "session";
1475
+ project: "project";
1476
+ team: "team";
1477
+ org: "org";
1478
+ company: "company";
1479
+ }>>>;
1480
+ }, z.core.$strip>;
1458
1481
  export declare const CentralHubConfigSchema: z.ZodObject<{
1459
1482
  url: z.ZodString;
1460
1483
  branch: z.ZodDefault<z.ZodString>;
@@ -2900,15 +2923,16 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
2900
2923
  }, z.core.$strip>>;
2901
2924
  letta: z.ZodOptional<z.ZodObject<{
2902
2925
  enabled: z.ZodDefault<z.ZodBoolean>;
2903
- apiKey: z.ZodOptional<z.ZodString>;
2904
2926
  endpoint: z.ZodOptional<z.ZodString>;
2927
+ apiKey: z.ZodOptional<z.ZodString>;
2905
2928
  userId: z.ZodOptional<z.ZodString>;
2906
- sessionId: z.ZodOptional<z.ZodString>;
2907
2929
  projectId: z.ZodOptional<z.ZodString>;
2908
2930
  teamId: z.ZodOptional<z.ZodString>;
2909
2931
  orgId: z.ZodOptional<z.ZodString>;
2910
2932
  companyId: z.ZodOptional<z.ZodString>;
2911
- agentId: z.ZodOptional<z.ZodString>;
2933
+ agentPrefix: z.ZodOptional<z.ZodString>;
2934
+ llmModel: z.ZodOptional<z.ZodString>;
2935
+ embeddingModel: z.ZodOptional<z.ZodString>;
2912
2936
  autoRehydrate: z.ZodDefault<z.ZodBoolean>;
2913
2937
  rehydrateLayers: z.ZodDefault<z.ZodArray<z.ZodEnum<{
2914
2938
  user: "user";
@@ -3027,6 +3051,7 @@ export type SkillsConfig = z.infer<typeof SkillsConfigSchema>;
3027
3051
  export type SkillDefinition = z.infer<typeof SkillDefinitionSchema>;
3028
3052
  export type RalphLoopConfig = z.infer<typeof RalphLoopConfigSchema>;
3029
3053
  export type Mem0Config = z.infer<typeof Mem0ConfigSchema>;
3054
+ export type LettaConfig = z.infer<typeof LettaConfigSchema>;
3030
3055
  export type CentralHubConfig = z.infer<typeof CentralHubConfigSchema>;
3031
3056
  export type KnowledgeRepoConfig = z.infer<typeof KnowledgeRepoConfigSchema>;
3032
3057
  export type OpenSpecConfig = z.infer<typeof OpenSpecConfigSchema>;
@@ -0,0 +1,24 @@
1
+ import type { LettaConfig, Memory, MemorySearchResult, AddMemoryInput, SearchMemoryInput, UpdateMemoryInput, MemoryStats, MemoryLayer } from "./types";
2
+ export declare class LettaAdapter {
3
+ private config;
4
+ private endpoint;
5
+ private agentCache;
6
+ constructor(config: LettaConfig);
7
+ add(input: AddMemoryInput): Promise<Memory>;
8
+ search(input: SearchMemoryInput): Promise<MemorySearchResult[]>;
9
+ get(id: string): Promise<Memory | null>;
10
+ update(input: UpdateMemoryInput): Promise<Memory>;
11
+ delete(id: string): Promise<void>;
12
+ getAll(layer?: MemoryLayer): Promise<Memory[]>;
13
+ getStats(): Promise<MemoryStats>;
14
+ isAvailable(): Promise<boolean>;
15
+ private getOrCreateAgent;
16
+ private getAgent;
17
+ private listAgents;
18
+ private request;
19
+ private getAgentName;
20
+ private getUserId;
21
+ private normalizeLayers;
22
+ private getAllLayers;
23
+ private passageToMemory;
24
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from "./types";
2
+ export { LettaAdapter } from "./adapter";
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Letta (formerly MemGPT) Memory Types
3
+ *
4
+ * Letta organizes memory around Agents with:
5
+ * - Core Memory (Blocks): Always in-context, editable by agent
6
+ * - Archival Memory (Passages): Out-of-context, searchable via embeddings
7
+ */
8
+ export type MemoryLayer = "user" | "session" | "project" | "team" | "org" | "company" | "agent";
9
+ export interface LettaConfig {
10
+ enabled: boolean;
11
+ /** Letta server endpoint (default: http://localhost:8283) */
12
+ endpoint?: string;
13
+ /** Optional API key for cloud Letta (not needed for self-hosted) */
14
+ apiKey?: string;
15
+ /** User identifier for scoping agents */
16
+ userId?: string;
17
+ /** Project identifier */
18
+ projectId?: string;
19
+ /** Team identifier */
20
+ teamId?: string;
21
+ /** Organization identifier */
22
+ orgId?: string;
23
+ /** Company identifier */
24
+ companyId?: string;
25
+ /** Default agent name prefix */
26
+ agentPrefix?: string;
27
+ /** LLM model for agent (e.g., "openai/gpt-4.1") */
28
+ llmModel?: string;
29
+ /** Embedding model for semantic search */
30
+ embeddingModel?: string;
31
+ /** Auto-rehydrate memories on session start */
32
+ autoRehydrate?: boolean;
33
+ /** Layers to rehydrate */
34
+ rehydrateLayers?: MemoryLayer[];
35
+ }
36
+ /** Letta Agent representation */
37
+ export interface LettaAgent {
38
+ id: string;
39
+ name: string;
40
+ description?: string;
41
+ created_at: string;
42
+ user_id?: string;
43
+ metadata?: Record<string, unknown>;
44
+ memory_blocks?: LettaBlock[];
45
+ tools?: string[];
46
+ }
47
+ /** Letta Memory Block (Core Memory - always in-context) */
48
+ export interface LettaBlock {
49
+ id: string;
50
+ label: string;
51
+ value: string;
52
+ description?: string;
53
+ limit?: number;
54
+ metadata?: Record<string, unknown>;
55
+ created_at?: string;
56
+ updated_at?: string;
57
+ }
58
+ /** Letta Passage (Archival Memory - searchable) */
59
+ export interface LettaPassage {
60
+ id: string;
61
+ text: string;
62
+ agent_id?: string;
63
+ tags?: string[];
64
+ metadata?: Record<string, unknown>;
65
+ created_at: string;
66
+ embedding?: number[];
67
+ }
68
+ /** Letta Archive container for passages */
69
+ export interface LettaArchive {
70
+ id: string;
71
+ name: string;
72
+ description?: string;
73
+ agent_id?: string;
74
+ created_at: string;
75
+ }
76
+ /** Unified memory representation (compatible with existing tools) */
77
+ export interface Memory {
78
+ id: string;
79
+ content: string;
80
+ layer: MemoryLayer;
81
+ metadata?: Record<string, unknown>;
82
+ createdAt: string;
83
+ updatedAt?: string;
84
+ /** Letta-specific: source type */
85
+ source?: "block" | "passage";
86
+ /** Letta-specific: agent ID */
87
+ agentId?: string;
88
+ }
89
+ export interface MemorySearchResult {
90
+ memory: Memory;
91
+ score: number;
92
+ }
93
+ export interface AddMemoryInput {
94
+ content: string;
95
+ layer: MemoryLayer;
96
+ metadata?: Record<string, unknown>;
97
+ /** Store as block (core memory) or passage (archival). Default: passage */
98
+ type?: "block" | "passage";
99
+ /** Block label if storing as block */
100
+ blockLabel?: string;
101
+ /** Tags for passage search */
102
+ tags?: string[];
103
+ }
104
+ export interface SearchMemoryInput {
105
+ query: string;
106
+ layer?: MemoryLayer | MemoryLayer[];
107
+ limit?: number;
108
+ threshold?: number;
109
+ /** Filter by tags */
110
+ tags?: string[];
111
+ /** Tag match mode */
112
+ tagMatchMode?: "any" | "all";
113
+ }
114
+ export interface UpdateMemoryInput {
115
+ id: string;
116
+ content?: string;
117
+ metadata?: Record<string, unknown>;
118
+ tags?: string[];
119
+ }
120
+ export interface MemoryStats {
121
+ totalMemories: number;
122
+ byLayer: Record<MemoryLayer, number>;
123
+ /** Letta-specific stats */
124
+ totalAgents?: number;
125
+ totalBlocks?: number;
126
+ totalPassages?: number;
127
+ }
128
+ /** Letta API response types */
129
+ export interface LettaApiResponse<T> {
130
+ data?: T;
131
+ error?: string;
132
+ message?: string;
133
+ }
134
+ export interface LettaSearchResponse {
135
+ passages: LettaPassage[];
136
+ total?: number;
137
+ }
138
+ export interface LettaAgentListResponse {
139
+ agents: LettaAgent[];
140
+ }
@@ -1,4 +1,4 @@
1
- import type { Mem0Adapter } from "../../features/mem0-memory/adapter";
1
+ import type { MemoryAdapter } from "../../tools/memory/types";
2
2
  import type { MemoryRehydrationConfig, RehydrationResult } from "./types";
3
3
  import { HOOK_NAME } from "./constants";
4
4
  export interface MemoryRehydrationHook {
@@ -12,6 +12,6 @@ export interface MemoryRehydrationHook {
12
12
  forceRehydrate: (sessionID: string) => Promise<RehydrationResult>;
13
13
  clearSession: (sessionID: string) => void;
14
14
  }
15
- export declare function createMemoryRehydrationHook(adapter: Mem0Adapter, config?: MemoryRehydrationConfig): MemoryRehydrationHook;
15
+ export declare function createMemoryRehydrationHook(adapter: MemoryAdapter, config?: MemoryRehydrationConfig): MemoryRehydrationHook;
16
16
  export { HOOK_NAME };
17
17
  export type { MemoryRehydrationConfig } from "./types";
package/dist/index.js CHANGED
@@ -43777,6 +43777,290 @@ class Mem0Adapter {
43777
43777
  });
43778
43778
  }
43779
43779
  }
43780
+
43781
+ // src/features/letta-memory/adapter.ts
43782
+ var DEFAULT_ENDPOINT2 = "http://localhost:8283";
43783
+ var DEFAULT_AGENT_PREFIX = "opencode";
43784
+ var DEFAULT_LLM_MODEL = "openai/gpt-4.1";
43785
+ var DEFAULT_EMBEDDING_MODEL = "openai/text-embedding-3-small";
43786
+
43787
+ class LettaAdapter {
43788
+ config;
43789
+ endpoint;
43790
+ agentCache = new Map;
43791
+ constructor(config3) {
43792
+ this.config = config3;
43793
+ this.endpoint = config3.endpoint ?? DEFAULT_ENDPOINT2;
43794
+ }
43795
+ async add(input) {
43796
+ if (!this.config.enabled) {
43797
+ throw new Error("Letta is not enabled");
43798
+ }
43799
+ const agent = await this.getOrCreateAgent(input.layer);
43800
+ const tags = [
43801
+ `layer:${input.layer}`,
43802
+ ...input.tags ?? [],
43803
+ ...input.metadata ? Object.entries(input.metadata).map(([k, v]) => `${k}:${v}`) : []
43804
+ ];
43805
+ const response2 = await this.request(`/v1/agents/${agent.id}/archival-memory`, {
43806
+ method: "POST",
43807
+ body: JSON.stringify({
43808
+ text: input.content,
43809
+ tags
43810
+ })
43811
+ });
43812
+ const passage = await response2.json();
43813
+ return this.passageToMemory(passage, input.layer, agent.id);
43814
+ }
43815
+ async search(input) {
43816
+ if (!this.config.enabled) {
43817
+ throw new Error("Letta is not enabled");
43818
+ }
43819
+ const layers = this.normalizeLayers(input.layer);
43820
+ const results = [];
43821
+ for (const layer of layers) {
43822
+ try {
43823
+ const agent = await this.getAgent(layer);
43824
+ if (!agent)
43825
+ continue;
43826
+ const params = new URLSearchParams;
43827
+ params.set("query", input.query);
43828
+ if (input.limit)
43829
+ params.set("limit", String(input.limit));
43830
+ if (input.tags?.length) {
43831
+ params.set("tags", input.tags.join(","));
43832
+ params.set("tag_match_mode", input.tagMatchMode ?? "any");
43833
+ }
43834
+ const response2 = await this.request(`/v1/agents/${agent.id}/archival-memory/search?${params.toString()}`, { method: "GET" });
43835
+ const data = await response2.json();
43836
+ const layerResults = data.map((passage, index) => ({
43837
+ memory: this.passageToMemory(passage, layer, agent.id),
43838
+ score: 1 - index * 0.05
43839
+ }));
43840
+ results.push(...layerResults);
43841
+ } catch {
43842
+ continue;
43843
+ }
43844
+ }
43845
+ return results.filter((r) => !input.threshold || r.score >= input.threshold).sort((a, b) => b.score - a.score).slice(0, input.limit ?? 10);
43846
+ }
43847
+ async get(id) {
43848
+ if (!this.config.enabled) {
43849
+ throw new Error("Letta is not enabled");
43850
+ }
43851
+ for (const layer of this.getAllLayers()) {
43852
+ try {
43853
+ const agent = await this.getAgent(layer);
43854
+ if (!agent)
43855
+ continue;
43856
+ const response2 = await this.request(`/v1/agents/${agent.id}/archival-memory`, { method: "GET" });
43857
+ const passages = await response2.json();
43858
+ const passage = passages.find((p) => p.id === id);
43859
+ if (passage) {
43860
+ return this.passageToMemory(passage, layer, agent.id);
43861
+ }
43862
+ } catch {
43863
+ continue;
43864
+ }
43865
+ }
43866
+ return null;
43867
+ }
43868
+ async update(input) {
43869
+ if (!this.config.enabled) {
43870
+ throw new Error("Letta is not enabled");
43871
+ }
43872
+ const existing = await this.get(input.id);
43873
+ if (!existing) {
43874
+ throw new Error(`Memory not found: ${input.id}`);
43875
+ }
43876
+ await this.delete(input.id);
43877
+ return this.add({
43878
+ content: input.content ?? existing.content,
43879
+ layer: existing.layer,
43880
+ metadata: input.metadata ? { ...existing.metadata, ...input.metadata } : existing.metadata,
43881
+ tags: input.tags
43882
+ });
43883
+ }
43884
+ async delete(id) {
43885
+ if (!this.config.enabled) {
43886
+ throw new Error("Letta is not enabled");
43887
+ }
43888
+ for (const layer of this.getAllLayers()) {
43889
+ try {
43890
+ const agent = await this.getAgent(layer);
43891
+ if (!agent)
43892
+ continue;
43893
+ await this.request(`/v1/agents/${agent.id}/archival-memory/${id}`, {
43894
+ method: "DELETE"
43895
+ });
43896
+ return;
43897
+ } catch {
43898
+ continue;
43899
+ }
43900
+ }
43901
+ throw new Error(`Memory not found: ${id}`);
43902
+ }
43903
+ async getAll(layer) {
43904
+ if (!this.config.enabled) {
43905
+ throw new Error("Letta is not enabled");
43906
+ }
43907
+ const layers = layer ? [layer] : this.getAllLayers();
43908
+ const memories = [];
43909
+ for (const l of layers) {
43910
+ try {
43911
+ const agent = await this.getAgent(l);
43912
+ if (!agent)
43913
+ continue;
43914
+ const response2 = await this.request(`/v1/agents/${agent.id}/archival-memory`, { method: "GET" });
43915
+ const passages = await response2.json();
43916
+ memories.push(...passages.map((p) => this.passageToMemory(p, l, agent.id)));
43917
+ } catch {
43918
+ continue;
43919
+ }
43920
+ }
43921
+ return memories;
43922
+ }
43923
+ async getStats() {
43924
+ const memories = await this.getAll();
43925
+ const byLayer = {
43926
+ user: 0,
43927
+ session: 0,
43928
+ project: 0,
43929
+ team: 0,
43930
+ org: 0,
43931
+ company: 0,
43932
+ agent: 0
43933
+ };
43934
+ for (const memory of memories) {
43935
+ byLayer[memory.layer]++;
43936
+ }
43937
+ const agents = await this.listAgents();
43938
+ return {
43939
+ totalMemories: memories.length,
43940
+ byLayer,
43941
+ totalAgents: agents.length,
43942
+ totalPassages: memories.length
43943
+ };
43944
+ }
43945
+ async isAvailable() {
43946
+ try {
43947
+ const response2 = await fetch(`${this.endpoint}/v1/health`, {
43948
+ method: "GET",
43949
+ signal: AbortSignal.timeout(5000)
43950
+ });
43951
+ return response2.ok;
43952
+ } catch {
43953
+ return false;
43954
+ }
43955
+ }
43956
+ async getOrCreateAgent(layer) {
43957
+ const existing = await this.getAgent(layer);
43958
+ if (existing)
43959
+ return existing;
43960
+ const agentName = this.getAgentName(layer);
43961
+ const response2 = await this.request("/v1/agents", {
43962
+ method: "POST",
43963
+ body: JSON.stringify({
43964
+ name: agentName,
43965
+ model: this.config.llmModel ?? DEFAULT_LLM_MODEL,
43966
+ embedding: this.config.embeddingModel ?? DEFAULT_EMBEDDING_MODEL,
43967
+ memory_blocks: [
43968
+ { label: "persona", value: `OpenCode memory agent for ${layer} layer` },
43969
+ { label: "human", value: this.getUserId(layer) }
43970
+ ],
43971
+ metadata: {
43972
+ layer,
43973
+ user_id: this.getUserId(layer),
43974
+ created_by: "oh-my-opencode"
43975
+ }
43976
+ })
43977
+ });
43978
+ const agent = await response2.json();
43979
+ this.agentCache.set(layer, agent);
43980
+ return agent;
43981
+ }
43982
+ async getAgent(layer) {
43983
+ if (this.agentCache.has(layer)) {
43984
+ return this.agentCache.get(layer);
43985
+ }
43986
+ const agentName = this.getAgentName(layer);
43987
+ const agents = await this.listAgents();
43988
+ const agent = agents.find((a) => a.name === agentName);
43989
+ if (agent) {
43990
+ this.agentCache.set(layer, agent);
43991
+ }
43992
+ return agent ?? null;
43993
+ }
43994
+ async listAgents() {
43995
+ try {
43996
+ const response2 = await this.request("/v1/agents", { method: "GET" });
43997
+ const data = await response2.json();
43998
+ return Array.isArray(data) ? data : [];
43999
+ } catch {
44000
+ return [];
44001
+ }
44002
+ }
44003
+ async request(path7, options) {
44004
+ const headers = {
44005
+ "Content-Type": "application/json"
44006
+ };
44007
+ if (this.config.apiKey) {
44008
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
44009
+ }
44010
+ const response2 = await fetch(`${this.endpoint}${path7}`, {
44011
+ method: options.method,
44012
+ headers,
44013
+ body: options.body
44014
+ });
44015
+ if (!response2.ok) {
44016
+ const text = await response2.text().catch(() => "");
44017
+ throw new Error(`Letta API error: ${response2.status} ${response2.statusText} - ${text}`);
44018
+ }
44019
+ return response2;
44020
+ }
44021
+ getAgentName(layer) {
44022
+ const prefix = this.config.agentPrefix ?? DEFAULT_AGENT_PREFIX;
44023
+ const userId = this.getUserId(layer);
44024
+ return `${prefix}-${layer}-${userId}`;
44025
+ }
44026
+ getUserId(layer) {
44027
+ switch (layer) {
44028
+ case "user":
44029
+ return this.config.userId ?? "default-user";
44030
+ case "session":
44031
+ return `session-${this.config.userId ?? "default"}`;
44032
+ case "project":
44033
+ return this.config.projectId ?? "default-project";
44034
+ case "team":
44035
+ return this.config.teamId ?? "default-team";
44036
+ case "org":
44037
+ return this.config.orgId ?? "default-org";
44038
+ case "company":
44039
+ return this.config.companyId ?? "default-company";
44040
+ case "agent":
44041
+ return "default-agent";
44042
+ }
44043
+ }
44044
+ normalizeLayers(layer) {
44045
+ if (!layer)
44046
+ return this.getAllLayers();
44047
+ return Array.isArray(layer) ? layer : [layer];
44048
+ }
44049
+ getAllLayers() {
44050
+ return ["user", "session", "project", "team", "org", "company", "agent"];
44051
+ }
44052
+ passageToMemory(passage, layer, agentId) {
44053
+ return {
44054
+ id: passage.id,
44055
+ content: passage.text,
44056
+ layer,
44057
+ metadata: passage.metadata,
44058
+ createdAt: passage.created_at,
44059
+ source: "passage",
44060
+ agentId
44061
+ };
44062
+ }
44063
+ }
43780
44064
  // src/features/knowledge-provider/registry.ts
43781
44065
  var DEFAULT_CONFIG2 = {
43782
44066
  defaultLimit: 10,
@@ -49637,6 +49921,21 @@ var Mem0ConfigSchema = exports_external.object({
49637
49921
  autoRehydrate: exports_external.boolean().default(true),
49638
49922
  rehydrateLayers: exports_external.array(MemoryLayerSchema).default(["user", "project", "team"])
49639
49923
  });
49924
+ var LettaConfigSchema = exports_external.object({
49925
+ enabled: exports_external.boolean().default(false),
49926
+ endpoint: exports_external.string().url().optional().describe("Letta server endpoint (default: http://localhost:8283)"),
49927
+ apiKey: exports_external.string().optional().describe("Optional API key for cloud Letta (not needed for self-hosted)"),
49928
+ userId: exports_external.string().optional(),
49929
+ projectId: exports_external.string().optional(),
49930
+ teamId: exports_external.string().optional(),
49931
+ orgId: exports_external.string().optional(),
49932
+ companyId: exports_external.string().optional(),
49933
+ agentPrefix: exports_external.string().optional().describe("Agent name prefix (default: opencode)"),
49934
+ llmModel: exports_external.string().optional().describe("LLM model for agent (e.g., openai/gpt-4.1)"),
49935
+ embeddingModel: exports_external.string().optional().describe("Embedding model for semantic search"),
49936
+ autoRehydrate: exports_external.boolean().default(true),
49937
+ rehydrateLayers: exports_external.array(MemoryLayerSchema).default(["user", "project", "team"])
49938
+ });
49640
49939
  var CentralHubConfigSchema = exports_external.object({
49641
49940
  url: exports_external.string().url(),
49642
49941
  branch: exports_external.string().default("main"),
@@ -49740,22 +50039,12 @@ var OhMyOpenCodeConfigSchema = exports_external.object({
49740
50039
  skills: SkillsConfigSchema.optional(),
49741
50040
  ralph_loop: RalphLoopConfigSchema.optional(),
49742
50041
  mem0: Mem0ConfigSchema.optional(),
49743
- letta: Mem0ConfigSchema.optional(),
50042
+ letta: LettaConfigSchema.optional(),
49744
50043
  knowledge_repo: KnowledgeRepoConfigSchema.optional(),
49745
50044
  knowledge_provider: KnowledgeProviderConfigSchema.optional(),
49746
50045
  openspec: OpenSpecConfigSchema.optional()
49747
50046
  });
49748
50047
  // src/plugin-config.ts
49749
- function normalizeLettaToMem0(config3) {
49750
- if (!config3.letta) {
49751
- return config3;
49752
- }
49753
- const { letta, ...rest } = config3;
49754
- if (config3.mem0) {
49755
- return { ...rest, mem0: deepMerge(letta, config3.mem0) };
49756
- }
49757
- return { ...rest, mem0: letta };
49758
- }
49759
50048
  function loadConfigFromPath2(configPath, ctx) {
49760
50049
  try {
49761
50050
  if (fs9.existsSync(configPath)) {
@@ -49772,9 +50061,8 @@ function loadConfigFromPath2(configPath, ctx) {
49772
50061
  });
49773
50062
  return null;
49774
50063
  }
49775
- const normalized = normalizeLettaToMem0(result.data);
49776
- log(`Config loaded from ${configPath}`, { agents: normalized.agents });
49777
- return normalized;
50064
+ log(`Config loaded from ${configPath}`, { agents: result.data.agents });
50065
+ return result.data;
49778
50066
  }
49779
50067
  } catch (err) {
49780
50068
  const errorMsg = err instanceof Error ? err.message : String(err);
@@ -49789,6 +50077,7 @@ function mergeConfigs(base, override) {
49789
50077
  ...override,
49790
50078
  agents: deepMerge(base.agents, override.agents),
49791
50079
  mem0: deepMerge(base.mem0, override.mem0),
50080
+ letta: deepMerge(base.letta, override.letta),
49792
50081
  disabled_agents: [
49793
50082
  ...new Set([
49794
50083
  ...base.disabled_agents ?? [],
@@ -55444,16 +55733,30 @@ var OhMyOpenCodePlugin = async (ctx) => {
55444
55733
  companyId: pluginConfig.mem0.companyId,
55445
55734
  agentId: pluginConfig.mem0.agentId
55446
55735
  }) : null;
55447
- const memoryTools = mem0Adapter ? createMemoryTools(mem0Adapter) : {};
55736
+ const lettaAdapter = pluginConfig.letta?.enabled ? new LettaAdapter({
55737
+ enabled: true,
55738
+ endpoint: pluginConfig.letta.endpoint,
55739
+ apiKey: pluginConfig.letta.apiKey,
55740
+ userId: pluginConfig.letta.userId,
55741
+ projectId: pluginConfig.letta.projectId,
55742
+ teamId: pluginConfig.letta.teamId,
55743
+ orgId: pluginConfig.letta.orgId,
55744
+ companyId: pluginConfig.letta.companyId,
55745
+ agentPrefix: pluginConfig.letta.agentPrefix,
55746
+ llmModel: pluginConfig.letta.llmModel,
55747
+ embeddingModel: pluginConfig.letta.embeddingModel
55748
+ }) : null;
55749
+ const memoryAdapter = lettaAdapter ?? mem0Adapter;
55750
+ const memoryTools = memoryAdapter ? createMemoryTools(memoryAdapter) : {};
55448
55751
  const knowledgeProviderRegistry = pluginConfig.knowledge_provider?.enabled ? await initializeKnowledgeProviderRegistry(pluginConfig, mem0Adapter) : null;
55449
55752
  const knowledgeMonitor = isHookEnabled("knowledge-monitor") && pluginConfig.knowledge_repo?.enabled ? createKnowledgeMonitorHook(ctx.directory, {
55450
55753
  enabled: true,
55451
55754
  checkPreTool: true,
55452
55755
  checkPostTool: false
55453
55756
  }) : null;
55454
- const memoryRehydration = isHookEnabled("memory-rehydration") && mem0Adapter && pluginConfig.mem0?.autoRehydrate !== false ? createMemoryRehydrationHook(mem0Adapter, {
55757
+ const memoryRehydration = isHookEnabled("memory-rehydration") && memoryAdapter && (pluginConfig.letta?.autoRehydrate !== false || pluginConfig.mem0?.autoRehydrate !== false) ? createMemoryRehydrationHook(memoryAdapter, {
55455
55758
  enabled: true,
55456
- layers: pluginConfig.mem0?.rehydrateLayers
55759
+ layers: pluginConfig.letta?.rehydrateLayers ?? pluginConfig.mem0?.rehydrateLayers
55457
55760
  }) : null;
55458
55761
  const contextWindowMonitor = isHookEnabled("context-window-monitor") ? createContextWindowMonitorHook(ctx) : null;
55459
55762
  const sessionRecovery = isHookEnabled("session-recovery") ? createSessionRecoveryHook(ctx, { experimental: pluginConfig.experimental }) : null;
@@ -1,2 +1,2 @@
1
1
  export { createMemoryTools } from "./tools";
2
- export type { MemoryToolsConfig, MemoryLayer } from "./types";
2
+ export type { MemoryAdapter, MemoryLayer, Memory, MemorySearchResult, MemoryStats } from "./types";
@@ -1,3 +1,3 @@
1
1
  import { type ToolDefinition } from "@opencode-ai/plugin/tool";
2
- import type { Mem0Adapter } from "../../features/mem0-memory/adapter";
3
- export declare function createMemoryTools(adapter: Mem0Adapter): Record<string, ToolDefinition>;
2
+ import type { MemoryAdapter } from "./types";
3
+ export declare function createMemoryTools(adapter: MemoryAdapter): Record<string, ToolDefinition>;
@@ -1,6 +1,44 @@
1
- import type { Mem0Adapter } from "../../features/mem0-memory/adapter";
2
1
  import type { MemoryLayer } from "../../features/mem0-memory/types";
3
- export interface MemoryToolsConfig {
4
- adapter: Mem0Adapter;
2
+ export interface Memory {
3
+ id: string;
4
+ content: string;
5
+ layer: MemoryLayer;
6
+ metadata?: Record<string, unknown>;
7
+ createdAt: string;
8
+ updatedAt?: string;
9
+ }
10
+ export interface MemorySearchResult {
11
+ memory: Memory;
12
+ score: number;
13
+ }
14
+ export interface AddMemoryInput {
15
+ content: string;
16
+ layer: MemoryLayer;
17
+ metadata?: Record<string, unknown>;
18
+ }
19
+ export interface SearchMemoryInput {
20
+ query: string;
21
+ layer?: MemoryLayer | MemoryLayer[];
22
+ limit?: number;
23
+ threshold?: number;
24
+ }
25
+ export interface UpdateMemoryInput {
26
+ id: string;
27
+ content?: string;
28
+ metadata?: Record<string, unknown>;
29
+ }
30
+ export interface MemoryStats {
31
+ totalMemories: number;
32
+ byLayer: Record<MemoryLayer, number>;
33
+ }
34
+ export interface MemoryAdapter {
35
+ add(input: AddMemoryInput): Promise<Memory>;
36
+ search(input: SearchMemoryInput): Promise<MemorySearchResult[]>;
37
+ get(id: string): Promise<Memory | null>;
38
+ update(input: UpdateMemoryInput): Promise<Memory>;
39
+ delete(id: string): Promise<void>;
40
+ getAll(layer?: MemoryLayer): Promise<Memory[]>;
41
+ getStats(): Promise<MemoryStats>;
42
+ isAvailable?(): Promise<boolean>;
5
43
  }
6
44
  export type { MemoryLayer };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode-kikokikok",
3
- "version": "2.15.0",
3
+ "version": "2.15.1",
4
4
  "description": "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",