@reclaimprotocol/agent 0.1.39 → 0.1.41

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.
Files changed (51) hide show
  1. package/README.md +32 -0
  2. package/lib/config/store.d.ts +7 -0
  3. package/lib/consts.d.ts +5 -0
  4. package/lib/consts.js +10 -0
  5. package/lib/mcp/api/operations.gen.d.ts +7 -0
  6. package/lib/mcp/api/operations.gen.js +54 -4
  7. package/lib/mcp/api/tools.js +4 -0
  8. package/lib/mcp/instructions.js +10 -8
  9. package/lib/mcp/server.js +6 -1
  10. package/lib/mcp/start.js +27 -1
  11. package/lib/mcp/tools/agent/example-app.d.ts +5 -1
  12. package/lib/mcp/tools/agent/example-app.js +87 -24
  13. package/lib/mcp/tools/agent/propose.js +7 -0
  14. package/lib/mcp/tools/agent/start-integration.d.ts +2 -0
  15. package/lib/mcp/tools/agent/start-integration.js +7 -0
  16. package/lib/mcp/tools/authenticate/authenticate.js +3 -0
  17. package/lib/mcp/tools/authenticate/eth-key.d.ts +15 -0
  18. package/lib/mcp/tools/authenticate/eth-key.js +72 -6
  19. package/lib/mcp/tools/authenticate/issue-org-keypair.d.ts +3 -2
  20. package/lib/mcp/tools/authenticate/issue-org-keypair.js +83 -18
  21. package/lib/mcp/tools/authenticate/issue-org-token.js +9 -2
  22. package/lib/telemetry/index.d.ts +9 -0
  23. package/lib/telemetry/index.js +13 -0
  24. package/lib/telemetry/telemetry.d.ts +54 -0
  25. package/lib/telemetry/telemetry.js +175 -0
  26. package/lib/telemetry/tool-call.d.ts +24 -0
  27. package/lib/telemetry/tool-call.js +102 -0
  28. package/package.json +2 -2
  29. package/skill/SKILL.builder.md +30 -11
  30. package/skill/SKILL.old.md +23 -5
  31. package/skill/builder-mode.md +29 -164
  32. package/skill/old-mode.md +40 -95
  33. package/skill/start-integration.md +12 -9
  34. package/skill/verification-client-integration.md +39 -9
  35. package/src/config/store.ts +4 -0
  36. package/src/consts.ts +11 -0
  37. package/src/mcp/api/operations.gen.ts +56 -4
  38. package/src/mcp/api/tools.ts +4 -0
  39. package/src/mcp/instructions.ts +10 -8
  40. package/src/mcp/server.ts +6 -1
  41. package/src/mcp/start.ts +34 -0
  42. package/src/mcp/tools/agent/example-app.ts +97 -30
  43. package/src/mcp/tools/agent/propose.ts +8 -0
  44. package/src/mcp/tools/agent/start-integration.ts +10 -0
  45. package/src/mcp/tools/authenticate/authenticate.ts +3 -0
  46. package/src/mcp/tools/authenticate/eth-key.ts +114 -6
  47. package/src/mcp/tools/authenticate/issue-org-keypair.ts +97 -19
  48. package/src/mcp/tools/authenticate/issue-org-token.ts +13 -2
  49. package/src/telemetry/index.ts +18 -0
  50. package/src/telemetry/telemetry.ts +206 -0
  51. package/src/telemetry/tool-call.ts +115 -0
