@opengeni/sdk 4.0.2 → 5.0.3-canary.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.
Files changed (48) hide show
  1. package/README.md +58 -9
  2. package/dist/artifact-client.d.ts +18 -8
  3. package/dist/artifacts.js +4 -4
  4. package/dist/browser.js +2 -2
  5. package/dist/chat/ids.d.ts +3 -3
  6. package/dist/chat/index.js +38 -51
  7. package/dist/chat/index.js.map +1 -1
  8. package/dist/chat/opengeni.d.ts +10 -12
  9. package/dist/chat/types.d.ts +7 -3
  10. package/dist/{chunk-O23OOWJK.js → chunk-4YAL54F3.js} +2 -2
  11. package/dist/{chunk-UW22XVCT.js → chunk-ARGX7UY4.js} +97 -2
  12. package/dist/chunk-ARGX7UY4.js.map +1 -0
  13. package/dist/chunk-J5USCWPE.js +195 -0
  14. package/dist/chunk-J5USCWPE.js.map +1 -0
  15. package/dist/{chunk-WNEGCYCE.js → chunk-TARU5CD2.js} +1 -1
  16. package/dist/chunk-TARU5CD2.js.map +1 -0
  17. package/dist/{chunk-3IZMCD2K.js → chunk-TOB3B4ZJ.js} +28 -41
  18. package/dist/chunk-TOB3B4ZJ.js.map +1 -0
  19. package/dist/{chunk-2H7P45YQ.js → chunk-UQGHX4DI.js} +173 -7
  20. package/dist/chunk-UQGHX4DI.js.map +1 -0
  21. package/dist/client.d.ts +39 -4
  22. package/dist/core.js +3 -3
  23. package/dist/document-authority.js +3 -3
  24. package/dist/editable-artifacts.js +1 -1
  25. package/dist/embedding-client.d.ts +72 -0
  26. package/dist/index.d.ts +4 -1
  27. package/dist/index.js +13 -8
  28. package/dist/index.js.map +1 -1
  29. package/dist/site-tool-bridge.d.ts +39 -0
  30. package/dist/site.d.ts +2 -0
  31. package/dist/site.js +7 -3
  32. package/dist/types.d.ts +23 -12
  33. package/package.json +3 -2
  34. package/src/artifact-client.ts +38 -63
  35. package/src/chat/ids.ts +3 -3
  36. package/src/chat/opengeni.ts +41 -57
  37. package/src/chat/types.ts +7 -3
  38. package/src/client.ts +253 -12
  39. package/src/embedding-client.ts +308 -0
  40. package/src/index.ts +16 -1
  41. package/src/site-tool-bridge.ts +141 -0
  42. package/src/site.ts +7 -0
  43. package/src/types.ts +18 -6
  44. package/dist/chunk-2H7P45YQ.js.map +0 -1
  45. package/dist/chunk-3IZMCD2K.js.map +0 -1
  46. package/dist/chunk-UW22XVCT.js.map +0 -1
  47. package/dist/chunk-WNEGCYCE.js.map +0 -1
  48. /package/dist/{chunk-O23OOWJK.js.map → chunk-4YAL54F3.js.map} +0 -0
@@ -1,5 +1,13 @@
1
1
  import { OpenGeniDocumentAuthorityClient } from "./document-authority-client";
2
2
  import type { FetchResponse } from "./client";
