fix(coding-agent): preserved legacy simple stream options
- Routed streamSimpleOpenAIResponses through the central simple-stream dispatcher. - Added wire-level coverage for hidden reasoning summary translation. Fixes #7403
This commit is contained in:
@@ -19,7 +19,15 @@
|
||||
* `types.ts` via the `export *` below — pi-ai still exports both as types,
|
||||
* only the runtime `Type` builder and `StringEnum()` helper were removed.
|
||||
*/
|
||||
import type { Api, AssistantMessage, Model } from "@oh-my-pi/pi-ai";
|
||||
import {
|
||||
type Api,
|
||||
type AssistantMessage,
|
||||
type AssistantMessageEventStream,
|
||||
type Context,
|
||||
type Model,
|
||||
type SimpleStreamOptions,
|
||||
streamSimple,
|
||||
} from "@oh-my-pi/pi-ai";
|
||||
import type { Effort } from "@oh-my-pi/pi-catalog/effort";
|
||||
import { clampThinkingLevelForModel } from "@oh-my-pi/pi-catalog/model-thinking";
|
||||
import {
|
||||
@@ -121,11 +129,19 @@ export { calculateCost, getBundledModel, getBundledModels, getBundledProviders,
|
||||
export const getModel = getBundledModel;
|
||||
export const getModels = getBundledModels;
|
||||
|
||||
// Upstream's `/compat` entrypoint exposes this legacy name for the simple
|
||||
// OpenAI Responses stream. OMP's provider uses the same simple-options
|
||||
// contract under `streamOpenAIResponses`; alias it for rewritten compat
|
||||
// imports from extensions such as pi-openai-server-compaction.
|
||||
export { streamOpenAIResponses as streamSimpleOpenAIResponses } from "@oh-my-pi/pi-ai";
|
||||
/**
|
||||
* Stream OpenAI Responses through the historical simple-options contract.
|
||||
*
|
||||
* Legacy `/compat` callers pass {@link SimpleStreamOptions}; routing through
|
||||
* `streamSimple` preserves option normalization before provider dispatch.
|
||||
*/
|
||||
export function streamSimpleOpenAIResponses(
|
||||
model: Model<"openai-responses">,
|
||||
context: Context,
|
||||
options?: SimpleStreamOptions,
|
||||
): AssistantMessageEventStream {
|
||||
return streamSimple(model, context, options);
|
||||
}
|
||||
/**
|
||||
* Compatibility re-exports for runtime helpers that upstream
|
||||
* `@earendil-works/pi-ai` exposed from its package root but omp's
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import type { AssistantMessage } from "@oh-my-pi/pi-ai";
|
||||
import { streamOpenAIResponses } from "@oh-my-pi/pi-ai";
|
||||
import type { AssistantMessage, FetchImpl } from "@oh-my-pi/pi-ai";
|
||||
import { buildModel } from "@oh-my-pi/pi-catalog/build";
|
||||
import { Effort } from "@oh-my-pi/pi-catalog/effort";
|
||||
import {
|
||||
isContextOverflow,
|
||||
parseJsonWithRepair,
|
||||
@@ -55,7 +56,56 @@ describe("legacy pi-ai shim root exports", () => {
|
||||
// parseStreamingJson completes a truncated object at the streaming edge.
|
||||
expect(parseStreamingJson<{ a: number }>('{"a": 1')).toEqual({ a: 1 });
|
||||
});
|
||||
it("aliases the legacy simple OpenAI Responses stream", () => {
|
||||
expect(streamSimpleOpenAIResponses).toBe(streamOpenAIResponses);
|
||||
it("maps legacy simple options before streaming OpenAI Responses", async () => {
|
||||
const requests: unknown[] = [];
|
||||
const fetchMock: FetchImpl = Object.assign(
|
||||
async () =>
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
error: { message: "intentional test response", type: "invalid_request_error" },
|
||||
}),
|
||||
{ status: 400, headers: { "content-type": "application/json" } },
|
||||
),
|
||||
{ preconnect: fetch.preconnect },
|
||||
);
|
||||
const model = buildModel({
|
||||
id: "legacy-simple-options",
|
||||
name: "Legacy Simple Options",
|
||||
api: "openai-responses",
|
||||
provider: "openai",
|
||||
baseUrl: "https://responses.example.test/v1",
|
||||
reasoning: true,
|
||||
compat: {
|
||||
supportsReasoningParams: true,
|
||||
supportsReasoningEffort: true,
|
||||
},
|
||||
thinking: {
|
||||
mode: "effort",
|
||||
efforts: [Effort.High],
|
||||
},
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 128_000,
|
||||
maxTokens: 16_384,
|
||||
});
|
||||
|
||||
const result = await streamSimpleOpenAIResponses(
|
||||
model,
|
||||
{ messages: [{ role: "user", content: "hello", timestamp: 0 }] },
|
||||
{
|
||||
apiKey: "test-key",
|
||||
reasoning: Effort.High,
|
||||
hideThinkingSummary: true,
|
||||
fetch: fetchMock,
|
||||
onPayload: request => {
|
||||
requests.push(request);
|
||||
},
|
||||
},
|
||||
).result();
|
||||
|
||||
expect(result.stopReason).toBe("error");
|
||||
expect(requests).toHaveLength(1);
|
||||
expect(requests[0]).toMatchObject({ reasoning: { effort: "high" } });
|
||||
expect(JSON.stringify(requests[0])).not.toContain('"summary"');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user