Tutorial 20 โ TypeScript package (@microsoft/agentmesh-sdk)¶
Package:
@microsoft/agentmesh-sdkยท Time: 30 minutes ยท Prerequisites: Node.js 18+
What You'll Learn¶
- Identity and Ed25519 DIDs in TypeScript/Node.js
- Trust scoring and peer verification
- Declarative policy evaluation
- Hash-chain audit logging
Build governance-aware AI agents in TypeScript and Node.js. The @microsoft/agentmesh-sdk package provides cryptographic identity (Ed25519 DIDs), trust scoring, declarative policy evaluation, and hash-chain audit logging โ all in a single npm install.
Prerequisites: Node.js โฅ 18 ยท TypeScript โฅ 5.4 Package: @microsoft/agentmesh-sdk v1.0.0 Modules: AgentIdentity, TrustManager, PolicyEngine, AuditLogger, AgentMeshClient
What you'll learn:
| Section | Topic |
|---|---|
| Quick Start | Evaluate a policy in 5 lines of TypeScript |
| AgentMeshClient | Unified governance pipeline โ identity + trust + policy + audit |
| PolicyEngine | Declarative rules, YAML policies, conflict resolution |
| AgentIdentity | Ed25519 key pairs, DIDs, delegation, capabilities |
| TrustManager | Bayesian trust scoring, tiers, decay |
| AuditLogger | Hash-chain audit logging and verification |
| Framework Integration | LangChain.js, OpenAI Node SDK |
| Configuration Reference | Defaults, environment variables, tuning |
| Error Handling | TypeScript-specific patterns |
| Cross-Reference | Equivalent Python tutorials |
Installation¶
The package has two runtime dependencies โ @noble/ed25519 for cryptography and js-yaml for YAML policy parsing. Both are installed automatically.
For TypeScript projects, types are included โ no separate @types/ package is needed.
# Verify the install
node -e "const sdk = require('@microsoft/agentmesh-sdk'); console.log(Object.keys(sdk))"
Quick Start¶
Five lines to evaluate your first policy:
import { PolicyEngine } from '@microsoft/agentmesh-sdk';
const engine = new PolicyEngine([
{ action: 'data.read', effect: 'allow' },
{ action: 'data.write', effect: 'deny' },
]);
console.log(engine.evaluate('data.read')); // 'allow'
console.log(engine.evaluate('data.write')); // 'deny'
console.log(engine.evaluate('data.delete')); // 'deny' โ default when no rule matches
Tip: The default decision when no rule matches is
'deny'โ secure by default.
Or use the unified AgentMeshClient for the full governance pipeline:
import { AgentMeshClient } from '@microsoft/agentmesh-sdk';
const client = AgentMeshClient.create('my-agent', {
capabilities: ['data.read', 'data.write'],
policyRules: [
{ action: 'data.read', effect: 'allow' },
{ action: 'data.write', effect: 'allow', conditions: { role: 'admin' } },
{ action: '*', effect: 'deny' },
],
});
const result = await client.executeWithGovernance('data.read');
console.log(result.decision); // 'allow'
console.log(result.trustScore); // { overall: 0.5, tier: 'Provisional', ... }
console.log(result.auditEntry); // { hash: '3a7f...', previousHash: '0000...', ... }
AgentMeshClient¶
The AgentMeshClient is the recommended entry point. It wires together identity, trust, policy, and audit into a single governance-aware pipeline.
Creating a Client¶
import { AgentMeshClient } from '@microsoft/agentmesh-sdk';
// Quick creation with defaults
const client = AgentMeshClient.create('sales-agent', {
capabilities: ['crm.read', 'crm.write', 'email.send'],
});
// Access individual components
console.log(client.identity.did); // did:agentmesh:sales-agent:<fingerprint>
console.log(client.trust); // TrustManager instance
console.log(client.policy); // PolicyEngine instance
console.log(client.audit); // AuditLogger instance
Full Configuration¶
import { AgentMeshClient, AgentMeshConfig } from '@microsoft/agentmesh-sdk';
const config: AgentMeshConfig = {
agentId: 'analytics-agent',
capabilities: ['data.read', 'report.generate'],
trust: {
initialScore: 0.6,
decayFactor: 0.98,
thresholds: {
untrusted: 0.0,
provisional: 0.3,
trusted: 0.6,
verified: 0.85,
},
},
policyRules: [
{ action: 'data.read', effect: 'allow' },
{ action: 'report.generate', effect: 'allow' },
{ action: '*', effect: 'deny' },
],
audit: {
maxEntries: 50_000,
},
};
const client = new AgentMeshClient(config);
The Governance Pipeline¶
executeWithGovernance() runs every action through a four-stage pipeline:
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
โ 1. Policy โโโโโถโ 2. Trust โโโโโถโ 3. Audit โโโโโถโ 4. Trust โ
โ Evaluate โ โ Score โ โ Log โ โ Update โ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
const result = await client.executeWithGovernance('data.read', {
userId: 'alice',
department: 'engineering',
});
// GovernanceResult
console.log(result.decision); // 'allow' | 'deny' | 'review'
console.log(result.trustScore); // TrustScore object
console.log(result.auditEntry); // AuditEntry with hash chain
console.log(result.executionTime); // milliseconds (e.g., 1.234)
GovernanceResult shape:
| Field | Type | Description |
|---|---|---|
decision | 'allow' \| 'deny' \| 'review' | Policy evaluation outcome |
trustScore | TrustScore | Current trust score after action |
auditEntry | AuditEntry | Immutable audit record created |
executionTime | number | Pipeline duration in milliseconds |
PolicyEngine¶
The PolicyEngine supports two modes: legacy flat rules (simple action matching) and rich YAML/JSON policies (expressions, rate limits, approvals, conflict resolution).
ยง4.1 Legacy Flat Rules¶
Flat rules match an action string and return an effect:
import { PolicyEngine, PolicyRule } from '@microsoft/agentmesh-sdk';
const rules: PolicyRule[] = [
{ action: 'data.read', effect: 'allow' },
{ action: 'data.write', effect: 'allow', conditions: { role: 'admin' } },
{ action: 'data.*', effect: 'deny' },
{ action: '*', effect: 'deny' },
];
const engine = new PolicyEngine(rules);
engine.evaluate('data.read'); // 'allow'
engine.evaluate('data.write', { role: 'admin' }); // 'allow'
engine.evaluate('data.write', { role: 'viewer' }); // 'deny' โ conditions don't match
engine.evaluate('data.delete'); // 'deny' โ wildcard catch-all
Evaluation order: First matching rule wins. Place specific rules before wildcards.
ยง4.2 Loading Rules from YAML¶
const engine = new PolicyEngine();
// Load from a YAML file on disk
await engine.loadFromYAML('./policies/production.yaml');
engine.evaluate('data.read'); // Uses loaded rules
ยง4.3 Rich Policy Documents¶
Rich policies add expressions, rate limits, approval workflows, and conflict resolution:
import { PolicyEngine } from '@microsoft/agentmesh-sdk';
const engine = new PolicyEngine();
const policy = engine.loadYaml(`
apiVersion: governance.toolkit/v1
name: data-access-policy
description: Controls data operations for analytics agents
agents:
- 'did:agentmesh:analytics-*'
scope: tenant
rules:
- name: admin-full-access
condition: "user.role == 'admin'"
ruleAction: allow
priority: 100
- name: analyst-read-only
condition: "user.role in ['analyst', 'viewer']"
ruleAction: allow
priority: 50
- name: rate-limit-writes
condition: "action == 'data.write'"
ruleAction: allow
priority: 75
limit: '100/hour'
- name: require-approval-for-delete
condition: "action == 'data.delete'"
ruleAction: require_approval
priority: 90
approvers:
- 'did:agentmesh:security-team'
- 'did:agentmesh:data-owner'
- name: default-deny
ruleAction: deny
priority: 0
default_action: deny
`);
console.log(policy.name); // 'data-access-policy'
ยง4.4 Rich Policy Evaluation¶
const result = engine.evaluatePolicy(
'did:agentmesh:analytics-agent:abc123',
{ user: { role: 'admin' }, action: 'data.write' }
);
console.log(result.allowed); // true
console.log(result.action); // 'allow'
console.log(result.matchedRule); // 'admin-full-access'
console.log(result.policyName); // 'data-access-policy'
console.log(result.rateLimited); // false
console.log(result.approvers); // []
console.log(result.evaluationMs); // 0.123
PolicyDecisionResult shape:
| Field | Type | Description |
|---|---|---|
allowed | boolean | Whether the action is permitted |
action | PolicyAction | 'allow' | 'deny' | 'warn' | 'require_approval' | 'log' |
matchedRule | string? | Name of the rule that matched |
policyName | string? | Name of the policy that matched |
reason | string? | Human-readable explanation |
approvers | string[] | Required approver DIDs (for require_approval) |
rateLimited | boolean | Whether rate limiting is active |
evaluatedAt | Date | Timestamp of evaluation |
evaluationMs | number? | Duration of evaluation in ms |
ยง4.5 Expression Syntax¶
Rich policy conditions use a simple expression language:
| Operator | Example | Description |
|---|---|---|
== | user.role == 'admin' | Equality (string, number, boolean) |
!= | status != 'blocked' | Not equal |
> | token_count > 2048 | Greater than |
< | risk_score < 0.5 | Less than |
>= | trust_level >= 0.85 | Greater than or equal |
<= | attempts <= 3 | Less than or equal |
in | role in ['admin', 'analyst'] | Membership in list |
not in | env not in ['prod'] | Not a member |
and | role == 'admin' and dept == 'eng' | Logical AND |
or | level > 5 or isVerified | Logical OR |
| (truthy) | isVerified | Property existence / truthiness |
Nested path access: Use dots to access nested properties โ user.role, request.headers.authorization, agent.trust.tier.
ยง4.6 Rate Limiting¶
Add a limit field to any rule to enforce rate limits:
rules:
- name: throttle-api-calls
condition: "action == 'api.call'"
ruleAction: allow
limit: '1000/minute'
Supported time windows:
| Format | Example |
|---|---|
N/second | 100/second |
N/minute | 1000/minute |
N/hour | 10000/hour |
N/day | 100000/day |
ยง4.7 Conflict Resolution¶
When multiple policies apply to the same action, the PolicyConflictResolver determines which rule wins:
import {
PolicyEngine,
PolicyConflictResolver,
ConflictResolutionStrategy,
} from '@microsoft/agentmesh-sdk';
const engine = new PolicyEngine([], ConflictResolutionStrategy.DenyOverrides);
Strategies:
| Strategy | Enum Value | Behaviour |
|---|---|---|
| Deny Overrides | deny_overrides | Any deny rule wins โ safety first |
| Allow Overrides | allow_overrides | Any allow rule wins โ permissive |
| Priority First Match | priority_first_match | Highest priority value wins (default) |
| Most Specific Wins | most_specific_wins | Most specific scope + highest priority wins |
const resolver = new PolicyConflictResolver(
ConflictResolutionStrategy.MostSpecificWins
);
const result = resolver.resolve([
{
action: 'allow',
priority: 50,
scope: PolicyScope.Global,
policyName: 'global-policy',
ruleName: 'allow-reads',
reason: 'Global read access',
approvers: [],
},
{
action: 'deny',
priority: 50,
scope: PolicyScope.Agent,
policyName: 'agent-policy',
ruleName: 'deny-untrusted',
reason: 'Agent-specific restriction',
approvers: [],
},
]);
console.log(result.winningDecision.action); // 'deny' โ agent scope is more specific
console.log(result.strategyUsed); // 'most_specific_wins'
console.log(result.conflictDetected); // true
console.log(result.resolutionTrace); // step-by-step resolution log
Scope specificity order (most โ least specific):
ยง4.8 Managing Multiple Policies¶
const engine = new PolicyEngine();
// Load multiple policies
engine.loadYaml(securityPolicyYaml);
engine.loadYaml(compliancePolicyYaml);
engine.loadYaml(operationalPolicyYaml);
// List and inspect
console.log(engine.listPolicies()); // ['security', 'compliance', 'operational']
console.log(engine.getPolicy('security')); // Policy object
// Remove a policy
engine.removePolicy('operational');
// Clear all policies
engine.clearPolicies();
AgentIdentity¶
Each agent gets a cryptographic identity backed by Ed25519 key pairs. The identity produces a DID (Decentralized Identifier) and supports signing, verification, delegation, and lifecycle management.
ยง5.1 Generating an Identity¶
import { AgentIdentity } from '@microsoft/agentmesh-sdk';
const agent = AgentIdentity.generate('sales-assistant', ['crm.read', 'email.send'], {
name: 'Sales Assistant',
description: 'Handles inbound sales inquiries',
organization: 'Contoso',
sponsor: 'alice@contoso.com',
expiresAt: new Date('2026-01-01'),
});
console.log(agent.did); // did:agentmesh:sales-assistant:<fingerprint>
console.log(agent.publicKey); // Uint8Array (Ed25519 DER)
console.log(agent.capabilities); // ['crm.read', 'email.send']
console.log(agent.status); // 'active'
console.log(agent.organization); // 'Contoso'
console.log(agent.sponsor); // 'alice@contoso.com'
DID format: did:agentmesh:<agentId>:<fingerprint>
The fingerprint is derived from the public key, making each DID globally unique and cryptographically verifiable.
ยง5.2 Signing and Verification¶
const message = new TextEncoder().encode('Transfer $500 to account 1234');
// Sign with private key
const signature = agent.sign(message);
// Verify with public key
const valid = agent.verify(message, signature);
console.log(valid); // true
// Tampered data fails verification
const tampered = new TextEncoder().encode('Transfer $50000 to account 9999');
console.log(agent.verify(tampered, signature)); // false
Note: Signing requires the private key. Identities imported via
fromJSON()without aprivateKeyfield can only verify, not sign.
ยง5.3 Capability Checking¶
Capabilities support exact matching and wildcard patterns:
const agent = AgentIdentity.generate('worker', [
'data.read',
'data.write',
'report.generate',
]);
agent.hasCapability('data.read'); // true
agent.hasCapability('data.delete'); // false
agent.hasCapability('data.*'); // true โ wildcard matches data.read & data.write
agent.hasCapability('report.generate'); // true
ยง5.4 Delegation¶
Create child identities with narrowed capabilities:
const parent = AgentIdentity.generate('orchestrator', [
'data.read', 'data.write', 'admin', 'deploy',
]);
// Child can only read and write โ no admin or deploy
const child = parent.delegate('data-worker', ['data.read', 'data.write'], {
description: 'Scoped worker for data pipeline',
sponsor: 'pipeline-team@contoso.com',
});
console.log(child.parentDid); // parent's DID
console.log(child.delegationDepth); // 1
console.log(child.hasCapability('data.read')); // true
console.log(child.hasCapability('admin')); // false โ not delegated
// Delegation chains
const grandchild = child.delegate('read-only', ['data.read']);
console.log(grandchild.delegationDepth); // 2
ยง5.5 Lifecycle Management¶
const agent = AgentIdentity.generate('temp-agent', ['task.run']);
console.log(agent.isActive()); // true
console.log(agent.status); // 'active'
// Suspend โ temporary, reversible
agent.suspend('Under investigation');
console.log(agent.isActive()); // false
console.log(agent.status); // 'suspended'
// Reactivate
agent.reactivate();
console.log(agent.isActive()); // true
// Revoke โ permanent, irreversible
agent.revoke('Compromised credentials');
console.log(agent.status); // 'revoked'
// Cannot reactivate a revoked identity
try {
agent.reactivate(); // throws
} catch (e) {
console.log(e.message); // Cannot reactivate a revoked identity
}
State machine:
generate() suspend() revoke()
โ โ โ
โผ โผ โผ
โโโโโโโโโโ โโโโโโโโโโโโโ โโโโโโโโโโโ
โ active โโโโโโถโ suspended โ โ revoked โ
โโโโโโโโโโ โโโโโโโโโโโโโ โโโโโโโโโโโ
โ reactivate() โ โฒ
โ โ โ
โ โผ โ
โ โโโโโโโโโโ โ
โโโโโโโโโโโถโ active โโโโโโโโโโโโโโโ
โโโโโโโโโโ revoke()
ยง5.6 Serialization¶
JSON round-trip:
// Export
const json = agent.toJSON();
// {
// did: 'did:agentmesh:sales-assistant:...',
// publicKey: 'base64...',
// privateKey: 'base64...',
// capabilities: ['crm.read', 'email.send'],
// name: 'Sales Assistant',
// status: 'active',
// createdAt: '2025-01-15T...',
// ...
// }
// Import
const restored = AgentIdentity.fromJSON(json);
console.log(restored.did === agent.did); // true
JWK / JWKS (RFC 7517):
// Export as JWK (public key only)
const jwk = agent.toJWK(false);
// { kty: 'OKP', crv: 'Ed25519', x: '...', kid: 'did:agentmesh:...' }
// Export with private key
const jwkPrivate = agent.toJWK(true);
// JWK Set
const jwks = agent.toJWKS(false);
// { keys: [{ kty: 'OKP', crv: 'Ed25519', ... }] }
// Import from JWK
const fromJwk = AgentIdentity.fromJWK(jwk);
// Import from JWKS (picks first key, or by kid)
const fromJwks = AgentIdentity.fromJWKS(jwks, agent.did);
W3C DID Document:
const didDoc = agent.toDIDDocument();
// {
// '@context': 'https://www.w3.org/ns/did/v1',
// id: 'did:agentmesh:sales-assistant:...',
// verificationMethod: [...],
// authentication: [...],
// ...
// }
ยง5.7 Identity Registry¶
Manage multiple identities with the IdentityRegistry:
import { AgentIdentity, IdentityRegistry } from '@microsoft/agentmesh-sdk';
const registry = new IdentityRegistry();
const agent1 = AgentIdentity.generate('agent-1', ['read'], {
sponsor: 'alice@contoso.com',
});
const agent2 = AgentIdentity.generate('agent-2', ['write'], {
sponsor: 'alice@contoso.com',
});
const agent3 = AgentIdentity.generate('agent-3', ['admin'], {
sponsor: 'bob@contoso.com',
});
registry.register(agent1);
registry.register(agent2);
registry.register(agent3);
console.log(registry.size); // 3
// Look up by DID
const found = registry.get(agent1.did);
console.log(found?.did); // agent1's DID
// Find all identities by sponsor
const aliceAgents = registry.getBySponsor('alice@contoso.com');
console.log(aliceAgents.length); // 2
// List all active identities
console.log(registry.listActive().length); // 3
// Revoke โ cascades to all delegates
registry.revoke(agent1.did, 'Decommissioned');
console.log(registry.listActive().length); // 2
TrustManager¶
The TrustManager maintains a Bayesian-inspired trust score for each peer agent. Scores decay over time and update based on interaction outcomes.
ยง6.1 Creating a Trust Manager¶
import { TrustManager, TrustConfig } from '@microsoft/agentmesh-sdk';
// Default configuration
const tm = new TrustManager();
// Custom configuration
const custom = new TrustManager({
initialScore: 0.6,
decayFactor: 0.98,
thresholds: {
untrusted: 0.0,
provisional: 0.3,
trusted: 0.6,
verified: 0.85,
},
});
Default values:
| Property | Default | Description |
|---|---|---|
initialScore | 0.5 | Starting score for unknown agents |
decayFactor | 0.95 | Hourly decay multiplier |
thresholds.untrusted | 0.0 | Floor for untrusted tier |
thresholds.provisional | 0.3 | Entry point for provisional trust |
thresholds.trusted | 0.6 | Entry point for trusted tier |
thresholds.verified | 0.85 | Entry point for verified tier |
ยง6.2 Recording Interactions¶
const tm = new TrustManager();
// Record successful interactions (default reward: 0.05)
tm.recordSuccess('peer-agent-1');
tm.recordSuccess('peer-agent-1');
tm.recordSuccess('peer-agent-1');
// Record failure (default penalty: 0.1)
tm.recordFailure('peer-agent-1');
// Custom reward / penalty values
tm.recordSuccess('peer-agent-2', 0.1); // larger reward
tm.recordFailure('peer-agent-2', 0.2); // harsher penalty
ยง6.3 Reading Trust Scores¶
const score = tm.getTrustScore('peer-agent-1');
console.log(score.overall); // 0.55 (0-1, rounded to 3 decimals)
console.log(score.tier); // 'Provisional'
console.log(score.dimensions.reliability); // 0.75 (3 successes / 4 total)
console.log(score.dimensions.consistency); // 0.55 (current score after updates)
TrustScore shape:
interface TrustScore {
overall: number; // 0-1, rounded to 3 decimals
dimensions: {
reliability: number; // success ratio: successes / total interactions
consistency: number; // current running score
};
tier: TrustTier; // 'Untrusted' | 'Provisional' | 'Trusted' | 'Verified'
}
ยง6.4 Trust Tiers¶
Tiers map numeric scores to access levels:
| Tier | Score Range | Typical Access |
|---|---|---|
| Untrusted | 0.00 โ 0.29 | Blocked or heavily restricted |
| Provisional | 0.30 โ 0.59 | Limited access, monitored |
| Trusted | 0.60 โ 0.84 | Standard access |
| Verified | 0.85 โ 1.00 | Full access, elevated privileges |
Untrusted โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 0.00 โ 0.29
Provisional โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 0.30 โ 0.59
Trusted โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 0.60 โ 0.84
Verified โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ 0.85 โ 1.00
ยง6.5 Peer Verification¶
Verify another agent's identity and establish initial trust:
import { AgentIdentity, TrustManager } from '@microsoft/agentmesh-sdk';
const tm = new TrustManager();
const peer = AgentIdentity.generate('remote-agent', ['data.read']);
const result = await tm.verifyPeer('remote-agent', peer);
console.log(result.verified); // true โ signature self-consistency checks passed
console.log(result.trustScore); // initial TrustScore
console.log(result.reason); // undefined when successful
ยง6.6 Trust Decay¶
Trust scores decay over time when there are no interactions. The decayFactor is applied hourly:
// With decayFactor: 0.95
// After 1 hour of inactivity: score ร 0.95
// After 2 hours: score ร 0.95ยฒ
// After 24 hours: score ร 0.95ยฒโด โ score ร 0.292
const tm = new TrustManager({ decayFactor: 0.95 });
tm.recordSuccess('agent-x');
tm.recordSuccess('agent-x');
// Score starts high, but decays if no further interactions
const score = tm.getTrustScore('agent-x');
console.log(score.overall); // Score reflects elapsed time since last interaction
Tip: Set
decayFactorcloser to1.0(e.g.,0.99) for slower decay, or lower (e.g.,0.90) for aggressive decay requiring frequent re-validation.
AuditLogger¶
The AuditLogger provides an append-only, hash-chain-linked audit trail. Each entry's SHA-256 hash incorporates the previous entry's hash, creating a tamper-evident chain similar to a blockchain.
ยง7.1 Logging Events¶
import { AuditLogger } from '@microsoft/agentmesh-sdk';
const logger = new AuditLogger();
const entry = logger.log({
agentId: 'sales-assistant',
action: 'crm.read',
decision: 'allow',
});
console.log(entry.timestamp); // ISO 8601 string
console.log(entry.hash); // SHA-256 of this entry
console.log(entry.previousHash); // SHA-256 of previous entry (genesis: '0' ร 64)
ยง7.2 Hash-Chain Integrity¶
const logger = new AuditLogger();
logger.log({ agentId: 'agent-1', action: 'data.read', decision: 'allow' });
logger.log({ agentId: 'agent-1', action: 'data.write', decision: 'deny' });
logger.log({ agentId: 'agent-2', action: 'report.send', decision: 'allow' });
// Verify the entire chain
console.log(logger.verify()); // true โ all hashes are consistent
console.log(logger.length); // 3
How the chain works:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Entry 0 Entry 1 Entry 2 โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ
โ โ hash: A โโโโโโโโถโ prev: A โโโโโโโโถโ prev: B โ โ
โ โ prev: 0โถโดโ โ hash: B โ โ hash: C โ โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ โ
โ โ
โ Genesis hash = '000...000' (64 zeros) โ
โ Each hash = SHA-256(timestamp + agentId + action + decision + prev) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
If any entry is tampered with, verify() returns false because the hash chain breaks.
ยง7.3 Querying the Log¶
// All entries for a specific agent
const agentEntries = logger.getEntries({ agentId: 'agent-1' });
console.log(agentEntries.length); // 2
// Filter by action
const reads = logger.getEntries({ action: 'data.read' });
// Filter by time
const recent = logger.getEntries({
since: new Date('2025-01-15T00:00:00Z'),
});
// Combine filters
const agentReads = logger.getEntries({
agentId: 'agent-1',
action: 'data.read',
since: new Date('2025-01-01'),
});
ยง7.4 Exporting the Audit Trail¶
// Export as JSON string
const json = logger.exportJSON();
console.log(json);
// [
// {
// "timestamp": "2025-01-15T10:30:00.000Z",
// "agentId": "agent-1",
// "action": "data.read",
// "decision": "allow",
// "hash": "3a7f...",
// "previousHash": "0000...0000"
// },
// ...
// ]
ยง7.5 Configuration¶
// Limit log size (oldest entries evicted when limit reached)
const logger = new AuditLogger({ maxEntries: 50_000 });
| Option | Default | Description |
|---|---|---|
maxEntries | 10,000 | Maximum entries before eviction |
Framework Integration¶
ยง8.1 LangChain.js¶
Wrap LangChain tool calls with governance checks:
import { AgentMeshClient } from '@microsoft/agentmesh-sdk';
import { ChatOpenAI } from '@langchain/openai';
import { DynamicTool } from '@langchain/core/tools';
const client = AgentMeshClient.create('langchain-agent', {
capabilities: ['search', 'calculate'],
policyRules: [
{ action: 'search', effect: 'allow' },
{ action: 'calculate', effect: 'allow' },
{ action: '*', effect: 'deny' },
],
});
// Governance-aware tool wrapper
function governedTool(name: string, fn: (input: string) => Promise<string>) {
return new DynamicTool({
name,
description: `Governed: ${name}`,
func: async (input: string) => {
const gov = await client.executeWithGovernance(name, { input });
if (gov.decision !== 'allow') {
return `Action '${name}' denied by policy: ${gov.auditEntry.action}`;
}
return fn(input);
},
});
}
const searchTool = governedTool('search', async (query) => {
// your search implementation
return `Results for: ${query}`;
});
ยง8.2 OpenAI Node SDK¶
Add governance to OpenAI function calls:
import { AgentMeshClient } from '@microsoft/agentmesh-sdk';
import OpenAI from 'openai';
const client = AgentMeshClient.create('openai-agent', {
capabilities: ['chat', 'function_call'],
policyRules: [
{ action: 'chat', effect: 'allow' },
{ action: 'function_call', effect: 'allow', conditions: { trusted: true } },
{ action: '*', effect: 'deny' },
],
});
const openai = new OpenAI();
async function governedCompletion(
messages: OpenAI.ChatCompletionMessageParam[],
tools?: OpenAI.ChatCompletionTool[]
) {
// Check policy before calling OpenAI
const gov = await client.executeWithGovernance('chat', {
messageCount: messages.length,
hasTools: !!tools,
});
if (gov.decision !== 'allow') {
throw new Error(`Governance denied: ${gov.decision}`);
}
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages,
tools,
});
// If the model wants to call a function, check that too
const toolCalls = response.choices[0]?.message?.tool_calls;
if (toolCalls) {
for (const call of toolCalls) {
const fnGov = await client.executeWithGovernance('function_call', {
functionName: call.function.name,
trusted: true,
});
if (fnGov.decision !== 'allow') {
console.warn(`Function call '${call.function.name}' denied`);
}
}
}
return response;
}
Configuration Reference¶
ยง9.1 Default Values¶
| Component | Property | Default |
|---|---|---|
PolicyEngine | Conflict strategy | PriorityFirstMatch |
PolicyEngine | Default action | 'deny' |
PolicyRule | priority | 0 |
PolicyRule | enabled | true |
TrustManager | initialScore | 0.5 |
TrustManager | decayFactor | 0.95 |
TrustManager | Success reward | 0.05 |
TrustManager | Failure penalty | 0.1 |
AuditLogger | maxEntries | 10,000 |
AuditLogger | Genesis hash | '0' ร 64 |
AgentIdentity | status | 'active' |
AgentIdentity | delegationDepth | 0 (root) |
ยง9.2 Environment Variables¶
The package itself is configuration-object driven, but you can wire environment variables into your configuration:
import { AgentMeshClient } from '@microsoft/agentmesh-sdk';
const client = AgentMeshClient.create(
process.env.AGENT_ID ?? 'default-agent',
{
capabilities: (process.env.AGENT_CAPABILITIES ?? 'read').split(','),
trust: {
initialScore: parseFloat(process.env.TRUST_INITIAL_SCORE ?? '0.5'),
decayFactor: parseFloat(process.env.TRUST_DECAY_FACTOR ?? '0.95'),
},
audit: {
maxEntries: parseInt(process.env.AUDIT_MAX_ENTRIES ?? '10000', 10),
},
}
);
Recommended environment variables:
| Variable | Example | Maps to |
|---|---|---|
AGENT_ID | sales-assistant | agentId |
AGENT_CAPABILITIES | read,write,search | capabilities (comma-separated) |
TRUST_INITIAL_SCORE | 0.6 | trust.initialScore |
TRUST_DECAY_FACTOR | 0.98 | trust.decayFactor |
AUDIT_MAX_ENTRIES | 50000 | audit.maxEntries |
POLICY_YAML_PATH | ./policies/prod.yaml | Path for loadFromYAML() |
ยง9.3 TypeScript Configuration¶
The package targets ES2020 and uses Node16 module resolution. Ensure your tsconfig.json includes:
{
"compilerOptions": {
"target": "ES2020",
"module": "Node16",
"moduleResolution": "Node16",
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true
}
}
Error Handling¶
ยง10.1 Identity Errors¶
import { AgentIdentity } from '@microsoft/agentmesh-sdk';
// Revoked identity cannot be reactivated
const agent = AgentIdentity.generate('temp', ['read']);
agent.revoke('Done');
try {
agent.reactivate();
} catch (error) {
console.error(error.message); // Cannot reactivate a revoked identity
}
// Duplicate registration
const registry = new IdentityRegistry();
registry.register(agent);
try {
registry.register(agent); // same DID
} catch (error) {
console.error(error.message); // Identity already registered
}
ยง10.2 Policy Errors¶
import { PolicyEngine } from '@microsoft/agentmesh-sdk';
const engine = new PolicyEngine();
// Invalid YAML
try {
engine.loadYaml('not: valid: yaml: {{');
} catch (error) {
console.error('YAML parse error:', error.message);
}
// Missing policy file
try {
await engine.loadFromYAML('./nonexistent.yaml');
} catch (error) {
console.error('File not found:', error.message);
}
ยง10.3 Governance Pipeline Errors¶
import { AgentMeshClient } from '@microsoft/agentmesh-sdk';
const client = AgentMeshClient.create('agent', {
policyRules: [{ action: '*', effect: 'deny' }],
});
// Wrap executeWithGovernance in try/catch
try {
const result = await client.executeWithGovernance('risky.action');
if (result.decision === 'deny') {
console.log('Action denied โ audit trail:', result.auditEntry.hash);
} else if (result.decision === 'review') {
console.log('Action requires review โ trust:', result.trustScore.tier);
}
} catch (error) {
console.error('Governance pipeline error:', error);
}
ยง10.4 TypeScript-Specific Patterns¶
Use type narrowing and discriminated unions for safe handling:
import type {
PolicyDecisionResult,
GovernanceResult,
TrustTier,
} from '@microsoft/agentmesh-sdk';
// Type guard for trust tiers
function requiresTrust(tier: TrustTier, minimum: TrustTier): boolean {
const order: TrustTier[] = ['Untrusted', 'Provisional', 'Trusted', 'Verified'];
return order.indexOf(tier) >= order.indexOf(minimum);
}
// Use with governance results
async function safeExecute(
client: AgentMeshClient,
action: string
): Promise<GovernanceResult> {
const result = await client.executeWithGovernance(action);
if (result.decision === 'deny') {
throw new Error(`Denied: ${action} (audit: ${result.auditEntry.hash})`);
}
if (!requiresTrust(result.trustScore.tier, 'Trusted')) {
console.warn(`Low trust for ${action}: ${result.trustScore.tier}`);
}
return result;
}
Cross-Reference¶
The TypeScript package mirrors the Python packages. Use this table to find the equivalent Python tutorial for each topic:
| TypeScript package | Python Package | Tutorial |
|---|---|---|
PolicyEngine | agent_os.policies | Tutorial 01 โ Policy Engine |
AgentIdentity, IdentityRegistry | agent_os.identity | Tutorial 02 โ Trust & Identity |
TrustManager | agent_os.trust | Tutorial 02 โ Trust & Identity |
| Framework integration | agent_os.integrations | Tutorial 03 โ Framework Integrations |
AuditLogger | agent_os.audit | Tutorial 04 โ Audit & Compliance |
Note: The TypeScript package wraps all governance features into a single
@microsoft/agentmesh-sdkpackage, while the Python implementation splits them across separateagent_os.*modules. The APIs are designed for cross-language parity โ policy YAML files work identically in both.
Source Files¶
| Component | Location |
|---|---|
| Main exports | agent-governance-typescript/src/index.ts |
| Type definitions | agent-governance-typescript/src/types.ts |
AgentIdentity | agent-governance-typescript/src/identity.ts |
TrustManager | agent-governance-typescript/src/trust.ts |
PolicyEngine | agent-governance-typescript/src/policy.ts |
AuditLogger | agent-governance-typescript/src/audit.ts |
AgentMeshClient | agent-governance-typescript/src/client.ts |
| Tests | agent-governance-typescript/tests/*.test.ts |
| Package config | agent-governance-typescript/package.json |
Next Steps¶
- Run the tests to see the package in action:
- Load a YAML policy from the repository's
policies/directory and evaluate it against your agent - Build a multi-agent system using
IdentityRegistry+TrustManagerto establish peer trust between cooperating agents - Add audit export to your CI/CD pipeline โ call
logger.exportJSON()and persist the trail for compliance reviews - Explore the Python tutorials (01โ04) for equivalent patterns in Python