human-in-the-loop 0.1.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.
- package/README.md +222 -0
- package/TODO.md +53 -0
- package/dist/index.cjs +899 -0
- package/dist/index.d.cts +344 -0
- package/dist/index.d.ts +344 -0
- package/dist/index.js +793 -0
- package/package.json +65 -0
- package/src/core/factory.test.ts +69 -0
- package/src/core/factory.ts +30 -0
- package/src/core/types.ts +191 -0
- package/src/index.ts +7 -0
- package/src/platforms/email/index.tsx +137 -0
- package/src/platforms/react/index.tsx +218 -0
- package/src/platforms/slack/index.ts +84 -0
- package/src/platforms/teams/index.ts +84 -0
- package/tsconfig.json +14 -0
- package/vitest.config.ts +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Human-in-the-Loop
|
|
2
|
+
|
|
3
|
+
A strongly-typed interface for human functions across multiple platforms.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install human-in-the-loop
|
|
9
|
+
# or
|
|
10
|
+
yarn add human-in-the-loop
|
|
11
|
+
# or
|
|
12
|
+
pnpm add human-in-the-loop
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- Strongly-typed human functions with TypeScript generics
|
|
18
|
+
- Support for multiple platforms:
|
|
19
|
+
- Slack (using Block Kit)
|
|
20
|
+
- Microsoft Teams
|
|
21
|
+
- React/ShadCN UI components
|
|
22
|
+
- Email (via React Email)
|
|
23
|
+
- Simple, consistent API across all platforms
|
|
24
|
+
- Type-safe inputs and outputs
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### Basic Example
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { createHumanFunction } from 'human-in-the-loop'
|
|
32
|
+
|
|
33
|
+
// Define a strongly-typed human function for approval
|
|
34
|
+
const getApproval = createHumanFunction<
|
|
35
|
+
{ documentTitle: string, documentUrl: string },
|
|
36
|
+
{ approved: boolean, comments?: string }
|
|
37
|
+
>({
|
|
38
|
+
platform: 'slack',
|
|
39
|
+
title: 'Document Approval Request',
|
|
40
|
+
description: 'Please review and approve the following document:',
|
|
41
|
+
options: [
|
|
42
|
+
{ value: 'approve', label: 'Approve' },
|
|
43
|
+
{ value: 'reject', label: 'Reject' }
|
|
44
|
+
],
|
|
45
|
+
freeText: true,
|
|
46
|
+
// Slack-specific options
|
|
47
|
+
channel: 'approvals'
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// Request human input
|
|
51
|
+
const task = await getApproval.request({
|
|
52
|
+
documentTitle: 'Q2 Financial Report',
|
|
53
|
+
documentUrl: 'https://example.com/docs/q2-finance'
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
console.log(`Task created with ID: ${task.taskId}`)
|
|
57
|
+
|
|
58
|
+
// Later, get the response
|
|
59
|
+
const response = await getApproval.getResponse(task.taskId)
|
|
60
|
+
if (response?.approved) {
|
|
61
|
+
console.log('Document was approved!')
|
|
62
|
+
if (response.comments) {
|
|
63
|
+
console.log(`Comments: ${response.comments}`)
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
console.log('Document was rejected or pending')
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Platform-Specific Examples
|
|
71
|
+
|
|
72
|
+
#### Slack
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { createHumanFunction } from 'human-in-the-loop'
|
|
76
|
+
|
|
77
|
+
const slackFeedback = createHumanFunction<
|
|
78
|
+
{ featureDescription: string },
|
|
79
|
+
{ rating: number, feedback?: string }
|
|
80
|
+
>({
|
|
81
|
+
platform: 'slack',
|
|
82
|
+
title: 'Feature Feedback Request',
|
|
83
|
+
description: 'Please provide feedback on our new feature:',
|
|
84
|
+
options: [
|
|
85
|
+
{ value: '1', label: '⭐ Poor' },
|
|
86
|
+
{ value: '2', label: '⭐⭐ Fair' },
|
|
87
|
+
{ value: '3', label: '⭐⭐⭐ Good' },
|
|
88
|
+
{ value: '4', label: '⭐⭐⭐⭐ Very Good' },
|
|
89
|
+
{ value: '5', label: '⭐⭐⭐⭐⭐ Excellent' }
|
|
90
|
+
],
|
|
91
|
+
freeText: true,
|
|
92
|
+
channel: 'product-feedback'
|
|
93
|
+
})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### Microsoft Teams
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { createHumanFunction } from 'human-in-the-loop'
|
|
100
|
+
|
|
101
|
+
const teamsApproval = createHumanFunction<
|
|
102
|
+
{ requestDetails: string },
|
|
103
|
+
{ approved: boolean }
|
|
104
|
+
>({
|
|
105
|
+
platform: 'teams',
|
|
106
|
+
title: 'Approval Request',
|
|
107
|
+
description: 'Please review and approve this request:',
|
|
108
|
+
options: [
|
|
109
|
+
{ value: 'approve', label: 'Approve' },
|
|
110
|
+
{ value: 'reject', label: 'Reject' }
|
|
111
|
+
],
|
|
112
|
+
webhookUrl: process.env.TEAMS_WEBHOOK_URL,
|
|
113
|
+
useAdaptiveCards: true
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### React
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import { createHumanFunction, ReactHumanFunction } from 'human-in-the-loop'
|
|
121
|
+
import React, { useState } from 'react'
|
|
122
|
+
|
|
123
|
+
// Create the human function
|
|
124
|
+
const reactFeedback = createHumanFunction<
|
|
125
|
+
{ productName: string },
|
|
126
|
+
{ rating: number, comments?: string }
|
|
127
|
+
>({
|
|
128
|
+
platform: 'react',
|
|
129
|
+
title: 'Product Feedback',
|
|
130
|
+
description: 'Please rate this product and provide any comments:',
|
|
131
|
+
options: [
|
|
132
|
+
{ value: '1', label: '1 - Poor' },
|
|
133
|
+
{ value: '2', label: '2 - Fair' },
|
|
134
|
+
{ value: '3', label: '3 - Good' },
|
|
135
|
+
{ value: '4', label: '4 - Very Good' },
|
|
136
|
+
{ value: '5', label: '5 - Excellent' }
|
|
137
|
+
],
|
|
138
|
+
freeText: true,
|
|
139
|
+
theme: 'light'
|
|
140
|
+
}) as ReactHumanFunction<{ productName: string }, { rating: number, comments?: string }>
|
|
141
|
+
|
|
142
|
+
// In your React component
|
|
143
|
+
function FeedbackComponent() {
|
|
144
|
+
const [taskId, setTaskId] = useState<string | null>(null)
|
|
145
|
+
|
|
146
|
+
const handleRequestFeedback = async () => {
|
|
147
|
+
const task = await reactFeedback.request({ productName: 'Super Product' })
|
|
148
|
+
setTaskId(task.taskId)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<div>
|
|
153
|
+
<button onClick={handleRequestFeedback}>Request Feedback</button>
|
|
154
|
+
|
|
155
|
+
{taskId && reactFeedback.getComponent(taskId, { productName: 'Super Product' })}
|
|
156
|
+
</div>
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### Email
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { createHumanFunction, EmailHumanFunction } from 'human-in-the-loop'
|
|
165
|
+
import React from 'react'
|
|
166
|
+
import { render } from 'react-email'
|
|
167
|
+
|
|
168
|
+
// Create the human function
|
|
169
|
+
const emailSurvey = createHumanFunction<
|
|
170
|
+
{ surveyTopic: string },
|
|
171
|
+
{ response: string }
|
|
172
|
+
>({
|
|
173
|
+
platform: 'email',
|
|
174
|
+
title: 'Customer Survey',
|
|
175
|
+
description: 'Please complete our customer satisfaction survey:',
|
|
176
|
+
options: [
|
|
177
|
+
{ value: 'very-satisfied', label: 'Very Satisfied' },
|
|
178
|
+
{ value: 'satisfied', label: 'Satisfied' },
|
|
179
|
+
{ value: 'neutral', label: 'Neutral' },
|
|
180
|
+
{ value: 'dissatisfied', label: 'Dissatisfied' },
|
|
181
|
+
{ value: 'very-dissatisfied', label: 'Very Dissatisfied' }
|
|
182
|
+
],
|
|
183
|
+
to: 'customer@example.com',
|
|
184
|
+
from: 'surveys@company.com',
|
|
185
|
+
callbackUrl: 'https://example.com/api/survey-response'
|
|
186
|
+
}) as EmailHumanFunction<{ surveyTopic: string }, { response: string }>
|
|
187
|
+
|
|
188
|
+
// Get the email template as HTML
|
|
189
|
+
const taskId = 'task-123'
|
|
190
|
+
const emailComponent = emailSurvey.getEmailComponent(taskId)
|
|
191
|
+
const emailHtml = render(emailComponent)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## API Reference
|
|
195
|
+
|
|
196
|
+
### `createHumanFunction<TInput, TOutput>(options)`
|
|
197
|
+
|
|
198
|
+
Creates a strongly-typed human function with the specified input and output types.
|
|
199
|
+
|
|
200
|
+
#### Options
|
|
201
|
+
|
|
202
|
+
- `platform`: The platform to use ('slack', 'teams', 'react', or 'email')
|
|
203
|
+
- `title`: Title of the request shown to humans
|
|
204
|
+
- `description`: Description of the task for humans
|
|
205
|
+
- `options`: Array of options for the human to choose from
|
|
206
|
+
- `freeText`: Whether to allow free text input
|
|
207
|
+
- `timeout`: Timeout in milliseconds after which the task is marked as timed out
|
|
208
|
+
|
|
209
|
+
Platform-specific options are also available based on the selected platform.
|
|
210
|
+
|
|
211
|
+
### `HumanFunction<TInput, TOutput>`
|
|
212
|
+
|
|
213
|
+
The interface for human functions.
|
|
214
|
+
|
|
215
|
+
#### Methods
|
|
216
|
+
|
|
217
|
+
- `request(input: TInput): Promise<HumanTaskRequest>`: Request human input with the given input data
|
|
218
|
+
- `getResponse(taskId: string): Promise<TOutput | null>`: Get the human response for a given task
|
|
219
|
+
|
|
220
|
+
## License
|
|
221
|
+
|
|
222
|
+
MIT
|
package/TODO.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Human-in-the-Loop Implementation Progress
|
|
2
|
+
|
|
3
|
+
## Core Implementation
|
|
4
|
+
- [x] Set up package structure
|
|
5
|
+
- [x] Define core types and interfaces
|
|
6
|
+
- [x] Implement factory function
|
|
7
|
+
- [x] Create basic tests
|
|
8
|
+
|
|
9
|
+
## Platform Implementations
|
|
10
|
+
- [x] Slack implementation
|
|
11
|
+
- [x] Create SlackHumanFunction class
|
|
12
|
+
- [x] Implement request and getResponse methods
|
|
13
|
+
- [ ] Implement real Slack Block Kit integration
|
|
14
|
+
- [x] Microsoft Teams implementation
|
|
15
|
+
- [x] Create TeamsHumanFunction class
|
|
16
|
+
- [x] Implement request and getResponse methods
|
|
17
|
+
- [ ] Implement real Teams Adaptive Cards integration
|
|
18
|
+
- [x] React/ShadCN implementation
|
|
19
|
+
- [x] Create ReactHumanFunction class
|
|
20
|
+
- [x] Implement HumanFeedback component
|
|
21
|
+
- [x] Add styling and theming support
|
|
22
|
+
- [ ] Add ShadCN UI components
|
|
23
|
+
- [x] Email (React Email) implementation
|
|
24
|
+
- [x] Create EmailHumanFunction class
|
|
25
|
+
- [x] Implement EmailTemplate component
|
|
26
|
+
- [ ] Implement real email sending functionality
|
|
27
|
+
|
|
28
|
+
## Documentation
|
|
29
|
+
- [x] Create README with usage examples
|
|
30
|
+
- [x] Add JSDoc comments to public APIs
|
|
31
|
+
- [ ] Create API reference documentation
|
|
32
|
+
- [ ] Add more comprehensive examples
|
|
33
|
+
|
|
34
|
+
## Technical Challenges and Blockers
|
|
35
|
+
- [ ] Need to implement real platform integrations (currently mocked)
|
|
36
|
+
- [ ] Need to add proper error handling and timeout mechanisms
|
|
37
|
+
- [ ] Need to implement persistent storage for responses
|
|
38
|
+
|
|
39
|
+
## Verification Requirements
|
|
40
|
+
- [x] Basic unit tests for factory function
|
|
41
|
+
- [ ] Integration tests for each platform
|
|
42
|
+
- [ ] End-to-end tests with real platform integrations
|
|
43
|
+
- [ ] Performance tests for large-scale usage
|
|
44
|
+
|
|
45
|
+
## Future Enhancements
|
|
46
|
+
- [ ] Add more comprehensive tests
|
|
47
|
+
- [ ] Implement real platform integrations (currently mocked)
|
|
48
|
+
- [ ] Add more customization options for each platform
|
|
49
|
+
- [ ] Create example applications
|
|
50
|
+
- [ ] Add support for more platforms (Discord, Telegram, etc.)
|
|
51
|
+
- [ ] Implement webhook handlers for platform callbacks
|
|
52
|
+
- [ ] Add authentication and authorization mechanisms
|
|
53
|
+
- [ ] Implement rate limiting and throttling
|