Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions packages/opencode/test/provider/harmoniqs-no-tools.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,25 +99,33 @@ describe("LLMRequestPrep.prepare - harmoniqs idempotency", () => {
}
}

// The per-provider header union carries the static shape only — harmoniqs
// injects Idempotency-Key at runtime (#374) — so tests index through a
// widened record rather than the narrowed type.
async function prepareHeaders(model: any) {
const result = await Effect.runPromise(LLMRequestPrep.prepare(baseInput(model)))
return result.headers as Record<string, string | undefined>
}

test("sends Idempotency-Key header for harmoniqs provider", async () => {
const result = await Effect.runPromise(LLMRequestPrep.prepare(baseInput(harmoniqsModel)))
expect(result.headers["Idempotency-Key"]).toBeDefined()
expect(result.headers["Idempotency-Key"]).toMatch(/^amicode:/)
const headers = await prepareHeaders(harmoniqsModel)
expect(headers["Idempotency-Key"]).toBeDefined()
expect(headers["Idempotency-Key"]).toMatch(/^amicode:/)
})

test("sends X-Session-Id header for harmoniqs provider", async () => {
const result = await Effect.runPromise(LLMRequestPrep.prepare(baseInput(harmoniqsModel)))
expect(result.headers["X-Session-Id"]).toBe(sessionID)
const headers = await prepareHeaders(harmoniqsModel)
expect(headers["X-Session-Id"]).toBe(sessionID)
})

test("does not send Idempotency-Key for non-harmoniqs providers", async () => {
const result = await Effect.runPromise(LLMRequestPrep.prepare(baseInput(anthropicModel)))
expect(result.headers["Idempotency-Key"]).toBeUndefined()
const headers = await prepareHeaders(anthropicModel)
expect(headers["Idempotency-Key"]).toBeUndefined()
})

test("generates unique Idempotency-Key per request", async () => {
const a = await Effect.runPromise(LLMRequestPrep.prepare(baseInput(harmoniqsModel)))
const b = await Effect.runPromise(LLMRequestPrep.prepare(baseInput(harmoniqsModel)))
expect(a.headers["Idempotency-Key"]).not.toBe(b.headers["Idempotency-Key"])
const a = await prepareHeaders(harmoniqsModel)
const b = await prepareHeaders(harmoniqsModel)
expect(a["Idempotency-Key"]).not.toBe(b["Idempotency-Key"])
})
})
23 changes: 23 additions & 0 deletions packages/ui/src/context/marked-math.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@ test("renders tight and loose-inner single-$ math", async () => {
expect(await parse("set $\\delta/2\\pi = 0.1$ MHz")).toContain('class="katex"')
})

test("renders digit-led single-$ inline math", async () => {
// #375 — the open-side digit guard rejected any math starting with a digit,
// which is the standard physics reporting shape ($3.53\times10^{-5}$)
expect(await parse("nice determinism check ($3.53\\times10^{-5}$ — free)")).toContain('class="katex"')
expect(await parse("floor through the mock seam ($3.1\\times10^{-3}$, T1-dominated)")).toContain(
'class="katex"',
)
expect(await parse("infidelity $10^{-5}$ at best")).toContain('class="katex"')
expect(await parse("$0.99$-style fidelity")).toContain('class="katex"')
})

test("keeps tight digit-pair currency literal under the close-side guard", async () => {
// Pandoc rule: the closing $ must not be followed by a digit — the first $
// in "$30-and-$50" closes against "3", so the pair stays literal
const html = await parse("prices: $30-and-$50 pairs")
expect(html).not.toContain('class="katex"')
expect(html).toContain("$30-and-$50")
})

test("keeps currency and env-var dollars literal", async () => {
const prices = await parse("costs $5 and $10 total")
expect(prices).not.toContain('class="katex"')
Expand Down Expand Up @@ -66,6 +85,10 @@ test("renderMathInText renders single-$ inline and spares prose dollars", () =>
expect(prices).toContain("$5")
expect(prices).toContain("$10")

// #375 — digit-led math through the global replace, tight pairs still literal
expect(renderMathInText("check ($3.53\\times10^{-5}$ — free)")).toContain('class="katex"')
expect(renderMathInText("prices: $30-and-$50 pairs")).not.toContain('class="katex"')

expect(renderMathInText("$$\n\\hat H\n$$")).toContain("katex-display")
expect(renderMathInText("inline \\(\\Omega_x\\) math")).toContain('class="katex"')
})
13 changes: 8 additions & 5 deletions packages/ui/src/context/marked.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -420,12 +420,15 @@ registerCustomTheme("OpenCode", () => Promise.resolve(OpenCodeTheme))

// Single-$ inline math — restored after #34850 removed it for currency false
// positives. Pandoc-style tight delimiters (no whitespace just inside either
// $), no digit-led content (so $5, and $30-and-$50 pairs, stay literal), no
// $$ adjacency, no escaped \$. One regex family, three shapes: the tokenizer
// start hint, the anchored tokenizer match, and the global replace below.
// $): the opening $ drops the digit-led guard so $3.53\times10^{-5}$ renders;
// instead the closing $ must not be followed by a digit (Pandoc's actual
// currency rule — $30-and-$50 pairs stay literal because the first closing $
// abuts a digit). No $$ adjacency, no escaped \$. One regex family, three
// shapes: the tokenizer start hint, the anchored tokenizer match, and the
// global replace below.
const singleDollarStartRegex = /(?<![\\$])\$(?!\$)/
const singleDollarTokenizerRegex = /^\$(?!\$|\s|\d)((?:\\.|[^$\\\n])+?)(?<![\\\s])\$(?!\$)/
const singleDollarInlineRegex = /(?<![\\$])\$(?!\$|\s|\d)((?:\\.|[^$\\\n])+?)(?<![\\\s])\$(?!\$)/g
const singleDollarTokenizerRegex = /^\$(?!\$|\s)((?:\\.|[^$\\\n])+?)(?<![\\\s])\$(?!\$|\d)/
const singleDollarInlineRegex = /(?<![\\$])\$(?!\$|\s)((?:\\.|[^$\\\n])+?)(?<![\\\s])\$(?!\$|\d)/g

export function renderMathInText(text: string): string {
let result = text
Expand Down
Loading