@easynet/agent-llm 1.0.10 → 1.0.12
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 +48 -60
- package/dist/{createAgentLlM.d.ts → api/create-agent-llm.d.ts} +2 -2
- package/dist/api/create-agent-llm.d.ts.map +1 -0
- package/dist/{chunk-L3K6IEC6.js → chunk-VR7BRFGB.js} +134 -134
- package/dist/chunk-VR7BRFGB.js.map +1 -0
- package/dist/{cli.d.ts → cli/index.d.ts} +1 -1
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/{cli.js → cli/index.js} +5 -5
- package/dist/cli/index.js.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/{loadLlmConfig.d.ts → config/loader.d.ts} +1 -1
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/{config.d.ts → config/parser.d.ts} +2 -2
- package/dist/config/parser.d.ts.map +1 -0
- package/dist/extensions/index.d.ts +8 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/{loadLLMExtensions.d.ts → extensions/loader.d.ts} +1 -1
- package/dist/extensions/loader.d.ts.map +1 -0
- package/dist/{npmProviderProtocol.d.ts → extensions/npm-protocol.d.ts} +3 -3
- package/dist/{npmProviderProtocol.d.ts.map → extensions/npm-protocol.d.ts.map} +1 -1
- package/dist/index.d.ts +13 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/{llmAdapter.d.ts → langchain/adapter.d.ts} +1 -1
- package/dist/langchain/adapter.d.ts.map +1 -0
- package/dist/langchain/index.d.ts +6 -0
- package/dist/langchain/index.d.ts.map +1 -0
- package/dist/{chatModelRegistry.d.ts → registry/chat-model.d.ts} +2 -2
- package/dist/registry/chat-model.d.ts.map +1 -0
- package/dist/{factory.d.ts → registry/client.d.ts} +2 -2
- package/dist/registry/client.d.ts.map +1 -0
- package/dist/registry/index.d.ts +8 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/chatModelRegistry.d.ts.map +0 -1
- package/dist/chunk-L3K6IEC6.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/createAgentLlM.d.ts.map +0 -1
- package/dist/factory.d.ts.map +0 -1
- package/dist/llmAdapter.d.ts.map +0 -1
- package/dist/loadLLMExtensions.d.ts.map +0 -1
- package/dist/loadLlmConfig.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,42 +1,64 @@
|
|
|
1
1
|
# @easynet/agent-llm
|
|
2
2
|
|
|
3
|
-
Load an LLM from **llm.yaml**
|
|
3
|
+
Load an LLM from **llm.yaml** for CLI or LangChain. Releases are automated via semantic-release on push to `master`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Extensible:** define your own extension (implement `ILLMExtension`).
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
**1.** Add `llm.yaml` in your project root:
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
llm:
|
|
15
|
+
default: small
|
|
16
|
+
strong:
|
|
17
|
+
provider: npm:@scope/package-name@latest#provider-name
|
|
18
|
+
base_url: https://your-api.example.com
|
|
19
|
+
model: your-model
|
|
20
|
+
small:
|
|
21
|
+
provider: openai
|
|
22
|
+
base_url: http://localhost:11434/v1
|
|
23
|
+
model: qwen3:0.6b
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**2.** Run:
|
|
8
27
|
|
|
9
28
|
```bash
|
|
10
|
-
npx @easynet/agent-llm "
|
|
11
|
-
npx @easynet/agent-llm "What is 10 + 20?"
|
|
29
|
+
npx @easynet/agent-llm "your prompt"
|
|
12
30
|
```
|
|
13
31
|
|
|
14
|
-
|
|
32
|
+
---
|
|
15
33
|
|
|
16
|
-
##
|
|
34
|
+
## LangChain agent
|
|
17
35
|
|
|
18
|
-
|
|
36
|
+
1. **Get the LLM** (async; resolves `npm:` providers and installs packages if needed):
|
|
19
37
|
|
|
20
38
|
```ts
|
|
21
39
|
import { createAgentLlM } from "@easynet/agent-llm";
|
|
22
|
-
import { createAgent, tool } from "langchain";
|
|
23
|
-
import { z } from "zod";
|
|
24
40
|
|
|
25
41
|
const llm = await createAgentLlM();
|
|
26
42
|
```
|
|
27
43
|
|
|
28
|
-
|
|
44
|
+
2. **Build the agent** with LangChain's `createAgent` and tools:
|
|
29
45
|
|
|
30
46
|
```ts
|
|
47
|
+
import { createAgent, tool } from "langchain";
|
|
48
|
+
import { z } from "zod";
|
|
49
|
+
|
|
31
50
|
const add = tool(
|
|
32
51
|
(input: { a: number; b: number }) => String(input.a + input.b),
|
|
33
52
|
{ name: "add", description: "Add two numbers.", schema: z.object({ a: z.number(), b: z.number() }) }
|
|
34
53
|
);
|
|
35
54
|
|
|
36
|
-
const agent = createAgent({
|
|
55
|
+
const agent = createAgent({
|
|
56
|
+
model: llm as unknown as Parameters<typeof createAgent>[0]["model"],
|
|
57
|
+
tools: [add],
|
|
58
|
+
});
|
|
37
59
|
```
|
|
38
60
|
|
|
39
|
-
|
|
61
|
+
3. **Invoke** with messages:
|
|
40
62
|
|
|
41
63
|
```ts
|
|
42
64
|
import { HumanMessage } from "@langchain/core/messages";
|
|
@@ -45,59 +67,25 @@ const result = await agent.invoke({ messages: [new HumanMessage("What is 10 + 20
|
|
|
45
67
|
console.log(result.messages?.slice(-1)[0]?.content);
|
|
46
68
|
```
|
|
47
69
|
|
|
48
|
-
Full example: [examples/langchain-react-agent.ts](examples/langchain-react-agent.ts).
|
|
49
|
-
|
|
50
|
-
## Config
|
|
70
|
+
Full runnable example: [examples/langchain-react-agent.ts](examples/langchain-react-agent.ts).
|
|
51
71
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```yaml
|
|
55
|
-
provider: openai
|
|
56
|
-
model: gpt-4o-mini
|
|
57
|
-
temperature: 0
|
|
58
|
-
apiKey: ${OPENAI_API_KEY}
|
|
59
|
-
# baseURL: https://api.openai.com/v1 # or Ollama, Groq, etc.
|
|
60
|
-
```
|
|
72
|
+
---
|
|
61
73
|
|
|
62
|
-
|
|
74
|
+
## npm provider protocol
|
|
63
75
|
|
|
64
|
-
|
|
76
|
+
Use a provider from an **npm package**. If the package is missing, the framework can install it and then load the provider.
|
|
65
77
|
|
|
66
|
-
|
|
78
|
+
Example in a named entry:
|
|
67
79
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
- **`provider: "npm:wallee-llm"`** – load wallee-llm and use its default provider (e.g. `cis`).
|
|
74
|
-
|
|
75
|
-
**createAgentLlM()** resolves npm: providers (and optionally installs packages) when reading config. For a raw llm section use **createChatModelFromLlmConfigWithNpm**:
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
import { createChatModelFromLlmConfigWithNpm, createAgentLlM } from "@easynet/agent-llm";
|
|
79
|
-
|
|
80
|
-
// From a raw llm section (e.g. from loadLlmConfig)
|
|
81
|
-
const model = await createChatModelFromLlmConfigWithNpm({ llmSection });
|
|
82
|
-
|
|
83
|
-
// From llm.yaml in the current directory
|
|
84
|
-
const llm = await createAgentLlM();
|
|
85
|
-
// Or with a path: createAgentLlM("path/to/llm.yaml")
|
|
80
|
+
```yaml
|
|
81
|
+
strong:
|
|
82
|
+
provider: "npm:@scope/package-name@latest#provider-name"
|
|
83
|
+
base_url: https://your-api.example.com
|
|
84
|
+
model: your-model
|
|
86
85
|
```
|
|
87
86
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
## Using with Workday Artifactory
|
|
87
|
+
---
|
|
91
88
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
```ini
|
|
95
|
-
registry=https://registry.npmjs.org/
|
|
96
|
-
@easynet:registry=https://artifactory.workday.com/artifactory/api/npm/npm-virtual/
|
|
97
|
-
```
|
|
89
|
+
## License
|
|
98
90
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
```bash
|
|
102
|
-
npx @easynet/agent-llm hi
|
|
103
|
-
```
|
|
91
|
+
MIT · [GitHub](https://github.com/easynet-world/agent-llm)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createChatModelFromLlmConfig } from "
|
|
1
|
+
import { createChatModelFromLlmConfig } from "../langchain/adapter.js";
|
|
2
2
|
export interface CreateAgentLlMOptions {
|
|
3
3
|
/** Path to YAML config file. If omitted, uses llm.yaml in the current directory (cwd). */
|
|
4
4
|
configPath?: string;
|
|
@@ -12,4 +12,4 @@ export interface CreateAgentLlMOptions {
|
|
|
12
12
|
* - createAgentLlM({ configPath: "...", installNpmIfMissing: true }) — options object
|
|
13
13
|
*/
|
|
14
14
|
export declare function createAgentLlM(configPathOrOptions?: string | CreateAgentLlMOptions): Promise<ReturnType<typeof createChatModelFromLlmConfig>>;
|
|
15
|
-
//# sourceMappingURL=
|
|
15
|
+
//# sourceMappingURL=create-agent-llm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-agent-llm.d.ts","sourceRoot":"","sources":["../../src/api/create-agent-llm.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;AAIvE,MAAM,WAAW,qBAAqB;IACpC,0FAA0F;IAC1F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kGAAkG;IAClG,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAgDD;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,mBAAmB,CAAC,EAAE,MAAM,GAAG,qBAAqB,GACnD,OAAO,CAAC,UAAU,CAAC,OAAO,4BAA4B,CAAC,CAAC,CAiB1D"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/config.ts
|
|
1
|
+
// src/config/parser.ts
|
|
2
2
|
var DEFAULT_LLM_ID = "default";
|
|
3
3
|
var RESERVED_KEYS = /* @__PURE__ */ new Set([
|
|
4
4
|
"default",
|
|
@@ -108,81 +108,48 @@ function normalizeLlmConfig(o) {
|
|
|
108
108
|
return config;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
// src/
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
111
|
+
// src/config/loader.ts
|
|
112
|
+
import { readFileSync, existsSync } from "fs";
|
|
113
|
+
import { parse as parseYaml } from "yaml";
|
|
114
|
+
function substituteEnv(obj) {
|
|
115
|
+
if (obj === null || obj === void 0) return obj;
|
|
116
|
+
if (typeof obj === "string") {
|
|
117
|
+
const m = obj.match(/^\$\{(\w+)\}$/);
|
|
118
|
+
return m ? process.env[m[1]] ?? obj : obj;
|
|
119
|
+
}
|
|
120
|
+
if (Array.isArray(obj)) return obj.map(substituteEnv);
|
|
121
|
+
if (typeof obj === "object") {
|
|
122
|
+
const out = {};
|
|
123
|
+
for (const [k, v] of Object.entries(obj)) out[k] = substituteEnv(v);
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
return obj;
|
|
118
127
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return new Error(`${context}: ${String(e)}`);
|
|
128
|
+
function parseLlmYaml(content, options = {}) {
|
|
129
|
+
const { substituteEnv: doSub = true } = options;
|
|
130
|
+
const parsed = parseYaml(content);
|
|
131
|
+
const llm = parsed?.llm;
|
|
132
|
+
if (llm == null) return void 0;
|
|
133
|
+
return doSub ? substituteEnv(llm) : llm;
|
|
126
134
|
}
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
135
|
+
function loadLlmConfig(filePath, options = {}) {
|
|
136
|
+
if (typeof filePath !== "string" || filePath.trim().length === 0) {
|
|
137
|
+
throw new Error("agent-llm: loadLlmConfig requires a non-empty file path");
|
|
138
|
+
}
|
|
139
|
+
if (!existsSync(filePath)) return null;
|
|
140
|
+
let raw;
|
|
131
141
|
try {
|
|
132
|
-
|
|
133
|
-
defaultId = parsed.defaultId;
|
|
134
|
-
configs = parsed.configs;
|
|
142
|
+
raw = readFileSync(filePath, "utf8");
|
|
135
143
|
} catch (e) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const defaultConfig = configs.find((c) => c.id === defaultId) ?? configs[0];
|
|
139
|
-
if (!defaultConfig) {
|
|
140
|
-
const model2 = modelEnv ?? process.env.OPENAI_MODEL ?? DEFAULT_MODEL;
|
|
141
|
-
const apiKey2 = apiKeyEnv ?? process.env.OPENAI_API_KEY;
|
|
142
|
-
try {
|
|
143
|
-
return new ChatOpenAI({
|
|
144
|
-
model: model2,
|
|
145
|
-
temperature: 0,
|
|
146
|
-
...apiKey2 ? { apiKey: apiKey2 } : {}
|
|
147
|
-
});
|
|
148
|
-
} catch (e) {
|
|
149
|
-
throw normalizeAgentLlMError(e, "agent-llm: failed to create default ChatOpenAI");
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
const provider = defaultConfig.provider ?? "openai";
|
|
153
|
-
const chatModelFactory = getChatModelFactory(provider);
|
|
154
|
-
if (chatModelFactory) {
|
|
155
|
-
const config = {
|
|
156
|
-
...defaultConfig,
|
|
157
|
-
model: modelEnv ?? defaultConfig.model,
|
|
158
|
-
temperature: typeof defaultConfig.temperature === "number" ? defaultConfig.temperature : 0
|
|
159
|
-
};
|
|
160
|
-
try {
|
|
161
|
-
return chatModelFactory(config);
|
|
162
|
-
} catch (e) {
|
|
163
|
-
throw normalizeAgentLlMError(e, `agent-llm: failed to create ChatModel for provider "${provider}"`);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
const model = modelEnv ?? defaultConfig?.model ?? process.env.OPENAI_MODEL ?? DEFAULT_MODEL;
|
|
167
|
-
let apiKey = apiKeyEnv ?? defaultConfig?.apiKey ?? process.env.OPENAI_API_KEY;
|
|
168
|
-
let baseURL = defaultConfig?.baseURL;
|
|
169
|
-
if (baseURL && !baseURL.replace(/\/$/, "").endsWith("/v1")) {
|
|
170
|
-
baseURL = baseURL.replace(/\/$/, "") + "/v1";
|
|
171
|
-
}
|
|
172
|
-
if (baseURL && apiKey === void 0) {
|
|
173
|
-
apiKey = "ollama";
|
|
144
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
145
|
+
throw new Error(`agent-llm: failed to read config file ${filePath}: ${msg}`, { cause: e });
|
|
174
146
|
}
|
|
175
|
-
const temperature = typeof defaultConfig?.temperature === "number" ? defaultConfig.temperature : 0;
|
|
176
|
-
const constructorOptions = {
|
|
177
|
-
model,
|
|
178
|
-
temperature,
|
|
179
|
-
...apiKey ? { apiKey } : {},
|
|
180
|
-
...baseURL ? { configuration: { baseURL } } : {}
|
|
181
|
-
};
|
|
182
147
|
try {
|
|
183
|
-
|
|
148
|
+
const llm = parseLlmYaml(raw, options);
|
|
149
|
+
return llm ?? null;
|
|
184
150
|
} catch (e) {
|
|
185
|
-
|
|
151
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
152
|
+
throw new Error(`agent-llm: failed to parse config file ${filePath}: ${msg}`, { cause: e });
|
|
186
153
|
}
|
|
187
154
|
}
|
|
188
155
|
|
|
@@ -316,8 +283,86 @@ function registerProvider(name, factory) {
|
|
|
316
283
|
PROVIDERS[name.toLowerCase()] = factory;
|
|
317
284
|
}
|
|
318
285
|
|
|
319
|
-
// src/
|
|
320
|
-
|
|
286
|
+
// src/registry/chat-model.ts
|
|
287
|
+
var CHAT_MODEL_FACTORIES = /* @__PURE__ */ new Map();
|
|
288
|
+
function registerChatModelProvider(providerName, factory) {
|
|
289
|
+
CHAT_MODEL_FACTORIES.set(providerName.toLowerCase(), factory);
|
|
290
|
+
}
|
|
291
|
+
function getChatModelFactory(providerName) {
|
|
292
|
+
return CHAT_MODEL_FACTORIES.get(providerName.toLowerCase());
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/langchain/adapter.ts
|
|
296
|
+
import { ChatOpenAI } from "@langchain/openai";
|
|
297
|
+
var DEFAULT_MODEL = "gpt-4o-mini";
|
|
298
|
+
function normalizeAgentLlMError(e, context) {
|
|
299
|
+
if (e instanceof Error) return new Error(`${context}: ${e.message}`, { cause: e });
|
|
300
|
+
return new Error(`${context}: ${String(e)}`);
|
|
301
|
+
}
|
|
302
|
+
function createChatModelFromLlmConfig(options) {
|
|
303
|
+
const { llmSection, modelEnv, apiKeyEnv } = options;
|
|
304
|
+
let defaultId;
|
|
305
|
+
let configs;
|
|
306
|
+
try {
|
|
307
|
+
const parsed = parseLlmSection(llmSection ?? null);
|
|
308
|
+
defaultId = parsed.defaultId;
|
|
309
|
+
configs = parsed.configs;
|
|
310
|
+
} catch (e) {
|
|
311
|
+
throw normalizeAgentLlMError(e, "agent-llm: failed to parse llm section");
|
|
312
|
+
}
|
|
313
|
+
const defaultConfig = configs.find((c) => c.id === defaultId) ?? configs[0];
|
|
314
|
+
if (!defaultConfig) {
|
|
315
|
+
const model2 = modelEnv ?? process.env.OPENAI_MODEL ?? DEFAULT_MODEL;
|
|
316
|
+
const apiKey2 = apiKeyEnv ?? process.env.OPENAI_API_KEY;
|
|
317
|
+
try {
|
|
318
|
+
return new ChatOpenAI({
|
|
319
|
+
model: model2,
|
|
320
|
+
temperature: 0,
|
|
321
|
+
...apiKey2 ? { apiKey: apiKey2 } : {}
|
|
322
|
+
});
|
|
323
|
+
} catch (e) {
|
|
324
|
+
throw normalizeAgentLlMError(e, "agent-llm: failed to create default ChatOpenAI");
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
const provider = defaultConfig.provider ?? "openai";
|
|
328
|
+
const chatModelFactory = getChatModelFactory(provider);
|
|
329
|
+
if (chatModelFactory) {
|
|
330
|
+
const config = {
|
|
331
|
+
...defaultConfig,
|
|
332
|
+
model: modelEnv ?? defaultConfig.model,
|
|
333
|
+
temperature: typeof defaultConfig.temperature === "number" ? defaultConfig.temperature : 0
|
|
334
|
+
};
|
|
335
|
+
try {
|
|
336
|
+
return chatModelFactory(config);
|
|
337
|
+
} catch (e) {
|
|
338
|
+
throw normalizeAgentLlMError(e, `agent-llm: failed to create ChatModel for provider "${provider}"`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
const model = modelEnv ?? defaultConfig?.model ?? process.env.OPENAI_MODEL ?? DEFAULT_MODEL;
|
|
342
|
+
let apiKey = apiKeyEnv ?? defaultConfig?.apiKey ?? process.env.OPENAI_API_KEY;
|
|
343
|
+
let baseURL = defaultConfig?.baseURL;
|
|
344
|
+
if (baseURL && !baseURL.replace(/\/$/, "").endsWith("/v1")) {
|
|
345
|
+
baseURL = baseURL.replace(/\/$/, "") + "/v1";
|
|
346
|
+
}
|
|
347
|
+
if (baseURL && apiKey === void 0) {
|
|
348
|
+
apiKey = "ollama";
|
|
349
|
+
}
|
|
350
|
+
const temperature = typeof defaultConfig?.temperature === "number" ? defaultConfig.temperature : 0;
|
|
351
|
+
const constructorOptions = {
|
|
352
|
+
model,
|
|
353
|
+
temperature,
|
|
354
|
+
...apiKey ? { apiKey } : {},
|
|
355
|
+
...baseURL ? { configuration: { baseURL } } : {}
|
|
356
|
+
};
|
|
357
|
+
try {
|
|
358
|
+
return new ChatOpenAI(constructorOptions);
|
|
359
|
+
} catch (e) {
|
|
360
|
+
throw normalizeAgentLlMError(e, "agent-llm: failed to create ChatOpenAI from config");
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// src/extensions/loader.ts
|
|
365
|
+
import { readdirSync, readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
321
366
|
import { join } from "path";
|
|
322
367
|
import { pathToFileURL } from "url";
|
|
323
368
|
var loadedPackages = /* @__PURE__ */ new Set();
|
|
@@ -356,9 +401,9 @@ function resolveLLMExtensionPackages(types) {
|
|
|
356
401
|
);
|
|
357
402
|
}
|
|
358
403
|
function readPackageProviderName(pkgPath) {
|
|
359
|
-
if (!
|
|
404
|
+
if (!existsSync2(pkgPath)) return null;
|
|
360
405
|
try {
|
|
361
|
-
const raw =
|
|
406
|
+
const raw = readFileSync2(pkgPath, "utf-8");
|
|
362
407
|
const pkg = JSON.parse(raw);
|
|
363
408
|
const declared = pkg.agentLlmProvider === true || Array.isArray(pkg.keywords) && pkg.keywords.includes("agent-llm-provider");
|
|
364
409
|
return declared && typeof pkg.name === "string" ? pkg.name : null;
|
|
@@ -369,7 +414,7 @@ function readPackageProviderName(pkgPath) {
|
|
|
369
414
|
function discoverLLMExtensions(cwd = process.cwd()) {
|
|
370
415
|
const dir = typeof cwd === "string" && cwd.trim().length > 0 ? cwd : process.cwd();
|
|
371
416
|
const nodeModules = join(dir, "node_modules");
|
|
372
|
-
if (!
|
|
417
|
+
if (!existsSync2(nodeModules)) return [];
|
|
373
418
|
const names = [];
|
|
374
419
|
const seen = /* @__PURE__ */ new Set();
|
|
375
420
|
try {
|
|
@@ -401,13 +446,13 @@ function discoverLLMExtensions(cwd = process.cwd()) {
|
|
|
401
446
|
}
|
|
402
447
|
async function loadModuleFromPath(pkgDir) {
|
|
403
448
|
const pkgJsonPath = join(pkgDir, "package.json");
|
|
404
|
-
if (!
|
|
449
|
+
if (!existsSync2(pkgJsonPath)) {
|
|
405
450
|
throw new Error(`package.json not found in ${pkgDir}`);
|
|
406
451
|
}
|
|
407
|
-
const pkgJson = JSON.parse(
|
|
452
|
+
const pkgJson = JSON.parse(readFileSync2(pkgJsonPath, "utf-8"));
|
|
408
453
|
const main = pkgJson?.main ?? "index.js";
|
|
409
454
|
const entryPath = join(pkgDir, main);
|
|
410
|
-
if (!
|
|
455
|
+
if (!existsSync2(entryPath)) {
|
|
411
456
|
throw new Error(`Entry ${main} not found in ${pkgDir}`);
|
|
412
457
|
}
|
|
413
458
|
const entryUrl = pathToFileURL(entryPath).href;
|
|
@@ -424,9 +469,9 @@ async function loadLLMExtensions(extensionPackages, options) {
|
|
|
424
469
|
loadedPackages.add(pkg);
|
|
425
470
|
let loaded = false;
|
|
426
471
|
const cwdPkgDir = join(cwd, "node_modules", pkg);
|
|
427
|
-
const cwdIsProject =
|
|
472
|
+
const cwdIsProject = existsSync2(join(cwd, "package.json")) && (() => {
|
|
428
473
|
try {
|
|
429
|
-
const name = JSON.parse(
|
|
474
|
+
const name = JSON.parse(readFileSync2(join(cwd, "package.json"), "utf-8")).name;
|
|
430
475
|
return name === pkg;
|
|
431
476
|
} catch {
|
|
432
477
|
return false;
|
|
@@ -434,7 +479,7 @@ async function loadLLMExtensions(extensionPackages, options) {
|
|
|
434
479
|
})();
|
|
435
480
|
const dirsToTry = [cwdPkgDir, ...cwdIsProject ? [cwd] : []];
|
|
436
481
|
for (const pkgDir of dirsToTry) {
|
|
437
|
-
if (!
|
|
482
|
+
if (!existsSync2(join(pkgDir, "package.json"))) continue;
|
|
438
483
|
try {
|
|
439
484
|
const m = await loadModuleFromPath(pkgDir);
|
|
440
485
|
const ext = getExtensionFromModule(m);
|
|
@@ -480,7 +525,7 @@ async function loadDiscoveredExtensions(cwd = process.cwd()) {
|
|
|
480
525
|
return names;
|
|
481
526
|
}
|
|
482
527
|
|
|
483
|
-
// src/
|
|
528
|
+
// src/extensions/npm-protocol.ts
|
|
484
529
|
import { execSync } from "child_process";
|
|
485
530
|
var NPM_PROTOCOL_PREFIX = "npm:";
|
|
486
531
|
function parseNpmProviderSpec(spec) {
|
|
@@ -636,52 +681,7 @@ async function createChatModelFromLlmConfigWithNpm(options) {
|
|
|
636
681
|
}
|
|
637
682
|
}
|
|
638
683
|
|
|
639
|
-
// src/
|
|
640
|
-
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
641
|
-
import { parse as parseYaml } from "yaml";
|
|
642
|
-
function substituteEnv(obj) {
|
|
643
|
-
if (obj === null || obj === void 0) return obj;
|
|
644
|
-
if (typeof obj === "string") {
|
|
645
|
-
const m = obj.match(/^\$\{(\w+)\}$/);
|
|
646
|
-
return m ? process.env[m[1]] ?? obj : obj;
|
|
647
|
-
}
|
|
648
|
-
if (Array.isArray(obj)) return obj.map(substituteEnv);
|
|
649
|
-
if (typeof obj === "object") {
|
|
650
|
-
const out = {};
|
|
651
|
-
for (const [k, v] of Object.entries(obj)) out[k] = substituteEnv(v);
|
|
652
|
-
return out;
|
|
653
|
-
}
|
|
654
|
-
return obj;
|
|
655
|
-
}
|
|
656
|
-
function parseLlmYaml(content, options = {}) {
|
|
657
|
-
const { substituteEnv: doSub = true } = options;
|
|
658
|
-
const parsed = parseYaml(content);
|
|
659
|
-
const llm = parsed?.llm;
|
|
660
|
-
if (llm == null) return void 0;
|
|
661
|
-
return doSub ? substituteEnv(llm) : llm;
|
|
662
|
-
}
|
|
663
|
-
function loadLlmConfig(filePath, options = {}) {
|
|
664
|
-
if (typeof filePath !== "string" || filePath.trim().length === 0) {
|
|
665
|
-
throw new Error("agent-llm: loadLlmConfig requires a non-empty file path");
|
|
666
|
-
}
|
|
667
|
-
if (!existsSync2(filePath)) return null;
|
|
668
|
-
let raw;
|
|
669
|
-
try {
|
|
670
|
-
raw = readFileSync2(filePath, "utf8");
|
|
671
|
-
} catch (e) {
|
|
672
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
673
|
-
throw new Error(`agent-llm: failed to read config file ${filePath}: ${msg}`, { cause: e });
|
|
674
|
-
}
|
|
675
|
-
try {
|
|
676
|
-
const llm = parseLlmYaml(raw, options);
|
|
677
|
-
return llm ?? null;
|
|
678
|
-
} catch (e) {
|
|
679
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
680
|
-
throw new Error(`agent-llm: failed to parse config file ${filePath}: ${msg}`, { cause: e });
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
// src/createAgentLlM.ts
|
|
684
|
+
// src/api/create-agent-llm.ts
|
|
685
685
|
import { join as join2 } from "path";
|
|
686
686
|
function resolveDefaultConfigPath() {
|
|
687
687
|
const cwd = process.cwd();
|
|
@@ -717,14 +717,17 @@ async function createAgentLlM(configPathOrOptions) {
|
|
|
717
717
|
|
|
718
718
|
export {
|
|
719
719
|
parseLlmSection,
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
720
|
+
substituteEnv,
|
|
721
|
+
parseLlmYaml,
|
|
722
|
+
loadLlmConfig,
|
|
723
723
|
createOpenAIChatClient,
|
|
724
724
|
createOpenAIImageClient,
|
|
725
725
|
createOpenAIClient,
|
|
726
726
|
createClient,
|
|
727
727
|
registerProvider,
|
|
728
|
+
registerChatModelProvider,
|
|
729
|
+
getChatModelFactory,
|
|
730
|
+
createChatModelFromLlmConfig,
|
|
728
731
|
resolveLLMExtensionPackages,
|
|
729
732
|
discoverLLMExtensions,
|
|
730
733
|
loadLLMExtensions,
|
|
@@ -736,9 +739,6 @@ export {
|
|
|
736
739
|
resolveNpmProvider,
|
|
737
740
|
resolveLlmSectionWithNpm,
|
|
738
741
|
createChatModelFromLlmConfigWithNpm,
|
|
739
|
-
substituteEnv,
|
|
740
|
-
parseLlmYaml,
|
|
741
|
-
loadLlmConfig,
|
|
742
742
|
createAgentLlM
|
|
743
743
|
};
|
|
744
|
-
//# sourceMappingURL=chunk-
|
|
744
|
+
//# sourceMappingURL=chunk-VR7BRFGB.js.map
|