@giovannijecha/jecode 0.5.0 → 0.6.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.
- package/README.md +19 -2
- package/dist/batch.js +54 -4
- package/dist/cli-info.js +3 -0
- package/dist/config.js +12 -0
- package/dist/context/capacity.js +18 -0
- package/dist/context/compactor.js +60 -0
- package/dist/context/policy.js +125 -0
- package/dist/context/projection.js +49 -0
- package/dist/controller-request.js +34 -0
- package/dist/controller.js +25 -18
- package/dist/conversation.js +31 -3
- package/dist/providers/anthropic.js +33 -3
- package/dist/providers/catalog.js +11 -4
- package/dist/providers/ollama.js +75 -1
- package/dist/providers/openai-codex.js +46 -2
- package/dist/providers/openai.js +17 -0
- package/dist/sessions/codec.js +39 -7
- package/dist/sessions/store.js +5 -5
- package/dist/settings-command.js +42 -2
- package/dist/settings.js +9 -0
- package/dist/tui/app-workflows.js +75 -4
- package/dist/usage.js +8 -0
- package/package.json +1 -1
package/dist/settings.js
CHANGED
|
@@ -3,6 +3,7 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
import { chmod, mkdir } from "node:fs/promises";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { atomicWrite } from "./atomic.js";
|
|
6
|
+
import { MAX_COMPACTION_PERCENT, MIN_COMPACTION_PERCENT } from "./context/policy.js";
|
|
6
7
|
import { EFFORTS } from "./effort.js";
|
|
7
8
|
import { providerNames } from "./providers/index.js";
|
|
8
9
|
import { parseOllamaEndpoint } from "./providers/ollama-endpoint.js";
|
|
@@ -59,6 +60,7 @@ function normalize(value) {
|
|
|
59
60
|
const reducedMotion = typeof value["reducedMotion"] === "boolean" ? value["reducedMotion"] : undefined;
|
|
60
61
|
const maxTokens = positiveInteger(value["maxTokens"]);
|
|
61
62
|
const maxSteps = positiveInteger(value["maxSteps"]);
|
|
63
|
+
const compactionPercent = percentage(value["compactionPercent"]);
|
|
62
64
|
return {
|
|
63
65
|
...(provider === undefined ? {} : { provider }),
|
|
64
66
|
...(models === undefined ? {} : { models }),
|
|
@@ -67,6 +69,7 @@ function normalize(value) {
|
|
|
67
69
|
...(reducedMotion === undefined ? {} : { reducedMotion }),
|
|
68
70
|
...(maxTokens === undefined ? {} : { maxTokens }),
|
|
69
71
|
...(maxSteps === undefined ? {} : { maxSteps }),
|
|
72
|
+
...(compactionPercent === undefined ? {} : { compactionPercent }),
|
|
70
73
|
};
|
|
71
74
|
}
|
|
72
75
|
function modelsOf(value, providers) {
|
|
@@ -91,6 +94,12 @@ function endpoint(value) {
|
|
|
91
94
|
function positiveInteger(value) {
|
|
92
95
|
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
93
96
|
}
|
|
97
|
+
function percentage(value) {
|
|
98
|
+
return typeof value === "number" && Number.isSafeInteger(value) &&
|
|
99
|
+
value >= MIN_COMPACTION_PERCENT && value <= MAX_COMPACTION_PERCENT
|
|
100
|
+
? value
|
|
101
|
+
: undefined;
|
|
102
|
+
}
|
|
94
103
|
function record(value) {
|
|
95
104
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
96
105
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// Foreground command and model-turn workflows for the TUI shell.
|
|
2
2
|
import { handleCommand } from "../commands.js";
|
|
3
3
|
import { runTurn } from "../controller.js";
|
|
4
|
+
import { resolveContextPolicy } from "../context/capacity.js";
|
|
5
|
+
import { compactContext } from "../context/compactor.js";
|
|
6
|
+
import { isContextOverflow, shouldResolveContextPolicy } from "../context/policy.js";
|
|
4
7
|
import { updateSettings } from "../settings.js";
|
|
5
8
|
import { saveTranscript } from "../transcript-export.js";
|
|
6
|
-
import { recordUsage } from "../usage.js";
|
|
9
|
+
import { recordAuxiliaryUsage, recordUsage } from "../usage.js";
|
|
7
10
|
import { answerAt } from "./approve.js";
|
|
8
11
|
import { cancel as cancelOpen } from "./overlay.js";
|
|
9
12
|
import { controllerOptions, turnFailure } from "./session-view.js";
|
|
@@ -81,12 +84,18 @@ export function appWorkflows(options) {
|
|
|
81
84
|
return;
|
|
82
85
|
const parentId = session.conversation.activeNodeId;
|
|
83
86
|
const history = session.conversation.history;
|
|
87
|
+
const modelHistory = session.conversation.contextHistory;
|
|
84
88
|
const historyStart = history.length;
|
|
85
89
|
const blockStart = state.blocks.length;
|
|
86
90
|
const createdAt = new Date().toISOString();
|
|
91
|
+
const prospectiveNodeId = session.conversation.nodes.length + 1;
|
|
87
92
|
let nodeId;
|
|
93
|
+
let context;
|
|
94
|
+
let contextPolicy;
|
|
88
95
|
options.emit({ kind: "user", text });
|
|
89
|
-
|
|
96
|
+
const user = { role: "user", content: [{ kind: "text", text }] };
|
|
97
|
+
history.push(user);
|
|
98
|
+
modelHistory.push(structuredClone(user));
|
|
90
99
|
const events = transcribe({
|
|
91
100
|
emit: options.emit,
|
|
92
101
|
render: options.render,
|
|
@@ -102,7 +111,7 @@ export function appWorkflows(options) {
|
|
|
102
111
|
},
|
|
103
112
|
usage: (usage) => recordUsage(session.usage, usage),
|
|
104
113
|
});
|
|
105
|
-
|
|
114
|
+
const persist = async (checkpoint, settlement) => {
|
|
106
115
|
const next = session.conversation.commit({
|
|
107
116
|
...(nodeId === undefined ? {} : { nodeId }),
|
|
108
117
|
parentId,
|
|
@@ -114,14 +123,76 @@ export function appWorkflows(options) {
|
|
|
114
123
|
},
|
|
115
124
|
messages: checkpoint.slice(historyStart),
|
|
116
125
|
blocks: state.blocks.slice(blockStart),
|
|
126
|
+
...(context === undefined ? {} : { context }),
|
|
117
127
|
}, settlement);
|
|
118
128
|
await session.persistence?.checkpoint(next);
|
|
119
129
|
session.conversation = next;
|
|
120
130
|
nodeId = next.activeNodeId;
|
|
121
131
|
};
|
|
132
|
+
const compact = async (checkpoint, projected, reason, error) => {
|
|
133
|
+
if (reason === "overflow" && (error === undefined || !isContextOverflow(error))) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
const force = reason === "overflow";
|
|
137
|
+
if (!shouldResolveContextPolicy(projected, session.usage.lastInputTokens, force)) {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
if (contextPolicy === undefined) {
|
|
141
|
+
state.status = "Checking context";
|
|
142
|
+
options.render();
|
|
143
|
+
contextPolicy = resolveContextPolicy({
|
|
144
|
+
provider: session.provider,
|
|
145
|
+
model: session.model,
|
|
146
|
+
compactionPercent: session.config.compactionPercent,
|
|
147
|
+
signal: activity.control.signal,
|
|
148
|
+
onStatus: (status) => {
|
|
149
|
+
state.status = status;
|
|
150
|
+
options.render();
|
|
151
|
+
},
|
|
152
|
+
}).finally(() => {
|
|
153
|
+
state.status = WAITING;
|
|
154
|
+
options.render();
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
const result = await compactContext({
|
|
158
|
+
provider: session.provider,
|
|
159
|
+
model: session.model,
|
|
160
|
+
effort: session.config.effort,
|
|
161
|
+
context: projected,
|
|
162
|
+
turn: checkpoint.slice(historyStart),
|
|
163
|
+
nodeId: nodeId ?? prospectiveNodeId,
|
|
164
|
+
coveredMessages: context?.messageCount ?? 0,
|
|
165
|
+
lastInputTokens: session.usage.lastInputTokens,
|
|
166
|
+
signal: activity.control.signal,
|
|
167
|
+
force,
|
|
168
|
+
policy: await contextPolicy,
|
|
169
|
+
onBegin: () => {
|
|
170
|
+
state.status = "Compacting";
|
|
171
|
+
options.render();
|
|
172
|
+
},
|
|
173
|
+
onEnd: () => {
|
|
174
|
+
state.status = WAITING;
|
|
175
|
+
options.render();
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
if (result === undefined)
|
|
179
|
+
return undefined;
|
|
180
|
+
context = result.anchor;
|
|
181
|
+
if (result.usage !== undefined)
|
|
182
|
+
recordAuxiliaryUsage(session.usage, result.usage);
|
|
183
|
+
return result.messages;
|
|
184
|
+
};
|
|
185
|
+
events.onContext = compact;
|
|
186
|
+
events.onCheckpoint = async (checkpoint, settlement, projected) => {
|
|
187
|
+
await persist(checkpoint, settlement);
|
|
188
|
+
const compacted = await compact(checkpoint, projected, "budget");
|
|
189
|
+
if (compacted !== undefined)
|
|
190
|
+
await persist(checkpoint, settlement);
|
|
191
|
+
return compacted;
|
|
192
|
+
};
|
|
122
193
|
let finishReason;
|
|
123
194
|
try {
|
|
124
|
-
await runTurn(history, controllerOptions(session, permissions.availableTools()), events, activity.control.signal);
|
|
195
|
+
await runTurn(history, controllerOptions(session, permissions.availableTools()), events, activity.control.signal, modelHistory);
|
|
125
196
|
}
|
|
126
197
|
catch (error) {
|
|
127
198
|
const interrupted = activity.control.signal.aborted;
|
package/dist/usage.js
CHANGED
|
@@ -13,6 +13,14 @@ export function emptyUsage() {
|
|
|
13
13
|
export function recordUsage(total, next) {
|
|
14
14
|
total.requests += 1;
|
|
15
15
|
total.lastInputTokens = next.inputTokens;
|
|
16
|
+
addUsage(total, next);
|
|
17
|
+
}
|
|
18
|
+
/** Account for an internal request without replacing the main context signal. */
|
|
19
|
+
export function recordAuxiliaryUsage(total, next) {
|
|
20
|
+
total.requests += 1;
|
|
21
|
+
addUsage(total, next);
|
|
22
|
+
}
|
|
23
|
+
function addUsage(total, next) {
|
|
16
24
|
total.inputTokens += next.inputTokens;
|
|
17
25
|
total.outputTokens += next.outputTokens;
|
|
18
26
|
total.cachedInputTokens += next.cachedInputTokens;
|