digital-workers 2.1.1 → 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.
- package/CHANGELOG.md +23 -0
- package/README.md +136 -180
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +34 -21
- package/dist/actions.js.map +1 -1
- package/dist/agent-comms.d.ts +438 -0
- package/dist/agent-comms.d.ts.map +1 -0
- package/dist/agent-comms.js +677 -0
- package/dist/agent-comms.js.map +1 -0
- package/dist/approve.d.ts +40 -8
- package/dist/approve.d.ts.map +1 -1
- package/dist/approve.js +86 -20
- package/dist/approve.js.map +1 -1
- package/dist/ask.d.ts +38 -7
- package/dist/ask.d.ts.map +1 -1
- package/dist/ask.js +85 -25
- package/dist/ask.js.map +1 -1
- package/dist/browse.d.ts +223 -0
- package/dist/browse.d.ts.map +1 -0
- package/dist/browse.js +392 -0
- package/dist/browse.js.map +1 -0
- package/dist/capability-tiers.d.ts +230 -0
- package/dist/capability-tiers.d.ts.map +1 -0
- package/dist/capability-tiers.js +388 -0
- package/dist/capability-tiers.js.map +1 -0
- package/dist/cascade-context.d.ts +523 -0
- package/dist/cascade-context.d.ts.map +1 -0
- package/dist/cascade-context.js +494 -0
- package/dist/cascade-context.js.map +1 -0
- package/dist/client.d.ts +162 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +64 -0
- package/dist/client.js.map +1 -0
- package/dist/decide.d.ts +42 -6
- package/dist/decide.d.ts.map +1 -1
- package/dist/decide.js +54 -11
- package/dist/decide.js.map +1 -1
- package/dist/do.d.ts +36 -7
- package/dist/do.d.ts.map +1 -1
- package/dist/do.js +82 -39
- package/dist/do.js.map +1 -1
- package/dist/error-escalation.d.ts +416 -0
- package/dist/error-escalation.d.ts.map +1 -0
- package/dist/error-escalation.js +656 -0
- package/dist/error-escalation.js.map +1 -0
- package/dist/generate.d.ts +48 -7
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +49 -8
- package/dist/generate.js.map +1 -1
- package/dist/goals.d.ts +10 -9
- package/dist/goals.d.ts.map +1 -1
- package/dist/goals.js +30 -24
- package/dist/goals.js.map +1 -1
- package/dist/image.d.ts +189 -0
- package/dist/image.d.ts.map +1 -0
- package/dist/image.js +528 -0
- package/dist/image.js.map +1 -0
- package/dist/index.d.ts +59 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +92 -2
- package/dist/index.js.map +1 -1
- package/dist/is.d.ts +45 -10
- package/dist/is.d.ts.map +1 -1
- package/dist/is.js +56 -21
- package/dist/is.js.map +1 -1
- package/dist/kpis.d.ts +24 -15
- package/dist/kpis.d.ts.map +1 -1
- package/dist/kpis.js +16 -14
- package/dist/kpis.js.map +1 -1
- package/dist/load-balancing.d.ts +395 -0
- package/dist/load-balancing.d.ts.map +1 -0
- package/dist/load-balancing.js +991 -0
- package/dist/load-balancing.js.map +1 -0
- package/dist/logger.d.ts +76 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +39 -0
- package/dist/logger.js.map +1 -0
- package/dist/notify.d.ts +38 -9
- package/dist/notify.d.ts.map +1 -1
- package/dist/notify.js +72 -17
- package/dist/notify.js.map +1 -1
- package/dist/role.d.ts +5 -4
- package/dist/role.d.ts.map +1 -1
- package/dist/role.js +13 -10
- package/dist/role.js.map +1 -1
- package/dist/runtime.d.ts +310 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +510 -0
- package/dist/runtime.js.map +1 -0
- package/dist/team.d.ts +11 -6
- package/dist/team.d.ts.map +1 -1
- package/dist/team.js +22 -15
- package/dist/team.js.map +1 -1
- package/dist/transports/email.d.ts +318 -0
- package/dist/transports/email.d.ts.map +1 -0
- package/dist/transports/email.js +779 -0
- package/dist/transports/email.js.map +1 -0
- package/dist/transports/slack.d.ts +515 -0
- package/dist/transports/slack.d.ts.map +1 -0
- package/dist/transports/slack.js +844 -0
- package/dist/transports/slack.js.map +1 -0
- package/dist/transports.d.ts.map +1 -1
- package/dist/transports.js +44 -25
- package/dist/transports.js.map +1 -1
- package/dist/types.d.ts +149 -19
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/id.d.ts +19 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +21 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/video.d.ts +203 -0
- package/dist/video.d.ts.map +1 -0
- package/dist/video.js +528 -0
- package/dist/video.js.map +1 -0
- package/dist/worker.d.ts +343 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +698 -0
- package/dist/worker.js.map +1 -0
- package/package.json +24 -5
- package/src/actions.ts +48 -38
- package/src/agent-comms.ts +1200 -0
- package/src/approve.ts +91 -20
- package/src/ask.ts +99 -25
- package/src/browse.ts +627 -0
- package/src/capability-tiers.ts +545 -0
- package/src/cascade-context.ts +648 -0
- package/src/client.ts +221 -0
- package/src/decide.ts +81 -35
- package/src/do.ts +98 -52
- package/src/error-escalation.ts +1123 -0
- package/src/generate.ts +52 -18
- package/src/goals.ts +36 -27
- package/src/image.ts +816 -0
- package/src/index.ts +410 -2
- package/src/is.ts +59 -25
- package/src/kpis.ts +41 -36
- package/src/load-balancing.ts +1467 -0
- package/src/logger.ts +93 -0
- package/src/notify.ts +78 -17
- package/src/role.ts +30 -20
- package/src/runtime.ts +796 -0
- package/src/team.ts +24 -19
- package/src/transports/email.ts +1160 -0
- package/src/transports/slack.ts +1320 -0
- package/src/transports.ts +58 -43
- package/src/types.ts +182 -46
- package/src/utils/id.ts +21 -0
- package/src/video.ts +906 -0
- package/src/worker.ts +1007 -0
- package/test/agent-comms.test.ts +1397 -0
- package/test/approve.test.ts +305 -0
- package/test/ask.test.ts +274 -0
- package/test/browse.test.ts +361 -0
- package/test/capability-tiers.test.ts +631 -0
- package/test/cascade-context.test.ts +692 -0
- package/test/decide.test.ts +252 -0
- package/test/do.test.ts +144 -0
- package/test/error-escalation.test.ts +1205 -0
- package/test/error-logging.test.ts +357 -0
- package/test/generate.test.ts +319 -0
- package/test/image.test.ts +398 -0
- package/test/is.test.ts +287 -0
- package/test/load-balancing-safety.test.ts +404 -0
- package/test/load-balancing-thread-safety.test.ts +464 -0
- package/test/load-balancing.test.ts +1145 -0
- package/test/notify.test.ts +434 -0
- package/test/primitives.test.ts +320 -0
- package/test/runtime-integration.test.ts +892 -0
- package/test/transports/crypto.test.ts +230 -0
- package/test/transports/email.test.ts +866 -0
- package/test/transports/id-generation.test.ts +91 -0
- package/test/transports/slack.test.ts +760 -0
- package/test/type-safety.test.ts +834 -0
- package/test/types.test.ts +95 -2
- package/test/video.test.ts +530 -0
- package/test/worker.test.ts +1433 -0
- package/tsconfig.json +4 -1
- package/vitest.config.ts +42 -0
- package/wrangler.jsonc +36 -0
- package/.turbo/turbo-build.log +0 -5
- package/src/actions.js +0 -436
- package/src/approve.js +0 -234
- package/src/ask.js +0 -226
- package/src/decide.js +0 -244
- package/src/do.js +0 -227
- package/src/generate.js +0 -298
- package/src/goals.js +0 -205
- package/src/index.js +0 -68
- package/src/is.js +0 -317
- package/src/kpis.js +0 -270
- package/src/notify.js +0 -219
- package/src/role.js +0 -110
- package/src/team.js +0 -130
- package/src/transports.js +0 -357
- package/src/types.js +0 -71
package/src/client.ts
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RPC Client for Digital Workers
|
|
3
|
+
*
|
|
4
|
+
* Provides a typed RPC client that connects to the deployed
|
|
5
|
+
* digital-workers worker using rpc.do for remote procedure calls.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createDigitalWorkersClient } from 'digital-workers/client'
|
|
10
|
+
*
|
|
11
|
+
* const client = createDigitalWorkersClient('https://digital-workers.workers.dev')
|
|
12
|
+
* const worker = await client.spawn({ name: 'my-agent', type: 'agent' })
|
|
13
|
+
* await client.send(worker.id, otherWorkerId, 'task', { data: 'hello' })
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @packageDocumentation
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { RPC, http } from 'rpc.do'
|
|
20
|
+
|
|
21
|
+
// ==================== Types ====================
|
|
22
|
+
|
|
23
|
+
/** Worker instance status */
|
|
24
|
+
type WorkerInstanceStatus = 'spawning' | 'running' | 'paused' | 'terminated' | 'error'
|
|
25
|
+
|
|
26
|
+
/** Worker instance state */
|
|
27
|
+
interface WorkerInstance {
|
|
28
|
+
id: string
|
|
29
|
+
name: string
|
|
30
|
+
status: WorkerInstanceStatus
|
|
31
|
+
type: 'agent' | 'human'
|
|
32
|
+
tier?: string | undefined
|
|
33
|
+
createdAt: Date
|
|
34
|
+
updatedAt: Date
|
|
35
|
+
metadata?: Record<string, unknown> | undefined
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Message sent between workers */
|
|
39
|
+
interface WorkerMessage<T = unknown> {
|
|
40
|
+
id: string
|
|
41
|
+
from: string
|
|
42
|
+
to: string
|
|
43
|
+
type: string
|
|
44
|
+
payload: T
|
|
45
|
+
timestamp: Date
|
|
46
|
+
acknowledged?: boolean
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Worker spawn options */
|
|
50
|
+
interface SpawnOptions {
|
|
51
|
+
name?: string
|
|
52
|
+
type?: 'agent' | 'human'
|
|
53
|
+
tier?: string
|
|
54
|
+
metadata?: Record<string, unknown>
|
|
55
|
+
timeout?: number
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Receive options */
|
|
59
|
+
interface ReceiveOptions {
|
|
60
|
+
type?: string
|
|
61
|
+
limit?: number
|
|
62
|
+
acknowledged?: boolean
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** List options */
|
|
66
|
+
interface ListOptions {
|
|
67
|
+
status?: WorkerInstanceStatus
|
|
68
|
+
type?: 'agent' | 'human'
|
|
69
|
+
tier?: string
|
|
70
|
+
limit?: number
|
|
71
|
+
includeTerminated?: boolean
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Set state options */
|
|
75
|
+
interface SetStateOptions {
|
|
76
|
+
metadata?: Record<string, unknown>
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Broadcast result */
|
|
80
|
+
interface BroadcastResult {
|
|
81
|
+
workerId: string
|
|
82
|
+
success: boolean
|
|
83
|
+
messageId?: string | undefined
|
|
84
|
+
error?: string | undefined
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Coordination task */
|
|
88
|
+
interface CoordinationTask<T = unknown> {
|
|
89
|
+
id: string
|
|
90
|
+
type: 'fanout' | 'pipeline' | 'race' | 'consensus'
|
|
91
|
+
workers: string[]
|
|
92
|
+
status: 'pending' | 'running' | 'completed' | 'failed'
|
|
93
|
+
result?: T | undefined
|
|
94
|
+
errors?: Error[] | undefined
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Consensus options */
|
|
98
|
+
interface ConsensusOptions {
|
|
99
|
+
quorum?: number
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ==================== API Type ====================
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* DigitalWorkersAPI - Type-safe interface matching DigitalWorkersServiceCore RPC methods
|
|
106
|
+
*
|
|
107
|
+
* This interface mirrors all public methods on DigitalWorkersServiceCore so that
|
|
108
|
+
* the RPC client provides full type safety when calling remote methods.
|
|
109
|
+
*/
|
|
110
|
+
export interface DigitalWorkersAPI {
|
|
111
|
+
// Worker Lifecycle Management
|
|
112
|
+
spawn(options?: SpawnOptions): Promise<WorkerInstance>
|
|
113
|
+
terminate(workerId: string): Promise<boolean>
|
|
114
|
+
pause(workerId: string): Promise<boolean>
|
|
115
|
+
resume(workerId: string): Promise<boolean>
|
|
116
|
+
|
|
117
|
+
// Worker Communication / Messaging
|
|
118
|
+
send<T = unknown>(
|
|
119
|
+
fromId: string,
|
|
120
|
+
toId: string,
|
|
121
|
+
type: string,
|
|
122
|
+
payload: T
|
|
123
|
+
): Promise<WorkerMessage<T>>
|
|
124
|
+
receive<T = unknown>(workerId: string, options?: ReceiveOptions): Promise<WorkerMessage<T>[]>
|
|
125
|
+
acknowledge(workerId: string, messageId: string): Promise<boolean>
|
|
126
|
+
broadcast<T = unknown>(
|
|
127
|
+
fromId: string,
|
|
128
|
+
toIds: string[],
|
|
129
|
+
type: string,
|
|
130
|
+
payload: T
|
|
131
|
+
): Promise<BroadcastResult[]>
|
|
132
|
+
|
|
133
|
+
// Worker State Management
|
|
134
|
+
getState(workerId: string): Promise<WorkerInstance | null>
|
|
135
|
+
setState(workerId: string, options: SetStateOptions): Promise<void>
|
|
136
|
+
list(options?: ListOptions): Promise<WorkerInstance[]>
|
|
137
|
+
|
|
138
|
+
// Worker Coordination Patterns
|
|
139
|
+
fanOut<T = unknown>(
|
|
140
|
+
coordinatorId: string,
|
|
141
|
+
workerIds: string[],
|
|
142
|
+
type: string,
|
|
143
|
+
payload: T
|
|
144
|
+
): Promise<CoordinationTask<T>>
|
|
145
|
+
pipeline<T = unknown>(workerIds: string[], type: string, payload: T): Promise<CoordinationTask<T>>
|
|
146
|
+
race<T = unknown>(workerIds: string[], type: string, payload: T): Promise<CoordinationTask<T>>
|
|
147
|
+
consensus<T = unknown>(
|
|
148
|
+
workerIds: string[],
|
|
149
|
+
type: string,
|
|
150
|
+
payload: T,
|
|
151
|
+
options?: ConsensusOptions
|
|
152
|
+
): Promise<CoordinationTask<T>>
|
|
153
|
+
getTaskStatus<T = unknown>(taskId: string): Promise<CoordinationTask<T> | null>
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ==================== Client Options ====================
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Options for creating a digital workers RPC client
|
|
160
|
+
*/
|
|
161
|
+
export interface DigitalWorkersClientOptions {
|
|
162
|
+
/** Authentication token or API key */
|
|
163
|
+
token?: string
|
|
164
|
+
/** Request timeout in milliseconds */
|
|
165
|
+
timeout?: number
|
|
166
|
+
/** Custom headers to include in requests */
|
|
167
|
+
headers?: Record<string, string>
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ==================== Client Factory ====================
|
|
171
|
+
|
|
172
|
+
/** Default URL for the digital-workers worker */
|
|
173
|
+
const DEFAULT_URL = 'https://digital-workers.workers.dev'
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Create a typed RPC client for the digital-workers worker
|
|
177
|
+
*
|
|
178
|
+
* @param url - The URL of the deployed digital-workers worker
|
|
179
|
+
* @param options - Optional client configuration
|
|
180
|
+
* @returns A typed RPC client with all DigitalWorkersServiceCore methods
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```ts
|
|
184
|
+
* import { createDigitalWorkersClient } from 'digital-workers/client'
|
|
185
|
+
*
|
|
186
|
+
* // Connect to production
|
|
187
|
+
* const client = createDigitalWorkersClient('https://digital-workers.workers.dev')
|
|
188
|
+
*
|
|
189
|
+
* // Spawn and manage workers
|
|
190
|
+
* const agent = await client.spawn({ name: 'my-agent', type: 'agent' })
|
|
191
|
+
* const human = await client.spawn({ name: 'reviewer', type: 'human' })
|
|
192
|
+
*
|
|
193
|
+
* // Send messages between workers
|
|
194
|
+
* await client.send(agent.id, human.id, 'review-request', { content: 'Please review' })
|
|
195
|
+
* const messages = await client.receive(human.id, { type: 'review-request' })
|
|
196
|
+
*
|
|
197
|
+
* // Coordinate multiple workers
|
|
198
|
+
* const task = await client.fanOut(agent.id, [worker1.id, worker2.id], 'process', data)
|
|
199
|
+
* const status = await client.getTaskStatus(task.id)
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
export function createDigitalWorkersClient(
|
|
203
|
+
url: string = DEFAULT_URL,
|
|
204
|
+
options?: DigitalWorkersClientOptions
|
|
205
|
+
) {
|
|
206
|
+
return RPC<DigitalWorkersAPI>(http(url, options?.token))
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Default client instance connected to the production digital-workers worker
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```ts
|
|
214
|
+
* import client from 'digital-workers/client'
|
|
215
|
+
*
|
|
216
|
+
* const worker = await client.spawn({ name: 'my-agent' })
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
const client = createDigitalWorkersClient()
|
|
220
|
+
|
|
221
|
+
export default client
|
package/src/decide.ts
CHANGED
|
@@ -1,21 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Decision-making functionality for digital workers
|
|
3
|
+
*
|
|
4
|
+
* IMPORTANT: Worker-Assisted Decisions vs LLM Judging
|
|
5
|
+
* ----------------------------------------------------
|
|
6
|
+
* This module provides structured decision-making that can involve human
|
|
7
|
+
* decision-makers, NOT simple LLM-based option selection.
|
|
8
|
+
*
|
|
9
|
+
* - `digital-workers.decide()` - Structured decision-making with criteria
|
|
10
|
+
* evaluation, confidence scoring, and optional human approval routing.
|
|
11
|
+
*
|
|
12
|
+
* - `ai-functions.decide()` - LLM as judge - compares options and picks
|
|
13
|
+
* the best one based on criteria (curried function pattern).
|
|
14
|
+
*
|
|
15
|
+
* Use digital-workers when you need:
|
|
16
|
+
* - Multi-criteria decision analysis
|
|
17
|
+
* - Confidence scores and alternative rankings
|
|
18
|
+
* - Human approval for critical decisions
|
|
19
|
+
* - Audit trail of decision reasoning
|
|
20
|
+
*
|
|
21
|
+
* Use ai-functions when you need:
|
|
22
|
+
* - Simple "pick the best" comparison
|
|
23
|
+
* - LLM judging between options
|
|
24
|
+
* - Curried decision function pattern
|
|
25
|
+
*
|
|
26
|
+
* @module
|
|
3
27
|
*/
|
|
4
28
|
|
|
5
29
|
import { generateObject } from 'ai-functions'
|
|
6
30
|
import type { Decision, DecideOptions } from './types.js'
|
|
7
31
|
|
|
8
32
|
/**
|
|
9
|
-
* Make a decision
|
|
33
|
+
* Make a structured decision with criteria evaluation and optional human routing.
|
|
34
|
+
*
|
|
35
|
+
* **Key Difference from ai-functions.decide():**
|
|
36
|
+
* Unlike `ai-functions.decide()` which is a curried LLM judge function
|
|
37
|
+
* (e.g., `decide\`criteria\`(optionA, optionB)`), this function provides
|
|
38
|
+
* comprehensive decision analysis with:
|
|
39
|
+
* - Multi-criteria scoring
|
|
40
|
+
* - Confidence levels
|
|
41
|
+
* - Alternative rankings
|
|
42
|
+
* - Optional human approval routing via `decide.withApproval()`
|
|
10
43
|
*
|
|
11
|
-
*
|
|
12
|
-
* or can route to human decision-makers for critical choices.
|
|
44
|
+
* This is a **decision framework**, not a simple LLM comparison primitive.
|
|
13
45
|
*
|
|
14
|
-
* @param options - Decision options
|
|
15
|
-
* @returns Promise resolving to decision
|
|
46
|
+
* @param options - Decision options including choices, context, and criteria
|
|
47
|
+
* @returns Promise resolving to decision with choice, reasoning, confidence, and alternatives
|
|
16
48
|
*
|
|
17
49
|
* @example
|
|
18
50
|
* ```ts
|
|
51
|
+
* // Structured decision with criteria evaluation
|
|
19
52
|
* const decision = await decide({
|
|
20
53
|
* options: ['Option A', 'Option B', 'Option C'],
|
|
21
54
|
* context: 'We need to choose a technology stack for our new project',
|
|
@@ -29,7 +62,8 @@ import type { Decision, DecideOptions } from './types.js'
|
|
|
29
62
|
*
|
|
30
63
|
* console.log(`Decision: ${decision.choice}`)
|
|
31
64
|
* console.log(`Reasoning: ${decision.reasoning}`)
|
|
32
|
-
* console.log(`Confidence: ${decision.confidence}`)
|
|
65
|
+
* console.log(`Confidence: ${decision.confidence}`) // 0-1 score
|
|
66
|
+
* console.log(`Alternatives:`, decision.alternatives)
|
|
33
67
|
* ```
|
|
34
68
|
*
|
|
35
69
|
* @example
|
|
@@ -50,23 +84,19 @@ import type { Decision, DecideOptions } from './types.js'
|
|
|
50
84
|
* criteria: ['Cost', 'Time to market', 'Risk', 'Scalability'],
|
|
51
85
|
* })
|
|
52
86
|
* ```
|
|
87
|
+
*
|
|
88
|
+
* @see {@link ai-functions#decide} for LLM-as-judge option comparison
|
|
53
89
|
*/
|
|
54
|
-
export async function decide<T = string>(
|
|
55
|
-
options:
|
|
56
|
-
): Promise<Decision<T>> {
|
|
57
|
-
const {
|
|
58
|
-
options: choices,
|
|
59
|
-
context,
|
|
60
|
-
criteria = [],
|
|
61
|
-
includeReasoning = true,
|
|
62
|
-
} = options
|
|
90
|
+
export async function decide<T = string>(options: DecideOptions<T>): Promise<Decision<T>> {
|
|
91
|
+
const { options: choices, context, criteria = [], includeReasoning = true } = options
|
|
63
92
|
|
|
64
93
|
// Format context for the prompt
|
|
65
|
-
const contextStr =
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
94
|
+
const contextStr =
|
|
95
|
+
typeof context === 'string'
|
|
96
|
+
? context
|
|
97
|
+
: context
|
|
98
|
+
? JSON.stringify(context, null, 2)
|
|
99
|
+
: 'No additional context provided'
|
|
70
100
|
|
|
71
101
|
// Format choices for the prompt
|
|
72
102
|
const choicesStr = choices
|
|
@@ -92,13 +122,18 @@ export async function decide<T = string>(
|
|
|
92
122
|
score: 'Score for this alternative from 0-100 (number)',
|
|
93
123
|
},
|
|
94
124
|
],
|
|
95
|
-
criteriaScores:
|
|
96
|
-
|
|
97
|
-
|
|
125
|
+
criteriaScores:
|
|
126
|
+
criteria.length > 0
|
|
127
|
+
? 'Scores for each criterion as object mapping criterion name to score (0-100)'
|
|
128
|
+
: undefined,
|
|
98
129
|
},
|
|
99
130
|
system: `You are a decision-making expert. Analyze the options carefully and make the best choice based on the context and criteria provided.
|
|
100
131
|
|
|
101
|
-
${
|
|
132
|
+
${
|
|
133
|
+
criteria.length > 0
|
|
134
|
+
? `Evaluation Criteria:\n${criteria.map((c, i) => `${i + 1}. ${c}`).join('\n')}`
|
|
135
|
+
: ''
|
|
136
|
+
}`,
|
|
102
137
|
prompt: `Make a decision based on the following:
|
|
103
138
|
|
|
104
139
|
Context:
|
|
@@ -107,7 +142,11 @@ ${contextStr}
|
|
|
107
142
|
Options:
|
|
108
143
|
${choicesStr}
|
|
109
144
|
|
|
110
|
-
${
|
|
145
|
+
${
|
|
146
|
+
criteria.length > 0
|
|
147
|
+
? `\nEvaluate each option against these criteria:\n${criteria.join(', ')}`
|
|
148
|
+
: ''
|
|
149
|
+
}
|
|
111
150
|
|
|
112
151
|
Provide your decision with clear reasoning.`,
|
|
113
152
|
})
|
|
@@ -157,9 +196,10 @@ decide.yesNo = async (
|
|
|
157
196
|
): Promise<Decision<'yes' | 'no'>> => {
|
|
158
197
|
return decide({
|
|
159
198
|
options: ['yes', 'no'] as const,
|
|
160
|
-
context:
|
|
161
|
-
|
|
162
|
-
|
|
199
|
+
context:
|
|
200
|
+
typeof context === 'string'
|
|
201
|
+
? `${question}\n\n${context}`
|
|
202
|
+
: `${question}\n\n${context ? JSON.stringify(context, null, 2) : ''}`,
|
|
163
203
|
})
|
|
164
204
|
}
|
|
165
205
|
|
|
@@ -189,11 +229,12 @@ decide.prioritize = async <T = string>(
|
|
|
189
229
|
context?: string | Record<string, unknown>,
|
|
190
230
|
criteria: string[] = []
|
|
191
231
|
): Promise<Array<Decision<T> & { rank: number }>> => {
|
|
192
|
-
const contextStr =
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
232
|
+
const contextStr =
|
|
233
|
+
typeof context === 'string'
|
|
234
|
+
? context
|
|
235
|
+
: context
|
|
236
|
+
? JSON.stringify(context, null, 2)
|
|
237
|
+
: 'No additional context provided'
|
|
197
238
|
|
|
198
239
|
const itemsStr = items
|
|
199
240
|
.map((item, i) => `${i + 1}. ${typeof item === 'object' ? JSON.stringify(item) : item}`)
|
|
@@ -213,7 +254,11 @@ decide.prioritize = async <T = string>(
|
|
|
213
254
|
},
|
|
214
255
|
system: `You are a prioritization expert. Rank items by priority based on the context and criteria.
|
|
215
256
|
|
|
216
|
-
${
|
|
257
|
+
${
|
|
258
|
+
criteria.length > 0
|
|
259
|
+
? `Prioritization Criteria:\n${criteria.map((c, i) => `${i + 1}. ${c}`).join('\n')}`
|
|
260
|
+
: ''
|
|
261
|
+
}`,
|
|
217
262
|
prompt: `Prioritize the following items:
|
|
218
263
|
|
|
219
264
|
Context:
|
|
@@ -287,9 +332,10 @@ decide.withApproval = async <T = string>(
|
|
|
287
332
|
}
|
|
288
333
|
)
|
|
289
334
|
|
|
335
|
+
const approvedBy = approval.approvedBy?.id ?? approval.approvedBy?.name
|
|
290
336
|
return {
|
|
291
337
|
...decision,
|
|
292
338
|
approved: approval.approved,
|
|
293
|
-
approvedBy
|
|
339
|
+
...(approvedBy !== undefined && { approvedBy }),
|
|
294
340
|
}
|
|
295
341
|
}
|
package/src/do.ts
CHANGED
|
@@ -1,23 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Task execution functionality for digital workers
|
|
3
|
+
*
|
|
4
|
+
* IMPORTANT: Worker Routing vs Direct LLM Calls
|
|
5
|
+
* ---------------------------------------------
|
|
6
|
+
* This module provides worker-routed task execution, NOT direct LLM calls.
|
|
7
|
+
*
|
|
8
|
+
* - `digital-workers.do()` - Routes tasks to Workers (AI Agents or Humans)
|
|
9
|
+
* based on capability matching, load balancing, and escalation policies.
|
|
10
|
+
*
|
|
11
|
+
* - `ai-functions.do()` - Directly calls the LLM to describe task execution.
|
|
12
|
+
*
|
|
13
|
+
* Use digital-workers when you need:
|
|
14
|
+
* - Task routing to appropriate workers
|
|
15
|
+
* - Human-in-the-loop escalation
|
|
16
|
+
* - Capability-based worker selection
|
|
17
|
+
* - Retry and timeout handling across workers
|
|
18
|
+
*
|
|
19
|
+
* Use ai-functions when you need:
|
|
20
|
+
* - Direct LLM text generation
|
|
21
|
+
* - Simple AI task description
|
|
22
|
+
* - No worker coordination required
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
3
25
|
*/
|
|
4
26
|
|
|
5
|
-
import { define } from 'ai-functions'
|
|
6
27
|
import type { TaskResult, DoOptions } from './types.js'
|
|
7
28
|
|
|
8
29
|
/**
|
|
9
|
-
* Execute a task
|
|
30
|
+
* Execute a task by routing to an appropriate Worker (AI Agent or Human).
|
|
10
31
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
32
|
+
* **Key Difference from ai-functions.do():**
|
|
33
|
+
* Unlike `ai-functions.do()` which directly calls the LLM to describe what
|
|
34
|
+
* actions would be taken, this function routes the task to a Worker (Agent
|
|
35
|
+
* or Human) based on capability matching. The Worker then executes the task
|
|
36
|
+
* using their specific tools and capabilities.
|
|
37
|
+
*
|
|
38
|
+
* This is a **worker coordination primitive**, not a direct LLM primitive.
|
|
13
39
|
*
|
|
14
40
|
* @param task - Description of the task to execute
|
|
15
41
|
* @param options - Execution options (retries, timeout, background, etc.)
|
|
16
|
-
* @returns Promise resolving to task result
|
|
42
|
+
* @returns Promise resolving to task result with execution details
|
|
17
43
|
*
|
|
18
44
|
* @example
|
|
19
45
|
* ```ts
|
|
20
|
-
* //
|
|
46
|
+
* // Route task to appropriate worker based on capability
|
|
21
47
|
* const result = await do('Generate monthly sales report', {
|
|
22
48
|
* timeout: 60000, // 1 minute
|
|
23
49
|
* context: {
|
|
@@ -33,7 +59,7 @@ import type { TaskResult, DoOptions } from './types.js'
|
|
|
33
59
|
*
|
|
34
60
|
* @example
|
|
35
61
|
* ```ts
|
|
36
|
-
* // Execute with retries
|
|
62
|
+
* // Execute with retries across workers
|
|
37
63
|
* const result = await do('Sync data to backup server', {
|
|
38
64
|
* maxRetries: 3,
|
|
39
65
|
* timeout: 30000,
|
|
@@ -46,7 +72,7 @@ import type { TaskResult, DoOptions } from './types.js'
|
|
|
46
72
|
*
|
|
47
73
|
* @example
|
|
48
74
|
* ```ts
|
|
49
|
-
* // Execute in background
|
|
75
|
+
* // Execute in background (worker handles async)
|
|
50
76
|
* const result = await do('Process large dataset', {
|
|
51
77
|
* background: true,
|
|
52
78
|
* context: {
|
|
@@ -55,66 +81,88 @@ import type { TaskResult, DoOptions } from './types.js'
|
|
|
55
81
|
* },
|
|
56
82
|
* })
|
|
57
83
|
* ```
|
|
84
|
+
*
|
|
85
|
+
* @see {@link ai-functions#do} for direct LLM task description
|
|
58
86
|
*/
|
|
59
87
|
export async function doTask<T = unknown>(
|
|
60
88
|
task: string,
|
|
61
89
|
options: DoOptions = {}
|
|
62
90
|
): Promise<TaskResult<T>> {
|
|
63
|
-
const {
|
|
64
|
-
maxRetries = 0,
|
|
65
|
-
timeout,
|
|
66
|
-
background = false,
|
|
67
|
-
context,
|
|
68
|
-
} = options
|
|
91
|
+
const { maxRetries = 0, timeout, background = false, context } = options
|
|
69
92
|
|
|
70
93
|
const startTime = Date.now()
|
|
71
94
|
const steps: TaskResult<T>['steps'] = []
|
|
72
95
|
|
|
73
|
-
// Use agentic function for complex tasks
|
|
74
|
-
const taskFn = define.agentic({
|
|
75
|
-
name: 'executeTask',
|
|
76
|
-
description: 'Execute a task using available tools and capabilities',
|
|
77
|
-
args: {
|
|
78
|
-
task: 'Description of the task to execute',
|
|
79
|
-
contextInfo: 'Additional context and parameters for the task',
|
|
80
|
-
},
|
|
81
|
-
returnType: {
|
|
82
|
-
result: 'The result of executing the task',
|
|
83
|
-
steps: ['List of steps taken to complete the task'],
|
|
84
|
-
},
|
|
85
|
-
instructions: `Execute the following task:
|
|
86
|
-
|
|
87
|
-
${task}
|
|
88
|
-
|
|
89
|
-
${context ? `Context: ${JSON.stringify(context, null, 2)}` : ''}
|
|
90
|
-
|
|
91
|
-
Work step-by-step to complete the task. Use available tools as needed.
|
|
92
|
-
Document each step you take for transparency.`,
|
|
93
|
-
maxIterations: 10,
|
|
94
|
-
tools: [], // Tools would be provided by the execution environment
|
|
95
|
-
})
|
|
96
|
-
|
|
97
96
|
let retries = 0
|
|
98
97
|
let lastError: Error | undefined
|
|
99
98
|
|
|
100
99
|
while (retries <= maxRetries) {
|
|
101
100
|
try {
|
|
101
|
+
// Use generateObject directly for more reliable execution
|
|
102
|
+
const { generateObject } = await import('ai-functions')
|
|
103
|
+
|
|
104
|
+
const executeTask = async (): Promise<{
|
|
105
|
+
result: T
|
|
106
|
+
steps: Array<{ action: string; result: unknown }>
|
|
107
|
+
}> => {
|
|
108
|
+
const response = await generateObject({
|
|
109
|
+
model: 'sonnet',
|
|
110
|
+
schema: {
|
|
111
|
+
result: 'The result of executing the task - provide a detailed response',
|
|
112
|
+
steps: [
|
|
113
|
+
{
|
|
114
|
+
action: 'Description of what was done in this step',
|
|
115
|
+
result: 'Outcome of this step',
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
success: 'Whether the task was completed successfully (boolean)',
|
|
119
|
+
},
|
|
120
|
+
system: `You are a capable AI worker executing tasks. You have access to the following context:
|
|
121
|
+
|
|
122
|
+
${context ? JSON.stringify(context, null, 2) : 'No additional context provided.'}
|
|
123
|
+
|
|
124
|
+
Execute the task step-by-step, documenting each action you take.
|
|
125
|
+
Provide detailed, actionable results that can be used directly.`,
|
|
126
|
+
prompt: `Execute the following task and provide the result:
|
|
127
|
+
|
|
128
|
+
Task: ${task}
|
|
129
|
+
|
|
130
|
+
Work through this task carefully:
|
|
131
|
+
1. Analyze what needs to be done
|
|
132
|
+
2. Execute each step
|
|
133
|
+
3. Provide the final result
|
|
134
|
+
|
|
135
|
+
Return a detailed result that fulfills the task requirements.`,
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
const obj = response.object as unknown as {
|
|
139
|
+
result: T
|
|
140
|
+
steps: Array<{ action: string; result: unknown }>
|
|
141
|
+
success: boolean
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!obj.success) {
|
|
145
|
+
throw new Error('Task execution failed')
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { result: obj.result, steps: obj.steps }
|
|
149
|
+
}
|
|
150
|
+
|
|
102
151
|
const response = await Promise.race([
|
|
103
|
-
|
|
152
|
+
executeTask(),
|
|
104
153
|
timeout
|
|
105
|
-
? new Promise((_, reject) =>
|
|
154
|
+
? new Promise<never>((_, reject) =>
|
|
106
155
|
setTimeout(() => reject(new Error('Task timeout')), timeout)
|
|
107
156
|
)
|
|
108
|
-
: new Promise(() => {}), // Never resolves if no timeout
|
|
109
|
-
])
|
|
110
|
-
|
|
111
|
-
const typedResponse = response as { result: T; steps?: Array<{ action: string; result: unknown }> }
|
|
157
|
+
: new Promise<never>(() => {}), // Never resolves if no timeout
|
|
158
|
+
])
|
|
112
159
|
|
|
113
160
|
// Track steps if provided
|
|
114
|
-
if (
|
|
161
|
+
if (response.steps) {
|
|
115
162
|
steps.push(
|
|
116
|
-
...
|
|
117
|
-
|
|
163
|
+
...response.steps.map((step) => ({
|
|
164
|
+
action: String(step.action),
|
|
165
|
+
result: step.result,
|
|
118
166
|
timestamp: new Date(),
|
|
119
167
|
}))
|
|
120
168
|
)
|
|
@@ -123,7 +171,7 @@ Document each step you take for transparency.`,
|
|
|
123
171
|
const duration = Date.now() - startTime
|
|
124
172
|
|
|
125
173
|
return {
|
|
126
|
-
result:
|
|
174
|
+
result: response.result,
|
|
127
175
|
success: true,
|
|
128
176
|
duration,
|
|
129
177
|
steps,
|
|
@@ -140,9 +188,7 @@ Document each step you take for transparency.`,
|
|
|
140
188
|
})
|
|
141
189
|
|
|
142
190
|
// Exponential backoff
|
|
143
|
-
await new Promise((resolve) =>
|
|
144
|
-
setTimeout(resolve, Math.pow(2, retries) * 1000)
|
|
145
|
-
)
|
|
191
|
+
await new Promise((resolve) => setTimeout(resolve, Math.pow(2, retries) * 1000))
|
|
146
192
|
}
|
|
147
193
|
}
|
|
148
194
|
}
|
|
@@ -218,7 +264,7 @@ doTask.sequence = async <T = unknown>(
|
|
|
218
264
|
results.push(result)
|
|
219
265
|
|
|
220
266
|
// Stop if a task fails (unless we're continuing on error)
|
|
221
|
-
if (!result.success && !options.context?.continueOnError) {
|
|
267
|
+
if (!result.success && !options.context?.['continueOnError']) {
|
|
222
268
|
break
|
|
223
269
|
}
|
|
224
270
|
}
|