human-in-the-loop 2.0.1 → 2.1.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # human-in-the-loop
2
2
 
3
+ ## 2.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [6beb531]
8
+ - ai-functions@2.1.1
9
+ - digital-workers@2.1.1
10
+
11
+ ## 2.0.3
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+ - rpc.do@0.2.0
17
+ - ai-functions@2.0.3
18
+ - digital-workers@2.0.3
19
+
20
+ ## 2.0.2
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies
25
+ - ai-functions@2.0.2
26
+ - digital-workers@2.0.2
27
+
3
28
  ## 2.0.1
4
29
 
5
30
  ### Patch Changes
@@ -0,0 +1,325 @@
1
+ /**
2
+ * Basic usage examples for human-in-the-loop
3
+ *
4
+ * This file demonstrates common patterns and use cases
5
+ */
6
+ import { Human, Role, Team, Goals, approve, ask, decide, notify, kpis, okrs, registerHuman, } from '../src/index.js';
7
+ // ============================================================================
8
+ // Setup: Define roles, teams, and humans
9
+ // ============================================================================
10
+ // Define roles
11
+ const techLead = Role({
12
+ id: 'tech-lead',
13
+ name: 'Tech Lead',
14
+ description: 'Technical leadership and architecture decisions',
15
+ capabilities: ['approve-prs', 'deploy-prod', 'review-code'],
16
+ escalatesTo: 'engineering-manager',
17
+ });
18
+ const engineer = Role({
19
+ id: 'engineer',
20
+ name: 'Software Engineer',
21
+ description: 'Software development',
22
+ capabilities: ['write-code', 'review-code'],
23
+ escalatesTo: 'tech-lead',
24
+ });
25
+ // Define teams
26
+ const engineeringTeam = Team({
27
+ id: 'engineering',
28
+ name: 'Engineering Team',
29
+ description: 'Product development team',
30
+ members: ['alice', 'bob', 'charlie'],
31
+ lead: 'alice',
32
+ });
33
+ // Register humans
34
+ const alice = registerHuman({
35
+ id: 'alice',
36
+ name: 'Alice Smith',
37
+ email: 'alice@example.com',
38
+ roles: ['tech-lead'],
39
+ teams: ['engineering'],
40
+ channels: {
41
+ slack: '@alice',
42
+ email: 'alice@example.com',
43
+ web: true,
44
+ },
45
+ });
46
+ const bob = registerHuman({
47
+ id: 'bob',
48
+ name: 'Bob Johnson',
49
+ email: 'bob@example.com',
50
+ roles: ['engineer'],
51
+ teams: ['engineering'],
52
+ channels: {
53
+ slack: '@bob',
54
+ email: 'bob@example.com',
55
+ },
56
+ });
57
+ // ============================================================================
58
+ // Example 1: Approval workflow
59
+ // ============================================================================
60
+ async function approvalExample() {
61
+ console.log('=== Approval Example ===\n');
62
+ try {
63
+ // Request approval for production deployment
64
+ const deployment = await approve({
65
+ title: 'Production Deployment',
66
+ description: 'Deploy version 2.0.0 to production',
67
+ subject: 'Production Deployment - v2.0.0',
68
+ input: {
69
+ version: '2.0.0',
70
+ environment: 'production',
71
+ changes: ['New AI features', 'Performance improvements', 'Bug fixes'],
72
+ },
73
+ assignee: alice.email,
74
+ priority: 'high',
75
+ timeout: 3600000, // 1 hour
76
+ escalatesTo: 'engineering-manager',
77
+ });
78
+ if (deployment.approved) {
79
+ console.log('✅ Deployment approved!');
80
+ console.log('Comments:', deployment.comments);
81
+ // Proceed with deployment
82
+ await deploy();
83
+ // Send success notification
84
+ await notify({
85
+ type: 'success',
86
+ title: 'Deployment Complete',
87
+ message: 'Version 2.0.0 successfully deployed to production',
88
+ recipient: [alice.email, engineeringTeam.id],
89
+ channels: ['slack', 'email'],
90
+ priority: 'normal',
91
+ });
92
+ }
93
+ else {
94
+ console.log('❌ Deployment rejected');
95
+ console.log('Reason:', deployment.comments);
96
+ }
97
+ }
98
+ catch (error) {
99
+ console.error('Approval failed:', error);
100
+ }
101
+ }
102
+ // ============================================================================
103
+ // Example 2: Ask a question
104
+ // ============================================================================
105
+ async function questionExample() {
106
+ console.log('\n=== Question Example ===\n');
107
+ try {
108
+ const answer = await ask({
109
+ title: 'Product Naming Decision',
110
+ question: 'What should we name the new AI assistant feature?',
111
+ context: {
112
+ feature: 'AI-powered code assistant',
113
+ targetAudience: 'developers',
114
+ competitors: ['GitHub Copilot', 'Cursor', 'Tabnine'],
115
+ },
116
+ assignee: 'product-manager@example.com',
117
+ suggestions: ['CodeMate', 'DevAssist', 'SmartCode', 'AIHelper'],
118
+ priority: 'normal',
119
+ });
120
+ console.log('Answer received:', answer);
121
+ }
122
+ catch (error) {
123
+ console.error('Question failed:', error);
124
+ }
125
+ }
126
+ // ============================================================================
127
+ // Example 3: Decision with options
128
+ // ============================================================================
129
+ async function decisionExample() {
130
+ console.log('\n=== Decision Example ===\n');
131
+ try {
132
+ const strategy = await decide({
133
+ title: 'Deployment Strategy',
134
+ description: 'Choose the deployment strategy for the new release',
135
+ options: ['blue-green', 'canary', 'rolling', 'all-at-once'],
136
+ context: {
137
+ riskLevel: 'high',
138
+ activeUsers: 100000,
139
+ deploymentWindow: '2 hours',
140
+ rollbackTime: '5 minutes',
141
+ },
142
+ criteria: [
143
+ 'Minimize risk to users',
144
+ 'Enable fast rollback',
145
+ 'Complete within deployment window',
146
+ ],
147
+ assignee: alice.email,
148
+ priority: 'high',
149
+ });
150
+ console.log('Selected strategy:', strategy);
151
+ }
152
+ catch (error) {
153
+ console.error('Decision failed:', error);
154
+ }
155
+ }
156
+ // ============================================================================
157
+ // Example 4: Goals and OKRs
158
+ // ============================================================================
159
+ function goalsExample() {
160
+ console.log('\n=== Goals and OKRs Example ===\n');
161
+ // Define team goals
162
+ const q1Goals = Goals({
163
+ id: 'engineering-q1-2024',
164
+ objectives: [
165
+ 'Launch AI assistant v2.0',
166
+ 'Improve system performance by 50%',
167
+ 'Reduce bug count by 40%',
168
+ ],
169
+ successCriteria: [
170
+ 'Release by March 31',
171
+ 'Pass all performance benchmarks',
172
+ 'Achieve customer satisfaction score of 4.5+',
173
+ ],
174
+ targetDate: new Date('2024-03-31'),
175
+ });
176
+ console.log('Q1 Goals:', q1Goals);
177
+ // Define OKRs
178
+ const q1OKRs = okrs({
179
+ id: 'engineering-okrs-q1-2024',
180
+ objective: 'Build world-class AI development tools',
181
+ keyResults: [
182
+ {
183
+ description: 'Increase active users by 50%',
184
+ progress: 0.3,
185
+ current: 13000,
186
+ target: 15000,
187
+ },
188
+ {
189
+ description: 'Achieve 95% uptime',
190
+ progress: 0.92,
191
+ current: 0.95,
192
+ target: 0.95,
193
+ },
194
+ {
195
+ description: 'Reduce average response time to <100ms',
196
+ progress: 0.75,
197
+ current: 120,
198
+ target: 100,
199
+ },
200
+ ],
201
+ period: 'Q1 2024',
202
+ owner: alice.email,
203
+ });
204
+ console.log('Q1 OKRs:', q1OKRs);
205
+ // Track KPIs
206
+ const performanceKPI = kpis({
207
+ id: 'api-response-time',
208
+ name: 'API Response Time',
209
+ value: 120,
210
+ target: 100,
211
+ unit: 'ms',
212
+ trend: 'down',
213
+ });
214
+ console.log('Performance KPI:', performanceKPI);
215
+ }
216
+ // ============================================================================
217
+ // Example 5: Using Human instance for advanced operations
218
+ // ============================================================================
219
+ async function advancedExample() {
220
+ console.log('\n=== Advanced Example ===\n');
221
+ // Create a custom Human instance with specific configuration
222
+ const human = Human({
223
+ defaultTimeout: 7200000, // 2 hours
224
+ defaultPriority: 'high',
225
+ autoEscalate: true,
226
+ escalationPolicies: [
227
+ {
228
+ id: 'critical-approval',
229
+ name: 'Critical Approval Policy',
230
+ conditions: {
231
+ timeout: 1800000, // 30 minutes
232
+ minPriority: 'critical',
233
+ },
234
+ escalationPath: [
235
+ {
236
+ assignee: 'tech-lead',
237
+ afterMs: 1800000, // 30 minutes
238
+ notifyVia: ['slack', 'sms'],
239
+ },
240
+ {
241
+ assignee: 'engineering-manager',
242
+ afterMs: 3600000, // 1 hour
243
+ notifyVia: ['slack', 'email', 'sms'],
244
+ },
245
+ {
246
+ assignee: 'cto',
247
+ afterMs: 7200000, // 2 hours
248
+ notifyVia: ['slack', 'email', 'sms'],
249
+ },
250
+ ],
251
+ },
252
+ ],
253
+ });
254
+ // Create an approval workflow
255
+ const deploymentWorkflow = human.createWorkflow({
256
+ id: 'prod-deployment-workflow',
257
+ name: 'Production Deployment Workflow',
258
+ steps: [
259
+ {
260
+ name: 'Code Review',
261
+ role: 'engineer',
262
+ approvers: [bob.id],
263
+ requireAll: true,
264
+ },
265
+ {
266
+ name: 'Security Review',
267
+ role: 'security-engineer',
268
+ approvers: ['security-team'],
269
+ requireAll: false,
270
+ },
271
+ {
272
+ name: 'Tech Lead Approval',
273
+ role: 'tech-lead',
274
+ approvers: [alice.id],
275
+ requireAll: true,
276
+ },
277
+ ],
278
+ currentStep: 0,
279
+ status: 'pending',
280
+ });
281
+ console.log('Created workflow:', deploymentWorkflow);
282
+ // Get the review queue
283
+ const queue = await human.getQueue({
284
+ name: 'High Priority Queue',
285
+ description: 'All high priority pending requests',
286
+ filters: {
287
+ status: ['pending', 'in_progress'],
288
+ priority: ['high', 'critical'],
289
+ },
290
+ sortBy: 'priority',
291
+ sortDirection: 'desc',
292
+ limit: 10,
293
+ });
294
+ console.log('Queue:', queue.name, 'Items:', queue.items.length);
295
+ }
296
+ // ============================================================================
297
+ // Mock deployment function
298
+ // ============================================================================
299
+ async function deploy() {
300
+ console.log('🚀 Deploying to production...');
301
+ // Simulate deployment
302
+ await new Promise((resolve) => setTimeout(resolve, 100));
303
+ console.log('✅ Deployment successful!');
304
+ }
305
+ // ============================================================================
306
+ // Run examples
307
+ // ============================================================================
308
+ async function main() {
309
+ console.log('Human-in-the-Loop Examples\n');
310
+ console.log('Note: These examples demonstrate the API.');
311
+ console.log('Actual human responses would need to be provided via the store.\n');
312
+ // Run examples (most will timeout or error without actual human responses)
313
+ // In a real system, humans would respond via UI, webhooks, or API calls
314
+ goalsExample();
315
+ // Uncomment to test async examples (they will wait for human responses)
316
+ // await approvalExample()
317
+ // await questionExample()
318
+ // await decisionExample()
319
+ // await advancedExample()
320
+ }
321
+ // Run if executed directly
322
+ if (import.meta.url === `file://${process.argv[1]}`) {
323
+ main().catch(console.error);
324
+ }
325
+ export { approvalExample, questionExample, decisionExample, goalsExample, advancedExample, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "human-in-the-loop",
3
- "version": "2.0.1",
3
+ "version": "2.1.1",
4
4
  "description": "Primitives for integrating human oversight and intervention in AI workflows",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -20,9 +20,8 @@
20
20
  "clean": "rm -rf dist"
21
21
  },
