operon-agents 0.1.0-alpha.2 → 0.1.0-alpha.21

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/index.d.ts CHANGED
@@ -14,11 +14,14 @@
14
14
  export * from "./harness.ts";
15
15
  export * from "./extensions/index.ts";
16
16
  export * from "./cron/index.ts";
17
+ export * from "./providers.ts";
17
18
  export * from "./local.ts";
19
+ export * from "./workspace-mcp.ts";
18
20
  export * from "operon-agents-core";
19
21
  export * as llm from "operon-agents-core/llm";
20
22
  export * as mcp from "operon-agents-core/mcp";
21
23
  export * as protocol from "operon-agents-core/protocol";
22
24
  export * as tools from "operon-agents-core/tools";
23
25
  export * as tracing from "operon-agents-core/tracing";
26
+ export * as telemetry from "./telemetry.ts";
24
27
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -16,8 +16,12 @@ export * from "./harness.js";
16
16
  // Core supplies the primitives they are built on (Capability / LoopHooks / ToolFilter / Injector).
17
17
  export * from "./extensions/index.js";
18
18
  export * from "./cron/index.js";
19
+ // Model providers the host configures (a self-hosted endpoint, a gateway) — see providers.ts.
20
+ export * from "./providers.js";
19
21
  // Deployment composition roots: local vs server injection presets (Invariant 7 — no engine "mode").
20
22
  export * from "./local.js";
23
+ // Per-directory MCP sharing for hosts that open many sessions in one folder (a desktop app).
24
+ export * from "./workspace-mcp.js";
21
25
  // The curated core engine, re-exported for convenience; `operon-agents/core` is the dedicated
22
26
  // primitives entrypoint.
23
27
  export * from "operon-agents-core";
@@ -26,4 +30,5 @@ export * as mcp from "operon-agents-core/mcp";
26
30
  export * as protocol from "operon-agents-core/protocol";
27
31
  export * as tools from "operon-agents-core/tools";
28
32
  export * as tracing from "operon-agents-core/tracing";
33
+ export * as telemetry from "./telemetry.js";
29
34
  //# sourceMappingURL=index.js.map
@@ -6,4 +6,5 @@
6
6
  * No stability guarantees — prefer the main `operon-agents` surface.
7
7
  */
8
8
  export * from "operon-agents-core/internal";
9
+ export { setHarnessCloseTimeoutsForTest } from "./harness.ts";
9
10
  //# sourceMappingURL=internal.d.ts.map
package/dist/internal.js CHANGED
@@ -6,4 +6,5 @@
6
6
  * No stability guarantees — prefer the main `operon-agents` surface.
7
7
  */
8
8
  export * from "operon-agents-core/internal";
9
+ export { setHarnessCloseTimeoutsForTest } from "./harness.js";
9
10
  //# sourceMappingURL=internal.js.map
package/dist/local.d.ts CHANGED
@@ -1,24 +1,41 @@
1
- import { type HookDef, type McpServerConfig, type PluginManager } from "operon-agents-core";
2
- import { type CreateSessionOptions, type Harness, type HarnessOptions, type HarnessSession } from "./harness.ts";
1
+ import type { ModelRuntime } from "operon-agents-core";
2
+ import { type HookDef, type Logger, type McpServerConfig, type PluginManager } from "operon-agents-core";
3
+ import { type Harness, type HarnessOptions } from "./harness.ts";
3
4
  export interface LocalDeploymentOptions<TContext = unknown> extends HarnessOptions<TContext> {
4
5
  /**
5
6
  * App home root — sessions (`<homeDir>/sessions`), MCP creds, logs, and disk-discovered agent
6
7
  * profiles all live under it. Defaults to `~/.agents`. (`homeDir` is a local-deployment concept;
7
- * the harness itself only knows `repository`.)
8
+ * the harness itself only knows `HarnessParts.sessionRepository`.)
8
9
  */
9
10
  readonly homeDir?: string;
10
- /** Workspace MCP servers to expose. */
11
+ /** MCP servers to expose, shared by every session of the harness. */
11
12
  readonly mcpServers?: Record<string, McpServerConfig>;
12
- /** Installed-plugin manager, if any. */
13
+ /** Installed-plugin manager, if any. Loaded once here, then handed out as `HarnessParts.pluginManager`. */
13
14
  readonly pluginManager?: PluginManager;
14
15
  /** Shell hooks from config (`config.hooks`), projected as HookDefs. */
15
16
  readonly hooks?: readonly HookDef[];
16
17
  /** Discover agent profiles from disk (`<homeDir>/agents` + `<cwd>/.agents/agents`). Default true. */
17
18
  readonly loadDiskProfiles?: boolean;
19
+ /** Diagnostics logger. Defaults to a rotating file under `<homeDir>/logs`. */
20
+ readonly logger?: Logger;
21
+ /** Context budget for the default compaction capability. */
22
+ readonly maxContextTokens?: number;
23
+ /**
24
+ * The model runtime this harness resolves providers through. Pass the same one the host used to
25
+ * build its `ChatModel` (see `createModelRuntimeFromConfig`) when a model lives on a configured
26
+ * endpoint — otherwise the two registries disagree about what exists. Omitted, the harness builds
27
+ * one from `<homeDir>/providers.toml` itself.
28
+ */
29
+ readonly modelRuntime?: ModelRuntime;
30
+ /** Skip reading `<homeDir>/providers.toml` entirely. Ignored when `modelRuntime` is given. */
31
+ readonly loadConfiguredProviders?: boolean;
18
32
  }
