open-agents-ai 0.11.4 → 0.11.6
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/dist/index.js +730 -41
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6831,36 +6831,112 @@ ${marker}` : marker);
|
|
|
6831
6831
|
const middle = messages.slice(2, -keepRecent);
|
|
6832
6832
|
if (middle.length === 0)
|
|
6833
6833
|
return messages;
|
|
6834
|
-
|
|
6834
|
+
let previousSummary = "";
|
|
6835
|
+
const nonCompactionMiddle = [];
|
|
6836
|
+
for (const msg of middle) {
|
|
6837
|
+
if (msg.role === "system" && typeof msg.content === "string" && msg.content.startsWith("[Context compacted")) {
|
|
6838
|
+
previousSummary = msg.content.replace(/^\[Context compacted[^\]]*\]\s*/, "").replace(/\n\n\[Continue from[^\]]*\]\s*$/, "").trim();
|
|
6839
|
+
} else {
|
|
6840
|
+
nonCompactionMiddle.push(msg);
|
|
6841
|
+
}
|
|
6842
|
+
}
|
|
6843
|
+
const newSummary = this.summarizeCompactedMessages(nonCompactionMiddle);
|
|
6844
|
+
const combinedSummary = previousSummary ? this.progressiveSummarize(previousSummary, newSummary) : newSummary;
|
|
6835
6845
|
this.emit({
|
|
6836
6846
|
type: "compaction",
|
|
6837
|
-
content: `Compacted ${middle.length} messages`,
|
|
6847
|
+
content: `Compacted ${middle.length} messages${previousSummary ? " (progressive)" : ""}`,
|
|
6838
6848
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6839
6849
|
});
|
|
6840
6850
|
const compactionMsg = {
|
|
6841
6851
|
role: "system",
|
|
6842
6852
|
content: `[Context compacted \u2014 summary of earlier work]
|
|
6843
6853
|
|
|
6844
|
-
${
|
|
6854
|
+
${combinedSummary}
|
|
6845
6855
|
|
|
6846
6856
|
[Continue from the recent context below. Do not repeat work already completed above.]`
|
|
6847
6857
|
};
|
|
6848
6858
|
return [...head, compactionMsg, ...recent];
|
|
6849
6859
|
}
|
|
6850
6860
|
/**
|
|
6851
|
-
*
|
|
6852
|
-
*
|
|
6853
|
-
|
|
6854
|
-
|
|
6861
|
+
* Progressive summarization: merge an older compacted summary with a newer one.
|
|
6862
|
+
* When the combined text exceeds the budget, condense the older summary.
|
|
6863
|
+
*/
|
|
6864
|
+
progressiveSummarize(olderSummary, newerSummary) {
|
|
6865
|
+
const MAX_SUMMARY_CHARS = 4e3;
|
|
6866
|
+
const combined = `${olderSummary}
|
|
6867
|
+
|
|
6868
|
+
---
|
|
6869
|
+
|
|
6870
|
+
${newerSummary}`;
|
|
6871
|
+
if (combined.length <= MAX_SUMMARY_CHARS) {
|
|
6872
|
+
return combined;
|
|
6873
|
+
}
|
|
6874
|
+
const condensed = this.condenseSummary(olderSummary);
|
|
6875
|
+
const result = `${condensed}
|
|
6876
|
+
|
|
6877
|
+
---
|
|
6878
|
+
|
|
6879
|
+
${newerSummary}`;
|
|
6880
|
+
if (result.length > MAX_SUMMARY_CHARS) {
|
|
6881
|
+
const budget = MAX_SUMMARY_CHARS - newerSummary.length - 60;
|
|
6882
|
+
return budget > 200 ? `[Earlier work, condensed]
|
|
6883
|
+
${olderSummary.slice(0, budget)}...
|
|
6884
|
+
|
|
6885
|
+
---
|
|
6886
|
+
|
|
6887
|
+
${newerSummary}` : newerSummary;
|
|
6888
|
+
}
|
|
6889
|
+
return result;
|
|
6890
|
+
}
|
|
6891
|
+
/**
|
|
6892
|
+
* Condense a summary by keeping section headings and only first 2 items under each.
|
|
6893
|
+
*/
|
|
6894
|
+
condenseSummary(summary) {
|
|
6895
|
+
const lines = summary.split("\n");
|
|
6896
|
+
const condensed = [];
|
|
6897
|
+
let itemCount = 0;
|
|
6898
|
+
for (const line of lines) {
|
|
6899
|
+
if (line.startsWith("##") || line.startsWith("---") || line.trim() === "") {
|
|
6900
|
+
condensed.push(line);
|
|
6901
|
+
itemCount = 0;
|
|
6902
|
+
} else if (line.startsWith("- ") || line.startsWith(" - ")) {
|
|
6903
|
+
if (itemCount < 2) {
|
|
6904
|
+
condensed.push(line);
|
|
6905
|
+
} else if (itemCount === 2) {
|
|
6906
|
+
condensed.push(" - ...(condensed)");
|
|
6907
|
+
}
|
|
6908
|
+
itemCount++;
|
|
6909
|
+
} else {
|
|
6910
|
+
condensed.push(line);
|
|
6911
|
+
}
|
|
6912
|
+
}
|
|
6913
|
+
return condensed.join("\n");
|
|
6914
|
+
}
|
|
6915
|
+
/**
|
|
6916
|
+
* Extract a rich structured summary from compacted messages, preserving:
|
|
6917
|
+
* - Assistant analysis/reasoning text
|
|
6918
|
+
* - File contents examined (key snippets, not just names)
|
|
6919
|
+
* - Specific code changes (old_string → new_string)
|
|
6920
|
+
* - Shell command results (test pass/fail, build errors)
|
|
6921
|
+
* - Search findings (grep/find results)
|
|
6855
6922
|
* - Errors encountered
|
|
6856
6923
|
*/
|
|
6857
6924
|
summarizeCompactedMessages(messages) {
|
|
6858
|
-
const
|
|
6859
|
-
const
|
|
6860
|
-
const
|
|
6925
|
+
const toolCallMap = /* @__PURE__ */ new Map();
|
|
6926
|
+
const assistantAnalysis = [];
|
|
6927
|
+
const filesRead = /* @__PURE__ */ new Map();
|
|
6928
|
+
const filesModified = /* @__PURE__ */ new Map();
|
|
6929
|
+
const commandResults = [];
|
|
6930
|
+
const searchFindings = [];
|
|
6861
6931
|
const errors = [];
|
|
6862
6932
|
let toolCallCount = 0;
|
|
6863
6933
|
for (const msg of messages) {
|
|
6934
|
+
if (msg.role === "assistant" && typeof msg.content === "string" && msg.content.trim()) {
|
|
6935
|
+
const text = msg.content.trim();
|
|
6936
|
+
if (text.length > 20) {
|
|
6937
|
+
assistantAnalysis.push(text.length > 400 ? text.slice(0, 400) + "..." : text);
|
|
6938
|
+
}
|
|
6939
|
+
}
|
|
6864
6940
|
if (msg.tool_calls) {
|
|
6865
6941
|
for (const tc of msg.tool_calls) {
|
|
6866
6942
|
toolCallCount++;
|
|
@@ -6871,37 +6947,134 @@ ${summary}
|
|
|
6871
6947
|
return {};
|
|
6872
6948
|
}
|
|
6873
6949
|
})();
|
|
6950
|
+
toolCallMap.set(tc.id, { name: tc.function.name, args });
|
|
6874
6951
|
const name = tc.function.name;
|
|
6875
|
-
if (name === "
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
|
|
6952
|
+
if (name === "file_edit") {
|
|
6953
|
+
const path = String(args.path || "");
|
|
6954
|
+
const oldStr = String(args.old_string || "").slice(0, 100);
|
|
6955
|
+
const newStr = String(args.new_string || "").slice(0, 100);
|
|
6956
|
+
if (path) {
|
|
6957
|
+
const changes = filesModified.get(path) || [];
|
|
6958
|
+
changes.push(`"${oldStr}" \u2192 "${newStr}"`);
|
|
6959
|
+
filesModified.set(path, changes);
|
|
6960
|
+
}
|
|
6961
|
+
} else if (name === "file_write") {
|
|
6962
|
+
const path = String(args.path || "");
|
|
6963
|
+
if (path) {
|
|
6964
|
+
if (!filesModified.has(path))
|
|
6965
|
+
filesModified.set(path, []);
|
|
6966
|
+
filesModified.get(path).push("(full file write)");
|
|
6967
|
+
}
|
|
6968
|
+
} else if (name === "batch_edit") {
|
|
6969
|
+
const path = String(args.path || "");
|
|
6970
|
+
if (path) {
|
|
6971
|
+
if (!filesModified.has(path))
|
|
6972
|
+
filesModified.set(path, []);
|
|
6973
|
+
filesModified.get(path).push("(batch edit)");
|
|
6974
|
+
}
|
|
6883
6975
|
}
|
|
6884
6976
|
}
|
|
6885
6977
|
}
|
|
6886
|
-
if (msg.role === "tool" && typeof msg.content === "string") {
|
|
6887
|
-
|
|
6888
|
-
|
|
6978
|
+
if (msg.role === "tool" && typeof msg.content === "string" && msg.tool_call_id) {
|
|
6979
|
+
const tc = toolCallMap.get(msg.tool_call_id);
|
|
6980
|
+
const content = msg.content;
|
|
6981
|
+
if (!tc) {
|
|
6982
|
+
if (content.startsWith("Error:"))
|
|
6983
|
+
errors.push(content.slice(0, 200));
|
|
6984
|
+
continue;
|
|
6985
|
+
}
|
|
6986
|
+
switch (tc.name) {
|
|
6987
|
+
case "file_read": {
|
|
6988
|
+
const path = String(tc.args.path || "");
|
|
6989
|
+
const lines = content.split("\n");
|
|
6990
|
+
const summary = lines.length > 5 ? `${lines.length} lines \u2014 ${lines.slice(0, 2).join("; ").slice(0, 120)}...` : content.slice(0, 150);
|
|
6991
|
+
if (path)
|
|
6992
|
+
filesRead.set(path, summary);
|
|
6993
|
+
break;
|
|
6994
|
+
}
|
|
6995
|
+
case "shell":
|
|
6996
|
+
case "background_run": {
|
|
6997
|
+
const cmd = String(tc.args.command || "").slice(0, 100);
|
|
6998
|
+
const hasError = content.startsWith("Error:") || /FAIL|ERR!/i.test(content);
|
|
6999
|
+
const hasPass = /PASS|passed|✓|success/i.test(content);
|
|
7000
|
+
let outcome;
|
|
7001
|
+
if (hasError) {
|
|
7002
|
+
const errorLines = content.split("\n").filter((l) => /error|FAIL|✗|×|ERR!/i.test(l)).slice(0, 3);
|
|
7003
|
+
outcome = errorLines.length > 0 ? errorLines.join("; ").slice(0, 200) : content.slice(0, 200);
|
|
7004
|
+
errors.push(`\`${cmd}\`: ${outcome.slice(0, 150)}`);
|
|
7005
|
+
} else if (hasPass) {
|
|
7006
|
+
outcome = "passed";
|
|
7007
|
+
} else {
|
|
7008
|
+
outcome = content.slice(0, 150);
|
|
7009
|
+
}
|
|
7010
|
+
commandResults.push({ cmd, outcome });
|
|
7011
|
+
break;
|
|
7012
|
+
}
|
|
7013
|
+
case "grep_search": {
|
|
7014
|
+
const pattern = String(tc.args.pattern || "");
|
|
7015
|
+
const matchCount = (content.match(/\n/g) || []).length;
|
|
7016
|
+
searchFindings.push(`grep "${pattern}": ${matchCount} matches \u2014 ${content.slice(0, 150)}`);
|
|
7017
|
+
break;
|
|
7018
|
+
}
|
|
7019
|
+
case "find_files": {
|
|
7020
|
+
const pattern = String(tc.args.pattern || "");
|
|
7021
|
+
const files = content.split("\n").filter(Boolean);
|
|
7022
|
+
searchFindings.push(`find "${pattern}": ${files.length} files \u2014 ${files.slice(0, 5).join(", ")}`);
|
|
7023
|
+
break;
|
|
7024
|
+
}
|
|
7025
|
+
default: {
|
|
7026
|
+
if (content.startsWith("Error:"))
|
|
7027
|
+
errors.push(`${tc.name}: ${content.slice(0, 200)}`);
|
|
7028
|
+
}
|
|
6889
7029
|
}
|
|
6890
7030
|
}
|
|
6891
7031
|
}
|
|
6892
7032
|
const parts = [];
|
|
6893
|
-
parts.push(
|
|
7033
|
+
parts.push(`## Compacted Work Summary (${toolCallCount} tool calls)
|
|
7034
|
+
`);
|
|
7035
|
+
if (assistantAnalysis.length > 0) {
|
|
7036
|
+
parts.push("### Agent Analysis");
|
|
7037
|
+
for (const analysis of assistantAnalysis.slice(-5)) {
|
|
7038
|
+
parts.push(`- ${analysis}`);
|
|
7039
|
+
}
|
|
7040
|
+
parts.push("");
|
|
7041
|
+
}
|
|
6894
7042
|
if (filesRead.size > 0) {
|
|
6895
|
-
parts.push(
|
|
7043
|
+
parts.push("### Files Examined");
|
|
7044
|
+
for (const [path, summary] of Array.from(filesRead).slice(0, 15)) {
|
|
7045
|
+
parts.push(`- \`${path}\`: ${summary}`);
|
|
7046
|
+
}
|
|
7047
|
+
parts.push("");
|
|
6896
7048
|
}
|
|
6897
7049
|
if (filesModified.size > 0) {
|
|
6898
|
-
parts.push(
|
|
7050
|
+
parts.push("### Code Changes Made");
|
|
7051
|
+
for (const [path, changes] of Array.from(filesModified).slice(0, 10)) {
|
|
7052
|
+
parts.push(`- **${path}**:`);
|
|
7053
|
+
for (const change of changes.slice(0, 3)) {
|
|
7054
|
+
parts.push(` - ${change}`);
|
|
7055
|
+
}
|
|
7056
|
+
}
|
|
7057
|
+
parts.push("");
|
|
7058
|
+
}
|
|
7059
|
+
if (commandResults.length > 0) {
|
|
7060
|
+
parts.push("### Commands Executed");
|
|
7061
|
+
for (const { cmd, outcome } of commandResults.slice(0, 8)) {
|
|
7062
|
+
parts.push(`- \`${cmd}\` \u2192 ${outcome}`);
|
|
7063
|
+
}
|
|
7064
|
+
parts.push("");
|
|
6899
7065
|
}
|
|
6900
|
-
if (
|
|
6901
|
-
parts.push(
|
|
7066
|
+
if (searchFindings.length > 0) {
|
|
7067
|
+
parts.push("### Search Findings");
|
|
7068
|
+
for (const finding of searchFindings.slice(0, 5)) {
|
|
7069
|
+
parts.push(`- ${finding}`);
|
|
7070
|
+
}
|
|
7071
|
+
parts.push("");
|
|
6902
7072
|
}
|
|
6903
7073
|
if (errors.length > 0) {
|
|
6904
|
-
parts.push(
|
|
7074
|
+
parts.push("### Errors Encountered");
|
|
7075
|
+
for (const error of errors.slice(0, 5)) {
|
|
7076
|
+
parts.push(`- ${error}`);
|
|
7077
|
+
}
|
|
6905
7078
|
}
|
|
6906
7079
|
return parts.join("\n");
|
|
6907
7080
|
}
|
|
@@ -8815,14 +8988,62 @@ function getEnvironment(repoRoot) {
|
|
|
8815
8988
|
];
|
|
8816
8989
|
return lines.join("\n");
|
|
8817
8990
|
}
|
|
8818
|
-
function
|
|
8991
|
+
function loadTaskMemories(repoRoot, store) {
|
|
8992
|
+
try {
|
|
8993
|
+
let tasks = store.listByRepo(repoRoot);
|
|
8994
|
+
if (tasks.length === 0) {
|
|
8995
|
+
tasks = store.recent(10);
|
|
8996
|
+
}
|
|
8997
|
+
if (tasks.length === 0)
|
|
8998
|
+
return "";
|
|
8999
|
+
const lines = ["Recent agent tasks (cross-session memory):"];
|
|
9000
|
+
for (const t of tasks.slice(0, 10)) {
|
|
9001
|
+
const date = t.createdAt.split("T")[0];
|
|
9002
|
+
const files = t.filesTouched.slice(0, 5).join(", ");
|
|
9003
|
+
lines.push(`- [${date}] ${t.goal.slice(0, 100)} \u2192 ${t.outcome}${files ? ` (files: ${files})` : ""}`);
|
|
9004
|
+
if (t.notes) {
|
|
9005
|
+
lines.push(` Notes: ${t.notes.slice(0, 150)}`);
|
|
9006
|
+
}
|
|
9007
|
+
}
|
|
9008
|
+
return lines.join("\n");
|
|
9009
|
+
} catch {
|
|
9010
|
+
return "";
|
|
9011
|
+
}
|
|
9012
|
+
}
|
|
9013
|
+
function loadFailurePatterns(store) {
|
|
9014
|
+
try {
|
|
9015
|
+
const unresolved = store.listUnresolved();
|
|
9016
|
+
if (unresolved.length === 0)
|
|
9017
|
+
return "";
|
|
9018
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9019
|
+
const unique = unresolved.filter((f) => {
|
|
9020
|
+
if (seen.has(f.fingerprint))
|
|
9021
|
+
return false;
|
|
9022
|
+
seen.add(f.fingerprint);
|
|
9023
|
+
return true;
|
|
9024
|
+
});
|
|
9025
|
+
if (unique.length === 0)
|
|
9026
|
+
return "";
|
|
9027
|
+
const lines = ["Known failure patterns (avoid repeating these):"];
|
|
9028
|
+
for (const f of unique.slice(0, 8)) {
|
|
9029
|
+
const file = f.filePath ? ` in ${f.filePath}` : "";
|
|
9030
|
+
lines.push(`- [${f.failureType}]${file}: ${f.errorMessage.slice(0, 150)}`);
|
|
9031
|
+
}
|
|
9032
|
+
return lines.join("\n");
|
|
9033
|
+
} catch {
|
|
9034
|
+
return "";
|
|
9035
|
+
}
|
|
9036
|
+
}
|
|
9037
|
+
function buildProjectContext(repoRoot, stores) {
|
|
8819
9038
|
return {
|
|
8820
9039
|
projectInstructions: loadProjectFiles(repoRoot),
|
|
8821
9040
|
projectMap: loadProjectMap(repoRoot),
|
|
8822
9041
|
gitInfo: getGitInfo(repoRoot),
|
|
8823
9042
|
memoryContext: loadMemoryContext(repoRoot),
|
|
8824
9043
|
sessionHistory: loadSessionHistory(repoRoot),
|
|
8825
|
-
environment: getEnvironment(repoRoot)
|
|
9044
|
+
environment: getEnvironment(repoRoot),
|
|
9045
|
+
taskMemories: stores?.taskMemoryStore ? loadTaskMemories(repoRoot, stores.taskMemoryStore) : "",
|
|
9046
|
+
failurePatterns: stores?.failureStore ? loadFailurePatterns(stores.failureStore) : ""
|
|
8826
9047
|
};
|
|
8827
9048
|
}
|
|
8828
9049
|
function formatContextForPrompt(ctx) {
|
|
@@ -8856,6 +9077,20 @@ Use this context to avoid re-learning known patterns. Update with memory_write i
|
|
|
8856
9077
|
sections.push(`## Session History
|
|
8857
9078
|
|
|
8858
9079
|
${ctx.sessionHistory}`);
|
|
9080
|
+
}
|
|
9081
|
+
if (ctx.taskMemories) {
|
|
9082
|
+
sections.push(`## Cross-Session Task Memory
|
|
9083
|
+
|
|
9084
|
+
${ctx.taskMemories}
|
|
9085
|
+
|
|
9086
|
+
Use this history to avoid re-doing completed work and to learn from past approaches.`);
|
|
9087
|
+
}
|
|
9088
|
+
if (ctx.failurePatterns) {
|
|
9089
|
+
sections.push(`## Known Failure Patterns
|
|
9090
|
+
|
|
9091
|
+
${ctx.failurePatterns}
|
|
9092
|
+
|
|
9093
|
+
Avoid approaches that led to these failures. If you encounter these errors, try a different strategy.`);
|
|
8859
9094
|
}
|
|
8860
9095
|
return sections.join("\n\n");
|
|
8861
9096
|
}
|
|
@@ -8866,6 +9101,354 @@ var init_project_context = __esm({
|
|
|
8866
9101
|
}
|
|
8867
9102
|
});
|
|
8868
9103
|
|
|
9104
|
+
// packages/memory/dist/db.js
|
|
9105
|
+
import Database from "better-sqlite3";
|
|
9106
|
+
function initDb(dbPath) {
|
|
9107
|
+
const db = new Database(dbPath);
|
|
9108
|
+
db.pragma("journal_mode = WAL");
|
|
9109
|
+
db.pragma("foreign_keys = ON");
|
|
9110
|
+
runMigrations(db);
|
|
9111
|
+
return db;
|
|
9112
|
+
}
|
|
9113
|
+
function closeDb(db) {
|
|
9114
|
+
db.close();
|
|
9115
|
+
}
|
|
9116
|
+
function runMigrations(db) {
|
|
9117
|
+
db.exec(`
|
|
9118
|
+
-- repo_profiles: one row per repository root.
|
|
9119
|
+
CREATE TABLE IF NOT EXISTS repo_profiles (
|
|
9120
|
+
repo_root TEXT PRIMARY KEY,
|
|
9121
|
+
languages TEXT NOT NULL DEFAULT '[]', -- JSON array
|
|
9122
|
+
frameworks TEXT NOT NULL DEFAULT '[]', -- JSON array
|
|
9123
|
+
build_system TEXT NOT NULL DEFAULT '',
|
|
9124
|
+
test_commands TEXT NOT NULL DEFAULT '[]', -- JSON array
|
|
9125
|
+
lint_commands TEXT NOT NULL DEFAULT '[]', -- JSON array
|
|
9126
|
+
package_manager TEXT NOT NULL DEFAULT '',
|
|
9127
|
+
notes TEXT,
|
|
9128
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
9129
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
|
|
9130
|
+
);
|
|
9131
|
+
|
|
9132
|
+
-- file_summaries: one row per (repo_root, file_path) pair.
|
|
9133
|
+
CREATE TABLE IF NOT EXISTS file_summaries (
|
|
9134
|
+
file_path TEXT NOT NULL,
|
|
9135
|
+
repo_root TEXT NOT NULL,
|
|
9136
|
+
purpose TEXT NOT NULL DEFAULT '',
|
|
9137
|
+
exports TEXT NOT NULL DEFAULT '[]', -- JSON array
|
|
9138
|
+
imports TEXT NOT NULL DEFAULT '[]', -- JSON array
|
|
9139
|
+
domain TEXT NOT NULL DEFAULT '',
|
|
9140
|
+
risk_level TEXT NOT NULL DEFAULT 'low', -- low | medium | high
|
|
9141
|
+
related_tests TEXT NOT NULL DEFAULT '[]', -- JSON array
|
|
9142
|
+
notes TEXT,
|
|
9143
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
9144
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
|
9145
|
+
PRIMARY KEY (file_path)
|
|
9146
|
+
);
|
|
9147
|
+
|
|
9148
|
+
CREATE INDEX IF NOT EXISTS idx_file_summaries_repo
|
|
9149
|
+
ON file_summaries (repo_root);
|
|
9150
|
+
|
|
9151
|
+
CREATE INDEX IF NOT EXISTS idx_file_summaries_domain
|
|
9152
|
+
ON file_summaries (domain);
|
|
9153
|
+
|
|
9154
|
+
CREATE INDEX IF NOT EXISTS idx_file_summaries_risk
|
|
9155
|
+
ON file_summaries (risk_level);
|
|
9156
|
+
|
|
9157
|
+
-- task_memory: historical record of agent tasks.
|
|
9158
|
+
CREATE TABLE IF NOT EXISTS task_memory (
|
|
9159
|
+
id TEXT PRIMARY KEY,
|
|
9160
|
+
session_id TEXT NOT NULL,
|
|
9161
|
+
repo_root TEXT NOT NULL,
|
|
9162
|
+
goal TEXT NOT NULL DEFAULT '',
|
|
9163
|
+
constraints TEXT NOT NULL DEFAULT '[]', -- JSON array
|
|
9164
|
+
files_touched TEXT NOT NULL DEFAULT '[]', -- JSON array
|
|
9165
|
+
patches TEXT NOT NULL DEFAULT '[]', -- JSON array
|
|
9166
|
+
outcome TEXT NOT NULL DEFAULT 'unknown', -- success | failure | partial | unknown
|
|
9167
|
+
quality_score REAL,
|
|
9168
|
+
notes TEXT,
|
|
9169
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
|
|
9170
|
+
);
|
|
9171
|
+
|
|
9172
|
+
CREATE INDEX IF NOT EXISTS idx_task_memory_session
|
|
9173
|
+
ON task_memory (session_id);
|
|
9174
|
+
|
|
9175
|
+
CREATE INDEX IF NOT EXISTS idx_task_memory_repo
|
|
9176
|
+
ON task_memory (repo_root);
|
|
9177
|
+
|
|
9178
|
+
CREATE INDEX IF NOT EXISTS idx_task_memory_outcome
|
|
9179
|
+
ON task_memory (outcome);
|
|
9180
|
+
|
|
9181
|
+
-- patch_history: individual file diffs applied by the agent.
|
|
9182
|
+
CREATE TABLE IF NOT EXISTS patch_history (
|
|
9183
|
+
id TEXT PRIMARY KEY,
|
|
9184
|
+
task_id TEXT NOT NULL,
|
|
9185
|
+
session_id TEXT NOT NULL,
|
|
9186
|
+
repo_root TEXT NOT NULL,
|
|
9187
|
+
file_path TEXT NOT NULL,
|
|
9188
|
+
diff TEXT NOT NULL DEFAULT '',
|
|
9189
|
+
status TEXT NOT NULL DEFAULT 'applied', -- applied | reverted | pending | failed
|
|
9190
|
+
applied_at TEXT,
|
|
9191
|
+
reverted_at TEXT,
|
|
9192
|
+
notes TEXT,
|
|
9193
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
|
|
9194
|
+
);
|
|
9195
|
+
|
|
9196
|
+
CREATE INDEX IF NOT EXISTS idx_patch_history_task
|
|
9197
|
+
ON patch_history (task_id);
|
|
9198
|
+
|
|
9199
|
+
CREATE INDEX IF NOT EXISTS idx_patch_history_file
|
|
9200
|
+
ON patch_history (file_path);
|
|
9201
|
+
|
|
9202
|
+
CREATE INDEX IF NOT EXISTS idx_patch_history_status
|
|
9203
|
+
ON patch_history (status);
|
|
9204
|
+
|
|
9205
|
+
-- failures: fingerprinted failure events for pattern detection.
|
|
9206
|
+
CREATE TABLE IF NOT EXISTS failures (
|
|
9207
|
+
id TEXT PRIMARY KEY,
|
|
9208
|
+
task_id TEXT NOT NULL,
|
|
9209
|
+
session_id TEXT NOT NULL,
|
|
9210
|
+
repo_root TEXT NOT NULL,
|
|
9211
|
+
failure_type TEXT NOT NULL DEFAULT '',
|
|
9212
|
+
fingerprint TEXT NOT NULL DEFAULT '',
|
|
9213
|
+
file_path TEXT,
|
|
9214
|
+
error_message TEXT NOT NULL DEFAULT '',
|
|
9215
|
+
context TEXT, -- JSON object or null
|
|
9216
|
+
resolved INTEGER NOT NULL DEFAULT 0, -- 0 = false, 1 = true
|
|
9217
|
+
resolved_at TEXT,
|
|
9218
|
+
notes TEXT,
|
|
9219
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
|
|
9220
|
+
);
|
|
9221
|
+
|
|
9222
|
+
CREATE INDEX IF NOT EXISTS idx_failures_type
|
|
9223
|
+
ON failures (failure_type);
|
|
9224
|
+
|
|
9225
|
+
CREATE INDEX IF NOT EXISTS idx_failures_fingerprint
|
|
9226
|
+
ON failures (fingerprint);
|
|
9227
|
+
|
|
9228
|
+
CREATE INDEX IF NOT EXISTS idx_failures_resolved
|
|
9229
|
+
ON failures (resolved);
|
|
9230
|
+
|
|
9231
|
+
-- validation_runs: results of lint / test / build / typecheck runs.
|
|
9232
|
+
CREATE TABLE IF NOT EXISTS validation_runs (
|
|
9233
|
+
id TEXT PRIMARY KEY,
|
|
9234
|
+
task_id TEXT NOT NULL,
|
|
9235
|
+
session_id TEXT NOT NULL,
|
|
9236
|
+
repo_root TEXT NOT NULL,
|
|
9237
|
+
run_type TEXT NOT NULL DEFAULT '', -- test | lint | build | typecheck
|
|
9238
|
+
command TEXT NOT NULL DEFAULT '',
|
|
9239
|
+
passed INTEGER NOT NULL DEFAULT 0, -- 0 = false, 1 = true
|
|
9240
|
+
duration_ms INTEGER,
|
|
9241
|
+
output TEXT,
|
|
9242
|
+
error_output TEXT,
|
|
9243
|
+
coverage_percent REAL,
|
|
9244
|
+
notes TEXT,
|
|
9245
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
|
|
9246
|
+
);
|
|
9247
|
+
|
|
9248
|
+
CREATE INDEX IF NOT EXISTS idx_validation_runs_task
|
|
9249
|
+
ON validation_runs (task_id);
|
|
9250
|
+
|
|
9251
|
+
CREATE INDEX IF NOT EXISTS idx_validation_runs_run_type
|
|
9252
|
+
ON validation_runs (run_type);
|
|
9253
|
+
|
|
9254
|
+
CREATE INDEX IF NOT EXISTS idx_validation_runs_passed
|
|
9255
|
+
ON validation_runs (passed);
|
|
9256
|
+
`);
|
|
9257
|
+
}
|
|
9258
|
+
var init_db = __esm({
|
|
9259
|
+
"packages/memory/dist/db.js"() {
|
|
9260
|
+
"use strict";
|
|
9261
|
+
}
|
|
9262
|
+
});
|
|
9263
|
+
|
|
9264
|
+
// packages/memory/dist/repoProfileStore.js
|
|
9265
|
+
var init_repoProfileStore = __esm({
|
|
9266
|
+
"packages/memory/dist/repoProfileStore.js"() {
|
|
9267
|
+
"use strict";
|
|
9268
|
+
}
|
|
9269
|
+
});
|
|
9270
|
+
|
|
9271
|
+
// packages/memory/dist/fileSummaryStore.js
|
|
9272
|
+
var init_fileSummaryStore = __esm({
|
|
9273
|
+
"packages/memory/dist/fileSummaryStore.js"() {
|
|
9274
|
+
"use strict";
|
|
9275
|
+
}
|
|
9276
|
+
});
|
|
9277
|
+
|
|
9278
|
+
// packages/memory/dist/taskMemoryStore.js
|
|
9279
|
+
import { randomUUID } from "node:crypto";
|
|
9280
|
+
function rowToTask(row) {
|
|
9281
|
+
return {
|
|
9282
|
+
id: row.id,
|
|
9283
|
+
sessionId: row.session_id,
|
|
9284
|
+
repoRoot: row.repo_root,
|
|
9285
|
+
goal: row.goal,
|
|
9286
|
+
constraints: JSON.parse(row.constraints),
|
|
9287
|
+
filesTouched: JSON.parse(row.files_touched),
|
|
9288
|
+
patches: JSON.parse(row.patches),
|
|
9289
|
+
outcome: row.outcome,
|
|
9290
|
+
qualityScore: row.quality_score ?? null,
|
|
9291
|
+
notes: row.notes ?? null,
|
|
9292
|
+
createdAt: row.created_at
|
|
9293
|
+
};
|
|
9294
|
+
}
|
|
9295
|
+
var TaskMemoryStore;
|
|
9296
|
+
var init_taskMemoryStore = __esm({
|
|
9297
|
+
"packages/memory/dist/taskMemoryStore.js"() {
|
|
9298
|
+
"use strict";
|
|
9299
|
+
TaskMemoryStore = class {
|
|
9300
|
+
db;
|
|
9301
|
+
constructor(db) {
|
|
9302
|
+
this.db = db;
|
|
9303
|
+
}
|
|
9304
|
+
/**
|
|
9305
|
+
* Insert a new task record and return its auto-generated id.
|
|
9306
|
+
*/
|
|
9307
|
+
insert(input) {
|
|
9308
|
+
const id = randomUUID();
|
|
9309
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
9310
|
+
this.db.prepare(`INSERT INTO task_memory
|
|
9311
|
+
(id, session_id, repo_root, goal, constraints,
|
|
9312
|
+
files_touched, patches, outcome, quality_score, notes, created_at)
|
|
9313
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.sessionId, input.repoRoot, input.goal, JSON.stringify(input.constraints), JSON.stringify(input.filesTouched), JSON.stringify(input.patches), input.outcome, input.qualityScore ?? null, input.notes ?? null, now);
|
|
9314
|
+
return id;
|
|
9315
|
+
}
|
|
9316
|
+
/** Retrieve a task record by id, or `null` if not found. */
|
|
9317
|
+
getById(id) {
|
|
9318
|
+
const row = this.db.prepare("SELECT * FROM task_memory WHERE id = ?").get(id);
|
|
9319
|
+
return row ? rowToTask(row) : null;
|
|
9320
|
+
}
|
|
9321
|
+
/** List all tasks associated with a session. */
|
|
9322
|
+
listBySession(sessionId) {
|
|
9323
|
+
const rows = this.db.prepare("SELECT * FROM task_memory WHERE session_id = ? ORDER BY created_at DESC").all(sessionId);
|
|
9324
|
+
return rows.map(rowToTask);
|
|
9325
|
+
}
|
|
9326
|
+
/** List all tasks for a repository root. */
|
|
9327
|
+
listByRepo(repoRoot) {
|
|
9328
|
+
const rows = this.db.prepare("SELECT * FROM task_memory WHERE repo_root = ? ORDER BY created_at DESC").all(repoRoot);
|
|
9329
|
+
return rows.map(rowToTask);
|
|
9330
|
+
}
|
|
9331
|
+
/** List tasks filtered by outcome. */
|
|
9332
|
+
listByOutcome(outcome) {
|
|
9333
|
+
const rows = this.db.prepare("SELECT * FROM task_memory WHERE outcome = ? ORDER BY created_at DESC").all(outcome);
|
|
9334
|
+
return rows.map(rowToTask);
|
|
9335
|
+
}
|
|
9336
|
+
/**
|
|
9337
|
+
* Return the N most recently created tasks across all sessions and repos.
|
|
9338
|
+
* Useful for building a rolling context window.
|
|
9339
|
+
*/
|
|
9340
|
+
recent(limit) {
|
|
9341
|
+
const rows = this.db.prepare("SELECT * FROM task_memory ORDER BY created_at DESC LIMIT ?").all(limit);
|
|
9342
|
+
return rows.map(rowToTask);
|
|
9343
|
+
}
|
|
9344
|
+
};
|
|
9345
|
+
}
|
|
9346
|
+
});
|
|
9347
|
+
|
|
9348
|
+
// packages/memory/dist/patchHistoryStore.js
|
|
9349
|
+
var init_patchHistoryStore = __esm({
|
|
9350
|
+
"packages/memory/dist/patchHistoryStore.js"() {
|
|
9351
|
+
"use strict";
|
|
9352
|
+
}
|
|
9353
|
+
});
|
|
9354
|
+
|
|
9355
|
+
// packages/memory/dist/failureStore.js
|
|
9356
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
9357
|
+
function rowToFailure(row) {
|
|
9358
|
+
return {
|
|
9359
|
+
id: row.id,
|
|
9360
|
+
taskId: row.task_id,
|
|
9361
|
+
sessionId: row.session_id,
|
|
9362
|
+
repoRoot: row.repo_root,
|
|
9363
|
+
failureType: row.failure_type,
|
|
9364
|
+
fingerprint: row.fingerprint,
|
|
9365
|
+
filePath: row.file_path ?? null,
|
|
9366
|
+
errorMessage: row.error_message,
|
|
9367
|
+
context: row.context !== null ? JSON.parse(row.context) : null,
|
|
9368
|
+
resolved: row.resolved === 1,
|
|
9369
|
+
resolvedAt: row.resolved_at ?? null,
|
|
9370
|
+
notes: row.notes ?? null,
|
|
9371
|
+
createdAt: row.created_at
|
|
9372
|
+
};
|
|
9373
|
+
}
|
|
9374
|
+
var FailureStore;
|
|
9375
|
+
var init_failureStore = __esm({
|
|
9376
|
+
"packages/memory/dist/failureStore.js"() {
|
|
9377
|
+
"use strict";
|
|
9378
|
+
FailureStore = class {
|
|
9379
|
+
db;
|
|
9380
|
+
constructor(db) {
|
|
9381
|
+
this.db = db;
|
|
9382
|
+
}
|
|
9383
|
+
/**
|
|
9384
|
+
* Record a new failure event and return its auto-generated id.
|
|
9385
|
+
*/
|
|
9386
|
+
insert(input) {
|
|
9387
|
+
const id = randomUUID2();
|
|
9388
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
9389
|
+
this.db.prepare(`INSERT INTO failures
|
|
9390
|
+
(id, task_id, session_id, repo_root, failure_type,
|
|
9391
|
+
fingerprint, file_path, error_message, context,
|
|
9392
|
+
resolved, resolved_at, notes, created_at)
|
|
9393
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.taskId, input.sessionId, input.repoRoot, input.failureType, input.fingerprint, input.filePath ?? null, input.errorMessage, input.context !== null ? JSON.stringify(input.context) : null, input.resolved ? 1 : 0, input.resolvedAt ?? null, input.notes ?? null, now);
|
|
9394
|
+
return id;
|
|
9395
|
+
}
|
|
9396
|
+
/** Retrieve a failure by id, or `null` if not found. */
|
|
9397
|
+
getById(id) {
|
|
9398
|
+
const row = this.db.prepare("SELECT * FROM failures WHERE id = ?").get(id);
|
|
9399
|
+
return row ? rowToFailure(row) : null;
|
|
9400
|
+
}
|
|
9401
|
+
/** List failures filtered by type. */
|
|
9402
|
+
listByType(failureType) {
|
|
9403
|
+
const rows = this.db.prepare("SELECT * FROM failures WHERE failure_type = ? ORDER BY created_at DESC").all(failureType);
|
|
9404
|
+
return rows.map(rowToFailure);
|
|
9405
|
+
}
|
|
9406
|
+
/** List all failures sharing the same content fingerprint. */
|
|
9407
|
+
listByFingerprint(fingerprint) {
|
|
9408
|
+
const rows = this.db.prepare("SELECT * FROM failures WHERE fingerprint = ? ORDER BY created_at DESC").all(fingerprint);
|
|
9409
|
+
return rows.map(rowToFailure);
|
|
9410
|
+
}
|
|
9411
|
+
/** List all failures that have not yet been marked as resolved. */
|
|
9412
|
+
listUnresolved() {
|
|
9413
|
+
const rows = this.db.prepare("SELECT * FROM failures WHERE resolved = 0 ORDER BY created_at DESC").all();
|
|
9414
|
+
return rows.map(rowToFailure);
|
|
9415
|
+
}
|
|
9416
|
+
/**
|
|
9417
|
+
* Mark a failure as resolved.
|
|
9418
|
+
*
|
|
9419
|
+
* @param id - The failure record id.
|
|
9420
|
+
* @param resolvedAt - ISO timestamp string of resolution time.
|
|
9421
|
+
*/
|
|
9422
|
+
markResolved(id, resolvedAt) {
|
|
9423
|
+
this.db.prepare(`UPDATE failures
|
|
9424
|
+
SET resolved = 1, resolved_at = ?
|
|
9425
|
+
WHERE id = ?`).run(resolvedAt, id);
|
|
9426
|
+
}
|
|
9427
|
+
};
|
|
9428
|
+
}
|
|
9429
|
+
});
|
|
9430
|
+
|
|
9431
|
+
// packages/memory/dist/validationStore.js
|
|
9432
|
+
var init_validationStore = __esm({
|
|
9433
|
+
"packages/memory/dist/validationStore.js"() {
|
|
9434
|
+
"use strict";
|
|
9435
|
+
}
|
|
9436
|
+
});
|
|
9437
|
+
|
|
9438
|
+
// packages/memory/dist/index.js
|
|
9439
|
+
var init_dist6 = __esm({
|
|
9440
|
+
"packages/memory/dist/index.js"() {
|
|
9441
|
+
"use strict";
|
|
9442
|
+
init_db();
|
|
9443
|
+
init_repoProfileStore();
|
|
9444
|
+
init_fileSummaryStore();
|
|
9445
|
+
init_taskMemoryStore();
|
|
9446
|
+
init_patchHistoryStore();
|
|
9447
|
+
init_failureStore();
|
|
9448
|
+
init_validationStore();
|
|
9449
|
+
}
|
|
9450
|
+
});
|
|
9451
|
+
|
|
8869
9452
|
// packages/cli/dist/tui/carousel.js
|
|
8870
9453
|
function fg(code, text) {
|
|
8871
9454
|
return isTTY3 ? `\x1B[38;5;${code}m${text}\x1B[0m` : text;
|
|
@@ -9330,15 +9913,17 @@ var init_voice = __esm({
|
|
|
9330
9913
|
}
|
|
9331
9914
|
/**
|
|
9332
9915
|
* Speak text asynchronously (non-blocking).
|
|
9333
|
-
*
|
|
9916
|
+
* Long text is chunked on sentence/line boundaries for reliable TTS.
|
|
9917
|
+
* Chunks are queued FIFO and played back-to-back without cutoff.
|
|
9334
9918
|
*/
|
|
9335
9919
|
speak(text) {
|
|
9336
9920
|
if (!this.enabled || !this.ready)
|
|
9337
9921
|
return;
|
|
9338
|
-
|
|
9922
|
+
const chunks = this.chunkText(text);
|
|
9923
|
+
if (this.speakQueue.length >= 30) {
|
|
9339
9924
|
this.speakQueue.length = 0;
|
|
9340
9925
|
}
|
|
9341
|
-
this.speakQueue.push(
|
|
9926
|
+
this.speakQueue.push(...chunks);
|
|
9342
9927
|
if (!this.speaking) {
|
|
9343
9928
|
this.drainQueue().catch(() => {
|
|
9344
9929
|
});
|
|
@@ -9352,13 +9937,47 @@ var init_voice = __esm({
|
|
|
9352
9937
|
this.config = null;
|
|
9353
9938
|
}
|
|
9354
9939
|
// -------------------------------------------------------------------------
|
|
9940
|
+
// Text chunking for long TTS input
|
|
9941
|
+
// -------------------------------------------------------------------------
|
|
9942
|
+
/**
|
|
9943
|
+
* Split long text into sentence-sized chunks suitable for ONNX TTS.
|
|
9944
|
+
* Splits on: newlines (list items, paragraphs), then sentence-ending
|
|
9945
|
+
* punctuation (.!?). Short text (<= 200 chars) passes through unchanged.
|
|
9946
|
+
*/
|
|
9947
|
+
chunkText(text) {
|
|
9948
|
+
if (text.length <= 200)
|
|
9949
|
+
return [text];
|
|
9950
|
+
const chunks = [];
|
|
9951
|
+
const lines = text.split(/\n+/);
|
|
9952
|
+
for (const line of lines) {
|
|
9953
|
+
const trimmed = line.replace(/^[\s\-*•]+/, "").trim();
|
|
9954
|
+
if (!trimmed)
|
|
9955
|
+
continue;
|
|
9956
|
+
if (trimmed.length <= 200) {
|
|
9957
|
+
chunks.push(trimmed);
|
|
9958
|
+
} else {
|
|
9959
|
+
const sentences = trimmed.split(/(?<=[.!?])\s+/);
|
|
9960
|
+
for (const sentence of sentences) {
|
|
9961
|
+
const s = sentence.trim();
|
|
9962
|
+
if (s)
|
|
9963
|
+
chunks.push(s);
|
|
9964
|
+
}
|
|
9965
|
+
}
|
|
9966
|
+
}
|
|
9967
|
+
return chunks.length > 0 ? chunks : [text.slice(0, 200)];
|
|
9968
|
+
}
|
|
9969
|
+
// -------------------------------------------------------------------------
|
|
9355
9970
|
// Queue drain
|
|
9356
9971
|
// -------------------------------------------------------------------------
|
|
9972
|
+
/**
|
|
9973
|
+
* Drain the speak queue FIFO — each item is synthesized and played to
|
|
9974
|
+
* completion before the next starts. Items play back-to-back without
|
|
9975
|
+
* cutting off previous audio.
|
|
9976
|
+
*/
|
|
9357
9977
|
async drainQueue() {
|
|
9358
9978
|
this.speaking = true;
|
|
9359
9979
|
while (this.speakQueue.length > 0) {
|
|
9360
|
-
const text = this.speakQueue.
|
|
9361
|
-
this.speakQueue.length = 0;
|
|
9980
|
+
const text = this.speakQueue.shift();
|
|
9362
9981
|
try {
|
|
9363
9982
|
await this.synthesizeAndPlay(text);
|
|
9364
9983
|
} catch {
|
|
@@ -9478,7 +10097,6 @@ var init_voice = __esm({
|
|
|
9478
10097
|
// Audio playback (system default speakers)
|
|
9479
10098
|
// -------------------------------------------------------------------------
|
|
9480
10099
|
async playWav(path) {
|
|
9481
|
-
this.killPlayback();
|
|
9482
10100
|
const cmd = this.getPlayCommand(path);
|
|
9483
10101
|
if (!cmd)
|
|
9484
10102
|
return;
|
|
@@ -9499,7 +10117,13 @@ var init_voice = __esm({
|
|
|
9499
10117
|
resolve14();
|
|
9500
10118
|
});
|
|
9501
10119
|
setTimeout(() => {
|
|
9502
|
-
this.
|
|
10120
|
+
if (this.currentPlayback === child) {
|
|
10121
|
+
try {
|
|
10122
|
+
child.kill("SIGTERM");
|
|
10123
|
+
} catch {
|
|
10124
|
+
}
|
|
10125
|
+
this.currentPlayback = null;
|
|
10126
|
+
}
|
|
9503
10127
|
resolve14();
|
|
9504
10128
|
}, 15e3);
|
|
9505
10129
|
});
|
|
@@ -10097,8 +10721,8 @@ Use task_status("${taskId}") or task_output("${taskId}") to check progress.`
|
|
|
10097
10721
|
}
|
|
10098
10722
|
};
|
|
10099
10723
|
}
|
|
10100
|
-
function startTask(task, config, repoRoot, voice, stream) {
|
|
10101
|
-
const projectCtx = buildProjectContext(repoRoot);
|
|
10724
|
+
function startTask(task, config, repoRoot, voice, stream, taskStores) {
|
|
10725
|
+
const projectCtx = buildProjectContext(repoRoot, taskStores?.contextStores);
|
|
10102
10726
|
const dynamicContext = formatContextForPrompt(projectCtx);
|
|
10103
10727
|
const backend = new OllamaAgenticBackend(config.backendUrl.replace(/\/$/, ""), config.model);
|
|
10104
10728
|
const runner = new AgenticRunner(backend, {
|
|
@@ -10112,9 +10736,16 @@ function startTask(task, config, repoRoot, voice, stream) {
|
|
|
10112
10736
|
streamEnabled: stream?.enabled ?? false
|
|
10113
10737
|
});
|
|
10114
10738
|
runner.registerTools(buildTools(repoRoot, config));
|
|
10739
|
+
const filesTouched = /* @__PURE__ */ new Set();
|
|
10115
10740
|
runner.onEvent((event) => {
|
|
10116
10741
|
switch (event.type) {
|
|
10117
10742
|
case "tool_call":
|
|
10743
|
+
if (event.toolArgs?.path && typeof event.toolArgs.path === "string") {
|
|
10744
|
+
const name = event.toolName ?? "";
|
|
10745
|
+
if (name === "file_write" || name === "file_edit" || name === "batch_edit") {
|
|
10746
|
+
filesTouched.add(event.toolArgs.path);
|
|
10747
|
+
}
|
|
10748
|
+
}
|
|
10118
10749
|
if (voice?.enabled) {
|
|
10119
10750
|
const desc = describeToolCall(event.toolName ?? "unknown", event.toolArgs ?? {});
|
|
10120
10751
|
renderVoiceText(desc);
|
|
@@ -10189,6 +10820,22 @@ function startTask(task, config, repoRoot, voice, stream) {
|
|
|
10189
10820
|
});
|
|
10190
10821
|
} catch {
|
|
10191
10822
|
}
|
|
10823
|
+
if (taskStores?.taskMemoryStore) {
|
|
10824
|
+
try {
|
|
10825
|
+
taskStores.taskMemoryStore.insert({
|
|
10826
|
+
sessionId,
|
|
10827
|
+
repoRoot,
|
|
10828
|
+
goal: task.slice(0, 500),
|
|
10829
|
+
constraints: [],
|
|
10830
|
+
filesTouched: Array.from(filesTouched).slice(0, 50),
|
|
10831
|
+
patches: [],
|
|
10832
|
+
outcome: result.completed ? "success" : "partial",
|
|
10833
|
+
qualityScore: null,
|
|
10834
|
+
notes: result.summary.slice(0, 500)
|
|
10835
|
+
});
|
|
10836
|
+
} catch {
|
|
10837
|
+
}
|
|
10838
|
+
}
|
|
10192
10839
|
});
|
|
10193
10840
|
return { runner, promise };
|
|
10194
10841
|
}
|
|
@@ -10200,6 +10847,17 @@ async function startInteractive(config, repoPath) {
|
|
|
10200
10847
|
}
|
|
10201
10848
|
initOaDirectory(repoRoot);
|
|
10202
10849
|
const savedSettings = resolveSettings(repoRoot);
|
|
10850
|
+
let memoryDb = null;
|
|
10851
|
+
let taskMemoryStore = null;
|
|
10852
|
+
let failureStore = null;
|
|
10853
|
+
let contextStores;
|
|
10854
|
+
try {
|
|
10855
|
+
memoryDb = initDb(config.dbPath);
|
|
10856
|
+
taskMemoryStore = new TaskMemoryStore(memoryDb);
|
|
10857
|
+
failureStore = new FailureStore(memoryDb);
|
|
10858
|
+
contextStores = { taskMemoryStore, failureStore };
|
|
10859
|
+
} catch {
|
|
10860
|
+
}
|
|
10203
10861
|
if (savedSettings.model)
|
|
10204
10862
|
config = { ...config, model: savedSettings.model };
|
|
10205
10863
|
if (savedSettings.backendUrl)
|
|
@@ -10330,6 +10988,12 @@ async function startInteractive(config, repoPath) {
|
|
|
10330
10988
|
if (carousel.isRunning)
|
|
10331
10989
|
carousel.stop();
|
|
10332
10990
|
voiceEngine.dispose();
|
|
10991
|
+
if (memoryDb) {
|
|
10992
|
+
try {
|
|
10993
|
+
closeDb(memoryDb);
|
|
10994
|
+
} catch {
|
|
10995
|
+
}
|
|
10996
|
+
}
|
|
10333
10997
|
rl.close();
|
|
10334
10998
|
},
|
|
10335
10999
|
async voiceToggle() {
|
|
@@ -10421,12 +11085,36 @@ ${c2.dim("Goodbye!")}
|
|
|
10421
11085
|
const task = startTask(fullInput, currentConfig, repoRoot, voiceEngine, {
|
|
10422
11086
|
enabled: streamEnabled,
|
|
10423
11087
|
renderer: streamRenderer
|
|
11088
|
+
}, {
|
|
11089
|
+
contextStores,
|
|
11090
|
+
taskMemoryStore: taskMemoryStore ?? void 0,
|
|
11091
|
+
failureStore: failureStore ?? void 0
|
|
10424
11092
|
});
|
|
10425
11093
|
activeTask = task;
|
|
10426
11094
|
showPrompt();
|
|
10427
11095
|
await task.promise;
|
|
10428
11096
|
} catch (err) {
|
|
10429
|
-
|
|
11097
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
11098
|
+
renderError(errMsg);
|
|
11099
|
+
if (failureStore) {
|
|
11100
|
+
try {
|
|
11101
|
+
const { createHash: createHash2 } = await import("node:crypto");
|
|
11102
|
+
failureStore.insert({
|
|
11103
|
+
taskId: "",
|
|
11104
|
+
sessionId: `${Date.now()}`,
|
|
11105
|
+
repoRoot,
|
|
11106
|
+
failureType: "runtime-error",
|
|
11107
|
+
fingerprint: createHash2("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
|
|
11108
|
+
filePath: null,
|
|
11109
|
+
errorMessage: errMsg.slice(0, 500),
|
|
11110
|
+
context: null,
|
|
11111
|
+
resolved: false,
|
|
11112
|
+
resolvedAt: null,
|
|
11113
|
+
notes: `Task: ${fullInput.slice(0, 200)}`
|
|
11114
|
+
});
|
|
11115
|
+
} catch {
|
|
11116
|
+
}
|
|
11117
|
+
}
|
|
10430
11118
|
} finally {
|
|
10431
11119
|
activeTask = null;
|
|
10432
11120
|
}
|
|
@@ -10513,6 +11201,7 @@ var init_interactive = __esm({
|
|
|
10513
11201
|
init_commands();
|
|
10514
11202
|
init_setup();
|
|
10515
11203
|
init_project_context();
|
|
11204
|
+
init_dist6();
|
|
10516
11205
|
init_oa_directory();
|
|
10517
11206
|
init_render();
|
|
10518
11207
|
init_carousel();
|
|
@@ -10715,7 +11404,7 @@ var init_embeddings = __esm({
|
|
|
10715
11404
|
});
|
|
10716
11405
|
|
|
10717
11406
|
// packages/indexer/dist/index.js
|
|
10718
|
-
var
|
|
11407
|
+
var init_dist7 = __esm({
|
|
10719
11408
|
"packages/indexer/dist/index.js"() {
|
|
10720
11409
|
"use strict";
|
|
10721
11410
|
init_codebase_indexer();
|
|
@@ -10822,7 +11511,7 @@ async function indexRepoCommand(opts, _config) {
|
|
|
10822
11511
|
var init_index_repo = __esm({
|
|
10823
11512
|
"packages/cli/dist/commands/index-repo.js"() {
|
|
10824
11513
|
"use strict";
|
|
10825
|
-
|
|
11514
|
+
init_dist7();
|
|
10826
11515
|
init_spinner();
|
|
10827
11516
|
init_output();
|
|
10828
11517
|
}
|
package/package.json
CHANGED