akm-cli 0.9.0-rc.2 → 0.9.0-rc.4
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/CHANGELOG.md +40 -12
- package/README.md +7 -8
- package/SECURITY.md +5 -3
- package/dist/akm +44 -33
- package/dist/akm-migrate-storage +44 -33
- package/dist/assets/backends/schtasks-template.xml +2 -1
- package/dist/assets/improve-strategies/catchup.json +3 -1
- package/dist/assets/improve-strategies/consolidate.json +3 -1
- package/dist/assets/improve-strategies/frequent.json +3 -1
- package/dist/assets/improve-strategies/graph-refresh.json +3 -1
- package/dist/assets/improve-strategies/memory-focus.json +4 -1
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -0
- package/dist/assets/improve-strategies/quick.json +3 -1
- package/dist/assets/improve-strategies/recombine-only.json +2 -0
- package/dist/assets/improve-strategies/reflect-distill.json +1 -0
- package/dist/assets/improve-strategies/synthesize.json +2 -0
- package/dist/assets/tasks/core/backup.yml +2 -2
- package/dist/cli/config-migrate.js +554 -26
- package/dist/cli.js +28 -11
- package/dist/commands/backup-cli.js +6 -4
- package/dist/commands/config-cli.js +10 -3
- package/dist/commands/feedback-cli.js +24 -7
- package/dist/commands/health/checks.js +94 -15
- package/dist/commands/health/html-report.js +23 -2
- package/dist/commands/health/improve-metrics.js +45 -6
- package/dist/commands/health/md-report.js +10 -1
- package/dist/commands/health/surfaces.js +2 -1
- package/dist/commands/health/windows.js +1 -1
- package/dist/commands/health.js +1 -1
- package/dist/commands/improve/anti-collapse.js +3 -3
- package/dist/commands/improve/collapse-detector.js +5 -5
- package/dist/commands/improve/consolidate.js +123 -66
- package/dist/commands/improve/distill/promote-memory.js +8 -6
- package/dist/commands/improve/distill/quality-gate.js +1 -1
- package/dist/commands/improve/distill-guards.js +1 -1
- package/dist/commands/improve/distill-promotion-policy.js +32 -26
- package/dist/commands/improve/distill.js +52 -36
- package/dist/commands/improve/eligibility.js +9 -8
- package/dist/commands/improve/extract-prompt.js +2 -2
- package/dist/commands/improve/extract.js +43 -11
- package/dist/commands/improve/improve-auto-accept.js +14 -28
- package/dist/commands/improve/improve-cli.js +4 -2
- package/dist/commands/improve/improve-strategies.js +2 -1
- package/dist/commands/improve/improve.js +49 -8
- package/dist/commands/improve/loop-stages.js +11 -6
- package/dist/commands/improve/preparation.js +51 -17
- package/dist/commands/improve/procedural.js +10 -6
- package/dist/commands/improve/recombine.js +31 -7
- package/dist/commands/improve/reflect.js +24 -14
- package/dist/commands/improve/salience.js +5 -1
- package/dist/commands/improve/source-identity.js +43 -0
- package/dist/commands/migrate-cli.js +36 -0
- package/dist/commands/mv-cli.js +647 -258
- package/dist/commands/proposal/drain.js +16 -4
- package/dist/commands/proposal/proposal-cli.js +3 -2
- package/dist/commands/proposal/proposal.js +16 -55
- package/dist/commands/proposal/repository.js +664 -58
- package/dist/commands/read/curate.js +4 -2
- package/dist/commands/read/knowledge.js +4 -1
- package/dist/commands/read/search.js +6 -2
- package/dist/commands/read/show.js +8 -7
- package/dist/commands/sources/self-update.js +156 -112
- package/dist/commands/sources/sources-cli.js +7 -2
- package/dist/commands/tasks/default-tasks.js +5 -5
- package/dist/commands/tasks/tasks-cli.js +7 -3
- package/dist/commands/tasks/tasks.js +261 -68
- package/dist/core/common.js +36 -3
- package/dist/core/config/config-io.js +2 -2
- package/dist/core/config/config-schema.js +15 -3
- package/dist/core/config/config.js +14 -13
- package/dist/core/file-lock.js +2 -2
- package/dist/core/improve-result.js +87 -7
- package/dist/core/migration-backup.js +816 -171
- package/dist/core/migration-operation.js +44 -0
- package/dist/core/state/migrations.js +4 -7
- package/dist/core/state-db.js +23 -7
- package/dist/core/write-source.js +86 -18
- package/dist/indexer/db/db.js +109 -53
- package/dist/indexer/index-writer-lock.js +38 -37
- package/dist/indexer/index-written-assets.js +73 -56
- package/dist/indexer/indexer.js +5 -1
- package/dist/indexer/search/search-source.js +2 -2
- package/dist/indexer/usage/usage-events.js +8 -2
- package/dist/integrations/agent/engine-resolution.js +14 -7
- package/dist/scripts/migrate-storage.js +887 -992
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +494 -574
- package/dist/setup/detected-engines.js +7 -13
- package/dist/setup/engine-config.js +14 -4
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/connection.js +1 -1
- package/dist/setup/steps/tasks.js +1 -1
- package/dist/sources/providers/git-stash.js +58 -21
- package/dist/sources/providers/git.js +1 -1
- package/dist/storage/engines/sqlite-migrations.js +138 -3
- package/dist/storage/repositories/events-repository.js +24 -0
- package/dist/storage/repositories/proposals-repository.js +14 -0
- package/dist/storage/repositories/task-history-repository.js +30 -3
- package/dist/tasks/backends/cron.js +71 -38
- package/dist/tasks/backends/exec-utils.js +55 -3
- package/dist/tasks/backends/launchd.js +241 -50
- package/dist/tasks/backends/schtasks.js +434 -59
- package/dist/tasks/command-executable.js +93 -0
- package/dist/tasks/embedded.js +2 -0
- package/dist/tasks/parser.js +142 -6
- package/dist/tasks/resolve-akm-bin.js +19 -4
- package/dist/tasks/runner.js +258 -93
- package/dist/tasks/schedule.js +108 -19
- package/dist/tasks/scheduler-invocation.js +86 -0
- package/dist/tasks/task-id.js +37 -0
- package/dist/workflows/db.js +24 -13
- package/dist/workflows/validator.js +24 -2
- package/docs/README.md +103 -0
- package/docs/migration/release-notes/0.9.0.md +28 -9
- package/docs/migration/v0.8-to-v0.9.md +186 -26
- package/package.json +2 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
5
|
import fs from "node:fs";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import { createLockPayload, probeLock, reclaimStaleLock, releaseLock, tryAcquireLockSync, } from "../core/file-lock.js";
|
|
@@ -9,7 +10,7 @@ import { getDbPath, getIndexWriterLockPath } from "../core/paths.js";
|
|
|
9
10
|
const INDEX_WRITER_LOCK_STALE_AFTER_MS = 12 * 60 * 60 * 1000;
|
|
10
11
|
const INDEX_WRITER_WAIT_MS = 100;
|
|
11
12
|
const DEFAULT_INDEX_WRITER_MAX_WAIT_MS = 10 * 60 * 1000;
|
|
12
|
-
const
|
|
13
|
+
const leaseContext = new AsyncLocalStorage();
|
|
13
14
|
function buildPayload(purpose) {
|
|
14
15
|
return createLockPayload({
|
|
15
16
|
purpose,
|
|
@@ -25,29 +26,20 @@ function throwIfAborted(signal) {
|
|
|
25
26
|
return;
|
|
26
27
|
throw signal.reason instanceof Error ? signal.reason : new Error("index writer wait aborted");
|
|
27
28
|
}
|
|
28
|
-
function
|
|
29
|
-
const held = heldLocks.get(lockPath);
|
|
30
|
-
if (!held)
|
|
31
|
-
return;
|
|
32
|
-
held.depth -= 1;
|
|
33
|
-
if (held.depth > 0)
|
|
34
|
-
return;
|
|
35
|
-
heldLocks.delete(lockPath);
|
|
36
|
-
process.off("exit", held.exitHandler);
|
|
37
|
-
releaseLock(held.ownership);
|
|
38
|
-
}
|
|
39
|
-
function retainHeldLock(lockPath, ownership) {
|
|
40
|
-
const existing = heldLocks.get(lockPath);
|
|
41
|
-
if (existing) {
|
|
42
|
-
existing.depth += 1;
|
|
43
|
-
return { lockPath, release: () => releaseHeldLock(lockPath) };
|
|
44
|
-
}
|
|
45
|
-
if (!ownership)
|
|
46
|
-
throw new Error(`Missing ownership for index writer lock at ${lockPath}.`);
|
|
29
|
+
function createLease(lockPath, ownership) {
|
|
47
30
|
const exitHandler = () => releaseLock(ownership);
|
|
48
31
|
process.on("exit", exitHandler);
|
|
49
|
-
|
|
50
|
-
return {
|
|
32
|
+
let released = false;
|
|
33
|
+
return {
|
|
34
|
+
lockPath,
|
|
35
|
+
release: () => {
|
|
36
|
+
if (released)
|
|
37
|
+
return;
|
|
38
|
+
released = true;
|
|
39
|
+
process.off("exit", exitHandler);
|
|
40
|
+
releaseLock(ownership);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
51
43
|
}
|
|
52
44
|
export async function acquireIndexWriterLease(options) {
|
|
53
45
|
const mode = options.mode ?? "wait";
|
|
@@ -61,14 +53,10 @@ export async function acquireIndexWriterLease(options) {
|
|
|
61
53
|
const releaseBarrier = tryAcquireMaintenanceBarrier();
|
|
62
54
|
if (releaseBarrier) {
|
|
63
55
|
try {
|
|
64
|
-
if (heldLocks.has(lockPath)) {
|
|
65
|
-
options.onAcquired?.({ waitedMs: Date.now() - startedAt });
|
|
66
|
-
return retainHeldLock(lockPath);
|
|
67
|
-
}
|
|
68
56
|
const ownership = tryAcquireLockSync(lockPath, buildPayload(options.purpose));
|
|
69
57
|
if (ownership) {
|
|
70
58
|
options.onAcquired?.({ waitedMs: Date.now() - startedAt });
|
|
71
|
-
return
|
|
59
|
+
return createLease(lockPath, ownership);
|
|
72
60
|
}
|
|
73
61
|
const probe = probeLock(lockPath, { staleAfterMs: INDEX_WRITER_LOCK_STALE_AFTER_MS });
|
|
74
62
|
if (probe.state === "stale") {
|
|
@@ -97,16 +85,29 @@ export async function acquireIndexWriterLease(options) {
|
|
|
97
85
|
}
|
|
98
86
|
}
|
|
99
87
|
export async function withIndexWriterLease(options, run) {
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
88
|
+
const lockPath = getIndexWriterLockPath();
|
|
89
|
+
const inherited = leaseContext.getStore();
|
|
90
|
+
if (inherited?.has(lockPath))
|
|
91
|
+
return run();
|
|
92
|
+
const context = inherited ?? new Set();
|
|
93
|
+
const execute = async () => {
|
|
94
|
+
const lease = await acquireIndexWriterLease(options);
|
|
95
|
+
if (!lease)
|
|
96
|
+
throw new Error(`index writer lease unavailable for ${options.purpose}`);
|
|
97
|
+
context.add(lockPath);
|
|
98
|
+
try {
|
|
99
|
+
return await run();
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
context.delete(lockPath);
|
|
103
|
+
lease.release();
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
return inherited ? execute() : leaseContext.run(context, execute);
|
|
107
|
+
}
|
|
108
|
+
/** Asset writes and index rebuilds share one lease so scans cannot publish stale snapshots. */
|
|
109
|
+
export function withAssetMutationLease(purpose, run) {
|
|
110
|
+
return withIndexWriterLease({ purpose }, run);
|
|
110
111
|
}
|
|
111
112
|
export function probeIndexWriterLease() {
|
|
112
113
|
return probeLock(getIndexWriterLockPath(), { staleAfterMs: INDEX_WRITER_LOCK_STALE_AFTER_MS });
|
|
@@ -24,7 +24,8 @@ import path from "node:path";
|
|
|
24
24
|
import { getDbPath } from "../core/paths.js";
|
|
25
25
|
import { warnVerbose } from "../core/warn.js";
|
|
26
26
|
import { takeWorkflowDocument } from "../workflows/runtime/document-cache.js";
|
|
27
|
-
import { closeDatabase, getEntryCount, openExistingDatabase, rebuildFts, upsertEntry, upsertWorkflowDocument, } from "./db/db.js";
|
|
27
|
+
import { closeDatabase, deleteEntriesByIds, getEntryCount, openExistingDatabase, rebuildFts, upsertEntry, upsertWorkflowDocument, } from "./db/db.js";
|
|
28
|
+
import { withIndexWriterLease } from "./index-writer-lock.js";
|
|
28
29
|
import { generateMetadataFlat } from "./passes/metadata.js";
|
|
29
30
|
import { buildSearchText } from "./search/search-fields.js";
|
|
30
31
|
/**
|
|
@@ -47,68 +48,84 @@ export const WRITE_PATH_INDEX_BUSY_TIMEOUT_MS = 5_000;
|
|
|
47
48
|
* first read (`ensureIndex`) or an explicit `akm index`, which also cover
|
|
48
49
|
* embeddings and the other passes this fast path skips.
|
|
49
50
|
*/
|
|
50
|
-
export async function indexWrittenAssets(stashDir, filePaths) {
|
|
51
|
+
export async function indexWrittenAssets(stashDir, filePaths, options = {}) {
|
|
51
52
|
try {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
if (pairs.length === 0)
|
|
80
|
-
return;
|
|
81
|
-
const db = openExistingDatabase(dbPath);
|
|
82
|
-
try {
|
|
83
|
-
db.exec(`PRAGMA busy_timeout = ${WRITE_PATH_INDEX_BUSY_TIMEOUT_MS}`);
|
|
84
|
-
if (getEntryCount(db) === 0)
|
|
85
|
-
return;
|
|
86
|
-
for (const { file, entry } of pairs) {
|
|
87
|
-
const entryKey = `${stashDir}:${entry.type}:${entry.name}`;
|
|
88
|
-
let entryWithSize = entry;
|
|
89
|
-
try {
|
|
90
|
-
entryWithSize = { ...entry, fileSize: fs.statSync(file).size };
|
|
53
|
+
return await withIndexWriterLease({ purpose: "index-written-assets" }, async () => {
|
|
54
|
+
if (options.recoverMoves !== false) {
|
|
55
|
+
const { recoverInterruptedMoveTransactions } = await import("../commands/mv-cli.js");
|
|
56
|
+
await recoverInterruptedMoveTransactions(stashDir);
|
|
57
|
+
}
|
|
58
|
+
const dbPath = getDbPath();
|
|
59
|
+
if (!fs.existsSync(dbPath))
|
|
60
|
+
return true;
|
|
61
|
+
// The full walk never descends into dot-directories (they hold state like
|
|
62
|
+
// `.meta/`, `.stash.json`), and `shouldIndexStashFile` relies on the walker
|
|
63
|
+
// for that — mirror it here so this fast path indexes exactly what a full
|
|
64
|
+
// run would.
|
|
65
|
+
const files = filePaths.filter((f) => {
|
|
66
|
+
const rel = path.relative(stashDir, f);
|
|
67
|
+
return !rel.split(/[\\/]+/).some((segment) => segment.startsWith("."));
|
|
68
|
+
});
|
|
69
|
+
if (files.length === 0)
|
|
70
|
+
return true;
|
|
71
|
+
// Generate metadata BEFORE opening the DB so the write window stays
|
|
72
|
+
// short. One call per file keeps the entry↔path pairing exact.
|
|
73
|
+
const pairs = [];
|
|
74
|
+
const unindexable = new Set();
|
|
75
|
+
for (const file of files) {
|
|
76
|
+
if (!fs.existsSync(file)) {
|
|
77
|
+
unindexable.add(file);
|
|
78
|
+
continue;
|
|
91
79
|
}
|
|
92
|
-
|
|
93
|
-
|
|
80
|
+
const generated = await generateMetadataFlat(stashDir, [file]);
|
|
81
|
+
const entry = generated.entries[0];
|
|
82
|
+
// Workflows also carry a workflow_documents side-table upsert — handled
|
|
83
|
+
// below, mirroring the full walk — since `akm mv` rewrites citer files
|
|
84
|
+
// that can be workflows.
|
|
85
|
+
if (entry)
|
|
86
|
+
pairs.push({ file, entry });
|
|
87
|
+
else
|
|
88
|
+
unindexable.add(file);
|
|
89
|
+
}
|
|
90
|
+
const db = openExistingDatabase(dbPath);
|
|
91
|
+
try {
|
|
92
|
+
db.exec(`PRAGMA busy_timeout = ${WRITE_PATH_INDEX_BUSY_TIMEOUT_MS}`);
|
|
93
|
+
if (getEntryCount(db) === 0)
|
|
94
|
+
return true;
|
|
95
|
+
for (const file of unindexable) {
|
|
96
|
+
const rows = db.prepare("SELECT id FROM entries WHERE file_path = ?").all(file);
|
|
97
|
+
deleteEntriesByIds(db, rows.map((row) => row.id));
|
|
94
98
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
for (const { file, entry } of pairs) {
|
|
100
|
+
const entryKey = `${stashDir}:${entry.type}:${entry.name}`;
|
|
101
|
+
let entryWithSize = entry;
|
|
102
|
+
try {
|
|
103
|
+
entryWithSize = { ...entry, fileSize: fs.statSync(file).size };
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// stat raced a delete — index without the size, like the full walk does.
|
|
107
|
+
}
|
|
108
|
+
const entryId = upsertEntry(db, entryKey, path.dirname(file), file, stashDir, entryWithSize, buildSearchText(entry));
|
|
109
|
+
if (entry.type === "workflow") {
|
|
110
|
+
// Same contract as the full walk (indexer.ts): the renderer cached
|
|
111
|
+
// the parsed document during metadata generation; persist it so the
|
|
112
|
+
// workflow runtime never sees an entry without its document.
|
|
113
|
+
const doc = takeWorkflowDocument(entry);
|
|
114
|
+
if (doc)
|
|
115
|
+
upsertWorkflowDocument(db, entryId, doc, fs.readFileSync(file));
|
|
116
|
+
}
|
|
103
117
|
}
|
|
118
|
+
if (pairs.length > 0 || unindexable.size > 0)
|
|
119
|
+
rebuildFts(db, { incremental: true });
|
|
104
120
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
121
|
+
finally {
|
|
122
|
+
closeDatabase(db);
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
});
|
|
110
126
|
}
|
|
111
127
|
catch (error) {
|
|
112
128
|
warnVerbose("Write-path index update skipped (asset appears after the next full index):", error instanceof Error ? error.message : String(error));
|
|
129
|
+
return false;
|
|
113
130
|
}
|
|
114
131
|
}
|
package/dist/indexer/indexer.js
CHANGED
|
@@ -155,7 +155,7 @@ async function runFinalizePhase(ctx) {
|
|
|
155
155
|
ctx.timing.tFtsEnd = Date.now();
|
|
156
156
|
// Re-link detached usage_events and recompute utility scores.
|
|
157
157
|
onProgress({ phase: "finalize", message: "Relinking usage events." });
|
|
158
|
-
relinkUsageEvents(db);
|
|
158
|
+
relinkUsageEvents(db, { sources, defaultStashDir: stashDir });
|
|
159
159
|
onProgress({ phase: "finalize", message: "Recomputing utility scores." });
|
|
160
160
|
recomputeUtilityScores(db);
|
|
161
161
|
// Purge LLM cache entries for assets that no longer exist in the index.
|
|
@@ -326,6 +326,10 @@ async function akmIndexReal(options) {
|
|
|
326
326
|
const sourceCacheEnd = Date.now();
|
|
327
327
|
const allSourceEntries = resolveSourceEntries(stashDir, config);
|
|
328
328
|
const allSourceDirs = allSourceEntries.map((s) => s.path);
|
|
329
|
+
const { recoverInterruptedMoveTransactions } = await import("../commands/mv-cli.js");
|
|
330
|
+
for (const sourceDir of new Set([stashDir, ...allSourceDirs])) {
|
|
331
|
+
await recoverInterruptedMoveTransactions(sourceDir);
|
|
332
|
+
}
|
|
329
333
|
onProgress({
|
|
330
334
|
phase: "preflight",
|
|
331
335
|
message: `Resolved ${allSourceDirs.length} stash source${allSourceDirs.length === 1 ? "" : "s"}.`,
|
|
@@ -5,6 +5,7 @@ import fs from "node:fs";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { resolveStashDir } from "../../core/common.js";
|
|
7
7
|
import { getSources, loadConfig } from "../../core/config/config.js";
|
|
8
|
+
import { resolveGitContentRoot } from "../../core/write-source.js";
|
|
8
9
|
import { resolveSourceProviderFactory } from "../../sources/provider-factory.js";
|
|
9
10
|
// Eager side-effect imports so all built-in source providers self-register
|
|
10
11
|
// before resolveEntryContentDir() runs.
|
|
@@ -141,8 +142,7 @@ function resolveEntryContentDir(entry) {
|
|
|
141
142
|
// that subdirectory. This is a content-layout convention, not a provider
|
|
142
143
|
// capability — keep it here.
|
|
143
144
|
if (GIT_STASH_TYPES.has(entry.type)) {
|
|
144
|
-
|
|
145
|
-
return isValidDirectory(contentDir) ? contentDir : dir;
|
|
145
|
+
return resolveGitContentRoot(dir);
|
|
146
146
|
}
|
|
147
147
|
return dir;
|
|
148
148
|
}
|
|
@@ -47,8 +47,14 @@ export function getUsageEvents(db, filters) {
|
|
|
47
47
|
params.push(filters.event_type);
|
|
48
48
|
}
|
|
49
49
|
if (filters?.entry_ref) {
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
if (filters.entry_ref.includes("//")) {
|
|
51
|
+
conditions.push("entry_ref = ?");
|
|
52
|
+
params.push(filters.entry_ref);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
conditions.push("(entry_ref = ? OR substr(entry_ref, -length(?) - 2) = '//' || ?)");
|
|
56
|
+
params.push(filters.entry_ref, filters.entry_ref, filters.entry_ref);
|
|
57
|
+
}
|
|
52
58
|
}
|
|
53
59
|
if (filters?.source) {
|
|
54
60
|
conditions.push("source = ?");
|
|
@@ -164,17 +164,24 @@ function lowerAgentEngine(name, engine, config) {
|
|
|
164
164
|
timeoutMs: hasOwn(engine, "timeoutMs") ? (engine.timeoutMs ?? null) : DEFAULT_AGENT_TIMEOUT_MS,
|
|
165
165
|
};
|
|
166
166
|
}
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
const fallbackName = engine.llmEngine ?? config.defaults?.llmEngine;
|
|
168
|
+
const fallback = fallbackName
|
|
169
|
+
? resolveLlmEngineUse(config, [{ engine: fallbackName }], { optional: true })
|
|
170
|
+
: undefined;
|
|
170
171
|
return {
|
|
171
172
|
kind: "sdk",
|
|
172
173
|
engine: name,
|
|
173
174
|
profile,
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
175
|
+
...(fallback
|
|
176
|
+
? {
|
|
177
|
+
fallbackConnection: fallback.connection,
|
|
178
|
+
...(fallback.credential ? { fallbackCredential: fallback.credential } : {}),
|
|
179
|
+
fallbackTimeoutMs: fallback.timeoutMs,
|
|
180
|
+
}
|
|
181
|
+
: {}),
|
|
182
|
+
timeoutMs: hasOwn(engine, "timeoutMs")
|
|
183
|
+
? (engine.timeoutMs ?? null)
|
|
184
|
+
: (fallback?.timeoutMs ?? DEFAULT_AGENT_TIMEOUT_MS),
|
|
178
185
|
};
|
|
179
186
|
}
|
|
180
187
|
/** Lower a named engine through the canonical harness platform. */
|