Haven provider + fix dropped completions on vLLM backends - #1

Open
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider
Open

Haven provider + fix dropped completions on vLLM backends#1
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider

Conversation

@coelhogonzalo

Copy link
Copy Markdown
Collaborator

Opened against this fork's main to trigger pr-build-upload-vsix.yaml, which
builds the VSIX natively for linux-x64, win32-x64 and darwin-arm64 and uploads
each as an artifact. The darwin-arm64 artifact is the one to share with macOS
users. Not intended for continuedev/continue.

Commits

  • Add first-class Haven providerprovider: haven, an OpenAI subclass on
    the raw-fetch path. Request bodies are HPKE-encrypted in-process to the
    Tinfoil enclave via haven-proxy's relay core, so no localhost proxy runs and
    Haven never sees prompts or completions.
  • Make haven-proxy ambient types visible to the gui/binary type-check programs.
  • Fix streamed completions being dropped when every chunk carries usage.

The streaming fix

chatCompletionStream deferred any chunk carrying a usage field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk — measured 59 of
59 frames against a live endpoint — so each chunk was stored into
lastChunkWithUsage and never yielded. Only the final chunk survived, and its
delta is empty.

The caller assembled an empty completion without raising, so the request logged
as a success with 0 generated tokens and the UI showed no reply at all. This
affected any vLLM-backed provider: openai endpoint, not just Haven.

The fix defers a chunk only when it has no choices, so content chunks pass
through with their usage attached while OpenAI's usage-only chunk is still
emitted last. Three tests cover all three stream shapes; reverting the fix fails
exactly the vLLM one with expected '' to be 'Hi there'.

This commit is independent of the Haven work and cherry-picks cleanly onto
main if it is worth sending upstream.

Verification

  • packages/openai-adapters: 3/3 new tests pass, tsc --noEmit clean.
  • core/llm/llms/Haven.vitest.ts: 10/10 pass.
  • Built and installed the win32-x64 VSIX locally; confirmed the fix is present
    in the shipped bundle and that chat returns non-zero generated tokens.

🤖 Generated with Claude Code

…roxy)
Adds provider: haven backed by the haven-proxy package's relay core:
request bodies are HPKE-encrypted end-to-end to the Tinfoil enclave on
this machine, so Haven never sees prompts or completions and no
localhost proxy process is needed.
- core/llm/llms/Haven.ts: OpenAI subclass on the raw-fetch path
(useOpenAIAdapterFor = []); POST chat/completions goes through
createSecureRelay, everything else through the normal fetch with
key-free headers (the relay injects X-Api-Key itself, only to the
Haven origin). Key resolution: config apiKey -> HAVEN_API_KEY ->
~/.haven-proxy/config.json, so the key never has to live in a
shareable config file.
- Registration, tool-support (per-model tool_call flags from the Haven
catalog) and chat-templating entries.
- config_schema.json: provider enum entry, description, model enum.
- haven-proxy.d.ts: ambient types (the package ships none).
- Haven.vitest.ts: relay-mocked coverage of streaming, buffered-SSE
synthesis, non-stream JSON, error mapping, abort, key resolution,
header hygiene, endpoint shape and context lengths.
gui and binary compile core sources with their own tsconfigs, which do not
include core's .d.ts files, so the haven-proxy module declarations were out
of scope there and the gui build failed. A triple-slash reference in
Haven.ts pulls the declarations into every program that compiles the file.
chatCompletionStream deferred any chunk with a `usage` field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk, so each one was
stored into lastChunkWithUsage and never yielded; only the final chunk
survived, and its delta is empty.
The caller assembled an empty completion with no error, so the request was
logged as a success with 0 generated tokens and the UI showed no reply at
all. This hit any vLLM-backed provider: openai endpoint.
Defer a chunk only when it has no choices, so content chunks pass through
with their usage attached and OpenAI's usage-only chunk is still emitted
last. Add tests covering all three stream shapes.
Distinguishes local builds carrying the Haven provider and the streaming
fix from the 1.3.40 marketplace release, so an installed VSIX is
identifiable and VS Code does not treat the marketplace build as an
equal-version replacement.
Also records the haven-proxy dependency in the gui lockfile, which the
Haven provider commit added to core.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@coelhogonzalo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Haven provider + fix dropped completions on vLLM backends - #1

