digital-tools 2.1.3 → 2.3.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.
Files changed (294) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +2 -0
  3. package/dist/client.d.ts +109 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +69 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/define.d.ts +2 -2
  8. package/dist/define.d.ts.map +1 -1
  9. package/dist/define.js +21 -11
  10. package/dist/define.js.map +1 -1
  11. package/dist/function-ref.d.ts +229 -0
  12. package/dist/function-ref.d.ts.map +1 -0
  13. package/dist/function-ref.js +28 -0
  14. package/dist/function-ref.js.map +1 -0
  15. package/dist/function-sugar.d.ts +57 -0
  16. package/dist/function-sugar.d.ts.map +1 -0
  17. package/dist/function-sugar.js +79 -0
  18. package/dist/function-sugar.js.map +1 -0
  19. package/dist/index.d.ts +10 -3
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +24 -4
  22. package/dist/index.js.map +1 -1
  23. package/dist/providers/analytics/mixpanel.d.ts.map +1 -1
  24. package/dist/providers/analytics/mixpanel.js +21 -18
  25. package/dist/providers/analytics/mixpanel.js.map +1 -1
  26. package/dist/providers/calendar/cal-com.d.ts.map +1 -1
  27. package/dist/providers/calendar/cal-com.js +10 -10
  28. package/dist/providers/calendar/cal-com.js.map +1 -1
  29. package/dist/providers/calendar/google-calendar.d.ts.map +1 -1
  30. package/dist/providers/calendar/google-calendar.js +4 -4
  31. package/dist/providers/calendar/google-calendar.js.map +1 -1
  32. package/dist/providers/crm/hubspot.d.ts.map +1 -1
  33. package/dist/providers/crm/hubspot.js +107 -85
  34. package/dist/providers/crm/hubspot.js.map +1 -1
  35. package/dist/providers/development/github.d.ts.map +1 -1
  36. package/dist/providers/development/github.js +40 -43
  37. package/dist/providers/development/github.js.map +1 -1
  38. package/dist/providers/ecommerce/shopify.d.ts.map +1 -1
  39. package/dist/providers/ecommerce/shopify.js +79 -62
  40. package/dist/providers/ecommerce/shopify.js.map +1 -1
  41. package/dist/providers/email/resend.d.ts.map +1 -1
  42. package/dist/providers/email/resend.js +20 -16
  43. package/dist/providers/email/resend.js.map +1 -1
  44. package/dist/providers/email/sendgrid.d.ts.map +1 -1
  45. package/dist/providers/email/sendgrid.js +12 -9
  46. package/dist/providers/email/sendgrid.js.map +1 -1
  47. package/dist/providers/finance/stripe.d.ts.map +1 -1
  48. package/dist/providers/finance/stripe.js +44 -42
  49. package/dist/providers/finance/stripe.js.map +1 -1
  50. package/dist/providers/forms/typeform.d.ts.map +1 -1
  51. package/dist/providers/forms/typeform.js +68 -58
  52. package/dist/providers/forms/typeform.js.map +1 -1
  53. package/dist/providers/knowledge/notion.d.ts.map +1 -1
  54. package/dist/providers/knowledge/notion.js +75 -41
  55. package/dist/providers/knowledge/notion.js.map +1 -1
  56. package/dist/providers/marketing/mailchimp.d.ts.map +1 -1
  57. package/dist/providers/marketing/mailchimp.js +74 -61
  58. package/dist/providers/marketing/mailchimp.js.map +1 -1
  59. package/dist/providers/media/cloudinary.d.ts.map +1 -1
  60. package/dist/providers/media/cloudinary.js +30 -28
  61. package/dist/providers/media/cloudinary.js.map +1 -1
  62. package/dist/providers/messaging/slack.d.ts.map +1 -1
  63. package/dist/providers/messaging/slack.js +75 -58
  64. package/dist/providers/messaging/slack.js.map +1 -1
  65. package/dist/providers/messaging/twilio-sms.d.ts.map +1 -1
  66. package/dist/providers/messaging/twilio-sms.js +33 -15
  67. package/dist/providers/messaging/twilio-sms.js.map +1 -1
  68. package/dist/providers/project-management/linear.d.ts.map +1 -1
  69. package/dist/providers/project-management/linear.js +31 -27
  70. package/dist/providers/project-management/linear.js.map +1 -1
  71. package/dist/providers/spreadsheet/google-sheets.d.ts.map +1 -1
  72. package/dist/providers/spreadsheet/google-sheets.js +21 -18
  73. package/dist/providers/spreadsheet/google-sheets.js.map +1 -1
  74. package/dist/providers/spreadsheet/xlsx.d.ts.map +1 -1
  75. package/dist/providers/spreadsheet/xlsx.js +4 -4
  76. package/dist/providers/spreadsheet/xlsx.js.map +1 -1
  77. package/dist/providers/storage/index.js +1 -0
  78. package/dist/providers/storage/index.js.map +1 -1
  79. package/dist/providers/storage/s3.d.ts.map +1 -1
  80. package/dist/providers/storage/s3.js +36 -27
  81. package/dist/providers/storage/s3.js.map +1 -1
  82. package/dist/providers/support/zendesk.d.ts.map +1 -1
  83. package/dist/providers/support/zendesk.js +24 -25
  84. package/dist/providers/support/zendesk.js.map +1 -1
  85. package/dist/providers/tasks/todoist.d.ts.map +1 -1
  86. package/dist/providers/tasks/todoist.js +18 -18
  87. package/dist/providers/tasks/todoist.js.map +1 -1
  88. package/dist/providers/video-conferencing/google-meet.d.ts.map +1 -1
  89. package/dist/providers/video-conferencing/google-meet.js +11 -11
  90. package/dist/providers/video-conferencing/google-meet.js.map +1 -1
  91. package/dist/providers/video-conferencing/jitsi.js +14 -14
  92. package/dist/providers/video-conferencing/jitsi.js.map +1 -1
  93. package/dist/providers/video-conferencing/teams.d.ts.map +1 -1
  94. package/dist/providers/video-conferencing/teams.js +9 -7
  95. package/dist/providers/video-conferencing/teams.js.map +1 -1
  96. package/dist/providers/video-conferencing/zoom.d.ts.map +1 -1
  97. package/dist/providers/video-conferencing/zoom.js +26 -24
  98. package/dist/providers/video-conferencing/zoom.js.map +1 -1
  99. package/dist/tools/data.d.ts.map +1 -1
  100. package/dist/tools/data.js +5 -12
  101. package/dist/tools/data.js.map +1 -1
  102. package/dist/tools/index.d.ts +1 -0
  103. package/dist/tools/index.d.ts.map +1 -1
  104. package/dist/tools/index.js +1 -0
  105. package/dist/tools/index.js.map +1 -1
  106. package/dist/tools/system.d.ts +289 -0
  107. package/dist/tools/system.d.ts.map +1 -0
  108. package/dist/tools/system.js +752 -0
  109. package/dist/tools/system.js.map +1 -0
  110. package/dist/tools/web.d.ts.map +1 -1
  111. package/dist/tools/web.js +22 -10
  112. package/dist/tools/web.js.map +1 -1
  113. package/dist/track-record.d.ts +101 -0
  114. package/dist/track-record.d.ts.map +1 -0
  115. package/dist/track-record.js +17 -0
  116. package/dist/track-record.js.map +1 -0
  117. package/dist/types.d.ts +210 -9
  118. package/dist/types.d.ts.map +1 -1
  119. package/dist/verb-registration.d.ts +122 -0
  120. package/dist/verb-registration.d.ts.map +1 -0
  121. package/dist/verb-registration.js +176 -0
  122. package/dist/verb-registration.js.map +1 -0
  123. package/dist/worker.d.ts +93 -0
  124. package/dist/worker.d.ts.map +1 -0
  125. package/dist/worker.js +315 -0
  126. package/dist/worker.js.map +1 -0
  127. package/dist/wrap.d.ts +89 -0
  128. package/dist/wrap.d.ts.map +1 -0
  129. package/dist/wrap.js +225 -0
  130. package/dist/wrap.js.map +1 -0
  131. package/package.json +31 -14
  132. package/src/client.ts +136 -0
  133. package/src/define.ts +30 -24
  134. package/src/function-ref.ts +264 -0
  135. package/src/function-sugar.ts +134 -0
  136. package/src/index.ts +132 -10
  137. package/src/providers/analytics/mixpanel.ts +19 -18
  138. package/src/providers/calendar/cal-com.ts +29 -18
  139. package/src/providers/calendar/google-calendar.ts +20 -14
  140. package/src/providers/crm/hubspot.ts +225 -99
  141. package/src/providers/development/github.ts +206 -135
  142. package/src/providers/ecommerce/shopify.ts +250 -89
  143. package/src/providers/email/resend.ts +101 -28
  144. package/src/providers/email/sendgrid.ts +12 -9
  145. package/src/providers/finance/stripe.ts +128 -49
  146. package/src/providers/forms/typeform.ts +74 -58
  147. package/src/providers/knowledge/notion.ts +340 -88
  148. package/src/providers/marketing/mailchimp.ts +86 -70
  149. package/src/providers/media/cloudinary.ts +99 -41
  150. package/src/providers/messaging/slack.ts +283 -85
  151. package/src/providers/messaging/twilio-sms.ts +35 -15
  152. package/src/providers/project-management/linear.ts +143 -55
  153. package/src/providers/spreadsheet/google-sheets.ts +222 -56
  154. package/src/providers/spreadsheet/xlsx.ts +47 -16
  155. package/src/providers/storage/s3.ts +119 -47
  156. package/src/providers/support/zendesk.ts +196 -46
  157. package/src/providers/tasks/todoist.ts +20 -26
  158. package/src/providers/video-conferencing/google-meet.ts +17 -20
  159. package/src/providers/video-conferencing/jitsi.ts +14 -14
  160. package/src/providers/video-conferencing/teams.ts +14 -13
  161. package/src/providers/video-conferencing/zoom.ts +54 -49
  162. package/src/tools/data.ts +6 -16
  163. package/src/tools/index.ts +1 -0
  164. package/src/tools/system.ts +887 -0
  165. package/src/tools/web.ts +22 -10
  166. package/src/track-record.ts +106 -0
  167. package/src/types.ts +241 -13
  168. package/src/verb-registration.ts +197 -0
  169. package/src/worker.ts +370 -0
  170. package/src/wrap.ts +260 -0
  171. package/test/client.test.ts +146 -0
  172. package/test/communication-tools-extended.test.ts +734 -0
  173. package/test/data-tools-extended.test.ts +743 -0
  174. package/test/define-extended.test.ts +819 -0
  175. package/test/define.test.ts +150 -41
  176. package/test/entities.test.ts +623 -0
  177. package/test/extended-entities.test.ts +1228 -0
  178. package/test/provider-implementations.test.ts +725 -0
  179. package/test/provider-registry-extended.test.ts +583 -0
  180. package/test/providers/google-sheets.test.ts +851 -0
  181. package/test/providers/helpers.ts +554 -0
  182. package/test/providers/hubspot.test.ts +576 -0
  183. package/test/providers/slack.test.ts +932 -0
  184. package/test/providers/stripe.test.ts +701 -0
  185. package/test/providers.test.ts +578 -0
  186. package/test/system-tools-extended.test.ts +632 -0
  187. package/test/system.test.ts +673 -0
  188. package/test/tools.test.ts +15 -11
  189. package/test/types.test.ts +402 -0
  190. package/test/verb-registration.test.ts +395 -0
  191. package/test/web-tools.test.ts +553 -0
  192. package/test/worker-extended.test.ts +699 -0
  193. package/test/worker.test.ts +576 -0
  194. package/test/wrap.test.ts +366 -0
  195. package/tsconfig.json +3 -13
  196. package/vitest.config.ts +37 -0
  197. package/wrangler.jsonc +9 -0
  198. package/.turbo/turbo-build.log +0 -4
  199. package/LICENSE +0 -21
  200. package/dist/providers/voice/vapi.d.ts +0 -27
  201. package/dist/providers/voice/vapi.d.ts.map +0 -1
  202. package/dist/providers/voice/vapi.js +0 -440
  203. package/dist/providers/voice/vapi.js.map +0 -1
  204. package/src/define.js +0 -259
  205. package/src/entities/advertising.js +0 -999
  206. package/src/entities/ai.js +0 -756
  207. package/src/entities/analytics.js +0 -1588
  208. package/src/entities/automation.js +0 -601
  209. package/src/entities/communication.js +0 -1150
  210. package/src/entities/crm.js +0 -1386
  211. package/src/entities/design.js +0 -546
  212. package/src/entities/development.js +0 -2212
  213. package/src/entities/document.js +0 -874
  214. package/src/entities/ecommerce.js +0 -1429
  215. package/src/entities/experiment.js +0 -1039
  216. package/src/entities/finance.js +0 -3478
  217. package/src/entities/forms.js +0 -1892
  218. package/src/entities/hr.js +0 -661
  219. package/src/entities/identity.js +0 -997
  220. package/src/entities/index.js +0 -282
  221. package/src/entities/infrastructure.js +0 -1153
  222. package/src/entities/knowledge.js +0 -1438
  223. package/src/entities/marketing.js +0 -1610
  224. package/src/entities/media.js +0 -1634
  225. package/src/entities/notification.js +0 -1199
  226. package/src/entities/presentation.js +0 -1274
  227. package/src/entities/productivity.js +0 -1317
  228. package/src/entities/project-management.js +0 -1136
  229. package/src/entities/recruiting.js +0 -736
  230. package/src/entities/shipping.js +0 -509
  231. package/src/entities/signature.js +0 -1102
  232. package/src/entities/site.js +0 -222
  233. package/src/entities/spreadsheet.js +0 -1341
  234. package/src/entities/storage.js +0 -1198
  235. package/src/entities/support.js +0 -1166
  236. package/src/entities/video-conferencing.js +0 -1750
  237. package/src/entities/video.js +0 -950
  238. package/src/entities.js +0 -1663
  239. package/src/index.js +0 -74
  240. package/src/providers/analytics/index.js +0 -17
  241. package/src/providers/analytics/mixpanel.js +0 -255
  242. package/src/providers/calendar/cal-com.js +0 -303
  243. package/src/providers/calendar/google-calendar.js +0 -335
  244. package/src/providers/calendar/index.js +0 -20
  245. package/src/providers/crm/hubspot.js +0 -566
  246. package/src/providers/crm/index.js +0 -17
  247. package/src/providers/development/github.js +0 -472
  248. package/src/providers/development/index.js +0 -17
  249. package/src/providers/ecommerce/index.js +0 -17
  250. package/src/providers/ecommerce/shopify.js +0 -378
  251. package/src/providers/email/index.js +0 -20
  252. package/src/providers/email/resend.js +0 -258
  253. package/src/providers/email/sendgrid.js +0 -161
  254. package/src/providers/finance/index.js +0 -17
  255. package/src/providers/finance/stripe.js +0 -549
  256. package/src/providers/forms/index.js +0 -17
  257. package/src/providers/forms/typeform.js +0 -500
  258. package/src/providers/index.js +0 -123
  259. package/src/providers/knowledge/index.js +0 -17
  260. package/src/providers/knowledge/notion.js +0 -389
  261. package/src/providers/marketing/index.js +0 -17
  262. package/src/providers/marketing/mailchimp.js +0 -443
  263. package/src/providers/media/cloudinary.js +0 -318
  264. package/src/providers/media/index.js +0 -17
  265. package/src/providers/messaging/index.js +0 -20
  266. package/src/providers/messaging/slack.js +0 -393
  267. package/src/providers/messaging/twilio-sms.js +0 -249
  268. package/src/providers/project-management/index.js +0 -17
  269. package/src/providers/project-management/linear.js +0 -575
  270. package/src/providers/registry.js +0 -86
  271. package/src/providers/spreadsheet/google-sheets.js +0 -375
  272. package/src/providers/spreadsheet/index.js +0 -20
  273. package/src/providers/spreadsheet/xlsx.js +0 -423
  274. package/src/providers/storage/index.js +0 -24
  275. package/src/providers/storage/s3.js +0 -419
  276. package/src/providers/support/index.js +0 -17
  277. package/src/providers/support/zendesk.js +0 -373
  278. package/src/providers/tasks/index.js +0 -17
  279. package/src/providers/tasks/todoist.js +0 -286
  280. package/src/providers/types.js +0 -9
  281. package/src/providers/video-conferencing/google-meet.js +0 -286
  282. package/src/providers/video-conferencing/index.js +0 -31
  283. package/src/providers/video-conferencing/jitsi.js +0 -254
  284. package/src/providers/video-conferencing/teams.js +0 -270
  285. package/src/providers/video-conferencing/zoom.js +0 -332
  286. package/src/registry.js +0 -128
  287. package/src/tools/communication.js +0 -184
  288. package/src/tools/data.js +0 -205
  289. package/src/tools/index.js +0 -11
  290. package/src/tools/web.js +0 -137
  291. package/src/types.js +0 -10
  292. package/test/define.test.js +0 -306
  293. package/test/registry.test.js +0 -357
  294. package/test/tools.test.js +0 -363