3
+ import type { SiteToolCallRequest } from "./site-tool-bridge";
4
+ import type { ToolGatewayCallResponse } from "./types";
5
+ import type {
6
+ CreateWorkspaceArtifactRequest,
7
+ PublishWorkspaceArtifactVersionRequest,
8
+ WorkspaceArtifactContentResponse,
9
+ WorkspaceArtifactMutationResponse,
10
+ } from "./workspace-artifacts";
3
11
  import type {
4
12
  CreateEditableArtifactMaterializationRequest,
5
13
  CreateEditableArtifactResourceRequest,
@@ -13,17 +21,6 @@ import type {
13
21
  ReadEditableArtifactMaterializationOptions,
14
22
  ReadEditableArtifactResourceOptions,
15
23
  } from "./editable-artifact-resources";
16
- import type {
17
- CreateWorkspaceArtifactRequest,
18
- PublishWorkspaceArtifactVersionRequest,
19
- RollbackWorkspaceArtifactRequest,
20
- SetWorkspaceArtifactStatusRequest,
21
- WorkspaceArtifactContentResponse,
22
- WorkspaceArtifactDetailResponse,
23
- WorkspaceArtifactListOptions,
24
- WorkspaceArtifactListResponse,
25
- WorkspaceArtifactMutationResponse,
26
- } from "./workspace-artifacts";
27
24
 
28
25
  /** Public SDK client. Optional operator and artifact operations stay out of the console core. */
29
26
  export class OpenGeniClient extends OpenGeniDocumentAuthorityClient {
@@ -142,53 +139,52 @@ export class OpenGeniClient extends OpenGeniDocumentAuthorityClient {
142
139
  options,
143
140
  );
144
141
  }
145
-
146
- async listWorkspaceArtifacts(
147
- workspaceId: string,
148
- options: WorkspaceArtifactListOptions = {},
149
- ): Promise<WorkspaceArtifactListResponse> {
150
- const query = new URLSearchParams();
151
- if (options.limit !== undefined) query.set("limit", String(options.limit));
152
- if (options.cursor) query.set("cursor", options.cursor);
153
- if (options.status) query.set("status", options.status);
154
- if (options.sourceSessionId) query.set("sourceSessionId", options.sourceSessionId);
155
- const suffix = query.size > 0 ? `?${query.toString()}` : "";
156
- return await this.requestJson<WorkspaceArtifactListResponse>(
157
- "GET",
158
- `/v1/workspaces/${workspaceId}/published-artifacts${suffix}`,
159
- );
160
- }
161
-
162
- async getWorkspaceArtifact(
142
+ /** Exact Site-version gateway call. Keep this client on the authenticated host;
143
+ * the API enforces live viewer access and the version's declared tool allowlist. */
144
+ async callWorkspaceSiteTool(
163
145
  workspaceId: string,
164
- artifactId: string,
165
- ): Promise<WorkspaceArtifactDetailResponse> {
166
- return await this.requestJson<WorkspaceArtifactDetailResponse>(
167
- "GET",
168
- `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}`,
146
+ request: SiteToolCallRequest,
147
+ options: { signal?: AbortSignal } = {},
148
+ ): Promise<ToolGatewayCallResponse> {
149
+ return this.requestJson<ToolGatewayCallResponse>(
150
+ "POST",
151
+ `/v1/workspaces/${encodeURIComponent(workspaceId)}/tools/calls`,
152
+ request,
153
+ undefined,
154
+ options,
169
155
  );
170
156
  }
171
157
 
172
158
  async getWorkspaceArtifactContent(
173
159
  workspaceId: string,
174
160
  artifactId: string,
175
- versionId?: string,
161
+ versionOrOptions?: string | { versionId?: string; signal?: AbortSignal },
176
162
  ): Promise<WorkspaceArtifactContentResponse> {
177
- const query = versionId ? `?versionId=${encodeURIComponent(versionId)}` : "";
163
+ const options =
164
+ typeof versionOrOptions === "string"
165
+ ? { versionId: versionOrOptions }
166
+ : (versionOrOptions ?? {});
167
+ const query = options.versionId ? `?versionId=${encodeURIComponent(options.versionId)}` : "";
178
168
  return await this.requestJson<WorkspaceArtifactContentResponse>(
179
169
  "GET",
180
- `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}/content${query}`,
170
+ `/v1/workspaces/${encodeURIComponent(workspaceId)}/published-artifacts/${encodeURIComponent(artifactId)}/content${query}`,
171
+ undefined,
172
+ undefined,
173
+ options,
181
174
  );
182
175
  }
183
176
 
184
177
  async createWorkspaceArtifact(
185
178
  workspaceId: string,
186
179
  request: CreateWorkspaceArtifactRequest,
180
+ options: { signal?: AbortSignal } = {},
187
181
  ): Promise<WorkspaceArtifactMutationResponse> {
188
182
  return await this.requestJson<WorkspaceArtifactMutationResponse>(
189
183
  "POST",
190
- `/v1/workspaces/${workspaceId}/published-artifacts`,
184
+ `/v1/workspaces/${encodeURIComponent(workspaceId)}/published-artifacts`,
191
185
  request,
186
+ undefined,
187
+ options,
192
188
  );
193
189
  }
194
190
 
@@ -196,35 +192,14 @@ export class OpenGeniClient extends OpenGeniDocumentAuthorityClient {
196
192
  workspaceId: string,
197
193
  artifactId: string,
198
194
  request: PublishWorkspaceArtifactVersionRequest,
195
+ options: { signal?: AbortSignal } = {},
199
196
  ): Promise<WorkspaceArtifactMutationResponse> {
200
197
  return await this.requestJson<WorkspaceArtifactMutationResponse>(
201
198
  "POST",
202
- `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}/versions`,
203
- request,
204
- );
205
- }
206
-
207
- async rollbackWorkspaceArtifact(
208
- workspaceId: string,
209
- artifactId: string,
210
- request: RollbackWorkspaceArtifactRequest,
211
- ): Promise<WorkspaceArtifactMutationResponse> {
212
- return await this.requestJson<WorkspaceArtifactMutationResponse>(
213
- "POST",
214
- `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}/rollback`,
215
- request,
216
- );
217
- }
218
-
219
- async setWorkspaceArtifactStatus(
220
- workspaceId: string,
221
- artifactId: string,
222
- request: SetWorkspaceArtifactStatusRequest,
223
- ): Promise<WorkspaceArtifactMutationResponse> {
224
- return await this.requestJson<WorkspaceArtifactMutationResponse>(
225
- "PATCH",
226
- `/v1/workspaces/${workspaceId}/published-artifacts/${encodeURIComponent(artifactId)}/status`,
199
+ `/v1/workspaces/${encodeURIComponent(workspaceId)}/published-artifacts/${encodeURIComponent(artifactId)}/versions`,
227
200
  request,
201
+ undefined,
202
+ options,
228
203
  );
229
204
  }
230
205
  }
package/src/chat/ids.ts CHANGED
@@ -2,9 +2,9 @@
2
2
  * Deterministic chat identities. A conversation id maps to exactly one
3
3
  * session id per workspace, so any process can address the same session
4
4
  * without storing a mapping, and a double-submitted create collapses through
5
- * the idempotency key. With an end-user label the conversation id is
6
- * namespaced to that user, so one user cannot address another user's
7
- * conversation by guessing its id.
5
+ * the idempotency key. The optional legacy label argument is retained only to
6
+ * reproduce historical addresses. New chat calls do not use it: authorization
7
+ * is independent of addressing, so collaborators can share a conversation.
8
8
  */
9
9
 
10
10
  /** The end-user label a conversation is namespaced to: the product `source` plus the opaque user id. */
@@ -1,4 +1,4 @@
1
- import { OpenGeniClient } from "../client";
1
+ import { OpenGeniEmbeddingClient as OpenGeniClient } from "../embedding-client";
2
2
  import { OpenGeniApiError } from "../errors";
3
3
  import type { CreateSessionRequest, Session, SessionEvent } from "../types";
4
4
  import { ChatPendingFold, ChatTurnFold, asRecord, stringValue } from "./fold";
@@ -51,7 +51,7 @@ export class OpenGeni {
51
51
  readonly organizationId: string;
52
52
  readonly source: string;
53
53
  readonly sessions: {
54
- /** Sessions of one tenant workspace, optionally filtered to one end user. */
54
+ /** Sessions visible to the selected canonical user, or explicit service caller. */
55
55
  list: (options: ChatSessionListOptions) => Promise<Session[]>;
56
56
  };
57
57
  private readonly workspaceName: ((tenant: string) => string) | undefined;
@@ -98,8 +98,9 @@ export class OpenGeni {
98
98
 
99
99
  /**
100
100
  * Address one conversation; the session is created lazily on the first send.
101
- * With a `user`, the conversation id is namespaced to that user (a different
102
- * user with the same conversation id reaches a different session).
101
+ * Identity selects authority, not the conversation address. Workspace
102
+ * membership must be provisioned by the host's explicit onboarding flow.
103
+ * Legacy user-namespaced conversations remain accessible by their session ID.
103
104
  */
104
105
  async chat(options: ChatOptions): Promise<Chat> {
105
106
  if (!options.conversation) throw new TypeError("chat() requires a conversation id.");
@@ -108,27 +109,22 @@ export class OpenGeni {
108
109
  options.memory === false
109
110
  ? "off"
110
111
  : options.memory === undefined
111
- ? agentAccess
112
+ ? agentAccess === "session"
113
+ ? "off"
114
+ : agentAccess
112
115
  : options.memory;
113
116
  if (memoryScope === "user" && !options.user) {
114
117
  throw new OpenGeniChatError(
115
118
  "memory_scope_requires_user",
116
- 'memory: "user" requires a user label so memories can be scoped to that end user.',
119
+ 'memory: "user" requires an authenticated product user.',
117
120
  );
118
121
  }
119
- const endUser = options.user ? { source: this.source, id: options.user } : undefined;
122
+ const client = options.user
123
+ ? this.client.asUser(options.user, { source: this.source })
124
+ : this.client;
120
125
  const workspaceId = await this.workspaceId(options);
121
- const sessionId = await chatSessionId(workspaceId, options.conversation, endUser);
122
- const session = await this.findSession(workspaceId, sessionId);
123
- // Reopening an existing session re-verifies the label it was created with.
124
- // The tuple derivation already makes a collision impossible; this keeps a
125
- // relabelled or hand-addressed session from crossing users regardless.
126
- if (session && endUser && !sameEndUser(session.endUser ?? null, endUser)) {
127
- throw new OpenGeniChatError(
128
- "conversation_not_authorized",
129
- "This conversation belongs to a different user.",
130
- );
131
- }
126
+ const sessionId = options.sessionId ?? (await chatSessionId(workspaceId, options.conversation));
127
+ const session = await this.findSession(client, workspaceId, sessionId);
132
128
  const buildCreate: BuildCreate = (text, importedHistory) => {
133
129
  const context =
134
130
  options.create?.modelContext === undefined && importedHistory
@@ -137,7 +133,6 @@ export class OpenGeni {
137
133
  return {
138
134
  agentAccess,
139
135
  memoryScope,
140
- ...(endUser ? { endUser } : {}),
141
136
  ...(options.model !== undefined ? { model: options.model } : {}),
142
137
  ...(options.instructions !== undefined ? { instructions: options.instructions } : {}),
143
138
  ...(options.skills !== undefined ? { skills: options.skills } : {}),
@@ -149,7 +144,7 @@ export class OpenGeni {
149
144
  idempotencyKey: chatIdempotencyKey(sessionId),
150
145
  };
151
146
  };
152
- return new Chat(this, {
147
+ return new Chat(client, {
153
148
  workspaceId,
154
149
  sessionId,
155
150
  conversation: options.conversation,
@@ -159,29 +154,19 @@ export class OpenGeni {
159
154
  }
160
155
 
161
156
  /**
162
- * Address an existing session by id (for example decoded from a response id).
163
- * `user` is the end user the caller authenticated: the session must carry
164
- * exactly that end-user label (`{ source, id }`) or the call throws
165
- * `conversation_not_authorized`. Pass `null` only from trusted server code
166
- * that vouches for the session itself; a session reached with `null` is not
167
- * checked against any user.
157
+ * Address an existing session with native API authorization. The same shared
158
+ * session can be opened by different authorized users. Pass null only for an
159
+ * explicitly service-owned operation; the API still enforces service access.
168
160
  */
169
161
  async chatBySessionId(target: {
170
162
  workspaceId: string;
171
163
  sessionId: string;
172
164
  user: string | null;
173
165
  }): Promise<Chat> {
174
- const session = await this.client.getSession(target.workspaceId, target.sessionId);
175
- if (
176
- target.user !== null &&
177
- !sameEndUser(session.endUser ?? null, { source: this.source, id: target.user })
178
- ) {
179
- throw new OpenGeniChatError(
180
- "conversation_not_authorized",
181
- "This conversation belongs to a different user.",
182
- );
183
- }
184
- return new Chat(this, {
166
+ const client =
167
+ target.user !== null ? this.client.asUser(target.user, { source: this.source }) : this.client;
168
+ const session = await client.getSession(target.workspaceId, target.sessionId);
169
+ return new Chat(client, {
185
170
  workspaceId: target.workspaceId,
186
171
  sessionId: target.sessionId,
187
172
  conversation: null,
@@ -190,9 +175,13 @@ export class OpenGeni {
190
175
  });
191
176
  }
192
177
 
193
- private async findSession(workspaceId: string, sessionId: string): Promise<Session | null> {
178
+ private async findSession(
179
+ client: OpenGeniClient,
180
+ workspaceId: string,
181
+ sessionId: string,
182
+ ): Promise<Session | null> {
194
183
  try {
195
- return await this.client.getSession(workspaceId, sessionId);
184
+ return await client.getSession(workspaceId, sessionId);
196
185
  } catch (error) {
197
186
  if (error instanceof OpenGeniApiError && error.status === 404) return null;
198
187
  throw error;
@@ -201,13 +190,15 @@ export class OpenGeni {
201
190
 
202
191
  private async listSessions(options: ChatSessionListOptions): Promise<Session[]> {
203
192
  const workspaceId = await this.workspaceId(options);
204
- return await this.client.requestJson<Session[]>(
193
+ const client = options.user
194
+ ? this.client.asUser(options.user, { source: this.source })
195
+ : this.client;
196
+ return await client.requestJson<Session[]>(
205
197
  "GET",
206
198
  `/v1/workspaces/${workspaceId}/sessions`,
207
199
  undefined,
208
200
  {
209
201
  ...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
210
- ...(options.user ? { endUserSource: this.source, endUserId: options.user } : {}),
211
202
  },
212
203
  );
213
204
  }
@@ -224,7 +215,7 @@ export class Chat {
224
215
  private pendingTurnId: string | null = null;
225
216
 
226
217
  constructor(
227
- private readonly og: OpenGeni,
218
+ private readonly client: OpenGeniClient,
228
219
  init: ChatInit,
229
220
  ) {
230
221
  this.workspaceId = init.workspaceId;
@@ -290,7 +281,7 @@ export class Chat {
290
281
  let lastAssistantTurn: string | null = null;
291
282
  let after = 0;
292
283
  while (true) {
293
- const result = await this.og.client.listEventPage(this.workspaceId, this.sessionId, {
284
+ const result = await this.client.listEventPage(this.workspaceId, this.sessionId, {
294
285
  after,
295
286
  includeTypes: [
296
287
  "user.message",
@@ -354,7 +345,7 @@ export class Chat {
354
345
  if (!this.buildCreate) {
355
346
  throw new OpenGeniChatError("session_missing", "This session no longer exists.");
356
347
  }
357
- const created = await this.og.client.createSession(
348
+ const created = await this.client.createSession(
358
349
  this.workspaceId,
359
350
  this.buildCreate(text, importedHistory),
360
351
  );
@@ -364,7 +355,7 @@ export class Chat {
364
355
  }
365
356
  // The idempotent create replayed an earlier session; deliver this message too.
366
357
  }
367
- const event = await this.og.client.sendMessage(this.workspaceId, this.sessionId, text);
358
+ const event = await this.client.sendMessage(this.workspaceId, this.sessionId, text);
368
359
  return submittedFrom(event);
369
360
  }
370
361
 
@@ -373,27 +364,27 @@ export class Chat {
373
364
  importedHistory: ChatImportedMessage[] | undefined,
374
365
  ): Promise<SubmittedTurn> {
375
366
  if (!this.session) return await this.submit(text, importedHistory);
376
- const result = await this.og.client.steerMessage(this.workspaceId, this.sessionId, text);
367
+ const result = await this.client.steerMessage(this.workspaceId, this.sessionId, text);
377
368
  return { after: result.accepted.sequence, turnId: result.turn.id ?? null };
378
369
  }
379
370
 
380
371
  private async submitResponse(input: ChatRespondInput): Promise<SubmittedTurn> {
381
372
  let event: SessionEvent;
382
373
  if ("decision" in input) {
383
- event = await this.og.client.sendApprovalDecision(this.workspaceId, this.sessionId, {
374
+ event = await this.client.sendApprovalDecision(this.workspaceId, this.sessionId, {
384
375
  approvalId: input.requestId,
385
376
  decision: input.decision,
386
377
  ...(input.message !== undefined ? { message: input.message } : {}),
387
378
  });
388
379
  } else if ("answers" in input) {
389
- event = await this.og.client.submitHumanInputResponse(
380
+ event = await this.client.submitHumanInputResponse(
390
381
  this.workspaceId,
391
382
  this.sessionId,
392
383
  input.requestId,
393
384
  { outcome: "answered", answers: input.answers },
394
385
  );
395
386
  } else {
396
- event = await this.og.client.submitHumanInputResponse(
387
+ event = await this.client.submitHumanInputResponse(
397
388
  this.workspaceId,
398
389
  this.sessionId,
399
390
  input.requestId,
@@ -414,7 +405,7 @@ export class Chat {
414
405
  else signal?.addEventListener("abort", onAbort, { once: true });
415
406
  const fold = new ChatTurnFold(this.workspaceId, this.sessionId, submitted.turnId);
416
407
  try {
417
- for await (const event of this.og.client.streamEvents(this.workspaceId, this.sessionId, {
408
+ for await (const event of this.client.streamEvents(this.workspaceId, this.sessionId, {
418
409
  after: submitted.after,
419
410
  signal: upstream.signal,
420
411
  })) {
@@ -508,10 +499,3 @@ function abortError(): Error {
508
499
  error.name = "AbortError";
509
500
  return error;
510
501
  }
511
-
512
- function sameEndUser(
513
- left: { source: string; id: string } | null,
514
- right: { source: string; id: string },
515
- ): boolean {
516
- return left !== null && left.source === right.source && left.id === right.id;
517
- }
package/src/chat/types.ts CHANGED
@@ -13,9 +13,10 @@ export type ChatAgentAccess = "session" | "user" | "workspace";
13
13
 
14
14
  /**
15
15
  * Memory scope for the session: which memories the agent reads and where it
16
- * saves. `false` disables Memory tools. Omitted follows `agentAccess`.
16
+ * saves. `false` disables Memory tools. Omitted follows user/workspace agent
17
+ * reach; session-only reach defaults to false. Task notes cover task-local data.
17
18
  */
18
- export type ChatMemory = "session" | "user" | "workspace" | false;
19
+ export type ChatMemory = "user" | "workspace" | false;
19
20
 
20
21
  export type OpenGeniOptions = {
21
22
  /** Organization API key. Keep it on the server. */
@@ -39,10 +40,13 @@ export type ChatTarget =
39
40
  | { workspaceId: string; tenant?: undefined };
40
41
 
41
42
  export type ChatOptions = ChatTarget & {
42
- /** Opaque end-user label inside the tenant. Required for `memory: "user"`. */
43
+ /** Host-authenticated external user; resolved through server-side asUser(). */
43
44
  user?: string | undefined;
44
45
  /** Stable conversation id; the session id is derived from it deterministically. */
45
46
  conversation: string;
47
+ /** Prefer the actual OpenGeni session ID for shared or existing conversations.
48
+ * The acting user is independent of the conversation's identity. */
49
+ sessionId?: string | undefined;
46
50
  /** Defaults to `"session"`: the agent sees only this conversation. */
47
51
  agentAccess?: ChatAgentAccess | undefined;
48
52
  memory?: ChatMemory | undefined;