Open
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider
Open

Haven provider + fix dropped completions on vLLM backends#1
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider

Conversation

@coelhogonzalo

Copy link
Copy Markdown
Collaborator

Opened against this fork's main to trigger pr-build-upload-vsix.yaml, which
builds the VSIX natively for linux-x64, win32-x64 and darwin-arm64 and uploads
each as an artifact. The darwin-arm64 artifact is the one to share with macOS
users. Not intended for continuedev/continue.

Commits

  • Add first-class Haven providerprovider: haven, an OpenAI subclass on
    the raw-fetch path. Request bodies are HPKE-encrypted in-process to the
    Tinfoil enclave via haven-proxy's relay core, so no localhost proxy runs and
    Haven never sees prompts or completions.
  • Make haven-proxy ambient types visible to the gui/binary type-check programs.
  • Fix streamed completions being dropped when every chunk carries usage.

The streaming fix

chatCompletionStream deferred any chunk carrying a usage field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk — measured 59 of
59 frames against a live endpoint — so each chunk was stored into
lastChunkWithUsage and never yielded. Only the final chunk survived, and its
delta is empty.

The caller assembled an empty completion without raising, so the request logged
as a success with 0 generated tokens and the UI showed no reply at all. This
affected any vLLM-backed provider: openai endpoint, not just Haven.

The fix defers a chunk only when it has no choices, so content chunks pass
through with their usage attached while OpenAI's usage-only chunk is still
emitted last. Three tests cover all three stream shapes; reverting the fix fails
exactly the vLLM one with expected '' to be 'Hi there'.

This commit is independent of the Haven work and cherry-picks cleanly onto
main if it is worth sending upstream.

Verification

  • packages/openai-adapters: 3/3 new tests pass, tsc --noEmit clean.
  • core/llm/llms/Haven.vitest.ts: 10/10 pass.
  • Built and installed the win32-x64 VSIX locally; confirmed the fix is present
    in the shipped bundle and that chat returns non-zero generated tokens.

🤖 Generated with Claude Code

…roxy)
Adds provider: haven backed by the haven-proxy package's relay core:
request bodies are HPKE-encrypted end-to-end to the Tinfoil enclave on
this machine, so Haven never sees prompts or completions and no
localhost proxy process is needed.
- core/llm/llms/Haven.ts: OpenAI subclass on the raw-fetch path
(useOpenAIAdapterFor = []); POST chat/completions goes through
createSecureRelay, everything else through the normal fetch with
key-free headers (the relay injects X-Api-Key itself, only to the
Haven origin). Key resolution: config apiKey -> HAVEN_API_KEY ->
~/.haven-proxy/config.json, so the key never has to live in a
shareable config file.
- Registration, tool-support (per-model tool_call flags from the Haven
catalog) and chat-templating entries.
- config_schema.json: provider enum entry, description, model enum.
- haven-proxy.d.ts: ambient types (the package ships none).
- Haven.vitest.ts: relay-mocked coverage of streaming, buffered-SSE
synthesis, non-stream JSON, error mapping, abort, key resolution,
header hygiene, endpoint shape and context lengths.
gui and binary compile core sources with their own tsconfigs, which do not
include core's .d.ts files, so the haven-proxy module declarations were out
of scope there and the gui build failed. A triple-slash reference in
Haven.ts pulls the declarations into every program that compiles the file.
chatCompletionStream deferred any chunk with a `usage` field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk, so each one was
stored into lastChunkWithUsage and never yielded; only the final chunk
survived, and its delta is empty.
The caller assembled an empty completion with no error, so the request was
logged as a success with 0 generated tokens and the UI showed no reply at
all. This hit any vLLM-backed provider: openai endpoint.
Defer a chunk only when it has no choices, so content chunks pass through
with their usage attached and OpenAI's usage-only chunk is still emitted
last. Add tests covering all three stream shapes.
Distinguishes local builds carrying the Haven provider and the streaming
fix from the 1.3.40 marketplace release, so an installed VSIX is
identifiable and VS Code does not treat the marketplace build as an
equal-version replacement.
Also records the haven-proxy dependency in the gui lockfile, which the
Haven provider commit added to core.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@coelhogonzalo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Haven provider + fix dropped completions on vLLM backends - #1