package/src/tools/web.ts CHANGED
@@ -23,7 +23,11 @@ export const fetchUrl = defineTool<
23
23
  type: 'object',
24
24
  properties: {
25
25
  url: { type: 'string', description: 'URL to fetch' },
26
- method: { type: 'string', description: 'HTTP method (default: GET)', enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] },
26
+ method: {
27
+ type: 'string',
28
+ description: 'HTTP method (default: GET)',
29
+ enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
30
+ },
27
31
  headers: { type: 'object', description: 'Request headers' },
28
32
  body: { type: 'string', description: 'Request body (for POST/PUT/PATCH)' },
29
33
  },
@@ -32,8 +36,8 @@ export const fetchUrl = defineTool<
32
36
  handler: async (input) => {
33
37
  const response = await fetch(input.url, {
34
38
  method: input.method || 'GET',
35
- headers: input.headers,
36
- body: input.body,
39
+ ...(input.headers !== undefined && { headers: input.headers }),
40
+ ...(input.body !== undefined && { body: input.body }),
37
41
  })
38
42
 
39
43
  const headers: Record<string, string> = {}
@@ -75,21 +79,26 @@ export const parseHtml = defineTool<
75
79
  },
76
80
  handler: async (input) => {
77
81
  // Basic HTML parsing without DOM (would use cheerio or jsdom in production)
78
- const text = input.html.replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim()
82
+ const text = input.html
83
+ .replace(/<[^>]*>/g, ' ')
84
+ .replace(/\s+/g, ' ')
85
+ .trim()
79
86
 
80
87
  // Extract links
81
88
  const linkRegex = /href="([^"]+)"/g
