The official TypeScript/JavaScript SDK for QWED.
Installation
npm install @qwed-ai/sdk
# or
yarn add @qwed-ai/sdk
# or
pnpm add @qwed-ai/sdk
Quick start
import { QWEDClient } from '@qwed-ai/sdk';
const client = new QWEDClient({ apiKey: 'qwed_your_key' });
const result = await client.verify('Is 2+2=4?');
console.log(result.verified); // true
console.log(result.status); // "VERIFIED"
Configuration
const client = new QWEDClient({
apiKey: 'qwed_...',
baseUrl: 'http://localhost:8000', // Optional
timeout: 30000, // Optional, default 30s
});
Verification methods
verify(query)
Auto-detect and verify any claim.
const result = await client.verify('What is 15% of 200?');
verifyMath(expression)
Verify mathematical expressions.
const result = await client.verifyMath('x**2 + 2*x + 1 = (x+1)**2');
console.log(result.verified); // true
verifyLogic(query)
Verify logical constraints using QWED-Logic DSL.
const result = await client.verifyLogic('(AND (GT x 5) (LT y 10))');
console.log(result.result?.model); // { x: 6, y: 9 }
verifyCode(code, options)
Check code for security vulnerabilities.
const result = await client.verifyCode(code, { language: 'python' });
for (const vuln of result.result?.vulnerabilities ?? []) {
console.log(`${vuln.severity}: ${vuln.message}`);
}
verifyFact(claim, context)
Verify factual claims against a provided context.
const result = await client.verifyFact(
'The company was founded in 2020',
'Acme Corp was established in 2020 in San Francisco.'
);
console.log(result.verified); // true
verifySQL(query, schema)
Validate SQL queries against a schema.
const result = await client.verifySQL(
'SELECT * FROM users WHERE id = 1',
'CREATE TABLE users (id INT, name TEXT)'
);
verifyProcess(reasoningTrace, options)
Validate the structural integrity of AI reasoning traces. Use this to ensure workflows follow deterministic process steps with IRAC pattern matching or custom milestone validation.
// Verify IRAC structure in a reasoning trace
const result = await client.verifyProcess(
`The issue is whether the contract was breached.
The rule is Article 2 of the UCC.
Applying this rule, the defendant failed to deliver on time.
In conclusion, breach occurred.`,
{ mode: 'irac' }
);
console.log(result.verified); // true
console.log(result.result?.score); // 1.0
console.log(result.result?.missing_steps); // []
You can also verify custom milestones:
const result = await client.verifyProcess(
'Risk assessment complete. Compliance verified. Implementation planned.',
{
mode: 'milestones',
keyMilestones: ['risk assessment', 'compliance', 'implementation'],
}
);
console.log(result.result?.process_rate); // 1.0
console.log(result.result?.missed_milestones); // []
| Parameter | Type | Default | Description |
|---|
reasoningTrace | string | — | The AI reasoning trace to validate |
options.mode | 'irac' | 'milestones' | 'irac' | Verification mode |
options.keyMilestones | string[] | — | Required milestones (milestones mode only) |
verifyRAG(targetDocumentId, retrievedChunks, options)
Verify that retrieved RAG chunks originate from the expected source document. This prevents Document-Level Retrieval Mismatch (DRM) hallucinations in RAG pipelines.
const result = await client.verifyRAG(
'contract_nda_v2',
[
{ id: 'c1', metadata: { document_id: 'contract_nda_v2' } },
{ id: 'c2', metadata: { document_id: 'contract_nda_v1' } }, // Wrong doc
],
{ maxDrmRate: '0' } // Zero tolerance
);
console.log(result.verified); // false
console.log(result.result?.drm_rate); // 0.5
console.log(result.result?.chunks_checked); // 2
console.log(result.result?.mismatched_count); // 1
| Parameter | Type | Default | Description |
|---|
targetDocumentId | string | — | Expected source document ID |
retrievedChunks | Record<string, unknown>[] | — | Array of chunk objects with metadata |
options.maxDrmRate | string | — | Maximum tolerable mismatch fraction (e.g. '0' or '1/10') |
verifyBatch(items)
Verify multiple items at once.
const results = await client.verifyBatch([
{ query: '2+2=4', type: VerificationType.Math },
{ query: '3*3=9', type: VerificationType.Math },
]);
console.log(results.summary.success_rate);
Agent verification
The TypeScript SDK supports the QWED Agent API for registering AI agents and verifying their actions with per-tenant rate limiting and server-enforced security checks.
registerAgent(registration)
Register an agent and receive credentials for subsequent verification calls.
const { agent_id, agent_token } = await client.registerAgent({
agent: {
name: 'research-assistant',
type: 'supervised',
principal_id: 'user-123',
framework: 'langchain',
},
permissions: {
allowed_engines: [VerificationType.Fact, VerificationType.Code],
},
budget: {
max_daily_cost_usd: 5.0,
max_requests_per_hour: 100,
},
});
verifyAgent(agentId, agentToken, query, options)
Verify an agent action. Security checks (exfiltration detection and MCP poisoning) are enforced server-side and cannot be disabled by the client.
Breaking change (v5.0.0): The checkExfiltration and checkMcpPoison options have been removed. Exfiltration detection always runs. MCP poison detection runs automatically when you provide a toolSchema.
Breaking change (v5.0.0): The context option with conversationId and stepNumber is now required. Requests without these fields are rejected with error code QWED-AGENT-CTX-001.
const response = await client.verifyAgent(
agent_id,
agent_token,
'Summarize the Q3 revenue report',
{
provider: 'openai',
context: {
conversationId: 'conv_abc123',
stepNumber: 1,
},
toolSchema: {
name: 'fetch_report',
description: 'Fetch quarterly report data',
},
}
);
console.log(response.decision); // "APPROVED" | "DENIED" | "CORRECTED"
console.log(response.verification?.risk_level); // "low"
console.log(response.budget_remaining);
| Parameter | Type | Default | Description |
|---|
agentId | number | — | Agent ID from registration |
agentToken | string | — | Agent token from registration |
query | string | — | The action or query to verify |
options.context | object | — | Action context (required in v5.0.0) |
options.context.conversationId | string | — | Unique conversation/session identifier |
options.context.stepNumber | number | — | Monotonically increasing step counter (>= 1) |
options.provider | string | — | LLM provider name |
options.toolSchema | object | — | MCP tool definition — triggers server-side MCPPoisonGuard inspection |
getAgentBudget(agentId, agentToken)
Check the remaining budget for a registered agent.
const budget = await client.getAgentBudget(agent_id, agent_token);
console.log(budget.cost.current_daily_usd);
console.log(budget.requests.max_per_hour);
IRAC audit fields
All guard-related verification responses include IRAC-compliant audit fields for compliance reporting:
const result = await client.verifyProcess(reasoningTrace, { mode: 'irac' });
console.log(result.result?.['irac.issue']); // What was evaluated
console.log(result.result?.['irac.rule']); // The rule being enforced
console.log(result.result?.['irac.application']); // How the rule was applied
console.log(result.result?.['irac.conclusion']); // Final verdict
Risk codes
Security-related responses may include a risk field indicating the type of threat detected:
| Risk code | Description |
|---|
DOCUMENT_RETRIEVAL_MISMATCH | RAG chunks from wrong source document |
EXFILTRATION_ATTEMPT | Data exfiltration to unauthorized endpoint |
MCP_POISONING | Poisoned MCP tool definition detected |
TOXIC_CHAIN | Unsafe reasoning chain detected |
SOVEREIGNTY_VIOLATION | Data residency policy violation |
FABRICATED_REASONING | Fabricated reasoning path detected |
TypeScript types
import {
VerificationType,
VerificationStatus,
VerificationResponse,
BatchResponse,
AgentRegistration,
AgentVerificationResponse,
AgentDecision,
} from '@qwed-ai/sdk';
VerificationType enum
enum VerificationType {
NaturalLanguage = 'natural_language',
Math = 'math',
Logic = 'logic',
Stats = 'stats',
Fact = 'fact',
Code = 'code',
SQL = 'sql',
Image = 'image',
Reasoning = 'reasoning',
Process = 'process',
RAG = 'rag',
Security = 'security',
}
VerificationStatus enum
The VerificationStatus enum includes all possible status values returned by the verification API. Downstream consumers must handle INCONCLUSIVE, BLOCKED, and UNKNOWN as distinct outcomes.
enum VerificationStatus {
Verified = 'VERIFIED',
CorrectionNeeded = 'CORRECTION_NEEDED',
Inconclusive = 'INCONCLUSIVE', // New in v5.0.0
Blocked = 'BLOCKED', // New in v5.0.0
Unknown = 'UNKNOWN', // New in v5.0.0
Error = 'ERROR',
}
| Status | Meaning |
|---|
VERIFIED | Claim is formally verified |
CORRECTION_NEEDED | Claim is incorrect — correct value included in response |
INCONCLUSIVE | Verification succeeded on the translated expression but the LLM translation step is non-deterministic |
BLOCKED | Request blocked by security policy |
UNKNOWN | Verification could not produce a definitive result (e.g., numerical sampling fallback) |
ERROR | Internal verification error |
Error handling
import { QWEDError, QWEDAuthError, QWEDRateLimitError } from '@qwed-ai/sdk';
try {
const result = await client.verify('test');
} catch (error) {
if (error instanceof QWEDRateLimitError) {
console.log(error.retryAfter); // seconds until retry
} else if (error instanceof QWEDAuthError) {
console.log('Invalid API key');
} else if (error instanceof QWEDError) {
console.log(error.code); // "QWED-001"
console.log(error.message); // "Verification failed"
}
}