@hatchet-dev/typescript-sdk 1.21.1 → 1.22.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/clients/hatchet-client/client-config.d.ts +27 -133
- package/clients/hatchet-client/client-config.js +24 -24
- package/legacy/legacy-client.js +2 -2
- package/legacy/step.d.ts +22 -121
- package/legacy/step.js +7 -4
- package/legacy/workflow.d.ts +46 -420
- package/legacy/workflow.js +5 -5
- package/package.json +12 -6
- package/protoc/dispatcher/dispatcher.d.ts +4 -0
- package/protoc/dispatcher/dispatcher.js +41 -1
- package/util/config-loader/config-loader.js +2 -2
- package/util/uuid.js +2 -2
- package/v1/agent/claude.d.ts +17 -0
- package/v1/agent/claude.js +83 -0
- package/v1/agent/openai.d.ts +4 -0
- package/v1/agent/openai.js +83 -0
- package/v1/client/client.js +2 -2
- package/v1/client/features/crons.d.ts +3 -15
- package/v1/client/features/crons.js +8 -8
- package/v1/client/features/schedules.d.ts +6 -20
- package/v1/client/features/schedules.js +10 -10
- package/v1/client/worker/context.d.ts +11 -1
- package/v1/client/worker/context.js +14 -0
- package/v1/client/worker/worker-internal.js +2 -2
- package/v1/declaration.d.ts +18 -1
- package/v1/declaration.js +10 -0
- package/v1/examples/agent/agent-claude.d.ts +1 -0
- package/v1/examples/agent/agent-claude.js +68 -0
- package/v1/examples/agent/agent-openai.d.ts +1 -0
- package/v1/examples/agent/agent-openai.js +72 -0
- package/v1/examples/agent/worker.d.ts +1 -0
- package/v1/examples/agent/worker.js +24 -0
- package/v1/examples/agent/workflow.d.ts +26 -0
- package/v1/examples/agent/workflow.js +48 -0
- package/v1/examples/durable/workflow.d.ts +6 -2
- package/v1/examples/durable/workflow.js +9 -6
- package/v1/examples/durable_eviction/workflow.js +6 -0
- package/v1/examples/e2e-worker.js +7 -0
- package/v1/examples/simple/run.js +5 -0
- package/v1/examples/simple/zod.d.ts +2 -6
- package/v1/examples/simple/zod.js +1 -1
- package/v1/examples/support_agent/run.d.ts +1 -0
- package/v1/examples/support_agent/run.js +42 -0
- package/v1/examples/support_agent/workflow.d.ts +43 -0
- package/v1/examples/support_agent/workflow.js +140 -0
- package/v1/examples/welcome_email/run.d.ts +1 -0
- package/v1/examples/welcome_email/run.js +40 -0
- package/v1/examples/welcome_email/workflow.d.ts +11 -0
- package/v1/examples/welcome_email/workflow.js +52 -0
- package/version.d.ts +1 -1
- package/version.js +1 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
12
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
13
|
+
var m = o[Symbol.asyncIterator], i;
|
|
14
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
15
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
16
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
// eslint-disable-next-line
|
|
20
|
+
const workflow_1 = require("./workflow");
|
|
21
|
+
const claude_agent_sdk_1 = require("@anthropic-ai/claude-agent-sdk");
|
|
22
|
+
const claude_agent_sdk_2 = require("@anthropic-ai/claude-agent-sdk");
|
|
23
|
+
function main() {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
// Generate a tool from a standalone task
|
|
26
|
+
// const temperatureTool = getTemperature.mcpTool('claude');
|
|
27
|
+
var _a, e_1, _b, _c;
|
|
28
|
+
// Or from a workflow
|
|
29
|
+
const temperatureTool = workflow_1.getTemperatureWorkflow.mcpTool('claude');
|
|
30
|
+
// Wrap the tool in an in-process MCP server
|
|
31
|
+
const weatherServer = (0, claude_agent_sdk_2.createSdkMcpServer)({
|
|
32
|
+
name: 'weather',
|
|
33
|
+
version: '1.0.0',
|
|
34
|
+
tools: [temperatureTool],
|
|
35
|
+
});
|
|
36
|
+
try {
|
|
37
|
+
for (var _d = true, _e = __asyncValues((0, claude_agent_sdk_1.query)({
|
|
38
|
+
prompt: "What's the temperature in San Francisco?",
|
|
39
|
+
options: {
|
|
40
|
+
mcpServers: { weather: weatherServer },
|
|
41
|
+
allowedTools: [`mcp__${weatherServer.name}__${temperatureTool.name}`],
|
|
42
|
+
},
|
|
43
|
+
})), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
44
|
+
_c = _f.value;
|
|
45
|
+
_d = false;
|
|
46
|
+
const message = _c;
|
|
47
|
+
// "result" is the final message after all tool calls complete
|
|
48
|
+
if (message.type === 'result' && message.subtype === 'success') {
|
|
49
|
+
console.log(message.result);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
54
|
+
finally {
|
|
55
|
+
try {
|
|
56
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
57
|
+
}
|
|
58
|
+
finally { if (e_1) throw e_1.error; }
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (require.main === module) {
|
|
63
|
+
main()
|
|
64
|
+
.catch(console.error)
|
|
65
|
+
.finally(() => {
|
|
66
|
+
process.exit(0);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
// eslint-disable-next-line
|
|
46
|
+
const workflow_1 = require("./workflow");
|
|
47
|
+
function main() {
|
|
48
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
// Generate a tool from a standalone task
|
|
50
|
+
// const temperatureTool = getTemperature.mcpTool('openai');
|
|
51
|
+
// Or from a workflow.
|
|
52
|
+
// mcpTool validates Zod v4 is installed before loading @openai/agents, so call it first
|
|
53
|
+
// to get a clear error message if the wrong Zod version is present.
|
|
54
|
+
const temperatureTool = workflow_1.getTemperatureWorkflow.mcpTool('openai');
|
|
55
|
+
// Dynamic import — @openai/agents crashes at load time with Zod v3, so we delay
|
|
56
|
+
// the import until after mcpTool has already verified Zod v4 is available.
|
|
57
|
+
const { Agent, run } = yield Promise.resolve().then(() => __importStar(require('@openai/agents')));
|
|
58
|
+
const agent = new Agent({
|
|
59
|
+
name: 'Agent',
|
|
60
|
+
tools: [temperatureTool],
|
|
61
|
+
});
|
|
62
|
+
const result = yield run(agent, 'What is the weather in San Francisco?');
|
|
63
|
+
console.log(result.finalOutput);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (require.main === module) {
|
|
67
|
+
main()
|
|
68
|
+
.catch(console.error)
|
|
69
|
+
.finally(() => {
|
|
70
|
+
process.exit(0);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const hatchet_client_1 = require("../hatchet-client");
|
|
13
|
+
const workflow_1 = require("./workflow");
|
|
14
|
+
function main() {
|
|
15
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
const worker = yield hatchet_client_1.hatchet.worker('temperature-worker', {
|
|
17
|
+
workflows: [workflow_1.getTemperature, workflow_1.getTemperatureWorkflow],
|
|
18
|
+
});
|
|
19
|
+
yield worker.start();
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
if (require.main === module) {
|
|
23
|
+
main();
|
|
24
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
declare const TemperatureInput: z.ZodObject<{
|
|
3
|
+
locationName: z.ZodString;
|
|
4
|
+
coords: z.ZodObject<{
|
|
5
|
+
latitude: z.ZodNumber;
|
|
6
|
+
longitude: z.ZodNumber;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
}, z.core.$strip>;
|
|
9
|
+
export type TemperatureInputWithZod = z.infer<typeof TemperatureInput>;
|
|
10
|
+
export declare const getTemperature: import("../..").TaskWorkflowDeclaration<{
|
|
11
|
+
locationName: string;
|
|
12
|
+
coords: {
|
|
13
|
+
latitude: number;
|
|
14
|
+
longitude: number;
|
|
15
|
+
};
|
|
16
|
+
}, {
|
|
17
|
+
text: string;
|
|
18
|
+
}, {}, {}, {}, {}>;
|
|
19
|
+
export declare const getTemperatureWorkflow: import("../..").WorkflowDeclaration<{
|
|
20
|
+
locationName: string;
|
|
21
|
+
coords: {
|
|
22
|
+
latitude: number;
|
|
23
|
+
longitude: number;
|
|
24
|
+
};
|
|
25
|
+
}, {}, {}>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getTemperatureWorkflow = exports.getTemperature = void 0;
|
|
13
|
+
// > Declaring a Task
|
|
14
|
+
const hatchet_client_1 = require("../hatchet-client");
|
|
15
|
+
const v4_1 = require("zod/v4");
|
|
16
|
+
// Note that for agent tools, Zod must be used to create the input and output types for workflows/tasks
|
|
17
|
+
const TemperatureCoordinates = v4_1.z.object({
|
|
18
|
+
latitude: v4_1.z.number(),
|
|
19
|
+
longitude: v4_1.z.number(),
|
|
20
|
+
});
|
|
21
|
+
const TemperatureInput = v4_1.z.object({
|
|
22
|
+
locationName: v4_1.z.string(),
|
|
23
|
+
coords: TemperatureCoordinates,
|
|
24
|
+
});
|
|
25
|
+
const temperatureRequest = (input) => __awaiter(void 0, void 0, void 0, function* () {
|
|
26
|
+
const response = yield fetch(`https://api.open-meteo.com/v1/forecast?latitude=${input.coords.latitude}&longitude=${input.coords.longitude}¤t=temperature_2m&temperature_unit=fahrenheit`);
|
|
27
|
+
const data = yield response.json();
|
|
28
|
+
return {
|
|
29
|
+
text: `Temperature: ${data.current.temperature_2m}°F`,
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
exports.getTemperature = hatchet_client_1.hatchet.task({
|
|
33
|
+
name: 'getTemperature',
|
|
34
|
+
retries: 3,
|
|
35
|
+
fn: temperatureRequest,
|
|
36
|
+
inputValidator: TemperatureInput,
|
|
37
|
+
description: 'Get the current temperature at a location',
|
|
38
|
+
});
|
|
39
|
+
exports.getTemperatureWorkflow = hatchet_client_1.hatchet.workflow({
|
|
40
|
+
name: 'getTemperatureWorkflow',
|
|
41
|
+
inputValidator: TemperatureInput,
|
|
42
|
+
description: 'Get the current temperature at a location',
|
|
43
|
+
});
|
|
44
|
+
exports.getTemperatureWorkflow.task({
|
|
45
|
+
name: 'getTemperature',
|
|
46
|
+
fn: temperatureRequest,
|
|
47
|
+
});
|
|
48
|
+
// !!
|
|
@@ -71,8 +71,12 @@ export declare const waitForTwoEventsSecondPushedFirst: import("../..").TaskWork
|
|
|
71
71
|
scope: string;
|
|
72
72
|
}, {
|
|
73
73
|
elapsed: number;
|
|
74
|
-
event1:
|
|
75
|
-
|
|
74
|
+
event1: {
|
|
75
|
+
order: string;
|
|
76
|
+
};
|
|
77
|
+
event2: {
|
|
78
|
+
order: string;
|
|
79
|
+
};
|
|
76
80
|
}, {}, {}, {}, {}>;
|
|
77
81
|
export declare const memoNowCaching: import("../..").TaskWorkflowDeclaration<import("../..").JsonObject, {
|
|
78
82
|
start_time: string;
|
|
@@ -13,7 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.durableSpawnDag = exports.dagChildWorkflow = exports.memoNowCaching = exports.waitForTwoEventsSecondPushedFirst = exports.waitForOrEventLookback = exports.waitForEventLookback = exports.LOOKBACK_WINDOW = exports.durableReplayReset = exports.REPLAY_RESET_MEMOIZED_MAX_SECONDS = exports.REPLAY_RESET_SLEEP_SECONDS = exports.durableNonDeterminism = exports.durableWithExplicitSpawn = exports.durableSleepEventSpawn = exports.durableWithBulkSpawn = exports.durableWithSpawn = exports.spawnChildTask = exports.waitForSleepTwice = exports.durableWorkflow = exports.SLEEP_TIME = exports.SLEEP_TIME_SECONDS = exports.EVENT_KEY = void 0;
|
|
16
|
-
const
|
|
16
|
+
const v4_1 = require("zod/v4");
|
|
17
17
|
const conditions_1 = require("../../conditions");
|
|
18
18
|
const non_determinism_error_1 = require("../../../util/errors/non-determinism-error");
|
|
19
19
|
const sleep_1 = __importDefault(require("../../../util/sleep"));
|
|
@@ -226,9 +226,12 @@ exports.durableReplayReset = hatchet_client_1.hatchet.durableTask({
|
|
|
226
226
|
}),
|
|
227
227
|
});
|
|
228
228
|
exports.LOOKBACK_WINDOW = '1m';
|
|
229
|
-
const lookbackEventPayloadSchema =
|
|
230
|
-
order:
|
|
231
|
-
user_id:
|
|
229
|
+
const lookbackEventPayloadSchema = v4_1.z.object({
|
|
230
|
+
order: v4_1.z.string(),
|
|
231
|
+
user_id: v4_1.z.number(),
|
|
232
|
+
});
|
|
233
|
+
const twoEventsPayloadSchema = v4_1.z.object({
|
|
234
|
+
order: v4_1.z.string(),
|
|
232
235
|
});
|
|
233
236
|
exports.waitForEventLookback = hatchet_client_1.hatchet.durableTask({
|
|
234
237
|
name: 'wait-for-event-lookback',
|
|
@@ -262,8 +265,8 @@ exports.waitForTwoEventsSecondPushedFirst = hatchet_client_1.hatchet.durableTask
|
|
|
262
265
|
executionTimeout: '10m',
|
|
263
266
|
fn: (input, ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
264
267
|
const start = Date.now();
|
|
265
|
-
const event1 = yield ctx.waitForEvent('key1', undefined,
|
|
266
|
-
const event2 = yield ctx.waitForEvent('key2', undefined,
|
|
268
|
+
const event1 = yield ctx.waitForEvent('key1', undefined, twoEventsPayloadSchema, input.scope, exports.LOOKBACK_WINDOW);
|
|
269
|
+
const event2 = yield ctx.waitForEvent('key2', undefined, twoEventsPayloadSchema, input.scope, exports.LOOKBACK_WINDOW);
|
|
267
270
|
return {
|
|
268
271
|
elapsed: (Date.now() - start) / 1000,
|
|
269
272
|
event1,
|
|
@@ -18,11 +18,13 @@ const hatchet_client_1 = require("../hatchet-client");
|
|
|
18
18
|
exports.EVICTION_TTL_SECONDS = 5;
|
|
19
19
|
exports.LONG_SLEEP_SECONDS = 15;
|
|
20
20
|
exports.EVENT_KEY = 'durable-eviction:event';
|
|
21
|
+
// > Eviction Policy
|
|
21
22
|
const EVICTION_POLICY = {
|
|
22
23
|
ttl: `${exports.EVICTION_TTL_SECONDS}s`,
|
|
23
24
|
allowCapacityEviction: true,
|
|
24
25
|
priority: 0,
|
|
25
26
|
};
|
|
27
|
+
// !!
|
|
26
28
|
exports.childTask = hatchet_client_1.hatchet.task({
|
|
27
29
|
name: 'eviction-child-task',
|
|
28
30
|
fn: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -30,6 +32,7 @@ exports.childTask = hatchet_client_1.hatchet.task({
|
|
|
30
32
|
return { child_status: 'completed' };
|
|
31
33
|
}),
|
|
32
34
|
});
|
|
35
|
+
// > Evictable Sleep
|
|
33
36
|
exports.evictableSleep = hatchet_client_1.hatchet.durableTask({
|
|
34
37
|
name: 'evictable-sleep',
|
|
35
38
|
executionTimeout: '5m',
|
|
@@ -39,6 +42,7 @@ exports.evictableSleep = hatchet_client_1.hatchet.durableTask({
|
|
|
39
42
|
return { status: 'completed' };
|
|
40
43
|
}),
|
|
41
44
|
});
|
|
45
|
+
// !!
|
|
42
46
|
// NOTE: DO NOT REGISTER ON E2E TEST WORKER
|
|
43
47
|
exports.evictableSleepForGracefulTermination = hatchet_client_1.hatchet.durableTask({
|
|
44
48
|
name: 'evictable-sleep-for-graceful-termination',
|
|
@@ -114,6 +118,7 @@ exports.capacityEvictableSleep = hatchet_client_1.hatchet.durableTask({
|
|
|
114
118
|
return { status: 'completed' };
|
|
115
119
|
}),
|
|
116
120
|
});
|
|
121
|
+
// > Non Evictable Sleep
|
|
117
122
|
exports.nonEvictableSleep = hatchet_client_1.hatchet.durableTask({
|
|
118
123
|
name: 'non-evictable-sleep',
|
|
119
124
|
executionTimeout: '5m',
|
|
@@ -127,3 +132,4 @@ exports.nonEvictableSleep = hatchet_client_1.hatchet.durableTask({
|
|
|
127
132
|
return { status: 'completed' };
|
|
128
133
|
}),
|
|
129
134
|
});
|
|
135
|
+
// !!
|
|
@@ -40,6 +40,8 @@ const workflow_18 = require("./streaming/workflow");
|
|
|
40
40
|
const workflow_19 = require("./timeout/workflow");
|
|
41
41
|
const workflow_20 = require("./webhooks/workflow");
|
|
42
42
|
const workflow_21 = require("./child_index/workflow");
|
|
43
|
+
const workflow_22 = require("./support_agent/workflow");
|
|
44
|
+
const workflow_23 = require("./welcome_email/workflow");
|
|
43
45
|
const workflows = [
|
|
44
46
|
workflow_1.bulkChild,
|
|
45
47
|
workflow_1.bulkParentWorkflow,
|
|
@@ -94,6 +96,11 @@ const workflows = [
|
|
|
94
96
|
workflow_21.childIndexParent,
|
|
95
97
|
workflow_21.scenarioTask,
|
|
96
98
|
workflow_21.orchestratorTask,
|
|
99
|
+
workflow_22.supportAgent,
|
|
100
|
+
workflow_22.triageTicket,
|
|
101
|
+
workflow_22.generateReply,
|
|
102
|
+
workflow_22.escalateTicket,
|
|
103
|
+
workflow_23.welcomeEmail,
|
|
97
104
|
];
|
|
98
105
|
function main() {
|
|
99
106
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -13,6 +13,7 @@ exports.extra = extra;
|
|
|
13
13
|
const hatchet_client_1 = require("../hatchet-client");
|
|
14
14
|
const workflow_1 = require("./workflow");
|
|
15
15
|
const workflow_with_child_1 = require("./workflow-with-child");
|
|
16
|
+
const zod_1 = require("./zod");
|
|
16
17
|
function main() {
|
|
17
18
|
return __awaiter(this, void 0, void 0, function* () {
|
|
18
19
|
// > Running a Task
|
|
@@ -23,6 +24,10 @@ function main() {
|
|
|
23
24
|
test: 'test',
|
|
24
25
|
},
|
|
25
26
|
});
|
|
27
|
+
const res3 = yield zod_1.simpleWithZod.run({
|
|
28
|
+
Message: 'HeLlO WoRlD',
|
|
29
|
+
});
|
|
30
|
+
console.log(res3.TransformedMessage);
|
|
26
31
|
// 👀 Access the results of the Task
|
|
27
32
|
console.log(res.TransformedMessage);
|
|
28
33
|
// !!
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import * as z from 'zod';
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
2
|
declare const SimpleInputSchema: z.ZodObject<{
|
|
3
3
|
Message: z.ZodString;
|
|
4
|
-
},
|
|
5
|
-
Message: string;
|
|
6
|
-
}, {
|
|
7
|
-
Message: string;
|
|
8
|
-
}>;
|
|
4
|
+
}, z.core.$strip>;
|
|
9
5
|
export type SimpleInputWithZod = z.infer<typeof SimpleInputSchema>;
|
|
10
6
|
export declare const simpleWithZod: import("../..").TaskWorkflowDeclaration<{
|
|
11
7
|
Message: string;
|
|
@@ -44,7 +44,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
45
|
exports.simpleWithZod = void 0;
|
|
46
46
|
// > Declaring a Task
|
|
47
|
-
const z = __importStar(require("zod"));
|
|
47
|
+
const z = __importStar(require("zod/v4"));
|
|
48
48
|
const hatchet_client_1 = require("../hatchet-client");
|
|
49
49
|
const SimpleInputSchema = z.object({
|
|
50
50
|
Message: z.string(),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const hatchet_client_1 = require("../hatchet-client");
|
|
13
|
+
const workflow_1 = require("./workflow");
|
|
14
|
+
// > Trigger the workflow
|
|
15
|
+
function main() {
|
|
16
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
+
const input = {
|
|
18
|
+
ticketId: 'ticket-42',
|
|
19
|
+
customerEmail: 'alice@example.com',
|
|
20
|
+
subject: 'Login broken',
|
|
21
|
+
body: "I can't log in since this morning.",
|
|
22
|
+
};
|
|
23
|
+
// Start the support agent workflow
|
|
24
|
+
const ref = yield workflow_1.supportAgent.runNoWait(input);
|
|
25
|
+
const runId = yield ref.getWorkflowRunId();
|
|
26
|
+
console.log(`Started workflow run: ${runId}`);
|
|
27
|
+
// Push a customer reply event (scoped to this ticket)
|
|
28
|
+
console.log('Pushing customer reply event...');
|
|
29
|
+
yield hatchet_client_1.hatchet.events.push(workflow_1.REPLY_EVENT_KEY, { message: 'I cleared my cookies and it works now. Thanks!' }, { scope: input.ticketId });
|
|
30
|
+
// Wait for the workflow to complete
|
|
31
|
+
const result = yield ref.output;
|
|
32
|
+
console.log('Workflow completed:', result);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// !!
|
|
36
|
+
if (require.main === module) {
|
|
37
|
+
main()
|
|
38
|
+
.catch(console.error)
|
|
39
|
+
.finally(() => {
|
|
40
|
+
process.exit(0);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export declare const REPLY_EVENT_KEY = "support:customer-reply";
|
|
2
|
+
export declare const TIMEOUT_SECONDS = 5;
|
|
3
|
+
export type SupportTicketInput = {
|
|
4
|
+
ticketId: string;
|
|
5
|
+
customerEmail: string;
|
|
6
|
+
subject: string;
|
|
7
|
+
body: string;
|
|
8
|
+
};
|
|
9
|
+
export type TriageOutput = {
|
|
10
|
+
category: string;
|
|
11
|
+
priority: string;
|
|
12
|
+
};
|
|
13
|
+
export type ReplyOutput = {
|
|
14
|
+
message: string;
|
|
15
|
+
};
|
|
16
|
+
export type EscalationOutput = {
|
|
17
|
+
reason: string;
|
|
18
|
+
assignedTo: string;
|
|
19
|
+
};
|
|
20
|
+
export declare const triageTicket: import("../..").TaskWorkflowDeclaration<SupportTicketInput, {
|
|
21
|
+
category: string;
|
|
22
|
+
priority: string;
|
|
23
|
+
}, {}, {}, {}, {}>;
|
|
24
|
+
export declare const generateReply: import("../..").TaskWorkflowDeclaration<SupportTicketInput, {
|
|
25
|
+
message: any;
|
|
26
|
+
}, {}, {}, {}, {}>;
|
|
27
|
+
export declare const escalateTicket: import("../..").TaskWorkflowDeclaration<SupportTicketInput, {
|
|
28
|
+
reason: string;
|
|
29
|
+
assignedTo: string;
|
|
30
|
+
}, {}, {}, {}, {}>;
|
|
31
|
+
export declare const supportAgent: import("../..").TaskWorkflowDeclaration<SupportTicketInput, {
|
|
32
|
+
ticketId: string;
|
|
33
|
+
status: "escalated";
|
|
34
|
+
triageCategory: string;
|
|
35
|
+
triagePriority: string;
|
|
36
|
+
initialReply: any;
|
|
37
|
+
} | {
|
|
38
|
+
ticketId: string;
|
|
39
|
+
status: "resolved";
|
|
40
|
+
triageCategory: string;
|
|
41
|
+
triagePriority: string;
|
|
42
|
+
initialReply: any;
|
|
43
|
+
}, {}, {}, {}, {}>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.supportAgent = exports.escalateTicket = exports.generateReply = exports.triageTicket = exports.TIMEOUT_SECONDS = exports.REPLY_EVENT_KEY = void 0;
|
|
13
|
+
const conditions_1 = require("../../conditions");
|
|
14
|
+
const duration_1 = require("../../client/duration");
|
|
15
|
+
const hatchet_client_1 = require("../hatchet-client");
|
|
16
|
+
exports.REPLY_EVENT_KEY = 'support:customer-reply';
|
|
17
|
+
const REPLY_LABEL = 'reply';
|
|
18
|
+
const TIMEOUT_LABEL = 'timeout';
|
|
19
|
+
exports.TIMEOUT_SECONDS = 5;
|
|
20
|
+
const LOOKBACK_WINDOW = '5m';
|
|
21
|
+
// !!
|
|
22
|
+
// > Triage task
|
|
23
|
+
// Classify the ticket into a category and priority.
|
|
24
|
+
exports.triageTicket = hatchet_client_1.hatchet.task({
|
|
25
|
+
name: 'triage-ticket',
|
|
26
|
+
fn: (input) => __awaiter(void 0, void 0, void 0, function* () {
|
|
27
|
+
const text = `${input.subject} ${input.body}`.toLowerCase();
|
|
28
|
+
let category;
|
|
29
|
+
if (['bill', 'charge', 'payment', 'invoice'].some((w) => text.includes(w))) {
|
|
30
|
+
category = 'billing';
|
|
31
|
+
}
|
|
32
|
+
else if (['login', 'password', 'auth', 'access'].some((w) => text.includes(w))) {
|
|
33
|
+
category = 'account';
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
category = 'technical';
|
|
37
|
+
}
|
|
38
|
+
let priority;
|
|
39
|
+
if (['urgent', 'critical', 'down', 'outage'].some((w) => text.includes(w))) {
|
|
40
|
+
priority = 'high';
|
|
41
|
+
}
|
|
42
|
+
else if (['twice', 'broken', 'error'].some((w) => text.includes(w))) {
|
|
43
|
+
priority = 'medium';
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
priority = 'low';
|
|
47
|
+
}
|
|
48
|
+
return { category, priority };
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
// !!
|
|
52
|
+
// > Generate reply task
|
|
53
|
+
// Generate an initial support reply using Claude.
|
|
54
|
+
exports.generateReply = hatchet_client_1.hatchet.task({
|
|
55
|
+
name: 'generate-reply',
|
|
56
|
+
fn: (input) => __awaiter(void 0, void 0, void 0, function* () {
|
|
57
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
58
|
+
if (!apiKey) {
|
|
59
|
+
return {
|
|
60
|
+
message: `Thank you for contacting support about: ${input.subject}. We are looking into this and will get back to you shortly.`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
64
|
+
const anthropic = require('@anthropic-ai/sdk');
|
|
65
|
+
const Anthropic = anthropic.default || anthropic;
|
|
66
|
+
const client = new Anthropic({ apiKey });
|
|
67
|
+
const response = yield client.messages.create({
|
|
68
|
+
model: 'claude-sonnet-4-20250514',
|
|
69
|
+
max_tokens: 300,
|
|
70
|
+
messages: [
|
|
71
|
+
{
|
|
72
|
+
role: 'user',
|
|
73
|
+
content: `You are a friendly support agent. Write a brief, helpful initial ` +
|
|
74
|
+
`reply to this support ticket.\n\n` +
|
|
75
|
+
`Subject: ${input.subject}\n` +
|
|
76
|
+
`Message: ${input.body}\n\n` +
|
|
77
|
+
`Keep the reply under 3 sentences.`,
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
const [block] = response.content;
|
|
82
|
+
const text = (block === null || block === void 0 ? void 0 : block.type) === 'text' ? block.text : '';
|
|
83
|
+
return { message: text };
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
86
|
+
// !!
|
|
87
|
+
// > Escalate task
|
|
88
|
+
// Escalate an unresolved ticket to the human support team.
|
|
89
|
+
exports.escalateTicket = hatchet_client_1.hatchet.task({
|
|
90
|
+
name: 'escalate-ticket',
|
|
91
|
+
fn: (input) => __awaiter(void 0, void 0, void 0, function* () {
|
|
92
|
+
return {
|
|
93
|
+
reason: `No customer reply within ${exports.TIMEOUT_SECONDS}s timeout`,
|
|
94
|
+
assignedTo: 'support-team@example.com',
|
|
95
|
+
};
|
|
96
|
+
}),
|
|
97
|
+
});
|
|
98
|
+
// !!
|
|
99
|
+
// > Support agent workflow
|
|
100
|
+
exports.supportAgent = hatchet_client_1.hatchet.durableTask({
|
|
101
|
+
name: 'support-agent',
|
|
102
|
+
executionTimeout: '10m',
|
|
103
|
+
fn: (input, ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
104
|
+
var _a, _b;
|
|
105
|
+
// Step 1: Triage the ticket
|
|
106
|
+
const triage = yield exports.triageTicket.run(input);
|
|
107
|
+
// Step 2: Generate an initial reply
|
|
108
|
+
const reply = yield exports.generateReply.run(input);
|
|
109
|
+
// Step 3: Wait for a customer reply or timeout
|
|
110
|
+
const now = yield ctx.now();
|
|
111
|
+
const considerEventsSince = new Date(now.getTime() - (0, duration_1.durationToMs)(LOOKBACK_WINDOW)).toISOString();
|
|
112
|
+
const waitResult = yield ctx.waitFor((0, conditions_1.Or)(new conditions_1.SleepCondition(`${exports.TIMEOUT_SECONDS}s`, TIMEOUT_LABEL), new conditions_1.UserEventCondition(exports.REPLY_EVENT_KEY, '', REPLY_LABEL, undefined, input.ticketId, considerEventsSince)));
|
|
113
|
+
// Determine which condition fired. ctx.waitFor returns
|
|
114
|
+
// { CREATE: { <label>: ... } } where <label> is the readableDataKey
|
|
115
|
+
// we assigned above ('timeout' or 'reply').
|
|
116
|
+
const create = (_a = waitResult['CREATE']) !== null && _a !== void 0 ? _a : waitResult;
|
|
117
|
+
const resolvedLabel = (_b = Object.keys(create)[0]) !== null && _b !== void 0 ? _b : '';
|
|
118
|
+
const customerReplied = resolvedLabel === REPLY_LABEL;
|
|
119
|
+
if (!customerReplied) {
|
|
120
|
+
// Step 4a: Timeout -> escalate
|
|
121
|
+
yield exports.escalateTicket.run(input);
|
|
122
|
+
return {
|
|
123
|
+
ticketId: input.ticketId,
|
|
124
|
+
status: 'escalated',
|
|
125
|
+
triageCategory: triage.category,
|
|
126
|
+
triagePriority: triage.priority,
|
|
127
|
+
initialReply: reply.message,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
// Step 4b: Customer replied -> resolve
|
|
131
|
+
return {
|
|
132
|
+
ticketId: input.ticketId,
|
|
133
|
+
status: 'resolved',
|
|
134
|
+
triageCategory: triage.category,
|
|
135
|
+
triagePriority: triage.priority,
|
|
136
|
+
initialReply: reply.message,
|
|
137
|
+
};
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
// !!
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|