82
89
  const links: string[] = []
83
90
  let match
84
91
  while ((match = linkRegex.exec(input.html)) !== null) {
85
- links.push(match[1])
92
+ if (match[1] !== undefined) {
93
+ links.push(match[1])
94
+ }
86
95
  }
87
96
 
88
97
  // Extract images
89
98
  const imgRegex = /src="([^"]+)"/g
90
99
  const images: string[] = []
91
100
  while ((match = imgRegex.exec(input.html)) !== null) {
92
- if (match[1].match(/\.(jpg|jpeg|png|gif|webp|svg)/i)) {
101
+ if (match[1] !== undefined && match[1].match(/\.(jpg|jpeg|png|gif|webp|svg)/i)) {
93
102
  images.push(match[1])
94
103
  }
95
104
  }
@@ -127,12 +136,13 @@ export const readUrl = defineTool<
127
136
 
128
137
  // Extract title
129
138
  const titleMatch = html.match(/<title[^>]*>([^<]+)<\/title>/i)
130
- const title = titleMatch ? titleMatch[1].trim() : ''
139
+ const title = titleMatch && titleMatch[1] ? titleMatch[1].trim() : ''
131
140
 
132
141
  // Extract body text
133
142
  const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i)
134
- const body = bodyMatch ? bodyMatch[1] : html
135
- const text = body.replace(/<script[\s\S]*?<\/script>/gi, '')
143
+ const body = bodyMatch && bodyMatch[1] ? bodyMatch[1] : html
144
+ const text = body
145
+ .replace(/<script[\s\S]*?<\/script>/gi, '')
136
146
  .replace(/<style[\s\S]*?<\/style>/gi, '')
