Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
d56bda1
feat(api): abort signal support for native-ollama (completePrompt + c…
easonliang28 Aug 19, 2026
346eeb3
fix(api): address CodeRabbit review on native-ollama abort handling
easonliang28 Aug 20, 2026
b3449a2
Merge branch 'main' into feat/abort-r1-native-ollama
easonLiangWorldedtech Aug 30, 2026
6d59fad
Merge branch 'main' into feat/abort-r1-native-ollama
easonLiangWorldedtech Sep 1, 2026
1a21368
Merge remote-tracking branch 'upstream/main' into feat/abort-r1-nativ…
easonliang28 Sep 2, 2026
df58e60
fix(api): harden native Ollama abort handling and credential gating
easonliang28 Sep 2, 2026
45c5c0a
fix(api): harden native Ollama cancellation and credential routing
easonliang28 Sep 3, 2026
ec8a491
fix(api): harden Ollama loopback check and stream finalization
easonliang28 Sep 3, 2026
e08e012
Merge upstream/main (79cd12f2c) into feat/abort-r1-native-ollama
easonliang28 Sep 3, 2026
5e1b719
fix(ci): declare vitest as a root devDependency so the mutation gate …
easonliang28 Sep 3, 2026
dc36ac7
Merge branch 'main' into feat/abort-r1-native-ollama
easonLiangWorldedtech Sep 3, 2026
95155b0
fix(api): harden native Ollama abort/timeout paths and add mutation-k…
easonliang28 Sep 3, 2026
0afb9bf
Merge remote-tracking branch 'origin/feat/abort-r1-native-ollama' int…
easonliang28 Sep 3, 2026
192059d
fix(api): kill remaining Ollama mutation survivors (thought tag, Abor…
easonliang28 Sep 3, 2026
c38b376
Merge branch main into feat/abort-r1-native-ollama
easonliang28 Sep 6, 2026
efb32e2
Merge branch 'main' into feat/abort-r1-native-ollama
easonLiangWorldedtech Sep 15, 2026
d8503d8
Merge remote-tracking branch 'upstream/main' into fix-pr-1299
easonliang28 Sep 27, 2026
d2d0cbf
chore: sync pnpm lockfile with root vitest devDependency
easonliang28 Sep 27, 2026
8cb94a5
test: replace double assertions in timer fakes with single structural…
easonliang28 Sep 27, 2026
37dbd62
chore: bump root vitest to 4.1.11 to clear dependency-review finding
easonliang28 Sep 27, 2026
718a89f
Merge branch 'main' into feat/abort-r1-native-ollama
easonLiangWorldedtech Sep 28, 2026
4389c9c
fix(native-ollama): detach abort listener, cancel discovery, align vi…
Sep 28, 2026
e34b840
Merge branch 'main' into feat/abort-r1-native-ollama
easonLiangWorldedtech Sep 29, 2026
d95082b
fix(native-ollama): prove the forwarded discovery signal is linked to…
Sep 29, 2026
2c4feb7
Merge remote-tracking branch 'upstream/main' into feat/abort-r1-nativ…
Oct 2, 2026
7c1d85f
Merge commit 'refs/shapes/upstream-main' into feat/abort-r1-native-ol…
Oct 2, 2026
4172aa2
Merge branch 'main' into feat/abort-r1-native-ollama
easonLiangWorldedtech Oct 5, 2026
bf76e72
Merge upstream main (285f6687a) into feat/abort-r1-native-ollama
easonliang28 Oct 13, 2026
4e318eb
Address review: caller-side transport cancellation coverage, credenti…
easonliang28 Oct 13, 2026
fa64caf
Revert remaining vitest peer bumps with the dependency move
easonliang28 Oct 13, 2026
91dc04c
Address review: reuse shared abort-signal helpers; warn on dropped AP…
easonliang28 Oct 14, 2026
d57c6cf
Merge upstream/main (58341d882) into feat/abort-r1-native-ollama
easonliang28 Oct 14, 2026
6e216e2
chore(api): remove Stryker suppression comments from touched files
easonliang28 Oct 14, 2026
e7ca0b0
fix(api): echo only the endpoint origin in the credential-drop warning
easonliang28 Oct 14, 2026
2c34c18
fix(api): reject non-finite and cap overflowing timeoutMs delays
easonliang28 Oct 14, 2026
153ffab
fix(api): round fractional timeouts and pin the aborted-outcome asser…
easonliang28 Oct 14, 2026
6319fe5
test(api): assert the rounded delay reaching AbortSignal.timeout
easonliang28 Oct 14, 2026
0d18b4d
fix(api): round fractional completion timeouts up before scheduling
easonliang28 Oct 14, 2026
d9c2969
chore(lint): guard api providers against repeat abort and logging mis…
edelauna Oct 20, 2026
ef1035e
fix(api): log only the endpoint origin in fetcher warnings
edelauna Oct 20, 2026
2ec4d68
fix(api): harden ollama key-drop warning and client creation
edelauna Oct 20, 2026
926b46d
test(webview): add Ollama key help visual baseline and translations
edelauna Oct 20, 2026
44cf144
fix(api): drop ollama key when debug proxy would see it in cleartext
edelauna Oct 21, 2026
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
37 changes: 37 additions & 0 deletions packages/config-eslint/api-provider-hygiene.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Guards for repeat review findings in src/api. Built-in no-restricted-syntax only: no custom rule code.
// Sources: shared helpers live in src/api/providers/utils/abort-signal.ts.
// Paths are relative to the `src` package, where this config is loaded.

const sharedAbortHelpers =
"mergeAbortSignalAndTimeout|mergeAbortSignals|throwIfAborted|isRequestAborted|createAbortError|rejectOnAbort|resolveModelWithAbort"

// Names that usually hold a secret or an endpoint that can embed credentials.
// `cacheKey` and `contextTokens` must not match.
const sensitiveName = "^(url|apiKey|secret|password)$|(Url|URL|ApiKey|Secret|Token)$"

export const apiProviderHygieneSelectors = [
{
selector: `:matches(FunctionDeclaration, VariableDeclarator)[id.name=/^(${sharedAbortHelpers})$/]`,
message: "Import this helper from providers/utils/abort-signal instead of declaring a local copy.",
},
{
selector:
"CallExpression[callee.object.name='AbortSignal'][callee.property.name='timeout']:not([arguments.0.type='Literal']):not([arguments.0.name=/^[A-Z][A-Z0-9_]*$/])",
message:
"Use mergeAbortSignalAndTimeout for a variable delay. AbortSignal.timeout throws on Infinity and fractions, and clamps large values to 1 ms.",
},
{
selector: `CallExpression[callee.object.name='console'] TemplateLiteral > :matches(Identifier[name=/${sensitiveName}/], MemberExpression[property.name=/${sensitiveName}/])`,
message:
"Do not log a URL, key, secret or token. A base URL can embed credentials or query secrets. Log the origin only.",
},
]

export const apiProviderHygieneConfig = {
files: ["api/**/*.ts"],
// The helper module owns the shared names. Tests build their own fixtures.
ignores: ["api/providers/utils/abort-signal.ts", "**/__tests__/**", "**/*.test.ts", "**/*.spec.ts"],
rules: {
"no-restricted-syntax": ["error", ...apiProviderHygieneSelectors],
},
}
90 changes: 90 additions & 0 deletions packages/config-eslint/api-provider-hygiene.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import assert from "node:assert/strict"
import { describe, it } from "node:test"

import { Linter } from "eslint"
import typescriptEslint from "typescript-eslint"

import { apiProviderHygieneConfig } from "./api-provider-hygiene.js"

const linter = new Linter({ configType: "flat" })
const config = [{ files: ["**/*.ts"], languageOptions: { parser: typescriptEslint.parser } }, apiProviderHygieneConfig]

const lint = (code, filename = "api/providers/example.ts") =>
linter.verify(code, config, { filename }).map((message) => message.message)

describe("api provider hygiene: shared abort helpers", () => {
for (const code of [
"function createAbortError(name: string) { return new Error(name) }",
"const rejectOnAbort = () => {}",
"async function resolveModelWithAbort() {}",
]) {
it(`flags a local copy: ${code}`, () => {
assert.equal(lint(code).length, 1)
})
}

it("allows importing the helper", () => {
assert.deepEqual(lint('import { createAbortError } from "./utils/abort-signal"\ncreateAbortError("x")'), [])
})

it("does not apply to the helper module", () => {
assert.deepEqual(lint("export function createAbortError() {}", "api/providers/utils/abort-signal.ts"), [])
})

it("does not apply to tests", () => {
assert.deepEqual(lint("function createAbortError() {}", "api/providers/__tests__/example.spec.ts"), [])
})

it("does not apply outside src/api", () => {
assert.deepEqual(lint("function createAbortError() {}", "services/example.ts"), [])
})
})

describe("api provider hygiene: AbortSignal.timeout", () => {
for (const code of [
"AbortSignal.timeout(timeoutMs)",
"AbortSignal.timeout(options.timeoutMs)",
"AbortSignal.timeout(seconds * 1000)",
]) {
it(`flags a variable delay: ${code}`, () => {
assert.equal(lint(code).length, 1)
})
}

for (const code of [
"AbortSignal.timeout(10_000)",
"AbortSignal.timeout(MODEL_CATALOG_FETCH_TIMEOUT_MS)",
"AbortSignal.any([a, b])",
]) {
it(`allows: ${code}`, () => {
assert.deepEqual(lint(code), [])
})
}
})

describe("api provider hygiene: sensitive values in logs", () => {
for (const code of [
"console.warn(`Error connecting at ${baseUrl}`)",
"console.warn(`Error connecting at ${this.options.ollamaBaseUrl}`)",
"console.error(`refresh failed for ${this._serverUrl}`)",
"console.log(`key ${apiKey}`)",
"console.log(`auth ${accessToken}`)",
"console.log(`from ${url}`)",
]) {
it(`flags: ${code}`, () => {
assert.equal(lint(code).length, 1)
})
}

for (const code of [
"console.error(`Error writing ${cacheKey} to disk`)",
"console.warn(`Current tokens: ${contextTokens}`)",
"console.warn(`Endpoint ${endpointOrigin} is not secure`)",
"const message = `at ${baseUrl}`",
'console.warn("static message")',
]) {
it(`allows: ${code}`, () => {
assert.deepEqual(lint(code), [])
})
}
})
5 changes: 3 additions & 2 deletions packages/config-eslint/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
"./base": "./base.js",
"./react": "./react.js",
"./next-js": "./next.js",
"./provider-identifiers": "./provider-identifiers.js"
"./provider-identifiers": "./provider-identifiers.js",
"./api-provider-hygiene": "./api-provider-hygiene.js"
},
"scripts": {
"test": "node --test provider-identifiers.test.js"
"test": "node --test provider-identifiers.test.js api-provider-hygiene.test.js"
},
"devDependencies": {
"@eslint/js": "9.39.4",
Expand Down
Loading
Loading