@loopstack/agent-example-workflow 0.2.1 → 0.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/README.md +36 -0
- package/dist/agent-example.module.d.ts +5 -0
- package/dist/agent-example.module.d.ts.map +1 -1
- package/dist/agent-example.module.js +16 -2
- package/dist/agent-example.module.js.map +1 -1
- package/dist/agent-example.workflow.d.ts +7 -3
- package/dist/agent-example.workflow.d.ts.map +1 -1
- package/dist/agent-example.workflow.js +35 -23
- package/dist/agent-example.workflow.js.map +1 -1
- package/dist/tools/calculator.tool.d.ts +9 -3
- package/dist/tools/calculator.tool.d.ts.map +1 -1
- package/dist/tools/calculator.tool.js +7 -8
- package/dist/tools/calculator.tool.js.map +1 -1
- package/dist/tools/weather-lookup.tool.d.ts +7 -3
- package/dist/tools/weather-lookup.tool.d.ts.map +1 -1
- package/dist/tools/weather-lookup.tool.js +3 -4
- package/dist/tools/weather-lookup.tool.js.map +1 -1
- package/package.json +3 -4
- package/src/__tests__/agent-example.workflow.spec.ts +11 -11
- package/src/agent-example.module.ts +19 -4
- package/src/agent-example.workflow.ts +25 -15
- package/src/tools/calculator.tool.ts +14 -9
- package/src/tools/weather-lookup.tool.ts +7 -5
- package/dist/agent-example.ui.yaml +0 -2
- package/src/agent-example.ui.yaml +0 -2
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @loopstack/agent-example-workflow
|
|
2
|
+
|
|
3
|
+
Demonstrates how to launch `AgentWorkflow` from [`@loopstack/agent`](../../features/agent-module) as a sub-workflow with custom tools (`weather_lookup`, `calculator`) and render progress/results in Studio.
|
|
4
|
+
|
|
5
|
+
## By using this example you'll get...
|
|
6
|
+
|
|
7
|
+
- A parent workflow that queues `AgentWorkflow` via `WORKFLOW_ORCHESTRATOR`
|
|
8
|
+
- A `LinkDocument` that embeds the running child workflow
|
|
9
|
+
- A callback transition that stores the final agent response as a `MessageDocument`
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install @loopstack/agent-example-workflow
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`@loopstack/agent` requires an LLM provider configuration. Use `AgentExampleModule.forFeature({ llm: ... })` when you want to override provider config per module.
|
|
18
|
+
|
|
19
|
+
## How It Works
|
|
20
|
+
|
|
21
|
+
1. `start` queues `AgentWorkflow` with a system prompt and selected tools.
|
|
22
|
+
2. A `LinkDocument` is saved to show embedded progress in Studio.
|
|
23
|
+
3. When the child workflow finishes, `agentComplete` receives callback payload data.
|
|
24
|
+
4. The workflow marks the link as successful and saves the final assistant message.
|
|
25
|
+
|
|
26
|
+
## Public API
|
|
27
|
+
|
|
28
|
+
- `AgentExampleModule`
|
|
29
|
+
- `AgentExampleWorkflow`
|
|
30
|
+
- `CalculatorTool`
|
|
31
|
+
- `WeatherLookupTool`
|
|
32
|
+
|
|
33
|
+
## Dependencies
|
|
34
|
+
|
|
35
|
+
- `@loopstack/common`
|
|
36
|
+
- `@loopstack/agent`
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { DynamicModule } from '@nestjs/common';
|
|
2
|
+
import type { LlmModuleConfig } from '@loopstack/llm-provider-module';
|
|
1
3
|
export declare class AgentExampleModule {
|
|
4
|
+
static forFeature(config?: {
|
|
5
|
+
llm?: LlmModuleConfig;
|
|
6
|
+
}): DynamicModule;
|
|
2
7
|
}
|
|
3
8
|
//# sourceMappingURL=agent-example.module.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-example.module.d.ts","sourceRoot":"","sources":["../src/agent-example.module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent-example.module.d.ts","sourceRoot":"","sources":["../src/agent-example.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAEvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAUtE,qBAKa,kBAAkB;IAC7B,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,eAAe,CAAA;KAAE,GAAG,aAAa;CAQrE"}
|
|
@@ -12,14 +12,28 @@ const agent_1 = require("@loopstack/agent");
|
|
|
12
12
|
const agent_example_workflow_1 = require("./agent-example.workflow");
|
|
13
13
|
const calculator_tool_1 = require("./tools/calculator.tool");
|
|
14
14
|
const weather_lookup_tool_1 = require("./tools/weather-lookup.tool");
|
|
15
|
+
const PROVIDERS = [agent_example_workflow_1.AgentExampleWorkflow, calculator_tool_1.CalculatorTool, weather_lookup_tool_1.WeatherLookupTool];
|
|
16
|
+
let AgentExampleRootModule = class AgentExampleRootModule {
|
|
17
|
+
};
|
|
18
|
+
AgentExampleRootModule = __decorate([
|
|
19
|
+
(0, common_1.Module)({})
|
|
20
|
+
], AgentExampleRootModule);
|
|
15
21
|
let AgentExampleModule = class AgentExampleModule {
|
|
22
|
+
static forFeature(config) {
|
|
23
|
+
return {
|
|
24
|
+
module: AgentExampleRootModule,
|
|
25
|
+
imports: [agent_1.AgentModule.forFeature(config)],
|
|
26
|
+
providers: PROVIDERS,
|
|
27
|
+
exports: PROVIDERS,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
16
30
|
};
|
|
17
31
|
exports.AgentExampleModule = AgentExampleModule;
|
|
18
32
|
exports.AgentExampleModule = AgentExampleModule = __decorate([
|
|
19
33
|
(0, common_1.Module)({
|
|
20
34
|
imports: [agent_1.AgentModule],
|
|
21
|
-
providers:
|
|
22
|
-
exports:
|
|
35
|
+
providers: PROVIDERS,
|
|
36
|
+
exports: PROVIDERS,
|
|
23
37
|
})
|
|
24
38
|
], AgentExampleModule);
|
|
25
39
|
//# sourceMappingURL=agent-example.module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-example.module.js","sourceRoot":"","sources":["../src/agent-example.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"agent-example.module.js","sourceRoot":"","sources":["../src/agent-example.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAuD;AACvD,4CAA+C;AAE/C,qEAAgE;AAChE,6DAAyD;AACzD,qEAAgE;AAEhE,MAAM,SAAS,GAAG,CAAC,6CAAoB,EAAE,gCAAc,EAAE,uCAAiB,CAAC,CAAC;AAG5E,IAAM,sBAAsB,GAA5B,MAAM,sBAAsB;CAAG,CAAA;AAAzB,sBAAsB;IAD3B,IAAA,eAAM,EAAC,EAAE,CAAC;GACL,sBAAsB,CAAG;AAOxB,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAC7B,MAAM,CAAC,UAAU,CAAC,MAAkC;QAClD,OAAO;YACL,MAAM,EAAE,sBAAsB;YAC9B,OAAO,EAAE,CAAC,mBAAW,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YACzC,SAAS,EAAE,SAAS;YACpB,OAAO,EAAE,SAAS;SACnB,CAAC;IACJ,CAAC;CACF,CAAA;AATY,gDAAkB;6BAAlB,kBAAkB;IAL9B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,mBAAW,CAAC;QACtB,SAAS,EAAE,SAAS;QACpB,OAAO,EAAE,SAAS;KACnB,CAAC;GACW,kBAAkB,CAS9B"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { AgentWorkflow } from '@loopstack/agent';
|
|
2
3
|
import { BaseWorkflow } from '@loopstack/common';
|
|
4
|
+
import type { TemplateRenderFn } from '@loopstack/common';
|
|
3
5
|
declare const AgentCallbackSchema: z.ZodObject<{
|
|
4
6
|
workflowId: z.ZodString;
|
|
5
7
|
status: z.ZodString;
|
|
@@ -9,9 +11,11 @@ declare const AgentCallbackSchema: z.ZodObject<{
|
|
|
9
11
|
}, z.core.$strip>;
|
|
10
12
|
type AgentCallback = z.infer<typeof AgentCallbackSchema>;
|
|
11
13
|
export declare class AgentExampleWorkflow extends BaseWorkflow {
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
private readonly agentWorkflow;
|
|
15
|
+
private readonly render;
|
|
16
|
+
constructor(agentWorkflow: AgentWorkflow, render: TemplateRenderFn);
|
|
17
|
+
start(state: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
18
|
+
agentComplete(state: Record<string, unknown>, payload: AgentCallback): Promise<unknown>;
|
|
15
19
|
}
|
|
16
20
|
export {};
|
|
17
21
|
//# sourceMappingURL=agent-example.workflow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-example.workflow.d.ts","sourceRoot":"","sources":["../src/agent-example.workflow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent-example.workflow.d.ts","sourceRoot":"","sources":["../src/agent-example.workflow.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EACL,YAAY,EAQb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,QAAA,MAAM,mBAAmB;;;;;;iBAEvB,CAAC;AAEH,KAAK,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEzD,qBAIa,oBAAqB,SAAQ,YAAY;IAElD,OAAO,CAAC,QAAQ,CAAC,aAAa;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADjC,aAAa,EAAE,aAAa,EACD,MAAM,EAAE,gBAAgB;IAMhE,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAwBvE,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;CAa9F"}
|
|
@@ -8,56 +8,68 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
8
8
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
exports.AgentExampleWorkflow = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
13
17
|
const zod_1 = require("zod");
|
|
14
18
|
const agent_1 = require("@loopstack/agent");
|
|
15
|
-
const
|
|
16
|
-
const AgentCallbackSchema =
|
|
19
|
+
const common_2 = require("@loopstack/common");
|
|
20
|
+
const AgentCallbackSchema = common_2.CallbackSchema.extend({
|
|
17
21
|
data: zod_1.z.object({ response: zod_1.z.string() }),
|
|
18
22
|
});
|
|
19
|
-
let AgentExampleWorkflow = class AgentExampleWorkflow extends
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
let AgentExampleWorkflow = class AgentExampleWorkflow extends common_2.BaseWorkflow {
|
|
24
|
+
agentWorkflow;
|
|
25
|
+
render;
|
|
26
|
+
constructor(agentWorkflow, render) {
|
|
27
|
+
super();
|
|
28
|
+
this.agentWorkflow = agentWorkflow;
|
|
29
|
+
this.render = render;
|
|
30
|
+
}
|
|
31
|
+
async start(state) {
|
|
32
|
+
const result = await this.agentWorkflow.run({
|
|
23
33
|
system: this.render(__dirname + '/templates/system.md'),
|
|
24
|
-
tools: ['
|
|
34
|
+
tools: ['weather_lookup', 'calculator'],
|
|
25
35
|
userMessage: "What's the weather in Tokyo? Also, what is 42 * 17?",
|
|
26
|
-
}, {
|
|
27
|
-
await this.
|
|
36
|
+
}, { callback: { transition: 'agentComplete' } });
|
|
37
|
+
await this.documentStore.save(common_2.LinkDocument, { label: 'Agent working...', workflowId: result.workflowId, embed: true, expanded: true }, { id: `link_${result.workflowId}` });
|
|
38
|
+
return state;
|
|
28
39
|
}
|
|
29
|
-
async agentComplete(payload) {
|
|
30
|
-
await this.
|
|
31
|
-
await this.
|
|
40
|
+
async agentComplete(state, payload) {
|
|
41
|
+
await this.documentStore.save(common_2.LinkDocument, { label: 'Agent complete', status: 'success', workflowId: payload.workflowId }, { id: `link_${payload.workflowId}` });
|
|
42
|
+
await this.documentStore.save(common_2.MessageDocument, {
|
|
32
43
|
role: 'assistant',
|
|
33
44
|
content: payload.data.response,
|
|
34
45
|
});
|
|
46
|
+
return {};
|
|
35
47
|
}
|
|
36
48
|
};
|
|
37
49
|
exports.AgentExampleWorkflow = AgentExampleWorkflow;
|
|
38
50
|
__decorate([
|
|
39
|
-
(0,
|
|
40
|
-
__metadata("design:type", agent_1.AgentWorkflow)
|
|
41
|
-
], AgentExampleWorkflow.prototype, "agent", void 0);
|
|
42
|
-
__decorate([
|
|
43
|
-
(0, common_1.Initial)({ to: 'running' }),
|
|
51
|
+
(0, common_2.Transition)({ to: 'running' }),
|
|
44
52
|
__metadata("design:type", Function),
|
|
45
|
-
__metadata("design:paramtypes", []),
|
|
53
|
+
__metadata("design:paramtypes", [Object]),
|
|
46
54
|
__metadata("design:returntype", Promise)
|
|
47
55
|
], AgentExampleWorkflow.prototype, "start", null);
|
|
48
56
|
__decorate([
|
|
49
|
-
(0,
|
|
57
|
+
(0, common_2.Transition)({
|
|
50
58
|
from: 'running',
|
|
59
|
+
to: 'end',
|
|
51
60
|
wait: true,
|
|
52
61
|
schema: AgentCallbackSchema,
|
|
53
62
|
}),
|
|
54
63
|
__metadata("design:type", Function),
|
|
55
|
-
__metadata("design:paramtypes", [Object]),
|
|
64
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
56
65
|
__metadata("design:returntype", Promise)
|
|
57
66
|
], AgentExampleWorkflow.prototype, "agentComplete", null);
|
|
58
67
|
exports.AgentExampleWorkflow = AgentExampleWorkflow = __decorate([
|
|
59
|
-
(0,
|
|
60
|
-
|
|
61
|
-
|
|
68
|
+
(0, common_2.Workflow)({
|
|
69
|
+
title: 'Agent Example',
|
|
70
|
+
description: 'Launches a generic agent sub-workflow with weather and calculator tools.',
|
|
71
|
+
}),
|
|
72
|
+
__param(1, (0, common_1.Inject)(common_2.TEMPLATE_RENDERER)),
|
|
73
|
+
__metadata("design:paramtypes", [agent_1.AgentWorkflow, Function])
|
|
62
74
|
], AgentExampleWorkflow);
|
|
63
75
|
//# sourceMappingURL=agent-example.workflow.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-example.workflow.js","sourceRoot":"","sources":["../src/agent-example.workflow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent-example.workflow.js","sourceRoot":"","sources":["../src/agent-example.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAwC;AACxC,6BAAwB;AACxB,4CAAiD;AACjD,8CAS2B;AAG3B,MAAM,mBAAmB,GAAG,uBAAc,CAAC,MAAM,CAAC;IAChD,IAAI,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,EAAE,CAAC;CACzC,CAAC,CAAC;AAQI,IAAM,oBAAoB,GAA1B,MAAM,oBAAqB,SAAQ,qBAAY;IAEjC;IAC2B;IAF9C,YACmB,aAA4B,EACD,MAAwB;QAEpE,KAAK,EAAE,CAAC;QAHS,kBAAa,GAAb,aAAa,CAAe;QACD,WAAM,GAAN,MAAM,CAAkB;IAGtE,CAAC;IAGK,AAAN,KAAK,CAAC,KAAK,CAAC,KAA8B;QACxC,MAAM,MAAM,GAAgB,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CACtD;YACE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,sBAAsB,CAAC;YACvD,KAAK,EAAE,CAAC,gBAAgB,EAAE,YAAY,CAAC;YACvC,WAAW,EAAE,qDAAqD;SACnE,EACD,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,eAAe,EAAE,EAAE,CAC9C,CAAC;QAEF,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAC3B,qBAAY,EACZ,EAAE,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EACzF,EAAE,EAAE,EAAE,QAAQ,MAAM,CAAC,UAAU,EAAE,EAAE,CACpC,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;IAQK,AAAN,KAAK,CAAC,aAAa,CAAC,KAA8B,EAAE,OAAsB;QACxE,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAC3B,qBAAY,EACZ,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,EAC9E,EAAE,EAAE,EAAE,QAAQ,OAAO,CAAC,UAAU,EAAE,EAAE,CACrC,CAAC;QAEF,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,wBAAe,EAAE;YAC7C,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,QAAQ;SAC/B,CAAC,CAAC;QACH,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAA;AA9CY,oDAAoB;AASzB;IADL,IAAA,mBAAU,EAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC;;;;iDAiB7B;AAQK;IANL,IAAA,mBAAU,EAAC;QACV,IAAI,EAAE,SAAS;QACf,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,mBAAmB;KAC5B,CAAC;;;;yDAaD;+BA7CU,oBAAoB;IAJhC,IAAA,iBAAQ,EAAC;QACR,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,0EAA0E;KACxF,CAAC;IAIG,WAAA,IAAA,eAAM,EAAC,0BAAiB,CAAC,CAAA;qCADM,qBAAa;GAFpC,oBAAoB,CA8ChC"}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { BaseTool, ToolResult } from '@loopstack/common';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
3
|
+
export type CalculatorResult = string;
|
|
4
|
+
export declare class CalculatorTool extends BaseTool<{
|
|
5
|
+
operation: string;
|
|
6
|
+
a: number;
|
|
7
|
+
b: number;
|
|
8
|
+
}, object, CalculatorResult> {
|
|
9
|
+
protected handle(args: {
|
|
4
10
|
operation: string;
|
|
5
11
|
a: number;
|
|
6
12
|
b: number;
|
|
7
|
-
}): Promise<ToolResult
|
|
13
|
+
}, _ctx: LoopstackContext): Promise<ToolResult<CalculatorResult>>;
|
|
8
14
|
}
|
|
9
15
|
//# sourceMappingURL=calculator.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calculator.tool.d.ts","sourceRoot":"","sources":["../../src/tools/calculator.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAQ,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"calculator.tool.d.ts","sourceRoot":"","sources":["../../src/tools/calculator.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAQ,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEtC,qBASa,cAAe,SAAQ,QAAQ,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE,gBAAgB,CAAC;cACjG,MAAM,CACpB,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,EACjD,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;CA2BzC"}
|
|
@@ -10,7 +10,7 @@ exports.CalculatorTool = void 0;
|
|
|
10
10
|
const zod_1 = require("zod");
|
|
11
11
|
const common_1 = require("@loopstack/common");
|
|
12
12
|
let CalculatorTool = class CalculatorTool extends common_1.BaseTool {
|
|
13
|
-
|
|
13
|
+
async handle(args, _ctx) {
|
|
14
14
|
let result;
|
|
15
15
|
switch (args.operation) {
|
|
16
16
|
case 'add':
|
|
@@ -24,24 +24,23 @@ let CalculatorTool = class CalculatorTool extends common_1.BaseTool {
|
|
|
24
24
|
break;
|
|
25
25
|
case 'divide':
|
|
26
26
|
if (args.b === 0) {
|
|
27
|
-
return
|
|
27
|
+
return { data: 'Error: Division by zero', error: 'Cannot divide by zero' };
|
|
28
28
|
}
|
|
29
29
|
result = args.a / args.b;
|
|
30
30
|
break;
|
|
31
31
|
default:
|
|
32
|
-
return
|
|
32
|
+
return { data: `Unknown operation: ${args.operation}`, error: 'Unsupported operation' };
|
|
33
33
|
}
|
|
34
|
-
return
|
|
34
|
+
return {
|
|
35
35
|
data: `${args.a} ${args.operation} ${args.b} = ${result}`,
|
|
36
|
-
}
|
|
36
|
+
};
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
39
|
exports.CalculatorTool = CalculatorTool;
|
|
40
40
|
exports.CalculatorTool = CalculatorTool = __decorate([
|
|
41
41
|
(0, common_1.Tool)({
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
},
|
|
42
|
+
name: 'calculator',
|
|
43
|
+
description: 'Perform a basic arithmetic calculation. Supports add, subtract, multiply, divide.',
|
|
45
44
|
schema: zod_1.z.object({
|
|
46
45
|
operation: zod_1.z.enum(['add', 'subtract', 'multiply', 'divide']).describe('The arithmetic operation.'),
|
|
47
46
|
a: zod_1.z.number().describe('First operand.'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calculator.tool.js","sourceRoot":"","sources":["../../src/tools/calculator.tool.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA+D;
|
|
1
|
+
{"version":3,"file":"calculator.tool.js","sourceRoot":"","sources":["../../src/tools/calculator.tool.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA+D;AAcxD,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,iBAA+E;IACvG,KAAK,CAAC,MAAM,CACpB,IAAiD,EACjD,IAAsB;QAEtB,IAAI,MAAc,CAAC;QAEnB,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC;YACvB,KAAK,KAAK;gBACR,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;gBACzB,MAAM;YACR,KAAK,UAAU;gBACb,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;gBACzB,MAAM;YACR,KAAK,UAAU;gBACb,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;gBACzB,MAAM;YACR,KAAK,QAAQ;gBACX,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;oBACjB,OAAO,EAAE,IAAI,EAAE,yBAAyB,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;gBAC7E,CAAC;gBACD,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;gBACzB,MAAM;YACR;gBACE,OAAO,EAAE,IAAI,EAAE,sBAAsB,IAAI,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;QAC5F,CAAC;QAED,OAAO;YACL,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,MAAM,MAAM,EAAE;SAC1D,CAAC;IACJ,CAAC;CACF,CAAA;AA/BY,wCAAc;yBAAd,cAAc;IAT1B,IAAA,aAAI,EAAC;QACJ,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,mFAAmF;QAChG,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,SAAS,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YAClG,CAAC,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YACxC,CAAC,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;SAC1C,CAAC;KACH,CAAC;GACW,cAAc,CA+B1B"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { BaseTool, ToolResult } from '@loopstack/common';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
3
|
+
export type WeatherLookupResult = string;
|
|
4
|
+
export declare class WeatherLookupTool extends BaseTool<{
|
|
5
|
+
city: string;
|
|
6
|
+
}, object, WeatherLookupResult> {
|
|
7
|
+
protected handle(args: {
|
|
4
8
|
city: string;
|
|
5
|
-
}): Promise<ToolResult
|
|
9
|
+
}, _ctx: LoopstackContext): Promise<ToolResult<WeatherLookupResult>>;
|
|
6
10
|
}
|
|
7
11
|
//# sourceMappingURL=weather-lookup.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weather-lookup.tool.d.ts","sourceRoot":"","sources":["../../src/tools/weather-lookup.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAQ,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"weather-lookup.tool.d.ts","sourceRoot":"","sources":["../../src/tools/weather-lookup.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAQ,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEzC,qBAOa,iBAAkB,SAAQ,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE,mBAAmB,CAAC;cAC5E,MAAM,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;CAejH"}
|
|
@@ -10,7 +10,7 @@ exports.WeatherLookupTool = void 0;
|
|
|
10
10
|
const zod_1 = require("zod");
|
|
11
11
|
const common_1 = require("@loopstack/common");
|
|
12
12
|
let WeatherLookupTool = class WeatherLookupTool extends common_1.BaseTool {
|
|
13
|
-
|
|
13
|
+
async handle(args, _ctx) {
|
|
14
14
|
const forecasts = {
|
|
15
15
|
london: '14°C, cloudy with light rain',
|
|
16
16
|
tokyo: '22°C, sunny with clear skies',
|
|
@@ -26,9 +26,8 @@ let WeatherLookupTool = class WeatherLookupTool extends common_1.BaseTool {
|
|
|
26
26
|
exports.WeatherLookupTool = WeatherLookupTool;
|
|
27
27
|
exports.WeatherLookupTool = WeatherLookupTool = __decorate([
|
|
28
28
|
(0, common_1.Tool)({
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
},
|
|
29
|
+
name: 'weather_lookup',
|
|
30
|
+
description: 'Look up the current weather for a given city. Returns a simulated forecast.',
|
|
32
31
|
schema: zod_1.z.object({
|
|
33
32
|
city: zod_1.z.string().describe('The city name to look up weather for.'),
|
|
34
33
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weather-lookup.tool.js","sourceRoot":"","sources":["../../src/tools/weather-lookup.tool.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA+D;
|
|
1
|
+
{"version":3,"file":"weather-lookup.tool.js","sourceRoot":"","sources":["../../src/tools/weather-lookup.tool.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA+D;AAYxD,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,iBAAuD;IAClF,KAAK,CAAC,MAAM,CAAC,IAAsB,EAAE,IAAsB;QAEnE,MAAM,SAAS,GAA2B;YACxC,MAAM,EAAE,8BAA8B;YACtC,KAAK,EAAE,8BAA8B;YACrC,UAAU,EAAE,qBAAqB;SAClC,CAAC;QAEF,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,2BAA2B,CAAC;QAE9D,OAAO,OAAO,CAAC,OAAO,CAAC;YACrB,IAAI,EAAE,cAAc,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE;SAC5C,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAhBY,8CAAiB;4BAAjB,iBAAiB;IAP7B,IAAA,aAAI,EAAC;QACJ,IAAI,EAAE,gBAAgB;QACtB,WAAW,EAAE,6EAA6E;QAC1F,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;SACnE,CAAC;KACH,CAAC;GACW,iBAAiB,CAgB7B"}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"claude",
|
|
10
10
|
"sub-workflow"
|
|
11
11
|
],
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.3.0",
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Jakob Klippel",
|
|
@@ -30,9 +30,8 @@
|
|
|
30
30
|
"watch": "nest build --watch"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@loopstack/agent": "^0.
|
|
34
|
-
"@loopstack/common": "^0.
|
|
35
|
-
"@loopstack/core": "^0.31.0",
|
|
33
|
+
"@loopstack/agent": "^0.5.0",
|
|
34
|
+
"@loopstack/common": "^0.32.0",
|
|
36
35
|
"@nestjs/common": "^11.1.19",
|
|
37
36
|
"zod": "^4.3.6"
|
|
38
37
|
},
|
|
@@ -8,22 +8,22 @@ import { AgentExampleWorkflow } from '../agent-example.workflow';
|
|
|
8
8
|
import { CalculatorTool } from '../tools/calculator.tool';
|
|
9
9
|
import { WeatherLookupTool } from '../tools/weather-lookup.tool';
|
|
10
10
|
|
|
11
|
+
const mockAgentWorkflow = {
|
|
12
|
+
run: vi.fn(),
|
|
13
|
+
};
|
|
14
|
+
|
|
11
15
|
describe('AgentExampleWorkflow', () => {
|
|
12
16
|
let module: TestingModule;
|
|
13
17
|
let workflow: AgentExampleWorkflow;
|
|
14
18
|
let processor: WorkflowProcessorService;
|
|
15
19
|
|
|
16
|
-
const mockAgent = {
|
|
17
|
-
run: vi.fn(),
|
|
18
|
-
};
|
|
19
|
-
|
|
20
20
|
beforeEach(async () => {
|
|
21
21
|
vi.clearAllMocks();
|
|
22
22
|
|
|
23
23
|
module = await createWorkflowTest()
|
|
24
24
|
.forWorkflow(AgentExampleWorkflow)
|
|
25
25
|
.withProviders(CalculatorTool, WeatherLookupTool)
|
|
26
|
-
.withMock(AgentWorkflow,
|
|
26
|
+
.withMock(AgentWorkflow, mockAgentWorkflow)
|
|
27
27
|
.compile();
|
|
28
28
|
|
|
29
29
|
workflow = module.get(AgentExampleWorkflow);
|
|
@@ -35,7 +35,7 @@ describe('AgentExampleWorkflow', () => {
|
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
it('launches AgentWorkflow and stops at running', async () => {
|
|
38
|
-
|
|
38
|
+
mockAgentWorkflow.run.mockResolvedValue({ workflowId: 'agent-sub-id' });
|
|
39
39
|
|
|
40
40
|
const result = await processor.process(workflow, {}, createStatelessContext());
|
|
41
41
|
|
|
@@ -43,19 +43,19 @@ describe('AgentExampleWorkflow', () => {
|
|
|
43
43
|
expect(result.stop).toBe(true);
|
|
44
44
|
expect(result.place).toBe('running');
|
|
45
45
|
|
|
46
|
-
expect(
|
|
46
|
+
expect(mockAgentWorkflow.run).toHaveBeenCalledWith(
|
|
47
47
|
expect.objectContaining({
|
|
48
48
|
system: expect.any(String),
|
|
49
|
-
tools: ['
|
|
49
|
+
tools: ['weather_lookup', 'calculator'],
|
|
50
50
|
userMessage: expect.any(String),
|
|
51
51
|
}),
|
|
52
|
-
|
|
52
|
+
{ callback: { transition: 'agentComplete' } },
|
|
53
53
|
);
|
|
54
54
|
|
|
55
55
|
expect(result.documents).toEqual(
|
|
56
56
|
expect.arrayContaining([
|
|
57
57
|
expect.objectContaining({
|
|
58
|
-
|
|
58
|
+
documentName: 'link',
|
|
59
59
|
content: expect.objectContaining({ workflowId: 'agent-sub-id' }),
|
|
60
60
|
}),
|
|
61
61
|
]),
|
|
@@ -89,7 +89,7 @@ describe('AgentExampleWorkflow', () => {
|
|
|
89
89
|
expect(result.documents).toEqual(
|
|
90
90
|
expect.arrayContaining([
|
|
91
91
|
expect.objectContaining({
|
|
92
|
-
|
|
92
|
+
documentName: 'message',
|
|
93
93
|
content: expect.objectContaining({ content: expect.stringContaining('714') }),
|
|
94
94
|
}),
|
|
95
95
|
]),
|
|
@@ -1,12 +1,27 @@
|
|
|
1
|
-
import { Module } from '@nestjs/common';
|
|
1
|
+
import { DynamicModule, Module } from '@nestjs/common';
|
|
2
2
|
import { AgentModule } from '@loopstack/agent';
|
|
3
|
+
import type { LlmModuleConfig } from '@loopstack/llm-provider-module';
|
|
3
4
|
import { AgentExampleWorkflow } from './agent-example.workflow';
|
|
4
5
|
import { CalculatorTool } from './tools/calculator.tool';
|
|
5
6
|
import { WeatherLookupTool } from './tools/weather-lookup.tool';
|
|
6
7
|
|
|
8
|
+
const PROVIDERS = [AgentExampleWorkflow, CalculatorTool, WeatherLookupTool];
|
|
9
|
+
|
|
10
|
+
@Module({})
|
|
11
|
+
class AgentExampleRootModule {}
|
|
12
|
+
|
|
7
13
|
@Module({
|
|
8
14
|
imports: [AgentModule],
|
|
9
|
-
providers:
|
|
10
|
-
exports:
|
|
15
|
+
providers: PROVIDERS,
|
|
16
|
+
exports: PROVIDERS,
|
|
11
17
|
})
|
|
12
|
-
export class AgentExampleModule {
|
|
18
|
+
export class AgentExampleModule {
|
|
19
|
+
static forFeature(config?: { llm?: LlmModuleConfig }): DynamicModule {
|
|
20
|
+
return {
|
|
21
|
+
module: AgentExampleRootModule,
|
|
22
|
+
imports: [AgentModule.forFeature(config)],
|
|
23
|
+
providers: PROVIDERS,
|
|
24
|
+
exports: PROVIDERS,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
import { Inject } from '@nestjs/common';
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
import { AgentWorkflow } from '@loopstack/agent';
|
|
3
4
|
import {
|
|
4
5
|
BaseWorkflow,
|
|
5
6
|
CallbackSchema,
|
|
6
|
-
Final,
|
|
7
|
-
Initial,
|
|
8
|
-
InjectWorkflow,
|
|
9
7
|
LinkDocument,
|
|
10
8
|
MessageDocument,
|
|
11
9
|
QueueResult,
|
|
10
|
+
TEMPLATE_RENDERER,
|
|
11
|
+
Transition,
|
|
12
12
|
Workflow,
|
|
13
13
|
} from '@loopstack/common';
|
|
14
|
+
import type { TemplateRenderFn } from '@loopstack/common';
|
|
14
15
|
|
|
15
16
|
const AgentCallbackSchema = CallbackSchema.extend({
|
|
16
17
|
data: z.object({ response: z.string() }),
|
|
@@ -19,44 +20,53 @@ const AgentCallbackSchema = CallbackSchema.extend({
|
|
|
19
20
|
type AgentCallback = z.infer<typeof AgentCallbackSchema>;
|
|
20
21
|
|
|
21
22
|
@Workflow({
|
|
22
|
-
|
|
23
|
+
title: 'Agent Example',
|
|
24
|
+
description: 'Launches a generic agent sub-workflow with weather and calculator tools.',
|
|
23
25
|
})
|
|
24
26
|
export class AgentExampleWorkflow extends BaseWorkflow {
|
|
25
|
-
|
|
27
|
+
constructor(
|
|
28
|
+
private readonly agentWorkflow: AgentWorkflow,
|
|
29
|
+
@Inject(TEMPLATE_RENDERER) private readonly render: TemplateRenderFn,
|
|
30
|
+
) {
|
|
31
|
+
super();
|
|
32
|
+
}
|
|
26
33
|
|
|
27
|
-
@
|
|
28
|
-
async start() {
|
|
29
|
-
const result: QueueResult = await this.
|
|
34
|
+
@Transition({ to: 'running' })
|
|
35
|
+
async start(state: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
36
|
+
const result: QueueResult = await this.agentWorkflow.run(
|
|
30
37
|
{
|
|
31
38
|
system: this.render(__dirname + '/templates/system.md'),
|
|
32
|
-
tools: ['
|
|
39
|
+
tools: ['weather_lookup', 'calculator'],
|
|
33
40
|
userMessage: "What's the weather in Tokyo? Also, what is 42 * 17?",
|
|
34
41
|
},
|
|
35
|
-
{
|
|
42
|
+
{ callback: { transition: 'agentComplete' } },
|
|
36
43
|
);
|
|
37
44
|
|
|
38
|
-
await this.
|
|
45
|
+
await this.documentStore.save(
|
|
39
46
|
LinkDocument,
|
|
40
47
|
{ label: 'Agent working...', workflowId: result.workflowId, embed: true, expanded: true },
|
|
41
48
|
{ id: `link_${result.workflowId}` },
|
|
42
49
|
);
|
|
50
|
+
return state;
|
|
43
51
|
}
|
|
44
52
|
|
|
45
|
-
@
|
|
53
|
+
@Transition({
|
|
46
54
|
from: 'running',
|
|
55
|
+
to: 'end',
|
|
47
56
|
wait: true,
|
|
48
57
|
schema: AgentCallbackSchema,
|
|
49
58
|
})
|
|
50
|
-
async agentComplete(payload: AgentCallback) {
|
|
51
|
-
await this.
|
|
59
|
+
async agentComplete(state: Record<string, unknown>, payload: AgentCallback): Promise<unknown> {
|
|
60
|
+
await this.documentStore.save(
|
|
52
61
|
LinkDocument,
|
|
53
62
|
{ label: 'Agent complete', status: 'success', workflowId: payload.workflowId },
|
|
54
63
|
{ id: `link_${payload.workflowId}` },
|
|
55
64
|
);
|
|
56
65
|
|
|
57
|
-
await this.
|
|
66
|
+
await this.documentStore.save(MessageDocument, {
|
|
58
67
|
role: 'assistant',
|
|
59
68
|
content: payload.data.response,
|
|
60
69
|
});
|
|
70
|
+
return {};
|
|
61
71
|
}
|
|
62
72
|
}
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { BaseTool, Tool, ToolResult } from '@loopstack/common';
|
|
3
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
4
|
+
|
|
5
|
+
export type CalculatorResult = string;
|
|
3
6
|
|
|
4
7
|
@Tool({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
},
|
|
8
|
+
name: 'calculator',
|
|
9
|
+
description: 'Perform a basic arithmetic calculation. Supports add, subtract, multiply, divide.',
|
|
8
10
|
schema: z.object({
|
|
9
11
|
operation: z.enum(['add', 'subtract', 'multiply', 'divide']).describe('The arithmetic operation.'),
|
|
10
12
|
a: z.number().describe('First operand.'),
|
|
11
13
|
b: z.number().describe('Second operand.'),
|
|
12
14
|
}),
|
|
13
15
|
})
|
|
14
|
-
export class CalculatorTool extends BaseTool {
|
|
15
|
-
|
|
16
|
+
export class CalculatorTool extends BaseTool<{ operation: string; a: number; b: number }, object, CalculatorResult> {
|
|
17
|
+
protected async handle(
|
|
18
|
+
args: { operation: string; a: number; b: number },
|
|
19
|
+
_ctx: LoopstackContext,
|
|
20
|
+
): Promise<ToolResult<CalculatorResult>> {
|
|
16
21
|
let result: number;
|
|
17
22
|
|
|
18
23
|
switch (args.operation) {
|
|
@@ -27,16 +32,16 @@ export class CalculatorTool extends BaseTool {
|
|
|
27
32
|
break;
|
|
28
33
|
case 'divide':
|
|
29
34
|
if (args.b === 0) {
|
|
30
|
-
return
|
|
35
|
+
return { data: 'Error: Division by zero', error: 'Cannot divide by zero' };
|
|
31
36
|
}
|
|
32
37
|
result = args.a / args.b;
|
|
33
38
|
break;
|
|
34
39
|
default:
|
|
35
|
-
return
|
|
40
|
+
return { data: `Unknown operation: ${args.operation}`, error: 'Unsupported operation' };
|
|
36
41
|
}
|
|
37
42
|
|
|
38
|
-
return
|
|
43
|
+
return {
|
|
39
44
|
data: `${args.a} ${args.operation} ${args.b} = ${result}`,
|
|
40
|
-
}
|
|
45
|
+
};
|
|
41
46
|
}
|
|
42
47
|
}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { BaseTool, Tool, ToolResult } from '@loopstack/common';
|
|
3
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
4
|
+
|
|
5
|
+
export type WeatherLookupResult = string;
|
|
3
6
|
|
|
4
7
|
@Tool({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
},
|
|
8
|
+
name: 'weather_lookup',
|
|
9
|
+
description: 'Look up the current weather for a given city. Returns a simulated forecast.',
|
|
8
10
|
schema: z.object({
|
|
9
11
|
city: z.string().describe('The city name to look up weather for.'),
|
|
10
12
|
}),
|
|
11
13
|
})
|
|
12
|
-
export class WeatherLookupTool extends BaseTool {
|
|
13
|
-
|
|
14
|
+
export class WeatherLookupTool extends BaseTool<{ city: string }, object, WeatherLookupResult> {
|
|
15
|
+
protected async handle(args: { city: string }, _ctx: LoopstackContext): Promise<ToolResult<WeatherLookupResult>> {
|
|
14
16
|
// Simulated weather data for demonstration purposes
|
|
15
17
|
const forecasts: Record<string, string> = {
|
|
16
18
|
london: '14°C, cloudy with light rain',
|