137
147
  .replace(/<[^>]*>/g, ' ')
138
148
  .replace(/\s+/g, ' ')
@@ -143,7 +153,9 @@ export const readUrl = defineTool<
143
153
  const links: string[] = []
144
154
  let match
145
155
  while ((match = linkRegex.exec(html)) !== null) {
146
- links.push(match[1])
156
+ if (match[1] !== undefined) {
157
+ links.push(match[1])
158
+ }
147
159
  }
148
160
 
149
161
  return { title, text: text.slice(0, 10000), links: [...new Set(links)] }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Track Record + Agent Mode + Promotion Policy (v3 §6 — Function-as-typed-primitive)
3
+ *
4
+ * Earned-autonomy primitives shared across `digital-tools` Function refs and
5
+ * (later) `digital-workers`. A Function or Worker accumulates a {@link TrackRecord}
6
+ * over time; a {@link PromotionPolicy} declares the threshold rules that move a
7
+ * Function up or down the {@link AgentMode} ladder (manual → supervised →
8
+ * autonomous, and back).
9
+ *
10
+ * These types live in `digital-tools` because the Function discriminated union
11
+ * is the first consumer; `digital-workers` re-exports the same types when it
12
+ * lands so per-Worker autonomy and per-Function autonomy use one vocabulary.
13
+ *
14
+ * @packageDocumentation
15
+ */
16
+
17
+ import type { Money } from 'autonomous-finance'
18
+
19
+ /**
20
+ * Operating mode of an agentic Function (or Worker).
21
+ *
22
+ * - `manual` — every invocation requires a human to initiate.
23
+ * - `supervised` — runs autonomously but every output is reviewed before
24
+ * being released downstream (gated on human sign-off).
25
+ * - `autonomous` — runs and releases without per-invocation review;
26
+ * oversight is post-hoc and sample-based.
27
+ */
28
+ export type AgentMode = 'manual' | 'supervised' | 'autonomous'
29
+
30
+ /**
31
+ * Direction of the most recent measured trend in a {@link TrackRecord}.
32
+ */
33
+ export type TrendDirection = 'improving' | 'stable' | 'declining'
34
+
35
+ /**
36
+ * Quality + cost + oversight signal accumulated over a Function or Worker's
37
+ * recent invocations. Drives {@link PromotionPolicy} thresholds.
38
+ *
39
+ * All fields are present for any Function that has been invoked at least once;
40
+ * the registry materialises a zero-sample record on first registration so
41
+ * thresholds always have a value to compare against.
42
+ */
43
+ export interface TrackRecord {
44
+ /** Fraction of invocations that met the OutcomeContract (0–1). */
45
+ accuracy: number
46
+ /** Number of invocations the record summarises. */
47
+ samples: number
48
+ /** Direction of the most recent measured trend. */
49
+ trend: TrendDirection
50
+ /** ISO-8601 timestamp of the most recent sample. */
51
+ lastUpdated: string
52
+ /** Average cost per successful invocation; absent until at least one success. */
53
+ costPerSuccess?: Money
54
+ /**
55
+ * Fraction of supervised invocations whose human reviewer overrode the
56
+ * Function's output (0–1). High values indicate the Function is not ready
57
+ * for promotion to `autonomous`.
58
+ */
59
+ reviewerOverrideRate?: number
60
+ /**
61
+ * Composite 0–100 score combining accuracy / cost / override rate. Used by
62
+ * downstream catalog UI when ranking Functions; the precise formula lives
63
+ * in `ai-evaluate` so it can evolve without a type change here.
64
+ */
65
+ digitalScore?: number
66
+ }
67
+
68
+ /**
69
+ * Threshold-gated rule that promotes or demotes a Function between
70
+ * {@link AgentMode} values based on its accumulated {@link TrackRecord}.
71
+ *
72
+ * Predicates are expressed as strings so they can be persisted alongside the
73
+ * Function definition and re-evaluated against fresh records without a code
74
+ * change. The evaluator (lives in `ai-evaluate`) parses them against a
75
+ * `TrackRecord` plus invocation context.
76
+ */
77
+ export interface PromotionRule {
78
+ /**
79
+ * String predicate evaluated against the {@link TrackRecord} (and optionally
80
+ * elapsed time / sample size). Examples:
81
+ * - `'accuracy >= 0.95 && samples >= 100'`
82
+ * - `'reviewerOverrideRate < 0.05 && trend === "improving"'`
83
+ */
84
+ when: string
85
+ /** Mode to move the Function to when {@link when} holds. */
86
+ to: AgentMode
87
+ /** Optional human-readable description of the rule's intent. */
88
+ rationale?: string
89
+ }
90
+
91
+ /**
92
+ * Declarative ladder describing when a Function may climb to a more
93
+ * autonomous {@link AgentMode} and when it must step back down.
94
+ *
95
+ * `evaluate` sets the cadence at which the policy is re-checked against the
96
+ * latest {@link TrackRecord}; `'continuous'` re-evaluates after every
97
+ * invocation, `'daily'` / `'weekly'` use a scheduled job.
98
+ */
99
+ export interface PromotionPolicy {
100
+ /** Rules that move the Function up the autonomy ladder. */
101
+ promote: PromotionRule[]
102
+ /** Rules that move the Function down the autonomy ladder. */
103
+ demote: PromotionRule[]
104
+ /** Cadence at which the policy is re-evaluated. */
105
+ evaluate: 'continuous' | 'daily' | 'weekly'
106
+ }
package/src/types.ts CHANGED
@@ -9,8 +9,17 @@
9
9
  */
