thincoder 0.12.26 → 0.12.28
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/package.json +1 -1
- package/src/agent/setup.mjs +18 -13
- package/src/provider/core.mjs +3 -1
- package/src/session.mjs +7 -1
package/package.json
CHANGED
package/src/agent/setup.mjs
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* agent/setup.mjs — runAgent pre-flight setup: context injection, system prompt construction, tool injection
|
|
3
3
|
*/
|
|
4
|
+
/** Local time, second precision, for the per-run transient reminder. */
|
|
5
|
+
function timeNowLocal() {
|
|
6
|
+
return new Date().toLocaleString("sv-SE")
|
|
7
|
+
}
|
|
8
|
+
|
|
4
9
|
import { search as memorySearch, docSearch } from "../memory.mjs"
|
|
5
10
|
import { pushReal } from "../context.mjs"
|
|
6
11
|
import { toOpenAISchema } from "../tools/index.mjs"
|
|
@@ -120,11 +125,6 @@ export async function prepareRun(agent, input, callbacks, {
|
|
|
120
125
|
}
|
|
121
126
|
}
|
|
122
127
|
if (depth === 0) {
|
|
123
|
-
agent.history.push({
|
|
124
|
-
role: "user",
|
|
125
|
-
content: `[System reminder: current time is ${new Date().toISOString()}.]`,
|
|
126
|
-
transient: true,
|
|
127
|
-
})
|
|
128
128
|
// Checklist injection: inject pending + in_progress items from .thincoder/checklist.md
|
|
129
129
|
try {
|
|
130
130
|
const { pendingItems } = await import("../tools/checklist.mjs")
|
|
@@ -139,6 +139,15 @@ export async function prepareRun(agent, input, callbacks, {
|
|
|
139
139
|
} catch { /* checklist not available — suppress error */ }
|
|
140
140
|
}
|
|
141
141
|
pushReal(agent, { role: "user", content: input })
|
|
142
|
+
// Time grounding for EVERY agent depth, pushed LAST (after the user input): transient,
|
|
143
|
+
// dropped on persist, fresh at every run start. Tail position keeps the second-precision
|
|
144
|
+
// content out of any prefix — caches stay hit (plugin hit a position-drift regression
|
|
145
|
+
// when the reminder was interleaved before the input; CLI is aligned preemptively).
|
|
146
|
+
agent.history.push({
|
|
147
|
+
role: "user",
|
|
148
|
+
content: `[System reminder: current time is ${timeNowLocal()} (local; timezone ${Intl.DateTimeFormat().resolvedOptions().timeZone || "local"}).]`,
|
|
149
|
+
transient: true,
|
|
150
|
+
})
|
|
142
151
|
}
|
|
143
152
|
|
|
144
153
|
if (agent._pendingReminders.length > 0) {
|
|
@@ -221,14 +230,10 @@ export async function prepareRun(agent, input, callbacks, {
|
|
|
221
230
|
? `${base}\n\n${mainOverlay}`
|
|
222
231
|
: base
|
|
223
232
|
|
|
224
|
-
//
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || "local"
|
|
229
|
-
const now = new Date()
|
|
230
|
-
const mins = String(now.getMinutes()).padStart(2, "0")
|
|
231
|
-
systemPrompt += `\n\nCurrent time: ${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")} ${String(now.getHours()).padStart(2, "0")}:${mins} (${timeZone}).`
|
|
233
|
+
// Time injection deliberately does NOT live here: system prompts must be byte-identical
|
|
234
|
+
// across runs (provider prefix caches). The time rides a transient user reminder per turn
|
|
235
|
+
// (see the current-time injection below) — variable content belongs in the history, not
|
|
236
|
+
// the cached prefix.
|
|
232
237
|
|
|
233
238
|
const projectRules = await loadProjectInstructions(agent.cwd)
|
|
234
239
|
if (projectRules) {
|
package/src/provider/core.mjs
CHANGED
|
@@ -240,7 +240,9 @@ export function normalizeToolPairing(messages) {
|
|
|
240
240
|
rest.push(m)
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
|
-
if (toolById.size === 0
|
|
243
|
+
if (toolById.size === 0 && !messages.some((m) => m.role === "assistant" && m.tool_calls?.length)) {
|
|
244
|
+
return messages // no tool messages AND no tool_calls declared — nothing to enforce
|
|
245
|
+
}
|
|
244
246
|
const out = []
|
|
245
247
|
for (const m of rest) {
|
|
246
248
|
out.push(m)
|
package/src/session.mjs
CHANGED
|
@@ -325,8 +325,14 @@ export function saveSession(agent) {
|
|
|
325
325
|
// _fullHistory is written at the source via pushReal — no flush needed here.
|
|
326
326
|
// history = FULL, never-compacted (human-readable; VS Code panel & CLI resume read this)
|
|
327
327
|
// contextHistory = machine context (possibly compacted) so CLI resume keeps the token savings
|
|
328
|
+
// Human line: transient machine injections never enter the readable record.
|
|
328
329
|
const history = (agent._fullHistory ?? agent.history).filter((m) => !m.transient && !isLegacyTransient(m))
|
|
329
|
-
|
|
330
|
+
// Machine line (contextHistory): KEEP transient messages — resume must rebuild the
|
|
331
|
+
// machine line byte-identical to what the provider cache saw. Dropping them made every
|
|
332
|
+
// process restart diverge at the first injection position (git/OS/time reminders are
|
|
333
|
+
// re-injected with FRESH content) → whole-prefix cache miss on the CLI's very first
|
|
334
|
+
// request of each session (2026-08-16 cache-hit report; Kimi review).
|
|
335
|
+
const contextHistory = agent.history.filter((m) => !isLegacyTransient(m))
|
|
330
336
|
const data = {
|
|
331
337
|
version: 2,
|
|
332
338
|
cwd: agent.cwd,
|