@oceanum/oceanumlab 4.6.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/LICENSE +29 -0
- package/README.md +116 -0
- package/lib/DatameshUI.d.ts +5 -0
- package/lib/DatameshUI.js +8 -0
- package/lib/DatameshUI.js.map +1 -0
- package/lib/DatameshWidget.d.ts +59 -0
- package/lib/DatameshWidget.js +573 -0
- package/lib/DatameshWidget.js.map +1 -0
- package/lib/DatasourceItem.d.ts +12 -0
- package/lib/DatasourceItem.js +47 -0
- package/lib/DatasourceItem.js.map +1 -0
- package/lib/aiLoop.d.ts +60 -0
- package/lib/aiLoop.js +85 -0
- package/lib/aiLoop.js.map +1 -0
- package/lib/chatRouter.d.ts +64 -0
- package/lib/chatRouter.js +225 -0
- package/lib/chatRouter.js.map +1 -0
- package/lib/constants.d.ts +14 -0
- package/lib/constants.js +15 -0
- package/lib/constants.js.map +1 -0
- package/lib/conversationPin.d.ts +68 -0
- package/lib/conversationPin.js +120 -0
- package/lib/conversationPin.js.map +1 -0
- package/lib/handler.d.ts +8 -0
- package/lib/handler.js +36 -0
- package/lib/handler.js.map +1 -0
- package/lib/index.d.ts +16 -0
- package/lib/index.js +273 -0
- package/lib/index.js.map +1 -0
- package/lib/kernelHandoff.d.ts +61 -0
- package/lib/kernelHandoff.js +236 -0
- package/lib/kernelHandoff.js.map +1 -0
- package/lib/notebookContext.d.ts +48 -0
- package/lib/notebookContext.js +118 -0
- package/lib/notebookContext.js.map +1 -0
- package/lib/notebookHost.d.ts +6 -0
- package/lib/notebookHost.js +72 -0
- package/lib/notebookHost.js.map +1 -0
- package/lib/notebookRun.d.ts +37 -0
- package/lib/notebookRun.js +70 -0
- package/lib/notebookRun.js.map +1 -0
- package/lib/progress.d.ts +43 -0
- package/lib/progress.js +103 -0
- package/lib/progress.js.map +1 -0
- package/lib/sse.d.ts +26 -0
- package/lib/sse.js +112 -0
- package/lib/sse.js.map +1 -0
- package/package.json +151 -0
- package/schema/datamesh-connect.json +35 -0
- package/src/DatameshUI.tsx +15 -0
- package/src/DatameshWidget.tsx +909 -0
- package/src/DatasourceItem.tsx +124 -0
- package/src/__tests__/aiLoop.spec.ts +304 -0
- package/src/__tests__/chatRouter.spec.ts +315 -0
- package/src/__tests__/conversationPin.spec.ts +236 -0
- package/src/__tests__/kernelHandoff.spec.ts +106 -0
- package/src/__tests__/notebookContext.spec.ts +97 -0
- package/src/__tests__/notebookHost.spec.ts +195 -0
- package/src/__tests__/notebookRun.spec.ts +95 -0
- package/src/__tests__/notebookSnapshot.spec.ts +62 -0
- package/src/__tests__/oceanumlab.spec.ts +9 -0
- package/src/__tests__/sse.spec.ts +304 -0
- package/src/aiLoop.ts +140 -0
- package/src/chatRouter.ts +329 -0
- package/src/constants.ts +16 -0
- package/src/conversationPin.ts +148 -0
- package/src/global.d.ts +5 -0
- package/src/handler.ts +46 -0
- package/src/index.ts +327 -0
- package/src/kernelHandoff.ts +284 -0
- package/src/notebookContext.ts +144 -0
- package/src/notebookHost.ts +97 -0
- package/src/notebookRun.ts +104 -0
- package/src/progress.ts +121 -0
- package/src/sse.ts +127 -0
- package/src/svg.d.ts +4 -0
- package/style/base.css +5 -0
- package/style/icons/oceanum-dark.svg +1 -0
- package/style/icons/oceanum-light.svg +1 -0
- package/style/icons/oceanum.png +0 -0
- package/style/icons/oceanum.svg +1 -0
- package/style/index.css +477 -0
- package/style/index.js +1 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the agent is doing right now, from the extension host to the widget
|
|
3
|
+
* (OCE-175).
|
|
4
|
+
*
|
|
5
|
+
* A channel is needed because the widget does not call the router: it issues
|
|
6
|
+
* the `oceanum-ai:submit-prompt` COMMAND, and command arguments must be JSON,
|
|
7
|
+
* so a callback cannot cross. The Stop button has the same constraint and
|
|
8
|
+
* solves it the same way -- an AbortController held in the plugin's closure.
|
|
9
|
+
*
|
|
10
|
+
* A module singleton rather than a JupyterLab `Signal`, because a Signal wants
|
|
11
|
+
* an owner object and there is no natural one here: the producer is a command
|
|
12
|
+
* handler and the consumer is a React component that mounts and unmounts
|
|
13
|
+
* independently of it.
|
|
14
|
+
*/
|
|
15
|
+
/** A phase the backend named, and the tool it is using if that is the phase. */
|
|
16
|
+
export interface Progress {
|
|
17
|
+
phase: string;
|
|
18
|
+
tool?: string;
|
|
19
|
+
}
|
|
20
|
+
type Listener = (progress: Progress | null) => void;
|
|
21
|
+
/** Subscribe. Returns the unsubscribe, for a React effect's cleanup. */
|
|
22
|
+
export declare function onProgress(listener: Listener): () => void;
|
|
23
|
+
/**
|
|
24
|
+
* Publish. `null` means "no longer working", which the widget uses to fall
|
|
25
|
+
* back to its own wording rather than leaving the last phase on screen after
|
|
26
|
+
* the answer has arrived.
|
|
27
|
+
*
|
|
28
|
+
* A listener that throws must not stop the others hearing, nor break the
|
|
29
|
+
* request: this is decoration, and a broken indicator is not worth failing an
|
|
30
|
+
* answer over.
|
|
31
|
+
*/
|
|
32
|
+
export declare function reportProgress(progress: Progress | null): void;
|
|
33
|
+
/**
|
|
34
|
+
* A reporter for one run: it publishes only while `isCurrent()` holds.
|
|
35
|
+
*
|
|
36
|
+
* A run that New chat or a newer prompt replaced is aborted, but it can take a
|
|
37
|
+
* while to unwind -- a cell that ignores the interrupt keeps it in its handoff
|
|
38
|
+
* -- and whatever it reports on the way out, a phase or its "no longer
|
|
39
|
+
* working", would land on the new run's progress line.
|
|
40
|
+
*/
|
|
41
|
+
export declare function reporterFor(isCurrent: () => boolean): (progress: Progress | null) => void;
|
|
42
|
+
export declare function describeProgress(progress: Progress | null): string;
|
|
43
|
+
export {};
|
package/lib/progress.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the agent is doing right now, from the extension host to the widget
|
|
3
|
+
* (OCE-175).
|
|
4
|
+
*
|
|
5
|
+
* A channel is needed because the widget does not call the router: it issues
|
|
6
|
+
* the `oceanum-ai:submit-prompt` COMMAND, and command arguments must be JSON,
|
|
7
|
+
* so a callback cannot cross. The Stop button has the same constraint and
|
|
8
|
+
* solves it the same way -- an AbortController held in the plugin's closure.
|
|
9
|
+
*
|
|
10
|
+
* A module singleton rather than a JupyterLab `Signal`, because a Signal wants
|
|
11
|
+
* an owner object and there is no natural one here: the producer is a command
|
|
12
|
+
* handler and the consumer is a React component that mounts and unmounts
|
|
13
|
+
* independently of it.
|
|
14
|
+
*/
|
|
15
|
+
const listeners = new Set();
|
|
16
|
+
/** Subscribe. Returns the unsubscribe, for a React effect's cleanup. */
|
|
17
|
+
export function onProgress(listener) {
|
|
18
|
+
listeners.add(listener);
|
|
19
|
+
return () => {
|
|
20
|
+
listeners.delete(listener);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Publish. `null` means "no longer working", which the widget uses to fall
|
|
25
|
+
* back to its own wording rather than leaving the last phase on screen after
|
|
26
|
+
* the answer has arrived.
|
|
27
|
+
*
|
|
28
|
+
* A listener that throws must not stop the others hearing, nor break the
|
|
29
|
+
* request: this is decoration, and a broken indicator is not worth failing an
|
|
30
|
+
* answer over.
|
|
31
|
+
*/
|
|
32
|
+
export function reportProgress(progress) {
|
|
33
|
+
for (const listener of listeners) {
|
|
34
|
+
try {
|
|
35
|
+
listener(progress);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
console.error('Oceanum AI: a progress listener threw', err);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A reporter for one run: it publishes only while `isCurrent()` holds.
|
|
44
|
+
*
|
|
45
|
+
* A run that New chat or a newer prompt replaced is aborted, but it can take a
|
|
46
|
+
* while to unwind -- a cell that ignores the interrupt keeps it in its handoff
|
|
47
|
+
* -- and whatever it reports on the way out, a phase or its "no longer
|
|
48
|
+
* working", would land on the new run's progress line.
|
|
49
|
+
*/
|
|
50
|
+
export function reporterFor(isCurrent) {
|
|
51
|
+
return progress => {
|
|
52
|
+
if (isCurrent()) {
|
|
53
|
+
reportProgress(progress);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* What each phase is, in the user's terms.
|
|
59
|
+
*
|
|
60
|
+
* An unlisted phase or tool falls back to something generic rather than
|
|
61
|
+
* showing its internal name: a new server-side tool should read as progress,
|
|
62
|
+
* not as a leak of what the agent is made of. And no phase at all reads as
|
|
63
|
+
* "Thinking…", which is what this said before there was anything better to
|
|
64
|
+
* say -- so a backend that does not stream, or a proxy that buffered the
|
|
65
|
+
* stream away, degrades to exactly the old behaviour rather than to a blank.
|
|
66
|
+
*/
|
|
67
|
+
const TOOL_LABELS = {
|
|
68
|
+
search_catalog: 'Searching the catalogue…',
|
|
69
|
+
get_datasource_info: 'Reading dataset details…',
|
|
70
|
+
save_memory: 'Saving a note…'
|
|
71
|
+
};
|
|
72
|
+
const PHASE_LABELS = {
|
|
73
|
+
generating: 'Thinking…',
|
|
74
|
+
interpreting: 'Reading the result…',
|
|
75
|
+
// Reported by the client, not the server: these two are the notebook's turn.
|
|
76
|
+
// Everything else here names something the agent is doing, and saying so
|
|
77
|
+
// while a cell runs would be actively false rather than merely vague.
|
|
78
|
+
running: 'Running the code…',
|
|
79
|
+
placing: 'Adding the code to the notebook…'
|
|
80
|
+
};
|
|
81
|
+
export function describeProgress(progress) {
|
|
82
|
+
var _a, _b;
|
|
83
|
+
if (!progress) {
|
|
84
|
+
return 'Thinking…';
|
|
85
|
+
}
|
|
86
|
+
if (progress.phase === 'tool') {
|
|
87
|
+
return (_a = labelFor(TOOL_LABELS, progress.tool)) !== null && _a !== void 0 ? _a : 'Looking something up…';
|
|
88
|
+
}
|
|
89
|
+
return (_b = labelFor(PHASE_LABELS, progress.phase)) !== null && _b !== void 0 ? _b : 'Working…';
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The label `labels` itself gives `name`, if any. Only its own entries: the
|
|
93
|
+
* name comes off the stream -- a tool name is whatever the model called -- and
|
|
94
|
+
* `__proto__` or `toString` must not reach into Object.prototype. That hands
|
|
95
|
+
* React an object or a function to render, and an object breaks the panel.
|
|
96
|
+
*/
|
|
97
|
+
function labelFor(labels, name) {
|
|
98
|
+
return name !== undefined &&
|
|
99
|
+
Object.prototype.hasOwnProperty.call(labels, name)
|
|
100
|
+
? labels[name]
|
|
101
|
+
: undefined;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAUH,MAAM,SAAS,GAAG,IAAI,GAAG,EAAY,CAAC;AAEtC,wEAAwE;AACxE,MAAM,UAAU,UAAU,CAAC,QAAkB;IAC3C,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO,GAAG,EAAE;QACV,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,QAAyB;IACtD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,SAAwB;IAExB,OAAO,QAAQ,CAAC,EAAE;QAChB,IAAI,SAAS,EAAE,EAAE,CAAC;YAChB,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,GAA2B;IAC1C,cAAc,EAAE,0BAA0B;IAC1C,mBAAmB,EAAE,0BAA0B;IAC/C,WAAW,EAAE,gBAAgB;CAC9B,CAAC;AAEF,MAAM,YAAY,GAA2B;IAC3C,UAAU,EAAE,WAAW;IACvB,YAAY,EAAE,qBAAqB;IACnC,6EAA6E;IAC7E,yEAAyE;IACzE,sEAAsE;IACtE,OAAO,EAAE,mBAAmB;IAC5B,OAAO,EAAE,kCAAkC;CAC5C,CAAC;AAEF,MAAM,UAAU,gBAAgB,CAAC,QAAyB;;IACxD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IAAI,QAAQ,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;QAC9B,OAAO,MAAA,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,mCAAI,uBAAuB,CAAC;IACzE,CAAC;IACD,OAAO,MAAA,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,mCAAI,UAAU,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,SAAS,QAAQ,CACf,MAA8B,EAC9B,IAAwB;IAExB,OAAO,IAAI,KAAK,SAAS;QACvB,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;QAClD,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;QACd,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC"}
|
package/lib/sse.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a Server-Sent Events body (OCE-175).
|
|
3
|
+
*
|
|
4
|
+
* Small and local rather than a dependency: SSE is a line format, the backend
|
|
5
|
+
* emits one `data:` line per event, and a library would bring a parser for the
|
|
6
|
+
* multi-line and retry-directive cases this stream does not use.
|
|
7
|
+
*
|
|
8
|
+
* Note it is NOT `EventSource`. That only issues GETs, and these are POSTs with
|
|
9
|
+
* a body and an auth header, which is why every client of this API hand-rolls
|
|
10
|
+
* the read.
|
|
11
|
+
*/
|
|
12
|
+
/** One frame off the wire. `data` is raw; the caller parses it. */
|
|
13
|
+
export interface SseEvent {
|
|
14
|
+
event: string;
|
|
15
|
+
data: string;
|
|
16
|
+
id?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Yield each event as it arrives.
|
|
20
|
+
*
|
|
21
|
+
* Decodes with `stream: true` so a multi-byte character split across two
|
|
22
|
+
* network chunks is reassembled rather than mangled -- a UTF-8 sequence has no
|
|
23
|
+
* obligation to arrive whole, and a dataset name with an accent in it is the
|
|
24
|
+
* kind of thing that finds this bug in production rather than in a test.
|
|
25
|
+
*/
|
|
26
|
+
export declare function readSse(body: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<SseEvent>;
|
package/lib/sse.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a Server-Sent Events body (OCE-175).
|
|
3
|
+
*
|
|
4
|
+
* Small and local rather than a dependency: SSE is a line format, the backend
|
|
5
|
+
* emits one `data:` line per event, and a library would bring a parser for the
|
|
6
|
+
* multi-line and retry-directive cases this stream does not use.
|
|
7
|
+
*
|
|
8
|
+
* Note it is NOT `EventSource`. That only issues GETs, and these are POSTs with
|
|
9
|
+
* a body and an auth header, which is why every client of this API hand-rolls
|
|
10
|
+
* the read.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Yield each event as it arrives.
|
|
14
|
+
*
|
|
15
|
+
* Decodes with `stream: true` so a multi-byte character split across two
|
|
16
|
+
* network chunks is reassembled rather than mangled -- a UTF-8 sequence has no
|
|
17
|
+
* obligation to arrive whole, and a dataset name with an accent in it is the
|
|
18
|
+
* kind of thing that finds this bug in production rather than in a test.
|
|
19
|
+
*/
|
|
20
|
+
export async function* readSse(body, signal) {
|
|
21
|
+
const reader = body.getReader();
|
|
22
|
+
const decoder = new TextDecoder();
|
|
23
|
+
let buffer = '';
|
|
24
|
+
/** Every complete frame currently in the buffer. Events are separated by a
|
|
25
|
+
* blank line; anything after the last one is partial and stays put. */
|
|
26
|
+
function* drain() {
|
|
27
|
+
let split = buffer.indexOf('\n\n');
|
|
28
|
+
while (split !== -1) {
|
|
29
|
+
const frame = buffer.slice(0, split);
|
|
30
|
+
buffer = buffer.slice(split + 2);
|
|
31
|
+
const parsed = parseFrame(frame);
|
|
32
|
+
if (parsed) {
|
|
33
|
+
yield parsed;
|
|
34
|
+
}
|
|
35
|
+
split = buffer.indexOf('\n\n');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
while (true) {
|
|
40
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const { done, value } = await reader.read();
|
|
44
|
+
if (done) {
|
|
45
|
+
// Flush the deferred `\r`, if any: no further chunk is coming, so it
|
|
46
|
+
// cannot be half of a CRLF and IS a line ending. Without this a stream
|
|
47
|
+
// using bare CR loses its final frame -- the terminator never forms.
|
|
48
|
+
buffer = normaliseNewlines(buffer, true);
|
|
49
|
+
yield* drain();
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
buffer = normaliseNewlines(buffer + decoder.decode(value, { stream: true }));
|
|
53
|
+
yield* drain();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
// Releases the reader's lock whether the consumer finished, threw, or
|
|
58
|
+
// stopped early -- a `break` in a for-await runs this. It does not cancel
|
|
59
|
+
// the body: the backend ends the stream after `done` or `error`, and Stop's
|
|
60
|
+
// abort closes the connection itself.
|
|
61
|
+
reader.releaseLock();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Collapse CRLF and bare CR to LF, so the rest of the parser can look for a
|
|
66
|
+
* single line ending.
|
|
67
|
+
*
|
|
68
|
+
* The spec allows all three, and our own backend sends LF -- but "our backend
|
|
69
|
+
* sends LF" is a statement about one hop. Anything between it and the browser
|
|
70
|
+
* may rewrite line endings, and the failure if it does is total rather than
|
|
71
|
+
* partial: the frame separator `\n\n` never matches `\r\n\r\n`, so ZERO events
|
|
72
|
+
* parse, the stream looks empty, and the caller reports the response as
|
|
73
|
+
* incomplete. Measured before this existed: 0 events from a well-formed CRLF
|
|
74
|
+
* stream.
|
|
75
|
+
*
|
|
76
|
+
* The trailing `\r` is held back, and that is the whole subtlety. A chunk may
|
|
77
|
+
* end mid-CRLF, with the `\n` arriving next; converting that `\r` to `\n` now
|
|
78
|
+
* and meeting its partner later would manufacture a blank line -- a frame
|
|
79
|
+
* boundary that was never sent, splitting one event into two malformed ones.
|
|
80
|
+
* So it waits for the next chunk, exactly as a split multi-byte character does.
|
|
81
|
+
*/
|
|
82
|
+
function normaliseNewlines(buffer, final = false) {
|
|
83
|
+
const held = !final && buffer.endsWith('\r') ? '\r' : '';
|
|
84
|
+
const body = held ? buffer.slice(0, -1) : buffer;
|
|
85
|
+
return body.replace(/\r\n/g, '\n').replace(/\r/g, '\n') + held;
|
|
86
|
+
}
|
|
87
|
+
function parseFrame(frame) {
|
|
88
|
+
let event = 'message';
|
|
89
|
+
let id;
|
|
90
|
+
const data = [];
|
|
91
|
+
for (const line of frame.split('\n')) {
|
|
92
|
+
// A comment. The backend sends these as keepalives during a long wait, and
|
|
93
|
+
// they carry nothing.
|
|
94
|
+
if (line.startsWith(':')) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (line.startsWith('event:')) {
|
|
98
|
+
event = line.slice('event:'.length).trim();
|
|
99
|
+
}
|
|
100
|
+
else if (line.startsWith('data:')) {
|
|
101
|
+
data.push(line.slice('data:'.length).trim());
|
|
102
|
+
}
|
|
103
|
+
else if (line.startsWith('id:')) {
|
|
104
|
+
id = line.slice('id:'.length).trim();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (data.length === 0) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
return { event, data: data.join('\n'), id };
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=sse.js.map
|
package/lib/sse.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oceanum/oceanumlab",
|
|
3
|
+
"version": "4.6.0",
|
|
4
|
+
"description": "A Jupyterlab extension to interact with the Oceanum.io platform",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"jupyter",
|
|
7
|
+
"jupyterlab",
|
|
8
|
+
"jupyterlab-extension"
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://github.com/oceanum-io/oceanumlab.git",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/oceanum-io/oceanumlab.git/issues"
|
|
13
|
+
},
|
|
14
|
+
"license": "BSD-3-Clause",
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "Oceanum",
|
|
17
|
+
"email": "developers@oceanum.science"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
|
|
21
|
+
"style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
|
|
22
|
+
"src/**/*.{ts,tsx}",
|
|
23
|
+
"schema/*.json"
|
|
24
|
+
],
|
|
25
|
+
"main": "lib/index.js",
|
|
26
|
+
"types": "lib/index.d.ts",
|
|
27
|
+
"style": "style/index.css",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/oceanum-io/oceanumlab.git"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "jlpm build:lib && jlpm build:labextension:dev",
|
|
34
|
+
"build:prod": "jlpm clean && jlpm build:lib:prod && jlpm build:labextension",
|
|
35
|
+
"build:labextension": "jupyter labextension build .",
|
|
36
|
+
"build:labextension:dev": "jupyter labextension build --development True .",
|
|
37
|
+
"build:lib": "tsc --sourceMap",
|
|
38
|
+
"build:lib:prod": "tsc",
|
|
39
|
+
"clean": "jlpm clean:lib",
|
|
40
|
+
"clean:lib": "rimraf lib tsconfig.tsbuildinfo",
|
|
41
|
+
"clean:lintcache": "rimraf .eslintcache .stylelintcache",
|
|
42
|
+
"clean:labextension": "rimraf oceanumlab/labextension oceanumlab/_version.py",
|
|
43
|
+
"clean:all": "jlpm clean:lib && jlpm clean:labextension && jlpm clean:lintcache",
|
|
44
|
+
"eslint": "jlpm eslint:check --fix",
|
|
45
|
+
"eslint:check": "ESLINT_USE_FLAT_CONFIG=false eslint . --cache --ext .ts,.tsx",
|
|
46
|
+
"install:extension": "jlpm build",
|
|
47
|
+
"lint": "jlpm stylelint && jlpm prettier && jlpm eslint",
|
|
48
|
+
"lint:check": "jlpm stylelint:check && jlpm prettier:check && jlpm eslint:check",
|
|
49
|
+
"prettier": "jlpm prettier:base --write --list-different",
|
|
50
|
+
"prettier:base": "prettier \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
|
|
51
|
+
"prettier:check": "jlpm prettier:base --check",
|
|
52
|
+
"stylelint": "jlpm stylelint:check --fix",
|
|
53
|
+
"stylelint:check": "stylelint --cache \"style/**/*.css\"",
|
|
54
|
+
"test": "jest --coverage",
|
|
55
|
+
"watch": "run-p watch:src watch:labextension",
|
|
56
|
+
"watch:src": "tsc -w --sourceMap",
|
|
57
|
+
"watch:labextension": "jupyter labextension watch ."
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@jupyterlab/application": "^4.6.3",
|
|
61
|
+
"@jupyterlab/apputils": "^4.7.3",
|
|
62
|
+
"@jupyterlab/cells": "^4.6.3",
|
|
63
|
+
"@jupyterlab/notebook": "^4.6.3",
|
|
64
|
+
"@jupyterlab/settingregistry": "^4.6.3",
|
|
65
|
+
"@phosphor-icons/react": "^2.1.10",
|
|
66
|
+
"marked": "^18.0.13"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@jupyterlab/builder": "^4.5.10",
|
|
70
|
+
"@jupyterlab/testutils": "^4.6.3",
|
|
71
|
+
"@types/jest": "^29.5.12",
|
|
72
|
+
"@types/json-schema": "^7.0.15",
|
|
73
|
+
"@types/react": "^18.2.75",
|
|
74
|
+
"@types/react-addons-linked-state-mixin": "^0.14.27",
|
|
75
|
+
"@typescript-eslint/eslint-plugin": "^7.6.0",
|
|
76
|
+
"@typescript-eslint/parser": "^7.6.0",
|
|
77
|
+
"css-loader": "^7.1.5",
|
|
78
|
+
"eslint": "^9.0.0",
|
|
79
|
+
"eslint-config-prettier": "^10.1.8",
|
|
80
|
+
"eslint-plugin-prettier": "^5.5.6",
|
|
81
|
+
"jest": "^29.7.0",
|
|
82
|
+
"npm-run-all": "^4.1.5",
|
|
83
|
+
"prettier": "^3.9.6",
|
|
84
|
+
"rimraf": "^6.1.3",
|
|
85
|
+
"source-map-loader": "^5.0.0",
|
|
86
|
+
"style-loader": "^4.0.0",
|
|
87
|
+
"stylelint": "^17.15.0",
|
|
88
|
+
"stylelint-config-recommended": "^18.0.0",
|
|
89
|
+
"stylelint-config-standard": "^40.0.0",
|
|
90
|
+
"stylelint-csstree-validator": "^4.0.0",
|
|
91
|
+
"stylelint-prettier": "^5.0.3",
|
|
92
|
+
"typescript": "~5.9.3",
|
|
93
|
+
"yjs": "^13.6.32"
|
|
94
|
+
},
|
|
95
|
+
"sideEffects": [
|
|
96
|
+
"style/*.css",
|
|
97
|
+
"style/index.js"
|
|
98
|
+
],
|
|
99
|
+
"styleModule": "style/index.js",
|
|
100
|
+
"publishConfig": {
|
|
101
|
+
"access": "public"
|
|
102
|
+
},
|
|
103
|
+
"jupyterlab": {
|
|
104
|
+
"extension": true,
|
|
105
|
+
"outputDir": "oceanumlab/labextension",
|
|
106
|
+
"schemaDir": "schema",
|
|
107
|
+
"webpackConfig": "./webpack.config.js"
|
|
108
|
+
},
|
|
109
|
+
"eslintIgnore": [
|
|
110
|
+
"node_modules",
|
|
111
|
+
"dist",
|
|
112
|
+
"coverage",
|
|
113
|
+
"**/*.d.ts",
|
|
114
|
+
"tests",
|
|
115
|
+
"**/__tests__",
|
|
116
|
+
"ui-tests"
|
|
117
|
+
],
|
|
118
|
+
"prettier": {
|
|
119
|
+
"singleQuote": true,
|
|
120
|
+
"trailingComma": "none",
|
|
121
|
+
"arrowParens": "avoid",
|
|
122
|
+
"endOfLine": "auto",
|
|
123
|
+
"overrides": [
|
|
124
|
+
{
|
|
125
|
+
"files": "package.json",
|
|
126
|
+
"options": {
|
|
127
|
+
"tabWidth": 4
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
"stylelint": {
|
|
133
|
+
"extends": [
|
|
134
|
+
"stylelint-config-recommended",
|
|
135
|
+
"stylelint-config-standard",
|
|
136
|
+
"stylelint-prettier/recommended"
|
|
137
|
+
],
|
|
138
|
+
"plugins": [
|
|
139
|
+
"stylelint-csstree-validator"
|
|
140
|
+
],
|
|
141
|
+
"rules": {
|
|
142
|
+
"csstree/validator": true,
|
|
143
|
+
"custom-property-pattern": null,
|
|
144
|
+
"no-descending-specificity": null,
|
|
145
|
+
"property-no-vendor-prefix": null,
|
|
146
|
+
"selector-class-pattern": "^([a-z][A-z\\d]*)(-{1,2}[A-z\\d]+)*$",
|
|
147
|
+
"selector-no-vendor-prefix": null,
|
|
148
|
+
"value-no-vendor-prefix": null
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"jupyter.lab.shortcuts": [],
|
|
3
|
+
"jupyter.lab.setting-icon": "oceanum:icon",
|
|
4
|
+
"jupyter.lab.setting-icon-label": "Oceanum",
|
|
5
|
+
"title": "Oceanum.io",
|
|
6
|
+
"description": "Oceanum.io JupyterLab extension settings",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"datameshToken": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"title": "Datamesh token",
|
|
12
|
+
"description": "Your Oceanum Datamesh token or JWT. Obtain at https://home.oceanum.io/account.",
|
|
13
|
+
"default": ""
|
|
14
|
+
},
|
|
15
|
+
"injectToken": {
|
|
16
|
+
"type": "boolean",
|
|
17
|
+
"title": "Inject token",
|
|
18
|
+
"description": "Inject Datamesh token into code.",
|
|
19
|
+
"default": false
|
|
20
|
+
},
|
|
21
|
+
"autoRunCode": {
|
|
22
|
+
"type": "boolean",
|
|
23
|
+
"title": "Auto-run code",
|
|
24
|
+
"description": "Run code cells the AI inserts as soon as they are placed.",
|
|
25
|
+
"default": false
|
|
26
|
+
},
|
|
27
|
+
"iterate": {
|
|
28
|
+
"type": "boolean",
|
|
29
|
+
"title": "Iterate",
|
|
30
|
+
"description": "After running, send each cell's output back to the AI so it can fix an error or take the next step. Only takes effect with Auto-run code on.",
|
|
31
|
+
"default": false
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"additionalProperties": false
|
|
35
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ReactWidget } from '@jupyterlab/apputils';
|
|
3
|
+
|
|
4
|
+
declare const DATAMESH_UI_SERVICE: string;
|
|
5
|
+
|
|
6
|
+
export class DatameshUI extends ReactWidget {
|
|
7
|
+
render(): React.ReactElement {
|
|
8
|
+
return (
|
|
9
|
+
<iframe
|
|
10
|
+
src={`${DATAMESH_UI_SERVICE}`}
|
|
11
|
+
className="datamesh-iframe"
|
|
12
|
+
></iframe>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
}
|