@opengeni/runtime 2.6.0-canary.0 → 2.6.0-canary.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/dist/{chunk-Y3NUMLY2.js → chunk-XQOF5GG5.js} +91 -37
- package/dist/chunk-XQOF5GG5.js.map +1 -0
- package/dist/first-party-client.d.ts +19 -0
- package/dist/index.d.ts +4 -5
- package/dist/index.js +3 -1
- package/dist/operational-instructions.d.ts +1 -1
- package/dist/runtime-skills.d.ts +2 -0
- package/dist/workspace-tool-gateway.js +1 -1
- package/package.json +11 -11
- package/src/bundled_default_skills/opengeni-visualize/SKILL.md +313 -0
- package/src/bundled_default_skills/opengeni-visualize/assets/base.css +1015 -0
- package/src/bundled_default_skills/opengeni-visualize/assets/helpers.html +349 -0
- package/src/bundled_management_skills/opengeni-skills/SKILL.md +25 -19
- package/src/bundled_site_skills/opengeni-sites/SKILL.md +69 -2
- package/src/first-party-client.ts +70 -0
- package/src/index.ts +12 -11
- package/src/operational-instructions.ts +3 -13
- package/src/runtime-skills.ts +8 -5
- package/src/workspace-governance.ts +1 -3
- package/dist/chunk-Y3NUMLY2.js.map +0 -1
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
<!--__INLINE_VISUALIZATION_FRAGMENT__-->
|
|
2
|
+
<script src="https://unpkg.com/@floating-ui/core@1.7.3/dist/floating-ui.core.umd.min.js"></script>
|
|
3
|
+
<script src="https://unpkg.com/@floating-ui/dom@1.7.4/dist/floating-ui.dom.umd.min.js"></script>
|
|
4
|
+
<script>
|
|
5
|
+
(() => {
|
|
6
|
+
if (window.FloatingUIDOM == null) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const { autoUpdate, computePosition, flip, offset, shift, size } = window.FloatingUIDOM;
|
|
10
|
+
const tooltipPlacements = new Set(["top", "right", "bottom", "left"]);
|
|
11
|
+
const tooltipId = `codex-visualization-tooltip-${
|
|
12
|
+
window.crypto?.randomUUID?.() ?? Date.now().toString(36)
|
|
13
|
+
}`;
|
|
14
|
+
const tooltipGap = 5;
|
|
15
|
+
const hoverDelay = 700;
|
|
16
|
+
const skipDelay = 300;
|
|
17
|
+
let activeTrigger = null;
|
|
18
|
+
let pendingTrigger = null;
|
|
19
|
+
let tooltip = null;
|
|
20
|
+
let openTimeout = null;
|
|
21
|
+
let autoUpdateCleanup = null;
|
|
22
|
+
let positionRequest = 0;
|
|
23
|
+
let skipDelayUntil = 0;
|
|
24
|
+
let lastPointerWasTouch = false;
|
|
25
|
+
let pinnedByTouch = false;
|
|
26
|
+
|
|
27
|
+
const getTrigger = (target) =>
|
|
28
|
+
target?.nodeType === Node.ELEMENT_NODE ? target.closest("[data-tooltip]") : null;
|
|
29
|
+
const containsTarget = (trigger, target) =>
|
|
30
|
+
target?.nodeType != null && trigger.contains(target);
|
|
31
|
+
const getContent = (trigger) => trigger.getAttribute("data-tooltip")?.trim() ?? "";
|
|
32
|
+
const getPlacement = (trigger) => {
|
|
33
|
+
const placement = trigger.getAttribute("data-tooltip-placement");
|
|
34
|
+
return tooltipPlacements.has(placement) ? placement : "top";
|
|
35
|
+
};
|
|
36
|
+
const getTooltip = () => {
|
|
37
|
+
if (tooltip == null) {
|
|
38
|
+
tooltip = document.createElement("div");
|
|
39
|
+
tooltip.id = tooltipId;
|
|
40
|
+
tooltip.className = "tooltip";
|
|
41
|
+
tooltip.setAttribute("role", "tooltip");
|
|
42
|
+
}
|
|
43
|
+
return tooltip;
|
|
44
|
+
};
|
|
45
|
+
const setDescribedBy = (trigger, described) => {
|
|
46
|
+
const ids = new Set(
|
|
47
|
+
(trigger.getAttribute("aria-describedby") ?? "").split(/\s+/).filter(Boolean),
|
|
48
|
+
);
|
|
49
|
+
if (described) {
|
|
50
|
+
ids.add(tooltipId);
|
|
51
|
+
} else {
|
|
52
|
+
ids.delete(tooltipId);
|
|
53
|
+
}
|
|
54
|
+
if (ids.size === 0) {
|
|
55
|
+
trigger.removeAttribute("aria-describedby");
|
|
56
|
+
} else {
|
|
57
|
+
trigger.setAttribute("aria-describedby", [...ids].join(" "));
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const clearOpenTimeout = () => {
|
|
61
|
+
if (openTimeout != null) {
|
|
62
|
+
window.clearTimeout(openTimeout);
|
|
63
|
+
openTimeout = null;
|
|
64
|
+
}
|
|
65
|
+
pendingTrigger = null;
|
|
66
|
+
};
|
|
67
|
+
const closeTooltip = (activateSkipDelay = true) => {
|
|
68
|
+
clearOpenTimeout();
|
|
69
|
+
pinnedByTouch = false;
|
|
70
|
+
positionRequest += 1;
|
|
71
|
+
autoUpdateCleanup?.();
|
|
72
|
+
autoUpdateCleanup = null;
|
|
73
|
+
if (activeTrigger == null) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
setDescribedBy(activeTrigger, false);
|
|
77
|
+
activeTrigger = null;
|
|
78
|
+
tooltip?.remove();
|
|
79
|
+
if (activateSkipDelay) {
|
|
80
|
+
skipDelayUntil = Date.now() + skipDelay;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const updatePosition = (trigger, floating) => {
|
|
84
|
+
const request = ++positionRequest;
|
|
85
|
+
void computePosition(trigger, floating, {
|
|
86
|
+
middleware: [
|
|
87
|
+
offset(tooltipGap),
|
|
88
|
+
flip({ padding: tooltipGap }),
|
|
89
|
+
shift({ padding: tooltipGap }),
|
|
90
|
+
size({
|
|
91
|
+
padding: tooltipGap,
|
|
92
|
+
apply({ availableHeight, availableWidth, elements }) {
|
|
93
|
+
elements.floating.style.setProperty(
|
|
94
|
+
"--tooltip-available-width",
|
|
95
|
+
`${Math.max(0, availableWidth)}px`,
|
|
96
|
+
);
|
|
97
|
+
elements.floating.style.setProperty(
|
|
98
|
+
"--tooltip-available-height",
|
|
99
|
+
`${Math.max(0, availableHeight)}px`,
|
|
100
|
+
);
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
],
|
|
104
|
+
placement: getPlacement(trigger),
|
|
105
|
+
strategy: "fixed",
|
|
106
|
+
})
|
|
107
|
+
.then(({ x, y }) => {
|
|
108
|
+
if (activeTrigger !== trigger || request !== positionRequest) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const scale = window.devicePixelRatio || 1;
|
|
112
|
+
floating.style.transform = `translate(${Math.round(x * scale) / scale}px, ${Math.round(y * scale) / scale}px)`;
|
|
113
|
+
floating.style.visibility = "visible";
|
|
114
|
+
})
|
|
115
|
+
.catch(() => {
|
|
116
|
+
if (activeTrigger === trigger && request === positionRequest) {
|
|
117
|
+
closeTooltip(false);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
const openTooltip = (trigger) => {
|
|
122
|
+
const content = getContent(trigger);
|
|
123
|
+
if (!trigger.isConnected || content.length === 0) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
clearOpenTimeout();
|
|
127
|
+
if (activeTrigger === trigger) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
closeTooltip();
|
|
131
|
+
const floating = getTooltip();
|
|
132
|
+
floating.textContent = content;
|
|
133
|
+
floating.style.visibility = "hidden";
|
|
134
|
+
floating.style.transform = "translate(0, 0)";
|
|
135
|
+
document.body.appendChild(floating);
|
|
136
|
+
activeTrigger = trigger;
|
|
137
|
+
setDescribedBy(trigger, true);
|
|
138
|
+
autoUpdateCleanup = autoUpdate(trigger, floating, () => {
|
|
139
|
+
updatePosition(trigger, floating);
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
const requestOpen = (trigger, immediate = false) => {
|
|
143
|
+
if (
|
|
144
|
+
getContent(trigger).length === 0 ||
|
|
145
|
+
activeTrigger === trigger ||
|
|
146
|
+
pendingTrigger === trigger
|
|
147
|
+
) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
clearOpenTimeout();
|
|
151
|
+
pendingTrigger = trigger;
|
|
152
|
+
const delay =
|
|
153
|
+
immediate || activeTrigger != null || Date.now() < skipDelayUntil ? 0 : hoverDelay;
|
|
154
|
+
if (delay === 0) {
|
|
155
|
+
openTooltip(trigger);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
openTimeout = window.setTimeout(() => {
|
|
159
|
+
openTimeout = null;
|
|
160
|
+
pendingTrigger = null;
|
|
161
|
+
openTooltip(trigger);
|
|
162
|
+
}, delay);
|
|
163
|
+
};
|
|
164
|
+
const handlePointerOpen = (event) => {
|
|
165
|
+
if (event.pointerType === "touch") {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const trigger = getTrigger(event.target);
|
|
169
|
+
if (trigger == null || containsTarget(trigger, event.relatedTarget)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
requestOpen(trigger);
|
|
173
|
+
};
|
|
174
|
+
const handlePointer = (event) => {
|
|
175
|
+
lastPointerWasTouch = event.type === "pointerdown" && event.pointerType === "touch";
|
|
176
|
+
};
|
|
177
|
+
const handleTouchClick = (event) => {
|
|
178
|
+
const isTouch = event.pointerType === "touch" || lastPointerWasTouch;
|
|
179
|
+
lastPointerWasTouch = false;
|
|
180
|
+
if (!isTouch || event.detail === 0) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const trigger = getTrigger(event.target);
|
|
184
|
+
if (
|
|
185
|
+
trigger == null ||
|
|
186
|
+
!trigger.isConnected ||
|
|
187
|
+
getContent(trigger).length === 0 ||
|
|
188
|
+
(pinnedByTouch && activeTrigger === trigger)
|
|
189
|
+
) {
|
|
190
|
+
if (pinnedByTouch) {
|
|
191
|
+
closeTooltip();
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
openTooltip(trigger);
|
|
196
|
+
pinnedByTouch = activeTrigger === trigger;
|
|
197
|
+
window.setTimeout(() => {
|
|
198
|
+
if (activeTrigger === trigger && !trigger.isConnected) {
|
|
199
|
+
closeTooltip(false);
|
|
200
|
+
}
|
|
201
|
+
}, 0);
|
|
202
|
+
};
|
|
203
|
+
const handleLeave = (event) => {
|
|
204
|
+
if (pinnedByTouch) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const trigger = getTrigger(event.target);
|
|
208
|
+
if (trigger == null || containsTarget(trigger, event.relatedTarget)) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (activeTrigger === trigger || pendingTrigger === trigger) {
|
|
212
|
+
closeTooltip();
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
const handleFocusIn = (event) => {
|
|
216
|
+
const trigger = getTrigger(event.target);
|
|
217
|
+
if (trigger?.matches(":focus-visible")) {
|
|
218
|
+
requestOpen(trigger, true);
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const handleKeyDown = (event) => {
|
|
222
|
+
if (event.key === "Escape") {
|
|
223
|
+
closeTooltip();
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
const handleContextMenu = (event) => {
|
|
227
|
+
lastPointerWasTouch = false;
|
|
228
|
+
const trigger = getTrigger(event.target);
|
|
229
|
+
if (activeTrigger === trigger || pendingTrigger === trigger) {
|
|
230
|
+
closeTooltip();
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
const destroy = () => {
|
|
234
|
+
closeTooltip(false);
|
|
235
|
+
lastPointerWasTouch = false;
|
|
236
|
+
document.removeEventListener("pointerover", handlePointerOpen);
|
|
237
|
+
document.removeEventListener("pointerdown", handlePointer);
|
|
238
|
+
document.removeEventListener("pointercancel", handlePointer);
|
|
239
|
+
document.removeEventListener("click", handleTouchClick);
|
|
240
|
+
document.removeEventListener("pointerout", handleLeave);
|
|
241
|
+
document.removeEventListener("focusin", handleFocusIn);
|
|
242
|
+
document.removeEventListener("focusout", handleLeave);
|
|
243
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
244
|
+
document.removeEventListener("contextmenu", handleContextMenu);
|
|
245
|
+
tooltip = null;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
document.addEventListener("pointerover", handlePointerOpen);
|
|
249
|
+
document.addEventListener("pointerdown", handlePointer);
|
|
250
|
+
document.addEventListener("pointercancel", handlePointer);
|
|
251
|
+
document.addEventListener("click", handleTouchClick);
|
|
252
|
+
document.addEventListener("pointerout", handleLeave);
|
|
253
|
+
document.addEventListener("focusin", handleFocusIn);
|
|
254
|
+
document.addEventListener("focusout", handleLeave);
|
|
255
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
256
|
+
document.addEventListener("contextmenu", handleContextMenu);
|
|
257
|
+
window.addEventListener("pagehide", destroy, { once: true });
|
|
258
|
+
})();
|
|
259
|
+
</script>
|
|
260
|
+
<script id="codex-visualization-tabs">
|
|
261
|
+
(() => {
|
|
262
|
+
const selector = '.nav[role="tablist"] [role="tab"]';
|
|
263
|
+
const disabled = ':disabled,[aria-disabled="true"]';
|
|
264
|
+
const selectTab = (selected) => {
|
|
265
|
+
const panelId = selected.getAttribute("aria-controls");
|
|
266
|
+
for (const tab of selected.closest('[role="tablist"]').querySelectorAll('[role="tab"]')) {
|
|
267
|
+
const active = tab === selected;
|
|
268
|
+
tab.classList.toggle("active", active);
|
|
269
|
+
tab.setAttribute("aria-selected", String(active));
|
|
270
|
+
const id = tab.getAttribute("aria-controls");
|
|
271
|
+
const panel = id && document.getElementById(id);
|
|
272
|
+
if (panel != null) {
|
|
273
|
+
panel.hidden = id !== panelId;
|
|
274
|
+
if (!panel.hidden && selected.id) {
|
|
275
|
+
panel.setAttribute("aria-labelledby", selected.id);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
const interact = (event) => {
|
|
281
|
+
const tab = event.target?.closest?.(selector);
|
|
282
|
+
if (event.defaultPrevented || tab == null || tab.matches(disabled)) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (event.type === "click") {
|
|
286
|
+
selectTab(tab);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const tabs = Array.from(
|
|
290
|
+
tab.closest('[role="tablist"]').querySelectorAll('[role="tab"]'),
|
|
291
|
+
).filter((candidate) => !candidate.matches(disabled));
|
|
292
|
+
const current = tabs.indexOf(tab);
|
|
293
|
+
let next;
|
|
294
|
+
if (event.key === "ArrowRight" || event.key === "ArrowDown") {
|
|
295
|
+
next = (current + 1) % tabs.length;
|
|
296
|
+
} else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
|
|
297
|
+
next = (current + tabs.length - 1) % tabs.length;
|
|
298
|
+
} else if (event.key === "Home") {
|
|
299
|
+
next = 0;
|
|
300
|
+
} else if (event.key === "End") {
|
|
301
|
+
next = tabs.length - 1;
|
|
302
|
+
} else {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
event.preventDefault();
|
|
306
|
+
tabs[next].focus();
|
|
307
|
+
selectTab(tabs[next]);
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
for (const list of document.querySelectorAll('.nav[role="tablist"]')) {
|
|
311
|
+
const selected =
|
|
312
|
+
list.querySelector('[role="tab"][aria-selected="true"]') ??
|
|
313
|
+
list.querySelector('[role="tab"].active') ??
|
|
314
|
+
list.querySelector('[role="tab"]');
|
|
315
|
+
if (selected != null) {
|
|
316
|
+
selectTab(selected);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
document.addEventListener("click", interact);
|
|
320
|
+
document.addEventListener("keydown", interact);
|
|
321
|
+
window.addEventListener(
|
|
322
|
+
"pagehide",
|
|
323
|
+
() => {
|
|
324
|
+
document.removeEventListener("click", interact);
|
|
325
|
+
document.removeEventListener("keydown", interact);
|
|
326
|
+
},
|
|
327
|
+
{ once: true },
|
|
328
|
+
);
|
|
329
|
+
})();
|
|
330
|
+
</script>
|
|
331
|
+
<script
|
|
332
|
+
id="codex-visualization-lucide"
|
|
333
|
+
async
|
|
334
|
+
src="https://unpkg.com/lucide@1.17.0/dist/umd/lucide.js"
|
|
335
|
+
></script>
|
|
336
|
+
<script>
|
|
337
|
+
(() => {
|
|
338
|
+
const initialize = () => {
|
|
339
|
+
globalThis.lucide?.createIcons({ attrs: { width: 16, height: 16 } });
|
|
340
|
+
};
|
|
341
|
+
if (globalThis.lucide != null) {
|
|
342
|
+
initialize();
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
document
|
|
346
|
+
.getElementById("codex-visualization-lucide")
|
|
347
|
+
?.addEventListener("load", initialize, { once: true });
|
|
348
|
+
})();
|
|
349
|
+
</script>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: opengeni-skills
|
|
3
|
-
description: Find, install, create, and edit workspace Skills; understand reading, file changes,
|
|
3
|
+
description: Find, install, create, and edit workspace Skills; understand reading, file changes, Agent learning settings, and optional sandbox checkout.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Managing Skills
|
|
7
7
|
|
|
8
8
|
A Skill is a folder containing `SKILL.md` and supporting UTF-8 text files.
|
|
9
|
-
Use Skills for reusable instructions and procedures. Use
|
|
9
|
+
Use Skills for reusable instructions and procedures. Use Knowledge for facts and
|
|
10
10
|
outcomes, and workspace instructions for short always-on rules.
|
|
11
11
|
|
|
12
12
|
## Read
|
|
@@ -63,13 +63,22 @@ Stop processes editing the directory before publishing it. Publishing reads the
|
|
|
63
63
|
whole folder; server revision checks prevent overwriting a newer saved revision,
|
|
64
64
|
but they do not freeze a directory another process is changing.
|
|
65
65
|
|
|
66
|
+
Facts and incidents belong in `knowledge_save`, with exact evidence and relevant
|
|
67
|
+
collections. Search published and pending Knowledge before adding duplicates.
|
|
68
|
+
Pending findings may inform further investigation but are not accepted facts or
|
|
69
|
+
permission to change a Skill. Use the current Skill content and its revision
|
|
70
|
+
when proposing procedural changes.
|
|
71
|
+
|
|
66
72
|
## Persistent changes
|
|
67
73
|
|
|
68
|
-
Shared workspace Skills are available to workspace agents.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
Shared workspace Skills are available to workspace agents. Private chats and
|
|
75
|
+
Personal workspaces save personal Skills for their verified initiating user.
|
|
76
|
+
Settings > Agent learning controls persistent agent changes, with a sparse chat
|
|
77
|
+
or scheduled-task override when configured. Automatic publishes a valid authorized
|
|
78
|
+
change; Review first saves an inactive revision and the task continues; Off
|
|
79
|
+
prevents agent authoring. Existing Skills remain readable and usable, and an
|
|
80
|
+
authorized human can still manage or install Skills in the UI. Do not change
|
|
81
|
+
settings or infer an override from “the user asked.” Report the actual receipt.
|
|
73
82
|
|
|
74
83
|
Saved history supports restoration. Upstream updates must preserve workspace
|
|
75
84
|
customizations; report an available update instead of replacing customized
|
|
@@ -77,15 +86,12 @@ content silently. Platform-owned built-in Skills are not workspace-editable.
|
|
|
77
86
|
|
|
78
87
|
Do not encode binary files as text to bypass the text-only boundary. Unsupported
|
|
79
88
|
files and size limits are explicit errors, not permission to drop files silently.
|
|
80
|
-
##
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
If the Skill changes before Save, make a new proposal for a fresh decision.
|
|
90
|
-
Autonomous saves return applied and need no confirmation. Off refuses durable
|
|
91
|
-
agent changes.
|
|
89
|
+
## Nonblocking review
|
|
90
|
+
|
|
91
|
+
A pending save, publish, or install is retained in Knowledge > Needs review.
|
|
92
|
+
Continue the task and link the pending revision. Do not call request_human_input
|
|
93
|
+
or a second activation tool to turn a pending receipt into a chat interruption.
|
|
94
|
+
The human reviews the exact revision in the shared review surface. Approval
|
|
95
|
+
publishes it; rejection leaves any previously published revision in place. A
|
|
96
|
+
stale review cannot overwrite a newer revision. Automatic receipts are available
|
|
97
|
+
immediately; Off creates no durable agent change.
|
|
@@ -15,6 +15,13 @@ provider-specific API wrapper, or OpenGeni-only build CLI.
|
|
|
15
15
|
|
|
16
16
|
## Start from the durable Site
|
|
17
17
|
|
|
18
|
+
- For an existing page the user wants to view and share, consider Sites before
|
|
19
|
+
choosing a temporary tunnel or another server. Inspect whether it can be
|
|
20
|
+
packaged as self-contained HTML, preserve its design and behavior, and retain
|
|
21
|
+
editable source when available. A local preview alone is still appropriate
|
|
22
|
+
when that is all the user requests. Explain workspace access for the published
|
|
23
|
+
link; do not imply it is public to anyone. If the app requires a backend that
|
|
24
|
+
Sites cannot host, explain that constraint instead of dropping functionality.
|
|
18
25
|
- For a new Site, create a normal project directory with `package.json`,
|
|
19
26
|
`index.html`, TypeScript/React source, styles, tests, and any ordinary build
|
|
20
27
|
configuration the app needs.
|
|
@@ -112,6 +119,41 @@ Exercise the real interactions at desktop and mobile widths, inspect console
|
|
|
112
119
|
errors, and take a screenshot when visual quality matters. Do not declare the
|
|
113
120
|
Site complete from compilation alone.
|
|
114
121
|
|
|
122
|
+
## Plain HTML without a browser build
|
|
123
|
+
|
|
124
|
+
For a small HTML-only Site, use ordinary HTML, CSS, and JavaScript. If it calls
|
|
125
|
+
OpenGeni tools or SDK methods, place this exact optional tag before your own
|
|
126
|
+
scripts (without async, defer, or type="module"):
|
|
127
|
+
|
|
128
|
+
```html
|
|
129
|
+
<script src="/__opengeni/site-tools/client.js"></script>
|
|
130
|
+
<script>
|
|
131
|
+
const site = createOpenGeniSiteClient();
|
|
132
|
+
// Use the actual tool paths discovered with ogtool on site.tools.
|
|
133
|
+
// site.client is the same ordinary SDK client as in a React Site.
|
|
134
|
+
</script>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The existing preview handler above serves this script. Serve the raw HTML with
|
|
138
|
+
`new Response(Bun.file("./index.html"))` alongside its tool route; no browser
|
|
139
|
+
build is needed. In the published viewer, the host resolves the tag to its
|
|
140
|
+
browser client. Both use the same SDK implementation and existing tool bridge.
|
|
141
|
+
Opening the file directly supplies no tool host. There are no credentials in
|
|
142
|
+
the tag or HTML. Declare requested tools and handle errors as for any Site.
|
|
143
|
+
|
|
144
|
+
Use the exact package pins above for the preview host. The preview runtime comes
|
|
145
|
+
from that installed SDK; the published runtime comes from the viewer's deployed
|
|
146
|
+
SDK. The tag does not install dependencies, replace React imports, or change Bun.
|
|
147
|
+
For TypeScript checking, React components, or imported browser dependencies,
|
|
148
|
+
use the normal typed SDK and build workflow above. Do not use both client-loading
|
|
149
|
+
paths in one document.
|
|
150
|
+
|
|
151
|
+
Publish the original HTML containing the tag, not the served client script or
|
|
152
|
+
transformed viewer document. For this path, upload `index.html` wherever the
|
|
153
|
+
publishing instructions below use `dist/index.html`. Inline ordinary styles,
|
|
154
|
+
scripts, and assets as usual; the OpenGeni client tag is resolved by the host.
|
|
155
|
+
An HTML-only Site can be a small widget; it does not require a full-page layout.
|
|
156
|
+
|
|
115
157
|
## Prefer OpenGeni's UI and typed client
|
|
116
158
|
|
|
117
159
|
- Prefer `@opengeni/react` components and compiled CSS for OpenGeni-native
|
|
@@ -259,13 +301,38 @@ access limitation. Missing publishing access itself still blocks publication.
|
|
|
259
301
|
SDK operations, with no direct `site.tools` calls, should publish
|
|
260
302
|
`requestedTools: []`.
|
|
261
303
|
4. The immutable requested set is only a maximum allowlist; publishing it grants
|
|
262
|
-
no tool authority and requires no separate tool approval.
|
|
263
|
-
|
|
304
|
+
no tool authority and requires no separate tool approval. Execution still follows
|
|
305
|
+
normal tool approval rules; handle approval-required responses in the UI.
|
|
264
306
|
5. The host intersects that set with the viewer's
|
|
265
307
|
live workspace, permission, and connection authority on every call. Handle
|
|
266
308
|
missing tools, revoked connections, stale catalogs, and access loss as normal
|
|
267
309
|
user-visible error states.
|
|
268
310
|
|
|
311
|
+
## Show a visualization or Site inside chat
|
|
312
|
+
|
|
313
|
+
For an inline visualization stored directly in a chat response, read
|
|
314
|
+
`opengeni-visualize`. That path does not require publishing a Site.
|
|
315
|
+
|
|
316
|
+
To embed a published Site, use a fenced `opengeni-site` block containing JSON:
|
|
317
|
+
|
|
318
|
+
```opengeni-site
|
|
319
|
+
{"siteId":"<artifact.id>","versionId":"<published version.id>"}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Use the actual returned ids. `versionId` is optional; omitting it loads the
|
|
323
|
+
current version when the embed opens. Including it preserves the intended
|
|
324
|
+
version. The viewer can choose another version within the embed without
|
|
325
|
+
publishing or rolling back the Site. The embed uses the same Site renderer,
|
|
326
|
+
reload/full-screen controls, tool declarations and viewer permissions as the
|
|
327
|
+
Site page. Embeds resolve in the chat's workspace. Keep a normal Site link when
|
|
328
|
+
it helps the user reopen or share it. Archived or inaccessible Sites display
|
|
329
|
+
an unavailable state.
|
|
330
|
+
|
|
331
|
+
Use inline HTML for a visualization that belongs in this response. Use a Site
|
|
332
|
+
for a reusable app or durable page, and embed it when useful. Both can be small;
|
|
333
|
+
neither requires a dashboard or full-page layout. React Sites still use the
|
|
334
|
+
normal build and publish workflow.
|
|
335
|
+
|
|
269
336
|
## Publish one immutable version
|
|
270
337
|
|
|
271
338
|
1. Call `opengeni__artifacts_prepare_upload` (no hashes or sizes required).
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_FIRST_PARTY_MCP_PERMISSIONS,
|
|
3
|
+
signDelegatedAccessToken,
|
|
4
|
+
type FirstPartyMcpToolName,
|
|
5
|
+
type Permission,
|
|
6
|
+
} from "@opengeni/contracts";
|
|
7
|
+
import {
|
|
8
|
+
firstPartyMcpInternalWorkspaceUrl,
|
|
9
|
+
resolveFirstPartyDelegationSecret,
|
|
10
|
+
type Settings,
|
|
11
|
+
} from "@opengeni/config";
|
|
12
|
+
import { OpenGeniClient } from "@opengeni/sdk";
|
|
13
|
+
import { guardedMcpFetch } from "./mcp-network";
|
|
14
|
+
|
|
15
|
+
/** Internal calls carry the same exact attempt and tool selection as MCP. */
|
|
16
|
+
export function createFirstPartyAttemptClient(input: {
|
|
17
|
+
settings: Settings;
|
|
18
|
+
scope: {
|
|
19
|
+
accountId: string;
|
|
20
|
+
workspaceId: string;
|
|
21
|
+
sessionId: string;
|
|
22
|
+
turnId: string;
|
|
23
|
+
attemptId: string;
|
|
24
|
+
executionGeneration: number;
|
|
25
|
+
};
|
|
26
|
+
selectedTools: readonly FirstPartyMcpToolName[];
|
|
27
|
+
permissions?: readonly Permission[];
|
|
28
|
+
fetch?: typeof fetch;
|
|
29
|
+
signal?: AbortSignal;
|
|
30
|
+
}) {
|
|
31
|
+
const secret = resolveFirstPartyDelegationSecret(input.settings);
|
|
32
|
+
if (!secret) throw new Error("First-party task access is unavailable");
|
|
33
|
+
const url = new URL(firstPartyMcpInternalWorkspaceUrl(input.settings, input.scope.workspaceId));
|
|
34
|
+
const suffix = `/v1/workspaces/${input.scope.workspaceId}/mcp`;
|
|
35
|
+
if (!url.pathname.endsWith(suffix)) throw new Error("First-party API URL is invalid");
|
|
36
|
+
url.pathname = url.pathname.slice(0, -suffix.length) || "/";
|
|
37
|
+
url.search = "";
|
|
38
|
+
url.hash = "";
|
|
39
|
+
const guarded = guardedMcpFetch(
|
|
40
|
+
{ ...input.settings, integrationsAllowPrivateNetworkTargets: true },
|
|
41
|
+
input.fetch ?? globalThis.fetch.bind(globalThis),
|
|
42
|
+
{
|
|
43
|
+
requireHttpsOutsideLocalTest: false,
|
|
44
|
+
...(process.versions.bun ? { pinResolvedDestination: false } : {}),
|
|
45
|
+
},
|
|
46
|
+
);
|
|
47
|
+
return new OpenGeniClient({
|
|
48
|
+
baseUrl: url.toString(),
|
|
49
|
+
fetch: async (request, init) => {
|
|
50
|
+
const bearer = await signDelegatedAccessToken(secret, {
|
|
51
|
+
...input.scope,
|
|
52
|
+
subjectId: "worker:knowledge-preparation",
|
|
53
|
+
principalKind: "agent_attempt",
|
|
54
|
+
permissions: [...(input.permissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS)],
|
|
55
|
+
firstPartyMcpTools: [...input.selectedTools],
|
|
56
|
+
exp: Math.floor(Date.now() / 1_000) + 60 * 60,
|
|
57
|
+
});
|
|
58
|
+
const headers = new Headers(init?.headers);
|
|
59
|
+
headers.set("authorization", `Bearer ${bearer}`);
|
|
60
|
+
const signals = [input.signal, init?.signal].filter(
|
|
61
|
+
(signal): signal is AbortSignal => !!signal,
|
|
62
|
+
);
|
|
63
|
+
return guarded(request, {
|
|
64
|
+
...init,
|
|
65
|
+
headers,
|
|
66
|
+
...(signals.length ? { signal: AbortSignal.any(signals) } : {}),
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1897,9 +1897,9 @@ export type BuildAgentOptions = {
|
|
|
1897
1897
|
attemptConnectorActionBindings?: readonly AttemptConnectorActionBinding[];
|
|
1898
1898
|
/** Exact open-suffix call the current human approved before this agent was rebuilt. */
|
|
1899
1899
|
approvedToolCallId?: string;
|
|
1900
|
-
//
|
|
1901
|
-
//
|
|
1902
|
-
//
|
|
1900
|
+
// Historical prompt-replay/embedding compatibility slot. New Knowledge is
|
|
1901
|
+
// retrieved through tools and must not be composed here as standing guidance.
|
|
1902
|
+
// Omitted/blank preserves the existing prompt bytes.
|
|
1903
1903
|
workspaceMemory?: string;
|
|
1904
1904
|
// Exact-attempt active policy and preference descriptor block. When present,
|
|
1905
1905
|
// runtime uses the structured governance precedence branch; absent preserves
|
|
@@ -2075,7 +2075,7 @@ export function coreInstructions(
|
|
|
2075
2075
|
): string[] {
|
|
2076
2076
|
return [
|
|
2077
2077
|
"If the session has a goal, you own it: keep working until you call opengeni__goal_complete with concrete evidence or opengeni__goal_pause with a rationale; resume a paused goal with opengeni__goal_resume regardless of who paused it or why; revise it with opengeni__goal_update; create one with opengeni__goal_set when given a long-running objective.",
|
|
2078
|
-
"
|
|
2078
|
+
"Use knowledge_search and knowledge_get when retained information is relevant. For questions about what the workspace knows, ground the answer in authorized Knowledge and attached sources. Missing internal facts remain unknown; do not infer a person's role or cite unrelated public search results as evidence. Keep any relevant external research clearly separate from workspace records. Default retrieval returns published information. Before retaining or correcting anything, also search view=needs_review for existing pending entries and collections; read those with knowledge_get view=needs_review. Pending means unapproved: you may inspect and improve it, but do not present it as accepted knowledge or activate behavioral guidance from it. Reuse the existing entryId and current version instead of creating another proposal each run. Save durable facts, decisions, requirements, incidents, fixes and outcomes autonomously with knowledge_save when useful for future work, whether requested explicitly or learned during ordinary work. When a user supplies or confirms a durable fact, use knowledge_retain_message to retain the actual message and cite its returned entryId/revisionId in the finding evidence. Preserve existing source evidence and relationships when correcting an entry; do not replace them with empty arrays merely because the user confirmed a new value. Explicit confirmation can supersede a conflicting pending proposal, but explain that outcome to the user. Preserve uncertainty and exact supporting evidence; the fact label is not a verification claim. Chat attachments retain their original files and automatically prepare source text when authoring is enabled. Use knowledge_retain_file for a newly fetched file or failed preparation. A source entry contains retained original text; a finding states a useful conclusion and cites the exact source revision. Do not create both when they would simply repeat the same text. Reuse collections for customers, products, systems or subjects across sources, and link one entry to multiple collections instead of copying it. Technical incidents belong with the affected system and should include cause, fix and outcome when known. Reorganize references when useful; do not erase source evidence or revision history. Private tasks author personal Knowledge; shared tasks author workspace Knowledge. Automatic publishes immediately, Review first keeps a pending proposal without pausing your task, and Off prevents authoring while permitting retrieval. Never bypass review by making a new entry, switching tools, or asking for another approval. Reuse the same operationId and exact request after an uncertain save, including recovery. Use task_note_save for temporary coordination in this task tree. Conversation history is separate. Workspace instructions are concise standing rules; Skills are reusable procedures with their own Agent learning settings. Do not save the same content in multiple authorities.",
|
|
2079
2079
|
...(workspaceEnvironment ? workspaceEnvironmentInstructions(workspaceEnvironment) : []),
|
|
2080
2080
|
// Rig doctrine (M3): data-conditional, inside the non-bypassable CORE so a
|
|
2081
2081
|
// white-label persona template can never drop it. Absent for rig-less sessions.
|
|
@@ -2130,11 +2130,9 @@ export function appendPersistentSessionSettings(
|
|
|
2130
2130
|
}
|
|
2131
2131
|
|
|
2132
2132
|
/**
|
|
2133
|
-
*
|
|
2134
|
-
*
|
|
2135
|
-
*
|
|
2136
|
-
* per-session instructions. An absent/blank value is a no-op that returns the
|
|
2137
|
-
* composed string byte-for-byte.
|
|
2133
|
+
* Historical prompt-composition compatibility helper. New Knowledge uses
|
|
2134
|
+
* retrieval tools; this slot preserves existing embedding/replay inputs only.
|
|
2135
|
+
* An absent/blank value returns the composed string byte-for-byte.
|
|
2138
2136
|
*/
|
|
2139
2137
|
export function appendWorkspaceMemory(composed: string, workspaceMemory?: string): string {
|
|
2140
2138
|
const trimmed = workspaceMemory?.trim();
|
|
@@ -2435,6 +2433,7 @@ export function buildOpenGeniAgent(
|
|
|
2435
2433
|
// are equivalent. Reading supplied Skill files never needs either.
|
|
2436
2434
|
const filesystemAvailable = (options.activeSandboxBackend ?? settings.sandboxBackend) !== "none";
|
|
2437
2435
|
const skillComposition = composeRuntimeSkills(options.skillActivations ?? [], {
|
|
2436
|
+
defaults: !hostSuppliedSkillCatalog,
|
|
2438
2437
|
editableArtifacts: !hostSuppliedSkillCatalog && editableArtifactToolsAvailable,
|
|
2439
2438
|
sites: !hostSuppliedSkillCatalog && filesystemAvailable,
|
|
2440
2439
|
videoGeneration: !hostSuppliedSkillCatalog && Boolean(options.videoGeneration),
|
|
@@ -2619,8 +2618,8 @@ export function buildOpenGeniAgent(
|
|
|
2619
2618
|
// when a codemode token was minted for this managed-sandbox turn,
|
|
2620
2619
|
// 4. + managed-sandbox Git binding discovery, ONLY when one provider has
|
|
2621
2620
|
// multiple credential bindings,
|
|
2622
|
-
// 5. +
|
|
2623
|
-
//
|
|
2621
|
+
// 5. + a nonblank historical memory compatibility block, when supplied;
|
|
2622
|
+
// canonical Knowledge is retrieved through tools,
|
|
2624
2623
|
// 6. + the per-session persona instructions (session-specific, so it
|
|
2625
2624
|
// refines both the workspace persona and the substrate note),
|
|
2626
2625
|
// 7. + host context for this exact turn, when supplied,
|
|
@@ -11101,3 +11100,5 @@ function sortJson(value: unknown): unknown {
|
|
|
11101
11100
|
}
|
|
11102
11101
|
return value;
|
|
11103
11102
|
}
|
|
11103
|
+
|
|
11104
|
+
export { createFirstPartyAttemptClient } from "./first-party-client";
|