nanocodex 0.4.0 → 0.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/README.md +944 -78
- package/actions/events.mjs +14 -25
- package/actions/index.d.mts +1 -0
- package/actions/index.mjs +11 -1
- package/actions/session.d.mts +29 -1
- package/actions/session.mjs +22 -0
- package/actions/turn.d.mts +15 -6
- package/actions/turn.mjs +10 -0
- package/actions/voice.d.mts +26 -0
- package/actions/voice.mjs +54 -0
- package/browser/Agent.d.mts +41 -24
- package/browser/Agent.mjs +7 -84
- package/browser/ChatGptSubscription.d.mts +7 -0
- package/browser/ChatGptSubscription.mjs +19 -0
- package/browser/InlineAgent.mjs +267 -0
- package/browser/Transport.d.mts +80 -0
- package/browser/Transport.mjs +63 -0
- package/browser/Voice.d.mts +86 -0
- package/browser/Voice.mjs +316 -0
- package/browser/VoiceSession.mjs +763 -0
- package/browser/WorkerAgent.d.mts +65 -0
- package/browser/WorkerAgent.mjs +1467 -0
- package/browser/agent.worker.mjs +3 -0
- package/browser/config.d.mts +36 -0
- package/browser/config.mjs +439 -0
- package/browser/engine.mjs +13 -0
- package/browser/harness.mjs +55 -0
- package/browser/host.d.mts +33 -5
- package/browser/host.mjs +320 -26
- package/browser/hostManagedWebSocket.d.mts +14 -0
- package/browser/hostManagedWebSocket.mjs +110 -0
- package/browser/index.d.mts +64 -1
- package/browser/index.mjs +22 -1
- package/browser/indexeddb-durability-store.mjs +210 -0
- package/browser/workspace.d.mts +16 -0
- package/browser/workspace.mjs +107 -0
- package/cloud/Client.d.mts +83 -0
- package/cloud/Client.mjs +231 -0
- package/cloud/Decorator.d.mts +31 -0
- package/cloud/Decorator.mjs +37 -0
- package/cloud/Dialog.d.mts +113 -0
- package/cloud/Dialog.mjs +366 -0
- package/cloud/Errors.d.mts +22 -0
- package/cloud/Errors.mjs +39 -0
- package/cloud/Principal.d.mts +26 -0
- package/cloud/Principal.mjs +88 -0
- package/cloud/RemoteProvider.mjs +88 -0
- package/cloud/Transport.d.mts +47 -0
- package/cloud/Transport.mjs +454 -0
- package/cloud/actions/account.d.mts +9 -0
- package/cloud/actions/account.mjs +19 -0
- package/cloud/actions/agent.d.mts +18 -0
- package/cloud/actions/agent.mjs +429 -0
- package/cloud/actions/connection.d.mts +133 -0
- package/cloud/actions/connection.mjs +580 -0
- package/cloud/actions/grant.d.mts +10 -0
- package/cloud/actions/grant.mjs +12 -0
- package/cloud/actions/index.d.mts +7 -0
- package/cloud/actions/index.mjs +7 -0
- package/cloud/actions/machineUsd.d.mts +23 -0
- package/cloud/actions/machineUsd.mjs +37 -0
- package/cloud/actions/model.d.mts +12 -0
- package/cloud/actions/model.mjs +50 -0
- package/cloud/actions/mpp.d.mts +28 -0
- package/cloud/actions/mpp.mjs +39 -0
- package/cloud/index.d.mts +30 -0
- package/cloud/index.mjs +9 -0
- package/cloud/internal.mjs +533 -0
- package/cloud/mercator.mjs +108 -0
- package/cloud/server/HostPrincipal.d.mts +34 -0
- package/cloud/server/HostPrincipal.mjs +202 -0
- package/cloud/server/index.d.mts +1 -0
- package/cloud/server/index.mjs +1 -0
- package/cloud/types.d.mts +212 -0
- package/cloudflare/Agent.d.mts +136 -0
- package/cloudflare/Agent.mjs +784 -0
- package/cloudflare/egress-subject.mjs +19 -0
- package/cloudflare/egress.d.mts +41 -0
- package/cloudflare/egress.mjs +119 -0
- package/cloudflare/event-socket.mjs +316 -0
- package/cloudflare/index.d.mts +7 -0
- package/cloudflare/index.mjs +6 -0
- package/host/Agent.d.mts +55 -0
- package/host/Agent.mjs +1 -0
- package/host/index.d.mts +71 -0
- package/host/index.mjs +10 -0
- package/index.d.mts +46 -0
- package/index.mjs +11 -0
- package/internal.mjs +673 -61
- package/managed/Agent.d.mts +459 -0
- package/managed/Agent.mjs +1824 -0
- package/managed/ManagedError.d.mts +9 -0
- package/managed/ManagedError.mjs +8 -0
- package/managed/README.md +244 -0
- package/managed/Voice.mjs +209 -0
- package/managed/index.d.mts +22 -0
- package/managed/index.mjs +2 -0
- package/managed/internal.mjs +119 -0
- package/node/Agent.d.mts +35 -8
- package/node/Agent.mjs +116 -25
- package/node/ChatGptSubscription.d.mts +9 -0
- package/node/ChatGptSubscription.mjs +17 -0
- package/node/Transport.d.mts +41 -0
- package/node/Transport.mjs +46 -0
- package/node/host.mjs +99 -17
- package/node/index.d.mts +45 -1
- package/node/index.mjs +16 -1
- package/node/workspace.d.mts +10 -0
- package/node/workspace.mjs +198 -0
- package/package.json +145 -11
- package/pkg-node/nanocodex.d.ts +523 -11
- package/pkg-node/nanocodex.js +2038 -179
- package/pkg-node/nanocodex_bg.wasm.d.ts +100 -29
- package/pkg-web/.nanocodex-bindgen-stamp +6 -0
- package/pkg-web/nanocodex-build.json +1 -0
- package/pkg-web/nanocodex.d.ts +623 -40
- package/pkg-web/nanocodex.js +2031 -178
- package/pkg-web/nanocodex_bg.js +2667 -0
- package/pkg-web/nanocodex_bg.wasm +0 -0
- package/pkg-web/nanocodex_bg.wasm.d.ts +100 -29
- package/pkg-web/nanocodex_worker.js +9 -0
- package/runtime/chatgpt-subscription.mjs +212 -0
- package/runtime/cloudflare-durability-store.d.mts +26 -0
- package/runtime/cloudflare-durability-store.mjs +14 -0
- package/runtime/code-evaluator.worker.mjs +137 -0
- package/runtime/code-runtime.mjs +1 -243
- package/runtime/durability-store.d.mts +85 -0
- package/runtime/durability-store.mjs +752 -0
- package/runtime/durability.mjs +174 -0
- package/runtime/managed-transport.mjs +461 -0
- package/runtime/mcp-runtime.mjs +534 -0
- package/runtime/postgres-durability-store.d.mts +64 -0
- package/runtime/postgres-durability-store.mjs +581 -0
- package/runtime/quickjs-evaluator.d.mts +17 -0
- package/runtime/quickjs-evaluator.mjs +236 -0
- package/runtime/response-controls.mjs +42 -0
- package/runtime/response-lanes.mjs +72 -0
- package/runtime/responses-transport.mjs +22 -0
- package/runtime/subagents.d.mts +107 -0
- package/runtime/subagents.mjs +54 -0
- package/runtime/subscription-store.d.mts +8 -0
- package/runtime/subscription-store.mjs +42 -0
- package/runtime/tempo-provider.d.mts +125 -0
- package/runtime/tempo-provider.mjs +264 -0
- package/runtime/tool-configuration.mjs +1 -0
- package/runtime/tool-router.mjs +1 -0
- package/runtime/utf8.mjs +1 -0
- package/runtime/worker-evaluator.mjs +162 -0
- package/runtime/workspace.d.mts +1 -0
- package/runtime/workspace.mjs +1 -0
- package/tools/Tools.d.mts +56 -0
- package/tools/Tools.mjs +136 -0
- package/tools/artifact.d.mts +1 -0
- package/tools/artifact.mjs +1 -0
- package/tools/attachment.mjs +1 -0
- package/tools/bash.d.mts +1 -0
- package/tools/bash.mjs +1 -0
- package/tools/browser/accountInfo.mjs +795 -0
- package/tools/browser/browserBuffer.mjs +18 -0
- package/tools/browser/browserCompiler.mjs +155 -0
- package/tools/browser/browserEgress.mjs +161 -0
- package/tools/browser/browserPython.mjs +133 -0
- package/tools/browser/browserShell.mjs +1075 -0
- package/tools/browser/browserSprintf.mjs +4 -0
- package/tools/browser/browserSsh.mjs +201 -0
- package/tools/browser/browserZlib.mjs +136 -0
- package/tools/browser/compiler.worker.mjs +160 -0
- package/tools/browser/devTunnelsSshBrowser.mjs +13 -0
- package/tools/browser/index.d.mts +209 -0
- package/tools/browser/index.mjs +174 -0
- package/tools/browser/opfsGit.mjs +248 -0
- package/tools/browser/python.worker.mjs +114 -0
- package/tools/browser/threadGit.mjs +197 -0
- package/tools/browser/unsupportedNodeRsa.mjs +5 -0
- package/tools/browser/workspace.mjs +83 -0
- package/tools/dataset.d.mts +1 -0
- package/tools/dataset.mjs +1 -0
- package/tools/datasetContract.mjs +1 -0
- package/tools/datasetEngine.mjs +1 -0
- package/tools/hostedCatalog.d.mts +1 -0
- package/tools/hostedCatalog.mjs +1 -0
- package/tools/index.d.mts +49 -0
- package/tools/index.mjs +19 -0
- package/tools/namedTool.mjs +1 -0
- package/tools/repository-workspace.d.mts +1 -0
- package/tools/repository-workspace.mjs +1 -0
- package/tools/ssh.d.mts +1 -0
- package/tools/ssh.mjs +1 -0
- package/tools/standard.mjs +1 -0
- package/tools/standardDescriptions.mjs +1 -0
- package/types.d.mts +431 -16
- package/worker/ChatGptSubscription.d.mts +9 -0
- package/worker/ChatGptSubscription.mjs +29 -0
- package/worker/index.d.mts +18 -0
- package/worker/index.mjs +5 -0
- package/pkg-node/nanocodex_bg.wasm +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { McpPayment, McpServers, MppSession } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
export declare const DEFAULT_MERCATOR_MCP_URL = "https://mercator.tempo.xyz/mcp";
|
|
4
|
+
|
|
5
|
+
export type TempoProvider<Session extends MppSession = MppSession> = MppSession & Readonly<{
|
|
6
|
+
kind: "tempo";
|
|
7
|
+
/** The underlying session, available for channel and payment telemetry. */
|
|
8
|
+
session: Session;
|
|
9
|
+
/** MPP-aware HTTP fetch using the same methods as paid MCP calls. */
|
|
10
|
+
fetch?: TempoPaymentFetch | undefined;
|
|
11
|
+
}>;
|
|
12
|
+
|
|
13
|
+
export function createTempoProvider<Session extends MppSession>(
|
|
14
|
+
options: { session: Session; payment: McpPayment; fetch?: TempoPaymentFetch | undefined },
|
|
15
|
+
): TempoProvider<Session>;
|
|
16
|
+
|
|
17
|
+
export type TempoPaymentFetch = (
|
|
18
|
+
input: RequestInfo | URL,
|
|
19
|
+
init?: RequestInit | undefined,
|
|
20
|
+
policy?: Readonly<{
|
|
21
|
+
maxAmount?: bigint | undefined;
|
|
22
|
+
intent?: "charge" | "session" | undefined;
|
|
23
|
+
}> | undefined,
|
|
24
|
+
) => Promise<Response>;
|
|
25
|
+
|
|
26
|
+
type WalletParameters = {
|
|
27
|
+
getClient: (...args: any[]) => any;
|
|
28
|
+
resolveAccount: (...args: any[]) => any;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** The adapter-neutral surface implemented by every Accounts SDK provider. */
|
|
32
|
+
export type AccountsWallet = {
|
|
33
|
+
getMppxParameters(options?: { accessKey?: `0x${string}` | undefined }): WalletParameters;
|
|
34
|
+
getAccount?(options?: unknown): { address: `0x${string}` };
|
|
35
|
+
store?: {
|
|
36
|
+
getState?(): { activeAccount?: number; accounts?: readonly { address: `0x${string}` }[]; chainId?: number };
|
|
37
|
+
accessKeys?: {
|
|
38
|
+
get(options: {
|
|
39
|
+
account: `0x${string}`;
|
|
40
|
+
accessKey: `0x${string}`;
|
|
41
|
+
chainId: number;
|
|
42
|
+
}): Promise<unknown>;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type AccountsTempoPolicy = {
|
|
48
|
+
/**
|
|
49
|
+
* These values stay structurally typed so a wallet may use any compatible
|
|
50
|
+
* Accounts/MPPx/Viem dependency instance without nominal package coupling.
|
|
51
|
+
*/
|
|
52
|
+
autoSwap?: unknown;
|
|
53
|
+
channelStore?: unknown;
|
|
54
|
+
decimals?: number | undefined;
|
|
55
|
+
escrow?: `0x${string}` | undefined;
|
|
56
|
+
maxDeposit?: string | undefined;
|
|
57
|
+
topUpAmount?: string | undefined;
|
|
58
|
+
[option: string]: unknown;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export type AccountsTempoSessionOptions = AccountsTempoPolicy & {
|
|
62
|
+
bootstrap?: boolean | undefined;
|
|
63
|
+
fetch?: typeof globalThis.fetch | undefined;
|
|
64
|
+
webSocket?: unknown;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export type AccountsTempoMercatorOptions = AccountsTempoPolicy & {
|
|
68
|
+
onChannelUpdate?: ((entry: {
|
|
69
|
+
channelId: `0x${string}`;
|
|
70
|
+
cumulativeAmount: bigint;
|
|
71
|
+
[field: string]: unknown;
|
|
72
|
+
}) => void | Promise<void>) | undefined;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export type AccountsTempoPaymentOptions = {
|
|
76
|
+
/** Raw fetch wrapped by MPPx. */
|
|
77
|
+
fetch?: typeof globalThis.fetch | undefined;
|
|
78
|
+
/** Maximum atomic amount accepted from one HTTP or MCP challenge. */
|
|
79
|
+
maxAmount?: bigint | undefined;
|
|
80
|
+
/** Optional application approval composed after the amount check. */
|
|
81
|
+
onPaymentRequired?: ((challenge: unknown) => boolean | Promise<boolean>) | undefined;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export type AccountsTempoSession = MppSession & {
|
|
85
|
+
readonly channelId: `0x${string}` | undefined;
|
|
86
|
+
readonly cumulative: bigint;
|
|
87
|
+
readonly opened: boolean;
|
|
88
|
+
readonly state: unknown;
|
|
89
|
+
close(): Promise<unknown>;
|
|
90
|
+
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
91
|
+
topUp(amount: string | bigint): Promise<unknown>;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export type AccountsTempoProviderOptions = {
|
|
95
|
+
/** Any provider returned by Accounts SDK `Provider.create(...)`. */
|
|
96
|
+
wallet: AccountsWallet;
|
|
97
|
+
/** Connected root account owning the delegated key. Inferred from Accounts when omitted. */
|
|
98
|
+
account?: `0x${string}` | undefined;
|
|
99
|
+
/** Optional Accounts SDK access key to pin for both model and MCP payments. */
|
|
100
|
+
accessKey?: `0x${string}` | undefined;
|
|
101
|
+
/** Chain on which the delegated key is authorized. Inferred from Accounts when omitted. */
|
|
102
|
+
chainId?: number | undefined;
|
|
103
|
+
/** Shared Tempo payment policy applied to the model session and Mercator. */
|
|
104
|
+
policy?: AccountsTempoPolicy | undefined;
|
|
105
|
+
/** Model-session-only overrides, such as `bootstrap` or `webSocket`. */
|
|
106
|
+
session?: AccountsTempoSessionOptions | undefined;
|
|
107
|
+
/** Mercator-only Tempo method overrides, such as `onChannelUpdate`. */
|
|
108
|
+
mercator?: AccountsTempoMercatorOptions | undefined;
|
|
109
|
+
/** Shared HTTP and MCP challenge policy. */
|
|
110
|
+
payment?: AccountsTempoPaymentOptions | undefined;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Constructs a Tempo provider from any Accounts SDK wallet adapter without
|
|
115
|
+
* taking a runtime dependency on `accounts`.
|
|
116
|
+
*/
|
|
117
|
+
export function createTempoProviderFromAccounts(
|
|
118
|
+
options: AccountsTempoProviderOptions,
|
|
119
|
+
): Promise<TempoProvider<AccountsTempoSession>>;
|
|
120
|
+
|
|
121
|
+
/** @internal */
|
|
122
|
+
export function resolveMcpServers(
|
|
123
|
+
provider: MppSession | undefined,
|
|
124
|
+
configured: McpServers | false | undefined,
|
|
125
|
+
): McpServers | undefined;
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
const tempoMcp = Symbol.for("nanocodex.tempo.mcp");
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_MERCATOR_MCP_URL = "https://mercator.tempo.xyz/mcp";
|
|
4
|
+
|
|
5
|
+
const defaultMercator = (payment) => ({
|
|
6
|
+
url: DEFAULT_MERCATOR_MCP_URL,
|
|
7
|
+
description: "Discovers and composes paid Tempo services and MPP flows.",
|
|
8
|
+
payment,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Marks an MPP session as a Tempo provider and uses the same wallet policy for
|
|
13
|
+
* Nanocodex's built-in paid Mercator MCP. Generic MPP sessions remain generic.
|
|
14
|
+
*/
|
|
15
|
+
export function createTempoProvider(options) {
|
|
16
|
+
const session = options?.session;
|
|
17
|
+
if (!session || typeof session.ws !== "function") {
|
|
18
|
+
throw new TypeError("session must provide ws(endpoint)");
|
|
19
|
+
}
|
|
20
|
+
if (!options.payment || !Array.isArray(options.payment.methods) || !options.payment.methods.length) {
|
|
21
|
+
throw new TypeError("Tempo provider payment must include at least one MPPx method");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const provider = {
|
|
25
|
+
kind: "tempo",
|
|
26
|
+
session,
|
|
27
|
+
ws(endpoint) {
|
|
28
|
+
return session.ws(endpoint);
|
|
29
|
+
},
|
|
30
|
+
...(typeof options.fetch === "function" ? { fetch: options.fetch } : {}),
|
|
31
|
+
};
|
|
32
|
+
if (typeof session.close === "function") {
|
|
33
|
+
provider.close = () => session.close();
|
|
34
|
+
}
|
|
35
|
+
Object.defineProperty(provider, tempoMcp, {
|
|
36
|
+
value: { mercator: defaultMercator(options.payment) },
|
|
37
|
+
});
|
|
38
|
+
return Object.freeze(provider);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Creates the model session and Mercator payment method from any Accounts SDK
|
|
43
|
+
* provider. Accounts adapters all meet the same getMppxParameters() contract,
|
|
44
|
+
* so wallet selection remains entirely application-owned.
|
|
45
|
+
*/
|
|
46
|
+
export async function createTempoProviderFromAccounts(options) {
|
|
47
|
+
const wallet = options?.wallet;
|
|
48
|
+
if (!wallet || typeof wallet.getMppxParameters !== "function") {
|
|
49
|
+
throw new TypeError("wallet must provide getMppxParameters(options)");
|
|
50
|
+
}
|
|
51
|
+
const accessKey = options.accessKey;
|
|
52
|
+
const walletParametersRaw = wallet.getMppxParameters(
|
|
53
|
+
accessKey === undefined ? undefined : { accessKey },
|
|
54
|
+
);
|
|
55
|
+
if (!walletParametersRaw || typeof walletParametersRaw.getClient !== "function"
|
|
56
|
+
|| typeof walletParametersRaw.resolveAccount !== "function") {
|
|
57
|
+
throw new TypeError("wallet.getMppxParameters() returned invalid MPPx parameters");
|
|
58
|
+
}
|
|
59
|
+
// Keep mppx out of normal/API-key browser bundles. It is loaded only when an
|
|
60
|
+
// application explicitly asks Nanocodex to construct a Tempo wallet path.
|
|
61
|
+
const [{ Mppx, tempo }, { createClient, http }] = await Promise.all([
|
|
62
|
+
import("mppx/client"),
|
|
63
|
+
import("viem/tempo"),
|
|
64
|
+
]);
|
|
65
|
+
const walletParameters = await pinnedScopedAccountParameters(
|
|
66
|
+
wallet,
|
|
67
|
+
walletParametersRaw,
|
|
68
|
+
accessKey,
|
|
69
|
+
{
|
|
70
|
+
account: options.account,
|
|
71
|
+
chainId: options.chainId,
|
|
72
|
+
createClient,
|
|
73
|
+
http,
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
const policy = options.policy ?? {};
|
|
77
|
+
const session = tempo.session.manager({
|
|
78
|
+
...policy,
|
|
79
|
+
...options.session,
|
|
80
|
+
...walletParameters,
|
|
81
|
+
});
|
|
82
|
+
const method = tempo({
|
|
83
|
+
...policy,
|
|
84
|
+
...options.mercator,
|
|
85
|
+
...walletParameters,
|
|
86
|
+
});
|
|
87
|
+
const paymentPolicy = options.payment ?? {};
|
|
88
|
+
const approvePayment = paymentApproval(paymentPolicy);
|
|
89
|
+
const payment = {
|
|
90
|
+
methods: [method],
|
|
91
|
+
...(approvePayment ? { onPaymentRequired: approvePayment } : {}),
|
|
92
|
+
};
|
|
93
|
+
const fetch = (input, init, requestPolicy) => {
|
|
94
|
+
const requestApproval = paymentApproval({
|
|
95
|
+
...paymentPolicy,
|
|
96
|
+
...(requestPolicy?.maxAmount === undefined
|
|
97
|
+
? {}
|
|
98
|
+
: { maxAmount: requestPolicy.maxAmount }),
|
|
99
|
+
});
|
|
100
|
+
const mppx = Mppx.create({
|
|
101
|
+
methods: [method],
|
|
102
|
+
polyfill: false,
|
|
103
|
+
...(paymentPolicy.fetch ? { fetch: paymentPolicy.fetch } : {}),
|
|
104
|
+
...(requestPolicy?.intent
|
|
105
|
+
? {
|
|
106
|
+
orderChallenges(candidates) {
|
|
107
|
+
return [...candidates].sort((left, right) =>
|
|
108
|
+
Number(right.challenge.intent === requestPolicy.intent)
|
|
109
|
+
- Number(left.challenge.intent === requestPolicy.intent));
|
|
110
|
+
},
|
|
111
|
+
}
|
|
112
|
+
: {}),
|
|
113
|
+
...(requestApproval
|
|
114
|
+
? {
|
|
115
|
+
async onChallenge(challenge, { createCredential }) {
|
|
116
|
+
if (!(await requestApproval(challenge))) {
|
|
117
|
+
throw new Error("MPP payment declined by Nanocodex policy.");
|
|
118
|
+
}
|
|
119
|
+
return createCredential();
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
: {}),
|
|
123
|
+
});
|
|
124
|
+
return mppx.fetch(input, init);
|
|
125
|
+
};
|
|
126
|
+
return createTempoProvider({
|
|
127
|
+
session,
|
|
128
|
+
payment,
|
|
129
|
+
fetch,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** @internal */
|
|
134
|
+
export async function pinnedScopedAccountParameters(wallet, parameters, accessKey, clientFactory) {
|
|
135
|
+
const getAccessKey = wallet?.store?.accessKeys?.get;
|
|
136
|
+
if (accessKey === undefined || typeof getAccessKey !== "function") return parameters;
|
|
137
|
+
|
|
138
|
+
const state = wallet.store.getState?.();
|
|
139
|
+
const rootAccount = clientFactory.account
|
|
140
|
+
?? wallet.getAccount?.()?.address
|
|
141
|
+
?? state?.accounts?.[state.activeAccount ?? 0]?.address;
|
|
142
|
+
const chainId = Number(clientFactory.chainId ?? state?.chainId ?? 4217);
|
|
143
|
+
if (typeof rootAccount !== "string") {
|
|
144
|
+
throw new Error("The connected Accounts root address is unavailable.");
|
|
145
|
+
}
|
|
146
|
+
const pinnedAccount = await getAccessKey.call(wallet.store.accessKeys, {
|
|
147
|
+
account: rootAccount,
|
|
148
|
+
accessKey,
|
|
149
|
+
chainId,
|
|
150
|
+
});
|
|
151
|
+
const expected = accessKey.toLowerCase();
|
|
152
|
+
if (!pinnedAccount || pinnedAccount.accessKeyAddress?.toLowerCase() !== expected) {
|
|
153
|
+
throw new Error(`Pinned access key "${accessKey}" is not available in the Accounts keystore.`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const clients = new Map();
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
...parameters,
|
|
160
|
+
getClient(info = {}) {
|
|
161
|
+
const source = parameters.getClient(info);
|
|
162
|
+
const requestedChainId = Number(info.chainId ?? source?.chain?.id ?? chainId);
|
|
163
|
+
if (requestedChainId !== chainId) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`Pinned access key "${accessKey}" is authorized for chain ${chainId}, not ${requestedChainId}.`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
let client = clients.get(requestedChainId);
|
|
169
|
+
if (client) return client;
|
|
170
|
+
|
|
171
|
+
const rpcUrl = source?.chain?.rpcUrls?.default?.http?.[0];
|
|
172
|
+
if (typeof rpcUrl !== "string") {
|
|
173
|
+
throw new Error(`No direct Tempo RPC URL is configured for chain ${requestedChainId}.`);
|
|
174
|
+
}
|
|
175
|
+
// The Accounts client routes JSON-RPC back through the wallet provider.
|
|
176
|
+
// That transport may auto-select a different valid access key while
|
|
177
|
+
// filling a transaction. Use the chain's direct RPC transport here, but
|
|
178
|
+
// keep reads rooted at the payer account. Setting the client account to
|
|
179
|
+
// the unpublished access key makes viem encode eth_call as a keychain
|
|
180
|
+
// call before the first payment transaction has attached its pending
|
|
181
|
+
// keyAuthorization, so even balanceOf fails with KeyNotFound. MPPx passes
|
|
182
|
+
// the exact local pinnedAccount returned by resolveAccount when it
|
|
183
|
+
// prepares and signs the mutating channel transaction; that is the point
|
|
184
|
+
// where viem attaches and consumes the pending authorization.
|
|
185
|
+
client = clientFactory.createClient({
|
|
186
|
+
account: { address: rootAccount, type: "json-rpc" },
|
|
187
|
+
chain: source.chain,
|
|
188
|
+
transport: clientFactory.http(rpcUrl),
|
|
189
|
+
});
|
|
190
|
+
clients.set(requestedChainId, client);
|
|
191
|
+
return client;
|
|
192
|
+
},
|
|
193
|
+
async resolveAccount(info) {
|
|
194
|
+
const authority = info?.operation?.kind === "authorizePaymentChannel"
|
|
195
|
+
? info.operation.authority?.toLowerCase()
|
|
196
|
+
: undefined;
|
|
197
|
+
if (authority !== undefined && authority !== expected) {
|
|
198
|
+
throw new Error(
|
|
199
|
+
`MPP channel authority "${info.operation.authority}" does not match pinned access key "${accessKey}".`,
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Accounts may have several valid delegated keys for the same Tempo
|
|
204
|
+
// account. Its generic resolver is allowed to choose any key whose
|
|
205
|
+
// scopes cover a transaction, but an MPP channel is bound to one exact
|
|
206
|
+
// authority. Load that signer directly so channel top-ups and closes
|
|
207
|
+
// can never drift to a newer matching key.
|
|
208
|
+
if (info.chainId !== chainId) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
`Pinned access key "${accessKey}" is authorized for chain ${chainId}, not ${info.chainId}.`,
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
if (info.account.address.toLowerCase() !== rootAccount.toLowerCase()) {
|
|
214
|
+
throw new Error(
|
|
215
|
+
`Pinned access key "${accessKey}" cannot sign for account "${info.account.address}".`,
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
return pinnedAccount;
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function paymentApproval(policy) {
|
|
224
|
+
const hasMaximum = policy.maxAmount !== undefined;
|
|
225
|
+
const approve = policy.onPaymentRequired;
|
|
226
|
+
if (!hasMaximum && typeof approve !== "function") return undefined;
|
|
227
|
+
const maximum = hasMaximum ? nonNegativeBigInt(policy.maxAmount, "payment.maxAmount") : undefined;
|
|
228
|
+
return async (challenge) => {
|
|
229
|
+
if (maximum !== undefined) {
|
|
230
|
+
const amount = challenge?.request?.amount;
|
|
231
|
+
if (typeof amount !== "string" || !/^\d+$/.test(amount)) {
|
|
232
|
+
throw new Error("MPP payment challenge has no valid atomic amount.");
|
|
233
|
+
}
|
|
234
|
+
if (BigInt(amount) > maximum) {
|
|
235
|
+
throw new Error(
|
|
236
|
+
`MPP payment amount ${amount} exceeds the per-request limit ${maximum}.`,
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return typeof approve === "function" ? approve(challenge) : true;
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function nonNegativeBigInt(value, name) {
|
|
245
|
+
let parsed;
|
|
246
|
+
try {
|
|
247
|
+
parsed = BigInt(value);
|
|
248
|
+
} catch (error) {
|
|
249
|
+
throw new TypeError(`${name} must be an atomic integer`, { cause: error });
|
|
250
|
+
}
|
|
251
|
+
if (parsed < 0n) throw new TypeError(`${name} must not be negative`);
|
|
252
|
+
return parsed;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** @internal */
|
|
256
|
+
export function resolveMcpServers(provider, configured) {
|
|
257
|
+
if (configured === false) return undefined;
|
|
258
|
+
const defaults = provider?.[tempoMcp];
|
|
259
|
+
if (!defaults) return configured;
|
|
260
|
+
return {
|
|
261
|
+
...defaults,
|
|
262
|
+
...configured,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "nanocodex-tools/runtime/tool-configuration";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "nanocodex-tools/runtime/tool-router";
|
package/runtime/utf8.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "nanocodex-tools/runtime/utf8";
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
const WORKER_PROTOCOL = "nanocodex.code-evaluator.v1";
|
|
2
|
+
let nextEvaluation = 1;
|
|
3
|
+
|
|
4
|
+
/** Creates the browser's per-cell, synchronously terminable Code Mode boundary. */
|
|
5
|
+
export function createWorkerEvaluator(options = {}) {
|
|
6
|
+
const createWorker = options.createWorker ?? createCodeEvaluatorWorker;
|
|
7
|
+
if (options.createWorker === undefined && typeof globalThis.Worker !== "function") {
|
|
8
|
+
throw new TypeError("browser Code Mode isolation requires Worker");
|
|
9
|
+
}
|
|
10
|
+
if (typeof createWorker !== "function") {
|
|
11
|
+
throw new TypeError("browser Code Mode isolation requires a Worker factory");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return (source, environment) => new Promise((resolve, reject) => {
|
|
15
|
+
environment.signal?.throwIfAborted();
|
|
16
|
+
const worker = createWorker();
|
|
17
|
+
const evaluationId = nextEvaluation++;
|
|
18
|
+
let closed = false;
|
|
19
|
+
|
|
20
|
+
const close = () => {
|
|
21
|
+
if (closed) return false;
|
|
22
|
+
closed = true;
|
|
23
|
+
environment.signal?.removeEventListener("abort", onAbort);
|
|
24
|
+
worker.onmessage = null;
|
|
25
|
+
worker.onerror = null;
|
|
26
|
+
worker.onmessageerror = null;
|
|
27
|
+
worker.terminate();
|
|
28
|
+
return true;
|
|
29
|
+
};
|
|
30
|
+
const fail = (error) => {
|
|
31
|
+
if (!close()) return;
|
|
32
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
33
|
+
};
|
|
34
|
+
const onAbort = () => {
|
|
35
|
+
const reason = environment.signal?.reason ?? new Error("Code Mode execution was cancelled");
|
|
36
|
+
// AbortSignal dispatch is synchronous. Let every parent-held nested tool
|
|
37
|
+
// observe cancellation before terminating its guest evaluator boundary.
|
|
38
|
+
queueMicrotask(() => fail(reason));
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
worker.onmessage = ({ data }) => {
|
|
42
|
+
if (closed || data?.protocol !== WORKER_PROTOCOL || data.evaluationId !== evaluationId) return;
|
|
43
|
+
if (data.type === "tool.call") {
|
|
44
|
+
const tool = environment.tools[data.name];
|
|
45
|
+
Promise.resolve().then(() => {
|
|
46
|
+
if (typeof tool !== "function") {
|
|
47
|
+
throw new Error(`unknown application tool: ${data.name}`);
|
|
48
|
+
}
|
|
49
|
+
return tool(data.input);
|
|
50
|
+
}).then(
|
|
51
|
+
(value) => postToolResult(worker, evaluationId, data.id, true, value, () => closed),
|
|
52
|
+
(error) => postToolResult(
|
|
53
|
+
worker,
|
|
54
|
+
evaluationId,
|
|
55
|
+
data.id,
|
|
56
|
+
false,
|
|
57
|
+
cloneableError(error),
|
|
58
|
+
() => closed,
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (data.type === "output") {
|
|
64
|
+
try {
|
|
65
|
+
if (data.kind === "text") environment.text(data.value);
|
|
66
|
+
else if (data.kind === "image") environment.image(data.value, data.detail);
|
|
67
|
+
else if (data.kind === "audio") environment.audio(data.value);
|
|
68
|
+
else if (data.kind === "notify") environment.notify(data.value);
|
|
69
|
+
else if (data.kind === "yield_control") environment.yield_control();
|
|
70
|
+
else if (data.kind === "generatedImage") environment.generatedImage(data.value);
|
|
71
|
+
else throw new Error(`unknown Code Mode output kind: ${data.kind}`);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
fail(error);
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (data.type === "console") {
|
|
78
|
+
const logger = typeof environment.console?.[data.level] === "function"
|
|
79
|
+
? environment.console[data.level]
|
|
80
|
+
: environment.console?.log;
|
|
81
|
+
logger?.(...data.values);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (data.type !== "completed" && data.type !== "failed") {
|
|
85
|
+
fail(new Error(`unknown Code Mode evaluator message: ${data.type}`));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
for (const [key, value] of data.storedWrites ?? []) environment.store(key, value);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
fail(error);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (!close()) return;
|
|
95
|
+
if (data.type === "completed") resolve();
|
|
96
|
+
else reject(new Error(data.error || "Code Mode evaluator failed"));
|
|
97
|
+
};
|
|
98
|
+
worker.onerror = (event) => fail(new Error(event?.message || "Code Mode evaluator Worker failed"));
|
|
99
|
+
worker.onmessageerror = () => fail(new Error("Code Mode evaluator Worker returned unreadable data"));
|
|
100
|
+
environment.signal?.addEventListener("abort", onAbort, { once: true });
|
|
101
|
+
try {
|
|
102
|
+
worker.postMessage({
|
|
103
|
+
protocol: WORKER_PROTOCOL,
|
|
104
|
+
evaluationId,
|
|
105
|
+
egress: options.egress,
|
|
106
|
+
type: "evaluate",
|
|
107
|
+
source,
|
|
108
|
+
storedEntries: environment.storedEntries,
|
|
109
|
+
toolDefinitions: environment.toolDefinitions,
|
|
110
|
+
toolNames: Object.keys(environment.tools),
|
|
111
|
+
});
|
|
112
|
+
} catch (error) {
|
|
113
|
+
fail(error);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Vite recognizes only this literal Worker + URL shape as a worker entry. Keep
|
|
119
|
+
// the test factory above out of the production construction path so the
|
|
120
|
+
// evaluator and its imports are emitted as one runnable browser asset.
|
|
121
|
+
function createCodeEvaluatorWorker() {
|
|
122
|
+
return new Worker(
|
|
123
|
+
new URL("./code-evaluator.worker.mjs", import.meta.url),
|
|
124
|
+
{ name: "nanocodex-code-evaluator", type: "module" },
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function postToolResult(worker, evaluationId, id, ok, value, isClosed) {
|
|
129
|
+
if (isClosed()) return;
|
|
130
|
+
try {
|
|
131
|
+
worker.postMessage({
|
|
132
|
+
protocol: WORKER_PROTOCOL,
|
|
133
|
+
evaluationId,
|
|
134
|
+
type: "tool.result",
|
|
135
|
+
id,
|
|
136
|
+
ok,
|
|
137
|
+
value,
|
|
138
|
+
});
|
|
139
|
+
} catch (error) {
|
|
140
|
+
worker.postMessage({
|
|
141
|
+
protocol: WORKER_PROTOCOL,
|
|
142
|
+
evaluationId,
|
|
143
|
+
type: "tool.result",
|
|
144
|
+
id,
|
|
145
|
+
ok: false,
|
|
146
|
+
value: `tool result could not cross the evaluator Worker boundary: ${errorMessage(error)}`,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function cloneableError(error) {
|
|
152
|
+
try {
|
|
153
|
+
structuredClone(error);
|
|
154
|
+
return error;
|
|
155
|
+
} catch {
|
|
156
|
+
return errorMessage(error);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function errorMessage(error) {
|
|
161
|
+
return error && (error.stack || error.message) ? error.stack || error.message : String(error);
|
|
162
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "nanocodex-tools/workspace";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "nanocodex-tools/workspace";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { McpServers, NamedTool, ToolMap } from "../types.mjs";
|
|
2
|
+
import type { Workspace } from "../runtime/workspace.mjs";
|
|
3
|
+
import type { HostedMachine } from "./hostedCatalog.mjs";
|
|
4
|
+
|
|
5
|
+
declare const toolsBrand: unique symbol;
|
|
6
|
+
|
|
7
|
+
export type AttachmentSocket = {
|
|
8
|
+
readonly readyState: number;
|
|
9
|
+
send(data: string): void;
|
|
10
|
+
close(code?: number, reason?: string): void;
|
|
11
|
+
addEventListener?(type: string, listener: (event: any) => void, options?: unknown): void;
|
|
12
|
+
on?(type: string, listener: (...args: any[]) => void): void;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type AttachmentTransport = Readonly<{
|
|
16
|
+
connect(target: string | URL): AttachmentSocket | Promise<AttachmentSocket>;
|
|
17
|
+
}>;
|
|
18
|
+
|
|
19
|
+
export type AttachmentTarget = string | URL | Readonly<{
|
|
20
|
+
endpoint: string | URL;
|
|
21
|
+
transport: AttachmentTransport;
|
|
22
|
+
}>;
|
|
23
|
+
|
|
24
|
+
export type AttachmentClient = Readonly<{
|
|
25
|
+
readonly connected: boolean;
|
|
26
|
+
closed(): Promise<void>;
|
|
27
|
+
close(): Promise<void>;
|
|
28
|
+
}>;
|
|
29
|
+
|
|
30
|
+
export type Tools = Readonly<{
|
|
31
|
+
readonly [toolsBrand]: true;
|
|
32
|
+
attach(target: AttachmentTarget): Readonly<{
|
|
33
|
+
connect(): Promise<AttachmentClient>;
|
|
34
|
+
closed(): Promise<void>;
|
|
35
|
+
close(): Promise<void>;
|
|
36
|
+
}>;
|
|
37
|
+
close(): Promise<void>;
|
|
38
|
+
}>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Creates one owned tool runtime. Caller-supplied tool ownership transfers only
|
|
42
|
+
* after this promise resolves; a rejected construction leaves those tools with
|
|
43
|
+
* the caller. The returned runtime joins all owned cleanup through close().
|
|
44
|
+
*/
|
|
45
|
+
export function createTools(options?: {
|
|
46
|
+
tools?: ToolMap | readonly NamedTool[];
|
|
47
|
+
/** Stable safe ASCII identifier (at most 123 bytes) for this independent attachment. */
|
|
48
|
+
attachmentId?: string;
|
|
49
|
+
/** Sole non-secret machine published by this host; its id must equal attachmentId. */
|
|
50
|
+
machines?: readonly HostedMachine[];
|
|
51
|
+
/** Portable workspace handle; React Native supplies one via createWorkspace({ backend }). */
|
|
52
|
+
workspace?: Workspace;
|
|
53
|
+
workspaceOptions?: { maxEntries?: number; maxReadBytes?: number; maxWriteBytes?: number };
|
|
54
|
+
mcp?: McpServers | false;
|
|
55
|
+
mcpOptions?: Readonly<Record<string, unknown>>;
|
|
56
|
+
}): Promise<Tools>;
|