Open
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider
Open

Haven provider + fix dropped completions on vLLM backends#1
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider

Conversation

@coelhogonzalo

Copy link
Copy Markdown
Collaborator

Opened against this fork's main to trigger pr-build-upload-vsix.yaml, which
builds the VSIX natively for linux-x64, win32-x64 and darwin-arm64 and uploads
each as an artifact. The darwin-arm64 artifact is the one to share with macOS
users. Not intended for continuedev/continue.

Commits

  • Add first-class Haven providerprovider: haven, an OpenAI subclass on
    the raw-fetch path. Request bodies are HPKE-encrypted in-process to the
    Tinfoil enclave via haven-proxy's relay core, so no localhost proxy runs and
    Haven never sees prompts or completions.
  • Make haven-proxy ambient types visible to the gui/binary type-check programs.
  • Fix streamed completions being dropped when every chunk carries usage.

The streaming fix

chatCompletionStream deferred any chunk carrying a usage field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk — measured 59 of
59 frames against a live endpoint — so each chunk was stored into
lastChunkWithUsage and never yielded. Only the final chunk survived, and its
delta is empty.

The caller assembled an empty completion without raising, so the request logged
as a success with 0 generated tokens and the UI showed no reply at all. This
affected any vLLM-backed provider: openai endpoint, not just Haven.

The fix defers a chunk only when it has no choices, so content chunks pass
through with their usage attached while OpenAI's usage-only chunk is still
emitted last. Three tests cover all three stream shapes; reverting the fix fails
exactly the vLLM one with expected '' to be 'Hi there'.

This commit is independent of the Haven work and cherry-picks cleanly onto
main if it is worth sending upstream.

Verification

  • packages/openai-adapters: 3/3 new tests pass, tsc --noEmit clean.
  • core/llm/llms/Haven.vitest.ts: 10/10 pass.
  • Built and installed the win32-x64 VSIX locally; confirmed the fix is present
    in the shipped bundle and that chat returns non-zero generated tokens.

🤖 Generated with Claude Code

…roxy)
Adds provider: haven backed by the haven-proxy package's relay core:
request bodies are HPKE-encrypted end-to-end to the Tinfoil enclave on
this machine, so Haven never sees prompts or completions and no
localhost proxy process is needed.
- core/llm/llms/Haven.ts: OpenAI subclass on the raw-fetch path
(useOpenAIAdapterFor = []); POST chat/completions goes through
createSecureRelay, everything else through the normal fetch with
key-free headers (the relay injects X-Api-Key itself, only to the
Haven origin). Key resolution: config apiKey -> HAVEN_API_KEY ->
~/.haven-proxy/config.json, so the key never has to live in a
shareable config file.
- Registration, tool-support (per-model tool_call flags from the Haven
catalog) and chat-templating entries.
- config_schema.json: provider enum entry, description, model enum.
- haven-proxy.d.ts: ambient types (the package ships none).
- Haven.vitest.ts: relay-mocked coverage of streaming, buffered-SSE
synthesis, non-stream JSON, error mapping, abort, key resolution,
header hygiene, endpoint shape and context lengths.
gui and binary compile core sources with their own tsconfigs, which do not
include core's .d.ts files, so the haven-proxy module declarations were out
of scope there and the gui build failed. A triple-slash reference in
Haven.ts pulls the declarations into every program that compiles the file.
chatCompletionStream deferred any chunk with a `usage` field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk, so each one was
stored into lastChunkWithUsage and never yielded; only the final chunk
survived, and its delta is empty.
The caller assembled an empty completion with no error, so the request was
logged as a success with 0 generated tokens and the UI showed no reply at
all. This hit any vLLM-backed provider: openai endpoint.
Defer a chunk only when it has no choices, so content chunks pass through
with their usage attached and OpenAI's usage-only chunk is still emitted
last. Add tests covering all three stream shapes.
Distinguishes local builds carrying the Haven provider and the streaming
fix from the 1.3.40 marketplace release, so an installed VSIX is
identifiable and VS Code does not treat the marketplace build as an
equal-version replacement.
Also records the haven-proxy dependency in the gui lockfile, which the
Haven provider commit added to core.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@coelhogonzalo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Haven provider + fix dropped completions on vLLM backends - #1

Open
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider
Open

