twin3-sdk 0.2.10-pre-alpha → 0.2.12-pre-alpha
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 +7 -7
- package/index.d.ts +32 -0
- package/js/index.js +157 -1
- package/js/local-memory.js +64 -0
- package/local-memory.d.ts +22 -0
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Twin3 SDK (`twin3-sdk`)
|
|
2
2
|
> **The Universal Capability Motherboard for Autonomous AI Agents & Self-Sovereign Humans**
|
|
3
3
|
|
|
4
|
-
[English](README.md) | [
|
|
4
|
+
[English](README.md) | [Traditional Chinese](README_ZH.md) | [GitHub: twin3-team/twin3-sdk](https://github.com/twin3-team/twin3-sdk)
|
|
5
5
|
|
|
6
6
|
[](https://python.org)
|
|
7
7
|
[](#the-seven-layer-symbiotic-architecture)
|
|
@@ -103,22 +103,22 @@ pip install -e /path/to/twin3-sdk
|
|
|
103
103
|
* Any protocol or algorithm improvement in `twin3-sdk` is reflected in both applications in **0 milliseconds**.
|
|
104
104
|
|
|
105
105
|
#### 2. Production Distribution
|
|
106
|
-
|
|
106
|
+
`v0.2.12-pre-alpha` is the current release candidate: `0.2.12-pre-alpha` for npm and `0.2.12a0` for PyPI. Publication is pending. Consumers must pin the exact released version and lock its registry integrity; never use a mutable range for a cryptographic protocol dependency. This release stays pre-alpha. Marketplace or sales copy may offer it for evaluation; it is not a stable release, and the npm dist-tag is `next`, not `latest`.
|
|
107
107
|
|
|
108
108
|
`package.json` `engines` sets Node.js to `>=18` and does not set an npm engine. Any npm that can install a tarball can consume the package. Packing this repository was checked with npm 10 or newer; the stricter npm version in the release runbook applies only to Trusted Publishing.
|
|
109
109
|
|
|
110
|
-
After
|
|
110
|
+
After publication, install the exact released version from the registry:
|
|
111
111
|
|
|
112
112
|
```bash
|
|
113
|
-
npm install twin3-sdk@0.2.
|
|
114
|
-
pip install twin3-sdk==0.2.
|
|
113
|
+
npm install twin3-sdk@0.2.12-pre-alpha
|
|
114
|
+
pip install twin3-sdk==0.2.12a0
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
For local evaluation, you can also use the packed npm tarball. Do not install from a git URL or a version range:
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
120
|
npm pack --ignore-scripts
|
|
121
|
-
npm install ./twin3-sdk-0.2.
|
|
121
|
+
npm install ./twin3-sdk-0.2.12-pre-alpha.tgz
|
|
122
122
|
```
|
|
123
123
|
|
|
124
124
|
---
|
package/index.d.ts
CHANGED
|
@@ -375,6 +375,38 @@ export declare const A2A_PROTOCOL_VERSION: "1.0";
|
|
|
375
375
|
export declare const A2A_DOCUMENT_SUFFIXES: readonly string[];
|
|
376
376
|
export declare const A2A_DISCOVERY_DOCUMENT_PATHS: readonly string[];
|
|
377
377
|
export interface A2AInterface { url: string; protocolBinding: "HTTP+JSON" | "JSONRPC" | "GRPC"; protocolVersion: string; }
|
|
378
|
+
export interface A2AAgentCardSignature {
|
|
379
|
+
protected: string;
|
|
380
|
+
signature: string;
|
|
381
|
+
header?: Record<string, unknown>;
|
|
382
|
+
}
|
|
383
|
+
export interface A2AJwks { keys: import("node:crypto").JsonWebKey[]; }
|
|
384
|
+
export interface A2AAgentCard extends Record<string, any> {
|
|
385
|
+
name: string;
|
|
386
|
+
description: string;
|
|
387
|
+
version: string;
|
|
388
|
+
supportedInterfaces: A2AInterface[];
|
|
389
|
+
skills: Record<string, any>[];
|
|
390
|
+
url?: string;
|
|
391
|
+
protocolVersion?: string;
|
|
392
|
+
preferredTransport?: A2AInterface["protocolBinding"];
|
|
393
|
+
signatures?: A2AAgentCardSignature[];
|
|
394
|
+
signatureStatus?: string;
|
|
395
|
+
}
|
|
396
|
+
export interface A2ASignatureVerification {
|
|
397
|
+
status: "signed";
|
|
398
|
+
mode: "a2a_jcs" | "legacy_signature_status_excluded";
|
|
399
|
+
kid: string;
|
|
400
|
+
alg: "EdDSA" | "ES256";
|
|
401
|
+
jku: string | null;
|
|
402
|
+
protected: { alg: "EdDSA" | "ES256"; typ: "JOSE"; kid: string; jku?: string; [name: string]: unknown };
|
|
403
|
+
}
|
|
404
|
+
/** Signs every supplied field except signatures; preserves signatureStatus.
|
|
405
|
+
* privateKey accepts Ed25519/P-256 KeyObject or PEM, or a 32-byte Ed25519 seed. */
|
|
406
|
+
export declare function signA2AAgentCard<T extends Record<string, any>>(card: T, privateKey: string | Buffer | import("node:crypto").KeyObject, kid: string, jku?: string | null): Omit<T, "signatures"> & { signatures: A2AAgentCardSignature[] };
|
|
407
|
+
/** Uses caller-trusted public JWKS, without fetching jku. Unsupported headers,
|
|
408
|
+
* ambiguous/missing kids and invalid keys are errors even in legacy mode. */
|
|
409
|
+
export declare function verifyA2AAgentCardSignature(card: Record<string, any>, jwks: A2AJwks, options?: { allowLegacy?: boolean }): A2ASignatureVerification;
|
|
378
410
|
export interface A2AValidationReport {
|
|
379
411
|
profile: "twin3-discovery-a2a-card-v1";
|
|
380
412
|
skills: string[];
|
package/js/index.js
CHANGED
|
@@ -473,6 +473,7 @@ const A2A_KNOWN_FIELDS = [
|
|
|
473
473
|
"name", "description", "supportedInterfaces", "provider", "version", "documentationUrl", "iconUrl",
|
|
474
474
|
"capabilities", "securitySchemes", "securityRequirements", "defaultInputModes", "defaultOutputModes",
|
|
475
475
|
"skills", "signatures", "signatureStatus", "models", "authenticatedSubject",
|
|
476
|
+
"url", "protocolVersion", "preferredTransport",
|
|
476
477
|
];
|
|
477
478
|
const A2A_DEFAULT_MODES = ["application/json", "text/plain"];
|
|
478
479
|
|
|
@@ -557,8 +558,16 @@ function a2aRequirements(value, schemes, code) {
|
|
|
557
558
|
|
|
558
559
|
function validateAgentCardV1(card) {
|
|
559
560
|
if (!card || typeof card !== "object" || Array.isArray(card)) fail("a2a_card_invalid");
|
|
560
|
-
const legacy = A2A_LEGACY_FIELDS.filter((name) => name in card);
|
|
561
|
+
const legacy = A2A_LEGACY_FIELDS.filter((name) => name in card && !["url", "preferredTransport"].includes(name));
|
|
561
562
|
if (legacy.length) fail("a2a_legacy_shape:" + legacy[0]);
|
|
563
|
+
if ("url" in card) {
|
|
564
|
+
a2aUrl(card.url, "a2a_legacy_shape:url");
|
|
565
|
+
if (!Array.isArray(card.supportedInterfaces) || !card.supportedInterfaces.some((iface) => iface && iface.url === card.url)) {
|
|
566
|
+
fail("a2a_legacy_shape:url");
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if ("preferredTransport" in card && !A2A_PROTOCOL_BINDINGS.includes(card.preferredTransport)) fail("a2a_field_invalid:preferredTransport");
|
|
570
|
+
if ("protocolVersion" in card) a2aText(card.protocolVersion, "a2a_field_invalid:protocolVersion");
|
|
562
571
|
a2aText(card.name, "a2a_field_required:name");
|
|
563
572
|
a2aText(card.description, "a2a_field_required:description");
|
|
564
573
|
a2aText(card.version, "a2a_field_required:version");
|
|
@@ -613,6 +622,7 @@ function validateAgentCardV1(card) {
|
|
|
613
622
|
ids.add(skill.id);
|
|
614
623
|
});
|
|
615
624
|
if ("signatures" in card && !Array.isArray(card.signatures)) fail("a2a_field_invalid:signatures");
|
|
625
|
+
(card.signatures || []).forEach(a2aSignatureEntry);
|
|
616
626
|
return {
|
|
617
627
|
profile: A2A_CARD_PROFILE,
|
|
618
628
|
skills: Array.from(ids).sort(),
|
|
@@ -624,6 +634,150 @@ function validateAgentCardV1(card) {
|
|
|
624
634
|
};
|
|
625
635
|
}
|
|
626
636
|
|
|
637
|
+
function a2aSignatureEntry(entry, index) {
|
|
638
|
+
const code = "a2a_signature_invalid:" + index;
|
|
639
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry) ||
|
|
640
|
+
!Object.hasOwn(entry, "protected") || !Object.hasOwn(entry, "signature") ||
|
|
641
|
+
Object.keys(entry).some((name) => !["protected", "signature", "header"].includes(name))) fail(code);
|
|
642
|
+
strictB64urlDecode(entry.protected, code);
|
|
643
|
+
strictB64urlDecode(entry.signature, code);
|
|
644
|
+
if (Object.hasOwn(entry, "header") && (!entry.header || typeof entry.header !== "object" || Array.isArray(entry.header))) fail(code);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function a2aSignatureBody(card) {
|
|
648
|
+
if (!card || typeof card !== "object" || Array.isArray(card)) fail("a2a_card_invalid");
|
|
649
|
+
const body = structuredClone(card);
|
|
650
|
+
delete body.signatures;
|
|
651
|
+
return body;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
function a2aSignaturePayload(body) {
|
|
655
|
+
try {
|
|
656
|
+
return canonicalJsonBuffer(body);
|
|
657
|
+
} catch (error) {
|
|
658
|
+
fail("a2a_not_canonicalizable", error);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
function a2aSigningInput(protectedB64, payload) {
|
|
663
|
+
return Buffer.from(protectedB64 + "." + payload.toString("base64url"), "ascii");
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function a2aPrivateKey(value) {
|
|
667
|
+
let key;
|
|
668
|
+
try {
|
|
669
|
+
if (Buffer.isBuffer(value) && value.length === 32) {
|
|
670
|
+
key = crypto.createPrivateKey({
|
|
671
|
+
key: Buffer.concat([Buffer.from("302e020100300506032b657004220420", "hex"), value]),
|
|
672
|
+
format: "der", type: "pkcs8",
|
|
673
|
+
});
|
|
674
|
+
} else {
|
|
675
|
+
key = value instanceof crypto.KeyObject ? value : crypto.createPrivateKey(value);
|
|
676
|
+
}
|
|
677
|
+
} catch (error) {
|
|
678
|
+
fail("a2a_private_key_invalid", error);
|
|
679
|
+
}
|
|
680
|
+
if (key.type !== "private") fail("a2a_private_key_invalid");
|
|
681
|
+
if (key.asymmetricKeyType === "ed25519") return { key, alg: "EdDSA" };
|
|
682
|
+
if (key.asymmetricKeyType === "ec" && key.asymmetricKeyDetails.namedCurve === "prime256v1") return { key, alg: "ES256" };
|
|
683
|
+
fail("a2a_private_key_invalid");
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/** A2A §8.4 detached JWS. Only signatures is excluded; no status is added. */
|
|
687
|
+
function signA2AAgentCard(card, privateKey, kid, jku = null) {
|
|
688
|
+
const { key, alg } = a2aPrivateKey(privateKey);
|
|
689
|
+
a2aText(kid, "a2a_kid_required");
|
|
690
|
+
const header = { alg, typ: "JOSE", kid };
|
|
691
|
+
if (jku !== null) {
|
|
692
|
+
a2aUrl(jku, "a2a_jku_invalid");
|
|
693
|
+
if (!jku.startsWith("https://")) fail("a2a_jku_invalid");
|
|
694
|
+
header.jku = jku;
|
|
695
|
+
}
|
|
696
|
+
const body = a2aSignatureBody(card);
|
|
697
|
+
validateAgentCardV1(body);
|
|
698
|
+
const protectedB64 = canonicalJsonBuffer(header).toString("base64url");
|
|
699
|
+
const input = a2aSigningInput(protectedB64, a2aSignaturePayload(body));
|
|
700
|
+
const signature = alg === "EdDSA" ? crypto.sign(null, input, key) :
|
|
701
|
+
crypto.sign("sha256", input, { key, dsaEncoding: "ieee-p1363" });
|
|
702
|
+
body.signatures = [{ protected: protectedB64, signature: signature.toString("base64url") }];
|
|
703
|
+
return body;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
function a2aProtectedHeader(entry) {
|
|
707
|
+
const code = "a2a_protected_invalid";
|
|
708
|
+
let header;
|
|
709
|
+
try {
|
|
710
|
+
header = JSON.parse(new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(strictB64urlDecode(entry.protected, code)));
|
|
711
|
+
} catch (error) {
|
|
712
|
+
fail(code, error);
|
|
713
|
+
}
|
|
714
|
+
if (!header || typeof header !== "object" || Array.isArray(header)) fail(code);
|
|
715
|
+
if (!["EdDSA", "ES256"].includes(header.alg)) fail("a2a_alg_unsupported");
|
|
716
|
+
a2aText(header.kid, code);
|
|
717
|
+
if (header.typ !== "JOSE") fail(code);
|
|
718
|
+
const unprotected = entry.header || {};
|
|
719
|
+
if (Object.keys(header).some((name) => Object.hasOwn(unprotected, name)) ||
|
|
720
|
+
[header, unprotected].some((h) => Object.hasOwn(h, "crit") || Object.hasOwn(h, "b64"))) fail(code);
|
|
721
|
+
if (Object.hasOwn(header, "jku")) {
|
|
722
|
+
a2aUrl(header.jku, code);
|
|
723
|
+
if (!header.jku.startsWith("https://")) fail(code);
|
|
724
|
+
}
|
|
725
|
+
return header;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
function a2aJwksKey(jwks, header) {
|
|
729
|
+
const matches = jwks.keys.filter((jwk) => jwk.kid === header.kid);
|
|
730
|
+
if (matches.length === 0) fail("a2a_kid_mismatch");
|
|
731
|
+
if (matches.length !== 1) fail("a2a_kid_ambiguous");
|
|
732
|
+
const jwk = matches[0];
|
|
733
|
+
const code = "a2a_jwk_invalid";
|
|
734
|
+
if (Object.hasOwn(jwk, "d") || (Object.hasOwn(jwk, "alg") && jwk.alg !== header.alg) ||
|
|
735
|
+
(Object.hasOwn(jwk, "use") && jwk.use !== "sig")) fail(code);
|
|
736
|
+
if (Object.hasOwn(jwk, "key_ops") && (!Array.isArray(jwk.key_ops) || !jwk.key_ops.includes("verify") ||
|
|
737
|
+
jwk.key_ops.some((op) => typeof op !== "string"))) fail(code);
|
|
738
|
+
const x = strictB64urlDecode(jwk.x, code);
|
|
739
|
+
if (x.length !== 32) fail(code);
|
|
740
|
+
if (header.alg === "EdDSA") {
|
|
741
|
+
if (jwk.kty !== "OKP" || jwk.crv !== "Ed25519") fail(code);
|
|
742
|
+
} else {
|
|
743
|
+
if (jwk.kty !== "EC" || jwk.crv !== "P-256" || strictB64urlDecode(jwk.y, code).length !== 32) fail(code);
|
|
744
|
+
}
|
|
745
|
+
try {
|
|
746
|
+
return crypto.createPublicKey({ key: jwk, format: "jwk" });
|
|
747
|
+
} catch (error) {
|
|
748
|
+
fail(code, error);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/** Verify with caller-trusted JWKS; never fetch jku. All standard signatures
|
|
753
|
+
* are tried before the opt-in signatureStatus-excluded legacy payload. */
|
|
754
|
+
function verifyA2AAgentCardSignature(card, jwks, { allowLegacy = false } = {}) {
|
|
755
|
+
if (typeof allowLegacy !== "boolean") fail("a2a_options_invalid");
|
|
756
|
+
validateAgentCardV1(card);
|
|
757
|
+
if (!card.signatures || card.signatures.length === 0) fail("a2a_signature_required");
|
|
758
|
+
if (!jwks || typeof jwks !== "object" || Array.isArray(jwks) || !Array.isArray(jwks.keys) ||
|
|
759
|
+
jwks.keys.some((jwk) => !jwk || typeof jwk !== "object" || Array.isArray(jwk))) fail("a2a_jwks_invalid");
|
|
760
|
+
const entries = card.signatures.map((entry) => {
|
|
761
|
+
const header = a2aProtectedHeader(entry);
|
|
762
|
+
return { protectedB64: entry.protected, header, key: a2aJwksKey(jwks, header),
|
|
763
|
+
signature: strictB64urlDecode(entry.signature, "a2a_signature_invalid") };
|
|
764
|
+
});
|
|
765
|
+
const body = a2aSignatureBody(card);
|
|
766
|
+
const modes = ["a2a_jcs", ...(allowLegacy ? ["legacy_signature_status_excluded"] : [])];
|
|
767
|
+
for (const mode of modes) {
|
|
768
|
+
if (mode === "legacy_signature_status_excluded") delete body.signatureStatus;
|
|
769
|
+
const payload = a2aSignaturePayload(body);
|
|
770
|
+
for (const { protectedB64, header, key, signature } of entries) {
|
|
771
|
+
if (signature.length !== 64) continue;
|
|
772
|
+
const input = a2aSigningInput(protectedB64, payload);
|
|
773
|
+
const ok = header.alg === "EdDSA" ? crypto.verify(null, input, key, signature) :
|
|
774
|
+
crypto.verify("sha256", input, { key, dsaEncoding: "ieee-p1363" }, signature);
|
|
775
|
+
if (ok) return { status: "signed", mode, kid: header.kid, alg: header.alg, jku: header.jku ?? null, protected: header };
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
fail("a2a_signature_invalid");
|
|
779
|
+
}
|
|
780
|
+
|
|
627
781
|
function agentCardPaths(origin = "") {
|
|
628
782
|
if (typeof origin !== "string") fail("a2a_origin_invalid");
|
|
629
783
|
if (origin) {
|
|
@@ -6372,6 +6526,8 @@ module.exports = {
|
|
|
6372
6526
|
signDescriptor,
|
|
6373
6527
|
unsignedDescriptor,
|
|
6374
6528
|
verifyDescriptor,
|
|
6529
|
+
signA2AAgentCard,
|
|
6530
|
+
verifyA2AAgentCardSignature,
|
|
6375
6531
|
DESCRIPTOR_CANONICALIZATION,
|
|
6376
6532
|
DESCRIPTOR_SIGNATURE_FIELDS,
|
|
6377
6533
|
buildWellKnownDocument,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { spawn } = require("node:child_process");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
const fs = require("node:fs");
|
|
6
|
+
|
|
7
|
+
function requiredText(value, limit = 1000) {
|
|
8
|
+
if (typeof value !== "string" || !value.trim() || value.length > limit || value.includes("\0")) throw new TypeError("local_memory_option_invalid");
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function startLocalMemory(options) {
|
|
13
|
+
if (!options || typeof options !== "object") throw new TypeError("local_memory_options_required");
|
|
14
|
+
const executable = requiredText(options.pythonExecutable);
|
|
15
|
+
const databasePath = requiredText(options.databasePath);
|
|
16
|
+
const directory = path.dirname(databasePath);
|
|
17
|
+
if (!path.isAbsolute(executable) || !path.isAbsolute(databasePath)) throw new TypeError("local_memory_absolute_path_required");
|
|
18
|
+
if (!["human", "enterprise"].includes(options.namespace)) throw new TypeError("local_memory_namespace_invalid");
|
|
19
|
+
const subject = requiredText(options.subject, 200);
|
|
20
|
+
const ontology = requiredText(options.ontology, 200);
|
|
21
|
+
if (!Array.isArray(options.dimensions) || !options.dimensions.length || options.dimensions.some(value => typeof value !== "string" || !value || value.includes(","))) throw new TypeError("local_memory_dimensions_invalid");
|
|
22
|
+
const port = options.port ?? 0;
|
|
23
|
+
if (!Number.isSafeInteger(port) || port < 0 || port > 65535) throw new TypeError("local_memory_port_invalid");
|
|
24
|
+
const args = ["-I", "-m", "twin3.memory.runtime", "--database", databasePath, "--subject", subject, "--namespace", options.namespace, "--ontology", ontology, "--dimensions", options.dimensions.join(","), "--port", String(port)];
|
|
25
|
+
if (options.model) args.push("--model", requiredText(options.model, 200));
|
|
26
|
+
if (options.embeddingModel) args.push("--embedding-model", requiredText(options.embeddingModel, 200));
|
|
27
|
+
if (options.modelEndpoint) args.push("--model-endpoint", requiredText(options.modelEndpoint, 200));
|
|
28
|
+
const child = spawn(executable, args, { shell: false, stdio: ["ignore", "pipe", "pipe"] });
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
let stdout = "";
|
|
31
|
+
let settled = false;
|
|
32
|
+
const timer = setTimeout(() => fail("local_memory_start_timeout"), 15000);
|
|
33
|
+
function fail(code) {
|
|
34
|
+
if (settled) return;
|
|
35
|
+
settled = true;
|
|
36
|
+
clearTimeout(timer);
|
|
37
|
+
child.kill("SIGINT");
|
|
38
|
+
reject(new Error(code));
|
|
39
|
+
}
|
|
40
|
+
child.stderr.on("data", () => {});
|
|
41
|
+
child.on("error", () => fail("local_memory_runtime_unavailable"));
|
|
42
|
+
child.on("exit", () => fail("local_memory_runtime_unavailable"));
|
|
43
|
+
child.stdout.on("data", chunk => {
|
|
44
|
+
if (settled) return;
|
|
45
|
+
stdout += chunk.toString("utf8");
|
|
46
|
+
if (stdout.length > 16384) return fail("local_memory_start_invalid");
|
|
47
|
+
if (!stdout.includes("\n")) return;
|
|
48
|
+
try {
|
|
49
|
+
const result = JSON.parse(stdout.split("\n")[0]);
|
|
50
|
+
const url = new URL(result.url);
|
|
51
|
+
if (result.capability !== "memory.local-v1" || result.identity_assurance !== "local_workspace_only" || url.protocol !== "http:" || url.hostname !== "127.0.0.1" || !url.port || url.pathname !== "/" || url.search || url.hash || url.username || url.password || typeof result.token_file !== "string" || path.dirname(fs.realpathSync(result.token_file)) !== fs.realpathSync(directory) || path.basename(result.token_file) !== `session-${url.port}.token`) return fail("local_memory_start_invalid");
|
|
52
|
+
settled = true;
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
child.stdout.removeAllListeners("data");
|
|
55
|
+
child.stdout.resume();
|
|
56
|
+
resolve({ url: result.url, tokenFile: result.token_file, identityAssurance: result.identity_assurance, process: child, stop: () => child.kill("SIGINT") });
|
|
57
|
+
} catch {
|
|
58
|
+
fail("local_memory_start_invalid");
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = { startLocalMemory };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface LocalMemoryOptions {
|
|
2
|
+
pythonExecutable: string;
|
|
3
|
+
databasePath: string;
|
|
4
|
+
namespace: "enterprise" | "human";
|
|
5
|
+
subject: string;
|
|
6
|
+
ontology: string;
|
|
7
|
+
dimensions: string[];
|
|
8
|
+
port?: number;
|
|
9
|
+
model?: string;
|
|
10
|
+
embeddingModel?: string;
|
|
11
|
+
modelEndpoint?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface LocalMemoryProcess {
|
|
15
|
+
url: string;
|
|
16
|
+
tokenFile: string;
|
|
17
|
+
identityAssurance: "local_workspace_only";
|
|
18
|
+
process: import("node:child_process").ChildProcess;
|
|
19
|
+
stop(): boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function startLocalMemory(options: LocalMemoryOptions): Promise<LocalMemoryProcess>;
|
package/package.json
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "twin3-sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.12-pre-alpha",
|
|
4
4
|
"description": "Universal Capability Motherboard for Autonomous AI Agents and Self-Sovereign Humans (JS/Node runtime)",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./js/index.js",
|
|
7
7
|
"types": "./index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
|
+
"./local-memory": {
|
|
10
|
+
"types": "./local-memory.d.ts",
|
|
11
|
+
"require": "./js/local-memory.js",
|
|
12
|
+
"default": "./js/local-memory.js"
|
|
13
|
+
},
|
|
9
14
|
".": {
|
|
10
15
|
"types": "./index.d.ts",
|
|
11
16
|
"require": "./js/index.js",
|
|
@@ -19,6 +24,8 @@
|
|
|
19
24
|
"./package.json": "./package.json"
|
|
20
25
|
},
|
|
21
26
|
"files": [
|
|
27
|
+
"js/local-memory.js",
|
|
28
|
+
"local-memory.d.ts",
|
|
22
29
|
"js/index.js",
|
|
23
30
|
"js/comm/counterparty.js",
|
|
24
31
|
"js/state.js",
|