digital-workers 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.
- package/CHANGELOG.md +9 -0
- package/README.md +2 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +33 -21
- package/dist/actions.js.map +1 -1
- package/dist/agent-comms.d.ts.map +1 -1
- package/dist/agent-comms.js +36 -25
- package/dist/agent-comms.js.map +1 -1
- 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.js +3 -3
- package/dist/capability-tiers.js.map +1 -1
- package/dist/cascade-context.d.ts +28 -28
- 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.map +1 -1
- package/dist/error-escalation.js +38 -38
- package/dist/error-escalation.js.map +1 -1
- 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 +49 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +58 -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.map +1 -1
- package/dist/load-balancing.js +124 -38
- package/dist/load-balancing.js.map +1 -1
- 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 +141 -19
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +5 -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 +32 -14
- package/src/actions.ts +39 -30
- package/src/agent-comms.ts +54 -92
- package/src/approve.ts +91 -20
- package/src/ask.ts +99 -25
- package/src/browse.ts +627 -0
- package/src/capability-tiers.ts +5 -5
- package/src/client.ts +221 -0
- package/src/decide.ts +81 -35
- package/src/do.ts +98 -52
- package/src/error-escalation.ts +55 -67
- package/src/generate.ts +52 -18
- package/src/goals.ts +36 -27
- package/src/image.ts +816 -0
- package/src/index.ts +187 -2
- package/src/is.ts +59 -25
- package/src/kpis.ts +41 -36
- package/src/load-balancing.ts +132 -46
- 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 +174 -46
- package/src/utils/id.ts +21 -0
- package/src/video.ts +906 -0
- package/src/worker.ts +1007 -0
- package/test/approve.test.ts +305 -0
- package/test/ask.test.ts +274 -0
- package/test/browse.test.ts +361 -0
- package/test/decide.test.ts +252 -0
- package/test/do.test.ts +144 -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/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 +60 -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 -4
- package/LICENSE +0 -21
- 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/index.ts
CHANGED
|
@@ -6,7 +6,29 @@
|
|
|
6
6
|
* defines a unified Worker interface that enables workflows to be designed
|
|
7
7
|
* once and executed by any combination of AI and human workers.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* ## Worker Routing vs ai-functions Primitives
|
|
10
|
+
*
|
|
11
|
+
* **IMPORTANT:** This package exports functions that overlap in name with
|
|
12
|
+
* `ai-functions` primitives (do, ask, decide, approve, generate, is) but
|
|
13
|
+
* serve fundamentally different purposes:
|
|
14
|
+
*
|
|
15
|
+
* | Function | digital-workers | ai-functions |
|
|
16
|
+
* |----------|----------------|--------------|
|
|
17
|
+
* | `do` | Routes tasks to Workers | Direct LLM task description |
|
|
18
|
+
* | `ask` | Routes questions via Slack/email | LLM content for human UI |
|
|
19
|
+
* | `decide` | Multi-criteria decision framework | LLM-as-judge comparison |
|
|
20
|
+
* | `approve` | Real approval workflow via channels | LLM-generated approval content |
|
|
21
|
+
* | `generate` | Content generation with metadata | Core LLM generation primitive |
|
|
22
|
+
* | `is` | Type/schema validation with errors | Boolean assertion via LLM |
|
|
23
|
+
* | `notify` | Real channel delivery | (no equivalent) |
|
|
24
|
+
*
|
|
25
|
+
* **digital-workers functions are worker coordination primitives** that route
|
|
26
|
+
* work to AI Agents or Humans via real communication channels.
|
|
27
|
+
*
|
|
28
|
+
* **ai-functions primitives are direct LLM operations** for text generation,
|
|
29
|
+
* decision-making, and content creation.
|
|
30
|
+
*
|
|
31
|
+
* ## Package relationships:
|
|
10
32
|
* - `autonomous-agents` - Implements Worker for AI agents
|
|
11
33
|
* - `human-in-the-loop` - Implements Worker for humans
|
|
12
34
|
* - `ai-workflows` - Uses digital-workers to orchestrate execution
|
|
@@ -32,12 +54,13 @@
|
|
|
32
54
|
* const worker$ = withWorkers($)
|
|
33
55
|
*
|
|
34
56
|
* $.on.Expense.submitted(async (expense) => {
|
|
57
|
+
* // These route to REAL workers via REAL channels
|
|
35
58
|
* await worker$.notify(finance, `New expense: ${expense.amount}`)
|
|
36
59
|
*
|
|
37
60
|
* const approval = await worker$.approve(
|
|
38
61
|
* `Expense: $${expense.amount}`,
|
|
39
62
|
* manager,
|
|
40
|
-
* { via: 'slack' }
|
|
63
|
+
* { via: 'slack' } // Actually sends to Slack!
|
|
41
64
|
* )
|
|
42
65
|
*
|
|
43
66
|
* if (approval.approved) {
|
|
@@ -72,13 +95,27 @@ export {
|
|
|
72
95
|
export { Role } from './role.js'
|
|
73
96
|
export { Team } from './team.js'
|
|
74
97
|
export { Goals } from './goals.js'
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Worker Routing Functions
|
|
101
|
+
*
|
|
102
|
+
* These functions route work to Workers (AI Agents or Humans) via real
|
|
103
|
+
* communication channels. They are NOT direct LLM primitives.
|
|
104
|
+
*
|
|
105
|
+
* For direct LLM primitives, use the identically-named functions from
|
|
106
|
+
* `ai-functions` instead. See module documentation for comparison table.
|
|
107
|
+
*/
|
|
75
108
|
export { approve } from './approve.js'
|
|
76
109
|
export { ask } from './ask.js'
|
|
110
|
+
export { browse } from './browse.js'
|
|
77
111
|
export { do } from './do.js'
|
|
78
112
|
export { decide } from './decide.js'
|
|
79
113
|
export { generate } from './generate.js'
|
|
114
|
+
export { image } from './image.js'
|
|
80
115
|
export { is } from './is.js'
|
|
81
116
|
export { notify } from './notify.js'
|
|
117
|
+
export { video } from './video.js'
|
|
118
|
+
|
|
82
119
|
export { kpis, okrs } from './kpis.js'
|
|
83
120
|
|
|
84
121
|
// Export verb definitions
|
|
@@ -114,6 +151,47 @@ export type {
|
|
|
114
151
|
ProfileConstraints,
|
|
115
152
|
} from './capability-tiers.js'
|
|
116
153
|
|
|
154
|
+
// Export browser automation types
|
|
155
|
+
export type {
|
|
156
|
+
BrowseOptions,
|
|
157
|
+
BrowseResult,
|
|
158
|
+
BrowseAction,
|
|
159
|
+
BrowseActionType,
|
|
160
|
+
Viewport,
|
|
161
|
+
ClickOptions,
|
|
162
|
+
TypeOptions,
|
|
163
|
+
ScrollOptions,
|
|
164
|
+
ScreenshotOptions,
|
|
165
|
+
ExtractOptions,
|
|
166
|
+
} from './browse.js'
|
|
167
|
+
|
|
168
|
+
// Export image generation types
|
|
169
|
+
export type {
|
|
170
|
+
ImageStyle,
|
|
171
|
+
ImageSize,
|
|
172
|
+
ImageFormat,
|
|
173
|
+
ImageOptions,
|
|
174
|
+
ImageResult,
|
|
175
|
+
VariationOptions,
|
|
176
|
+
EditOptions,
|
|
177
|
+
UpscaleOptions,
|
|
178
|
+
UpscaleResult,
|
|
179
|
+
} from './image.js'
|
|
180
|
+
|
|
181
|
+
// Export video generation types
|
|
182
|
+
export type {
|
|
183
|
+
VideoOptions,
|
|
184
|
+
VideoResult,
|
|
185
|
+
VideoResolution,
|
|
186
|
+
VideoAspectRatio,
|
|
187
|
+
VideoModel,
|
|
188
|
+
VideoStyle,
|
|
189
|
+
VideoMetadata,
|
|
190
|
+
VideoFromImageOptions,
|
|
191
|
+
VideoExtendOptions,
|
|
192
|
+
VideoEditOptions,
|
|
193
|
+
} from './video.js'
|
|
194
|
+
|
|
117
195
|
// Export transport bridge (connects to digital-tools)
|
|
118
196
|
export type {
|
|
119
197
|
Transport,
|
|
@@ -274,6 +352,76 @@ export type {
|
|
|
274
352
|
CompositeBalancerConfig,
|
|
275
353
|
} from './load-balancing.js'
|
|
276
354
|
|
|
355
|
+
// Export Slack transport adapter
|
|
356
|
+
export {
|
|
357
|
+
SlackTransport,
|
|
358
|
+
createSlackTransport,
|
|
359
|
+
registerSlackTransport,
|
|
360
|
+
// Block Kit helpers
|
|
361
|
+
slackSection,
|
|
362
|
+
slackHeader,
|
|
363
|
+
slackDivider,
|
|
364
|
+
slackContext,
|
|
365
|
+
slackButton,
|
|
366
|
+
slackActions,
|
|
367
|
+
} from './transports/slack.js'
|
|
368
|
+
|
|
369
|
+
export type {
|
|
370
|
+
SlackTransportConfig,
|
|
371
|
+
SlackBlockType,
|
|
372
|
+
SlackTextObject,
|
|
373
|
+
SlackButtonElement,
|
|
374
|
+
SlackConfirmDialog,
|
|
375
|
+
SlackSectionBlock,
|
|
376
|
+
SlackDividerBlock,
|
|
377
|
+
SlackHeaderBlock,
|
|
378
|
+
SlackContextBlock,
|
|
379
|
+
SlackActionsBlock,
|
|
380
|
+
SlackBlock,
|
|
381
|
+
SlackMessage,
|
|
382
|
+
SlackApiResponse,
|
|
383
|
+
SlackPostMessageResponse,
|
|
384
|
+
SlackUserInfoResponse,
|
|
385
|
+
SlackConversationInfoResponse,
|
|
386
|
+
SlackInteractionPayload,
|
|
387
|
+
SlackActionPayload,
|
|
388
|
+
SlackWebhookRequest,
|
|
389
|
+
WebhookHandlerResult,
|
|
390
|
+
} from './transports/slack.js'
|
|
391
|
+
|
|
392
|
+
// Export Email transport adapter
|
|
393
|
+
export {
|
|
394
|
+
EmailTransport,
|
|
395
|
+
createEmailTransport,
|
|
396
|
+
createEmailTransportWithProvider,
|
|
397
|
+
createResendProvider,
|
|
398
|
+
// Template generators
|
|
399
|
+
generateNotificationEmail,
|
|
400
|
+
generateApprovalEmail,
|
|
401
|
+
// Reply parsing
|
|
402
|
+
parseApprovalReply,
|
|
403
|
+
// Type guards
|
|
404
|
+
isEmailTransportConfig,
|
|
405
|
+
isApproved,
|
|
406
|
+
isRejected,
|
|
407
|
+
} from './transports/email.js'
|
|
408
|
+
|
|
409
|
+
export type {
|
|
410
|
+
// Provider types
|
|
411
|
+
EmailProvider,
|
|
412
|
+
EmailMessage,
|
|
413
|
+
EmailSendResult,
|
|
414
|
+
EmailAttachment,
|
|
415
|
+
EmailTag,
|
|
416
|
+
// Configuration types
|
|
417
|
+
EmailTransportConfig,
|
|
418
|
+
EmailTemplateOptions,
|
|
419
|
+
// Approval types
|
|
420
|
+
ApprovalRequestData,
|
|
421
|
+
ParsedEmailReply,
|
|
422
|
+
InboundEmail,
|
|
423
|
+
} from './transports/email.js'
|
|
424
|
+
|
|
277
425
|
// Export error escalation for multi-level error handling
|
|
278
426
|
export {
|
|
279
427
|
// Error Classification
|
|
@@ -339,3 +487,40 @@ export type {
|
|
|
339
487
|
HandleErrorOptions,
|
|
340
488
|
EscalationMetrics,
|
|
341
489
|
} from './error-escalation.js'
|
|
490
|
+
|
|
491
|
+
// Export runtime integration for human request processing
|
|
492
|
+
export {
|
|
493
|
+
// Classes
|
|
494
|
+
HumanRequestProcessor,
|
|
495
|
+
InMemoryRequestStore,
|
|
496
|
+
// Factory functions
|
|
497
|
+
createHumanRequestProcessor,
|
|
498
|
+
} from './runtime.js'
|
|
499
|
+
|
|
500
|
+
export type {
|
|
501
|
+
// Request types
|
|
502
|
+
HumanRequest,
|
|
503
|
+
HumanRequestStore,
|
|
504
|
+
RequestStatus,
|
|
505
|
+
RequestType,
|
|
506
|
+
RequestResult,
|
|
507
|
+
CreateRequestData,
|
|
508
|
+
UpdateRequestData,
|
|
509
|
+
// Processor types
|
|
510
|
+
ProcessorConfig,
|
|
511
|
+
TransportAdapters,
|
|
512
|
+
SubmitResult,
|
|
513
|
+
SubmitRequestData,
|
|
514
|
+
WebhookPayload,
|
|
515
|
+
WebhookResult,
|
|
516
|
+
CompleteCallbackData,
|
|
517
|
+
TimeoutCallbackData,
|
|
518
|
+
CancelResult,
|
|
519
|
+
} from './runtime.js'
|
|
520
|
+
|
|
521
|
+
// Export logger interface for error logging
|
|
522
|
+
export type { Logger } from './logger.js'
|
|
523
|
+
export { noopLogger, createConsoleLogger } from './logger.js'
|
|
524
|
+
|
|
525
|
+
// Export ID generation utilities
|
|
526
|
+
export { generateRequestId } from './utils/id.js'
|
package/src/is.ts
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Type validation and checking functionality for digital workers
|
|
3
|
+
*
|
|
4
|
+
* IMPORTANT: Schema Validation vs Boolean Assertion
|
|
5
|
+
* --------------------------------------------------
|
|
6
|
+
* This module provides comprehensive type/schema validation,
|
|
7
|
+
* NOT simple boolean assertions.
|
|
8
|
+
*
|
|
9
|
+
* - `digital-workers.is()` - Validates values against types or schemas,
|
|
10
|
+
* returns detailed validation results with errors and optional coercion.
|
|
11
|
+
*
|
|
12
|
+
* - `ai-functions.is()` - Boolean assertion via LLM (e.g., `is\`${x} is valid\``)
|
|
13
|
+
* returns true/false based on natural language checking.
|
|
14
|
+
*
|
|
15
|
+
* Use digital-workers when you need:
|
|
16
|
+
* - Type validation with error messages
|
|
17
|
+
* - Schema validation with field-level errors
|
|
18
|
+
* - Value coercion (string to number, etc.)
|
|
19
|
+
* - Structured validation results
|
|
20
|
+
*
|
|
21
|
+
* Use ai-functions when you need:
|
|
22
|
+
* - Natural language boolean checks
|
|
23
|
+
* - LLM-based semantic validation
|
|
24
|
+
* - Template literal assertions
|
|
25
|
+
*
|
|
26
|
+
* @module
|
|
3
27
|
*/
|
|
4
28
|
|
|
5
29
|
import { generateObject } from 'ai-functions'
|
|
@@ -7,26 +31,35 @@ import { schema as convertSchema, type SimpleSchema } from 'ai-functions'
|
|
|
7
31
|
import type { TypeCheckResult, IsOptions } from './types.js'
|
|
8
32
|
|
|
9
33
|
/**
|
|
10
|
-
*
|
|
34
|
+
* Validate a value against a type or schema with detailed results.
|
|
11
35
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
36
|
+
* **Key Difference from ai-functions.is():**
|
|
37
|
+
* Unlike `ai-functions.is()` which is a boolean assertion using natural
|
|
38
|
+
* language (e.g., `is\`${email} is valid\`` returns true/false), this
|
|
39
|
+
* function performs structured type/schema validation and returns a
|
|
40
|
+
* `TypeCheckResult` with:
|
|
41
|
+
* - Validation status
|
|
42
|
+
* - Error messages for invalid fields
|
|
43
|
+
* - Optionally coerced values
|
|
44
|
+
*
|
|
45
|
+
* This is a **validation primitive**, not a boolean assertion primitive.
|
|
14
46
|
*
|
|
15
47
|
* @param value - The value to check
|
|
16
|
-
* @param type - Type name or schema to validate against
|
|
17
|
-
* @param options - Validation options
|
|
18
|
-
* @returns Promise resolving to
|
|
48
|
+
* @param type - Type name ('email', 'url', 'number') or schema to validate against
|
|
49
|
+
* @param options - Validation options (coerce, strict)
|
|
50
|
+
* @returns Promise resolving to TypeCheckResult with valid, value, and errors
|
|
19
51
|
*
|
|
20
52
|
* @example
|
|
21
53
|
* ```ts
|
|
22
|
-
* // Simple type checking
|
|
54
|
+
* // Simple type checking with result object
|
|
23
55
|
* const result = await is('hello@example.com', 'email')
|
|
24
56
|
* console.log(result.valid) // true
|
|
57
|
+
* console.log(result.errors) // undefined when valid
|
|
25
58
|
* ```
|
|
26
59
|
*
|
|
27
60
|
* @example
|
|
28
61
|
* ```ts
|
|
29
|
-
* // Schema validation
|
|
62
|
+
* // Schema validation with detailed errors
|
|
30
63
|
* const result = await is(
|
|
31
64
|
* { name: 'John', age: 30 },
|
|
32
65
|
* {
|
|
@@ -41,11 +74,13 @@ import type { TypeCheckResult, IsOptions } from './types.js'
|
|
|
41
74
|
*
|
|
42
75
|
* @example
|
|
43
76
|
* ```ts
|
|
44
|
-
* // With coercion
|
|
77
|
+
* // With coercion - transforms value to target type
|
|
45
78
|
* const result = await is('123', 'number', { coerce: true })
|
|
46
79
|
* console.log(result.valid) // true
|
|
47
|
-
* console.log(result.value) // 123 (as number)
|
|
80
|
+
* console.log(result.value) // 123 (as number, not string)
|
|
48
81
|
* ```
|
|
82
|
+
*
|
|
83
|
+
* @see {@link ai-functions#is} for natural language boolean assertions
|
|
49
84
|
*/
|
|
50
85
|
export async function is(
|
|
51
86
|
value: unknown,
|
|
@@ -102,8 +137,7 @@ async function validateSimpleType(
|
|
|
102
137
|
|
|
103
138
|
return {
|
|
104
139
|
valid: isValid,
|
|
105
|
-
|
|
106
|
-
errors: isValid ? undefined : [`Value is not a valid ${type}`],
|
|
140
|
+
...(isValid ? { value } : { errors: [`Value is not a valid ${type}`] }),
|
|
107
141
|
}
|
|
108
142
|
}
|
|
109
143
|
|
|
@@ -118,7 +152,11 @@ async function validateSimpleType(
|
|
|
118
152
|
system: `You are a type validation expert. Determine if a value matches an expected type.
|
|
119
153
|
|
|
120
154
|
${coerce ? 'If the value can be coerced to the expected type, provide the coerced value.' : ''}
|
|
121
|
-
${
|
|
155
|
+
${
|
|
156
|
+
strict
|
|
157
|
+
? 'Be strict in your validation - require exact type matches.'
|
|
158
|
+
: 'Be flexible - allow reasonable type conversions.'
|
|
159
|
+
}`,
|
|
122
160
|
prompt: `Validate if this value matches the expected type:
|
|
123
161
|
|
|
124
162
|
Value: ${JSON.stringify(value)}
|
|
@@ -136,7 +174,7 @@ Determine if the value is valid for this type.`,
|
|
|
136
174
|
return {
|
|
137
175
|
valid: validation.valid,
|
|
138
176
|
value: coerce && validation.coercedValue !== undefined ? validation.coercedValue : value,
|
|
139
|
-
|
|
177
|
+
...(!validation.valid && { errors: validation.errors }),
|
|
140
178
|
}
|
|
141
179
|
}
|
|
142
180
|
|
|
@@ -201,7 +239,7 @@ Check if the value matches the schema structure and types.`,
|
|
|
201
239
|
return {
|
|
202
240
|
valid: validation.valid,
|
|
203
241
|
value: coerce && validation.coercedValue !== undefined ? validation.coercedValue : value,
|
|
204
|
-
|
|
242
|
+
...(!validation.valid && { errors: validation.errors }),
|
|
205
243
|
}
|
|
206
244
|
}
|
|
207
245
|
}
|
|
@@ -209,10 +247,7 @@ Check if the value matches the schema structure and types.`,
|
|
|
209
247
|
/**
|
|
210
248
|
* Try to coerce a value to a specific type
|
|
211
249
|
*/
|
|
212
|
-
function coerceValue(
|
|
213
|
-
value: unknown,
|
|
214
|
-
type: string
|
|
215
|
-
): { success: boolean; value?: unknown } {
|
|
250
|
+
function coerceValue(value: unknown, type: string): { success: boolean; value?: unknown } {
|
|
216
251
|
try {
|
|
217
252
|
switch (type) {
|
|
218
253
|
case 'string':
|
|
@@ -266,8 +301,7 @@ is.email = async (value: unknown): Promise<TypeCheckResult> => {
|
|
|
266
301
|
|
|
267
302
|
return {
|
|
268
303
|
valid,
|
|
269
|
-
|
|
270
|
-
errors: valid ? undefined : ['Invalid email format'],
|
|
304
|
+
...(valid ? { value } : { errors: ['Invalid email format'] }),
|
|
271
305
|
}
|
|
272
306
|
}
|
|
273
307
|
|
|
@@ -310,10 +344,11 @@ is.date = async (value: unknown, options: IsOptions = {}): Promise<TypeCheckResu
|
|
|
310
344
|
const { coerce } = options
|
|
311
345
|
|
|
312
346
|
if (value instanceof Date) {
|
|
347
|
+
const isValid = !isNaN(value.getTime())
|
|
313
348
|
return {
|
|
314
|
-
valid:
|
|
349
|
+
valid: isValid,
|
|
315
350
|
value,
|
|
316
|
-
errors:
|
|
351
|
+
...(!isValid && { errors: ['Invalid date'] }),
|
|
317
352
|
}
|
|
318
353
|
}
|
|
319
354
|
|
|
@@ -360,8 +395,7 @@ is.custom = async (
|
|
|
360
395
|
const valid = await validator(value)
|
|
361
396
|
return {
|
|
362
397
|
valid,
|
|
363
|
-
|
|
364
|
-
errors: valid ? undefined : ['Custom validation failed'],
|
|
398
|
+
...(valid ? { value } : { errors: ['Custom validation failed'] }),
|
|
365
399
|
}
|
|
366
400
|
} catch (error) {
|
|
367
401
|
return {
|
package/src/kpis.ts
CHANGED
|
@@ -2,11 +2,20 @@
|
|
|
2
2
|
* KPI and OKR tracking functionality for digital workers
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { KPI, OKR } from '
|
|
5
|
+
import type { KPI, OKR, KeyResult } from 'org.ai'
|
|
6
|
+
import { calculateProgress, isOnTrack, calculateGap } from 'org.ai'
|
|
7
|
+
import type { WorkerKPI, WorkerOKR } from './types.js'
|
|
8
|
+
|
|
9
|
+
// Re-export KPI, OKR from org.ai for convenience
|
|
10
|
+
export type { KPI, OKR, KeyResult } from 'org.ai'
|
|
6
11
|
|
|
7
12
|
/**
|
|
8
13
|
* Define and track Key Performance Indicators
|
|
9
14
|
*
|
|
15
|
+
* Uses WorkerKPI which has a simpler interface with `current` and `target`
|
|
16
|
+
* as required number fields. For the full org.ai KPI with `id`, `value`,
|
|
17
|
+
* `category`, and `history`, use the KPI type directly.
|
|
18
|
+
*
|
|
10
19
|
* @param definition - KPI definition or array of KPIs
|
|
11
20
|
* @returns The defined KPI(s)
|
|
12
21
|
*
|
|
@@ -46,9 +55,9 @@ import type { KPI, OKR } from './types.js'
|
|
|
46
55
|
* ])
|
|
47
56
|
* ```
|
|
48
57
|
*/
|
|
49
|
-
export function kpis(definition:
|
|
50
|
-
export function kpis(definition:
|
|
51
|
-
export function kpis(definition:
|
|
58
|
+
export function kpis(definition: WorkerKPI): WorkerKPI
|
|
59
|
+
export function kpis(definition: WorkerKPI[]): WorkerKPI[]
|
|
60
|
+
export function kpis(definition: WorkerKPI | WorkerKPI[]): WorkerKPI | WorkerKPI[] {
|
|
52
61
|
return definition
|
|
53
62
|
}
|
|
54
63
|
|
|
@@ -66,9 +75,9 @@ export function kpis(definition: KPI | KPI[]): KPI | KPI[] {
|
|
|
66
75
|
* console.log(updated.trend) // 'up' (automatically determined)
|
|
67
76
|
* ```
|
|
68
77
|
*/
|
|
69
|
-
kpis.update = (kpi:
|
|
78
|
+
kpis.update = (kpi: WorkerKPI, current: number): WorkerKPI => {
|
|
70
79
|
// Determine trend
|
|
71
|
-
let trend:
|
|
80
|
+
let trend: WorkerKPI['trend'] = 'stable'
|
|
72
81
|
if (current > kpi.current) {
|
|
73
82
|
trend = 'up'
|
|
74
83
|
} else if (current < kpi.current) {
|
|
@@ -94,9 +103,8 @@ kpis.update = (kpi: KPI, current: number): KPI => {
|
|
|
94
103
|
* const progress = kpis.progress(kpi) // 0.75
|
|
95
104
|
* ```
|
|
96
105
|
*/
|
|
97
|
-
kpis.progress = (kpi: Pick<
|
|
98
|
-
|
|
99
|
-
return Math.min(1, Math.max(0, kpi.current / kpi.target))
|
|
106
|
+
kpis.progress = (kpi: Pick<WorkerKPI, 'current' | 'target'>): number => {
|
|
107
|
+
return calculateProgress(kpi)
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
/**
|
|
@@ -112,8 +120,8 @@ kpis.progress = (kpi: Pick<KPI, 'current' | 'target'>): number => {
|
|
|
112
120
|
* const onTrack = kpis.onTrack(kpi) // true (85% >= 80%)
|
|
113
121
|
* ```
|
|
114
122
|
*/
|
|
115
|
-
kpis.onTrack = (kpi: Pick<
|
|
116
|
-
return
|
|
123
|
+
kpis.onTrack = (kpi: Pick<WorkerKPI, 'current' | 'target'>, threshold = 0.8): boolean => {
|
|
124
|
+
return isOnTrack(kpi, threshold)
|
|
117
125
|
}
|
|
118
126
|
|
|
119
127
|
/**
|
|
@@ -128,8 +136,8 @@ kpis.onTrack = (kpi: Pick<KPI, 'current' | 'target'>, threshold = 0.8): boolean
|
|
|
128
136
|
* const gap = kpis.gap(kpi) // 25
|
|
129
137
|
* ```
|
|
130
138
|
*/
|
|
131
|
-
kpis.gap = (kpi: Pick<
|
|
132
|
-
return kpi
|
|
139
|
+
kpis.gap = (kpi: Pick<WorkerKPI, 'current' | 'target'>): number => {
|
|
140
|
+
return calculateGap(kpi)
|
|
133
141
|
}
|
|
134
142
|
|
|
135
143
|
/**
|
|
@@ -151,7 +159,7 @@ kpis.gap = (kpi: Pick<KPI, 'current' | 'target'>): number => {
|
|
|
151
159
|
* // "Deployment Frequency: 5/10 deploys/week (50%, trending up)"
|
|
152
160
|
* ```
|
|
153
161
|
*/
|
|
154
|
-
kpis.format = (kpi:
|
|
162
|
+
kpis.format = (kpi: WorkerKPI): string => {
|
|
155
163
|
const progress = kpis.progress(kpi)
|
|
156
164
|
const progressPercent = Math.round(progress * 100)
|
|
157
165
|
const trendEmoji = kpi.trend === 'up' ? '↑' : kpi.trend === 'down' ? '↓' : '→'
|
|
@@ -175,17 +183,15 @@ kpis.format = (kpi: KPI): string => {
|
|
|
175
183
|
* ```
|
|
176
184
|
*/
|
|
177
185
|
kpis.compare = (
|
|
178
|
-
previous: Pick<
|
|
179
|
-
current: Pick<
|
|
186
|
+
previous: Pick<WorkerKPI, 'current' | 'target'>,
|
|
187
|
+
current: Pick<WorkerKPI, 'current' | 'target'>
|
|
180
188
|
): {
|
|
181
189
|
delta: number
|
|
182
190
|
percentChange: number
|
|
183
191
|
improved: boolean
|
|
184
192
|
} => {
|
|
185
193
|
const delta = current.current - previous.current
|
|
186
|
-
const percentChange = previous.current !== 0
|
|
187
|
-
? (delta / previous.current) * 100
|
|
188
|
-
: 0
|
|
194
|
+
const percentChange = previous.current !== 0 ? (delta / previous.current) * 100 : 0
|
|
189
195
|
|
|
190
196
|
// Improved if we got closer to the target
|
|
191
197
|
const previousGap = Math.abs(previous.target - previous.current)
|
|
@@ -202,6 +208,10 @@ kpis.compare = (
|
|
|
202
208
|
/**
|
|
203
209
|
* Define OKRs (Objectives and Key Results)
|
|
204
210
|
*
|
|
211
|
+
* Uses WorkerOKR which has WorkerRef for owner.
|
|
212
|
+
* For the full org.ai OKR with `id`, `status`, `period`, etc.,
|
|
213
|
+
* use the OKR type directly.
|
|
214
|
+
*
|
|
205
215
|
* @param definition - OKR definition
|
|
206
216
|
* @returns The defined OKR
|
|
207
217
|
*
|
|
@@ -229,12 +239,12 @@ kpis.compare = (
|
|
|
229
239
|
* unit: '%',
|
|
230
240
|
* },
|
|
231
241
|
* ],
|
|
232
|
-
* owner: 'engineering-team',
|
|
242
|
+
* owner: { id: 'engineering-team', type: 'agent' },
|
|
233
243
|
* dueDate: new Date('2024-03-31'),
|
|
234
244
|
* })
|
|
235
245
|
* ```
|
|
236
246
|
*/
|
|
237
|
-
export function okrs(definition:
|
|
247
|
+
export function okrs(definition: WorkerOKR): WorkerOKR {
|
|
238
248
|
return definition
|
|
239
249
|
}
|
|
240
250
|
|
|
@@ -250,7 +260,7 @@ export function okrs(definition: OKR): OKR {
|
|
|
250
260
|
* console.log(progress) // 0.67 (67% complete)
|
|
251
261
|
* ```
|
|
252
262
|
*/
|
|
253
|
-
okrs.progress = (okr:
|
|
263
|
+
okrs.progress = (okr: WorkerOKR): number => {
|
|
254
264
|
if (okr.keyResults.length === 0) return 0
|
|
255
265
|
|
|
256
266
|
const totalProgress = okr.keyResults.reduce((sum, kr) => {
|
|
@@ -277,17 +287,11 @@ okrs.progress = (okr: OKR): number => {
|
|
|
277
287
|
* )
|
|
278
288
|
* ```
|
|
279
289
|
*/
|
|
280
|
-
okrs.updateKeyResult = (
|
|
281
|
-
|
|
282
|
-
keyResultName: string,
|
|
283
|
-
current: number
|
|
284
|
-
): OKR => {
|
|
290
|
+
okrs.updateKeyResult = (okr: WorkerOKR, keyResultName: string, current: number): WorkerOKR => {
|
|
291
|
+
const { progress: _progress, ...rest } = okr
|
|
285
292
|
return {
|
|
286
|
-
...
|
|
287
|
-
keyResults: okr.keyResults.map((kr) =>
|
|
288
|
-
kr.name === keyResultName ? { ...kr, current } : kr
|
|
289
|
-
),
|
|
290
|
-
progress: undefined, // Will be recalculated
|
|
293
|
+
...rest,
|
|
294
|
+
keyResults: okr.keyResults.map((kr) => (kr.name === keyResultName ? { ...kr, current } : kr)),
|
|
291
295
|
}
|
|
292
296
|
}
|
|
293
297
|
|
|
@@ -303,7 +307,7 @@ okrs.updateKeyResult = (
|
|
|
303
307
|
* const onTrack = okrs.onTrack(engineeringOKR)
|
|
304
308
|
* ```
|
|
305
309
|
*/
|
|
306
|
-
okrs.onTrack = (okr:
|
|
310
|
+
okrs.onTrack = (okr: WorkerOKR, threshold = 0.7): boolean => {
|
|
307
311
|
return okrs.progress(okr) >= threshold
|
|
308
312
|
}
|
|
309
313
|
|
|
@@ -323,7 +327,7 @@ okrs.onTrack = (okr: OKR, threshold = 0.7): boolean => {
|
|
|
323
327
|
* // • Change Failure Rate: 15/5 % (300%)
|
|
324
328
|
* ```
|
|
325
329
|
*/
|
|
326
|
-
okrs.format = (okr:
|
|
330
|
+
okrs.format = (okr: WorkerOKR): string => {
|
|
327
331
|
const progress = okrs.progress(okr)
|
|
328
332
|
const progressPercent = Math.round(progress * 100)
|
|
329
333
|
|
|
@@ -332,12 +336,13 @@ okrs.format = (okr: OKR): string => {
|
|
|
332
336
|
...okr.keyResults.map((kr) => {
|
|
333
337
|
const krProgress = kpis.progress(kr)
|
|
334
338
|
const krPercent = Math.round(krProgress * 100)
|
|
335
|
-
return `
|
|
339
|
+
return ` - ${kr.name}: ${kr.current}/${kr.target} ${kr.unit} (${krPercent}%)`
|
|
336
340
|
}),
|
|
337
341
|
]
|
|
338
342
|
|
|
339
343
|
if (okr.owner) {
|
|
340
|
-
|
|
344
|
+
const ownerDisplay = typeof okr.owner === 'string' ? okr.owner : okr.owner.id
|
|
345
|
+
lines.push(` Owner: ${ownerDisplay}`)
|
|
341
346
|
}
|
|
342
347
|
|
|
343
348
|
if (okr.dueDate) {
|