19
- /** Build `HarnessOptions` wired for a local, single-machine deployment. */
33
+ /** Build `HarnessOptions` wired for a local, single-environment deployment. */
20
34
  export declare function localHarnessOptions<TContext>(options: LocalDeploymentOptions<TContext>): Promise<HarnessOptions<TContext>>;
35
+ /**
36
+ * The local entry point: one harness per process, one `createSession()` per conversation on it.
37
+ * Its `close()` closes those sessions and then the harness scope — the cron timer, the workspace
38
+ * MCP connections and the rotating log handle all live there, so nothing else tears them down.
39
+ */
21
40
  export declare function createLocalHarness<TContext = unknown>(options: LocalDeploymentOptions<TContext>): Promise<Harness<TContext>>;
22
- /** Convenience: a local harness with one session opened and ready to `prompt()`. */
23
- export declare function createLocalSession<TContext = unknown>(options: LocalDeploymentOptions<TContext>, session?: CreateSessionOptions<TContext>): Promise<HarnessSession<TContext>>;
24
41
  //# sourceMappingURL=local.d.ts.map
package/dist/local.js CHANGED
@@ -1,58 +1,128 @@
1
1
  /**
2
- * The local composition root — every convention a single-machine, single-operator app runs on,
3
- * bundled in one place: disk sessions under `<homeDir>/sessions`, the local machine, a rotating
2
+ * The local composition root — every convention a single-environment, single-operator app runs on,
3
+ * bundled in one place: disk sessions under `<homeDir>/sessions`, the local environment, a rotating
4
4
  * file log, file-backed MCP credentials, disk-discovered agent profiles, and the cron extension.
5
5
  *
6
- * There is deliberately no server counterpart. A hosted deployment injects its own repository,
7
- * machine, logger and credential store, and those choices belong to the host — a preset that
8
- * bundled them saved three lines while forcing one `McpOAuthService` (and therefore one
9
- * credential store, which has no tenant dimension) to be shared across every session in the
10
- * process. Servers call `createHarness` directly; see `examples/managed-agents`.
11
- *
12
- * There is still no "mode" inside the engine (Architecture Invariant 7): this file only picks
13
- * backends, and returns a plain `Harness` nothing downstream can distinguish.
6
+ * It is a PRESET: pure data in (`LocalDeploymentOptions`), the three composition hooks out.
7
+ * The `harness` hook registers the process-lived objects on the harness scope; the `session`
8
+ * hook builds each session's capability set. A hosted deployment writes its own preset the same
9
+ * way (see `examples/managed-agents`) — there is still no "mode" inside the engine
10
+ * (Architecture Invariant 7): this file only picks backends, and returns plain `HarnessOptions`
11
+ * nothing downstream can distinguish.
14
12
  */
15
13
  import { homedir } from "node:os";
16
14
  import { cronExtension } from "./cron/index.js";
