@nexart/ai-execution 0.8.0 → 0.10.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 +167 -3
- package/dist/index.cjs +182 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -3
- package/dist/index.d.ts +68 -3
- package/dist/index.mjs +178 -1
- package/dist/index.mjs.map +1 -1
- package/dist/langchain.cjs +480 -0
- package/dist/langchain.cjs.map +1 -0
- package/dist/langchain.d.cts +185 -0
- package/dist/langchain.d.ts +185 -0
- package/dist/langchain.mjs +444 -0
- package/dist/langchain.mjs.map +1 -0
- package/dist/providers/anthropic.d.cts +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/openai.d.cts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/wrap.d.cts +1 -1
- package/dist/providers/wrap.d.ts +1 -1
- package/dist/{types-CcqCDPrD.d.cts → types-C5t12OK8.d.cts} +2 -0
- package/dist/{types-CcqCDPrD.d.ts → types-C5t12OK8.d.ts} +2 -0
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @nexart/ai-execution v0.
|
|
1
|
+
# @nexart/ai-execution v0.10.0
|
|
2
2
|
|
|
3
3
|
Tamper-evident records and Certified Execution Records (CER) for AI operations.
|
|
4
4
|
|
|
@@ -7,7 +7,7 @@ Tamper-evident records and Certified Execution Records (CER) for AI operations.
|
|
|
7
7
|
| Component | Version |
|
|
8
8
|
|---|---|
|
|
9
9
|
| Service | — |
|
|
10
|
-
| SDK | 0.
|
|
10
|
+
| SDK | 0.10.0 |
|
|
11
11
|
| Protocol | 1.2.0 |
|
|
12
12
|
|
|
13
13
|
## Why Not Just Store Logs?
|
|
@@ -672,6 +672,168 @@ Priority when multiple failures exist: `CANONICALIZATION_ERROR` > `SCHEMA_ERROR`
|
|
|
672
672
|
| `runAnthropicExecution` | `@nexart/ai-execution/providers/anthropic` |
|
|
673
673
|
| `wrapProvider` | `@nexart/ai-execution/providers/wrap` |
|
|
674
674
|
|
|
675
|
+
## LangChain Integration
|
|
676
|
+
|
|
677
|
+
`@nexart/ai-execution` v0.10.0 includes a minimal LangChain helper surface. Certify the final input and output of any LangChain chain, agent, or runnable as a tamper-evident CER — no LangChain package dependency required.
|
|
678
|
+
|
|
679
|
+
`certifyLangChainRun` operates in two modes depending on whether `nodeUrl` and `apiKey` are supplied:
|
|
680
|
+
|
|
681
|
+
| Mode | How to call | Returns |
|
|
682
|
+
|---|---|---|
|
|
683
|
+
| **Local** (default) | No `nodeUrl` / `apiKey` | `LangChainCerResult` (sync) |
|
|
684
|
+
| **Node-attested** | `nodeUrl` + `apiKey` on input | `Promise<LangChainAttestedResult>` |
|
|
685
|
+
|
|
686
|
+
### Mode 1 — Local CER creation (synchronous, no network)
|
|
687
|
+
|
|
688
|
+
`createLangChainCer` is always local. `certifyLangChainRun` without `nodeUrl`/`apiKey` is identical.
|
|
689
|
+
|
|
690
|
+
```ts
|
|
691
|
+
import { createLangChainCer, certifyLangChainRun } from '@nexart/ai-execution';
|
|
692
|
+
// or: import { ... } from '@nexart/ai-execution/langchain';
|
|
693
|
+
|
|
694
|
+
// Using createLangChainCer — always explicit about local-only behaviour
|
|
695
|
+
const { bundle, certificateHash, executionId } = createLangChainCer({
|
|
696
|
+
executionId: 'run-001', // optional — UUID generated if omitted
|
|
697
|
+
provider: 'openai',
|
|
698
|
+
model: 'gpt-4o-mini',
|
|
699
|
+
input: { messages: [{ role: 'user', content: 'What is the capital of France?' }] },
|
|
700
|
+
output: { text: 'Paris.' },
|
|
701
|
+
metadata: { appId: 'my-app', projectId: 'docs-bot' },
|
|
702
|
+
parameters: { temperature: 0, maxTokens: 200, topP: null, seed: null },
|
|
703
|
+
createdAt: new Date().toISOString(), // pin for deterministic hash
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
console.log(certificateHash); // sha256:...
|
|
707
|
+
|
|
708
|
+
// certifyLangChainRun without nodeUrl/apiKey: identical, sync
|
|
709
|
+
const { bundle: b2 } = certifyLangChainRun({
|
|
710
|
+
provider: 'openai', model: 'gpt-4o-mini',
|
|
711
|
+
input: { messages: [{ role: 'user', content: 'Summarise this.' }] },
|
|
712
|
+
output: { text: 'Summary...' },
|
|
713
|
+
});
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
### Mode 2 — Node-attested certification (async)
|
|
717
|
+
|
|
718
|
+
Add `nodeUrl` and `apiKey` to the same input to route through the existing `certifyAndAttestDecision()` path. The function returns a `Promise<LangChainAttestedResult>` with the `receipt` from the NexArt node.
|
|
719
|
+
|
|
720
|
+
```ts
|
|
721
|
+
import { certifyLangChainRun } from '@nexart/ai-execution';
|
|
722
|
+
|
|
723
|
+
const result = await certifyLangChainRun({
|
|
724
|
+
executionId: 'run-001',
|
|
725
|
+
provider: 'openai',
|
|
726
|
+
model: 'gpt-4o-mini',
|
|
727
|
+
input: { messages: [{ role: 'user', content: 'What is the capital of France?' }] },
|
|
728
|
+
output: { text: 'Paris.' },
|
|
729
|
+
metadata: { appId: 'my-app', projectId: 'docs-bot' },
|
|
730
|
+
createdAt: new Date().toISOString(),
|
|
731
|
+
nodeUrl: 'https://node.nexart.io', // ← triggers attested mode
|
|
732
|
+
apiKey: process.env.NEXART_API_KEY!, // ← required with nodeUrl
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
console.log(result.certificateHash); // sha256:... (same semantics as local)
|
|
736
|
+
console.log(result.attested); // true
|
|
737
|
+
console.log(result.receipt);
|
|
738
|
+
// {
|
|
739
|
+
// attestationId: "nxa_attest_...",
|
|
740
|
+
// certificateHash: "sha256:...",
|
|
741
|
+
// nodeRuntimeHash: "sha256:...",
|
|
742
|
+
// protocolVersion: "1.2.0"
|
|
743
|
+
// }
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
`result.bundle` passes `verifyCer()` identically to local mode — the `certificateHash` covers only the CER content, not the receipt fields.
|
|
747
|
+
|
|
748
|
+
### Three helpers
|
|
749
|
+
|
|
750
|
+
| Helper | Returns | Network |
|
|
751
|
+
|---|---|---|
|
|
752
|
+
| `createLangChainCer(input)` | `LangChainCerResult` (sync) | Never |
|
|
753
|
+
| `certifyLangChainRun(input)` without `nodeUrl`/`apiKey` | `LangChainCerResult` (sync) | Never |
|
|
754
|
+
| `certifyLangChainRun({ ...input, nodeUrl, apiKey })` | `Promise<LangChainAttestedResult>` | Yes — NexArt node |
|
|
755
|
+
|
|
756
|
+
### Result types
|
|
757
|
+
|
|
758
|
+
```ts
|
|
759
|
+
interface LangChainCerResult {
|
|
760
|
+
bundle: CerAiExecutionBundle;
|
|
761
|
+
certificateHash: string;
|
|
762
|
+
executionId: string;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
interface LangChainAttestedResult extends LangChainCerResult {
|
|
766
|
+
receipt: AttestationReceipt;
|
|
767
|
+
attested: true;
|
|
768
|
+
}
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
### Input normalization
|
|
772
|
+
|
|
773
|
+
| Input shape | Stored in CER as |
|
|
774
|
+
|---|---|
|
|
775
|
+
| `string` | `string` (pass-through) |
|
|
776
|
+
| Plain object `{}` | `Record<string, unknown>` (pass-through) |
|
|
777
|
+
| Array `[]` | `{ items: [...] }` |
|
|
778
|
+
| Anything else | `String(value)` |
|
|
779
|
+
|
|
780
|
+
### Prompt extraction
|
|
781
|
+
|
|
782
|
+
Resolved in this order: `metadata.prompt` → `input.messages[0].content` → `input.prompt` → `input.text` → `"[LangChain run]"`.
|
|
783
|
+
|
|
784
|
+
### Metadata mapping
|
|
785
|
+
|
|
786
|
+
| Metadata key | Mapped to |
|
|
787
|
+
|---|---|
|
|
788
|
+
| `appId` | `snapshot.appId` |
|
|
789
|
+
| `runId` | `snapshot.runId` |
|
|
790
|
+
| `workflowId` | `snapshot.workflowId` |
|
|
791
|
+
| `conversationId` | `snapshot.conversationId` |
|
|
792
|
+
| `prompt` | Used as the CER `prompt` field |
|
|
793
|
+
| All other keys | `bundle.meta.tags` (as `"key:value"` strings) |
|
|
794
|
+
|
|
795
|
+
### Verification
|
|
796
|
+
|
|
797
|
+
Bundles from all three helpers are fully protocol-aligned:
|
|
798
|
+
|
|
799
|
+
```ts
|
|
800
|
+
import { verifyCer, verifyAiCerBundleDetailed } from '@nexart/ai-execution';
|
|
801
|
+
|
|
802
|
+
const basic = verifyCer(bundle);
|
|
803
|
+
// { ok: true, code: 'OK' }
|
|
804
|
+
|
|
805
|
+
const detailed = verifyAiCerBundleDetailed(bundle);
|
|
806
|
+
// { status: 'VERIFIED', checks: { bundleIntegrity: 'PASS', nodeSignature: 'SKIPPED' }, ... }
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
### Testing the attested path without a network
|
|
810
|
+
|
|
811
|
+
Use the injectable `_attestFn` test option (same pattern as `certifyAndAttestRun`'s `attestStep`):
|
|
812
|
+
|
|
813
|
+
```ts
|
|
814
|
+
import type { AttestDecisionFn } from '@nexart/ai-execution';
|
|
815
|
+
|
|
816
|
+
const mockAttest: AttestDecisionFn = async (params, _opts) => {
|
|
817
|
+
const { certifyDecision } = await import('@nexart/ai-execution');
|
|
818
|
+
const bundle = certifyDecision(params);
|
|
819
|
+
return { bundle, receipt: { attestationId: 'mock-123', certificateHash: bundle.certificateHash,
|
|
820
|
+
nodeRuntimeHash: 'sha256:' + 'beef'.repeat(16), protocolVersion: '1.2.0' } };
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
const result = await certifyLangChainRun(
|
|
824
|
+
{ ...input, nodeUrl: 'https://node.nexart.io', apiKey: 'nxa_test' },
|
|
825
|
+
{ _attestFn: mockAttest },
|
|
826
|
+
);
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
### V3 roadmap (not yet implemented)
|
|
830
|
+
|
|
831
|
+
- `BaseCallbackHandler` integration for automatic mid-chain CER capture at `onLLMEnd`
|
|
832
|
+
- LangSmith trace correlation via `metadata.runId` → `snapshot.conversationId`
|
|
833
|
+
- Separate `@nexart/langchain` package once the callback surface is proven in production
|
|
834
|
+
|
|
835
|
+
---
|
|
836
|
+
|
|
675
837
|
## Version History
|
|
676
838
|
|
|
677
839
|
| Version | Description |
|
|
@@ -685,7 +847,9 @@ Priority when multiple failures exist: `CANONICALIZATION_ERROR` > `SCHEMA_ERROR`
|
|
|
685
847
|
| v0.5.0 | Ed25519 signed receipt verification: `verifyNodeReceiptSignature`, `verifyBundleAttestation`, `fetchNodeKeys`, `selectNodeKey`; new attestation `CerVerifyCode` entries; `SPEC.md`; `NodeKeysDocument`, `SignedAttestationReceipt`, `NodeReceiptVerifyResult` types |
|
|
686
848
|
| v0.6.0 | Frictionless integration: `certifyDecisionFromProviderCall` (OpenAI/Anthropic/Gemini/Mistral/Bedrock drop-in); `sanitizeForStorage` + `sanitizeForStamp` redaction helpers; `createClient(defaults)` factory; regression fixture suite; all backward-compatible, no hash changes |
|
|
687
849
|
| v0.7.0 | AIEF alignment: `verifyAief()` (AIEF §9.1 adapter); `verifyRunSummary()` chain verifier; `makeToolEvent()` + `hashToolOutput()` + `snapshot.toolCalls` (AIEF-06); `BundleDeclaration` block (`stabilitySchemeId`, `protectedSetId`, `protectedFields`) excluded from `certificateHash`; `redactBeforeSeal()` pre-seal verifiable redaction; `validateProfile()` (flexible/AIEF_L2/L3/L4); 5 new `CerVerifyCode` entries; backward-compatible, no hash changes |
|
|
688
|
-
|
|
|
850
|
+
| v0.8.0 | Helper APIs: `exportVerifiableRedacted()` (post-seal re-seal with redacted snapshot + provenance metadata); `certifyAndAttestRun()` (one-call multi-step certify + optional per-step attestation with injectable mock); test determinism fix; all v0.1–v0.7 bundles verify identically |
|
|
851
|
+
| v0.9.0 | CER Protocol types: `CerVerificationResult`, `ReasonCode`, `CheckStatus`; `verifyAiCerBundleDetailed()`; `CertifyDecisionParams.createdAt` wired through; determinism bug fix |
|
|
852
|
+
| **v0.10.0** | LangChain integration: `createLangChainCer()` (sync/local); `certifyLangChainRun()` dual-mode — local (sync) or node-attested (`Promise<LangChainAttestedResult>` when `nodeUrl`+`apiKey` supplied); `LangChainAttestedResult`, `AttestDecisionFn`; injectable `_attestFn` for test mocking; `@nexart/ai-execution/langchain` subpath; 47 tests (was 34); all prior bundles verify identically |
|
|
689
853
|
| v1.0.0 | Planned: API stabilization, freeze public API surface |
|
|
690
854
|
|
|
691
855
|
## Releasing
|
package/dist/index.cjs
CHANGED
|
@@ -33,6 +33,7 @@ __export(src_exports, {
|
|
|
33
33
|
CerAttestationError: () => CerAttestationError,
|
|
34
34
|
CerVerificationError: () => CerVerificationError,
|
|
35
35
|
CerVerifyCode: () => CerVerifyCode,
|
|
36
|
+
ReasonCode: () => ReasonCode,
|
|
36
37
|
RunBuilder: () => RunBuilder,
|
|
37
38
|
attest: () => attest,
|
|
38
39
|
attestIfNeeded: () => attestIfNeeded,
|
|
@@ -40,9 +41,11 @@ __export(src_exports, {
|
|
|
40
41
|
certifyAndAttestRun: () => certifyAndAttestRun,
|
|
41
42
|
certifyDecision: () => certifyDecision,
|
|
42
43
|
certifyDecisionFromProviderCall: () => certifyDecisionFromProviderCall,
|
|
44
|
+
certifyLangChainRun: () => certifyLangChainRun,
|
|
43
45
|
computeInputHash: () => computeInputHash,
|
|
44
46
|
computeOutputHash: () => computeOutputHash,
|
|
45
47
|
createClient: () => createClient,
|
|
48
|
+
createLangChainCer: () => createLangChainCer,
|
|
46
49
|
createSnapshot: () => createSnapshot,
|
|
47
50
|
exportCer: () => exportCer,
|
|
48
51
|
exportVerifiableRedacted: () => exportVerifiableRedacted,
|
|
@@ -65,6 +68,7 @@ __export(src_exports, {
|
|
|
65
68
|
toCanonicalJson: () => toCanonicalJson,
|
|
66
69
|
validateProfile: () => validateProfile,
|
|
67
70
|
verify: () => verifyCer,
|
|
71
|
+
verifyAiCerBundleDetailed: () => verifyAiCerBundleDetailed,
|
|
68
72
|
verifyAief: () => verifyAief,
|
|
69
73
|
verifyBundleAttestation: () => verifyBundleAttestation,
|
|
70
74
|
verifyCer: () => verifyCer,
|
|
@@ -459,7 +463,7 @@ function certifyDecision(params) {
|
|
|
459
463
|
conversationId: params.conversationId,
|
|
460
464
|
prevStepHash: params.prevStepHash
|
|
461
465
|
});
|
|
462
|
-
return sealCer(snapshot, { meta: params.meta });
|
|
466
|
+
return sealCer(snapshot, { createdAt: params.createdAt, meta: params.meta });
|
|
463
467
|
}
|
|
464
468
|
|
|
465
469
|
// src/run.ts
|
|
@@ -2540,11 +2544,185 @@ async function certifyAndAttestRun(steps, options) {
|
|
|
2540
2544
|
finalStepHash: runSummary.finalStepHash
|
|
2541
2545
|
};
|
|
2542
2546
|
}
|
|
2547
|
+
|
|
2548
|
+
// src/cerProtocol.ts
|
|
2549
|
+
var ReasonCode = {
|
|
2550
|
+
BUNDLE_HASH_MISMATCH: "BUNDLE_HASH_MISMATCH",
|
|
2551
|
+
NODE_SIGNATURE_INVALID: "NODE_SIGNATURE_INVALID",
|
|
2552
|
+
NODE_SIGNATURE_MISSING: "NODE_SIGNATURE_MISSING",
|
|
2553
|
+
RECEIPT_HASH_MISMATCH: "RECEIPT_HASH_MISMATCH",
|
|
2554
|
+
SCHEMA_VERSION_UNSUPPORTED: "SCHEMA_VERSION_UNSUPPORTED",
|
|
2555
|
+
RECORD_NOT_FOUND: "RECORD_NOT_FOUND",
|
|
2556
|
+
BUNDLE_CORRUPTED: "BUNDLE_CORRUPTED"
|
|
2557
|
+
};
|
|
2558
|
+
|
|
2559
|
+
// src/verifyDetailed.ts
|
|
2560
|
+
function mapCerCodeToReasonCodes(cerCode) {
|
|
2561
|
+
switch (cerCode) {
|
|
2562
|
+
case CerVerifyCode.CERTIFICATE_HASH_MISMATCH:
|
|
2563
|
+
case CerVerifyCode.SNAPSHOT_HASH_MISMATCH:
|
|
2564
|
+
case CerVerifyCode.INPUT_HASH_MISMATCH:
|
|
2565
|
+
case CerVerifyCode.OUTPUT_HASH_MISMATCH:
|
|
2566
|
+
return [ReasonCode.BUNDLE_HASH_MISMATCH];
|
|
2567
|
+
case CerVerifyCode.SCHEMA_ERROR:
|
|
2568
|
+
return [ReasonCode.SCHEMA_VERSION_UNSUPPORTED];
|
|
2569
|
+
case CerVerifyCode.CANONICALIZATION_ERROR:
|
|
2570
|
+
case CerVerifyCode.UNKNOWN_ERROR:
|
|
2571
|
+
case CerVerifyCode.INVALID_SHA256_FORMAT:
|
|
2572
|
+
return [ReasonCode.BUNDLE_CORRUPTED];
|
|
2573
|
+
case CerVerifyCode.ATTESTATION_INVALID_SIGNATURE:
|
|
2574
|
+
case CerVerifyCode.ATTESTATION_KEY_FORMAT_UNSUPPORTED:
|
|
2575
|
+
case CerVerifyCode.ATTESTATION_KEY_NOT_FOUND:
|
|
2576
|
+
return [ReasonCode.NODE_SIGNATURE_INVALID];
|
|
2577
|
+
case CerVerifyCode.ATTESTATION_MISSING:
|
|
2578
|
+
return [ReasonCode.NODE_SIGNATURE_MISSING];
|
|
2579
|
+
default:
|
|
2580
|
+
return [];
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
function verifyAiCerBundleDetailed(bundle) {
|
|
2584
|
+
const verifiedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2585
|
+
const verifier = "@nexart/ai-execution";
|
|
2586
|
+
if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) {
|
|
2587
|
+
return {
|
|
2588
|
+
status: "FAILED",
|
|
2589
|
+
checks: { bundleIntegrity: "FAIL", nodeSignature: "SKIPPED", receiptConsistency: "SKIPPED" },
|
|
2590
|
+
reasonCodes: [ReasonCode.BUNDLE_CORRUPTED],
|
|
2591
|
+
certificateHash: "",
|
|
2592
|
+
bundleType: "",
|
|
2593
|
+
verifiedAt,
|
|
2594
|
+
verifier
|
|
2595
|
+
};
|
|
2596
|
+
}
|
|
2597
|
+
const b = bundle;
|
|
2598
|
+
const bundleType = typeof b["bundleType"] === "string" ? b["bundleType"] : "";
|
|
2599
|
+
const certificateHash = typeof b["certificateHash"] === "string" ? b["certificateHash"] : "";
|
|
2600
|
+
if (bundleType !== "cer.ai.execution.v1") {
|
|
2601
|
+
return {
|
|
2602
|
+
status: "FAILED",
|
|
2603
|
+
checks: { bundleIntegrity: "FAIL", nodeSignature: "SKIPPED", receiptConsistency: "SKIPPED" },
|
|
2604
|
+
reasonCodes: [ReasonCode.SCHEMA_VERSION_UNSUPPORTED],
|
|
2605
|
+
certificateHash,
|
|
2606
|
+
bundleType,
|
|
2607
|
+
verifiedAt,
|
|
2608
|
+
verifier
|
|
2609
|
+
};
|
|
2610
|
+
}
|
|
2611
|
+
const cerResult = verifyCer(bundle);
|
|
2612
|
+
const bundleIntegrity = cerResult.ok ? "PASS" : "FAIL";
|
|
2613
|
+
const attestationPresent = hasAttestation(bundle);
|
|
2614
|
+
const nodeSignature = attestationPresent ? "PASS" : "SKIPPED";
|
|
2615
|
+
const receiptConsistency = attestationPresent ? "PASS" : "SKIPPED";
|
|
2616
|
+
const reasonCodes = cerResult.ok ? [] : mapCerCodeToReasonCodes(cerResult.code);
|
|
2617
|
+
return {
|
|
2618
|
+
status: cerResult.ok ? "VERIFIED" : "FAILED",
|
|
2619
|
+
checks: { bundleIntegrity, nodeSignature, receiptConsistency },
|
|
2620
|
+
reasonCodes,
|
|
2621
|
+
certificateHash,
|
|
2622
|
+
bundleType,
|
|
2623
|
+
verifiedAt,
|
|
2624
|
+
verifier
|
|
2625
|
+
};
|
|
2626
|
+
}
|
|
2627
|
+
|
|
2628
|
+
// src/langchain.ts
|
|
2629
|
+
var crypto6 = __toESM(require("crypto"), 1);
|
|
2630
|
+
function normalizeCerValue(value) {
|
|
2631
|
+
if (typeof value === "string") return value;
|
|
2632
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
2633
|
+
return value;
|
|
2634
|
+
}
|
|
2635
|
+
if (Array.isArray(value)) return { items: value };
|
|
2636
|
+
return String(value);
|
|
2637
|
+
}
|
|
2638
|
+
function extractPrompt(input, metadata) {
|
|
2639
|
+
if (typeof metadata?.prompt === "string" && metadata.prompt.length > 0) {
|
|
2640
|
+
return metadata.prompt;
|
|
2641
|
+
}
|
|
2642
|
+
if (input !== null && typeof input === "object" && !Array.isArray(input)) {
|
|
2643
|
+
const obj = input;
|
|
2644
|
+
if (Array.isArray(obj.messages) && obj.messages.length > 0) {
|
|
2645
|
+
const first = obj.messages[0];
|
|
2646
|
+
if (typeof first?.content === "string" && first.content.length > 0) {
|
|
2647
|
+
return first.content;
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
if (typeof obj.prompt === "string" && obj.prompt.length > 0) return obj.prompt;
|
|
2651
|
+
if (typeof obj.text === "string" && obj.text.length > 0) return obj.text;
|
|
2652
|
+
}
|
|
2653
|
+
if (typeof input === "string" && input.length > 0) return input;
|
|
2654
|
+
return "[LangChain run]";
|
|
2655
|
+
}
|
|
2656
|
+
function buildMeta(metadata) {
|
|
2657
|
+
if (!metadata || Object.keys(metadata).length === 0) return void 0;
|
|
2658
|
+
const reserved = /* @__PURE__ */ new Set(["prompt", "appId", "runId", "workflowId", "conversationId"]);
|
|
2659
|
+
const extraTags = [];
|
|
2660
|
+
for (const [k, v] of Object.entries(metadata)) {
|
|
2661
|
+
if (!reserved.has(k)) {
|
|
2662
|
+
extraTags.push(typeof v === "string" ? `${k}:${v}` : `${k}:${JSON.stringify(v)}`);
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
return extraTags.length > 0 ? { tags: extraTags } : void 0;
|
|
2666
|
+
}
|
|
2667
|
+
function resolveParameters(params) {
|
|
2668
|
+
return {
|
|
2669
|
+
temperature: params?.temperature ?? 0,
|
|
2670
|
+
maxTokens: params?.maxTokens ?? 0,
|
|
2671
|
+
topP: params?.topP ?? null,
|
|
2672
|
+
seed: params?.seed ?? null
|
|
2673
|
+
};
|
|
2674
|
+
}
|
|
2675
|
+
function buildCertifyParams(input, executionId) {
|
|
2676
|
+
return {
|
|
2677
|
+
executionId,
|
|
2678
|
+
timestamp: input.timestamp,
|
|
2679
|
+
createdAt: input.createdAt,
|
|
2680
|
+
provider: input.provider,
|
|
2681
|
+
model: input.model,
|
|
2682
|
+
modelVersion: input.modelVersion ?? null,
|
|
2683
|
+
prompt: extractPrompt(input.input, input.metadata),
|
|
2684
|
+
input: normalizeCerValue(input.input),
|
|
2685
|
+
output: normalizeCerValue(input.output),
|
|
2686
|
+
parameters: resolveParameters(input.parameters),
|
|
2687
|
+
appId: typeof input.metadata?.appId === "string" ? input.metadata.appId : null,
|
|
2688
|
+
runId: typeof input.metadata?.runId === "string" ? input.metadata.runId : void 0,
|
|
2689
|
+
workflowId: typeof input.metadata?.workflowId === "string" ? input.metadata.workflowId : void 0,
|
|
2690
|
+
conversationId: typeof input.metadata?.conversationId === "string" ? input.metadata.conversationId : void 0,
|
|
2691
|
+
meta: buildMeta(input.metadata)
|
|
2692
|
+
};
|
|
2693
|
+
}
|
|
2694
|
+
function createLangChainCer(input) {
|
|
2695
|
+
const executionId = input.executionId ?? crypto6.randomUUID();
|
|
2696
|
+
const bundle = certifyDecision(buildCertifyParams(input, executionId));
|
|
2697
|
+
return {
|
|
2698
|
+
bundle,
|
|
2699
|
+
certificateHash: bundle.certificateHash,
|
|
2700
|
+
executionId: bundle.snapshot.executionId
|
|
2701
|
+
};
|
|
2702
|
+
}
|
|
2703
|
+
function certifyLangChainRun(input, _options) {
|
|
2704
|
+
if (input.nodeUrl && input.apiKey) {
|
|
2705
|
+
const executionId = input.executionId ?? crypto6.randomUUID();
|
|
2706
|
+
const certifyParams = buildCertifyParams({ ...input, executionId }, executionId);
|
|
2707
|
+
const attestFn = _options?._attestFn ?? certifyAndAttestDecision;
|
|
2708
|
+
return attestFn(certifyParams, { nodeUrl: input.nodeUrl, apiKey: input.apiKey }).then(
|
|
2709
|
+
({ bundle, receipt }) => ({
|
|
2710
|
+
bundle,
|
|
2711
|
+
receipt,
|
|
2712
|
+
certificateHash: bundle.certificateHash,
|
|
2713
|
+
executionId: bundle.snapshot.executionId,
|
|
2714
|
+
attested: true
|
|
2715
|
+
})
|
|
2716
|
+
);
|
|
2717
|
+
}
|
|
2718
|
+
return createLangChainCer(input);
|
|
2719
|
+
}
|
|
2543
2720
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2544
2721
|
0 && (module.exports = {
|
|
2545
2722
|
CerAttestationError,
|
|
2546
2723
|
CerVerificationError,
|
|
2547
2724
|
CerVerifyCode,
|
|
2725
|
+
ReasonCode,
|
|
2548
2726
|
RunBuilder,
|
|
2549
2727
|
attest,
|
|
2550
2728
|
attestIfNeeded,
|
|
@@ -2552,9 +2730,11 @@ async function certifyAndAttestRun(steps, options) {
|
|
|
2552
2730
|
certifyAndAttestRun,
|
|
2553
2731
|
certifyDecision,
|
|
2554
2732
|
certifyDecisionFromProviderCall,
|
|
2733
|
+
certifyLangChainRun,
|
|
2555
2734
|
computeInputHash,
|
|
2556
2735
|
computeOutputHash,
|
|
2557
2736
|
createClient,
|
|
2737
|
+
createLangChainCer,
|
|
2558
2738
|
createSnapshot,
|
|
2559
2739
|
exportCer,
|
|
2560
2740
|
exportVerifiableRedacted,
|
|
@@ -2577,6 +2757,7 @@ async function certifyAndAttestRun(steps, options) {
|
|
|
2577
2757
|
toCanonicalJson,
|
|
2578
2758
|
validateProfile,
|
|
2579
2759
|
verify,
|
|
2760
|
+
verifyAiCerBundleDetailed,
|
|
2580
2761
|
verifyAief,
|
|
2581
2762
|
verifyBundleAttestation,
|
|
2582
2763
|
verifyCer,
|