10
10
 
11
11
  import type { JSONSchema } from 'ai-functions'
12
+ import type { Frame, ActionRef } from 'digital-objects'
13
+ import type { Identity, PaymentReceipt } from 'id.org.ai'
12
14
  import type { z } from 'zod'
13
15
 
16
+ // Re-export for downstream consumers (digital-tasks/digital-workers can use the same Frame)
17
+ export type { Frame, ActionRef } from 'digital-objects'
18
+
19
+ // Re-export id.org.ai canonical types so consumers don't need a separate import.
20
+ // `wrapTool()` populates these on `ToolHandlerContext` after broker gating.
21
+ export type { Identity, PaymentReceipt } from 'id.org.ai'
22
+
14
23
  // ============================================================================
15
24
  // Tool Category Ontology
16
25
  // ============================================================================
@@ -38,10 +47,10 @@ export type ToolCategory =
38
47
  export type CommunicationSubcategory =
39
48
  | 'email'
40
49
  | 'sms'
41
- | 'channel' // Brand-agnostic team messaging (Slack/Teams/Discord)
42
- | 'workspace' // Team messaging workspace/organization
50
+ | 'channel' // Brand-agnostic team messaging (Slack/Teams/Discord)
51
+ | 'workspace' // Team messaging workspace/organization
43
52
  | 'direct-message' // Private/DM conversations
44
- | 'chat' // Generic chat
53
+ | 'chat' // Generic chat
45
54
  | 'notification'
46
55
  | 'voice'
47
56
  | 'video-call'
@@ -283,15 +292,166 @@ export interface ToolOutput {
283
292
  streaming?: boolean
284
293
  }
285
294
 
295
+ // ============================================================================
296
+ // SVO Co-Design Types (aip-oejp): verb / frame / auth / pricing / handler ctx
297
+ // ============================================================================
298
+
299
+ /**
300
+ * Reference to an Identity in `id.org.ai`.
301
+ *
302
+ * Currently a string ID; the canonical type will move to `id.org.ai`
303
+ * once that package is published. Until then, treat as opaque.
304
+ */
305
+ export type IdentityRef = string
306
+
307
+ /**
308
+ * Payment rail used to satisfy a tool's `pricing` requirement.
309
+ *
310
+ * Minimal local definition — the canonical type will come from
311
+ * `id.org.ai` (PaymentBroker) once that package is published.
312
+ */
313
+ export interface PaymentRail {
314
+ /** Rail used to settle the payment */
315
+ rail: 'x402' | 'mpp'
316
+ /** Optional receipt / proof of payment from the broker */
317
+ receipt?: string
318
+ }
319
+
320
+ /**
321
+ * Authentication requirement for invoking a tool.
322
+ *
323
+ * Declares which auth scheme and scopes the caller must present
324
+ * before the handler is executed.
325
+ */
326
+ export interface AuthRequirement {
327
+ /** OAuth scopes / API key scopes required */
328
+ scopes: string[]
329
+ /** Auth mechanism the tool requires; `none` means public */
330
+ required: 'oauth' | 'apiKey' | 'none'
331
+ }
332
+
333
+ /**
334
+ * Payment requirement attached to a tool, MDXLD-shaped and
335
+ * compatible with x402 / MPP payment rails.
336
+ *
337
+ * When present, callers must satisfy this before the handler runs;
338
+ * the broker (id.org.ai) negotiates an acceptable rail and injects
339
+ * a `PaymentRail` into the handler context.
340
+ */
341
+ export interface PaymentRequired {
342
+ /** MDXLD type discriminator */
343
+ $type: 'PaymentRequired'
344
+ /** Amount as a string (preserves precision for crypto/fiat) */
345
+ amount: string
346
+ /** ISO 4217 currency code or asset symbol (e.g. 'USD', 'USDC') */
347
+ currency: string
348
+ /** Payment rails this tool will accept */
349
+ accepts: ('x402' | 'mpp')[]
350
+ /** Wallet address or stripeAccountId of the recipient */
351
+ recipient: string
352
+ /** Optional facilitator URL/identifier */
353
+ facilitator?: string
354
+ }
355
+
356
+ /**
357
+ * Context object passed to a tool handler when invoked through
358
+ * an SVO-aware dispatcher.
359
+ *
360
+ * This is distinct from the registry-level `ToolContext` (executor
361
+ * metadata for tracing/audit) — `ToolHandlerContext` carries
362
+ * runtime resources the handler needs to perform the action:
363
+ * the caller's identity, an injected payment rail (if `pricing`
364
+ * was satisfied), and the parent Action that caused the call.
365
+ *
366
+ * Handlers that don't need any of this can keep the arity-1
367
+ * `(args) => result` signature; arity-2 `(args, ctx) => result`
368
+ * is opt-in.
369
+ *
370
+ * `wrapTool()` (the broker-aware HTTP wrapper) populates `identity`
371
+ * with a full id.org.ai `Identity` record and, when `pricing` is
372
+ * satisfied, populates `paymentReceipt` with the canonical receipt
373
+ * from `PaymentBroker.settle()`. Older dispatchers that pass an
374
+ * opaque `IdentityRef` string and/or the local `PaymentRail` shape
375
+ * remain supported (the handler signature widens, not narrows).
376
+ */
377
+ export interface ToolHandlerContext {
378
+ /**
379
+ * Identity of the caller. Either:
380
+ * - the canonical {@link Identity} record from `id.org.ai`
381
+ * (populated by `wrapTool()` after `AuthBroker.gate()`), or
382
+ * - an opaque {@link IdentityRef} string for legacy dispatchers.
383
+ */
384
+ identity: Identity | IdentityRef
385
+ /**
386
+ * Backwards-compatible local `PaymentRail` shape. Older dispatchers
387
+ * may set this; new code should prefer {@link paymentReceipt} which
388
+ * carries the full id.org.ai receipt (txRef, settledAt, response
389
+ * header, …).
390
+ */
391
+ payment?: PaymentRail
392
+ /**
393
+ * Canonical {@link PaymentReceipt} from `PaymentBroker.settle()`.
394
+ * Populated by `wrapTool()` when the tool's `pricing` is satisfied.
395
+ */
396
+ paymentReceipt?: PaymentReceipt
397
+ /** Parent Action that caused this tool invocation, if any */
398
+ parentAction?: ActionRef
399
+ }
400
+
286
401
  // ============================================================================
