@geminixiang/mikan 1.0.0-beta.4 → 1.0.0-beta.41
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 +714 -0
- package/README.md +99 -36
- package/dist/adapter.d.ts +11 -1
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +18 -1
- package/dist/adapter.js.map +1 -1
- package/dist/adapters/discord/bot.d.ts +6 -7
- package/dist/adapters/discord/bot.d.ts.map +1 -1
- package/dist/adapters/discord/bot.js +88 -122
- package/dist/adapters/discord/bot.js.map +1 -1
- package/dist/adapters/discord/components.d.ts +33 -0
- package/dist/adapters/discord/components.d.ts.map +1 -0
- package/dist/adapters/discord/components.js +32 -0
- package/dist/adapters/discord/components.js.map +1 -0
- package/dist/adapters/discord/context.d.ts +3 -1
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +66 -217
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/discord/format.d.ts +3 -0
- package/dist/adapters/discord/format.d.ts.map +1 -0
- package/dist/adapters/discord/format.js +86 -0
- package/dist/adapters/discord/format.js.map +1 -0
- package/dist/adapters/github/bot.d.ts +89 -0
- package/dist/adapters/github/bot.d.ts.map +1 -0
- package/dist/adapters/github/bot.js +653 -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 +12 -0
- package/dist/adapters/github/context.d.ts.map +1 -0
- package/dist/adapters/github/context.js +101 -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 +91 -0
- package/dist/adapters/github/github-ops.d.ts.map +1 -0
- package/dist/adapters/github/github-ops.js +406 -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 +57 -0
- package/dist/adapters/github/ids.js.map +1 -0
- package/dist/adapters/github/repo.d.ts +33 -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 +373 -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 +86 -23
- package/dist/adapters/intake.js.map +1 -1
- package/dist/adapters/markdown-tables.d.ts +37 -0
- package/dist/adapters/markdown-tables.d.ts.map +1 -0
- package/dist/adapters/markdown-tables.js +164 -0
- package/dist/adapters/markdown-tables.js.map +1 -0
- 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 +440 -0
- package/dist/adapters/progressive-renderer.js.map +1 -0
- package/dist/adapters/shared.d.ts +23 -10
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/shared.js +60 -22
- package/dist/adapters/shared.js.map +1 -1
- package/dist/adapters/slack/assistant.d.ts +101 -0
- package/dist/adapters/slack/assistant.d.ts.map +1 -0
- package/dist/adapters/slack/assistant.js +204 -0
- package/dist/adapters/slack/assistant.js.map +1 -0
- package/dist/adapters/slack/blocks.d.ts +14 -0
- package/dist/adapters/slack/blocks.d.ts.map +1 -1
- package/dist/adapters/slack/blocks.js +105 -147
- package/dist/adapters/slack/blocks.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +95 -13
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +545 -211
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/context.d.ts +3 -1
- package/dist/adapters/slack/context.d.ts.map +1 -1
- package/dist/adapters/slack/context.js +11 -17
- 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 +197 -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 +7 -11
- package/dist/adapters/slack/session.js.map +1 -1
- package/dist/adapters/slack/stream-limits.d.ts +35 -0
- package/dist/adapters/slack/stream-limits.d.ts.map +1 -0
- package/dist/adapters/slack/stream-limits.js +56 -0
- package/dist/adapters/slack/stream-limits.js.map +1 -0
- 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/attach.js +1 -1
- package/dist/adapters/slack/tools/attach.js.map +1 -1
- 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 +40 -2
- 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 +8 -9
- package/dist/adapters/telegram/bot.d.ts.map +1 -1
- package/dist/adapters/telegram/bot.js +115 -163
- package/dist/adapters/telegram/bot.js.map +1 -1
- package/dist/adapters/telegram/context.d.ts +2 -0
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +53 -188
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/adapters/types.d.ts +132 -12
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/agent-events.d.ts +3 -2
- package/dist/agent-events.d.ts.map +1 -1
- package/dist/agent-events.js +19 -1
- package/dist/agent-events.js.map +1 -1
- package/dist/agent.d.ts +14 -19
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +841 -298
- 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 +61 -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 +117 -0
- package/dist/cli/boot.js.map +1 -0
- package/dist/cli/download.d.ts.map +1 -0
- package/dist/{download.js → cli/download.js} +2 -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 +188 -0
- package/dist/cli/ext-dev.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 +324 -0
- package/dist/cli/ext.js.map +1 -0
- package/dist/cli/office.d.ts +2 -0
- package/dist/cli/office.d.ts.map +1 -0
- package/dist/cli/office.js +91 -0
- package/dist/cli/office.js.map +1 -0
- package/dist/cli/types.d.ts +16 -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 +3 -2
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/auto-reply.d.ts.map +1 -1
- package/dist/commands/auto-reply.js +5 -9
- package/dist/commands/auto-reply.js.map +1 -1
- package/dist/commands/extensions.d.ts +18 -6
- package/dist/commands/extensions.d.ts.map +1 -1
- package/dist/commands/extensions.js +64 -14
- 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 +40 -5
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/manifest.d.ts +37 -0
- package/dist/commands/manifest.d.ts.map +1 -0
- package/dist/commands/manifest.js +151 -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 +63 -24
- package/dist/commands/model.js.map +1 -1
- package/dist/commands/new.d.ts.map +1 -1
- package/dist/commands/new.js +15 -3
- 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 +83 -33
- package/dist/commands/sandbox.js.map +1 -1
- package/dist/commands/session-view.d.ts.map +1 -1
- package/dist/commands/session-view.js +6 -3
- package/dist/commands/session-view.js.map +1 -1
- package/dist/commands/types.d.ts +79 -7
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js.map +1 -1
- package/dist/config.d.ts +23 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +222 -135
- package/dist/config.js.map +1 -1
- package/dist/env-manifest.d.ts +30 -0
- package/dist/env-manifest.d.ts.map +1 -0
- package/dist/env-manifest.js +233 -0
- package/dist/env-manifest.js.map +1 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +20 -81
- package/dist/events.js.map +1 -1
- package/dist/execution-resolver.d.ts +7 -8
- package/dist/execution-resolver.d.ts.map +1 -1
- package/dist/execution-resolver.js +106 -110
- package/dist/execution-resolver.js.map +1 -1
- package/dist/extension-schedules.d.ts +31 -0
- package/dist/extension-schedules.d.ts.map +1 -0
- package/dist/extension-schedules.js +229 -0
- package/dist/extension-schedules.js.map +1 -0
- package/dist/harness/auth.d.ts +2 -1
- package/dist/harness/auth.d.ts.map +1 -1
- package/dist/harness/auth.js +11 -5
- package/dist/harness/auth.js.map +1 -1
- package/dist/harness/event-format.d.ts +27 -0
- package/dist/harness/event-format.d.ts.map +1 -0
- package/dist/harness/event-format.js +160 -0
- package/dist/harness/event-format.js.map +1 -0
- package/dist/harness/extensions/loader.d.ts +27 -49
- package/dist/harness/extensions/loader.d.ts.map +1 -1
- package/dist/harness/extensions/loader.js +486 -130
- package/dist/harness/extensions/loader.js.map +1 -1
- package/dist/harness/extensions/registry.d.ts +107 -2
- package/dist/harness/extensions/registry.d.ts.map +1 -1
- package/dist/harness/extensions/registry.js +316 -0
- package/dist/harness/extensions/registry.js.map +1 -1
- package/dist/harness/extensions/types.d.ts +482 -42
- 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 +46 -24
- 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 +232 -46
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/session-store.d.ts +11 -5
- package/dist/harness/session-store.d.ts.map +1 -1
- package/dist/harness/session-store.js +141 -36
- 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 +12 -1
- package/dist/harness/settings.js.map +1 -1
- package/dist/harness/skills.d.ts +10 -29
- package/dist/harness/skills.d.ts.map +1 -1
- package/dist/harness/skills.js +48 -6
- 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 +299 -0
- package/dist/harness/subagent-profiles.js.map +1 -0
- package/dist/harness/subagent-runner.d.ts +45 -0
- package/dist/harness/subagent-runner.d.ts.map +1 -0
- package/dist/harness/subagent-runner.js +680 -0
- package/dist/harness/subagent-runner.js.map +1 -0
- package/dist/harness/types.d.ts +267 -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 +36 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -6
- package/dist/index.js.map +1 -1
- package/dist/main.js +391 -127
- package/dist/main.js.map +1 -1
- package/dist/observability/instrument.js +7 -5
- package/dist/observability/instrument.js.map +1 -1
- package/dist/observability/sentry.d.ts +2 -0
- package/dist/observability/sentry.d.ts.map +1 -1
- package/dist/observability/sentry.js +10 -2
- package/dist/observability/sentry.js.map +1 -1
- package/dist/office/address.d.ts +31 -0
- package/dist/office/address.d.ts.map +1 -0
- package/dist/office/address.js +113 -0
- package/dist/office/address.js.map +1 -0
- package/dist/office/index.d.ts +11 -0
- package/dist/office/index.d.ts.map +1 -0
- package/dist/office/index.js +11 -0
- package/dist/office/index.js.map +1 -0
- package/dist/office/layout.d.ts +27 -0
- package/dist/office/layout.d.ts.map +1 -0
- package/dist/office/layout.js +97 -0
- package/dist/office/layout.js.map +1 -0
- package/dist/office/migration.d.ts +44 -0
- package/dist/office/migration.d.ts.map +1 -0
- package/dist/office/migration.js +255 -0
- package/dist/office/migration.js.map +1 -0
- package/dist/office/registry.d.ts +75 -0
- package/dist/office/registry.d.ts.map +1 -0
- package/dist/office/registry.js +646 -0
- package/dist/office/registry.js.map +1 -0
- package/dist/office/types.d.ts +71 -0
- package/dist/office/types.d.ts.map +1 -0
- package/dist/office/types.js +2 -0
- package/dist/office/types.js.map +1 -0
- package/dist/packages/admin.d.ts +17 -0
- package/dist/packages/admin.d.ts.map +1 -0
- package/dist/packages/admin.js +98 -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 +98 -0
- package/dist/packages/inspect.js.map +1 -0
- package/dist/packages/materialize.d.ts +40 -0
- package/dist/packages/materialize.d.ts.map +1 -0
- package/dist/packages/materialize.js +297 -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 +208 -0
- package/dist/packages/resolve.js.map +1 -0
- package/dist/packages/source.d.ts +39 -0
- package/dist/packages/source.d.ts.map +1 -0
- package/dist/packages/source.js +189 -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 +66 -0
- package/dist/provisioner.d.ts.map +1 -1
- package/dist/provisioner.js +335 -13
- 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 +562 -118
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/session-lifecycle.d.ts +38 -0
- package/dist/runtime/session-lifecycle.d.ts.map +1 -0
- package/dist/runtime/session-lifecycle.js +193 -0
- package/dist/runtime/session-lifecycle.js.map +1 -0
- package/dist/runtime/types.d.ts +66 -7
- 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 +13 -1
- 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 +13 -3
- 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 +13 -2
- 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 +3 -0
- package/dist/sandbox/host.d.ts.map +1 -1
- package/dist/sandbox/host.js +18 -3
- package/dist/sandbox/host.js.map +1 -1
- package/dist/sandbox/identity.d.ts +44 -0
- package/dist/sandbox/identity.d.ts.map +1 -0
- package/dist/sandbox/identity.js +68 -0
- package/dist/sandbox/identity.js.map +1 -0
- package/dist/sandbox/image.d.ts.map +1 -1
- package/dist/sandbox/image.js +2 -0
- package/dist/sandbox/image.js.map +1 -1
- package/dist/sandbox/index.d.ts +17 -4
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +37 -3
- package/dist/sandbox/index.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 +14 -0
- package/dist/sandbox/utils.d.ts.map +1 -1
- package/dist/sandbox/utils.js +68 -1
- 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} +135 -131
- 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 +50 -0
- package/dist/sessions/conversation-log.js.map +1 -0
- package/dist/sessions/history-line.d.ts +29 -0
- package/dist/sessions/history-line.d.ts.map +1 -0
- package/dist/sessions/history-line.js +45 -0
- package/dist/sessions/history-line.js.map +1 -0
- 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 +33 -0
- package/dist/sessions/session-key.d.ts.map +1 -0
- package/dist/sessions/session-key.js +115 -0
- package/dist/sessions/session-key.js.map +1 -0
- package/dist/sessions/store.d.ts +15 -7
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +127 -36
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/types.d.ts +19 -5
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js.map +1 -1
- package/dist/settings-mutation.d.ts +40 -0
- package/dist/settings-mutation.d.ts.map +1 -0
- package/dist/settings-mutation.js +61 -0
- package/dist/settings-mutation.js.map +1 -0
- package/dist/subagent-progress.d.ts +39 -0
- package/dist/subagent-progress.d.ts.map +1 -0
- package/dist/subagent-progress.js +225 -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 +26 -18
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +14 -13
- 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 +58 -45
- package/dist/tools/event.js.map +1 -1
- package/dist/tools/generate-image.d.ts +23 -0
- package/dist/tools/generate-image.d.ts.map +1 -0
- package/dist/tools/generate-image.js +65 -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 +19 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +25 -2
- 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 +39 -33
- 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 +61 -0
- package/dist/tools/subagent.d.ts.map +1 -0
- package/dist/tools/subagent.js +434 -0
- package/dist/tools/subagent.js.map +1 -0
- package/dist/tools/types.d.ts +40 -32
- 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 +2 -1
- package/dist/trigger.d.ts.map +1 -1
- package/dist/trigger.js +6 -9
- package/dist/trigger.js.map +1 -1
- package/dist/types.d.ts +411 -59
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -2
- package/dist/types.js.map +1 -1
- package/dist/utils/file-guards.d.ts +9 -0
- package/dist/utils/file-guards.d.ts.map +1 -1
- package/dist/utils/file-guards.js +44 -1
- package/dist/utils/file-guards.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 +25 -0
- package/dist/vault/disabled.js.map +1 -0
- package/dist/vault/index.d.ts +45 -2
- package/dist/vault/index.d.ts.map +1 -1
- package/dist/vault/index.js +127 -36
- package/dist/vault/index.js.map +1 -1
- package/dist/vault/types.d.ts +6 -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 +31 -3
- package/dist/web/admin/portal.d.ts.map +1 -1
- package/dist/web/admin/portal.js +850 -345
- package/dist/web/admin/portal.js.map +1 -1
- package/dist/web/admin/provider-models.js +1 -1
- package/dist/web/admin/provider-models.js.map +1 -1
- package/dist/web/admin/types.d.ts +23 -3
- package/dist/web/admin/types.d.ts.map +1 -1
- package/dist/web/admin/types.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 +1 -32
- package/dist/web/login/oauth.js.map +1 -1
- package/dist/web/login/portal.d.ts +1 -1
- package/dist/web/login/portal.d.ts.map +1 -1
- package/dist/web/login/portal.js +13 -36
- 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 +21 -0
- package/dist/web/portal-shell.d.ts.map +1 -0
- package/dist/{portal-shell.js → web/portal-shell.js} +67 -2
- package/dist/web/portal-shell.js.map +1 -0
- package/dist/web/server.d.ts +3 -2
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +11 -4
- package/dist/web/server.js.map +1 -1
- package/dist/web/session-view/portal.d.ts +1 -1
- package/dist/web/session-view/portal.d.ts.map +1 -1
- package/dist/web/session-view/portal.js +37 -28
- package/dist/web/session-view/portal.js.map +1 -1
- package/dist/web/session-view/service.d.ts +1 -1
- package/dist/web/session-view/service.d.ts.map +1 -1
- package/dist/web/session-view/service.js +61 -18
- package/dist/web/session-view/service.js.map +1 -1
- package/dist/web/session-view/types.d.ts +0 -3
- package/dist/web/session-view/types.d.ts.map +1 -1
- package/dist/web/session-view/types.js.map +1 -1
- package/dist/web/token-store.js +1 -1
- package/dist/web/token-store.js.map +1 -1
- package/dist/workspace-projection/index.d.ts +10 -0
- package/dist/workspace-projection/index.d.ts.map +1 -0
- package/dist/workspace-projection/index.js +120 -0
- package/dist/workspace-projection/index.js.map +1 -0
- package/dist/workspace-projection/types.d.ts +16 -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 +68 -37
- 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/adapters/telegram/html.d.ts +0 -3
- package/dist/adapters/telegram/html.d.ts.map +0 -1
- package/dist/adapters/telegram/html.js +0 -98
- package/dist/adapters/telegram/html.js.map +0 -1
- package/dist/commands/parse.d.ts +0 -7
- package/dist/commands/parse.d.ts.map +0 -1
- package/dist/commands/parse.js +0 -14
- package/dist/commands/parse.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/sandbox/path-context.d.ts +0 -3
- package/dist/sandbox/path-context.d.ts.map +0 -1
- package/dist/sandbox/path-context.js +0 -20
- package/dist/sandbox/path-context.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/sessions/metadata.d.ts +0 -3
- package/dist/sessions/metadata.d.ts.map +0 -1
- package/dist/sessions/metadata.js +0 -11
- package/dist/sessions/metadata.js.map +0 -1
- package/dist/sessions/policy.d.ts +0 -6
- package/dist/sessions/policy.d.ts.map +0 -1
- package/dist/sessions/policy.js +0 -23
- package/dist/sessions/policy.js.map +0 -1
- package/dist/store.d.ts +0 -46
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -177
- package/dist/store.js.map +0 -1
- package/dist/tools/truncate.d.ts +0 -33
- package/dist/tools/truncate.d.ts.map +0 -1
- package/dist/tools/truncate.js +0 -184
- package/dist/tools/truncate.js.map +0 -1
- package/dist/utils/date.d.ts +0 -10
- package/dist/utils/date.d.ts.map +0 -1
- package/dist/utils/date.js +0 -23
- package/dist/utils/date.js.map +0 -1
- package/dist/utils/env.d.ts +0 -3
- package/dist/utils/env.d.ts.map +0 -1
- package/dist/utils/env.js +0 -12
- package/dist/utils/env.js.map +0 -1
- package/dist/utils/fs-atomic.d.ts +0 -10
- package/dist/utils/fs-atomic.d.ts.map +0 -1
- package/dist/utils/fs-atomic.js +0 -45
- package/dist/utils/fs-atomic.js.map +0 -1
- package/dist/utils/html.d.ts +0 -2
- package/dist/utils/html.d.ts.map +0 -1
- package/dist/utils/html.js +0 -4
- package/dist/utils/html.js.map +0 -1
- package/dist/utils/http-body.d.ts +0 -10
- package/dist/utils/http-body.d.ts.map +0 -1
- package/dist/utils/http-body.js +0 -34
- package/dist/utils/http-body.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/web/agent-events/portal.d.ts +0 -3
- package/dist/web/agent-events/portal.d.ts.map +0 -1
- package/dist/web/agent-events/portal.js +0 -18
- package/dist/web/agent-events/portal.js.map +0 -1
- package/dist/web/request.d.ts +0 -3
- package/dist/web/request.d.ts.map +0 -1
- package/dist/web/request.js +0 -13
- package/dist/web/request.js.map +0 -1
- package/dist/web/session-view/command.d.ts +0 -4
- package/dist/web/session-view/command.d.ts.map +0 -1
- package/dist/web/session-view/command.js +0 -7
- package/dist/web/session-view/command.js.map +0 -1
- /package/dist/{download.d.ts → cli/download.d.ts} +0 -0
package/dist/agent.js
CHANGED
|
@@ -1,24 +1,104 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
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 {} from "@earendil-works/pi-ai";
|
|
6
|
+
import { DEFAULT_EVENT_BUDGET, formatSkillsForPrompt, loadExtensions, loadSkillsFromDir, MikanAgentSession, MikanModels, parseCommandInput, } from "./harness/index.js";
|
|
7
|
+
import { runSubagent } from "./harness/subagent-runner.js";
|
|
8
|
+
import { loadSubagentProfiles } from "./harness/subagent-profiles.js";
|
|
9
|
+
import { mergeSubagentProgress, parseSubagentProgressSnapshot, renderSubagentDashboard, settleSubagentProgress, } from "./subagent-progress.js";
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
11
|
+
import { existsSync, lstatSync } from "node:fs";
|
|
12
|
+
import { chmod, mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
13
|
+
import { tmpdir } from "node:os";
|
|
14
|
+
import { basename, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
6
15
|
import { resolveConversationSettings } from "./config.js";
|
|
7
|
-
import {
|
|
16
|
+
import { resolveWorkspaceProjection } from "./workspace-projection/index.js";
|
|
17
|
+
import { packageSkillRuntimeDir, resolveConversationPackages } from "./packages/index.js";
|
|
8
18
|
import { ActorExecutionResolver } from "./execution-resolver.js";
|
|
9
19
|
import * as log from "./log.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
20
|
+
import { assertSandboxSupportsWorkspacePolicy, createExecutor, getUnresolvedSandboxPathContext, } from "./sandbox/index.js";
|
|
21
|
+
import { addLifecycleBreadcrumb, metricAttributes, reportUserFacingError, updateActiveSpanAttribution, } from "./observability/sentry.js";
|
|
22
|
+
import { ChatHistorySync } from "./sessions/chat-history-sync.js";
|
|
23
|
+
import { formatHistoryLine } from "./sessions/history-line.js";
|
|
24
|
+
import { conversationIdOf, isThreadSessionKey } from "./sessions/session-key.js";
|
|
15
25
|
import { extractSessionUuid, openManagedSession, } from "./sessions/store.js";
|
|
16
26
|
import { HostEventStore } from "./tools/event.js";
|
|
17
|
-
import { createMikanTools } from "./tools/index.js";
|
|
27
|
+
import { createMikanTools, createSubagentTool, DEFAULT_GLOBAL_SUBAGENT_SLOTS, SubagentSlotPool, } from "./tools/index.js";
|
|
28
|
+
// One process-wide fan-out account: per-conversation queues serialize runs,
|
|
29
|
+
// but each run can fan out up to the per-run cap — without this shared
|
|
30
|
+
// ceiling, N busy conversations hold N × cap live subagent sessions.
|
|
31
|
+
const globalSubagentSlots = new SubagentSlotPool(DEFAULT_GLOBAL_SUBAGENT_SLOTS);
|
|
18
32
|
import * as Sentry from "@sentry/node";
|
|
19
|
-
import { formatLocalTimestamp } from "./utils/date.js";
|
|
20
|
-
import { resolveConfiguredModel } from "./model-registry.js";
|
|
21
33
|
import { emitAgentEvent } from "./agent-events.js";
|
|
34
|
+
export function translateRuntimePathToHost(runtimePath, pathContext) {
|
|
35
|
+
return pathContext.runtimeToHostPath?.(runtimePath) ?? runtimePath;
|
|
36
|
+
}
|
|
37
|
+
function isWithinPathRoot(path, root) {
|
|
38
|
+
const pathRelative = relative(root, path);
|
|
39
|
+
return (pathRelative === "" ||
|
|
40
|
+
(pathRelative !== ".." && !pathRelative.startsWith(`..${sep}`) && !isAbsolute(pathRelative)));
|
|
41
|
+
}
|
|
42
|
+
function hasParentTraversal(path) {
|
|
43
|
+
return path.split(/[\\/]/).some((segment) => segment === "..");
|
|
44
|
+
}
|
|
45
|
+
export function translateAttachPathToHost(filePath, pathContext) {
|
|
46
|
+
if (!pathContext.runtimeToHostPath) {
|
|
47
|
+
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");
|
|
48
|
+
}
|
|
49
|
+
if (hasParentTraversal(filePath)) {
|
|
50
|
+
throw new Error("Cannot attach files: parent-directory traversal is not allowed");
|
|
51
|
+
}
|
|
52
|
+
const runtimeRoot = resolve(pathContext.runtimeWorkspaceRoot);
|
|
53
|
+
const runtimePath = posix.isAbsolute(filePath)
|
|
54
|
+
? filePath
|
|
55
|
+
: posix.join(pathContext.runtimeWorkspaceRoot, filePath);
|
|
56
|
+
const normalizedRuntimePath = resolve(runtimePath);
|
|
57
|
+
if (!isWithinPathRoot(normalizedRuntimePath, runtimeRoot)) {
|
|
58
|
+
throw new Error("Cannot attach files: path must be within the runtime workspace");
|
|
59
|
+
}
|
|
60
|
+
const hostRoot = resolve(pathContext.hostWorkspaceRoot);
|
|
61
|
+
const translatedPath = pathContext.runtimeToHostPath(runtimePath);
|
|
62
|
+
const hostPath = resolve(translatedPath);
|
|
63
|
+
if (!isWithinPathRoot(hostPath, hostRoot)) {
|
|
64
|
+
throw new Error("Cannot attach files: path must be within the host workspace");
|
|
65
|
+
}
|
|
66
|
+
return hostPath;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Normalize an attachment path using runtime lexical semantics only. The
|
|
70
|
+
* executor remains the authority for reading the resulting runtime path.
|
|
71
|
+
*/
|
|
72
|
+
function normalizeAttachRuntimePath(filePath, runtimeWorkspaceRoot) {
|
|
73
|
+
if (hasParentTraversal(filePath)) {
|
|
74
|
+
throw new Error("Cannot attach files: parent-directory traversal is not allowed");
|
|
75
|
+
}
|
|
76
|
+
const runtimeRoot = posix.resolve(runtimeWorkspaceRoot);
|
|
77
|
+
const runtimePath = posix.resolve(runtimeRoot, filePath);
|
|
78
|
+
const runtimeRelativePath = posix.relative(runtimeRoot, runtimePath);
|
|
79
|
+
if (runtimeRelativePath === ".." ||
|
|
80
|
+
runtimeRelativePath.startsWith("../") ||
|
|
81
|
+
posix.isAbsolute(runtimeRelativePath)) {
|
|
82
|
+
throw new Error("Cannot attach files: path must be within the runtime workspace");
|
|
83
|
+
}
|
|
84
|
+
return runtimePath;
|
|
85
|
+
}
|
|
86
|
+
async function withStagedRuntimeFile(executor, runtimePath, upload) {
|
|
87
|
+
const content = Buffer.from(await executor.readFileBase64(runtimePath), "base64");
|
|
88
|
+
let stagingDir;
|
|
89
|
+
try {
|
|
90
|
+
stagingDir = await mkdtemp(join(tmpdir(), "mikan-upload-"));
|
|
91
|
+
await chmod(stagingDir, 0o700);
|
|
92
|
+
const stagedPath = join(stagingDir, basename(runtimePath));
|
|
93
|
+
await writeFile(stagedPath, content, { mode: 0o600, flag: "wx" });
|
|
94
|
+
await chmod(stagedPath, 0o600);
|
|
95
|
+
await upload(stagedPath);
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
if (stagingDir)
|
|
99
|
+
await rm(stagingDir, { recursive: true, force: true });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
22
102
|
const IMAGE_MIME_TYPES = {
|
|
23
103
|
jpg: "image/jpeg",
|
|
24
104
|
jpeg: "image/jpeg",
|
|
@@ -29,18 +109,51 @@ const IMAGE_MIME_TYPES = {
|
|
|
29
109
|
function getImageMimeType(filename) {
|
|
30
110
|
return IMAGE_MIME_TYPES[filename.toLowerCase().split(".").pop() || ""];
|
|
31
111
|
}
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
112
|
+
function formatTimestampedUserMessage(message) {
|
|
113
|
+
return formatHistoryLine({
|
|
114
|
+
date: new Date(),
|
|
115
|
+
userName: message.userName,
|
|
116
|
+
threadTs: message.threadTs,
|
|
117
|
+
text: message.text,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
async function collectMessageAttachments(message, workspacePath, pathContext, readAttachment) {
|
|
121
|
+
const imageAttachments = [];
|
|
122
|
+
const nonImagePaths = [];
|
|
123
|
+
for (const attachment of message.attachments || []) {
|
|
124
|
+
const runtimePath = `${workspacePath}/${attachment.localPath}`;
|
|
125
|
+
const hostPath = pathContext?.runtimeToHostPath?.(runtimePath) ?? runtimePath;
|
|
126
|
+
const mimeType = getImageMimeType(attachment.localPath);
|
|
127
|
+
if (mimeType && existsSync(hostPath) && readAttachment) {
|
|
128
|
+
try {
|
|
129
|
+
imageAttachments.push({
|
|
130
|
+
type: "image",
|
|
131
|
+
mimeType,
|
|
132
|
+
data: await readAttachment(runtimePath),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
nonImagePaths.push(runtimePath);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
nonImagePaths.push(runtimePath);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return { imageAttachments, nonImagePaths };
|
|
144
|
+
}
|
|
145
|
+
export async function buildPromptPayload(message, workspacePath, pathContext, readAttachment) {
|
|
146
|
+
let userMessage = formatTimestampedUserMessage(message);
|
|
147
|
+
const { imageAttachments, nonImagePaths } = await collectMessageAttachments(message, workspacePath, pathContext, readAttachment);
|
|
148
|
+
if (nonImagePaths.length > 0) {
|
|
149
|
+
userMessage += `\n\n<slack_attachments>\n${nonImagePaths.join("\n")}\n</slack_attachments>`;
|
|
150
|
+
}
|
|
151
|
+
return { userMessage, imageAttachments };
|
|
38
152
|
}
|
|
39
|
-
async function getMemory(
|
|
153
|
+
async function getMemory(projection) {
|
|
40
154
|
const parts = [];
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (existsSync(workspaceMemoryPath)) {
|
|
155
|
+
const workspaceMemoryPath = projection.promptSources.globalMemoryPath;
|
|
156
|
+
if (workspaceMemoryPath && isRegularFile(workspaceMemoryPath)) {
|
|
44
157
|
try {
|
|
45
158
|
const content = (await readFile(workspaceMemoryPath, "utf-8")).trim();
|
|
46
159
|
if (content) {
|
|
@@ -51,9 +164,8 @@ async function getMemory(conversationDir) {
|
|
|
51
164
|
log.logWarning("Failed to read workspace memory", `${workspaceMemoryPath}: ${error}`);
|
|
52
165
|
}
|
|
53
166
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (existsSync(conversationMemoryPath)) {
|
|
167
|
+
const conversationMemoryPath = projection.promptSources.conversationMemoryPath;
|
|
168
|
+
if (isRegularFile(conversationMemoryPath)) {
|
|
57
169
|
try {
|
|
58
170
|
const content = (await readFile(conversationMemoryPath, "utf-8")).trim();
|
|
59
171
|
if (content) {
|
|
@@ -69,12 +181,20 @@ async function getMemory(conversationDir) {
|
|
|
69
181
|
}
|
|
70
182
|
return parts.join("\n\n");
|
|
71
183
|
}
|
|
72
|
-
function
|
|
184
|
+
function isRegularFile(path) {
|
|
185
|
+
try {
|
|
186
|
+
const stats = lstatSync(path);
|
|
187
|
+
return stats.isFile() && !stats.isSymbolicLink();
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function loadMikanSkills(office, workspacePath, projection) {
|
|
73
194
|
const skillMap = new Map();
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
const hostWorkspacePath = join(conversationDir, "..");
|
|
195
|
+
// workspacePath is the runtime-side root (e.g. /workspace); host paths under
|
|
196
|
+
// the workspace root translate onto it for prompt references.
|
|
197
|
+
const hostWorkspacePath = office.workspace.root;
|
|
78
198
|
// Helper to translate host paths to container paths
|
|
79
199
|
const translatePath = (hostPath) => {
|
|
80
200
|
if (hostPath.startsWith(hostWorkspacePath)) {
|
|
@@ -82,26 +202,66 @@ function loadMikanSkills(conversationDir, workspacePath) {
|
|
|
82
202
|
}
|
|
83
203
|
return hostPath;
|
|
84
204
|
};
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
205
|
+
// Package skills first: they are the lowest precedence, so a workspace or
|
|
206
|
+
// conversation skill of the same name below overwrites them. A package can
|
|
207
|
+
// offer a capability without taking the name away from whoever wants to
|
|
208
|
+
// replace it locally.
|
|
209
|
+
//
|
|
210
|
+
// Unlike extension-shipped skills, these are NOT inlined into the prompt:
|
|
211
|
+
// conversationPackageSkillMounts exposes them read-only at a runtime path,
|
|
212
|
+
// so the agent can read the files — including any scripts or templates the
|
|
213
|
+
// skill ships alongside its SKILL.md, which inlining could never carry.
|
|
214
|
+
const mounted = workspacePath !== hostWorkspacePath;
|
|
215
|
+
for (const { slug, dir } of resolveConversationPackages({ office }).skillDirs) {
|
|
216
|
+
const runtimeDir = packageSkillRuntimeDir(slug);
|
|
217
|
+
for (const skill of loadSkillsFromDir({ dir, source: `package:${slug}` }).skills) {
|
|
218
|
+
// In host mode there is no mount, so the host path is already the path
|
|
219
|
+
// the agent will use.
|
|
220
|
+
if (mounted) {
|
|
221
|
+
skill.filePath = runtimeDir + skill.filePath.slice(dir.length);
|
|
222
|
+
skill.baseDir = runtimeDir + skill.baseDir.slice(dir.length);
|
|
223
|
+
}
|
|
224
|
+
skillMap.set(skill.name, skill);
|
|
225
|
+
}
|
|
92
226
|
}
|
|
93
|
-
// Load
|
|
94
|
-
const
|
|
95
|
-
|
|
227
|
+
// Load workspace-level skills only when the office projection authorizes it.
|
|
228
|
+
const workspaceSkillsDir = projection.promptSources.globalSkillsDir;
|
|
229
|
+
if (workspaceSkillsDir) {
|
|
230
|
+
for (const skill of loadSkillsFromDir({ dir: workspaceSkillsDir, source: "workspace" })
|
|
231
|
+
.skills) {
|
|
232
|
+
skill.filePath = translatePath(skill.filePath);
|
|
233
|
+
skill.baseDir = translatePath(skill.baseDir);
|
|
234
|
+
skillMap.set(skill.name, skill);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Load conversation-specific skills (override workspace skills on collision).
|
|
238
|
+
// Host prompt construction must never follow an agent-created symlink out of
|
|
239
|
+
// the conversation office, so this load rejects symlinks per entry — on
|
|
240
|
+
// exactly the paths it reads. Vendored node_modules and dot directories are
|
|
241
|
+
// never read and never disqualify anything.
|
|
242
|
+
const conversationSkillsDir = projection.promptSources.conversationSkillsDir;
|
|
243
|
+
const conversationSkills = loadSkillsFromDir({
|
|
244
|
+
dir: conversationSkillsDir,
|
|
245
|
+
source: "channel",
|
|
246
|
+
rejectSymlinks: true,
|
|
247
|
+
});
|
|
248
|
+
const skippedSkillLinks = [];
|
|
249
|
+
for (const diagnostic of conversationSkills.diagnostics) {
|
|
250
|
+
if (diagnostic.code !== "symlink")
|
|
251
|
+
continue;
|
|
252
|
+
log.logWarning("Skipping conversation skill entry (symlink)", diagnostic.path);
|
|
253
|
+
skippedSkillLinks.push(translatePath(diagnostic.path));
|
|
254
|
+
}
|
|
255
|
+
for (const skill of conversationSkills.skills) {
|
|
96
256
|
skill.filePath = translatePath(skill.filePath);
|
|
97
257
|
skill.baseDir = translatePath(skill.baseDir);
|
|
98
258
|
skillMap.set(skill.name, skill);
|
|
99
259
|
}
|
|
100
|
-
return Array.from(skillMap.values());
|
|
260
|
+
return { skills: Array.from(skillMap.values()), skippedSkillLinks };
|
|
101
261
|
}
|
|
102
|
-
function buildRuntimePaths(runtimeWorkspaceRoot,
|
|
262
|
+
function buildRuntimePaths(runtimeWorkspaceRoot, office) {
|
|
103
263
|
const workspaceRoot = runtimeWorkspaceRoot.replace(/\/+$/, "") || "/";
|
|
104
|
-
const conversationPath = posix.join(workspaceRoot,
|
|
264
|
+
const conversationPath = posix.join(workspaceRoot, office.key);
|
|
105
265
|
return {
|
|
106
266
|
workspaceRoot,
|
|
107
267
|
conversationPath,
|
|
@@ -111,7 +271,7 @@ function buildRuntimePaths(runtimeWorkspaceRoot, conversationId) {
|
|
|
111
271
|
function buildEnvDescription(sandboxType, workspaceRoot) {
|
|
112
272
|
switch (sandboxType) {
|
|
113
273
|
case "image":
|
|
114
|
-
return `You are running inside a managed per-
|
|
274
|
+
return `You are running inside a managed per-conversation container.
|
|
115
275
|
- Runtime workspace root: ${workspaceRoot}
|
|
116
276
|
- Bash commands start in: ${workspaceRoot}
|
|
117
277
|
- Install tools with the image's package manager
|
|
@@ -152,8 +312,8 @@ export function resolveTriggerAttribution(message) {
|
|
|
152
312
|
return `@${message.userName}`;
|
|
153
313
|
return undefined;
|
|
154
314
|
}
|
|
155
|
-
function buildSystemPrompt(workspacePath,
|
|
156
|
-
const { workspaceRoot, conversationPath, scratchPath } = buildRuntimePaths(workspacePath,
|
|
315
|
+
function buildSystemPrompt(workspacePath, office, conversationKind, currentUserId, memory, sandboxConfig, platform, skills, projection, skippedSkillLinks = []) {
|
|
316
|
+
const { workspaceRoot, conversationPath, scratchPath } = buildRuntimePaths(workspacePath, office);
|
|
157
317
|
const sandboxType = sandboxConfig.type;
|
|
158
318
|
const isContainerLike = sandboxType === "container" || sandboxType === "image";
|
|
159
319
|
const isFirecracker = sandboxType === "firecracker";
|
|
@@ -171,11 +331,26 @@ function buildSystemPrompt(workspacePath, conversationId, conversationKind, curr
|
|
|
171
331
|
// system prompt stays byte-stable across a conversation's turns and keeps the
|
|
172
332
|
// provider prompt cache warm (a changing system prefix invalidates the cache
|
|
173
333
|
// for the whole request, including the far larger conversation history).
|
|
334
|
+
const workspaceLayout = projection.layout === "full"
|
|
335
|
+
? `${workspaceRoot}/ contains the complete trusted workspace.`
|
|
336
|
+
: projection.layout === "shared-support"
|
|
337
|
+
? `${workspaceRoot}/ contains shared MEMORY.md, skills/, events/, and this conversation's directory.`
|
|
338
|
+
: `${conversationPath}/ is the only conversation workspace mounted; global memory, skills, and events are not available.`;
|
|
339
|
+
const skillStorageGuidance = projection.doorPolicy === "trusted"
|
|
340
|
+
? `Store shared skills in \`${workspaceRoot}/skills/<name>/\` or conversation-specific skills in \`${conversationPath}/skills/<name>/\`.`
|
|
341
|
+
: `Store skills in \`${conversationPath}/skills/<name>/\`; this office cannot access workspace-global skills.`;
|
|
342
|
+
const memoryGuidance = projection.doorPolicy === "trusted"
|
|
343
|
+
? `Write important shared knowledge to \`${workspaceRoot}/MEMORY.md\` and conversation-specific knowledge to \`${conversationPath}/MEMORY.md\`.`
|
|
344
|
+
: `Write durable knowledge only to \`${conversationPath}/MEMORY.md\`; this office cannot access workspace-global memory.`;
|
|
345
|
+
const systemLogPath = projection.layout === "conversation"
|
|
346
|
+
? `${conversationPath}/SYSTEM.md`
|
|
347
|
+
: `${workspaceRoot}/SYSTEM.md`;
|
|
174
348
|
const slackBlockKitInstructions = platform.name === "slack"
|
|
175
349
|
? `
|
|
176
350
|
## Slack Rendering
|
|
177
|
-
- The Slack adapter renders responses
|
|
178
|
-
-
|
|
351
|
+
- The Slack adapter renders responses natively from standard Markdown. Answer in normal Markdown/GFM.
|
|
352
|
+
- Markdown pipe tables are rendered as native Slack tables.
|
|
353
|
+
- For interactive elements (buttons, select menus), use the slack_blockkit tool; user interactions arrive as "[Slack action] <action_id>: <value>" messages.
|
|
179
354
|
`
|
|
180
355
|
: "";
|
|
181
356
|
return `You are mikan, a ${platform.name} bot assistant. Be concise. No emojis.
|
|
@@ -196,7 +371,7 @@ Channels: ${channelMappings}
|
|
|
196
371
|
|
|
197
372
|
Users: ${userMappings}
|
|
198
373
|
|
|
199
|
-
When mentioning users,
|
|
374
|
+
When mentioning users, write <@userName> using the exact userName from the Users table above (e.g., <@mario>). Never invent handles from other platforms (GitHub, email); the platform adapter converts <@userName> to the platform's native mention form.
|
|
200
375
|
|
|
201
376
|
## Environment
|
|
202
377
|
${envDescription}
|
|
@@ -204,10 +379,13 @@ ${envDescription}
|
|
|
204
379
|
- Do not use host-only paths unless you are running in host mode and verified they exist.
|
|
205
380
|
|
|
206
381
|
## Workspace Layout
|
|
207
|
-
${
|
|
382
|
+
${workspaceLayout}
|
|
383
|
+
${projection.layout === "conversation"
|
|
384
|
+
? `${conversationPath}/ # This conversation`
|
|
385
|
+
: `${workspaceRoot}/
|
|
208
386
|
├── MEMORY.md # Global memory (all conversations)
|
|
209
387
|
├── skills/ # Global CLI tools you create
|
|
210
|
-
└── ${
|
|
388
|
+
└── ${office.key}/ # This conversation`}
|
|
211
389
|
├── MEMORY.md # Conversation-specific memory
|
|
212
390
|
├── log.jsonl # Human-readable message history (no tool results)
|
|
213
391
|
├── sessions/ # Structured session history used for context reconstruction
|
|
@@ -222,7 +400,7 @@ ${workspaceRoot}/
|
|
|
222
400
|
You can create reusable CLI tools for recurring tasks (email, APIs, data processing, etc.).
|
|
223
401
|
|
|
224
402
|
### Creating Skills
|
|
225
|
-
|
|
403
|
+
${skillStorageGuidance}
|
|
226
404
|
Each skill directory needs a \`SKILL.md\` with YAML frontmatter:
|
|
227
405
|
|
|
228
406
|
\`\`\`markdown
|
|
@@ -240,7 +418,9 @@ Scripts are in: {baseDir}/
|
|
|
240
418
|
\`name\` and \`description\` are required. Use \`{baseDir}\` as placeholder for the skill's directory path.
|
|
241
419
|
|
|
242
420
|
### Available Skills
|
|
243
|
-
${skills.length > 0 ? formatSkillsForPrompt(skills) : "(no skills installed yet)"}
|
|
421
|
+
${skills.length > 0 ? formatSkillsForPrompt(skills) : "(no skills installed yet)"}${skippedSkillLinks.length > 0
|
|
422
|
+
? `\n\nNote: these skill entries were skipped because they are symlinks, which the host never follows when reading this conversation's skills: ${skippedSkillLinks.join(", ")}. Replace each with a real file or directory (for example \`cp -rL\`) to load it.`
|
|
423
|
+
: ""}
|
|
244
424
|
|
|
245
425
|
## Events
|
|
246
426
|
Use the \`event\` tool to schedule immediate, one-shot, or periodic follow-ups. It writes to the host-side mikan control plane and fills routing fields for the current conversation automatically.
|
|
@@ -254,16 +434,14 @@ When events trigger, messages are prefixed like \`[EVENT:filename:type:time]\`.
|
|
|
254
434
|
For periodic events where there's nothing to report, respond with exactly \`[SILENT]\`. Debounce external triggers; prefer one summarized event over many.
|
|
255
435
|
|
|
256
436
|
## Memory
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
- Conversation (${conversationPath}/MEMORY.md): conversation-specific decisions, ongoing work
|
|
260
|
-
Update when you learn something important or when asked to remember something.
|
|
437
|
+
${memoryGuidance}
|
|
438
|
+
Update it when you learn something important or when asked to remember something.
|
|
261
439
|
|
|
262
440
|
### Current Memory
|
|
263
441
|
${memory}
|
|
264
442
|
|
|
265
443
|
## System Configuration Log
|
|
266
|
-
Maintain ${
|
|
444
|
+
Maintain ${systemLogPath} to log all environment modifications:
|
|
267
445
|
- Installed packages (apt install, npm install, uv pip install)
|
|
268
446
|
- Environment variables set
|
|
269
447
|
- Config files modified (~/.gitconfig, cron jobs, etc.)
|
|
@@ -329,81 +507,21 @@ Do not add this to \`[SILENT]\` responses.`);
|
|
|
329
507
|
}
|
|
330
508
|
return parts.join("\n\n");
|
|
331
509
|
}
|
|
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
|
-
};
|
|
510
|
+
export function appendTriggerAttribution(text, triggerAttribution, sessionLink) {
|
|
511
|
+
if (!triggerAttribution)
|
|
512
|
+
return text;
|
|
513
|
+
const trimmed = text.trimEnd();
|
|
514
|
+
const legacySuffix = `_Triggered by ${triggerAttribution}_`;
|
|
515
|
+
// Slack mrkdwn italics cannot span a URL — a `_..._` wrapping a link renders
|
|
516
|
+
// the underscores literally. Keep the session link outside the italic span.
|
|
517
|
+
const suffix = sessionLink ? `${legacySuffix} · session: ${sessionLink}` : legacySuffix;
|
|
518
|
+
if (trimmed.endsWith(suffix))
|
|
519
|
+
return text;
|
|
520
|
+
const body = trimmed.endsWith(legacySuffix)
|
|
521
|
+
? trimmed.slice(0, -legacySuffix.length).trimEnd()
|
|
522
|
+
: trimmed;
|
|
523
|
+
return `${body}\n\n${suffix}`;
|
|
402
524
|
}
|
|
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
525
|
function mergeExtensionSkills(local, extension) {
|
|
408
526
|
if (extension.length === 0)
|
|
409
527
|
return local;
|
|
@@ -414,37 +532,6 @@ function mergeExtensionSkills(local, extension) {
|
|
|
414
532
|
byName.set(skill.name, skill);
|
|
415
533
|
return [...byName.values()];
|
|
416
534
|
}
|
|
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
535
|
function createEmptyUsageTotals() {
|
|
449
536
|
return {
|
|
450
537
|
input: 0,
|
|
@@ -461,6 +548,13 @@ function createRunState() {
|
|
|
461
548
|
queue: null,
|
|
462
549
|
pendingTools: new Map(),
|
|
463
550
|
toolProgress: new Map(),
|
|
551
|
+
subagentProgress: new Map(),
|
|
552
|
+
completedSubagentProgress: [],
|
|
553
|
+
subagentToolCalls: new Set(),
|
|
554
|
+
subagentProgressShown: false,
|
|
555
|
+
suppressResponseDeltas: false,
|
|
556
|
+
lastSubagentProgressAt: 0,
|
|
557
|
+
toolProgressTimer: undefined,
|
|
464
558
|
totalUsage: createEmptyUsageTotals(),
|
|
465
559
|
llmCallCount: 0,
|
|
466
560
|
stopReason: "stop",
|
|
@@ -480,6 +574,15 @@ function resetRunState(runState, responder, sessionConversation, userName, sessi
|
|
|
480
574
|
};
|
|
481
575
|
runState.pendingTools.clear();
|
|
482
576
|
runState.toolProgress.clear();
|
|
577
|
+
runState.subagentProgress.clear();
|
|
578
|
+
runState.completedSubagentProgress = [];
|
|
579
|
+
runState.subagentToolCalls.clear();
|
|
580
|
+
runState.subagentProgressShown = false;
|
|
581
|
+
runState.suppressResponseDeltas = false;
|
|
582
|
+
runState.lastSubagentProgressAt = 0;
|
|
583
|
+
if (runState.toolProgressTimer)
|
|
584
|
+
clearTimeout(runState.toolProgressTimer);
|
|
585
|
+
runState.toolProgressTimer = undefined;
|
|
483
586
|
runState.totalUsage = createEmptyUsageTotals();
|
|
484
587
|
runState.llmCallCount = 0;
|
|
485
588
|
runState.stopReason = "stop";
|
|
@@ -515,53 +618,6 @@ function createRunQueue(responder, runState) {
|
|
|
515
618
|
wait: () => queueChain,
|
|
516
619
|
};
|
|
517
620
|
}
|
|
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
621
|
function getFinalAssistantText(session) {
|
|
566
622
|
const lastAssistant = session.messages.findLast((message) => message.role === "assistant");
|
|
567
623
|
return (lastAssistant?.content
|
|
@@ -569,21 +625,6 @@ function getFinalAssistantText(session) {
|
|
|
569
625
|
.map((content) => content.text)
|
|
570
626
|
.join("\n") || "");
|
|
571
627
|
}
|
|
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
628
|
function isEventTriggerAttribution(triggerAttribution) {
|
|
588
629
|
return triggerAttribution?.startsWith("[event:") === true;
|
|
589
630
|
}
|
|
@@ -593,22 +634,86 @@ function extractToolLabel(toolName, args) {
|
|
|
593
634
|
return toolName;
|
|
594
635
|
return label.trim() || toolName;
|
|
595
636
|
}
|
|
637
|
+
/** Non-subagent tool activity lines; subagent calls render as the dashboard. */
|
|
596
638
|
function formatToolProgress(runState) {
|
|
597
|
-
const lines = Array.from(runState.toolProgress.
|
|
639
|
+
const lines = Array.from(runState.toolProgress.entries()).flatMap(([toolCallId, item]) => {
|
|
640
|
+
if (runState.subagentToolCalls.has(toolCallId))
|
|
641
|
+
return [];
|
|
598
642
|
const marker = item.status === "running" ? "•" : item.status === "error" ? "✗" : "✓";
|
|
599
|
-
return `${marker} ${item.label}
|
|
643
|
+
return [`${marker} ${item.label}`];
|
|
600
644
|
});
|
|
601
645
|
return lines.join("\n");
|
|
602
646
|
}
|
|
603
647
|
function formatResponseWithToolProgress(text, runState) {
|
|
604
648
|
const progress = formatToolProgress(runState);
|
|
605
|
-
return progress
|
|
649
|
+
return [progress, text].filter(Boolean).join("\n\n");
|
|
606
650
|
}
|
|
607
|
-
|
|
651
|
+
/**
|
|
652
|
+
* The one dashboard render path. A responder that overrides
|
|
653
|
+
* `replaceSubagentProgress` converts the snapshot for a pipeline that is not
|
|
654
|
+
* response-source Markdown (Telegram HTML); every other platform receives the
|
|
655
|
+
* Markdown dashboard — "dashboard, blank line, answer" — through
|
|
656
|
+
* `replaceResponse`, the same conversion as any response.
|
|
657
|
+
*/
|
|
658
|
+
async function replaceWithSubagentDashboard(responder, snapshot, finalText, options) {
|
|
659
|
+
if (responder.replaceSubagentProgress) {
|
|
660
|
+
await responder.replaceSubagentProgress(snapshot, finalText);
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
const dashboard = renderSubagentDashboard(snapshot);
|
|
664
|
+
await responder.replaceResponse(finalText ? `${dashboard}\n\n${finalText}` : dashboard, options);
|
|
665
|
+
}
|
|
666
|
+
async function replaceResponseWithToolProgress(responder, runState, subagentProgress = mergeSubagentProgress([...runState.subagentProgress.values()])) {
|
|
667
|
+
if (subagentProgress) {
|
|
668
|
+
await replaceWithSubagentDashboard(responder, subagentProgress);
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
608
671
|
const progress = formatToolProgress(runState);
|
|
609
672
|
if (progress)
|
|
610
673
|
await responder.replaceResponse(progress);
|
|
611
674
|
}
|
|
675
|
+
const TOOL_PROGRESS_DEBOUNCE_MS = 500;
|
|
676
|
+
const SUBAGENT_PROGRESS_THROTTLE_MS = 2000;
|
|
677
|
+
function subagentProgressDelay(runState) {
|
|
678
|
+
if (!runState.subagentProgressShown)
|
|
679
|
+
return 0;
|
|
680
|
+
return Math.max(0, runState.lastSubagentProgressAt + SUBAGENT_PROGRESS_THROTTLE_MS - Date.now());
|
|
681
|
+
}
|
|
682
|
+
function scheduleToolProgressUpdate(responder, runState) {
|
|
683
|
+
if (runState.toolProgressTimer)
|
|
684
|
+
return;
|
|
685
|
+
const subagentProgress = mergeSubagentProgress([...runState.subagentProgress.values()]);
|
|
686
|
+
const delay = subagentProgress ? subagentProgressDelay(runState) : TOOL_PROGRESS_DEBOUNCE_MS;
|
|
687
|
+
runState.toolProgressTimer = setTimeout(() => {
|
|
688
|
+
runState.toolProgressTimer = undefined;
|
|
689
|
+
const snapshot = mergeSubagentProgress([...runState.subagentProgress.values()]);
|
|
690
|
+
if (snapshot) {
|
|
691
|
+
runState.subagentProgressShown = true;
|
|
692
|
+
runState.lastSubagentProgressAt = Date.now();
|
|
693
|
+
}
|
|
694
|
+
runState.queue?.enqueue(() => replaceResponseWithToolProgress(responder, runState, snapshot), "tool progress update");
|
|
695
|
+
}, delay);
|
|
696
|
+
runState.toolProgressTimer.unref();
|
|
697
|
+
}
|
|
698
|
+
function flushToolProgressUpdate(responder, runState) {
|
|
699
|
+
if (runState.toolProgressTimer)
|
|
700
|
+
clearTimeout(runState.toolProgressTimer);
|
|
701
|
+
runState.toolProgressTimer = undefined;
|
|
702
|
+
const subagentProgress = mergeSubagentProgress([...runState.subagentProgress.values()]);
|
|
703
|
+
if (subagentProgress) {
|
|
704
|
+
runState.subagentProgressShown = true;
|
|
705
|
+
runState.lastSubagentProgressAt = Date.now();
|
|
706
|
+
}
|
|
707
|
+
runState.queue?.enqueue(() => replaceResponseWithToolProgress(responder, runState, subagentProgress), "tool progress update");
|
|
708
|
+
}
|
|
709
|
+
function extractSubagentProgress(partialResult) {
|
|
710
|
+
if (!partialResult || typeof partialResult !== "object")
|
|
711
|
+
return undefined;
|
|
712
|
+
const details = partialResult.details;
|
|
713
|
+
if (!details || typeof details !== "object")
|
|
714
|
+
return undefined;
|
|
715
|
+
return parseSubagentProgressSnapshot(details.progress);
|
|
716
|
+
}
|
|
612
717
|
async function finalizeRunResponse(responder, session, runState, options) {
|
|
613
718
|
if (runState.stopReason === "error" && runState.errorMessage) {
|
|
614
719
|
if (!runState.reportedLlmError) {
|
|
@@ -673,7 +778,17 @@ async function finalizeRunResponse(responder, session, runState, options) {
|
|
|
673
778
|
if (!finalText.trim())
|
|
674
779
|
return;
|
|
675
780
|
try {
|
|
676
|
-
|
|
781
|
+
const finalResponse = appendTriggerAttribution(finalText, options?.triggerAttribution, options?.triggerSessionLink);
|
|
782
|
+
const finalDashboard = mergeSubagentProgress(runState.completedSubagentProgress);
|
|
783
|
+
if (finalDashboard) {
|
|
784
|
+
await replaceWithSubagentDashboard(responder, finalDashboard, finalResponse, {
|
|
785
|
+
createOverflowLink: options?.createOverflowLink,
|
|
786
|
+
});
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
await responder.replaceResponse(formatResponseWithToolProgress(finalResponse, runState), {
|
|
790
|
+
createOverflowLink: options?.createOverflowLink,
|
|
791
|
+
});
|
|
677
792
|
}
|
|
678
793
|
catch (err) {
|
|
679
794
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -739,6 +854,226 @@ async function reportUsageSummary(ctx) {
|
|
|
739
854
|
await waitForQueue();
|
|
740
855
|
}
|
|
741
856
|
}
|
|
857
|
+
function extractToolResultText(result) {
|
|
858
|
+
if (typeof result === "string") {
|
|
859
|
+
return result;
|
|
860
|
+
}
|
|
861
|
+
if (result &&
|
|
862
|
+
typeof result === "object" &&
|
|
863
|
+
"content" in result &&
|
|
864
|
+
Array.isArray(result.content)) {
|
|
865
|
+
const content = result.content;
|
|
866
|
+
const textParts = [];
|
|
867
|
+
for (const part of content) {
|
|
868
|
+
if (part.type === "text" && part.text) {
|
|
869
|
+
textParts.push(part.text);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
if (textParts.length > 0) {
|
|
873
|
+
return textParts.join("\n");
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
return JSON.stringify(result);
|
|
877
|
+
}
|
|
878
|
+
function buildThreadSessionName(message) {
|
|
879
|
+
const text = message?.text?.trim();
|
|
880
|
+
if (!text)
|
|
881
|
+
return undefined;
|
|
882
|
+
const userLabel = message?.userName || message?.user || "unknown";
|
|
883
|
+
return `[${userLabel}]: ${text}`;
|
|
884
|
+
}
|
|
885
|
+
function createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner, workspace) {
|
|
886
|
+
const executionResolver = vaultManager && sandboxConfig.type !== "host"
|
|
887
|
+
? new ActorExecutionResolver(sandboxConfig, vaultManager, provisioner, workspace)
|
|
888
|
+
: undefined;
|
|
889
|
+
// activeExecutor is replaced at the start of each run() call when executionResolver
|
|
890
|
+
// is present, so the stable `executor` wrapper always delegates to the latest resolved value.
|
|
891
|
+
let activeExecutor = executionResolver !== undefined
|
|
892
|
+
? createExecutor({ type: "host" })
|
|
893
|
+
: createExecutor(sandboxConfig);
|
|
894
|
+
const executor = {
|
|
895
|
+
exec(command, options) {
|
|
896
|
+
return activeExecutor.exec(command, options);
|
|
897
|
+
},
|
|
898
|
+
readFile(path, options) {
|
|
899
|
+
return activeExecutor.readFile(path, options);
|
|
900
|
+
},
|
|
901
|
+
readFileBase64(path, options) {
|
|
902
|
+
return activeExecutor.readFileBase64(path, options);
|
|
903
|
+
},
|
|
904
|
+
writeFile(path, content, options) {
|
|
905
|
+
return activeExecutor.writeFile(path, content, options);
|
|
906
|
+
},
|
|
907
|
+
getWorkspacePath(hostPath) {
|
|
908
|
+
return activeExecutor.getWorkspacePath(hostPath);
|
|
909
|
+
},
|
|
910
|
+
getSandboxConfig() {
|
|
911
|
+
return activeExecutor.getSandboxConfig();
|
|
912
|
+
},
|
|
913
|
+
getPathContext(hostWorkspaceRoot) {
|
|
914
|
+
return activeExecutor.getPathContext(hostWorkspaceRoot);
|
|
915
|
+
},
|
|
916
|
+
};
|
|
917
|
+
return {
|
|
918
|
+
executionResolver,
|
|
919
|
+
executor,
|
|
920
|
+
getPathContext: () => executor.getPathContext(workspace.root),
|
|
921
|
+
async resolveExecutorForRun(context) {
|
|
922
|
+
if (!executionResolver)
|
|
923
|
+
return;
|
|
924
|
+
activeExecutor = await executionResolver.resolve(context);
|
|
925
|
+
},
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Extension host services over mikan's runtime infrastructure: schedules
|
|
930
|
+
* become event files under `<workspaceDir>/events` (picked up live by
|
|
931
|
+
* EventsWatcher), secrets come from `vaults/extensions/<slug>/env`, and
|
|
932
|
+
* notify posts through the platform bots when main.ts provides a notifier.
|
|
933
|
+
*/
|
|
934
|
+
function buildExtensionHostServices(params) {
|
|
935
|
+
const { workspace, address, vaultManager, platformNotifier, platformReactor, platformUploader, platformBlockKit, platformDmOpener, platformHistoryFetcher, platformUserLister, extensionScheduleEngine, runSubagentService, } = params;
|
|
936
|
+
const eventStore = HostEventStore.fromWorkspaceDir(workspace.root);
|
|
937
|
+
return {
|
|
938
|
+
stateDir: workspace.stateDir,
|
|
939
|
+
scheduleStore: {
|
|
940
|
+
write: async (filename, payload) => {
|
|
941
|
+
await eventStore.write(filename, payload);
|
|
942
|
+
},
|
|
943
|
+
delete: async (filename) => (await eventStore.delete(filename)).deleted,
|
|
944
|
+
list: async () => (await eventStore.list()).flatMap((entry) => entry.payload ? [{ filename: entry.filename, payload: entry.payload }] : []),
|
|
945
|
+
},
|
|
946
|
+
...(platformNotifier ? { postMessage: platformNotifier } : {}),
|
|
947
|
+
...(platformReactor ? { addReaction: platformReactor } : {}),
|
|
948
|
+
...(platformUploader ? { uploadFile: platformUploader } : {}),
|
|
949
|
+
...(platformDmOpener ? { openDirectConversation: platformDmOpener } : {}),
|
|
950
|
+
...(platformHistoryFetcher ? { fetchHistory: platformHistoryFetcher } : {}),
|
|
951
|
+
...(platformUserLister ? { listUsers: platformUserLister } : {}),
|
|
952
|
+
...(extensionScheduleEngine
|
|
953
|
+
? {
|
|
954
|
+
callbackScheduleStore: {
|
|
955
|
+
upsert: (slug, name, spec) => extensionScheduleEngine.upsert(address, slug, name, spec),
|
|
956
|
+
delete: (slug, name) => extensionScheduleEngine.delete(address, slug, name),
|
|
957
|
+
list: (slug) => extensionScheduleEngine.list(address, slug),
|
|
958
|
+
},
|
|
959
|
+
}
|
|
960
|
+
: {}),
|
|
961
|
+
...(platformBlockKit
|
|
962
|
+
? { postBlocks: platformBlockKit.postBlocks, updateBlocks: platformBlockKit.updateBlocks }
|
|
963
|
+
: {}),
|
|
964
|
+
...(runSubagentService ? { runSubagent: runSubagentService } : {}),
|
|
965
|
+
...(vaultManager
|
|
966
|
+
? {
|
|
967
|
+
resolveSecrets: (slug) => vaultManager.resolve(`extensions/${slug}`)?.env ?? {},
|
|
968
|
+
}
|
|
969
|
+
: {}),
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
async function createConfiguredAgentSession(params) {
|
|
973
|
+
const { office, systemPrompt, model, thinkingLevel, tools, sessionStore, models, vaultManager, platformNotifier, platformReactor, platformUploader, platformBlockKit, platformDmOpener, platformHistoryFetcher, platformUserLister, extensionScheduleEngine, } = params;
|
|
974
|
+
const { address } = office;
|
|
975
|
+
const conversationId = address.conversationId;
|
|
976
|
+
const workspaceDir = office.workspace.root;
|
|
977
|
+
// Host-only dirs under the state dir: extension code runs in the mikan
|
|
978
|
+
// process, so it must never load from workspace paths — those are mounted
|
|
979
|
+
// into sandbox containers and agent-writable (sandbox escape otherwise).
|
|
980
|
+
// resolveConversationPackages only ever returns state-dir paths (and host
|
|
981
|
+
// paths an administrator named explicitly in settings); it never reaches
|
|
982
|
+
// the network on this path, so a slow remote cannot delay a reply.
|
|
983
|
+
let session;
|
|
984
|
+
const loadedProfiles = loadSubagentProfiles(workspaceDir);
|
|
985
|
+
for (const diagnostic of loadedProfiles.diagnostics) {
|
|
986
|
+
log.logWarning(`[${conversationId}] Subagent profile ignored: ${diagnostic.path}`, diagnostic.message);
|
|
987
|
+
}
|
|
988
|
+
// Narrowed to the profiles whose tools actually exist once extensions have
|
|
989
|
+
// contributed theirs. Both subagent entry points read this at call time, so
|
|
990
|
+
// they always agree on which profiles are launchable.
|
|
991
|
+
let runnableSubagentProfiles = loadedProfiles.profiles;
|
|
992
|
+
const resolvedPackages = resolveConversationPackages({ office });
|
|
993
|
+
for (const error of resolvedPackages.errors) {
|
|
994
|
+
log.logWarning(`Package unavailable: ${error.source}`, error.message);
|
|
995
|
+
}
|
|
996
|
+
const extensionsResult = await loadExtensions({
|
|
997
|
+
dirs: resolvedPackages.extensionDirs,
|
|
998
|
+
roots: resolvedPackages.extensionRoots,
|
|
999
|
+
context: { address, conversationId, workspaceDir, model, thinkingLevel },
|
|
1000
|
+
services: buildExtensionHostServices({
|
|
1001
|
+
workspace: office.workspace,
|
|
1002
|
+
address,
|
|
1003
|
+
vaultManager,
|
|
1004
|
+
platformNotifier,
|
|
1005
|
+
platformReactor,
|
|
1006
|
+
platformUploader,
|
|
1007
|
+
platformBlockKit,
|
|
1008
|
+
platformDmOpener,
|
|
1009
|
+
platformHistoryFetcher,
|
|
1010
|
+
platformUserLister,
|
|
1011
|
+
extensionScheduleEngine,
|
|
1012
|
+
runSubagentService: (request, extensionTools) => {
|
|
1013
|
+
const activeParent = session?.isActiveRun ? session : undefined;
|
|
1014
|
+
return runSubagent({
|
|
1015
|
+
request,
|
|
1016
|
+
defaultModel: model,
|
|
1017
|
+
thinkingLevel,
|
|
1018
|
+
models,
|
|
1019
|
+
workspaceDir,
|
|
1020
|
+
availableTools: [...tools, ...extensionTools],
|
|
1021
|
+
profiles: runnableSubagentProfiles,
|
|
1022
|
+
slots: globalSubagentSlots,
|
|
1023
|
+
...(activeParent
|
|
1024
|
+
? {
|
|
1025
|
+
parentMessages: [...activeParent.messages],
|
|
1026
|
+
onUsage: activeParent.captureExternalUsageSink(),
|
|
1027
|
+
}
|
|
1028
|
+
: {}),
|
|
1029
|
+
});
|
|
1030
|
+
},
|
|
1031
|
+
}),
|
|
1032
|
+
});
|
|
1033
|
+
const contributedTools = extensionsResult.registry.getContributedTools();
|
|
1034
|
+
const subagentAvailableTools = [...tools, ...contributedTools];
|
|
1035
|
+
const availableToolNames = new Set(subagentAvailableTools.map((tool) => tool.name));
|
|
1036
|
+
runnableSubagentProfiles = new Map([...loadedProfiles.profiles].filter(([, profile]) => profile.tools.every((tool) => availableToolNames.has(tool))));
|
|
1037
|
+
for (const err of extensionsResult.errors) {
|
|
1038
|
+
log.logWarning(`[${conversationId}] Extension load error: ${err.path}`, err.error);
|
|
1039
|
+
}
|
|
1040
|
+
if (extensionsResult.extensions.length > 0) {
|
|
1041
|
+
log.logInfo(`[${conversationId}] Loaded ${extensionsResult.extensions.length} extension(s): ${extensionsResult.extensions.map((extension) => extension.name).join(", ")}`);
|
|
1042
|
+
}
|
|
1043
|
+
const subagentTool = createSubagentTool((request, hooks) => runSubagent({
|
|
1044
|
+
request,
|
|
1045
|
+
...(hooks?.onActivity ? { onActivity: hooks.onActivity } : {}),
|
|
1046
|
+
defaultModel: model,
|
|
1047
|
+
thinkingLevel,
|
|
1048
|
+
models,
|
|
1049
|
+
workspaceDir,
|
|
1050
|
+
availableTools: subagentAvailableTools,
|
|
1051
|
+
profiles: runnableSubagentProfiles,
|
|
1052
|
+
slots: globalSubagentSlots,
|
|
1053
|
+
parentMessages: [...session.messages],
|
|
1054
|
+
onUsage: session.captureExternalUsageSink(),
|
|
1055
|
+
}), runnableSubagentProfiles);
|
|
1056
|
+
session = new MikanAgentSession({
|
|
1057
|
+
systemPrompt,
|
|
1058
|
+
model,
|
|
1059
|
+
thinkingLevel,
|
|
1060
|
+
tools: [...tools, subagentTool],
|
|
1061
|
+
models,
|
|
1062
|
+
sessionStore,
|
|
1063
|
+
extensions: extensionsResult.registry,
|
|
1064
|
+
});
|
|
1065
|
+
const activeSession = session;
|
|
1066
|
+
const reloaded = activeSession.reloadFromSession();
|
|
1067
|
+
if (reloaded > 0) {
|
|
1068
|
+
log.logInfo(`[${conversationId}] Reloaded ${reloaded} messages from session context`);
|
|
1069
|
+
}
|
|
1070
|
+
return {
|
|
1071
|
+
session: activeSession,
|
|
1072
|
+
extensionSkills: extensionsResult.skills,
|
|
1073
|
+
extensionRegistry: extensionsResult.registry,
|
|
1074
|
+
disposeExtensions: extensionsResult.dispose,
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
742
1077
|
function reloadSessionMessages(session, conversationId) {
|
|
743
1078
|
const reloaded = session.reloadFromSession();
|
|
744
1079
|
if (reloaded > 0) {
|
|
@@ -746,31 +1081,36 @@ function reloadSessionMessages(session, conversationId) {
|
|
|
746
1081
|
}
|
|
747
1082
|
}
|
|
748
1083
|
async function prepareRunContext(params) {
|
|
749
|
-
const { message, responder, platform,
|
|
1084
|
+
const { message, responder, platform, office, sessionUuid, runState, executor, executionResolver, resolveExecutorForRun, getPathContext, session, setEventContext, setSandboxContext, setUploadFunction, setImageUploadFunction, setReactFunction, bindPlatformToolPacks, } = params;
|
|
1085
|
+
const conversationId = office.address.conversationId;
|
|
750
1086
|
let pathContext = params.pathContext;
|
|
751
|
-
const sessionConversation = message.sessionKey
|
|
752
|
-
await mkdir(join(
|
|
1087
|
+
const sessionConversation = conversationIdOf(message.sessionKey);
|
|
1088
|
+
await mkdir(join(office.dir, "scratch"), { recursive: true });
|
|
753
1089
|
if (executionResolver) {
|
|
754
1090
|
await resolveExecutorForRun({
|
|
755
|
-
|
|
1091
|
+
address: message.address,
|
|
756
1092
|
userId: message.userId,
|
|
757
|
-
|
|
1093
|
+
trustModel: platform.trustModel,
|
|
758
1094
|
});
|
|
759
1095
|
pathContext = getPathContext();
|
|
760
1096
|
}
|
|
761
1097
|
reloadSessionMessages(session, conversationId);
|
|
762
|
-
const
|
|
763
|
-
const
|
|
1098
|
+
const projection = resolveWorkspaceProjection(office);
|
|
1099
|
+
const memory = await getMemory(projection);
|
|
1100
|
+
const conversationSkillLoad = loadMikanSkills(office, pathContext.runtimeWorkspaceRoot, projection);
|
|
1101
|
+
const skills = mergeExtensionSkills(conversationSkillLoad.skills, params.extensionSkills ?? []);
|
|
764
1102
|
const triggerAttribution = resolveTriggerAttribution(message);
|
|
765
|
-
const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot,
|
|
1103
|
+
const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot, office, message.conversationKind, message.userId, memory, executor.getSandboxConfig(), platform, skills, projection, conversationSkillLoad.skippedSkillLinks);
|
|
766
1104
|
session.agent.state.systemPrompt = systemPrompt;
|
|
767
1105
|
// Cache diagnosis: a byte-stable system prompt is the precondition for
|
|
768
1106
|
// provider prompt caching. If this hash changes between turns of one
|
|
769
1107
|
// conversation, something turn-varying leaked into the prompt; if it is
|
|
770
1108
|
// stable and cacheRead stays 0, the miss is provider-side (e.g. OpenRouter
|
|
771
|
-
// routing the model across upstream hosts).
|
|
1109
|
+
// routing the model across upstream hosts). This is the base prompt mikan
|
|
1110
|
+
// builds; a `before_agent_start` extension may still rewrite it per turn
|
|
1111
|
+
// (logged separately by the runner).
|
|
772
1112
|
const promptHash = createHash("sha256").update(systemPrompt).digest("hex").slice(0, 8);
|
|
773
|
-
log.logInfo(`[${conversationId}] System prompt: ${systemPrompt.length} chars, sha ${promptHash}`);
|
|
1113
|
+
log.logInfo(`[${conversationId}] System prompt (base): ${systemPrompt.length} chars, sha ${promptHash}`);
|
|
774
1114
|
setEventContext({
|
|
775
1115
|
platform: platform.name,
|
|
776
1116
|
conversationId,
|
|
@@ -779,18 +1119,33 @@ async function prepareRunContext(params) {
|
|
|
779
1119
|
});
|
|
780
1120
|
setSandboxContext({ conversationId, userId: message.userId });
|
|
781
1121
|
setUploadFunction(async (filePath, title) => {
|
|
782
|
-
const
|
|
1122
|
+
const runtimePath = normalizeAttachRuntimePath(filePath, pathContext.runtimeWorkspaceRoot);
|
|
1123
|
+
await withStagedRuntimeFile(executor, runtimePath, (stagedPath) => responder.uploadFile(stagedPath, title));
|
|
1124
|
+
});
|
|
1125
|
+
// generate_image writes its file host-side, so it uploads by host path —
|
|
1126
|
+
// no staging through the sandbox, where the file may not be mounted.
|
|
1127
|
+
setImageUploadFunction(async (hostPath, title) => {
|
|
783
1128
|
await responder.uploadFile(hostPath, title);
|
|
784
1129
|
});
|
|
1130
|
+
// The react tool is available only when the responder supports reactions
|
|
1131
|
+
// (interactive turns on platforms with reaction support); otherwise unset
|
|
1132
|
+
// so the tool reports it is unavailable rather than silently no-op'ing.
|
|
1133
|
+
setReactFunction(responder.react ? async (emoji) => responder.react(emoji) : null);
|
|
1134
|
+
// Platform capability packs (e.g. GitHub PR/CI) enable themselves per run;
|
|
1135
|
+
// core does not branch on platform name here.
|
|
1136
|
+
bindPlatformToolPacks({
|
|
1137
|
+
conversationId,
|
|
1138
|
+
platformName: platform.name,
|
|
1139
|
+
threadTs: message.threadTs,
|
|
1140
|
+
});
|
|
785
1141
|
resetRunState(runState, responder, sessionConversation, message.userName, sessionUuid, triggerAttribution);
|
|
786
1142
|
const runQueue = createRunQueue(responder, runState);
|
|
787
1143
|
runState.queue = runQueue.queue;
|
|
788
1144
|
log.logInfo(`Context sizes - system: ${systemPrompt.length} chars, memory: ${memory.length} chars`);
|
|
789
1145
|
log.logInfo(`Channels: ${platform.channels.length}, Users: ${platform.users.length}`);
|
|
790
|
-
const { userMessage, imageAttachments } = buildPromptPayload(message, pathContext.runtimeWorkspaceRoot, pathContext);
|
|
1146
|
+
const { userMessage, imageAttachments } = await buildPromptPayload(message, pathContext.runtimeWorkspaceRoot, pathContext, (runtimePath) => executor.readFileBase64(runtimePath));
|
|
791
1147
|
const turnInstructions = buildTurnInstructions(message.id.startsWith("event:"), triggerAttribution, platform.name);
|
|
792
1148
|
const finalUserMessage = turnInstructions ? `${turnInstructions}\n\n${userMessage}` : userMessage;
|
|
793
|
-
await writePromptDebugContext(conversationDir, systemPrompt, session, finalUserMessage, imageAttachments.length);
|
|
794
1149
|
return {
|
|
795
1150
|
sessionConversation,
|
|
796
1151
|
runQueue,
|
|
@@ -800,6 +1155,62 @@ async function prepareRunContext(params) {
|
|
|
800
1155
|
pathContext,
|
|
801
1156
|
};
|
|
802
1157
|
}
|
|
1158
|
+
/**
|
|
1159
|
+
* The dream run reads a transcript in which the agent held its full tool set,
|
|
1160
|
+
* but `sessionDreamTools` has since narrowed it. Left to infer its grant from
|
|
1161
|
+
* the transcript, the model calls a tool it no longer holds and burns one of
|
|
1162
|
+
* its five turns on the failure — so the grant is stated, and derived from the
|
|
1163
|
+
* tools actually handed to the run rather than restated by hand.
|
|
1164
|
+
*/
|
|
1165
|
+
function sessionDreamPrompt(conversationMemoryPath, toolNames) {
|
|
1166
|
+
// read/edit/write are core tools, so an empty grant does not arise today;
|
|
1167
|
+
// the fallback only keeps this sentence coherent if that ever changes.
|
|
1168
|
+
const grant = toolNames.length === 0
|
|
1169
|
+
? "You have no tools in this run and cannot change memory. Say so and stop."
|
|
1170
|
+
: `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.`;
|
|
1171
|
+
return [
|
|
1172
|
+
"Before this conversation is reset or rotated, preserve only durable information worth carrying into future sessions of this same conversation.",
|
|
1173
|
+
`Review the existing transcript and update only the conversation-specific MEMORY.md at ${conversationMemoryPath}.`,
|
|
1174
|
+
grant,
|
|
1175
|
+
"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.",
|
|
1176
|
+
"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.",
|
|
1177
|
+
"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.",
|
|
1178
|
+
].join("\n");
|
|
1179
|
+
}
|
|
1180
|
+
const SESSION_DREAM_BUDGET = {
|
|
1181
|
+
maxDurationMs: 2 * 60 * 1000,
|
|
1182
|
+
maxLlmCalls: 10,
|
|
1183
|
+
};
|
|
1184
|
+
function sessionDreamTools(tools, conversationMemoryPath) {
|
|
1185
|
+
return tools
|
|
1186
|
+
.filter((tool) => tool.name === "read" || tool.name === "edit" || tool.name === "write")
|
|
1187
|
+
.map((tool) => {
|
|
1188
|
+
if (tool.name === "read")
|
|
1189
|
+
return tool;
|
|
1190
|
+
return Object.assign({}, tool, {
|
|
1191
|
+
execute: async (...args) => {
|
|
1192
|
+
const params = args[1];
|
|
1193
|
+
if (params.path !== conversationMemoryPath) {
|
|
1194
|
+
throw new Error(`Session Dream may only modify ${conversationMemoryPath}`);
|
|
1195
|
+
}
|
|
1196
|
+
return tool.execute(...args);
|
|
1197
|
+
},
|
|
1198
|
+
});
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
async function noopResponderMethod() { }
|
|
1202
|
+
function createNoopResponder() {
|
|
1203
|
+
return {
|
|
1204
|
+
respond: noopResponderMethod,
|
|
1205
|
+
replaceResponse: noopResponderMethod,
|
|
1206
|
+
respondDiagnostic: noopResponderMethod,
|
|
1207
|
+
respondToolResult: noopResponderMethod,
|
|
1208
|
+
setTyping: noopResponderMethod,
|
|
1209
|
+
setWorking: noopResponderMethod,
|
|
1210
|
+
uploadFile: noopResponderMethod,
|
|
1211
|
+
deleteResponse: noopResponderMethod,
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
803
1214
|
function formatAgentActorName(userName, fallback) {
|
|
804
1215
|
return userName ? `DM:${userName}` : fallback;
|
|
805
1216
|
}
|
|
@@ -837,7 +1248,12 @@ function attachSessionEventHandlers(params) {
|
|
|
837
1248
|
label: extractToolLabel(event.toolName, event.args),
|
|
838
1249
|
status: "running",
|
|
839
1250
|
});
|
|
840
|
-
|
|
1251
|
+
if (event.toolName === "subagent") {
|
|
1252
|
+
runState.subagentToolCalls.add(event.toolCallId);
|
|
1253
|
+
}
|
|
1254
|
+
else {
|
|
1255
|
+
queue.enqueue(() => replaceResponseWithToolProgress(responder, runState), "tool progress update");
|
|
1256
|
+
}
|
|
841
1257
|
addLifecycleBreadcrumb("agent.tool.started", {
|
|
842
1258
|
tool: event.toolName,
|
|
843
1259
|
...baseAttrs,
|
|
@@ -845,6 +1261,16 @@ function attachSessionEventHandlers(params) {
|
|
|
845
1261
|
log.logToolStart(logCtx, event.toolName, label, event.args);
|
|
846
1262
|
return;
|
|
847
1263
|
}
|
|
1264
|
+
if (event.type === "tool_execution_update") {
|
|
1265
|
+
const subagentProgress = extractSubagentProgress(event.partialResult);
|
|
1266
|
+
if (subagentProgress) {
|
|
1267
|
+
runState.subagentProgress.set(event.toolCallId, subagentProgress);
|
|
1268
|
+
runState.subagentToolCalls.add(event.toolCallId);
|
|
1269
|
+
runState.suppressResponseDeltas = true;
|
|
1270
|
+
scheduleToolProgressUpdate(responder, runState);
|
|
1271
|
+
}
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
848
1274
|
if (event.type === "tool_execution_end") {
|
|
849
1275
|
const resultStr = extractToolResultText(event.result);
|
|
850
1276
|
const pending = pendingTools.get(event.toolCallId);
|
|
@@ -856,7 +1282,15 @@ function attachSessionEventHandlers(params) {
|
|
|
856
1282
|
const progress = runState.toolProgress.get(event.toolCallId);
|
|
857
1283
|
if (progress)
|
|
858
1284
|
progress.status = event.isError ? "error" : "done";
|
|
859
|
-
|
|
1285
|
+
const subagentProgress = runState.subagentProgress.get(event.toolCallId);
|
|
1286
|
+
if (subagentProgress) {
|
|
1287
|
+
runState.subagentProgress.set(event.toolCallId, settleSubagentProgress(subagentProgress, event.isError));
|
|
1288
|
+
}
|
|
1289
|
+
flushToolProgressUpdate(responder, runState);
|
|
1290
|
+
const completedProgress = runState.subagentProgress.get(event.toolCallId);
|
|
1291
|
+
if (completedProgress)
|
|
1292
|
+
runState.completedSubagentProgress.push(completedProgress);
|
|
1293
|
+
runState.subagentProgress.delete(event.toolCallId);
|
|
860
1294
|
pendingTools.delete(event.toolCallId);
|
|
861
1295
|
const durationMs = pending ? Date.now() - pending.startTime : 0;
|
|
862
1296
|
Sentry.metrics.count("agent.tool.calls", 1, {
|
|
@@ -884,6 +1318,9 @@ function attachSessionEventHandlers(params) {
|
|
|
884
1318
|
}
|
|
885
1319
|
else {
|
|
886
1320
|
log.logToolSuccess(logCtx, event.toolName, durationMs, resultStr);
|
|
1321
|
+
if (event.toolName === "slack_blockkit") {
|
|
1322
|
+
runState.finalResponseHandledByTool = true;
|
|
1323
|
+
}
|
|
887
1324
|
}
|
|
888
1325
|
return;
|
|
889
1326
|
}
|
|
@@ -913,7 +1350,7 @@ function attachSessionEventHandlers(params) {
|
|
|
913
1350
|
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
914
1351
|
event: { kind: "responseDelta", delta: assistantMessageEvent.delta },
|
|
915
1352
|
});
|
|
916
|
-
if (responder.appendResponseDelta) {
|
|
1353
|
+
if (responder.appendResponseDelta && !runState.suppressResponseDeltas) {
|
|
917
1354
|
queue.enqueue(async () => {
|
|
918
1355
|
await responder.appendResponseDelta?.(assistantMessageEvent.delta ?? "");
|
|
919
1356
|
}, "response delta");
|
|
@@ -1010,6 +1447,12 @@ function attachSessionEventHandlers(params) {
|
|
|
1010
1447
|
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
1011
1448
|
event: { kind: "turnEnd" },
|
|
1012
1449
|
});
|
|
1450
|
+
// A run that produced a subagent dashboard finalizes through it:
|
|
1451
|
+
// finalizeRunResponse renders "dashboard, blank line, answer", and a
|
|
1452
|
+
// finish here would first overwrite the dashboard with the bare
|
|
1453
|
+
// answer on every platform.
|
|
1454
|
+
if (runState.completedSubagentProgress.length > 0)
|
|
1455
|
+
return;
|
|
1013
1456
|
if (responder.finishResponse) {
|
|
1014
1457
|
queue.enqueue(async () => {
|
|
1015
1458
|
await responder.finishResponse?.(finalText);
|
|
@@ -1069,27 +1512,6 @@ function attachSessionEventHandlers(params) {
|
|
|
1069
1512
|
}
|
|
1070
1513
|
});
|
|
1071
1514
|
}
|
|
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
1515
|
/**
|
|
1094
1516
|
* Create a new PiAgentWrapper for a channel.
|
|
1095
1517
|
* Sets up the session and subscribes to events once.
|
|
@@ -1097,32 +1519,45 @@ function extractToolResultText(result) {
|
|
|
1097
1519
|
* Runner caching is handled by the caller (channelStates in main.ts).
|
|
1098
1520
|
* This is a stateless factory function.
|
|
1099
1521
|
*/
|
|
1100
|
-
export async function createRunner(
|
|
1101
|
-
const
|
|
1102
|
-
const
|
|
1103
|
-
const
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
const
|
|
1107
|
-
|
|
1522
|
+
export async function createRunner(options) {
|
|
1523
|
+
const { sandboxConfig, sessionKey, office, sessionScope, vaultManager, provisioner, resourceController, sessionView, platformNotifier, platformReactor, platformUploader, platformBlockKit, platformDmOpener, platformHistoryFetcher, platformUserLister, extensionScheduleEngine, platformToolPackFactories, } = options;
|
|
1524
|
+
const conversationId = office.address.conversationId;
|
|
1525
|
+
const conversationDir = office.dir;
|
|
1526
|
+
const workspaceDir = office.workspace.root;
|
|
1527
|
+
const agentConfig = resolveConversationSettings(office);
|
|
1528
|
+
const projection = resolveWorkspaceProjection(office);
|
|
1529
|
+
assertSandboxSupportsWorkspacePolicy(sandboxConfig, projection.doorPolicy);
|
|
1530
|
+
const { executionResolver, executor, getPathContext, resolveExecutorForRun } = createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner, office.workspace);
|
|
1531
|
+
let pathContext = getUnresolvedSandboxPathContext(sandboxConfig, workspaceDir);
|
|
1532
|
+
const modelRegistry = options.models ?? MikanModels.create();
|
|
1108
1533
|
if (modelRegistry.getError()) {
|
|
1109
1534
|
log.logWarning("models.json load error", modelRegistry.getError());
|
|
1110
1535
|
}
|
|
1111
|
-
const model =
|
|
1536
|
+
const model = modelRegistry.resolve(agentConfig.provider, agentConfig.model);
|
|
1537
|
+
// Create tools (per-runner, with per-runner upload function setter)
|
|
1538
|
+
const { tools, setUploadFunction, setImageUploadFunction, setReactFunction, bindPlatformToolPacks, setEventContext, setSandboxContext, } = createMikanTools(executor, workspaceDir, { sandbox: sandboxConfig, resourceController: resourceController ?? provisioner }, platformToolPackFactories ?? [], {
|
|
1539
|
+
model,
|
|
1540
|
+
getApiKey: () => modelRegistry.getApiKeyForProvider(model.provider),
|
|
1541
|
+
// The conversation's own office dir: mounted into the sandbox, unlike
|
|
1542
|
+
// the workspace base — generated images must land somewhere the agent
|
|
1543
|
+
// (and a future run) can still reach.
|
|
1544
|
+
outputDir: conversationDir,
|
|
1545
|
+
});
|
|
1112
1546
|
// Initial system prompt (will be updated each run with fresh memory/channels/users/skills)
|
|
1113
|
-
const memory = await getMemory(
|
|
1114
|
-
const skills = loadMikanSkills(
|
|
1547
|
+
const memory = await getMemory(projection);
|
|
1548
|
+
const { skills, skippedSkillLinks } = loadMikanSkills(office, pathContext.runtimeWorkspaceRoot, projection);
|
|
1115
1549
|
const emptyPlatform = {
|
|
1116
1550
|
name: "chat",
|
|
1117
1551
|
formattingGuide: "",
|
|
1118
1552
|
channels: [],
|
|
1119
1553
|
users: [],
|
|
1554
|
+
trustModel: "membership",
|
|
1120
1555
|
};
|
|
1121
|
-
const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot,
|
|
1556
|
+
const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot, office, "shared", undefined, memory, sandboxConfig, emptyPlatform, skills, projection, skippedSkillLinks);
|
|
1122
1557
|
// Create session manager and settings manager. Top-level/private sessions
|
|
1123
1558
|
// use the conversation's current pointer; scoped sessions use fixed files.
|
|
1124
1559
|
// Platform-specific scope behavior is resolved before runner creation.
|
|
1125
|
-
const isThread = sessionKey
|
|
1560
|
+
const isThread = isThreadSessionKey(sessionKey);
|
|
1126
1561
|
const { contextFile, threadRootMessage } = sessionScope;
|
|
1127
1562
|
const sessionManager = openManagedSession(contextFile, pathContext.runtimeWorkspaceRoot);
|
|
1128
1563
|
const threadSessionName = buildThreadSessionName(threadRootMessage);
|
|
@@ -1130,10 +1565,9 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1130
1565
|
sessionManager.appendSessionInfo(threadSessionName);
|
|
1131
1566
|
}
|
|
1132
1567
|
const sessionUuid = extractSessionUuid(contextFile);
|
|
1133
|
-
const chatSessionManager = new
|
|
1134
|
-
const { session, extensionSkills } = await createConfiguredAgentSession({
|
|
1135
|
-
|
|
1136
|
-
workspaceDir,
|
|
1568
|
+
const chatSessionManager = new ChatHistorySync();
|
|
1569
|
+
const { session, extensionSkills, extensionRegistry, disposeExtensions } = await createConfiguredAgentSession({
|
|
1570
|
+
office,
|
|
1137
1571
|
systemPrompt,
|
|
1138
1572
|
model,
|
|
1139
1573
|
thinkingLevel: agentConfig.thinkingLevel,
|
|
@@ -1142,6 +1576,13 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1142
1576
|
models: modelRegistry,
|
|
1143
1577
|
vaultManager,
|
|
1144
1578
|
platformNotifier,
|
|
1579
|
+
platformReactor,
|
|
1580
|
+
platformUploader,
|
|
1581
|
+
platformBlockKit,
|
|
1582
|
+
platformDmOpener,
|
|
1583
|
+
platformHistoryFetcher,
|
|
1584
|
+
platformUserLister,
|
|
1585
|
+
extensionScheduleEngine,
|
|
1145
1586
|
});
|
|
1146
1587
|
// Mutable per-run state - event handler references this
|
|
1147
1588
|
const runState = createRunState();
|
|
@@ -1160,8 +1601,7 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1160
1601
|
message,
|
|
1161
1602
|
responder,
|
|
1162
1603
|
platform,
|
|
1163
|
-
|
|
1164
|
-
conversationDir,
|
|
1604
|
+
office,
|
|
1165
1605
|
sessionUuid,
|
|
1166
1606
|
runState,
|
|
1167
1607
|
executor,
|
|
@@ -1173,6 +1613,9 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1173
1613
|
setEventContext,
|
|
1174
1614
|
setSandboxContext,
|
|
1175
1615
|
setUploadFunction,
|
|
1616
|
+
setImageUploadFunction,
|
|
1617
|
+
setReactFunction,
|
|
1618
|
+
bindPlatformToolPacks,
|
|
1176
1619
|
pathContext,
|
|
1177
1620
|
});
|
|
1178
1621
|
pathContext = prepared.pathContext;
|
|
@@ -1201,10 +1644,39 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1201
1644
|
// Autonomous (event/trigger) runs get an explicit resource ceiling since
|
|
1202
1645
|
// no human is watching the loop; interactive turns stay human-gated.
|
|
1203
1646
|
const isEventRun = message.id.startsWith("event:");
|
|
1204
|
-
|
|
1647
|
+
// Event runs have no triggering platform message, so identity fields
|
|
1648
|
+
// stay unset and extensions must null-check them.
|
|
1649
|
+
const origin = isEventRun
|
|
1650
|
+
? { kind: "event", platform: platform.name }
|
|
1651
|
+
: {
|
|
1652
|
+
kind: "interactive",
|
|
1653
|
+
platform: platform.name,
|
|
1654
|
+
messageTs: message.id,
|
|
1655
|
+
userId: message.userId,
|
|
1656
|
+
userName: message.userName,
|
|
1657
|
+
threadTs: message.threadTs,
|
|
1658
|
+
attachments: message.attachments,
|
|
1659
|
+
};
|
|
1660
|
+
const outcome = await session.prompt(prepared.userMessage, {
|
|
1661
|
+
origin,
|
|
1205
1662
|
...(prepared.imageAttachments.length > 0 ? { images: prepared.imageAttachments } : {}),
|
|
1206
1663
|
...(isEventRun ? { budget: DEFAULT_EVENT_BUDGET } : {}),
|
|
1207
1664
|
});
|
|
1665
|
+
if (outcome?.blocked) {
|
|
1666
|
+
const text = outcome.reason
|
|
1667
|
+
? `_Turn blocked by an extension: ${outcome.reason}_`
|
|
1668
|
+
: "_Turn blocked by an extension._";
|
|
1669
|
+
sendAgentEvent({
|
|
1670
|
+
sessionId: sessionUuid,
|
|
1671
|
+
actorName: formatAgentActorName(message.userName, prepared.sessionConversation),
|
|
1672
|
+
event: { kind: "diagnostic", text },
|
|
1673
|
+
});
|
|
1674
|
+
await responder.respondDiagnostic(text, { style: "muted" });
|
|
1675
|
+
runState.responder = null;
|
|
1676
|
+
runState.logCtx = null;
|
|
1677
|
+
runState.queue = null;
|
|
1678
|
+
return { stopReason: "blocked" };
|
|
1679
|
+
}
|
|
1208
1680
|
// Wait for queued messages
|
|
1209
1681
|
await prepared.runQueue.wait();
|
|
1210
1682
|
const sessionViewTokenStore = sessionView?.tokenStore;
|
|
@@ -1247,9 +1719,89 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1247
1719
|
runState.queue = null;
|
|
1248
1720
|
return { stopReason: runState.stopReason, errorMessage: runState.errorMessage };
|
|
1249
1721
|
},
|
|
1722
|
+
async dreamSessionMemory(message, platform) {
|
|
1723
|
+
const responder = createNoopResponder();
|
|
1724
|
+
const prepared = await prepareRunContext({
|
|
1725
|
+
message,
|
|
1726
|
+
responder,
|
|
1727
|
+
platform,
|
|
1728
|
+
office,
|
|
1729
|
+
sessionUuid,
|
|
1730
|
+
runState,
|
|
1731
|
+
executor,
|
|
1732
|
+
executionResolver,
|
|
1733
|
+
resolveExecutorForRun,
|
|
1734
|
+
getPathContext,
|
|
1735
|
+
session,
|
|
1736
|
+
extensionSkills,
|
|
1737
|
+
setEventContext,
|
|
1738
|
+
setSandboxContext,
|
|
1739
|
+
setUploadFunction,
|
|
1740
|
+
setImageUploadFunction,
|
|
1741
|
+
setReactFunction,
|
|
1742
|
+
bindPlatformToolPacks,
|
|
1743
|
+
pathContext,
|
|
1744
|
+
});
|
|
1745
|
+
pathContext = prepared.pathContext;
|
|
1746
|
+
try {
|
|
1747
|
+
const conversationMemoryPath = posix.join(prepared.pathContext.runtimeWorkspaceRoot, office.key, "MEMORY.md");
|
|
1748
|
+
const dreamTools = sessionDreamTools(session.agent.state.tools, conversationMemoryPath);
|
|
1749
|
+
const outcome = await session.prompt(sessionDreamPrompt(conversationMemoryPath, dreamTools.map((tool) => tool.name)), {
|
|
1750
|
+
origin: {
|
|
1751
|
+
kind: "interactive",
|
|
1752
|
+
platform: platform.name,
|
|
1753
|
+
messageTs: message.id,
|
|
1754
|
+
userId: message.userId,
|
|
1755
|
+
userName: message.userName,
|
|
1756
|
+
threadTs: message.threadTs,
|
|
1757
|
+
attachments: message.attachments,
|
|
1758
|
+
},
|
|
1759
|
+
budget: SESSION_DREAM_BUDGET,
|
|
1760
|
+
tools: dreamTools,
|
|
1761
|
+
});
|
|
1762
|
+
if (outcome?.blocked) {
|
|
1763
|
+
return { stopReason: "blocked", errorMessage: outcome.reason };
|
|
1764
|
+
}
|
|
1765
|
+
await prepared.runQueue.wait();
|
|
1766
|
+
// A budget abort carries its reason in the tally, not in errorMessage,
|
|
1767
|
+
// and that reason is the only thing that tells the user why memory was
|
|
1768
|
+
// not preserved.
|
|
1769
|
+
return {
|
|
1770
|
+
stopReason: runState.stopReason,
|
|
1771
|
+
errorMessage: runState.errorMessage ?? session.getLastRunStats().budgetExceededReason,
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
finally {
|
|
1775
|
+
runState.responder = null;
|
|
1776
|
+
runState.logCtx = null;
|
|
1777
|
+
runState.queue = null;
|
|
1778
|
+
}
|
|
1779
|
+
},
|
|
1250
1780
|
abort() {
|
|
1251
1781
|
session.abort();
|
|
1252
1782
|
},
|
|
1783
|
+
async tryExtensionCommand(message, responder) {
|
|
1784
|
+
const parsed = parseCommandInput(message.text);
|
|
1785
|
+
if (!parsed)
|
|
1786
|
+
return false;
|
|
1787
|
+
return extensionRegistry.dispatchCommand(parsed.name, {
|
|
1788
|
+
args: parsed.args,
|
|
1789
|
+
conversationId,
|
|
1790
|
+
userId: message.userId,
|
|
1791
|
+
userName: message.userName,
|
|
1792
|
+
threadTs: message.threadTs,
|
|
1793
|
+
respond: (text) => responder.respond(text),
|
|
1794
|
+
});
|
|
1795
|
+
},
|
|
1796
|
+
async tryExtensionAction(slug, action) {
|
|
1797
|
+
return extensionRegistry.dispatchAction(slug, action);
|
|
1798
|
+
},
|
|
1799
|
+
async tryExtensionScheduleCallback(slug, callback, event) {
|
|
1800
|
+
return extensionRegistry.dispatchScheduleCallback(slug, callback, event);
|
|
1801
|
+
},
|
|
1802
|
+
async dispose() {
|
|
1803
|
+
await disposeExtensions();
|
|
1804
|
+
},
|
|
1253
1805
|
getCurrentStep() {
|
|
1254
1806
|
const pending = runState.pendingTools;
|
|
1255
1807
|
if (pending.size === 0)
|
|
@@ -1265,13 +1817,4 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1265
1817
|
},
|
|
1266
1818
|
};
|
|
1267
1819
|
}
|
|
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
1820
|
//# sourceMappingURL=agent.js.map
|