22
22
  "dependencies": {
23
- "ai-functions": "workspace:*",
24
- "digital-workers": "workspace:*",
25
- "rpc.do": "^0.1.0"
23
+ "ai-functions": "2.1.1",
24
+ "digital-workers": "2.1.1"
26
25
  },
27
26
  "keywords": [
28
27
  "human",
package/src/helpers.js ADDED
@@ -0,0 +1,274 @@
1
+ /**
2
+ * Helper functions for common human-in-the-loop patterns
3
+ */
4
+ import { Human } from './human.js';
5
+ /**
6
+ * Create a default Human instance for convenience
7
+ */
8
+ const defaultHuman = Human();
9
+ /**
10
+ * Define a human role
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * const techLead = Role({
15
+ * id: 'tech-lead',
16
+ * name: 'Tech Lead',
17
+ * capabilities: ['approve-prs', 'deploy-prod'],
18
+ * escalatesTo: 'engineering-manager',
19
+ * })
20
+ * ```
21
+ */
22
+ export function Role(role) {
23
+ return defaultHuman.defineRole(role);
24
+ }
25
+ /**
26
+ * Define a team
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const engineering = Team({
31
+ * id: 'engineering',
32
+ * name: 'Engineering Team',
33
+ * members: ['alice', 'bob', 'charlie'],
34
+ * lead: 'alice',
35
+ * })
36
+ * ```
37
+ */
38
+ export function Team(team) {
39
+ return defaultHuman.defineTeam(team);
40
+ }
41
+ /**
42
+ * Define goals for a team or individual
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const q1Goals = Goals({
47
+ * id: 'q1-2024',
48
+ * objectives: [
49
+ * 'Launch v2.0',
50
+ * 'Improve performance by 50%',
51
+ * ],
52
+ * targetDate: new Date('2024-03-31'),
53
+ * })
54
+ * ```
55
+ */
56
+ export function Goals(goals) {
57
+ return defaultHuman.defineGoals(goals);
58
+ }
59
+ /**
60
+ * Request approval from a human
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * const result = await approve({
65
+ * title: 'Deploy to production',
66
+ * description: 'Deploy v2.0.0 to production',
67
+ * subject: 'Production Deployment',
68
+ * input: { version: '2.0.0', environment: 'prod' },
69
+ * assignee: 'tech-lead@example.com',
70
+ * priority: 'high',
71
+ * })
72
+ *
73
+ * if (result.approved) {
74
+ * await deploy()
75
+ * }
76
+ * ```
77
+ */
78
+ export async function approve(params) {
79
+ return defaultHuman.approve(params);
80
+ }
81
+ /**
82
+ * Ask a question to a human
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const answer = await ask({
87
+ * title: 'Product naming',
88
+ * question: 'What should we name the new feature?',
89
+ * context: { feature: 'AI Assistant' },
90
+ * assignee: 'product-manager@example.com',
91
+ * })
92
+ * ```
93
+ */
94
+ export async function ask(params) {
95
+ return defaultHuman.ask(params);
96
+ }
97
+ /**
98
+ * Request a human to perform a task
99
+ *
100
+ * This uses the digital-workers interface for humans
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * const result = await do({
105
+ * title: 'Review code',
106
+ * instructions: 'Review the PR and provide feedback',
107
+ * input: { prUrl: 'https://github.com/...' },
108
+ * assignee: 'senior-dev@example.com',
109
+ * })
110
+ * ```
111
+ */
112
+ export async function do_(params) {
113
+ return defaultHuman.do(params);
114
+ }
115
+ // Export as 'do' for the API, but define as 'do_' to avoid reserved keyword
116
+ export { do_ as do };
117
+ /**
118
+ * Request a human to make a decision
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * const choice = await decide({
123
+ * title: 'Pick deployment strategy',
124
+ * options: ['blue-green', 'canary', 'rolling'],
125
+ * context: { risk: 'high', users: 100000 },
126
+ * assignee: 'devops-lead@example.com',
127
+ * })
128
+ * ```
129
+ */
130
+ export async function decide(params) {
131
+ return defaultHuman.decide(params);
132
+ }
133
+ /**
134
+ * Request generation/content creation from a human
135
+ *
136
+ * This is a specialized form of do() for content generation
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * const content = await generate({
141
+ * title: 'Write blog post',
142
+ * instructions: 'Write a blog post about our new feature',
143
+ * input: { topic: 'AI Assistant', targetAudience: 'developers' },
144
+ * assignee: 'content-writer@example.com',
145
+ * })
146
+ * ```
147
+ */
148
+ export async function generate(params) {
149
+ return defaultHuman.do(params);
150
+ }
151
+ /**
152
+ * Type checking/validation request
153
+ *
154
+ * Ask a human to validate data or check type compliance
155
+ *
156
+ * @example
157
+ * ```ts
158
+ * const valid = await is({
159
+ * title: 'Validate user data',
160
+ * question: 'Is this user data valid and complete?',
161
+ * input: userData,
162
+ * assignee: 'data-specialist@example.com',
163
+ * })
164
+ * ```
165
+ */
166
+ export async function is(params) {
167
+ const result = await defaultHuman.decide({
168
+ title: params.title,
169
+ description: params.question,
170
+ options: ['true', 'false'],
171
+ context: params.input,
172
+ assignee: params.assignee,
173
+ role: params.role,
174
+ team: params.team,
175
+ priority: params.priority,
176
+ timeout: params.timeout,
177
+ metadata: params.metadata,
178
+ });
179
+ return result === 'true';
180
+ }
181
+ /**
182
+ * Send a notification to a human
183
+ *
184
+ * @example
185
+ * ```ts
186
+ * await notify({
187
+ * type: 'info',
188
+ * title: 'Deployment complete',
189
+ * message: 'Version 2.0.0 deployed successfully',
190
+ * recipient: 'team@example.com',
191
+ * channels: ['slack', 'email'],
192
+ * })
193
+ * ```
194
+ */
195
+ export async function notify(params) {
196
+ await defaultHuman.notify(params);
197
+ }
198
+ /**
199
+ * Track Key Performance Indicators
200
+ *
201
+ * @example
202
+ * ```ts
203
+ * kpis({
204
+ * id: 'monthly-revenue',
205
+ * name: 'Monthly Revenue',
206
+ * value: 150000,
207
+ * target: 200000,
208
+ * unit: 'USD',
209
+ * trend: 'up',
210
+ * })
211
+ * ```
212
+ */
213
+ export function kpis(kpis) {
214
+ return defaultHuman.trackKPIs(kpis);
215
+ }
216
+ /**
217
+ * Define Objectives and Key Results
218
+ *
219
+ * @example
220
+ * ```ts
221
+ * okrs({
222
+ * id: 'q1-2024-growth',
223
+ * objective: 'Accelerate user growth',
224
+ * keyResults: [
225
+ * {
226
+ * description: 'Increase active users by 50%',
227
+ * progress: 0.3,
228
+ * current: 13000,
229
+ * target: 15000,
230
+ * },
231
+ * {
232
+ * description: 'Achieve 95% customer satisfaction',
233
+ * progress: 0.85,
234
+ * current: 0.93,
235
+ * target: 0.95,
236
+ * },
237
+ * ],
238
+ * period: 'Q1 2024',
239
+ * owner: 'ceo@example.com',
240
+ * })
241
+ * ```
242
+ */
243
+ export function okrs(okrs) {
244
+ return defaultHuman.defineOKRs(okrs);
245
+ }
246
+ /**
247
+ * Register a human worker in the system
248
+ *
249
+ * @example
250
+ * ```ts
251
+ * const alice = registerHuman({
252
+ * id: 'alice',
253
+ * name: 'Alice Smith',
254
+ * email: 'alice@example.com',
255
+ * roles: ['tech-lead', 'developer'],
256
+ * teams: ['engineering', 'frontend'],
257
+ * channels: {
258
+ * slack: '@alice',
259
+ * email: 'alice@example.com',
260
+ * },
261
+ * })
262
+ * ```
263
+ */
264
+ export function registerHuman(human) {
265
+ return defaultHuman.registerHuman(human);
266
+ }
267
+ /**
268
+ * Get the default Human manager instance
269
+ *
270
+ * Use this to access the underlying HumanManager for advanced operations
271
+ */
272
+ export function getDefaultHuman() {
273
+ return defaultHuman;
274
+ }