Haven provider + fix dropped completions on vLLM backends#1
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider

Conversation

@coelhogonzalo

Copy link
Copy Markdown
Collaborator

Opened against this fork's main to trigger pr-build-upload-vsix.yaml, which
builds the VSIX natively for linux-x64, win32-x64 and darwin-arm64 and uploads
each as an artifact. The darwin-arm64 artifact is the one to share with macOS
users. Not intended for continuedev/continue.

Commits

  • Add first-class Haven providerprovider: haven, an OpenAI subclass on
    the raw-fetch path. Request bodies are HPKE-encrypted in-process to the
    Tinfoil enclave via haven-proxy's relay core, so no localhost proxy runs and
    Haven never sees prompts or completions.
  • Make haven-proxy ambient types visible to the gui/binary type-check programs.
  • Fix streamed completions being dropped when every chunk carries usage.

The streaming fix

chatCompletionStream deferred any chunk carrying a usage field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk — measured 59 of
59 frames against a live endpoint — so each chunk was stored into
lastChunkWithUsage and never yielded. Only the final chunk survived, and its
delta is empty.

The caller assembled an empty completion without raising, so the request logged
as a success with 0 generated tokens and the UI showed no reply at all. This
affected any vLLM-backed provider: openai endpoint, not just Haven.

The fix defers a chunk only when it has no choices, so content chunks pass
through with their usage attached while OpenAI's usage-only chunk is still
emitted last. Three tests cover all three stream shapes; reverting the fix fails
exactly the vLLM one with expected '' to be 'Hi there'.

This commit is independent of the Haven work and cherry-picks cleanly onto
main if it is worth sending upstream.

Verification

  • packages/openai-adapters: 3/3 new tests pass, tsc --noEmit clean.
  • core/llm/llms/Haven.vitest.ts: 10/10 pass.
  • Built and installed the win32-x64 VSIX locally; confirmed the fix is present
    in the shipped bundle and that chat returns non-zero generated tokens.

🤖 Generated with Claude Code

…roxy)
Adds provider: haven backed by the haven-proxy package's relay core:
request bodies are HPKE-encrypted end-to-end to the Tinfoil enclave on
this machine, so Haven never sees prompts or completions and no
localhost proxy process is needed.
- core/llm/llms/Haven.ts: OpenAI subclass on the raw-fetch path
(useOpenAIAdapterFor = []); POST chat/completions goes through
createSecureRelay, everything else through the normal fetch with
key-free headers (the relay injects X-Api-Key itself, only to the
Haven origin). Key resolution: config apiKey -> HAVEN_API_KEY ->
~/.haven-proxy/config.json, so the key never has to live in a
shareable config file.
- Registration, tool-support (per-model tool_call flags from the Haven
catalog) and chat-templating entries.
- config_schema.json: provider enum entry, description, model enum.
- haven-proxy.d.ts: ambient types (the package ships none).
- Haven.vitest.ts: relay-mocked coverage of streaming, buffered-SSE
synthesis, non-stream JSON, error mapping, abort, key resolution,
header hygiene, endpoint shape and context lengths.
gui and binary compile core sources with their own tsconfigs, which do not
include core's .d.ts files, so the haven-proxy module declarations were out
of scope there and the gui build failed. A triple-slash reference in
Haven.ts pulls the declarations into every program that compiles the file.
chatCompletionStream deferred any chunk with a `usage` field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk, so each one was
stored into lastChunkWithUsage and never yielded; only the final chunk
survived, and its delta is empty.
The caller assembled an empty completion with no error, so the request was
logged as a success with 0 generated tokens and the UI showed no reply at
all. This hit any vLLM-backed provider: openai endpoint.
Defer a chunk only when it has no choices, so content chunks pass through
with their usage attached and OpenAI's usage-only chunk is still emitted
last. Add tests covering all three stream shapes.
Distinguishes local builds carrying the Haven provider and the streaming
fix from the 1.3.40 marketplace release, so an installed VSIX is
identifiable and VS Code does not treat the marketplace build as an
equal-version replacement.
Also records the haven-proxy dependency in the gui lockfile, which the
Haven provider commit added to core.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@coelhogonzalo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Haven provider + fix dropped completions on vLLM backends - #1

Open
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider
Open

