@hilbras/omninode 2.0.0-alpha.6 → 2.0.0-alpha.8
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 +15 -3
- package/dist/cli/index.js +261 -41
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +179 -31
- package/dist/index.js +264 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -125,6 +125,7 @@ var providerConfigSchema = z.object({
|
|
|
125
125
|
type: z.enum(["openai-compatible", "omnihilbras", "openrouter", "local", "custom"]),
|
|
126
126
|
base_url: z.string().url(),
|
|
127
127
|
api_key_env_var: z.string().min(1).optional(),
|
|
128
|
+
timeout_ms: z.number().int().positive().optional(),
|
|
128
129
|
headers: z.record(z.string()).optional(),
|
|
129
130
|
enabled: z.boolean().optional(),
|
|
130
131
|
metadata: z.record(z.unknown()).optional()
|
|
@@ -189,7 +190,9 @@ var projectConfigSchema = z.object({
|
|
|
189
190
|
memory: z.object({
|
|
190
191
|
provider: z.string().min(1).default("local"),
|
|
191
192
|
base_url: z.string().url().optional(),
|
|
192
|
-
api_key_env_var: z.string().min(1).optional()
|
|
193
|
+
api_key_env_var: z.string().min(1).optional(),
|
|
194
|
+
/** When true, memory failures fail tasks instead of being tolerated (§12). */
|
|
195
|
+
required: z.boolean().optional()
|
|
193
196
|
}).strict().optional()
|
|
194
197
|
}).strict();
|
|
195
198
|
var appConfigSchema = z.object({
|
|
@@ -271,7 +274,8 @@ function toAppConfig(yaml) {
|
|
|
271
274
|
memory: {
|
|
272
275
|
provider: yaml.project.memory.provider,
|
|
273
276
|
baseUrl: yaml.project.memory.base_url,
|
|
274
|
-
apiKeyEnvVar: yaml.project.memory.api_key_env_var
|
|
277
|
+
apiKeyEnvVar: yaml.project.memory.api_key_env_var,
|
|
278
|
+
required: yaml.project.memory.required
|
|
275
279
|
}
|
|
276
280
|
} : {}
|
|
277
281
|
},
|
|
@@ -302,6 +306,7 @@ function toProviderConfig(raw) {
|
|
|
302
306
|
type: raw.type,
|
|
303
307
|
baseUrl: raw.base_url,
|
|
304
308
|
apiKeyEnvVar: raw.api_key_env_var,
|
|
309
|
+
timeoutMs: raw.timeout_ms,
|
|
305
310
|
headers: raw.headers,
|
|
306
311
|
enabled: raw.enabled,
|
|
307
312
|
metadata: raw.metadata
|
|
@@ -524,6 +529,7 @@ function providerTransportError(context) {
|
|
|
524
529
|
}
|
|
525
530
|
|
|
526
531
|
// src/providers/openai-compatible/index.ts
|
|
532
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
527
533
|
var OpenAICompatibleProvider = class {
|
|
528
534
|
config;
|
|
529
535
|
providerId;
|
|
@@ -543,6 +549,10 @@ var OpenAICompatibleProvider = class {
|
|
|
543
549
|
};
|
|
544
550
|
this.log = log.child({ provider: config.name });
|
|
545
551
|
}
|
|
552
|
+
/** Provider-level request timeout (roadmap §6.6/§11) with the shared default. */
|
|
553
|
+
get requestTimeoutMs() {
|
|
554
|
+
return this.config.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
555
|
+
}
|
|
546
556
|
/** Authenticate + discover (roadmap §10, Model Discovery). */
|
|
547
557
|
async connect() {
|
|
548
558
|
authHeaders(this.config, this.env);
|
|
@@ -554,11 +564,17 @@ var OpenAICompatibleProvider = class {
|
|
|
554
564
|
const models = this.discovered ?? await this.connect();
|
|
555
565
|
return models.find((m) => m.id === modelId);
|
|
556
566
|
}
|
|
557
|
-
|
|
567
|
+
/** Raw /models body (protected so adapters can capture gateway-level metadata). */
|
|
568
|
+
async rawModelsResponse() {
|
|
569
|
+
const response = await this.modelsRequest();
|
|
570
|
+
return response.body;
|
|
571
|
+
}
|
|
572
|
+
async modelsRequest() {
|
|
558
573
|
let response;
|
|
559
574
|
try {
|
|
560
575
|
response = await requestJson(`${this.config.baseUrl}/models`, {
|
|
561
|
-
headers: authHeaders(this.config, this.env)
|
|
576
|
+
headers: authHeaders(this.config, this.env),
|
|
577
|
+
timeoutMs: this.requestTimeoutMs
|
|
562
578
|
});
|
|
563
579
|
} catch (error) {
|
|
564
580
|
if (error instanceof ProviderError) throw error;
|
|
@@ -573,6 +589,10 @@ var OpenAICompatibleProvider = class {
|
|
|
573
589
|
body
|
|
574
590
|
});
|
|
575
591
|
}
|
|
592
|
+
return response;
|
|
593
|
+
}
|
|
594
|
+
async listModels() {
|
|
595
|
+
const body = await this.rawModelsResponse();
|
|
576
596
|
const entries = extractModelEntries(body, this.config);
|
|
577
597
|
const models = [];
|
|
578
598
|
let skipped = 0;
|
|
@@ -615,6 +635,10 @@ var OpenAICompatibleProvider = class {
|
|
|
615
635
|
}
|
|
616
636
|
};
|
|
617
637
|
}
|
|
638
|
+
/** Streaming where the gateway supports it (§11). */
|
|
639
|
+
stream(request, onChunk) {
|
|
640
|
+
return streamChatCompletion(this.config, request, onChunk, this.env);
|
|
641
|
+
}
|
|
618
642
|
async healthCheck() {
|
|
619
643
|
const lastCheckedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
620
644
|
try {
|
|
@@ -649,6 +673,7 @@ var OpenAICompatibleProvider = class {
|
|
|
649
673
|
response = await requestJson(`${this.config.baseUrl}/chat/completions`, {
|
|
650
674
|
method: "POST",
|
|
651
675
|
headers: authHeaders(this.config, this.env),
|
|
676
|
+
timeoutMs: this.requestTimeoutMs,
|
|
652
677
|
body: {
|
|
653
678
|
model: request.model,
|
|
654
679
|
messages: request.messages,
|
|
@@ -693,6 +718,74 @@ var OpenAICompatibleProvider = class {
|
|
|
693
718
|
};
|
|
694
719
|
}
|
|
695
720
|
};
|
|
721
|
+
async function streamChatCompletion(config, request, onChunk, env = process.env) {
|
|
722
|
+
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
723
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
724
|
+
let response;
|
|
725
|
+
try {
|
|
726
|
+
response = await fetch(`${baseUrl}/chat/completions`, {
|
|
727
|
+
method: "POST",
|
|
728
|
+
headers: {
|
|
729
|
+
accept: "text/event-stream",
|
|
730
|
+
"content-type": "application/json",
|
|
731
|
+
...authHeaders(config, env)
|
|
732
|
+
},
|
|
733
|
+
body: JSON.stringify({
|
|
734
|
+
model: request.model,
|
|
735
|
+
messages: request.messages,
|
|
736
|
+
stream: true,
|
|
737
|
+
...request.temperature !== void 0 ? { temperature: request.temperature } : {},
|
|
738
|
+
...request.maxTokens !== void 0 ? { max_tokens: request.maxTokens } : {}
|
|
739
|
+
}),
|
|
740
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
741
|
+
});
|
|
742
|
+
} catch (error) {
|
|
743
|
+
throw providerTransportError({ provider: config.name, operation: "stream", cause: error });
|
|
744
|
+
}
|
|
745
|
+
if (!response.ok) {
|
|
746
|
+
const body = await response.json().catch(() => void 0);
|
|
747
|
+
throw providerHttpError({ provider: config.name, operation: "stream", status: response.status, body });
|
|
748
|
+
}
|
|
749
|
+
if (!response.body) {
|
|
750
|
+
throw providerHttpError({
|
|
751
|
+
provider: config.name,
|
|
752
|
+
operation: "stream",
|
|
753
|
+
status: 500,
|
|
754
|
+
body: { error: { message: "streaming is not supported by this endpoint" } }
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
let content = "";
|
|
758
|
+
let model = request.model;
|
|
759
|
+
let finishReason;
|
|
760
|
+
const decoder = new TextDecoder();
|
|
761
|
+
let buffer = "";
|
|
762
|
+
for await (const piece of response.body) {
|
|
763
|
+
buffer += decoder.decode(piece, { stream: true });
|
|
764
|
+
let newline = buffer.indexOf("\n");
|
|
765
|
+
while (newline >= 0) {
|
|
766
|
+
const line = buffer.slice(0, newline).trim();
|
|
767
|
+
buffer = buffer.slice(newline + 1);
|
|
768
|
+
newline = buffer.indexOf("\n");
|
|
769
|
+
if (line.length === 0 || line.startsWith(":")) continue;
|
|
770
|
+
const data = line.startsWith("data:") ? line.slice(5).trim() : line;
|
|
771
|
+
if (data === "[DONE]") continue;
|
|
772
|
+
let event;
|
|
773
|
+
try {
|
|
774
|
+
event = JSON.parse(data);
|
|
775
|
+
} catch {
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
if (typeof event.model === "string") model = event.model;
|
|
779
|
+
const choices = Array.isArray(event.choices) ? event.choices : [];
|
|
780
|
+
const first = choices[0];
|
|
781
|
+
const delta = typeof first?.delta?.content === "string" ? first.delta.content : "";
|
|
782
|
+
if (delta.length > 0) content += delta;
|
|
783
|
+
if (typeof first?.finish_reason === "string") finishReason = first.finish_reason;
|
|
784
|
+
onChunk({ delta, ...finishReason !== void 0 ? { finishReason } : {}, raw: event });
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
return { model, content, ...finishReason !== void 0 ? { finishReason } : {} };
|
|
788
|
+
}
|
|
696
789
|
function normalizeModalities(value) {
|
|
697
790
|
const list = Array.isArray(value) ? value : typeof value === "string" ? [value] : void 0;
|
|
698
791
|
if (!list) return void 0;
|
|
@@ -726,10 +819,32 @@ function inferHealth(error) {
|
|
|
726
819
|
|
|
727
820
|
// src/providers/omnihilbras/index.ts
|
|
728
821
|
var OmniHilbrasProvider = class extends OpenAICompatibleProvider {
|
|
822
|
+
gateway;
|
|
823
|
+
async listModels() {
|
|
824
|
+
const raw = await this.rawModelsResponse();
|
|
825
|
+
await this.extractGatewayMetadata(raw);
|
|
826
|
+
const models = await super.listModels();
|
|
827
|
+
return this.gateway ? models.map((model) => ({ ...model, metadata: { ...model.metadata, gateway: this.gateway } })) : models;
|
|
828
|
+
}
|
|
729
829
|
/**
|
|
730
830
|
* Run the full connect flow. Throws on authentication or transport failure
|
|
731
831
|
* (use healthCheck() for a non-throwing probe).
|
|
732
832
|
*/
|
|
833
|
+
/**
|
|
834
|
+
* Gateway metadata reported alongside the model list (gateway version, tier,
|
|
835
|
+
* region…), kept separate from per-model metadata (§11 — provider metadata).
|
|
836
|
+
*/
|
|
837
|
+
gatewayMetadata() {
|
|
838
|
+
return this.gateway;
|
|
839
|
+
}
|
|
840
|
+
async extractGatewayMetadata(body) {
|
|
841
|
+
if (body !== null && typeof body === "object") {
|
|
842
|
+
const gateway = body.gateway;
|
|
843
|
+
if (gateway !== null && typeof gateway === "object") {
|
|
844
|
+
this.gateway = gateway;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
733
848
|
async connectAndRegister(registry) {
|
|
734
849
|
const apiKey = resolveApiKey(this.config);
|
|
735
850
|
const discovered = await this.listModels();
|
|
@@ -2089,6 +2204,23 @@ var FileAuditLog = class {
|
|
|
2089
2204
|
}
|
|
2090
2205
|
};
|
|
2091
2206
|
|
|
2207
|
+
// src/memory/base.ts
|
|
2208
|
+
function defaultSearch(provider, text, options = {}) {
|
|
2209
|
+
return provider.retrieve({
|
|
2210
|
+
text,
|
|
2211
|
+
...options.scope !== void 0 ? { scope: options.scope } : {},
|
|
2212
|
+
...options.limit !== void 0 ? { limit: options.limit } : {}
|
|
2213
|
+
});
|
|
2214
|
+
}
|
|
2215
|
+
function defaultMetadata(name, options = {}) {
|
|
2216
|
+
return {
|
|
2217
|
+
name,
|
|
2218
|
+
capabilities: options.capabilities ?? ["retrieve", "store", "search"],
|
|
2219
|
+
relevanceRanking: options.relevanceRanking ?? false,
|
|
2220
|
+
...options.backend !== void 0 ? { backend: options.backend } : {}
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2092
2224
|
// src/memory/local.ts
|
|
2093
2225
|
var STOPWORDS = /* @__PURE__ */ new Set([
|
|
2094
2226
|
"the",
|
|
@@ -2151,9 +2283,27 @@ var LocalMemoryProvider = class extends JsonFileStore {
|
|
|
2151
2283
|
constructor(directory) {
|
|
2152
2284
|
super({ ...directory !== void 0 ? { directory } : {}, fileName: "memory.json" });
|
|
2153
2285
|
}
|
|
2154
|
-
|
|
2286
|
+
metadata() {
|
|
2287
|
+
return defaultMetadata(this.name, {
|
|
2288
|
+
capabilities: ["retrieve", "store", "search", "categories", "tags"],
|
|
2289
|
+
relevanceRanking: true,
|
|
2290
|
+
backend: { kind: "json-file", deterministicScoring: true }
|
|
2291
|
+
});
|
|
2292
|
+
}
|
|
2293
|
+
search(text, options = {}) {
|
|
2294
|
+
return defaultSearch(this, text, options);
|
|
2295
|
+
}
|
|
2296
|
+
/** @deprecated v1 alias of {@link retrieve}. */
|
|
2297
|
+
query(query) {
|
|
2298
|
+
return this.retrieve(query);
|
|
2299
|
+
}
|
|
2300
|
+
/** @deprecated v1 alias of {@link store}. */
|
|
2301
|
+
write(entry) {
|
|
2302
|
+
return this.store(entry);
|
|
2303
|
+
}
|
|
2304
|
+
async retrieve(query) {
|
|
2155
2305
|
const entries = await this.readAll();
|
|
2156
|
-
const filtered = entries.filter((entry) => query.scope ? entry.scope === query.scope : true).filter(
|
|
2306
|
+
const filtered = entries.filter((entry) => query.scope ? entry.scope === query.scope : true).filter((entry) => query.category ? entry.category === query.category : true).filter(
|
|
2157
2307
|
(entry) => query.tags && query.tags.length > 0 ? query.tags.every((tag) => (entry.tags ?? []).includes(tag)) : true
|
|
2158
2308
|
);
|
|
2159
2309
|
if (!query.text || query.text.trim().length === 0) {
|
|
@@ -2162,7 +2312,7 @@ var LocalMemoryProvider = class extends JsonFileStore {
|
|
|
2162
2312
|
const queryKeywords = keywords(query.text);
|
|
2163
2313
|
return filtered.map((entry) => ({ entry, score: relevanceScore(queryKeywords, entry) })).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score).slice(0, query.limit ?? 10).map(({ entry }) => entry);
|
|
2164
2314
|
}
|
|
2165
|
-
|
|
2315
|
+
store(entry) {
|
|
2166
2316
|
return this.mutate((entries) => {
|
|
2167
2317
|
const index = entries.findIndex((e) => e.key === entry.key);
|
|
2168
2318
|
const stamped = {
|
|
@@ -2193,11 +2343,40 @@ var RememberaMemoryProvider = class {
|
|
|
2193
2343
|
this.env = config.env ?? process.env;
|
|
2194
2344
|
this.log = log.child({ component: "remembera" });
|
|
2195
2345
|
}
|
|
2346
|
+
get authenticationConfigured() {
|
|
2347
|
+
return this.apiKeyEnvVar === void 0 || Boolean(this.env[this.apiKeyEnvVar]);
|
|
2348
|
+
}
|
|
2196
2349
|
headers() {
|
|
2197
2350
|
const key = this.apiKeyEnvVar ? resolveApiKey({ name: "remembera", apiKeyEnvVar: this.apiKeyEnvVar }, this.env) : void 0;
|
|
2198
2351
|
return key ? { authorization: `Bearer ${key}` } : {};
|
|
2199
2352
|
}
|
|
2200
|
-
|
|
2353
|
+
/** Search delegates to the gateway's relevance query. */
|
|
2354
|
+
search(text, options = {}) {
|
|
2355
|
+
return defaultSearch(
|
|
2356
|
+
this,
|
|
2357
|
+
text,
|
|
2358
|
+
{
|
|
2359
|
+
...options.scope !== void 0 ? { scope: options.scope } : {},
|
|
2360
|
+
...options.limit !== void 0 ? { limit: options.limit } : {}
|
|
2361
|
+
}
|
|
2362
|
+
);
|
|
2363
|
+
}
|
|
2364
|
+
metadata() {
|
|
2365
|
+
return defaultMetadata(this.name, {
|
|
2366
|
+
capabilities: ["retrieve", "store", "search", "categories", "tags"],
|
|
2367
|
+
relevanceRanking: true,
|
|
2368
|
+
backend: { kind: "http", baseUrl: this.baseUrl, authenticated: this.authenticationConfigured }
|
|
2369
|
+
});
|
|
2370
|
+
}
|
|
2371
|
+
/** @deprecated v1 alias of {@link retrieve}. */
|
|
2372
|
+
query(query) {
|
|
2373
|
+
return this.retrieve(query);
|
|
2374
|
+
}
|
|
2375
|
+
/** @deprecated v1 alias of {@link store}. */
|
|
2376
|
+
write(entry) {
|
|
2377
|
+
return this.store(entry);
|
|
2378
|
+
}
|
|
2379
|
+
async retrieve(query) {
|
|
2201
2380
|
const { status, body } = await this.request(`${this.baseUrl}/api/memory/query`, query);
|
|
2202
2381
|
if (status !== 200) {
|
|
2203
2382
|
throw new MemoryError(`Remembera query returned HTTP ${status}.`);
|
|
@@ -2208,7 +2387,7 @@ var RememberaMemoryProvider = class {
|
|
|
2208
2387
|
}
|
|
2209
2388
|
return entries.map((entry) => this.toEntry(entry)).filter((entry) => entry !== void 0);
|
|
2210
2389
|
}
|
|
2211
|
-
async
|
|
2390
|
+
async store(entry) {
|
|
2212
2391
|
const { status } = await this.request(`${this.baseUrl}/api/memory`, entry);
|
|
2213
2392
|
if (status !== 200 && status !== 201) {
|
|
2214
2393
|
throw new MemoryError(`Remembera write returned HTTP ${status}.`);
|
|
@@ -2243,6 +2422,7 @@ var RememberaMemoryProvider = class {
|
|
|
2243
2422
|
content: entry.content,
|
|
2244
2423
|
scope: scope === "project" || scope === "role" || scope === "task" || scope === "knowledge" ? scope : "knowledge",
|
|
2245
2424
|
...Array.isArray(entry.tags) ? { tags: entry.tags.filter((t) => typeof t === "string") } : {},
|
|
2425
|
+
...typeof entry.category === "string" ? { category: entry.category } : {},
|
|
2246
2426
|
...typeof entry.createdAt === "string" ? { createdAt: entry.createdAt } : {},
|
|
2247
2427
|
...typeof entry.updatedAt === "string" ? { updatedAt: entry.updatedAt } : {}
|
|
2248
2428
|
};
|
|
@@ -2273,57 +2453,54 @@ function createMemoryProvider(config) {
|
|
|
2273
2453
|
}
|
|
2274
2454
|
|
|
2275
2455
|
// src/memory/service.ts
|
|
2456
|
+
var DEFAULT_ENTRY_LIMIT = 8;
|
|
2276
2457
|
var MAX_CONTEXT_CHARS = 4e3;
|
|
2277
2458
|
var MemoryService = class {
|
|
2278
|
-
constructor(provider, log = logger) {
|
|
2459
|
+
constructor(provider, log = logger, options = {}) {
|
|
2279
2460
|
this.provider = provider;
|
|
2280
2461
|
this.log = log.child({ component: "memory", provider: provider.name });
|
|
2462
|
+
this.required = options.required ?? false;
|
|
2463
|
+
this.maxContextChars = options.maxContextChars ?? MAX_CONTEXT_CHARS;
|
|
2281
2464
|
}
|
|
2282
2465
|
provider;
|
|
2283
2466
|
log;
|
|
2467
|
+
required;
|
|
2468
|
+
maxContextChars;
|
|
2284
2469
|
get providerRef() {
|
|
2285
2470
|
return this.provider;
|
|
2286
2471
|
}
|
|
2287
2472
|
get providerName() {
|
|
2288
2473
|
return this.provider.name;
|
|
2289
2474
|
}
|
|
2290
|
-
|
|
2291
|
-
|
|
2475
|
+
get isRequired() {
|
|
2476
|
+
return this.required;
|
|
2477
|
+
}
|
|
2478
|
+
/** Structured, budgeted context for a task (§12 — avoid loading all memory). */
|
|
2479
|
+
async contextFor(query) {
|
|
2480
|
+
let entries;
|
|
2292
2481
|
try {
|
|
2293
|
-
|
|
2482
|
+
entries = await this.provider.retrieve({
|
|
2294
2483
|
text: query.objective,
|
|
2295
2484
|
...query.role ? { tags: [query.role] } : {},
|
|
2296
|
-
limit:
|
|
2485
|
+
limit: query.limit ?? DEFAULT_ENTRY_LIMIT
|
|
2297
2486
|
});
|
|
2298
|
-
if (entries.length === 0) return "";
|
|
2299
|
-
const byScope = /* @__PURE__ */ new Map();
|
|
2300
|
-
for (const entry of entries) {
|
|
2301
|
-
byScope.set(entry.scope, [...byScope.get(entry.scope) ?? [], entry]);
|
|
2302
|
-
}
|
|
2303
|
-
const parts = [];
|
|
2304
|
-
for (const scope of ["project", "task", "role", "knowledge"]) {
|
|
2305
|
-
const scopeEntries = byScope.get(scope) ?? [];
|
|
2306
|
-
if (scopeEntries.length === 0) continue;
|
|
2307
|
-
const lines = scopeEntries.map((entry) => `- ${entry.content}`).join("\n");
|
|
2308
|
-
parts.push(`### Relevant memory (${scope})
|
|
2309
|
-
${lines}`);
|
|
2310
|
-
}
|
|
2311
|
-
const context = parts.join("\n\n");
|
|
2312
|
-
return context.length > MAX_CONTEXT_CHARS ? `${context.slice(0, MAX_CONTEXT_CHARS)}\u2026` : context;
|
|
2313
2487
|
} catch (error) {
|
|
2314
|
-
this.
|
|
2315
|
-
`Memory query failed (continuing without memory): ${error instanceof Error ? error.message : String(error)}`
|
|
2316
|
-
);
|
|
2317
|
-
return "";
|
|
2488
|
+
return this.handleFailure("retrieve", error, { text: "", entries: [], truncated: false });
|
|
2318
2489
|
}
|
|
2490
|
+
return this.format(entries);
|
|
2319
2491
|
}
|
|
2320
|
-
/**
|
|
2492
|
+
/** Prompt-ready context text (v1 convenience wrapper). */
|
|
2493
|
+
async gatherContext(query) {
|
|
2494
|
+
return (await this.contextFor(query)).text;
|
|
2495
|
+
}
|
|
2496
|
+
/** Records a finished task's outcome — task history plus "known problems" (§12). */
|
|
2321
2497
|
async recordTaskOutcome(task) {
|
|
2322
2498
|
const outcome = task.result?.summary ?? task.result?.error ?? "(no output)";
|
|
2323
2499
|
try {
|
|
2324
|
-
await this.provider.
|
|
2500
|
+
await this.provider.store({
|
|
2325
2501
|
key: `task:${task.id}`,
|
|
2326
2502
|
scope: "task",
|
|
2503
|
+
category: "tasks",
|
|
2327
2504
|
content: `Objective: ${task.objective}
|
|
2328
2505
|
Status: ${task.status}
|
|
2329
2506
|
Outcome: ${outcome}`,
|
|
@@ -2334,18 +2511,53 @@ Outcome: ${outcome}`,
|
|
|
2334
2511
|
(report) => report.findings.filter((finding) => finding.severity === "high" || finding.severity === "critical").map((finding) => ({ report, finding }))
|
|
2335
2512
|
);
|
|
2336
2513
|
for (const { report, finding } of significant) {
|
|
2337
|
-
await this.provider.
|
|
2514
|
+
await this.provider.store({
|
|
2338
2515
|
key: `finding:${report.id}:${finding.id}`,
|
|
2339
2516
|
scope: "project",
|
|
2517
|
+
category: "problems",
|
|
2340
2518
|
content: `[${finding.severity}] ${finding.title} \u2014 ${finding.detail}`,
|
|
2341
2519
|
tags: ["known-problem", report.agent]
|
|
2342
2520
|
});
|
|
2343
2521
|
}
|
|
2344
2522
|
} catch (error) {
|
|
2345
|
-
this.
|
|
2346
|
-
|
|
2523
|
+
this.handleFailure("store", error, void 0);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
format(entries) {
|
|
2527
|
+
if (entries.length === 0) return { text: "", entries, truncated: false };
|
|
2528
|
+
const byScope = /* @__PURE__ */ new Map();
|
|
2529
|
+
for (const entry of entries) {
|
|
2530
|
+
byScope.set(entry.scope, [...byScope.get(entry.scope) ?? [], entry]);
|
|
2531
|
+
}
|
|
2532
|
+
const parts = [];
|
|
2533
|
+
for (const scope of ["project", "task", "role", "knowledge"]) {
|
|
2534
|
+
const scopeEntries = byScope.get(scope) ?? [];
|
|
2535
|
+
if (scopeEntries.length === 0) continue;
|
|
2536
|
+
const lines = scopeEntries.map((entry) => {
|
|
2537
|
+
const category = entry.category ? `[${entry.category}] ` : "";
|
|
2538
|
+
return `- ${category}${entry.content}`;
|
|
2539
|
+
}).join("\n");
|
|
2540
|
+
parts.push(`### Relevant memory (${scope})
|
|
2541
|
+
${lines}`);
|
|
2542
|
+
}
|
|
2543
|
+
let text = parts.join("\n\n");
|
|
2544
|
+
const truncated = text.length > this.maxContextChars;
|
|
2545
|
+
if (truncated) text = `${text.slice(0, this.maxContextChars - 1)}\u2026`;
|
|
2546
|
+
return { text, entries, truncated };
|
|
2547
|
+
}
|
|
2548
|
+
/**
|
|
2549
|
+
* Failure policy (§12): continue unless memory is explicitly required.
|
|
2550
|
+
*/
|
|
2551
|
+
handleFailure(operation, error, fallback) {
|
|
2552
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2553
|
+
if (this.required) {
|
|
2554
|
+
throw new MemoryError(
|
|
2555
|
+
`Memory is marked required, but ${operation} failed: ${message}`,
|
|
2556
|
+
{ cause: error }
|
|
2347
2557
|
);
|
|
2348
2558
|
}
|
|
2559
|
+
this.log.warn(`Memory ${operation} failed (continuing without memory): ${message}`);
|
|
2560
|
+
return fallback ?? { text: "", entries: [], truncated: false };
|
|
2349
2561
|
}
|
|
2350
2562
|
};
|
|
2351
2563
|
|
|
@@ -2357,7 +2569,11 @@ function createTaskEngine(config, log = logger, directory) {
|
|
|
2357
2569
|
agents,
|
|
2358
2570
|
roles,
|
|
2359
2571
|
store: new FileTaskStore(directory),
|
|
2360
|
-
...config.project.memory !== void 0 ? {
|
|
2572
|
+
...config.project.memory !== void 0 ? {
|
|
2573
|
+
memory: new MemoryService(createMemoryProvider(config.project.memory), log, {
|
|
2574
|
+
required: config.project.memory.required
|
|
2575
|
+
})
|
|
2576
|
+
} : {},
|
|
2361
2577
|
audit: new FileAuditLog(),
|
|
2362
2578
|
log
|
|
2363
2579
|
});
|
|
@@ -3439,7 +3655,11 @@ function buildPipelineEngine(config, log = logger) {
|
|
|
3439
3655
|
agents,
|
|
3440
3656
|
roles,
|
|
3441
3657
|
store: new FileTaskStore(),
|
|
3442
|
-
...config.project.memory !== void 0 ? {
|
|
3658
|
+
...config.project.memory !== void 0 ? {
|
|
3659
|
+
memory: new MemoryService(createMemoryProvider(config.project.memory), log, {
|
|
3660
|
+
required: config.project.memory.required
|
|
3661
|
+
})
|
|
3662
|
+
} : {},
|
|
3443
3663
|
audit: new FileAuditLog(),
|
|
3444
3664
|
log
|
|
3445
3665
|
});
|
|
@@ -3477,7 +3697,7 @@ var ProjectStores = class {
|
|
|
3477
3697
|
};
|
|
3478
3698
|
|
|
3479
3699
|
// src/version.ts
|
|
3480
|
-
var OMNINODE_VERSION = "2.0.0-alpha.
|
|
3700
|
+
var OMNINODE_VERSION = "2.0.0-alpha.8";
|
|
3481
3701
|
export {
|
|
3482
3702
|
AgentAdapterRegistry,
|
|
3483
3703
|
AgentError,
|
|
@@ -3494,6 +3714,7 @@ export {
|
|
|
3494
3714
|
JsonFileStore,
|
|
3495
3715
|
LocalMemoryProvider,
|
|
3496
3716
|
Logger,
|
|
3717
|
+
MAX_CONTEXT_CHARS,
|
|
3497
3718
|
MAX_MESSAGE_BYTES,
|
|
3498
3719
|
MemoryError,
|
|
3499
3720
|
MemoryService,
|
|
@@ -3542,7 +3763,9 @@ export {
|
|
|
3542
3763
|
createTaskEngine,
|
|
3543
3764
|
decodeMessage,
|
|
3544
3765
|
decodeStream,
|
|
3766
|
+
defaultMetadata,
|
|
3545
3767
|
defaultProjectConfigYaml,
|
|
3768
|
+
defaultSearch,
|
|
3546
3769
|
describeExit,
|
|
3547
3770
|
encodeMessage,
|
|
3548
3771
|
envelope,
|