@opengeni/sdk 3.1.0 → 3.1.2
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/README.md +1037 -71
- package/dist/accounts.d.ts +5 -1
- package/dist/accounts.js +13 -1
- package/dist/accounts.js.map +1 -1
- package/dist/adapters/express.d.ts +31 -0
- package/dist/adapters/express.js +87 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/hono.d.ts +16 -0
- package/dist/adapters/hono.js +8 -0
- package/dist/adapters/hono.js.map +1 -0
- package/dist/adapters/next.d.ts +29 -0
- package/dist/adapters/next.js +22 -0
- package/dist/adapters/next.js.map +1 -0
- package/dist/allowance-refusal.d.ts +2 -0
- package/dist/allowance-refusal.js +50 -0
- package/dist/allowance-refusal.js.map +1 -0
- package/dist/app-links.d.ts +42 -0
- package/dist/app-links.js +66 -0
- package/dist/app-links.js.map +1 -0
- package/dist/artifact-catalog.d.ts +40 -0
- package/dist/artifact-client.d.ts +20 -8
- package/dist/artifacts.d.ts +1 -1
- package/dist/artifacts.js +8 -6
- package/dist/automations.js +8 -2
- package/dist/automations.js.map +1 -1
- package/dist/azure-live-transport.d.ts +32 -0
- package/dist/browser.d.ts +7 -2
- package/dist/browser.js +27 -5
- package/dist/chat/fold.d.ts +75 -0
- package/dist/chat/handler.d.ts +41 -0
- package/dist/chat/http.d.ts +67 -0
- package/dist/chat/ids.d.ts +34 -0
- package/dist/chat/index.d.ts +9 -0
- package/dist/chat/index.js +1703 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/openai.d.ts +30 -0
- package/dist/chat/opengeni.d.ts +129 -0
- package/dist/chat/types.d.ts +207 -0
- package/dist/chat/vercel.d.ts +49 -0
- package/dist/chats.d.ts +8 -0
- package/dist/chunk-4AHR4KGA.js +301 -0
- package/dist/chunk-4AHR4KGA.js.map +1 -0
- package/dist/chunk-6HZGAIUE.js +1665 -0
- package/dist/chunk-6HZGAIUE.js.map +1 -0
- package/dist/chunk-7EWT3PV6.js +368 -0
- package/dist/chunk-7EWT3PV6.js.map +1 -0
- package/dist/{chunk-VYCTL62C.js → chunk-GZQSWAKD.js} +1 -1
- package/dist/chunk-GZQSWAKD.js.map +1 -0
- package/dist/chunk-JXXCTW5W.js +1392 -0
- package/dist/chunk-JXXCTW5W.js.map +1 -0
- package/dist/{chunk-YTAWBDO2.js → chunk-KADZ5PGG.js} +28 -2
- package/dist/chunk-KADZ5PGG.js.map +1 -0
- package/dist/{chunk-YKZME56C.js → chunk-KWADQ227.js} +3 -3
- package/dist/{chunk-YKZME56C.js.map → chunk-KWADQ227.js.map} +1 -1
- package/dist/{chunk-7ZXBPJZP.js → chunk-NEM5N6C6.js} +3902 -1457
- package/dist/chunk-NEM5N6C6.js.map +1 -0
- package/dist/{chunk-GW3EJ2GP.js → chunk-O7KANXC3.js} +86 -13
- package/dist/chunk-O7KANXC3.js.map +1 -0
- package/dist/{chunk-VUQZAB3O.js → chunk-OAKHWFSV.js} +28 -32
- package/dist/chunk-OAKHWFSV.js.map +1 -0
- package/dist/chunk-P7UWKORG.js +561 -0
- package/dist/chunk-P7UWKORG.js.map +1 -0
- package/dist/chunk-QGEIL4TR.js +195 -0
- package/dist/chunk-QGEIL4TR.js.map +1 -0
- package/dist/chunk-RJHCBZF7.js +270 -0
- package/dist/chunk-RJHCBZF7.js.map +1 -0
- package/dist/chunk-S3D75WSQ.js +340 -0
- package/dist/chunk-S3D75WSQ.js.map +1 -0
- package/dist/chunk-UM4ZXXJR.js +9 -0
- package/dist/chunk-UM4ZXXJR.js.map +1 -0
- package/dist/chunk-VPVMLM7Q.js +15 -0
- package/dist/chunk-VPVMLM7Q.js.map +1 -0
- package/dist/{chunk-C2H7HBNP.js → chunk-WVCJRSGJ.js} +119 -14
- package/dist/chunk-WVCJRSGJ.js.map +1 -0
- package/dist/chunk-XA7HVIHI.js +126 -0
- package/dist/chunk-XA7HVIHI.js.map +1 -0
- package/dist/{chunk-TX3EIENU.js → chunk-YDVPI7WT.js} +73 -2
- package/dist/chunk-YDVPI7WT.js.map +1 -0
- package/dist/chunk-YKIHNLWD.js +153 -0
- package/dist/chunk-YKIHNLWD.js.map +1 -0
- package/dist/chunk-ZDUBPV33.js +277 -0
- package/dist/chunk-ZDUBPV33.js.map +1 -0
- package/dist/client.d.ts +1065 -124
- package/dist/codex-realtime-controller.d.ts +13 -0
- package/dist/codex-realtime-controller.js +4 -2
- package/dist/codex-realtime-v3-wire.d.ts +3 -2
- package/dist/codex-realtime.d.ts +5 -1
- package/dist/company-brain.d.ts +1 -11
- package/dist/company-profile.d.ts +13 -0
- package/dist/core.d.ts +7 -2
- package/dist/core.js +25 -6
- package/dist/deprecation.d.ts +47 -0
- package/dist/document-authority-client.d.ts +24 -2
- package/dist/document-authority.js +7 -5
- package/dist/editable-artifacts/index.d.ts +1 -1
- package/dist/editable-artifacts/types.d.ts +12 -2
- package/dist/editable-artifacts.js +19 -3
- package/dist/editable-artifacts.js.map +1 -1
- package/dist/embedding-client.d.ts +129 -0
- package/dist/errors.d.ts +76 -1
- package/dist/feedback.d.ts +23 -0
- package/dist/gateway-realtime-transport.js +1 -1
- package/dist/github-repositories.d.ts +10 -0
- package/dist/github-repositories.js +36 -0
- package/dist/github-repositories.js.map +1 -0
- package/dist/index.d.ts +64 -11
- package/dist/index.js +566 -141
- package/dist/index.js.map +1 -1
- package/dist/insights-usage.d.ts +33 -0
- package/dist/insights-usage.js +7 -0
- package/dist/insights-usage.js.map +1 -0
- package/dist/interaction.d.ts +103 -71
- package/dist/interaction.js +4 -2
- package/dist/knowledge.d.ts +7 -0
- package/dist/knowledge.js +20 -0
- package/dist/knowledge.js.map +1 -0
- package/dist/known-tools.d.ts +4 -0
- package/dist/message-links.d.ts +68 -0
- package/dist/model-context.d.ts +68 -0
- package/dist/model-display.d.ts +2 -0
- package/dist/model-display.js +17 -0
- package/dist/model-display.js.map +1 -0
- package/dist/model-picker-order.d.ts +1 -0
- package/dist/model-picker-order.js +10 -0
- package/dist/model-picker-order.js.map +1 -0
- package/dist/organization-integration-policy.d.ts +26 -0
- package/dist/organization-integration-policy.js +26 -0
- package/dist/organization-integration-policy.js.map +1 -0
- package/dist/pr-review-client.d.ts +1 -1
- package/dist/pr-review.d.ts +1 -1
- package/dist/pr-review.js.map +1 -1
- package/dist/preference-registry.d.ts +1 -1
- package/dist/prepared-mcp-setup.d.ts +5 -0
- package/dist/proxy.d.ts +13 -11
- package/dist/realtime.d.ts +4 -2
- package/dist/realtime.js +253 -7
- package/dist/realtime.js.map +1 -1
- package/dist/session-history-import.d.ts +22 -0
- package/dist/session-history-import.js +36 -0
- package/dist/session-history-import.js.map +1 -0
- package/dist/session-list-entries.d.ts +1 -0
- package/dist/session-list-entries.js +7 -0
- package/dist/session-list-entries.js.map +1 -0
- package/dist/session-message-search.d.ts +53 -0
- package/dist/session-proxy-client.d.ts +28 -0
- package/dist/session-proxy.d.ts +334 -0
- package/dist/session-proxy.js +24 -0
- package/dist/session-proxy.js.map +1 -0
- package/dist/session-titles.d.ts +2 -0
- package/dist/session-usage-limits.d.ts +10 -0
- package/dist/session-usage-limits.js +43 -0
- package/dist/session-usage-limits.js.map +1 -0
- package/dist/shared-catalog-loader.d.ts +34 -0
- package/dist/site-bridge-host.d.ts +112 -0
- package/dist/site-bridge-host.js +285 -0
- package/dist/site-bridge-host.js.map +1 -0
- package/dist/site-browser-entry.d.ts +1 -0
- package/dist/site-browser-runtime.gen.d.ts +1 -0
- package/dist/site-data.d.ts +178 -0
- package/dist/site-document.d.ts +5 -0
- package/dist/site-document.js +20 -0
- package/dist/site-document.js.map +1 -0
- package/dist/site-document.test.d.ts +1 -0
- package/dist/site-http.d.ts +17 -0
- package/dist/site-sql.d.ts +31 -0
- package/dist/site-tool-bridge.d.ts +57 -0
- package/dist/site.d.ts +182 -0
- package/dist/site.js +62 -0
- package/dist/site.js.map +1 -0
- package/dist/skills.d.ts +75 -0
- package/dist/sse.d.ts +1 -1
- package/dist/stream.d.ts +2 -0
- package/dist/tenant-workspaces.d.ts +47 -0
- package/dist/tenant-workspaces.js +8 -0
- package/dist/tenant-workspaces.js.map +1 -0
- package/dist/tool-auth.d.ts +87 -0
- package/dist/tool-auth.js +23 -0
- package/dist/tool-auth.js.map +1 -0
- package/dist/tool-display-metadata.d.ts +3 -0
- package/dist/tools-37DCTCNZ.js +12 -0
- package/dist/tools-37DCTCNZ.js.map +1 -0
- package/dist/tools.d.ts +81 -0
- package/dist/transcription.d.ts +1 -1
- package/dist/types.d.ts +2848 -573
- package/dist/usage-allowances.d.ts +36 -0
- package/dist/usage-allowances.js +80 -0
- package/dist/usage-allowances.js.map +1 -0
- package/dist/vault-types.d.ts +236 -0
- package/dist/vaults-api.d.ts +57 -0
- package/dist/workspace-artifacts.d.ts +47 -5
- package/dist/workspace-instruction-policies.d.ts +2 -2
- package/dist/workspace-integrations.d.ts +74 -0
- package/dist/workspace-integrations.js +65 -0
- package/dist/workspace-integrations.js.map +1 -0
- package/dist/workspace-state.d.ts +8 -71
- package/package.json +99 -5
- package/src/accounts.ts +18 -0
- package/src/adapters/express.ts +136 -0
- package/src/adapters/hono.ts +18 -0
- package/src/adapters/next.ts +42 -0
- package/src/allowance-refusal.ts +5 -0
- package/src/app-links.ts +117 -0
- package/src/artifact-catalog.ts +51 -0
- package/src/artifact-client.ts +40 -49
- package/src/artifacts.ts +1 -0
- package/src/automations-client.ts +8 -2
- package/src/azure-live-transport.ts +286 -0
- package/src/browser.ts +37 -0
- package/src/chat/fold.ts +431 -0
- package/src/chat/handler.ts +240 -0
- package/src/chat/http.ts +257 -0
- package/src/chat/ids.ts +85 -0
- package/src/chat/index.ts +88 -0
- package/src/chat/openai.ts +439 -0
- package/src/chat/opengeni.ts +737 -0
- package/src/chat/types.ts +219 -0
- package/src/chat/vercel.ts +204 -0
- package/src/chats.ts +16 -0
- package/src/client.ts +5822 -1847
- package/src/codex-realtime-controller.ts +163 -8
- package/src/codex-realtime-v3-wire.ts +4 -3
- package/src/codex-realtime-v3.ts +12 -3
- package/src/codex-realtime.ts +11 -3
- package/src/company-brain.ts +0 -40
- package/src/company-profile.ts +13 -0
- package/src/core.ts +20 -0
- package/src/deprecation.ts +149 -0
- package/src/document-authority-client.ts +104 -1
- package/src/editable-artifacts/controller.ts +36 -2
- package/src/editable-artifacts/index.ts +1 -0
- package/src/editable-artifacts/types.ts +29 -16
- package/src/embedding-client.ts +519 -0
- package/src/errors.ts +303 -4
- package/src/feedback.ts +20 -0
- package/src/gateway-realtime-transport.ts +3 -3
- package/src/github-repositories.ts +60 -0
- package/src/index.ts +611 -64
- package/src/insights-usage.ts +61 -0
- package/src/interaction.ts +274 -93
- package/src/knowledge.ts +72 -0
- package/src/known-tools.ts +279 -0
- package/src/message-links.ts +178 -0
- package/src/model-context.ts +113 -0
- package/src/model-display.ts +11 -0
- package/src/model-picker-order.ts +6 -0
- package/src/organization-integration-policy.ts +54 -0
- package/src/pr-review-client.ts +1 -1
- package/src/pr-review.ts +1 -1
- package/src/preference-registry.ts +2 -0
- package/src/prepared-mcp-setup.ts +123 -0
- package/src/proxy.ts +23 -12
- package/src/realtime.ts +16 -6
- package/src/session-history-import.ts +84 -0
- package/src/session-list-entries.ts +1 -0
- package/src/session-message-search.ts +47 -0
- package/src/session-proxy-client.ts +68 -0
- package/src/session-proxy.ts +2098 -0
- package/src/session-titles.ts +10 -0
- package/src/session-usage-limits.ts +71 -0
- package/src/shared-catalog-loader.ts +169 -0
- package/src/site-bridge-host.ts +422 -0
- package/src/site-browser-entry.ts +6 -0
- package/src/site-browser-runtime.gen.ts +2 -0
- package/src/site-data.ts +372 -0
- package/src/site-document.test.ts +64 -0
- package/src/site-document.ts +18 -0
- package/src/site-http.ts +171 -0
- package/src/site-sql.ts +153 -0
- package/src/site-tool-bridge.ts +401 -0
- package/src/site.ts +867 -0
- package/src/skills.ts +69 -0
- package/src/sse.ts +9 -3
- package/src/stream.ts +33 -10
- package/src/tenant-workspaces.ts +148 -0
- package/src/tool-auth.ts +301 -0
- package/src/tool-display-metadata.ts +27 -0
- package/src/tools.ts +452 -0
- package/src/transcription.ts +3 -0
- package/src/types.ts +3216 -581
- package/src/usage-allowances.ts +189 -0
- package/src/vault-types.ts +293 -0
- package/src/vaults-api.ts +288 -0
- package/src/workspace-artifacts.ts +55 -6
- package/src/workspace-instruction-policies.ts +2 -1
- package/src/workspace-integrations.ts +402 -0
- package/src/workspace-state.ts +8 -82
- package/dist/chunk-7ZXBPJZP.js.map +0 -1
- package/dist/chunk-C2H7HBNP.js.map +0 -1
- package/dist/chunk-C4DJPZRU.js +0 -119
- package/dist/chunk-C4DJPZRU.js.map +0 -1
- package/dist/chunk-GW3EJ2GP.js.map +0 -1
- package/dist/chunk-TX3EIENU.js.map +0 -1
- package/dist/chunk-VUQZAB3O.js.map +0 -1
- package/dist/chunk-VYCTL62C.js.map +0 -1
- package/dist/chunk-YTAWBDO2.js.map +0 -1
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import type { FetchLike } from "../client.js";
|
|
2
|
+
import type { Chats } from "../chats.js";
|
|
3
|
+
import type { WorkspaceIdResolverOptions } from "../tenant-workspaces.js";
|
|
4
|
+
import type { CreateSessionRequest, AgentConfigRequest, HumanInputAnswer, LatencyMode, ReasoningEffort, SessionEvent, Session, SessionSkill, ToolRef } from "../types.js";
|
|
5
|
+
/** Which other sessions the agent may reach from this one. */
|
|
6
|
+
export type ChatAgentAccess = "session" | "user" | "workspace";
|
|
7
|
+
/**
|
|
8
|
+
* Compatibility option for personal or workspace Knowledge. `false` initializes
|
|
9
|
+
* Knowledge authoring to Off; authorized retrieval remains available. Omitted
|
|
10
|
+
* follows `chats`: private with a user, or legacy reach-based defaults without one.
|
|
11
|
+
* Task notes cover temporary session-tree data.
|
|
12
|
+
*/
|
|
13
|
+
export type ChatMemory = "user" | "workspace" | false;
|
|
14
|
+
export type OpenGeniOptions = {
|
|
15
|
+
/** Organization API key. Keep it on the server. */
|
|
16
|
+
apiKey: string;
|
|
17
|
+
/**
|
|
18
|
+
* The organization (account) id that owns every workspace. Optional: when
|
|
19
|
+
* omitted it is read once from the API key.
|
|
20
|
+
*/
|
|
21
|
+
organizationId?: string | undefined;
|
|
22
|
+
/** Defaults to `https://app.opengeni.ai`. */
|
|
23
|
+
baseUrl?: string | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* The product identity used as the external-source label for tenant
|
|
26
|
+
* workspaces and end users. Defaults to `"app"`.
|
|
27
|
+
*/
|
|
28
|
+
source?: string | undefined;
|
|
29
|
+
fetch?: FetchLike | undefined;
|
|
30
|
+
/** Display name for a tenant workspace created on first use. Defaults to the tenant id. */
|
|
31
|
+
workspaceName?: ((tenant: string) => string) | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Per-user workspaces only (`{ user }` alone, or `chats: "isolated"`):
|
|
34
|
+
* permissions for the one owner the SDK adds explicitly. Tenant workspaces
|
|
35
|
+
* rely on Opengeni, which adds a user on their first request. Both default
|
|
36
|
+
* to workspace read, session create/read/control (including sending
|
|
37
|
+
* messages), file upload/read, and per-session MCP attachment; no admin
|
|
38
|
+
* permissions. Never updates an existing membership: use
|
|
39
|
+
* `client.updateExternalWorkspaceMember` for that.
|
|
40
|
+
*/
|
|
41
|
+
memberPermissions?: WorkspaceIdResolverOptions["memberPermissions"];
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Which workspace, in your own ids: `tenant` (one workspace per tenant),
|
|
45
|
+
* neither (the `user`'s own workspace), or an explicit `workspaceId`.
|
|
46
|
+
*/
|
|
47
|
+
export type ChatTarget = {
|
|
48
|
+
tenant: string;
|
|
49
|
+
workspaceId?: undefined;
|
|
50
|
+
} | {
|
|
51
|
+
workspaceId: string;
|
|
52
|
+
tenant?: undefined;
|
|
53
|
+
} | {
|
|
54
|
+
user: string;
|
|
55
|
+
tenant?: undefined;
|
|
56
|
+
workspaceId?: undefined;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* A workspace in your own ids, for `og.workspaceId(...)`: `{ tenant }` (one
|
|
60
|
+
* workspace per tenant), `{ user }` (one workspace per user), or
|
|
61
|
+
* `{ workspaceId }`. Precedence: workspaceId, then tenant, then user.
|
|
62
|
+
*/
|
|
63
|
+
export type WorkspaceTarget = {
|
|
64
|
+
tenant?: string | undefined;
|
|
65
|
+
user?: string | undefined;
|
|
66
|
+
workspaceId?: string | undefined;
|
|
67
|
+
};
|
|
68
|
+
export type ChatOptions = ChatTarget & {
|
|
69
|
+
/**
|
|
70
|
+
* Host-authenticated external user; resolved through server-side asUser().
|
|
71
|
+
* Without a tenant or workspaceId, the user gets one workspace of their own.
|
|
72
|
+
*/
|
|
73
|
+
user?: string | undefined;
|
|
74
|
+
/** Stable conversation id; the session id is derived from it deterministically. */
|
|
75
|
+
conversation: string;
|
|
76
|
+
/** Prefer the actual Opengeni session ID for shared or existing conversations.
|
|
77
|
+
* The acting user is independent of the conversation's identity. */
|
|
78
|
+
sessionId?: string | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Private (default with a user) uses personal Knowledge and session-only reach;
|
|
81
|
+
* shared uses workspace Knowledge/reach, isolated adds a workspace per tenant/user.
|
|
82
|
+
* Without a user, omission keeps workspace visibility, session reach and Knowledge off.
|
|
83
|
+
*/
|
|
84
|
+
chats?: Chats | undefined;
|
|
85
|
+
/** Agent identity, capabilities and instructions; implicit markdown falls back on older servers. */
|
|
86
|
+
agent?: AgentConfigRequest | undefined;
|
|
87
|
+
/** Explicit agent reach overrides the `chats` default. */
|
|
88
|
+
agentAccess?: ChatAgentAccess | undefined;
|
|
89
|
+
memory?: ChatMemory | undefined;
|
|
90
|
+
model?: string | undefined;
|
|
91
|
+
instructions?: string | undefined;
|
|
92
|
+
skills?: SessionSkill[] | undefined;
|
|
93
|
+
tools?: ToolRef[] | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Raw create-request passthrough (for example `sandboxBackend: "none"` for a
|
|
96
|
+
* pure chat). Explicit values win over facade-derived ones; the message and
|
|
97
|
+
* identity/idempotency fields always come from the facade.
|
|
98
|
+
*/
|
|
99
|
+
create?: Partial<CreateSessionRequest> | undefined;
|
|
100
|
+
};
|
|
101
|
+
/** A turn stopped to wait for a human decision. */
|
|
102
|
+
export type ChatPending = {
|
|
103
|
+
kind: "approval" | "human_input";
|
|
104
|
+
/** The id to pass back through `chat.respond`. */
|
|
105
|
+
requestId: string;
|
|
106
|
+
/** Tool name for an approval; null for structured human input. */
|
|
107
|
+
name: string | null;
|
|
108
|
+
/** The producer's exact payload (approval entry or human-input request). */
|
|
109
|
+
payload: unknown;
|
|
110
|
+
};
|
|
111
|
+
export type ChatReplyStatus = "completed" | "pending" | "cancelled";
|
|
112
|
+
export type ChatReply = {
|
|
113
|
+
text: string;
|
|
114
|
+
sessionId: string;
|
|
115
|
+
workspaceId: string;
|
|
116
|
+
turnId: string | null;
|
|
117
|
+
/** `pending` waits on `chat.respond`; `cancelled` carries the text produced before the cancel. */
|
|
118
|
+
status: ChatReplyStatus;
|
|
119
|
+
/** Set when the turn is waiting on `chat.respond` instead of finished. */
|
|
120
|
+
pending: ChatPending | null;
|
|
121
|
+
/** A non-destructive completion without a model-authored final answer. */
|
|
122
|
+
emptyFinalReply?: true;
|
|
123
|
+
/** Display this informational notice when emptyFinalReply is present. */
|
|
124
|
+
notice?: string;
|
|
125
|
+
/** Every event consumed while folding this turn. */
|
|
126
|
+
events: SessionEvent[];
|
|
127
|
+
toString(): string;
|
|
128
|
+
};
|
|
129
|
+
export type ChatToolStatus = "started" | "completed" | "failed";
|
|
130
|
+
export type ChatChunk = {
|
|
131
|
+
type: "text";
|
|
132
|
+
text: string;
|
|
133
|
+
} | {
|
|
134
|
+
type: "tool";
|
|
135
|
+
name: string;
|
|
136
|
+
status: ChatToolStatus;
|
|
137
|
+
callId?: string | undefined;
|
|
138
|
+
input?: unknown;
|
|
139
|
+
} | {
|
|
140
|
+
type: "pending";
|
|
141
|
+
pending: ChatPending;
|
|
142
|
+
} | {
|
|
143
|
+
type: "done";
|
|
144
|
+
reply: ChatReply;
|
|
145
|
+
};
|
|
146
|
+
export type ChatMessage = {
|
|
147
|
+
role: "user" | "assistant";
|
|
148
|
+
text: string;
|
|
149
|
+
sequence: number;
|
|
150
|
+
};
|
|
151
|
+
/** Durable text and unresolved decisions restored when a chat is reopened. */
|
|
152
|
+
export type ChatSnapshot = {
|
|
153
|
+
messages: ChatMessage[];
|
|
154
|
+
pending: ChatPending[];
|
|
155
|
+
status: Session["status"] | null;
|
|
156
|
+
};
|
|
157
|
+
export type ChatRespondInput = {
|
|
158
|
+
requestId: string;
|
|
159
|
+
decision: "approve" | "reject";
|
|
160
|
+
message?: string | undefined;
|
|
161
|
+
} | {
|
|
162
|
+
requestId: string;
|
|
163
|
+
answers: HumanInputAnswer[];
|
|
164
|
+
} | {
|
|
165
|
+
requestId: string;
|
|
166
|
+
skip: true;
|
|
167
|
+
};
|
|
168
|
+
/** One earlier message from the product's own history, imported as context on the first send. */
|
|
169
|
+
export type ChatImportedMessage = {
|
|
170
|
+
role: "user" | "assistant" | "system";
|
|
171
|
+
text: string;
|
|
172
|
+
};
|
|
173
|
+
export type ChatSendOptions = {
|
|
174
|
+
signal?: AbortSignal | undefined;
|
|
175
|
+
/** Supersede the current inference instead of queueing behind it. */
|
|
176
|
+
steer?: boolean | undefined;
|
|
177
|
+
/**
|
|
178
|
+
* Earlier messages the product already holds, oldest first. Used only when
|
|
179
|
+
* this send creates the session: they become the first message's
|
|
180
|
+
* `modelContext` (skipped when `create.modelContext` was supplied), trimmed
|
|
181
|
+
* from the oldest end to 30,000 characters. Never resent on later turns:
|
|
182
|
+
* after the first message Opengeni owns the history.
|
|
183
|
+
*/
|
|
184
|
+
importedHistory?: ChatImportedMessage[] | undefined;
|
|
185
|
+
/** Model for this message's turn; omitted keeps the session's current policy. */
|
|
186
|
+
model?: string | undefined;
|
|
187
|
+
reasoningEffort?: ReasoningEffort | undefined;
|
|
188
|
+
latencyMode?: LatencyMode | undefined;
|
|
189
|
+
/**
|
|
190
|
+
* Model-visible application context for this one message (for example the
|
|
191
|
+
* page or record the user is looking at). Not shown in the transcript and not
|
|
192
|
+
* secret. On the creating message it is combined with imported history.
|
|
193
|
+
*/
|
|
194
|
+
modelContext?: string | undefined;
|
|
195
|
+
};
|
|
196
|
+
export type ChatSessionListOptions = ChatTarget & {
|
|
197
|
+
user?: string | undefined;
|
|
198
|
+
/** Match the chat's mode; isolated lists that user's separate workspace. */
|
|
199
|
+
chats?: Chats | undefined;
|
|
200
|
+
limit?: number | undefined;
|
|
201
|
+
};
|
|
202
|
+
/** A turn ended without a usable reply, or the facade was misused. */
|
|
203
|
+
export declare class OpenGeniChatError extends Error {
|
|
204
|
+
readonly code: string;
|
|
205
|
+
readonly event: SessionEvent | null;
|
|
206
|
+
constructor(code: string, message: string, event?: SessionEvent | null);
|
|
207
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type ChatResolve } from "./http.js";
|
|
2
|
+
import type { Opengeni } from "./opengeni.js";
|
|
3
|
+
import type { ChatChunk } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Vercel AI SDK UI message stream (protocol v1, as consumed by `useChat` with
|
|
6
|
+
* the default transport in AI SDK 5, 6, and 7; approval requests need 6+).
|
|
7
|
+
* Parts are `data: <json>` SSE
|
|
8
|
+
* lines terminated by `data: [DONE]`, under the
|
|
9
|
+
* `x-vercel-ai-ui-message-stream: v1` header.
|
|
10
|
+
*/
|
|
11
|
+
export declare const UI_MESSAGE_STREAM_HEADER = "x-vercel-ai-ui-message-stream";
|
|
12
|
+
export declare const UI_MESSAGE_STREAM_VERSION = "v1";
|
|
13
|
+
export type UIMessageStreamOptions = {
|
|
14
|
+
/** Assistant message id announced in the `start` part. Defaults to a random UUID. */
|
|
15
|
+
messageId?: string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Emit Opengeni's own tool activity as tool parts. Off by default: those
|
|
18
|
+
* tools are not in the app's typed tool set. When on, parts are marked
|
|
19
|
+
* `dynamic` and `providerExecuted`, so `useChat` renders them as
|
|
20
|
+
* `dynamic-tool` parts and never tries to execute them. Approval requests
|
|
21
|
+
* are always emitted (as dynamic tool parts) because answering them is part
|
|
22
|
+
* of the conversation.
|
|
23
|
+
*/
|
|
24
|
+
toolParts?: boolean | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Emit the `start` / `start-step` / `finish-step` / `finish` framing. Set to
|
|
27
|
+
* false when writing into an existing AI SDK stream that owns its framing
|
|
28
|
+
* (for example `createUIMessageStream({ execute: ({ writer }) => ... })`).
|
|
29
|
+
* Defaults to true.
|
|
30
|
+
*/
|
|
31
|
+
framing?: boolean | undefined;
|
|
32
|
+
};
|
|
33
|
+
/** Protocol parts for one reply, in order. */
|
|
34
|
+
export declare function uiMessageStreamParts(chunks: AsyncIterable<ChatChunk>, options?: UIMessageStreamOptions): AsyncGenerator<Record<string, unknown>, void, void>;
|
|
35
|
+
export declare function uiMessageStreamBlocks(chunks: AsyncIterable<ChatChunk>, options?: UIMessageStreamOptions): AsyncGenerator<string, void, void>;
|
|
36
|
+
export declare function chatChunksToUIMessageStream(chunks: AsyncIterable<ChatChunk>, options?: UIMessageStreamOptions & {
|
|
37
|
+
onCancel?: (() => void) | undefined;
|
|
38
|
+
}): ReadableStream<Uint8Array>;
|
|
39
|
+
export declare function uiMessageStreamResponse(chunks: AsyncIterable<ChatChunk>, options?: UIMessageStreamOptions): Response;
|
|
40
|
+
/** Text of the last user `UIMessage` (`parts` of type `text`, joined). */
|
|
41
|
+
export declare function lastUIMessageText(messages: unknown): string | null;
|
|
42
|
+
/**
|
|
43
|
+
* `useChat` request handler: body `{ id, messages, trigger, messageId }`.
|
|
44
|
+
* Conversation: the host's `resolve`, else the `x-opengeni-conversation`
|
|
45
|
+
* header, else the chat `id`. Only the last user message is sent; the
|
|
46
|
+
* messages before it are imported once as context when this request creates
|
|
47
|
+
* the session. `regenerate-message` steers instead of queueing.
|
|
48
|
+
*/
|
|
49
|
+
export declare function handleVercelChatRequest(og: Opengeni, request: Request, resolve: ChatResolve, options?: Pick<UIMessageStreamOptions, "toolParts">): Promise<Response>;
|
package/dist/chats.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CreateSessionRequest } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Private chats use personal Knowledge and session-only agent reach; shared chats
|
|
4
|
+
* use workspace Knowledge and reach. Isolated adds a separate workspace per user.
|
|
5
|
+
*/
|
|
6
|
+
export type Chats = "private" | "shared" | "isolated";
|
|
7
|
+
/** SDK defaults only: the API still authorizes visibility, agent reach and Knowledge separately. */
|
|
8
|
+
export declare function chatDefaults(chats: Chats): Required<Pick<CreateSessionRequest, "visibility" | "agentAccess" | "memoryScope">>;
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OpenGeniStreamError,
|
|
3
|
+
isAbortError,
|
|
4
|
+
isRetryableStreamError
|
|
5
|
+
} from "./chunk-7EWT3PV6.js";
|
|
6
|
+
|
|
7
|
+
// src/sse.ts
|
|
8
|
+
async function* parseSseStream(stream) {
|
|
9
|
+
const reader = stream.getReader();
|
|
10
|
+
const decoder = new TextDecoder();
|
|
11
|
+
let buffer = "";
|
|
12
|
+
let id;
|
|
13
|
+
let event;
|
|
14
|
+
let dataLines = null;
|
|
15
|
+
const dispatch = () => {
|
|
16
|
+
const message = dataLines === null ? null : {
|
|
17
|
+
...id !== void 0 ? { id } : {},
|
|
18
|
+
...event !== void 0 ? { event } : {},
|
|
19
|
+
data: dataLines.join("\n")
|
|
20
|
+
};
|
|
21
|
+
id = void 0;
|
|
22
|
+
event = void 0;
|
|
23
|
+
dataLines = null;
|
|
24
|
+
return message;
|
|
25
|
+
};
|
|
26
|
+
const handleLine = (line) => {
|
|
27
|
+
if (line === "") {
|
|
28
|
+
return dispatch();
|
|
29
|
+
}
|
|
30
|
+
if (line.startsWith(":")) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const colon = line.indexOf(":");
|
|
34
|
+
const field = colon === -1 ? line : line.slice(0, colon);
|
|
35
|
+
let value = colon === -1 ? "" : line.slice(colon + 1);
|
|
36
|
+
if (value.startsWith(" ")) {
|
|
37
|
+
value = value.slice(1);
|
|
38
|
+
}
|
|
39
|
+
if (field === "data") {
|
|
40
|
+
(dataLines ??= []).push(value);
|
|
41
|
+
} else if (field === "event") {
|
|
42
|
+
event = value;
|
|
43
|
+
} else if (field === "id") {
|
|
44
|
+
id = value;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
};
|
|
48
|
+
try {
|
|
49
|
+
while (true) {
|
|
50
|
+
const { done, value } = await reader.read();
|
|
51
|
+
if (done) {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
buffer += decoder.decode(value, { stream: true });
|
|
55
|
+
let newline = buffer.indexOf("\n");
|
|
56
|
+
while (newline !== -1) {
|
|
57
|
+
let line = buffer.slice(0, newline);
|
|
58
|
+
buffer = buffer.slice(newline + 1);
|
|
59
|
+
if (line.endsWith("\r")) {
|
|
60
|
+
line = line.slice(0, -1);
|
|
61
|
+
}
|
|
62
|
+
const message = handleLine(line);
|
|
63
|
+
if (message) {
|
|
64
|
+
yield message;
|
|
65
|
+
}
|
|
66
|
+
newline = buffer.indexOf("\n");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} finally {
|
|
70
|
+
void reader.cancel().catch(() => {
|
|
71
|
+
});
|
|
72
|
+
try {
|
|
73
|
+
reader.releaseLock();
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/stream.ts
|
|
80
|
+
var SESSION_EVENT_STREAM_COVERAGE = Symbol.for(
|
|
81
|
+
"@opengeni/sdk/session-event-stream-covered-through"
|
|
82
|
+
);
|
|
83
|
+
async function* streamSessionEvents(transport, options = {}) {
|
|
84
|
+
const signal = options.signal;
|
|
85
|
+
const reconnect = options.reconnect ?? true;
|
|
86
|
+
const baseDelayMs = options.reconnectDelayMs ?? 500;
|
|
87
|
+
const maxDelayMs = options.maxReconnectDelayMs ?? 1e4;
|
|
88
|
+
const jitterRatio = options.reconnectJitterRatio ?? 0.2;
|
|
89
|
+
const beforeLiveTimeoutMs = options.beforeLiveTimeoutMs ?? 15e3;
|
|
90
|
+
const heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? 45e3;
|
|
91
|
+
const maxAttempts = options.maxReconnectAttempts ?? Number.POSITIVE_INFINITY;
|
|
92
|
+
let cursor = options.after ?? 0;
|
|
93
|
+
let failedAttempts = 0;
|
|
94
|
+
let delayMs = baseDelayMs;
|
|
95
|
+
let everConnected = false;
|
|
96
|
+
while (true) {
|
|
97
|
+
if (signal?.aborted) break;
|
|
98
|
+
options.onStateChange?.(everConnected || failedAttempts > 0 ? "reconnecting" : "connecting");
|
|
99
|
+
const cursorAtOpen = cursor;
|
|
100
|
+
try {
|
|
101
|
+
const body = await transport.openStream(cursor, signal);
|
|
102
|
+
everConnected = true;
|
|
103
|
+
failedAttempts = 0;
|
|
104
|
+
delayMs = baseDelayMs;
|
|
105
|
+
try {
|
|
106
|
+
options.onOpen?.();
|
|
107
|
+
} catch {
|
|
108
|
+
}
|
|
109
|
+
await runBeforeLive(options.beforeLive, beforeLiveTimeoutMs, signal);
|
|
110
|
+
options.onStateChange?.("live");
|
|
111
|
+
for await (const message of parseSseStream(
|
|
112
|
+
withStreamInactivityTimeout(body, heartbeatTimeoutMs, signal)
|
|
113
|
+
)) {
|
|
114
|
+
if (signal?.aborted) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const event = parseSessionEvent(message.data);
|
|
118
|
+
if (!event) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const coveredSequence = trustedSseSequence(message.id, event.sequence);
|
|
122
|
+
markSessionEventStreamCoverage(event, coveredSequence);
|
|
123
|
+
if (coveredSequence <= cursor) continue;
|
|
124
|
+
if (event.sequence > cursor + 1) {
|
|
125
|
+
for await (const missed of backfillEvents(transport, cursor, event.sequence - 1)) {
|
|
126
|
+
cursor = missed.sequence;
|
|
127
|
+
yield missed;
|
|
128
|
+
if (signal?.aborted) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
cursor = coveredSequence;
|
|
134
|
+
yield event;
|
|
135
|
+
}
|
|
136
|
+
if (!reconnect) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (cursor === cursorAtOpen) {
|
|
140
|
+
await sleep(jitteredDelay(baseDelayMs, jitterRatio), signal);
|
|
141
|
+
}
|
|
142
|
+
continue;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
if (signal?.aborted || isAbortError(error)) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (!reconnect || !isRetryableStreamError(error)) {
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
failedAttempts += 1;
|
|
151
|
+
if (failedAttempts > maxAttempts) {
|
|
152
|
+
throw new OpenGeniStreamError(
|
|
153
|
+
`event stream gave up after ${maxAttempts} consecutive failed reconnect attempts: ${error instanceof Error ? error.message : String(error)}`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
await sleep(jitteredDelay(delayMs, jitterRatio), signal);
|
|
158
|
+
delayMs = Math.min(Math.max(delayMs * 2, baseDelayMs), maxDelayMs);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function runBeforeLive(beforeLive, timeoutMs, signal) {
|
|
162
|
+
if (!beforeLive) return;
|
|
163
|
+
let timer;
|
|
164
|
+
let abortListener;
|
|
165
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
166
|
+
timer = setTimeout(
|
|
167
|
+
() => reject(new TypeError(`stream reconciliation timed out after ${timeoutMs}ms`)),
|
|
168
|
+
timeoutMs
|
|
169
|
+
);
|
|
170
|
+
if (signal) {
|
|
171
|
+
abortListener = () => reject(new DOMException("Aborted", "AbortError"));
|
|
172
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
try {
|
|
176
|
+
await Promise.race([Promise.resolve().then(beforeLive), timeout]);
|
|
177
|
+
} finally {
|
|
178
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
179
|
+
if (signal && abortListener) signal.removeEventListener("abort", abortListener);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function jitteredDelay(delayMs, ratio) {
|
|
183
|
+
if (delayMs <= 0 || ratio <= 0) return delayMs;
|
|
184
|
+
const boundedRatio = Math.min(ratio, 1);
|
|
185
|
+
const spread = delayMs * boundedRatio;
|
|
186
|
+
return Math.max(0, delayMs - spread + Math.random() * spread * 2);
|
|
187
|
+
}
|
|
188
|
+
function withStreamInactivityTimeout(stream, timeoutMs, signal) {
|
|
189
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0) {
|
|
190
|
+
throw new RangeError("stream heartbeat timeout must be a positive safe integer");
|
|
191
|
+
}
|
|
192
|
+
const reader = stream.getReader();
|
|
193
|
+
return new ReadableStream({
|
|
194
|
+
pull: async (controller) => {
|
|
195
|
+
let timer;
|
|
196
|
+
let abortListener;
|
|
197
|
+
try {
|
|
198
|
+
const result = await Promise.race([
|
|
199
|
+
reader.read(),
|
|
200
|
+
new Promise((_resolve, reject) => {
|
|
201
|
+
timer = setTimeout(
|
|
202
|
+
() => reject(new TypeError(`event stream heartbeat timed out after ${timeoutMs}ms`)),
|
|
203
|
+
timeoutMs
|
|
204
|
+
);
|
|
205
|
+
if (signal) {
|
|
206
|
+
abortListener = () => reject(new DOMException("Aborted", "AbortError"));
|
|
207
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
208
|
+
}
|
|
209
|
+
})
|
|
210
|
+
]);
|
|
211
|
+
if (result.done) controller.close();
|
|
212
|
+
else controller.enqueue(result.value);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
void reader.cancel(error).catch(() => {
|
|
215
|
+
});
|
|
216
|
+
controller.error(error);
|
|
217
|
+
} finally {
|
|
218
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
219
|
+
if (signal && abortListener) signal.removeEventListener("abort", abortListener);
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
cancel: (reason) => {
|
|
223
|
+
void reader.cancel(reason).catch(() => {
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
async function* backfillEvents(transport, fromExclusive, toInclusive) {
|
|
229
|
+
let cursor = fromExclusive;
|
|
230
|
+
while (cursor < toInclusive) {
|
|
231
|
+
const page = await transport.listEvents(cursor, Math.min(500, toInclusive - cursor));
|
|
232
|
+
const advancing = page.filter((event) => event.sequence > cursor && event.sequence <= toInclusive).sort((a, b) => a.sequence - b.sequence);
|
|
233
|
+
if (advancing.length === 0) {
|
|
234
|
+
throw new OpenGeniStreamError(
|
|
235
|
+
`event replay backfill stalled: expected sequences ${cursor + 1}..${toInclusive} but the replay endpoint returned none of them`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
for (const event of advancing) {
|
|
239
|
+
if (event.sequence !== cursor + 1) {
|
|
240
|
+
throw new OpenGeniStreamError(
|
|
241
|
+
`event replay backfill is missing sequence ${cursor + 1} (replay endpoint skipped to ${event.sequence}); refusing to deliver with a gap`
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
cursor = event.sequence;
|
|
245
|
+
yield event;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function parseSessionEvent(data) {
|
|
250
|
+
let parsed;
|
|
251
|
+
try {
|
|
252
|
+
parsed = JSON.parse(data);
|
|
253
|
+
} catch {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
if (typeof parsed !== "object" || parsed === null || typeof parsed.sequence !== "number" || typeof parsed.type !== "string" || typeof parsed.id !== "string") {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
return parsed;
|
|
260
|
+
}
|
|
261
|
+
function sessionEventStreamCoveredThrough(event) {
|
|
262
|
+
const covered = event[SESSION_EVENT_STREAM_COVERAGE];
|
|
263
|
+
return typeof covered === "number" && Number.isSafeInteger(covered) && covered >= event.sequence ? covered : null;
|
|
264
|
+
}
|
|
265
|
+
function trustedSseSequence(id, sequence) {
|
|
266
|
+
if (id === void 0 || !/^\d+$/.test(id)) return sequence;
|
|
267
|
+
const covered = Number(id);
|
|
268
|
+
return Number.isSafeInteger(covered) && covered >= sequence ? covered : sequence;
|
|
269
|
+
}
|
|
270
|
+
function markSessionEventStreamCoverage(event, covered) {
|
|
271
|
+
Object.defineProperty(event, SESSION_EVENT_STREAM_COVERAGE, {
|
|
272
|
+
value: covered,
|
|
273
|
+
enumerable: false,
|
|
274
|
+
configurable: false,
|
|
275
|
+
writable: false
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
async function sleep(delayMs, signal) {
|
|
279
|
+
if (signal?.aborted || delayMs <= 0) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
await new Promise((resolve) => {
|
|
283
|
+
const timer = setTimeout(done, delayMs);
|
|
284
|
+
function done() {
|
|
285
|
+
clearTimeout(timer);
|
|
286
|
+
signal?.removeEventListener("abort", done);
|
|
287
|
+
resolve();
|
|
288
|
+
}
|
|
289
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export {
|
|
294
|
+
parseSseStream,
|
|
295
|
+
streamSessionEvents,
|
|
296
|
+
runBeforeLive,
|
|
297
|
+
jitteredDelay,
|
|
298
|
+
withStreamInactivityTimeout,
|
|
299
|
+
sessionEventStreamCoveredThrough
|
|
300
|
+
};
|
|
301
|
+
//# sourceMappingURL=chunk-4AHR4KGA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sse.ts","../src/stream.ts"],"sourcesContent":["/**\n * Minimal incremental Server-Sent Events parser over a byte stream.\n *\n * Implements the parts of the SSE wire format Opengeni uses: `id`, `event`,\n * and `data` fields, multi-line data, comment lines, and both LF and CRLF\n * line endings. Messages without any `data` (comments, id-only blocks) are\n * not emitted.\n */\nexport type SseMessage = {\n id?: string;\n event?: string;\n data: string;\n};\n\nexport async function* parseSseStream(\n stream: ReadableStream<Uint8Array>,\n): AsyncGenerator<SseMessage, void, void> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let id: string | undefined;\n let event: string | undefined;\n let dataLines: string[] | null = null;\n\n const dispatch = (): SseMessage | null => {\n const message =\n dataLines === null\n ? null\n : {\n ...(id !== undefined ? { id } : {}),\n ...(event !== undefined ? { event } : {}),\n data: dataLines.join(\"\\n\"),\n };\n id = undefined;\n event = undefined;\n dataLines = null;\n return message;\n };\n\n const handleLine = (line: string): SseMessage | null => {\n if (line === \"\") {\n return dispatch();\n }\n if (line.startsWith(\":\")) {\n return null;\n }\n const colon = line.indexOf(\":\");\n const field = colon === -1 ? line : line.slice(0, colon);\n let value = colon === -1 ? \"\" : line.slice(colon + 1);\n if (value.startsWith(\" \")) {\n value = value.slice(1);\n }\n if (field === \"data\") {\n (dataLines ??= []).push(value);\n } else if (field === \"event\") {\n event = value;\n } else if (field === \"id\") {\n id = value;\n }\n // Other fields (e.g. `retry`) are ignored; reconnect pacing is the\n // streaming layer's concern.\n return null;\n };\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n buffer += decoder.decode(value, { stream: true });\n let newline = buffer.indexOf(\"\\n\");\n while (newline !== -1) {\n let line = buffer.slice(0, newline);\n buffer = buffer.slice(newline + 1);\n if (line.endsWith(\"\\r\")) {\n line = line.slice(0, -1);\n }\n const message = handleLine(line);\n if (message) {\n yield message;\n }\n newline = buffer.indexOf(\"\\n\");\n }\n }\n // Per the SSE spec, a block is only dispatched on a blank line. Anything\n // still pending at end-of-stream came from a truncated connection and is\n // discarded — the streaming layer replays from its cursor on reconnect.\n } finally {\n // Never await cancel(): some fetch bodies settle it only once their request\n // aborts, which would deadlock the consumer's unwinding.\n void reader.cancel().catch(() => {});\n try {\n reader.releaseLock();\n } catch {\n // A pending read (older stream implementations) keeps the lock; cancel releases it.\n }\n }\n}\n","import { isAbortError, isRetryableStreamError, OpenGeniStreamError } from \"./errors\";\nimport { parseSseStream } from \"./sse\";\nimport type { SessionEvent } from \"./types\";\n\nconst SESSION_EVENT_STREAM_COVERAGE = Symbol.for(\n \"@opengeni/sdk/session-event-stream-covered-through\",\n);\n\n/**\n * Transport boundary for the streaming core. The client implements it with\n * `fetch`; unit tests script it directly.\n */\nexport type SessionEventStreamTransport = {\n /** Open the SSE stream, replaying durable events after `after` first. */\n openStream: (\n after: number,\n signal: AbortSignal | undefined,\n ) => Promise<ReadableStream<Uint8Array>>;\n /** Replay durable events by sequence (`GET .../events?after=&limit=`). */\n listEvents: (after: number, limit: number) => Promise<SessionEvent[]>;\n};\n\nexport type StreamConnectionState = \"connecting\" | \"live\" | \"reconnecting\";\n\nexport type StreamSessionEventsOptions = {\n /** Resume after this sequence number (exclusive). Defaults to 0 (full replay). */\n after?: number;\n /** Aborting ends the stream gracefully (the generator returns). */\n signal?: AbortSignal;\n /** Reconnect on transient drops. Defaults to true. */\n reconnect?: boolean;\n /** Initial reconnect backoff. Defaults to 500ms. */\n reconnectDelayMs?: number;\n /** Backoff ceiling. Defaults to 10s. */\n maxReconnectDelayMs?: number;\n /** Random backoff spread as a fraction of the delay. Defaults to 0.2. */\n reconnectJitterRatio?: number;\n /**\n * Give up after this many consecutive failed reconnect attempts (i.e. N\n * reconnects = N+1 total open-stream calls). Defaults to unlimited.\n */\n maxReconnectAttempts?: number;\n /**\n * Notify the consumer as soon as the SSE response body is open. This callback\n * is deliberately synchronous and non-blocking: use it to start projection\n * reconciliation without delaying consumption of live event bytes.\n */\n onOpen?: (() => void) | undefined;\n /** Await authoritative client reconciliation before exposing `live`. */\n beforeLive?: (() => void | Promise<void>) | undefined;\n /** Maximum reconciliation time before reconnecting. Defaults to 15s. */\n beforeLiveTimeoutMs?: number;\n /** Maximum time without any SSE bytes before reconnecting. Defaults to 45s. */\n heartbeatTimeoutMs?: number;\n onStateChange?: (state: StreamConnectionState) => void;\n};\n\n/**\n * Stream a session's events with exactly-once, in-order delivery.\n *\n * Guarantees, anchored on the per-session contiguous `sequence`:\n * - **No duplicates**: events at or below the cursor are dropped, so server\n * replay overlap and reconnect overlap never re-yield.\n * - **No gaps**: each reconnect resumes from the last seen sequence, and a\n * gap observed inside one connection is backfilled from the durable replay\n * endpoint before the newer event is yielded (events are durable before\n * they are published live, so the backfill always finds them).\n * - **Ordered**: sequences are yielded strictly ascending.\n *\n * The generator ends when `signal` aborts, when the server closes and\n * `reconnect` is false, or with an error for non-retryable failures.\n */\nexport async function* streamSessionEvents(\n transport: SessionEventStreamTransport,\n options: StreamSessionEventsOptions = {},\n): AsyncGenerator<SessionEvent, void, void> {\n const signal = options.signal;\n const reconnect = options.reconnect ?? true;\n const baseDelayMs = options.reconnectDelayMs ?? 500;\n const maxDelayMs = options.maxReconnectDelayMs ?? 10_000;\n const jitterRatio = options.reconnectJitterRatio ?? 0.2;\n const beforeLiveTimeoutMs = options.beforeLiveTimeoutMs ?? 15_000;\n const heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? 45_000;\n const maxAttempts = options.maxReconnectAttempts ?? Number.POSITIVE_INFINITY;\n let cursor = options.after ?? 0;\n let failedAttempts = 0;\n let delayMs = baseDelayMs;\n let everConnected = false;\n\n while (true) {\n if (signal?.aborted) break;\n options.onStateChange?.(everConnected || failedAttempts > 0 ? \"reconnecting\" : \"connecting\");\n const cursorAtOpen = cursor;\n try {\n const body = await transport.openStream(cursor, signal);\n everConnected = true;\n failedAttempts = 0;\n delayMs = baseDelayMs;\n try {\n options.onOpen?.();\n } catch {\n // A notification observer cannot own or interrupt the event transport.\n }\n await runBeforeLive(options.beforeLive, beforeLiveTimeoutMs, signal);\n options.onStateChange?.(\"live\");\n for await (const message of parseSseStream(\n withStreamInactivityTimeout(body, heartbeatTimeoutMs, signal),\n )) {\n // Re-check after every yield resumption: an abort from the consumer\n // must not let already-buffered events keep flowing.\n if (signal?.aborted) {\n return;\n }\n const event = parseSessionEvent(message.data);\n if (!event) {\n continue;\n }\n const coveredSequence = trustedSseSequence(message.id, event.sequence);\n markSessionEventStreamCoverage(event, coveredSequence);\n if (coveredSequence <= cursor) continue;\n if (event.sequence > cursor + 1) {\n for await (const missed of backfillEvents(transport, cursor, event.sequence - 1)) {\n cursor = missed.sequence;\n yield missed;\n if (signal?.aborted) {\n return;\n }\n }\n }\n cursor = coveredSequence;\n yield event;\n }\n if (!reconnect) {\n return;\n }\n // Clean server close: reconnect immediately when the connection made\n // progress (servers legitimately cycle long SSE connections); pace\n // empty closes so a misbehaving server is not hammered in a hot loop.\n if (cursor === cursorAtOpen) {\n await sleep(jitteredDelay(baseDelayMs, jitterRatio), signal);\n }\n continue;\n } catch (error) {\n if (signal?.aborted || isAbortError(error)) {\n return;\n }\n if (!reconnect || !isRetryableStreamError(error)) {\n throw error;\n }\n failedAttempts += 1;\n if (failedAttempts > maxAttempts) {\n throw new OpenGeniStreamError(\n `event stream gave up after ${maxAttempts} consecutive failed reconnect attempts: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n await sleep(jitteredDelay(delayMs, jitterRatio), signal);\n delayMs = Math.min(Math.max(delayMs * 2, baseDelayMs), maxDelayMs);\n }\n}\n\nexport async function runBeforeLive(\n beforeLive: (() => void | Promise<void>) | undefined,\n timeoutMs: number,\n signal: AbortSignal | undefined,\n): Promise<void> {\n if (!beforeLive) return;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let abortListener: (() => void) | undefined;\n const timeout = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(\n () => reject(new TypeError(`stream reconciliation timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n if (signal) {\n abortListener = () => reject(new DOMException(\"Aborted\", \"AbortError\"));\n signal.addEventListener(\"abort\", abortListener, { once: true });\n }\n });\n try {\n await Promise.race([Promise.resolve().then(beforeLive), timeout]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n if (signal && abortListener) signal.removeEventListener(\"abort\", abortListener);\n }\n}\n\nexport function jitteredDelay(delayMs: number, ratio: number): number {\n if (delayMs <= 0 || ratio <= 0) return delayMs;\n const boundedRatio = Math.min(ratio, 1);\n const spread = delayMs * boundedRatio;\n return Math.max(0, delayMs - spread + Math.random() * spread * 2);\n}\n\nexport function withStreamInactivityTimeout(\n stream: ReadableStream<Uint8Array>,\n timeoutMs: number,\n signal: AbortSignal | undefined,\n): ReadableStream<Uint8Array> {\n if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0) {\n throw new RangeError(\"stream heartbeat timeout must be a positive safe integer\");\n }\n const reader = stream.getReader();\n return new ReadableStream<Uint8Array>({\n pull: async (controller) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let abortListener: (() => void) | undefined;\n try {\n const result = await Promise.race([\n reader.read(),\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(\n () => reject(new TypeError(`event stream heartbeat timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n if (signal) {\n abortListener = () => reject(new DOMException(\"Aborted\", \"AbortError\"));\n signal.addEventListener(\"abort\", abortListener, { once: true });\n }\n }),\n ]);\n if (result.done) controller.close();\n else controller.enqueue(result.value);\n } catch (error) {\n void reader.cancel(error).catch(() => {});\n controller.error(error);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n if (signal && abortListener) signal.removeEventListener(\"abort\", abortListener);\n }\n },\n cancel: (reason) => {\n // Do not wait for the underlying body: it may settle cancel() only after\n // its request aborts (see parseSseStream).\n void reader.cancel(reason).catch(() => {});\n },\n });\n}\n\n/**\n * Yield the durable events with `fromExclusive < sequence <= toInclusive`,\n * in order. Sequences are contiguous, so every one of them must exist in the\n * replay endpoint; if any is missing the function throws instead of skipping\n * it — continuing would silently break the gap-free delivery guarantee.\n */\nasync function* backfillEvents(\n transport: SessionEventStreamTransport,\n fromExclusive: number,\n toInclusive: number,\n): AsyncGenerator<SessionEvent, void, void> {\n let cursor = fromExclusive;\n while (cursor < toInclusive) {\n const page = await transport.listEvents(cursor, Math.min(500, toInclusive - cursor));\n const advancing = page\n .filter((event) => event.sequence > cursor && event.sequence <= toInclusive)\n .sort((a, b) => a.sequence - b.sequence);\n if (advancing.length === 0) {\n throw new OpenGeniStreamError(\n `event replay backfill stalled: expected sequences ${cursor + 1}..${toInclusive} but the replay endpoint returned none of them`,\n );\n }\n for (const event of advancing) {\n if (event.sequence !== cursor + 1) {\n throw new OpenGeniStreamError(\n `event replay backfill is missing sequence ${cursor + 1} (replay endpoint skipped to ${event.sequence}); refusing to deliver with a gap`,\n );\n }\n cursor = event.sequence;\n yield event;\n }\n }\n}\n\nfunction parseSessionEvent(data: string): SessionEvent | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(data);\n } catch {\n return null;\n }\n if (\n typeof parsed !== \"object\" ||\n parsed === null ||\n typeof (parsed as { sequence?: unknown }).sequence !== \"number\" ||\n typeof (parsed as { type?: unknown }).type !== \"string\" ||\n typeof (parsed as { id?: unknown }).id !== \"string\"\n ) {\n return null;\n }\n return parsed as SessionEvent;\n}\n\n/** Trusted SSE coverage attached non-enumerably to a streamed event. */\nexport function sessionEventStreamCoveredThrough(event: SessionEvent): number | null {\n const covered = (event as SessionEvent & { [SESSION_EVENT_STREAM_COVERAGE]?: unknown })[\n SESSION_EVENT_STREAM_COVERAGE\n ];\n return typeof covered === \"number\" && Number.isSafeInteger(covered) && covered >= event.sequence\n ? covered\n : null;\n}\n\nfunction trustedSseSequence(id: string | undefined, sequence: number): number {\n if (id === undefined || !/^\\d+$/.test(id)) return sequence;\n const covered = Number(id);\n return Number.isSafeInteger(covered) && covered >= sequence ? covered : sequence;\n}\n\nfunction markSessionEventStreamCoverage(event: SessionEvent, covered: number): void {\n Object.defineProperty(event, SESSION_EVENT_STREAM_COVERAGE, {\n value: covered,\n enumerable: false,\n configurable: false,\n writable: false,\n });\n}\n\nasync function sleep(delayMs: number, signal: AbortSignal | undefined): Promise<void> {\n if (signal?.aborted || delayMs <= 0) {\n return;\n }\n await new Promise<void>((resolve) => {\n const timer = setTimeout(done, delayMs);\n function done(): void {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", done);\n resolve();\n }\n signal?.addEventListener(\"abort\", done, { once: true });\n });\n}\n"],"mappings":"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","names":[]}
|