@robosystems/core 0.12.0 → 0.13.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.
- package/components/console/ConsoleContent.js +57 -7
- package/components/console/graphAwareConfig.js +2 -0
- package/components/console/types.d.ts +6 -0
- package/hooks/index.d.ts +1 -0
- package/hooks/index.js +1 -0
- package/hooks/use-graph-writes.d.ts +6 -0
- package/hooks/use-graph-writes.js +22 -0
- package/index.d.ts +2 -2
- package/index.js +2 -2
- package/lib/graph-writes.d.ts +20 -0
- package/lib/graph-writes.js +19 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';
|
|
|
6
6
|
import { HiTerminal } from 'react-icons/hi';
|
|
7
7
|
import { useGraphContext } from '../../contexts';
|
|
8
8
|
import { useStreamingQuery } from '../../hooks';
|
|
9
|
+
import { emitGraphWrites, readGraphWrites, } from '../../lib/graph-writes';
|
|
9
10
|
import { ConsoleMarkdown } from './ConsoleMarkdown';
|
|
10
11
|
import { ProgressiveText } from './ProgressiveText';
|
|
11
12
|
function generateMessageId() {
|
|
@@ -53,6 +54,23 @@ function downloadText(filename, text, mime) {
|
|
|
53
54
|
anchor.click();
|
|
54
55
|
URL.revokeObjectURL(url);
|
|
55
56
|
}
|
|
57
|
+
const WRITE_LABELS = {
|
|
58
|
+
'create-taxonomy-block': 'Created taxonomy block',
|
|
59
|
+
'create-information-block': 'Created block',
|
|
60
|
+
'update-information-block': 'Updated block',
|
|
61
|
+
'assert-metrics': 'Asserted metrics',
|
|
62
|
+
'compute-metrics': 'Computed metrics',
|
|
63
|
+
'compute-forecast': 'Computed forecast',
|
|
64
|
+
'create-agent': 'Created counterparty',
|
|
65
|
+
'update-agent': 'Updated counterparty',
|
|
66
|
+
remember: 'Saved memory',
|
|
67
|
+
};
|
|
68
|
+
function describeWrite(write) {
|
|
69
|
+
var _a, _b;
|
|
70
|
+
const label = (_a = WRITE_LABELS[write.operation]) !== null && _a !== void 0 ? _a : write.operation;
|
|
71
|
+
const subject = (_b = write.name) !== null && _b !== void 0 ? _b : write.id;
|
|
72
|
+
return subject ? `${label}: ${subject}` : label;
|
|
73
|
+
}
|
|
56
74
|
function copyRowsJson(rows) {
|
|
57
75
|
var _a;
|
|
58
76
|
(_a = navigator.clipboard) === null || _a === void 0 ? void 0 : _a.writeText(JSON.stringify(rows, null, 2));
|
|
@@ -102,6 +120,9 @@ export function ConsoleContent({ config }) {
|
|
|
102
120
|
(config.enableRecall
|
|
103
121
|
? ` /recall - Recall semantic memories\n`
|
|
104
122
|
: '') +
|
|
123
|
+
(config.enableAuthor
|
|
124
|
+
? ` /do - Make a change (a block, a counterparty, a memory)\n`
|
|
125
|
+
: '') +
|
|
105
126
|
` /mcp - Connect an MCP client (sign in — no key)\n` +
|
|
106
127
|
` /mcp key - Mint a graph-scoped API key for header-only clients\n` +
|
|
107
128
|
` /help - Show this help message\n` +
|
|
@@ -145,6 +166,7 @@ export function ConsoleContent({ config }) {
|
|
|
145
166
|
setTerminalMessages((prev) => [...prev, message]);
|
|
146
167
|
}, []);
|
|
147
168
|
const addResultMessage = useCallback((content, data, cypher, opts) => {
|
|
169
|
+
var _a;
|
|
148
170
|
const message = {
|
|
149
171
|
id: generateMessageId(),
|
|
150
172
|
type: 'system',
|
|
@@ -154,6 +176,7 @@ export function ConsoleContent({ config }) {
|
|
|
154
176
|
cypher,
|
|
155
177
|
markdown: opts === null || opts === void 0 ? void 0 : opts.markdown,
|
|
156
178
|
footer: opts === null || opts === void 0 ? void 0 : opts.footer,
|
|
179
|
+
writes: ((_a = opts === null || opts === void 0 ? void 0 : opts.writes) === null || _a === void 0 ? void 0 : _a.length) ? opts.writes : undefined,
|
|
157
180
|
};
|
|
158
181
|
setTerminalMessages((prev) => [...prev, message]);
|
|
159
182
|
}, []);
|
|
@@ -328,7 +351,9 @@ export function ConsoleContent({ config }) {
|
|
|
328
351
|
setCurrentQueryStartTime(null);
|
|
329
352
|
}
|
|
330
353
|
};
|
|
331
|
-
|
|
354
|
+
// `operatorType` names an operator (`author` for /do); unset, the API
|
|
355
|
+
// chooses one for a question.
|
|
356
|
+
const executeOperatorQuery = async (userQuery, operatorType) => {
|
|
332
357
|
var _a;
|
|
333
358
|
if (!graphId) {
|
|
334
359
|
addErrorMessage(config.noSelectionError);
|
|
@@ -342,10 +367,11 @@ export function ConsoleContent({ config }) {
|
|
|
342
367
|
try {
|
|
343
368
|
const { clients } = await import('@robosystems/client/clients');
|
|
344
369
|
const history = conversationRef.current;
|
|
345
|
-
const
|
|
370
|
+
const request = Object.assign({ message: userQuery,
|
|
346
371
|
// `standard` gives the operator loop six tool turns; `quick` (three)
|
|
347
372
|
// was exhausted by schema + examples before the first query ran.
|
|
348
|
-
mode: 'standard' }, (history.length > 0 ? { history } : {}))
|
|
373
|
+
mode: 'standard' }, (history.length > 0 ? { history } : {}));
|
|
374
|
+
const options = {
|
|
349
375
|
mode: 'auto',
|
|
350
376
|
onProgress: (message, percentage) => {
|
|
351
377
|
if (isStale())
|
|
@@ -356,7 +382,10 @@ export function ConsoleContent({ config }) {
|
|
|
356
382
|
percentage,
|
|
357
383
|
});
|
|
358
384
|
},
|
|
359
|
-
}
|
|
385
|
+
};
|
|
386
|
+
const result = operatorType
|
|
387
|
+
? await clients.operator.executeOperator(graphId, operatorType, request, options)
|
|
388
|
+
: await clients.operator.executeQuery(graphId, request, options);
|
|
360
389
|
// The user switched graphs while the operator ran: the reset already
|
|
361
390
|
// cleared the console, so drop the answer rather than print it (and
|
|
362
391
|
// record it as history) under the new graph.
|
|
@@ -378,6 +407,9 @@ export function ConsoleContent({ config }) {
|
|
|
378
407
|
}
|
|
379
408
|
const duration = Date.now() - startTime;
|
|
380
409
|
const metadata = (result.metadata || {});
|
|
410
|
+
const writes = readGraphWrites(metadata);
|
|
411
|
+
// Pages showing this graph reload what the console just changed.
|
|
412
|
+
emitGraphWrites(requestGraphId, writes);
|
|
381
413
|
const creditsUsed = metadata.credits_consumed;
|
|
382
414
|
const resultCount = metadata.result_count;
|
|
383
415
|
// Prefer the structured outputs the operator loop now returns
|
|
@@ -429,7 +461,11 @@ export function ConsoleContent({ config }) {
|
|
|
429
461
|
// otherwise collapse under markdown). With no narrative, fall back to the
|
|
430
462
|
// plain footer, matching the direct-query result style.
|
|
431
463
|
if (narrative) {
|
|
432
|
-
addResultMessage(narrative, rows, cypher, {
|
|
464
|
+
addResultMessage(narrative, rows, cypher, {
|
|
465
|
+
markdown: true,
|
|
466
|
+
footer,
|
|
467
|
+
writes,
|
|
468
|
+
});
|
|
433
469
|
// Record the exchange for follow-ups. Only a narrative answer is
|
|
434
470
|
// worth carrying; the answer is clipped so history stays cheap.
|
|
435
471
|
conversationRef.current = [
|
|
@@ -439,7 +475,7 @@ export function ConsoleContent({ config }) {
|
|
|
439
475
|
].slice(-6);
|
|
440
476
|
}
|
|
441
477
|
else {
|
|
442
|
-
addResultMessage(footer, rows, cypher);
|
|
478
|
+
addResultMessage(footer, rows, cypher, { writes });
|
|
443
479
|
}
|
|
444
480
|
}
|
|
445
481
|
catch (error) {
|
|
@@ -596,6 +632,17 @@ export function ConsoleContent({ config }) {
|
|
|
596
632
|
}
|
|
597
633
|
return;
|
|
598
634
|
}
|
|
635
|
+
// Handle /do — the author operator, which may change the graph. Writes
|
|
636
|
+
// are never inferred from a question; they need this command.
|
|
637
|
+
if (config.enableAuthor && /^\/do(\s|$)/i.test(command)) {
|
|
638
|
+
const request = command.slice(3).trim();
|
|
639
|
+
if (!request) {
|
|
640
|
+
addErrorMessage('Usage: /do <change>\n\nExamples:\n /do add Notion Labs as a vendor\n /do remember that we report ARPC on subscription revenue only');
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
await executeOperatorQuery(request, 'author');
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
599
646
|
// Handle /recall command — built-in only when the target supports
|
|
600
647
|
// semantic memory (user graphs; shared repositories reject it). When
|
|
601
648
|
// disabled it falls through to the unknown-command branch below.
|
|
@@ -702,7 +749,10 @@ export function ConsoleContent({ config }) {
|
|
|
702
749
|
? 'text-green-400'
|
|
703
750
|
: message.type === 'error'
|
|
704
751
|
? 'text-red-400'
|
|
705
|
-
: 'text-gray-300'}`, children: [message.type === 'user' && (_jsx("span", { className: "mr-2 text-green-500", children: "$" })), message.isAnimating ? (_jsx(ProgressiveText, { text: message.content, onComplete: () => handleAnimationComplete(message.id), onUpdate: scrollToBottom })) : message.markdown ? (_jsx(ConsoleMarkdown, { content: message.content })) : (message.content)] }), message.
|
|
752
|
+
: 'text-gray-300'}`, children: [message.type === 'user' && (_jsx("span", { className: "mr-2 text-green-500", children: "$" })), message.isAnimating ? (_jsx(ProgressiveText, { text: message.content, onComplete: () => handleAnimationComplete(message.id), onUpdate: scrollToBottom })) : message.markdown ? (_jsx(ConsoleMarkdown, { content: message.content })) : (message.content)] }), message.writes && (_jsxs("div", { className: "mt-3 rounded border border-emerald-900/60 bg-emerald-950/30 px-3 py-2", children: [_jsx("div", { className: "text-xs tracking-wider text-emerald-400 uppercase", children: "Changes made" }), _jsx("ul", { className: "mt-1 space-y-0.5 text-sm text-emerald-200", children: message.writes.map((write, idx) => {
|
|
753
|
+
var _a;
|
|
754
|
+
return (_jsxs("li", { children: ["\u2713 ", describeWrite(write)] }, `${write.operation}-${(_a = write.id) !== null && _a !== void 0 ? _a : idx}`));
|
|
755
|
+
}) })] })), message.footer && (_jsx("div", { className: "mt-3 text-xs whitespace-pre-wrap text-gray-500", children: message.footer })), message.cypher && (_jsxs("div", { className: "mt-3 overflow-hidden rounded border border-gray-800 bg-gray-900/40", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-800 px-3 py-1.5", children: [_jsx("span", { className: "text-xs tracking-wider text-gray-500 uppercase", children: "Generated Cypher" }), _jsx("button", { onClick: () => { var _a; return handleCommand(`/query ${(_a = message.cypher) !== null && _a !== void 0 ? _a : ''}`); }, className: "rounded bg-cyan-600/90 px-2 py-0.5 text-xs font-medium text-white transition-colors hover:bg-cyan-600", children: "Run" })] }), _jsx("pre", { className: "overflow-x-auto px-3 py-2 font-mono text-xs whitespace-pre-wrap text-cyan-300", children: message.cypher })] })), message.data && message.data.length > 0 && (_jsxs("div", { className: "mt-3 overflow-hidden rounded border border-gray-800", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-800 bg-gray-900 px-4 py-2", children: [_jsxs("span", { className: "text-xs text-gray-500", children: [message.data.length, " row", message.data.length === 1 ? '' : 's'] }), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { onClick: () => copyRowsJson(message.data), className: "rounded border border-gray-700 px-2 py-0.5 text-xs text-gray-300 transition-colors hover:bg-gray-800", children: "Copy JSON" }), _jsx("button", { onClick: () => downloadText('results.csv', rowsToCsv(message.data), 'text/csv'), className: "rounded border border-gray-700 px-2 py-0.5 text-xs text-gray-300 transition-colors hover:bg-gray-800", children: "Download CSV" })] })] }), _jsx("div", { className: "max-h-96 overflow-auto", children: _jsxs("table", { className: "w-full border-collapse text-xs", children: [_jsx("thead", { className: "sticky top-0", children: _jsx("tr", { className: "border-b border-gray-800 bg-gray-900", children: Object.keys(message.data[0]).map((key) => (_jsx("th", { className: "px-4 py-2 text-left font-semibold whitespace-nowrap text-cyan-400", children: key }, key))) }) }), _jsx("tbody", { children: message.data
|
|
706
756
|
.slice(0, MAX_TABLE_ROWS)
|
|
707
757
|
.map((row, idx) => (_jsx("tr", { className: "border-b border-gray-900 hover:bg-gray-900/50", children: Object.keys(message.data[0]).map((key) => {
|
|
708
758
|
const value = row[key];
|
|
@@ -404,6 +404,8 @@ export function buildGraphAwareConsoleConfig(graph, branding) {
|
|
|
404
404
|
noSelectionError: (_c = branding.noSelectionError) !== null && _c !== void 0 ? _c : 'No graph selected. Please select a graph first.',
|
|
405
405
|
// Semantic memory is per-user-graph; shared repositories reject it.
|
|
406
406
|
enableRecall: !isRepository,
|
|
407
|
+
// Writes need a user graph; the API also checks the write role.
|
|
408
|
+
enableAuthor: !isRepository,
|
|
407
409
|
};
|
|
408
410
|
}
|
|
409
411
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { GraphWrite } from '../../lib/graph-writes';
|
|
1
2
|
export interface SampleQuery {
|
|
2
3
|
name: string;
|
|
3
4
|
query: string;
|
|
@@ -65,6 +66,9 @@ export interface ConsoleConfig {
|
|
|
65
66
|
* shared repositories don't support memory, so the graph-aware builder
|
|
66
67
|
* enables it only for user graphs. */
|
|
67
68
|
enableRecall?: boolean;
|
|
69
|
+
/** Enable `/do`, which runs the write-capable author operator. The API
|
|
70
|
+
* gates it on the graph write role; off for shared repositories. */
|
|
71
|
+
enableAuthor?: boolean;
|
|
68
72
|
/** Extra slash commands beyond the built-in set */
|
|
69
73
|
extraCommands?: ConsoleExtraCommand[];
|
|
70
74
|
}
|
|
@@ -90,4 +94,6 @@ export interface TerminalMessage {
|
|
|
90
94
|
* breaks survive markdown rendering.
|
|
91
95
|
*/
|
|
92
96
|
footer?: string;
|
|
97
|
+
/** Changes the author operator made, shown as a receipt below the answer. */
|
|
98
|
+
writes?: GraphWrite[];
|
|
93
99
|
}
|
package/hooks/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { useApiError } from './use-api-error';
|
|
2
2
|
export { useCrossAppLink, type CrossAppTarget, type OpenCrossAppOptions, type UseCrossAppLinkResult, } from './use-cross-app-link';
|
|
3
|
+
export { useGraphWrites } from './use-graph-writes';
|
|
3
4
|
export { useMediaQuery } from './use-media-query';
|
|
4
5
|
export { useStreamingQuery } from './use-streaming-query';
|
|
5
6
|
export { useToast, type ToastMessage } from './use-toast';
|
package/hooks/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { useApiError } from './use-api-error';
|
|
2
2
|
export { useCrossAppLink, } from './use-cross-app-link';
|
|
3
|
+
export { useGraphWrites } from './use-graph-writes';
|
|
3
4
|
export { useMediaQuery } from './use-media-query';
|
|
4
5
|
export { useStreamingQuery } from './use-streaming-query';
|
|
5
6
|
export { useToast } from './use-toast';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type GraphWrite } from '../lib/graph-writes';
|
|
2
|
+
/**
|
|
3
|
+
* Calls `onWrites` when the console changes the graph a page is showing, so
|
|
4
|
+
* the page can reload what it displays. Writes to other graphs are ignored.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useGraphWrites(graphId: string | null | undefined, onWrites: (writes: GraphWrite[]) => void): void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
|
+
import { GRAPH_WRITES_EVENT, } from '../lib/graph-writes';
|
|
4
|
+
/**
|
|
5
|
+
* Calls `onWrites` when the console changes the graph a page is showing, so
|
|
6
|
+
* the page can reload what it displays. Writes to other graphs are ignored.
|
|
7
|
+
*/
|
|
8
|
+
export function useGraphWrites(graphId, onWrites) {
|
|
9
|
+
const onWritesRef = useRef(onWrites);
|
|
10
|
+
onWritesRef.current = onWrites;
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!graphId)
|
|
13
|
+
return;
|
|
14
|
+
const handler = (event) => {
|
|
15
|
+
const detail = event.detail;
|
|
16
|
+
if ((detail === null || detail === void 0 ? void 0 : detail.graphId) === graphId)
|
|
17
|
+
onWritesRef.current(detail.writes);
|
|
18
|
+
};
|
|
19
|
+
window.addEventListener(GRAPH_WRITES_EVENT, handler);
|
|
20
|
+
return () => window.removeEventListener(GRAPH_WRITES_EVENT, handler);
|
|
21
|
+
}, [graphId]);
|
|
22
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -2,9 +2,9 @@ export * as AuthCore from './auth-core';
|
|
|
2
2
|
export { clearToken, getAuthHeader, getRefreshToken, getToken, getValidToken, handleAuthResponse, hasValidToken, storeToken, } from './auth-core/token-storage';
|
|
3
3
|
export { clearUserCookies, clearUserLocalStorage, clearUserSessionStorage, listUserData, performLogoutCleanup, resetUIState, } from './auth-core/cleanup';
|
|
4
4
|
export { AppSwitcher, AuthGuard, AuthProvider, LoginRedirector, SignInForm, SignUpForm, useAuth, } from './auth-components';
|
|
5
|
-
export { useApiError, useMediaQuery, useToast, useUser, useUserLimits, type ToastMessage, } from './hooks';
|
|
5
|
+
export { useApiError, useGraphWrites, useMediaQuery, useToast, useUser, useUserLimits, type ToastMessage, } from './hooks';
|
|
6
6
|
export { createGraphContext, createGraphProvider, createUseGraphContext, EntityProvider, GraphContext, GraphProvider, OrgProvider, ServiceOfferingsProvider, SidebarProvider, useEntity, useGraphContext, useOrg, useServiceOfferings, useSidebarContext, type EntityContextValue, type EntityProviderProps, type GraphContextValue, type GraphProviderProps, type GraphState, type OrgContextState, type OrgContextValue, type OrgProviderProps, type ServiceOfferings, } from './contexts';
|
|
7
|
-
export { clientGraphCookie, clientSidebarCookie, createMcpConnectorUrl, entityCookie, graphCookie, sidebarCookie, type EntityCookie, type GraphCookie, type McpConnectorUrl, type SidebarCookie, } from './lib';
|
|
7
|
+
export { clientGraphCookie, clientSidebarCookie, createMcpConnectorUrl, emitGraphWrites, entityCookie, GRAPH_WRITES_EVENT, graphCookie, readGraphWrites, sidebarCookie, type EntityCookie, type GraphCookie, type GraphWrite, type GraphWritesDetail, type McpConnectorUrl, type SidebarCookie, } from './lib';
|
|
8
8
|
export { ApiError, errorStatus, extractErrorDetail, isApiError, isSessionRejection, isTransientError, toApiError, unwrapSdk, type SdkResult, } from './lib/sdk-errors';
|
|
9
9
|
export { generateEntityUri, isUUID, UUID_REGEX } from './utils';
|
|
10
10
|
export { clearGraphSelection, getGraphSelection, persistGraphSelection, } from './actions/graph-actions';
|
package/index.js
CHANGED
|
@@ -8,7 +8,7 @@ export { clearUserCookies, clearUserLocalStorage, clearUserSessionStorage, listU
|
|
|
8
8
|
// Export auth-components
|
|
9
9
|
export { AppSwitcher, AuthGuard, AuthProvider, LoginRedirector, SignInForm, SignUpForm, useAuth, } from './auth-components';
|
|
10
10
|
// Export hooks
|
|
11
|
-
export { useApiError, useMediaQuery, useToast, useUser, useUserLimits, } from './hooks';
|
|
11
|
+
export { useApiError, useGraphWrites, useMediaQuery, useToast, useUser, useUserLimits, } from './hooks';
|
|
12
12
|
// Export contexts
|
|
13
13
|
export {
|
|
14
14
|
// Graph context exports
|
|
@@ -20,7 +20,7 @@ OrgProvider,
|
|
|
20
20
|
// Service offerings context
|
|
21
21
|
ServiceOfferingsProvider, SidebarProvider, useEntity, useGraphContext, useOrg, useServiceOfferings, useSidebarContext, } from './contexts';
|
|
22
22
|
// Export lib utilities
|
|
23
|
-
export { clientGraphCookie, clientSidebarCookie, createMcpConnectorUrl, entityCookie, graphCookie, sidebarCookie, } from './lib';
|
|
23
|
+
export { clientGraphCookie, clientSidebarCookie, createMcpConnectorUrl, emitGraphWrites, entityCookie, GRAPH_WRITES_EVENT, graphCookie, readGraphWrites, sidebarCookie, } from './lib';
|
|
24
24
|
// Export the SDK error seam (unwrap an SDK result or throw ApiError)
|
|
25
25
|
export { ApiError, errorStatus, extractErrorDetail, isApiError, isSessionRejection, isTransientError, toApiError, unwrapSdk, } from './lib/sdk-errors';
|
|
26
26
|
// Export utils
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A write an operator made, as the API reports it in `metadata.writes`.
|
|
3
|
+
* `id` is null when the tool returned no object id (for example a memory).
|
|
4
|
+
*/
|
|
5
|
+
export interface GraphWrite {
|
|
6
|
+
operation: string;
|
|
7
|
+
id: string | null;
|
|
8
|
+
name: string | null;
|
|
9
|
+
block_type?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface GraphWritesDetail {
|
|
12
|
+
graphId: string;
|
|
13
|
+
writes: GraphWrite[];
|
|
14
|
+
}
|
|
15
|
+
/** Window event fired after the console changes a graph. */
|
|
16
|
+
export declare const GRAPH_WRITES_EVENT = "robosystems:graph-writes";
|
|
17
|
+
/** Tell any page showing `graphId` that it changed. No-op when nothing was written. */
|
|
18
|
+
export declare function emitGraphWrites(graphId: string, writes: GraphWrite[]): void;
|
|
19
|
+
/** Read `metadata.writes` defensively: anything malformed yields no writes. */
|
|
20
|
+
export declare function readGraphWrites(metadata: unknown): GraphWrite[];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Window event fired after the console changes a graph. */
|
|
2
|
+
export const GRAPH_WRITES_EVENT = 'robosystems:graph-writes';
|
|
3
|
+
/** Tell any page showing `graphId` that it changed. No-op when nothing was written. */
|
|
4
|
+
export function emitGraphWrites(graphId, writes) {
|
|
5
|
+
if (typeof window === 'undefined' || writes.length === 0)
|
|
6
|
+
return;
|
|
7
|
+
window.dispatchEvent(new CustomEvent(GRAPH_WRITES_EVENT, {
|
|
8
|
+
detail: { graphId, writes },
|
|
9
|
+
}));
|
|
10
|
+
}
|
|
11
|
+
/** Read `metadata.writes` defensively: anything malformed yields no writes. */
|
|
12
|
+
export function readGraphWrites(metadata) {
|
|
13
|
+
const writes = metadata === null || metadata === void 0 ? void 0 : metadata.writes;
|
|
14
|
+
if (!Array.isArray(writes))
|
|
15
|
+
return [];
|
|
16
|
+
return writes.filter((w) => typeof w === 'object' &&
|
|
17
|
+
w !== null &&
|
|
18
|
+
typeof w.operation === 'string');
|
|
19
|
+
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { clientSidebarCookie, sidebarCookie, type SidebarCookie, } from './sidebar-cookie';
|
|
2
2
|
export { clientGraphCookie, graphCookie, type GraphCookie, } from './graph-cookie';
|
|
3
3
|
export { entityCookie, type EntityCookie } from './entity-cookie';
|
|
4
|
+
export { GRAPH_WRITES_EVENT, emitGraphWrites, readGraphWrites, type GraphWrite, type GraphWritesDetail, } from './graph-writes';
|
|
4
5
|
export { createMcpConnectorUrl, type McpConnectorUrl } from './mcp-connector';
|
|
5
6
|
export { ApiError, errorStatus, extractErrorDetail, isApiError, isSessionRejection, isTransientError, toApiError, unwrapSdk, type SdkResult, } from './sdk-errors';
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { clientSidebarCookie, sidebarCookie, } from './sidebar-cookie';
|
|
2
2
|
export { clientGraphCookie, graphCookie, } from './graph-cookie';
|
|
3
3
|
export { entityCookie } from './entity-cookie';
|
|
4
|
+
export { GRAPH_WRITES_EVENT, emitGraphWrites, readGraphWrites, } from './graph-writes';
|
|
4
5
|
export { createMcpConnectorUrl } from './mcp-connector';
|
|
5
6
|
export { ApiError, errorStatus, extractErrorDetail, isApiError, isSessionRejection, isTransientError, toApiError, unwrapSdk, } from './sdk-errors';
|
package/package.json
CHANGED