oh-my-opencode-kikokikok 2.15.8 → 2.15.10
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 +1 -1
- package/dist/features/letta-memory/adapter.d.ts +27 -4
- package/dist/index.js +157 -32
- package/package.json +1 -1
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.
|
|
2256
|
+
version: "2.15.10",
|
|
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",
|
|
@@ -3,11 +3,34 @@ export declare class LettaAdapter {
|
|
|
3
3
|
private config;
|
|
4
4
|
private endpoint;
|
|
5
5
|
private agentCache;
|
|
6
|
-
private
|
|
7
|
-
private
|
|
6
|
+
private modelCache;
|
|
7
|
+
private modelCachePromise;
|
|
8
|
+
private resolvedEmbeddingModel;
|
|
9
|
+
private resolvedLlmModel;
|
|
10
|
+
private providerInitPromise;
|
|
8
11
|
constructor(config: LettaConfig);
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Ensures the openai-proxy provider is registered in Letta when:
|
|
14
|
+
* 1. Models with openai-proxy/ prefix exist (from OPENAI_API_BASE env var)
|
|
15
|
+
* 2. No user-created openai-proxy provider exists
|
|
16
|
+
* 3. Copilot proxy is available locally
|
|
17
|
+
*
|
|
18
|
+
* This fixes the provider mismatch where Letta's built-in OpenAI provider
|
|
19
|
+
* creates models with openai-proxy/ handles but the provider is named "openai",
|
|
20
|
+
* causing agent creation to fail.
|
|
21
|
+
*/
|
|
22
|
+
ensureOpenAIProxyProvider(): Promise<void>;
|
|
23
|
+
private doEnsureOpenAIProxyProvider;
|
|
24
|
+
private isCopilotProxyAvailable;
|
|
25
|
+
private getModels;
|
|
26
|
+
/**
|
|
27
|
+
* Resolves user model name to Letta handle. Letta requires exact handle matches
|
|
28
|
+
* AND valid provider prefix (letta/, openai/). Models with other prefixes like
|
|
29
|
+
* openai-proxy/ will fail agent creation even if registered in the model list.
|
|
30
|
+
*/
|
|
31
|
+
private resolveModelHandle;
|
|
32
|
+
private getEmbeddingModel;
|
|
33
|
+
private getLlmModel;
|
|
11
34
|
add(input: AddMemoryInput): Promise<Memory>;
|
|
12
35
|
search(input: SearchMemoryInput): Promise<MemorySearchResult[]>;
|
|
13
36
|
get(id: string): Promise<Memory | null>;
|
package/dist/index.js
CHANGED
|
@@ -43783,29 +43783,87 @@ var DEFAULT_ENDPOINT2 = "http://localhost:8283";
|
|
|
43783
43783
|
var DEFAULT_AGENT_PREFIX = "opencode";
|
|
43784
43784
|
var DEFAULT_LLM_MODEL = "letta/letta-free";
|
|
43785
43785
|
var DEFAULT_EMBEDDING_MODEL = "letta/letta-free";
|
|
43786
|
+
var VALID_PROVIDERS = ["letta", "openai", "openai-proxy"];
|
|
43787
|
+
var COPILOT_PROXY_ENDPOINT = "http://host.docker.internal:4141/v1";
|
|
43788
|
+
var COPILOT_PROXY_LOCAL = "http://localhost:4141/v1";
|
|
43786
43789
|
|
|
43787
43790
|
class LettaAdapter {
|
|
43788
43791
|
config;
|
|
43789
43792
|
endpoint;
|
|
43790
43793
|
agentCache = new Map;
|
|
43791
|
-
|
|
43792
|
-
|
|
43794
|
+
modelCache = null;
|
|
43795
|
+
modelCachePromise = null;
|
|
43796
|
+
resolvedEmbeddingModel = null;
|
|
43797
|
+
resolvedLlmModel = null;
|
|
43798
|
+
providerInitPromise = null;
|
|
43793
43799
|
constructor(config3) {
|
|
43794
43800
|
this.config = config3;
|
|
43795
43801
|
this.endpoint = config3.endpoint ?? DEFAULT_ENDPOINT2;
|
|
43796
43802
|
}
|
|
43797
|
-
async
|
|
43798
|
-
if (this.
|
|
43799
|
-
return this.
|
|
43803
|
+
async ensureOpenAIProxyProvider() {
|
|
43804
|
+
if (this.providerInitPromise) {
|
|
43805
|
+
return this.providerInitPromise;
|
|
43800
43806
|
}
|
|
43801
|
-
|
|
43802
|
-
|
|
43807
|
+
this.providerInitPromise = this.doEnsureOpenAIProxyProvider();
|
|
43808
|
+
return this.providerInitPromise;
|
|
43809
|
+
}
|
|
43810
|
+
async doEnsureOpenAIProxyProvider() {
|
|
43811
|
+
try {
|
|
43812
|
+
const models = await this.getModels();
|
|
43813
|
+
const hasOpenAIProxyModels = models.some((m) => m.handle.startsWith("openai-proxy/"));
|
|
43814
|
+
if (!hasOpenAIProxyModels) {
|
|
43815
|
+
return;
|
|
43816
|
+
}
|
|
43817
|
+
const providersResponse = await fetch(`${this.endpoint}/v1/providers/`, {
|
|
43818
|
+
method: "GET",
|
|
43819
|
+
redirect: "follow",
|
|
43820
|
+
signal: AbortSignal.timeout(1e4)
|
|
43821
|
+
});
|
|
43822
|
+
if (!providersResponse.ok) {
|
|
43823
|
+
return;
|
|
43824
|
+
}
|
|
43825
|
+
const providers = await providersResponse.json();
|
|
43826
|
+
const hasOpenAIProxyProvider = providers.some((p) => p.name === "openai-proxy");
|
|
43827
|
+
if (hasOpenAIProxyProvider) {
|
|
43828
|
+
return;
|
|
43829
|
+
}
|
|
43830
|
+
const proxyAvailable = await this.isCopilotProxyAvailable();
|
|
43831
|
+
if (!proxyAvailable) {
|
|
43832
|
+
return;
|
|
43833
|
+
}
|
|
43834
|
+
await fetch(`${this.endpoint}/v1/providers/`, {
|
|
43835
|
+
method: "POST",
|
|
43836
|
+
headers: { "Content-Type": "application/json" },
|
|
43837
|
+
redirect: "follow",
|
|
43838
|
+
signal: AbortSignal.timeout(1e4),
|
|
43839
|
+
body: JSON.stringify({
|
|
43840
|
+
name: "openai-proxy",
|
|
43841
|
+
provider_type: "openai",
|
|
43842
|
+
api_key: "dummy",
|
|
43843
|
+
base_url: COPILOT_PROXY_ENDPOINT
|
|
43844
|
+
})
|
|
43845
|
+
});
|
|
43846
|
+
} catch {}
|
|
43847
|
+
}
|
|
43848
|
+
async isCopilotProxyAvailable() {
|
|
43849
|
+
try {
|
|
43850
|
+
const response2 = await fetch(`${COPILOT_PROXY_LOCAL}/models`, {
|
|
43851
|
+
method: "GET",
|
|
43852
|
+
signal: AbortSignal.timeout(5000)
|
|
43853
|
+
});
|
|
43854
|
+
return response2.ok;
|
|
43855
|
+
} catch {
|
|
43856
|
+
return false;
|
|
43803
43857
|
}
|
|
43804
|
-
|
|
43805
|
-
|
|
43806
|
-
|
|
43858
|
+
}
|
|
43859
|
+
async getModels() {
|
|
43860
|
+
if (this.modelCache) {
|
|
43861
|
+
return this.modelCache;
|
|
43862
|
+
}
|
|
43863
|
+
if (this.modelCachePromise) {
|
|
43864
|
+
return this.modelCachePromise;
|
|
43807
43865
|
}
|
|
43808
|
-
this.
|
|
43866
|
+
this.modelCachePromise = (async () => {
|
|
43809
43867
|
try {
|
|
43810
43868
|
const response2 = await fetch(`${this.endpoint}/v1/models`, {
|
|
43811
43869
|
method: "GET",
|
|
@@ -43813,26 +43871,89 @@ class LettaAdapter {
|
|
|
43813
43871
|
signal: AbortSignal.timeout(1e4)
|
|
43814
43872
|
});
|
|
43815
43873
|
if (!response2.ok) {
|
|
43816
|
-
return;
|
|
43874
|
+
return [];
|
|
43817
43875
|
}
|
|
43818
43876
|
const models = await response2.json();
|
|
43819
|
-
|
|
43820
|
-
|
|
43821
|
-
|
|
43822
|
-
|
|
43823
|
-
|
|
43824
|
-
this.detectedEmbeddingModel = model.handle;
|
|
43825
|
-
}
|
|
43826
|
-
} catch {}
|
|
43877
|
+
this.modelCache = models;
|
|
43878
|
+
return models;
|
|
43879
|
+
} catch {
|
|
43880
|
+
return [];
|
|
43881
|
+
}
|
|
43827
43882
|
})();
|
|
43828
|
-
|
|
43829
|
-
|
|
43883
|
+
return this.modelCachePromise;
|
|
43884
|
+
}
|
|
43885
|
+
async resolveModelHandle(requestedModel, isEmbedding = false) {
|
|
43886
|
+
const models = await this.getModels();
|
|
43887
|
+
if (models.length === 0) {
|
|
43888
|
+
return requestedModel;
|
|
43889
|
+
}
|
|
43890
|
+
const hasValidProvider = (handle) => {
|
|
43891
|
+
const provider = handle.split("/")[0];
|
|
43892
|
+
return VALID_PROVIDERS.includes(provider);
|
|
43893
|
+
};
|
|
43894
|
+
const exactMatch = models.find((m) => m.handle === requestedModel && hasValidProvider(m.handle));
|
|
43895
|
+
if (exactMatch) {
|
|
43896
|
+
return exactMatch.handle;
|
|
43897
|
+
}
|
|
43898
|
+
const requestedName = requestedModel.includes("/") ? requestedModel.split("/").pop() : requestedModel;
|
|
43899
|
+
const candidates = models.filter((m) => {
|
|
43900
|
+
if (!hasValidProvider(m.handle)) {
|
|
43901
|
+
return false;
|
|
43902
|
+
}
|
|
43903
|
+
if (isEmbedding && !m.name.includes("embedding")) {
|
|
43904
|
+
return false;
|
|
43905
|
+
}
|
|
43906
|
+
return m.name.includes(requestedName) || m.handle.includes(requestedName);
|
|
43907
|
+
});
|
|
43908
|
+
if (candidates.length > 0) {
|
|
43909
|
+
const proxyModel = candidates.find((m) => m.model_endpoint?.includes("host.docker.internal"));
|
|
43910
|
+
return proxyModel?.handle ?? candidates[0].handle;
|
|
43911
|
+
}
|
|
43912
|
+
if (isEmbedding) {
|
|
43913
|
+
const validEmbeddingModels = models.filter((m) => m.name.includes("embedding") && hasValidProvider(m.handle));
|
|
43914
|
+
if (validEmbeddingModels.length > 0) {
|
|
43915
|
+
const preferredName = this.config.preferredEmbeddingModel ?? "text-embedding-3-small";
|
|
43916
|
+
const preferred = validEmbeddingModels.find((m) => m.name.includes(preferredName));
|
|
43917
|
+
return preferred?.handle ?? validEmbeddingModels[0].handle;
|
|
43918
|
+
}
|
|
43919
|
+
}
|
|
43920
|
+
return isEmbedding ? DEFAULT_EMBEDDING_MODEL : DEFAULT_LLM_MODEL;
|
|
43830
43921
|
}
|
|
43831
|
-
|
|
43832
|
-
if (
|
|
43833
|
-
return
|
|
43922
|
+
async getEmbeddingModel() {
|
|
43923
|
+
if (this.resolvedEmbeddingModel) {
|
|
43924
|
+
return this.resolvedEmbeddingModel;
|
|
43925
|
+
}
|
|
43926
|
+
const configModel = this.config.embeddingModel;
|
|
43927
|
+
if (configModel) {
|
|
43928
|
+
this.resolvedEmbeddingModel = await this.resolveModelHandle(configModel, true);
|
|
43929
|
+
} else {
|
|
43930
|
+
const models = await this.getModels();
|
|
43931
|
+
const hasValidProvider = (handle) => {
|
|
43932
|
+
const provider = handle.split("/")[0];
|
|
43933
|
+
return VALID_PROVIDERS.includes(provider);
|
|
43934
|
+
};
|
|
43935
|
+
const validEmbeddingModels = models.filter((m) => m.name.includes("embedding") && hasValidProvider(m.handle));
|
|
43936
|
+
if (validEmbeddingModels.length > 0) {
|
|
43937
|
+
const preferredName = this.config.preferredEmbeddingModel ?? "text-embedding-3-small";
|
|
43938
|
+
const preferred = validEmbeddingModels.find((m) => m.name.includes(preferredName));
|
|
43939
|
+
this.resolvedEmbeddingModel = preferred?.handle ?? validEmbeddingModels[0].handle;
|
|
43940
|
+
} else {
|
|
43941
|
+
this.resolvedEmbeddingModel = DEFAULT_EMBEDDING_MODEL;
|
|
43942
|
+
}
|
|
43834
43943
|
}
|
|
43835
|
-
return
|
|
43944
|
+
return this.resolvedEmbeddingModel;
|
|
43945
|
+
}
|
|
43946
|
+
async getLlmModel() {
|
|
43947
|
+
if (this.resolvedLlmModel) {
|
|
43948
|
+
return this.resolvedLlmModel;
|
|
43949
|
+
}
|
|
43950
|
+
const configModel = this.config.llmModel;
|
|
43951
|
+
if (configModel) {
|
|
43952
|
+
this.resolvedLlmModel = await this.resolveModelHandle(configModel, false);
|
|
43953
|
+
} else {
|
|
43954
|
+
this.resolvedLlmModel = DEFAULT_LLM_MODEL;
|
|
43955
|
+
}
|
|
43956
|
+
return this.resolvedLlmModel;
|
|
43836
43957
|
}
|
|
43837
43958
|
async add(input) {
|
|
43838
43959
|
if (!this.config.enabled) {
|
|
@@ -44001,7 +44122,11 @@ class LettaAdapter {
|
|
|
44001
44122
|
redirect: "follow",
|
|
44002
44123
|
signal: AbortSignal.timeout(5000)
|
|
44003
44124
|
});
|
|
44004
|
-
|
|
44125
|
+
if (response2.ok) {
|
|
44126
|
+
await this.ensureOpenAIProxyProvider();
|
|
44127
|
+
return true;
|
|
44128
|
+
}
|
|
44129
|
+
return false;
|
|
44005
44130
|
} catch {
|
|
44006
44131
|
return false;
|
|
44007
44132
|
}
|
|
@@ -44015,8 +44140,8 @@ class LettaAdapter {
|
|
|
44015
44140
|
}
|
|
44016
44141
|
return existing;
|
|
44017
44142
|
}
|
|
44018
|
-
const embeddingModel = await this.
|
|
44019
|
-
const llmModel = this.
|
|
44143
|
+
const embeddingModel = await this.getEmbeddingModel();
|
|
44144
|
+
const llmModel = await this.getLlmModel();
|
|
44020
44145
|
const agentName = this.getAgentName(layer);
|
|
44021
44146
|
const response2 = await this.request("/v1/agents", {
|
|
44022
44147
|
method: "POST",
|
|
@@ -44047,7 +44172,7 @@ class LettaAdapter {
|
|
|
44047
44172
|
if (!embeddingHandle)
|
|
44048
44173
|
return false;
|
|
44049
44174
|
if (embeddingHandle === "letta/letta-free") {
|
|
44050
|
-
const detected = await this.
|
|
44175
|
+
const detected = await this.getEmbeddingModel();
|
|
44051
44176
|
return detected !== "letta/letta-free";
|
|
44052
44177
|
}
|
|
44053
44178
|
return false;
|
|
@@ -44055,8 +44180,8 @@ class LettaAdapter {
|
|
|
44055
44180
|
async recreateAgentWithCorrectEmbedding(existingAgent, layer) {
|
|
44056
44181
|
await this.request(`/v1/agents/${existingAgent.id}`, { method: "DELETE" }).catch(() => {});
|
|
44057
44182
|
this.agentCache.delete(layer);
|
|
44058
|
-
const embeddingModel = await this.
|
|
44059
|
-
const llmModel = this.
|
|
44183
|
+
const embeddingModel = await this.getEmbeddingModel();
|
|
44184
|
+
const llmModel = await this.getLlmModel();
|
|
44060
44185
|
const agentName = this.getAgentName(layer);
|
|
44061
44186
|
const response2 = await this.request("/v1/agents", {
|
|
44062
44187
|
method: "POST",
|