@jini-ai/agentic 0.3.7 → 0.4.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/CHANGELOG.md +94 -0
- package/README.md +33 -6
- package/dist/core/a2ui/agent-to-renderer.d.ts +3 -1
- package/dist/core/a2ui/agent-to-renderer.js +1 -1
- package/dist/core/a2ui/catalog.d.ts +14 -5
- package/dist/core/a2ui/catalog.js +5 -5
- package/dist/core/a2ui/common-types.d.ts +11 -3
- package/dist/core/a2ui/common-types.js +5 -3
- package/dist/core/a2ui/index.d.ts +1 -1
- package/dist/core/a2ui/index.js +1 -1
- package/dist/core/a2ui/interpreter.d.ts +45 -10
- package/dist/core/a2ui/interpreter.js +38 -43
- package/dist/core/a2ui/json-pointer.d.ts +16 -4
- package/dist/core/a2ui/json-pointer.js +7 -7
- package/dist/core/a2ui/renderer-to-agent.d.ts +22 -8
- package/dist/core/a2ui/renderer-to-agent.js +5 -5
- package/dist/core/a2ui/resolve.d.ts +7 -2
- package/dist/core/a2ui/resolve.js +10 -9
- package/dist/core/a2ui/tree.d.ts +8 -2
- package/dist/core/a2ui/tree.js +2 -2
- package/dist/core/ag-ui.d.ts +17 -9
- package/dist/core/ag-ui.js +4 -4
- package/dist/core/capability.d.ts +12 -3
- package/dist/core/capability.js +3 -3
- package/dist/core/dom/dom-page-driver.d.ts +8 -4
- package/dist/core/dom/dom-page-driver.js +19 -20
- package/dist/core/dom/index.d.ts +3 -3
- package/dist/core/dom/index.js +1 -1
- package/dist/core/dom/model-context.d.ts +18 -8
- package/dist/core/dom/model-context.js +12 -15
- package/dist/core/dom/native-model-context.d.ts +6 -0
- package/dist/core/dom/native-model-context.js +19 -0
- package/dist/core/element-handles.d.ts +6 -2
- package/dist/core/element-handles.js +3 -3
- package/dist/core/gen-ui/encoder.d.ts +21 -11
- package/dist/core/gen-ui/encoder.js +8 -7
- package/dist/core/gen-ui/events.d.ts +6 -5
- package/dist/core/gen-ui/events.js +6 -5
- package/dist/core/gen-ui/index.d.ts +1 -1
- package/dist/core/gen-ui/index.js +1 -1
- package/dist/core/guards.d.ts +17 -5
- package/dist/core/guards.js +6 -6
- package/dist/core/handle.d.ts +12 -5
- package/dist/core/handle.js +9 -8
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.js +2 -1
- package/dist/core/list-handles.d.ts +4 -1
- package/dist/core/list-handles.js +1 -1
- package/dist/core/mcp-ui-apps.d.ts +39 -9
- package/dist/core/mcp-ui-apps.js +10 -8
- package/dist/core/messages.d.ts +6 -0
- package/dist/core/messages.js +6 -0
- package/dist/core/page-capabilities.d.ts +0 -11
- package/dist/core/page-capabilities.js +13 -1
- package/dist/core/page-driver.d.ts +32 -11
- package/dist/core/page-executor.d.ts +8 -2
- package/dist/core/page-executor.js +31 -31
- package/dist/core/webmcp.d.ts +27 -8
- package/dist/core/webmcp.js +14 -14
- package/dist/index.d.ts +30 -0
- package/dist/index.js +30 -0
- package/dist/skills/install/archive.d.ts +8 -0
- package/dist/skills/install/archive.js +47 -0
- package/dist/skills/install/fetch-adapter.d.ts +6 -0
- package/dist/skills/install/fetch-adapter.js +6 -0
- package/dist/skills/install/github.d.ts +21 -0
- package/dist/skills/install/github.js +92 -0
- package/dist/skills/install/index.d.ts +11 -0
- package/dist/skills/install/index.js +11 -0
- package/dist/skills/install/install-service.d.ts +44 -0
- package/dist/skills/install/install-service.js +121 -0
- package/dist/skills/install/layout.d.ts +13 -0
- package/dist/skills/install/layout.js +22 -0
- package/dist/skills/install/live-registration.d.ts +61 -0
- package/dist/skills/install/live-registration.js +64 -0
- package/dist/skills/install/node-filesystem.d.ts +4 -0
- package/dist/skills/install/node-filesystem.js +41 -0
- package/dist/skills/install/ports.d.ts +101 -0
- package/dist/skills/install/ports.js +2 -0
- package/dist/skills/install/state.d.ts +13 -0
- package/dist/skills/install/state.js +23 -0
- package/dist/skills/install/validation.d.ts +45 -0
- package/dist/skills/install/validation.js +104 -0
- package/package.json +20 -5
package/dist/core/capability.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* @param id - Capability id to resolve.
|
|
18
18
|
* @returns The definition, or `undefined` when the id is not in the manifest.
|
|
19
19
|
*/
|
|
20
|
-
export function findCapability(capabilities, id) {
|
|
20
|
+
export function findCapability({ capabilities, id }, _optional = {}) {
|
|
21
21
|
return capabilities.find((capability) => capability.id === id);
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
@@ -33,7 +33,7 @@ export function findCapability(capabilities, id) {
|
|
|
33
33
|
* @param input - Raw caller-supplied arguments.
|
|
34
34
|
* @returns An error message, or `null` when the input is acceptable.
|
|
35
35
|
*/
|
|
36
|
-
export function findCapabilityInputError(capability, input) {
|
|
36
|
+
export function findCapabilityInputError({ capability, input }, _optional = {}) {
|
|
37
37
|
const { properties, required, additionalProperties } = capability.inputSchema;
|
|
38
38
|
for (const name of required ?? []) {
|
|
39
39
|
if (input[name] === undefined)
|
|
@@ -73,7 +73,7 @@ export function findCapabilityInputError(capability, input) {
|
|
|
73
73
|
* @param hasSession - Whether a live frontend session is attached.
|
|
74
74
|
* @returns Only the capabilities that can actually be satisfied right now.
|
|
75
75
|
*/
|
|
76
|
-
export function availableCapabilities(capabilities, hasSession) {
|
|
76
|
+
export function availableCapabilities({ capabilities, hasSession }, _optional = {}) {
|
|
77
77
|
return hasSession ? capabilities : capabilities.filter((c) => c.surface === 'server');
|
|
78
78
|
}
|
|
79
79
|
//# sourceMappingURL=capability.js.map
|
|
@@ -4,15 +4,17 @@ export interface DomPageDriverPage {
|
|
|
4
4
|
/** Shown to a caller by `page.find_elements`/`page.navigate`'s refusal message — see
|
|
5
5
|
* `PageSummary.label` for why this exists at all. */
|
|
6
6
|
readonly label: string;
|
|
7
|
-
readonly navigate: () => void;
|
|
7
|
+
readonly navigate: (required: Record<string, never>) => void;
|
|
8
8
|
}
|
|
9
|
-
export interface
|
|
9
|
+
export interface DomPageDriverRequired {
|
|
10
10
|
/** The subtree to expose. Never pass `document`. */
|
|
11
11
|
readonly root: ParentNode & {
|
|
12
12
|
querySelector: Element['querySelector'];
|
|
13
13
|
};
|
|
14
14
|
/** Page ids this driver may navigate to, each with its label and how to get there. */
|
|
15
15
|
readonly pages: Readonly<Record<string, DomPageDriverPage>>;
|
|
16
|
+
}
|
|
17
|
+
export interface DomPageDriverOptions {
|
|
16
18
|
/**
|
|
17
19
|
* The id of the page currently shown, reported on every element.
|
|
18
20
|
*
|
|
@@ -30,7 +32,9 @@ export interface DomPageDriverOptions {
|
|
|
30
32
|
* @param options - The subtree, the navigable pages, and the current page id.
|
|
31
33
|
* @returns A driver ready to hand to `executePageCapability`.
|
|
32
34
|
*/
|
|
33
|
-
export declare function createDomPageDriver(
|
|
35
|
+
export declare function createDomPageDriver({ root, pages }: DomPageDriverRequired, options?: DomPageDriverOptions): PageDriver;
|
|
34
36
|
/** Reads the current page's `data-agent-page`, for hosts that tag the body. */
|
|
35
|
-
export declare function currentAgentPage(root
|
|
37
|
+
export declare function currentAgentPage({ root }: {
|
|
38
|
+
root: ParentNode;
|
|
39
|
+
}, _optional?: Record<string, never>): string | undefined;
|
|
36
40
|
//# sourceMappingURL=dom-page-driver.d.ts.map
|
|
@@ -228,8 +228,7 @@ function describe(element, page) {
|
|
|
228
228
|
* @param options - The subtree, the navigable pages, and the current page id.
|
|
229
229
|
* @returns A driver ready to hand to `executePageCapability`.
|
|
230
230
|
*/
|
|
231
|
-
export function createDomPageDriver(options) {
|
|
232
|
-
const { root, pages } = options;
|
|
231
|
+
export function createDomPageDriver({ root, pages }, options = {}) {
|
|
233
232
|
/**
|
|
234
233
|
* The page a specific element belongs to — its own nearest `[data-agent-page]` ancestor, not a
|
|
235
234
|
* single document-wide guess.
|
|
@@ -257,7 +256,7 @@ export function createDomPageDriver(options) {
|
|
|
257
256
|
* publishes the same handle twice makes `find`'s single-match resolution ambiguous — surfaced
|
|
258
257
|
* here so both callers below can refuse rather than silently pick one.
|
|
259
258
|
*/
|
|
260
|
-
const findAll = (handle) => Array.from(root.querySelectorAll(resolveHandleSelector(handle)))
|
|
259
|
+
const findAll = (handle) => Array.from(root.querySelectorAll(resolveHandleSelector({ handle })))
|
|
261
260
|
.filter((element) => !isPrivate(element));
|
|
262
261
|
/**
|
|
263
262
|
* More than one element answers to the same handle — a page-authoring bug (duplicate
|
|
@@ -312,7 +311,7 @@ export function createDomPageDriver(options) {
|
|
|
312
311
|
return candidate ?? element;
|
|
313
312
|
};
|
|
314
313
|
return {
|
|
315
|
-
async findElements(filter) {
|
|
314
|
+
async findElements(_required, filter = {}) {
|
|
316
315
|
const found = Array.from(root.querySelectorAll(`[${AGENT_ELEMENT_ATTRIBUTE}]`))
|
|
317
316
|
.filter((element) => !isPrivate(element))
|
|
318
317
|
.map((element) => describe(element, pageOf(element)))
|
|
@@ -327,16 +326,16 @@ export function createDomPageDriver(options) {
|
|
|
327
326
|
|| element.label.toLowerCase().includes(query);
|
|
328
327
|
});
|
|
329
328
|
},
|
|
330
|
-
async listPages() {
|
|
329
|
+
async listPages(_required, _optional = {}) {
|
|
331
330
|
// `Object.entries`, same own-enumerable-keys-only guarantee `Object.keys` gives `navigate`'s
|
|
332
331
|
// own `hasOwnProperty` check above — no risk of a `pages.label`/`pages.navigate`-shaped
|
|
333
332
|
// prototype entry leaking in as a fake page id.
|
|
334
333
|
return Object.entries(pages).map(([id, page]) => ({ id, label: page.label }));
|
|
335
334
|
},
|
|
336
|
-
async describeField(handle) {
|
|
335
|
+
async describeField({ handle }, _optional = {}) {
|
|
337
336
|
return fieldDescriptorOf(controlOf(find(handle)));
|
|
338
337
|
},
|
|
339
|
-
async describeState(handle) {
|
|
338
|
+
async describeState({ handle }, _optional = {}) {
|
|
340
339
|
// Unlike every other method here, a handle that no longer resolves is an answer rather than
|
|
341
340
|
// an error: an element that a click removed is exactly what the caller is asking about. A
|
|
342
341
|
// handle resolving to *more than one* element is a different situation entirely — not an
|
|
@@ -402,7 +401,7 @@ export function createDomPageDriver(options) {
|
|
|
402
401
|
* would hang for the whole life of a backgrounded tab; without the frames every write would
|
|
403
402
|
* report its own target unchanged, because the read would beat the render.
|
|
404
403
|
*/
|
|
405
|
-
async settle() {
|
|
404
|
+
async settle(_required, _optional = {}) {
|
|
406
405
|
await new Promise((resolve) => {
|
|
407
406
|
let timer;
|
|
408
407
|
// No re-entry guard: whichever side loses the race calls this again, and both of its
|
|
@@ -422,7 +421,7 @@ export function createDomPageDriver(options) {
|
|
|
422
421
|
raf(() => raf(finish));
|
|
423
422
|
});
|
|
424
423
|
},
|
|
425
|
-
async highlight(handle, durationMs) {
|
|
424
|
+
async highlight({ handle, durationMs }, _optional = {}) {
|
|
426
425
|
const element = find(handle);
|
|
427
426
|
// Same refusal as `click()`, for the same reason: an SVG (or other non-HTMLElement) target
|
|
428
427
|
// has no `.style` to draw an outline on, so silently returning here drew nothing while
|
|
@@ -448,16 +447,16 @@ export function createDomPageDriver(options) {
|
|
|
448
447
|
}, durationMs);
|
|
449
448
|
highlights.set(handle, { timer, restore });
|
|
450
449
|
},
|
|
451
|
-
async scrollTo(handle) {
|
|
450
|
+
async scrollTo({ handle }, _optional = {}) {
|
|
452
451
|
find(handle).scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
453
452
|
},
|
|
454
|
-
async click(handle) {
|
|
453
|
+
async click({ handle }, _optional = {}) {
|
|
455
454
|
const control = controlOf(find(handle));
|
|
456
455
|
if (!(control instanceof HTMLElement))
|
|
457
456
|
throw new Error(`"${handle}" is not clickable`);
|
|
458
457
|
control.click();
|
|
459
458
|
},
|
|
460
|
-
async fill(handle, text) {
|
|
459
|
+
async fill({ handle, text }, _optional = {}) {
|
|
461
460
|
const control = controlOf(find(handle));
|
|
462
461
|
if (isEditableRegion(control)) {
|
|
463
462
|
// A contenteditable region has no `value`; its content *is* its children, and a real
|
|
@@ -483,7 +482,7 @@ export function createDomPageDriver(options) {
|
|
|
483
482
|
control.dispatchEvent(new Event('input', { bubbles: true }));
|
|
484
483
|
control.dispatchEvent(new Event('change', { bubbles: true }));
|
|
485
484
|
},
|
|
486
|
-
async selectOption(handle, option, selected = true) {
|
|
485
|
+
async selectOption({ handle, option }, { selected = true } = {}) {
|
|
487
486
|
const control = controlOf(find(handle));
|
|
488
487
|
if (!(control instanceof HTMLSelectElement)) {
|
|
489
488
|
throw new Error(`"${handle}" is not a dropdown`);
|
|
@@ -518,8 +517,8 @@ export function createDomPageDriver(options) {
|
|
|
518
517
|
// the same shape of problem regardless of which side authored it. `handle` needs no
|
|
519
518
|
// treatment: it is already validated ASCII, length-capped by isValidElementHandle before
|
|
520
519
|
// this driver is ever called.
|
|
521
|
-
const safeOption = normalizeAgentLabel(option).text;
|
|
522
|
-
const available = options.map((entry) => normalizeAgentLabel(entry.text.trim()).text)
|
|
520
|
+
const safeOption = normalizeAgentLabel({ raw: option }).text;
|
|
521
|
+
const available = options.map((entry) => normalizeAgentLabel({ raw: entry.text.trim() }).text)
|
|
523
522
|
.filter((text) => text.length > 0);
|
|
524
523
|
throw new Error(`"${safeOption}" is not an option of "${handle}". Available: ${available.length > 0 ? available.join(', ') : '(none)'}`);
|
|
525
524
|
}
|
|
@@ -535,7 +534,7 @@ export function createDomPageDriver(options) {
|
|
|
535
534
|
// ignoring this would tell the caller a deselect happened when nothing changed, and clearing
|
|
536
535
|
// the control would invent a third state (no selection) that a native <select> cannot hold.
|
|
537
536
|
throw new Error(`"${handle}" is a single-select; its choice cannot be removed, only replaced — `
|
|
538
|
-
+ `select a different option instead of deselecting "${normalizeAgentLabel(option).text}"`);
|
|
537
|
+
+ `select a different option instead of deselecting "${normalizeAgentLabel({ raw: option }).text}"`);
|
|
539
538
|
}
|
|
540
539
|
else {
|
|
541
540
|
// Same prototype-setter dance as `fill`, for the same reason: React tracks the previous
|
|
@@ -549,7 +548,7 @@ export function createDomPageDriver(options) {
|
|
|
549
548
|
control.dispatchEvent(new Event('input', { bubbles: true }));
|
|
550
549
|
control.dispatchEvent(new Event('change', { bubbles: true }));
|
|
551
550
|
},
|
|
552
|
-
async navigate(page) {
|
|
551
|
+
async navigate({ page }, _optional = {}) {
|
|
553
552
|
// `hasOwnProperty`, not `pages[page]`: a plain object literal inherits everything
|
|
554
553
|
// `Object.prototype` contributes, so a bare lookup answered `navigate("constructor")` with
|
|
555
554
|
// the `Object` constructor — a function the host never published, which this then called,
|
|
@@ -564,8 +563,8 @@ export function createDomPageDriver(options) {
|
|
|
564
563
|
// the executor entirely, hands `page` in unsanitized, so the same bound-and-strip treatment
|
|
565
564
|
// applies here too rather than assuming the only caller is the one that already checked.
|
|
566
565
|
if (!published)
|
|
567
|
-
throw new Error(`"${normalizeAgentLabel(page).text}" is not a published page`);
|
|
568
|
-
pages[page].navigate();
|
|
566
|
+
throw new Error(`"${normalizeAgentLabel({ raw: page }).text}" is not a published page`);
|
|
567
|
+
pages[page].navigate({});
|
|
569
568
|
},
|
|
570
569
|
};
|
|
571
570
|
}
|
|
@@ -616,7 +615,7 @@ function fillEditableRegion(control, text) {
|
|
|
616
615
|
control.dispatchEvent(new Event('input', { bubbles: true }));
|
|
617
616
|
}
|
|
618
617
|
/** Reads the current page's `data-agent-page`, for hosts that tag the body. */
|
|
619
|
-
export function currentAgentPage(root) {
|
|
618
|
+
export function currentAgentPage({ root }, _optional = {}) {
|
|
620
619
|
const tagged = root.querySelector(`[${AGENT_PAGE_ATTRIBUTE}]`);
|
|
621
620
|
return tagged?.getAttribute(AGENT_PAGE_ATTRIBUTE) ?? undefined;
|
|
622
621
|
}
|
package/dist/core/dom/index.d.ts
CHANGED
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The one `PageDriver` (see `@jini-ai/agentic`'s `page-driver.ts`) that reads and writes a real DOM
|
|
5
5
|
* subtree. Split into its own entry point, compiled under its own `DOM`-lib `tsconfig.dom.json`,
|
|
6
|
-
* so the rest of this package can stay provably DOM-free — see
|
|
6
|
+
* so the rest of this package can stay provably DOM-free — see archived provenance ledger's "The DOM split".
|
|
7
7
|
*
|
|
8
8
|
* `@jini-ai/chat-react` is this package's one in-repo consumer today.
|
|
9
9
|
*/
|
|
10
|
-
export { createDomPageDriver, currentAgentPage, type DomPageDriverOptions, type DomPageDriverPage, } from './dom-page-driver.js';
|
|
10
|
+
export { createDomPageDriver, currentAgentPage, type DomPageDriverRequired, type DomPageDriverOptions, type DomPageDriverPage, } from './dom-page-driver.js';
|
|
11
11
|
/**
|
|
12
12
|
* WebMCP feature detection — moved 2026-07-26 from `@jini-ai/ui`'s `agent-tools/model-context.ts`
|
|
13
13
|
* (plan §8 step 6). See `model-context.ts`'s module doc for why it lives here rather than
|
|
14
14
|
* alongside `../webmcp.ts`'s DOM-free projection.
|
|
15
15
|
*/
|
|
16
|
-
export { getAgentModelContext, type AgentModelContextLike, type AgentModelContextToolRegistration, } from './model-context.js';
|
|
16
|
+
export { getAgentModelContext, type AgentModelContextLike, type ModelContextHostPort, type AgentModelContextRegisterToolOptions, type AgentModelContextToolRegistration, } from './model-context.js';
|
|
17
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/core/dom/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The one `PageDriver` (see `@jini-ai/agentic`'s `page-driver.ts`) that reads and writes a real DOM
|
|
5
5
|
* subtree. Split into its own entry point, compiled under its own `DOM`-lib `tsconfig.dom.json`,
|
|
6
|
-
* so the rest of this package can stay provably DOM-free — see
|
|
6
|
+
* so the rest of this package can stay provably DOM-free — see archived provenance ledger's "The DOM split".
|
|
7
7
|
*
|
|
8
8
|
* `@jini-ai/chat-react` is this package's one in-repo consumer today.
|
|
9
9
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module dom/model-context
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* `document.modelContext`,
|
|
4
|
+
* Host-injected access to the browser's (draft) WebMCP surface —
|
|
5
|
+
* the host supplies `document.modelContext`, followed by the deprecated `navigator.modelContext`
|
|
6
6
|
* alias (the spec moved the getter from Navigator to Document in 2026;
|
|
7
7
|
* see the polyfill ecosystem's own back-compat posture). No `@mcp-b/*` or
|
|
8
8
|
* other WebMCP package dependency: this module only needs the shape, the
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
* bridges already use.
|
|
12
12
|
* A page that wants `document.modelContext` to actually exist in a browser
|
|
13
13
|
* without native support must load a real polyfill itself (e.g.
|
|
14
|
-
* `@mcp-b/webmcp-polyfill`) — this module only
|
|
14
|
+
* `@mcp-b/webmcp-polyfill`) — this module adapts only the candidates the host supplies.
|
|
15
15
|
*
|
|
16
16
|
* Moved 2026-07-26 from `@jini-ai/ui/src/features/agent-tools/model-context.ts` (plan §4/§8 step 6).
|
|
17
17
|
* Lives under `src/dom/`, not alongside `../webmcp.ts`'s pure `CapabilityDef` → WebMCP-tool
|
|
18
|
-
* projection, because it
|
|
18
|
+
* projection, because it adapts the native browser API — `webmcp.ts`'s own module doc is explicit
|
|
19
19
|
* that "that detection is deliberately NOT here: it touches browser globals, and this package
|
|
20
20
|
* holds none," which is exactly the DOM-free guarantee `src/dom/` exists to carve an exception
|
|
21
21
|
* for. See `dom/index.ts`'s re-export of this module.
|
|
@@ -56,14 +56,24 @@ export interface AgentModelContextLike {
|
|
|
56
56
|
* ModelContextRegisterToolOptions options = {})` — it is **async**. Callers must not assume it
|
|
57
57
|
* has taken effect synchronously, and must not let a rejection escape.
|
|
58
58
|
*/
|
|
59
|
-
registerTool(
|
|
59
|
+
registerTool(required: {
|
|
60
|
+
tool: AgentModelContextToolRegistration;
|
|
61
|
+
}, options?: AgentModelContextRegisterToolOptions): Promise<void>;
|
|
60
62
|
/**
|
|
61
63
|
* NOT in the spec — the draft's only unregistration mechanism is aborting the `signal` passed to
|
|
62
64
|
* `registerTool`. Kept optional purely so a polyfill that happens to expose one can be used;
|
|
63
65
|
* never rely on its presence, and always pass a `signal` as the real cleanup path.
|
|
64
66
|
*/
|
|
65
|
-
unregisterTool?(
|
|
67
|
+
unregisterTool?(required: {
|
|
68
|
+
name: string;
|
|
69
|
+
}, _optional?: Record<string, never>): void;
|
|
66
70
|
}
|
|
67
|
-
/**
|
|
68
|
-
export
|
|
71
|
+
/** Ordered host candidates: modern document first, then any deprecated navigator alias. */
|
|
72
|
+
export interface ModelContextHostPort {
|
|
73
|
+
candidates(required: Record<string, never>): readonly unknown[];
|
|
74
|
+
}
|
|
75
|
+
/** Adapts the first installed native surface to Jini's argument-object port. */
|
|
76
|
+
export declare function getAgentModelContext({ host }: {
|
|
77
|
+
host: ModelContextHostPort;
|
|
78
|
+
}, _optional?: Record<string, never>): AgentModelContextLike | undefined;
|
|
69
79
|
//# sourceMappingURL=model-context.d.ts.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module dom/model-context
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* `document.modelContext`,
|
|
4
|
+
* Host-injected access to the browser's (draft) WebMCP surface —
|
|
5
|
+
* the host supplies `document.modelContext`, followed by the deprecated `navigator.modelContext`
|
|
6
6
|
* alias (the spec moved the getter from Navigator to Document in 2026;
|
|
7
7
|
* see the polyfill ecosystem's own back-compat posture). No `@mcp-b/*` or
|
|
8
8
|
* other WebMCP package dependency: this module only needs the shape, the
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
* bridges already use.
|
|
12
12
|
* A page that wants `document.modelContext` to actually exist in a browser
|
|
13
13
|
* without native support must load a real polyfill itself (e.g.
|
|
14
|
-
* `@mcp-b/webmcp-polyfill`) — this module only
|
|
14
|
+
* `@mcp-b/webmcp-polyfill`) — this module adapts only the candidates the host supplies.
|
|
15
15
|
*
|
|
16
16
|
* Moved 2026-07-26 from `@jini-ai/ui/src/features/agent-tools/model-context.ts` (plan §4/§8 step 6).
|
|
17
17
|
* Lives under `src/dom/`, not alongside `../webmcp.ts`'s pure `CapabilityDef` → WebMCP-tool
|
|
18
|
-
* projection, because it
|
|
18
|
+
* projection, because it adapts the native browser API — `webmcp.ts`'s own module doc is explicit
|
|
19
19
|
* that "that detection is deliberately NOT here: it touches browser globals, and this package
|
|
20
20
|
* holds none," which is exactly the DOM-free guarantee `src/dom/` exists to carve an exception
|
|
21
21
|
* for. See `dom/index.ts`'s re-export of this module.
|
|
@@ -28,17 +28,14 @@
|
|
|
28
28
|
* fixture: a raw (non-`toWebMcpTool`) registration carrying a `title` failed TypeScript's
|
|
29
29
|
* excess-property check against the un-widened type here.
|
|
30
30
|
*/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const nav = globalThis.navigator;
|
|
40
|
-
if (isModelContext(nav?.modelContext))
|
|
41
|
-
return nav.modelContext;
|
|
31
|
+
import { adaptNativeModelContext } from './native-model-context.js';
|
|
32
|
+
/** Adapts the first installed native surface to Jini's argument-object port. */
|
|
33
|
+
export function getAgentModelContext({ host }, _optional = {}) {
|
|
34
|
+
for (const value of host.candidates({})) {
|
|
35
|
+
const context = adaptNativeModelContext({ value });
|
|
36
|
+
if (context)
|
|
37
|
+
return context;
|
|
38
|
+
}
|
|
42
39
|
return undefined;
|
|
43
40
|
}
|
|
44
41
|
//# sourceMappingURL=model-context.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AgentModelContextLike } from './model-context.js';
|
|
2
|
+
/** Preserve native receiver binding and stable port identity across feature detection. */
|
|
3
|
+
export declare function adaptNativeModelContext({ value }: {
|
|
4
|
+
value: unknown;
|
|
5
|
+
}): AgentModelContextLike | undefined;
|
|
6
|
+
//# sourceMappingURL=native-model-context.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const adapters = new WeakMap();
|
|
2
|
+
/** Preserve native receiver binding and stable port identity across feature detection. */
|
|
3
|
+
export function adaptNativeModelContext({ value }) {
|
|
4
|
+
if (typeof value !== 'object' || value === null || typeof value.registerTool !== 'function')
|
|
5
|
+
return undefined;
|
|
6
|
+
const existing = adapters.get(value);
|
|
7
|
+
if (existing)
|
|
8
|
+
return existing;
|
|
9
|
+
const native = value;
|
|
10
|
+
const adapter = {
|
|
11
|
+
registerTool: ({ tool }, options) => native.registerTool(tool, options),
|
|
12
|
+
...(typeof native.unregisterTool === 'function'
|
|
13
|
+
? { unregisterTool: ({ name }) => native.unregisterTool(name) }
|
|
14
|
+
: {}),
|
|
15
|
+
};
|
|
16
|
+
adapters.set(value, adapter);
|
|
17
|
+
return adapter;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=native-model-context.js.map
|
|
@@ -28,7 +28,9 @@ export declare const AGENT_ELEMENT_ROLES: readonly AgentElementRole[];
|
|
|
28
28
|
* @param handle - Candidate handle, typically caller-supplied.
|
|
29
29
|
* @returns True when it is safe to interpolate into an attribute selector.
|
|
30
30
|
*/
|
|
31
|
-
export declare function isValidElementHandle(handle
|
|
31
|
+
export declare function isValidElementHandle({ handle }: {
|
|
32
|
+
handle: string;
|
|
33
|
+
}, _optional?: Record<string, never>): boolean;
|
|
32
34
|
/**
|
|
33
35
|
* Builds the one selector shape this system will ever resolve.
|
|
34
36
|
*
|
|
@@ -36,7 +38,9 @@ export declare function isValidElementHandle(handle: string): boolean;
|
|
|
36
38
|
* @returns The attribute selector for that handle.
|
|
37
39
|
* @throws If the handle is not valid — never fall back to treating it as a raw selector.
|
|
38
40
|
*/
|
|
39
|
-
export declare function resolveHandleSelector(handle
|
|
41
|
+
export declare function resolveHandleSelector({ handle }: {
|
|
42
|
+
handle: string;
|
|
43
|
+
}, _optional?: Record<string, never>): string;
|
|
40
44
|
/** A tagged element as described back to a caller. `label` is page-authored, so it is untrusted. */
|
|
41
45
|
export interface AgentElementDescriptor {
|
|
42
46
|
readonly handle: string;
|
|
@@ -25,7 +25,7 @@ const MAX_HANDLE_LENGTH = 128;
|
|
|
25
25
|
* @param handle - Candidate handle, typically caller-supplied.
|
|
26
26
|
* @returns True when it is safe to interpolate into an attribute selector.
|
|
27
27
|
*/
|
|
28
|
-
export function isValidElementHandle(handle) {
|
|
28
|
+
export function isValidElementHandle({ handle }, _optional = {}) {
|
|
29
29
|
return handle.length > 0 && handle.length <= MAX_HANDLE_LENGTH && HANDLE_PATTERN.test(handle);
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
@@ -35,8 +35,8 @@ export function isValidElementHandle(handle) {
|
|
|
35
35
|
* @returns The attribute selector for that handle.
|
|
36
36
|
* @throws If the handle is not valid — never fall back to treating it as a raw selector.
|
|
37
37
|
*/
|
|
38
|
-
export function resolveHandleSelector(handle) {
|
|
39
|
-
if (!isValidElementHandle(handle)) {
|
|
38
|
+
export function resolveHandleSelector({ handle }, _optional = {}) {
|
|
39
|
+
if (!isValidElementHandle({ handle })) {
|
|
40
40
|
throw new Error(`invalid element handle "${handle.slice(0, MAX_HANDLE_LENGTH)}": `
|
|
41
41
|
+ 'handles are lowercase words joined by single hyphens, and are never CSS selectors');
|
|
42
42
|
}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
+
import type { Clock } from "@jini-ai/core/primitives";
|
|
1
2
|
/**
|
|
2
|
-
* @module
|
|
3
|
+
* @module gen-ui/encoder
|
|
3
4
|
*
|
|
4
|
-
* Encodes `@jini-ai/protocol`'s `RunProtocolEvent` stream into
|
|
5
|
+
* Encodes `@jini-ai/protocol`'s `RunProtocolEvent` stream into custom gen-ui wire events (see
|
|
5
6
|
* `./events.ts`'s module doc). Rewritten from scratch against `@jini-ai/protocol`'s actual
|
|
6
7
|
* current shape — the ported adapter's original encoder targeted a different, product-specific
|
|
7
8
|
* event union with no direct correspondence to `RunProtocolEvent`/`RunAgentPayload`; only the
|
|
8
9
|
* *shape* of the job (a big per-event-kind switch, unrecognized events silently dropped) carried
|
|
9
|
-
* over. See `
|
|
10
|
+
* over. See `archived provenance ledger` for the full old→new field-mapping table and the generalization
|
|
10
11
|
* writeup for the six event kinds that had no generic equivalent before this task.
|
|
11
12
|
*
|
|
12
13
|
* Folded in 2026-07-26 from the standalone `@jini-ai/agui` package (plan §3a) into this `src/gen-ui/`
|
|
13
14
|
* subdirectory — kept out of the flat `ag-ui.ts` namespace because that file is a different
|
|
14
15
|
* projection ({@link CapabilityDef} → an AG-UI *frontend tool*); this one turns a run's event
|
|
15
|
-
* stream into
|
|
16
|
+
* stream into Jini's own gen-ui *wire* events. These are separate protocols; the old package name
|
|
17
|
+
* did not make this custom event vocabulary compatible with external AG-UI.
|
|
16
18
|
*/
|
|
17
19
|
import type { RunProtocolEvent } from '@jini-ai/protocol';
|
|
18
20
|
import type { GenUiEvent } from './events.js';
|
|
@@ -20,12 +22,12 @@ export interface GenUiEncodeContext {
|
|
|
20
22
|
/** The run this event belongs to — stamped onto every produced `GenUiEvent`. */
|
|
21
23
|
readonly runId: string;
|
|
22
24
|
/** Passed through onto the produced event's `seq`, when the caller tracks one (e.g. an SSE `Last-Event-ID`-shaped cursor). Omitted entirely (not set to `undefined`) when absent, matching the original adapter's own base-field construction. */
|
|
23
|
-
readonly seq?: number;
|
|
24
|
-
/**
|
|
25
|
-
readonly now?: () => number;
|
|
25
|
+
readonly seq?: number | undefined;
|
|
26
|
+
/** Optional clock override for this event; the factory's required clock supplies the default. */
|
|
27
|
+
readonly now?: ((required: Record<string, never>) => number) | undefined;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
|
-
* A stateful
|
|
30
|
+
* A stateful gen-ui encoder for one run's event stream. Stateful because `tool_use`/`tool_result`
|
|
29
31
|
* correlation requires remembering each in-flight tool call's name/args between the two protocol
|
|
30
32
|
* events that describe its start and end — a pure per-event function cannot do this alone. Create
|
|
31
33
|
* one instance per run (e.g. one per `RunLifecycle.stream(runId, ...)` subscription); do not share
|
|
@@ -34,11 +36,17 @@ export interface GenUiEncodeContext {
|
|
|
34
36
|
*/
|
|
35
37
|
export interface GenUiEncoder {
|
|
36
38
|
/**
|
|
37
|
-
* Encodes one `RunProtocolEvent` into
|
|
39
|
+
* Encodes one `RunProtocolEvent` into a `GenUiEvent`, or `null` if this event has no gen-ui
|
|
38
40
|
* equivalent (an unrecognized/not-yet-generalized event kind — silently dropped by the relay,
|
|
39
41
|
* matching the original adapter's own default behavior).
|
|
40
42
|
*/
|
|
41
|
-
encode(
|
|
43
|
+
encode(required: {
|
|
44
|
+
event: RunProtocolEvent;
|
|
45
|
+
runId: string;
|
|
46
|
+
}, optional?: {
|
|
47
|
+
seq?: number | undefined;
|
|
48
|
+
now?: ((required: Record<string, never>) => number) | undefined;
|
|
49
|
+
}): GenUiEvent | null;
|
|
42
50
|
}
|
|
43
51
|
/**
|
|
44
52
|
* Creates a fresh `GenUiEncoder` with its own, empty tool-call correlation map.
|
|
@@ -46,5 +54,7 @@ export interface GenUiEncoder {
|
|
|
46
54
|
* of currently in-flight (not yet resolved) tool calls for the run this instance encodes.
|
|
47
55
|
* @overallScore 100/100
|
|
48
56
|
*/
|
|
49
|
-
export declare function createGenUiEncoder(
|
|
57
|
+
export declare function createGenUiEncoder({ clock }: {
|
|
58
|
+
clock: Clock;
|
|
59
|
+
}, _optional?: Record<string, never>): GenUiEncoder;
|
|
50
60
|
//# sourceMappingURL=encoder.d.ts.map
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* of currently in-flight (not yet resolved) tool calls for the run this instance encodes.
|
|
5
5
|
* @overallScore 100/100
|
|
6
6
|
*/
|
|
7
|
-
export function createGenUiEncoder() {
|
|
7
|
+
export function createGenUiEncoder({ clock }, _optional = {}) {
|
|
8
8
|
const pendingToolCalls = new Map();
|
|
9
9
|
function baseFields(ctx) {
|
|
10
|
-
const ts = ctx.now ? ctx.now() :
|
|
10
|
+
const ts = ctx.now ? ctx.now({}) : clock.nowMs();
|
|
11
11
|
return ctx.seq !== undefined ? { runId: ctx.runId, ts, seq: ctx.seq } : { runId: ctx.runId, ts };
|
|
12
12
|
}
|
|
13
13
|
function encodeAgentPayload(payload, ctx) {
|
|
@@ -38,7 +38,7 @@ export function createGenUiEncoder() {
|
|
|
38
38
|
result: payload.content,
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
// Generalization (see
|
|
41
|
+
// Generalization (see archived provenance ledger): pipeline_stage_started/completed generalized into a
|
|
42
42
|
// named-stage boundary any multi-step driver can emit, flowing through the same 'agent'
|
|
43
43
|
// channel as tool_use/tool_result.
|
|
44
44
|
case 'stage_start':
|
|
@@ -57,19 +57,20 @@ export function createGenUiEncoder() {
|
|
|
57
57
|
stageId: payload.stageId,
|
|
58
58
|
...(payload.iteration !== undefined ? { iteration: payload.iteration } : {}),
|
|
59
59
|
};
|
|
60
|
-
// Generalization (see
|
|
60
|
+
// Generalization (see archived provenance ledger): genui_surface_request/response generalized into a
|
|
61
61
|
// generic human-in-the-loop ask/answer pair.
|
|
62
62
|
case 'surface_request':
|
|
63
63
|
return { ...base, kind: 'ui.surface_requested', surfaceId: payload.surfaceId, surfaceKind: payload.surfaceKind, payload: payload.payload };
|
|
64
64
|
case 'surface_response':
|
|
65
65
|
return { ...base, kind: 'ui.surface_responded', surfaceId: payload.surfaceId, value: payload.value, respondedBy: payload.respondedBy };
|
|
66
66
|
// 'status' / 'thinking_start' / 'thinking_delta' / 'tool_input_delta' / 'usage' / 'raw':
|
|
67
|
-
// no
|
|
67
|
+
// no gen-ui equivalent — silently dropped, matching the original adapter's default behavior.
|
|
68
68
|
default:
|
|
69
69
|
return null;
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
function encode(event,
|
|
72
|
+
function encode({ event, runId }, { seq, now } = {}) {
|
|
73
|
+
const ctx = { runId, seq, now };
|
|
73
74
|
switch (event.kind) {
|
|
74
75
|
case 'start':
|
|
75
76
|
return { ...baseFields(ctx), kind: 'run.lifecycle', status: 'started' };
|
|
@@ -86,7 +87,7 @@ export function createGenUiEncoder() {
|
|
|
86
87
|
}
|
|
87
88
|
case 'agent':
|
|
88
89
|
return encodeAgentPayload(event.payload, ctx);
|
|
89
|
-
// 'stdout' / 'stderr' / 'error': no
|
|
90
|
+
// 'stdout' / 'stderr' / 'error': no gen-ui equivalent — silently dropped, matching the
|
|
90
91
|
// original adapter's default behavior for unrecognized event kinds.
|
|
91
92
|
default:
|
|
92
93
|
return null;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @module
|
|
2
|
+
* @module gen-ui/events
|
|
3
3
|
*
|
|
4
|
-
* The
|
|
5
|
-
* Protocol) is CopilotKit's
|
|
6
|
-
* a UI client — see https://github.com/ag-ui-protocol/ag-ui.
|
|
4
|
+
* The custom gen-ui wire event shapes `./encoder.ts` produces. AG-UI (Agent-User Interaction
|
|
5
|
+
* Protocol) is CopilotKit's separate, external wire protocol for streaming an agent's run over SSE to
|
|
6
|
+
* a UI client — see https://github.com/ag-ui-protocol/ag-ui. These six `kind` values belong to
|
|
7
|
+
* Jini's own protocol, not the external AG-UI event vocabulary. This module is a near-verbatim port
|
|
7
8
|
* of a 312-line adapter that encoded a product's own run-event stream into this shape; the types
|
|
8
|
-
* themselves are unchanged in kind, only de-branded (see `
|
|
9
|
+
* themselves are unchanged in kind, only de-branded (see `archived provenance ledger` for the full
|
|
9
10
|
* field-mapping table and provenance).
|
|
10
11
|
*
|
|
11
12
|
* Folded in 2026-07-26 from the standalone `@jini-ai/agui` package (plan §3a) into this `src/gen-ui/`
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @module
|
|
2
|
+
* @module gen-ui/events
|
|
3
3
|
*
|
|
4
|
-
* The
|
|
5
|
-
* Protocol) is CopilotKit's
|
|
6
|
-
* a UI client — see https://github.com/ag-ui-protocol/ag-ui.
|
|
4
|
+
* The custom gen-ui wire event shapes `./encoder.ts` produces. AG-UI (Agent-User Interaction
|
|
5
|
+
* Protocol) is CopilotKit's separate, external wire protocol for streaming an agent's run over SSE to
|
|
6
|
+
* a UI client — see https://github.com/ag-ui-protocol/ag-ui. These six `kind` values belong to
|
|
7
|
+
* Jini's own protocol, not the external AG-UI event vocabulary. This module is a near-verbatim port
|
|
7
8
|
* of a 312-line adapter that encoded a product's own run-event stream into this shape; the types
|
|
8
|
-
* themselves are unchanged in kind, only de-branded (see `
|
|
9
|
+
* themselves are unchanged in kind, only de-branded (see `archived provenance ledger` for the full
|
|
9
10
|
* field-mapping table and provenance).
|
|
10
11
|
*
|
|
11
12
|
* Folded in 2026-07-26 from the standalone `@jini-ai/agui` package (plan §3a) into this `src/gen-ui/`
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* **This is not AG-UI**, despite what this directory was called until 2026-07-27. The real
|
|
9
9
|
* Agent-User Interaction Protocol uses a 33-member `SCREAMING_SNAKE` event enum and shares zero
|
|
10
10
|
* event names with these six; `../ag-ui.ts` is the genuine AG-UI projection and lives at `src/`
|
|
11
|
-
* root, apart from this. See `
|
|
11
|
+
* root, apart from this. See `archived provenance ledger` for how the two came to be confused.
|
|
12
12
|
*
|
|
13
13
|
* Nothing here opens a connection or touches a browser global. Transport (SSE, WebSocket) belongs
|
|
14
14
|
* to a host — `@jini-ai/http-kit`'s run-stream route is the shipped consumer.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* **This is not AG-UI**, despite what this directory was called until 2026-07-27. The real
|
|
9
9
|
* Agent-User Interaction Protocol uses a 33-member `SCREAMING_SNAKE` event enum and shares zero
|
|
10
10
|
* event names with these six; `../ag-ui.ts` is the genuine AG-UI projection and lives at `src/`
|
|
11
|
-
* root, apart from this. See `
|
|
11
|
+
* root, apart from this. See `archived provenance ledger` for how the two came to be confused.
|
|
12
12
|
*
|
|
13
13
|
* Nothing here opens a connection or touches a browser global. Transport (SSE, WebSocket) belongs
|
|
14
14
|
* to a host — `@jini-ai/http-kit`'s run-stream route is the shipped consumer.
|