Haven provider + fix dropped completions on vLLM backends#1
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider

Conversation

@coelhogonzalo

Copy link
Copy Markdown
Collaborator

Opened against this fork's main to trigger pr-build-upload-vsix.yaml, which
builds the VSIX natively for linux-x64, win32-x64 and darwin-arm64 and uploads
each as an artifact. The darwin-arm64 artifact is the one to share with macOS
users. Not intended for continuedev/continue.

Commits

  • Add first-class Haven providerprovider: haven, an OpenAI subclass on
    the raw-fetch path. Request bodies are HPKE-encrypted in-process to the
    Tinfoil enclave via haven-proxy's relay core, so no localhost proxy runs and
    Haven never sees prompts or completions.
  • Make haven-proxy ambient types visible to the gui/binary type-check programs.
  • Fix streamed completions being dropped when every chunk carries usage.

The streaming fix

chatCompletionStream deferred any chunk carrying a usage field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk — measured 59 of
59 frames against a live endpoint — so each chunk was stored into
lastChunkWithUsage and never yielded. Only the final chunk survived, and its
delta is empty.

The caller assembled an empty completion without raising, so the request logged
as a success with 0 generated tokens and the UI showed no reply at all. This
affected any vLLM-backed provider: openai endpoint, not just Haven.

The fix defers a chunk only when it has no choices, so content chunks pass
through with their usage attached while OpenAI's usage-only chunk is still
emitted last. Three tests cover all three stream shapes; reverting the fix fails
exactly the vLLM one with expected '' to be 'Hi there'.

This commit is independent of the Haven work and cherry-picks cleanly onto
main if it is worth sending upstream.

Verification

  • packages/openai-adapters: 3/3 new tests pass, tsc --noEmit clean.
  • core/llm/llms/Haven.vitest.ts: 10/10 pass.
  • Built and installed the win32-x64 VSIX locally; confirmed the fix is present
    in the shipped bundle and that chat returns non-zero generated tokens.

🤖 Generated with Claude Code

…roxy)
Adds provider: haven backed by the haven-proxy package's relay core:
request bodies are HPKE-encrypted end-to-end to the Tinfoil enclave on
this machine, so Haven never sees prompts or completions and no
localhost proxy process is needed.
- core/llm/llms/Haven.ts: OpenAI subclass on the raw-fetch path
(useOpenAIAdapterFor = []); POST chat/completions goes through
createSecureRelay, everything else through the normal fetch with
key-free headers (the relay injects X-Api-Key itself, only to the
Haven origin). Key resolution: config apiKey -> HAVEN_API_KEY ->
~/.haven-proxy/config.json, so the key never has to live in a
shareable config file.
- Registration, tool-support (per-model tool_call flags from the Haven
catalog) and chat-templating entries.
- config_schema.json: provider enum entry, description, model enum.
- haven-proxy.d.ts: ambient types (the package ships none).
- Haven.vitest.ts: relay-mocked coverage of streaming, buffered-SSE
synthesis, non-stream JSON, error mapping, abort, key resolution,
header hygiene, endpoint shape and context lengths.
gui and binary compile core sources with their own tsconfigs, which do not
include core's .d.ts files, so the haven-proxy module declarations were out
of scope there and the gui build failed. A triple-slash reference in
Haven.ts pulls the declarations into every program that compiles the file.
chatCompletionStream deferred any chunk with a `usage` field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk, so each one was
stored into lastChunkWithUsage and never yielded; only the final chunk
survived, and its delta is empty.
The caller assembled an empty completion with no error, so the request was
logged as a success with 0 generated tokens and the UI showed no reply at
all. This hit any vLLM-backed provider: openai endpoint.
Defer a chunk only when it has no choices, so content chunks pass through
with their usage attached and OpenAI's usage-only chunk is still emitted
last. Add tests covering all three stream shapes.
Distinguishes local builds carrying the Haven provider and the streaming
fix from the 1.3.40 marketplace release, so an installed VSIX is
identifiable and VS Code does not treat the marketplace build as an
equal-version replacement.
Also records the haven-proxy dependency in the gui lockfile, which the
Haven provider commit added to core.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@coelhogonzalo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Haven provider + fix dropped completions on vLLM backends - #1

Open
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider
Open

Haven provider + fix dropped completions on vLLM backends#1
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider

