jeopi-cli 16.2.27 → 16.2.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.
@@ -19,6 +19,9 @@ export interface AdvisorAgent {
19
19
  readonly state: {
20
20
  messages: AgentMessage[];
21
21
  error?: string;
22
+ model?: {
23
+ id: string;
24
+ };
22
25
  };
23
26
  }
24
27
  export interface AdvisorRuntimeHost {
@@ -3,6 +3,18 @@ export interface HistoryFormatOptions {
3
3
  title?: string;
4
4
  /** Render assistant thinking blocks (default: elided). */
5
5
  includeThinking?: boolean;
6
+ /**
7
+ * When rendering thinking (requires `includeThinking`), disguise it through
8
+ * {@link renderDemotedThinking} for this target model id instead of the literal
9
+ * `_thinking:_ ` label. Anthropic's `reasoning_extraction` classifier can flag a
10
+ * transcript that replays a *different* model's prior thinking back at a
11
+ * Fable/Mythos model labeled as "thinking" — this is the same trigger
12
+ * `renderDemotedThinking` already avoids for cross-model/cross-turn replay in the
13
+ * wire layer. Omitted for the human-facing `history://` dump, where the explicit
14
+ * label is more useful than the disguise and there is no live model on the other
15
+ * end to refuse it.
16
+ */
17
+ demoteThinkingForModelId?: string;
6
18
  /** Render tool intent comment before tool call lines. */
7
19
  includeToolIntent?: boolean;
8
20
  /** Render watched-session roles as inline `**agent**:` / `**user**:` labels (collapsing consecutive same-role messages) instead of `## ` headings, so a primary transcript embedded inside an advisor turn stays visually distinct. */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "jeopi-cli",
4
- "version": "16.2.27",
4
+ "version": "16.2.28",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/akillness/jeopi",
7
7
  "author": "Can Boluk",
@@ -43,6 +43,7 @@
43
43
  "gen:docs": "bun scripts/generate-docs-index.ts --generate",
44
44
  "gen:docs:reset": "bun scripts/generate-docs-index.ts --reset",
45
45
  "gen:tool-views": "bun --cwd=../collab-web run gen:tool-views",
46
+ "gen:share-viewer": "bun scripts/generate-share-viewer.ts",
46
47
  "gen:bundle": "bun scripts/bundle-dist.ts",
47
48
  "gen:mupdf": "bun scripts/embed-mupdf-wasm.ts --generate",
48
49
  "gen:mupdf:reset": "bun scripts/embed-mupdf-wasm.ts --reset",
@@ -56,17 +57,17 @@
56
57
  "@agentclientprotocol/sdk": "0.25.0",
57
58
  "@babel/parser": "^7.29.7",
58
59
  "@mozilla/readability": "^0.6.0",
59
- "jeopi-hashline": "16.2.27",
60
- "jeopi-stats": "16.2.27",
61
- "jeopi-agent-core": "16.2.27",
62
- "jeopi-ai": "16.2.27",
63
- "jeopi-catalog": "16.2.27",
64
- "jeopi-mnemopi": "16.2.27",
65
- "jeopi-natives": "16.2.27",
66
- "jeopi-tui": "16.2.27",
67
- "jeopi-utils": "16.2.27",
68
- "jeopi-wire": "16.2.27",
69
- "jeopi-snapcompact": "16.2.27",
60
+ "jeopi-hashline": "16.2.28",
61
+ "jeopi-stats": "16.2.28",
62
+ "jeopi-agent-core": "16.2.28",
63
+ "jeopi-ai": "16.2.28",
64
+ "jeopi-catalog": "16.2.28",
65
+ "jeopi-mnemopi": "16.2.28",
66
+ "jeopi-natives": "16.2.28",
67
+ "jeopi-tui": "16.2.28",
68
+ "jeopi-utils": "16.2.28",
69
+ "jeopi-wire": "16.2.28",
70
+ "jeopi-snapcompact": "16.2.28",
70
71
  "@opentelemetry/api": "^1.9.1",
71
72
  "@opentelemetry/context-async-hooks": "^2.7.1",
72
73
  "@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
@@ -1381,6 +1381,49 @@ describe("advisor", () => {
1381
1381
  expect(strippedNotices).toHaveLength(1);
1382
1382
  });
1383
1383
 
1384
+ it("never sends the literal reasoning_extraction-triggering label when the advisor's own model is Fable/Mythos (no refusal, no degrade)", async () => {
1385
+ const promptInputs: string[] = [];
1386
+ const strippedNotices: number[] = [];
1387
+ const agent: AdvisorAgent = {
1388
+ prompt: async input => {
1389
+ promptInputs.push(input);
1390
+ },
1391
+ abort: () => {},
1392
+ reset: () => {},
1393
+ state: { messages: [], model: { id: "claude-fable-5" } },
1394
+ };
1395
+ const thinking = "secret chain of thought the classifier flags";
1396
+ const messages: AgentMessage[] = [
1397
+ { role: "user", content: "do the thing", timestamp: 1 } as AgentMessage,
1398
+ {
1399
+ role: "assistant",
1400
+ content: [
1401
+ { type: "thinking", thinking },
1402
+ { type: "text", text: "done" },
1403
+ ],
1404
+ timestamp: 2,
1405
+ } as AgentMessage,
1406
+ ];
1407
+ const host: AdvisorRuntimeHost = {
1408
+ snapshotMessages: () => messages,
1409
+ enqueueAdvice: () => {},
1410
+ notifyThinkingStripped: () => strippedNotices.push(1),
1411
+ };
1412
+ const runtime = new AdvisorRuntime(agent, host, 0);
1413
+
1414
+ runtime.onTurnEnd(messages);
1415
+ await runtime.waitForCatchup(5000, 1);
1416
+
1417
+ // Sent once, on the first attempt — the disguised form carries the
1418
+ // reasoning content but never the literal "_thinking:_" label, so
1419
+ // there is nothing for the classifier to catch and no degrade fires.
1420
+ expect(promptInputs).toHaveLength(1);
1421
+ expect(promptInputs[0]).not.toContain("_thinking:_");
1422
+ expect(promptInputs[0]).toContain(thinking);
1423
+ expect(strippedNotices).toHaveLength(0);
1424
+ expect(runtime.backlog).toBe(0);
1425
+ });
1426
+
1384
1427
  it("skips the degrade path when thinking is disabled at construction and falls through to the watchdog", async () => {
1385
1428
  const promptInputs: string[] = [];
1386
1429
  const strippedNotices: number[] = [];
@@ -21,7 +21,7 @@ export interface AdvisorAgent {
21
21
  * turn `Agent.#runLoop` records on its internal state.
22
22
  */
23
23
  rollbackTo?(count: number): void;
24
- readonly state: { messages: AgentMessage[]; error?: string };
24
+ readonly state: { messages: AgentMessage[]; error?: string; model?: { id: string } };
25
25
  }
26
26
 
27
27
  export interface AdvisorRuntimeHost {
@@ -116,7 +116,12 @@ export class AdvisorRuntime {
116
116
  * `false` exactly once, the first time a classifier refusal is caught — see
117
117
  * the `#drain` catch block. That single flip is sufficient to both change
118
118
  * future renders AND guard against re-triggering the degrade path, so no
119
- * separate one-shot flag is needed alongside it.
119
+ * separate one-shot flag is needed alongside it. When the render target is a
120
+ * Fable/Mythos model, {@link formatSessionHistoryMarkdown}'s
121
+ * `demoteThinkingForModelId` (wired from `agent.state.model.id` in
122
+ * {@link AdvisorRuntime.#renderDelta}) already disguises the rendered thinking
123
+ * before the first send, so this latch mainly guards other/unforeseen
124
+ * classifier triggers on the first turn.
120
125
  */
121
126
  #includeThinking: boolean;
122
127
 
@@ -243,6 +248,7 @@ export class AdvisorRuntime {
243
248
  const formattedDelta = obfuscator?.hasSecrets() ? obfuscateAdvisorDelta(obfuscator, delta) : delta;
244
249
  const md = formatSessionHistoryMarkdown(formattedDelta, {
245
250
  includeThinking: this.#includeThinking,
251
+ demoteThinkingForModelId: this.agent.state.model?.id,
246
252
  includeToolIntent: true,
247
253
  watchedRoles: true,
248
254
  expandPrimaryContext: true,