ai-runtime-engine 1.1.0

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.
Files changed (269) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/LICENSE +15 -0
  3. package/README.md +489 -0
  4. package/dist/artifacts/artifacts.d.ts +28 -0
  5. package/dist/artifacts/artifacts.js +46 -0
  6. package/dist/benchmark/benchmark.d.ts +23 -0
  7. package/dist/benchmark/benchmark.js +40 -0
  8. package/dist/cli/cli.d.ts +6 -0
  9. package/dist/cli/cli.js +161 -0
  10. package/dist/cli/commands/cleanup.d.ts +47 -0
  11. package/dist/cli/commands/cleanup.js +96 -0
  12. package/dist/cli/commands/config.d.ts +8 -0
  13. package/dist/cli/commands/config.js +28 -0
  14. package/dist/cli/commands/doctor.d.ts +57 -0
  15. package/dist/cli/commands/doctor.js +86 -0
  16. package/dist/cli/commands/executions.d.ts +9 -0
  17. package/dist/cli/commands/executions.js +25 -0
  18. package/dist/cli/commands/info.d.ts +43 -0
  19. package/dist/cli/commands/info.js +53 -0
  20. package/dist/cli/commands/init.d.ts +5 -0
  21. package/dist/cli/commands/init.js +75 -0
  22. package/dist/cli/commands/inspect.d.ts +16 -0
  23. package/dist/cli/commands/inspect.js +60 -0
  24. package/dist/cli/commands/phase2.d.ts +22 -0
  25. package/dist/cli/commands/phase2.js +83 -0
  26. package/dist/cli/commands/route.d.ts +14 -0
  27. package/dist/cli/commands/route.js +49 -0
  28. package/dist/cli/commands/run.d.ts +11 -0
  29. package/dist/cli/commands/run.js +37 -0
  30. package/dist/cli/commands/setup.d.ts +34 -0
  31. package/dist/cli/commands/setup.js +104 -0
  32. package/dist/cli/commands/skills.d.ts +28 -0
  33. package/dist/cli/commands/skills.js +48 -0
  34. package/dist/cli/commands/test.d.ts +7 -0
  35. package/dist/cli/commands/test.js +29 -0
  36. package/dist/cli/context.d.ts +12 -0
  37. package/dist/cli/context.js +16 -0
  38. package/dist/cli/interactive/repl.d.ts +6 -0
  39. package/dist/cli/interactive/repl.js +45 -0
  40. package/dist/cli/interactive/session.d.ts +36 -0
  41. package/dist/cli/interactive/session.js +356 -0
  42. package/dist/cli/prompt.d.ts +6 -0
  43. package/dist/cli/prompt.js +18 -0
  44. package/dist/cli/render.d.ts +7 -0
  45. package/dist/cli/render.js +14 -0
  46. package/dist/comparison/analysis.d.ts +46 -0
  47. package/dist/comparison/analysis.js +177 -0
  48. package/dist/comparison/comparator.d.ts +46 -0
  49. package/dist/comparison/comparator.js +270 -0
  50. package/dist/comparison/comparison.d.ts +140 -0
  51. package/dist/comparison/comparison.js +9 -0
  52. package/dist/comparison/render.d.ts +7 -0
  53. package/dist/comparison/render.js +66 -0
  54. package/dist/config/defaults.d.ts +52 -0
  55. package/dist/config/defaults.js +56 -0
  56. package/dist/config/load.d.ts +17 -0
  57. package/dist/config/load.js +50 -0
  58. package/dist/config/providerDefaults.d.ts +17 -0
  59. package/dist/config/providerDefaults.js +61 -0
  60. package/dist/config/schema.d.ts +9 -0
  61. package/dist/config/schema.js +78 -0
  62. package/dist/context/budget.d.ts +13 -0
  63. package/dist/context/budget.js +17 -0
  64. package/dist/context/compiler.d.ts +61 -0
  65. package/dist/context/compiler.js +125 -0
  66. package/dist/context/tokens.d.ts +19 -0
  67. package/dist/context/tokens.js +38 -0
  68. package/dist/conversations/conversations.d.ts +38 -0
  69. package/dist/conversations/conversations.js +64 -0
  70. package/dist/core/capabilities/evidence.d.ts +40 -0
  71. package/dist/core/capabilities/evidence.js +102 -0
  72. package/dist/core/capabilities/overlay.d.ts +15 -0
  73. package/dist/core/capabilities/overlay.js +0 -0
  74. package/dist/core/capabilities/taxonomy.d.ts +19 -0
  75. package/dist/core/capabilities/taxonomy.js +25 -0
  76. package/dist/core/fallback/errors.d.ts +30 -0
  77. package/dist/core/fallback/errors.js +80 -0
  78. package/dist/core/fallback/fallback.d.ts +40 -0
  79. package/dist/core/fallback/fallback.js +82 -0
  80. package/dist/core/fallback/retryPolicy.d.ts +11 -0
  81. package/dist/core/fallback/retryPolicy.js +14 -0
  82. package/dist/core/health/health.d.ts +3 -0
  83. package/dist/core/health/health.js +5 -0
  84. package/dist/core/health/monitor.d.ts +23 -0
  85. package/dist/core/health/monitor.js +82 -0
  86. package/dist/core/policies/budget.d.ts +19 -0
  87. package/dist/core/policies/budget.js +37 -0
  88. package/dist/core/registry/builtinTasks.d.ts +8 -0
  89. package/dist/core/registry/builtinTasks.js +54 -0
  90. package/dist/core/registry/registry.d.ts +18 -0
  91. package/dist/core/registry/registry.js +33 -0
  92. package/dist/core/registry/taskRegistry.d.ts +15 -0
  93. package/dist/core/registry/taskRegistry.js +30 -0
  94. package/dist/core/router/confidence.d.ts +7 -0
  95. package/dist/core/router/confidence.js +20 -0
  96. package/dist/core/router/dimensions.d.ts +16 -0
  97. package/dist/core/router/dimensions.js +60 -0
  98. package/dist/core/router/executor.d.ts +16 -0
  99. package/dist/core/router/executor.js +25 -0
  100. package/dist/core/router/filter.d.ts +34 -0
  101. package/dist/core/router/filter.js +113 -0
  102. package/dist/core/router/normalize.d.ts +30 -0
  103. package/dist/core/router/normalize.js +119 -0
  104. package/dist/core/router/request.d.ts +4 -0
  105. package/dist/core/router/request.js +21 -0
  106. package/dist/core/router/router.d.ts +32 -0
  107. package/dist/core/router/router.js +195 -0
  108. package/dist/core/router/routingPrefs.d.ts +11 -0
  109. package/dist/core/router/routingPrefs.js +30 -0
  110. package/dist/core/router/scorer.d.ts +19 -0
  111. package/dist/core/router/scorer.js +50 -0
  112. package/dist/core/router/weights.d.ts +9 -0
  113. package/dist/core/router/weights.js +31 -0
  114. package/dist/core/validation/validator.d.ts +16 -0
  115. package/dist/core/validation/validator.js +33 -0
  116. package/dist/discovery/modelCatalog.d.ts +28 -0
  117. package/dist/discovery/modelCatalog.js +105 -0
  118. package/dist/discovery/openapi.d.ts +25 -0
  119. package/dist/discovery/openapi.js +76 -0
  120. package/dist/executions/checkpoint.d.ts +26 -0
  121. package/dist/executions/checkpoint.js +114 -0
  122. package/dist/executions/execution.d.ts +51 -0
  123. package/dist/executions/execution.js +8 -0
  124. package/dist/executions/store.d.ts +52 -0
  125. package/dist/executions/store.js +124 -0
  126. package/dist/generation/generateAdapter.d.ts +17 -0
  127. package/dist/generation/generateAdapter.js +30 -0
  128. package/dist/index.d.ts +147 -0
  129. package/dist/index.js +107 -0
  130. package/dist/learning/feedback.d.ts +9 -0
  131. package/dist/learning/feedback.js +18 -0
  132. package/dist/learning/learningStore.d.ts +68 -0
  133. package/dist/learning/learningStore.js +138 -0
  134. package/dist/learning/performanceStore.d.ts +27 -0
  135. package/dist/learning/performanceStore.js +0 -0
  136. package/dist/marketplace/presets.d.ts +24 -0
  137. package/dist/marketplace/presets.js +52 -0
  138. package/dist/mcp/mcp.d.ts +31 -0
  139. package/dist/mcp/mcp.js +54 -0
  140. package/dist/memory/bm25.d.ts +16 -0
  141. package/dist/memory/bm25.js +56 -0
  142. package/dist/memory/classifier.d.ts +14 -0
  143. package/dist/memory/classifier.js +17 -0
  144. package/dist/memory/memory.d.ts +80 -0
  145. package/dist/memory/memory.js +191 -0
  146. package/dist/orchestration/executor.d.ts +35 -0
  147. package/dist/orchestration/executor.js +65 -0
  148. package/dist/orchestration/orchestrator.d.ts +42 -0
  149. package/dist/orchestration/orchestrator.js +63 -0
  150. package/dist/orchestration/plan.d.ts +37 -0
  151. package/dist/orchestration/plan.js +70 -0
  152. package/dist/orchestration/planner.d.ts +29 -0
  153. package/dist/orchestration/planner.js +69 -0
  154. package/dist/plugin/ai.d.ts +82 -0
  155. package/dist/plugin/ai.js +167 -0
  156. package/dist/probing/probe.d.ts +25 -0
  157. package/dist/probing/probe.js +63 -0
  158. package/dist/providers/factory.d.ts +18 -0
  159. package/dist/providers/factory.js +54 -0
  160. package/dist/providers/httpClient.d.ts +34 -0
  161. package/dist/providers/httpClient.js +80 -0
  162. package/dist/providers/httpProvider.d.ts +49 -0
  163. package/dist/providers/httpProvider.js +135 -0
  164. package/dist/providers/mock/demo.d.ts +13 -0
  165. package/dist/providers/mock/demo.js +58 -0
  166. package/dist/providers/mock/mockProvider.d.ts +35 -0
  167. package/dist/providers/mock/mockProvider.js +121 -0
  168. package/dist/providers/mock/scenarios.d.ts +44 -0
  169. package/dist/providers/mock/scenarios.js +30 -0
  170. package/dist/providers/provider.d.ts +26 -0
  171. package/dist/providers/provider.js +11 -0
  172. package/dist/providers/wire/anthropicWire.d.ts +6 -0
  173. package/dist/providers/wire/anthropicWire.js +83 -0
  174. package/dist/providers/wire/openaiWire.d.ts +7 -0
  175. package/dist/providers/wire/openaiWire.js +81 -0
  176. package/dist/providers/wire/registry.d.ts +8 -0
  177. package/dist/providers/wire/registry.js +20 -0
  178. package/dist/providers/wire/types.d.ts +39 -0
  179. package/dist/providers/wire/types.js +24 -0
  180. package/dist/runtime/config.d.ts +31 -0
  181. package/dist/runtime/config.js +121 -0
  182. package/dist/runtime/context.d.ts +34 -0
  183. package/dist/runtime/context.js +11 -0
  184. package/dist/runtime/events.d.ts +99 -0
  185. package/dist/runtime/events.js +82 -0
  186. package/dist/runtime/host.d.ts +27 -0
  187. package/dist/runtime/host.js +7 -0
  188. package/dist/runtime/intent/classifier.d.ts +30 -0
  189. package/dist/runtime/intent/classifier.js +60 -0
  190. package/dist/runtime/intent/signals.d.ts +19 -0
  191. package/dist/runtime/intent/signals.js +46 -0
  192. package/dist/runtime/modes/availability.d.ts +11 -0
  193. package/dist/runtime/modes/availability.js +17 -0
  194. package/dist/runtime/modes/chat.d.ts +18 -0
  195. package/dist/runtime/modes/chat.js +67 -0
  196. package/dist/runtime/modes/modeResolver.d.ts +43 -0
  197. package/dist/runtime/modes/modeResolver.js +78 -0
  198. package/dist/runtime/policy.d.ts +72 -0
  199. package/dist/runtime/policy.js +59 -0
  200. package/dist/runtime/providerView.d.ts +62 -0
  201. package/dist/runtime/providerView.js +105 -0
  202. package/dist/runtime/routing.d.ts +26 -0
  203. package/dist/runtime/routing.js +65 -0
  204. package/dist/runtime/runtime.d.ts +191 -0
  205. package/dist/runtime/runtime.js +718 -0
  206. package/dist/runtime/types.d.ts +153 -0
  207. package/dist/runtime/types.js +9 -0
  208. package/dist/runtime/workspace/detectors.d.ts +15 -0
  209. package/dist/runtime/workspace/detectors.js +57 -0
  210. package/dist/runtime/workspace/workspace.d.ts +29 -0
  211. package/dist/runtime/workspace/workspace.js +116 -0
  212. package/dist/security/credentials.d.ts +26 -0
  213. package/dist/security/credentials.js +34 -0
  214. package/dist/security/redact.d.ts +16 -0
  215. package/dist/security/redact.js +57 -0
  216. package/dist/skills/builtins/fileAnalyzer.d.ts +7 -0
  217. package/dist/skills/builtins/fileAnalyzer.js +47 -0
  218. package/dist/skills/builtins/repositoryAnalyzer.d.ts +6 -0
  219. package/dist/skills/builtins/repositoryAnalyzer.js +47 -0
  220. package/dist/skills/discovery.d.ts +61 -0
  221. package/dist/skills/discovery.js +211 -0
  222. package/dist/skills/manifest.d.ts +30 -0
  223. package/dist/skills/manifest.js +75 -0
  224. package/dist/skills/registry.d.ts +15 -0
  225. package/dist/skills/registry.js +22 -0
  226. package/dist/skills/skill.d.ts +64 -0
  227. package/dist/skills/skill.js +8 -0
  228. package/dist/store/area.d.ts +54 -0
  229. package/dist/store/area.js +164 -0
  230. package/dist/store/paths.d.ts +15 -0
  231. package/dist/store/paths.js +48 -0
  232. package/dist/store/store.d.ts +59 -0
  233. package/dist/store/store.js +140 -0
  234. package/dist/telemetry/sinks/file.d.ts +12 -0
  235. package/dist/telemetry/sinks/file.js +28 -0
  236. package/dist/telemetry/telemetry.d.ts +36 -0
  237. package/dist/telemetry/telemetry.js +63 -0
  238. package/dist/tools/builtins/filesystem.d.ts +7 -0
  239. package/dist/tools/builtins/filesystem.js +53 -0
  240. package/dist/tools/builtins/git.d.ts +10 -0
  241. package/dist/tools/builtins/git.js +66 -0
  242. package/dist/tools/builtins/shell.d.ts +17 -0
  243. package/dist/tools/builtins/shell.js +91 -0
  244. package/dist/tools/jail.d.ts +12 -0
  245. package/dist/tools/jail.js +98 -0
  246. package/dist/tools/permissions.d.ts +25 -0
  247. package/dist/tools/permissions.js +24 -0
  248. package/dist/tools/registry.d.ts +10 -0
  249. package/dist/tools/registry.js +20 -0
  250. package/dist/tools/runner.d.ts +23 -0
  251. package/dist/tools/runner.js +64 -0
  252. package/dist/tools/tool.d.ts +53 -0
  253. package/dist/tools/tool.js +24 -0
  254. package/dist/tools/untrusted.d.ts +13 -0
  255. package/dist/tools/untrusted.js +30 -0
  256. package/dist/types.d.ts +460 -0
  257. package/dist/types.js +12 -0
  258. package/dist/util/clock.d.ts +6 -0
  259. package/dist/util/clock.js +4 -0
  260. package/dist/util/extractJson.d.ts +8 -0
  261. package/dist/util/extractJson.js +54 -0
  262. package/dist/verification/verify.d.ts +26 -0
  263. package/dist/verification/verify.js +67 -0
  264. package/docs/GUIDE.md +358 -0
  265. package/docs/README.md +21 -0
  266. package/docs/architecture.md +78 -0
  267. package/docs/router.md +376 -0
  268. package/docs/security.md +55 -0
  269. package/package.json +67 -0
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Provider/model inspection views for the interactive surfaces. Distinguishes cataloged (documented)
3
+ * vs accessible (health-derived) vs capability-verified (probed) state, and derives a display-only
4
+ * `AccessState` from the FROZEN `HealthState` enum (the enum is never modified). A freshness cache keeps
5
+ * a chatty REPL from re-hitting providers on every command; stale records display as ACCESS_UNKNOWN and
6
+ * never count as proof of usability.
7
+ */
8
+ import { systemClock } from '../util/clock.js';
9
+ /** Map a HealthState to an AccessState. Exhaustive over the 12 frozen states (compile-checked). */
10
+ export function deriveAccessState(state) {
11
+ switch (state) {
12
+ case 'NOT_CONFIGURED':
13
+ return 'NOT_CONFIGURED';
14
+ case 'CONFIGURED':
15
+ return 'CONFIGURED';
16
+ case 'AVAILABLE':
17
+ return 'AVAILABLE';
18
+ case 'DEGRADED':
19
+ return 'DEGRADED';
20
+ case 'RATE_LIMITED':
21
+ return 'RATE_LIMITED';
22
+ case 'QUOTA_EXCEEDED':
23
+ return 'QUOTA_EXCEEDED';
24
+ case 'AUTH_FAILED':
25
+ return 'AUTH_FAILED';
26
+ case 'NETWORK_ERROR':
27
+ return 'DEGRADED';
28
+ case 'MODEL_UNAVAILABLE':
29
+ return 'MODEL_UNAVAILABLE';
30
+ case 'CAPABILITY_MISMATCH':
31
+ return 'DEGRADED';
32
+ case 'DISABLED':
33
+ return 'CONFIGURED';
34
+ case 'UNKNOWN':
35
+ return 'ACCESS_UNKNOWN';
36
+ }
37
+ }
38
+ const GROUPS = ['input', 'output', 'intelligence', 'agent'];
39
+ function hasVerifiedCapability(profile) {
40
+ for (const group of GROUPS) {
41
+ const bucket = profile[group];
42
+ for (const cap of Object.values(bucket))
43
+ if (cap.evidence === 'verified')
44
+ return true;
45
+ }
46
+ return profile.context.contextWindow.evidence === 'verified';
47
+ }
48
+ /** Build a joined provider/model view. Live: calls checkHealth() + discover(). */
49
+ export async function buildProviderViews(source, opts) {
50
+ const ttlMs = opts.ttlMs ?? 60_000;
51
+ const [health, metas] = await Promise.all([source.checkHealth(), source.discover()]);
52
+ const healthById = new Map(health.map((h) => [h.providerId, h]));
53
+ const metaById = new Map(metas.map((m) => [m.id, m]));
54
+ return source.providers().map((p) => {
55
+ const h = healthById.get(p.id);
56
+ const meta = metaById.get(p.id);
57
+ const models = (meta?.models ?? []).map((m) => ({
58
+ id: m.id,
59
+ cataloged: m.source !== 'unknown',
60
+ verified: hasVerifiedCapability(m.capabilities),
61
+ ...(m.contextWindow !== undefined ? { contextWindow: m.contextWindow } : {}),
62
+ ...(m.quality?.tier ? { quality: m.quality.tier } : {}),
63
+ source: m.source,
64
+ }));
65
+ const healthState = h?.state ?? 'UNKNOWN';
66
+ // A positive checkedAt is a real self-reported timestamp; 0/undefined means "no timestamp" — since
67
+ // buildProviderViews just called checkHealth() live, treat that as fresh, not ancient.
68
+ const checkedAt = h?.checkedAt !== undefined && h.checkedAt > 0 ? h.checkedAt : undefined;
69
+ const ageMs = checkedAt !== undefined ? Math.max(0, opts.now - checkedAt) : undefined;
70
+ const stale = ageMs !== undefined ? ageMs > ttlMs : false;
71
+ const accessState = stale ? 'ACCESS_UNKNOWN' : deriveAccessState(healthState);
72
+ return {
73
+ id: p.id,
74
+ name: p.name,
75
+ kind: p.kind,
76
+ enabled: p.enabled,
77
+ accessState,
78
+ healthState,
79
+ ...(checkedAt !== undefined ? { checkedAt } : {}),
80
+ ...(ageMs !== undefined ? { ageMs } : {}),
81
+ stale,
82
+ models,
83
+ };
84
+ });
85
+ }
86
+ /** Memoizes provider views for a ttl so a long-lived REPL doesn't re-hit providers on every command. */
87
+ export class ProviderViewCache {
88
+ source;
89
+ clock;
90
+ ttlMs;
91
+ last;
92
+ constructor(source, options = {}) {
93
+ this.source = source;
94
+ this.clock = options.clock ?? systemClock;
95
+ this.ttlMs = options.ttlMs ?? 60_000;
96
+ }
97
+ async get(force = false) {
98
+ const now = this.clock.now();
99
+ if (!force && this.last && now - this.last.at < this.ttlMs)
100
+ return this.last.views;
101
+ const views = await buildProviderViews(this.source, { now, ttlMs: this.ttlMs });
102
+ this.last = { at: now, views };
103
+ return views;
104
+ }
105
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Runtime routing-preference resolution. Exclude/prefer come from three sources — env
3
+ * (`AI_EXCLUDE_PROVIDERS`/`AI_EXCLUDE_MODELS`/`AI_PREFER_PROVIDERS`/`AI_PREFER_MODELS`, comma-separated),
4
+ * project config (`routing:`), and per-run — and are UNIONed across all three. Union (not replace) is the
5
+ * safe choice for exclusions: an exclusion set at any level always holds, so a higher-precedence source
6
+ * can never silently re-admit something a lower one excluded. Preferences union too (harmless, soft).
7
+ */
8
+ import type { RoutingPreferences } from '../types.js';
9
+ export interface RoutingSources {
10
+ env?: NodeJS.ProcessEnv;
11
+ config?: RoutingPreferences;
12
+ perRun?: RoutingPreferences;
13
+ }
14
+ /** Resolve effective routing prefs by unioning env + config + per-run. Returns undefined when nothing is set. */
15
+ export declare function resolveRoutingPrefs(sources: RoutingSources): RoutingPreferences | undefined;
16
+ /**
17
+ * Fold learned soft-prefer providers into a routing prefs object. An excluded provider is NEVER added
18
+ * back (belt-and-suspenders with the filter's hard gate) — so learning can never re-admit an exclusion.
19
+ */
20
+ export declare function withPreferredProviders(base: RoutingPreferences | undefined, providers: string[]): RoutingPreferences | undefined;
21
+ /**
22
+ * Union two routing-prefs objects. Exclusions are a FLOOR — the union always keeps every exclusion from
23
+ * either side, so a lower-priority `override` (e.g. a caller's escape-hatch request.routing) can add
24
+ * preferences but can NEVER drop a resolved exclusion. Returns undefined when both are empty/undefined.
25
+ */
26
+ export declare function mergeRouting(base: RoutingPreferences | undefined, override: RoutingPreferences | undefined): RoutingPreferences | undefined;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Runtime routing-preference resolution. Exclude/prefer come from three sources — env
3
+ * (`AI_EXCLUDE_PROVIDERS`/`AI_EXCLUDE_MODELS`/`AI_PREFER_PROVIDERS`/`AI_PREFER_MODELS`, comma-separated),
4
+ * project config (`routing:`), and per-run — and are UNIONed across all three. Union (not replace) is the
5
+ * safe choice for exclusions: an exclusion set at any level always holds, so a higher-precedence source
6
+ * can never silently re-admit something a lower one excluded. Preferences union too (harmless, soft).
7
+ */
8
+ function csv(v) {
9
+ return (v ?? '').split(',').map((s) => s.trim()).filter(Boolean);
10
+ }
11
+ function union(...lists) {
12
+ const seen = new Set();
13
+ const out = [];
14
+ for (const list of lists)
15
+ for (const x of list ?? [])
16
+ if (!seen.has(x)) {
17
+ seen.add(x);
18
+ out.push(x);
19
+ }
20
+ return out;
21
+ }
22
+ /** Resolve effective routing prefs by unioning env + config + per-run. Returns undefined when nothing is set. */
23
+ export function resolveRoutingPrefs(sources) {
24
+ const env = sources.env ?? {};
25
+ const excludeProviders = union(csv(env.AI_EXCLUDE_PROVIDERS), sources.config?.excludeProviders, sources.perRun?.excludeProviders);
26
+ const excludeModels = union(csv(env.AI_EXCLUDE_MODELS), sources.config?.excludeModels, sources.perRun?.excludeModels);
27
+ const preferProviders = union(csv(env.AI_PREFER_PROVIDERS), sources.config?.preferProviders, sources.perRun?.preferProviders);
28
+ const preferModels = union(csv(env.AI_PREFER_MODELS), sources.config?.preferModels, sources.perRun?.preferModels);
29
+ const prefs = {
30
+ ...(excludeProviders.length ? { excludeProviders } : {}),
31
+ ...(excludeModels.length ? { excludeModels } : {}),
32
+ ...(preferProviders.length ? { preferProviders } : {}),
33
+ ...(preferModels.length ? { preferModels } : {}),
34
+ };
35
+ return Object.keys(prefs).length ? prefs : undefined;
36
+ }
37
+ /**
38
+ * Fold learned soft-prefer providers into a routing prefs object. An excluded provider is NEVER added
39
+ * back (belt-and-suspenders with the filter's hard gate) — so learning can never re-admit an exclusion.
40
+ */
41
+ export function withPreferredProviders(base, providers) {
42
+ const excluded = new Set(base?.excludeProviders ?? []);
43
+ const add = providers.filter((p) => !excluded.has(p));
44
+ if (!add.length)
45
+ return base;
46
+ return { ...(base ?? {}), preferProviders: union(base?.preferProviders, add) };
47
+ }
48
+ /**
49
+ * Union two routing-prefs objects. Exclusions are a FLOOR — the union always keeps every exclusion from
50
+ * either side, so a lower-priority `override` (e.g. a caller's escape-hatch request.routing) can add
51
+ * preferences but can NEVER drop a resolved exclusion. Returns undefined when both are empty/undefined.
52
+ */
53
+ export function mergeRouting(base, override) {
54
+ if (!base)
55
+ return override;
56
+ if (!override)
57
+ return base;
58
+ const merged = {
59
+ ...(union(base.excludeProviders, override.excludeProviders).length ? { excludeProviders: union(base.excludeProviders, override.excludeProviders) } : {}),
60
+ ...(union(base.excludeModels, override.excludeModels).length ? { excludeModels: union(base.excludeModels, override.excludeModels) } : {}),
61
+ ...(union(base.preferProviders, override.preferProviders).length ? { preferProviders: union(base.preferProviders, override.preferProviders) } : {}),
62
+ ...(union(base.preferModels, override.preferModels).length ? { preferModels: union(base.preferModels, override.preferModels) } : {}),
63
+ };
64
+ return Object.keys(merged).length ? merged : undefined;
65
+ }
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Runtime — the high-level facade OVER the existing `AI` router. It resolves a mode + policy, assembles
3
+ * a RuntimeContext, executes chat through `AI.run()`, and streams redacted lifecycle events. It never
4
+ * routes or scores; all model selection stays in the one router. Unimplemented modes degrade to chat.
5
+ */
6
+ import { AI } from '../plugin/ai.js';
7
+ import type { AIOptions } from '../plugin/ai.js';
8
+ import type { WorkspaceInfo } from './workspace/workspace.js';
9
+ import type { IntentClassifier } from './intent/classifier.js';
10
+ import type { RuntimeEvent } from './events.js';
11
+ import type { RuntimeHost } from './host.js';
12
+ import { RuntimeStore } from '../store/store.js';
13
+ import { ConversationStore } from '../conversations/conversations.js';
14
+ import { MemoryStore } from '../memory/memory.js';
15
+ import type { Tool, ToolResult } from '../tools/tool.js';
16
+ import { resolvePermissions } from '../tools/permissions.js';
17
+ import type { Skill, SkillResult, SkillValidation, SkillPlan } from '../skills/skill.js';
18
+ import type { SkillSource, LoadedSource } from '../skills/discovery.js';
19
+ import { ExecutionStore } from '../executions/store.js';
20
+ import type { Execution } from '../executions/execution.js';
21
+ import { ArtifactStore } from '../artifacts/artifacts.js';
22
+ import type { CompareInput } from '../comparison/comparator.js';
23
+ import type { ComparisonResult } from '../comparison/comparison.js';
24
+ import { LearningStore } from '../learning/learningStore.js';
25
+ import type { FeedbackSignal } from '../learning/feedback.js';
26
+ import type { PermissionPolicy } from './policy.js';
27
+ import type { RuntimeConfig, RuntimeResult, RuntimeRunInput, RuntimeSettings } from './types.js';
28
+ export interface RuntimeOptions {
29
+ /** Workspace root; defaults to process.cwd(). */
30
+ workspace?: string;
31
+ /** Explicit config file path (bypasses discovery). */
32
+ config?: string;
33
+ /** Injection passed straight to the inner AI (fetchImpl, clock, env, sinks). */
34
+ ai?: AIOptions;
35
+ /** Intent classifier; defaults to the deterministic heuristic one. */
36
+ classifier?: IntentClassifier;
37
+ /** Detect workspace traits at load (default true). */
38
+ detectWorkspace?: boolean;
39
+ /** Host integration: event sink, credential resolver, workspace, approval (Phase 5). */
40
+ host?: RuntimeHost;
41
+ /** 'disabled' turns off all local persistence (conversations, memory) — for CI/tests/ephemeral use. */
42
+ persistence?: 'enabled' | 'disabled';
43
+ /** The config file actually resolved (set by Runtime.load; surfaced via `runtime.configFile`). */
44
+ configFile?: string;
45
+ }
46
+ export declare class Runtime {
47
+ private readonly _ai;
48
+ private readonly settingsValue;
49
+ private readonly classifier;
50
+ private readonly env;
51
+ private readonly workspace?;
52
+ private readonly emitter;
53
+ private readonly _store;
54
+ private readonly _memory;
55
+ private readonly _conversations;
56
+ private readonly estimator;
57
+ private readonly _tools;
58
+ private readonly _skills;
59
+ private readonly _executions;
60
+ private readonly _artifacts;
61
+ private readonly _learning;
62
+ private readonly workspaceRoot;
63
+ private readonly configPermissions;
64
+ private readonly approval?;
65
+ private readonly _configFile?;
66
+ private _loadedSkillSources;
67
+ constructor(config?: RuntimeConfig, options?: RuntimeOptions, workspace?: WorkspaceInfo);
68
+ /** Build a Runtime from a workspace: load config (.ai-runtime/config.yaml > root fallback), detect workspace. */
69
+ static load(options?: RuntimeOptions): Promise<Runtime>;
70
+ /**
71
+ * Load consented local skills — the conventional `.ai-runtime/skills/` dir plus any `skills.paths` in
72
+ * config — and register them. Manifests are data; module skills run the user's own code, which is why
73
+ * only these consented locations auto-load. Off when `skills.autoload: false`. Resilient: a broken
74
+ * source is recorded (see `skillSources()`), never fatal. Called by `Runtime.load`.
75
+ */
76
+ autoloadSkills(): Promise<void>;
77
+ /** What autoloadSkills loaded (or failed to), for `info`/`doctor`/`skills` reporting. */
78
+ skillSources(): LoadedSource[];
79
+ /** Scan the workspace for skill-looking files elsewhere (report only — nothing is loaded). */
80
+ discoverSkillCandidates(): SkillSource[];
81
+ /** Explicitly load chosen skill sources (e.g. candidates the user picked) and register them. */
82
+ loadSkillSources(sources: SkillSource[]): Promise<LoadedSource[]>;
83
+ /** The config file this runtime resolved (`.ai-runtime/config.yaml` or a fallback), if any. */
84
+ get configFile(): string | undefined;
85
+ /** The inner router facade — register providers/tasks/MCP sources here. */
86
+ get ai(): AI;
87
+ /** The local runtime store (conversations, memory, indexes, cache). */
88
+ get store(): RuntimeStore;
89
+ /** Durable scoped memory. */
90
+ get memory(): MemoryStore;
91
+ /** Persistent conversation history. */
92
+ get conversations(): ConversationStore;
93
+ private memoryEnabled;
94
+ /** Durable cross-run learning (provider/skill/workflow/plan outcomes; feeds soft prefer signals). */
95
+ get learning(): LearningStore;
96
+ private learningEnabled;
97
+ /**
98
+ * Effective exclude/prefer routing for a run: env + project config + per-run (unioned), then learned
99
+ * soft-prefer folded in — but never re-admitting an excluded provider. Learning stays subordinate to
100
+ * every hard gate (exclude/privacy/pin/capability/budget), which the router filter enforces.
101
+ */
102
+ private effectiveRouting;
103
+ /** Apply free-text feedback (e.g. "that worked" / "wrong root cause") to the most recent outcome. */
104
+ feedback(text: string, opts?: {
105
+ providerId?: string;
106
+ model?: string;
107
+ }): FeedbackSignal;
108
+ /** A coarse goal pattern (first few significant tokens) keying workflow/plan learning. */
109
+ private goalType;
110
+ /** Resolve exact-version SkillRefs for the skill steps of a plan (for skill/workflow learning). */
111
+ private planSkillRefs;
112
+ /** Register a tool. Chainable. */
113
+ registerTool(tool: Tool): this;
114
+ tools(): Tool[];
115
+ /** Register a skill. Chainable. */
116
+ registerSkill(skill: Skill): this;
117
+ /** Skills whose required tools are all registered. */
118
+ skills(): Skill[];
119
+ /** The resolved tool permissions for this runtime (config grants over deny-by-default defaults). */
120
+ permissions(): ReturnType<typeof resolvePermissions>;
121
+ private toolContext;
122
+ /** Invoke a registered tool with the runtime's resolved permissions + host approval. */
123
+ runTool(id: string, input: unknown, overrides?: {
124
+ permissions?: PermissionPolicy;
125
+ signal?: AbortSignal;
126
+ }): Promise<ToolResult>;
127
+ /** Run a skill end-to-end (plan → execute → validate) with tools bound to the runtime's permissions. */
128
+ runSkill(id: string, input: unknown, overrides?: {
129
+ permissions?: PermissionPolicy;
130
+ signal?: AbortSignal;
131
+ }): Promise<{
132
+ plan: SkillPlan;
133
+ result: SkillResult;
134
+ validation: SkillValidation;
135
+ }>;
136
+ workspaceInfo(): WorkspaceInfo | undefined;
137
+ settings(): Readonly<RuntimeSettings>;
138
+ /** Subscribe to runtime lifecycle events; returns an unsubscribe function. */
139
+ on(listener: (event: RuntimeEvent) => void): () => void;
140
+ /** Recent runtime events (redacted, metadata only). */
141
+ events(): RuntimeEvent[];
142
+ run(input: string | RuntimeRunInput): Promise<RuntimeResult>;
143
+ /** The persistent execution store and its owner-lease machinery. */
144
+ get executionStore(): ExecutionStore;
145
+ /** The artifact store (content owner behind ArtifactRef). */
146
+ get artifacts(): ArtifactStore;
147
+ /** Recent persisted executions, newest first. */
148
+ executions(): Execution[];
149
+ /** plan/execute/orchestrate/agent/debug: run the orchestrator and persist a resumable Execution. */
150
+ private runOrchestration;
151
+ /** Run `fn` while heartbeating the execution lease so a long run never lets the lease expire. */
152
+ private withHeartbeat;
153
+ private orchestrateInput;
154
+ /** Record an EXECUTED orchestration outcome for learning. plan-only, dry-run, and waiting states are
155
+ * skipped — no skill ran, so there is no success/failure to learn (recording them would teach noise). */
156
+ private recordOrchestration;
157
+ private execStatus;
158
+ private mapOutcome;
159
+ private resultFromExecution;
160
+ /**
161
+ * Compare a task across several models/providers and return a normalized comparison (agreement,
162
+ * differences, contradictions, missing info, and an EVIDENCE-first ranking). Runs entirely through the
163
+ * ONE router (`AI.run()` pins) — no second selection engine. Pass a `validate` for evidence-based
164
+ * ranking (beats any judge), or a `judge` pin for a labeled opinion; with neither it reports only.
165
+ */
166
+ compare(input: Omit<CompareInput, 'ai'>): Promise<ComparisonResult>;
167
+ /** compare mode: fan out over pins (default: every enabled, non-excluded provider) and render. Read-only. */
168
+ private runCompareMode;
169
+ /** Default compare pins: one per enabled, non-excluded provider (model left to the provider default). */
170
+ private defaultComparePins;
171
+ /**
172
+ * Resume a persisted execution: acquire its lease, reconcile the workspace, then continue (if
173
+ * unchanged) or replan (on drift) — never blindly. Answers a pending clarification/approval.
174
+ */
175
+ resumeExecution(id: string, opts?: {
176
+ clarificationAnswer?: string;
177
+ approve?: boolean;
178
+ signal?: AbortSignal;
179
+ }): Promise<RuntimeResult>;
180
+ private orchestrateRunners;
181
+ /** Mark an execution paused (it can be resumed later). */
182
+ pauseExecution(id: string): boolean;
183
+ /** Cancel an execution (terminal). */
184
+ cancelExecution(id: string): boolean;
185
+ /** Assemble the context blocks for a chat run: user system (critical), workspace (high), memory (normal). */
186
+ private contextBlocks;
187
+ /** Best-effort estimator calibration from provider-reported input usage (estimates never claim to be exact). */
188
+ private calibrate;
189
+ /** Capture an explicit "remember …" fact and retrieve relevant facts for context. Off when disabled. */
190
+ private applyMemory;
191
+ }