Conversation

@coelhogonzalo

Copy link
Copy Markdown
Collaborator

Opened against this fork's main to trigger pr-build-upload-vsix.yaml, which
builds the VSIX natively for linux-x64, win32-x64 and darwin-arm64 and uploads
each as an artifact. The darwin-arm64 artifact is the one to share with macOS
users. Not intended for continuedev/continue.

Commits

  • Add first-class Haven providerprovider: haven, an OpenAI subclass on
    the raw-fetch path. Request bodies are HPKE-encrypted in-process to the
    Tinfoil enclave via haven-proxy's relay core, so no localhost proxy runs and
    Haven never sees prompts or completions.
  • Make haven-proxy ambient types visible to the gui/binary type-check programs.
  • Fix streamed completions being dropped when every chunk carries usage.

The streaming fix

chatCompletionStream deferred any chunk carrying a usage field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk — measured 59 of
59 frames against a live endpoint — so each chunk was stored into
lastChunkWithUsage and never yielded. Only the final chunk survived, and its
delta is empty.

The caller assembled an empty completion without raising, so the request logged
as a success with 0 generated tokens and the UI showed no reply at all. This
affected any vLLM-backed provider: openai endpoint, not just Haven.

The fix defers a chunk only when it has no choices, so content chunks pass
through with their usage attached while OpenAI's usage-only chunk is still
emitted last. Three tests cover all three stream shapes; reverting the fix fails
exactly the vLLM one with expected '' to be 'Hi there'.

This commit is independent of the Haven work and cherry-picks cleanly onto
main if it is worth sending upstream.

Verification

  • packages/openai-adapters: 3/3 new tests pass, tsc --noEmit clean.
  • core/llm/llms/Haven.vitest.ts: 10/10 pass.
  • Built and installed the win32-x64 VSIX locally; confirmed the fix is present
    in the shipped bundle and that chat returns non-zero generated tokens.

🤖 Generated with Claude Code

…roxy)
Adds provider: haven backed by the haven-proxy package's relay core:
request bodies are HPKE-encrypted end-to-end to the Tinfoil enclave on
this machine, so Haven never sees prompts or completions and no
localhost proxy process is needed.
- core/llm/llms/Haven.ts: OpenAI subclass on the raw-fetch path
(useOpenAIAdapterFor = []); POST chat/completions goes through
createSecureRelay, everything else through the normal fetch with
key-free headers (the relay injects X-Api-Key itself, only to the
Haven origin). Key resolution: config apiKey -> HAVEN_API_KEY ->
~/.haven-proxy/config.json, so the key never has to live in a
shareable config file.
- Registration, tool-support (per-model tool_call flags from the Haven
catalog) and chat-templating entries.
- config_schema.json: provider enum entry, description, model enum.
- haven-proxy.d.ts: ambient types (the package ships none).
- Haven.vitest.ts: relay-mocked coverage of streaming, buffered-SSE
synthesis, non-stream JSON, error mapping, abort, key resolution,
header hygiene, endpoint shape and context lengths.
gui and binary compile core sources with their own tsconfigs, which do not
include core's .d.ts files, so the haven-proxy module declarations were out
of scope there and the gui build failed. A triple-slash reference in
Haven.ts pulls the declarations into every program that compiles the file.
chatCompletionStream deferred any chunk with a `usage` field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk, so each one was
stored into lastChunkWithUsage and never yielded; only the final chunk
survived, and its delta is empty.
The caller assembled an empty completion with no error, so the request was
logged as a success with 0 generated tokens and the UI showed no reply at
all. This hit any vLLM-backed provider: openai endpoint.
Defer a chunk only when it has no choices, so content chunks pass through
with their usage attached and OpenAI's usage-only chunk is still emitted
last. Add tests covering all three stream shapes.
Distinguishes local builds carrying the Haven provider and the streaming
fix from the 1.3.40 marketplace release, so an installed VSIX is
identifiable and VS Code does not treat the marketplace build as an
equal-version replacement.
Also records the haven-proxy dependency in the gui lockfile, which the
Haven provider commit added to core.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@coelhogonzalo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Haven provider + fix dropped completions on vLLM backends - #1

Open
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider
Open

Haven provider + fix dropped completions on vLLM backends#1
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider

