human-in-the-loop 0.1.0 → 2.0.2
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.
- package/.turbo/turbo-build.log +5 -0
- package/CHANGELOG.md +17 -0
- package/README.md +600 -166
- package/dist/helpers.d.ts +308 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +275 -0
- package/dist/helpers.js.map +1 -0
- package/dist/human.d.ts +315 -0
- package/dist/human.d.ts.map +1 -0
- package/dist/human.js +476 -0
- package/dist/human.js.map +1 -0
- package/dist/index.d.ts +48 -343
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -793
- package/dist/index.js.map +1 -0
- package/dist/store.d.ts +61 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +162 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +399 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/examples/basic-usage.ts +386 -0
- package/package.json +23 -54
- package/src/helpers.ts +379 -0
- package/src/human.test.ts +384 -0
- package/src/human.ts +626 -0
- package/src/index.ts +102 -6
- package/src/store.ts +201 -0
- package/src/types.ts +431 -0
- package/tsconfig.json +6 -11
- package/TODO.md +0 -53
- package/dist/index.cjs +0 -899
- package/dist/index.d.cts +0 -344
- package/src/core/factory.test.ts +0 -69
- package/src/core/factory.ts +0 -30
- package/src/core/types.ts +0 -191
- package/src/platforms/email/index.tsx +0 -137
- package/src/platforms/react/index.tsx +0 -218
- package/src/platforms/slack/index.ts +0 -84
- package/src/platforms/teams/index.ts +0 -84
- package/vitest.config.ts +0 -15
package/src/helpers.ts
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper functions for common human-in-the-loop patterns
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
Role,
|
|
7
|
+
Team,
|
|
8
|
+
Goals,
|
|
9
|
+
KPIs,
|
|
10
|
+
OKRs,
|
|
11
|
+
Human as HumanType,
|
|
12
|
+
ApprovalResponse,
|
|
13
|
+
ReviewResponse,
|
|
14
|
+
} from './types.js'
|
|
15
|
+
import { Human } from './human.js'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Create a default Human instance for convenience
|
|
19
|
+
*/
|
|
20
|
+
const defaultHuman = Human()
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Define a human role
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* const techLead = Role({
|
|
28
|
+
* id: 'tech-lead',
|
|
29
|
+
* name: 'Tech Lead',
|
|
30
|
+
* capabilities: ['approve-prs', 'deploy-prod'],
|
|
31
|
+
* escalatesTo: 'engineering-manager',
|
|
32
|
+
* })
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function Role(role: Role): Role {
|
|
36
|
+
return defaultHuman.defineRole(role)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Define a team
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* const engineering = Team({
|
|
45
|
+
* id: 'engineering',
|
|
46
|
+
* name: 'Engineering Team',
|
|
47
|
+
* members: ['alice', 'bob', 'charlie'],
|
|
48
|
+
* lead: 'alice',
|
|
49
|
+
* })
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function Team(team: Team): Team {
|
|
53
|
+
return defaultHuman.defineTeam(team)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Define goals for a team or individual
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* const q1Goals = Goals({
|
|
62
|
+
* id: 'q1-2024',
|
|
63
|
+
* objectives: [
|
|
64
|
+
* 'Launch v2.0',
|
|
65
|
+
* 'Improve performance by 50%',
|
|
66
|
+
* ],
|
|
67
|
+
* targetDate: new Date('2024-03-31'),
|
|
68
|
+
* })
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function Goals(goals: Goals): Goals {
|
|
72
|
+
return defaultHuman.defineGoals(goals)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Request approval from a human
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* const result = await approve({
|
|
81
|
+
* title: 'Deploy to production',
|
|
82
|
+
* description: 'Deploy v2.0.0 to production',
|
|
83
|
+
* subject: 'Production Deployment',
|
|
84
|
+
* input: { version: '2.0.0', environment: 'prod' },
|
|
85
|
+
* assignee: 'tech-lead@example.com',
|
|
86
|
+
* priority: 'high',
|
|
87
|
+
* })
|
|
88
|
+
*
|
|
89
|
+
* if (result.approved) {
|
|
90
|
+
* await deploy()
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export async function approve<TData = unknown>(params: {
|
|
95
|
+
title: string
|
|
96
|
+
description: string
|
|
97
|
+
subject: string
|
|
98
|
+
input: TData
|
|
99
|
+
assignee?: string | string[]
|
|
100
|
+
role?: string
|
|
101
|
+
team?: string
|
|
102
|
+
priority?: 'low' | 'normal' | 'high' | 'critical'
|
|
103
|
+
timeout?: number
|
|
104
|
+
escalatesTo?: string | string[]
|
|
105
|
+
requiresApproval?: boolean
|
|
106
|
+
approvers?: string[]
|
|
107
|
+
metadata?: Record<string, unknown>
|
|
108
|
+
}): Promise<ApprovalResponse> {
|
|
109
|
+
return defaultHuman.approve(params)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Ask a question to a human
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* const answer = await ask({
|
|
118
|
+
* title: 'Product naming',
|
|
119
|
+
* question: 'What should we name the new feature?',
|
|
120
|
+
* context: { feature: 'AI Assistant' },
|
|
121
|
+
* assignee: 'product-manager@example.com',
|
|
122
|
+
* })
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
export async function ask(params: {
|
|
126
|
+
title: string
|
|
127
|
+
question: string
|
|
128
|
+
context?: unknown
|
|
129
|
+
assignee?: string | string[]
|
|
130
|
+
role?: string
|
|
131
|
+
team?: string
|
|
132
|
+
priority?: 'low' | 'normal' | 'high' | 'critical'
|
|
133
|
+
timeout?: number
|
|
134
|
+
suggestions?: string[]
|
|
135
|
+
metadata?: Record<string, unknown>
|
|
136
|
+
}): Promise<string> {
|
|
137
|
+
return defaultHuman.ask(params)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Request a human to perform a task
|
|
142
|
+
*
|
|
143
|
+
* This uses the digital-workers interface for humans
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* const result = await do({
|
|
148
|
+
* title: 'Review code',
|
|
149
|
+
* instructions: 'Review the PR and provide feedback',
|
|
150
|
+
* input: { prUrl: 'https://github.com/...' },
|
|
151
|
+
* assignee: 'senior-dev@example.com',
|
|
152
|
+
* })
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
export async function do_<TInput = unknown, TOutput = unknown>(params: {
|
|
156
|
+
title: string
|
|
157
|
+
instructions: string
|
|
158
|
+
input: TInput
|
|
159
|
+
assignee?: string | string[]
|
|
160
|
+
role?: string
|
|
161
|
+
team?: string
|
|
162
|
+
priority?: 'low' | 'normal' | 'high' | 'critical'
|
|
163
|
+
timeout?: number
|
|
164
|
+
tools?: any[]
|
|
165
|
+
estimatedEffort?: string
|
|
166
|
+
metadata?: Record<string, unknown>
|
|
167
|
+
}): Promise<TOutput> {
|
|
168
|
+
return defaultHuman.do(params)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Export as 'do' for the API, but define as 'do_' to avoid reserved keyword
|
|
172
|
+
export { do_ as do }
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Request a human to make a decision
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* const choice = await decide({
|
|
180
|
+
* title: 'Pick deployment strategy',
|
|
181
|
+
* options: ['blue-green', 'canary', 'rolling'],
|
|
182
|
+
* context: { risk: 'high', users: 100000 },
|
|
183
|
+
* assignee: 'devops-lead@example.com',
|
|
184
|
+
* })
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
export async function decide<TOptions extends string = string>(params: {
|
|
188
|
+
title: string
|
|
189
|
+
description?: string
|
|
190
|
+
options: TOptions[]
|
|
191
|
+
context?: unknown
|
|
192
|
+
assignee?: string | string[]
|
|
193
|
+
role?: string
|
|
194
|
+
team?: string
|
|
195
|
+
priority?: 'low' | 'normal' | 'high' | 'critical'
|
|
196
|
+
timeout?: number
|
|
197
|
+
criteria?: string[]
|
|
198
|
+
metadata?: Record<string, unknown>
|
|
199
|
+
}): Promise<TOptions> {
|
|
200
|
+
return defaultHuman.decide(params)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Request generation/content creation from a human
|
|
205
|
+
*
|
|
206
|
+
* This is a specialized form of do() for content generation
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* const content = await generate({
|
|
211
|
+
* title: 'Write blog post',
|
|
212
|
+
* instructions: 'Write a blog post about our new feature',
|
|
213
|
+
* input: { topic: 'AI Assistant', targetAudience: 'developers' },
|
|
214
|
+
* assignee: 'content-writer@example.com',
|
|
215
|
+
* })
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
export async function generate<TInput = unknown>(params: {
|
|
219
|
+
title: string
|
|
220
|
+
instructions: string
|
|
221
|
+
input: TInput
|
|
222
|
+
assignee?: string | string[]
|
|
223
|
+
role?: string
|
|
224
|
+
team?: string
|
|
225
|
+
priority?: 'low' | 'normal' | 'high' | 'critical'
|
|
226
|
+
timeout?: number
|
|
227
|
+
metadata?: Record<string, unknown>
|
|
228
|
+
}): Promise<string> {
|
|
229
|
+
return defaultHuman.do<TInput, string>(params)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Type checking/validation request
|
|
234
|
+
*
|
|
235
|
+
* Ask a human to validate data or check type compliance
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```ts
|
|
239
|
+
* const valid = await is({
|
|
240
|
+
* title: 'Validate user data',
|
|
241
|
+
* question: 'Is this user data valid and complete?',
|
|
242
|
+
* input: userData,
|
|
243
|
+
* assignee: 'data-specialist@example.com',
|
|
244
|
+
* })
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
export async function is(params: {
|
|
248
|
+
title: string
|
|
249
|
+
question: string
|
|
250
|
+
input: unknown
|
|
251
|
+
assignee?: string | string[]
|
|
252
|
+
role?: string
|
|
253
|
+
team?: string
|
|
254
|
+
priority?: 'low' | 'normal' | 'high' | 'critical'
|
|
255
|
+
timeout?: number
|
|
256
|
+
metadata?: Record<string, unknown>
|
|
257
|
+
}): Promise<boolean> {
|
|
258
|
+
const result = await defaultHuman.decide<'true' | 'false'>({
|
|
259
|
+
title: params.title,
|
|
260
|
+
description: params.question,
|
|
261
|
+
options: ['true', 'false'],
|
|
262
|
+
context: params.input,
|
|
263
|
+
assignee: params.assignee,
|
|
264
|
+
role: params.role,
|
|
265
|
+
team: params.team,
|
|
266
|
+
priority: params.priority,
|
|
267
|
+
timeout: params.timeout,
|
|
268
|
+
metadata: params.metadata,
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
return result === 'true'
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Send a notification to a human
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* ```ts
|
|
279
|
+
* await notify({
|
|
280
|
+
* type: 'info',
|
|
281
|
+
* title: 'Deployment complete',
|
|
282
|
+
* message: 'Version 2.0.0 deployed successfully',
|
|
283
|
+
* recipient: 'team@example.com',
|
|
284
|
+
* channels: ['slack', 'email'],
|
|
285
|
+
* })
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
export async function notify(params: {
|
|
289
|
+
type: 'info' | 'warning' | 'error' | 'success'
|
|
290
|
+
title: string
|
|
291
|
+
message: string
|
|
292
|
+
recipient: string | string[]
|
|
293
|
+
channels?: ('slack' | 'email' | 'sms' | 'web')[]
|
|
294
|
+
priority?: 'low' | 'normal' | 'high' | 'critical'
|
|
295
|
+
data?: unknown
|
|
296
|
+
}): Promise<void> {
|
|
297
|
+
await defaultHuman.notify(params)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Track Key Performance Indicators
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```ts
|
|
305
|
+
* kpis({
|
|
306
|
+
* id: 'monthly-revenue',
|
|
307
|
+
* name: 'Monthly Revenue',
|
|
308
|
+
* value: 150000,
|
|
309
|
+
* target: 200000,
|
|
310
|
+
* unit: 'USD',
|
|
311
|
+
* trend: 'up',
|
|
312
|
+
* })
|
|
313
|
+
* ```
|
|
314
|
+
*/
|
|
315
|
+
export function kpis(kpis: KPIs): KPIs {
|
|
316
|
+
return defaultHuman.trackKPIs(kpis)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Define Objectives and Key Results
|
|
321
|
+
*
|
|
322
|
+
* @example
|
|
323
|
+
* ```ts
|
|
324
|
+
* okrs({
|
|
325
|
+
* id: 'q1-2024-growth',
|
|
326
|
+
* objective: 'Accelerate user growth',
|
|
327
|
+
* keyResults: [
|
|
328
|
+
* {
|
|
329
|
+
* description: 'Increase active users by 50%',
|
|
330
|
+
* progress: 0.3,
|
|
331
|
+
* current: 13000,
|
|
332
|
+
* target: 15000,
|
|
333
|
+
* },
|
|
334
|
+
* {
|
|
335
|
+
* description: 'Achieve 95% customer satisfaction',
|
|
336
|
+
* progress: 0.85,
|
|
337
|
+
* current: 0.93,
|
|
338
|
+
* target: 0.95,
|
|
339
|
+
* },
|
|
340
|
+
* ],
|
|
341
|
+
* period: 'Q1 2024',
|
|
342
|
+
* owner: 'ceo@example.com',
|
|
343
|
+
* })
|
|
344
|
+
* ```
|
|
345
|
+
*/
|
|
346
|
+
export function okrs(okrs: OKRs): OKRs {
|
|
347
|
+
return defaultHuman.defineOKRs(okrs)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Register a human worker in the system
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* ```ts
|
|
355
|
+
* const alice = registerHuman({
|
|
356
|
+
* id: 'alice',
|
|
357
|
+
* name: 'Alice Smith',
|
|
358
|
+
* email: 'alice@example.com',
|
|
359
|
+
* roles: ['tech-lead', 'developer'],
|
|
360
|
+
* teams: ['engineering', 'frontend'],
|
|
361
|
+
* channels: {
|
|
362
|
+
* slack: '@alice',
|
|
363
|
+
* email: 'alice@example.com',
|
|
364
|
+
* },
|
|
365
|
+
* })
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
export function registerHuman(human: HumanType): HumanType {
|
|
369
|
+
return defaultHuman.registerHuman(human)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Get the default Human manager instance
|
|
374
|
+
*
|
|
375
|
+
* Use this to access the underlying HumanManager for advanced operations
|
|
376
|
+
*/
|
|
377
|
+
export function getDefaultHuman(): ReturnType<typeof Human> {
|
|
378
|
+
return defaultHuman
|
|
379
|
+
}
|