0.0.0-2 β’ Published 8 months ago
@lit-protocol/vincent-tool-sdk v0.0.0-2
vincent-tool
This library was generated with Nx.
Building
Run nx build vincent-tool to build the library.
Usage
Vincent Policy & Tool SDK
This library provides a type-safe lifecycle system for defining and composing policies and tools, with strong TypeScript inference support throughout.
π§© Core Concepts
- Policies encapsulate decision logic (precheck, evaluate, commit) and define their input/output schemas.
- Tools orchestrate multiple policies and expose
precheckandexecutelifecycle methods. - Context injection provides
allow()/deny()andsucceed()/fail()methods, with schema-safe return typing. - All inference is preserved automatically using
createVincentPolicy,createVincentToolPolicy, andcreateVincentTool.
π Calling commit() on a Policy from within a Tool
Policies can define a commit() lifecycle method to finalize changes once a tool executes successfully. These commit() functions are injected automatically into the allowedPolicies object of the ToolContext.
Example Policy (max daily spend)
import { z } from 'zod';
import { createVincentPolicy } from '@lit-protocol/vincent-tool-sdk';
import {
getAmountSpentToday,
adjustDailySpendAmount,
} from '@my-org/spending-limit-client';
export const dailySpendPolicy = createVincentPolicy({
ipfsCid: 'policy-committable',
packageName: '@lit-protocol/max-spend-policy',
toolParamsSchema: z.object({
buySomething: z.boolean(),
buyAmount: z.number(),
}),
userParamsSchema: z.object({
perBuyLimit: z.number(),
maxAmountPerDay: z.number(),
}),
evalAllowResultSchema: z.object({
ok: z.boolean(),
amountRemaining: z.number(),
amountToSpend: z.number(),
}),
evalDenyResultSchema: z.union([
z.object({
reason: z.literal('Buy amount request exceeds per-buy limit'),
buyAmount: z.number(),
}),
z.object({
reason: z.enum(['Buy amount request exceeds max amount per day']),
buyAmount: z.number(),
amountSpentToday: z.number(),
amountRemaining: z.number(),
}),
]),
commitParamsSchema: z.object({ amountSpent: z.number() }),
commitAllowResultSchema: z.object({
transactionId: z.string(),
timestamp: z.number(),
}),
commitDenyResultSchema: z.object({
errorCode: z.number().optional(),
message: z.string(),
}),
evaluate: async ({ toolParams, userParams }, context) => {
const { maxAmountPerDay, perBuyLimit } = userParams;
const { buyAmount } = toolParams;
if (buyAmount > perBuyLimit) {
return context.deny({
reason: 'Buy amount request exceeds per-buy limit',
buyAmount,
});
}
const amountSpentToday = await getAmountSpentToday(
context.delegation.delegator,
);
const amountRemaining = maxAmountPerDay - amountSpentToday;
if (buyAmount > amountRemaining) {
return context.deny({
reason: 'Buy amount request exceeds max amount per day',
amountSpentToday,
buyAmount,
amountRemaining,
});
}
return context.allow({
ok: true,
amountRemaining,
amountToSpend: buyAmount,
});
},
commit: async ({ amountSpent }, context) => {
try {
const spendCommitResult: { transactionId: string; timestamp: number } =
await adjustDailySpendAmount(context.delegation.delegator, amountSpent);
return context.allow(spendCommitResult);
} catch (e: unknown) {
if (e instanceof Error) {
if ('errorCode' in e) {
return context.deny({
errorCode: e.errorCode as number,
message: e.message,
});
} else {
return context.deny({ message: e.message });
}
}
return context.deny({ message: String(e) });
}
},
});Example Tool - Uniswap
import { z } from 'zod';
import { createVincentToolPolicy, createVincentTool } from '@lit-protocol/vincent-tool-sdk';
import { dailySpendPolicy } from '@lit-protocol/max-spend-policy';
import uniswapV3Client from '@uniswap/v3-sdk';
const toolParamsSchema = z.object({
buy: z.boolean(),
buyAmount: z.number(),
});
export const myTokenSwapTool = createVincentTool({
toolParamsSchema,
supportedPolicies: [
createVincentToolPolicy({
toolParamsSchema,
policyDef: dailySpendPolicy,
toolParameterMappings: { buy: 'buyAmount' },
}),
],
executeSuccessSchema: z.object({
message: z.string(),
amountSpent: z.number().optional(),
spendCommitResult: z
.object({
transactionId: z.string(),
timestamp: z.number(),
})
.optional(),
}),
executeFailSchema: z.object({ error: z.string(), message: z.string() }),
async execute(toolParams, { succeed, fail, policiesContext }) {
const spendPolicyContext =
policiesContext.allowedPolicies['@lit-protocol/max-spend-policy'];
const amountSpent: number = await uniswapV3Client.performSwap({});
if (spendPolicyContext) {
const spendCommitResult = await spendPolicyContext.commit({
amountSpent,
});
if (!spendCommitResult.allow) {
return fail({
error: `Policy commit denied with code ${spendCommitResult.result.errorCode}`,
message: 'Tool executed but policy commit denied',
});
}
if (spendCommitResult.allow) {
return succeed({
amountSpent,
spendCommitResult: spendCommitResult.result,
message: 'Tool executed and spending limit policy commit completed',
});
}
}
return succeed({
message: 'Tool executed for user without enabled spending limit',
});
},
});π¨βπ» Consumer Usage (with Inference!)
Note: These are low-level interfaces that are not typically used by app, tool or policy developers directly. Consumers at this level are our LIT action wrappers and the LitToolClient -- see @lit-protocol/vincent-sdk for the LitToolClient.
Tool and policy authors export their tool and policies like this:
export const myTool = createVincentTool(...);
export const limitPolicy = createVincentPolicy(...);Then, consumers can use:
import { myTool } from 'awesome-tool-package';
const typedTool = createVincentTool(myTool.__vincentToolDef);
typedTool.execute(
{ amount: 50, action: 'transfer' },
{
delegation: { delegatee: 'a', delegator: 'b' },
policiesContext: {
evaluatedPolicies: ['limit-check', 'type-check'],
allowedPolicies: {
'limit-check': { result: { approved: true } },
'type-check': { result: { allowed: true } },
},
},
},
); // β
fully typed and schema validatedπ§ Summary of Create Functions
| Function | Purpose |
|---|---|
createVincentPolicy(def) | Defines a reusable, type-safe policy with lifecycle methods |
createVincentToolPolicy({ policyDef, mappings }) | Adapts a policy to a toolβs parameter schema |
createVincentTool(def) | Composes policies and schemas into a type-safe tool with execute and precheck |
π§ Tip
Tool and policy authors should export the result of createVincentPolicy / createVincentTool()