compact-agent 1.8.4 → 1.10.0

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.
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Turn-boundary context cleanup.
3
+ *
4
+ * Background. The conversation history sent to the model grows as:
5
+ * [user, assistant(tool_calls), tool, assistant(tool_calls), tool, …,
6
+ * assistant(final text), user, assistant(tool_calls), tool, …]
7
+ *
8
+ * Once a turn is *complete* (assistant returned text with no tool_calls),
9
+ * the in-progress scaffolding from that turn — the assistant messages
10
+ * carrying tool_calls and the tool-result messages — is no longer
11
+ * actionable. But it still LOOKS actionable to a weaker model: it sees
12
+ * "tool_calls" entries and treats them as pending TODOs, which is why
13
+ * owl-alpha kept re-writing the same poem on every new user turn:
14
+ *
15
+ * turn 1 user: "write a poem"
16
+ * ... model writes poem ...
17
+ * turn 2 user: "find a github repo for X"
18
+ * model: "I'll handle BOTH requests" (because it still sees the
19
+ * poem's tool_calls scaffolding as if it hadn't run)
20
+ * turn 3 user: "research further"
21
+ * model: "I'll handle all THREE requests" ← infinite re-execution
22
+ *
23
+ * Fix. Before each new turn, walk back through history. For every
24
+ * COMPLETED turn (any turn before the latest user message), collapse the
25
+ * [user, ...intermediate scaffolding..., final assistant text] sequence
26
+ * into [user, "final assistant text + [Completed: used X, Y]"]. The model
27
+ * sees a clean conversational record of what already happened, with no
28
+ * dangling tool_calls signals to misinterpret.
29
+ *
30
+ * The currently-active turn (everything from the latest user message
31
+ * forward) is left untouched — its tool_calls and tool-result messages
32
+ * are still in-flight and the API protocol requires them paired.
33
+ */
34
+ /**
35
+ * Collapse all completed turns in a message list. Returns a new array;
36
+ * input is not mutated.
37
+ *
38
+ * A completed turn is any turn ENDING before the latest user message.
39
+ * The latest user message and everything after it is the "active turn"
40
+ * and is passed through unchanged.
41
+ */
42
+ export function collapseCompletedTurns(messages) {
43
+ // Locate the latest user message — the start of the active turn.
44
+ let activeStart = -1;
45
+ for (let i = messages.length - 1; i >= 0; i--) {
46
+ if (messages[i].role === 'user') {
47
+ activeStart = i;
48
+ break;
49
+ }
50
+ }
51
+ // No user message yet (e.g. fresh session start) → nothing to collapse.
52
+ if (activeStart <= 0)
53
+ return messages.slice();
54
+ const history = messages.slice(0, activeStart);
55
+ const active = messages.slice(activeStart);
56
+ const collapsed = [];
57
+ let i = 0;
58
+ while (i < history.length) {
59
+ const m = history[i];
60
+ // Pass-through system/user messages until we find a user message
61
+ // that starts a turn. Stray non-system/user messages get kept as-is
62
+ // (defensive: shouldn't happen in normal flow, but don't lose data).
63
+ if (m.role === 'system') {
64
+ collapsed.push(m);
65
+ i++;
66
+ continue;
67
+ }
68
+ if (m.role !== 'user') {
69
+ // Orphan assistant/tool message at the head of history — keep verbatim
70
+ // and skip past it. Avoids losing context if message ordering ever
71
+ // gets weird.
72
+ collapsed.push(m);
73
+ i++;
74
+ continue;
75
+ }
76
+ // m is a user message — start of a historical turn.
77
+ const userMsg = m;
78
+ collapsed.push(userMsg);
79
+ i++;
80
+ // Walk forward collecting the rest of this turn (everything up to
81
+ // but not including the next user message).
82
+ const toolsUsed = [];
83
+ let finalText = '';
84
+ while (i < history.length && history[i].role !== 'user') {
85
+ const t = history[i];
86
+ if (t.role === 'assistant') {
87
+ if (t.tool_calls && t.tool_calls.length > 0) {
88
+ for (const tc of t.tool_calls) {
89
+ // tc.function.name on function-tool variants. Defensive .? in
90
+ // case the union shape changes.
91
+ const name = tc.function?.name;
92
+ if (name)
93
+ toolsUsed.push(name);
94
+ }
95
+ }
96
+ if (typeof t.content === 'string' && t.content.trim()) {
97
+ // Keep the LAST assistant text we see — that's the model's
98
+ // final summary at the end of the turn. Intermediate "I'll
99
+ // now do X" sentences are intentionally discarded since the
100
+ // tool list below already captures what happened.
101
+ finalText = t.content;
102
+ }
103
+ }
104
+ // role === 'tool' messages are intentionally dropped here.
105
+ i++;
106
+ }
107
+ // Emit the collapsed turn. If the assistant produced no final text
108
+ // but ran tools, synthesize a one-line "completed" marker; if neither
109
+ // tools nor text, skip emitting anything (empty turn — odd but safe).
110
+ if (finalText || toolsUsed.length > 0) {
111
+ const uniqueTools = Array.from(new Set(toolsUsed));
112
+ const trailer = uniqueTools.length > 0
113
+ ? `\n\n[Completed in a prior turn. Tools used: ${uniqueTools.join(', ')}. Do NOT re-execute these — they were for that prior user message, not the current one.]`
114
+ : '';
115
+ collapsed.push({
116
+ role: 'assistant',
117
+ content: (finalText || '(no text response)') + trailer,
118
+ });
119
+ }
120
+ }
121
+ return [...collapsed, ...active];
122
+ }
123
+ //# sourceMappingURL=turn-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn-context.js","sourceRoot":"","sources":["../src/turn-context.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -16,6 +16,7 @@ export interface CrowcoderConfig {
16
16
  maxTokens: number;