Conversation

@coelhogonzalo

Copy link
Copy Markdown
Collaborator

Opened against this fork's main to trigger pr-build-upload-vsix.yaml, which
builds the VSIX natively for linux-x64, win32-x64 and darwin-arm64 and uploads
each as an artifact. The darwin-arm64 artifact is the one to share with macOS
users. Not intended for continuedev/continue.

Commits

  • Add first-class Haven providerprovider: haven, an OpenAI subclass on
    the raw-fetch path. Request bodies are HPKE-encrypted in-process to the
    Tinfoil enclave via haven-proxy's relay core, so no localhost proxy runs and
    Haven never sees prompts or completions.
  • Make haven-proxy ambient types visible to the gui/binary type-check programs.
  • Fix streamed completions being dropped when every chunk carries usage.

The streaming fix

chatCompletionStream deferred any chunk carrying a usage field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk — measured 59 of
59 frames against a live endpoint — so each chunk was stored into
lastChunkWithUsage and never yielded. Only the final chunk survived, and its
delta is empty.

The caller assembled an empty completion without raising, so the request logged
as a success with 0 generated tokens and the UI showed no reply at all. This
affected any vLLM-backed provider: openai endpoint, not just Haven.

The fix defers a chunk only when it has no choices, so content chunks pass
through with their usage attached while OpenAI's usage-only chunk is still
emitted last. Three tests cover all three stream shapes; reverting the fix fails
exactly the vLLM one with expected '' to be 'Hi there'.

This commit is independent of the Haven work and cherry-picks cleanly onto
main if it is worth sending upstream.

Verification

  • packages/openai-adapters: 3/3 new tests pass, tsc --noEmit clean.
  • core/llm/llms/Haven.vitest.ts: 10/10 pass.
  • Built and installed the win32-x64 VSIX locally; confirmed the fix is present
    in the shipped bundle and that chat returns non-zero generated tokens.

🤖 Generated with Claude Code

…roxy)
Adds provider: haven backed by the haven-proxy package's relay core:
request bodies are HPKE-encrypted end-to-end to the Tinfoil enclave on
this machine, so Haven never sees prompts or completions and no
localhost proxy process is needed.
- core/llm/llms/Haven.ts: OpenAI subclass on the raw-fetch path
(useOpenAIAdapterFor = []); POST chat/completions goes through
createSecureRelay, everything else through the normal fetch with
key-free headers (the relay injects X-Api-Key itself, only to the
Haven origin). Key resolution: config apiKey -> HAVEN_API_KEY ->
~/.haven-proxy/config.json, so the key never has to live in a
shareable config file.
- Registration, tool-support (per-model tool_call flags from the Haven
catalog) and chat-templating entries.
- config_schema.json: provider enum entry, description, model enum.
- haven-proxy.d.ts: ambient types (the package ships none).
- Haven.vitest.ts: relay-mocked coverage of streaming, buffered-SSE
synthesis, non-stream JSON, error mapping, abort, key resolution,
header hygiene, endpoint shape and context lengths.
gui and binary compile core sources with their own tsconfigs, which do not
include core's .d.ts files, so the haven-proxy module declarations were out
of scope there and the gui build failed. A triple-slash reference in
Haven.ts pulls the declarations into every program that compiles the file.
chatCompletionStream deferred any chunk with a `usage` field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk, so each one was
stored into lastChunkWithUsage and never yielded; only the final chunk
survived, and its delta is empty.
The caller assembled an empty completion with no error, so the request was
logged as a success with 0 generated tokens and the UI showed no reply at
all. This hit any vLLM-backed provider: openai endpoint.
Defer a chunk only when it has no choices, so content chunks pass through
with their usage attached and OpenAI's usage-only chunk is still emitted
last. Add tests covering all three stream shapes.
Distinguishes local builds carrying the Haven provider and the streaming
fix from the 1.3.40 marketplace release, so an installed VSIX is
identifiable and VS Code does not treat the marketplace build as an
equal-version replacement.
Also records the haven-proxy dependency in the gui lockfile, which the
Haven provider commit added to core.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@coelhogonzalo
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Haven provider + fix dropped completions on vLLM backends - #1

Open
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider
Open

Haven provider + fix dropped completions on vLLM backends#1
coelhogonzalo wants to merge 4 commits into
mainfrom
feat/haven-provider

