Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,24 @@ const { answers } = await nebo.decide({
- Billed like any model call; see pricing at https://neboai.com/pricing.
- Types: `DecideQuestion`, `DecideRequest`, `DecideAnswer`, `Decision`.

### `nebo.share({ name, content })`
Hand the owner a file to share. The file goes into his Work folder, beside
the chat the app is open on, and Nebo opens its own Share dialog on it. He
chooses who can open the link (anyone with it, a password, or only him) and
when it ends. The link is `neboai.com/s/<token>`; an HTML file opens there as
a live page. The page never makes or changes a link itself.

```js
const { artifact } = await nebo.share({ name: 'Launch deck.html', content: html });
// artifact → '/api/v1/files/Design Studio/Launch deck.html'
```

- `content` is the file's text (HTML, Markdown, CSV, SVG …), up to the
bot's upload limit.
- Sharing the same `name` again replaces the file in Work.
- Throws an `Error` whose message is the reason (400: a bad name or empty
content).

### `nebo.chat`
- `mount(element, options?)`: Embed chat UI
- `unmount()`: Remove chat UI
Expand Down
6 changes: 3 additions & 3 deletions dist/index.cjs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* - nebo.decide → typed decisions (choice / score / noul) with confidence
* - nebo.surfaces → real-time agent events (AG-UI)
* - nebo.a2ui → agent-driven UI via @a2ui/web_core (A2UI v0.9)
* - nebo.share → a file into the owner's Work, and Nebo's Share dialog on it
* - nebo.identity → agent context (name, persona, skills, inputs)
* - nebo.chat → embedded full-featured chat UI via iframe
*/
Expand All @@ -26,10 +27,12 @@ export { janus } from './janus';
export { decide } from './decide';
export { neboFetch } from './fetch';
export { identity } from './identity';
export { share } from './share';
export { chat } from './chat';
export { setAppId, setBaseUrl, getAppId, getBaseUrl } from './config';
export type { AgentResponse, InvokeOptions, JanusMessage, JanusOptions, StreamChunk, DecideQuestion, DecideRequest, DecideAnswer, Decision, } from './types';
export type { AgentIdentity } from './identity';
export type { ShareFile, Shared } from './share';
export type { ChatOptions, ChatContext } from './chat';
export type { A2UIMessageProcessor } from './a2ui';
export type { SurfaceEvent, NeboSurfaceEvent, SurfaceEventMap, RunStartedEvent, RunFinishedEvent, RunErrorEvent, TextStartEvent, TextContentEvent, TextEndEvent, ToolCallStartEvent, ToolCallEndEvent, StateSnapshotEvent, StateDeltaEvent, SurfaceCreateEvent, SurfaceUpdateEvent, SurfaceDeleteEvent, DataUpdateEvent, CustomEvent, } from './surfaces';
123 changes: 67 additions & 56 deletions dist/index.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
let i = null, d = null;
function h() {
if (i) return i;
let d = null, h = null;
function i() {
if (d) return d;
if (window.location.protocol === "neboapp:")
return i = window.location.hostname, i;
return d = window.location.hostname, d;
const s = window.location.pathname.match(/^\/apps\/([^/]+)\/ui/);
if (s)
return i = s[1], i;
return d = s[1], d;
const e = document.querySelector('meta[name="nebo-app-id"]');
if (e)
return i = e.getAttribute("content") || "", i;
return d = e.getAttribute("content") || "", d;
throw new Error(
'[nebo-sdk] Cannot detect app ID. In production, serve from /apps/{id}/ui/. In dev, add <meta name="nebo-app-id" content="your-id"> to index.html.'
);
}
function u() {
if (d) return d;
function l() {
if (h) return h;
if (window.location.protocol === "neboapp:")
return d = "http://localhost:27895", d;
return h = "http://localhost:27895", h;
const s = document.querySelector('meta[name="nebo-base-url"]');
return s ? (d = s.getAttribute("content") || "", d) : (d = window.location.origin, d);
return s ? (h = s.getAttribute("content") || "", h) : (h = window.location.origin, h);
}
function k(s) {
i = s;
d = s;
}
function x(s) {
d = s;
h = s;
}
async function D(s, e) {
const t = h(), n = u();
const t = i(), n = l();
if (s.startsWith("http://") || s.startsWith("https://")) {
const f = `${n}/api/v1/apps/${t}/http/proxy`, r = {};
e != null && e.headers && new Headers(e.headers).forEach((E, j) => {
Expand All @@ -38,14 +38,14 @@ async function D(s, e) {
method: (e == null ? void 0 : e.method) || "GET",
headers: r,
body: e != null && e.body ? String(e.body) : void 0
}, l = await (await fetch(f, {
}, u = await (await fetch(f, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(p)
})).json();
return new Response(l.body, {
status: l.status,
headers: l.headers
return new Response(u.body, {
status: u.status,
headers: u.headers
});
}
const a = s.startsWith("/") ? s : `/${s}`, o = `${n}/api/v1/apps/${t}/api${a}`;
Expand All @@ -54,7 +54,7 @@ async function D(s, e) {
class N {
constructor(e) {
this.ws = null, this.reconnectTimer = null, this.reconnectDelay = 1e3, this.maxReconnectDelay = 3e4, this._closed = !1, this.onopen = null, this.onmessage = null, this.onerror = null, this.onclose = null;
const t = h(), a = u().replace(/^http/, "ws");
const t = i(), a = l().replace(/^http/, "ws");
this.url = `${a}/ws/app/${t}`, this.connect();
}
connect() {
Expand Down Expand Up @@ -100,7 +100,7 @@ function J() {
} catch {
return;
}
e.type !== "app_data_changed" || !e.data || e.data.appId && e.data.appId !== h() || T.forEach((t) => t(e.data));
e.type !== "app_data_changed" || !e.data || e.data.appId && e.data.appId !== i() || T.forEach((t) => t(e.data));
});
}
function C(s) {
Expand All @@ -119,10 +119,10 @@ function C(s) {
}
}
function b(s) {
const e = h(), t = u();
const e = i(), t = l();
return s ? `${t}/api/v1/apps/${e}/storage/${encodeURIComponent(s)}` : `${t}/api/v1/apps/${e}/storage`;
}
const W = {
const P = {
async getItem(s) {
const e = await fetch(b(s));
if (e.status === 404) return null;
Expand Down Expand Up @@ -158,10 +158,10 @@ const W = {
}
};
function v(s) {
const e = h();
return `${u()}/api/v1/apps/${e}/agents/${s}`;
const e = i();
return `${l()}/api/v1/apps/${e}/agents/${s}`;
}
const P = {
const U = {
async invoke(s, e) {
return (await fetch(v("invoke"), {
method: "POST",
Expand Down Expand Up @@ -196,22 +196,22 @@ const P = {
o = p.pop() || "";
for (const y of p)
if (y.startsWith("data: ")) {
const l = y.slice(6);
if (l === "[DONE]") return;
const u = y.slice(6);
if (u === "[DONE]") return;
try {
yield JSON.parse(l);
yield JSON.parse(u);
} catch {
yield { text: l, done: !1 };
yield { text: u, done: !1 };
}
}
}
}
};
function I(s) {
const e = h();
return `${u()}/api/v1/apps/${e}/janus/${s}`;
const e = i();
return `${l()}/api/v1/apps/${e}/janus/${s}`;
}
const U = {
const W = {
async complete(s) {
const t = await (await fetch(I("complete"), {
method: "POST",
Expand Down Expand Up @@ -250,8 +250,8 @@ const U = {
}
}
};
async function F(s) {
const e = await fetch(`${u()}/api/v1/apps/${h()}/janus/decide`, {
async function R(s) {
const e = await fetch(`${l()}/api/v1/apps/${i()}/janus/decide`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(s)
Expand All @@ -260,6 +260,16 @@ async function F(s) {
throw new Error(t.error || `decide failed (${e.status})`);
return t;
}
async function F(s) {
const e = new URLSearchParams(window.location.search).get("thread") || "", t = await fetch(`${l()}/api/v1/apps/${i()}/share`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: s.name, content: s.content, thread: e })
}), n = await t.json().catch(() => ({}));
if (!t.ok)
throw new Error(n.error || `share failed (${t.status})`);
return n;
}
class M {
constructor() {
this.ws = null, this.listeners = /* @__PURE__ */ new Map(), this._connected = !1, this._a2uiHandler = null, this.state = {};
Expand Down Expand Up @@ -362,8 +372,8 @@ class M {
return t;
}
}
const O = new M();
class R {
const $ = new M();
class A {
constructor() {
this.processor = null, this.sendFn = null;
}
Expand Down Expand Up @@ -430,12 +440,12 @@ class R {
}));
}
}
const $ = new R();
const O = new A();
let w = null;
const A = {
const L = {
async get() {
if (w) return w;
const s = h(), e = u(), t = await fetch(`${e}/api/v1/apps/${s}/identity`);
const s = i(), e = l(), t = await fetch(`${e}/api/v1/apps/${s}/identity`);
if (!t.ok)
throw new Error(`[nebo-sdk] identity fetch failed: ${t.status}`);
return w = await t.json(), w;
Expand All @@ -452,10 +462,10 @@ function H(s) {
e(s.data);
}
}
const L = {
const q = {
mount(s, e) {
c && this.unmount();
const t = h(), n = u(), a = new URLSearchParams();
const t = i(), n = l(), a = new URLSearchParams();
e != null && e.placeholder && a.set("placeholder", e.placeholder), e != null && e.theme && a.set("theme", e.theme), e != null && e.borderless && a.set("borderless", "1"), e != null && e.contextId && a.set("ctx", e.contextId), e != null && e.scope && a.set("scope", e.scope);
const o = a.toString(), f = `${n}/chat-embed/${t}${o ? "?" + o : ""}`, r = document.createElement("iframe");
r.src = f, r.style.width = "100%", r.style.height = (e == null ? void 0 : e.height) || "400px", r.style.border = e != null && e.borderless ? "none" : "", r.style.borderRadius = e != null && e.borderless ? "0" : "0.5rem", r.style.colorScheme = "normal", r.setAttribute("allow", "microphone"), s.appendChild(r), c = r, S = s, m = H, window.addEventListener("message", m);
Expand Down Expand Up @@ -497,9 +507,9 @@ const L = {
);
}
};
class q {
class B {
constructor() {
this.fetch = D, this.WebSocket = N, this.storage = W, this.agents = P, this.janus = U, this.decide = F, this.surfaces = O, this.a2ui = $, this.identity = A, this.chat = L, O._a2uiHandler = (e) => $._handleMessage(e), $._setSendFn((e) => O._rawSend(e));
this.fetch = D, this.WebSocket = N, this.storage = P, this.agents = U, this.janus = W, this.decide = R, this.share = F, this.surfaces = $, this.a2ui = O, this.identity = L, this.chat = q, $._a2uiHandler = (e) => O._handleMessage(e), O._setSendFn((e) => $._rawSend(e));
}
/**
* Manually configure the SDK (optional — auto-detection works in most cases).
Expand All @@ -508,24 +518,25 @@ class q {
e.appId && k(e.appId), e.baseUrl && x(e.baseUrl);
}
}
const z = new q();
const G = new B();
export {
R as NeboA2UI,
q as NeboSDK,
A as NeboA2UI,
B as NeboSDK,
M as NeboSurfaces,
N as NeboWebSocket,
$ as a2ui,
P as agents,
L as chat,
F as decide,
h as getAppId,
u as getBaseUrl,
A as identity,
U as janus,
z as nebo,
O as a2ui,
U as agents,
q as chat,
R as decide,
i as getAppId,
l as getBaseUrl,
L as identity,
W as janus,
G as nebo,
D as neboFetch,
k as setAppId,
x as setBaseUrl,
W as storage,
O as surfaces
F as share,
P as storage,
$ as surfaces
};
Loading
Loading