@opencode-ai/ai 0.0.0-dev-18659 → 0.0.0-dev-18661
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Effect, Schema } from "effect";
|
|
1
|
+
import { Effect, Option, Schema } from "effect";
|
|
2
2
|
import { HttpTransport } from "../route/transport/index.js";
|
|
3
3
|
import { Protocol } from "../route/protocol.js";
|
|
4
4
|
import { AIError, LLMEvent, ProviderInternalError, Usage, } from "../schema/index.js";
|
|
@@ -624,6 +624,14 @@ const onOutputTextDone = (state, event, id) => {
|
|
|
624
624
|
const events = [];
|
|
625
625
|
return [{ ...state, lifecycle: Lifecycle.textEnd(state.lifecycle, events, id) }, events];
|
|
626
626
|
};
|
|
627
|
+
const decodeMessagePart = Schema.decodeUnknownOption(Schema.Union([OpenResponsesOutputText, Schema.Struct({ type: Schema.tag("refusal"), refusal: Schema.String })]));
|
|
628
|
+
const decodeSummaryPart = Schema.decodeUnknownOption(OpenResponsesReasoningSummaryText);
|
|
629
|
+
const decodeReasoningPart = Schema.decodeUnknownOption(Schema.Struct({ type: Schema.tag("reasoning_text"), text: Schema.String }));
|
|
630
|
+
const joinReasoningText = (parts) => {
|
|
631
|
+
if (!parts.some((part) => part !== undefined && part.length > 0))
|
|
632
|
+
return undefined;
|
|
633
|
+
return parts.filter((part) => part !== undefined).join("\n\n");
|
|
634
|
+
};
|
|
627
635
|
export const outputItemID = (state, event) => event.output_index === undefined ? event.item_id : (state.outputItems[event.output_index] ?? event.item_id);
|
|
628
636
|
const startReasoningSummaryPart = (state, itemID, index) => {
|
|
629
637
|
const item = state.reasoningItems[itemID];
|
|
@@ -821,19 +829,30 @@ const onFunctionCallArgumentsDelta = Effect.fn("OpenResponses.onFunctionCallArgu
|
|
|
821
829
|
events.push(...result.events);
|
|
822
830
|
return [{ ...state, lifecycle, tools: result.tools }, events];
|
|
823
831
|
});
|
|
824
|
-
const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (state,
|
|
825
|
-
const item = event.item;
|
|
832
|
+
const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (state, item) {
|
|
826
833
|
if (!item)
|
|
827
834
|
return [state, NO_EVENTS];
|
|
828
835
|
if (item.type === "message" && item.id !== undefined) {
|
|
836
|
+
const message = state.message?.id === item.id ? state.message : undefined;
|
|
829
837
|
const itemPhase = messagePhase(item.phase);
|
|
830
|
-
const phase = itemPhase === undefined
|
|
838
|
+
const phase = itemPhase === undefined ? message?.phase : itemPhase;
|
|
839
|
+
const parts = Array.isArray(item.content) ? item.content : [];
|
|
840
|
+
const content = [];
|
|
841
|
+
for (const part of parts) {
|
|
842
|
+
const decoded = Option.getOrUndefined(decodeMessagePart(part));
|
|
843
|
+
if (!decoded)
|
|
844
|
+
continue;
|
|
845
|
+
content.push(decoded.type === "output_text" ? decoded.text : decoded.refusal);
|
|
846
|
+
}
|
|
847
|
+
const text = content.length > 0 ? content.join("") : undefined;
|
|
848
|
+
const metadata = providerMetadata(state, { itemId: item.id, ...(phase === undefined ? {} : { phase }) });
|
|
831
849
|
const events = [];
|
|
850
|
+
const lifecycle = message && text ? Lifecycle.textStart(state.lifecycle, events, item.id, metadata) : state.lifecycle;
|
|
832
851
|
return [
|
|
833
852
|
{
|
|
834
853
|
...state,
|
|
835
|
-
lifecycle: Lifecycle.textEnd(
|
|
836
|
-
message:
|
|
854
|
+
lifecycle: Lifecycle.textEnd(lifecycle, events, item.id, metadata, text),
|
|
855
|
+
message: message ? undefined : state.message,
|
|
837
856
|
},
|
|
838
857
|
events,
|
|
839
858
|
];
|
|
@@ -883,15 +902,36 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
|
|
|
883
902
|
];
|
|
884
903
|
}
|
|
885
904
|
if (isReasoningItem(item)) {
|
|
886
|
-
|
|
905
|
+
if (state.reasoningItems[item.id]?.open === false)
|
|
906
|
+
return [state, NO_EVENTS];
|
|
887
907
|
const metadata = reasoningMetadata(state, item);
|
|
908
|
+
const summaryParts = Array.isArray(item.summary) ? item.summary : [];
|
|
909
|
+
const summary = [];
|
|
910
|
+
for (const part of summaryParts) {
|
|
911
|
+
const decoded = Option.getOrUndefined(decodeSummaryPart(part));
|
|
912
|
+
// Keep missing entries so the array still matches the provider's summary indexes.
|
|
913
|
+
summary.push(decoded?.text);
|
|
914
|
+
}
|
|
915
|
+
const reasoningParts = Array.isArray(item.content) ? item.content : [];
|
|
916
|
+
const content = [];
|
|
917
|
+
for (const part of reasoningParts) {
|
|
918
|
+
const decoded = Option.getOrUndefined(decodeReasoningPart(part));
|
|
919
|
+
if (decoded)
|
|
920
|
+
content.push(decoded.text);
|
|
921
|
+
}
|
|
922
|
+
const itemText = joinReasoningText(summary) ?? joinReasoningText(content);
|
|
923
|
+
const events = [];
|
|
888
924
|
const reasoningItem = state.reasoningItems[item.id];
|
|
889
925
|
if (reasoningItem) {
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
const
|
|
893
|
-
|
|
894
|
-
|
|
926
|
+
const fragments = Object.entries(reasoningItem.summaryParts);
|
|
927
|
+
let lifecycle = state.lifecycle;
|
|
928
|
+
for (const [index, status] of fragments) {
|
|
929
|
+
if (status === "concluded")
|
|
930
|
+
continue;
|
|
931
|
+
// Do not repeat earlier summaries that were already emitted as separate fragments.
|
|
932
|
+
const finalText = fragments.length === 1 ? itemText : summary[Number(index)];
|
|
933
|
+
lifecycle = Lifecycle.reasoningEnd(lifecycle, events, `${item.id}:${index}`, metadata, finalText || undefined);
|
|
934
|
+
}
|
|
895
935
|
return [
|
|
896
936
|
{
|
|
897
937
|
...state,
|
|
@@ -911,7 +951,11 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
|
|
|
911
951
|
if (!state.lifecycle.reasoning.has(item.id)) {
|
|
912
952
|
const lifecycle = Lifecycle.stepStart(state.lifecycle, events);
|
|
913
953
|
events.push(LLMEvent.reasoningStart({ id: item.id, providerMetadata: metadata }));
|
|
914
|
-
events.push(LLMEvent.reasoningEnd({
|
|
954
|
+
events.push(LLMEvent.reasoningEnd({
|
|
955
|
+
id: item.id,
|
|
956
|
+
providerMetadata: metadata,
|
|
957
|
+
text: itemText,
|
|
958
|
+
}));
|
|
915
959
|
return [
|
|
916
960
|
{
|
|
917
961
|
...state,
|
|
@@ -937,22 +981,25 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
|
|
|
937
981
|
return [state, NO_EVENTS];
|
|
938
982
|
});
|
|
939
983
|
const onResponseFinish = Effect.fn("OpenResponses.onResponseFinish")(function* (state, event) {
|
|
940
|
-
|
|
941
|
-
|
|
984
|
+
let current = state;
|
|
985
|
+
const events = [];
|
|
986
|
+
if (event.type === "response.completed") {
|
|
987
|
+
for (const item of event.response?.output ?? []) {
|
|
942
988
|
const id = item.id ?? (item.type === "function_call" ? item.call_id : undefined);
|
|
943
|
-
if (id === undefined
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
989
|
+
if (id === undefined)
|
|
990
|
+
continue;
|
|
991
|
+
if (item.type !== "function_call" || !current.tools[id])
|
|
992
|
+
continue;
|
|
993
|
+
const [next, emitted] = yield* onOutputItemDone(current, item);
|
|
994
|
+
current = next;
|
|
995
|
+
events.push(...emitted);
|
|
996
|
+
}
|
|
997
|
+
}
|
|
951
998
|
// Some compatible providers omit output_item.done even after completing the response.
|
|
952
999
|
const pending = event.type === "response.completed"
|
|
953
1000
|
? yield* ToolStream.finishAll(current.id, current.tools)
|
|
954
1001
|
: { tools: current.tools, events: NO_EVENTS };
|
|
955
|
-
|
|
1002
|
+
events.push(...pending.events);
|
|
956
1003
|
const hasFunctionCall = pending.events.some((event) => LLMEvent.is.toolCall(event) || LLMEvent.is.toolInputError(event)) ||
|
|
957
1004
|
current.hasFunctionCall;
|
|
958
1005
|
const lifecycle = Lifecycle.finish(current.lifecycle, events, {
|
|
@@ -1061,7 +1108,7 @@ export const step = (state, input) => {
|
|
|
1061
1108
|
if (event.type === "response.output_item.done") {
|
|
1062
1109
|
if (event.item?.type === "message" && event.item.id === undefined)
|
|
1063
1110
|
return ProviderShared.eventError(state.id, `${event.type} message is missing id`);
|
|
1064
|
-
return onOutputItemDone(state, event);
|
|
1111
|
+
return onOutputItemDone(state, event.item);
|
|
1065
1112
|
}
|
|
1066
1113
|
if (event.type === "response.completed" || event.type === "response.incomplete")
|
|
1067
1114
|
return onResponseFinish(state, event);
|
|
@@ -846,15 +846,15 @@ const step = (state, event) => Effect.gen(function* () {
|
|
|
846
846
|
lifecycle = Lifecycle.stepStart(lifecycle, events);
|
|
847
847
|
events.push(...result.events);
|
|
848
848
|
}
|
|
849
|
-
const
|
|
849
|
+
const incompleteTools = finishReason?.normalized === "content-filter" || finishReason?.normalized === "length";
|
|
850
850
|
if (finishReason !== undefined &&
|
|
851
|
-
!
|
|
851
|
+
!incompleteTools &&
|
|
852
852
|
state.finishReason === undefined &&
|
|
853
853
|
Object.keys(pendingTools).length)
|
|
854
854
|
return yield* ProviderShared.eventError(ADAPTER, "OpenAI Chat tool call delta is missing id or name", ProviderShared.encodeJson(event));
|
|
855
|
-
//
|
|
855
|
+
// Filtering or truncation terminates the response without confirming pending tool calls.
|
|
856
856
|
const finished = finishReason !== undefined &&
|
|
857
|
-
!
|
|
857
|
+
!incompleteTools &&
|
|
858
858
|
state.finishReason === undefined &&
|
|
859
859
|
Object.keys(tools).length > 0
|
|
860
860
|
? yield* ToolStream.finishAll(ADAPTER, tools)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
-
"version": "0.0.0-dev-
|
|
3
|
+
"version": "0.0.0-dev-18661",
|
|
4
4
|
"name": "@opencode-ai/ai",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@clack/prompts": "1.0.0-alpha.1",
|
|
32
32
|
"@effect/platform-node": "4.0.0-rc.112",
|
|
33
|
-
"@opencode-ai/http-recorder": "0.0.0-dev-
|
|
33
|
+
"@opencode-ai/http-recorder": "0.0.0-dev-18661",
|
|
34
34
|
"@tsconfig/bun": "1.0.9",
|
|
35
35
|
"@types/bun": "1.3.13",
|
|
36
36
|
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@smithy/eventstream-codec": "4.2.14",
|
|
41
41
|
"@smithy/util-utf8": "4.2.2",
|
|
42
|
-
"@opencode-ai/schema": "0.0.0-dev-
|
|
42
|
+
"@opencode-ai/schema": "0.0.0-dev-18661",
|
|
43
43
|
"aws4fetch": "1.0.20",
|
|
44
44
|
"effect": "4.0.0-rc.112",
|
|
45
45
|
"google-auth-library": "10.5.0"
|