@opengeni/sdk 0.26.1 → 0.28.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/sdk",
3
- "version": "0.26.1",
3
+ "version": "0.28.2",
4
4
  "description": "Framework-agnostic TypeScript SDK for the OpenGeni API: typed client, session lifecycle, SSE event streaming with reconnect + replay-by-sequence, and proxy re-streaming helpers.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
package/src/client.ts CHANGED
@@ -46,7 +46,8 @@ import type {
46
46
  CreateCapabilityCatalogItemRequest,
47
47
  CreateCheckoutRequest,
48
48
  CreateCheckoutResponse,
49
- ConnectOpenGeniSlackBotRequest,
49
+ OpenGeniSlackBotInstallRequest,
50
+ OpenGeniSlackBotInstallStart,
50
51
  CreateConnectionRequest,
51
52
  CreateDocumentBaseRequest,
52
53
  CreateFileUploadRequest,
@@ -2589,17 +2590,16 @@ export class OpenGeniClient {
2589
2590
  return response.connection;
2590
2591
  }
2591
2592
 
2592
- /** Validate and store/reinstall the workspace-shared OpenGeni Slack bot credential. */
2593
- async connectOpenGeniSlackBot(
2593
+ /** Start the public Slack installation flow for the workspace-shared OpenGeni bot. */
2594
+ async startOpenGeniSlackBotInstall(
2594
2595
  workspaceId: string,
2595
- request: ConnectOpenGeniSlackBotRequest,
2596
- ): Promise<ConnectionMetadata> {
2597
- const response = await this.requestJson<ConnectionResponse>(
2596
+ request: OpenGeniSlackBotInstallRequest = {},
2597
+ ): Promise<OpenGeniSlackBotInstallStart> {
2598
+ return await this.requestJson<OpenGeniSlackBotInstallStart>(
2598
2599
  "POST",
2599
- `/v1/workspaces/${workspaceId}/connections/slack-bot`,
2600
+ `/v1/workspaces/${workspaceId}/connections/slack-bot/install`,
2600
2601
  request,
2601
2602
  );
2602
- return response.connection;
2603
2603
  }
2604
2604
 
2605
2605
  async updateConnection(
package/src/index.ts CHANGED
@@ -24,6 +24,8 @@ export {
24
24
  export type { ProxySessionEventStreamOptions, SseReStreamOptions } from "./proxy";
25
25
  export { parseSseStream } from "./sse";
26
26
  export type { SseMessage } from "./sse";
27
+ export { normalizeMcpOutput } from "./mcp-output";
28
+ export type { NormalizedMcpOutput } from "./mcp-output";
27
29
  // Desktop (noVNC) transport contract — pure, zero-dep (the RFB import lives in
28
30
  // @opengeni/react). URL assembler + connection state machine + rotation fence.
29
31
  export { desktopSocketUrl, nextDesktopState, applyUrlRotation } from "./desktop";
@@ -191,7 +193,8 @@ export type {
191
193
  CreateApiKeyRequest,
192
194
  CreateApiKeyResponse,
193
195
  CreateCapabilityCatalogItemRequest,
194
- ConnectOpenGeniSlackBotRequest,
196
+ OpenGeniSlackBotInstallRequest,
197
+ OpenGeniSlackBotInstallStart,
195
198
  CreateConnectionRequest,
196
199
  CreateCheckoutRequest,
197
200
  CreateCheckoutResponse,
@@ -321,6 +324,7 @@ export type {
321
324
  SessionCommandReceipt,
322
325
  SteerSessionQueueItemRequest,
323
326
  WorkspaceInferenceControlResponse,
327
+ SessionPendingInputPreview,
324
328
  SessionSystemUpdate,
325
329
  SessionSystemUpdateKind,
326
330
  SessionSystemUpdateState,
@@ -0,0 +1,161 @@
1
+ /**
2
+ * A transport-tolerant MCP tool result.
3
+ *
4
+ * `value` is the canonical machine-readable payload after recognized MCP/JSON
5
+ * envelopes are removed. `text` is the best presentation string without
6
+ * discarding structured data. `raw` always retains the original evidence.
7
+ */
8
+ export type NormalizedMcpOutput = Readonly<{
9
+ raw: unknown;
10
+ value: unknown;
11
+ text: string;
12
+ isError: boolean;
13
+ }>;
14
+
15
+ const MAX_MCP_OUTPUT_DEPTH = 8;
16
+ const RESULT_ENVELOPE_KEYS = new Set(["result", "isError", "jsonrpc", "id", "_meta"]);
17
+
18
+ /** Normalize common direct, JSON, and standard MCP result envelopes without throwing. */
19
+ export function normalizeMcpOutput(output: unknown): NormalizedMcpOutput {
20
+ const normalized = normalizeValue(output, 0, new Set<object>());
21
+ return {
22
+ raw: output,
23
+ value: normalized.value,
24
+ text: normalized.text,
25
+ isError: normalized.isError,
26
+ };
27
+ }
28
+
29
+ type NormalizedValue = Omit<NormalizedMcpOutput, "raw">;
30
+
31
+ function normalizeValue(value: unknown, depth: number, ancestors: Set<object>): NormalizedValue {
32
+ if (value === null || value === undefined) {
33
+ return { value, text: "", isError: false };
34
+ }
35
+ if (typeof value === "string") {
36
+ return normalizeText(value, depth, ancestors);
37
+ }
38
+ if (typeof value !== "object") {
39
+ return { value, text: String(value), isError: false };
40
+ }
41
+ if (depth >= MAX_MCP_OUTPUT_DEPTH || ancestors.has(value)) {
42
+ return { value, text: safeStringify(value), isError: false };
43
+ }
44
+
45
+ ancestors.add(value);
46
+ try {
47
+ if (Array.isArray(value)) {
48
+ return { value, text: safeStringify(value), isError: false };
49
+ }
50
+
51
+ const record = value as Record<string, unknown>;
52
+ const envelopeError = record.isError === true;
53
+
54
+ if (record.type === "text" && typeof record.text === "string") {
55
+ const normalized = normalizeText(record.text, depth + 1, ancestors);
56
+ return {
57
+ value: normalized.value,
58
+ text: record.text,
59
+ isError: envelopeError || normalized.isError,
60
+ };
61
+ }
62
+
63
+ if ("structuredContent" in record) {
64
+ const normalized = normalizeValue(record.structuredContent, depth + 1, ancestors);
65
+ return {
66
+ value: normalized.value,
67
+ text: firstMcpText(record.content) ?? normalized.text,
68
+ isError: envelopeError || normalized.isError,
69
+ };
70
+ }
71
+
72
+ if (isMcpContent(record.content)) {
73
+ const text = firstMcpText(record.content);
74
+ if (text !== null) {
75
+ const normalized = normalizeText(text, depth + 1, ancestors);
76
+ return {
77
+ value: normalized.value,
78
+ text,
79
+ isError: envelopeError || normalized.isError,
80
+ };
81
+ }
82
+ return {
83
+ value,
84
+ text: safeStringify(value),
85
+ isError: envelopeError,
86
+ };
87
+ }
88
+
89
+ if (isResultEnvelope(record)) {
90
+ const normalized = normalizeValue(record.result, depth + 1, ancestors);
91
+ return {
92
+ value: normalized.value,
93
+ text: normalized.text,
94
+ isError: envelopeError || normalized.isError,
95
+ };
96
+ }
97
+
98
+ return {
99
+ value,
100
+ text: safeStringify(value),
101
+ isError: envelopeError,
102
+ };
103
+ } finally {
104
+ ancestors.delete(value);
105
+ }
106
+ }
107
+
108
+ function normalizeText(text: string, depth: number, ancestors: Set<object>): NormalizedValue {
109
+ try {
110
+ const parsed: unknown = JSON.parse(text);
111
+ const normalized = normalizeValue(parsed, depth + 1, ancestors);
112
+ return {
113
+ value: normalized.value,
114
+ text,
115
+ isError: normalized.isError,
116
+ };
117
+ } catch {
118
+ return { value: text, text, isError: false };
119
+ }
120
+ }
121
+
122
+ function isMcpContent(value: unknown): value is readonly Record<string, unknown>[] {
123
+ return (
124
+ Array.isArray(value) &&
125
+ value.some(
126
+ (part) =>
127
+ part !== null &&
128
+ typeof part === "object" &&
129
+ typeof (part as { type?: unknown }).type === "string",
130
+ )
131
+ );
132
+ }
133
+
134
+ function firstMcpText(value: unknown): string | null {
135
+ if (!Array.isArray(value)) {
136
+ return null;
137
+ }
138
+ for (const part of value) {
139
+ if (
140
+ part !== null &&
141
+ typeof part === "object" &&
142
+ (part as { type?: unknown }).type === "text" &&
143
+ typeof (part as { text?: unknown }).text === "string"
144
+ ) {
145
+ return (part as { text: string }).text;
146
+ }
147
+ }
148
+ return null;
149
+ }
150
+
151
+ function isResultEnvelope(record: Record<string, unknown>): boolean {
152
+ return "result" in record && Object.keys(record).every((key) => RESULT_ENVELOPE_KEYS.has(key));
153
+ }
154
+
155
+ function safeStringify(value: unknown): string {
156
+ try {
157
+ return JSON.stringify(value) ?? "";
158
+ } catch {
159
+ return String(value);
160
+ }
161
+ }
package/src/types.ts CHANGED
@@ -408,13 +408,16 @@ export type CreateConnectionRequest = {
408
408
  metadata?: Record<string, unknown> | undefined;
409
409
  };
410
410
 
411
- export type ConnectOpenGeniSlackBotRequest = {
412
- /** Write-only Slack bot token. It is never returned by the API. */
413
- token: string;
411
+ export type OpenGeniSlackBotInstallRequest = {
414
412
  /** Existing OpenGeni Slack bot connection to reinstall in place. */
415
413
  connectionId?: string | undefined;
416
414
  };
417
415
 
416
+ export type OpenGeniSlackBotInstallStart = {
417
+ authorizationUrl: string;
418
+ expiresAt: string;
419
+ };
420
+
418
421
  export type UpdateConnectionRequest = {
419
422
  providerDomain?: string | undefined;
420
423
  subjectId?: string | null | undefined;
@@ -491,6 +494,7 @@ export type Session = {
491
494
  // the session carried none. Org-visible metadata, never a timeline event.
492
495
  instructions: string | null;
493
496
  resources: ResourceRef[];
497
+ skills: SessionSkill[];
494
498
  tools: ToolRef[];
495
499
  toolPolicy?: SessionToolPolicy | undefined;
496
500
  toolPolicyVersion?: number | undefined;
@@ -513,6 +517,7 @@ export type Session = {
513
517
  rigId: string | null;
514
518
  rigVersionId: string | null;
515
519
  firstPartyMcpPermissions: string[] | null;
520
+ firstPartyMcpTools: FirstPartyMcpToolName[] | null;
516
521
  mcpServers: SessionMcpServerMetadata[];
517
522
  parentSessionId: string | null;
518
523
  /** Immutable server-authored nested-agent lineage and policy snapshot. */
@@ -754,6 +759,9 @@ export const SESSION_EVENT_TYPES = [
754
759
  "goal.continuation",
755
760
  "system.update.pending",
756
761
  "system.update.delivered",
762
+ "system.update.superseded",
763
+ "system.update.cancelled",
764
+ "system.update.settled",
757
765
  "session.control.paused",
758
766
  "session.control.resumed",
759
767
  "session.control.steer_requested",
@@ -1560,6 +1568,8 @@ export type CreateSessionRequest = {
1560
1568
  // user-visible timeline. Trimmed, non-empty, max 32768 chars.
1561
1569
  instructions?: string | undefined;
1562
1570
  resources?: ResourceRef[] | undefined;
1571
+ /** Inline skills fixed onto this session; omitted children inherit them. */
1572
+ skills?: SessionSkill[] | undefined;
1563
1573
  tools?: ToolRef[] | undefined;
1564
1574
  metadata?: Record<string, unknown> | undefined;
1565
1575
  model?: string | undefined;
@@ -1588,6 +1598,7 @@ export type CreateSessionRequest = {
1588
1598
  expectedNewSessionDraftRevision?: number | undefined;
1589
1599
  maxNestedAgentDepth?: number | undefined;
1590
1600
  firstPartyMcpPermissions?: string[] | undefined;
1601
+ firstPartyMcpTools?: FirstPartyMcpToolName[] | undefined;
1591
1602
  mcpServers?: SessionMcpServerInput[] | undefined;
1592
1603
  // Shared-sandbox placement (mirror of `@opengeni/contracts` CreateSessionRequest.sandbox,
1593
1604
  // addendum 05 §D.1). Three-way union; OMITTED ⇒ the context-dependent server default
@@ -1653,6 +1664,58 @@ export type KnownPermission = (typeof KNOWN_PERMISSIONS)[number];
1653
1664
  */
1654
1665
  export type Permission = KnownPermission | (string & {});
1655
1666
 
1667
+ export type FirstPartyMcpToolName =
1668
+ | "set_session_title"
1669
+ | "goal_set"
1670
+ | "goal_update"
1671
+ | "goal_complete"
1672
+ | "goal_pause"
1673
+ | "memory_search"
1674
+ | "memory_save"
1675
+ | "memory_correct"
1676
+ | "sandboxes_list"
1677
+ | "sandbox_attach"
1678
+ | "sandbox_swap"
1679
+ | "run_on"
1680
+ | "sandbox_provision"
1681
+ | "rig_list"
1682
+ | "rig_get"
1683
+ | "rig_propose_change"
1684
+ | "rig_verify"
1685
+ | "rig_promote"
1686
+ | "sessions_list"
1687
+ | "session_get"
1688
+ | "session_events"
1689
+ | "session_create"
1690
+ | "session_send_message"
1691
+ | "session_pause"
1692
+ | "session_resume"
1693
+ | "session_steer"
1694
+ | "set_other_session_title"
1695
+ | "variable_set_list"
1696
+ | "environment_list"
1697
+ | "variable_set_set_variable"
1698
+ | "environment_set_variable"
1699
+ | "github_connect_link"
1700
+ | "github_token"
1701
+ | "github_repositories_list"
1702
+ | "social_connections_list"
1703
+ | "social_posts_recent"
1704
+ | "social_daily_analysis_context"
1705
+ | "scheduled_tasks_list"
1706
+ | "scheduled_tasks_get"
1707
+ | "scheduled_tasks_create"
1708
+ | "scheduled_tasks_update"
1709
+ | "scheduled_tasks_pause"
1710
+ | "scheduled_tasks_resume"
1711
+ | "scheduled_tasks_trigger"
1712
+ | "scheduled_tasks_delete"
1713
+ | "scheduled_task_runs_list"
1714
+ | "slack_bot_list_channels"
1715
+ | "slack_bot_channel_history"
1716
+ | "slack_bot_list_users"
1717
+ | "slack_bot_post_message";
1718
+
1656
1719
  export type ProductAccessMode = "local" | "configured" | "managed";
1657
1720
 
1658
1721
  export type ModelCapabilitySupportV1 = "supported" | "unsupported" | "unknown";
@@ -2365,8 +2428,20 @@ export type SessionQueueSnapshot = {
2365
2428
  /** The latest interrupted attempt has not yet durably proved physical quiescence. */
2366
2429
  stoppingPreviousAttempt: boolean;
2367
2430
  items: SessionTurn[];
2431
+ /** Canonical pending machine inputs. Events only invalidate this snapshot. */
2432
+ pendingInputs: SessionPendingInputPreview[];
2433
+ /** Exact next bounded input batch that will join an already-waiting prompt. */
2434
+ pendingInputAttachment: {
2435
+ turnId: string;
2436
+ inputIds: string[];
2437
+ } | null;
2368
2438
  };
2369
2439
 
2440
+ export type SessionPendingInputPreview = Pick<
2441
+ SessionSystemUpdate,
2442
+ "id" | "sessionId" | "kind" | "classification" | "sourceId" | "summary" | "createdAt"
2443
+ >;
2444
+
2370
2445
  export type SystemUpdateClassification = "success" | "failure" | "action_required" | "info";
2371
2446
 
2372
2447
  export type SessionSystemUpdateKind =
@@ -2378,7 +2453,6 @@ export type SessionSystemUpdateKind =
2378
2453
 
2379
2454
  export type SessionSystemUpdateState =
2380
2455
  | "pending"
2381
- | "deferred"
2382
2456
  | "delivered"
2383
2457
  | "cancelled"
2384
2458
  | "superseded"
@@ -2396,6 +2470,7 @@ export type SessionSystemUpdate = {
2396
2470
  lineage: Record<string, unknown>;
2397
2471
  state: SessionSystemUpdateState;
2398
2472
  deliveredTurnId: string | null;
2473
+ deliveredHistoryItemId: string | null;
2399
2474
  deliveredAt: string | null;
2400
2475
  createdAt: string;
2401
2476
  };
@@ -3125,6 +3200,8 @@ export type CapabilityPackSkill = {
3125
3200
  files: CapabilityPackSkillFile[];
3126
3201
  };
3127
3202
 
3203
+ export type SessionSkill = CapabilityPackSkill;
3204
+
3128
3205
  export type CapabilityPackVariableSetSpec = {
3129
3206
  description: string;
3130
3207
  requiredVariables: string[];
@@ -3313,9 +3390,10 @@ export type CapabilityCatalogItem = {
3313
3390
  enabledReason: string | null;
3314
3391
  /** The connection backing this enabled installation, or null when none is involved. */
3315
3392
  connectionRef: {
3316
- connectionId: string;
3393
+ connectionId?: string | undefined;
3317
3394
  providerDomain: string;
3318
3395
  kind: string;
3396
+ subjectScope?: "subject" | "workspace" | undefined;
3319
3397
  } | null;
3320
3398
  metadata: Record<string, unknown>;
3321
3399
  createdAt?: string | undefined;