@opengeni/sdk 1.0.2-canary.37191796234001 → 1.0.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 +111 -85
- package/dist/adapters/next.js +5 -5
- package/dist/artifacts.js +7 -7
- package/dist/browser.js +6 -6
- package/dist/chat/index.d.ts +1 -1
- package/dist/chat/index.js +94 -28
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/opengeni.d.ts +33 -6
- package/dist/chat/types.d.ts +34 -8
- package/dist/{chunk-IZA6XTJ2.js → chunk-2UXZUCEZ.js} +3 -3
- package/dist/{chunk-IZA6XTJ2.js.map → chunk-2UXZUCEZ.js.map} +1 -1
- package/dist/{chunk-D37KNKO6.js → chunk-4SMEOV3P.js} +3 -3
- package/dist/{chunk-D37KNKO6.js.map → chunk-4SMEOV3P.js.map} +1 -1
- package/dist/{chunk-OP3VOVII.js → chunk-AH5D5Q5V.js} +2 -2
- package/dist/{chunk-4UPT3FIF.js → chunk-APXVSSSY.js} +2 -2
- package/dist/{chunk-MKLHWLPF.js → chunk-DUVIYER4.js} +6 -6
- package/dist/{chunk-MKLHWLPF.js.map → chunk-DUVIYER4.js.map} +1 -1
- package/dist/{chunk-6TEGEI4E.js → chunk-FG3OO5LM.js} +16 -13
- package/dist/{chunk-6TEGEI4E.js.map → chunk-FG3OO5LM.js.map} +1 -1
- package/dist/{chunk-DSVI5QBQ.js → chunk-HMGADJGZ.js} +2 -2
- 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-SRWDF5FG.js → chunk-LY2K6ELJ.js} +11 -9
- package/dist/chunk-LY2K6ELJ.js.map +1 -0
- package/dist/{chunk-EBDZD5XW.js → chunk-MOTJYIYL.js} +8 -3
- package/dist/{chunk-EBDZD5XW.js.map → chunk-MOTJYIYL.js.map} +1 -1
- package/dist/{chunk-L2JTM5ZK.js → chunk-NC57YMUO.js} +2 -2
- package/dist/{chunk-ANKRFHYG.js → chunk-RWKB6YZG.js} +21 -8
- package/dist/chunk-RWKB6YZG.js.map +1 -0
- package/dist/{chunk-P7BAOGEM.js → chunk-U6CV2SXO.js} +2 -2
- package/dist/{chunk-P7BAOGEM.js.map → chunk-U6CV2SXO.js.map} +1 -1
- package/dist/{chunk-U54UBB7D.js → chunk-V6GIY62B.js} +3 -3
- package/dist/{chunk-U54UBB7D.js.map → chunk-V6GIY62B.js.map} +1 -1
- package/dist/{chunk-5VTRBY4Z.js → chunk-WU6GQG25.js} +2 -2
- package/dist/{chunk-5VTRBY4Z.js.map → chunk-WU6GQG25.js.map} +1 -1
- package/dist/{chunk-LF2ONL44.js → chunk-YIKA2QT4.js} +1 -1
- package/dist/chunk-YIKA2QT4.js.map +1 -0
- package/dist/client.d.ts +5 -2
- package/dist/codex-realtime-controller.js +2 -2
- package/dist/core.js +7 -7
- package/dist/document-authority.js +6 -6
- package/dist/editable-artifacts.js +1 -1
- package/dist/embedding-client.d.ts +6 -1
- package/dist/gateway-realtime-transport.js +1 -1
- package/dist/index.js +15 -15
- package/dist/interaction.js +2 -2
- package/dist/realtime.js +3 -3
- package/dist/session-proxy.d.ts +12 -4
- package/dist/session-proxy.js +5 -5
- package/dist/site-browser-runtime.gen.d.ts +1 -1
- package/dist/site-document.js +1 -1
- package/dist/site-document.js.map +1 -1
- package/dist/site.js +7 -7
- package/dist/tenant-workspaces.d.ts +27 -13
- package/dist/tenant-workspaces.js +2 -2
- package/dist/tool-auth.js +1 -1
- package/dist/{tools-LZISRKDU.js → tools-FXBLUWAE.js} +3 -3
- package/dist/types.d.ts +6 -0
- package/dist/workspace-integrations.js +1 -1
- package/package.json +3 -3
- package/src/chat/index.ts +1 -0
- package/src/chat/opengeni.ts +95 -20
- package/src/chat/types.ts +33 -9
- package/src/client.ts +12 -6
- package/src/codex-realtime.ts +1 -1
- package/src/embedding-client.ts +6 -1
- package/src/errors.ts +2 -2
- package/src/gateway-realtime-transport.ts +3 -3
- package/src/session-proxy.ts +38 -5
- package/src/site-browser-runtime.gen.ts +1 -1
- package/src/site.ts +2 -2
- package/src/tenant-workspaces.ts +54 -26
- package/src/tool-auth.ts +1 -1
- package/src/tools.ts +1 -1
- package/src/types.ts +6 -0
- package/src/workspace-integrations.ts +1 -1
- package/dist/chunk-ANKRFHYG.js.map +0 -1
- package/dist/chunk-LF2ONL44.js.map +0 -1
- package/dist/chunk-SRWDF5FG.js.map +0 -1
- /package/dist/{chunk-OP3VOVII.js.map → chunk-AH5D5Q5V.js.map} +0 -0
- /package/dist/{chunk-4UPT3FIF.js.map → chunk-APXVSSSY.js.map} +0 -0
- /package/dist/{chunk-DSVI5QBQ.js.map → chunk-HMGADJGZ.js.map} +0 -0
- /package/dist/{chunk-L2JTM5ZK.js.map → chunk-NC57YMUO.js.map} +0 -0
- /package/dist/{tools-LZISRKDU.js.map → tools-FXBLUWAE.js.map} +0 -0
package/README.md
CHANGED
|
@@ -52,79 +52,96 @@ change allowances.
|
|
|
52
52
|
|
|
53
53
|
## Embed the conversation (default)
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
`@opengeni/react`'s `
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
Embedding Opengeni is one backend route plus one component, and you only speak
|
|
56
|
+
in your own ids. The browser renders `@opengeni/react`'s `OpenGeniChat` (or
|
|
57
|
+
`SessionConversation`); your server mounts `createSessionProxyHandler`, a
|
|
58
|
+
same-origin proxy that acts as your authenticated user:
|
|
59
59
|
|
|
60
60
|
```ts
|
|
61
|
-
//
|
|
62
|
-
import {
|
|
61
|
+
// lib/opengeni.ts (server only: the organization API key never reaches the browser)
|
|
62
|
+
import { OpenGeni } from "@opengeni/sdk/chat";
|
|
63
63
|
|
|
64
|
-
const og = new
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
export const og = new OpenGeni({ apiKey: process.env.OPENGENI_API_KEY! });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
// app/api/opengeni/[...path]/route.ts (any web-standard host works; see the adapters below)
|
|
69
|
+
import { createSessionProxyRoute } from "@opengeni/sdk/next";
|
|
70
|
+
import { og } from "@/lib/opengeni";
|
|
68
71
|
|
|
69
|
-
export const
|
|
72
|
+
export const dynamic = "force-dynamic";
|
|
73
|
+
export const { GET, POST, PUT, PATCH, DELETE } = createSessionProxyRoute(og, {
|
|
70
74
|
resolve: async (request) => {
|
|
71
|
-
const me = await authenticate(request); // your session
|
|
75
|
+
const me = await authenticate(request); // your existing session check
|
|
72
76
|
if (!me) return new Response("Unauthorized", { status: 401 });
|
|
73
|
-
return {
|
|
77
|
+
return { user: me.id, tenant: me.orgId }; // or { user: me.id }
|
|
74
78
|
},
|
|
75
|
-
|
|
76
|
-
// Optional. Omit to keep session creation purely server-side.
|
|
77
|
-
createSession: ({ initialMessage, idempotencyKey }) => ({
|
|
78
|
-
initialMessage,
|
|
79
|
-
idempotencyKey: idempotencyKey ?? crypto.randomUUID(),
|
|
80
|
-
tools: [{ kind: "mcp", id: "acme" }], // explicit, server-chosen tool selection
|
|
81
|
-
firstPartyMcpTools: [],
|
|
82
|
-
}),
|
|
79
|
+
createSession: (input) => input, // let the browser start chats
|
|
83
80
|
});
|
|
84
81
|
```
|
|
85
82
|
|
|
86
83
|
```tsx
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
import { OpenGeniChat
|
|
84
|
+
// app/assistant/assistant.tsx (browser): no provider, client, or workspace id.
|
|
85
|
+
"use client";
|
|
86
|
+
import { OpenGeniChat } from "@opengeni/react";
|
|
90
87
|
import "@opengeni/react/compiled.css";
|
|
91
88
|
|
|
92
|
-
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
<OpenGeniChat />
|
|
96
|
-
</OpenGeniProvider>;
|
|
89
|
+
export function Assistant() {
|
|
90
|
+
return <OpenGeniChat baseUrl="/api/opengeni" />; // chat list + conversation
|
|
91
|
+
}
|
|
97
92
|
```
|
|
98
93
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
94
|
+
`baseUrl` makes the component create the browser client for your mount and use
|
|
95
|
+
the workspace the proxy resolved for the signed-in user (reported in the
|
|
96
|
+
proxy's client config). One conversation alone is
|
|
97
|
+
`<SessionConversation baseUrl="/api/opengeni" sessionId={id} />`. The
|
|
98
|
+
`<OpenGeniProvider client={client} workspaceId={workspaceId}>` form keeps
|
|
99
|
+
working, for example for several components or the headless hooks.
|
|
100
|
+
|
|
101
|
+
What `resolve` returns decides the workspace:
|
|
102
|
+
|
|
103
|
+
- `{ user, tenant }`: one workspace per tenant; chats are private per user by
|
|
104
|
+
default.
|
|
105
|
+
- `{ user }`: one workspace per user. It stays single-user: the SDK adds its
|
|
106
|
+
owner once, and Opengeni never admits anyone else to it.
|
|
107
|
+
- `{ user, workspaceId }`: bring your own workspace id.
|
|
108
|
+
|
|
109
|
+
Workspaces are created on first use and cached per `OpenGeni` instance.
|
|
110
|
+
`og.workspaceId({ tenant })` and `og.workspaceId({ user })` return the same ids
|
|
111
|
+
the proxy uses. There is no onboarding step: the first request a user makes
|
|
112
|
+
adds them to a tenant (or your own) workspace with conversation permissions
|
|
113
|
+
(workspace read, session create/read/control, file upload/read, and attaching
|
|
114
|
+
your per-session MCP servers; no admin). That needs an organization API key
|
|
115
|
+
with `members:manage` (full access includes it) plus those permissions.
|
|
116
|
+
Opengeni never changes an existing membership, so narrowing or widening one
|
|
117
|
+
with `updateExternalWorkspaceMember` sticks. A user you remove from a tenant
|
|
118
|
+
workspace is added again on their next request, because your product decides
|
|
119
|
+
who its users are; stop resolving a user you no longer admit. A removal from a
|
|
120
|
+
per-user workspace sticks. `organizationId` is optional:
|
|
121
|
+
the facade reads it once from the key. Keep `user` and `tenant`
|
|
122
|
+
host-authenticated, never from the request body or path.
|
|
123
|
+
|
|
124
|
+
The proxy and facade accept `chats`. `"private"` (the default with a user)
|
|
125
|
+
uses private visibility, session-only agent reach and personal Knowledge;
|
|
126
|
+
`"shared"` uses workspace visibility, agent reach and Knowledge, so a tenant's
|
|
127
|
+
users see each other's chats. Without a user and with `chats` omitted, the
|
|
128
|
+
facade keeps workspace visibility, session-only agent reach and Knowledge
|
|
129
|
+
authoring off. The API wire values are `visibility: "private" | "workspace"`;
|
|
130
|
+
stored visibility is `user_private | workspace_shared`. Explicit hook/create
|
|
131
|
+
fields override defaults. Keep MCP URLs and credentials in the server's
|
|
132
|
+
`createSession` hook; the browser cannot choose them through the proxy.
|
|
133
|
+
|
|
134
|
+
You can also pass a plain `OpenGeniClient` (organization key) instead of the
|
|
135
|
+
facade; then `resolve` must return `{ user, workspaceId }`. The explicit
|
|
136
|
+
membership APIs (`ensureWorkspace`, `addExternalWorkspaceMember`,
|
|
137
|
+
`updateExternalWorkspaceMember`, `cancelExternalWorkspaceMemberGrant`) keep
|
|
138
|
+
working for products that manage access themselves. Legacy
|
|
139
|
+
`chats: "isolated"` with `{ tenant, user }` still provisions a separate
|
|
140
|
+
workspace per user and tenant. Per-user workspaces add their owner with a
|
|
141
|
+
stable onboarding key, so a retry never restores a revoked grant;
|
|
142
|
+
`memberPermissions` replaces that owner's permissions on first onboarding
|
|
143
|
+
only. The standalone resolver is on the server-only
|
|
144
|
+
`@opengeni/sdk/tenant-workspaces` subpath.
|
|
128
145
|
|
|
129
146
|
The facade also accepts `agent` (identity, capabilities, instructions, renderer)
|
|
130
147
|
and defaults its renderer to `"markdown"`. Current servers always admit agent
|
|
@@ -260,12 +277,12 @@ still cannot send `mcpCredentialUpdates` itself. With `modelSelection: false`
|
|
|
260
277
|
the proxy reports `modelSelection: false` in the client config, and
|
|
261
278
|
`SessionConversation` hides its model picker.
|
|
262
279
|
|
|
263
|
-
|
|
264
|
-
[External users](#external-users-asuser))
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
`
|
|
268
|
-
|
|
280
|
+
Opengeni adds each user to the workspace on their first request (see
|
|
281
|
+
[External users](#external-users-asuser)), with `workspace:read`,
|
|
282
|
+
`sessions:create`, `sessions:read`, `sessions:control`, `files:upload`,
|
|
283
|
+
`files:read`, and `mcp_servers:attach`. Pass the facade from `@opengeni/sdk/chat`
|
|
284
|
+
instead of a client to resolve `{ tenant, user }` or `{ user }` to a workspace
|
|
285
|
+
created on first use.
|
|
269
286
|
|
|
270
287
|
## Quick start
|
|
271
288
|
|
|
@@ -401,17 +418,34 @@ On a product backend, `client.asUser(externalId, { source? })` returns a separat
|
|
|
401
418
|
client that sends the external actor assertion with the organization key. IDs
|
|
402
419
|
are opaque and case-sensitive; the default source is `default`. Keep the key and
|
|
403
420
|
this client server-side. Each request requires the intersection of the key's
|
|
404
|
-
permissions and the user's
|
|
405
|
-
|
|
421
|
+
permissions and the user's workspace membership. API-key rotation does not
|
|
422
|
+
change the external identity.
|
|
423
|
+
|
|
424
|
+
Membership is automatic: when an `asUser` request reaches a shared workspace of
|
|
425
|
+
the key's own organization and the user has no membership there, Opengeni adds
|
|
426
|
+
one with conversation permissions (workspace read, session create/read/control,
|
|
427
|
+
file upload/read, `mcp_servers:attach`) and continues the request. This needs
|
|
428
|
+
the same authority as explicit onboarding: the key holds `members:manage` (or a
|
|
429
|
+
legacy `workspace:admin`) and every one of those permissions, with the
|
|
430
|
+
workspace in its scope; otherwise the request is a `403` as before. It never
|
|
431
|
+
applies to linked native identities, Personal workspaces, SDK per-user
|
|
432
|
+
workspaces (`opengeni-sdk:user-isolation:*` external source), other
|
|
433
|
+
organizations, requests that need a permission outside those defaults, or any
|
|
434
|
+
non-key caller, and it never changes an existing membership. The identity is
|
|
435
|
+
re-checked as active under the same lock, and the grant writes the same
|
|
436
|
+
receipt and lifecycle event as explicit onboarding, attributed to the key. A
|
|
437
|
+
user removed from a shared workspace is added again on their next request; a
|
|
438
|
+
suspended or offboarded identity stays refused.
|
|
406
439
|
|
|
407
440
|
Use the service client—not an `asUser` client—to call
|
|
408
441
|
`addExternalWorkspaceMember(workspaceId, { identity: { externalId, source? }, permissions })`
|
|
409
|
-
|
|
410
|
-
the key permits, excludes Personal workspaces, and refuses to overwrite an
|
|
411
|
-
existing membership with different permissions
|
|
442
|
+
to choose permissions up front. It requires `members:manage`, cannot grant more
|
|
443
|
+
than the key permits, excludes Personal workspaces, and refuses to overwrite an
|
|
444
|
+
existing membership with different permissions (`409`, also when automatic
|
|
445
|
+
membership already created it); change an existing member's permissions with the keyed
|
|
412
446
|
`updateExternalWorkspaceMember(organizationId, workspaceId, organizationMembershipId,
|
|
413
|
-
{ operationId, permissions })`, which never tears down work.
|
|
414
|
-
|
|
447
|
+
{ operationId, permissions })`, which never tears down work. `asUser` calls never
|
|
448
|
+
reactivate disabled identities.
|
|
415
449
|
|
|
416
450
|
Service `removeWorkspaceMember` supports external members through the existing
|
|
417
451
|
fenced workspace teardown. Account-wide `updateExternalIdentityMembership(
|
|
@@ -464,21 +498,13 @@ import { OpenGeni, createChatHandler } from "@opengeni/sdk/chat";
|
|
|
464
498
|
|
|
465
499
|
const og = new OpenGeni({
|
|
466
500
|
baseUrl: process.env.OPENGENI_API_BASE_URL!, // omitted = production https://app.opengeni.ai
|
|
467
|
-
apiKey: process.env.OPENGENI_API_KEY!,
|
|
468
|
-
organizationId: process.env.OPENGENI_ORGANIZATION_ID!,
|
|
501
|
+
apiKey: process.env.OPENGENI_API_KEY!, // the organization id is derived from the key
|
|
469
502
|
source: "acme-app", // labels your product's tenants and users (default "app")
|
|
470
503
|
});
|
|
471
504
|
|
|
472
|
-
// Once per user, when your product admits them to the tenant. Chat requests
|
|
473
|
-
// never grant workspace membership; without it the API answers 403.
|
|
474
|
-
await og.client.addExternalWorkspaceMember(await og.workspaceId({ tenant: "acme" }), {
|
|
475
|
-
identity: { externalId: "u_42", source: og.source },
|
|
476
|
-
permissions: ["workspace:read", "sessions:create", "sessions:read", "sessions:control"],
|
|
477
|
-
});
|
|
478
|
-
|
|
479
505
|
const chat = await og.chat({
|
|
480
|
-
tenant: "acme", // one workspace per customer, created on first use
|
|
481
|
-
user: "u_42", // authenticated product user;
|
|
506
|
+
tenant: "acme", // one workspace per customer, created on first use; omit for one per user
|
|
507
|
+
user: "u_42", // authenticated product user; added to the workspace on first use
|
|
482
508
|
conversation: "c_9", // stable conversation id, independent of the acting user
|
|
483
509
|
agentAccess: "session", // "session" (default) | "user" | "workspace"
|
|
484
510
|
memory: "user", // "user" | "workspace" | false; session-only agent reach defaults to false
|
|
@@ -521,8 +547,8 @@ export const POST = handler; // send a message, or answer a pending request at .
|
|
|
521
547
|
Conversation IDs do not change with the acting user. Authorized collaborators
|
|
522
548
|
can use the same session; private visibility prevents access by other users.
|
|
523
549
|
Use `chatBySessionId` for existing and legacy user-namespaced conversations.
|
|
524
|
-
|
|
525
|
-
|
|
550
|
+
A user is added to the workspace on their first request (see
|
|
551
|
+
[External users](#external-users-asuser)). Without a `user`, the host must name the conversation
|
|
526
552
|
from `resolve`. The Vercel and OpenAI adapters send only the latest user
|
|
527
553
|
message; the earlier messages in that request are imported once, as context on
|
|
528
554
|
the first message of a conversation, after which OpenGeni owns the history.
|
|
@@ -703,7 +729,7 @@ const og = new OpenGeniClient({
|
|
|
703
729
|
baseUrl: process.env.OPENGENI_API_BASE_URL!,
|
|
704
730
|
apiKey: process.env.OPENGENI_API_KEY!,
|
|
705
731
|
});
|
|
706
|
-
// Existing tenant mapping
|
|
732
|
+
// Existing tenant mapping; the original creator is admitted on first use.
|
|
707
733
|
const actor = og.asUser(originalExternalUserId, { source });
|
|
708
734
|
const imported = await importArchivedSession(actor, workspaceId, {
|
|
709
735
|
importId: "embedded:thread-42", // Stable; persist the exact request before sending.
|
package/dist/adapters/next.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createSessionProxyHandler
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-RWKB6YZG.js";
|
|
4
4
|
import "../chunk-UM4ZXXJR.js";
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
5
|
+
import "../chunk-U6CV2SXO.js";
|
|
6
|
+
import "../chunk-APXVSSSY.js";
|
|
7
|
+
import "../chunk-YIKA2QT4.js";
|
|
8
|
+
import "../chunk-V6GIY62B.js";
|
|
9
9
|
|
|
10
10
|
// src/adapters/next.ts
|
|
11
11
|
function toNextRouteHandlers(handler) {
|
package/dist/artifacts.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
OpenGeniClient
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-AH5D5Q5V.js";
|
|
4
|
+
import "./chunk-HMGADJGZ.js";
|
|
5
|
+
import "./chunk-FG3OO5LM.js";
|
|
6
|
+
import "./chunk-APXVSSSY.js";
|
|
7
|
+
import "./chunk-YIKA2QT4.js";
|
|
8
|
+
import "./chunk-NC57YMUO.js";
|
|
9
|
+
import "./chunk-V6GIY62B.js";
|
|
10
10
|
export {
|
|
11
11
|
OpenGeniClient
|
|
12
12
|
};
|
package/dist/browser.js
CHANGED
|
@@ -5,16 +5,16 @@ import {
|
|
|
5
5
|
OpenGeniToolCallError,
|
|
6
6
|
OpenGeniToolReapprovalRequiredError,
|
|
7
7
|
OpenGeniToolsClient
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-4SMEOV3P.js";
|
|
9
9
|
import {
|
|
10
10
|
OpenGeniClient
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-FG3OO5LM.js";
|
|
12
|
+
import "./chunk-APXVSSSY.js";
|
|
13
13
|
import {
|
|
14
14
|
OPENGENI_API_CONTRACT_HEADER,
|
|
15
15
|
OPENGENI_API_CONTRACT_REVISION
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-YIKA2QT4.js";
|
|
17
|
+
import "./chunk-NC57YMUO.js";
|
|
18
18
|
import {
|
|
19
19
|
OpenGeniAllowanceExhaustedError,
|
|
20
20
|
OpenGeniApiContractMismatchError,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
OpenGeniStreamError,
|
|
26
26
|
formatErrorMessage,
|
|
27
27
|
isRetryableStreamError
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-V6GIY62B.js";
|
|
29
29
|
export {
|
|
30
30
|
OPENGENI_API_CONTRACT_HEADER,
|
|
31
31
|
OPENGENI_API_CONTRACT_REVISION,
|
package/dist/chat/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type { Chats } from "../chats.js";
|
|
2
2
|
export { OpenGeniSetupError } from "../errors.js";
|
|
3
3
|
export { Chat, DEFAULT_CHAT_SOURCE, DEFAULT_OPENGENI_BASE_URL, IMPORTED_HISTORY_MAX_CHARS, OpenGeni, formatImportedHistory, } from "./opengeni.js";
|
|
4
|
-
export { OpenGeniChatError, type ChatAgentAccess, type ChatChunk, type ChatImportedMessage, type ChatMemory, type ChatMessage, type ChatOptions, type ChatPending, type ChatReply, type ChatReplyStatus, type ChatRespondInput, type ChatSendOptions, type ChatSessionListOptions, type ChatSnapshot, type ChatTarget, type ChatToolStatus, type OpenGeniOptions, } from "./types.js";
|
|
4
|
+
export { OpenGeniChatError, type ChatAgentAccess, type ChatChunk, type ChatImportedMessage, type ChatMemory, type ChatMessage, type ChatOptions, type ChatPending, type ChatReply, type ChatReplyStatus, type ChatRespondInput, type ChatSendOptions, type ChatSessionListOptions, type ChatSnapshot, type ChatTarget, type WorkspaceTarget, type ChatToolStatus, type OpenGeniOptions, } from "./types.js";
|
|
5
5
|
export { CHAT_SESSION_NAMESPACE, chatIdempotencyKey, chatIdentityName, chatSessionId, uuidV5, type ChatUserLabel, } from "./ids.js";
|
|
6
6
|
export { ChatTurnFold, approvalPending, humanInputPending, type ChatFoldStep, type ChatTurnTerminal, } from "./fold.js";
|
|
7
7
|
export { CHAT_CONVERSATION_HEADER, CHAT_FORMAT_HEADER, chatChunksToSseBlocks, chatChunksToSseResponse, chatChunksToSseStream, createChatHandler, handleNativeChatRequest, handleNativeHistoryRequest, handleNativeRespondRequest, parseChatChunkStream, respondInputFromBody, type ChatHandlerFormat, type ChatHandlerOptions, type ChatResolution, type ChatResolve, } from "./handler.js";
|
package/dist/chat/index.js
CHANGED
|
@@ -6,27 +6,27 @@ import {
|
|
|
6
6
|
createWorkspaceIdResolver,
|
|
7
7
|
isUuid,
|
|
8
8
|
uuidV5
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-LY2K6ELJ.js";
|
|
10
10
|
import {
|
|
11
11
|
EMPTY_FINAL_REPLY_NOTICE,
|
|
12
12
|
OpenGeniEmbeddingClient,
|
|
13
13
|
turnCompletedWithEmptyFinalReply
|
|
14
|
-
} from "../chunk-
|
|
15
|
-
import "../chunk-
|
|
16
|
-
import "../chunk-
|
|
14
|
+
} from "../chunk-MOTJYIYL.js";
|
|
15
|
+
import "../chunk-AH5D5Q5V.js";
|
|
16
|
+
import "../chunk-HMGADJGZ.js";
|
|
17
17
|
import {
|
|
18
18
|
chatDefaults
|
|
19
19
|
} from "../chunk-UM4ZXXJR.js";
|
|
20
|
-
import "../chunk-
|
|
20
|
+
import "../chunk-FG3OO5LM.js";
|
|
21
21
|
import {
|
|
22
22
|
parseSseStream
|
|
23
|
-
} from "../chunk-
|
|
24
|
-
import "../chunk-
|
|
25
|
-
import "../chunk-
|
|
23
|
+
} from "../chunk-APXVSSSY.js";
|
|
24
|
+
import "../chunk-YIKA2QT4.js";
|
|
25
|
+
import "../chunk-NC57YMUO.js";
|
|
26
26
|
import {
|
|
27
27
|
OpenGeniApiError,
|
|
28
28
|
OpenGeniSetupError
|
|
29
|
-
} from "../chunk-
|
|
29
|
+
} from "../chunk-V6GIY62B.js";
|
|
30
30
|
|
|
31
31
|
// src/chat/types.ts
|
|
32
32
|
var OpenGeniChatError = class extends Error {
|
|
@@ -378,44 +378,116 @@ var IMPORTED_HISTORY_HEADER = "Earlier conversation imported from the product, o
|
|
|
378
378
|
var IMPORTED_HISTORY_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "system"]);
|
|
379
379
|
var OpenGeni = class {
|
|
380
380
|
client;
|
|
381
|
+
/**
|
|
382
|
+
* The organization id: the one passed to the constructor, else the one
|
|
383
|
+
* derived from the API key once {@link resolveOrganizationId} (or any
|
|
384
|
+
* workspace lookup) has run. An empty string before that; prefer
|
|
385
|
+
* `await og.resolveOrganizationId()`.
|
|
386
|
+
*/
|
|
381
387
|
organizationId;
|
|
382
388
|
source;
|
|
383
389
|
sessions;
|
|
384
390
|
resolveWorkspaceId;
|
|
385
391
|
implicitAgentAdmission;
|
|
392
|
+
pendingOrganizationId;
|
|
386
393
|
constructor(options) {
|
|
387
|
-
if (!options.apiKey) throw new TypeError("
|
|
388
|
-
if (!options.organizationId) throw new TypeError("OpenGeni requires an organizationId.");
|
|
394
|
+
if (!options.apiKey) throw new TypeError("Opengeni requires an apiKey.");
|
|
389
395
|
this.client = new OpenGeniEmbeddingClient({
|
|
390
396
|
baseUrl: options.baseUrl ?? DEFAULT_OPENGENI_BASE_URL,
|
|
391
397
|
apiKey: options.apiKey,
|
|
392
398
|
...options.fetch ? { fetch: options.fetch } : {}
|
|
393
399
|
});
|
|
394
|
-
this.organizationId = options.organizationId;
|
|
400
|
+
this.organizationId = options.organizationId ?? "";
|
|
395
401
|
this.source = options.source ?? DEFAULT_CHAT_SOURCE;
|
|
396
402
|
this.resolveWorkspaceId = createWorkspaceIdResolver(this.client, {
|
|
397
|
-
organizationId: this.
|
|
403
|
+
organizationId: () => this.resolveOrganizationId(),
|
|
398
404
|
source: this.source,
|
|
399
405
|
workspaceName: options.workspaceName,
|
|
400
406
|
memberPermissions: options.memberPermissions
|
|
401
407
|
});
|
|
402
408
|
this.sessions = { list: (listOptions) => this.listSessions(listOptions) };
|
|
403
409
|
}
|
|
404
|
-
/**
|
|
410
|
+
/**
|
|
411
|
+
* The organization that owns every workspace this facade creates. Uses the
|
|
412
|
+
* constructor's `organizationId`, else reads it once from the API key
|
|
413
|
+
* (`GET /v1/access/me`) and caches it.
|
|
414
|
+
*/
|
|
415
|
+
async resolveOrganizationId() {
|
|
416
|
+
if (this.organizationId) return this.organizationId;
|
|
417
|
+
if (!this.pendingOrganizationId) {
|
|
418
|
+
const pending = this.client.getAccessContext().then((access) => {
|
|
419
|
+
const credential = access.credential;
|
|
420
|
+
if (credential && credential.kind !== "organization_api_key") {
|
|
421
|
+
throw new TypeError(
|
|
422
|
+
"OpenGeni needs an organization API key to create workspaces; this is a workspace key."
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
const organizationId = credential?.accountId ?? access.defaultAccountId;
|
|
426
|
+
if (!organizationId) {
|
|
427
|
+
throw new TypeError(
|
|
428
|
+
"Could not derive the organization from this API key. Pass organizationId."
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
this.organizationId = organizationId;
|
|
432
|
+
return organizationId;
|
|
433
|
+
});
|
|
434
|
+
pending.catch(() => {
|
|
435
|
+
if (this.pendingOrganizationId === pending) this.pendingOrganizationId = void 0;
|
|
436
|
+
});
|
|
437
|
+
this.pendingOrganizationId = pending;
|
|
438
|
+
}
|
|
439
|
+
return await this.pendingOrganizationId;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Translate your own ids to the Opengeni workspace id, creating the
|
|
443
|
+
* workspace on first use (cached per instance):
|
|
444
|
+
* `{ tenant }` is one workspace per tenant, `{ user }` (no tenant) is one
|
|
445
|
+
* workspace per user, and `{ workspaceId }` is returned as is. Opengeni adds
|
|
446
|
+
* a tenant workspace's users on their first request; a per-user workspace
|
|
447
|
+
* gets its one owner from the SDK and admits nobody else.
|
|
448
|
+
*/
|
|
405
449
|
async workspaceId(target) {
|
|
450
|
+
if (target.workspaceId === "" || target.tenant === "") {
|
|
451
|
+
throw new TypeError("tenant and workspaceId must be non-empty ids.");
|
|
452
|
+
}
|
|
406
453
|
if (target.workspaceId) return target.workspaceId;
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
454
|
+
if (target.tenant) {
|
|
455
|
+
return await this.workspaceIdFor({ tenant: target.tenant }, { isolation: "tenant" });
|
|
456
|
+
}
|
|
457
|
+
if ("tenant" in target || "workspaceId" in target) {
|
|
458
|
+
throw new TypeError(
|
|
459
|
+
"tenant or workspaceId is undefined. Pass a non-empty id, or omit the key for one workspace per user."
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
const user = "user" in target ? target.user : void 0;
|
|
463
|
+
if (user) {
|
|
464
|
+
return await this.workspaceIdFor({ user }, { isolation: "user" });
|
|
465
|
+
}
|
|
466
|
+
throw new TypeError("Pass tenant, user, or workspaceId.");
|
|
410
467
|
}
|
|
411
|
-
/**
|
|
468
|
+
/**
|
|
469
|
+
* Resolve a tenant workspace or a user's own workspace (user isolation, per
|
|
470
|
+
* tenant when one is given). A user's own workspace is provisioned with that
|
|
471
|
+
* user as its only explicit member.
|
|
472
|
+
*/
|
|
412
473
|
async workspaceIdFor(target, options) {
|
|
413
474
|
return await this.resolveWorkspaceId(target, options);
|
|
414
475
|
}
|
|
476
|
+
/** `chats: "isolated"` keeps its tenant-plus-user workspace; a user alone gets their own. */
|
|
477
|
+
async isolatedWorkspaceId(target) {
|
|
478
|
+
if (target.workspaceId) {
|
|
479
|
+
throw new TypeError('chats: "isolated" requires a tenant or user, not a workspaceId.');
|
|
480
|
+
}
|
|
481
|
+
return await this.workspaceIdFor(
|
|
482
|
+
{ tenant: target.tenant, user: target.user },
|
|
483
|
+
{ isolation: "user" }
|
|
484
|
+
);
|
|
485
|
+
}
|
|
415
486
|
/**
|
|
416
487
|
* Address one conversation; the session is created lazily on the first send.
|
|
417
|
-
* Identity selects authority, not the conversation address.
|
|
418
|
-
*
|
|
488
|
+
* Identity selects authority, not the conversation address. The workspace
|
|
489
|
+
* is the tenant's, the user's own (user only), or the explicit id; Opengeni
|
|
490
|
+
* adds the user to it on their first request.
|
|
419
491
|
* Legacy user-namespaced conversations remain accessible by their session ID.
|
|
420
492
|
*/
|
|
421
493
|
async chat(options) {
|
|
@@ -442,10 +514,7 @@ var OpenGeni = class {
|
|
|
442
514
|
);
|
|
443
515
|
}
|
|
444
516
|
const client = options.user ? this.client.asUser(options.user, { source: this.source }) : this.client;
|
|
445
|
-
const workspaceId = options.chats === "isolated" ? await this.
|
|
446
|
-
{ tenant: options.tenant ?? "", user: options.user },
|
|
447
|
-
{ isolation: "user" }
|
|
448
|
-
) : await this.workspaceId(options);
|
|
517
|
+
const workspaceId = options.chats === "isolated" ? await this.isolatedWorkspaceId(options) : await this.workspaceId(options);
|
|
449
518
|
const sessionId = options.sessionId ?? await chatSessionId(workspaceId, options.conversation);
|
|
450
519
|
const session = await this.findSession(client, workspaceId, sessionId);
|
|
451
520
|
const buildCreate = (text, send) => {
|
|
@@ -537,10 +606,7 @@ var OpenGeni = class {
|
|
|
537
606
|
}
|
|
538
607
|
}
|
|
539
608
|
async listSessions(options) {
|
|
540
|
-
const workspaceId = options.chats === "isolated" ? await this.
|
|
541
|
-
{ tenant: options.tenant ?? "", user: options.user },
|
|
542
|
-
{ isolation: "user" }
|
|
543
|
-
) : await this.workspaceId(options);
|
|
609
|
+
const workspaceId = options.chats === "isolated" ? await this.isolatedWorkspaceId(options) : await this.workspaceId(options);
|
|
544
610
|
const client = options.user ? this.client.asUser(options.user, { source: this.source }) : this.client;
|
|
545
611
|
return await client.requestJson(
|
|
546
612
|
"GET",
|