287
402
  // Core Tool Interface
288
403
  // ============================================================================
289
404
 
290
405
  /**
291
- * Core Tool definition - the foundational type
406
+ * Core Tool definition - the foundational type for digital tools.
407
+ *
408
+ * Tools can be used by both humans and AI agents. They provide a standardized
409
+ * interface for performing actions across various categories including
410
+ * communication, data, development, documents, finance, and more.
411
+ *
412
+ * @typeParam TInput - The type of input the tool handler accepts
413
+ * @typeParam TOutput - The type of output the tool handler returns
414
+ *
415
+ * @example Basic tool definition
416
+ * ```typescript
417
+ * import { Tool, defineTool } from 'digital-tools'
292
418
  *
293
- * Tools can be used by both humans and AI agents. They provide
294
- * a standardized interface for performing actions.
419
+ * const greetTool: Tool<{ name: string }, string> = {
420
+ * id: 'communication.greeting.hello',
421
+ * name: 'Greet User',
422
+ * description: 'Generates a greeting message for the specified user',
423
+ * category: 'communication',
424
+ * parameters: [{
425
+ * name: 'name',
426
+ * description: 'Name of the person to greet',
427
+ * schema: { type: 'string' },
428
+ * required: true,
429
+ * }],
430
+ * handler: ({ name }) => `Hello, ${name}!`,
431
+ * }
432
+ * ```
433
+ *
434
+ * @example Using defineTool helper with Zod schema
435
+ * ```typescript
436
+ * import { defineTool } from 'digital-tools'
437
+ * import { z } from 'zod'
438
+ *
439
+ * const fetchTool = defineTool({
440
+ * id: 'web.fetch.url',
441
+ * name: 'Fetch URL',
442
+ * description: 'Fetches content from a URL',
443
+ * category: 'web',
444
+ * input: z.object({ url: z.string().url() }),
445
+ * handler: async ({ url }) => {
446
+ * const response = await fetch(url)
447
+ * return response.text()
448
+ * },
449
+ * })
450
+ * ```
451
+ *
452
+ * @see {@link ToolCategory} for available categories
453
+ * @see {@link ToolRegistry} for tool registration and discovery
454
+ * @see {@link defineTool} for the recommended way to create tools
295
455
  */