Conversation

@coelhogonzalo

Copy link
Copy Markdown
Collaborator

Opened against this fork's main to trigger pr-build-upload-vsix.yaml, which
builds the VSIX natively for linux-x64, win32-x64 and darwin-arm64 and uploads
each as an artifact. The darwin-arm64 artifact is the one to share with macOS
users. Not intended for continuedev/continue.

Commits

  • Add first-class Haven providerprovider: haven, an OpenAI subclass on
    the raw-fetch path. Request bodies are HPKE-encrypted in-process to the
    Tinfoil enclave via haven-proxy's relay core, so no localhost proxy runs and
    Haven never sees prompts or completions.
  • Make haven-proxy ambient types visible to the gui/binary type-check programs.
  • Fix streamed completions being dropped when every chunk carries usage.

The streaming fix

chatCompletionStream deferred any chunk carrying a usage field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk — measured 59 of
59 frames against a live endpoint — so each chunk was stored into
lastChunkWithUsage and never yielded. Only the final chunk survived, and its
delta is empty.

The caller assembled an empty completion without raising, so the request logged
as a success with 0 generated tokens and the UI showed no reply at all. This
affected any vLLM-backed provider: openai endpoint, not just Haven.

The fix defers a chunk only when it has no choices, so content chunks pass
through with their usage attached while OpenAI's usage-only chunk is still
emitted last. Three tests cover all three stream shapes; reverting the fix fails
exactly the vLLM one with expected '' to be 'Hi there'.

This commit is independent of the Haven work and cherry-picks cleanly onto
main if it is worth sending upstream.

Verification

  • packages/openai-adapters: 3/3 new tests pass, tsc --noEmit clean.
  • core/llm/llms/Haven.vitest.ts: 10/10 pass.
  • Built and installed the win32-x64 VSIX locally; confirmed the fix is present
    in the shipped bundle and that chat returns non-zero generated tokens.

🤖 Generated with Claude Code

…roxy)
Adds provider: haven backed by the haven-proxy package's relay core:
request bodies are HPKE-encrypted end-to-end to the Tinfoil enclave on
this machine, so Haven never sees prompts or completions and no
localhost proxy process is needed.
- core/llm/llms/Haven.ts: OpenAI subclass on the raw-fetch path
(useOpenAIAdapterFor = []); POST chat/completions goes through
createSecureRelay, everything else through the normal fetch with
key-free headers (the relay injects X-Api-Key itself, only to the
Haven origin). Key resolution: config apiKey -> HAVEN_API_KEY ->
~/.haven-proxy/config.json, so the key never has to live in a
shareable config file.
- Registration, tool-support (per-model tool_call flags from the Haven
catalog) and chat-templating entries.
- config_schema.json: provider enum entry, description, model enum.
- haven-proxy.d.ts: ambient types (the package ships none).
- Haven.vitest.ts: relay-mocked coverage of streaming, buffered-SSE
synthesis, non-stream JSON, error mapping, abort, key resolution,
header hygiene, endpoint shape and context lengths.
gui and binary compile core sources with their own tsconfigs, which do not
include core's .d.ts files, so the haven-proxy module declarations were out
of scope there and the gui build failed. A triple-slash reference in
Haven.ts pulls the declarations into every program that compiles the file.
chatCompletionStream deferred any chunk with a `usage` field to the end of
the stream, assuming OpenAI's convention where usage arrives once on a final
chunk with no choices. vLLM attaches usage to every chunk, so each one was
stored into lastChunkWithUsage and never yielded; only the final chunk
survived, and its delta is empty.
The caller assembled an empty completion with no error, so the request was
logged as a success with 0 generated tokens and the UI showed no reply at
all. This hit any vLLM-backed provider: openai endpoint.
Defer a chunk only when it has no choices, so content chunks pass through
with their usage attached and OpenAI's usage-only chunk is still emitted
last. Add tests covering all three stream shapes.
Distinguishes local builds carrying the Haven provider and the streaming
fix from the 1.3.40 marketplace release, so an installed VSIX is
identifiable and VS Code does not treat the marketplace build as an
equal-version replacement.
Also records the haven-proxy dependency in the gui lockfile, which the
Haven provider commit added to core.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@coelhogonzalo