@arden-hq/loop 0.0.0-stage → 0.1.0
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.
- package/LICENSE +202 -0
- package/README.md +121 -2
- package/dist/abort.d.ts +9 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/abort.js +31 -0
- package/dist/abort.js.map +1 -0
- package/dist/agent/agent.d.ts +48 -0
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/agent/agent.js +146 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/background-tools.d.ts +51 -0
- package/dist/agent/background-tools.d.ts.map +1 -0
- package/dist/agent/background-tools.js +257 -0
- package/dist/agent/background-tools.js.map +1 -0
- package/dist/agent/budget.d.ts +5 -0
- package/dist/agent/budget.d.ts.map +1 -0
- package/dist/agent/budget.js +48 -0
- package/dist/agent/budget.js.map +1 -0
- package/dist/agent/config.d.ts +61 -0
- package/dist/agent/config.d.ts.map +1 -0
- package/dist/agent/config.js +99 -0
- package/dist/agent/config.js.map +1 -0
- package/dist/agent/guards.d.ts +10 -0
- package/dist/agent/guards.d.ts.map +1 -0
- package/dist/agent/guards.js +136 -0
- package/dist/agent/guards.js.map +1 -0
- package/dist/agent/history-journal.d.ts +18 -0
- package/dist/agent/history-journal.d.ts.map +1 -0
- package/dist/agent/history-journal.js +87 -0
- package/dist/agent/history-journal.js.map +1 -0
- package/dist/agent/history-projection.d.ts +6 -0
- package/dist/agent/history-projection.d.ts.map +1 -0
- package/dist/agent/history-projection.js +62 -0
- package/dist/agent/history-projection.js.map +1 -0
- package/dist/agent/interactions.d.ts +14 -0
- package/dist/agent/interactions.d.ts.map +1 -0
- package/dist/agent/interactions.js +85 -0
- package/dist/agent/interactions.js.map +1 -0
- package/dist/agent/middleware.d.ts +5 -0
- package/dist/agent/middleware.d.ts.map +1 -0
- package/dist/agent/middleware.js +55 -0
- package/dist/agent/middleware.js.map +1 -0
- package/dist/agent/model-output-projection.d.ts +27 -0
- package/dist/agent/model-output-projection.d.ts.map +1 -0
- package/dist/agent/model-output-projection.js +138 -0
- package/dist/agent/model-output-projection.js.map +1 -0
- package/dist/agent/model-output.d.ts +19 -0
- package/dist/agent/model-output.d.ts.map +1 -0
- package/dist/agent/model-output.js +172 -0
- package/dist/agent/model-output.js.map +1 -0
- package/dist/agent/model-turn.d.ts +29 -0
- package/dist/agent/model-turn.d.ts.map +1 -0
- package/dist/agent/model-turn.js +401 -0
- package/dist/agent/model-turn.js.map +1 -0
- package/dist/agent/policy.d.ts +28 -0
- package/dist/agent/policy.d.ts.map +1 -0
- package/dist/agent/policy.js +109 -0
- package/dist/agent/policy.js.map +1 -0
- package/dist/agent/provider-capabilities.d.ts +12 -0
- package/dist/agent/provider-capabilities.d.ts.map +1 -0
- package/dist/agent/provider-capabilities.js +76 -0
- package/dist/agent/provider-capabilities.js.map +1 -0
- package/dist/agent/recovery.d.ts +8 -0
- package/dist/agent/recovery.d.ts.map +1 -0
- package/dist/agent/recovery.js +21 -0
- package/dist/agent/recovery.js.map +1 -0
- package/dist/agent/replies.d.ts +3 -0
- package/dist/agent/replies.d.ts.map +1 -0
- package/dist/agent/replies.js +24 -0
- package/dist/agent/replies.js.map +1 -0
- package/dist/agent/run-state.d.ts +98 -0
- package/dist/agent/run-state.d.ts.map +1 -0
- package/dist/agent/run-state.js +454 -0
- package/dist/agent/run-state.js.map +1 -0
- package/dist/agent/run.d.ts +6 -0
- package/dist/agent/run.d.ts.map +1 -0
- package/dist/agent/run.js +462 -0
- package/dist/agent/run.js.map +1 -0
- package/dist/agent/streamed-call-history.d.ts +20 -0
- package/dist/agent/streamed-call-history.d.ts.map +1 -0
- package/dist/agent/streamed-call-history.js +71 -0
- package/dist/agent/streamed-call-history.js.map +1 -0
- package/dist/agent/streaming-tools.d.ts +23 -0
- package/dist/agent/streaming-tools.d.ts.map +1 -0
- package/dist/agent/streaming-tools.js +67 -0
- package/dist/agent/streaming-tools.js.map +1 -0
- package/dist/agent/structured-output.d.ts +27 -0
- package/dist/agent/structured-output.d.ts.map +1 -0
- package/dist/agent/structured-output.js +26 -0
- package/dist/agent/structured-output.js.map +1 -0
- package/dist/agent/tool-admission.d.ts +18 -0
- package/dist/agent/tool-admission.d.ts.map +1 -0
- package/dist/agent/tool-admission.js +22 -0
- package/dist/agent/tool-admission.js.map +1 -0
- package/dist/contracts/events.d.ts +236 -0
- package/dist/contracts/events.d.ts.map +1 -0
- package/dist/contracts/events.js +13 -0
- package/dist/contracts/events.js.map +1 -0
- package/dist/contracts/messages.d.ts +234 -0
- package/dist/contracts/messages.d.ts.map +1 -0
- package/dist/contracts/messages.js +11 -0
- package/dist/contracts/messages.js.map +1 -0
- package/dist/contracts/provider.d.ts +177 -0
- package/dist/contracts/provider.d.ts.map +1 -0
- package/dist/contracts/provider.js +26 -0
- package/dist/contracts/provider.js.map +1 -0
- package/dist/contracts/tools.d.ts +217 -0
- package/dist/contracts/tools.d.ts.map +1 -0
- package/dist/contracts/tools.js +16 -0
- package/dist/contracts/tools.js.map +1 -0
- package/dist/errors.d.ts +112 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +190 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/concurrency.d.ts +11 -0
- package/dist/internal/concurrency.d.ts.map +1 -0
- package/dist/internal/concurrency.js +86 -0
- package/dist/internal/concurrency.js.map +1 -0
- package/dist/internal/stream.d.ts +25 -0
- package/dist/internal/stream.d.ts.map +1 -0
- package/dist/internal/stream.js +97 -0
- package/dist/internal/stream.js.map +1 -0
- package/dist/internal/validate.d.ts +30 -0
- package/dist/internal/validate.d.ts.map +1 -0
- package/dist/internal/validate.js +480 -0
- package/dist/internal/validate.js.map +1 -0
- package/dist/providers/kit/errors.d.ts +40 -0
- package/dist/providers/kit/errors.d.ts.map +1 -0
- package/dist/providers/kit/errors.js +48 -0
- package/dist/providers/kit/errors.js.map +1 -0
- package/dist/providers/kit/index.d.ts +10 -0
- package/dist/providers/kit/index.d.ts.map +1 -0
- package/dist/providers/kit/index.js +10 -0
- package/dist/providers/kit/index.js.map +1 -0
- package/dist/providers/kit/retry.d.ts +43 -0
- package/dist/providers/kit/retry.d.ts.map +1 -0
- package/dist/providers/kit/retry.js +118 -0
- package/dist/providers/kit/retry.js.map +1 -0
- package/dist/providers/kit/sse.d.ts +22 -0
- package/dist/providers/kit/sse.d.ts.map +1 -0
- package/dist/providers/kit/sse.js +70 -0
- package/dist/providers/kit/sse.js.map +1 -0
- package/dist/providers/openai-responses/citations.d.ts +21 -0
- package/dist/providers/openai-responses/citations.d.ts.map +1 -0
- package/dist/providers/openai-responses/citations.js +65 -0
- package/dist/providers/openai-responses/citations.js.map +1 -0
- package/dist/providers/openai-responses/continuation.d.ts +19 -0
- package/dist/providers/openai-responses/continuation.d.ts.map +1 -0
- package/dist/providers/openai-responses/continuation.js +28 -0
- package/dist/providers/openai-responses/continuation.js.map +1 -0
- package/dist/providers/openai-responses/errors.d.ts +28 -0
- package/dist/providers/openai-responses/errors.d.ts.map +1 -0
- package/dist/providers/openai-responses/errors.js +103 -0
- package/dist/providers/openai-responses/errors.js.map +1 -0
- package/dist/providers/openai-responses/history.d.ts +8 -0
- package/dist/providers/openai-responses/history.d.ts.map +1 -0
- package/dist/providers/openai-responses/history.js +93 -0
- package/dist/providers/openai-responses/history.js.map +1 -0
- package/dist/providers/openai-responses/items.d.ts +106 -0
- package/dist/providers/openai-responses/items.d.ts.map +1 -0
- package/dist/providers/openai-responses/items.js +124 -0
- package/dist/providers/openai-responses/items.js.map +1 -0
- package/dist/providers/openai-responses/parameter-schema.d.ts +11 -0
- package/dist/providers/openai-responses/parameter-schema.d.ts.map +1 -0
- package/dist/providers/openai-responses/parameter-schema.js +186 -0
- package/dist/providers/openai-responses/parameter-schema.js.map +1 -0
- package/dist/providers/openai-responses/provider.d.ts +54 -0
- package/dist/providers/openai-responses/provider.d.ts.map +1 -0
- package/dist/providers/openai-responses/provider.js +270 -0
- package/dist/providers/openai-responses/provider.js.map +1 -0
- package/dist/providers/openai-responses/request.d.ts +41 -0
- package/dist/providers/openai-responses/request.d.ts.map +1 -0
- package/dist/providers/openai-responses/request.js +276 -0
- package/dist/providers/openai-responses/request.js.map +1 -0
- package/dist/providers/openai-responses/response.d.ts +7 -0
- package/dist/providers/openai-responses/response.d.ts.map +1 -0
- package/dist/providers/openai-responses/response.js +354 -0
- package/dist/providers/openai-responses/response.js.map +1 -0
- package/dist/providers/openai-responses/stored-items.d.ts +9 -0
- package/dist/providers/openai-responses/stored-items.d.ts.map +1 -0
- package/dist/providers/openai-responses/stored-items.js +133 -0
- package/dist/providers/openai-responses/stored-items.js.map +1 -0
- package/dist/providers/openai-responses/tool-search.d.ts +12 -0
- package/dist/providers/openai-responses/tool-search.d.ts.map +1 -0
- package/dist/providers/openai-responses/tool-search.js +68 -0
- package/dist/providers/openai-responses/tool-search.js.map +1 -0
- package/dist/providers/openai-responses/tools.d.ts +33 -0
- package/dist/providers/openai-responses/tools.d.ts.map +1 -0
- package/dist/providers/openai-responses/tools.js +53 -0
- package/dist/providers/openai-responses/tools.js.map +1 -0
- package/dist/providers/openai-responses/web-search.d.ts +5 -0
- package/dist/providers/openai-responses/web-search.d.ts.map +1 -0
- package/dist/providers/openai-responses/web-search.js +114 -0
- package/dist/providers/openai-responses/web-search.js.map +1 -0
- package/dist/providers/openai-responses/websocket.d.ts +29 -0
- package/dist/providers/openai-responses/websocket.d.ts.map +1 -0
- package/dist/providers/openai-responses/websocket.js +400 -0
- package/dist/providers/openai-responses/websocket.js.map +1 -0
- package/dist/tools/dispatch.d.ts +65 -0
- package/dist/tools/dispatch.d.ts.map +1 -0
- package/dist/tools/dispatch.js +536 -0
- package/dist/tools/dispatch.js.map +1 -0
- package/dist/tools/display-title.d.ts +18 -0
- package/dist/tools/display-title.d.ts.map +1 -0
- package/dist/tools/display-title.js +50 -0
- package/dist/tools/display-title.js.map +1 -0
- package/dist/tools/search.d.ts +36 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +224 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/tool.d.ts +200 -0
- package/dist/tools/tool.d.ts.map +1 -0
- package/dist/tools/tool.js +275 -0
- package/dist/tools/tool.js.map +1 -0
- package/dist/tools/truncate.d.ts +18 -0
- package/dist/tools/truncate.d.ts.map +1 -0
- package/dist/tools/truncate.js +76 -0
- package/dist/tools/truncate.js.map +1 -0
- package/package.json +67 -4
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ToolDeclaration, ToolSearch } from "../../contracts/tools.js";
|
|
2
|
+
export interface FunctionTool {
|
|
3
|
+
readonly async?: boolean;
|
|
4
|
+
readonly type: "function";
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly description: string;
|
|
7
|
+
readonly parameters: Readonly<Record<string, unknown>>;
|
|
8
|
+
readonly strict: false;
|
|
9
|
+
readonly defer_loading?: true;
|
|
10
|
+
}
|
|
11
|
+
export interface ClientToolSearchTool {
|
|
12
|
+
readonly type: "tool_search";
|
|
13
|
+
readonly execution: "client";
|
|
14
|
+
readonly description: string;
|
|
15
|
+
readonly parameters: Readonly<Record<string, unknown>>;
|
|
16
|
+
}
|
|
17
|
+
export interface NamespaceTool {
|
|
18
|
+
readonly type: "namespace";
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly description: string;
|
|
21
|
+
readonly tools: ReadonlyArray<FunctionTool>;
|
|
22
|
+
}
|
|
23
|
+
/** The namespace a group travels under on this wire: its own name, unless OpenAI reserves it. */
|
|
24
|
+
export declare const providerNamespace: (group: string) => string;
|
|
25
|
+
export declare const functionTool: (tool: ToolDeclaration) => FunctionTool;
|
|
26
|
+
export declare const clientToolSearchTool: (search: ToolSearch) => ClientToolSearchTool;
|
|
27
|
+
/**
|
|
28
|
+
* Found tools grouped into namespaces, in order of first appearance. OpenAI's
|
|
29
|
+
* models were trained to search namespaces, and a namespaced call comes back
|
|
30
|
+
* with its `namespace` beside the tool's own name.
|
|
31
|
+
*/
|
|
32
|
+
export declare const namespacedTools: (declarations: ReadonlyArray<ToolDeclaration>) => ReadonlyArray<NamespaceTool>;
|
|
33
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/providers/openai-responses/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAK3E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACtD,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAA;IACtB,QAAQ,CAAC,aAAa,CAAC,EAAE,IAAI,CAAA;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CACvD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,CAAA;CAC5C;AAYD,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,UAAW,MAAM,KAAG,MACS,CAAA;AAE3D,eAAO,MAAM,YAAY,SAAU,eAAe,KAAG,YAcpD,CAAA;AAED,eAAO,MAAM,oBAAoB,WAAY,UAAU,KAAG,oBAKxD,CAAA;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,iBACZ,aAAa,CAAC,eAAe,CAAC,KAC3C,aAAa,CAAC,aAAa,CAc7B,CAAA"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { OpenAiResponsesProviderError } from "./errors.js";
|
|
2
|
+
import { asRecord } from "./items.js";
|
|
3
|
+
import { projectFunctionParameters } from "./parameter-schema.js";
|
|
4
|
+
const DEFAULT_NAMESPACE = "tools";
|
|
5
|
+
/**
|
|
6
|
+
* Namespaces OpenAI keeps for its own tools. A request that declares or
|
|
7
|
+
* replays a function inside one is refused with HTTP 400 ("Function
|
|
8
|
+
* 'browser.browser_screenshot' is not allowed in reserved namespace
|
|
9
|
+
* 'browser'", seen 2026-09-27).
|
|
10
|
+
*/
|
|
11
|
+
const RESERVED_NAMESPACES = new Set(["browser"]);
|
|
12
|
+
/** The namespace a group travels under on this wire: its own name, unless OpenAI reserves it. */
|
|
13
|
+
export const providerNamespace = (group) => RESERVED_NAMESPACES.has(group) ? `${group}_tools` : group;
|
|
14
|
+
export const functionTool = (tool) => {
|
|
15
|
+
if (tool.name.trim().length === 0 || asRecord(tool.parameters) === null) {
|
|
16
|
+
throw new OpenAiResponsesProviderError("The tool catalog contains an unsupported function schema");
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
type: "function",
|
|
20
|
+
name: tool.name,
|
|
21
|
+
description: tool.description,
|
|
22
|
+
parameters: projectFunctionParameters(tool.parameters),
|
|
23
|
+
strict: false,
|
|
24
|
+
...(tool.async === true ? { async: true } : {})
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export const clientToolSearchTool = (search) => ({
|
|
28
|
+
type: "tool_search",
|
|
29
|
+
execution: "client",
|
|
30
|
+
description: search.description,
|
|
31
|
+
parameters: search.parameters
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Found tools grouped into namespaces, in order of first appearance. OpenAI's
|
|
35
|
+
* models were trained to search namespaces, and a namespaced call comes back
|
|
36
|
+
* with its `namespace` beside the tool's own name.
|
|
37
|
+
*/
|
|
38
|
+
export const namespacedTools = (declarations) => {
|
|
39
|
+
const groups = new Map();
|
|
40
|
+
for (const declaration of declarations) {
|
|
41
|
+
const name = providerNamespace(declaration.group ?? DEFAULT_NAMESPACE);
|
|
42
|
+
const tools = groups.get(name) ?? [];
|
|
43
|
+
tools.push({ ...functionTool(declaration), defer_loading: true });
|
|
44
|
+
groups.set(name, tools);
|
|
45
|
+
}
|
|
46
|
+
return [...groups.entries()].map(([name, tools]) => ({
|
|
47
|
+
type: "namespace",
|
|
48
|
+
name,
|
|
49
|
+
description: `Tools in the ${name} namespace.`,
|
|
50
|
+
tools
|
|
51
|
+
}));
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/providers/openai-responses/tools.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAA;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AA0BjE,MAAM,iBAAiB,GAAG,OAAO,CAAA;AAEjC;;;;;GAKG;AACH,MAAM,mBAAmB,GAAwB,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAA;AAErE,iGAAiG;AACjG,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAa,EAAU,EAAE,CACzD,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAA;AAE3D,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAqB,EAAgB,EAAE;IAClE,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,IAAI,EAAE,CAAC;QACxE,MAAM,IAAI,4BAA4B,CACpC,0DAA0D,CAC3D,CAAA;IACH,CAAC;IACD,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,yBAAyB,CAAC,IAAI,CAAC,UAAU,CAAC;QACtD,MAAM,EAAE,KAAK;QACb,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChD,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,MAAkB,EAAwB,EAAE,CAAC,CAAC;IACjF,IAAI,EAAE,aAAa;IACnB,SAAS,EAAE,QAAQ;IACnB,WAAW,EAAE,MAAM,CAAC,WAAW;IAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;CAC9B,CAAC,CAAA;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,YAA4C,EACd,EAAE;IAChC,MAAM,MAAM,GAAG,IAAI,GAAG,EAA+B,CAAA;IACrD,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,iBAAiB,CAAC,WAAW,CAAC,KAAK,IAAI,iBAAiB,CAAC,CAAA;QACtE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;QACpC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,YAAY,CAAC,WAAW,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;QACjE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACzB,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACnD,IAAI,EAAE,WAAW;QACjB,IAAI;QACJ,WAAW,EAAE,gBAAgB,IAAI,aAAa;QAC9C,KAAK;KACN,CAAC,CAAC,CAAA;AACL,CAAC,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { JsonValue, ProviderToolCall } from "../../contracts/messages.js";
|
|
2
|
+
import { type ResponseShape, type WebSearchOutputItem } from "./items.js";
|
|
3
|
+
export declare const searchArguments: (item: WebSearchOutputItem) => Readonly<Record<string, JsonValue>>;
|
|
4
|
+
export declare const webSearchCalls: (response: ResponseShape) => ReadonlyArray<ProviderToolCall>;
|
|
5
|
+
//# sourceMappingURL=web-search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../../src/providers/openai-responses/web-search.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAc,SAAS,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAC1F,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACzB,MAAM,YAAY,CAAA;AAkEnB,eAAO,MAAM,eAAe,SAAU,mBAAmB,KAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAoB7F,CAAA;AAkBD,eAAO,MAAM,cAAc,aAAc,aAAa,KAAG,aAAa,CAAC,gBAAgB,CAiBtF,CAAA"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { publicWebUrl } from "@arden-hq/std/url";
|
|
2
|
+
import { clipLine, cutText } from "@arden-hq/std/text";
|
|
3
|
+
import { asRecord, WEB_SEARCH_TOOL_NAME } from "./items.js";
|
|
4
|
+
const MAX_WEB_SOURCE_REFS = 20;
|
|
5
|
+
const MAX_PROVIDER_RESULT_CHARS = 20_000;
|
|
6
|
+
const boundedLine = (value, limit) => {
|
|
7
|
+
if (typeof value !== "string")
|
|
8
|
+
return null;
|
|
9
|
+
const text = clipLine(value, limit);
|
|
10
|
+
return text.length === 0 ? null : text;
|
|
11
|
+
};
|
|
12
|
+
const webUrl = (value) => {
|
|
13
|
+
if (typeof value !== "string")
|
|
14
|
+
return null;
|
|
15
|
+
const page = publicWebUrl(value);
|
|
16
|
+
return page.kind === "ok" ? page.url.toString() : null;
|
|
17
|
+
};
|
|
18
|
+
const sourceRef = (value) => {
|
|
19
|
+
const source = asRecord(value);
|
|
20
|
+
if (source?.type !== "url" && source?.type !== "url_citation")
|
|
21
|
+
return null;
|
|
22
|
+
const url = webUrl(source.url);
|
|
23
|
+
if (url === null)
|
|
24
|
+
return null;
|
|
25
|
+
const title = boundedLine(source.title, 256) ?? new URL(url).hostname;
|
|
26
|
+
return { provider: "web", kind: "page", ref: url, title, url };
|
|
27
|
+
};
|
|
28
|
+
const itemCitations = (item) => {
|
|
29
|
+
if (item.type !== "message")
|
|
30
|
+
return [];
|
|
31
|
+
return item.content.flatMap((part) => {
|
|
32
|
+
if (part.type !== "output_text")
|
|
33
|
+
return [];
|
|
34
|
+
return part.annotations.flatMap((annotation) => {
|
|
35
|
+
const ref = sourceRef(annotation);
|
|
36
|
+
return ref === null ? [] : [ref];
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const citedSources = (response) => response.output.flatMap(itemCitations);
|
|
41
|
+
const searchSources = (item, citations) => {
|
|
42
|
+
const actionSources = Array.isArray(item.action?.sources)
|
|
43
|
+
? item.action.sources.flatMap((source) => {
|
|
44
|
+
const ref = sourceRef(source);
|
|
45
|
+
return ref === null ? [] : [ref];
|
|
46
|
+
})
|
|
47
|
+
: [];
|
|
48
|
+
const unique = new Map();
|
|
49
|
+
for (const ref of [...citations, ...actionSources]) {
|
|
50
|
+
if (!unique.has(ref.ref))
|
|
51
|
+
unique.set(ref.ref, ref);
|
|
52
|
+
if (unique.size >= MAX_WEB_SOURCE_REFS)
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
return [...unique.values()];
|
|
56
|
+
};
|
|
57
|
+
export const searchArguments = (item) => {
|
|
58
|
+
const action = item.action;
|
|
59
|
+
if (action === undefined)
|
|
60
|
+
return {};
|
|
61
|
+
const values = {};
|
|
62
|
+
for (const [key, limit] of [
|
|
63
|
+
["type", 64],
|
|
64
|
+
["query", 1_000],
|
|
65
|
+
["url", 4_096],
|
|
66
|
+
["pattern", 1_000]
|
|
67
|
+
]) {
|
|
68
|
+
const value = boundedLine(action[key], limit);
|
|
69
|
+
if (value !== null)
|
|
70
|
+
values[key] = value;
|
|
71
|
+
}
|
|
72
|
+
if (Array.isArray(action.queries)) {
|
|
73
|
+
values.queries = action.queries.slice(0, 20).flatMap((query) => {
|
|
74
|
+
const value = boundedLine(query, 1_000);
|
|
75
|
+
return value === null ? [] : [value];
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return values;
|
|
79
|
+
};
|
|
80
|
+
const searchAction = (args) => {
|
|
81
|
+
if (typeof args.query === "string")
|
|
82
|
+
return `Searched for: ${args.query}`;
|
|
83
|
+
if (typeof args.url === "string")
|
|
84
|
+
return `Opened: ${args.url}`;
|
|
85
|
+
return "Searched the web.";
|
|
86
|
+
};
|
|
87
|
+
const searchResult = (item, sources) => {
|
|
88
|
+
const args = searchArguments(item);
|
|
89
|
+
const action = searchAction(args);
|
|
90
|
+
const result = sources.length === 0
|
|
91
|
+
? action
|
|
92
|
+
: `${action}\n\nSources:\n${sources.map((source) => `- ${source.title}: ${source.url}`).join("\n")}`;
|
|
93
|
+
return cutText(result, MAX_PROVIDER_RESULT_CHARS, { suffix: "\n[Source summary truncated.]" });
|
|
94
|
+
};
|
|
95
|
+
export const webSearchCalls = (response) => {
|
|
96
|
+
const citations = citedSources(response);
|
|
97
|
+
return response.output.flatMap((item) => {
|
|
98
|
+
if (item.type !== "web_search_call")
|
|
99
|
+
return [];
|
|
100
|
+
const sources = searchSources(item, citations);
|
|
101
|
+
return [
|
|
102
|
+
{
|
|
103
|
+
id: item.id,
|
|
104
|
+
name: WEB_SEARCH_TOOL_NAME,
|
|
105
|
+
arguments: searchArguments(item),
|
|
106
|
+
result: searchResult(item, sources),
|
|
107
|
+
done: true,
|
|
108
|
+
loaded_tool_names: [],
|
|
109
|
+
source_refs: sources
|
|
110
|
+
}
|
|
111
|
+
];
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=web-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-search.js","sourceRoot":"","sources":["../../../src/providers/openai-responses/web-search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Metadata } from "../../contracts/messages.js";
|
|
2
|
+
import type { ModelProvider, ModelProviderSession } from "../../contracts/provider.js";
|
|
3
|
+
/** Hosts supply the platform socket and authentication headers; Loop owns the protocol. */
|
|
4
|
+
export interface ResponsesWebSocket {
|
|
5
|
+
readonly isClosed: () => boolean;
|
|
6
|
+
readonly events: AsyncIterable<unknown>;
|
|
7
|
+
readonly send: (event: Metadata) => void;
|
|
8
|
+
readonly close: () => void;
|
|
9
|
+
}
|
|
10
|
+
export type ConnectResponsesWebSocket = (options: {
|
|
11
|
+
readonly url: string;
|
|
12
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
13
|
+
readonly signal: AbortSignal;
|
|
14
|
+
}) => Promise<ResponsesWebSocket>;
|
|
15
|
+
export declare const openResponsesSession: (options: {
|
|
16
|
+
readonly connect: ConnectResponsesWebSocket;
|
|
17
|
+
readonly headers: (signal: AbortSignal, forceRefresh: boolean) => Promise<Record<string, string>>;
|
|
18
|
+
readonly baseUrl: string;
|
|
19
|
+
readonly modelPrefix: string;
|
|
20
|
+
readonly defaultInstructions?: string;
|
|
21
|
+
readonly omitMaxOutputTokens?: boolean;
|
|
22
|
+
readonly maxAttempts: number;
|
|
23
|
+
readonly idleTimeoutMs: number;
|
|
24
|
+
readonly capabilities: NonNullable<ModelProvider["capabilities"]>;
|
|
25
|
+
readonly transport: (model: string) => "sse" | "websocket";
|
|
26
|
+
readonly cacheScopeHeader?: string;
|
|
27
|
+
readonly fallback: ModelProvider["stream"];
|
|
28
|
+
}) => ModelProviderSession;
|
|
29
|
+
//# sourceMappingURL=websocket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../../src/providers/openai-responses/websocket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EAIrB,MAAM,6BAA6B,CAAA;AAoBpC,2FAA2F;AAC3F,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAA;IAChC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAA;IACvC,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAA;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAC3B;AAED,MAAM,MAAM,yBAAyB,GAAG,CAAC,OAAO,EAAE;IAChD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAClD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAC7B,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAA;AAEjC,eAAO,MAAM,oBAAoB,YAAa;IAC5C,QAAQ,CAAC,OAAO,EAAE,yBAAyB,CAAA;IAC3C,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACjG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;IACrC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,YAAY,EAAE,WAAW,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAA;IACjE,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,GAAG,WAAW,CAAA;IAC1D,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;CAC3C,KAAG,oBAmZH,CAAA"}
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
import { raceAbort, backoffSleep, isRetryableFailure, nextRetry, retryDelayMs, RetryableProviderError, HttpStatusError } from "../kit/index.js";
|
|
2
|
+
import { OpenAiResponsesProviderError } from "./errors.js";
|
|
3
|
+
import { asRecord } from "./items.js";
|
|
4
|
+
import { makePayload } from "./request.js";
|
|
5
|
+
import { makeEventMapper, responseCode, responseFailureMessage } from "./response.js";
|
|
6
|
+
import { incrementalInput, responseContinuation } from "./continuation.js";
|
|
7
|
+
export const openResponsesSession = (options) => {
|
|
8
|
+
const lifetime = new AbortController();
|
|
9
|
+
let connection;
|
|
10
|
+
let saved;
|
|
11
|
+
let next = "create";
|
|
12
|
+
let responseId;
|
|
13
|
+
let priorInput = [];
|
|
14
|
+
let steeredInput = [];
|
|
15
|
+
let pending;
|
|
16
|
+
let route;
|
|
17
|
+
let previous;
|
|
18
|
+
let socketUnavailable = false;
|
|
19
|
+
const close = () => {
|
|
20
|
+
connection?.socket.close();
|
|
21
|
+
connection = undefined;
|
|
22
|
+
saved = undefined;
|
|
23
|
+
pending = undefined;
|
|
24
|
+
next = "create";
|
|
25
|
+
responseId = undefined;
|
|
26
|
+
priorInput = [];
|
|
27
|
+
steeredInput = [];
|
|
28
|
+
previous = undefined;
|
|
29
|
+
};
|
|
30
|
+
const streamAttempt = async function* (request, recoveredRejections, forceRefresh) {
|
|
31
|
+
const capabilities = await options.capabilities(request.model);
|
|
32
|
+
if (route !== undefined &&
|
|
33
|
+
(route.model !== request.model || route.cacheScope !== request.cacheScope))
|
|
34
|
+
close();
|
|
35
|
+
if (capabilities.steering !== "native" &&
|
|
36
|
+
capabilities.asyncTools !== "native" &&
|
|
37
|
+
connection?.socket.isClosed())
|
|
38
|
+
close();
|
|
39
|
+
route = { model: request.model, cacheScope: request.cacheScope };
|
|
40
|
+
const signal = AbortSignal.any([
|
|
41
|
+
lifetime.signal,
|
|
42
|
+
...(request.signal === undefined ? [] : [request.signal])
|
|
43
|
+
]);
|
|
44
|
+
const requestPayload = options.omitMaxOutputTokens === true
|
|
45
|
+
? (({ maxOutputTokens: _, ...rest }) => rest)(request)
|
|
46
|
+
: request;
|
|
47
|
+
const payload = makePayload(requestPayload, options.modelPrefix, options.defaultInstructions);
|
|
48
|
+
const delta = capabilities.steering === "native" || previous === undefined
|
|
49
|
+
? undefined
|
|
50
|
+
: incrementalInput(payload, previous);
|
|
51
|
+
const additionalInput = continuationInput(payload.input, priorInput, steeredInput);
|
|
52
|
+
const automatic = next === "automatic";
|
|
53
|
+
const carry = automatic ? additionalInput.filter((item) => item.role === "user") : [];
|
|
54
|
+
const deferredOutputs = automatic && additionalInput.some((item) => item.type === "function_call_output");
|
|
55
|
+
const onAbort = () => connection?.socket.close();
|
|
56
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
57
|
+
let polling = false;
|
|
58
|
+
let pollFailure;
|
|
59
|
+
let generating = false;
|
|
60
|
+
let failedSteer = false;
|
|
61
|
+
let terminal;
|
|
62
|
+
let terminalRaw;
|
|
63
|
+
let progressed = false;
|
|
64
|
+
let refreshHeaders = forceRefresh;
|
|
65
|
+
const map = makeEventMapper(request.model, request.toolSearch);
|
|
66
|
+
let pollWork = Promise.resolve();
|
|
67
|
+
const poll = () => {
|
|
68
|
+
if (capabilities.steering !== "native" ||
|
|
69
|
+
!generating ||
|
|
70
|
+
polling ||
|
|
71
|
+
pending !== undefined ||
|
|
72
|
+
responseId === undefined ||
|
|
73
|
+
signal.aborted)
|
|
74
|
+
return;
|
|
75
|
+
polling = true;
|
|
76
|
+
pollWork = (async () => {
|
|
77
|
+
const target = responseId;
|
|
78
|
+
const messages = (await request.steering?.take()) ?? [];
|
|
79
|
+
if (messages.length === 0 || signal.aborted)
|
|
80
|
+
return;
|
|
81
|
+
if (target === undefined)
|
|
82
|
+
return;
|
|
83
|
+
pending = { kind: "submitted", target };
|
|
84
|
+
const input = makePayload({ ...request, messages, tools: [], deferredTools: [] }, options.modelPrefix, undefined).input;
|
|
85
|
+
steeredInput = [...steeredInput, ...input];
|
|
86
|
+
if (connection === undefined)
|
|
87
|
+
throw new Error("Responses socket closed before the steer was sent");
|
|
88
|
+
connection.socket.send({ type: "response.steer", previous_response_id: target, input });
|
|
89
|
+
})()
|
|
90
|
+
.catch((cause) => {
|
|
91
|
+
pollFailure = { cause };
|
|
92
|
+
connection?.socket.close();
|
|
93
|
+
})
|
|
94
|
+
.finally(() => {
|
|
95
|
+
polling = false;
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
const timer = setInterval(poll, 100);
|
|
99
|
+
const connect = async () => {
|
|
100
|
+
const headers = await options.headers(signal, refreshHeaders);
|
|
101
|
+
refreshHeaders = false;
|
|
102
|
+
const socket = await options
|
|
103
|
+
.connect({
|
|
104
|
+
url: `${options.baseUrl.replace(/^http/, "ws")}/responses`,
|
|
105
|
+
headers: {
|
|
106
|
+
...headers,
|
|
107
|
+
...(options.cacheScopeHeader === undefined || request.cacheScope === undefined
|
|
108
|
+
? {}
|
|
109
|
+
: { [options.cacheScopeHeader]: request.cacheScope })
|
|
110
|
+
},
|
|
111
|
+
signal
|
|
112
|
+
})
|
|
113
|
+
.catch((cause) => {
|
|
114
|
+
throw new ConnectionFailure(cause);
|
|
115
|
+
});
|
|
116
|
+
return { socket, events: socket.events[Symbol.asyncIterator]() };
|
|
117
|
+
};
|
|
118
|
+
try {
|
|
119
|
+
connection ??= await connect();
|
|
120
|
+
if (next !== "automatic") {
|
|
121
|
+
const { stream: _, ...body } = payload;
|
|
122
|
+
if (next === "required" && responseId !== undefined) {
|
|
123
|
+
const input = additionalInput;
|
|
124
|
+
if (!input.some((item) => item.type === "function_call_output"))
|
|
125
|
+
throw new OpenAiResponsesProviderError("Steering continuation requires tool output");
|
|
126
|
+
connection.socket.send({
|
|
127
|
+
type: "response.create",
|
|
128
|
+
...body,
|
|
129
|
+
previous_response_id: responseId,
|
|
130
|
+
input
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
else
|
|
134
|
+
connection.socket.send({
|
|
135
|
+
type: "response.create",
|
|
136
|
+
...body,
|
|
137
|
+
...(delta === undefined || previous === undefined
|
|
138
|
+
? {}
|
|
139
|
+
: {
|
|
140
|
+
previous_response_id: previous.responseId,
|
|
141
|
+
input: delta
|
|
142
|
+
})
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
next = "create";
|
|
146
|
+
priorInput = payload.input;
|
|
147
|
+
while (true) {
|
|
148
|
+
if (pollFailure !== undefined)
|
|
149
|
+
throw pollFailure.cause;
|
|
150
|
+
const deadline = new AbortController();
|
|
151
|
+
const timer = setTimeout(() => deadline.abort(), options.idleTimeoutMs);
|
|
152
|
+
const read = await (async () => {
|
|
153
|
+
try {
|
|
154
|
+
if (saved !== undefined)
|
|
155
|
+
return { done: false, value: saved };
|
|
156
|
+
return await raceAbort(connection.events.next(), AbortSignal.any([signal, deadline.signal]));
|
|
157
|
+
}
|
|
158
|
+
catch (cause) {
|
|
159
|
+
if (deadline.signal.aborted && !signal.aborted)
|
|
160
|
+
throw new RetryableProviderError("OpenAI WebSocket response stream timed out");
|
|
161
|
+
throw cause;
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
clearTimeout(timer);
|
|
165
|
+
}
|
|
166
|
+
})();
|
|
167
|
+
saved = undefined;
|
|
168
|
+
if (read.done)
|
|
169
|
+
throw new RetryableProviderError("OpenAI WebSocket disconnected before response completion");
|
|
170
|
+
const event = asRecord(read.value);
|
|
171
|
+
if (event === null || typeof event.type !== "string")
|
|
172
|
+
throw new OpenAiResponsesProviderError("Invalid OpenAI WebSocket event");
|
|
173
|
+
if (event.type.startsWith("response.") && event.type !== "response.created")
|
|
174
|
+
progressed = true;
|
|
175
|
+
if (event.type === "error" &&
|
|
176
|
+
responseCode(event) === "native_turn_context_mismatch" &&
|
|
177
|
+
capabilities.steering !== "native" &&
|
|
178
|
+
capabilities.asyncTools !== "native" &&
|
|
179
|
+
!automatic &&
|
|
180
|
+
!progressed &&
|
|
181
|
+
!recoveredRejections.has("context")) {
|
|
182
|
+
recoveredRejections.add("context");
|
|
183
|
+
close();
|
|
184
|
+
yield { _tag: "ProviderStreamRetry", attempt: 1, maxAttempts: 2, delayMs: 0 };
|
|
185
|
+
connection = await connect();
|
|
186
|
+
const { stream: _, ...body } = payload;
|
|
187
|
+
connection.socket.send({ type: "response.create", ...body });
|
|
188
|
+
priorInput = payload.input;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (event.type === "error" &&
|
|
192
|
+
responseCode(event) === "previous_response_not_found" &&
|
|
193
|
+
delta !== undefined &&
|
|
194
|
+
!progressed &&
|
|
195
|
+
!recoveredRejections.has("missing")) {
|
|
196
|
+
recoveredRejections.add("missing");
|
|
197
|
+
previous = undefined;
|
|
198
|
+
const { stream: _, ...body } = payload;
|
|
199
|
+
connection.socket.send({ type: "response.create", ...body });
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (event.type === "error" &&
|
|
203
|
+
["native_turn_context_mismatch", "previous_response_not_found"].includes(responseCode(event) ?? ""))
|
|
204
|
+
throw new OpenAiResponsesProviderError(responseFailureMessage(event));
|
|
205
|
+
if (event.type === "response.created") {
|
|
206
|
+
if (terminal !== undefined) {
|
|
207
|
+
saved = event;
|
|
208
|
+
next = "automatic";
|
|
209
|
+
yield { ...terminal, continuation: true };
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const response = asRecord(event.response);
|
|
213
|
+
if (typeof response?.id !== "string")
|
|
214
|
+
throw new OpenAiResponsesProviderError("Missing OpenAI response identity");
|
|
215
|
+
responseId = response.id;
|
|
216
|
+
if (automatic || pending?.kind === "accepted") {
|
|
217
|
+
pending = undefined;
|
|
218
|
+
steeredInput = [];
|
|
219
|
+
}
|
|
220
|
+
generating = true;
|
|
221
|
+
if (carry.length > 0) {
|
|
222
|
+
pending = { kind: "submitted", target: responseId };
|
|
223
|
+
steeredInput = carry;
|
|
224
|
+
connection.socket.send({
|
|
225
|
+
type: "response.steer",
|
|
226
|
+
previous_response_id: responseId,
|
|
227
|
+
input: carry
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
else
|
|
231
|
+
poll();
|
|
232
|
+
}
|
|
233
|
+
if (event.type === "response.steer.accepted") {
|
|
234
|
+
const steer = asRecord(event.steer);
|
|
235
|
+
if (pending === undefined ||
|
|
236
|
+
steer?.previous_response_id !== pending.target ||
|
|
237
|
+
typeof steer.id !== "string") {
|
|
238
|
+
throw new OpenAiResponsesProviderError("Unexpected steering acknowledgement");
|
|
239
|
+
}
|
|
240
|
+
pending = { kind: "accepted", target: pending.target, id: steer.id };
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (event.type === "response.steer.failed") {
|
|
244
|
+
pending = undefined;
|
|
245
|
+
failedSteer = true;
|
|
246
|
+
if (terminal !== undefined) {
|
|
247
|
+
yield { ...terminal, continuation: true };
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (event.type === "response.steer.pending") {
|
|
253
|
+
if (terminal === undefined)
|
|
254
|
+
throw new OpenAiResponsesProviderError("Steering pending without a completed response");
|
|
255
|
+
next = "required";
|
|
256
|
+
yield { ...terminal, continuation: true };
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const isTerminal = event.type === "response.completed" || event.type === "response.incomplete";
|
|
260
|
+
if (isTerminal) {
|
|
261
|
+
generating = false;
|
|
262
|
+
await pollWork;
|
|
263
|
+
terminalRaw = event;
|
|
264
|
+
}
|
|
265
|
+
const details = asRecord(asRecord(event.response)?.incomplete_details);
|
|
266
|
+
const mapped = event.type === "response.incomplete" && details?.reason === "steered"
|
|
267
|
+
? map({ ...event, type: "response.completed" })
|
|
268
|
+
: map(event);
|
|
269
|
+
for (const item of mapped) {
|
|
270
|
+
if (item._tag === "Completed")
|
|
271
|
+
terminal = item;
|
|
272
|
+
else {
|
|
273
|
+
yield item;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (terminal !== undefined && pending === undefined) {
|
|
277
|
+
if (terminalRaw?.type === "response.incomplete" && details?.reason === "steered") {
|
|
278
|
+
throw new OpenAiResponsesProviderError("Steered response has no tracked steering input");
|
|
279
|
+
}
|
|
280
|
+
const completedId = asRecord(terminalRaw?.response)?.id;
|
|
281
|
+
previous =
|
|
282
|
+
terminalRaw?.type === "response.completed" &&
|
|
283
|
+
typeof completedId === "string" &&
|
|
284
|
+
capabilities.steering !== "native"
|
|
285
|
+
? responseContinuation({
|
|
286
|
+
payload,
|
|
287
|
+
message: terminal.message,
|
|
288
|
+
responseId: completedId,
|
|
289
|
+
asyncTools: new Set([...request.tools, ...request.deferredTools].flatMap((tool) => tool.async === true ? [tool.name] : []))
|
|
290
|
+
})
|
|
291
|
+
: undefined;
|
|
292
|
+
yield deferredOutputs || failedSteer ? { ...terminal, continuation: true } : terminal;
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
catch (cause) {
|
|
298
|
+
close();
|
|
299
|
+
throw cause;
|
|
300
|
+
}
|
|
301
|
+
finally {
|
|
302
|
+
generating = false;
|
|
303
|
+
clearInterval(timer);
|
|
304
|
+
await pollWork;
|
|
305
|
+
signal.removeEventListener("abort", onAbort);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
return {
|
|
309
|
+
close: () => {
|
|
310
|
+
lifetime.abort();
|
|
311
|
+
close();
|
|
312
|
+
},
|
|
313
|
+
stream: async function* (request) {
|
|
314
|
+
if (options.transport(request.model) !== "websocket" || socketUnavailable) {
|
|
315
|
+
close();
|
|
316
|
+
yield* await options.fallback(request);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const signal = AbortSignal.any([
|
|
320
|
+
lifetime.signal,
|
|
321
|
+
...(request.signal === undefined ? [] : [request.signal])
|
|
322
|
+
]);
|
|
323
|
+
const recoveredRejections = new Set();
|
|
324
|
+
let authRetried = false;
|
|
325
|
+
let forceRefresh = false;
|
|
326
|
+
for (let attempt = 1;; attempt++) {
|
|
327
|
+
signal.throwIfAborted();
|
|
328
|
+
const capabilities = await options.capabilities(request.model);
|
|
329
|
+
const boundary = next === "create" && pending === undefined;
|
|
330
|
+
const portable = capabilities.steering !== "native" && capabilities.asyncTools !== "native";
|
|
331
|
+
try {
|
|
332
|
+
const refresh = forceRefresh;
|
|
333
|
+
forceRefresh = false;
|
|
334
|
+
yield* streamAttempt(request, recoveredRejections, refresh);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
catch (failure) {
|
|
338
|
+
const cause = failure instanceof ConnectionFailure ? failure.cause : failure;
|
|
339
|
+
if (signal.aborted || !boundary || (!portable && !(failure instanceof ConnectionFailure)))
|
|
340
|
+
throw cause;
|
|
341
|
+
if (!authRetried &&
|
|
342
|
+
failure instanceof ConnectionFailure &&
|
|
343
|
+
cause instanceof HttpStatusError &&
|
|
344
|
+
cause.status === 401) {
|
|
345
|
+
authRetried = true;
|
|
346
|
+
forceRefresh = true;
|
|
347
|
+
attempt--;
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
if (!isRetryableFailure(cause))
|
|
351
|
+
throw cause;
|
|
352
|
+
const delayMs = nextRetry(attempt, cause, { maxAttempts: options.maxAttempts });
|
|
353
|
+
if (delayMs === undefined) {
|
|
354
|
+
const fallbackDelayMs = cause instanceof HttpStatusError &&
|
|
355
|
+
(cause.retryAfter !== null || cause.retryAfterMs !== null)
|
|
356
|
+
? retryDelayMs(attempt, cause)
|
|
357
|
+
: 0;
|
|
358
|
+
socketUnavailable = true;
|
|
359
|
+
yield {
|
|
360
|
+
_tag: "ProviderStreamRetry",
|
|
361
|
+
attempt,
|
|
362
|
+
maxAttempts: options.maxAttempts + 1,
|
|
363
|
+
delayMs: fallbackDelayMs
|
|
364
|
+
};
|
|
365
|
+
if (fallbackDelayMs > 0)
|
|
366
|
+
await backoffSleep(fallbackDelayMs, signal);
|
|
367
|
+
signal.throwIfAborted();
|
|
368
|
+
yield* await options.fallback(request);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
yield { _tag: "ProviderStreamRetry", attempt, maxAttempts: options.maxAttempts, delayMs };
|
|
372
|
+
await backoffSleep(delayMs, signal);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
};
|
|
378
|
+
class ConnectionFailure extends Error {
|
|
379
|
+
constructor(cause) {
|
|
380
|
+
super("OpenAI WebSocket connection failed", { cause });
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
const continuationInput = (input, previous, steered) => {
|
|
384
|
+
const seen = new Map();
|
|
385
|
+
for (const item of [...previous, ...steered]) {
|
|
386
|
+
const key = JSON.stringify(item);
|
|
387
|
+
seen.set(key, (seen.get(key) ?? 0) + 1);
|
|
388
|
+
}
|
|
389
|
+
return input.filter((item) => {
|
|
390
|
+
if (item.role !== "user" && item.type !== "function_call_output")
|
|
391
|
+
return false;
|
|
392
|
+
const key = JSON.stringify(item);
|
|
393
|
+
const count = seen.get(key) ?? 0;
|
|
394
|
+
if (count === 0)
|
|
395
|
+
return true;
|
|
396
|
+
seen.set(key, count - 1);
|
|
397
|
+
return false;
|
|
398
|
+
});
|
|
399
|
+
};
|
|
400
|
+
//# sourceMappingURL=websocket.js.map
|