@oharness/engine 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/agent/agent.d.ts +83 -0
  2. package/dist/agent/agent.js +112 -1
  3. package/dist/agent/agent.js.map +1 -1
  4. package/dist/agent/memory-backup.d.ts +2 -0
  5. package/dist/agent/memory-backup.js +9 -1
  6. package/dist/agent/memory-backup.js.map +1 -1
  7. package/dist/agent/memory-limits.js +8 -1
  8. package/dist/agent/memory-limits.js.map +1 -1
  9. package/dist/agent/memory-usage.d.ts +1 -1
  10. package/dist/agent/memory-usage.js +2 -3
  11. package/dist/agent/memory-usage.js.map +1 -1
  12. package/dist/agent/memory.d.ts +3 -0
  13. package/dist/agent/memory.js +6 -18
  14. package/dist/agent/memory.js.map +1 -1
  15. package/dist/agent/session.d.ts +9 -0
  16. package/dist/agent/session.js +14 -2
  17. package/dist/agent/session.js.map +1 -1
  18. package/dist/agent/settings.js +3 -2
  19. package/dist/agent/settings.js.map +1 -1
  20. package/dist/agent/store.d.ts +45 -4
  21. package/dist/agent/store.js +198 -25
  22. package/dist/agent/store.js.map +1 -1
  23. package/dist/artifacts/files.d.ts +52 -0
  24. package/dist/artifacts/files.js +169 -0
  25. package/dist/artifacts/files.js.map +1 -0
  26. package/dist/auth/store.js +3 -2
  27. package/dist/auth/store.js.map +1 -1
  28. package/dist/config-files.js +3 -2
  29. package/dist/config-files.js.map +1 -1
  30. package/dist/config.d.ts +6 -1
  31. package/dist/config.js +10 -2
  32. package/dist/config.js.map +1 -1
  33. package/dist/harness.d.ts +62 -1
  34. package/dist/harness.js +174 -12
  35. package/dist/harness.js.map +1 -1
  36. package/dist/paths.d.ts +5 -0
  37. package/dist/paths.js +21 -3
  38. package/dist/paths.js.map +1 -1
  39. package/dist/providers/builtin.d.ts +2 -0
  40. package/dist/providers/builtin.js +38 -24
  41. package/dist/providers/builtin.js.map +1 -1
  42. package/dist/providers/catalog.d.ts +5 -0
  43. package/dist/providers/catalog.js +32 -1
  44. package/dist/providers/catalog.js.map +1 -1
  45. package/dist/providers/catalog.json +241 -123
  46. package/dist/providers/discovery.js +17 -0
  47. package/dist/providers/discovery.js.map +1 -1
  48. package/dist/providers/models-dev.d.ts +89 -0
  49. package/dist/providers/models-dev.js +160 -0
  50. package/dist/providers/models-dev.js.map +1 -0
  51. package/dist/providers/models-dev.json +821 -0
  52. package/dist/providers/registry.d.ts +12 -0
  53. package/dist/providers/registry.js +33 -1
  54. package/dist/providers/registry.js.map +1 -1
  55. package/dist/providers/types.d.ts +21 -0
  56. package/dist/providers/types.js +16 -0
  57. package/dist/providers/types.js.map +1 -1
  58. package/dist/runtime-plugins/builtin/memory-migrate.d.ts +5 -21
  59. package/dist/runtime-plugins/builtin/memory-migrate.js +5 -125
  60. package/dist/runtime-plugins/builtin/memory-migrate.js.map +1 -1
  61. package/dist/runtime-plugins/builtin/memory.d.ts +3 -0
  62. package/dist/runtime-plugins/builtin/memory.js +12 -10
  63. package/dist/runtime-plugins/builtin/memory.js.map +1 -1
  64. package/dist/schedule/clock.d.ts +76 -0
  65. package/dist/schedule/clock.js +147 -0
  66. package/dist/schedule/clock.js.map +1 -0
  67. package/dist/schedule/cron.d.ts +9 -0
  68. package/dist/schedule/cron.js +18 -0
  69. package/dist/schedule/cron.js.map +1 -1
  70. package/dist/schedule/lock.d.ts +38 -0
  71. package/dist/schedule/lock.js +100 -0
  72. package/dist/schedule/lock.js.map +1 -0
  73. package/dist/schedule/runner.d.ts +67 -0
  74. package/dist/schedule/runner.js +100 -0
  75. package/dist/schedule/runner.js.map +1 -0
  76. package/dist/schedule/scheduler.d.ts +56 -15
  77. package/dist/schedule/scheduler.js +80 -107
  78. package/dist/schedule/scheduler.js.map +1 -1
  79. package/dist/storage/kv.js +3 -2
  80. package/dist/storage/kv.js.map +1 -1
  81. package/dist/storage/project.d.ts +26 -0
  82. package/dist/storage/project.js +74 -15
  83. package/dist/storage/project.js.map +1 -1
  84. package/dist/tools/builtin/routine.d.ts +31 -0
  85. package/dist/tools/builtin/routine.js +70 -0
  86. package/dist/tools/builtin/routine.js.map +1 -0
  87. package/dist/util/fs.d.ts +6 -0
  88. package/dist/util/fs.js +22 -0
  89. package/dist/util/fs.js.map +1 -0
  90. package/package.json +3 -3
