@geminixiang/mikan 1.0.0-beta.3 → 1.0.0-beta.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +563 -0
- package/README.md +60 -24
- package/dist/adapter.d.ts +1 -1
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js.map +1 -1
- package/dist/adapters/discord/bot.d.ts +1 -0
- package/dist/adapters/discord/bot.d.ts.map +1 -1
- package/dist/adapters/discord/bot.js +47 -65
- package/dist/adapters/discord/bot.js.map +1 -1
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +46 -211
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/github/bot.d.ts +86 -0
- package/dist/adapters/github/bot.d.ts.map +1 -0
- package/dist/adapters/github/bot.js +640 -0
- package/dist/adapters/github/bot.js.map +1 -0
- package/dist/adapters/github/client.d.ts +122 -0
- package/dist/adapters/github/client.d.ts.map +1 -0
- package/dist/adapters/github/client.js +314 -0
- package/dist/adapters/github/client.js.map +1 -0
- package/dist/adapters/github/cloudbuild.d.ts +19 -0
- package/dist/adapters/github/cloudbuild.d.ts.map +1 -0
- package/dist/adapters/github/cloudbuild.js +71 -0
- package/dist/adapters/github/cloudbuild.js.map +1 -0
- package/dist/adapters/github/context.d.ts +9 -0
- package/dist/adapters/github/context.d.ts.map +1 -0
- package/dist/adapters/github/context.js +98 -0
- package/dist/adapters/github/context.js.map +1 -0
- package/dist/adapters/github/gcp-auth.d.ts +28 -0
- package/dist/adapters/github/gcp-auth.d.ts.map +1 -0
- package/dist/adapters/github/gcp-auth.js +196 -0
- package/dist/adapters/github/gcp-auth.js.map +1 -0
- package/dist/adapters/github/github-ops.d.ts +90 -0
- package/dist/adapters/github/github-ops.d.ts.map +1 -0
- package/dist/adapters/github/github-ops.js +405 -0
- package/dist/adapters/github/github-ops.js.map +1 -0
- package/dist/adapters/github/ids.d.ts +34 -0
- package/dist/adapters/github/ids.d.ts.map +1 -0
- package/dist/adapters/github/ids.js +53 -0
- package/dist/adapters/github/ids.js.map +1 -0
- package/dist/adapters/github/repo.d.ts +32 -0
- package/dist/adapters/github/repo.d.ts.map +1 -0
- package/dist/adapters/github/repo.js +141 -0
- package/dist/adapters/github/repo.js.map +1 -0
- package/dist/adapters/github/tool-pack.d.ts +14 -0
- package/dist/adapters/github/tool-pack.d.ts.map +1 -0
- package/dist/adapters/github/tool-pack.js +56 -0
- package/dist/adapters/github/tool-pack.js.map +1 -0
- package/dist/adapters/github/tools/checks.d.ts +19 -0
- package/dist/adapters/github/tools/checks.d.ts.map +1 -0
- package/dist/adapters/github/tools/checks.js +105 -0
- package/dist/adapters/github/tools/checks.js.map +1 -0
- package/dist/adapters/github/tools/issue.d.ts +21 -0
- package/dist/adapters/github/tools/issue.d.ts.map +1 -0
- package/dist/adapters/github/tools/issue.js +48 -0
- package/dist/adapters/github/tools/issue.js.map +1 -0
- package/dist/adapters/github/tools/pr.d.ts +22 -0
- package/dist/adapters/github/tools/pr.d.ts.map +1 -0
- package/dist/adapters/github/tools/pr.js +48 -0
- package/dist/adapters/github/tools/pr.js.map +1 -0
- package/dist/adapters/github/tools/read.d.ts +21 -0
- package/dist/adapters/github/tools/read.d.ts.map +1 -0
- package/dist/adapters/github/tools/read.js +141 -0
- package/dist/adapters/github/tools/read.js.map +1 -0
- package/dist/adapters/github/tools/review-reply.d.ts +17 -0
- package/dist/adapters/github/tools/review-reply.d.ts.map +1 -0
- package/dist/adapters/github/tools/review-reply.js +38 -0
- package/dist/adapters/github/tools/review-reply.js.map +1 -0
- package/dist/adapters/github/tools/sync.d.ts +17 -0
- package/dist/adapters/github/tools/sync.d.ts.map +1 -0
- package/dist/adapters/github/tools/sync.js +34 -0
- package/dist/adapters/github/tools/sync.js.map +1 -0
- package/dist/adapters/github/types.d.ts +372 -0
- package/dist/adapters/github/types.d.ts.map +1 -0
- package/dist/adapters/github/types.js +2 -0
- package/dist/adapters/github/types.js.map +1 -0
- package/dist/adapters/intake.d.ts +16 -5
- package/dist/adapters/intake.d.ts.map +1 -1
- package/dist/adapters/intake.js +84 -22
- package/dist/adapters/intake.js.map +1 -1
- package/dist/adapters/progressive-renderer.d.ts +7 -0
- package/dist/adapters/progressive-renderer.d.ts.map +1 -0
- package/dist/adapters/progressive-renderer.js +383 -0
- package/dist/adapters/progressive-renderer.js.map +1 -0
- package/dist/adapters/slack/blocks.d.ts.map +1 -1
- package/dist/adapters/slack/blocks.js +111 -111
- package/dist/adapters/slack/blocks.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +10 -6
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +173 -145
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/context.d.ts.map +1 -1
- package/dist/adapters/slack/context.js +3 -14
- package/dist/adapters/slack/context.js.map +1 -1
- package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
- package/dist/adapters/slack/response-lifecycle.js +126 -323
- package/dist/adapters/slack/response-lifecycle.js.map +1 -1
- package/dist/adapters/slack/session.d.ts.map +1 -1
- package/dist/adapters/slack/session.js +5 -8
- package/dist/adapters/slack/session.js.map +1 -1
- package/dist/adapters/slack/tool-pack.d.ts +11 -0
- package/dist/adapters/slack/tool-pack.d.ts.map +1 -0
- package/dist/adapters/slack/tool-pack.js +45 -0
- package/dist/adapters/slack/tool-pack.js.map +1 -0
- package/dist/adapters/slack/tools/blockkit.d.ts +14 -0
- package/dist/adapters/slack/tools/blockkit.d.ts.map +1 -0
- package/dist/adapters/slack/tools/blockkit.js +106 -0
- package/dist/adapters/slack/tools/blockkit.js.map +1 -0
- package/dist/adapters/slack/types.d.ts +37 -0
- package/dist/adapters/slack/types.d.ts.map +1 -1
- package/dist/adapters/slack/types.js.map +1 -1
- package/dist/adapters/telegram/bot.d.ts +1 -2
- package/dist/adapters/telegram/bot.d.ts.map +1 -1
- package/dist/adapters/telegram/bot.js +51 -63
- package/dist/adapters/telegram/bot.js.map +1 -1
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +55 -182
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/adapters/types.d.ts +86 -10
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/agent.d.ts +14 -19
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +745 -243
- package/dist/agent.js.map +1 -1
- package/dist/cli/arg-grammar.d.ts +25 -0
- package/dist/cli/arg-grammar.d.ts.map +1 -0
- package/dist/cli/arg-grammar.js +59 -0
- package/dist/cli/arg-grammar.js.map +1 -0
- package/dist/cli/boot.d.ts +5 -0
- package/dist/cli/boot.d.ts.map +1 -0
- package/dist/cli/boot.js +112 -0
- package/dist/cli/boot.js.map +1 -0
- package/dist/cli/download.d.ts.map +1 -0
- package/dist/cli/download.js.map +1 -0
- package/dist/cli/ext-dev.d.ts +2 -0
- package/dist/cli/ext-dev.d.ts.map +1 -0
- package/dist/cli/ext-dev.js +177 -0
- package/dist/cli/ext-dev.js.map +1 -0
- package/dist/cli/ext-git.d.ts +17 -0
- package/dist/cli/ext-git.d.ts.map +1 -0
- package/dist/cli/ext-git.js +107 -0
- package/dist/cli/ext-git.js.map +1 -0
- package/dist/cli/ext.d.ts +2 -0
- package/dist/cli/ext.d.ts.map +1 -0
- package/dist/cli/ext.js +222 -0
- package/dist/cli/ext.js.map +1 -0
- package/dist/cli/types.d.ts +20 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/commands/admin.d.ts.map +1 -1
- package/dist/commands/admin.js +2 -1
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/auto-reply.d.ts.map +1 -1
- package/dist/commands/auto-reply.js +2 -6
- package/dist/commands/auto-reply.js.map +1 -1
- package/dist/commands/extensions.d.ts.map +1 -1
- package/dist/commands/extensions.js +18 -8
- package/dist/commands/extensions.js.map +1 -1
- package/dist/commands/login.d.ts +2 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +35 -3
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/manifest.d.ts +30 -0
- package/dist/commands/manifest.d.ts.map +1 -0
- package/dist/commands/manifest.js +121 -0
- package/dist/commands/manifest.js.map +1 -0
- package/dist/commands/model.d.ts +2 -3
- package/dist/commands/model.d.ts.map +1 -1
- package/dist/commands/model.js +57 -20
- package/dist/commands/model.js.map +1 -1
- package/dist/commands/new.d.ts.map +1 -1
- package/dist/commands/new.js +10 -2
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/registry.d.ts +2 -2
- package/dist/commands/registry.d.ts.map +1 -1
- package/dist/commands/registry.js +1 -2
- package/dist/commands/registry.js.map +1 -1
- package/dist/commands/sandbox.d.ts.map +1 -1
- package/dist/commands/sandbox.js +23 -17
- package/dist/commands/sandbox.js.map +1 -1
- package/dist/commands/text.d.ts +2 -0
- package/dist/commands/text.d.ts.map +1 -0
- package/dist/commands/text.js +16 -0
- package/dist/commands/text.js.map +1 -0
- package/dist/commands/types.d.ts +70 -2
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js.map +1 -1
- package/dist/config.d.ts +1 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +102 -95
- package/dist/config.js.map +1 -1
- package/dist/env-manifest.d.ts +28 -0
- package/dist/env-manifest.d.ts.map +1 -0
- package/dist/env-manifest.js +214 -0
- package/dist/env-manifest.js.map +1 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +9 -73
- package/dist/events.js.map +1 -1
- package/dist/execution-resolver.d.ts +7 -6
- package/dist/execution-resolver.d.ts.map +1 -1
- package/dist/execution-resolver.js +105 -110
- package/dist/execution-resolver.js.map +1 -1
- package/dist/harness/auth.d.ts +2 -1
- package/dist/harness/auth.d.ts.map +1 -1
- package/dist/harness/auth.js +6 -0
- package/dist/harness/auth.js.map +1 -1
- package/dist/harness/event-format.d.ts +25 -0
- package/dist/harness/event-format.d.ts.map +1 -0
- package/dist/harness/event-format.js +159 -0
- package/dist/harness/event-format.js.map +1 -0
- package/dist/harness/extensions/blockkit.d.ts +19 -0
- package/dist/harness/extensions/blockkit.d.ts.map +1 -0
- package/dist/harness/extensions/blockkit.js +42 -0
- package/dist/harness/extensions/blockkit.js.map +1 -0
- package/dist/harness/extensions/loader.d.ts +25 -48
- package/dist/harness/extensions/loader.d.ts.map +1 -1
- package/dist/harness/extensions/loader.js +373 -113
- package/dist/harness/extensions/loader.js.map +1 -1
- package/dist/harness/extensions/registry.d.ts +75 -2
- package/dist/harness/extensions/registry.d.ts.map +1 -1
- package/dist/harness/extensions/registry.js +239 -0
- package/dist/harness/extensions/registry.js.map +1 -1
- package/dist/harness/extensions/types.d.ts +318 -25
- package/dist/harness/extensions/types.d.ts.map +1 -1
- package/dist/harness/extensions/types.js.map +1 -1
- package/dist/harness/index.d.ts +18 -8
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +7 -4
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/models.d.ts +7 -4
- package/dist/harness/models.d.ts.map +1 -1
- package/dist/harness/models.js +10 -0
- package/dist/harness/models.js.map +1 -1
- package/dist/harness/runner.d.ts +50 -54
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +230 -44
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/session-store.d.ts +9 -5
- package/dist/harness/session-store.d.ts.map +1 -1
- package/dist/harness/session-store.js +131 -30
- package/dist/harness/session-store.js.map +1 -1
- package/dist/harness/settings.d.ts +2 -20
- package/dist/harness/settings.d.ts.map +1 -1
- package/dist/harness/settings.js +11 -0
- package/dist/harness/settings.js.map +1 -1
- package/dist/harness/skills.d.ts +2 -29
- package/dist/harness/skills.d.ts.map +1 -1
- package/dist/harness/skills.js.map +1 -1
- package/dist/harness/subagent-profiles.d.ts +8 -0
- package/dist/harness/subagent-profiles.d.ts.map +1 -0
- package/dist/harness/subagent-profiles.js +290 -0
- package/dist/harness/subagent-profiles.js.map +1 -0
- package/dist/harness/subagent-runner.d.ts +39 -0
- package/dist/harness/subagent-runner.d.ts.map +1 -0
- package/dist/harness/subagent-runner.js +615 -0
- package/dist/harness/subagent-runner.js.map +1 -0
- package/dist/harness/types.d.ts +263 -1
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/usage.d.ts +6 -0
- package/dist/harness/usage.d.ts.map +1 -0
- package/dist/harness/usage.js +32 -0
- package/dist/harness/usage.js.map +1 -0
- package/dist/index.d.ts +33 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -6
- package/dist/index.js.map +1 -1
- package/dist/main.js +253 -109
- package/dist/main.js.map +1 -1
- package/dist/observability/instrument.js +6 -4
- package/dist/observability/instrument.js.map +1 -1
- package/dist/observability/sentry.d.ts.map +1 -1
- package/dist/observability/sentry.js +3 -2
- package/dist/observability/sentry.js.map +1 -1
- package/dist/packages/admin.d.ts +17 -0
- package/dist/packages/admin.d.ts.map +1 -0
- package/dist/packages/admin.js +96 -0
- package/dist/packages/admin.js.map +1 -0
- package/dist/packages/index.d.ts +6 -0
- package/dist/packages/index.d.ts.map +1 -0
- package/dist/packages/index.js +6 -0
- package/dist/packages/index.js.map +1 -0
- package/dist/packages/inspect.d.ts +11 -0
- package/dist/packages/inspect.d.ts.map +1 -0
- package/dist/packages/inspect.js +100 -0
- package/dist/packages/inspect.js.map +1 -0
- package/dist/packages/materialize.d.ts +39 -0
- package/dist/packages/materialize.d.ts.map +1 -0
- package/dist/packages/materialize.js +300 -0
- package/dist/packages/materialize.js.map +1 -0
- package/dist/packages/resolve.d.ts +25 -0
- package/dist/packages/resolve.d.ts.map +1 -0
- package/dist/packages/resolve.js +212 -0
- package/dist/packages/resolve.js.map +1 -0
- package/dist/packages/source.d.ts +33 -0
- package/dist/packages/source.d.ts.map +1 -0
- package/dist/packages/source.js +177 -0
- package/dist/packages/source.js.map +1 -0
- package/dist/packages/types.d.ts +104 -0
- package/dist/packages/types.d.ts.map +1 -0
- package/dist/packages/types.js +2 -0
- package/dist/packages/types.js.map +1 -0
- package/dist/provisioner.d.ts.map +1 -1
- package/dist/provisioner.js +6 -6
- package/dist/provisioner.js.map +1 -1
- package/dist/runtime/conversation-runtime.d.ts +1 -1
- package/dist/runtime/conversation-runtime.d.ts.map +1 -1
- package/dist/runtime/conversation-runtime.js +481 -98
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/session-lifecycle.d.ts +28 -0
- package/dist/runtime/session-lifecycle.d.ts.map +1 -0
- package/dist/runtime/session-lifecycle.js +161 -0
- package/dist/runtime/session-lifecycle.js.map +1 -0
- package/dist/runtime/types.d.ts +45 -5
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sandbox/cloudflare.d.ts +3 -0
- package/dist/sandbox/cloudflare.d.ts.map +1 -1
- package/dist/sandbox/cloudflare.js +11 -0
- package/dist/sandbox/cloudflare.js.map +1 -1
- package/dist/sandbox/container.d.ts +4 -0
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +12 -2
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/firecracker.d.ts +3 -0
- package/dist/sandbox/firecracker.d.ts.map +1 -1
- package/dist/sandbox/firecracker.js +11 -1
- package/dist/sandbox/firecracker.js.map +1 -1
- package/dist/sandbox/gondolin.d.ts +57 -0
- package/dist/sandbox/gondolin.d.ts.map +1 -0
- package/dist/sandbox/gondolin.js +764 -0
- package/dist/sandbox/gondolin.js.map +1 -0
- package/dist/sandbox/host.d.ts +4 -0
- package/dist/sandbox/host.d.ts.map +1 -1
- package/dist/sandbox/host.js +52 -0
- package/dist/sandbox/host.js.map +1 -1
- package/dist/sandbox/identity.d.ts +16 -0
- package/dist/sandbox/identity.d.ts.map +1 -0
- package/dist/sandbox/identity.js +42 -0
- package/dist/sandbox/identity.js.map +1 -0
- package/dist/sandbox/image.d.ts.map +1 -1
- package/dist/sandbox/image.js +1 -0
- package/dist/sandbox/image.js.map +1 -1
- package/dist/sandbox/index.d.ts +15 -4
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +25 -3
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/path-context.js +18 -8
- package/dist/sandbox/path-context.js.map +1 -1
- package/dist/sandbox/types.d.ts +65 -1
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/sandbox/types.js.map +1 -1
- package/dist/sandbox/utils.d.ts +12 -0
- package/dist/sandbox/utils.d.ts.map +1 -1
- package/dist/sandbox/utils.js +38 -0
- package/dist/sandbox/utils.js.map +1 -1
- package/dist/sessions/chat-history-sync.d.ts +25 -0
- package/dist/sessions/chat-history-sync.d.ts.map +1 -0
- package/dist/sessions/{agent-memory-file-manager.js → chat-history-sync.js} +98 -124
- package/dist/sessions/chat-history-sync.js.map +1 -0
- package/dist/sessions/conversation-log.d.ts +9 -0
- package/dist/sessions/conversation-log.d.ts.map +1 -0
- package/dist/sessions/conversation-log.js +47 -0
- package/dist/sessions/conversation-log.js.map +1 -0
- package/dist/sessions/history-line.d.ts +20 -0
- package/dist/sessions/history-line.d.ts.map +1 -0
- package/dist/sessions/history-line.js +24 -0
- package/dist/sessions/history-line.js.map +1 -0
- package/dist/sessions/policy.d.ts.map +1 -1
- package/dist/sessions/policy.js +5 -3
- package/dist/sessions/policy.js.map +1 -1
- package/dist/sessions/rotation.d.ts +2 -0
- package/dist/sessions/rotation.d.ts.map +1 -0
- package/dist/sessions/rotation.js +39 -0
- package/dist/sessions/rotation.js.map +1 -0
- package/dist/sessions/session-key.d.ts +40 -0
- package/dist/sessions/session-key.d.ts.map +1 -0
- package/dist/sessions/session-key.js +92 -0
- package/dist/sessions/session-key.js.map +1 -0
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +40 -18
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/types.d.ts +17 -4
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js.map +1 -1
- package/dist/settings-mutation.d.ts +8 -0
- package/dist/settings-mutation.d.ts.map +1 -0
- package/dist/settings-mutation.js +43 -0
- package/dist/settings-mutation.js.map +1 -0
- package/dist/subagent-progress.d.ts +43 -0
- package/dist/subagent-progress.d.ts.map +1 -0
- package/dist/subagent-progress.js +220 -0
- package/dist/subagent-progress.js.map +1 -0
- package/dist/tools/bash.d.ts +3 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +25 -17
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +10 -12
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/event.d.ts +1 -1
- package/dist/tools/event.d.ts.map +1 -1
- package/dist/tools/event.js +53 -43
- package/dist/tools/event.js.map +1 -1
- package/dist/tools/generate-image.d.ts +17 -0
- package/dist/tools/generate-image.d.ts.map +1 -0
- package/dist/tools/generate-image.js +63 -0
- package/dist/tools/generate-image.js.map +1 -0
- package/dist/tools/host-fn-tool.d.ts +21 -0
- package/dist/tools/host-fn-tool.d.ts.map +1 -0
- package/dist/tools/host-fn-tool.js +32 -0
- package/dist/tools/host-fn-tool.js.map +1 -0
- package/dist/tools/index.d.ts +14 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +28 -3
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/react.d.ts +15 -0
- package/dist/tools/react.d.ts.map +1 -0
- package/dist/tools/react.js +29 -0
- package/dist/tools/react.js.map +1 -0
- package/dist/tools/read.d.ts +1 -0
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +37 -31
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/sandbox.d.ts +2 -2
- package/dist/tools/sandbox.d.ts.map +1 -1
- package/dist/tools/sandbox.js +14 -9
- package/dist/tools/sandbox.js.map +1 -1
- package/dist/tools/subagent-slots.d.ts +28 -0
- package/dist/tools/subagent-slots.d.ts.map +1 -0
- package/dist/tools/subagent-slots.js +72 -0
- package/dist/tools/subagent-slots.js.map +1 -0
- package/dist/tools/subagent.d.ts +54 -0
- package/dist/tools/subagent.d.ts.map +1 -0
- package/dist/tools/subagent.js +401 -0
- package/dist/tools/subagent.js.map +1 -0
- package/dist/tools/types.d.ts +40 -6
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js.map +1 -1
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +2 -8
- package/dist/tools/write.js.map +1 -1
- package/dist/trigger.d.ts.map +1 -1
- package/dist/trigger.js +1 -2
- package/dist/trigger.js.map +1 -1
- package/dist/types.d.ts +232 -32
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/date.d.ts +1 -1
- package/dist/utils/date.js +1 -1
- package/dist/utils/date.js.map +1 -1
- package/dist/vault/disabled.d.ts +9 -0
- package/dist/vault/disabled.d.ts.map +1 -0
- package/dist/vault/disabled.js +22 -0
- package/dist/vault/disabled.js.map +1 -0
- package/dist/vault/index.d.ts +0 -2
- package/dist/vault/index.d.ts.map +1 -1
- package/dist/vault/index.js +30 -33
- package/dist/vault/index.js.map +1 -1
- package/dist/vault/injection.d.ts +10 -0
- package/dist/vault/injection.d.ts.map +1 -0
- package/dist/vault/injection.js +30 -0
- package/dist/vault/injection.js.map +1 -0
- package/dist/vault/policy.d.ts +20 -0
- package/dist/vault/policy.d.ts.map +1 -0
- package/dist/vault/policy.js +20 -0
- package/dist/vault/policy.js.map +1 -0
- package/dist/vault/types.d.ts +4 -2
- package/dist/vault/types.d.ts.map +1 -1
- package/dist/vault/types.js.map +1 -1
- package/dist/web/admin/portal.d.ts +17 -2
- package/dist/web/admin/portal.d.ts.map +1 -1
- package/dist/web/admin/portal.js +385 -155
- package/dist/web/admin/portal.js.map +1 -1
- package/dist/web/admin/types.d.ts +18 -0
- package/dist/web/admin/types.d.ts.map +1 -1
- package/dist/web/admin/types.js.map +1 -1
- package/dist/web/agent-events/portal.d.ts.map +1 -1
- package/dist/web/agent-events/portal.js +2 -1
- package/dist/web/agent-events/portal.js.map +1 -1
- package/dist/web/login/oauth.d.ts +2 -3
- package/dist/web/login/oauth.d.ts.map +1 -1
- package/dist/web/login/oauth.js +0 -31
- package/dist/web/login/oauth.js.map +1 -1
- package/dist/web/login/portal.js +1 -1
- package/dist/web/login/portal.js.map +1 -1
- package/dist/web/login/types.d.ts +0 -11
- package/dist/web/login/types.d.ts.map +1 -1
- package/dist/web/login/types.js.map +1 -1
- package/dist/web/portal-shell.d.ts +4 -0
- package/dist/web/portal-shell.d.ts.map +1 -0
- package/dist/{portal-shell.js → web/portal-shell.js} +2 -2
- package/dist/web/portal-shell.js.map +1 -0
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +7 -0
- package/dist/web/server.js.map +1 -1
- package/dist/web/session-view/command.d.ts.map +1 -1
- package/dist/web/session-view/command.js +4 -1
- package/dist/web/session-view/command.js.map +1 -1
- package/dist/web/session-view/portal.d.ts.map +1 -1
- package/dist/web/session-view/portal.js +4 -3
- package/dist/web/session-view/portal.js.map +1 -1
- package/dist/web/session-view/service.d.ts.map +1 -1
- package/dist/web/session-view/service.js +2 -1
- package/dist/web/session-view/service.js.map +1 -1
- package/dist/web/session-view/types.d.ts +2 -1
- package/dist/web/session-view/types.d.ts.map +1 -1
- package/dist/web/session-view/types.js.map +1 -1
- package/dist/workspace-projection/index.d.ts +5 -0
- package/dist/workspace-projection/index.d.ts.map +1 -0
- package/dist/workspace-projection/index.js +71 -0
- package/dist/workspace-projection/index.js.map +1 -0
- package/dist/workspace-projection/types.d.ts +7 -0
- package/dist/workspace-projection/types.d.ts.map +1 -0
- package/dist/workspace-projection/types.js +2 -0
- package/dist/workspace-projection/types.js.map +1 -0
- package/package.json +28 -15
- package/dist/adapters/streaming.d.ts +0 -18
- package/dist/adapters/streaming.d.ts.map +0 -1
- package/dist/adapters/streaming.js +0 -44
- package/dist/adapters/streaming.js.map +0 -1
- package/dist/download.d.ts.map +0 -1
- package/dist/download.js.map +0 -1
- package/dist/model-registry.d.ts +0 -4
- package/dist/model-registry.d.ts.map +0 -1
- package/dist/model-registry.js +0 -7
- package/dist/model-registry.js.map +0 -1
- package/dist/portal-shell.d.ts +0 -4
- package/dist/portal-shell.d.ts.map +0 -1
- package/dist/portal-shell.js.map +0 -1
- package/dist/runtime/agent-run-controller.d.ts +0 -31
- package/dist/runtime/agent-run-controller.d.ts.map +0 -1
- package/dist/runtime/agent-run-controller.js +0 -195
- package/dist/runtime/agent-run-controller.js.map +0 -1
- package/dist/sessions/agent-memory-file-manager.d.ts +0 -19
- package/dist/sessions/agent-memory-file-manager.d.ts.map +0 -1
- package/dist/sessions/agent-memory-file-manager.js.map +0 -1
- package/dist/vault/routing.d.ts +0 -3
- package/dist/vault/routing.d.ts.map +0 -1
- package/dist/vault/routing.js +0 -13
- package/dist/vault/routing.js.map +0 -1
- /package/dist/{download.d.ts → cli/download.d.ts} +0 -0
- /package/dist/{download.js → cli/download.js} +0 -0
package/dist/agent.js
CHANGED
|
@@ -1,24 +1,129 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Agent runner: prompt construction, path translation, run lifecycle, and createRunner.
|
|
3
|
+
* Single module — do not split helpers that only this file uses.
|
|
4
|
+
*/
|
|
5
|
+
import { DEFAULT_EVENT_BUDGET, formatSkillsForPrompt, loadExtensions, loadSkillsFromDir, MikanAgentSession, MikanModels, parseCommandInput, } from "./harness/index.js";
|
|
6
|
+
import { runSubagent } from "./harness/subagent-runner.js";
|
|
7
|
+
import { loadSubagentProfiles } from "./harness/subagent-profiles.js";
|
|
8
|
+
import { mergeSubagentProgress, parseSubagentProgressSnapshot, renderSubagentDashboard, settleSubagentProgress, } from "./subagent-progress.js";
|
|
2
9
|
import { createHash } from "crypto";
|
|
3
|
-
import { existsSync,
|
|
4
|
-
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
5
|
-
import {
|
|
10
|
+
import { existsSync, lstatSync } from "fs";
|
|
11
|
+
import { chmod, mkdtemp, mkdir, readFile, rm, writeFile } from "fs/promises";
|
|
12
|
+
import { tmpdir } from "os";
|
|
13
|
+
import { basename, isAbsolute, join, posix, relative, resolve, sep } from "path";
|
|
6
14
|
import { resolveConversationSettings } from "./config.js";
|
|
7
|
-
import {
|
|
15
|
+
import { effectiveStateDir } from "./cli/arg-grammar.js";
|
|
16
|
+
import { packageSkillRuntimeDir, resolveConversationPackages } from "./packages/index.js";
|
|
8
17
|
import { ActorExecutionResolver } from "./execution-resolver.js";
|
|
9
18
|
import * as log from "./log.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
19
|
+
import { createExecutor, getUnresolvedSandboxPathContext, } from "./sandbox/index.js";
|
|
20
|
+
import { addLifecycleBreadcrumb, metricAttributes, reportUserFacingError, updateActiveSpanAttribution, } from "./observability/sentry.js";
|
|
21
|
+
import { ChatHistorySync } from "./sessions/chat-history-sync.js";
|
|
22
|
+
import { formatHistoryLine } from "./sessions/history-line.js";
|
|
23
|
+
import { conversationIdOf, isThreadSessionKey } from "./sessions/session-key.js";
|
|
15
24
|
import { extractSessionUuid, openManagedSession, } from "./sessions/store.js";
|
|
16
25
|
import { HostEventStore } from "./tools/event.js";
|
|
17
|
-
import { createMikanTools } from "./tools/index.js";
|
|
26
|
+
import { createMikanTools, createSubagentTool, DEFAULT_GLOBAL_SUBAGENT_SLOTS, SubagentSlotPool, } from "./tools/index.js";
|
|
27
|
+
// One process-wide fan-out account: per-conversation queues serialize runs,
|
|
28
|
+
// but each run can fan out up to the per-run cap — without this shared
|
|
29
|
+
// ceiling, N busy conversations hold N × cap live subagent sessions.
|
|
30
|
+
const globalSubagentSlots = new SubagentSlotPool(DEFAULT_GLOBAL_SUBAGENT_SLOTS);
|
|
18
31
|
import * as Sentry from "@sentry/node";
|
|
19
|
-
import { formatLocalTimestamp } from "./utils/date.js";
|
|
20
|
-
import { resolveConfiguredModel } from "./model-registry.js";
|
|
21
32
|
import { emitAgentEvent } from "./agent-events.js";
|
|
33
|
+
export function translateRuntimePathToHost(runtimePath, pathContext) {
|
|
34
|
+
return pathContext.runtimeToHostPath?.(runtimePath) ?? runtimePath;
|
|
35
|
+
}
|
|
36
|
+
function isWithinPathRoot(path, root) {
|
|
37
|
+
const pathRelative = relative(root, path);
|
|
38
|
+
return (pathRelative === "" ||
|
|
39
|
+
(pathRelative !== ".." && !pathRelative.startsWith(`..${sep}`) && !isAbsolute(pathRelative)));
|
|
40
|
+
}
|
|
41
|
+
function hasParentTraversal(path) {
|
|
42
|
+
return path.split(/[\\/]/).some((segment) => segment === "..");
|
|
43
|
+
}
|
|
44
|
+
export function translateAttachPathToHost(filePath, pathContext) {
|
|
45
|
+
if (!pathContext.runtimeToHostPath) {
|
|
46
|
+
throw new Error("Cannot attach files: this sandbox has no host-backed runtime path mapping; attachments are unavailable for remote sandboxes such as Cloudflare or Firecracker");
|
|
47
|
+
}
|
|
48
|
+
if (hasParentTraversal(filePath)) {
|
|
49
|
+
throw new Error("Cannot attach files: parent-directory traversal is not allowed");
|
|
50
|
+
}
|
|
51
|
+
const runtimeRoot = resolve(pathContext.runtimeWorkspaceRoot);
|
|
52
|
+
const runtimePath = posix.isAbsolute(filePath)
|
|
53
|
+
? filePath
|
|
54
|
+
: posix.join(pathContext.runtimeWorkspaceRoot, filePath);
|
|
55
|
+
const normalizedRuntimePath = resolve(runtimePath);
|
|
56
|
+
if (!isWithinPathRoot(normalizedRuntimePath, runtimeRoot)) {
|
|
57
|
+
throw new Error("Cannot attach files: path must be within the runtime workspace");
|
|
58
|
+
}
|
|
59
|
+
const hostRoot = resolve(pathContext.hostWorkspaceRoot);
|
|
60
|
+
const translatedPath = pathContext.runtimeToHostPath(runtimePath);
|
|
61
|
+
const hostPath = resolve(translatedPath);
|
|
62
|
+
if (!isWithinPathRoot(hostPath, hostRoot)) {
|
|
63
|
+
throw new Error("Cannot attach files: path must be within the host workspace");
|
|
64
|
+
}
|
|
65
|
+
// Reject symlinks in every existing component. Missing files are left for
|
|
66
|
+
// the uploader's normal error, but a present attachment must be a regular
|
|
67
|
+
// non-symlink path all the way from the workspace root.
|
|
68
|
+
if (existsSync(hostPath)) {
|
|
69
|
+
let current = hostRoot;
|
|
70
|
+
const pathParts = relative(hostRoot, hostPath).split(sep).filter(Boolean);
|
|
71
|
+
for (const [index, part] of pathParts.entries()) {
|
|
72
|
+
current = join(current, part);
|
|
73
|
+
let stat;
|
|
74
|
+
try {
|
|
75
|
+
stat = lstatSync(current);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
if (stat.isSymbolicLink()) {
|
|
81
|
+
throw new Error("Cannot attach files: symlink components are not allowed");
|
|
82
|
+
}
|
|
83
|
+
if (index === pathParts.length - 1 && !stat.isFile()) {
|
|
84
|
+
throw new Error("Cannot attach files: path must be a regular file");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return hostPath;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Normalize an attachment path using runtime lexical semantics only. The
|
|
92
|
+
* executor remains the authority for reading the resulting runtime path.
|
|
93
|
+
*/
|
|
94
|
+
function normalizeAttachRuntimePath(filePath, runtimeWorkspaceRoot) {
|
|
95
|
+
if (hasParentTraversal(filePath)) {
|
|
96
|
+
throw new Error("Cannot attach files: parent-directory traversal is not allowed");
|
|
97
|
+
}
|
|
98
|
+
const runtimeRoot = posix.resolve(runtimeWorkspaceRoot);
|
|
99
|
+
const runtimePath = posix.resolve(runtimeRoot, filePath);
|
|
100
|
+
const runtimeRelativePath = posix.relative(runtimeRoot, runtimePath);
|
|
101
|
+
if (runtimeRelativePath === ".." ||
|
|
102
|
+
runtimeRelativePath.startsWith("../") ||
|
|
103
|
+
posix.isAbsolute(runtimeRelativePath)) {
|
|
104
|
+
throw new Error("Cannot attach files: path must be within the runtime workspace");
|
|
105
|
+
}
|
|
106
|
+
return runtimePath;
|
|
107
|
+
}
|
|
108
|
+
async function withStagedRuntimeFile(executor, runtimePath, upload) {
|
|
109
|
+
if (!executor.readFileBase64NoSymlinks) {
|
|
110
|
+
throw new Error("Attachments are unavailable: this sandbox cannot guarantee symlink-free path traversal");
|
|
111
|
+
}
|
|
112
|
+
const content = Buffer.from(await executor.readFileBase64NoSymlinks(runtimePath), "base64");
|
|
113
|
+
let stagingDir;
|
|
114
|
+
try {
|
|
115
|
+
stagingDir = await mkdtemp(join(tmpdir(), "mikan-upload-"));
|
|
116
|
+
await chmod(stagingDir, 0o700);
|
|
117
|
+
const stagedPath = join(stagingDir, basename(runtimePath));
|
|
118
|
+
await writeFile(stagedPath, content, { mode: 0o600, flag: "wx" });
|
|
119
|
+
await chmod(stagedPath, 0o600);
|
|
120
|
+
await upload(stagedPath);
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
if (stagingDir)
|
|
124
|
+
await rm(stagingDir, { recursive: true, force: true });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
22
127
|
const IMAGE_MIME_TYPES = {
|
|
23
128
|
jpg: "image/jpeg",
|
|
24
129
|
jpeg: "image/jpeg",
|
|
@@ -29,12 +134,46 @@ const IMAGE_MIME_TYPES = {
|
|
|
29
134
|
function getImageMimeType(filename) {
|
|
30
135
|
return IMAGE_MIME_TYPES[filename.toLowerCase().split(".").pop() || ""];
|
|
31
136
|
}
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
137
|
+
function formatTimestampedUserMessage(message) {
|
|
138
|
+
return formatHistoryLine({
|
|
139
|
+
date: new Date(),
|
|
140
|
+
userName: message.userName,
|
|
141
|
+
threadTs: message.threadTs,
|
|
142
|
+
text: message.text,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
async function collectMessageAttachments(message, workspacePath, pathContext, readAttachment) {
|
|
146
|
+
const imageAttachments = [];
|
|
147
|
+
const nonImagePaths = [];
|
|
148
|
+
for (const attachment of message.attachments || []) {
|
|
149
|
+
const runtimePath = `${workspacePath}/${attachment.localPath}`;
|
|
150
|
+
const hostPath = pathContext?.runtimeToHostPath?.(runtimePath) ?? runtimePath;
|
|
151
|
+
const mimeType = getImageMimeType(attachment.localPath);
|
|
152
|
+
if (mimeType && existsSync(hostPath) && readAttachment) {
|
|
153
|
+
try {
|
|
154
|
+
imageAttachments.push({
|
|
155
|
+
type: "image",
|
|
156
|
+
mimeType,
|
|
157
|
+
data: await readAttachment(runtimePath),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
nonImagePaths.push(runtimePath);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
nonImagePaths.push(runtimePath);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return { imageAttachments, nonImagePaths };
|
|
169
|
+
}
|
|
170
|
+
export async function buildPromptPayload(message, workspacePath, pathContext, readAttachment) {
|
|
171
|
+
let userMessage = formatTimestampedUserMessage(message);
|
|
172
|
+
const { imageAttachments, nonImagePaths } = await collectMessageAttachments(message, workspacePath, pathContext, readAttachment);
|
|
173
|
+
if (nonImagePaths.length > 0) {
|
|
174
|
+
userMessage += `\n\n<slack_attachments>\n${nonImagePaths.join("\n")}\n</slack_attachments>`;
|
|
175
|
+
}
|
|
176
|
+
return { userMessage, imageAttachments };
|
|
38
177
|
}
|
|
39
178
|
async function getMemory(conversationDir) {
|
|
40
179
|
const parts = [];
|
|
@@ -82,6 +221,32 @@ function loadMikanSkills(conversationDir, workspacePath) {
|
|
|
82
221
|
}
|
|
83
222
|
return hostPath;
|
|
84
223
|
};
|
|
224
|
+
// Package skills first: they are the lowest precedence, so a workspace or
|
|
225
|
+
// conversation skill of the same name below overwrites them. A package can
|
|
226
|
+
// offer a capability without taking the name away from whoever wants to
|
|
227
|
+
// replace it locally.
|
|
228
|
+
//
|
|
229
|
+
// Unlike extension-shipped skills, these are NOT inlined into the prompt:
|
|
230
|
+
// conversationPackageSkillMounts exposes them read-only at a runtime path,
|
|
231
|
+
// so the agent can read the files — including any scripts or templates the
|
|
232
|
+
// skill ships alongside its SKILL.md, which inlining could never carry.
|
|
233
|
+
const mounted = workspacePath !== hostWorkspacePath;
|
|
234
|
+
for (const { slug, dir } of resolveConversationPackages({
|
|
235
|
+
conversationId: basename(conversationDir),
|
|
236
|
+
stateDir: effectiveStateDir(),
|
|
237
|
+
conversationDir,
|
|
238
|
+
}).skillDirs) {
|
|
239
|
+
const runtimeDir = packageSkillRuntimeDir(slug);
|
|
240
|
+
for (const skill of loadSkillsFromDir({ dir, source: `package:${slug}` }).skills) {
|
|
241
|
+
// In host mode there is no mount, so the host path is already the path
|
|
242
|
+
// the agent will use.
|
|
243
|
+
if (mounted) {
|
|
244
|
+
skill.filePath = runtimeDir + skill.filePath.slice(dir.length);
|
|
245
|
+
skill.baseDir = runtimeDir + skill.baseDir.slice(dir.length);
|
|
246
|
+
}
|
|
247
|
+
skillMap.set(skill.name, skill);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
85
250
|
// Load workspace-level skills (global)
|
|
86
251
|
const workspaceSkillsDir = join(hostWorkspacePath, "skills");
|
|
87
252
|
for (const skill of loadSkillsFromDir({ dir: workspaceSkillsDir, source: "workspace" }).skills) {
|
|
@@ -174,8 +339,9 @@ function buildSystemPrompt(workspacePath, conversationId, conversationKind, curr
|
|
|
174
339
|
const slackBlockKitInstructions = platform.name === "slack"
|
|
175
340
|
? `
|
|
176
341
|
## Slack Rendering
|
|
177
|
-
- The Slack adapter renders responses
|
|
178
|
-
-
|
|
342
|
+
- The Slack adapter renders responses natively from standard Markdown. Answer in normal Markdown/GFM.
|
|
343
|
+
- Markdown pipe tables are rendered as native Slack tables.
|
|
344
|
+
- For interactive elements (buttons, select menus), use the slack_blockkit tool; user interactions arrive as "[Slack action] <action_id>: <value>" messages.
|
|
179
345
|
`
|
|
180
346
|
: "";
|
|
181
347
|
return `You are mikan, a ${platform.name} bot assistant. Be concise. No emojis.
|
|
@@ -329,81 +495,21 @@ Do not add this to \`[SILENT]\` responses.`);
|
|
|
329
495
|
}
|
|
330
496
|
return parts.join("\n\n");
|
|
331
497
|
}
|
|
332
|
-
export function
|
|
333
|
-
if (
|
|
334
|
-
return
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
: createExecutor(sandboxConfig);
|
|
347
|
-
const executor = {
|
|
348
|
-
exec(command, options) {
|
|
349
|
-
return activeExecutor.exec(command, options);
|
|
350
|
-
},
|
|
351
|
-
getWorkspacePath(hostPath) {
|
|
352
|
-
return activeExecutor.getWorkspacePath(hostPath);
|
|
353
|
-
},
|
|
354
|
-
getSandboxConfig() {
|
|
355
|
-
return activeExecutor.getSandboxConfig();
|
|
356
|
-
},
|
|
357
|
-
getPathContext(hostWorkspaceRoot) {
|
|
358
|
-
return activeExecutor.getPathContext(hostWorkspaceRoot);
|
|
359
|
-
},
|
|
360
|
-
};
|
|
361
|
-
return {
|
|
362
|
-
executionResolver,
|
|
363
|
-
executor,
|
|
364
|
-
getPathContext: () => executor.getPathContext(hostWorkspacePath),
|
|
365
|
-
async resolveExecutorForRun(context) {
|
|
366
|
-
if (!executionResolver)
|
|
367
|
-
return;
|
|
368
|
-
activeExecutor = await executionResolver.resolve(context);
|
|
369
|
-
},
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* Extension host services over mikan's runtime infrastructure: schedules
|
|
374
|
-
* become event files under `<workspaceDir>/events` (picked up live by
|
|
375
|
-
* EventsWatcher), secrets come from `vaults/extensions/<slug>/env`, and
|
|
376
|
-
* notify posts through the platform bots when main.ts provides a notifier.
|
|
377
|
-
*/
|
|
378
|
-
function buildExtensionHostServices(params) {
|
|
379
|
-
const { workspaceDir, vaultManager, platformNotifier } = params;
|
|
380
|
-
const eventStore = HostEventStore.fromWorkspaceDir(workspaceDir);
|
|
381
|
-
return {
|
|
382
|
-
stateDir: readEnv("STATE_DIR"),
|
|
383
|
-
scheduleStore: {
|
|
384
|
-
write: async (filename, payload) => {
|
|
385
|
-
// Event files tolerate a missing platform (single-platform default),
|
|
386
|
-
// so the harness payload is a valid event payload as written.
|
|
387
|
-
await eventStore.write(filename, payload);
|
|
388
|
-
},
|
|
389
|
-
delete: async (filename) => (await eventStore.delete(filename)).deleted,
|
|
390
|
-
list: async () => (await eventStore.list()).map((entry) => ({
|
|
391
|
-
filename: entry.filename,
|
|
392
|
-
payload: entry.payload,
|
|
393
|
-
})),
|
|
394
|
-
},
|
|
395
|
-
...(platformNotifier ? { postMessage: platformNotifier } : {}),
|
|
396
|
-
...(vaultManager
|
|
397
|
-
? {
|
|
398
|
-
resolveSecrets: (slug) => vaultManager.resolve(`extensions/${slug}`)?.env ?? {},
|
|
399
|
-
}
|
|
400
|
-
: {}),
|
|
401
|
-
};
|
|
498
|
+
export function appendTriggerAttribution(text, triggerAttribution, sessionLink) {
|
|
499
|
+
if (!triggerAttribution)
|
|
500
|
+
return text;
|
|
501
|
+
const trimmed = text.trimEnd();
|
|
502
|
+
const legacySuffix = `_Triggered by ${triggerAttribution}_`;
|
|
503
|
+
// Slack mrkdwn italics cannot span a URL — a `_..._` wrapping a link renders
|
|
504
|
+
// the underscores literally. Keep the session link outside the italic span.
|
|
505
|
+
const suffix = sessionLink ? `${legacySuffix} · session: ${sessionLink}` : legacySuffix;
|
|
506
|
+
if (trimmed.endsWith(suffix))
|
|
507
|
+
return text;
|
|
508
|
+
const body = trimmed.endsWith(legacySuffix)
|
|
509
|
+
? trimmed.slice(0, -legacySuffix.length).trimEnd()
|
|
510
|
+
: trimmed;
|
|
511
|
+
return `${body}\n\n${suffix}`;
|
|
402
512
|
}
|
|
403
|
-
/**
|
|
404
|
-
* Local (workspace/conversation) skills override extension skills on name
|
|
405
|
-
* collision: an admin's on-disk skill always beats an extension's.
|
|
406
|
-
*/
|
|
407
513
|
function mergeExtensionSkills(local, extension) {
|
|
408
514
|
if (extension.length === 0)
|
|
409
515
|
return local;
|
|
@@ -414,37 +520,6 @@ function mergeExtensionSkills(local, extension) {
|
|
|
414
520
|
byName.set(skill.name, skill);
|
|
415
521
|
return [...byName.values()];
|
|
416
522
|
}
|
|
417
|
-
async function createConfiguredAgentSession(params) {
|
|
418
|
-
const { conversationId, workspaceDir, systemPrompt, model, thinkingLevel, tools, sessionStore, models, vaultManager, platformNotifier, } = params;
|
|
419
|
-
// Host-only dirs under the state dir: extension code runs in the mikan
|
|
420
|
-
// process, so it must never load from workspace paths — those are mounted
|
|
421
|
-
// into sandbox containers and agent-writable (sandbox escape otherwise).
|
|
422
|
-
const extensionsResult = await loadExtensions({
|
|
423
|
-
dirs: defaultExtensionDirs(conversationId, readEnv("STATE_DIR")),
|
|
424
|
-
context: { conversationId, workspaceDir, model, thinkingLevel },
|
|
425
|
-
services: buildExtensionHostServices({ workspaceDir, vaultManager, platformNotifier }),
|
|
426
|
-
});
|
|
427
|
-
for (const err of extensionsResult.errors) {
|
|
428
|
-
log.logWarning(`[${conversationId}] Extension load error: ${err.path}`, err.error);
|
|
429
|
-
}
|
|
430
|
-
if (extensionsResult.extensions.length > 0) {
|
|
431
|
-
log.logInfo(`[${conversationId}] Loaded ${extensionsResult.extensions.length} extension(s): ${extensionsResult.extensions.map((extension) => extension.name).join(", ")}`);
|
|
432
|
-
}
|
|
433
|
-
const session = new MikanAgentSession({
|
|
434
|
-
systemPrompt,
|
|
435
|
-
model,
|
|
436
|
-
thinkingLevel,
|
|
437
|
-
tools,
|
|
438
|
-
models,
|
|
439
|
-
sessionStore,
|
|
440
|
-
extensions: extensionsResult.registry,
|
|
441
|
-
});
|
|
442
|
-
const reloaded = session.reloadFromSession();
|
|
443
|
-
if (reloaded > 0) {
|
|
444
|
-
log.logInfo(`[${conversationId}] Reloaded ${reloaded} messages from session context`);
|
|
445
|
-
}
|
|
446
|
-
return { session, extensionSkills: extensionsResult.skills };
|
|
447
|
-
}
|
|
448
523
|
function createEmptyUsageTotals() {
|
|
449
524
|
return {
|
|
450
525
|
input: 0,
|
|
@@ -461,6 +536,13 @@ function createRunState() {
|
|
|
461
536
|
queue: null,
|
|
462
537
|
pendingTools: new Map(),
|
|
463
538
|
toolProgress: new Map(),
|
|
539
|
+
subagentProgress: new Map(),
|
|
540
|
+
completedSubagentProgress: [],
|
|
541
|
+
subagentToolCalls: new Set(),
|
|
542
|
+
subagentProgressShown: false,
|
|
543
|
+
suppressResponseDeltas: false,
|
|
544
|
+
lastSubagentProgressAt: 0,
|
|
545
|
+
toolProgressTimer: undefined,
|
|
464
546
|
totalUsage: createEmptyUsageTotals(),
|
|
465
547
|
llmCallCount: 0,
|
|
466
548
|
stopReason: "stop",
|
|
@@ -480,6 +562,15 @@ function resetRunState(runState, responder, sessionConversation, userName, sessi
|
|
|
480
562
|
};
|
|
481
563
|
runState.pendingTools.clear();
|
|
482
564
|
runState.toolProgress.clear();
|
|
565
|
+
runState.subagentProgress.clear();
|
|
566
|
+
runState.completedSubagentProgress = [];
|
|
567
|
+
runState.subagentToolCalls.clear();
|
|
568
|
+
runState.subagentProgressShown = false;
|
|
569
|
+
runState.suppressResponseDeltas = false;
|
|
570
|
+
runState.lastSubagentProgressAt = 0;
|
|
571
|
+
if (runState.toolProgressTimer)
|
|
572
|
+
clearTimeout(runState.toolProgressTimer);
|
|
573
|
+
runState.toolProgressTimer = undefined;
|
|
483
574
|
runState.totalUsage = createEmptyUsageTotals();
|
|
484
575
|
runState.llmCallCount = 0;
|
|
485
576
|
runState.stopReason = "stop";
|
|
@@ -515,53 +606,6 @@ function createRunQueue(responder, runState) {
|
|
|
515
606
|
wait: () => queueChain,
|
|
516
607
|
};
|
|
517
608
|
}
|
|
518
|
-
function formatTimestampedUserMessage(message) {
|
|
519
|
-
const timestamp = formatLocalTimestamp(new Date());
|
|
520
|
-
const threadContext = message.threadTs ? ` [in-thread:${message.threadTs}]` : "";
|
|
521
|
-
return `[${timestamp}] [${message.userName || "unknown"}]${threadContext}: ${message.text}`;
|
|
522
|
-
}
|
|
523
|
-
function collectMessageAttachments(message, workspacePath, pathContext) {
|
|
524
|
-
const imageAttachments = [];
|
|
525
|
-
const nonImagePaths = [];
|
|
526
|
-
for (const attachment of message.attachments || []) {
|
|
527
|
-
const runtimePath = `${workspacePath}/${attachment.localPath}`;
|
|
528
|
-
const hostPath = pathContext?.runtimeToHostPath?.(runtimePath) ?? runtimePath;
|
|
529
|
-
const mimeType = getImageMimeType(attachment.localPath);
|
|
530
|
-
if (mimeType && existsSync(hostPath)) {
|
|
531
|
-
try {
|
|
532
|
-
imageAttachments.push({
|
|
533
|
-
type: "image",
|
|
534
|
-
mimeType,
|
|
535
|
-
data: readFileSync(hostPath).toString("base64"),
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
catch {
|
|
539
|
-
nonImagePaths.push(runtimePath);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
else {
|
|
543
|
-
nonImagePaths.push(runtimePath);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
return { imageAttachments, nonImagePaths };
|
|
547
|
-
}
|
|
548
|
-
export function buildPromptPayload(message, workspacePath, pathContext) {
|
|
549
|
-
let userMessage = formatTimestampedUserMessage(message);
|
|
550
|
-
const { imageAttachments, nonImagePaths } = collectMessageAttachments(message, workspacePath, pathContext);
|
|
551
|
-
if (nonImagePaths.length > 0) {
|
|
552
|
-
userMessage += `\n\n<slack_attachments>\n${nonImagePaths.join("\n")}\n</slack_attachments>`;
|
|
553
|
-
}
|
|
554
|
-
return { userMessage, imageAttachments };
|
|
555
|
-
}
|
|
556
|
-
async function writePromptDebugContext(conversationDir, systemPrompt, session, userMessage, imageAttachmentCount) {
|
|
557
|
-
const debugContext = {
|
|
558
|
-
systemPrompt,
|
|
559
|
-
messages: session.messages,
|
|
560
|
-
newUserMessage: userMessage,
|
|
561
|
-
imageAttachmentCount,
|
|
562
|
-
};
|
|
563
|
-
await writeFile(join(conversationDir, "last_prompt.jsonl"), JSON.stringify(debugContext, null, 2));
|
|
564
|
-
}
|
|
565
609
|
function getFinalAssistantText(session) {
|
|
566
610
|
const lastAssistant = session.messages.findLast((message) => message.role === "assistant");
|
|
567
611
|
return (lastAssistant?.content
|
|
@@ -569,21 +613,6 @@ function getFinalAssistantText(session) {
|
|
|
569
613
|
.map((content) => content.text)
|
|
570
614
|
.join("\n") || "");
|
|
571
615
|
}
|
|
572
|
-
export function appendTriggerAttribution(text, triggerAttribution, sessionLink) {
|
|
573
|
-
if (!triggerAttribution)
|
|
574
|
-
return text;
|
|
575
|
-
const trimmed = text.trimEnd();
|
|
576
|
-
const legacySuffix = `_Triggered by ${triggerAttribution}_`;
|
|
577
|
-
const suffix = sessionLink
|
|
578
|
-
? `_Triggered by ${triggerAttribution} · session: ${sessionLink}_`
|
|
579
|
-
: legacySuffix;
|
|
580
|
-
if (trimmed.endsWith(suffix))
|
|
581
|
-
return text;
|
|
582
|
-
const body = trimmed.endsWith(legacySuffix)
|
|
583
|
-
? trimmed.slice(0, -legacySuffix.length).trimEnd()
|
|
584
|
-
: trimmed;
|
|
585
|
-
return `${body}\n\n${suffix}`;
|
|
586
|
-
}
|
|
587
616
|
function isEventTriggerAttribution(triggerAttribution) {
|
|
588
617
|
return triggerAttribution?.startsWith("[event:") === true;
|
|
589
618
|
}
|
|
@@ -593,22 +622,86 @@ function extractToolLabel(toolName, args) {
|
|
|
593
622
|
return toolName;
|
|
594
623
|
return label.trim() || toolName;
|
|
595
624
|
}
|
|
625
|
+
/** Non-subagent tool activity lines; subagent calls render as the dashboard. */
|
|
596
626
|
function formatToolProgress(runState) {
|
|
597
|
-
const lines = Array.from(runState.toolProgress.
|
|
627
|
+
const lines = Array.from(runState.toolProgress.entries()).flatMap(([toolCallId, item]) => {
|
|
628
|
+
if (runState.subagentToolCalls.has(toolCallId))
|
|
629
|
+
return [];
|
|
598
630
|
const marker = item.status === "running" ? "•" : item.status === "error" ? "✗" : "✓";
|
|
599
|
-
return `${marker} ${item.label}
|
|
631
|
+
return [`${marker} ${item.label}`];
|
|
600
632
|
});
|
|
601
633
|
return lines.join("\n");
|
|
602
634
|
}
|
|
603
635
|
function formatResponseWithToolProgress(text, runState) {
|
|
604
636
|
const progress = formatToolProgress(runState);
|
|
605
|
-
return progress
|
|
637
|
+
return [progress, text].filter(Boolean).join("\n\n");
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* The one dashboard render path. A responder that overrides
|
|
641
|
+
* `replaceSubagentProgress` converts the snapshot for a pipeline that is not
|
|
642
|
+
* response-source Markdown (Telegram HTML); every other platform receives the
|
|
643
|
+
* Markdown dashboard — "dashboard, blank line, answer" — through
|
|
644
|
+
* `replaceResponse`, the same conversion as any response.
|
|
645
|
+
*/
|
|
646
|
+
async function replaceWithSubagentDashboard(responder, snapshot, finalText, options) {
|
|
647
|
+
if (responder.replaceSubagentProgress) {
|
|
648
|
+
await responder.replaceSubagentProgress(snapshot, finalText);
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
const dashboard = renderSubagentDashboard(snapshot);
|
|
652
|
+
await responder.replaceResponse(finalText ? `${dashboard}\n\n${finalText}` : dashboard, options);
|
|
606
653
|
}
|
|
607
|
-
async function replaceResponseWithToolProgress(responder, runState) {
|
|
654
|
+
async function replaceResponseWithToolProgress(responder, runState, subagentProgress = mergeSubagentProgress([...runState.subagentProgress.values()])) {
|
|
655
|
+
if (subagentProgress) {
|
|
656
|
+
await replaceWithSubagentDashboard(responder, subagentProgress);
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
608
659
|
const progress = formatToolProgress(runState);
|
|
609
660
|
if (progress)
|
|
610
661
|
await responder.replaceResponse(progress);
|
|
611
662
|
}
|
|
663
|
+
const TOOL_PROGRESS_DEBOUNCE_MS = 500;
|
|
664
|
+
const SUBAGENT_PROGRESS_THROTTLE_MS = 2000;
|
|
665
|
+
function subagentProgressDelay(runState) {
|
|
666
|
+
if (!runState.subagentProgressShown)
|
|
667
|
+
return 0;
|
|
668
|
+
return Math.max(0, runState.lastSubagentProgressAt + SUBAGENT_PROGRESS_THROTTLE_MS - Date.now());
|
|
669
|
+
}
|
|
670
|
+
function scheduleToolProgressUpdate(responder, runState) {
|
|
671
|
+
if (runState.toolProgressTimer)
|
|
672
|
+
return;
|
|
673
|
+
const subagentProgress = mergeSubagentProgress([...runState.subagentProgress.values()]);
|
|
674
|
+
const delay = subagentProgress ? subagentProgressDelay(runState) : TOOL_PROGRESS_DEBOUNCE_MS;
|
|
675
|
+
runState.toolProgressTimer = setTimeout(() => {
|
|
676
|
+
runState.toolProgressTimer = undefined;
|
|
677
|
+
const snapshot = mergeSubagentProgress([...runState.subagentProgress.values()]);
|
|
678
|
+
if (snapshot) {
|
|
679
|
+
runState.subagentProgressShown = true;
|
|
680
|
+
runState.lastSubagentProgressAt = Date.now();
|
|
681
|
+
}
|
|
682
|
+
runState.queue?.enqueue(() => replaceResponseWithToolProgress(responder, runState, snapshot), "tool progress update");
|
|
683
|
+
}, delay);
|
|
684
|
+
runState.toolProgressTimer.unref();
|
|
685
|
+
}
|
|
686
|
+
function flushToolProgressUpdate(responder, runState) {
|
|
687
|
+
if (runState.toolProgressTimer)
|
|
688
|
+
clearTimeout(runState.toolProgressTimer);
|
|
689
|
+
runState.toolProgressTimer = undefined;
|
|
690
|
+
const subagentProgress = mergeSubagentProgress([...runState.subagentProgress.values()]);
|
|
691
|
+
if (subagentProgress) {
|
|
692
|
+
runState.subagentProgressShown = true;
|
|
693
|
+
runState.lastSubagentProgressAt = Date.now();
|
|
694
|
+
}
|
|
695
|
+
runState.queue?.enqueue(() => replaceResponseWithToolProgress(responder, runState, subagentProgress), "tool progress update");
|
|
696
|
+
}
|
|
697
|
+
function extractSubagentProgress(partialResult) {
|
|
698
|
+
if (!partialResult || typeof partialResult !== "object")
|
|
699
|
+
return undefined;
|
|
700
|
+
const details = partialResult.details;
|
|
701
|
+
if (!details || typeof details !== "object")
|
|
702
|
+
return undefined;
|
|
703
|
+
return parseSubagentProgressSnapshot(details.progress);
|
|
704
|
+
}
|
|
612
705
|
async function finalizeRunResponse(responder, session, runState, options) {
|
|
613
706
|
if (runState.stopReason === "error" && runState.errorMessage) {
|
|
614
707
|
if (!runState.reportedLlmError) {
|
|
@@ -673,7 +766,17 @@ async function finalizeRunResponse(responder, session, runState, options) {
|
|
|
673
766
|
if (!finalText.trim())
|
|
674
767
|
return;
|
|
675
768
|
try {
|
|
676
|
-
|
|
769
|
+
const finalResponse = appendTriggerAttribution(finalText, options?.triggerAttribution, options?.triggerSessionLink);
|
|
770
|
+
const finalDashboard = mergeSubagentProgress(runState.completedSubagentProgress);
|
|
771
|
+
if (finalDashboard) {
|
|
772
|
+
await replaceWithSubagentDashboard(responder, finalDashboard, finalResponse, {
|
|
773
|
+
createOverflowLink: options?.createOverflowLink,
|
|
774
|
+
});
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
await responder.replaceResponse(formatResponseWithToolProgress(finalResponse, runState), {
|
|
778
|
+
createOverflowLink: options?.createOverflowLink,
|
|
779
|
+
});
|
|
677
780
|
}
|
|
678
781
|
catch (err) {
|
|
679
782
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -739,6 +842,215 @@ async function reportUsageSummary(ctx) {
|
|
|
739
842
|
await waitForQueue();
|
|
740
843
|
}
|
|
741
844
|
}
|
|
845
|
+
function extractToolResultText(result) {
|
|
846
|
+
if (typeof result === "string") {
|
|
847
|
+
return result;
|
|
848
|
+
}
|
|
849
|
+
if (result &&
|
|
850
|
+
typeof result === "object" &&
|
|
851
|
+
"content" in result &&
|
|
852
|
+
Array.isArray(result.content)) {
|
|
853
|
+
const content = result.content;
|
|
854
|
+
const textParts = [];
|
|
855
|
+
for (const part of content) {
|
|
856
|
+
if (part.type === "text" && part.text) {
|
|
857
|
+
textParts.push(part.text);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
if (textParts.length > 0) {
|
|
861
|
+
return textParts.join("\n");
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
return JSON.stringify(result);
|
|
865
|
+
}
|
|
866
|
+
function buildThreadSessionName(message) {
|
|
867
|
+
const text = message?.text?.trim();
|
|
868
|
+
if (!text)
|
|
869
|
+
return undefined;
|
|
870
|
+
const userLabel = message?.userName || message?.user || "unknown";
|
|
871
|
+
return `[${userLabel}]: ${text}`;
|
|
872
|
+
}
|
|
873
|
+
function createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner, workspaceDir, hostWorkspacePath) {
|
|
874
|
+
const executionResolver = vaultManager && sandboxConfig.type !== "host"
|
|
875
|
+
? new ActorExecutionResolver(sandboxConfig, vaultManager, provisioner, workspaceDir, hostWorkspacePath)
|
|
876
|
+
: undefined;
|
|
877
|
+
// activeExecutor is replaced at the start of each run() call when executionResolver
|
|
878
|
+
// is present, so the stable `executor` wrapper always delegates to the latest resolved value.
|
|
879
|
+
let activeExecutor = executionResolver !== undefined
|
|
880
|
+
? createExecutor({ type: "host" })
|
|
881
|
+
: createExecutor(sandboxConfig);
|
|
882
|
+
const executor = {
|
|
883
|
+
exec(command, options) {
|
|
884
|
+
return activeExecutor.exec(command, options);
|
|
885
|
+
},
|
|
886
|
+
readFile(path, options) {
|
|
887
|
+
return activeExecutor.readFile(path, options);
|
|
888
|
+
},
|
|
889
|
+
readFileBase64(path, options) {
|
|
890
|
+
return activeExecutor.readFileBase64(path, options);
|
|
891
|
+
},
|
|
892
|
+
readFileBase64NoSymlinks(path, options) {
|
|
893
|
+
if (!activeExecutor.readFileBase64NoSymlinks) {
|
|
894
|
+
throw new Error("Attachments are unavailable: this sandbox cannot guarantee symlink-free path traversal");
|
|
895
|
+
}
|
|
896
|
+
return activeExecutor.readFileBase64NoSymlinks(path, options);
|
|
897
|
+
},
|
|
898
|
+
writeFile(path, content, options) {
|
|
899
|
+
return activeExecutor.writeFile(path, content, options);
|
|
900
|
+
},
|
|
901
|
+
getWorkspacePath(hostPath) {
|
|
902
|
+
return activeExecutor.getWorkspacePath(hostPath);
|
|
903
|
+
},
|
|
904
|
+
getSandboxConfig() {
|
|
905
|
+
return activeExecutor.getSandboxConfig();
|
|
906
|
+
},
|
|
907
|
+
getPathContext(hostWorkspaceRoot) {
|
|
908
|
+
return activeExecutor.getPathContext(hostWorkspaceRoot);
|
|
909
|
+
},
|
|
910
|
+
};
|
|
911
|
+
return {
|
|
912
|
+
executionResolver,
|
|
913
|
+
executor,
|
|
914
|
+
getPathContext: () => executor.getPathContext(hostWorkspacePath),
|
|
915
|
+
async resolveExecutorForRun(context) {
|
|
916
|
+
if (!executionResolver)
|
|
917
|
+
return;
|
|
918
|
+
activeExecutor = await executionResolver.resolve(context);
|
|
919
|
+
},
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Extension host services over mikan's runtime infrastructure: schedules
|
|
924
|
+
* become event files under `<workspaceDir>/events` (picked up live by
|
|
925
|
+
* EventsWatcher), secrets come from `vaults/extensions/<slug>/env`, and
|
|
926
|
+
* notify posts through the platform bots when main.ts provides a notifier.
|
|
927
|
+
*/
|
|
928
|
+
function buildExtensionHostServices(params) {
|
|
929
|
+
const { workspaceDir, vaultManager, platformNotifier, platformReactor, platformUploader, platformBlockKit, runSubagentService, } = params;
|
|
930
|
+
const eventStore = HostEventStore.fromWorkspaceDir(workspaceDir);
|
|
931
|
+
return {
|
|
932
|
+
stateDir: effectiveStateDir(),
|
|
933
|
+
scheduleStore: {
|
|
934
|
+
write: async (filename, payload) => {
|
|
935
|
+
await eventStore.write(filename, payload);
|
|
936
|
+
},
|
|
937
|
+
delete: async (filename) => (await eventStore.delete(filename)).deleted,
|
|
938
|
+
list: async () => (await eventStore.list()).flatMap((entry) => entry.payload ? [{ filename: entry.filename, payload: entry.payload }] : []),
|
|
939
|
+
},
|
|
940
|
+
...(platformNotifier ? { postMessage: platformNotifier } : {}),
|
|
941
|
+
...(platformReactor ? { addReaction: platformReactor } : {}),
|
|
942
|
+
...(platformUploader ? { uploadFile: platformUploader } : {}),
|
|
943
|
+
...(platformBlockKit
|
|
944
|
+
? { postBlocks: platformBlockKit.postBlocks, updateBlocks: platformBlockKit.updateBlocks }
|
|
945
|
+
: {}),
|
|
946
|
+
...(runSubagentService ? { runSubagent: runSubagentService } : {}),
|
|
947
|
+
...(vaultManager
|
|
948
|
+
? {
|
|
949
|
+
resolveSecrets: (slug) => vaultManager.resolve(`extensions/${slug}`)?.env ?? {},
|
|
950
|
+
}
|
|
951
|
+
: {}),
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
async function createConfiguredAgentSession(params) {
|
|
955
|
+
const { conversationId, workspaceDir, systemPrompt, model, thinkingLevel, tools, sessionStore, models, vaultManager, platformNotifier, platformReactor, platformUploader, platformBlockKit, } = params;
|
|
956
|
+
// Host-only dirs under the state dir: extension code runs in the mikan
|
|
957
|
+
// process, so it must never load from workspace paths — those are mounted
|
|
958
|
+
// into sandbox containers and agent-writable (sandbox escape otherwise).
|
|
959
|
+
// resolveConversationPackages only ever returns state-dir paths (and host
|
|
960
|
+
// paths an administrator named explicitly in settings); it never reaches
|
|
961
|
+
// the network on this path, so a slow remote cannot delay a reply.
|
|
962
|
+
let session;
|
|
963
|
+
const loadedProfiles = loadSubagentProfiles(workspaceDir);
|
|
964
|
+
for (const diagnostic of loadedProfiles.diagnostics) {
|
|
965
|
+
log.logWarning(`[${conversationId}] Subagent profile ignored: ${diagnostic.path}`, diagnostic.message);
|
|
966
|
+
}
|
|
967
|
+
// Narrowed to the profiles whose tools actually exist once extensions have
|
|
968
|
+
// contributed theirs. Both subagent entry points read this at call time, so
|
|
969
|
+
// they always agree on which profiles are launchable.
|
|
970
|
+
let runnableSubagentProfiles = loadedProfiles.profiles;
|
|
971
|
+
const resolvedPackages = resolveConversationPackages({
|
|
972
|
+
conversationId,
|
|
973
|
+
stateDir: effectiveStateDir(),
|
|
974
|
+
conversationDir: join(workspaceDir, conversationId),
|
|
975
|
+
});
|
|
976
|
+
for (const error of resolvedPackages.errors) {
|
|
977
|
+
log.logWarning(`Package unavailable: ${error.source}`, error.message);
|
|
978
|
+
}
|
|
979
|
+
const extensionsResult = await loadExtensions({
|
|
980
|
+
dirs: resolvedPackages.extensionDirs,
|
|
981
|
+
roots: resolvedPackages.extensionRoots,
|
|
982
|
+
context: { conversationId, workspaceDir, model, thinkingLevel },
|
|
983
|
+
services: buildExtensionHostServices({
|
|
984
|
+
workspaceDir,
|
|
985
|
+
vaultManager,
|
|
986
|
+
platformNotifier,
|
|
987
|
+
platformReactor,
|
|
988
|
+
platformUploader,
|
|
989
|
+
platformBlockKit,
|
|
990
|
+
runSubagentService: (request, extensionTools) => {
|
|
991
|
+
const activeParent = session?.isActiveRun ? session : undefined;
|
|
992
|
+
return runSubagent({
|
|
993
|
+
request,
|
|
994
|
+
defaultModel: model,
|
|
995
|
+
thinkingLevel,
|
|
996
|
+
models,
|
|
997
|
+
workspaceDir,
|
|
998
|
+
availableTools: [...tools, ...extensionTools],
|
|
999
|
+
profiles: runnableSubagentProfiles,
|
|
1000
|
+
slots: globalSubagentSlots,
|
|
1001
|
+
...(activeParent
|
|
1002
|
+
? {
|
|
1003
|
+
parentMessages: [...activeParent.messages],
|
|
1004
|
+
onUsage: activeParent.captureExternalUsageSink(),
|
|
1005
|
+
}
|
|
1006
|
+
: {}),
|
|
1007
|
+
});
|
|
1008
|
+
},
|
|
1009
|
+
}),
|
|
1010
|
+
});
|
|
1011
|
+
const contributedTools = extensionsResult.registry.getContributedTools();
|
|
1012
|
+
const subagentAvailableTools = [...tools, ...contributedTools];
|
|
1013
|
+
const availableToolNames = new Set(subagentAvailableTools.map((tool) => tool.name));
|
|
1014
|
+
runnableSubagentProfiles = new Map([...loadedProfiles.profiles].filter(([, profile]) => profile.tools.every((tool) => availableToolNames.has(tool))));
|
|
1015
|
+
for (const err of extensionsResult.errors) {
|
|
1016
|
+
log.logWarning(`[${conversationId}] Extension load error: ${err.path}`, err.error);
|
|
1017
|
+
}
|
|
1018
|
+
if (extensionsResult.extensions.length > 0) {
|
|
1019
|
+
log.logInfo(`[${conversationId}] Loaded ${extensionsResult.extensions.length} extension(s): ${extensionsResult.extensions.map((extension) => extension.name).join(", ")}`);
|
|
1020
|
+
}
|
|
1021
|
+
const subagentTool = createSubagentTool((request) => runSubagent({
|
|
1022
|
+
request,
|
|
1023
|
+
defaultModel: model,
|
|
1024
|
+
thinkingLevel,
|
|
1025
|
+
models,
|
|
1026
|
+
workspaceDir,
|
|
1027
|
+
availableTools: subagentAvailableTools,
|
|
1028
|
+
profiles: runnableSubagentProfiles,
|
|
1029
|
+
slots: globalSubagentSlots,
|
|
1030
|
+
parentMessages: [...session.messages],
|
|
1031
|
+
onUsage: session.captureExternalUsageSink(),
|
|
1032
|
+
}), runnableSubagentProfiles);
|
|
1033
|
+
session = new MikanAgentSession({
|
|
1034
|
+
systemPrompt,
|
|
1035
|
+
model,
|
|
1036
|
+
thinkingLevel,
|
|
1037
|
+
tools: [...tools, subagentTool],
|
|
1038
|
+
models,
|
|
1039
|
+
sessionStore,
|
|
1040
|
+
extensions: extensionsResult.registry,
|
|
1041
|
+
});
|
|
1042
|
+
const activeSession = session;
|
|
1043
|
+
const reloaded = activeSession.reloadFromSession();
|
|
1044
|
+
if (reloaded > 0) {
|
|
1045
|
+
log.logInfo(`[${conversationId}] Reloaded ${reloaded} messages from session context`);
|
|
1046
|
+
}
|
|
1047
|
+
return {
|
|
1048
|
+
session: activeSession,
|
|
1049
|
+
extensionSkills: extensionsResult.skills,
|
|
1050
|
+
extensionRegistry: extensionsResult.registry,
|
|
1051
|
+
disposeExtensions: extensionsResult.dispose,
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
742
1054
|
function reloadSessionMessages(session, conversationId) {
|
|
743
1055
|
const reloaded = session.reloadFromSession();
|
|
744
1056
|
if (reloaded > 0) {
|
|
@@ -746,15 +1058,16 @@ function reloadSessionMessages(session, conversationId) {
|
|
|
746
1058
|
}
|
|
747
1059
|
}
|
|
748
1060
|
async function prepareRunContext(params) {
|
|
749
|
-
const { message, responder, platform, conversationId, conversationDir, sessionUuid, runState, executor, executionResolver, resolveExecutorForRun, getPathContext, session, setEventContext, setSandboxContext, setUploadFunction, } = params;
|
|
1061
|
+
const { message, responder, platform, conversationId, conversationDir, sessionUuid, runState, executor, executionResolver, resolveExecutorForRun, getPathContext, session, setEventContext, setSandboxContext, setUploadFunction, setReactFunction, bindPlatformToolPacks, } = params;
|
|
750
1062
|
let pathContext = params.pathContext;
|
|
751
|
-
const sessionConversation = message.sessionKey
|
|
1063
|
+
const sessionConversation = conversationIdOf(message.sessionKey);
|
|
752
1064
|
await mkdir(join(conversationDir, "scratch"), { recursive: true });
|
|
753
1065
|
if (executionResolver) {
|
|
754
1066
|
await resolveExecutorForRun({
|
|
755
1067
|
platform: platform.name,
|
|
756
1068
|
userId: message.userId,
|
|
757
1069
|
conversationId,
|
|
1070
|
+
trustModel: platform.trustModel,
|
|
758
1071
|
});
|
|
759
1072
|
pathContext = getPathContext();
|
|
760
1073
|
}
|
|
@@ -768,9 +1081,11 @@ async function prepareRunContext(params) {
|
|
|
768
1081
|
// provider prompt caching. If this hash changes between turns of one
|
|
769
1082
|
// conversation, something turn-varying leaked into the prompt; if it is
|
|
770
1083
|
// stable and cacheRead stays 0, the miss is provider-side (e.g. OpenRouter
|
|
771
|
-
// routing the model across upstream hosts).
|
|
1084
|
+
// routing the model across upstream hosts). This is the base prompt mikan
|
|
1085
|
+
// builds; a `before_agent_start` extension may still rewrite it per turn
|
|
1086
|
+
// (logged separately by the runner).
|
|
772
1087
|
const promptHash = createHash("sha256").update(systemPrompt).digest("hex").slice(0, 8);
|
|
773
|
-
log.logInfo(`[${conversationId}] System prompt: ${systemPrompt.length} chars, sha ${promptHash}`);
|
|
1088
|
+
log.logInfo(`[${conversationId}] System prompt (base): ${systemPrompt.length} chars, sha ${promptHash}`);
|
|
774
1089
|
setEventContext({
|
|
775
1090
|
platform: platform.name,
|
|
776
1091
|
conversationId,
|
|
@@ -779,18 +1094,30 @@ async function prepareRunContext(params) {
|
|
|
779
1094
|
});
|
|
780
1095
|
setSandboxContext({ conversationId, userId: message.userId });
|
|
781
1096
|
setUploadFunction(async (filePath, title) => {
|
|
782
|
-
const
|
|
783
|
-
await responder.uploadFile(
|
|
1097
|
+
const runtimePath = normalizeAttachRuntimePath(filePath, pathContext.runtimeWorkspaceRoot);
|
|
1098
|
+
await withStagedRuntimeFile(executor, runtimePath, (stagedPath) => responder.uploadFile(stagedPath, title));
|
|
1099
|
+
});
|
|
1100
|
+
// The react tool is available only when the responder supports reactions
|
|
1101
|
+
// (interactive turns on platforms with reaction support); otherwise unset
|
|
1102
|
+
// so the tool reports it is unavailable rather than silently no-op'ing.
|
|
1103
|
+
setReactFunction(responder.react ? async (emoji) => responder.react(emoji) : null);
|
|
1104
|
+
// Platform capability packs (e.g. GitHub PR/CI) enable themselves per run;
|
|
1105
|
+
// core does not branch on platform name here.
|
|
1106
|
+
bindPlatformToolPacks({
|
|
1107
|
+
conversationId,
|
|
1108
|
+
platformName: platform.name,
|
|
1109
|
+
threadTs: message.threadTs,
|
|
784
1110
|
});
|
|
785
1111
|
resetRunState(runState, responder, sessionConversation, message.userName, sessionUuid, triggerAttribution);
|
|
786
1112
|
const runQueue = createRunQueue(responder, runState);
|
|
787
1113
|
runState.queue = runQueue.queue;
|
|
788
1114
|
log.logInfo(`Context sizes - system: ${systemPrompt.length} chars, memory: ${memory.length} chars`);
|
|
789
1115
|
log.logInfo(`Channels: ${platform.channels.length}, Users: ${platform.users.length}`);
|
|
790
|
-
const { userMessage, imageAttachments } = buildPromptPayload(message, pathContext.runtimeWorkspaceRoot, pathContext
|
|
1116
|
+
const { userMessage, imageAttachments } = await buildPromptPayload(message, pathContext.runtimeWorkspaceRoot, pathContext, executor.readFileBase64NoSymlinks
|
|
1117
|
+
? (runtimePath) => executor.readFileBase64NoSymlinks(runtimePath)
|
|
1118
|
+
: undefined);
|
|
791
1119
|
const turnInstructions = buildTurnInstructions(message.id.startsWith("event:"), triggerAttribution, platform.name);
|
|
792
1120
|
const finalUserMessage = turnInstructions ? `${turnInstructions}\n\n${userMessage}` : userMessage;
|
|
793
|
-
await writePromptDebugContext(conversationDir, systemPrompt, session, finalUserMessage, imageAttachments.length);
|
|
794
1121
|
return {
|
|
795
1122
|
sessionConversation,
|
|
796
1123
|
runQueue,
|
|
@@ -800,6 +1127,63 @@ async function prepareRunContext(params) {
|
|
|
800
1127
|
pathContext,
|
|
801
1128
|
};
|
|
802
1129
|
}
|
|
1130
|
+
/**
|
|
1131
|
+
* The dream run reads a transcript in which the agent held its full tool set,
|
|
1132
|
+
* but `sessionDreamTools` has since narrowed it. Left to infer its grant from
|
|
1133
|
+
* the transcript, the model calls a tool it no longer holds and burns one of
|
|
1134
|
+
* its five turns on the failure — so the grant is stated, and derived from the
|
|
1135
|
+
* tools actually handed to the run rather than restated by hand.
|
|
1136
|
+
*/
|
|
1137
|
+
function sessionDreamPrompt(conversationMemoryPath, toolNames) {
|
|
1138
|
+
// read/edit/write are core tools, so an empty grant does not arise today;
|
|
1139
|
+
// the fallback only keeps this sentence coherent if that ever changes.
|
|
1140
|
+
const grant = toolNames.length === 0
|
|
1141
|
+
? "You have no tools in this run and cannot change memory. Say so and stop."
|
|
1142
|
+
: `Your tools this run: ${toolNames.join(", ")}. Nothing else will execute, including tools used earlier in this transcript. ${conversationMemoryPath} is the only path you may write.`;
|
|
1143
|
+
return [
|
|
1144
|
+
"Before this conversation is reset or rotated, preserve only durable information worth carrying into future sessions of this same conversation.",
|
|
1145
|
+
`Review the existing transcript and update only the conversation-specific MEMORY.md at ${conversationMemoryPath}.`,
|
|
1146
|
+
grant,
|
|
1147
|
+
"Do not modify the workspace-level global MEMORY.md. Information from one DM or channel must not be promoted into memory shared with other conversations by this maintenance run.",
|
|
1148
|
+
"Preserve durable decisions, preferences, facts, and ongoing work specific to this conversation. Preserve the concrete values and details needed to resume the work; do not replace them with abstract categories, summaries of retention rules, or statements that merely say a kind of information is durable. An explicit user statement that a fact, preference, or decision should persist is strong evidence that its exact content is worth preserving.",
|
|
1149
|
+
"Deduplicate against existing conversation memory. Do not preserve transient discussion, tool noise, secrets, speculative details, or test scaffolding. If there is nothing new worth preserving, make no changes. Do no unrelated work.",
|
|
1150
|
+
].join("\n");
|
|
1151
|
+
}
|
|
1152
|
+
const SESSION_DREAM_BUDGET = {
|
|
1153
|
+
maxDurationMs: 2 * 60 * 1000,
|
|
1154
|
+
maxLlmCalls: 5,
|
|
1155
|
+
maxCostUsd: 0.25,
|
|
1156
|
+
};
|
|
1157
|
+
function sessionDreamTools(tools, conversationMemoryPath) {
|
|
1158
|
+
return tools
|
|
1159
|
+
.filter((tool) => tool.name === "read" || tool.name === "edit" || tool.name === "write")
|
|
1160
|
+
.map((tool) => {
|
|
1161
|
+
if (tool.name === "read")
|
|
1162
|
+
return tool;
|
|
1163
|
+
return Object.assign({}, tool, {
|
|
1164
|
+
execute: async (...args) => {
|
|
1165
|
+
const params = args[1];
|
|
1166
|
+
if (params.path !== conversationMemoryPath) {
|
|
1167
|
+
throw new Error(`Session Dream may only modify ${conversationMemoryPath}`);
|
|
1168
|
+
}
|
|
1169
|
+
return tool.execute(...args);
|
|
1170
|
+
},
|
|
1171
|
+
});
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
async function noopResponderMethod() { }
|
|
1175
|
+
function createNoopResponder() {
|
|
1176
|
+
return {
|
|
1177
|
+
respond: noopResponderMethod,
|
|
1178
|
+
replaceResponse: noopResponderMethod,
|
|
1179
|
+
respondDiagnostic: noopResponderMethod,
|
|
1180
|
+
respondToolResult: noopResponderMethod,
|
|
1181
|
+
setTyping: noopResponderMethod,
|
|
1182
|
+
setWorking: noopResponderMethod,
|
|
1183
|
+
uploadFile: noopResponderMethod,
|
|
1184
|
+
deleteResponse: noopResponderMethod,
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
803
1187
|
function formatAgentActorName(userName, fallback) {
|
|
804
1188
|
return userName ? `DM:${userName}` : fallback;
|
|
805
1189
|
}
|
|
@@ -837,7 +1221,12 @@ function attachSessionEventHandlers(params) {
|
|
|
837
1221
|
label: extractToolLabel(event.toolName, event.args),
|
|
838
1222
|
status: "running",
|
|
839
1223
|
});
|
|
840
|
-
|
|
1224
|
+
if (event.toolName === "subagent") {
|
|
1225
|
+
runState.subagentToolCalls.add(event.toolCallId);
|
|
1226
|
+
}
|
|
1227
|
+
else {
|
|
1228
|
+
queue.enqueue(() => replaceResponseWithToolProgress(responder, runState), "tool progress update");
|
|
1229
|
+
}
|
|
841
1230
|
addLifecycleBreadcrumb("agent.tool.started", {
|
|
842
1231
|
tool: event.toolName,
|
|
843
1232
|
...baseAttrs,
|
|
@@ -845,6 +1234,16 @@ function attachSessionEventHandlers(params) {
|
|
|
845
1234
|
log.logToolStart(logCtx, event.toolName, label, event.args);
|
|
846
1235
|
return;
|
|
847
1236
|
}
|
|
1237
|
+
if (event.type === "tool_execution_update") {
|
|
1238
|
+
const subagentProgress = extractSubagentProgress(event.partialResult);
|
|
1239
|
+
if (subagentProgress) {
|
|
1240
|
+
runState.subagentProgress.set(event.toolCallId, subagentProgress);
|
|
1241
|
+
runState.subagentToolCalls.add(event.toolCallId);
|
|
1242
|
+
runState.suppressResponseDeltas = true;
|
|
1243
|
+
scheduleToolProgressUpdate(responder, runState);
|
|
1244
|
+
}
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
848
1247
|
if (event.type === "tool_execution_end") {
|
|
849
1248
|
const resultStr = extractToolResultText(event.result);
|
|
850
1249
|
const pending = pendingTools.get(event.toolCallId);
|
|
@@ -856,7 +1255,15 @@ function attachSessionEventHandlers(params) {
|
|
|
856
1255
|
const progress = runState.toolProgress.get(event.toolCallId);
|
|
857
1256
|
if (progress)
|
|
858
1257
|
progress.status = event.isError ? "error" : "done";
|
|
859
|
-
|
|
1258
|
+
const subagentProgress = runState.subagentProgress.get(event.toolCallId);
|
|
1259
|
+
if (subagentProgress) {
|
|
1260
|
+
runState.subagentProgress.set(event.toolCallId, settleSubagentProgress(subagentProgress, event.isError));
|
|
1261
|
+
}
|
|
1262
|
+
flushToolProgressUpdate(responder, runState);
|
|
1263
|
+
const completedProgress = runState.subagentProgress.get(event.toolCallId);
|
|
1264
|
+
if (completedProgress)
|
|
1265
|
+
runState.completedSubagentProgress.push(completedProgress);
|
|
1266
|
+
runState.subagentProgress.delete(event.toolCallId);
|
|
860
1267
|
pendingTools.delete(event.toolCallId);
|
|
861
1268
|
const durationMs = pending ? Date.now() - pending.startTime : 0;
|
|
862
1269
|
Sentry.metrics.count("agent.tool.calls", 1, {
|
|
@@ -884,6 +1291,9 @@ function attachSessionEventHandlers(params) {
|
|
|
884
1291
|
}
|
|
885
1292
|
else {
|
|
886
1293
|
log.logToolSuccess(logCtx, event.toolName, durationMs, resultStr);
|
|
1294
|
+
if (event.toolName === "slack_blockkit") {
|
|
1295
|
+
runState.finalResponseHandledByTool = true;
|
|
1296
|
+
}
|
|
887
1297
|
}
|
|
888
1298
|
return;
|
|
889
1299
|
}
|
|
@@ -913,7 +1323,7 @@ function attachSessionEventHandlers(params) {
|
|
|
913
1323
|
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
914
1324
|
event: { kind: "responseDelta", delta: assistantMessageEvent.delta },
|
|
915
1325
|
});
|
|
916
|
-
if (responder.appendResponseDelta) {
|
|
1326
|
+
if (responder.appendResponseDelta && !runState.suppressResponseDeltas) {
|
|
917
1327
|
queue.enqueue(async () => {
|
|
918
1328
|
await responder.appendResponseDelta?.(assistantMessageEvent.delta ?? "");
|
|
919
1329
|
}, "response delta");
|
|
@@ -1010,6 +1420,12 @@ function attachSessionEventHandlers(params) {
|
|
|
1010
1420
|
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
1011
1421
|
event: { kind: "turnEnd" },
|
|
1012
1422
|
});
|
|
1423
|
+
// A run that produced a subagent dashboard finalizes through it:
|
|
1424
|
+
// finalizeRunResponse renders "dashboard, blank line, answer", and a
|
|
1425
|
+
// finish here would first overwrite the dashboard with the bare
|
|
1426
|
+
// answer on every platform.
|
|
1427
|
+
if (runState.completedSubagentProgress.length > 0)
|
|
1428
|
+
return;
|
|
1013
1429
|
if (responder.finishResponse) {
|
|
1014
1430
|
queue.enqueue(async () => {
|
|
1015
1431
|
await responder.finishResponse?.(finalText);
|
|
@@ -1069,27 +1485,6 @@ function attachSessionEventHandlers(params) {
|
|
|
1069
1485
|
}
|
|
1070
1486
|
});
|
|
1071
1487
|
}
|
|
1072
|
-
function extractToolResultText(result) {
|
|
1073
|
-
if (typeof result === "string") {
|
|
1074
|
-
return result;
|
|
1075
|
-
}
|
|
1076
|
-
if (result &&
|
|
1077
|
-
typeof result === "object" &&
|
|
1078
|
-
"content" in result &&
|
|
1079
|
-
Array.isArray(result.content)) {
|
|
1080
|
-
const content = result.content;
|
|
1081
|
-
const textParts = [];
|
|
1082
|
-
for (const part of content) {
|
|
1083
|
-
if (part.type === "text" && part.text) {
|
|
1084
|
-
textParts.push(part.text);
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
if (textParts.length > 0) {
|
|
1088
|
-
return textParts.join("\n");
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
return JSON.stringify(result);
|
|
1092
|
-
}
|
|
1093
1488
|
/**
|
|
1094
1489
|
* Create a new PiAgentWrapper for a channel.
|
|
1095
1490
|
* Sets up the session and subscribes to events once.
|
|
@@ -1097,18 +1492,22 @@ function extractToolResultText(result) {
|
|
|
1097
1492
|
* Runner caching is handled by the caller (channelStates in main.ts).
|
|
1098
1493
|
* This is a stateless factory function.
|
|
1099
1494
|
*/
|
|
1100
|
-
export async function createRunner(
|
|
1495
|
+
export async function createRunner(options) {
|
|
1496
|
+
const { sandboxConfig, sessionKey, conversationId, conversationDir, workspaceDir, sessionScope, vaultManager, provisioner, resourceController, sessionView, platformNotifier, platformReactor, platformUploader, platformBlockKit, platformToolPackFactories, } = options;
|
|
1101
1497
|
const agentConfig = resolveConversationSettings(conversationDir);
|
|
1102
1498
|
const workspaceBase = join(conversationDir, "..");
|
|
1103
1499
|
const { executionResolver, executor, getPathContext, resolveExecutorForRun } = createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner, workspaceDir, workspaceBase);
|
|
1104
1500
|
let pathContext = getUnresolvedSandboxPathContext(sandboxConfig, workspaceBase);
|
|
1105
|
-
|
|
1106
|
-
const { tools, setUploadFunction, setEventContext, setSandboxContext } = createMikanTools(executor, workspaceDir, { sandbox: sandboxConfig, provisioner });
|
|
1107
|
-
const modelRegistry = MikanModels.create();
|
|
1501
|
+
const modelRegistry = options.models ?? MikanModels.create();
|
|
1108
1502
|
if (modelRegistry.getError()) {
|
|
1109
1503
|
log.logWarning("models.json load error", modelRegistry.getError());
|
|
1110
1504
|
}
|
|
1111
|
-
const model =
|
|
1505
|
+
const model = modelRegistry.resolve(agentConfig.provider, agentConfig.model);
|
|
1506
|
+
// Create tools (per-runner, with per-runner upload function setter)
|
|
1507
|
+
const { tools, setUploadFunction, setReactFunction, bindPlatformToolPacks, setEventContext, setSandboxContext, } = createMikanTools(executor, workspaceDir, { sandbox: sandboxConfig, resourceController: resourceController ?? provisioner }, platformToolPackFactories ?? [], {
|
|
1508
|
+
model,
|
|
1509
|
+
getApiKey: () => modelRegistry.getApiKeyForProvider(model.provider),
|
|
1510
|
+
});
|
|
1112
1511
|
// Initial system prompt (will be updated each run with fresh memory/channels/users/skills)
|
|
1113
1512
|
const memory = await getMemory(conversationDir);
|
|
1114
1513
|
const skills = loadMikanSkills(conversationDir, pathContext.runtimeWorkspaceRoot);
|
|
@@ -1117,12 +1516,13 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1117
1516
|
formattingGuide: "",
|
|
1118
1517
|
channels: [],
|
|
1119
1518
|
users: [],
|
|
1519
|
+
trustModel: "membership",
|
|
1120
1520
|
};
|
|
1121
1521
|
const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot, conversationId, "shared", undefined, memory, sandboxConfig, emptyPlatform, skills);
|
|
1122
1522
|
// Create session manager and settings manager. Top-level/private sessions
|
|
1123
1523
|
// use the conversation's current pointer; scoped sessions use fixed files.
|
|
1124
1524
|
// Platform-specific scope behavior is resolved before runner creation.
|
|
1125
|
-
const isThread = sessionKey
|
|
1525
|
+
const isThread = isThreadSessionKey(sessionKey);
|
|
1126
1526
|
const { contextFile, threadRootMessage } = sessionScope;
|
|
1127
1527
|
const sessionManager = openManagedSession(contextFile, pathContext.runtimeWorkspaceRoot);
|
|
1128
1528
|
const threadSessionName = buildThreadSessionName(threadRootMessage);
|
|
@@ -1130,8 +1530,8 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1130
1530
|
sessionManager.appendSessionInfo(threadSessionName);
|
|
1131
1531
|
}
|
|
1132
1532
|
const sessionUuid = extractSessionUuid(contextFile);
|
|
1133
|
-
const chatSessionManager = new
|
|
1134
|
-
const { session, extensionSkills } = await createConfiguredAgentSession({
|
|
1533
|
+
const chatSessionManager = new ChatHistorySync();
|
|
1534
|
+
const { session, extensionSkills, extensionRegistry, disposeExtensions } = await createConfiguredAgentSession({
|
|
1135
1535
|
conversationId,
|
|
1136
1536
|
workspaceDir,
|
|
1137
1537
|
systemPrompt,
|
|
@@ -1142,6 +1542,9 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1142
1542
|
models: modelRegistry,
|
|
1143
1543
|
vaultManager,
|
|
1144
1544
|
platformNotifier,
|
|
1545
|
+
platformReactor,
|
|
1546
|
+
platformUploader,
|
|
1547
|
+
platformBlockKit,
|
|
1145
1548
|
});
|
|
1146
1549
|
// Mutable per-run state - event handler references this
|
|
1147
1550
|
const runState = createRunState();
|
|
@@ -1173,6 +1576,8 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1173
1576
|
setEventContext,
|
|
1174
1577
|
setSandboxContext,
|
|
1175
1578
|
setUploadFunction,
|
|
1579
|
+
setReactFunction,
|
|
1580
|
+
bindPlatformToolPacks,
|
|
1176
1581
|
pathContext,
|
|
1177
1582
|
});
|
|
1178
1583
|
pathContext = prepared.pathContext;
|
|
@@ -1201,10 +1606,39 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1201
1606
|
// Autonomous (event/trigger) runs get an explicit resource ceiling since
|
|
1202
1607
|
// no human is watching the loop; interactive turns stay human-gated.
|
|
1203
1608
|
const isEventRun = message.id.startsWith("event:");
|
|
1204
|
-
|
|
1609
|
+
// Event runs have no triggering platform message, so identity fields
|
|
1610
|
+
// stay unset and extensions must null-check them.
|
|
1611
|
+
const origin = isEventRun
|
|
1612
|
+
? { kind: "event", platform: platform.name }
|
|
1613
|
+
: {
|
|
1614
|
+
kind: "interactive",
|
|
1615
|
+
platform: platform.name,
|
|
1616
|
+
messageTs: message.id,
|
|
1617
|
+
userId: message.userId,
|
|
1618
|
+
userName: message.userName,
|
|
1619
|
+
threadTs: message.threadTs,
|
|
1620
|
+
attachments: message.attachments,
|
|
1621
|
+
};
|
|
1622
|
+
const outcome = await session.prompt(prepared.userMessage, {
|
|
1623
|
+
origin,
|
|
1205
1624
|
...(prepared.imageAttachments.length > 0 ? { images: prepared.imageAttachments } : {}),
|
|
1206
1625
|
...(isEventRun ? { budget: DEFAULT_EVENT_BUDGET } : {}),
|
|
1207
1626
|
});
|
|
1627
|
+
if (outcome?.blocked) {
|
|
1628
|
+
const text = outcome.reason
|
|
1629
|
+
? `_Turn blocked by an extension: ${outcome.reason}_`
|
|
1630
|
+
: "_Turn blocked by an extension._";
|
|
1631
|
+
sendAgentEvent({
|
|
1632
|
+
sessionId: sessionUuid,
|
|
1633
|
+
actorName: formatAgentActorName(message.userName, prepared.sessionConversation),
|
|
1634
|
+
event: { kind: "diagnostic", text },
|
|
1635
|
+
});
|
|
1636
|
+
await responder.respondDiagnostic(text, { style: "muted" });
|
|
1637
|
+
runState.responder = null;
|
|
1638
|
+
runState.logCtx = null;
|
|
1639
|
+
runState.queue = null;
|
|
1640
|
+
return { stopReason: "blocked" };
|
|
1641
|
+
}
|
|
1208
1642
|
// Wait for queued messages
|
|
1209
1643
|
await prepared.runQueue.wait();
|
|
1210
1644
|
const sessionViewTokenStore = sessionView?.tokenStore;
|
|
@@ -1247,9 +1681,86 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1247
1681
|
runState.queue = null;
|
|
1248
1682
|
return { stopReason: runState.stopReason, errorMessage: runState.errorMessage };
|
|
1249
1683
|
},
|
|
1684
|
+
async dreamSessionMemory(message, platform) {
|
|
1685
|
+
const responder = createNoopResponder();
|
|
1686
|
+
const prepared = await prepareRunContext({
|
|
1687
|
+
message,
|
|
1688
|
+
responder,
|
|
1689
|
+
platform,
|
|
1690
|
+
conversationId,
|
|
1691
|
+
conversationDir,
|
|
1692
|
+
sessionUuid,
|
|
1693
|
+
runState,
|
|
1694
|
+
executor,
|
|
1695
|
+
executionResolver,
|
|
1696
|
+
resolveExecutorForRun,
|
|
1697
|
+
getPathContext,
|
|
1698
|
+
session,
|
|
1699
|
+
extensionSkills,
|
|
1700
|
+
setEventContext,
|
|
1701
|
+
setSandboxContext,
|
|
1702
|
+
setUploadFunction,
|
|
1703
|
+
setReactFunction,
|
|
1704
|
+
bindPlatformToolPacks,
|
|
1705
|
+
pathContext,
|
|
1706
|
+
});
|
|
1707
|
+
pathContext = prepared.pathContext;
|
|
1708
|
+
try {
|
|
1709
|
+
const conversationMemoryPath = posix.join(prepared.pathContext.runtimeWorkspaceRoot, conversationId, "MEMORY.md");
|
|
1710
|
+
const dreamTools = sessionDreamTools(session.agent.state.tools, conversationMemoryPath);
|
|
1711
|
+
const outcome = await session.prompt(sessionDreamPrompt(conversationMemoryPath, dreamTools.map((tool) => tool.name)), {
|
|
1712
|
+
origin: {
|
|
1713
|
+
kind: "interactive",
|
|
1714
|
+
platform: platform.name,
|
|
1715
|
+
messageTs: message.id,
|
|
1716
|
+
userId: message.userId,
|
|
1717
|
+
userName: message.userName,
|
|
1718
|
+
threadTs: message.threadTs,
|
|
1719
|
+
attachments: message.attachments,
|
|
1720
|
+
},
|
|
1721
|
+
budget: SESSION_DREAM_BUDGET,
|
|
1722
|
+
tools: dreamTools,
|
|
1723
|
+
});
|
|
1724
|
+
if (outcome?.blocked) {
|
|
1725
|
+
return { stopReason: "blocked", errorMessage: outcome.reason };
|
|
1726
|
+
}
|
|
1727
|
+
await prepared.runQueue.wait();
|
|
1728
|
+
// A budget abort carries its reason in the tally, not in errorMessage,
|
|
1729
|
+
// and that reason is the only thing that tells the user why memory was
|
|
1730
|
+
// not preserved.
|
|
1731
|
+
return {
|
|
1732
|
+
stopReason: runState.stopReason,
|
|
1733
|
+
errorMessage: runState.errorMessage ?? session.getLastRunStats().budgetExceededReason,
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
finally {
|
|
1737
|
+
runState.responder = null;
|
|
1738
|
+
runState.logCtx = null;
|
|
1739
|
+
runState.queue = null;
|
|
1740
|
+
}
|
|
1741
|
+
},
|
|
1250
1742
|
abort() {
|
|
1251
1743
|
session.abort();
|
|
1252
1744
|
},
|
|
1745
|
+
async tryExtensionCommand(message, responder) {
|
|
1746
|
+
const parsed = parseCommandInput(message.text);
|
|
1747
|
+
if (!parsed)
|
|
1748
|
+
return false;
|
|
1749
|
+
return extensionRegistry.dispatchCommand(parsed.name, {
|
|
1750
|
+
args: parsed.args,
|
|
1751
|
+
conversationId,
|
|
1752
|
+
userId: message.userId,
|
|
1753
|
+
userName: message.userName,
|
|
1754
|
+
threadTs: message.threadTs,
|
|
1755
|
+
respond: (text) => responder.respond(text),
|
|
1756
|
+
});
|
|
1757
|
+
},
|
|
1758
|
+
async tryExtensionAction(slug, action) {
|
|
1759
|
+
return extensionRegistry.dispatchAction(slug, action);
|
|
1760
|
+
},
|
|
1761
|
+
async dispose() {
|
|
1762
|
+
await disposeExtensions();
|
|
1763
|
+
},
|
|
1253
1764
|
getCurrentStep() {
|
|
1254
1765
|
const pending = runState.pendingTools;
|
|
1255
1766
|
if (pending.size === 0)
|
|
@@ -1265,13 +1776,4 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1265
1776
|
},
|
|
1266
1777
|
};
|
|
1267
1778
|
}
|
|
1268
|
-
export function translateRuntimePathToHost(runtimePath, pathContext) {
|
|
1269
|
-
return pathContext.runtimeToHostPath?.(runtimePath) ?? runtimePath;
|
|
1270
|
-
}
|
|
1271
|
-
export function translateAttachPathToHost(filePath, pathContext) {
|
|
1272
|
-
const runtimePath = posix.isAbsolute(filePath)
|
|
1273
|
-
? filePath
|
|
1274
|
-
: posix.join(pathContext.runtimeWorkspaceRoot, filePath);
|
|
1275
|
-
return translateRuntimePathToHost(runtimePath, pathContext);
|
|
1276
|
-
}
|
|
1277
1779
|
//# sourceMappingURL=agent.js.map
|