@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
package/README.md
CHANGED
|
@@ -46,17 +46,17 @@ skills/ Bundled skill definitions (cron, github, summarize, weather, s
|
|
|
46
46
|
|
|
47
47
|
## CLI Commands
|
|
48
48
|
|
|
49
|
-
| Command
|
|
50
|
-
|
|
51
|
-
| `nanobot onboard`
|
|
52
|
-
| `nanobot gateway`
|
|
53
|
-
| `nanobot agent -m "..."`
|
|
54
|
-
| `nanobot agent`
|
|
55
|
-
| `nanobot channels status`
|
|
56
|
-
| `nanobot cron list`
|
|
57
|
-
| `nanobot cron add`
|
|
58
|
-
| `nanobot cron remove <id>` | Remove a scheduled job
|
|
59
|
-
| `nanobot status`
|
|
49
|
+
| Command | Description |
|
|
50
|
+
| -------------------------- | ------------------------------------------------------------ |
|
|
51
|
+
| `nanobot onboard` | Initialize config and workspace |
|
|
52
|
+
| `nanobot gateway` | Start the full gateway (agent + channels + cron + heartbeat) |
|
|
53
|
+
| `nanobot agent -m "..."` | Send a single message to the agent |
|
|
54
|
+
| `nanobot agent` | Interactive chat mode |
|
|
55
|
+
| `nanobot channels status` | Show channel configuration |
|
|
56
|
+
| `nanobot cron list` | List scheduled jobs |
|
|
57
|
+
| `nanobot cron add` | Add a scheduled job |
|
|
58
|
+
| `nanobot cron remove <id>` | Remove a scheduled job |
|
|
59
|
+
| `nanobot status` | Show config and API key status |
|
|
60
60
|
|
|
61
61
|
## Scripts
|
|
62
62
|
|
|
@@ -69,13 +69,13 @@ npm run start # Run built CLI
|
|
|
69
69
|
|
|
70
70
|
## Dependencies
|
|
71
71
|
|
|
72
|
-
| Package
|
|
73
|
-
|
|
74
|
-
| `openai`
|
|
75
|
-
| `zod`
|
|
76
|
-
| `commander`
|
|
77
|
-
| `grammy`
|
|
78
|
-
| `cron-parser` | Cron expression parsing
|
|
72
|
+
| Package | Purpose |
|
|
73
|
+
| ------------- | ------------------------------------ |
|
|
74
|
+
| `openai` | LLM provider (OpenAI-compatible API) |
|
|
75
|
+
| `zod` | Config schema validation |
|
|
76
|
+
| `commander` | CLI framework |
|
|
77
|
+
| `grammy` | Telegram bot (grammY) |
|
|
78
|
+
| `cron-parser` | Cron expression parsing |
|
|
79
79
|
|
|
80
80
|
## Configuration
|
|
81
81
|
|
package/dist/agent/context.d.mts
CHANGED
|
@@ -3,12 +3,12 @@ import { MemoryStore } from "./memory.mjs";
|
|
|
3
3
|
import { SkillsLoader } from "./skills.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/agent/context.d.ts
|
|
6
|
-
|
|
6
|
+
interface AgentIdentity {
|
|
7
7
|
name?: string;
|
|
8
8
|
emoji?: string;
|
|
9
9
|
creature?: string;
|
|
10
10
|
vibe?: string;
|
|
11
|
-
}
|
|
11
|
+
}
|
|
12
12
|
/**
|
|
13
13
|
* Builds the context (system prompt + messages) for the agent.
|
|
14
14
|
*/
|
|
@@ -33,14 +33,14 @@ declare class ContextBuilder {
|
|
|
33
33
|
/** Add a tool result to the message list. */
|
|
34
34
|
addToolResult(messages: ChatMessage[], toolCallId: string, toolName: string, result: string): ChatMessage[];
|
|
35
35
|
/** Add an assistant message to the message list. */
|
|
36
|
-
addAssistantMessage(messages: ChatMessage[], content: string | null, toolCalls?:
|
|
36
|
+
addAssistantMessage(messages: ChatMessage[], content: string | null, toolCalls?: {
|
|
37
37
|
id: string;
|
|
38
38
|
type: "function";
|
|
39
39
|
function: {
|
|
40
40
|
name: string;
|
|
41
41
|
arguments: string;
|
|
42
42
|
};
|
|
43
|
-
}
|
|
43
|
+
}[]): ChatMessage[];
|
|
44
44
|
}
|
|
45
45
|
//#endregion
|
|
46
46
|
export { AgentIdentity, ContextBuilder };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.mts","names":[],"sources":["../../src/agent/context.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"context.d.mts","names":[],"sources":["../../src/agent/context.ts"],"mappings":";;;;;UA4CiB,aAAA;EACf,IAAA;EACA,KAAA;EACA,QAAA;EACA,IAAA;AAAA;;;;cAkFW,cAAA;EAAA,QACH,SAAA;EAAA,SACC,MAAA,EAAQ,WAAA;EAAA,SACR,MAAA,EAAQ,YAAA;cAEL,SAAA;;EAOZ,iBAAA,CAAA;EAAA,QA0CQ,WAAA;EAAA,QAmFA,kBAAA;EAmBJ;EANJ,aAAA,CAAc,MAAA;IACZ,OAAA,EAAS,WAAA;IACT,cAAA;IACA,KAAA;IACA,OAAA;IACA,MAAA;EAAA,IACE,WAAA;EAAA,QAyBI,gBAAA;EAnLS;EAgOjB,aAAA,CACE,QAAA,EAAU,WAAA,IACV,UAAA,UACA,QAAA,UACA,MAAA,WACC,WAAA;EApOc;EA+OjB,mBAAA,CACE,QAAA,EAAU,WAAA,IACV,OAAA,iBACA,SAAA;IACE,EAAA;IACA,IAAA;IACA,QAAA;MAAY,IAAA;MAAc,SAAA;IAAA;EAAA,MAE3B,WAAA;AAAA"}
|
package/dist/agent/context.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import { join } from "node:path";
|
|
|
12
12
|
function resolveTimezone(workspace) {
|
|
13
13
|
const userMd = join(workspace, "USER.md");
|
|
14
14
|
if (existsSync(userMd)) try {
|
|
15
|
-
const tzMatch = readFileSync(userMd, "
|
|
15
|
+
const tzMatch = readFileSync(userMd, "utf8").match(/^timezone:\s*(.+)/im);
|
|
16
16
|
if (tzMatch) {
|
|
17
17
|
const tz = tzMatch[1].trim();
|
|
18
18
|
if (tz && !tz.includes("not set")) {
|
|
@@ -39,15 +39,15 @@ function resolveIdentity(workspace) {
|
|
|
39
39
|
const identityMd = join(workspace, "IDENTITY.md");
|
|
40
40
|
if (!existsSync(identityMd)) return identity;
|
|
41
41
|
try {
|
|
42
|
-
const lines = readFileSync(identityMd, "
|
|
42
|
+
const lines = readFileSync(identityMd, "utf8").split(/\r?\n/);
|
|
43
43
|
for (const line of lines) {
|
|
44
44
|
const cleaned = line.trim().replace(/^\s*-\s*/, "");
|
|
45
45
|
const colonIndex = cleaned.indexOf(":");
|
|
46
46
|
if (colonIndex === -1) continue;
|
|
47
|
-
const label = cleaned.slice(0, colonIndex).
|
|
48
|
-
const value = cleaned.slice(colonIndex + 1).
|
|
47
|
+
const label = cleaned.slice(0, colonIndex).replaceAll(/[*_]/g, "").trim().toLowerCase();
|
|
48
|
+
const value = cleaned.slice(colonIndex + 1).replaceAll(/^[*_]+|[*_]+$/g, "").trim();
|
|
49
49
|
if (!value) continue;
|
|
50
|
-
const normalized = value.toLowerCase().
|
|
50
|
+
const normalized = value.toLowerCase().replaceAll(/[\u2013\u2014]/g, "-").replaceAll(/\s+/g, " ");
|
|
51
51
|
if (IDENTITY_PLACEHOLDERS.has(normalized)) continue;
|
|
52
52
|
if (/^\(.*\)$/.test(value) || /^_.*_$/.test(value)) continue;
|
|
53
53
|
if (label === "name") identity.name = value;
|
|
@@ -79,8 +79,7 @@ var ContextBuilder = class {
|
|
|
79
79
|
}
|
|
80
80
|
/** Build the system prompt from bootstrap files, memory, and skills. */
|
|
81
81
|
buildSystemPrompt() {
|
|
82
|
-
const parts = [];
|
|
83
|
-
parts.push(this.getIdentity());
|
|
82
|
+
const parts = [this.getIdentity()];
|
|
84
83
|
const bootstrap = this.loadBootstrapFiles();
|
|
85
84
|
if (bootstrap) parts.push(bootstrap);
|
|
86
85
|
const memory = this.memory.getMemoryContext();
|
|
@@ -100,14 +99,14 @@ var ContextBuilder = class {
|
|
|
100
99
|
const tz = resolveTimezone(this.workspace);
|
|
101
100
|
const identity = resolveIdentity(this.workspace);
|
|
102
101
|
const dateStr = now.toLocaleString("en-US", {
|
|
103
|
-
timeZone: tz,
|
|
104
|
-
year: "numeric",
|
|
105
|
-
month: "2-digit",
|
|
106
102
|
day: "2-digit",
|
|
107
103
|
hour: "2-digit",
|
|
104
|
+
hour12: false,
|
|
108
105
|
minute: "2-digit",
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
month: "2-digit",
|
|
107
|
+
timeZone: tz,
|
|
108
|
+
year: "numeric"
|
|
109
|
+
}).replaceAll("/", "-");
|
|
111
110
|
const dayName = now.toLocaleDateString("en-US", {
|
|
112
111
|
timeZone: tz,
|
|
113
112
|
weekday: "long"
|
|
@@ -174,7 +173,7 @@ To recall past events, grep ${this.workspace}/memory/HISTORY.md`;
|
|
|
174
173
|
for (const filename of BOOTSTRAP_FILES) {
|
|
175
174
|
const filePath = join(this.workspace, filename);
|
|
176
175
|
if (existsSync(filePath)) {
|
|
177
|
-
const content = readFileSync(filePath, "
|
|
176
|
+
const content = readFileSync(filePath, "utf8");
|
|
178
177
|
parts.push(`## ${filename}\n\n${content}`);
|
|
179
178
|
}
|
|
180
179
|
}
|
|
@@ -186,14 +185,14 @@ To recall past events, grep ${this.workspace}/memory/HISTORY.md`;
|
|
|
186
185
|
let systemPrompt = this.buildSystemPrompt();
|
|
187
186
|
if (params.channel && params.chatId) systemPrompt += `\n\n## Current Session\nChannel: ${params.channel}\nChat ID: ${params.chatId}`;
|
|
188
187
|
messages.push({
|
|
189
|
-
|
|
190
|
-
|
|
188
|
+
content: systemPrompt,
|
|
189
|
+
role: "system"
|
|
191
190
|
});
|
|
192
191
|
for (const msg of params.history) messages.push(msg);
|
|
193
192
|
const userContent = this.buildUserContent(params.currentMessage, params.media);
|
|
194
193
|
messages.push({
|
|
195
|
-
|
|
196
|
-
|
|
194
|
+
content: userContent,
|
|
195
|
+
role: "user"
|
|
197
196
|
});
|
|
198
197
|
return messages;
|
|
199
198
|
}
|
|
@@ -205,41 +204,41 @@ To recall past events, grep ${this.workspace}/memory/HISTORY.md`;
|
|
|
205
204
|
try {
|
|
206
205
|
const data = readFileSync(filePath);
|
|
207
206
|
const mime = {
|
|
208
|
-
|
|
207
|
+
gif: "image/gif",
|
|
209
208
|
jpeg: "image/jpeg",
|
|
209
|
+
jpg: "image/jpeg",
|
|
210
210
|
png: "image/png",
|
|
211
|
-
gif: "image/gif",
|
|
212
211
|
webp: "image/webp"
|
|
213
212
|
}[filePath.split(".").pop()?.toLowerCase() ?? ""];
|
|
214
213
|
if (!mime) continue;
|
|
215
214
|
const b64 = data.toString("base64");
|
|
216
215
|
images.push({
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
image_url: { url: `data:${mime};base64,${b64}` },
|
|
217
|
+
type: "image_url"
|
|
219
218
|
});
|
|
220
219
|
} catch {}
|
|
221
220
|
}
|
|
222
221
|
if (images.length === 0) return text;
|
|
223
222
|
return [...images, {
|
|
224
|
-
|
|
225
|
-
text
|
|
223
|
+
text,
|
|
224
|
+
type: "text"
|
|
226
225
|
}];
|
|
227
226
|
}
|
|
228
227
|
/** Add a tool result to the message list. */
|
|
229
228
|
addToolResult(messages, toolCallId, toolName, result) {
|
|
230
229
|
messages.push({
|
|
231
|
-
|
|
232
|
-
tool_call_id: toolCallId,
|
|
230
|
+
content: result,
|
|
233
231
|
name: toolName,
|
|
234
|
-
|
|
232
|
+
role: "tool",
|
|
233
|
+
tool_call_id: toolCallId
|
|
235
234
|
});
|
|
236
235
|
return messages;
|
|
237
236
|
}
|
|
238
237
|
/** Add an assistant message to the message list. */
|
|
239
238
|
addAssistantMessage(messages, content, toolCalls) {
|
|
240
239
|
const msg = {
|
|
241
|
-
|
|
242
|
-
|
|
240
|
+
content: content ?? "",
|
|
241
|
+
role: "assistant"
|
|
243
242
|
};
|
|
244
243
|
if (toolCalls) msg.tool_calls = toolCalls;
|
|
245
244
|
messages.push(msg);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.mjs","names":[],"sources":["../../src/agent/context.ts"],"sourcesContent":["import { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ChatMessage, ContentPart } from \"../providers/base.js\";\nimport { MemoryStore } from \"./memory.js\";\nimport { SkillsLoader } from \"./skills.js\";\n\n/**\n * Resolve user timezone from USER.md.\n * Looks for a line like: Timezone: Asia/Tokyo\n * Falls back to host detection / UTC.\n */\nfunction resolveTimezone(workspace: string): string {\n const userMd = join(workspace, \"USER.md\");\n if (existsSync(userMd)) {\n try {\n const content = readFileSync(userMd, \"utf-8\");\n const tzMatch = content.match(/^timezone:\\s*(.+)/im);\n if (tzMatch) {\n const tz = tzMatch[1].trim();\n if (tz && !tz.includes(\"not set\")) {\n // Validate IANA timezone\n new Intl.DateTimeFormat(\"en-US\", { timeZone: tz }).format(new Date());\n return tz;\n }\n }\n } catch {\n // Invalid value or read error, fall through\n }\n }\n\n const host = Intl.DateTimeFormat().resolvedOptions().timeZone;\n return host?.trim() || \"UTC\";\n}\n\n/** Placeholder values in IDENTITY.md that mean \"not yet filled in\". */\nconst IDENTITY_PLACEHOLDERS = new Set([\n \"(not set)\",\n \"(pick something you like)\",\n \"(your signature)\",\n \"(how do you come across?)\",\n]);\n\nexport type AgentIdentity = {\n name?: string;\n emoji?: string;\n creature?: string;\n vibe?: string;\n};\n\n/**\n * Parse IDENTITY.md from the workspace to resolve the agent's chosen identity.\n * Returns fields that have been filled in (skips placeholders).\n */\nfunction resolveIdentity(workspace: string): AgentIdentity {\n const identity: AgentIdentity = {};\n const identityMd = join(workspace, \"IDENTITY.md\");\n if (!existsSync(identityMd)) return identity;\n\n try {\n const content = readFileSync(identityMd, \"utf-8\");\n const lines = content.split(/\\r?\\n/);\n for (const line of lines) {\n // Strip list markers and bold markers\n const cleaned = line.trim().replace(/^\\s*-\\s*/, \"\");\n const colonIndex = cleaned.indexOf(\":\");\n if (colonIndex === -1) continue;\n\n const label = cleaned.slice(0, colonIndex).replace(/[*_]/g, \"\").trim().toLowerCase();\n const value = cleaned.slice(colonIndex + 1).replace(/^[*_]+|[*_]+$/g, \"\").trim();\n if (!value) continue;\n\n // Check if it's a placeholder\n const normalized = value.toLowerCase().replace(/[\\u2013\\u2014]/g, \"-\").replace(/\\s+/g, \" \");\n if (IDENTITY_PLACEHOLDERS.has(normalized)) continue;\n // Also check if it looks like a template hint wrapped in parens or italics\n if (/^\\(.*\\)$/.test(value) || /^_.*_$/.test(value)) continue;\n\n if (label === \"name\") identity.name = value;\n if (label === \"emoji\") identity.emoji = value;\n if (label === \"creature\") identity.creature = value;\n if (label === \"vibe\") identity.vibe = value;\n }\n } catch {\n // Read error, return empty\n }\n\n return identity;\n}\n\nconst BOOTSTRAP_FILES = [\n \"AGENTS.md\",\n \"SOUL.md\",\n \"USER.md\",\n \"TOOLS.md\",\n \"IDENTITY.md\",\n];\n\n/**\n * Builds the context (system prompt + messages) for the agent.\n */\nexport class ContextBuilder {\n private workspace: string;\n readonly memory: MemoryStore;\n readonly skills: SkillsLoader;\n\n constructor(workspace: string) {\n this.workspace = workspace;\n this.memory = new MemoryStore(workspace);\n this.skills = new SkillsLoader(workspace);\n }\n\n /** Build the system prompt from bootstrap files, memory, and skills. */\n buildSystemPrompt(): string {\n const parts: string[] = [];\n\n // Core identity\n parts.push(this.getIdentity());\n\n // Bootstrap files\n const bootstrap = this.loadBootstrapFiles();\n if (bootstrap) parts.push(bootstrap);\n\n // Memory context\n const memory = this.memory.getMemoryContext();\n if (memory) parts.push(`# Memory\\n\\n${memory}`);\n\n // Always-loaded skills\n const alwaysSkills = this.skills.getAlwaysSkills();\n if (alwaysSkills.length > 0) {\n console.log(`Skills always-loaded: ${alwaysSkills.join(\", \")}`);\n const alwaysContent = this.skills.loadSkillsForContext(alwaysSkills);\n if (alwaysContent) {\n parts.push(`# Active Skills\\n\\n${alwaysContent}`);\n }\n }\n\n // Available skills summary\n const skillsSummary = this.skills.buildSkillsSummary();\n if (skillsSummary) {\n parts.push(\n `# Skills (mandatory)\\n\\n` +\n `Before replying, scan the <skills> entries below.\\n` +\n `- If a skill clearly applies to the user's request: read its SKILL.md at the <location> path using read_file, then follow its instructions.\\n` +\n `- If multiple skills could apply: choose the most specific one, then read and follow it.\\n` +\n `- If no skill applies: respond normally without reading any SKILL.md.\\n` +\n `- Never improvise when a matching skill exists. Always read and follow the skill first.\\n\\n` +\n skillsSummary,\n );\n }\n\n return parts.join(\"\\n\\n---\\n\\n\");\n }\n\n private getIdentity(): string {\n const now = new Date();\n const tz = resolveTimezone(this.workspace);\n const identity = resolveIdentity(this.workspace);\n const dateStr = now.toLocaleString(\"en-US\", { timeZone: tz, year: \"numeric\", month: \"2-digit\", day: \"2-digit\", hour: \"2-digit\", minute: \"2-digit\", hour12: false }).replace(/\\//g, \"-\");\n const dayName = now.toLocaleDateString(\"en-US\", { timeZone: tz, weekday: \"long\" });\n\n // Use identity name if set, otherwise generic\n const agentName = identity.name || \"kodama\";\n const identityLine = identity.name\n ? `You are ${agentName}, a personal AI assistant.`\n : \"You are a personal AI assistant running inside kodamabot.\";\n\n return `# ${agentName}\n\n${identityLine} You have access to tools that allow you to:\n- Read, write, and edit files\n- Execute shell commands\n- Search the web and fetch web pages\n- Send messages to users on chat channels\n- Spawn subagents for complex background tasks\n\n## Current Time\n${dateStr} (${dayName})\nTimezone: ${tz}${tz === \"UTC\" ? \"\\nNote: Timezone is not yet configured. Do NOT assume the user's local time or make time-of-day references (morning, night, etc.). Ask the user where they are so you can set their timezone.\" : \"\"}\n\n## Workspace\nYour workspace is at: ${this.workspace}\n- Identity: ${this.workspace}/IDENTITY.md\n- User info: ${this.workspace}/USER.md\n- Persona: ${this.workspace}/SOUL.md\n- Instructions: ${this.workspace}/AGENTS.md\n- Heartbeat: ${this.workspace}/HEARTBEAT.md\n- Long-term memory: ${this.workspace}/memory/MEMORY.md\n- History log: ${this.workspace}/memory/HISTORY.md (grep-searchable)\n- Custom skills: ${this.workspace}/skills/{skill-name}/SKILL.md\n\nIMPORTANT: When responding to direct questions or conversations, reply directly with your text response.\nOnly use the 'message' tool when you need to send a message to a specific chat channel.\nFor normal conversation, just respond with text - do not call the message tool.\n\nIMPORTANT: When you decide to use tools, ALWAYS include a brief text message alongside your tool calls.\nThis text is sent to the user immediately so they know you're working. Keep it natural and conversational.\nNever mention internal file names (IDENTITY.md, USER.md, SOUL.md, MEMORY.md, etc.) to the user. These are implementation details. Just act naturally — save things silently, don't narrate file operations.\n\n## Installing Skills\nWhen asked to install a skill (from a URL, file, or any source):\n1. Fetch/read the skill content\n2. ALWAYS install it to: ${this.workspace}/skills/{skill-name}/SKILL.md\n3. If the skill references a different workspace path (e.g. .moltbot/, .otherbot/, etc.), rewrite ALL paths to use ${this.workspace}/ instead\n4. Preserve the skill's frontmatter, instructions, scripts, references, and assets — only change the workspace paths\n\n## Identity & Onboarding\nIf IDENTITY.md has no Name set, and USER.md contains \"(not set)\" values, this is a new user.\nOn their FIRST message, greet them warmly and ask:\n1. What they'd like to call you (your name — you're becoming someone, not just a chatbot)\n2. What they'd like to be called\n3. Where they're located (to determine timezone, e.g. Asia/Tokyo, America/New_York)\n\nThen update IDENTITY.md and USER.md with the real values using the edit_file tool. Use IANA timezone format.\nOnly do this ONCE — if both files already have real values, skip onboarding.\n\n## Persona\nIf SOUL.md is present, embody its persona and tone. Avoid stiff, generic replies; follow its guidance unless higher-priority instructions override it.\n\nAlways be helpful, accurate, and concise. When using tools, explain what you're doing.\nWhen remembering something important, write to ${this.workspace}/memory/MEMORY.md\nTo recall past events, grep ${this.workspace}/memory/HISTORY.md`;\n }\n\n private loadBootstrapFiles(): string {\n const parts: string[] = [];\n for (const filename of BOOTSTRAP_FILES) {\n const filePath = join(this.workspace, filename);\n if (existsSync(filePath)) {\n const content = readFileSync(filePath, \"utf-8\");\n parts.push(`## ${filename}\\n\\n${content}`);\n }\n }\n return parts.join(\"\\n\\n\");\n }\n\n /** Build the complete message list for an LLM call. */\n buildMessages(params: {\n history: ChatMessage[];\n currentMessage: string;\n media?: string[];\n channel?: string;\n chatId?: string;\n }): ChatMessage[] {\n const messages: ChatMessage[] = [];\n\n // System prompt\n let systemPrompt = this.buildSystemPrompt();\n if (params.channel && params.chatId) {\n systemPrompt += `\\n\\n## Current Session\\nChannel: ${params.channel}\\nChat ID: ${params.chatId}`;\n }\n messages.push({ role: \"system\", content: systemPrompt });\n\n // History — replay full rich messages (user, assistant w/ tool_calls, tool results, etc.)\n for (const msg of params.history) {\n messages.push(msg);\n }\n\n // Current message (with optional image attachments)\n const userContent = this.buildUserContent(\n params.currentMessage,\n params.media,\n );\n messages.push({ role: \"user\", content: userContent });\n\n return messages;\n }\n\n private buildUserContent(\n text: string,\n media?: string[],\n ): string | ContentPart[] {\n if (!media || media.length === 0) return text;\n\n const images: ContentPart[] = [];\n for (const filePath of media) {\n if (!existsSync(filePath)) continue;\n try {\n const data = readFileSync(filePath);\n const ext = filePath.split(\".\").pop()?.toLowerCase() ?? \"\";\n const mimeMap: Record<string, string> = {\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n png: \"image/png\",\n gif: \"image/gif\",\n webp: \"image/webp\",\n };\n const mime = mimeMap[ext];\n if (!mime) continue;\n\n const b64 = data.toString(\"base64\");\n images.push({\n type: \"image_url\",\n image_url: { url: `data:${mime};base64,${b64}` },\n });\n } catch {\n // skip unreadable files\n }\n }\n\n if (images.length === 0) return text;\n return [...images, { type: \"text\", text }];\n }\n\n /** Add a tool result to the message list. */\n addToolResult(\n messages: ChatMessage[],\n toolCallId: string,\n toolName: string,\n result: string,\n ): ChatMessage[] {\n messages.push({\n role: \"tool\",\n tool_call_id: toolCallId,\n name: toolName,\n content: result,\n });\n return messages;\n }\n\n /** Add an assistant message to the message list. */\n addAssistantMessage(\n messages: ChatMessage[],\n content: string | null,\n toolCalls?: Array<{\n id: string;\n type: \"function\";\n function: { name: string; arguments: string };\n }>,\n ): ChatMessage[] {\n const msg: ChatMessage = {\n role: \"assistant\",\n content: content ?? \"\",\n };\n if (toolCalls) {\n msg.tool_calls = toolCalls;\n }\n messages.push(msg);\n return messages;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"context.mjs","names":[],"sources":["../../src/agent/context.ts"],"sourcesContent":["import { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport type { ChatMessage, ContentPart } from \"../providers/base.js\";\n\nimport { MemoryStore } from \"./memory.js\";\nimport { SkillsLoader } from \"./skills.js\";\n\n/**\n * Resolve user timezone from USER.md.\n * Looks for a line like: Timezone: Asia/Tokyo\n * Falls back to host detection / UTC.\n */\nfunction resolveTimezone(workspace: string): string {\n const userMd = join(workspace, \"USER.md\");\n if (existsSync(userMd)) {\n try {\n const content = readFileSync(userMd, \"utf8\");\n const tzMatch = content.match(/^timezone:\\s*(.+)/im);\n if (tzMatch) {\n const tz = tzMatch[1].trim();\n if (tz && !tz.includes(\"not set\")) {\n // Validate IANA timezone\n new Intl.DateTimeFormat(\"en-US\", { timeZone: tz }).format(new Date());\n return tz;\n }\n }\n } catch {\n // Invalid value or read error, fall through\n }\n }\n\n const host = Intl.DateTimeFormat().resolvedOptions().timeZone;\n return host?.trim() || \"UTC\";\n}\n\n/** Placeholder values in IDENTITY.md that mean \"not yet filled in\". */\nconst IDENTITY_PLACEHOLDERS = new Set([\n \"(not set)\",\n \"(pick something you like)\",\n \"(your signature)\",\n \"(how do you come across?)\",\n]);\n\nexport interface AgentIdentity {\n name?: string;\n emoji?: string;\n creature?: string;\n vibe?: string;\n}\n\n/**\n * Parse IDENTITY.md from the workspace to resolve the agent's chosen identity.\n * Returns fields that have been filled in (skips placeholders).\n */\nfunction resolveIdentity(workspace: string): AgentIdentity {\n const identity: AgentIdentity = {};\n const identityMd = join(workspace, \"IDENTITY.md\");\n if (!existsSync(identityMd)) {\n return identity;\n }\n\n try {\n const content = readFileSync(identityMd, \"utf8\");\n const lines = content.split(/\\r?\\n/);\n for (const line of lines) {\n // Strip list markers and bold markers\n const cleaned = line.trim().replace(/^\\s*-\\s*/, \"\");\n const colonIndex = cleaned.indexOf(\":\");\n if (colonIndex === -1) {\n continue;\n }\n\n const label = cleaned\n .slice(0, colonIndex)\n .replaceAll(/[*_]/g, \"\")\n .trim()\n .toLowerCase();\n const value = cleaned\n .slice(colonIndex + 1)\n .replaceAll(/^[*_]+|[*_]+$/g, \"\")\n .trim();\n if (!value) {\n continue;\n }\n\n // Check if it's a placeholder\n const normalized = value\n .toLowerCase()\n .replaceAll(/[\\u2013\\u2014]/g, \"-\")\n .replaceAll(/\\s+/g, \" \");\n if (IDENTITY_PLACEHOLDERS.has(normalized)) {\n continue;\n }\n // Also check if it looks like a template hint wrapped in parens or italics\n if (/^\\(.*\\)$/.test(value) || /^_.*_$/.test(value)) {\n continue;\n }\n\n if (label === \"name\") {\n identity.name = value;\n }\n if (label === \"emoji\") {\n identity.emoji = value;\n }\n if (label === \"creature\") {\n identity.creature = value;\n }\n if (label === \"vibe\") {\n identity.vibe = value;\n }\n }\n } catch {\n // Read error, return empty\n }\n\n return identity;\n}\n\nconst BOOTSTRAP_FILES = [\n \"AGENTS.md\",\n \"SOUL.md\",\n \"USER.md\",\n \"TOOLS.md\",\n \"IDENTITY.md\",\n];\n\n/**\n * Builds the context (system prompt + messages) for the agent.\n */\nexport class ContextBuilder {\n private workspace: string;\n readonly memory: MemoryStore;\n readonly skills: SkillsLoader;\n\n constructor(workspace: string) {\n this.workspace = workspace;\n this.memory = new MemoryStore(workspace);\n this.skills = new SkillsLoader(workspace);\n }\n\n /** Build the system prompt from bootstrap files, memory, and skills. */\n buildSystemPrompt(): string {\n const parts: string[] = [this.getIdentity()];\n\n // Bootstrap files\n const bootstrap = this.loadBootstrapFiles();\n if (bootstrap) {\n parts.push(bootstrap);\n }\n\n // Memory context\n const memory = this.memory.getMemoryContext();\n if (memory) {\n parts.push(`# Memory\\n\\n${memory}`);\n }\n\n // Always-loaded skills\n const alwaysSkills = this.skills.getAlwaysSkills();\n if (alwaysSkills.length > 0) {\n console.log(`Skills always-loaded: ${alwaysSkills.join(\", \")}`);\n const alwaysContent = this.skills.loadSkillsForContext(alwaysSkills);\n if (alwaysContent) {\n parts.push(`# Active Skills\\n\\n${alwaysContent}`);\n }\n }\n\n // Available skills summary\n const skillsSummary = this.skills.buildSkillsSummary();\n if (skillsSummary) {\n parts.push(\n `# Skills (mandatory)\\n\\n` +\n `Before replying, scan the <skills> entries below.\\n` +\n `- If a skill clearly applies to the user's request: read its SKILL.md at the <location> path using read_file, then follow its instructions.\\n` +\n `- If multiple skills could apply: choose the most specific one, then read and follow it.\\n` +\n `- If no skill applies: respond normally without reading any SKILL.md.\\n` +\n `- Never improvise when a matching skill exists. Always read and follow the skill first.\\n\\n` +\n skillsSummary\n );\n }\n\n return parts.join(\"\\n\\n---\\n\\n\");\n }\n\n private getIdentity(): string {\n const now = new Date();\n const tz = resolveTimezone(this.workspace);\n const identity = resolveIdentity(this.workspace);\n const dateStr = now\n .toLocaleString(\"en-US\", {\n day: \"2-digit\",\n hour: \"2-digit\",\n hour12: false,\n minute: \"2-digit\",\n month: \"2-digit\",\n timeZone: tz,\n year: \"numeric\",\n })\n .replaceAll(\"/\", \"-\");\n const dayName = now.toLocaleDateString(\"en-US\", {\n timeZone: tz,\n weekday: \"long\",\n });\n\n // Use identity name if set, otherwise generic\n const agentName = identity.name || \"kodama\";\n const identityLine = identity.name\n ? `You are ${agentName}, a personal AI assistant.`\n : \"You are a personal AI assistant running inside kodamabot.\";\n\n return `# ${agentName}\n\n${identityLine} You have access to tools that allow you to:\n- Read, write, and edit files\n- Execute shell commands\n- Search the web and fetch web pages\n- Send messages to users on chat channels\n- Spawn subagents for complex background tasks\n\n## Current Time\n${dateStr} (${dayName})\nTimezone: ${tz}${tz === \"UTC\" ? \"\\nNote: Timezone is not yet configured. Do NOT assume the user's local time or make time-of-day references (morning, night, etc.). Ask the user where they are so you can set their timezone.\" : \"\"}\n\n## Workspace\nYour workspace is at: ${this.workspace}\n- Identity: ${this.workspace}/IDENTITY.md\n- User info: ${this.workspace}/USER.md\n- Persona: ${this.workspace}/SOUL.md\n- Instructions: ${this.workspace}/AGENTS.md\n- Heartbeat: ${this.workspace}/HEARTBEAT.md\n- Long-term memory: ${this.workspace}/memory/MEMORY.md\n- History log: ${this.workspace}/memory/HISTORY.md (grep-searchable)\n- Custom skills: ${this.workspace}/skills/{skill-name}/SKILL.md\n\nIMPORTANT: When responding to direct questions or conversations, reply directly with your text response.\nOnly use the 'message' tool when you need to send a message to a specific chat channel.\nFor normal conversation, just respond with text - do not call the message tool.\n\nIMPORTANT: When you decide to use tools, ALWAYS include a brief text message alongside your tool calls.\nThis text is sent to the user immediately so they know you're working. Keep it natural and conversational.\nNever mention internal file names (IDENTITY.md, USER.md, SOUL.md, MEMORY.md, etc.) to the user. These are implementation details. Just act naturally — save things silently, don't narrate file operations.\n\n## Installing Skills\nWhen asked to install a skill (from a URL, file, or any source):\n1. Fetch/read the skill content\n2. ALWAYS install it to: ${this.workspace}/skills/{skill-name}/SKILL.md\n3. If the skill references a different workspace path (e.g. .moltbot/, .otherbot/, etc.), rewrite ALL paths to use ${this.workspace}/ instead\n4. Preserve the skill's frontmatter, instructions, scripts, references, and assets — only change the workspace paths\n\n## Identity & Onboarding\nIf IDENTITY.md has no Name set, and USER.md contains \"(not set)\" values, this is a new user.\nOn their FIRST message, greet them warmly and ask:\n1. What they'd like to call you (your name — you're becoming someone, not just a chatbot)\n2. What they'd like to be called\n3. Where they're located (to determine timezone, e.g. Asia/Tokyo, America/New_York)\n\nThen update IDENTITY.md and USER.md with the real values using the edit_file tool. Use IANA timezone format.\nOnly do this ONCE — if both files already have real values, skip onboarding.\n\n## Persona\nIf SOUL.md is present, embody its persona and tone. Avoid stiff, generic replies; follow its guidance unless higher-priority instructions override it.\n\nAlways be helpful, accurate, and concise. When using tools, explain what you're doing.\nWhen remembering something important, write to ${this.workspace}/memory/MEMORY.md\nTo recall past events, grep ${this.workspace}/memory/HISTORY.md`;\n }\n\n private loadBootstrapFiles(): string {\n const parts: string[] = [];\n for (const filename of BOOTSTRAP_FILES) {\n const filePath = join(this.workspace, filename);\n if (existsSync(filePath)) {\n const content = readFileSync(filePath, \"utf8\");\n parts.push(`## ${filename}\\n\\n${content}`);\n }\n }\n return parts.join(\"\\n\\n\");\n }\n\n /** Build the complete message list for an LLM call. */\n buildMessages(params: {\n history: ChatMessage[];\n currentMessage: string;\n media?: string[];\n channel?: string;\n chatId?: string;\n }): ChatMessage[] {\n const messages: ChatMessage[] = [];\n\n // System prompt\n let systemPrompt = this.buildSystemPrompt();\n if (params.channel && params.chatId) {\n systemPrompt += `\\n\\n## Current Session\\nChannel: ${params.channel}\\nChat ID: ${params.chatId}`;\n }\n messages.push({ content: systemPrompt, role: \"system\" });\n\n // History — replay full rich messages (user, assistant w/ tool_calls, tool results, etc.)\n for (const msg of params.history) {\n messages.push(msg);\n }\n\n // Current message (with optional image attachments)\n const userContent = this.buildUserContent(\n params.currentMessage,\n params.media\n );\n messages.push({ content: userContent, role: \"user\" });\n\n return messages;\n }\n\n private buildUserContent(\n text: string,\n media?: string[]\n ): string | ContentPart[] {\n if (!media || media.length === 0) {\n return text;\n }\n\n const images: ContentPart[] = [];\n for (const filePath of media) {\n if (!existsSync(filePath)) {\n continue;\n }\n try {\n const data = readFileSync(filePath);\n const ext = filePath.split(\".\").pop()?.toLowerCase() ?? \"\";\n const mimeMap: Record<string, string> = {\n gif: \"image/gif\",\n jpeg: \"image/jpeg\",\n jpg: \"image/jpeg\",\n png: \"image/png\",\n webp: \"image/webp\",\n };\n const mime = mimeMap[ext];\n if (!mime) {\n continue;\n }\n\n const b64 = data.toString(\"base64\");\n images.push({\n image_url: { url: `data:${mime};base64,${b64}` },\n type: \"image_url\",\n });\n } catch {\n // skip unreadable files\n }\n }\n\n if (images.length === 0) {\n return text;\n }\n return [...images, { text, type: \"text\" }];\n }\n\n /** Add a tool result to the message list. */\n addToolResult(\n messages: ChatMessage[],\n toolCallId: string,\n toolName: string,\n result: string\n ): ChatMessage[] {\n messages.push({\n content: result,\n name: toolName,\n role: \"tool\",\n tool_call_id: toolCallId,\n });\n return messages;\n }\n\n /** Add an assistant message to the message list. */\n addAssistantMessage(\n messages: ChatMessage[],\n content: string | null,\n toolCalls?: {\n id: string;\n type: \"function\";\n function: { name: string; arguments: string };\n }[]\n ): ChatMessage[] {\n const msg: ChatMessage = {\n content: content ?? \"\",\n role: \"assistant\",\n };\n if (toolCalls) {\n msg.tool_calls = toolCalls;\n }\n messages.push(msg);\n return messages;\n }\n}\n"],"mappings":"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"}
|
package/dist/agent/loop.d.mts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { LLMProvider } from "../providers/base.mjs";
|
|
2
2
|
import { ContextBuilder } from "./context.mjs";
|
|
3
3
|
import { MessageBus } from "../bus/queue.mjs";
|
|
4
|
-
import { Tool } from "./tools/base.mjs";
|
|
5
|
-
import { ToolRegistry } from "./tools/registry.mjs";
|
|
6
4
|
import { ExecToolConfig } from "../config/schema.mjs";
|
|
7
|
-
import {
|
|
5
|
+
import { Tool } from "./tools/base.mjs";
|
|
8
6
|
import { SessionManager } from "../session/manager.mjs";
|
|
7
|
+
import { SubagentManager } from "./subagent.mjs";
|
|
8
|
+
import { ToolRegistry } from "./tools/registry.mjs";
|
|
9
9
|
|
|
10
10
|
//#region src/agent/loop.d.ts
|
|
11
11
|
/**
|
|
@@ -33,6 +33,8 @@ declare class AgentLoop {
|
|
|
33
33
|
private _running;
|
|
34
34
|
/** In-flight AbortControllers keyed by session key. */
|
|
35
35
|
private inflight;
|
|
36
|
+
/** Promises that resolve when an aborted processMessage finishes saving. */
|
|
37
|
+
private inflightDone;
|
|
36
38
|
constructor(params: {
|
|
37
39
|
bus: MessageBus;
|
|
38
40
|
provider: LLMProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loop.d.mts","names":[],"sources":["../../src/agent/loop.ts"],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"loop.d.mts","names":[],"sources":["../../src/agent/loop.ts"],"mappings":";;;;;;;;;;;;AAwCA;;;;;;;cAAa,SAAA;EAAA,QACH,GAAA;EAAA,QACA,QAAA;EAAA,QACA,SAAA;EAAA,QACA,KAAA;EAAA,QACA,kBAAA;EAAA,QACA,SAAA;EAAA,QACA,aAAA;EAAA,QACA,YAAA;EAAA,SAEC,OAAA,EAAS,cAAA;EAAA,SACT,QAAA,EAAU,cAAA;EAAA,SACV,KAAA,EAAO,YAAA;EAAA,SACP,SAAA,EAAW,eAAA;EAAA,QAEZ,QAAA;EARA;EAAA,QAWA,QAAA;EARC;EAAA,QAWD,YAAA;cAEI,MAAA;IACV,GAAA,EAAK,UAAA;IACL,QAAA,EAAU,WAAA;IACV,SAAA;IACA,KAAA;IACA,kBAAA;IACA,SAAA;IACA,aAAA;IACA,YAAA;IACA,WAAA;IACA,UAAA,GAAa,cAAA;IACb,mBAAA;IACA,YAAA;IACA,aAAA;IACA,WAAA,GAAc,IAAA;EAAA;EAAA,QAqCR,oBAAA;EA7CN;EAgHI,GAAA,CAAA,GAAO,OAAA;EA9GX;EAqJF,IAAA,CAAA;EAnJE;EAAA,QAyJY,cAAA;EAAA,QA6GA,oBAAA;EAAA,QA4CA,YAAA;EA/SZ;EAAA,QA8ZM,uBAAA;EAAA,QAgBA,kBAAA;EA3bI;EA6cN,aAAA,CACJ,OAAA,UACA,UAAA,WACA,OAAA,WACA,MAAA,YACC,OAAA;EA5VG;EAAA,QAoXQ,iBAAA;AAAA"}
|
package/dist/agent/loop.mjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { createOutboundMessage } from "../bus/events.mjs";
|
|
2
|
+
import { SessionManager } from "../session/manager.mjs";
|
|
2
3
|
import { MemoryStore } from "./memory.mjs";
|
|
3
4
|
import { getBuiltinSkillsDir } from "./skills.mjs";
|
|
4
5
|
import { ContextBuilder } from "./context.mjs";
|
|
5
|
-
import { ToolRegistry } from "./tools/registry.mjs";
|
|
6
6
|
import { EditFileTool, ListDirTool, ReadFileTool, WriteFileTool } from "./tools/filesystem.mjs";
|
|
7
|
+
import { ToolRegistry } from "./tools/registry.mjs";
|
|
7
8
|
import { ExecTool } from "./tools/shell.mjs";
|
|
8
9
|
import { WebFetchTool, WebSearchTool } from "./tools/web.mjs";
|
|
9
|
-
import {
|
|
10
|
-
import { SpawnTool } from "./tools/spawn.mjs";
|
|
10
|
+
import { SubagentManager } from "./subagent.mjs";
|
|
11
11
|
import { CronTool } from "./tools/cron.mjs";
|
|
12
12
|
import { FlexTool } from "./tools/flex.mjs";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { MessageTool } from "./tools/message.mjs";
|
|
14
|
+
import { SpawnTool } from "./tools/spawn.mjs";
|
|
15
15
|
|
|
16
16
|
//#region src/agent/loop.ts
|
|
17
17
|
/**
|
|
@@ -39,6 +39,8 @@ var AgentLoop = class {
|
|
|
39
39
|
_running = false;
|
|
40
40
|
/** In-flight AbortControllers keyed by session key. */
|
|
41
41
|
inflight = /* @__PURE__ */ new Map();
|
|
42
|
+
/** Promises that resolve when an aborted processMessage finishes saving. */
|
|
43
|
+
inflightDone = /* @__PURE__ */ new Map();
|
|
42
44
|
constructor(params) {
|
|
43
45
|
this.bus = params.bus;
|
|
44
46
|
this.provider = params.provider;
|
|
@@ -54,13 +56,13 @@ var AgentLoop = class {
|
|
|
54
56
|
this.sessions = new SessionManager(params.workspace);
|
|
55
57
|
this.tools = new ToolRegistry();
|
|
56
58
|
this.subagents = new SubagentManager({
|
|
57
|
-
provider: params.provider,
|
|
58
|
-
workspace: params.workspace,
|
|
59
|
-
bus: params.bus,
|
|
60
|
-
model: this.model,
|
|
61
59
|
braveApiKey: params.braveApiKey,
|
|
60
|
+
bus: params.bus,
|
|
62
61
|
execConfig,
|
|
63
|
-
|
|
62
|
+
model: this.model,
|
|
63
|
+
provider: params.provider,
|
|
64
|
+
restrictToWorkspace,
|
|
65
|
+
workspace: params.workspace
|
|
64
66
|
});
|
|
65
67
|
this.registerDefaultTools(execConfig, restrictToWorkspace, params.braveApiKey, params.toolsEnabled, params.toolsDisabled, params.customTools);
|
|
66
68
|
}
|
|
@@ -85,9 +87,9 @@ var AgentLoop = class {
|
|
|
85
87
|
readOnlyPaths
|
|
86
88
|
}));
|
|
87
89
|
registerIfEnabled(new ExecTool({
|
|
88
|
-
|
|
90
|
+
restrictToWorkspace,
|
|
89
91
|
timeout: execConfig.timeout,
|
|
90
|
-
|
|
92
|
+
workingDir: this.workspace
|
|
91
93
|
}));
|
|
92
94
|
registerIfEnabled(new WebSearchTool({ apiKey: braveApiKey }));
|
|
93
95
|
registerIfEnabled(new WebFetchTool());
|
|
@@ -103,17 +105,19 @@ var AgentLoop = class {
|
|
|
103
105
|
console.log("Agent loop started");
|
|
104
106
|
while (this._running) try {
|
|
105
107
|
const msg = await this.bus.consumeInboundTimeout(1e3);
|
|
106
|
-
|
|
108
|
+
const sessionKey = `${msg.channel}:${msg.chatId}`;
|
|
109
|
+
const done = this.processMessage(msg).then(async (response) => {
|
|
107
110
|
if (response) await this.bus.publishOutbound(response);
|
|
108
|
-
}).catch(async (
|
|
109
|
-
if (isAbortError(
|
|
110
|
-
console.error("Error processing message:",
|
|
111
|
+
}).catch(async (error) => {
|
|
112
|
+
if (isAbortError(error)) return;
|
|
113
|
+
console.error("Error processing message:", error);
|
|
111
114
|
await this.bus.publishOutbound(createOutboundMessage({
|
|
112
115
|
channel: msg.channel,
|
|
113
116
|
chatId: msg.chatId,
|
|
114
|
-
content: `Sorry, I encountered an error: ${
|
|
117
|
+
content: `Sorry, I encountered an error: ${error instanceof Error ? error.message : error}`
|
|
115
118
|
}));
|
|
116
119
|
});
|
|
120
|
+
this.inflightDone.set(sessionKey, done);
|
|
117
121
|
} catch {}
|
|
118
122
|
}
|
|
119
123
|
/** Stop the agent loop. */
|
|
@@ -131,17 +135,22 @@ var AgentLoop = class {
|
|
|
131
135
|
console.log(`Aborting in-flight request for ${sessionKey}`);
|
|
132
136
|
existing.abort();
|
|
133
137
|
}
|
|
138
|
+
const prev = this.inflightDone.get(sessionKey);
|
|
139
|
+
if (prev) {
|
|
140
|
+
await prev;
|
|
141
|
+
this.inflightDone.delete(sessionKey);
|
|
142
|
+
}
|
|
134
143
|
const controller = new AbortController();
|
|
135
144
|
this.inflight.set(sessionKey, controller);
|
|
136
145
|
const session = this.sessions.getOrCreate(sessionKey);
|
|
137
146
|
if (session.history.length > this.memoryWindow) await this.consolidateMemory(session);
|
|
138
147
|
this.updateToolContexts(msg.channel, msg.chatId);
|
|
139
148
|
const messages = this.context.buildMessages({
|
|
140
|
-
history: session.getHistory(),
|
|
141
|
-
currentMessage: msg.content,
|
|
142
|
-
media: msg.media.length > 0 ? msg.media : void 0,
|
|
143
149
|
channel: msg.channel,
|
|
144
|
-
chatId: msg.chatId
|
|
150
|
+
chatId: msg.chatId,
|
|
151
|
+
currentMessage: msg.content,
|
|
152
|
+
history: session.getHistory(),
|
|
153
|
+
media: msg.media.length > 0 ? msg.media : void 0
|
|
145
154
|
});
|
|
146
155
|
const newMsgStart = 1 + session.getHistory().length;
|
|
147
156
|
try {
|
|
@@ -159,8 +168,8 @@ var AgentLoop = class {
|
|
|
159
168
|
chatId: msg.chatId,
|
|
160
169
|
content: result.content
|
|
161
170
|
});
|
|
162
|
-
} catch (
|
|
163
|
-
if (isAbortError(
|
|
171
|
+
} catch (error) {
|
|
172
|
+
if (isAbortError(error)) {
|
|
164
173
|
const userMessages = messages.slice(newMsgStart).filter((m) => m.role === "user");
|
|
165
174
|
if (userMessages.length > 0) {
|
|
166
175
|
session.addTurnMessages(userMessages);
|
|
@@ -169,7 +178,7 @@ var AgentLoop = class {
|
|
|
169
178
|
console.log(`Request aborted for ${sessionKey}, user message saved to history`);
|
|
170
179
|
return null;
|
|
171
180
|
}
|
|
172
|
-
throw
|
|
181
|
+
throw error;
|
|
173
182
|
} finally {
|
|
174
183
|
if (this.inflight.get(sessionKey) === controller) this.inflight.delete(sessionKey);
|
|
175
184
|
}
|
|
@@ -190,10 +199,10 @@ var AgentLoop = class {
|
|
|
190
199
|
const session = this.sessions.getOrCreate(sessionKey);
|
|
191
200
|
this.updateToolContexts(originChannel, originChatId);
|
|
192
201
|
const messages = this.context.buildMessages({
|
|
193
|
-
history: session.getHistory(),
|
|
194
|
-
currentMessage: msg.content,
|
|
195
202
|
channel: originChannel,
|
|
196
|
-
chatId: originChatId
|
|
203
|
+
chatId: originChatId,
|
|
204
|
+
currentMessage: msg.content,
|
|
205
|
+
history: session.getHistory()
|
|
197
206
|
});
|
|
198
207
|
const newMsgStart = 1 + session.getHistory().length;
|
|
199
208
|
const result = await this.runAgentLoop(messages);
|
|
@@ -209,13 +218,13 @@ var AgentLoop = class {
|
|
|
209
218
|
let finalContent = null;
|
|
210
219
|
let sentToolCallNotice = false;
|
|
211
220
|
const toolsUsed = [];
|
|
212
|
-
for (let i = 0; i < this.maxIterations; i
|
|
221
|
+
for (let i = 0; i < this.maxIterations; i += 1) {
|
|
213
222
|
const response = await this.provider.chat({
|
|
223
|
+
maxTokens: this.maxTokens,
|
|
214
224
|
messages,
|
|
215
|
-
tools: this.tools.getDefinitions(),
|
|
216
225
|
model: this.model,
|
|
217
|
-
|
|
218
|
-
|
|
226
|
+
signal,
|
|
227
|
+
tools: this.tools.getDefinitions()
|
|
219
228
|
});
|
|
220
229
|
if (response.hasToolCalls) {
|
|
221
230
|
if (!sentToolCallNotice && onToolCallText) {
|
|
@@ -224,12 +233,12 @@ var AgentLoop = class {
|
|
|
224
233
|
sentToolCallNotice = true;
|
|
225
234
|
}
|
|
226
235
|
const toolCallDicts = response.toolCalls.map((tc) => ({
|
|
227
|
-
id: tc.id,
|
|
228
|
-
type: "function",
|
|
229
236
|
function: {
|
|
230
237
|
name: tc.name,
|
|
231
238
|
arguments: JSON.stringify(tc.arguments)
|
|
232
|
-
}
|
|
239
|
+
},
|
|
240
|
+
id: tc.id,
|
|
241
|
+
type: "function"
|
|
233
242
|
}));
|
|
234
243
|
this.context.addAssistantMessage(messages, response.content, toolCallDicts);
|
|
235
244
|
for (const tc of response.toolCalls) {
|
|
@@ -250,26 +259,26 @@ var AgentLoop = class {
|
|
|
250
259
|
finalContent = response.content;
|
|
251
260
|
if ((!finalContent || finalContent.trim().length === 0) && i > 0) {
|
|
252
261
|
messages.push({
|
|
253
|
-
|
|
254
|
-
|
|
262
|
+
content: "",
|
|
263
|
+
role: "assistant"
|
|
255
264
|
});
|
|
256
265
|
messages.push({
|
|
257
|
-
|
|
258
|
-
|
|
266
|
+
content: "(You used tools but didn't respond to the user. Please provide a brief response summarizing what you did.)",
|
|
267
|
+
role: "user"
|
|
259
268
|
});
|
|
260
269
|
continue;
|
|
261
270
|
}
|
|
262
271
|
messages.push({
|
|
263
|
-
|
|
264
|
-
|
|
272
|
+
content: finalContent ?? "",
|
|
273
|
+
role: "assistant"
|
|
265
274
|
});
|
|
266
275
|
break;
|
|
267
276
|
}
|
|
268
277
|
}
|
|
269
278
|
if (!finalContent || finalContent.trim().length === 0) finalContent = "I've completed processing but have no response to give.";
|
|
270
|
-
if (messages
|
|
271
|
-
|
|
272
|
-
|
|
279
|
+
if (messages.at(-1)?.role !== "assistant" || messages.at(-1)?.content !== finalContent) messages.push({
|
|
280
|
+
content: finalContent,
|
|
281
|
+
role: "assistant"
|
|
273
282
|
});
|
|
274
283
|
return {
|
|
275
284
|
content: finalContent,
|
|
@@ -280,10 +289,10 @@ var AgentLoop = class {
|
|
|
280
289
|
getToolCallFallbackText(toolCalls) {
|
|
281
290
|
const toolNames = toolCalls.map((tc) => tc.name);
|
|
282
291
|
const fallbacks = {
|
|
283
|
-
|
|
284
|
-
web_fetch: "ページを読み込み中...",
|
|
292
|
+
flex_message: "カードを作成中...",
|
|
285
293
|
spawn: "サブエージェントを起動中...",
|
|
286
|
-
|
|
294
|
+
web_fetch: "ページを読み込み中...",
|
|
295
|
+
web_search: "検索中..."
|
|
287
296
|
};
|
|
288
297
|
for (const name of toolNames) if (fallbacks[name]) return fallbacks[name];
|
|
289
298
|
return "ちょっと待ってね...";
|
|
@@ -301,10 +310,10 @@ var AgentLoop = class {
|
|
|
301
310
|
const session = this.sessions.getOrCreate(sessionKey);
|
|
302
311
|
this.updateToolContexts(channel, chatId);
|
|
303
312
|
const messages = this.context.buildMessages({
|
|
304
|
-
history: session.getHistory(),
|
|
305
|
-
currentMessage: content,
|
|
306
313
|
channel,
|
|
307
|
-
chatId
|
|
314
|
+
chatId,
|
|
315
|
+
currentMessage: content,
|
|
316
|
+
history: session.getHistory()
|
|
308
317
|
});
|
|
309
318
|
const newMsgStart = 1 + session.getHistory().length;
|
|
310
319
|
const result = await this.runAgentLoop(messages);
|
|
@@ -346,11 +355,11 @@ Respond with ONLY valid JSON, no markdown fences.`;
|
|
|
346
355
|
try {
|
|
347
356
|
let text = ((await this.provider.chat({
|
|
348
357
|
messages: [{
|
|
349
|
-
|
|
350
|
-
|
|
358
|
+
content: "You are a memory consolidation agent. Respond only with valid JSON.",
|
|
359
|
+
role: "system"
|
|
351
360
|
}, {
|
|
352
|
-
|
|
353
|
-
|
|
361
|
+
content: prompt,
|
|
362
|
+
role: "user"
|
|
354
363
|
}],
|
|
355
364
|
model: this.consolidationModel
|
|
356
365
|
})).content || "").trim();
|
|
@@ -364,8 +373,8 @@ Respond with ONLY valid JSON, no markdown fences.`;
|
|
|
364
373
|
const update = typeof result.memory_update === "string" ? result.memory_update : JSON.stringify(result.memory_update, null, 2);
|
|
365
374
|
memory.writeLongTerm(update);
|
|
366
375
|
}
|
|
367
|
-
} catch (
|
|
368
|
-
console.error("Memory consolidation failed:",
|
|
376
|
+
} catch (error) {
|
|
377
|
+
console.error("Memory consolidation failed:", error);
|
|
369
378
|
const fallbackEntry = `[${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)}] Consolidation failed, archiving raw messages:\n${conversation.slice(0, 2e3)}`;
|
|
370
379
|
memory.appendHistory(fallbackEntry);
|
|
371
380
|
}
|