17
17
  temperature: number;
18
18
  permissionMode: 'ask' | 'auto' | 'yolo';
19
+ alwaysAllowedTools?: string[];
19
20
  dryRun?: boolean;
20
21
  theme?: 'full' | 'compact' | 'minimal';
21
22
  palette?: string;
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAkFA,MAAM,CAAC,MAAM,SAAS,GAAmC;IACvD,SAAS,EAAE;QACT,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,+BAA+B;QACxC,YAAY,EAAE,0BAA0B;QACxC,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,2BAA2B;QACpC,YAAY,EAAE,QAAQ;QACtB,WAAW,EAAE,IAAI;KAClB;IACD,UAAU,EAAE;QACV,IAAI,EAAE,wBAAwB;QAC9B,OAAO,EAAE,8BAA8B;QACvC,YAAY,EAAE,2BAA2B;QACzC,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,0DAA0D;QACnE,YAAY,EAAE,kBAAkB;QAChC,WAAW,EAAE,IAAI;KAClB;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,6BAA6B;QACtC,YAAY,EAAE,eAAe;QAC7B,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,2BAA2B;QACpC,YAAY,EAAE,sBAAsB;QACpC,WAAW,EAAE,KAAK;KACnB;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,0BAA0B;QACnC,YAAY,EAAE,cAAc;QAC5B,WAAW,EAAE,KAAK;KACnB;IACD,GAAG,EAAE;QACH,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,sCAAsC;QAC/C,YAAY,EAAE,YAAY;QAC1B,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,EAAE;QACX,YAAY,EAAE,EAAE;QAChB,WAAW,EAAE,IAAI;KAClB;CACF,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAmFA,MAAM,CAAC,MAAM,SAAS,GAAmC;IACvD,SAAS,EAAE;QACT,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,+BAA+B;QACxC,YAAY,EAAE,0BAA0B;QACxC,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,2BAA2B;QACpC,YAAY,EAAE,QAAQ;QACtB,WAAW,EAAE,IAAI;KAClB;IACD,UAAU,EAAE;QACV,IAAI,EAAE,wBAAwB;QAC9B,OAAO,EAAE,8BAA8B;QACvC,YAAY,EAAE,2BAA2B;QACzC,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,0DAA0D;QACnE,YAAY,EAAE,kBAAkB;QAChC,WAAW,EAAE,IAAI;KAClB;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,6BAA6B;QACtC,YAAY,EAAE,eAAe;QAC7B,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,2BAA2B;QACpC,YAAY,EAAE,sBAAsB;QACpC,WAAW,EAAE,KAAK;KACnB;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,0BAA0B;QACnC,YAAY,EAAE,cAAc;QAC5B,WAAW,EAAE,KAAK;KACnB;IACD,GAAG,EAAE;QACH,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,sCAAsC;QAC/C,YAAY,EAAE,YAAY;QAC1B,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,EAAE;QACX,YAAY,EAAE,EAAE;QAChB,WAAW,EAAE,IAAI;KAClB;CACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compact-agent",
3
- "version": "1.8.4",
3
+ "version": "1.10.0",
4
4
  "description": "A dense, feature-rich AI coding agent for the terminal. Built-in voice dictation (Whisper) + TTS readout (ElevenLabs) + screen-reader mode for blind / low-vision users. 80+ slash commands, 9 modes including Hermes self-improving loop, multi-agent orchestration, bundled everything-claude-code skills library, learning system, and observable LLM transport. Works with OpenRouter, OpenAI, Anthropic-compatible, Ollama, LM Studio, DeepSeek, or any OpenAI-compatible API.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -29,7 +29,10 @@
29
29
  "tts",
30
30
  "screen-reader",
31
31
  "dictation",
32
- "blind"
32
+ "blind",
33
+ "memory",
34
+ "mempalace",
35
+ "knowledge-graph"
33
36
  ],
34
37
  "bin": {
35
38
  "compact-agent": "./bin/crowcoder.js"