feat(view,tests): query blocks stay code in text the agent did not write
This commit is contained in:
1 parent
43d1e1a4a3
commit
91699a382e
5 files changed
+66
-4
No files matched your search
+17
-1
@@ -223,7 +223,12 @@ function stamped(messages: HistoryMessage[]): HistoryMessage[] {
|
|||||||
|
|
||||||
const HISTORY: Record<string, HistoryMessage[]> = {
|
const HISTORY: Record<string, HistoryMessage[]> = {
|
||||||
[MASTER]: [
|
[MASTER]: [
|
||||||
{ content: "с утра: дневник приехал? что в хендауте", role: "user" },
|
{
|
||||||
|
content: "с утра: дневник приехал? что в хендауте",
|
||||||
|
role: "user",
|
||||||
|
service:
|
||||||
|
"[envelope - background signal, not a message; react only if it bears on the question]\ntime: 2026-08-29 06:04 (Warsaw)\nvault, changed since 05:09: 📅 дни/2026-08-29.md (+4)\n--- 📅 дни/2026-08-29.md, added lines only ---\n+ # планы\n+ просрочены:\n+ ```tasks\n+ not done\n+ 06:04 - пожалуй пойду спать",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
content:
|
content:
|
||||||
"Приехал. В [[2026-08-28|хендауте]] два хвоста: **бластер** ждёт выбора модели, и **ufw на dell** - порт 62990 снаружи молчит. Ветка по ufw открыта, см. [[ufw на dell]].",
|
"Приехал. В [[2026-08-28|хендауте]] два хвоста: **бластер** ждёт выбора модели, и **ufw на dell** - порт 62990 снаружи молчит. Ветка по ufw открыта, см. [[ufw на dell]].",
|
||||||
@@ -232,6 +237,11 @@ const HISTORY: Record<string, HistoryMessage[]> = {
|
|||||||
{ content: "ок, гони ufw", role: "user" },
|
{ content: "ок, гони ufw", role: "user" },
|
||||||
{
|
{
|
||||||
content: [
|
content: [
|
||||||
|
{
|
||||||
|
thinking:
|
||||||
|
"The firewall rule and the proxy config can disagree in two ways: the port is closed, or nothing listens behind it. Reading the Caddy site first tells me which port the outside is supposed to reach at all.",
|
||||||
|
type: "thinking",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: "Смотрю правила через `ssh dell` и сверяю с `site.caddy`.",
|
text: "Смотрю правила через `ssh dell` и сверяю с `site.caddy`.",
|
||||||
type: "text",
|
type: "text",
|
||||||
@@ -242,6 +252,12 @@ const HISTORY: Record<string, HistoryMessage[]> = {
|
|||||||
name: "Bash",
|
name: "Bash",
|
||||||
type: "tool_use",
|
type: "tool_use",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "tu_say",
|
||||||
|
input: { text: "Нашёл: снаружи должен отвечать 443, не 62990." },
|
||||||
|
name: "mcp__gateway__say",
|
||||||
|
type: "tool_use",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
role: "assistant",
|
role: "assistant",
|
||||||
},
|
},
|
||||||
|
|||||||
+15
-3
@@ -1,5 +1,6 @@
|
|||||||
import type { App, Component } from "obsidian";
|
import type { App, Component } from "obsidian";
|
||||||
import { MarkdownRenderer, Platform } from "obsidian";
|
import { MarkdownPreviewRenderer, MarkdownRenderer, Platform } from "obsidian";
|
||||||
|
import { inertFences } from "$lib/panel/fences";
|
||||||
import type { PanelHost } from "$lib/panel/host";
|
import type { PanelHost } from "$lib/panel/host";
|
||||||
|
|
||||||
export interface HostOptions {
|
export interface HostOptions {
|
||||||
@@ -12,17 +13,28 @@ export interface HostOptions {
|
|||||||
sourcePath: () => string;
|
sourcePath: () => string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QUERY_LANGUAGES = new Set(["tasks", "dataview", "dataviewjs", "query"]);
|
||||||
|
|
||||||
|
function runs(language: string): boolean {
|
||||||
|
const registered = (
|
||||||
|
MarkdownPreviewRenderer as unknown as {
|
||||||
|
codeBlockPostProcessors?: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
).codeBlockPostProcessors;
|
||||||
|
return QUERY_LANGUAGES.has(language) || language in (registered ?? {});
|
||||||
|
}
|
||||||
|
|
||||||
// The Obsidian side of the panel: markdown through the app's own renderer,
|
// The Obsidian side of the panel: markdown through the app's own renderer,
|
||||||
// [[links]] opened in place, a conversation's note opened by its binding.
|
// [[links]] opened in place, a conversation's note opened by its binding.
|
||||||
export function obsidianHost(options: HostOptions): PanelHost {
|
export function obsidianHost(options: HostOptions): PanelHost {
|
||||||
const { app, component } = options;
|
const { app, component } = options;
|
||||||
return {
|
return {
|
||||||
markdown(node, text) {
|
markdown(node, text, { inert = false } = {}) {
|
||||||
let alive = true;
|
let alive = true;
|
||||||
const staging = document.createElement("div");
|
const staging = document.createElement("div");
|
||||||
MarkdownRenderer.render(
|
MarkdownRenderer.render(
|
||||||
app,
|
app,
|
||||||
text,
|
inert ? inertFences(text, runs) : text,
|
||||||
staging,
|
staging,
|
||||||
options.sourcePath(),
|
options.sourcePath(),
|
||||||
component
|
component
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { inertFences } from "$lib/panel/fences";
|
||||||
|
|
||||||
|
const runs = (language: string) => ["tasks", "dataview"].includes(language);
|
||||||
|
|
||||||
|
describe("inertFences", () => {
|
||||||
|
it("turns a query block into code", () => {
|
||||||
|
expect(inertFences("```tasks\nnot done\n```", runs)).toBe(
|
||||||
|
"```text\nnot done\n```"
|
||||||
|
);
|
||||||
|
expect(inertFences("~~~Dataview\nlist\n~~~", runs)).toBe(
|
||||||
|
"~~~text\nlist\n~~~"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reaches a block opened inside a list item or a quote", () => {
|
||||||
|
expect(inertFences("+ ```tasks\n+ not done", runs)).toBe(
|
||||||
|
"+ ```text\n+ not done"
|
||||||
|
);
|
||||||
|
expect(inertFences("> 1. ````tasks {x}", runs)).toBe("> 1. ````text {x}");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("leaves ordinary code and closing fences alone", () => {
|
||||||
|
const text = "```python\nprint(1)\n```\ninline `tasks` stays";
|
||||||
|
expect(inertFences(text, runs)).toBe(text);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -34,6 +34,12 @@ export const moment = () => undefined;
|
|||||||
export const requestUrl = () =>
|
export const requestUrl = () =>
|
||||||
Promise.reject(new Error("no network in the stub"));
|
Promise.reject(new Error("no network in the stub"));
|
||||||
export const setIcon = () => undefined;
|
export const setIcon = () => undefined;
|
||||||
|
export const MarkdownPreviewRenderer = {
|
||||||
|
codeBlockPostProcessors: { tasks: () => undefined } as Record<
|
||||||
|
string,
|
||||||
|
unknown
|
||||||
|
>,
|
||||||
|
};
|
||||||
|
|
||||||
function escapeHtml(value: string): string {
|
function escapeHtml(value: string): string {
|
||||||
return value
|
return value
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { defineConfig } from "vitest/config";
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
$lib: new URL("../beaver-gateway/ui/src/lib", import.meta.url).pathname,
|
||||||
obsidian: new URL("./tests/obsidian-stub.ts", import.meta.url).pathname,
|
obsidian: new URL("./tests/obsidian-stub.ts", import.meta.url).pathname,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in new issue
Block a user