@jmanuelcorral/openteam 0.1.38 → 0.1.41
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/.opencode/command/openteam.md +5 -5
- package/AGENTS.md +50 -35
- package/README.es.md +759 -0
- package/README.md +213 -480
- package/dist/capabilities/types.d.ts +1 -1
- package/dist/cli/consoleServe.d.ts.map +1 -1
- package/dist/cli.js +1123 -232
- package/dist/commands/frontierCatalog.d.ts +27 -0
- package/dist/commands/frontierCatalog.d.ts.map +1 -0
- package/dist/commands/graph.d.ts +65 -0
- package/dist/commands/graph.d.ts.map +1 -0
- package/dist/commands/orchestratorAgent.d.ts +2 -1
- package/dist/commands/orchestratorAgent.d.ts.map +1 -1
- package/dist/commands/setup.d.ts +3 -18
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/migrations.d.ts +27 -0
- package/dist/config/migrations.d.ts.map +1 -0
- package/dist/config/resolve.d.ts +34 -0
- package/dist/config/resolve.d.ts.map +1 -0
- package/dist/config/schema.d.ts +235 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/console/assets.d.ts +9 -0
- package/dist/console/assets.d.ts.map +1 -0
- package/dist/console/render.d.ts.map +1 -1
- package/dist/context/redaction.d.ts +48 -0
- package/dist/context/redaction.d.ts.map +1 -0
- package/dist/context/schema.d.ts +115 -0
- package/dist/context/schema.d.ts.map +1 -0
- package/dist/context/types.d.ts +8 -0
- package/dist/context/types.d.ts.map +1 -0
- package/dist/contract/opencode.d.ts +1 -1
- package/dist/contract/opencode.d.ts.map +1 -1
- package/dist/graph/events.d.ts +25 -0
- package/dist/graph/events.d.ts.map +1 -0
- package/dist/graph/ids.d.ts +5 -0
- package/dist/graph/ids.d.ts.map +1 -0
- package/dist/graph/planner.d.ts +15 -0
- package/dist/graph/planner.d.ts.map +1 -0
- package/dist/graph/policies.d.ts +34 -0
- package/dist/graph/policies.d.ts.map +1 -0
- package/dist/graph/privacyPolicy.d.ts +29 -0
- package/dist/graph/privacyPolicy.d.ts.map +1 -0
- package/dist/graph/reducer.d.ts +27 -0
- package/dist/graph/reducer.d.ts.map +1 -0
- package/dist/graph/replay.d.ts +20 -0
- package/dist/graph/replay.d.ts.map +1 -0
- package/dist/graph/reviewerPolicy.d.ts +27 -0
- package/dist/graph/reviewerPolicy.d.ts.map +1 -0
- package/dist/graph/schema.d.ts +220 -0
- package/dist/graph/schema.d.ts.map +1 -0
- package/dist/graph/types.d.ts +40 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/validate.d.ts +19 -0
- package/dist/graph/validate.d.ts.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +873 -88
- package/dist/local/embeddings.d.ts +29 -0
- package/dist/local/embeddings.d.ts.map +1 -0
- package/dist/local/extractClient.d.ts +31 -0
- package/dist/local/extractClient.d.ts.map +1 -0
- package/dist/local/openai-compatible.d.ts +1 -0
- package/dist/local/openai-compatible.d.ts.map +1 -1
- package/dist/mcp/semanticRecall.d.ts +25 -0
- package/dist/mcp/semanticRecall.d.ts.map +1 -0
- package/dist/mcp/server.d.ts +22 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/memory/consolidate.d.ts +21 -0
- package/dist/memory/consolidate.d.ts.map +1 -0
- package/dist/memory/extract.d.ts +68 -0
- package/dist/memory/extract.d.ts.map +1 -0
- package/dist/memory/fold.d.ts +24 -0
- package/dist/memory/fold.d.ts.map +1 -0
- package/dist/memory/index.d.ts +18 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/inject.d.ts +29 -0
- package/dist/memory/inject.d.ts.map +1 -0
- package/dist/memory/log.d.ts +16 -0
- package/dist/memory/log.d.ts.map +1 -0
- package/dist/memory/merge.d.ts +38 -0
- package/dist/memory/merge.d.ts.map +1 -0
- package/dist/memory/rank.d.ts +32 -0
- package/dist/memory/rank.d.ts.map +1 -0
- package/dist/memory/recall.d.ts +30 -0
- package/dist/memory/recall.d.ts.map +1 -0
- package/dist/memory/temporal.d.ts +39 -0
- package/dist/memory/temporal.d.ts.map +1 -0
- package/dist/memory/types.d.ts +159 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/vector.d.ts +18 -0
- package/dist/memory/vector.d.ts.map +1 -0
- package/dist/orchestrator/graphCancellation.d.ts +84 -0
- package/dist/orchestrator/graphCancellation.d.ts.map +1 -0
- package/dist/orchestrator/graphEffects.d.ts +63 -0
- package/dist/orchestrator/graphEffects.d.ts.map +1 -0
- package/dist/orchestrator/graphReview.d.ts +84 -0
- package/dist/orchestrator/graphReview.d.ts.map +1 -0
- package/dist/orchestrator/graphRuntime.d.ts +69 -0
- package/dist/orchestrator/graphRuntime.d.ts.map +1 -0
- package/dist/orchestrator/opencodeSessionAdapter.d.ts +117 -0
- package/dist/orchestrator/opencodeSessionAdapter.d.ts.map +1 -0
- package/dist/orchestrator/roles.d.ts +1 -1
- package/dist/orchestrator/roles.d.ts.map +1 -1
- package/dist/orchestrator/sdd.d.ts +38 -2
- package/dist/orchestrator/sdd.d.ts.map +1 -1
- package/dist/orchestrator/sddCompiler.d.ts +44 -0
- package/dist/orchestrator/sddCompiler.d.ts.map +1 -0
- package/dist/orchestrator/sessionReconciler.d.ts +74 -0
- package/dist/orchestrator/sessionReconciler.d.ts.map +1 -0
- package/dist/orchestrator/shadowComparator.d.ts +62 -0
- package/dist/orchestrator/shadowComparator.d.ts.map +1 -0
- package/dist/plugin/hooks.d.ts +13 -0
- package/dist/plugin/hooks.d.ts.map +1 -1
- package/dist/plugin/memoryInject.d.ts +25 -0
- package/dist/plugin/memoryInject.d.ts.map +1 -0
- package/dist/router/chooseModel.d.ts.map +1 -1
- package/dist/router/cost.d.ts +4 -0
- package/dist/router/cost.d.ts.map +1 -0
- package/dist/router/frontierBaseline.d.ts +13 -0
- package/dist/router/frontierBaseline.d.ts.map +1 -0
- package/dist/router/modelSelection.d.ts +18 -0
- package/dist/router/modelSelection.d.ts.map +1 -0
- package/dist/storage/graph/codec.d.ts +52 -0
- package/dist/storage/graph/codec.d.ts.map +1 -0
- package/dist/storage/graph/fsGraphJournal.d.ts +3 -0
- package/dist/storage/graph/fsGraphJournal.d.ts.map +1 -0
- package/dist/storage/graph/importLegacy.d.ts +62 -0
- package/dist/storage/graph/importLegacy.d.ts.map +1 -0
- package/dist/storage/graph/memoryGraphJournal.d.ts +11 -0
- package/dist/storage/graph/memoryGraphJournal.d.ts.map +1 -0
- package/dist/storage/graph/migrateLegacyBriefs.d.ts +32 -0
- package/dist/storage/graph/migrateLegacyBriefs.d.ts.map +1 -0
- package/dist/storage/graph/projections.d.ts +31 -0
- package/dist/storage/graph/projections.d.ts.map +1 -0
- package/dist/storage/graph/provider.d.ts +52 -0
- package/dist/storage/graph/provider.d.ts.map +1 -0
- package/dist/storage/graph/recovery.d.ts +38 -0
- package/dist/storage/graph/recovery.d.ts.map +1 -0
- package/dist/storage/graph/runRegistry.d.ts +17 -0
- package/dist/storage/graph/runRegistry.d.ts.map +1 -0
- package/dist/storage/graph/snapshot.d.ts +44 -0
- package/dist/storage/graph/snapshot.d.ts.map +1 -0
- package/dist/storage/graph/workspaceLease.d.ts +36 -0
- package/dist/storage/graph/workspaceLease.d.ts.map +1 -0
- package/dist/storage/graph/writer.d.ts +20 -0
- package/dist/storage/graph/writer.d.ts.map +1 -0
- package/dist/storage/index/memoryConsolidate.d.ts +24 -0
- package/dist/storage/index/memoryConsolidate.d.ts.map +1 -0
- package/dist/storage/index/memoryIndex.d.ts +52 -0
- package/dist/storage/index/memoryIndex.d.ts.map +1 -0
- package/dist/storage/index/memoryRecall.d.ts +23 -0
- package/dist/storage/index/memoryRecall.d.ts.map +1 -0
- package/dist/storage/index/memoryRuntime.d.ts +41 -0
- package/dist/storage/index/memoryRuntime.d.ts.map +1 -0
- package/dist/telemetry/events.d.ts +3 -1
- package/dist/telemetry/events.d.ts.map +1 -1
- package/dist/telemetry/graphProjection.d.ts +36 -0
- package/dist/telemetry/graphProjection.d.ts.map +1 -0
- package/dist/telemetry/hash.d.ts.map +1 -1
- package/dist/web/server.d.ts +4 -0
- package/dist/web/server.d.ts.map +1 -1
- package/package.json +14 -6
package/dist/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
|
+
|
|
1
4
|
// src/index.ts
|
|
2
5
|
import { dirname as dirname2 } from "node:path";
|
|
3
6
|
|
|
@@ -21,7 +24,7 @@ function buildOrchestratorAgent(frontier, options = {}) {
|
|
|
21
24
|
];
|
|
22
25
|
const frontmatter = [
|
|
23
26
|
"---",
|
|
24
|
-
'description: "Orquestador
|
|
27
|
+
'description: "Orquestador multiagente de openteam: en cada petición comprueba si existe equipo; si no, entiende las tareas y crea el equipo de subagentes a demanda, planifica dependencias, paraleliza el trabajo independiente y mantiene el todo con el responsable de cada tarea, con routing local-first."',
|
|
25
28
|
"mode: primary",
|
|
26
29
|
`model: ${model}`,
|
|
27
30
|
"temperature: 0.2",
|
|
@@ -30,7 +33,7 @@ function buildOrchestratorAgent(frontier, options = {}) {
|
|
|
30
33
|
].join(`
|
|
31
34
|
`);
|
|
32
35
|
const body = [
|
|
33
|
-
"Eres el orquestador de **openteam
|
|
36
|
+
"Eres el orquestador multiagente de **openteam**. Eres el único agente",
|
|
34
37
|
"primario: no existe un equipo precreado. Tú **construyes el equipo de",
|
|
35
38
|
"subagentes a demanda** según el objetivo del usuario y del repositorio.",
|
|
36
39
|
"",
|
|
@@ -56,7 +59,7 @@ function buildOrchestratorAgent(frontier, options = {}) {
|
|
|
56
59
|
"",
|
|
57
60
|
"## Casting: elige un universo y nombra al equipo",
|
|
58
61
|
"",
|
|
59
|
-
"
|
|
62
|
+
"El equipo tiene una identidad temática persistente:",
|
|
60
63
|
"",
|
|
61
64
|
"1. Al crear el equipo por primera vez, **elige un universo** temático (p. ej.",
|
|
62
65
|
" una película, serie, cómic o mitología). Si el usuario tiene preferencia,",
|
|
@@ -333,6 +336,11 @@ var PrivacyModeSchema = z.enum([
|
|
|
333
336
|
"off"
|
|
334
337
|
]);
|
|
335
338
|
var BaselineModeSchema = z.enum(["auto", "pinned"]);
|
|
339
|
+
var GraphModeSchema = z.enum(["off", "shadow", "active"]);
|
|
340
|
+
var GraphConfigSchema = z.object({
|
|
341
|
+
mode: GraphModeSchema.default("off"),
|
|
342
|
+
killSwitch: z.boolean().default(false)
|
|
343
|
+
});
|
|
336
344
|
var ConsoleHostSchema = z.enum(["127.0.0.1", "localhost"]);
|
|
337
345
|
var ConsoleConfigSchema = z.object({
|
|
338
346
|
host: ConsoleHostSchema.default("127.0.0.1"),
|
|
@@ -379,6 +387,50 @@ var LocalRuntimeSchema = z.object({
|
|
|
379
387
|
discovery: z.enum(["cli", "sdk", "manual"]).optional(),
|
|
380
388
|
defaultModel: ModelRefSchema
|
|
381
389
|
});
|
|
390
|
+
var MemoryScopeSchema = z.enum(["project", "user"]);
|
|
391
|
+
var MemoryExtractionModeSchema = z.enum([
|
|
392
|
+
"local",
|
|
393
|
+
"localWithFrontierFallback"
|
|
394
|
+
]);
|
|
395
|
+
var MemoryEmbeddingsProviderSchema = z.enum(["local", "none"]);
|
|
396
|
+
var MemorySemanticSchema = z.object({
|
|
397
|
+
enabled: z.boolean().default(false),
|
|
398
|
+
storeContent: z.boolean().default(false),
|
|
399
|
+
logPath: z.string().min(1).default(".opencode/openteam/memory/records.jsonl"),
|
|
400
|
+
indexPath: z.string().min(1).default(".opencode/openteam/memory/index.sqlite"),
|
|
401
|
+
scope: MemoryScopeSchema.default("project"),
|
|
402
|
+
extraction: z.object({
|
|
403
|
+
mode: MemoryExtractionModeSchema.default("local"),
|
|
404
|
+
model: ModelRefSchema.nullable().default(null)
|
|
405
|
+
}).default({ mode: "local", model: null }),
|
|
406
|
+
embeddings: z.object({
|
|
407
|
+
provider: MemoryEmbeddingsProviderSchema.default("local"),
|
|
408
|
+
model: ModelRefSchema.nullable().default(null),
|
|
409
|
+
dim: z.number().int().positive().default(768)
|
|
410
|
+
}).default({ provider: "local", model: null, dim: 768 }),
|
|
411
|
+
recall: z.object({
|
|
412
|
+
maxResults: z.number().int().positive().default(8),
|
|
413
|
+
minSimilarity: z.number().min(0).max(1).default(0.2)
|
|
414
|
+
}).default({ maxResults: 8, minSimilarity: 0.2 }),
|
|
415
|
+
injection: z.object({
|
|
416
|
+
enabled: z.boolean().default(false),
|
|
417
|
+
maxChars: z.number().int().positive().default(1200),
|
|
418
|
+
maxItems: z.number().int().positive().default(8)
|
|
419
|
+
}).default({ enabled: false, maxChars: 1200, maxItems: 8 })
|
|
420
|
+
}).default({
|
|
421
|
+
enabled: false,
|
|
422
|
+
storeContent: false,
|
|
423
|
+
logPath: ".opencode/openteam/memory/records.jsonl",
|
|
424
|
+
indexPath: ".opencode/openteam/memory/index.sqlite",
|
|
425
|
+
scope: "project",
|
|
426
|
+
extraction: { mode: "local", model: null },
|
|
427
|
+
embeddings: { provider: "local", model: null, dim: 768 },
|
|
428
|
+
recall: { maxResults: 8, minSimilarity: 0.2 },
|
|
429
|
+
injection: { enabled: false, maxChars: 1200, maxItems: 8 }
|
|
430
|
+
});
|
|
431
|
+
var MemoryConfigSchema = z.object({
|
|
432
|
+
semantic: MemorySemanticSchema
|
|
433
|
+
});
|
|
382
434
|
var OpenTeamConfigObjectSchema = z.object({
|
|
383
435
|
baseline: z.object({
|
|
384
436
|
mode: BaselineModeSchema.default("auto"),
|
|
@@ -429,9 +481,14 @@ var OpenTeamConfigObjectSchema = z.object({
|
|
|
429
481
|
}).default({ hardStopOnBudgetExhaustion: false }),
|
|
430
482
|
privacyMode: PrivacyModeSchema.default("forceLocalOnSensitive"),
|
|
431
483
|
console: ConsoleConfigSchema,
|
|
432
|
-
storage: StorageConfigSchema
|
|
484
|
+
storage: StorageConfigSchema,
|
|
485
|
+
memory: MemoryConfigSchema.optional(),
|
|
486
|
+
graph: GraphConfigSchema.optional()
|
|
433
487
|
});
|
|
434
488
|
var OpenTeamConfigSchema = OpenTeamConfigObjectSchema;
|
|
489
|
+
function resolveMemorySemantic(config) {
|
|
490
|
+
return config.memory?.semantic ?? MemorySemanticSchema.parse(undefined);
|
|
491
|
+
}
|
|
435
492
|
|
|
436
493
|
// src/config/persist.ts
|
|
437
494
|
var DEFAULT_CONFIG_PATH = ".opencode/openteam.json";
|
|
@@ -447,9 +504,40 @@ async function writeOpenTeamConfigFile(config, path = DEFAULT_CONFIG_PATH, stora
|
|
|
447
504
|
// src/commands/setup.ts
|
|
448
505
|
var OPENCODE_CONFIG_PATH = "opencode.json";
|
|
449
506
|
|
|
507
|
+
// src/config/migrations.ts
|
|
508
|
+
var CURRENT_CONFIG_VERSION = 1;
|
|
509
|
+
|
|
510
|
+
class ConfigMigrationError extends Error {
|
|
511
|
+
code;
|
|
512
|
+
detail;
|
|
513
|
+
constructor(code, detail) {
|
|
514
|
+
super(`${code}: ${detail}`);
|
|
515
|
+
this.name = "ConfigMigrationError";
|
|
516
|
+
this.code = code;
|
|
517
|
+
this.detail = detail;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
function migrateConfig(raw) {
|
|
521
|
+
if (typeof raw !== "object" || raw === null) {
|
|
522
|
+
return raw;
|
|
523
|
+
}
|
|
524
|
+
const record = raw;
|
|
525
|
+
const version = record.configVersion;
|
|
526
|
+
if (version === undefined) {
|
|
527
|
+
return { ...record, configVersion: CURRENT_CONFIG_VERSION };
|
|
528
|
+
}
|
|
529
|
+
if (typeof version !== "number" || !Number.isInteger(version) || version < 1) {
|
|
530
|
+
throw new ConfigMigrationError("unknown-version", String(version));
|
|
531
|
+
}
|
|
532
|
+
if (version > CURRENT_CONFIG_VERSION) {
|
|
533
|
+
throw new ConfigMigrationError("unsupported-version", String(version));
|
|
534
|
+
}
|
|
535
|
+
return record;
|
|
536
|
+
}
|
|
537
|
+
|
|
450
538
|
// src/config/load.ts
|
|
451
539
|
function loadOpenTeamConfig(raw) {
|
|
452
|
-
return OpenTeamConfigSchema.parse(raw ?? {});
|
|
540
|
+
return OpenTeamConfigSchema.parse(migrateConfig(raw ?? {}));
|
|
453
541
|
}
|
|
454
542
|
|
|
455
543
|
// src/local/openai-compatible.ts
|
|
@@ -459,6 +547,9 @@ function normalizeBaseURL(baseURL) {
|
|
|
459
547
|
function modelsEndpoint(baseURL) {
|
|
460
548
|
return `${normalizeBaseURL(baseURL)}/models`;
|
|
461
549
|
}
|
|
550
|
+
function embeddingsEndpoint(baseURL) {
|
|
551
|
+
return `${normalizeBaseURL(baseURL)}/embeddings`;
|
|
552
|
+
}
|
|
462
553
|
function errorMessage(error) {
|
|
463
554
|
if (error instanceof Error) {
|
|
464
555
|
return error.message;
|
|
@@ -1562,9 +1653,9 @@ var HELP = [
|
|
|
1562
1653
|
" openteam local on Reactiva el routing local-first",
|
|
1563
1654
|
" openteam doctor Diagnóstico de runtimes y config",
|
|
1564
1655
|
" openteam agents Lista los agentes y el LLM (local/frontier) de cada uno",
|
|
1565
|
-
" openteam console Lanza la Console web multi-sesión (Ctrl+C para parar; --open abre el navegador)",
|
|
1566
|
-
" openteam console --status Muestra la config de la Console sin lanzarla",
|
|
1567
|
-
" openteam tunnel Expone la Console vía Dev Tunnels (--terminal expone opencode; Ctrl+C para cerrar)",
|
|
1656
|
+
" openteam console [alfa] Lanza la Console web multi-sesión (Ctrl+C para parar; --open abre el navegador)",
|
|
1657
|
+
" openteam console --status [alfa] Muestra la config de la Console sin lanzarla",
|
|
1658
|
+
" openteam tunnel [alfa] Expone la Console vía Dev Tunnels (--terminal expone opencode; Ctrl+C para cerrar)",
|
|
1568
1659
|
" openteam mcp Servidor MCP de solo lectura (memoria del equipo) sobre stdio",
|
|
1569
1660
|
" openteam report Resumen de coste/ahorro (telemetría)",
|
|
1570
1661
|
" openteam yolo status Muestra si el modo YOLO está activo",
|
|
@@ -1942,6 +2033,85 @@ function classifyHeuristic(task) {
|
|
|
1942
2033
|
};
|
|
1943
2034
|
}
|
|
1944
2035
|
|
|
2036
|
+
// src/router/modelSelection.ts
|
|
2037
|
+
function modelKey2(model) {
|
|
2038
|
+
return `${model.providerID}/${model.modelID}`;
|
|
2039
|
+
}
|
|
2040
|
+
function sameModel(left, right) {
|
|
2041
|
+
return left.providerID === right.providerID && left.modelID === right.modelID;
|
|
2042
|
+
}
|
|
2043
|
+
function compareModels(left, right) {
|
|
2044
|
+
return modelKey2(left).localeCompare(modelKey2(right));
|
|
2045
|
+
}
|
|
2046
|
+
function uniqueModelSelections(models) {
|
|
2047
|
+
const byKey = new Map;
|
|
2048
|
+
for (const model of models) {
|
|
2049
|
+
byKey.set(modelKey2(model), model);
|
|
2050
|
+
}
|
|
2051
|
+
return [...byKey.values()].sort(compareModels);
|
|
2052
|
+
}
|
|
2053
|
+
function localDefault(config) {
|
|
2054
|
+
return config.local.runtimes.find((runtime) => runtime.enabled)?.defaultModel ?? config.router.localDefault;
|
|
2055
|
+
}
|
|
2056
|
+
function resolveConfiguredFrontierBaseline(config) {
|
|
2057
|
+
if (config.baseline.mode === "pinned" && config.baseline.pinnedModel !== null) {
|
|
2058
|
+
return config.baseline.pinnedModel;
|
|
2059
|
+
}
|
|
2060
|
+
return config.baseline.hardDefault;
|
|
2061
|
+
}
|
|
2062
|
+
function compareAvailableModels2(left, right) {
|
|
2063
|
+
return compareModels(left, right);
|
|
2064
|
+
}
|
|
2065
|
+
function defaultAvailableModels2(config) {
|
|
2066
|
+
return [
|
|
2067
|
+
{
|
|
2068
|
+
...localDefault(config),
|
|
2069
|
+
kind: "local",
|
|
2070
|
+
available: true
|
|
2071
|
+
},
|
|
2072
|
+
{
|
|
2073
|
+
...resolveConfiguredFrontierBaseline(config),
|
|
2074
|
+
kind: "frontier",
|
|
2075
|
+
available: true
|
|
2076
|
+
}
|
|
2077
|
+
].sort(compareAvailableModels2);
|
|
2078
|
+
}
|
|
2079
|
+
function availableModels(input) {
|
|
2080
|
+
return (input.availableModels ?? defaultAvailableModels2(input.config)).slice().sort(compareAvailableModels2);
|
|
2081
|
+
}
|
|
2082
|
+
function listedModel(input, model) {
|
|
2083
|
+
return availableModels(input).find((candidate) => sameModel(candidate, model));
|
|
2084
|
+
}
|
|
2085
|
+
function frontierAvailable(input, model) {
|
|
2086
|
+
return listedModel(input, model)?.available !== false;
|
|
2087
|
+
}
|
|
2088
|
+
function localCandidateIsUsable(input, model) {
|
|
2089
|
+
return model.kind === "local" && model.available && !(input.task.requiresTools === true && model.supportsTools === false);
|
|
2090
|
+
}
|
|
2091
|
+
function availableLocalFallbacks(input, selected) {
|
|
2092
|
+
return uniqueModelSelections(availableModels(input).filter((model) => localCandidateIsUsable(input, model)).filter((model) => !sameModel(model, selected)).map((model) => ({
|
|
2093
|
+
providerID: model.providerID,
|
|
2094
|
+
modelID: model.modelID
|
|
2095
|
+
})));
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
// src/router/cost.ts
|
|
2099
|
+
function modelProfile(input, model) {
|
|
2100
|
+
return input.profiles?.find((profile) => sameModel(profile.ref, model));
|
|
2101
|
+
}
|
|
2102
|
+
function estimatedCostUSD(input, model) {
|
|
2103
|
+
const profile = modelProfile(input, model);
|
|
2104
|
+
if (profile === undefined) {
|
|
2105
|
+
return 0;
|
|
2106
|
+
}
|
|
2107
|
+
const inputTokens = input.task.estimatedInputTokens ?? 0;
|
|
2108
|
+
const outputTokens = input.task.estimatedOutputTokens ?? 0;
|
|
2109
|
+
return inputTokens / 1e6 * profile.costPer1M.inputUSD + outputTokens / 1e6 * profile.costPer1M.outputUSD;
|
|
2110
|
+
}
|
|
2111
|
+
function roundUSD(value) {
|
|
2112
|
+
return Math.round(value * 1000000000000) / 1000000000000;
|
|
2113
|
+
}
|
|
2114
|
+
|
|
1945
2115
|
// src/capabilities/select.ts
|
|
1946
2116
|
var BLENDED_COST_INPUT_WEIGHT = 0.75;
|
|
1947
2117
|
var BLENDED_COST_OUTPUT_WEIGHT = 1 - BLENDED_COST_INPUT_WEIGHT;
|
|
@@ -1973,7 +2143,7 @@ function deriveRequirement(tier, task) {
|
|
|
1973
2143
|
function blendedCostPer1M(profile) {
|
|
1974
2144
|
return profile.costPer1M.inputUSD * BLENDED_COST_INPUT_WEIGHT + profile.costPer1M.outputUSD * BLENDED_COST_OUTPUT_WEIGHT;
|
|
1975
2145
|
}
|
|
1976
|
-
function
|
|
2146
|
+
function modelKey3(profile) {
|
|
1977
2147
|
return `${profile.ref.providerID}/${profile.ref.modelID}`;
|
|
1978
2148
|
}
|
|
1979
2149
|
function compareCapableFrontier(req, left, right) {
|
|
@@ -1989,7 +2159,7 @@ function compareCapableFrontier(req, left, right) {
|
|
|
1989
2159
|
if (reasoningWasteDelta !== 0) {
|
|
1990
2160
|
return reasoningWasteDelta;
|
|
1991
2161
|
}
|
|
1992
|
-
return
|
|
2162
|
+
return modelKey3(left).localeCompare(modelKey3(right));
|
|
1993
2163
|
}
|
|
1994
2164
|
function satisfiesRequirement(req, profile) {
|
|
1995
2165
|
return profile.kind === "frontier" && profile.availability !== "unavailable" && profile.contextWindow >= req.minContextWindow && profile.reasoningTier >= req.minReasoningTier && profile.codeQualityTier >= req.minCodeQualityTier && (!req.needsTools || profile.supportsToolCalling) && (!req.needsVision || profile.supportsVision);
|
|
@@ -1999,13 +2169,7 @@ function selectCheapestCapableFrontier(req, profiles) {
|
|
|
1999
2169
|
return selected?.ref ?? null;
|
|
2000
2170
|
}
|
|
2001
2171
|
|
|
2002
|
-
// src/router/
|
|
2003
|
-
function resolveConfiguredFrontierBaseline(config) {
|
|
2004
|
-
if (config.baseline.mode === "pinned" && config.baseline.pinnedModel !== null) {
|
|
2005
|
-
return config.baseline.pinnedModel;
|
|
2006
|
-
}
|
|
2007
|
-
return config.baseline.hardDefault;
|
|
2008
|
-
}
|
|
2172
|
+
// src/router/frontierBaseline.ts
|
|
2009
2173
|
function resolveFrontierBaseline(input, tier) {
|
|
2010
2174
|
if (input.config.baseline.mode === "pinned" && input.config.baseline.pinnedModel !== null) {
|
|
2011
2175
|
return { model: input.config.baseline.pinnedModel, rationale: [] };
|
|
@@ -2025,48 +2189,8 @@ function resolveFrontierBaseline(input, tier) {
|
|
|
2025
2189
|
}
|
|
2026
2190
|
return { model: input.config.baseline.hardDefault, rationale: [] };
|
|
2027
2191
|
}
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
}
|
|
2031
|
-
function modelKey3(model) {
|
|
2032
|
-
return `${model.providerID}/${model.modelID}`;
|
|
2033
|
-
}
|
|
2034
|
-
function sameModel(left, right) {
|
|
2035
|
-
return left.providerID === right.providerID && left.modelID === right.modelID;
|
|
2036
|
-
}
|
|
2037
|
-
function compareModels(left, right) {
|
|
2038
|
-
return modelKey3(left).localeCompare(modelKey3(right));
|
|
2039
|
-
}
|
|
2040
|
-
function uniqueModelSelections(models) {
|
|
2041
|
-
const byKey = new Map;
|
|
2042
|
-
for (const model of models) {
|
|
2043
|
-
byKey.set(modelKey3(model), model);
|
|
2044
|
-
}
|
|
2045
|
-
return [...byKey.values()].sort(compareModels);
|
|
2046
|
-
}
|
|
2047
|
-
function defaultAvailableModels2(config) {
|
|
2048
|
-
return [
|
|
2049
|
-
{
|
|
2050
|
-
...localDefault(config),
|
|
2051
|
-
kind: "local",
|
|
2052
|
-
available: true
|
|
2053
|
-
},
|
|
2054
|
-
{
|
|
2055
|
-
...resolveConfiguredFrontierBaseline(config),
|
|
2056
|
-
kind: "frontier",
|
|
2057
|
-
available: true
|
|
2058
|
-
}
|
|
2059
|
-
].sort(compareAvailableModels2);
|
|
2060
|
-
}
|
|
2061
|
-
function compareAvailableModels2(left, right) {
|
|
2062
|
-
return compareModels(left, right);
|
|
2063
|
-
}
|
|
2064
|
-
function availableModels(input) {
|
|
2065
|
-
return (input.availableModels ?? defaultAvailableModels2(input.config)).slice().sort(compareAvailableModels2);
|
|
2066
|
-
}
|
|
2067
|
-
function listedModel(input, model) {
|
|
2068
|
-
return availableModels(input).find((candidate) => sameModel(candidate, model));
|
|
2069
|
-
}
|
|
2192
|
+
|
|
2193
|
+
// src/router/chooseModel.ts
|
|
2070
2194
|
function localStatus(input, model) {
|
|
2071
2195
|
const listed = listedModel(input, model);
|
|
2072
2196
|
return {
|
|
@@ -2074,18 +2198,6 @@ function localStatus(input, model) {
|
|
|
2074
2198
|
missingTools: input.task.requiresTools === true && listed?.supportsTools === false
|
|
2075
2199
|
};
|
|
2076
2200
|
}
|
|
2077
|
-
function frontierAvailable(input, model) {
|
|
2078
|
-
return listedModel(input, model)?.available !== false;
|
|
2079
|
-
}
|
|
2080
|
-
function localCandidateIsUsable(input, model) {
|
|
2081
|
-
return model.kind === "local" && model.available && !(input.task.requiresTools === true && model.supportsTools === false);
|
|
2082
|
-
}
|
|
2083
|
-
function availableLocalFallbacks(input, selected) {
|
|
2084
|
-
return uniqueModelSelections(availableModels(input).filter((model) => localCandidateIsUsable(input, model)).filter((model) => !sameModel(model, selected)).map((model) => ({
|
|
2085
|
-
providerID: model.providerID,
|
|
2086
|
-
modelID: model.modelID
|
|
2087
|
-
})));
|
|
2088
|
-
}
|
|
2089
2201
|
function buildFallbackChain(input, selected, frontier, allowFrontier) {
|
|
2090
2202
|
const chain = availableLocalFallbacks(input, selected);
|
|
2091
2203
|
if (allowFrontier && !sameModel(frontier, selected) && frontierAvailable(input, frontier)) {
|
|
@@ -2141,21 +2253,6 @@ function resolveFrontierPrimary(input, frontier, rationale) {
|
|
|
2141
2253
|
function tierForInput(input) {
|
|
2142
2254
|
return input.tier ?? classifyHeuristic(input.task).tier;
|
|
2143
2255
|
}
|
|
2144
|
-
function modelProfile(input, model) {
|
|
2145
|
-
return input.profiles?.find((profile) => sameModel(profile.ref, model));
|
|
2146
|
-
}
|
|
2147
|
-
function estimatedCostUSD(input, model) {
|
|
2148
|
-
const profile = modelProfile(input, model);
|
|
2149
|
-
if (profile === undefined) {
|
|
2150
|
-
return 0;
|
|
2151
|
-
}
|
|
2152
|
-
const inputTokens = input.task.estimatedInputTokens ?? 0;
|
|
2153
|
-
const outputTokens = input.task.estimatedOutputTokens ?? 0;
|
|
2154
|
-
return inputTokens / 1e6 * profile.costPer1M.inputUSD + outputTokens / 1e6 * profile.costPer1M.outputUSD;
|
|
2155
|
-
}
|
|
2156
|
-
function roundUSD(value) {
|
|
2157
|
-
return Math.round(value * 1000000000000) / 1000000000000;
|
|
2158
|
-
}
|
|
2159
2256
|
function finalizeDecision(input, tier, frontier, budgetAction, core) {
|
|
2160
2257
|
const selectedCostUSD = estimatedCostUSD(input, core.selected);
|
|
2161
2258
|
const baselineCostUSD = estimatedCostUSD(input, frontier.model);
|
|
@@ -2482,10 +2579,22 @@ function deriveTaskSignals(input, output) {
|
|
|
2482
2579
|
}
|
|
2483
2580
|
return signals;
|
|
2484
2581
|
}
|
|
2582
|
+
function injectMemoryBlock(output, block) {
|
|
2583
|
+
for (const part of output.parts) {
|
|
2584
|
+
if (part.type === "text" && typeof part.text === "string") {
|
|
2585
|
+
part.text = `${block}
|
|
2586
|
+
|
|
2587
|
+
${part.text}`;
|
|
2588
|
+
return true;
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
return false;
|
|
2592
|
+
}
|
|
2485
2593
|
function createChatMessageHook(config, getAvailable, options = {}) {
|
|
2486
2594
|
const sink = options.sink ?? createNullEventSink();
|
|
2487
2595
|
const now = options.now ?? Date.now;
|
|
2488
2596
|
return async (input, output) => {
|
|
2597
|
+
const prompt = promptText(output);
|
|
2489
2598
|
const signals = deriveTaskSignals(input, output);
|
|
2490
2599
|
const decision2 = chooseModel({
|
|
2491
2600
|
config,
|
|
@@ -2495,7 +2604,7 @@ function createChatMessageHook(config, getAvailable, options = {}) {
|
|
|
2495
2604
|
output.message.model = decision2.selected;
|
|
2496
2605
|
const telemetryContext = {
|
|
2497
2606
|
ts: now(),
|
|
2498
|
-
promptHash: hashPrompt(
|
|
2607
|
+
promptHash: hashPrompt(prompt),
|
|
2499
2608
|
promptChars: signals.promptChars,
|
|
2500
2609
|
sessionID: input.sessionID ?? output.message.sessionID
|
|
2501
2610
|
};
|
|
@@ -2506,6 +2615,14 @@ function createChatMessageHook(config, getAvailable, options = {}) {
|
|
|
2506
2615
|
telemetryContext.tokensOut = signals.estimatedOutputTokens;
|
|
2507
2616
|
}
|
|
2508
2617
|
emitTelemetry(sink, costRecordToRouteEvent(toCostRecord(decision2, telemetryContext)));
|
|
2618
|
+
if (options.injectMemory !== undefined) {
|
|
2619
|
+
try {
|
|
2620
|
+
const block = await options.injectMemory(prompt);
|
|
2621
|
+
if (block !== null && block.length > 0) {
|
|
2622
|
+
injectMemoryBlock(output, block);
|
|
2623
|
+
}
|
|
2624
|
+
} catch {}
|
|
2625
|
+
}
|
|
2509
2626
|
};
|
|
2510
2627
|
}
|
|
2511
2628
|
function createHooks(config, getAvailable, options = {}) {
|
|
@@ -2514,6 +2631,247 @@ function createHooks(config, getAvailable, options = {}) {
|
|
|
2514
2631
|
};
|
|
2515
2632
|
}
|
|
2516
2633
|
|
|
2634
|
+
// src/memory/inject.ts
|
|
2635
|
+
var DEFAULT_INJECTION_PARAMS = {
|
|
2636
|
+
maxChars: 1200,
|
|
2637
|
+
header: "Contexto de memoria de openteam (solo referencia):",
|
|
2638
|
+
maxItems: 8
|
|
2639
|
+
};
|
|
2640
|
+
function formatRecordLine(record) {
|
|
2641
|
+
if (record.kind === "fact") {
|
|
2642
|
+
const base = `- ${record.subject} ${record.predicate} ${record.object}`;
|
|
2643
|
+
return record.category === null ? base : `${base} (${record.category})`;
|
|
2644
|
+
}
|
|
2645
|
+
if (record.kind === "preference") {
|
|
2646
|
+
const base = `- [${record.category}] ${record.preference}`;
|
|
2647
|
+
return record.context === null ? base : `${base} — ${record.context}`;
|
|
2648
|
+
}
|
|
2649
|
+
const aliases = record.aliases.length > 0 ? ` (alias: ${record.aliases.join(", ")})` : "";
|
|
2650
|
+
return `- ${record.canonicalName} [${record.type}]${aliases}`;
|
|
2651
|
+
}
|
|
2652
|
+
function buildMemoryBlock(results, params = DEFAULT_INJECTION_PARAMS) {
|
|
2653
|
+
if (results.length === 0) {
|
|
2654
|
+
return null;
|
|
2655
|
+
}
|
|
2656
|
+
const lines = [];
|
|
2657
|
+
let used = params.header.length;
|
|
2658
|
+
for (const result of results) {
|
|
2659
|
+
if (lines.length >= params.maxItems) {
|
|
2660
|
+
break;
|
|
2661
|
+
}
|
|
2662
|
+
const line = formatRecordLine(result.record);
|
|
2663
|
+
const cost = line.length + 1;
|
|
2664
|
+
if (used + cost > params.maxChars) {
|
|
2665
|
+
break;
|
|
2666
|
+
}
|
|
2667
|
+
lines.push(line);
|
|
2668
|
+
used += cost;
|
|
2669
|
+
}
|
|
2670
|
+
if (lines.length === 0) {
|
|
2671
|
+
return null;
|
|
2672
|
+
}
|
|
2673
|
+
return `${params.header}
|
|
2674
|
+
${lines.join(`
|
|
2675
|
+
`)}`;
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2678
|
+
// src/memory/types.ts
|
|
2679
|
+
import { z as z5 } from "zod";
|
|
2680
|
+
var SHARED_OWNER_KEY = "*";
|
|
2681
|
+
var OwnerKeySchema = z5.string().min(1);
|
|
2682
|
+
var MemoryKindSchema = z5.enum(["fact", "preference", "entity"]);
|
|
2683
|
+
var MemoryBaseSchema = z5.object({
|
|
2684
|
+
id: z5.string().min(1),
|
|
2685
|
+
ownerKey: OwnerKeySchema,
|
|
2686
|
+
confidence: z5.number().min(0).max(1),
|
|
2687
|
+
validFrom: z5.number().finite(),
|
|
2688
|
+
validUntil: z5.number().finite().nullable().default(null),
|
|
2689
|
+
createdAt: z5.number().finite(),
|
|
2690
|
+
invalidatedAt: z5.number().finite().nullable().default(null),
|
|
2691
|
+
sourceHash: z5.string().min(1),
|
|
2692
|
+
supersededBy: z5.string().min(1).nullable().default(null)
|
|
2693
|
+
});
|
|
2694
|
+
var FactSchema = MemoryBaseSchema.extend({
|
|
2695
|
+
kind: z5.literal("fact"),
|
|
2696
|
+
subject: z5.string().min(1),
|
|
2697
|
+
predicate: z5.string().min(1),
|
|
2698
|
+
object: z5.string().min(1),
|
|
2699
|
+
category: z5.string().min(1).nullable().default(null)
|
|
2700
|
+
});
|
|
2701
|
+
var PreferenceSchema = MemoryBaseSchema.extend({
|
|
2702
|
+
kind: z5.literal("preference"),
|
|
2703
|
+
category: z5.string().min(1),
|
|
2704
|
+
preference: z5.string().min(1),
|
|
2705
|
+
context: z5.string().min(1).nullable().default(null),
|
|
2706
|
+
lastAccessedAt: z5.number().finite().nullable().default(null),
|
|
2707
|
+
accessCount: z5.number().int().min(0).default(0)
|
|
2708
|
+
});
|
|
2709
|
+
var EntitySchema = MemoryBaseSchema.extend({
|
|
2710
|
+
kind: z5.literal("entity"),
|
|
2711
|
+
canonicalName: z5.string().min(1),
|
|
2712
|
+
type: z5.string().min(1),
|
|
2713
|
+
aliases: z5.array(z5.string().min(1)).default([])
|
|
2714
|
+
});
|
|
2715
|
+
var MemoryRecordSchema = z5.discriminatedUnion("kind", [
|
|
2716
|
+
FactSchema,
|
|
2717
|
+
PreferenceSchema,
|
|
2718
|
+
EntitySchema
|
|
2719
|
+
]);
|
|
2720
|
+
var RecallQuerySchema = z5.object({
|
|
2721
|
+
ownerKey: OwnerKeySchema,
|
|
2722
|
+
kinds: z5.array(MemoryKindSchema).default(["fact", "preference", "entity"]),
|
|
2723
|
+
asOf: z5.number().finite().nullable().default(null),
|
|
2724
|
+
limit: z5.number().int().positive().default(8),
|
|
2725
|
+
minSimilarity: z5.number().min(0).max(1).default(0.2),
|
|
2726
|
+
includeShared: z5.boolean().default(true)
|
|
2727
|
+
});
|
|
2728
|
+
|
|
2729
|
+
// src/memory/rank.ts
|
|
2730
|
+
var DAY_MS = 86400000;
|
|
2731
|
+
var DEFAULT_RANK_SIGNALS = {
|
|
2732
|
+
similarityWeight: 1,
|
|
2733
|
+
recencyWeight: 0.2,
|
|
2734
|
+
accessWeight: 0.1,
|
|
2735
|
+
recencyHalfLifeMs: 14 * DAY_MS
|
|
2736
|
+
};
|
|
2737
|
+
function recencyTimestamp(record) {
|
|
2738
|
+
if (record.kind === "preference" && record.lastAccessedAt !== null) {
|
|
2739
|
+
return record.lastAccessedAt;
|
|
2740
|
+
}
|
|
2741
|
+
return record.createdAt;
|
|
2742
|
+
}
|
|
2743
|
+
function recencyScore(record, signals) {
|
|
2744
|
+
const ageMs = Math.max(0, signals.now - recencyTimestamp(record));
|
|
2745
|
+
return 0.5 ** (ageMs / signals.recencyHalfLifeMs);
|
|
2746
|
+
}
|
|
2747
|
+
function accessScore(record) {
|
|
2748
|
+
if (record.kind !== "preference") {
|
|
2749
|
+
return 0;
|
|
2750
|
+
}
|
|
2751
|
+
return 1 - 1 / (1 + record.accessCount);
|
|
2752
|
+
}
|
|
2753
|
+
function scoreCandidate(candidate, signals) {
|
|
2754
|
+
return signals.similarityWeight * candidate.similarity + signals.recencyWeight * recencyScore(candidate.record, signals) + signals.accessWeight * accessScore(candidate.record);
|
|
2755
|
+
}
|
|
2756
|
+
function rankRecall(candidates, signals) {
|
|
2757
|
+
return candidates.map((candidate) => ({
|
|
2758
|
+
...candidate,
|
|
2759
|
+
score: scoreCandidate(candidate, signals)
|
|
2760
|
+
})).sort((a, b) => {
|
|
2761
|
+
if (b.score !== a.score) {
|
|
2762
|
+
return b.score - a.score;
|
|
2763
|
+
}
|
|
2764
|
+
return a.record.id < b.record.id ? -1 : a.record.id > b.record.id ? 1 : 0;
|
|
2765
|
+
});
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
// src/memory/temporal.ts
|
|
2769
|
+
function isTransactionActiveAt(record, asOf) {
|
|
2770
|
+
return record.invalidatedAt === null || record.invalidatedAt > asOf;
|
|
2771
|
+
}
|
|
2772
|
+
function isValidAt(record, asOf) {
|
|
2773
|
+
if (record.validFrom > asOf) {
|
|
2774
|
+
return false;
|
|
2775
|
+
}
|
|
2776
|
+
return record.validUntil === null || record.validUntil > asOf;
|
|
2777
|
+
}
|
|
2778
|
+
function isActiveAt(record, asOf) {
|
|
2779
|
+
return isTransactionActiveAt(record, asOf) && isValidAt(record, asOf);
|
|
2780
|
+
}
|
|
2781
|
+
function filterActive(records, asOf) {
|
|
2782
|
+
return records.filter((record) => isActiveAt(record, asOf));
|
|
2783
|
+
}
|
|
2784
|
+
function coalesceWindow(a, b) {
|
|
2785
|
+
const validFrom = Math.min(a.validFrom, b.validFrom);
|
|
2786
|
+
const validUntil = a.validUntil === null || b.validUntil === null ? null : Math.max(a.validUntil, b.validUntil);
|
|
2787
|
+
return { validFrom, validUntil };
|
|
2788
|
+
}
|
|
2789
|
+
|
|
2790
|
+
// src/memory/vector.ts
|
|
2791
|
+
function dot(a, b) {
|
|
2792
|
+
if (a.length !== b.length) {
|
|
2793
|
+
throw new Error(`dimension mismatch: ${a.length} vs ${b.length}`);
|
|
2794
|
+
}
|
|
2795
|
+
let sum = 0;
|
|
2796
|
+
for (let i = 0;i < a.length; i += 1) {
|
|
2797
|
+
sum += a[i] * b[i];
|
|
2798
|
+
}
|
|
2799
|
+
return sum;
|
|
2800
|
+
}
|
|
2801
|
+
function norm(a) {
|
|
2802
|
+
let sum = 0;
|
|
2803
|
+
for (let i = 0;i < a.length; i += 1) {
|
|
2804
|
+
const value = a[i];
|
|
2805
|
+
sum += value * value;
|
|
2806
|
+
}
|
|
2807
|
+
return Math.sqrt(sum);
|
|
2808
|
+
}
|
|
2809
|
+
function cosineSimilarity(a, b) {
|
|
2810
|
+
const denom = norm(a) * norm(b);
|
|
2811
|
+
if (denom === 0) {
|
|
2812
|
+
return 0;
|
|
2813
|
+
}
|
|
2814
|
+
return dot(a, b) / denom;
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2817
|
+
// src/memory/recall.ts
|
|
2818
|
+
function matchesScope(record, query) {
|
|
2819
|
+
if (record.ownerKey === query.ownerKey) {
|
|
2820
|
+
return true;
|
|
2821
|
+
}
|
|
2822
|
+
return query.includeShared && record.ownerKey === SHARED_OWNER_KEY;
|
|
2823
|
+
}
|
|
2824
|
+
function recall(records, queryEmbedding, query, deps) {
|
|
2825
|
+
const asOf = query.asOf ?? deps.now;
|
|
2826
|
+
const kinds = new Set(query.kinds);
|
|
2827
|
+
const candidates = [];
|
|
2828
|
+
for (const record of filterActive(records, asOf)) {
|
|
2829
|
+
if (!kinds.has(record.kind) || !matchesScope(record, query)) {
|
|
2830
|
+
continue;
|
|
2831
|
+
}
|
|
2832
|
+
const embedding = deps.embeddings.get(record.id);
|
|
2833
|
+
if (embedding === undefined) {
|
|
2834
|
+
continue;
|
|
2835
|
+
}
|
|
2836
|
+
const similarity = cosineSimilarity(queryEmbedding, embedding);
|
|
2837
|
+
if (similarity < query.minSimilarity) {
|
|
2838
|
+
continue;
|
|
2839
|
+
}
|
|
2840
|
+
candidates.push({ record, similarity });
|
|
2841
|
+
}
|
|
2842
|
+
const signals = {
|
|
2843
|
+
now: deps.now,
|
|
2844
|
+
...deps.signals ?? DEFAULT_RANK_SIGNALS
|
|
2845
|
+
};
|
|
2846
|
+
return rankRecall(candidates, signals).slice(0, query.limit);
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2849
|
+
// src/storage/index/memoryRecall.ts
|
|
2850
|
+
async function recallMemory(deps, queryText, query) {
|
|
2851
|
+
const [queryEmbedding] = await deps.embedder([queryText]);
|
|
2852
|
+
if (queryEmbedding === undefined) {
|
|
2853
|
+
return [];
|
|
2854
|
+
}
|
|
2855
|
+
const records = deps.index.allRecords();
|
|
2856
|
+
const embeddings = deps.index.embeddingMap();
|
|
2857
|
+
const recallDeps = deps.signals === undefined ? { embeddings, now: deps.now } : { embeddings, now: deps.now, signals: deps.signals };
|
|
2858
|
+
return recall(records, queryEmbedding, query, recallDeps);
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
// src/plugin/memoryInject.ts
|
|
2862
|
+
function buildMemoryInjector(deps, policy) {
|
|
2863
|
+
return async (queryText) => {
|
|
2864
|
+
const query = RecallQuerySchema.parse({
|
|
2865
|
+
ownerKey: policy.ownerKey,
|
|
2866
|
+
limit: policy.maxResults,
|
|
2867
|
+
minSimilarity: policy.minSimilarity,
|
|
2868
|
+
includeShared: policy.includeShared
|
|
2869
|
+
});
|
|
2870
|
+
const results = await recallMemory({ index: deps.index, embedder: deps.embedder, now: deps.now() }, queryText, query);
|
|
2871
|
+
return buildMemoryBlock(results, policy.injection);
|
|
2872
|
+
};
|
|
2873
|
+
}
|
|
2874
|
+
|
|
2517
2875
|
// src/plugin/toolcalls.ts
|
|
2518
2876
|
function key(sessionID, callID) {
|
|
2519
2877
|
return `${sessionID}\x00${callID}`;
|
|
@@ -2546,6 +2904,414 @@ function createToolcallTracker(deps) {
|
|
|
2546
2904
|
};
|
|
2547
2905
|
}
|
|
2548
2906
|
|
|
2907
|
+
// src/local/embeddings.ts
|
|
2908
|
+
function parseEmbeddingsResponse(payload) {
|
|
2909
|
+
if (typeof payload !== "object" || payload === null || !Array.isArray(payload.data)) {
|
|
2910
|
+
throw new Error("Respuesta de /embeddings malformada: falta 'data'");
|
|
2911
|
+
}
|
|
2912
|
+
const data = payload.data;
|
|
2913
|
+
return data.map((entry, index) => {
|
|
2914
|
+
const embedding = typeof entry === "object" && entry !== null ? entry.embedding : undefined;
|
|
2915
|
+
if (!Array.isArray(embedding) || !embedding.every((n) => typeof n === "number" && Number.isFinite(n))) {
|
|
2916
|
+
throw new Error(`Respuesta de /embeddings malformada: vector inválido en índice ${index}`);
|
|
2917
|
+
}
|
|
2918
|
+
return embedding;
|
|
2919
|
+
});
|
|
2920
|
+
}
|
|
2921
|
+
async function embedTexts(request, deps) {
|
|
2922
|
+
if (request.texts.length === 0) {
|
|
2923
|
+
return [];
|
|
2924
|
+
}
|
|
2925
|
+
let response;
|
|
2926
|
+
try {
|
|
2927
|
+
response = await deps.fetch(embeddingsEndpoint(request.baseURL), {
|
|
2928
|
+
method: "POST",
|
|
2929
|
+
headers: {
|
|
2930
|
+
"content-type": "application/json",
|
|
2931
|
+
accept: "application/json"
|
|
2932
|
+
},
|
|
2933
|
+
body: JSON.stringify({
|
|
2934
|
+
model: request.modelID,
|
|
2935
|
+
input: [...request.texts]
|
|
2936
|
+
})
|
|
2937
|
+
});
|
|
2938
|
+
} catch (error) {
|
|
2939
|
+
throw new Error(`Embeddings local falló: ${errorMessage(error)}`);
|
|
2940
|
+
}
|
|
2941
|
+
if (!response.ok) {
|
|
2942
|
+
throw new Error(`Embeddings local falló: HTTP ${response.status} en /embeddings`);
|
|
2943
|
+
}
|
|
2944
|
+
let payload;
|
|
2945
|
+
try {
|
|
2946
|
+
payload = await response.json();
|
|
2947
|
+
} catch (error) {
|
|
2948
|
+
throw new Error(`Embeddings local falló: ${errorMessage(error)}`);
|
|
2949
|
+
}
|
|
2950
|
+
const vectors = parseEmbeddingsResponse(payload);
|
|
2951
|
+
if (vectors.length !== request.texts.length) {
|
|
2952
|
+
throw new Error(`Embeddings local devolvió ${vectors.length} vectores para ${request.texts.length} textos`);
|
|
2953
|
+
}
|
|
2954
|
+
return vectors;
|
|
2955
|
+
}
|
|
2956
|
+
function createLocalEmbedder(request, deps) {
|
|
2957
|
+
return (texts) => embedTexts({ ...request, texts }, deps);
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2960
|
+
// src/storage/index/bunSqlite.ts
|
|
2961
|
+
async function createBunSqliteDatabase(path) {
|
|
2962
|
+
const mod = await import("bun:sqlite");
|
|
2963
|
+
return new mod.Database(path);
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2966
|
+
// src/memory/merge.ts
|
|
2967
|
+
var SEP = "\x00";
|
|
2968
|
+
function factSlotKey(fact) {
|
|
2969
|
+
return [fact.subject, fact.predicate, fact.ownerKey].join(SEP);
|
|
2970
|
+
}
|
|
2971
|
+
function factValueKey(fact) {
|
|
2972
|
+
return [factSlotKey(fact), fact.object].join(SEP);
|
|
2973
|
+
}
|
|
2974
|
+
function preferenceSlotKey(preference) {
|
|
2975
|
+
return [preference.category, preference.ownerKey].join(SEP);
|
|
2976
|
+
}
|
|
2977
|
+
function preferenceValueKey(preference) {
|
|
2978
|
+
return [preferenceSlotKey(preference), preference.preference].join(SEP);
|
|
2979
|
+
}
|
|
2980
|
+
function entitySlotKey(entity) {
|
|
2981
|
+
return [entity.canonicalName, entity.type, entity.ownerKey].join(SEP);
|
|
2982
|
+
}
|
|
2983
|
+
function coalesceFact(existing, incoming) {
|
|
2984
|
+
const window = coalesceWindow(existing, incoming);
|
|
2985
|
+
return {
|
|
2986
|
+
...existing,
|
|
2987
|
+
validFrom: window.validFrom,
|
|
2988
|
+
validUntil: window.validUntil,
|
|
2989
|
+
confidence: Math.max(existing.confidence, incoming.confidence)
|
|
2990
|
+
};
|
|
2991
|
+
}
|
|
2992
|
+
function applyFact(state, incoming, now) {
|
|
2993
|
+
const incomingSlot = factSlotKey(incoming);
|
|
2994
|
+
const incomingValue = factValueKey(incoming);
|
|
2995
|
+
const superseded = [];
|
|
2996
|
+
const records = [];
|
|
2997
|
+
let reaffirmed = false;
|
|
2998
|
+
for (const fact of state) {
|
|
2999
|
+
if (!isActiveAt(fact, now)) {
|
|
3000
|
+
records.push(fact);
|
|
3001
|
+
continue;
|
|
3002
|
+
}
|
|
3003
|
+
if (factValueKey(fact) === incomingValue) {
|
|
3004
|
+
records.push(coalesceFact(fact, incoming));
|
|
3005
|
+
reaffirmed = true;
|
|
3006
|
+
continue;
|
|
3007
|
+
}
|
|
3008
|
+
if (factSlotKey(fact) === incomingSlot) {
|
|
3009
|
+
const dead = {
|
|
3010
|
+
...fact,
|
|
3011
|
+
invalidatedAt: now,
|
|
3012
|
+
supersededBy: incoming.id
|
|
3013
|
+
};
|
|
3014
|
+
superseded.push(dead);
|
|
3015
|
+
records.push(dead);
|
|
3016
|
+
continue;
|
|
3017
|
+
}
|
|
3018
|
+
records.push(fact);
|
|
3019
|
+
}
|
|
3020
|
+
if (!reaffirmed) {
|
|
3021
|
+
records.push(incoming);
|
|
3022
|
+
}
|
|
3023
|
+
return { records, superseded };
|
|
3024
|
+
}
|
|
3025
|
+
function applyPreference(state, incoming, now) {
|
|
3026
|
+
const incomingSlot = preferenceSlotKey(incoming);
|
|
3027
|
+
const incomingValue = preferenceValueKey(incoming);
|
|
3028
|
+
const superseded = [];
|
|
3029
|
+
const records = [];
|
|
3030
|
+
let reaffirmed = false;
|
|
3031
|
+
for (const preference of state) {
|
|
3032
|
+
if (!isActiveAt(preference, now)) {
|
|
3033
|
+
records.push(preference);
|
|
3034
|
+
continue;
|
|
3035
|
+
}
|
|
3036
|
+
if (preferenceValueKey(preference) === incomingValue) {
|
|
3037
|
+
records.push({
|
|
3038
|
+
...preference,
|
|
3039
|
+
confidence: Math.max(preference.confidence, incoming.confidence)
|
|
3040
|
+
});
|
|
3041
|
+
reaffirmed = true;
|
|
3042
|
+
continue;
|
|
3043
|
+
}
|
|
3044
|
+
if (preferenceSlotKey(preference) === incomingSlot) {
|
|
3045
|
+
const dead = {
|
|
3046
|
+
...preference,
|
|
3047
|
+
invalidatedAt: now,
|
|
3048
|
+
supersededBy: incoming.id
|
|
3049
|
+
};
|
|
3050
|
+
superseded.push(dead);
|
|
3051
|
+
records.push(dead);
|
|
3052
|
+
continue;
|
|
3053
|
+
}
|
|
3054
|
+
records.push(preference);
|
|
3055
|
+
}
|
|
3056
|
+
if (!reaffirmed) {
|
|
3057
|
+
records.push(incoming);
|
|
3058
|
+
}
|
|
3059
|
+
return { records, superseded };
|
|
3060
|
+
}
|
|
3061
|
+
function mergeAliases(existing, incoming) {
|
|
3062
|
+
const seen = new Set(existing);
|
|
3063
|
+
const merged = [...existing];
|
|
3064
|
+
for (const alias of incoming) {
|
|
3065
|
+
if (!seen.has(alias)) {
|
|
3066
|
+
seen.add(alias);
|
|
3067
|
+
merged.push(alias);
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
return merged;
|
|
3071
|
+
}
|
|
3072
|
+
function applyEntity(state, incoming, now) {
|
|
3073
|
+
const incomingSlot = entitySlotKey(incoming);
|
|
3074
|
+
const records = [];
|
|
3075
|
+
let merged = false;
|
|
3076
|
+
for (const entity of state) {
|
|
3077
|
+
if (isActiveAt(entity, now) && entitySlotKey(entity) === incomingSlot) {
|
|
3078
|
+
records.push({
|
|
3079
|
+
...entity,
|
|
3080
|
+
aliases: mergeAliases(entity.aliases, incoming.aliases),
|
|
3081
|
+
confidence: Math.max(entity.confidence, incoming.confidence)
|
|
3082
|
+
});
|
|
3083
|
+
merged = true;
|
|
3084
|
+
continue;
|
|
3085
|
+
}
|
|
3086
|
+
records.push(entity);
|
|
3087
|
+
}
|
|
3088
|
+
if (!merged) {
|
|
3089
|
+
records.push(incoming);
|
|
3090
|
+
}
|
|
3091
|
+
return { records, superseded: [] };
|
|
3092
|
+
}
|
|
3093
|
+
|
|
3094
|
+
// src/memory/fold.ts
|
|
3095
|
+
function emptyState() {
|
|
3096
|
+
return { facts: [], preferences: [], entities: [] };
|
|
3097
|
+
}
|
|
3098
|
+
function applyTombstone(state, tombstone) {
|
|
3099
|
+
const mark = (records) => records.map((record) => record.id === tombstone.id ? {
|
|
3100
|
+
...record,
|
|
3101
|
+
invalidatedAt: tombstone.invalidatedAt,
|
|
3102
|
+
supersededBy: tombstone.supersededBy
|
|
3103
|
+
} : record);
|
|
3104
|
+
if (tombstone.kind === "fact") {
|
|
3105
|
+
state.facts = mark(state.facts);
|
|
3106
|
+
} else if (tombstone.kind === "preference") {
|
|
3107
|
+
state.preferences = mark(state.preferences);
|
|
3108
|
+
} else {
|
|
3109
|
+
state.entities = mark(state.entities);
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
function foldAssertions(assertions) {
|
|
3113
|
+
const state = emptyState();
|
|
3114
|
+
for (const assertion of assertions) {
|
|
3115
|
+
if (assertion.invalidatedAt !== null) {
|
|
3116
|
+
applyTombstone(state, assertion);
|
|
3117
|
+
continue;
|
|
3118
|
+
}
|
|
3119
|
+
if (assertion.kind === "fact") {
|
|
3120
|
+
state.facts = applyFact(state.facts, assertion, assertion.createdAt).records;
|
|
3121
|
+
} else if (assertion.kind === "preference") {
|
|
3122
|
+
state.preferences = applyPreference(state.preferences, assertion, assertion.createdAt).records;
|
|
3123
|
+
} else {
|
|
3124
|
+
state.entities = applyEntity(state.entities, assertion, assertion.createdAt).records;
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
return state;
|
|
3128
|
+
}
|
|
3129
|
+
function allRecords(state) {
|
|
3130
|
+
return [...state.facts, ...state.preferences, ...state.entities];
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
// src/memory/log.ts
|
|
3134
|
+
function parseMemoryLog(text) {
|
|
3135
|
+
const records = [];
|
|
3136
|
+
for (const line of text.split(`
|
|
3137
|
+
`)) {
|
|
3138
|
+
const trimmed = line.trim();
|
|
3139
|
+
if (trimmed.length === 0) {
|
|
3140
|
+
continue;
|
|
3141
|
+
}
|
|
3142
|
+
let candidate;
|
|
3143
|
+
try {
|
|
3144
|
+
candidate = JSON.parse(trimmed);
|
|
3145
|
+
} catch {
|
|
3146
|
+
continue;
|
|
3147
|
+
}
|
|
3148
|
+
const parsed = MemoryRecordSchema.safeParse(candidate);
|
|
3149
|
+
if (parsed.success) {
|
|
3150
|
+
records.push(parsed.data);
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3153
|
+
return records;
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
// src/storage/index/memoryIndex.ts
|
|
3157
|
+
var SCHEMA = `
|
|
3158
|
+
CREATE TABLE IF NOT EXISTS memory_records (
|
|
3159
|
+
id TEXT PRIMARY KEY,
|
|
3160
|
+
kind TEXT NOT NULL,
|
|
3161
|
+
owner_key TEXT NOT NULL,
|
|
3162
|
+
created_at INTEGER NOT NULL,
|
|
3163
|
+
invalidated_at INTEGER,
|
|
3164
|
+
payload TEXT NOT NULL
|
|
3165
|
+
);
|
|
3166
|
+
CREATE INDEX IF NOT EXISTS idx_memory_owner ON memory_records(owner_key, kind);
|
|
3167
|
+
CREATE TABLE IF NOT EXISTS memory_embeddings (
|
|
3168
|
+
record_id TEXT PRIMARY KEY,
|
|
3169
|
+
dim INTEGER NOT NULL,
|
|
3170
|
+
vector TEXT NOT NULL
|
|
3171
|
+
);
|
|
3172
|
+
`;
|
|
3173
|
+
var INSERT_SQL = `INSERT OR REPLACE INTO memory_records
|
|
3174
|
+
(id, kind, owner_key, created_at, invalidated_at, payload)
|
|
3175
|
+
VALUES (?, ?, ?, ?, ?, ?)`;
|
|
3176
|
+
var INSERT_EMBEDDING_SQL = `INSERT OR REPLACE INTO memory_embeddings
|
|
3177
|
+
(record_id, dim, vector) VALUES (?, ?, ?)`;
|
|
3178
|
+
function insertRecords(db, records) {
|
|
3179
|
+
const stmt = db.query(INSERT_SQL);
|
|
3180
|
+
db.run("BEGIN");
|
|
3181
|
+
try {
|
|
3182
|
+
for (const record of records) {
|
|
3183
|
+
stmt.run(record.id, record.kind, record.ownerKey, record.createdAt, record.invalidatedAt, JSON.stringify(record));
|
|
3184
|
+
}
|
|
3185
|
+
db.run("COMMIT");
|
|
3186
|
+
} catch (error) {
|
|
3187
|
+
db.run("ROLLBACK");
|
|
3188
|
+
throw error;
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
function createMemoryIndex(db) {
|
|
3192
|
+
db.exec(SCHEMA);
|
|
3193
|
+
const allRecordsFn = () => {
|
|
3194
|
+
const rows = db.query("SELECT payload FROM memory_records ORDER BY created_at ASC, id ASC").all();
|
|
3195
|
+
const records = [];
|
|
3196
|
+
for (const row of rows) {
|
|
3197
|
+
let candidate;
|
|
3198
|
+
try {
|
|
3199
|
+
candidate = JSON.parse(row.payload);
|
|
3200
|
+
} catch {
|
|
3201
|
+
continue;
|
|
3202
|
+
}
|
|
3203
|
+
const parsed = MemoryRecordSchema.safeParse(candidate);
|
|
3204
|
+
if (parsed.success) {
|
|
3205
|
+
records.push(parsed.data);
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
return records;
|
|
3209
|
+
};
|
|
3210
|
+
const state = () => {
|
|
3211
|
+
const facts = [];
|
|
3212
|
+
const preferences = [];
|
|
3213
|
+
const entities = [];
|
|
3214
|
+
for (const record of allRecordsFn()) {
|
|
3215
|
+
if (record.kind === "fact") {
|
|
3216
|
+
facts.push(record);
|
|
3217
|
+
} else if (record.kind === "preference") {
|
|
3218
|
+
preferences.push(record);
|
|
3219
|
+
} else {
|
|
3220
|
+
entities.push(record);
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
return { facts, preferences, entities };
|
|
3224
|
+
};
|
|
3225
|
+
return {
|
|
3226
|
+
rebuild(assertions) {
|
|
3227
|
+
const folded = allRecords(foldAssertions(assertions));
|
|
3228
|
+
db.run("DELETE FROM memory_records");
|
|
3229
|
+
insertRecords(db, folded);
|
|
3230
|
+
},
|
|
3231
|
+
allRecords: allRecordsFn,
|
|
3232
|
+
state,
|
|
3233
|
+
activeAt(asOf) {
|
|
3234
|
+
return filterActive(allRecordsFn(), asOf);
|
|
3235
|
+
},
|
|
3236
|
+
putEmbeddings(entries) {
|
|
3237
|
+
const stmt = db.query(INSERT_EMBEDDING_SQL);
|
|
3238
|
+
db.run("BEGIN");
|
|
3239
|
+
try {
|
|
3240
|
+
for (const entry of entries) {
|
|
3241
|
+
stmt.run(entry.recordId, entry.vector.length, JSON.stringify(entry.vector));
|
|
3242
|
+
}
|
|
3243
|
+
db.run("COMMIT");
|
|
3244
|
+
} catch (error) {
|
|
3245
|
+
db.run("ROLLBACK");
|
|
3246
|
+
throw error;
|
|
3247
|
+
}
|
|
3248
|
+
},
|
|
3249
|
+
embeddingMap() {
|
|
3250
|
+
const rows = db.query("SELECT record_id, vector FROM memory_embeddings").all();
|
|
3251
|
+
const map = new Map;
|
|
3252
|
+
for (const row of rows) {
|
|
3253
|
+
try {
|
|
3254
|
+
const vector = JSON.parse(row.vector);
|
|
3255
|
+
if (Array.isArray(vector) && vector.every((n) => typeof n === "number")) {
|
|
3256
|
+
map.set(row.record_id, vector);
|
|
3257
|
+
}
|
|
3258
|
+
} catch {}
|
|
3259
|
+
}
|
|
3260
|
+
return map;
|
|
3261
|
+
},
|
|
3262
|
+
pruneEmbeddings() {
|
|
3263
|
+
const result = db.run("DELETE FROM memory_embeddings WHERE record_id NOT IN (SELECT id FROM memory_records)");
|
|
3264
|
+
return typeof result?.changes === "number" ? result.changes : 0;
|
|
3265
|
+
},
|
|
3266
|
+
close() {
|
|
3267
|
+
db.close();
|
|
3268
|
+
}
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
async function rebuildMemoryIndexFromStorage(index, logPath, deps) {
|
|
3272
|
+
const text = await deps.storage.read(logPath) ?? "";
|
|
3273
|
+
const assertions = parseMemoryLog(text);
|
|
3274
|
+
index.rebuild(assertions);
|
|
3275
|
+
return assertions.length;
|
|
3276
|
+
}
|
|
3277
|
+
|
|
3278
|
+
// src/storage/index/memoryRuntime.ts
|
|
3279
|
+
async function buildMemoryRuntimeFromConfig(config, deps, options = {}) {
|
|
3280
|
+
const semantic = resolveMemorySemantic(config);
|
|
3281
|
+
if (!semantic.enabled || semantic.embeddings.provider === "none") {
|
|
3282
|
+
return;
|
|
3283
|
+
}
|
|
3284
|
+
if (options.requireInjectionEnabled === true && !semantic.injection.enabled) {
|
|
3285
|
+
return;
|
|
3286
|
+
}
|
|
3287
|
+
const runtime = config.local.runtimes.find((rt) => rt.enabled && rt.baseURL !== undefined);
|
|
3288
|
+
if (runtime?.baseURL === undefined) {
|
|
3289
|
+
return;
|
|
3290
|
+
}
|
|
3291
|
+
const modelID = semantic.embeddings.model?.modelID ?? runtime.defaultModel.modelID;
|
|
3292
|
+
const openDatabase = deps.openDatabase ?? createBunSqliteDatabase;
|
|
3293
|
+
const makeEmbedder = deps.createEmbedder ?? createLocalEmbedder;
|
|
3294
|
+
const fetchImpl = deps.fetch ?? globalThis.fetch;
|
|
3295
|
+
const now = deps.now ?? (() => Date.now());
|
|
3296
|
+
try {
|
|
3297
|
+
const db = await openDatabase(semantic.indexPath);
|
|
3298
|
+
const index = createMemoryIndex(db);
|
|
3299
|
+
await rebuildMemoryIndexFromStorage(index, semantic.logPath, {
|
|
3300
|
+
storage: deps.storage
|
|
3301
|
+
});
|
|
3302
|
+
const embedder = makeEmbedder({ baseURL: runtime.baseURL, modelID }, { fetch: fetchImpl });
|
|
3303
|
+
return {
|
|
3304
|
+
index,
|
|
3305
|
+
embedder,
|
|
3306
|
+
now,
|
|
3307
|
+
ownerKey: semantic.scope === "user" ? "user" : "project",
|
|
3308
|
+
semantic
|
|
3309
|
+
};
|
|
3310
|
+
} catch {
|
|
3311
|
+
return;
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
|
|
2549
3315
|
// src/index.ts
|
|
2550
3316
|
function createShellExec($) {
|
|
2551
3317
|
return async (command, args) => {
|
|
@@ -2565,6 +3331,24 @@ function logTelemetryError(error) {
|
|
|
2565
3331
|
const message = error instanceof Error ? error.message : String(error);
|
|
2566
3332
|
console.warn(`[openteam] telemetry write failed: ${message}`);
|
|
2567
3333
|
}
|
|
3334
|
+
async function buildMemoryInjectorFromConfig(config, storage) {
|
|
3335
|
+
const runtime = await buildMemoryRuntimeFromConfig(config, { storage }, { requireInjectionEnabled: true });
|
|
3336
|
+
if (runtime === undefined) {
|
|
3337
|
+
return;
|
|
3338
|
+
}
|
|
3339
|
+
const { index, embedder, now, ownerKey, semantic } = runtime;
|
|
3340
|
+
return buildMemoryInjector({ index, embedder, now }, {
|
|
3341
|
+
ownerKey,
|
|
3342
|
+
minSimilarity: semantic.recall.minSimilarity,
|
|
3343
|
+
maxResults: semantic.recall.maxResults,
|
|
3344
|
+
includeShared: true,
|
|
3345
|
+
injection: {
|
|
3346
|
+
maxChars: semantic.injection.maxChars,
|
|
3347
|
+
maxItems: semantic.injection.maxItems,
|
|
3348
|
+
header: "Contexto de memoria de openteam (solo referencia):"
|
|
3349
|
+
}
|
|
3350
|
+
});
|
|
3351
|
+
}
|
|
2568
3352
|
function telemetryOptions(rawOptions) {
|
|
2569
3353
|
const telemetry = rawOptions !== null && typeof rawOptions === "object" && "telemetry" in rawOptions && rawOptions.telemetry !== null && typeof rawOptions.telemetry === "object" ? rawOptions.telemetry : {};
|
|
2570
3354
|
const enabled = !("enabled" in telemetry) || telemetry.enabled !== false;
|
|
@@ -2645,7 +3429,8 @@ var server = async (ctx, rawOptions) => {
|
|
|
2645
3429
|
const sessionsDir = telemetryOptions(rawOptions).sessionsDir;
|
|
2646
3430
|
const storage = createFsStorageProvider(process.cwd());
|
|
2647
3431
|
const sink = createEventSink(rawOptions, storage);
|
|
2648
|
-
const
|
|
3432
|
+
const injectMemory = await buildMemoryInjectorFromConfig(config, storage);
|
|
3433
|
+
const hooks = createHooks(config, cache.get, injectMemory === undefined ? { sink } : { sink, injectMemory });
|
|
2649
3434
|
const cliDeps = createCliDeps(config, registry, telemetryPath, sessionsDir, storage);
|
|
2650
3435
|
const toolcalls = createToolcallTracker({ sink });
|
|
2651
3436
|
const now = () => Date.now();
|