@@ -0,0 +1,160 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { parseJson } from "../util/json.js";
5
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
6
+ const EFFORTS = ["low", "medium", "high", "xhigh", "max"];
7
+ const DEFAULT_EFFORTS = ["low", "medium", "high"];
8
+ /** The bundled snapshot, or an empty one: it is a convenience, never a requirement. */
9
+ export async function loadModelsDev() {
10
+ try {
11
+ const parsed = parseJson(await readFile(path.join(HERE, "models-dev.json"), "utf8"));
12
+ if (parsed.ok && parsed.value && typeof parsed.value.providers === "object")
13
+ return parsed.value;
14
+ }
15
+ catch {
16
+ // Missing from a build that did not copy it: fall through to nothing.
17
+ }
18
+ return { providers: {} };
19
+ }
20
+ /** A models.dev release date as ms, when it is one. */
21
+ function releasedAt(model) {
22
+ const ms = model.release_date ? Date.parse(model.release_date) : NaN;
23
+ return Number.isFinite(ms) ? { releasedAt: ms } : {};
24
+ }
25
+ /**
26
+ * Release dates by model id, across every provider in the snapshot.
27
+ *
28
+ * For ordering a list in which a model arrived with no date of its own, or a
29
+ * doubtful one: a gateway's `deepseek-v4-flash` is DeepSeek's model, and
30
+ * OpenRouter's `anthropic/claude-opus-5` is Anthropic's. Looked up by the
31
+ * whole id and by the part after the last slash, lowercased; where providers
32
+ * disagree about the same id the earliest date is kept, since a reseller
33
+ * listing a model later does not make it newer.
34
+ */
35
+ export function releaseDates(snapshot) {
36
+ const dates = new Map();
37
+ const keep = (key, ms) => {
38
+ const held = dates.get(key);
39
+ if (held === undefined || ms < held)
40
+ dates.set(key, ms);
41
+ };
42
+ for (const provider of Object.values(snapshot.providers)) {
43
+ for (const model of Object.values(provider.models ?? {})) {
44
+ const { releasedAt: ms } = releasedAt(model);
45
+ if (ms === undefined)
46
+ continue;
47
+ const id = dateKey(model.id);
48
+ keep(id, ms);
49
+ keep(id.slice(id.lastIndexOf("/") + 1), ms);
50
+ }
51
+ }
52
+ return dates;
53
+ }
54
+ /**
55
+ * An id as both sides of the lookup spell it: lowercased, with a version's
56
+ * dots as dashes — a gateway's "claude-opus-4.8" is models.dev's
57
+ * "claude-opus-4-8".
58
+ */
59
+ function dateKey(id) {
60
+ return id.toLowerCase().replace(/\./g, "-");
61
+ }
62
+ /**
63
+ * The date for a wire id from `releaseDates`: the earlier of the whole id's
64
+ * and its last part's, so a reseller's "vendor/model" entry cannot postdate
65
+ * the vendor's own "model".
66
+ */
67
+ export function releaseDateOf(dates, wireId) {
68
+ // A routing variant (":batch", ":free") is the same model released the same day.
69
+ const id = dateKey(wireId.replace(/^~/, "").replace(/:[a-z-]+$/, ""));
70
+ const found = [dates.get(id), dates.get(id.slice(id.lastIndexOf("/") + 1))].filter((ms) => ms !== undefined);
71
+ return found.length ? Math.min(...found) : undefined;
72
+ }
73
+ /**
74
+ * Whether a models.dev entry belongs in a harness picker at all: something
75
+ * that answers in text, can call tools, and is not on its way out.
76
+ */
77
+ export function isUsableModel(model) {
78
+ if (model.status === "deprecated")
79
+ return false;
80
+ if (model.tool_call === false)
81
+ return false;
82
+ const output = model.modalities?.output;
83
+ return !output || output.includes("text");
84
+ }
85
+ export function specFromModelsDev(entry, model) {
86
+ const cost = model.cost ?? {};
87
+ const efforts = effortLevels(model);
88
+ return {
89
+ id: `${entry.id}/${model.id}`,
90
+ provider: entry.id,
91
+ model: model.id,
92
+ displayName: model.name || model.id,
93
+ ...releasedAt(model),
94
+ // The same defaults discovery uses for an endpoint that states nothing.
95
+ contextWindow: model.limit?.context || 128_000,
96
+ maxOutputTokens: model.limit?.output || 8_192,
97
+ supportsTools: model.tool_call !== false,
98
+ supportsImages: (model.modalities?.input ?? []).includes("image"),
99
+ supportsParallelToolCalls: true,
100
+ supportsPromptCache: (cost.cache_read ?? 0) > 0,
101
+ thinkingMode: model.reasoning ? "effort" : "none",
102
+ effortLevels: efforts,
103
+ supportsSampling: model.temperature !== false,
104
+ // The same rule as pi-ai's seed: a plan's models are not billed per token,
105
+ // and an unquoted price is left out rather than written as zero.
106
+ ...(entry.subscription
107
+ ? {}
108
+ : {
109
+ ...price("costPer1MInput", cost.input),
110
+ ...price("costPer1MOutput", cost.output),
111
+ ...price("costPer1MCacheRead", cost.cache_read),
112
+ ...price("costPer1MCacheWrite", cost.cache_write),
113
+ }),
114
+ };
115
+ }
116
+ /**
117
+ * The tiers a model names, when it names them as effort levels; the ordinary
118
+ * three otherwise. A toggle or a token budget is still driven by effort here,
119
+ * which the wire layer translates — the same reading pi-ai's seed takes.
120
+ */
121
+ function effortLevels(model) {
122
+ if (!model.reasoning)
123
+ return [];
124
+ const named = (model.reasoning_options ?? []).find((option) => option.type === "effort")?.values;
125
+ if (!named?.length)
126
+ return [...DEFAULT_EFFORTS];
127
+ const levels = EFFORTS.filter((level) => named.includes(level));
128
+ return levels.length ? levels : [...DEFAULT_EFFORTS];
129
+ }
130
+ function price(field, value) {
131
+ return value && value > 0 ? { [field]: value } : {};
132
+ }
133
+ /**
134
+ * Specs for every catalog provider that names a models.dev id, skipping the
135
+ * models already `taken` — by the catalog files and by pi-ai's seed, both of
136
+ * which rank above this.
137
+ */
138
+ export function modelsDevSeeds(providers, snapshot, taken, listed) {
139
+ const seeded = [];
140
+ for (const entry of Object.values(providers)) {
141
+ if (!entry.modelsDev || listed?.has(entry.id))
142
+ continue;
143
+ const source = snapshot.providers[entry.modelsDev];
144
+ if (!source)
145
+ continue;
146
+ const excluded = new Set(entry.excludeModels ?? []);
147
+ for (const model of Object.values(source.models ?? {})) {
148
+ if (!model?.id || excluded.has(model.id) || !isUsableModel(model))
149
+ continue;
150
+ const spec = specFromModelsDev(entry, model);
151
+ if (taken.has(spec.id) || taken.has(`${spec.provider} ${spec.model}`))
152
+ continue;
153
+ taken.add(spec.id);
154
+ taken.add(`${spec.provider} ${spec.model}`);
155
+ seeded.push(spec);
156
+ }
157
+ }
158
+ return seeded;
159
+ }
160
+ //# sourceMappingURL=models-dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models-dev.js","sourceRoot":"","sources":["../../src/providers/models-dev.ts"],"names":[],"mappings":"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"}