mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 09:39:25 +00:00
fix(release): repair validation blockers (#156082)
This commit is contained in:
parent
1a94a1e236
commit
e96300a5a9
4 changed files with 41 additions and 25 deletions
|
|
@ -123,6 +123,10 @@ private final class ApprovalGatewayFixture: @unchecked Sendable {
|
|||
socket.emitReceiveSuccessOnce(.data(Data(event.utf8)))
|
||||
}
|
||||
|
||||
func waitUntilReady() async throws {
|
||||
_ = try await self.readySocket()
|
||||
}
|
||||
|
||||
private func readySocket() async throws -> GatewayTestWebSocketTask {
|
||||
let deadline = ContinuousClock.now + .seconds(2)
|
||||
while ContinuousClock.now < deadline {
|
||||
|
|
@ -210,16 +214,20 @@ struct ExecApprovalQueueStoreTests {
|
|||
try #require(await self.waitUntil { store.requests.isEmpty })
|
||||
}
|
||||
|
||||
@Test func `expired requests disappear without a gateway resolution event`() async throws {
|
||||
let fixture = ApprovalGatewayFixture(initialRequests: [
|
||||
ApprovalFixtureRequest(id: "short-lived", expiresOffsetMs: 500),
|
||||
])
|
||||
@Test func `live requests disappear at expiry without a gateway resolution event`() async throws {
|
||||
let fixture = ApprovalGatewayFixture()
|
||||
let store = ExecApprovalQueueStore(gateway: fixture.gateway)
|
||||
defer { store.stop() }
|
||||
|
||||
store.start()
|
||||
await store.refresh()
|
||||
#expect(store.requests.map(\.id) == ["short-lived"])
|
||||
|
||||
try await fixture.waitUntilReady()
|
||||
let request = ApprovalFixtureRequest(id: "short-lived", expiresOffsetMs: 500)
|
||||
try await fixture.sendEvent(name: "exec.approval.requested", payload: request.json)
|
||||
|
||||
try #require(await self.waitUntil { store.requests.map(\.id) == ["short-lived"] })
|
||||
try #require(await self.waitUntil { store.requests.isEmpty })
|
||||
#expect(await fixture.requestLog.requests(method: "exec.approval.resolve").isEmpty)
|
||||
}
|
||||
|
||||
@Test func `explicit decision policy excludes allow always and blocks unavailable decisions`() async {
|
||||
|
|
|
|||
|
|
@ -598,25 +598,32 @@ describe("opencode-go provider plugin", () => {
|
|||
});
|
||||
|
||||
it.each([
|
||||
["openai-completions", "https://opencode.ai/zen/go/v1"],
|
||||
["anthropic-messages", "https://opencode.ai/zen/go"],
|
||||
] as const)("sends stable conversation identity to the %s endpoint", async (api, baseUrl) => {
|
||||
const provider = await registerSingleProviderPlugin(plugin);
|
||||
const streamFn = vi.fn(() => ({}) as never);
|
||||
const wrapped = provider.wrapStreamFn?.({ streamFn } as never);
|
||||
["stream", "openai-completions", "https://opencode.ai/zen/go/v1"],
|
||||
["stream", "anthropic-messages", "https://opencode.ai/zen/go"],
|
||||
["simple completion", "openai-completions", "https://opencode.ai/zen/go/v1"],
|
||||
["simple completion", "anthropic-messages", "https://opencode.ai/zen/go"],
|
||||
] as const)(
|
||||
"sends stable conversation identity through the %s %s endpoint",
|
||||
async (surface, api, baseUrl) => {
|
||||
const provider = await registerSingleProviderPlugin(plugin);
|
||||
const streamFn = vi.fn(() => ({}) as never);
|
||||
const wrapper =
|
||||
surface === "stream" ? provider.wrapStreamFn : provider.wrapSimpleCompletionStreamFn;
|
||||
const wrapped = wrapper?.({ streamFn } as never);
|
||||
|
||||
await wrapped?.(
|
||||
{ provider: "opencode-go", id: "fixture", api, baseUrl } as never,
|
||||
{ messages: [] } as never,
|
||||
{ sessionId: "conversation-123" },
|
||||
);
|
||||
await wrapped?.(
|
||||
{ provider: "opencode-go", id: "fixture", api, baseUrl } as never,
|
||||
{ messages: [] } as never,
|
||||
{ sessionId: "conversation-123" },
|
||||
);
|
||||
|
||||
expect(streamFn).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
expect.objectContaining({ headers: { "x-opencode-session": "conversation-123" } }),
|
||||
);
|
||||
});
|
||||
expect(streamFn).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
expect.objectContaining({ headers: { "x-opencode-session": "conversation-123" } }),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it("preserves explicit session routing and leaves custom proxies unchanged", async () => {
|
||||
const provider = await registerSingleProviderPlugin(plugin);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import {
|
|||
resolveOpencodeGoStarterModel,
|
||||
} from "./provider-catalog.js";
|
||||
import { resolveThinkingProfile } from "./provider-policy-api.js";
|
||||
import { createOpencodeGoWrapper } from "./stream.js";
|
||||
import { createOpencodeGoSessionHeaderWrapper, createOpencodeGoWrapper } from "./stream.js";
|
||||
|
||||
const PROVIDER_ID = "opencode-go";
|
||||
type OpencodeGoCatalogAuth = { apiKey?: string; discoveryApiKey?: string };
|
||||
|
|
@ -119,6 +119,7 @@ export default defineSingleProviderPluginEntry({
|
|||
...buildProviderReplayFamilyHooks({ family: "passthrough-gemini" }),
|
||||
resolveThinkingProfile,
|
||||
wrapStreamFn: (ctx) => createOpencodeGoWrapper(ctx.streamFn, ctx.thinkingLevel),
|
||||
wrapSimpleCompletionStreamFn: (ctx) => createOpencodeGoSessionHeaderWrapper(ctx.streamFn),
|
||||
isModernModelRef: () => true,
|
||||
},
|
||||
register(api) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ function hasOpencodeSessionHeader(headers: Record<string, string> | undefined):
|
|||
return Object.keys(headers ?? {}).some((name) => name.toLowerCase() === OPENCODE_SESSION_HEADER);
|
||||
}
|
||||
|
||||
function createOpencodeGoSessionHeaderWrapper(
|
||||
export function createOpencodeGoSessionHeaderWrapper(
|
||||
baseStreamFn: ProviderWrapStreamFnContext["streamFn"],
|
||||
): ProviderWrapStreamFnContext["streamFn"] {
|
||||
if (!baseStreamFn) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue