@jcheesepkg/nanobot 0.9.1 → 0.9.2
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 +18 -18
- package/dist/agent/context.d.mts +4 -4
- package/dist/agent/context.d.mts.map +1 -1
- package/dist/agent/context.mjs +27 -28
- package/dist/agent/context.mjs.map +1 -1
- package/dist/agent/loop.d.mts +5 -3
- package/dist/agent/loop.d.mts.map +1 -1
- package/dist/agent/loop.mjs +64 -55
- package/dist/agent/loop.mjs.map +1 -1
- package/dist/agent/memory.d.mts.map +1 -1
- package/dist/agent/memory.mjs +3 -3
- package/dist/agent/memory.mjs.map +1 -1
- package/dist/agent/skills.d.mts.map +1 -1
- package/dist/agent/skills.mjs +4 -4
- package/dist/agent/skills.mjs.map +1 -1
- package/dist/agent/subagent.d.mts.map +1 -1
- package/dist/agent/subagent.mjs +22 -22
- package/dist/agent/subagent.mjs.map +1 -1
- package/dist/agent/tools/base.mjs +2 -2
- package/dist/agent/tools/base.mjs.map +1 -1
- package/dist/agent/tools/cron.d.mts +1 -1
- package/dist/agent/tools/cron.d.mts.map +1 -1
- package/dist/agent/tools/cron.mjs +11 -11
- package/dist/agent/tools/cron.mjs.map +1 -1
- package/dist/agent/tools/filesystem.d.mts +4 -4
- package/dist/agent/tools/filesystem.d.mts.map +1 -1
- package/dist/agent/tools/filesystem.mjs +20 -20
- package/dist/agent/tools/filesystem.mjs.map +1 -1
- package/dist/agent/tools/flex.d.mts +1 -1
- package/dist/agent/tools/flex.d.mts.map +1 -1
- package/dist/agent/tools/flex.mjs +112 -112
- package/dist/agent/tools/flex.mjs.map +1 -1
- package/dist/agent/tools/flex.test.mjs +60 -59
- package/dist/agent/tools/flex.test.mjs.map +1 -1
- package/dist/agent/tools/message.d.mts +1 -1
- package/dist/agent/tools/message.d.mts.map +1 -1
- package/dist/agent/tools/message.mjs +4 -4
- package/dist/agent/tools/message.mjs.map +1 -1
- package/dist/agent/tools/registry.d.mts.map +1 -1
- package/dist/agent/tools/registry.mjs +4 -4
- package/dist/agent/tools/registry.mjs.map +1 -1
- package/dist/agent/tools/shell.d.mts +1 -1
- package/dist/agent/tools/shell.mjs +4 -4
- package/dist/agent/tools/shell.mjs.map +1 -1
- package/dist/agent/tools/spawn.d.mts +1 -1
- package/dist/agent/tools/spawn.d.mts.map +1 -1
- package/dist/agent/tools/spawn.mjs +4 -4
- package/dist/agent/tools/spawn.mjs.map +1 -1
- package/dist/agent/tools/web.d.mts +2 -2
- package/dist/agent/tools/web.d.mts.map +1 -1
- package/dist/agent/tools/web.mjs +36 -36
- package/dist/agent/tools/web.mjs.map +1 -1
- package/dist/bus/events.mjs +1 -1
- package/dist/bus/events.mjs.map +1 -1
- package/dist/bus/queue.d.mts.map +1 -1
- package/dist/bus/queue.mjs.map +1 -1
- package/dist/channels/base.d.mts.map +1 -1
- package/dist/channels/base.mjs +2 -2
- package/dist/channels/base.mjs.map +1 -1
- package/dist/channels/line.d.mts +1 -0
- package/dist/channels/line.d.mts.map +1 -1
- package/dist/channels/line.mjs +65 -65
- package/dist/channels/line.mjs.map +1 -1
- package/dist/channels/line.test.mjs +26 -27
- package/dist/channels/line.test.mjs.map +1 -1
- package/dist/channels/manager.d.mts.map +1 -1
- package/dist/channels/manager.mjs +9 -9
- package/dist/channels/manager.mjs.map +1 -1
- package/dist/channels/telegram.mjs +34 -34
- package/dist/channels/telegram.mjs.map +1 -1
- package/dist/cli/index.mjs +36 -36
- package/dist/cli/index.mjs.map +1 -1
- package/dist/config/loader.d.mts.map +1 -1
- package/dist/config/loader.mjs +1 -1
- package/dist/config/loader.mjs.map +1 -1
- package/dist/config/schema.d.mts +387 -387
- package/dist/config/schema.d.mts.map +1 -1
- package/dist/config/schema.mjs +42 -42
- package/dist/config/schema.mjs.map +1 -1
- package/dist/gateway/server.d.mts.map +1 -1
- package/dist/gateway/server.mjs +48 -54
- package/dist/gateway/server.mjs.map +1 -1
- package/dist/heartbeat/service.d.mts.map +1 -1
- package/dist/heartbeat/service.mjs +8 -8
- package/dist/heartbeat/service.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/node_modules/{@jridgewell → .bun/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell}/sourcemap-codec/dist/sourcemap-codec.mjs +1 -1
- package/dist/node_modules/.bun/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs.map +1 -0
- package/dist/node_modules/{@vitest → .bun/@vitest_expect@2.1.9/node_modules/@vitest}/expect/dist/index.mjs +8 -8
- package/dist/node_modules/.bun/@vitest_expect@2.1.9/node_modules/@vitest/expect/dist/index.mjs.map +1 -0
- package/dist/node_modules/{@vitest → .bun/@vitest_pretty-format@2.1.9/node_modules/@vitest}/pretty-format/dist/index.mjs +2 -2
- package/dist/node_modules/.bun/@vitest_pretty-format@2.1.9/node_modules/@vitest/pretty-format/dist/index.mjs.map +1 -0
- package/dist/node_modules/{@vitest → .bun/@vitest_runner@2.1.9/node_modules/@vitest}/runner/dist/chunk-tasks.mjs +1 -1
- package/dist/node_modules/.bun/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/chunk-tasks.mjs.map +1 -0
- package/dist/node_modules/{@vitest → .bun/@vitest_runner@2.1.9/node_modules/@vitest}/runner/dist/index.mjs +6 -6
- package/dist/node_modules/.bun/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/index.mjs.map +1 -0
- package/dist/node_modules/{@vitest → .bun/@vitest_snapshot@2.1.9/node_modules/@vitest}/snapshot/dist/index.mjs +5 -5
- package/dist/node_modules/.bun/@vitest_snapshot@2.1.9/node_modules/@vitest/snapshot/dist/index.mjs.map +1 -0
- package/dist/node_modules/{@vitest → .bun/@vitest_spy@2.1.9/node_modules/@vitest}/spy/dist/index.mjs +2 -2
- package/dist/node_modules/.bun/@vitest_spy@2.1.9/node_modules/@vitest/spy/dist/index.mjs.map +1 -0
- package/dist/node_modules/{@vitest → .bun/@vitest_utils@2.1.9/node_modules/@vitest}/utils/dist/chunk-_commonjsHelpers.mjs +3 -3
- package/dist/node_modules/.bun/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/chunk-_commonjsHelpers.mjs.map +1 -0
- package/dist/node_modules/{@vitest → .bun/@vitest_utils@2.1.9/node_modules/@vitest}/utils/dist/diff.mjs +4 -4
- package/dist/node_modules/.bun/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/diff.mjs.map +1 -0
- package/dist/node_modules/{@vitest → .bun/@vitest_utils@2.1.9/node_modules/@vitest}/utils/dist/error.mjs +3 -3
- package/dist/node_modules/.bun/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/error.mjs.map +1 -0
- package/dist/node_modules/{@vitest → .bun/@vitest_utils@2.1.9/node_modules/@vitest}/utils/dist/helpers.mjs +1 -1
- package/dist/node_modules/.bun/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/helpers.mjs.map +1 -0
- package/dist/node_modules/{@vitest → .bun/@vitest_utils@2.1.9/node_modules/@vitest}/utils/dist/index.mjs +3 -3
- package/dist/node_modules/.bun/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/index.mjs.map +1 -0
- package/dist/node_modules/{@vitest → .bun/@vitest_utils@2.1.9/node_modules/@vitest}/utils/dist/source-map.mjs +1 -1
- package/dist/node_modules/.bun/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/source-map.mjs.map +1 -0
- package/dist/node_modules/{chai → .bun/chai@5.3.3/node_modules/chai}/index.mjs +1 -1
- package/dist/node_modules/.bun/chai@5.3.3/node_modules/chai/index.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/arguments.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/arguments.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/array.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/array.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/bigint.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/bigint.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/class.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/class.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/date.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/date.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/error.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/error.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/function.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/function.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/helpers.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/helpers.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/html.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/html.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/index.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/index.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/map.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/map.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/number.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/number.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/object.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/object.mjs.map +1 -0
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/promise.mjs +6 -0
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/promise.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/regexp.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/regexp.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/set.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/set.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/string.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/string.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/symbol.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/symbol.mjs.map +1 -0
- package/dist/node_modules/{loupe → .bun/loupe@3.2.1/node_modules/loupe}/lib/typedarray.mjs +1 -1
- package/dist/node_modules/.bun/loupe@3.2.1/node_modules/loupe/lib/typedarray.mjs.map +1 -0
- package/dist/node_modules/{magic-string → .bun/magic-string@0.30.21/node_modules/magic-string}/dist/magic-string.es.mjs +2 -2
- package/dist/node_modules/.bun/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.mjs.map +1 -0
- package/dist/node_modules/{@vitest/snapshot → .bun/pathe@1.1.2}/node_modules/pathe/dist/shared/pathe.ff20891b.mjs +1 -1
- package/dist/node_modules/.bun/pathe@1.1.2/node_modules/pathe/dist/shared/pathe.ff20891b.mjs.map +1 -0
- package/dist/node_modules/{tinyrainbow → .bun/tinyrainbow@1.2.0/node_modules/tinyrainbow}/dist/chunk-BVHSVHOK.mjs +1 -1
- package/dist/node_modules/.bun/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/chunk-BVHSVHOK.mjs.map +1 -0
- package/dist/node_modules/{tinyrainbow → .bun/tinyrainbow@1.2.0/node_modules/tinyrainbow}/dist/node.mjs +1 -1
- package/dist/node_modules/.bun/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/node.mjs.map +1 -0
- package/dist/node_modules/{tinyspy → .bun/tinyspy@3.0.2/node_modules/tinyspy}/dist/index.mjs +1 -1
- package/dist/node_modules/.bun/tinyspy@3.0.2/node_modules/tinyspy/dist/index.mjs.map +1 -0
- package/dist/node_modules/{vitest → .bun/vitest@2.1.9_7700f9e9ace41f23/node_modules/vitest}/dist/chunks/_commonjsHelpers.BFTU3MAI.mjs +1 -1
- package/dist/node_modules/.bun/vitest@2.1.9_7700f9e9ace41f23/node_modules/vitest/dist/chunks/_commonjsHelpers.BFTU3MAI.mjs.map +1 -0
- package/dist/node_modules/{vitest → .bun/vitest@2.1.9_7700f9e9ace41f23/node_modules/vitest}/dist/chunks/date.W2xKR2qe.mjs +1 -1
- package/dist/node_modules/.bun/vitest@2.1.9_7700f9e9ace41f23/node_modules/vitest/dist/chunks/date.W2xKR2qe.mjs.map +1 -0
- package/dist/node_modules/{vitest → .bun/vitest@2.1.9_7700f9e9ace41f23/node_modules/vitest}/dist/chunks/utils.C8RiOc4B.mjs +2 -2
- package/dist/node_modules/.bun/vitest@2.1.9_7700f9e9ace41f23/node_modules/vitest/dist/chunks/utils.C8RiOc4B.mjs.map +1 -0
- package/dist/node_modules/{vitest → .bun/vitest@2.1.9_7700f9e9ace41f23/node_modules/vitest}/dist/chunks/vi.DgezovHB.mjs +11 -11
- package/dist/node_modules/.bun/vitest@2.1.9_7700f9e9ace41f23/node_modules/vitest/dist/chunks/vi.DgezovHB.mjs.map +1 -0
- package/dist/providers/base.d.mts +2 -2
- package/dist/providers/base.d.mts.map +1 -1
- package/dist/providers/openai-provider.d.mts.map +1 -1
- package/dist/providers/openai-provider.mjs +10 -9
- package/dist/providers/openai-provider.mjs.map +1 -1
- package/dist/providers/registry.d.mts +1 -1
- package/dist/providers/registry.d.mts.map +1 -1
- package/dist/providers/registry.mjs +99 -99
- package/dist/providers/registry.mjs.map +1 -1
- package/dist/session/manager.d.mts +2 -2
- package/dist/session/manager.d.mts.map +1 -1
- package/dist/session/manager.mjs +18 -19
- package/dist/session/manager.mjs.map +1 -1
- package/dist/utils/helpers.d.mts.map +1 -1
- package/dist/utils/helpers.mjs.map +1 -1
- package/package.json +11 -11
- package/skills/cron/SKILL.md +12 -8
- package/skills/daily-summary/SKILL.md +4 -0
- package/skills/english/SKILL.md +21 -7
- package/skills/expense/SKILL.md +11 -7
- package/skills/fortune/SKILL.md +24 -20
- package/skills/habit/SKILL.md +2 -1
- package/skills/hydration/SKILL.md +3 -0
- package/skills/memory/SKILL.md +1 -0
- package/skills/mood/SKILL.md +10 -6
- package/skills/skill-creator/SKILL.md +3 -0
- package/skills/summarize/SKILL.md +1 -0
- package/skills/weather/SKILL.md +10 -8
- package/dist/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs.map +0 -1
- package/dist/node_modules/@vitest/expect/dist/index.mjs.map +0 -1
- package/dist/node_modules/@vitest/pretty-format/dist/index.mjs.map +0 -1
- package/dist/node_modules/@vitest/runner/dist/chunk-tasks.mjs.map +0 -1
- package/dist/node_modules/@vitest/runner/dist/index.mjs.map +0 -1
- package/dist/node_modules/@vitest/snapshot/dist/index.mjs.map +0 -1
- package/dist/node_modules/@vitest/snapshot/node_modules/pathe/dist/shared/pathe.ff20891b.mjs.map +0 -1
- package/dist/node_modules/@vitest/spy/dist/index.mjs.map +0 -1
- package/dist/node_modules/@vitest/utils/dist/chunk-_commonjsHelpers.mjs.map +0 -1
- package/dist/node_modules/@vitest/utils/dist/diff.mjs.map +0 -1
- package/dist/node_modules/@vitest/utils/dist/error.mjs.map +0 -1
- package/dist/node_modules/@vitest/utils/dist/helpers.mjs.map +0 -1
- package/dist/node_modules/@vitest/utils/dist/index.mjs.map +0 -1
- package/dist/node_modules/@vitest/utils/dist/source-map.mjs.map +0 -1
- package/dist/node_modules/chai/index.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/arguments.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/array.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/bigint.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/class.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/date.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/error.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/function.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/helpers.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/html.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/index.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/map.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/number.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/object.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/promise.mjs +0 -6
- package/dist/node_modules/loupe/lib/promise.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/regexp.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/set.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/string.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/symbol.mjs.map +0 -1
- package/dist/node_modules/loupe/lib/typedarray.mjs.map +0 -1
- package/dist/node_modules/magic-string/dist/magic-string.es.mjs.map +0 -1
- package/dist/node_modules/tinyrainbow/dist/chunk-BVHSVHOK.mjs.map +0 -1
- package/dist/node_modules/tinyrainbow/dist/node.mjs.map +0 -1
- package/dist/node_modules/tinyspy/dist/index.mjs.map +0 -1
- package/dist/node_modules/vitest/dist/chunks/_commonjsHelpers.BFTU3MAI.mjs.map +0 -1
- package/dist/node_modules/vitest/dist/chunks/date.W2xKR2qe.mjs.map +0 -1
- package/dist/node_modules/vitest/dist/chunks/utils.C8RiOc4B.mjs.map +0 -1
- package/dist/node_modules/vitest/dist/chunks/vi.DgezovHB.mjs.map +0 -1
- /package/dist/node_modules/{@vitest → .bun/@vitest_runner@2.1.9/node_modules/@vitest}/runner/dist/utils.mjs +0 -0
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import { FlexTool } from "./flex.mjs";
|
|
2
|
-
import { describe, it } from "../../node_modules/@vitest/runner/dist/index.mjs";
|
|
3
|
-
import { globalExpect } from "../../node_modules/vitest/dist/chunks/vi.DgezovHB.mjs";
|
|
2
|
+
import { describe, it } from "../../node_modules/.bun/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/index.mjs";
|
|
3
|
+
import { globalExpect } from "../../node_modules/.bun/vitest@2.1.9_7700f9e9ace41f23/node_modules/vitest/dist/chunks/vi.DgezovHB.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/agent/tools/flex.test.ts
|
|
6
6
|
const tool = new FlexTool();
|
|
7
7
|
async function exec(template, data = {}) {
|
|
8
8
|
const jsonPart = (await tool.execute({
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
data,
|
|
10
|
+
template
|
|
11
11
|
})).split("\n\n(")[0];
|
|
12
12
|
return JSON.parse(jsonPart);
|
|
13
13
|
}
|
|
14
14
|
async function execRaw(template, data = {}) {
|
|
15
15
|
return tool.execute({
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
data,
|
|
17
|
+
template
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
20
|
describe("fortune", () => {
|
|
21
21
|
it("builds with defaults", async () => {
|
|
22
22
|
const flex = await exec("fortune", {
|
|
23
|
+
message: "良い日",
|
|
23
24
|
sign: "♍ 乙女座",
|
|
24
|
-
stars: 4
|
|
25
|
-
message: "良い日"
|
|
25
|
+
stars: 4
|
|
26
26
|
});
|
|
27
27
|
globalExpect(flex.type).toBe("bubble");
|
|
28
28
|
globalExpect(flex.size).toBe("kilo");
|
|
29
|
-
const body = flex
|
|
29
|
+
const { body } = flex;
|
|
30
30
|
globalExpect(body.type).toBe("box");
|
|
31
31
|
globalExpect(body.contents.length).toBeGreaterThanOrEqual(4);
|
|
32
32
|
globalExpect(body.contents[0].text).toBe("♍ 乙女座");
|
|
@@ -38,27 +38,28 @@ describe("fortune", () => {
|
|
|
38
38
|
globalExpect((await exec("fortune", { stars: 99 })).body.contents[2].text).toBe("★★★★★");
|
|
39
39
|
});
|
|
40
40
|
it("includes lucky color and item", async () => {
|
|
41
|
-
const contents = (await exec("fortune", {
|
|
42
|
-
sign: "♈ 牡羊座",
|
|
43
|
-
stars: 3,
|
|
41
|
+
const { contents } = (await exec("fortune", {
|
|
44
42
|
lucky_color: "赤",
|
|
45
|
-
lucky_item: "傘"
|
|
46
|
-
|
|
43
|
+
lucky_item: "傘",
|
|
44
|
+
sign: "♈ 牡羊座",
|
|
45
|
+
stars: 3
|
|
46
|
+
})).body;
|
|
47
47
|
globalExpect(contents.find((c) => c.type === "box" && Array.isArray(c.contents) && c.contents.some((t) => t.text === "ラッキーカラー"))).toBeTruthy();
|
|
48
48
|
globalExpect(contents.find((c) => c.type === "box" && Array.isArray(c.contents) && c.contents.some((t) => t.text === "ラッキーアイテム"))).toBeTruthy();
|
|
49
49
|
});
|
|
50
50
|
it("omits lucky fields when not provided", async () => {
|
|
51
|
-
|
|
51
|
+
const { contents } = (await exec("fortune", { stars: 5 })).body;
|
|
52
|
+
globalExpect(contents.some((c) => c.type === "separator")).toBeFalsy();
|
|
52
53
|
});
|
|
53
54
|
});
|
|
54
55
|
describe("info_card", () => {
|
|
55
56
|
it("builds with title and body", async () => {
|
|
56
57
|
const flex = await exec("info_card", {
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
body: "本文テキスト",
|
|
59
|
+
title: "テスト"
|
|
59
60
|
});
|
|
60
61
|
globalExpect(flex.type).toBe("bubble");
|
|
61
|
-
const contents = flex.body
|
|
62
|
+
const { contents } = flex.body;
|
|
62
63
|
globalExpect(contents[0].text).toBe("テスト");
|
|
63
64
|
globalExpect(contents[1].type).toBe("separator");
|
|
64
65
|
globalExpect(contents[2].text).toBe("本文テキスト");
|
|
@@ -70,7 +71,6 @@ describe("info_card", () => {
|
|
|
70
71
|
describe("action_buttons", () => {
|
|
71
72
|
it("builds with custom buttons", async () => {
|
|
72
73
|
const flex = await exec("action_buttons", {
|
|
73
|
-
prompt: "好きな色は?",
|
|
74
74
|
buttons: [{
|
|
75
75
|
label: "赤",
|
|
76
76
|
text: "赤が好き",
|
|
@@ -79,7 +79,8 @@ describe("action_buttons", () => {
|
|
|
79
79
|
label: "青",
|
|
80
80
|
text: "青が好き",
|
|
81
81
|
style: "secondary"
|
|
82
|
-
}]
|
|
82
|
+
}],
|
|
83
|
+
prompt: "好きな色は?"
|
|
83
84
|
});
|
|
84
85
|
globalExpect(flex.type).toBe("bubble");
|
|
85
86
|
globalExpect(flex.body.contents[0].text).toBe("好きな色は?");
|
|
@@ -97,7 +98,6 @@ describe("action_buttons", () => {
|
|
|
97
98
|
describe("receipt", () => {
|
|
98
99
|
it("builds with items and total", async () => {
|
|
99
100
|
const flex = await exec("receipt", {
|
|
100
|
-
title: "ランチ",
|
|
101
101
|
items: [{
|
|
102
102
|
name: "ラーメン",
|
|
103
103
|
value: "¥900"
|
|
@@ -105,11 +105,12 @@ describe("receipt", () => {
|
|
|
105
105
|
name: "餃子",
|
|
106
106
|
value: "¥400"
|
|
107
107
|
}],
|
|
108
|
+
title: "ランチ",
|
|
108
109
|
total: "¥1,300"
|
|
109
110
|
});
|
|
110
111
|
globalExpect(flex.type).toBe("bubble");
|
|
111
|
-
const contents = flex.body
|
|
112
|
-
globalExpect(contents
|
|
112
|
+
const { contents } = flex.body;
|
|
113
|
+
globalExpect(contents).toHaveLength(6);
|
|
113
114
|
globalExpect(contents[0].text).toContain("ランチ");
|
|
114
115
|
const totalRow = contents[5];
|
|
115
116
|
globalExpect(totalRow.contents[1].text).toBe("¥1,300");
|
|
@@ -118,18 +119,18 @@ describe("receipt", () => {
|
|
|
118
119
|
globalExpect((await exec("receipt", { items: [{
|
|
119
120
|
name: "Item",
|
|
120
121
|
value: "100"
|
|
121
|
-
}] })).body.contents
|
|
122
|
+
}] })).body.contents).toHaveLength(3);
|
|
122
123
|
});
|
|
123
124
|
});
|
|
124
125
|
describe("morning_summary", () => {
|
|
125
126
|
it("builds with all fields", async () => {
|
|
126
127
|
const flex = await exec("morning_summary", {
|
|
127
|
-
greeting: "おはよう!",
|
|
128
|
-
date: "2月13日 木曜日",
|
|
129
|
-
weather: "東京 12°C 曇り",
|
|
130
128
|
advice: "コートでOK",
|
|
129
|
+
date: "2月13日 木曜日",
|
|
130
|
+
greeting: "おはよう!",
|
|
131
|
+
header_color: "#FF6B6B",
|
|
131
132
|
schedule: ["10:00 ミーティング", "14:00 歯医者"],
|
|
132
|
-
|
|
133
|
+
weather: "東京 12°C 曇り"
|
|
133
134
|
});
|
|
134
135
|
globalExpect(flex.type).toBe("bubble");
|
|
135
136
|
globalExpect(flex.header.backgroundColor).toBe("#FF6B6B");
|
|
@@ -138,7 +139,7 @@ describe("morning_summary", () => {
|
|
|
138
139
|
const body = flex.body.contents;
|
|
139
140
|
globalExpect(body[0].text).toBe("東京 12°C 曇り");
|
|
140
141
|
globalExpect(body[1].text).toBe("コートでOK");
|
|
141
|
-
globalExpect(body
|
|
142
|
+
globalExpect(body).toHaveLength(5);
|
|
142
143
|
});
|
|
143
144
|
it("uses default header color", async () => {
|
|
144
145
|
globalExpect((await exec("morning_summary", {})).header.backgroundColor).toBe("#1DB446");
|
|
@@ -161,12 +162,12 @@ describe("hydration", () => {
|
|
|
161
162
|
});
|
|
162
163
|
it("uses custom unit and button text", async () => {
|
|
163
164
|
const flex = await exec("hydration", {
|
|
164
|
-
|
|
165
|
+
button_label: "Had one!",
|
|
166
|
+
button_text: "drank coffee",
|
|
165
167
|
current: 2,
|
|
166
168
|
goal: 4,
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
button_text: "drank coffee"
|
|
169
|
+
title: "Coffee",
|
|
170
|
+
unit: "cups"
|
|
170
171
|
});
|
|
171
172
|
globalExpect(flex.body.contents[0].text).toBe("Coffee");
|
|
172
173
|
globalExpect(flex.body.contents[1].text).toBe("今日: 2cups / 4cups");
|
|
@@ -178,7 +179,6 @@ describe("custom", () => {
|
|
|
178
179
|
it("builds carousel from bubbles array", async () => {
|
|
179
180
|
const flex = await exec("custom", { bubbles: [
|
|
180
181
|
{
|
|
181
|
-
type: "bubble",
|
|
182
182
|
body: {
|
|
183
183
|
type: "box",
|
|
184
184
|
layout: "vertical",
|
|
@@ -186,10 +186,10 @@ describe("custom", () => {
|
|
|
186
186
|
type: "text",
|
|
187
187
|
text: "Card 1"
|
|
188
188
|
}]
|
|
189
|
-
}
|
|
189
|
+
},
|
|
190
|
+
type: "bubble"
|
|
190
191
|
},
|
|
191
192
|
{
|
|
192
|
-
type: "bubble",
|
|
193
193
|
body: {
|
|
194
194
|
type: "box",
|
|
195
195
|
layout: "vertical",
|
|
@@ -197,10 +197,10 @@ describe("custom", () => {
|
|
|
197
197
|
type: "text",
|
|
198
198
|
text: "Card 2"
|
|
199
199
|
}]
|
|
200
|
-
}
|
|
200
|
+
},
|
|
201
|
+
type: "bubble"
|
|
201
202
|
},
|
|
202
203
|
{
|
|
203
|
-
type: "bubble",
|
|
204
204
|
body: {
|
|
205
205
|
type: "box",
|
|
206
206
|
layout: "vertical",
|
|
@@ -208,7 +208,8 @@ describe("custom", () => {
|
|
|
208
208
|
type: "text",
|
|
209
209
|
text: "Card 3"
|
|
210
210
|
}]
|
|
211
|
-
}
|
|
211
|
+
},
|
|
212
|
+
type: "bubble"
|
|
212
213
|
}
|
|
213
214
|
] });
|
|
214
215
|
globalExpect(flex.type).toBe("carousel");
|
|
@@ -218,7 +219,6 @@ describe("custom", () => {
|
|
|
218
219
|
});
|
|
219
220
|
it("prefers bubbles over other custom fields", async () => {
|
|
220
221
|
const flex = await exec("custom", {
|
|
221
|
-
title: "Ignored",
|
|
222
222
|
bubbles: [{
|
|
223
223
|
type: "bubble",
|
|
224
224
|
body: {
|
|
@@ -229,48 +229,48 @@ describe("custom", () => {
|
|
|
229
229
|
text: "Used"
|
|
230
230
|
}]
|
|
231
231
|
}
|
|
232
|
-
}]
|
|
232
|
+
}],
|
|
233
|
+
title: "Ignored"
|
|
233
234
|
});
|
|
234
235
|
globalExpect(flex.type).toBe("carousel");
|
|
235
236
|
globalExpect(flex.contents).toHaveLength(1);
|
|
236
237
|
});
|
|
237
238
|
it("uses raw contents array when provided", async () => {
|
|
238
239
|
const contents = [{
|
|
239
|
-
|
|
240
|
-
|
|
240
|
+
text: "Hello",
|
|
241
|
+
type: "text"
|
|
241
242
|
}, {
|
|
242
|
-
|
|
243
|
-
|
|
243
|
+
text: "World",
|
|
244
|
+
type: "text"
|
|
244
245
|
}];
|
|
245
246
|
const flex = await exec("custom", { contents });
|
|
246
247
|
globalExpect(flex.type).toBe("bubble");
|
|
247
|
-
globalExpect(flex.body.contents).
|
|
248
|
+
globalExpect(flex.body.contents).toStrictEqual(contents);
|
|
248
249
|
});
|
|
249
250
|
it("auto-builds card from title + body", async () => {
|
|
250
251
|
const flex = await exec("custom", {
|
|
251
|
-
|
|
252
|
-
|
|
252
|
+
body: "Body text",
|
|
253
|
+
title: "Title"
|
|
253
254
|
});
|
|
254
255
|
globalExpect(flex.type).toBe("bubble");
|
|
255
|
-
const contents = flex.body
|
|
256
|
+
const { contents } = flex.body;
|
|
256
257
|
globalExpect(contents[0].text).toBe("Title");
|
|
257
258
|
globalExpect(contents[1].type).toBe("separator");
|
|
258
259
|
globalExpect(contents[2].text).toBe("Body text");
|
|
259
260
|
});
|
|
260
261
|
it("auto-builds card with colored header", async () => {
|
|
261
262
|
const flex = await exec("custom", {
|
|
262
|
-
title: "Workout",
|
|
263
263
|
body: "Great session!",
|
|
264
|
-
header_color: "#FF0000"
|
|
264
|
+
header_color: "#FF0000",
|
|
265
|
+
title: "Workout"
|
|
265
266
|
});
|
|
266
267
|
globalExpect(flex.header).toBeTruthy();
|
|
267
268
|
globalExpect(flex.header.backgroundColor).toBe("#FF0000");
|
|
268
269
|
globalExpect(flex.header.contents[0].text).toBe("Workout");
|
|
269
|
-
globalExpect(flex.body.contents.filter((c) => c.type === "text").every((t) => t.text !== "Workout")).
|
|
270
|
+
globalExpect(flex.body.contents.filter((c) => c.type === "text").every((t) => t.text !== "Workout")).toBeTruthy();
|
|
270
271
|
});
|
|
271
272
|
it("auto-builds card with buttons", async () => {
|
|
272
273
|
const flex = await exec("custom", {
|
|
273
|
-
title: "Choose",
|
|
274
274
|
buttons: [{
|
|
275
275
|
label: "Option A",
|
|
276
276
|
text: "A",
|
|
@@ -279,7 +279,8 @@ describe("custom", () => {
|
|
|
279
279
|
label: "Option B",
|
|
280
280
|
text: "B",
|
|
281
281
|
style: "secondary"
|
|
282
|
-
}]
|
|
282
|
+
}],
|
|
283
|
+
title: "Choose"
|
|
283
284
|
});
|
|
284
285
|
globalExpect(flex.footer).toBeTruthy();
|
|
285
286
|
globalExpect(flex.footer.contents).toHaveLength(2);
|
|
@@ -287,11 +288,11 @@ describe("custom", () => {
|
|
|
287
288
|
});
|
|
288
289
|
it("auto-builds button from button_label/button_text shorthand", async () => {
|
|
289
290
|
const flex = await exec("custom", {
|
|
290
|
-
title: "🪴 モンステラ",
|
|
291
291
|
body: "水やり記録なし\n今日は水やりした?",
|
|
292
|
-
header_color: "#4CAF50",
|
|
293
292
|
button_label: "水やりした!",
|
|
294
|
-
button_text: "水やり モンステラ した"
|
|
293
|
+
button_text: "水やり モンステラ した",
|
|
294
|
+
header_color: "#4CAF50",
|
|
295
|
+
title: "🪴 モンステラ"
|
|
295
296
|
});
|
|
296
297
|
globalExpect(flex.footer).toBeTruthy();
|
|
297
298
|
globalExpect(flex.footer.contents).toHaveLength(1);
|
|
@@ -301,13 +302,13 @@ describe("custom", () => {
|
|
|
301
302
|
});
|
|
302
303
|
it("prefers buttons array over button_label shorthand", async () => {
|
|
303
304
|
const flex = await exec("custom", {
|
|
304
|
-
title: "Test",
|
|
305
305
|
button_label: "Ignored",
|
|
306
306
|
buttons: [{
|
|
307
307
|
label: "Used",
|
|
308
308
|
text: "used",
|
|
309
309
|
style: "secondary"
|
|
310
|
-
}]
|
|
310
|
+
}],
|
|
311
|
+
title: "Test"
|
|
311
312
|
});
|
|
312
313
|
globalExpect(flex.footer.contents).toHaveLength(1);
|
|
313
314
|
globalExpect(flex.footer.contents[0].action.label).toBe("Used");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flex.test.mjs","names":[],"sources":["../../../src/agent/tools/flex.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { FlexTool } from \"./flex.js\";\n\nconst tool = new FlexTool();\n\n// Helper: execute and parse result as JSON (strip instruction suffix)\nasync function exec(template: string, data: Record<string, unknown> = {}) {\n const result = await tool.execute({ template, data });\n const jsonPart = result.split(\"\\n\\n(\")[0];\n return JSON.parse(jsonPart);\n}\n\n// Helper: execute and return raw string (for error cases)\nasync function execRaw(template: string, data: Record<string, unknown> = {}) {\n return tool.execute({ template, data });\n}\n\n// ---------------------------------------------------------------------------\n// fortune\n// ---------------------------------------------------------------------------\ndescribe(\"fortune\", () => {\n it(\"builds with defaults\", async () => {\n const flex = await exec(\"fortune\", { sign: \"♍ 乙女座\", stars: 4, message: \"良い日\" });\n expect(flex.type).toBe(\"bubble\");\n expect(flex.size).toBe(\"kilo\");\n\n const body = flex.body;\n expect(body.type).toBe(\"box\");\n // sign, 今日の運勢, stars, message\n expect(body.contents.length).toBeGreaterThanOrEqual(4);\n expect(body.contents[0].text).toBe(\"♍ 乙女座\");\n expect(body.contents[2].text).toBe(\"★★★★☆\");\n expect(body.contents[3].text).toBe(\"良い日\");\n });\n\n it(\"clamps stars to 1-5\", async () => {\n const low = await exec(\"fortune\", { stars: -10 });\n expect(low.body.contents[2].text).toBe(\"★☆☆☆☆\");\n\n const high = await exec(\"fortune\", { stars: 99 });\n expect(high.body.contents[2].text).toBe(\"★★★★★\");\n });\n\n it(\"includes lucky color and item\", async () => {\n const flex = await exec(\"fortune\", {\n sign: \"♈ 牡羊座\",\n stars: 3,\n lucky_color: \"赤\",\n lucky_item: \"傘\",\n });\n const contents = flex.body.contents;\n // Should have separator + color row + item row\n const colorRow = contents.find(\n (c: Record<string, unknown>) =>\n c.type === \"box\" &&\n Array.isArray(c.contents) &&\n (c.contents as Record<string, unknown>[]).some((t) => t.text === \"ラッキーカラー\"),\n );\n expect(colorRow).toBeTruthy();\n\n const itemRow = contents.find(\n (c: Record<string, unknown>) =>\n c.type === \"box\" &&\n Array.isArray(c.contents) &&\n (c.contents as Record<string, unknown>[]).some((t) => t.text === \"ラッキーアイテム\"),\n );\n expect(itemRow).toBeTruthy();\n });\n\n it(\"omits lucky fields when not provided\", async () => {\n const flex = await exec(\"fortune\", { stars: 5 });\n const contents = flex.body.contents;\n const hasSeparator = contents.some((c: Record<string, unknown>) => c.type === \"separator\");\n expect(hasSeparator).toBe(false);\n });\n});\n\n// ---------------------------------------------------------------------------\n// info_card\n// ---------------------------------------------------------------------------\ndescribe(\"info_card\", () => {\n it(\"builds with title and body\", async () => {\n const flex = await exec(\"info_card\", { title: \"テスト\", body: \"本文テキスト\" });\n expect(flex.type).toBe(\"bubble\");\n const contents = flex.body.contents;\n expect(contents[0].text).toBe(\"テスト\");\n expect(contents[1].type).toBe(\"separator\");\n expect(contents[2].text).toBe(\"本文テキスト\");\n });\n\n it(\"uses defaults when no data\", async () => {\n const flex = await exec(\"info_card\", {});\n expect(flex.body.contents[0].text).toBe(\"お知らせ\");\n });\n});\n\n// ---------------------------------------------------------------------------\n// action_buttons\n// ---------------------------------------------------------------------------\ndescribe(\"action_buttons\", () => {\n it(\"builds with custom buttons\", async () => {\n const flex = await exec(\"action_buttons\", {\n prompt: \"好きな色は?\",\n buttons: [\n { label: \"赤\", text: \"赤が好き\", style: \"primary\" },\n { label: \"青\", text: \"青が好き\", style: \"secondary\" },\n ],\n });\n expect(flex.type).toBe(\"bubble\");\n expect(flex.body.contents[0].text).toBe(\"好きな色は?\");\n expect(flex.footer.contents).toHaveLength(2);\n expect(flex.footer.contents[0].action.label).toBe(\"赤\");\n expect(flex.footer.contents[1].action.text).toBe(\"青が好き\");\n });\n\n it(\"adds default yes/no buttons when empty\", async () => {\n const flex = await exec(\"action_buttons\", { prompt: \"OK?\" });\n expect(flex.footer.contents).toHaveLength(2);\n expect(flex.footer.contents[0].action.label).toBe(\"はい\");\n expect(flex.footer.contents[1].action.label).toBe(\"いいえ\");\n });\n});\n\n// ---------------------------------------------------------------------------\n// receipt\n// ---------------------------------------------------------------------------\ndescribe(\"receipt\", () => {\n it(\"builds with items and total\", async () => {\n const flex = await exec(\"receipt\", {\n title: \"ランチ\",\n items: [\n { name: \"ラーメン\", value: \"¥900\" },\n { name: \"餃子\", value: \"¥400\" },\n ],\n total: \"¥1,300\",\n });\n expect(flex.type).toBe(\"bubble\");\n const contents = flex.body.contents;\n // title, separator, 2 items, separator, total\n expect(contents.length).toBe(6);\n expect(contents[0].text).toContain(\"ランチ\");\n // total row\n const totalRow = contents[5] as Record<string, unknown>;\n expect((totalRow.contents as Record<string, unknown>[])[1].text).toBe(\"¥1,300\");\n });\n\n it(\"omits total when not provided\", async () => {\n const flex = await exec(\"receipt\", {\n items: [{ name: \"Item\", value: \"100\" }],\n });\n // title, separator, 1 item = 3 contents (no total separator or total row)\n expect(flex.body.contents.length).toBe(3);\n });\n});\n\n// ---------------------------------------------------------------------------\n// morning_summary\n// ---------------------------------------------------------------------------\ndescribe(\"morning_summary\", () => {\n it(\"builds with all fields\", async () => {\n const flex = await exec(\"morning_summary\", {\n greeting: \"おはよう!\",\n date: \"2月13日 木曜日\",\n weather: \"東京 12°C 曇り\",\n advice: \"コートでOK\",\n schedule: [\"10:00 ミーティング\", \"14:00 歯医者\"],\n header_color: \"#FF6B6B\",\n });\n expect(flex.type).toBe(\"bubble\");\n expect(flex.header.backgroundColor).toBe(\"#FF6B6B\");\n expect(flex.header.contents[0].text).toBe(\"おはよう!\");\n expect(flex.header.contents[1].text).toBe(\"2月13日 木曜日\");\n\n const body = flex.body.contents;\n expect(body[0].text).toBe(\"東京 12°C 曇り\");\n expect(body[1].text).toBe(\"コートでOK\");\n // separator + 2 schedule items\n expect(body.length).toBe(5);\n });\n\n it(\"uses default header color\", async () => {\n const flex = await exec(\"morning_summary\", {});\n expect(flex.header.backgroundColor).toBe(\"#1DB446\");\n });\n\n it(\"shows fallback body when no weather/schedule\", async () => {\n const flex = await exec(\"morning_summary\", { greeting: \"やぁ\" });\n expect(flex.body.contents[0].text).toBe(\"良い一日を!\");\n });\n});\n\n// ---------------------------------------------------------------------------\n// hydration\n// ---------------------------------------------------------------------------\ndescribe(\"hydration\", () => {\n it(\"builds with current/goal\", async () => {\n const flex = await exec(\"hydration\", { current: 3, goal: 8 });\n expect(flex.type).toBe(\"bubble\");\n expect(flex.size).toBe(\"kilo\");\n expect(flex.body.contents[0].text).toBe(\"水飲んだ?\");\n expect(flex.body.contents[1].text).toBe(\"今日: 3杯 / 8杯\");\n expect(flex.footer.contents[0].action.label).toBe(\"飲んだ!\");\n });\n\n it(\"uses custom unit and button text\", async () => {\n const flex = await exec(\"hydration\", {\n title: \"Coffee\",\n current: 2,\n goal: 4,\n unit: \"cups\",\n button_label: \"Had one!\",\n button_text: \"drank coffee\",\n });\n expect(flex.body.contents[0].text).toBe(\"Coffee\");\n expect(flex.body.contents[1].text).toBe(\"今日: 2cups / 4cups\");\n expect(flex.footer.contents[0].action.label).toBe(\"Had one!\");\n expect(flex.footer.contents[0].action.text).toBe(\"drank coffee\");\n });\n});\n\n// ---------------------------------------------------------------------------\n// custom\n// ---------------------------------------------------------------------------\ndescribe(\"custom\", () => {\n it(\"builds carousel from bubbles array\", async () => {\n const flex = await exec(\"custom\", {\n bubbles: [\n { type: \"bubble\", body: { type: \"box\", layout: \"vertical\", contents: [{ type: \"text\", text: \"Card 1\" }] } },\n { type: \"bubble\", body: { type: \"box\", layout: \"vertical\", contents: [{ type: \"text\", text: \"Card 2\" }] } },\n { type: \"bubble\", body: { type: \"box\", layout: \"vertical\", contents: [{ type: \"text\", text: \"Card 3\" }] } },\n ],\n });\n expect(flex.type).toBe(\"carousel\");\n expect(flex.contents).toHaveLength(3);\n expect(flex.contents[0].type).toBe(\"bubble\");\n expect(flex.contents[2].body.contents[0].text).toBe(\"Card 3\");\n });\n\n it(\"prefers bubbles over other custom fields\", async () => {\n const flex = await exec(\"custom\", {\n title: \"Ignored\",\n bubbles: [\n { type: \"bubble\", body: { type: \"box\", layout: \"vertical\", contents: [{ type: \"text\", text: \"Used\" }] } },\n ],\n });\n expect(flex.type).toBe(\"carousel\");\n expect(flex.contents).toHaveLength(1);\n });\n\n it(\"uses raw contents array when provided\", async () => {\n const contents = [\n { type: \"text\", text: \"Hello\" },\n { type: \"text\", text: \"World\" },\n ];\n const flex = await exec(\"custom\", { contents });\n expect(flex.type).toBe(\"bubble\");\n expect(flex.body.contents).toEqual(contents);\n });\n\n it(\"auto-builds card from title + body\", async () => {\n const flex = await exec(\"custom\", { title: \"Title\", body: \"Body text\" });\n expect(flex.type).toBe(\"bubble\");\n const contents = flex.body.contents;\n expect(contents[0].text).toBe(\"Title\");\n expect(contents[1].type).toBe(\"separator\");\n expect(contents[2].text).toBe(\"Body text\");\n });\n\n it(\"auto-builds card with colored header\", async () => {\n const flex = await exec(\"custom\", {\n title: \"Workout\",\n body: \"Great session!\",\n header_color: \"#FF0000\",\n });\n expect(flex.header).toBeTruthy();\n expect(flex.header.backgroundColor).toBe(\"#FF0000\");\n expect(flex.header.contents[0].text).toBe(\"Workout\");\n // Title should be removed from body since it's in the header\n const bodyTexts = flex.body.contents.filter(\n (c: Record<string, unknown>) => c.type === \"text\",\n );\n expect(bodyTexts.every((t: Record<string, unknown>) => t.text !== \"Workout\")).toBe(true);\n });\n\n it(\"auto-builds card with buttons\", async () => {\n const flex = await exec(\"custom\", {\n title: \"Choose\",\n buttons: [\n { label: \"Option A\", text: \"A\", style: \"primary\" },\n { label: \"Option B\", text: \"B\", style: \"secondary\" },\n ],\n });\n expect(flex.footer).toBeTruthy();\n expect(flex.footer.contents).toHaveLength(2);\n expect(flex.footer.contents[0].action.label).toBe(\"Option A\");\n });\n\n it(\"auto-builds button from button_label/button_text shorthand\", async () => {\n const flex = await exec(\"custom\", {\n title: \"🪴 モンステラ\",\n body: \"水やり記録なし\\n今日は水やりした?\",\n header_color: \"#4CAF50\",\n button_label: \"水やりした!\",\n button_text: \"水やり モンステラ した\",\n });\n expect(flex.footer).toBeTruthy();\n expect(flex.footer.contents).toHaveLength(1);\n expect(flex.footer.contents[0].action.label).toBe(\"水やりした!\");\n expect(flex.footer.contents[0].action.text).toBe(\"水やり モンステラ した\");\n expect(flex.footer.contents[0].style).toBe(\"primary\");\n });\n\n it(\"prefers buttons array over button_label shorthand\", async () => {\n const flex = await exec(\"custom\", {\n title: \"Test\",\n button_label: \"Ignored\",\n buttons: [{ label: \"Used\", text: \"used\", style: \"secondary\" }],\n });\n expect(flex.footer.contents).toHaveLength(1);\n expect(flex.footer.contents[0].action.label).toBe(\"Used\");\n });\n\n it(\"errors when no contents, title, body, or buttons\", async () => {\n const result = await execRaw(\"custom\", {});\n expect(result).toContain(\"Error\");\n expect(result).toContain(\"custom template requires\");\n });\n});\n\n// ---------------------------------------------------------------------------\n// unknown template\n// ---------------------------------------------------------------------------\ndescribe(\"unknown template\", () => {\n it(\"returns error for unknown template\", async () => {\n const result = await execRaw(\"nonexistent\", {});\n expect(result).toContain(\"Error: unknown template\");\n expect(result).toContain(\"nonexistent\");\n });\n});\n\n// ---------------------------------------------------------------------------\n// tool metadata\n// ---------------------------------------------------------------------------\ndescribe(\"tool metadata\", () => {\n it(\"has correct name and description\", () => {\n expect(tool.name).toBe(\"flex_message\");\n expect(tool.description).toContain(\"Flex Message\");\n });\n\n it(\"generates valid tool definition\", () => {\n const def = tool.getDefinition();\n expect(def.type).toBe(\"function\");\n expect(def.function.name).toBe(\"flex_message\");\n expect(def.function.parameters.required).toContain(\"template\");\n expect(def.function.parameters.required).toContain(\"data\");\n });\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"flex.test.mjs","names":[],"sources":["../../../src/agent/tools/flex.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\n\nimport { FlexTool } from \"./flex.js\";\n\nconst tool = new FlexTool();\n\n// Helper: execute and parse result as JSON (strip instruction suffix)\nasync function exec(template: string, data: Record<string, unknown> = {}) {\n const result = await tool.execute({ data, template });\n const jsonPart = result.split(\"\\n\\n(\")[0];\n return JSON.parse(jsonPart);\n}\n\n// Helper: execute and return raw string (for error cases)\nasync function execRaw(template: string, data: Record<string, unknown> = {}) {\n return tool.execute({ data, template });\n}\n\n// ---------------------------------------------------------------------------\n// fortune\n// ---------------------------------------------------------------------------\ndescribe(\"fortune\", () => {\n it(\"builds with defaults\", async () => {\n const flex = await exec(\"fortune\", {\n message: \"良い日\",\n sign: \"♍ 乙女座\",\n stars: 4,\n });\n expect(flex.type).toBe(\"bubble\");\n expect(flex.size).toBe(\"kilo\");\n\n const { body } = flex;\n expect(body.type).toBe(\"box\");\n // sign, 今日の運勢, stars, message\n expect(body.contents.length).toBeGreaterThanOrEqual(4);\n expect(body.contents[0].text).toBe(\"♍ 乙女座\");\n expect(body.contents[2].text).toBe(\"★★★★☆\");\n expect(body.contents[3].text).toBe(\"良い日\");\n });\n\n it(\"clamps stars to 1-5\", async () => {\n const low = await exec(\"fortune\", { stars: -10 });\n expect(low.body.contents[2].text).toBe(\"★☆☆☆☆\");\n\n const high = await exec(\"fortune\", { stars: 99 });\n expect(high.body.contents[2].text).toBe(\"★★★★★\");\n });\n\n it(\"includes lucky color and item\", async () => {\n const flex = await exec(\"fortune\", {\n lucky_color: \"赤\",\n lucky_item: \"傘\",\n sign: \"♈ 牡羊座\",\n stars: 3,\n });\n const { contents } = flex.body;\n // Should have separator + color row + item row\n const colorRow = contents.find(\n (c: Record<string, unknown>) =>\n c.type === \"box\" &&\n Array.isArray(c.contents) &&\n (c.contents as Record<string, unknown>[]).some(\n (t) => t.text === \"ラッキーカラー\"\n )\n );\n expect(colorRow).toBeTruthy();\n\n const itemRow = contents.find(\n (c: Record<string, unknown>) =>\n c.type === \"box\" &&\n Array.isArray(c.contents) &&\n (c.contents as Record<string, unknown>[]).some(\n (t) => t.text === \"ラッキーアイテム\"\n )\n );\n expect(itemRow).toBeTruthy();\n });\n\n it(\"omits lucky fields when not provided\", async () => {\n const flex = await exec(\"fortune\", { stars: 5 });\n const { contents } = flex.body;\n const hasSeparator = contents.some(\n (c: Record<string, unknown>) => c.type === \"separator\"\n );\n expect(hasSeparator).toBeFalsy();\n });\n});\n\n// ---------------------------------------------------------------------------\n// info_card\n// ---------------------------------------------------------------------------\ndescribe(\"info_card\", () => {\n it(\"builds with title and body\", async () => {\n const flex = await exec(\"info_card\", {\n body: \"本文テキスト\",\n title: \"テスト\",\n });\n expect(flex.type).toBe(\"bubble\");\n const { contents } = flex.body;\n expect(contents[0].text).toBe(\"テスト\");\n expect(contents[1].type).toBe(\"separator\");\n expect(contents[2].text).toBe(\"本文テキスト\");\n });\n\n it(\"uses defaults when no data\", async () => {\n const flex = await exec(\"info_card\", {});\n expect(flex.body.contents[0].text).toBe(\"お知らせ\");\n });\n});\n\n// ---------------------------------------------------------------------------\n// action_buttons\n// ---------------------------------------------------------------------------\ndescribe(\"action_buttons\", () => {\n it(\"builds with custom buttons\", async () => {\n const flex = await exec(\"action_buttons\", {\n buttons: [\n { label: \"赤\", text: \"赤が好き\", style: \"primary\" },\n { label: \"青\", text: \"青が好き\", style: \"secondary\" },\n ],\n prompt: \"好きな色は?\",\n });\n expect(flex.type).toBe(\"bubble\");\n expect(flex.body.contents[0].text).toBe(\"好きな色は?\");\n expect(flex.footer.contents).toHaveLength(2);\n expect(flex.footer.contents[0].action.label).toBe(\"赤\");\n expect(flex.footer.contents[1].action.text).toBe(\"青が好き\");\n });\n\n it(\"adds default yes/no buttons when empty\", async () => {\n const flex = await exec(\"action_buttons\", { prompt: \"OK?\" });\n expect(flex.footer.contents).toHaveLength(2);\n expect(flex.footer.contents[0].action.label).toBe(\"はい\");\n expect(flex.footer.contents[1].action.label).toBe(\"いいえ\");\n });\n});\n\n// ---------------------------------------------------------------------------\n// receipt\n// ---------------------------------------------------------------------------\ndescribe(\"receipt\", () => {\n it(\"builds with items and total\", async () => {\n const flex = await exec(\"receipt\", {\n items: [\n { name: \"ラーメン\", value: \"¥900\" },\n { name: \"餃子\", value: \"¥400\" },\n ],\n title: \"ランチ\",\n total: \"¥1,300\",\n });\n expect(flex.type).toBe(\"bubble\");\n const { contents } = flex.body;\n // title, separator, 2 items, separator, total\n expect(contents).toHaveLength(6);\n expect(contents[0].text).toContain(\"ランチ\");\n // total row\n const totalRow = contents[5] as Record<string, unknown>;\n expect((totalRow.contents as Record<string, unknown>[])[1].text).toBe(\n \"¥1,300\"\n );\n });\n\n it(\"omits total when not provided\", async () => {\n const flex = await exec(\"receipt\", {\n items: [{ name: \"Item\", value: \"100\" }],\n });\n // title, separator, 1 item = 3 contents (no total separator or total row)\n expect(flex.body.contents).toHaveLength(3);\n });\n});\n\n// ---------------------------------------------------------------------------\n// morning_summary\n// ---------------------------------------------------------------------------\ndescribe(\"morning_summary\", () => {\n it(\"builds with all fields\", async () => {\n const flex = await exec(\"morning_summary\", {\n advice: \"コートでOK\",\n date: \"2月13日 木曜日\",\n greeting: \"おはよう!\",\n header_color: \"#FF6B6B\",\n schedule: [\"10:00 ミーティング\", \"14:00 歯医者\"],\n weather: \"東京 12°C 曇り\",\n });\n expect(flex.type).toBe(\"bubble\");\n expect(flex.header.backgroundColor).toBe(\"#FF6B6B\");\n expect(flex.header.contents[0].text).toBe(\"おはよう!\");\n expect(flex.header.contents[1].text).toBe(\"2月13日 木曜日\");\n\n const body = flex.body.contents;\n expect(body[0].text).toBe(\"東京 12°C 曇り\");\n expect(body[1].text).toBe(\"コートでOK\");\n // separator + 2 schedule items\n expect(body).toHaveLength(5);\n });\n\n it(\"uses default header color\", async () => {\n const flex = await exec(\"morning_summary\", {});\n expect(flex.header.backgroundColor).toBe(\"#1DB446\");\n });\n\n it(\"shows fallback body when no weather/schedule\", async () => {\n const flex = await exec(\"morning_summary\", { greeting: \"やぁ\" });\n expect(flex.body.contents[0].text).toBe(\"良い一日を!\");\n });\n});\n\n// ---------------------------------------------------------------------------\n// hydration\n// ---------------------------------------------------------------------------\ndescribe(\"hydration\", () => {\n it(\"builds with current/goal\", async () => {\n const flex = await exec(\"hydration\", { current: 3, goal: 8 });\n expect(flex.type).toBe(\"bubble\");\n expect(flex.size).toBe(\"kilo\");\n expect(flex.body.contents[0].text).toBe(\"水飲んだ?\");\n expect(flex.body.contents[1].text).toBe(\"今日: 3杯 / 8杯\");\n expect(flex.footer.contents[0].action.label).toBe(\"飲んだ!\");\n });\n\n it(\"uses custom unit and button text\", async () => {\n const flex = await exec(\"hydration\", {\n button_label: \"Had one!\",\n button_text: \"drank coffee\",\n current: 2,\n goal: 4,\n title: \"Coffee\",\n unit: \"cups\",\n });\n expect(flex.body.contents[0].text).toBe(\"Coffee\");\n expect(flex.body.contents[1].text).toBe(\"今日: 2cups / 4cups\");\n expect(flex.footer.contents[0].action.label).toBe(\"Had one!\");\n expect(flex.footer.contents[0].action.text).toBe(\"drank coffee\");\n });\n});\n\n// ---------------------------------------------------------------------------\n// custom\n// ---------------------------------------------------------------------------\ndescribe(\"custom\", () => {\n it(\"builds carousel from bubbles array\", async () => {\n const flex = await exec(\"custom\", {\n bubbles: [\n {\n body: {\n type: \"box\",\n layout: \"vertical\",\n contents: [{ type: \"text\", text: \"Card 1\" }],\n },\n type: \"bubble\",\n },\n {\n body: {\n type: \"box\",\n layout: \"vertical\",\n contents: [{ type: \"text\", text: \"Card 2\" }],\n },\n type: \"bubble\",\n },\n {\n body: {\n type: \"box\",\n layout: \"vertical\",\n contents: [{ type: \"text\", text: \"Card 3\" }],\n },\n type: \"bubble\",\n },\n ],\n });\n expect(flex.type).toBe(\"carousel\");\n expect(flex.contents).toHaveLength(3);\n expect(flex.contents[0].type).toBe(\"bubble\");\n expect(flex.contents[2].body.contents[0].text).toBe(\"Card 3\");\n });\n\n it(\"prefers bubbles over other custom fields\", async () => {\n const flex = await exec(\"custom\", {\n bubbles: [\n {\n type: \"bubble\",\n body: {\n type: \"box\",\n layout: \"vertical\",\n contents: [{ type: \"text\", text: \"Used\" }],\n },\n },\n ],\n title: \"Ignored\",\n });\n expect(flex.type).toBe(\"carousel\");\n expect(flex.contents).toHaveLength(1);\n });\n\n it(\"uses raw contents array when provided\", async () => {\n const contents = [\n { text: \"Hello\", type: \"text\" },\n { text: \"World\", type: \"text\" },\n ];\n const flex = await exec(\"custom\", { contents });\n expect(flex.type).toBe(\"bubble\");\n expect(flex.body.contents).toStrictEqual(contents);\n });\n\n it(\"auto-builds card from title + body\", async () => {\n const flex = await exec(\"custom\", { body: \"Body text\", title: \"Title\" });\n expect(flex.type).toBe(\"bubble\");\n const { contents } = flex.body;\n expect(contents[0].text).toBe(\"Title\");\n expect(contents[1].type).toBe(\"separator\");\n expect(contents[2].text).toBe(\"Body text\");\n });\n\n it(\"auto-builds card with colored header\", async () => {\n const flex = await exec(\"custom\", {\n body: \"Great session!\",\n header_color: \"#FF0000\",\n title: \"Workout\",\n });\n expect(flex.header).toBeTruthy();\n expect(flex.header.backgroundColor).toBe(\"#FF0000\");\n expect(flex.header.contents[0].text).toBe(\"Workout\");\n // Title should be removed from body since it's in the header\n const bodyTexts = flex.body.contents.filter(\n (c: Record<string, unknown>) => c.type === \"text\"\n );\n expect(\n bodyTexts.every((t: Record<string, unknown>) => t.text !== \"Workout\")\n ).toBeTruthy();\n });\n\n it(\"auto-builds card with buttons\", async () => {\n const flex = await exec(\"custom\", {\n buttons: [\n { label: \"Option A\", text: \"A\", style: \"primary\" },\n { label: \"Option B\", text: \"B\", style: \"secondary\" },\n ],\n title: \"Choose\",\n });\n expect(flex.footer).toBeTruthy();\n expect(flex.footer.contents).toHaveLength(2);\n expect(flex.footer.contents[0].action.label).toBe(\"Option A\");\n });\n\n it(\"auto-builds button from button_label/button_text shorthand\", async () => {\n const flex = await exec(\"custom\", {\n body: \"水やり記録なし\\n今日は水やりした?\",\n button_label: \"水やりした!\",\n button_text: \"水やり モンステラ した\",\n header_color: \"#4CAF50\",\n title: \"🪴 モンステラ\",\n });\n expect(flex.footer).toBeTruthy();\n expect(flex.footer.contents).toHaveLength(1);\n expect(flex.footer.contents[0].action.label).toBe(\"水やりした!\");\n expect(flex.footer.contents[0].action.text).toBe(\"水やり モンステラ した\");\n expect(flex.footer.contents[0].style).toBe(\"primary\");\n });\n\n it(\"prefers buttons array over button_label shorthand\", async () => {\n const flex = await exec(\"custom\", {\n button_label: \"Ignored\",\n buttons: [{ label: \"Used\", text: \"used\", style: \"secondary\" }],\n title: \"Test\",\n });\n expect(flex.footer.contents).toHaveLength(1);\n expect(flex.footer.contents[0].action.label).toBe(\"Used\");\n });\n\n it(\"errors when no contents, title, body, or buttons\", async () => {\n const result = await execRaw(\"custom\", {});\n expect(result).toContain(\"Error\");\n expect(result).toContain(\"custom template requires\");\n });\n});\n\n// ---------------------------------------------------------------------------\n// unknown template\n// ---------------------------------------------------------------------------\ndescribe(\"unknown template\", () => {\n it(\"returns error for unknown template\", async () => {\n const result = await execRaw(\"nonexistent\", {});\n expect(result).toContain(\"Error: unknown template\");\n expect(result).toContain(\"nonexistent\");\n });\n});\n\n// ---------------------------------------------------------------------------\n// tool metadata\n// ---------------------------------------------------------------------------\ndescribe(\"tool metadata\", () => {\n it(\"has correct name and description\", () => {\n expect(tool.name).toBe(\"flex_message\");\n expect(tool.description).toContain(\"Flex Message\");\n });\n\n it(\"generates valid tool definition\", () => {\n const def = tool.getDefinition();\n expect(def.type).toBe(\"function\");\n expect(def.function.name).toBe(\"flex_message\");\n expect(def.function.parameters.required).toContain(\"template\");\n expect(def.function.parameters.required).toContain(\"data\");\n });\n});\n"],"mappings":"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"}
|
|
@@ -8,7 +8,6 @@ declare class MessageTool extends Tool {
|
|
|
8
8
|
readonly name = "message";
|
|
9
9
|
readonly description = "Send a message to the user. Use this when you want to communicate something.";
|
|
10
10
|
readonly parameters: {
|
|
11
|
-
type: string;
|
|
12
11
|
properties: {
|
|
13
12
|
content: {
|
|
14
13
|
type: string;
|
|
@@ -24,6 +23,7 @@ declare class MessageTool extends Tool {
|
|
|
24
23
|
};
|
|
25
24
|
};
|
|
26
25
|
required: string[];
|
|
26
|
+
type: string;
|
|
27
27
|
};
|
|
28
28
|
private sendCallback;
|
|
29
29
|
private defaultChannel;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.mts","names":[],"sources":["../../../src/agent/tools/message.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"message.d.mts","names":[],"sources":["../../../src/agent/tools/message.ts"],"mappings":";;;;KAIK,YAAA,IAAgB,GAAA,EAAK,eAAA,KAAoB,OAAA;;cAGjC,WAAA,SAAoB,IAAA;EAAA,SACtB,IAAA;EAAA,SACA,WAAA;EAAA,SAEA,UAAA;;;;;;;;;;;;;;;;;;UAmBD,YAAA;EAAA,QACA,cAAA;EAAA,QACA,aAAA;cAEI,MAAA;IACV,YAAA,GAAe,YAAA;IACf,cAAA;IACA,aAAA;EAAA;;EASF,UAAA,CAAW,OAAA,UAAiB,MAAA;;EAM5B,eAAA,CAAgB,QAAA,EAAU,YAAA;EAIpB,OAAA,CAAQ,IAAA,EAAM,MAAA,oBAA0B,OAAA;AAAA"}
|
|
@@ -6,7 +6,6 @@ var MessageTool = class extends Tool {
|
|
|
6
6
|
name = "message";
|
|
7
7
|
description = "Send a message to the user. Use this when you want to communicate something.";
|
|
8
8
|
parameters = {
|
|
9
|
-
type: "object",
|
|
10
9
|
properties: {
|
|
11
10
|
content: {
|
|
12
11
|
type: "string",
|
|
@@ -21,7 +20,8 @@ var MessageTool = class extends Tool {
|
|
|
21
20
|
description: "Optional: target chat/user ID"
|
|
22
21
|
}
|
|
23
22
|
},
|
|
24
|
-
required: ["content"]
|
|
23
|
+
required: ["content"],
|
|
24
|
+
type: "object"
|
|
25
25
|
};
|
|
26
26
|
sendCallback;
|
|
27
27
|
defaultChannel;
|
|
@@ -57,8 +57,8 @@ var MessageTool = class extends Tool {
|
|
|
57
57
|
try {
|
|
58
58
|
await this.sendCallback(msg);
|
|
59
59
|
return `Message sent to ${channel}:${chatId}`;
|
|
60
|
-
} catch (
|
|
61
|
-
return `Error sending message: ${
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return `Error sending message: ${error instanceof Error ? error.message : error}`;
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.mjs","names":[],"sources":["../../../src/agent/tools/message.ts"],"sourcesContent":["import type { OutboundMessage } from \"../../bus/events.js\";\nimport { Tool } from \"./base.js\";\n\ntype SendCallback = (msg: OutboundMessage) => Promise<void>;\n\n/** Tool to send messages to users on chat channels. */\nexport class MessageTool extends Tool {\n readonly name = \"message\";\n readonly description =\n \"Send a message to the user. Use this when you want to communicate something.\";\n readonly parameters = {\n
|
|
1
|
+
{"version":3,"file":"message.mjs","names":[],"sources":["../../../src/agent/tools/message.ts"],"sourcesContent":["import type { OutboundMessage } from \"../../bus/events.js\";\n\nimport { Tool } from \"./base.js\";\n\ntype SendCallback = (msg: OutboundMessage) => Promise<void>;\n\n/** Tool to send messages to users on chat channels. */\nexport class MessageTool extends Tool {\n readonly name = \"message\";\n readonly description =\n \"Send a message to the user. Use this when you want to communicate something.\";\n readonly parameters = {\n properties: {\n content: {\n type: \"string\",\n description: \"The message content to send\",\n },\n channel: {\n type: \"string\",\n description: \"Optional: target channel (telegram, etc.)\",\n },\n chat_id: {\n type: \"string\",\n description: \"Optional: target chat/user ID\",\n },\n },\n required: [\"content\"],\n type: \"object\",\n };\n\n private sendCallback: SendCallback | null;\n private defaultChannel: string;\n private defaultChatId: string;\n\n constructor(params?: {\n sendCallback?: SendCallback;\n defaultChannel?: string;\n defaultChatId?: string;\n }) {\n super();\n this.sendCallback = params?.sendCallback ?? null;\n this.defaultChannel = params?.defaultChannel ?? \"\";\n this.defaultChatId = params?.defaultChatId ?? \"\";\n }\n\n /** Set the current message context. */\n setContext(channel: string, chatId: string): void {\n this.defaultChannel = channel;\n this.defaultChatId = chatId;\n }\n\n /** Set the callback for sending messages. */\n setSendCallback(callback: SendCallback): void {\n this.sendCallback = callback;\n }\n\n async execute(args: Record<string, unknown>): Promise<string> {\n const content = String(args.content);\n const channel = args.channel ? String(args.channel) : this.defaultChannel;\n const chatId = args.chat_id ? String(args.chat_id) : this.defaultChatId;\n\n if (!channel || !chatId) {\n return \"Error: No target channel/chat specified\";\n }\n if (!this.sendCallback) {\n return \"Error: Message sending not configured\";\n }\n\n const msg: OutboundMessage = {\n channel,\n chatId,\n content,\n media: [],\n metadata: {},\n };\n\n try {\n await this.sendCallback(msg);\n return `Message sent to ${channel}:${chatId}`;\n } catch (error) {\n return `Error sending message: ${error instanceof Error ? error.message : error}`;\n }\n }\n}\n"],"mappings":";;;;AAOA,IAAa,cAAb,cAAiC,KAAK;CACpC,AAAS,OAAO;CAChB,AAAS,cACP;CACF,AAAS,aAAa;EACpB,YAAY;GACV,SAAS;IACP,MAAM;IACN,aAAa;IACd;GACD,SAAS;IACP,MAAM;IACN,aAAa;IACd;GACD,SAAS;IACP,MAAM;IACN,aAAa;IACd;GACF;EACD,UAAU,CAAC,UAAU;EACrB,MAAM;EACP;CAED,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,YAAY,QAIT;AACD,SAAO;AACP,OAAK,eAAe,QAAQ,gBAAgB;AAC5C,OAAK,iBAAiB,QAAQ,kBAAkB;AAChD,OAAK,gBAAgB,QAAQ,iBAAiB;;;CAIhD,WAAW,SAAiB,QAAsB;AAChD,OAAK,iBAAiB;AACtB,OAAK,gBAAgB;;;CAIvB,gBAAgB,UAA8B;AAC5C,OAAK,eAAe;;CAGtB,MAAM,QAAQ,MAAgD;EAC5D,MAAM,UAAU,OAAO,KAAK,QAAQ;EACpC,MAAM,UAAU,KAAK,UAAU,OAAO,KAAK,QAAQ,GAAG,KAAK;EAC3D,MAAM,SAAS,KAAK,UAAU,OAAO,KAAK,QAAQ,GAAG,KAAK;AAE1D,MAAI,CAAC,WAAW,CAAC,OACf,QAAO;AAET,MAAI,CAAC,KAAK,aACR,QAAO;EAGT,MAAM,MAAuB;GAC3B;GACA;GACA;GACA,OAAO,EAAE;GACT,UAAU,EAAE;GACb;AAED,MAAI;AACF,SAAM,KAAK,aAAa,IAAI;AAC5B,UAAO,mBAAmB,QAAQ,GAAG;WAC9B,OAAO;AACd,UAAO,0BAA0B,iBAAiB,QAAQ,MAAM,UAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.mts","names":[],"sources":["../../../src/agent/tools/registry.ts"],"mappings":";;;;;;AAMA;cAAa,YAAA;EAAA,QACH,KAAA;EAGO;EAAf,QAAA,CAAS,IAAA,EAAM,IAAA;EAoBG;EAflB,UAAA,CAAW,IAAA;
|
|
1
|
+
{"version":3,"file":"registry.d.mts","names":[],"sources":["../../../src/agent/tools/registry.ts"],"mappings":";;;;;;AAMA;cAAa,YAAA;EAAA,QACH,KAAA;EAGO;EAAf,QAAA,CAAS,IAAA,EAAM,IAAA;EAoBG;EAflB,UAAA,CAAW,IAAA;EAoBiD;EAf5D,GAAA,CAAI,IAAA,WAAe,IAAA;EAegD;EAVnE,GAAA,CAAI,IAAA;EAfJ;EAoBA,cAAA,CAAA,GAAkB,cAAA;EApBT;EAyBH,OAAA,CAAQ,IAAA,UAAc,IAAA,EAAM,MAAA,oBAA0B,OAAA;EApBjD;EAmCX,QAAA,CAAA;EA9BI;EAAA,IAmCA,IAAA,CAAA;AAAA"}
|
|
@@ -22,7 +22,7 @@ var ToolRegistry = class {
|
|
|
22
22
|
}
|
|
23
23
|
/** Get tool definitions for the LLM. */
|
|
24
24
|
getDefinitions() {
|
|
25
|
-
return
|
|
25
|
+
return [...this.tools.values()].map((t) => t.getDefinition());
|
|
26
26
|
}
|
|
27
27
|
/** Execute a tool by name with arguments. */
|
|
28
28
|
async execute(name, args) {
|
|
@@ -30,15 +30,15 @@ var ToolRegistry = class {
|
|
|
30
30
|
if (!tool) return `Error: Unknown tool '${name}'`;
|
|
31
31
|
try {
|
|
32
32
|
return await tool.execute(args);
|
|
33
|
-
} catch (
|
|
34
|
-
const message =
|
|
33
|
+
} catch (error) {
|
|
34
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
35
35
|
console.error(`Error executing ${name}: ${message}`);
|
|
36
36
|
return `Error executing ${name}: ${message}`;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
/** Get all registered tool names. */
|
|
40
40
|
getNames() {
|
|
41
|
-
return
|
|
41
|
+
return [...this.tools.keys()];
|
|
42
42
|
}
|
|
43
43
|
/** Get count of registered tools. */
|
|
44
44
|
get size() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.mjs","names":[],"sources":["../../../src/agent/tools/registry.ts"],"sourcesContent":["import type { ToolDefinition } from \"../../providers/base.js\";\nimport type { Tool } from \"./base.js\";\n\n/**\n * Dynamic tool registration and execution.\n */\nexport class ToolRegistry {\n private tools = new Map<string, Tool>();\n\n /** Register a tool. */\n register(tool: Tool): void {\n this.tools.set(tool.name, tool);\n }\n\n /** Unregister a tool by name. */\n unregister(name: string): boolean {\n return this.tools.delete(name);\n }\n\n /** Get a tool by name. */\n get(name: string): Tool | undefined {\n return this.tools.get(name);\n }\n\n /** Check if a tool exists. */\n has(name: string): boolean {\n return this.tools.has(name);\n }\n\n /** Get tool definitions for the LLM. */\n getDefinitions(): ToolDefinition[] {\n return
|
|
1
|
+
{"version":3,"file":"registry.mjs","names":[],"sources":["../../../src/agent/tools/registry.ts"],"sourcesContent":["import type { ToolDefinition } from \"../../providers/base.js\";\nimport type { Tool } from \"./base.js\";\n\n/**\n * Dynamic tool registration and execution.\n */\nexport class ToolRegistry {\n private tools = new Map<string, Tool>();\n\n /** Register a tool. */\n register(tool: Tool): void {\n this.tools.set(tool.name, tool);\n }\n\n /** Unregister a tool by name. */\n unregister(name: string): boolean {\n return this.tools.delete(name);\n }\n\n /** Get a tool by name. */\n get(name: string): Tool | undefined {\n return this.tools.get(name);\n }\n\n /** Check if a tool exists. */\n has(name: string): boolean {\n return this.tools.has(name);\n }\n\n /** Get tool definitions for the LLM. */\n getDefinitions(): ToolDefinition[] {\n return [...this.tools.values()].map((t) => t.getDefinition());\n }\n\n /** Execute a tool by name with arguments. */\n async execute(name: string, args: Record<string, unknown>): Promise<string> {\n const tool = this.tools.get(name);\n if (!tool) {\n return `Error: Unknown tool '${name}'`;\n }\n try {\n return await tool.execute(args);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`Error executing ${name}: ${message}`);\n return `Error executing ${name}: ${message}`;\n }\n }\n\n /** Get all registered tool names. */\n getNames(): string[] {\n return [...this.tools.keys()];\n }\n\n /** Get count of registered tools. */\n get size(): number {\n return this.tools.size;\n }\n}\n"],"mappings":";;;;AAMA,IAAa,eAAb,MAA0B;CACxB,AAAQ,wBAAQ,IAAI,KAAmB;;CAGvC,SAAS,MAAkB;AACzB,OAAK,MAAM,IAAI,KAAK,MAAM,KAAK;;;CAIjC,WAAW,MAAuB;AAChC,SAAO,KAAK,MAAM,OAAO,KAAK;;;CAIhC,IAAI,MAAgC;AAClC,SAAO,KAAK,MAAM,IAAI,KAAK;;;CAI7B,IAAI,MAAuB;AACzB,SAAO,KAAK,MAAM,IAAI,KAAK;;;CAI7B,iBAAmC;AACjC,SAAO,CAAC,GAAG,KAAK,MAAM,QAAQ,CAAC,CAAC,KAAK,MAAM,EAAE,eAAe,CAAC;;;CAI/D,MAAM,QAAQ,MAAc,MAAgD;EAC1E,MAAM,OAAO,KAAK,MAAM,IAAI,KAAK;AACjC,MAAI,CAAC,KACH,QAAO,wBAAwB,KAAK;AAEtC,MAAI;AACF,UAAO,MAAM,KAAK,QAAQ,KAAK;WACxB,OAAO;GACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,WAAQ,MAAM,mBAAmB,KAAK,IAAI,UAAU;AACpD,UAAO,mBAAmB,KAAK,IAAI;;;;CAKvC,WAAqB;AACnB,SAAO,CAAC,GAAG,KAAK,MAAM,MAAM,CAAC;;;CAI/B,IAAI,OAAe;AACjB,SAAO,KAAK,MAAM"}
|
|
@@ -5,7 +5,6 @@ declare class ExecTool extends Tool {
|
|
|
5
5
|
readonly name = "exec";
|
|
6
6
|
readonly description = "Execute a shell command and return its output. Use for running programs, scripts, git, etc.";
|
|
7
7
|
readonly parameters: {
|
|
8
|
-
type: string;
|
|
9
8
|
properties: {
|
|
10
9
|
command: {
|
|
11
10
|
type: string;
|
|
@@ -17,6 +16,7 @@ declare class ExecTool extends Tool {
|
|
|
17
16
|
};
|
|
18
17
|
};
|
|
19
18
|
required: string[];
|
|
19
|
+
type: string;
|
|
20
20
|
};
|
|
21
21
|
private workingDir;
|
|
22
22
|
private defaultTimeout;
|
|
@@ -30,7 +30,7 @@ const SENSITIVE_ENV_PATTERNS = [
|
|
|
30
30
|
* Only the first word (binary name) of the command is matched.
|
|
31
31
|
* These commands still do NOT get the core LLM/channel secrets.
|
|
32
32
|
*/
|
|
33
|
-
const TRUSTED_COMMANDS = ["summarize"];
|
|
33
|
+
const TRUSTED_COMMANDS = new Set(["summarize"]);
|
|
34
34
|
/** Env vars injected for trusted commands only. */
|
|
35
35
|
const SKILL_ENV_KEYS = [
|
|
36
36
|
"LLM_API_KEY",
|
|
@@ -59,13 +59,12 @@ function buildSkillEnv() {
|
|
|
59
59
|
/** Check if a command starts with a trusted binary. */
|
|
60
60
|
function isTrustedCommand(command) {
|
|
61
61
|
const firstWord = command.replace(/^\s*(timeout\s+\d+\s+|env\s+\S+=\S+\s+)*/, "").trim().split(/\s+/)[0];
|
|
62
|
-
return TRUSTED_COMMANDS.
|
|
62
|
+
return TRUSTED_COMMANDS.has(firstWord);
|
|
63
63
|
}
|
|
64
64
|
var ExecTool = class extends Tool {
|
|
65
65
|
name = "exec";
|
|
66
66
|
description = "Execute a shell command and return its output. Use for running programs, scripts, git, etc.";
|
|
67
67
|
parameters = {
|
|
68
|
-
type: "object",
|
|
69
68
|
properties: {
|
|
70
69
|
command: {
|
|
71
70
|
type: "string",
|
|
@@ -76,7 +75,8 @@ var ExecTool = class extends Tool {
|
|
|
76
75
|
description: "Timeout in seconds (default: 60)"
|
|
77
76
|
}
|
|
78
77
|
},
|
|
79
|
-
required: ["command"]
|
|
78
|
+
required: ["command"],
|
|
79
|
+
type: "object"
|
|
80
80
|
};
|
|
81
81
|
workingDir;
|
|
82
82
|
defaultTimeout;
|