@ton-agent-kit/plugin-identity 1.1.0 → 1.2.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.
@@ -1,126 +1,126 @@
1
- import { z } from "zod";
2
- import { Address, internal, toNano } from "@ton/core";
3
- import { defineAction, toFriendlyAddress, sendTransaction } from "@ton-agent-kit/core";
4
- import { loadAgentRegistry, saveAgentRegistry } from "../utils";
5
- import { resolveContractAddress } from "../reputation-config";
6
- import { buildRateBody, callContractGetter, lookupAgentIndex, parseAgentDataFromStack } from "../reputation-helpers";
7
-
8
- export function createGetAgentReputationAction(contractAddress?: string) {
9
- return defineAction({
10
- name: "get_agent_reputation",
11
- description:
12
- "Get the reputation score of a registered agent. Set addTask=true and success=true/false to record a task result. Works both on-chain and locally.",
13
- schema: z.object({
14
- agentId: z.string().describe("Agent ID or name to check or update"),
15
- addTask: z
16
- .union([z.boolean(), z.string()])
17
- .optional()
18
- .describe("Set to true to record a completed task"),
19
- success: z
20
- .union([z.boolean(), z.string()])
21
- .optional()
22
- .describe("If addTask is true, whether the task was successful"),
23
- }),
24
- handler: async (agent, params) => {
25
- const addTask = typeof params.addTask === "string" ? params.addTask === "true" : params.addTask;
26
- const success = typeof params.success === "string" ? params.success === "true" : params.success;
27
-
28
- const addr = resolveContractAddress(contractAddress, agent.network);
29
-
30
- // ── On-chain mode ──
31
- if (addr) {
32
- try {
33
- const apiBase =
34
- agent.network === "testnet"
35
- ? "https://testnet.tonapi.io/v2"
36
- : "https://tonapi.io/v2";
37
-
38
- // Get the actual agent name for on-chain lookup
39
- // Prefer JSON registry (has the exact name used at registration)
40
- const jsonRegistry = loadAgentRegistry();
41
- const jsonRecord = jsonRegistry[params.agentId];
42
- const agentName = jsonRecord?.name
43
- || (params.agentId.startsWith("agent_") ? params.agentId.slice(6) : params.agentId);
44
-
45
- // If rating, send Rate message
46
- if (addTask) {
47
- const body = buildRateBody(agentName, success !== false);
48
-
49
- await sendTransaction(agent, [
50
- internal({
51
- to: Address.parse(addr),
52
- value: toNano("0.03"),
53
- bounce: true,
54
- body,
55
- }),
56
- ]);
57
- }
58
-
59
- // Look up agent index by name hash
60
- const idx = await lookupAgentIndex(apiBase, addr, agentName, agent.config.TONAPI_KEY);
61
-
62
- if (idx !== null) {
63
- // Get on-chain data using index
64
- const dataRes = await callContractGetter(
65
- apiBase, addr, "agentData", [idx.toString()], agent.config.TONAPI_KEY,
66
- );
67
- const repRes = await callContractGetter(
68
- apiBase, addr, "agentReputation", [idx.toString()], agent.config.TONAPI_KEY,
69
- );
70
-
71
- const agentData = dataRes?.stack ? parseAgentDataFromStack(dataRes.stack) : null;
72
- const repScore = repRes?.stack?.[0]?.num
73
- ? Number(BigInt(repRes.stack[0].num))
74
- : 0;
75
-
76
- return {
77
- agentId: params.agentId,
78
- name: agentName,
79
- reputation: {
80
- score: repScore,
81
- totalTasks: agentData?.totalTasks || 0,
82
- successfulTasks: agentData?.successes || 0,
83
- },
84
- available: agentData?.available ?? true,
85
- onChain: true,
86
- contractAddress: addr,
87
- };
88
- }
89
-
90
- // Agent not found on-chain — fall through to JSON
91
- } catch {
92
- // Fall through to JSON
93
- }
94
- }
95
-
96
- // ── JSON fallback mode ──
97
- const registry = loadAgentRegistry();
98
- const agentRecord = registry[params.agentId];
99
- if (!agentRecord) throw new Error(`Agent not found: ${params.agentId}`);
100
-
101
- if (addTask) {
102
- agentRecord.reputation.totalTasks += 1;
103
- if (success !== false) {
104
- agentRecord.reputation.successfulTasks += 1;
105
- }
106
- agentRecord.reputation.score = Math.round(
107
- (agentRecord.reputation.successfulTasks / agentRecord.reputation.totalTasks) * 100,
108
- );
109
- saveAgentRegistry(registry);
110
- }
111
-
112
- return {
113
- agentId: params.agentId,
114
- name: agentRecord.name,
115
- address: agentRecord.address,
116
- friendlyAddress: toFriendlyAddress(Address.parse(agentRecord.address), agent.network),
117
- reputation: agentRecord.reputation,
118
- available: agentRecord.available !== false,
119
- onChain: false,
120
- registeredAt: agentRecord.registeredAt,
121
- };
122
- },
123
- });
124
- }
125
-
126
- export const getAgentReputationAction = createGetAgentReputationAction();
1
+ import { z } from "zod";
2
+ import { Address, internal, toNano } from "@ton/core";
3
+ import { defineAction, toFriendlyAddress, sendTransaction } from "@ton-agent-kit/core";
4
+ import { loadAgentRegistry, saveAgentRegistry } from "../utils";
5
+ import { resolveContractAddress } from "../reputation-config";
6
+ import { buildRateBody, callContractGetter, lookupAgentIndex, parseAgentDataFromStack } from "../reputation-helpers";
7
+
8
+ export function createGetAgentReputationAction(contractAddress?: string) {
9
+ return defineAction({
10
+ name: "get_agent_reputation",
11
+ description:
12
+ "Get the reputation score of a registered agent. Set addTask=true and success=true/false to record a task result. Works both on-chain and locally.",
13
+ schema: z.object({
14
+ agentId: z.string().describe("Agent ID or name to check or update"),
15
+ addTask: z
16
+ .union([z.boolean(), z.string()])
17
+ .optional()
18
+ .describe("Set to true to record a completed task"),
19
+ success: z
20
+ .union([z.boolean(), z.string()])
21
+ .optional()
22
+ .describe("If addTask is true, whether the task was successful"),
23
+ }),
24
+ handler: async (agent, params) => {
25
+ const addTask = typeof params.addTask === "string" ? params.addTask === "true" : params.addTask;
26
+ const success = typeof params.success === "string" ? params.success === "true" : params.success;
27
+
28
+ const addr = resolveContractAddress(contractAddress, agent.network);
29
+
30
+ // ── On-chain mode ──
31
+ if (addr) {
32
+ try {
33
+ const apiBase =
34
+ agent.network === "testnet"
35
+ ? "https://testnet.tonapi.io/v2"
36
+ : "https://tonapi.io/v2";
37
+
38
+ // Get the actual agent name for on-chain lookup
39
+ // Prefer JSON registry (has the exact name used at registration)
40
+ const jsonRegistry = loadAgentRegistry();
41
+ const jsonRecord = jsonRegistry[params.agentId];
42
+ const agentName = jsonRecord?.name
43
+ || (params.agentId.startsWith("agent_") ? params.agentId.slice(6) : params.agentId);
44
+
45
+ // If rating, send Rate message
46
+ if (addTask) {
47
+ const body = buildRateBody(agentName, success !== false);
48
+
49
+ await sendTransaction(agent, [
50
+ internal({
51
+ to: Address.parse(addr),
52
+ value: toNano("0.05"),
53
+ bounce: true,
54
+ body,
55
+ }),
56
+ ]);
57
+ }
58
+
59
+ // Look up agent index by name hash
60
+ const idx = await lookupAgentIndex(apiBase, addr, agentName, agent.config.TONAPI_KEY);
61
+
62
+ if (idx !== null) {
63
+ // Get on-chain data using index
64
+ const dataRes = await callContractGetter(
65
+ apiBase, addr, "agentData", [idx.toString()], agent.config.TONAPI_KEY,
66
+ );
67
+ const repRes = await callContractGetter(
68
+ apiBase, addr, "agentReputation", [idx.toString()], agent.config.TONAPI_KEY,
69
+ );
70
+
71
+ const agentData = dataRes?.stack ? parseAgentDataFromStack(dataRes.stack) : null;
72
+ const repScore = repRes?.stack?.[0]?.num
73
+ ? Number(BigInt(repRes.stack[0].num))
74
+ : 0;
75
+
76
+ return {
77
+ agentId: params.agentId,
78
+ name: agentName,
79
+ reputation: {
80
+ score: repScore,
81
+ totalTasks: agentData?.totalTasks || 0,
82
+ successfulTasks: agentData?.successes || 0,
83
+ },
84
+ available: agentData?.available ?? true,
85
+ onChain: true,
86
+ contractAddress: addr,
87
+ };
88
+ }
89
+
90
+ // Agent not found on-chain — fall through to JSON
91
+ } catch {
92
+ // Fall through to JSON
93
+ }
94
+ }
95
+
96
+ // ── JSON fallback mode ──
97
+ const registry = loadAgentRegistry();
98
+ const agentRecord = registry[params.agentId];
99
+ if (!agentRecord) throw new Error(`Agent not found: ${params.agentId}`);
100
+
101
+ if (addTask) {
102
+ agentRecord.reputation.totalTasks += 1;
103
+ if (success !== false) {
104
+ agentRecord.reputation.successfulTasks += 1;
105
+ }
106
+ agentRecord.reputation.score = Math.round(
107
+ (agentRecord.reputation.successfulTasks / agentRecord.reputation.totalTasks) * 100,
108
+ );
109
+ saveAgentRegistry(registry);
110
+ }
111
+
112
+ return {
113
+ agentId: params.agentId,
114
+ name: agentRecord.name,
115
+ address: agentRecord.address,
116
+ friendlyAddress: toFriendlyAddress(Address.parse(agentRecord.address), agent.network),
117
+ reputation: agentRecord.reputation,
118
+ available: agentRecord.available !== false,
119
+ onChain: false,
120
+ registeredAt: agentRecord.registeredAt,
121
+ };
122
+ },
123
+ });
124
+ }
125
+
126
+ export const getAgentReputationAction = createGetAgentReputationAction();
@@ -1,65 +1,65 @@
1
- import { z } from "zod";
2
- import { defineAction } from "@ton-agent-kit/core";
3
- import { resolveContractAddress } from "../reputation-config";
4
- import { callContractGetter, parseDisputeData } from "../reputation-helpers";
5
-
6
- export const getOpenDisputesAction = defineAction({
7
- name: "get_open_disputes",
8
- description:
9
- "Get all open (unsettled) disputes from the reputation contract. Arbiters use this to find disputes they can join and vote on.",
10
- schema: z.object({
11
- limit: z.coerce.number().optional().describe("Max disputes to return. Default 20."),
12
- }),
13
- handler: async (agent, params) => {
14
- const addr = resolveContractAddress(undefined, agent.network);
15
- if (!addr) {
16
- return { disputes: [], count: 0, message: "No reputation contract configured" };
17
- }
18
-
19
- const apiBase = agent.network === "testnet"
20
- ? "https://testnet.tonapi.io/v2"
21
- : "https://tonapi.io/v2";
22
-
23
- const limit = params.limit || 20;
24
-
25
- const countRes = await callContractGetter(apiBase, addr, "disputeCount", undefined, agent.config.TONAPI_KEY);
26
- const totalDisputes = countRes?.stack?.[0]?.num ? Number(BigInt(countRes.stack[0].num)) : 0;
27
-
28
- if (totalDisputes === 0) {
29
- return { disputes: [], count: 0, total: 0, message: "No disputes registered" };
30
- }
31
-
32
- const disputes: any[] = [];
33
- let checked = 0;
34
- for (let i = totalDisputes - 1; i >= 0 && disputes.length < limit; i--) {
35
- try {
36
- const dataRes = await callContractGetter(apiBase, addr, "disputeData", [i.toString()], agent.config.TONAPI_KEY);
37
- if (dataRes?.stack) {
38
- const dispute = parseDisputeData(dataRes.stack);
39
- if (dispute && !dispute.settled) {
40
- disputes.push({
41
- index: i,
42
- escrowAddress: dispute.escrowAddress,
43
- depositor: dispute.depositor,
44
- beneficiary: dispute.beneficiary,
45
- amount: dispute.amount,
46
- votingDeadline: new Date(dispute.votingDeadline * 1000).toISOString(),
47
- isExpired: Date.now() / 1000 > dispute.votingDeadline,
48
- });
49
- }
50
- }
51
- } catch {}
52
- checked++;
53
- if (checked > 100) break;
54
- }
55
-
56
- return {
57
- disputes,
58
- count: disputes.length,
59
- total: totalDisputes,
60
- onChain: true,
61
- contractAddress: addr,
62
- message: `Found ${disputes.length} open dispute(s)`,
63
- };
64
- },
65
- });
1
+ import { z } from "zod";
2
+ import { defineAction } from "@ton-agent-kit/core";
3
+ import { resolveContractAddress } from "../reputation-config";
4
+ import { callContractGetter, parseDisputeData } from "../reputation-helpers";
5
+
6
+ export const getOpenDisputesAction = defineAction({
7
+ name: "get_open_disputes",
8
+ description:
9
+ "Get all open (unsettled) disputes from the reputation contract. Arbiters use this to find disputes they can join and vote on.",
10
+ schema: z.object({
11
+ limit: z.coerce.number().optional().describe("Max disputes to return. Default 20."),
12
+ }),
13
+ handler: async (agent, params) => {
14
+ const addr = resolveContractAddress(undefined, agent.network);
15
+ if (!addr) {
16
+ return { disputes: [], count: 0, message: "No reputation contract configured" };
17
+ }
18
+
19
+ const apiBase = agent.network === "testnet"
20
+ ? "https://testnet.tonapi.io/v2"
21
+ : "https://tonapi.io/v2";
22
+
23
+ const limit = params.limit || 20;
24
+
25
+ const countRes = await callContractGetter(apiBase, addr, "disputeCount", undefined, agent.config.TONAPI_KEY);
26
+ const totalDisputes = countRes?.stack?.[0]?.num ? Number(BigInt(countRes.stack[0].num)) : 0;
27
+
28
+ if (totalDisputes === 0) {
29
+ return { disputes: [], count: 0, total: 0, message: "No disputes registered" };
30
+ }
31
+
32
+ const disputes: any[] = [];
33
+ let checked = 0;
34
+ for (let i = totalDisputes - 1; i >= 0 && disputes.length < limit; i--) {
35
+ try {
36
+ const dataRes = await callContractGetter(apiBase, addr, "disputeData", [i.toString()], agent.config.TONAPI_KEY);
37
+ if (dataRes?.stack) {
38
+ const dispute = parseDisputeData(dataRes.stack);
39
+ if (dispute && !dispute.settled) {
40
+ disputes.push({
41
+ index: i,
42
+ escrowAddress: dispute.escrowAddress,
43
+ depositor: dispute.depositor,
44
+ beneficiary: dispute.beneficiary,
45
+ amount: dispute.amount,
46
+ votingDeadline: new Date(dispute.votingDeadline * 1000).toISOString(),
47
+ isExpired: Date.now() / 1000 > dispute.votingDeadline,
48
+ });
49
+ }
50
+ }
51
+ } catch {}
52
+ checked++;
53
+ if (checked > 100) break;
54
+ }
55
+
56
+ return {
57
+ disputes,
58
+ count: disputes.length,
59
+ total: totalDisputes,
60
+ onChain: true,
61
+ contractAddress: addr,
62
+ message: `Found ${disputes.length} open dispute(s)`,
63
+ };
64
+ },
65
+ });
@@ -1,114 +1,114 @@
1
- import { z } from "zod";
2
- import { defineAction } from "@ton-agent-kit/core";
3
-
4
- export const processPendingRatingsAction = defineAction({
5
- name: "process_pending_ratings",
6
- description:
7
- "Process pending reputation ratings left by completed escrow deals. Each escrow completion (release, auto-release, refund) creates pending ratings for both buyer and seller. Call this to review or auto-submit them.",
8
- schema: z.object({
9
- autoSubmit: z
10
- .boolean()
11
- .optional()
12
- .describe("Automatically submit all pending ratings with suggested success values. Defaults to false (returns pending list for review)."),
13
- }),
14
- handler: async (agent, params) => {
15
- // Load pending ratings from memory
16
- let entries: any[] = [];
17
- try {
18
- const r = await (agent as any).runAction("list_context", {
19
- namespace: "pending_ratings",
20
- });
21
- entries = r.entries || [];
22
- } catch {
23
- return {
24
- processed: 0,
25
- pending: 0,
26
- ratings: [],
27
- message: "Memory plugin not available. Cannot process pending ratings.",
28
- };
29
- }
30
-
31
- if (entries.length === 0) {
32
- return {
33
- processed: 0,
34
- pending: 0,
35
- ratings: [],
36
- message: "No pending ratings to process.",
37
- };
38
- }
39
-
40
- // Parse entries
41
- const pending: any[] = [];
42
- for (const entry of entries) {
43
- try {
44
- const data = JSON.parse(entry.value);
45
- pending.push({ ...data, memoryKey: entry.key });
46
- } catch {
47
- continue;
48
- }
49
- }
50
-
51
- if (!params.autoSubmit) {
52
- return {
53
- processed: 0,
54
- pending: pending.length,
55
- ratings: pending.map((p) => ({
56
- escrowId: p.escrowId,
57
- raterRole: p.raterRole,
58
- targetAddress: p.targetAddress,
59
- suggestedSuccess: p.suggestedSuccess,
60
- escrowOutcome: p.escrowOutcome,
61
- })),
62
- message: `${pending.length} pending rating(s) found. Set autoSubmit=true to submit them.`,
63
- };
64
- }
65
-
66
- // Auto-submit ratings
67
- let processed = 0;
68
- const results: any[] = [];
69
-
70
- for (const rating of pending) {
71
- try {
72
- // Find the target agent ID by address match in the registry
73
- // Use a simple name-based lookup: the target address is stored in the rating
74
- await (agent as any).runAction("get_agent_reputation", {
75
- agentId: rating.targetAddress,
76
- addTask: true,
77
- success: rating.suggestedSuccess,
78
- });
79
-
80
- // Delete the processed rating from memory
81
- try {
82
- await (agent as any).runAction("delete_context", {
83
- key: rating.memoryKey,
84
- namespace: "pending_ratings",
85
- });
86
- } catch {}
87
-
88
- processed++;
89
- results.push({
90
- escrowId: rating.escrowId,
91
- raterRole: rating.raterRole,
92
- targetAddress: rating.targetAddress,
93
- success: rating.suggestedSuccess,
94
- submitted: true,
95
- });
96
- } catch (err: any) {
97
- results.push({
98
- escrowId: rating.escrowId,
99
- raterRole: rating.raterRole,
100
- targetAddress: rating.targetAddress,
101
- submitted: false,
102
- error: err.message,
103
- });
104
- }
105
- }
106
-
107
- return {
108
- processed,
109
- pending: pending.length - processed,
110
- ratings: results,
111
- message: `Processed ${processed}/${pending.length} ratings.`,
112
- };
113
- },
114
- });
1
+ import { z } from "zod";
2
+ import { defineAction } from "@ton-agent-kit/core";
3
+
4
+ export const processPendingRatingsAction = defineAction({
5
+ name: "process_pending_ratings",
6
+ description:
7
+ "Process pending reputation ratings left by completed escrow deals. Each escrow completion (release, auto-release, refund) creates pending ratings for both buyer and seller. Call this to review or auto-submit them.",
8
+ schema: z.object({
9
+ autoSubmit: z
10
+ .boolean()
11
+ .optional()
12
+ .describe("Automatically submit all pending ratings with suggested success values. Defaults to false (returns pending list for review)."),
13
+ }),
14
+ handler: async (agent, params) => {
15
+ // Load pending ratings from memory
16
+ let entries: any[] = [];
17
+ try {
18
+ const r = await (agent as any).runAction("list_context", {
19
+ namespace: "pending_ratings",
20
+ });
21
+ entries = r.entries || [];
22
+ } catch {
23
+ return {
24
+ processed: 0,
25
+ pending: 0,
26
+ ratings: [],
27
+ message: "Memory plugin not available. Cannot process pending ratings.",
28
+ };
29
+ }
30
+
31
+ if (entries.length === 0) {
32
+ return {
33
+ processed: 0,
34
+ pending: 0,
35
+ ratings: [],
36
+ message: "No pending ratings to process.",
37
+ };
38
+ }
39
+
40
+ // Parse entries
41
+ const pending: any[] = [];
42
+ for (const entry of entries) {
43
+ try {
44
+ const data = JSON.parse(entry.value);
45
+ pending.push({ ...data, memoryKey: entry.key });
46
+ } catch {
47
+ continue;
48
+ }
49
+ }
50
+
51
+ if (!params.autoSubmit) {
52
+ return {
53
+ processed: 0,
54
+ pending: pending.length,
55
+ ratings: pending.map((p) => ({
56
+ escrowId: p.escrowId,
57
+ raterRole: p.raterRole,
58
+ targetAddress: p.targetAddress,
59
+ suggestedSuccess: p.suggestedSuccess,
60
+ escrowOutcome: p.escrowOutcome,
61
+ })),
62
+ message: `${pending.length} pending rating(s) found. Set autoSubmit=true to submit them.`,
63
+ };
64
+ }
65
+
66
+ // Auto-submit ratings
67
+ let processed = 0;
68
+ const results: any[] = [];
69
+
70
+ for (const rating of pending) {
71
+ try {
72
+ // Find the target agent ID by address match in the registry
73
+ // Use a simple name-based lookup: the target address is stored in the rating
74
+ await (agent as any).runAction("get_agent_reputation", {
75
+ agentId: rating.targetAddress,
76
+ addTask: true,
77
+ success: rating.suggestedSuccess,
78
+ });
79
+
80
+ // Delete the processed rating from memory
81
+ try {
82
+ await (agent as any).runAction("delete_context", {
83
+ key: rating.memoryKey,
84
+ namespace: "pending_ratings",
85
+ });
86
+ } catch {}
87
+
88
+ processed++;
89
+ results.push({
90
+ escrowId: rating.escrowId,
91
+ raterRole: rating.raterRole,
92
+ targetAddress: rating.targetAddress,
93
+ success: rating.suggestedSuccess,
94
+ submitted: true,
95
+ });
96
+ } catch (err: any) {
97
+ results.push({
98
+ escrowId: rating.escrowId,
99
+ raterRole: rating.raterRole,
100
+ targetAddress: rating.targetAddress,
101
+ submitted: false,
102
+ error: err.message,
103
+ });
104
+ }
105
+ }
106
+
107
+ return {
108
+ processed,
109
+ pending: pending.length - processed,
110
+ ratings: results,
111
+ message: `Processed ${processed}/${pending.length} ratings.`,
112
+ };
113
+ },
114
+ });