@opengeni/sdk 0.27.0 → 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/README.md +28 -0
- package/dist/index.d.ts +31 -3
- package/dist/index.js +125 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +3 -0
- package/src/mcp-output.ts +161 -0
- package/src/types.ts +70 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/sdk",
|
|
3
|
-
"version": "0.
|
|
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/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";
|
|
@@ -322,6 +324,7 @@ export type {
|
|
|
322
324
|
SessionCommandReceipt,
|
|
323
325
|
SteerSessionQueueItemRequest,
|
|
324
326
|
WorkspaceInferenceControlResponse,
|
|
327
|
+
SessionPendingInputPreview,
|
|
325
328
|
SessionSystemUpdate,
|
|
326
329
|
SessionSystemUpdateKind,
|
|
327
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
|
@@ -517,6 +517,7 @@ export type Session = {
|
|
|
517
517
|
rigId: string | null;
|
|
518
518
|
rigVersionId: string | null;
|
|
519
519
|
firstPartyMcpPermissions: string[] | null;
|
|
520
|
+
firstPartyMcpTools: FirstPartyMcpToolName[] | null;
|
|
520
521
|
mcpServers: SessionMcpServerMetadata[];
|
|
521
522
|
parentSessionId: string | null;
|
|
522
523
|
/** Immutable server-authored nested-agent lineage and policy snapshot. */
|
|
@@ -758,6 +759,9 @@ export const SESSION_EVENT_TYPES = [
|
|
|
758
759
|
"goal.continuation",
|
|
759
760
|
"system.update.pending",
|
|
760
761
|
"system.update.delivered",
|
|
762
|
+
"system.update.superseded",
|
|
763
|
+
"system.update.cancelled",
|
|
764
|
+
"system.update.settled",
|
|
761
765
|
"session.control.paused",
|
|
762
766
|
"session.control.resumed",
|
|
763
767
|
"session.control.steer_requested",
|
|
@@ -1594,6 +1598,7 @@ export type CreateSessionRequest = {
|
|
|
1594
1598
|
expectedNewSessionDraftRevision?: number | undefined;
|
|
1595
1599
|
maxNestedAgentDepth?: number | undefined;
|
|
1596
1600
|
firstPartyMcpPermissions?: string[] | undefined;
|
|
1601
|
+
firstPartyMcpTools?: FirstPartyMcpToolName[] | undefined;
|
|
1597
1602
|
mcpServers?: SessionMcpServerInput[] | undefined;
|
|
1598
1603
|
// Shared-sandbox placement (mirror of `@opengeni/contracts` CreateSessionRequest.sandbox,
|
|
1599
1604
|
// addendum 05 §D.1). Three-way union; OMITTED ⇒ the context-dependent server default
|
|
@@ -1659,6 +1664,58 @@ export type KnownPermission = (typeof KNOWN_PERMISSIONS)[number];
|
|
|
1659
1664
|
*/
|
|
1660
1665
|
export type Permission = KnownPermission | (string & {});
|
|
1661
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
|
+
|
|
1662
1719
|
export type ProductAccessMode = "local" | "configured" | "managed";
|
|
1663
1720
|
|
|
1664
1721
|
export type ModelCapabilitySupportV1 = "supported" | "unsupported" | "unknown";
|
|
@@ -2371,8 +2428,20 @@ export type SessionQueueSnapshot = {
|
|
|
2371
2428
|
/** The latest interrupted attempt has not yet durably proved physical quiescence. */
|
|
2372
2429
|
stoppingPreviousAttempt: boolean;
|
|
2373
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;
|
|
2374
2438
|
};
|
|
2375
2439
|
|
|
2440
|
+
export type SessionPendingInputPreview = Pick<
|
|
2441
|
+
SessionSystemUpdate,
|
|
2442
|
+
"id" | "sessionId" | "kind" | "classification" | "sourceId" | "summary" | "createdAt"
|
|
2443
|
+
>;
|
|
2444
|
+
|
|
2376
2445
|
export type SystemUpdateClassification = "success" | "failure" | "action_required" | "info";
|
|
2377
2446
|
|
|
2378
2447
|
export type SessionSystemUpdateKind =
|
|
@@ -2384,7 +2453,6 @@ export type SessionSystemUpdateKind =
|
|
|
2384
2453
|
|
|
2385
2454
|
export type SessionSystemUpdateState =
|
|
2386
2455
|
| "pending"
|
|
2387
|
-
| "deferred"
|
|
2388
2456
|
| "delivered"
|
|
2389
2457
|
| "cancelled"
|
|
2390
2458
|
| "superseded"
|
|
@@ -2402,6 +2470,7 @@ export type SessionSystemUpdate = {
|
|
|
2402
2470
|
lineage: Record<string, unknown>;
|
|
2403
2471
|
state: SessionSystemUpdateState;
|
|
2404
2472
|
deliveredTurnId: string | null;
|
|
2473
|
+
deliveredHistoryItemId: string | null;
|
|
2405
2474
|
deliveredAt: string | null;
|
|
2406
2475
|
createdAt: string;
|
|
2407
2476
|
};
|