17
- import { join } from "node:path";
18
- import { DiskSessionRepository, McpOAuthService, RotatingFileSink, loadAgentProfiles, resolveGlobalLogPath, sinkLogger, } from "operon-agents-core";
15
+ import { createModelRuntimeFromConfig } from "./providers.js";
16
+ import { join, resolve } from "node:path";
17
+ import { DiskSessionRepository, LocalEnvironment, McpOAuthService, RotatingFileSink, SkillRegistry, createMcpServers, loadSkillRoots, loadAgentProfiles, resolveGlobalLogPath, sinkLogger, } from "operon-agents-core";
19
18
  import { createHarness, defaultCapabilities, } from "./harness.js";
20
- /** Build `HarnessOptions` wired for a local, single-machine deployment. */
19
+ /** Build `HarnessOptions` wired for a local, single-environment deployment. */
21
20
  export async function localHarnessOptions(options) {
22
- const homeDir = options.homeDir ?? join(homedir(), ".agents");
23
- // MCP OAuth credentials on local disk (0600) — the local default backend (`<homeDir>/credentials/mcp`).
24
- const oauthService = new McpOAuthService({ homeDir });
25
- // Diagnostics roll on disk under <homeDir>/logs.
26
- const logger = options.logger ?? sinkLogger(new RotatingFileSink({ path: resolveGlobalLogPath({ homeDir }) }));
21
+ const { homeDir: home, mcpServers, pluginManager, hooks, loadDiskProfiles, logger, maxContextTokens, modelRuntime, loadConfiguredProviders, harness, session, extensions, ...engine } = options;
22
+ // Filled by the `harness` half below, read by the `session` half — one process, one set.
23
+ let sharedParts = {};
24
+ // Set when the shared skill scan ran through a LocalEnvironment at the default workDir (the host
25
+ // named no environment): that catalog only describes sessions rooted there.
26
+ let sharedSkillsWorkDir;
27
+ const homeDir = home ?? join(homedir(), ".agents");
27
28
  // Agent profiles come from disk here; the server preset supplies them externally instead.
28
29
  const extraSubagentProfiles = options.extraSubagentProfiles ??
29
- ((options.loadDiskProfiles ?? true)
30
+ ((loadDiskProfiles ?? true)
30
31
  ? await loadAgentProfiles({ homeDir, cwd: options.workDir ?? process.cwd() })
31
32
  : undefined);
33
+ // Installed plugins are read ONCE per process, not per session: the manager is a harness-tier
34
+ // object, and `session.plugins.reload()` is the explicit refresh.
35
+ if (pluginManager !== undefined)
36
+ await pluginManager.load();
37
+ // Configured endpoints are resolved once per harness, not per session: the registry is a
38
+ // harness-tier object, and a session only ever reads it.
39
+ const runtime = modelRuntime ??
40
+ ((loadConfiguredProviders ?? true)
41
+ ? await createModelRuntimeFromConfig({ homeDir })
42
+ : undefined);
32
43
  return {
33
- ...options,
34
- // Disk sessions under <homeDir>/sessions; an injected repository still wins. The machine defaults to local.
35
- repository: options.repository ?? new DiskSessionRepository(homeDir),
36
- logger,
44
+ ...engine,
37
45
  ...(extraSubagentProfiles !== undefined ? { extraSubagentProfiles } : {}),
38
- capabilities: options.capabilities ??
39
- (() => defaultCapabilities({
40
- ...(options.maxContextTokens !== undefined ? { maxContextTokens: options.maxContextTokens } : {}),
41
- ...(options.mcpServers !== undefined ? { mcpServers: options.mcpServers } : {}),
42
- ...(options.pluginManager !== undefined ? { pluginManager: options.pluginManager } : {}),
43
- ...(options.hooks !== undefined ? { hooks: options.hooks } : {}),
46
+ harness: async () => {
47
+ // Disk sessions under <homeDir>/sessions; diagnostics roll on disk under <homeDir>/logs.
48
+ // The MCP connections, the skill scan and the OAuth store are process-wide: one set for
49
+ // every session this harness opens, built once, here.
50
+ const oauthService = new McpOAuthService({ homeDir });
51
+ const configs = { ...(mcpServers ?? {}), ...(pluginManager?.mcpServerConfigs() ?? {}) };
52
+ let servers;
53
+ if (Object.keys(configs).length > 0) {
54
+ servers = createMcpServers(configs, { oauthService });
55
+ // The set has no session and no event sink of its own: failures surface through
56
+ // `onStatusChange`, which each session subscribes to when it views it.
57
+ await servers.connect({ sessionId: "" });
58
+ }
59
+ const fromHost = await harness?.();
60
+ // Skills follow the EXECUTION environment, not the host's disk: the catalog the model sees
61
+ // must be the one whose scripts its Bash can reach. A host that named an environment above
62
+ // is scanned through it; an environment FACTORY (one per session) has no single filesystem
63
+ // to scan, so there is no shared registry then and each session scans through its own.
64
+ //
65
+ // A host that named none gets NO harness-wide environment: each session runs in a
66
+ // LocalEnvironment at its own workDir (the harness's fallback). The shared scan then goes
67
+ // through the default workDir and is reused only by sessions rooted there.
68
+ const hostEnvironment = fromHost?.environment;
69
+ const defaultWorkDir = resolve(options.workDir ?? process.cwd());
70
+ const scanEnvironment = hostEnvironment ?? new LocalEnvironment(defaultWorkDir);
71
+ let skillRegistry = fromHost?.skillRegistry;
72
+ if (skillRegistry === undefined && typeof scanEnvironment !== "function") {
73
+ skillRegistry = new SkillRegistry();
74
+ await loadSkillRoots(scanEnvironment, skillRegistry, {
75
+ ...(pluginManager !== undefined ? { roots: pluginManager.skillRoots(), includeDefaultRoots: true } : {}),
76
+ });
77
+ if (hostEnvironment === undefined)
78
+ sharedSkillsWorkDir = defaultWorkDir;
79
+ }
80
+ sharedParts = {
81
+ sessionRepository: new DiskSessionRepository(homeDir),
82
+ logger: logger ?? sinkLogger(new RotatingFileSink({ path: resolveGlobalLogPath({ homeDir }) })),
44
83
  oauthService,
84
+ ...(hostEnvironment !== undefined ? { environment: hostEnvironment } : {}),
85
+ ...(servers !== undefined ? { mcpServers: servers } : {}),
86
+ ...(skillRegistry !== undefined ? { skillRegistry } : {}),
87
+ ...(pluginManager !== undefined ? { pluginManager } : {}),
88
+ // What `ExtensionHost.registerProvider` mutates, and where a session's model is looked up.
89
+ ...(runtime !== undefined ? { modelRuntime: runtime } : {}),
90
+ ...fromHost,
91
+ close: async () => {
92
+ await fromHost?.close?.();
93
+ await servers?.shutdown();
94
+ },
95
+ };
96
+ return sharedParts;
97
+ },
98
+ session: session ??
99
+ ((ctx) => defaultCapabilities({
100
+ shared: sessionSharedParts(sharedParts, sharedSkillsWorkDir, ctx.workDir),
101
+ ownEnvironment: ctx.ownEnvironment,
102
+ // `createSession({ mcpServers })` — layered over the process-shared connections.
103
+ ...(ctx.mcpServers !== undefined ? { sessionMcpServers: ctx.mcpServers } : {}),
104
+ ...(maxContextTokens !== undefined ? { maxContextTokens } : {}),
105
+ ...(pluginManager !== undefined ? { pluginManager } : {}),
106
+ ...(hooks !== undefined ? { hooks } : {}),
45
107
  })),
46
108
  // Cron rides the extension channel now: LOCAL deployments attach it, the server profile
47
109
  // simply doesn't — Invariant 7 ("cron is local-only") is structural, not an option to pass.
48
- extensions: [cronExtension(), ...(options.extensions ?? [])],
110
+ extensions: [cronExtension(), ...(extensions ?? [])],
49
111
  };
50
112
  }
113
+ /**
114
+ * The local entry point: one harness per process, one `createSession()` per conversation on it.
115
+ * Its `close()` closes those sessions and then the harness scope — the cron timer, the workspace
116
+ * MCP connections and the rotating log handle all live there, so nothing else tears them down.
117
+ */
51
118
  export async function createLocalHarness(options) {
52
119
  return createHarness(await localHarnessOptions(options));
53
120
  }
54
- /** Convenience: a local harness with one session opened and ready to `prompt()`. */
55
- export async function createLocalSession(options, session = {}) {
56
- return (await createLocalHarness(options)).createSession(session);
121
+ /** The shared parts a session may reuse: all of them, less a skill catalog scanned for another workDir. */
122
+ function sessionSharedParts(parts, skillsWorkDir, workDir) {
123
+ if (skillsWorkDir === undefined || resolve(workDir) === skillsWorkDir)
124
+ return parts;
125
+ const { skillRegistry: _skillRegistry, ...rest } = parts;
126
+ return rest;
57
127
  }
58
128
  //# sourceMappingURL=local.js.map
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Model providers configured by the host, as opposed to the ones the engine ships with.
3
+ *
4
+ * The built-in catalog knows every major provider, but each of those is a fixed list at a fixed
5
+ * URL. A self-hosted endpoint — vLLM, Ollama, LiteLLM, a gateway, a proxy in front of a vendor —
6
+ * is neither: its address is local knowledge, and which models it serves is a question only that
7
+ * endpoint can answer. So a provider here is a URL plus how to authenticate, and its model list is
8
+ * fetched from the endpoint (`GET {baseUrl}/models`, the OpenAI-compatible shape every one of them
9
+ * speaks) rather than declared.
10
+ *
11
+ * The file is `<homeDir>/providers.toml`, so every local host — the TUI, the app server, a script
12
+ * that builds its own harness — sees the same providers without each inventing a config format.
13
+ * Nothing else in the framework reads it: this is the provider registry, not a general config.
14
+ *
15
+ * ```toml
16
+ * # A self-hosted endpoint. Models come from GET http://localhost:8000/v1/models.
17
+ * [providers.local]
18
+ * base_url = "http://localhost:8000/v1"
19
+ * api_key_env = "LOCAL_API_KEY" # optional; omit for a keyless server
20
+ * context_window = 128000 # the default applied to every model it reports
21
+ *
22
+ * # Per-model facts the endpoint does not report.
23
+ * [providers.local.models."qwen3-coder"]
24
+ * name = "Qwen3 Coder"
25
+ * context_window = 256000
26
+ * reasoning = true
27
+ *
28
+ * # A provider whose models are declared rather than fetched.
29
+ * [providers.corp]
30
+ * base_url = "https://llm.corp.internal/v1"
31
+ * api_key_env = "CORP_API_KEY"
32
+ * fetch_models = false
33
+ * [providers.corp.models."gpt-4o-mini"]
34
+ * context_window = 128000
35
+ * ```
36
+ */
37
+ import { z } from "zod";
38
+ import { type Api, type ModelRuntime } from "operon-agents-core";
39
+ /** The wire dialects a configured endpoint can speak. Almost everything speaks the first. */
40
+ export declare const PROVIDER_APIS: readonly ["openai-completions", "openai-responses", "anthropic-messages"];
41
+ export type ProviderApi = (typeof PROVIDER_APIS)[number];
42
+ declare const ProviderEntrySchema: z.ZodObject<{
43
+ base_url: z.ZodString;
44
+ name: z.ZodOptional<z.ZodString>;
45
+ api: z.ZodDefault<z.ZodEnum<{
46
+ "openai-completions": "openai-completions";
47
+ "openai-responses": "openai-responses";
48
+ "anthropic-messages": "anthropic-messages";
49
+ }>>;
50
+ api_key_env: z.ZodOptional<z.ZodString>;
51
+ api_key: z.ZodOptional<z.ZodString>;
52
+ fetch_models: z.ZodDefault<z.ZodBoolean>;
53
+ context_window: z.ZodDefault<z.ZodNumber>;
54
+ max_output_tokens: z.ZodDefault<z.ZodNumber>;
55
+ reasoning: z.ZodDefault<z.ZodBoolean>;
56
+ vision: z.ZodDefault<z.ZodBoolean>;
57
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
58
+ models: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
59
+ name: z.ZodOptional<z.ZodString>;
60
+ context_window: z.ZodOptional<z.ZodNumber>;
61
+ max_output_tokens: z.ZodOptional<z.ZodNumber>;
62
+ reasoning: z.ZodOptional<z.ZodBoolean>;
63
+ vision: z.ZodOptional<z.ZodBoolean>;
64
+ api: z.ZodOptional<z.ZodEnum<{
65
+ "openai-completions": "openai-completions";
66
+ "openai-responses": "openai-responses";
67
+ "anthropic-messages": "anthropic-messages";
68
+ }>>;
69
+ }, z.core.$strip>>>;
70
+ }, z.core.$strip>;
71
+ export declare const ProvidersFileSchema: z.ZodObject<{
72
+ providers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
73
+ base_url: z.ZodString;
74
+ name: z.ZodOptional<z.ZodString>;
75
+ api: z.ZodDefault<z.ZodEnum<{
76
+ "openai-completions": "openai-completions";
77
+ "openai-responses": "openai-responses";
78
+ "anthropic-messages": "anthropic-messages";
79
+ }>>;
80
+ api_key_env: z.ZodOptional<z.ZodString>;
81
+ api_key: z.ZodOptional<z.ZodString>;
82
+ fetch_models: z.ZodDefault<z.ZodBoolean>;
83
+ context_window: z.ZodDefault<z.ZodNumber>;
84
+ max_output_tokens: z.ZodDefault<z.ZodNumber>;
85
+ reasoning: z.ZodDefault<z.ZodBoolean>;
86
+ vision: z.ZodDefault<z.ZodBoolean>;
87
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
88
+ models: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
89
+ name: z.ZodOptional<z.ZodString>;
90
+ context_window: z.ZodOptional<z.ZodNumber>;
91
+ max_output_tokens: z.ZodOptional<z.ZodNumber>;
92
+ reasoning: z.ZodOptional<z.ZodBoolean>;
93
+ vision: z.ZodOptional<z.ZodBoolean>;
94
+ api: z.ZodOptional<z.ZodEnum<{
95
+ "openai-completions": "openai-completions";
96
+ "openai-responses": "openai-responses";
97
+ "anthropic-messages": "anthropic-messages";
98
+ }>>;
99
+ }, z.core.$strip>>>;
100
+ }, z.core.$strip>>>;
101
+ }, z.core.$strip>;
102
+ export type ProviderEntry = z.infer<typeof ProviderEntrySchema>;
103
+ export type ProvidersFile = z.infer<typeof ProvidersFileSchema>;
104
+ export interface LoadedProviders {
105
+ readonly providers: Readonly<Record<string, ProviderEntry>>;
106
+ /** Problems that did not stop the load: a malformed entry, an unreadable file. */
107
+ readonly warnings: readonly string[];
108
+ }
109
+ export declare function providersConfigPath(homeDir: string): string;
110
+ /**
111
+ * Read `<homeDir>/providers.toml`. A missing file is the normal case and yields no providers; a
112
+ * malformed one yields none plus a warning, because refusing to start over a config file the host
113
+ * may not even use would be worse than running with the built-in providers alone.
114
+ */
115
+ export declare function loadProviderConfigs(homeDir: string): Promise<LoadedProviders>;
116
+ /** The model ids an OpenAI-compatible `/models` response lists, in the order the endpoint gave. */
117
+ export declare function parseModelsResponse(body: unknown): readonly string[];
118
+ /**
119
+ * Turn one config entry into a provider the engine can stream through. Its model list starts at
120
+ * whatever the config declared and is replaced by the endpoint's on the first refresh.
121
+ */
122
+ export declare function providerFromConfig(providerId: string, entry: ProviderEntry): import("@earendil-works/pi-ai").Provider<Api>;
123
+ export interface ModelRuntimeFromConfigOptions {
124
+ readonly homeDir: string;
125
+ /**
126
+ * Ask each configured endpoint for its models. Default true. With it off the runtime carries
127
+ * only what the config declared, which is what an offline start wants.
128
+ */
129
+ readonly refresh?: boolean;
130
+ /** Per-endpoint budget for the model-list fetch. Default 5s: a dead endpoint must not hang startup. */
131
+ readonly refreshTimeoutMs?: number;
132
+ readonly onWarning?: (message: string) => void;
133
+ }
134
+ /**
135
+ * One model runtime carrying the engine's built-in providers plus everything in
136
+ * `<homeDir>/providers.toml`, with each configured endpoint asked what it serves.
137
+ *
138
+ * Hand the same runtime to `defineModel({ provider, model, runtime })` and to
139
+ * `createLocalHarness({ modelRuntime })`, so the model a host resolves and the models its sessions
140
+ * can switch to come from one registry.
141
+ */
142
+ export declare function createModelRuntimeFromConfig(options: ModelRuntimeFromConfigOptions): Promise<ModelRuntime>;
143
+ export {};
144
+ //# sourceMappingURL=providers.d.ts.map