@@ -0,0 +1,115 @@
1
+ import { isProblemError } from '@reclaimprotocol/client/api'
2
+ import { currentTelemetry } from './index.ts'
3
+
4
+ const GOAL_MAX = 300
5
+ const USER_REQUEST_MAX = 500
6
+ const DOMAIN_MAX = 200
7
+ const DATA_POINTS_MAX = 20
8
+ const DATA_POINT_MAX = 200
9
+
10
+ /**
11
+ * Times a tool call and records it. Call `end()` once when the call
12
+ * finishes. It never throws, so it can't change the outcome of the call.
13
+ */
14
+ export function startToolCall(tool: string, args: unknown) {
15
+ const startedAt = Date.now()
16
+ return {
17
+ end(err?: unknown) {
18
+ try {
19
+ const telemetry = currentTelemetry()
20
+ if(!telemetry) {
21
+ return
22
+ }
23
+
24
+ const input = allowlistedInput(tool, args)
25
+ telemetry.track('tool_call', {
26
+ tool,
27
+ ok: err === undefined,
28
+ ...(err === undefined ? {} : { errorCode: errorCode(err) }),
29
+ durationMs: Date.now() - startedAt,
30
+ mode: telemetry.mode,
31
+ ...(input ? { input } : {}),
32
+ })
33
+ } catch{
34
+ // Telemetry must never affect a tool call.
35
+ }
36
+ },
37
+ }
38
+ }
39
+
40
+ /**
41
+ * A category for the error, such as `http_401`. It's never the message,
42
+ * because messages can contain URLs, tokens, or file paths.
43
+ */
44
+ export function errorCode(err: unknown): string {
45
+ if(isProblemError(err)) {
46
+ return `http_${err.output.statusCode}`
47
+ }
48
+
49
+ if(isRecord(err) && err.isBoom === true && isRecord(err.output)) {
50
+ return `http_${String(err.output.statusCode)}`
51
+ }
52
+
53
+ if(err instanceof Error) {
54
+ if(err.name === 'ZodError') {
55
+ return 'invalid_input'
56
+ }
57
+
58
+ if(err.name === 'TimeoutError' || err.name === 'AbortError') {
59
+ return 'timeout'
60
+ }
61
+ }
62
+
63
+ return 'error'
64
+ }
65
+
66
+ /**
67
+ * The only arguments Reclaim records, and only for these tools. They are the
68
+ * developer's own description of what they want to build, which tells us
69
+ * which providers to add. Every other argument is dropped here, so a new tool
70
+ * records nothing until you add it to this list on purpose.
71
+ */
72
+ export function allowlistedInput(tool: string, args: unknown) {
73
+ if(!isRecord(args)) {
74
+ return undefined
75
+ }
76
+
77
+ switch (tool) {
78
+ case 'start_integration':
79
+ return compact({
80
+ goal: cut(args.goal, GOAL_MAX),
81
+ userRequest: cut(args.userRequest, USER_REQUEST_MAX),
82
+ })
83
+ case 'propose_provider':
84
+ return compact({ userRequest: cut(args.userRequest, USER_REQUEST_MAX) })
85
+ case 'discover_resolve': {
86
+ const query = isRecord(args.query) ? args.query : {}
87
+ const dataPoints = Array.isArray(query.dataPoints)
88
+ ? query.dataPoints
89
+ .slice(0, DATA_POINTS_MAX)
90
+ .map((p) => cut(p, DATA_POINT_MAX))
91
+ .filter((p) => p !== undefined)
92
+ : undefined
93
+ return compact({
94
+ domain: cut(query.domain, DOMAIN_MAX),
95
+ dataPoints: dataPoints?.length ? dataPoints : undefined,
96
+ })
97
+ }
98
+
99
+ default:
100
+ return undefined
101
+ }
102
+ }
103
+
104
+ function cut(value: unknown, max: number): string | undefined {
105
+ return typeof value === 'string' && value ? value.slice(0, max) : undefined
106
+ }
107
+
108
+ /** Returns the object, or undefined when every field is undefined. */
109
+ function compact<T extends object>(obj: T): T | undefined {
110
+ return Object.values(obj).some((v) => v !== undefined) ? obj : undefined
111
+ }
112
+
113
+ function isRecord(value: unknown): value is Record<string, unknown> {
114
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
115
+ }