296
456
  export interface Tool<TInput = unknown, TOutput = unknown> {
297
457
  /** Unique tool identifier (e.g., 'communication.email.send') */
@@ -329,6 +489,31 @@ export interface Tool<TInput = unknown, TOutput = unknown> {
329
489
  /** Rate limiting */
330
490
  rateLimit?: RateLimit
331
491
 
492
+ // SVO Co-Design (aip-oejp) — all optional, additive over existing tools
493
+ /**
494
+ * Canonical Verb name this tool implements (e.g. 'send', 'transcribe').
495
+ *
496
+ * Used by SVO-aware dispatchers to resolve a Verb in `digital-objects`
497
+ * and pick a Tool registered for it. Cross-package Verb auto-registration
498
+ * is intentionally NOT performed here — see follow-up bead.
499
+ */
500
+ verb?: string
501
+
502
+ /**
503
+ * Frame declaring the complement-role types this tool accepts.
504
+ *
505
+ * Reuses the canonical {@link Frame} type from `digital-objects` so
506
+ * Tool frames and Verb frames stay in lockstep. When absent, the tool
507
+ * is treated as permissive (frame inferred from input shape).
508
+ */
509
+ frame?: Frame
510
+
511
+ /** Auth requirement gate; absent means no auth required */
512
+ auth?: AuthRequirement
513
+
514
+ /** Pricing requirement (x402/MPP); absent means free */
515
+ pricing?: PaymentRequired
516
+
332
517
  // Input/Output
333
518
  /** Input parameters */
334
519
  parameters: ToolParameter[]
@@ -336,8 +521,16 @@ export interface Tool<TInput = unknown, TOutput = unknown> {
336
521
  /** Output definition */
337
522
  output?: ToolOutput
338
523
 
339
- /** The tool implementation */
340
- handler: (input: TInput) => TOutput | Promise<TOutput>
524
+ /**
525
+ * The tool implementation.
526
+ *
527
+ * Backward-compatible: handlers may take just `(input)` (arity-1) or
528
+ * opt into the SVO handler context with `(input, ctx)` (arity-2).
529
+ * Dispatchers that don't have a {@link ToolHandlerContext} should
530
+ * call the handler with the input only — TypeScript permits this
531
+ * because the second parameter is optional.
532
+ */
533
+ handler: (input: TInput, ctx?: ToolHandlerContext) => TOutput | Promise<TOutput>
341
534
 
342
535
  // Metadata
343
536
  /** Tool author/owner */
@@ -360,8 +553,22 @@ export interface Tool<TInput = unknown, TOutput = unknown> {
360
553
  }
361
554
 
362
555
  /**
363
- * Any tool type - used for arrays and collections of tools
364
- * with different input/output types
556
+ * Any tool type - used for arrays and collections of tools with different
557
+ * input/output types.
558
+ *
559
+ * Use this type when you need to work with heterogeneous collections of tools,
560
+ * such as in registries, tool lists, or when the specific input/output types
561
+ * are not known at compile time.
562
+ *
563
+ * @example Tool collection
564
+ * ```typescript
565
+ * import { AnyTool } from 'digital-tools'
566
+ *
567
+ * const tools: AnyTool[] = [emailTool, slackTool, fetchTool]
568
+ * tools.forEach(tool => console.log(tool.name))
569
+ * ```
570
+ *
571
+ * @see {@link Tool} for the base tool type with specific type parameters
365
572
  */
366
573
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
367
574
  export type AnyTool = Tool<any, any>
@@ -388,10 +595,31 @@ export interface DefineToolOptions<TInput, TOutput> {
388
595
  input: Schema
389
596
  /** Output schema (optional) */
390
597
  output?: Schema
391
- /** The handler function */
392
- handler: (input: TInput) => TOutput | Promise<TOutput>
598
+
599
+ // SVO Co-Design (aip-oejp) all optional, additive
600
+ /** Canonical Verb name this tool implements */
601
+ verb?: string
602
+ /** Frame from `digital-objects` declaring complement-role types */
603
+ frame?: Frame
604
+ /** Auth requirement; absent means no auth required */
605
+ auth?: AuthRequirement
606
+ /** Pricing requirement (x402/MPP); absent means free */
607
+ pricing?: PaymentRequired
608
+
609
+ /**
610
+ * The handler function.
611
+ *
612
+ * Backward-compatible: arity-1 `(input)` handlers continue to work;
613
+ * arity-2 `(input, ctx)` handlers receive the SVO {@link ToolHandlerContext}.
614
+ */
615
+ handler: (input: TInput, ctx?: ToolHandlerContext) => TOutput | Promise<TOutput>
393
616
  /** Additional options */
394
- options?: Partial<Omit<Tool<TInput, TOutput>, 'id' | 'name' | 'description' | 'category' | 'parameters' | 'handler'>>
617
+ options?: Partial<
618
+ Omit<
619
+ Tool<TInput, TOutput>,
620
+ 'id' | 'name' | 'description' | 'category' | 'parameters' | 'handler'
621
+ >
622
+ >
395
623
  }
396
624
 
397
625
  /**
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Verb Auto-Registration (aip-47tm)
3
+ *
4
+ * Bridges `defineTool()` (synchronous, side-effect-free builder) to
5
+ * `digital-objects`' provider-mediated `defineVerb()` (async, I/O-bound).
6
+ *
7
+ * ## Design choice — Option B: explicit bootstrap
8
+ *
9
+ * `defineTool({ verb, frame })` records the metadata on the Tool but does
10
+ * NOT call `provider.defineVerb()` itself. Cross-package side effects
11
+ * from a pure builder are surprising; the provider is also caller-supplied,
12
+ * so eager registration would force `defineTool` to know about a provider
13
+ * it doesn't currently take.
14
+ *
15
+ * Instead, registration is an explicit, idempotent helper:
16
+ *
17
+ * - `registerToolVerb(provider, tool)` — single-tool, used from
18
+ * custom dispatchers that
19
+ * want lazy-on-first-call.
20
+ * - `registerToolVerbs(provider, tools)` — bootstrap list, used at
21
+ * startup once per provider.
22
+ *
23
+ * Both are idempotent: re-registering a Verb with the same name and same
24
+ * frame is a no-op. Re-registering with a different frame throws —
25
+ * silent overwrite would mask an ontology drift bug.
26
+ *
27
+ * ## Why not Option A (lazy in `wrapTool`)
28
+ *
29
+ * `wrapTool()` takes auth + payment brokers, not a `DigitalObjectsProvider`.
30
+ * Wiring a provider into `wrapTool()` would couple HTTP wrapping to the
31
+ * digital-objects ontology — a layering inversion. Callers that want
32
+ * lazy-on-first-call can compose `registerToolVerb()` into their own
33
+ * dispatcher; the helper is fast enough to call per-request because the
34
+ * idempotency check short-circuits to a single `getVerb()` lookup.
35
+ *
36
+ * ## Why not Option C (eager-with-deferred-provider queue)
37
+ *
38
+ * A module-level queue is global state in `digital-tools` — exactly what
39
+ * the bead forbids. It also can't flush deterministically across
40
+ * concurrent test workers, and ordering becomes load-dependent.
41
+ *
42
+ * @packageDocumentation
43
+ */
44
+
45
+ import type { Frame, Verb, VerbDefinition } from 'digital-objects'
46
+ import type { AnyTool, Tool } from './types.js'
47
+
48
+ /**
49
+ * Subset of `DigitalObjectsProvider` that this module requires.
50
+ *
51
+ * We deliberately accept only `getVerb` + `defineVerb` (rather than the
52
+ * full provider interface) so callers can pass any object with these
53
+ * two methods — including HTTP/RPC clients, test doubles, and the
54
+ * canonical `MemoryProvider`.
55
+ */
56
+ export interface VerbRegistrationProvider {
57
+ defineVerb(def: VerbDefinition): Promise<Verb>
58
+ getVerb(name: string): Promise<Verb | null>
59
+ }
60
+
61
+ /**
62
+ * Compare two optional Frames structurally. Returns true when both are
63
+ * undefined, or both define the same set of role -> NounRef mappings.
64
+ *
65
+ * `manner` (string[]) is compared as an unordered set since the role
66
+ * order is not semantically meaningful.
67
+ */
68
+ function framesEqual(a: Frame | undefined, b: Frame | undefined): boolean {
69
+ if (a === b) return true
70
+ if (!a || !b) return false
71
+
72
+ const keys = new Set<keyof Frame>([
73
+ ...(Object.keys(a) as (keyof Frame)[]),
74
+ ...(Object.keys(b) as (keyof Frame)[]),
75
+ ])
76
+
77
+ for (const k of keys) {
78
+ const av = a[k]
79
+ const bv = b[k]
80
+ if (k === 'manner') {
81
+ const aArr = (av as string[] | undefined) ?? []
82
+ const bArr = (bv as string[] | undefined) ?? []
83
+ if (aArr.length !== bArr.length) return false
84
+ const aSet = new Set(aArr)
85
+ for (const v of bArr) if (!aSet.has(v)) return false
86
+ } else {
87
+ if (av !== bv) return false
88
+ }
89
+ }
90
+ return true
91
+ }
92
+
93
+ /**
94
+ * Mismatch error raised when a Tool tries to register a Verb whose name
95
+ * already exists with a different frame. We do not silently overwrite —
96
+ * conflicting ontology shapes are almost always a bug (two tools claiming
97
+ * the same verb with different role expectations).
98
+ */
99
+ export class VerbRegistrationConflictError extends Error {
100
+ constructor(
101
+ public readonly verbName: string,
102
+ public readonly existing: Frame | undefined,
103
+ public readonly incoming: Frame | undefined
104
+ ) {
105
+ super(
106
+ `Verb "${verbName}" is already registered with a different frame. ` +
107
+ `Tools that share a verb name must declare the same frame. ` +
108
+ `Re-registering a verb with the same frame is a no-op (idempotent), ` +
109
+ `but the incoming frame does not match the existing one.`
110
+ )
111
+ this.name = 'VerbRegistrationConflictError'
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Register the Verb declared by a single Tool against `provider`.
117
+ *
118
+ * - Tools without a `verb` field are skipped (they are not SVO-aware).
119
+ * - If the verb already exists with the same frame, the call is a no-op
120
+ * and the existing Verb is returned (idempotent).
121
+ * - If the verb already exists with a different frame, throws
122
+ * {@link VerbRegistrationConflictError}.
123
+ *
124
+ * Suitable for both eager bootstrap and lazy-per-request use:
125
+ * the idempotency check is a single `getVerb()` lookup, so it is safe
126
+ * to call from a hot dispatch path.
127
+ *
128
+ * @returns The registered Verb, or `null` if the tool has no `verb` field.
129
+ *
130
+ * @example Lazy registration in a custom dispatcher
131
+ * ```ts
132
+ * async function dispatch(provider: DigitalObjectsProvider, tool: Tool, args: unknown) {
133
+ * await registerToolVerb(provider, tool) // idempotent, cheap on subsequent calls
134
+ * return tool.handler(args)
135
+ * }
136
+ * ```
137
+ */
138
+ export async function registerToolVerb(
139
+ provider: VerbRegistrationProvider,
140
+ tool: Tool<unknown, unknown> | AnyTool
141
+ ): Promise<Verb | null> {
142
+ if (!tool.verb) return null
143
+
144
+ const existing = await provider.getVerb(tool.verb)
145
+ if (existing) {
146
+ if (framesEqual(existing.frame, tool.frame)) {
147
+ return existing
148
+ }
149
+ throw new VerbRegistrationConflictError(tool.verb, existing.frame, tool.frame)
150
+ }
151
+
152
+ return provider.defineVerb({
153
+ name: tool.verb,
154
+ ...(tool.frame !== undefined && { frame: tool.frame }),
155
+ ...(tool.description !== undefined && { description: tool.description }),
156
+ })
157
+ }
158
+
159
+ /**
160
+ * Bootstrap helper: register the Verbs for every SVO-aware tool in
161
+ * `tools` against `provider`.
162
+ *
163
+ * Tools without a `verb` field are skipped silently (legacy / non-SVO
164
+ * tools coexist with SVO-aware tools in the same registry).
165
+ *
166
+ * Conflicts (same verb name, different frame) throw on the first
167
+ * conflicting tool — the caller can decide whether to retry without
168
+ * the conflicting tool or surface the error.
169
+ *
170
+ * @returns The list of Verbs that were registered (or already existed,
171
+ * for idempotent calls). Tools with no verb are not included.
172
+ *
173
+ * @example Startup
174
+ * ```ts
175
+ * import { MemoryProvider, registerToolVerbs, getBuiltinTools } from 'digital-tools'
176
+ *
177
+ * const provider = new MemoryProvider()
178
+ * await registerToolVerbs(provider, getBuiltinTools())
179
+ * ```
180
+ */
181
+ export async function registerToolVerbs(
182
+ provider: VerbRegistrationProvider,
183
+ tools: ReadonlyArray<Tool<unknown, unknown> | AnyTool>
184
+ ): Promise<Verb[]> {
185
+ const registered: Verb[] = []
186
+ for (const tool of tools) {
187
+ const verb = await registerToolVerb(provider, tool)
188
+ if (verb) registered.push(verb)
189
+ }
190
+ return registered
191
+ }
192
+
193
+ /**
194
+ * Alias for {@link registerToolVerbs}. The "bootstrap" name reads better
195
+ * at startup sites where a list of tools is wired against a provider once.
196
+ */
197
+ export const bootstrapTools = registerToolVerbs