forked from CopilotKit/OpenBot
-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add the BitMind gateway — service auth, attestation, and a governed relay #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
ae41d89
feat: add the BitMind gateway - service auth, attestation, and a gove…
bitcloud-dev 77095ce
fix: address review on the BitMind gateway
bitcloud-dev ed08c53
fix: close the cancellation and media-type gaps the re-review found
bitcloud-dev 0a179b3
fix: let only the slot's owner release it
bitcloud-dev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| import type { BaseEvent, RunAgentInput } from "@ag-ui/core"; | ||
| import { EventEncoder } from "@ag-ui/encoder"; | ||
| import { type RunStreamEvent, streamRun } from "./stream"; | ||
|
|
||
| /** | ||
| * One run, answered as an AG-UI SSE response — with a way to make it stop. | ||
| * | ||
| * Its own module for the reason `stream.ts` is: `index.ts` calls `serve()` at module | ||
| * scope, so the response lifecycle — and above all its cancellation — has to live | ||
| * where a test can reach it without binding a port. | ||
| * | ||
| * Cancellation has two doors and both lead to the same abort. The caller's signal | ||
| * (the HTTP request's own) fires when the client disconnects; the stream's `cancel()` | ||
| * fires when the consumer lets go of the body. Either way the model invocation is | ||
| * aborted through the signal handed to `makeEvents`, because a consumer that hung up | ||
| * does not stop the model on its own — the tokens keep costing money and the process | ||
| * keeps holding capacity for a reply nobody will read. | ||
| */ | ||
| export function respondWithRun( | ||
| input: RunAgentInput, | ||
| makeEvents: (signal: AbortSignal) => Promise<AsyncIterable<RunStreamEvent>>, | ||
| clientSignal?: AbortSignal, | ||
| ): Response { | ||
| const encoder = new EventEncoder(); | ||
| const halt = new AbortController(); | ||
| if (clientSignal?.aborted) halt.abort(clientSignal.reason); | ||
| clientSignal?.addEventListener( | ||
| "abort", | ||
| () => { | ||
| halt.abort(clientSignal.reason); | ||
| }, | ||
| { once: true }, | ||
| ); | ||
|
|
||
| const stream = new ReadableStream<Uint8Array>({ | ||
| async start(controller) { | ||
| const utf8 = new TextEncoder(); | ||
| const send = (event: BaseEvent) => { | ||
| try { | ||
| controller.enqueue(utf8.encode(encoder.encodeSSE(event))); | ||
| } catch { | ||
| // The consumer is gone; there is nowhere to say anything. The abort below | ||
| // is what stops the work itself. | ||
| } | ||
| }; | ||
|
|
||
| send({ | ||
| type: "RUN_STARTED", | ||
| threadId: input.threadId, | ||
| runId: input.runId, | ||
| } as BaseEvent); | ||
|
|
||
| await streamRun(() => makeEvents(halt.signal), input, send, halt.signal); | ||
|
|
||
| try { | ||
| controller.close(); | ||
| } catch { | ||
| // Already cancelled by the consumer. | ||
| } | ||
| }, | ||
| cancel(reason) { | ||
| halt.abort( | ||
| reason instanceof Error | ||
| ? reason | ||
| : new Error("run cancelled by its consumer"), | ||
| ); | ||
| }, | ||
| }); | ||
|
|
||
| return new Response(stream, { | ||
| headers: { | ||
| "content-type": encoder.getContentType(), | ||
| "cache-control": "no-cache", | ||
| connection: "keep-alive", | ||
| }, | ||
| }); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new abort signal reaches the model stream, but not an in-flight tool call. If cancellation arrives while
callTool'sfetchis executing, the graph can stop waiting while the governed action continues and may still complete after the run was cancelled. Please thread the run signal throughbuildGraph/the tool node intocallTooland pass it tofetch, with a cancellation test that blocks inside the tool request rather than only inside model event generation.