@geminixiang/mikan 1.0.0-beta.4 → 1.0.0-beta.40
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 +688 -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 +82 -117
- package/dist/adapters/discord/bot.js.map +1 -1
- 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 +54 -215
- package/dist/adapters/discord/context.js.map +1 -1
- 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/progressive-renderer.d.ts +7 -0
- package/dist/adapters/progressive-renderer.d.ts.map +1 -0
- package/dist/adapters/progressive-renderer.js +383 -0
- package/dist/adapters/progressive-renderer.js.map +1 -0
- package/dist/adapters/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/blocks.d.ts +14 -0
- package/dist/adapters/slack/blocks.d.ts.map +1 -1
- package/dist/adapters/slack/blocks.js +147 -111
- package/dist/adapters/slack/blocks.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +43 -13
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +385 -207
- 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 +126 -323
- package/dist/adapters/slack/response-lifecycle.js.map +1 -1
- package/dist/adapters/slack/session.d.ts.map +1 -1
- package/dist/adapters/slack/session.js +7 -11
- package/dist/adapters/slack/session.js.map +1 -1
- package/dist/adapters/slack/tool-pack.d.ts +11 -0
- package/dist/adapters/slack/tool-pack.d.ts.map +1 -0
- package/dist/adapters/slack/tool-pack.js +45 -0
- package/dist/adapters/slack/tool-pack.js.map +1 -0
- package/dist/adapters/slack/tools/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 +90 -117
- 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 +61 -184
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/adapters/telegram/html.d.ts.map +1 -1
- package/dist/adapters/telegram/html.js +10 -7
- package/dist/adapters/telegram/html.js.map +1 -1
- package/dist/adapters/types.d.ts +109 -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 +840 -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.map +1 -1
- package/dist/commands/extensions.js +9 -6
- 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 +229 -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 +39 -0
- package/dist/harness/subagent-runner.d.ts.map +1 -0
- package/dist/harness/subagent-runner.js +617 -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 +43 -0
- package/dist/subagent-progress.d.ts.map +1 -0
- package/dist/subagent-progress.js +220 -0
- package/dist/subagent-progress.js.map +1 -0
- package/dist/tools/bash.d.ts +3 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +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 +54 -0
- package/dist/tools/subagent.d.ts.map +1 -0
- package/dist/tools/subagent.js +411 -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 +403 -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 +846 -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 +67 -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/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,225 @@ 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) => runSubagent({
|
|
1044
|
+
request,
|
|
1045
|
+
defaultModel: model,
|
|
1046
|
+
thinkingLevel,
|
|
1047
|
+
models,
|
|
1048
|
+
workspaceDir,
|
|
1049
|
+
availableTools: subagentAvailableTools,
|
|
1050
|
+
profiles: runnableSubagentProfiles,
|
|
1051
|
+
slots: globalSubagentSlots,
|
|
1052
|
+
parentMessages: [...session.messages],
|
|
1053
|
+
onUsage: session.captureExternalUsageSink(),
|
|
1054
|
+
}), runnableSubagentProfiles);
|
|
1055
|
+
session = new MikanAgentSession({
|
|
1056
|
+
systemPrompt,
|
|
1057
|
+
model,
|
|
1058
|
+
thinkingLevel,
|
|
1059
|
+
tools: [...tools, subagentTool],
|
|
1060
|
+
models,
|
|
1061
|
+
sessionStore,
|
|
1062
|
+
extensions: extensionsResult.registry,
|
|
1063
|
+
});
|
|
1064
|
+
const activeSession = session;
|
|
1065
|
+
const reloaded = activeSession.reloadFromSession();
|
|
1066
|
+
if (reloaded > 0) {
|
|
1067
|
+
log.logInfo(`[${conversationId}] Reloaded ${reloaded} messages from session context`);
|
|
1068
|
+
}
|
|
1069
|
+
return {
|
|
1070
|
+
session: activeSession,
|
|
1071
|
+
extensionSkills: extensionsResult.skills,
|
|
1072
|
+
extensionRegistry: extensionsResult.registry,
|
|
1073
|
+
disposeExtensions: extensionsResult.dispose,
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
742
1076
|
function reloadSessionMessages(session, conversationId) {
|
|
743
1077
|
const reloaded = session.reloadFromSession();
|
|
744
1078
|
if (reloaded > 0) {
|
|
@@ -746,31 +1080,36 @@ function reloadSessionMessages(session, conversationId) {
|
|
|
746
1080
|
}
|
|
747
1081
|
}
|
|
748
1082
|
async function prepareRunContext(params) {
|
|
749
|
-
const { message, responder, platform,
|
|
1083
|
+
const { message, responder, platform, office, sessionUuid, runState, executor, executionResolver, resolveExecutorForRun, getPathContext, session, setEventContext, setSandboxContext, setUploadFunction, setImageUploadFunction, setReactFunction, bindPlatformToolPacks, } = params;
|
|
1084
|
+
const conversationId = office.address.conversationId;
|
|
750
1085
|
let pathContext = params.pathContext;
|
|
751
|
-
const sessionConversation = message.sessionKey
|
|
752
|
-
await mkdir(join(
|
|
1086
|
+
const sessionConversation = conversationIdOf(message.sessionKey);
|
|
1087
|
+
await mkdir(join(office.dir, "scratch"), { recursive: true });
|
|
753
1088
|
if (executionResolver) {
|
|
754
1089
|
await resolveExecutorForRun({
|
|
755
|
-
|
|
1090
|
+
address: message.address,
|
|
756
1091
|
userId: message.userId,
|
|
757
|
-
|
|
1092
|
+
trustModel: platform.trustModel,
|
|
758
1093
|
});
|
|
759
1094
|
pathContext = getPathContext();
|
|
760
1095
|
}
|
|
761
1096
|
reloadSessionMessages(session, conversationId);
|
|
762
|
-
const
|
|
763
|
-
const
|
|
1097
|
+
const projection = resolveWorkspaceProjection(office);
|
|
1098
|
+
const memory = await getMemory(projection);
|
|
1099
|
+
const conversationSkillLoad = loadMikanSkills(office, pathContext.runtimeWorkspaceRoot, projection);
|
|
1100
|
+
const skills = mergeExtensionSkills(conversationSkillLoad.skills, params.extensionSkills ?? []);
|
|
764
1101
|
const triggerAttribution = resolveTriggerAttribution(message);
|
|
765
|
-
const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot,
|
|
1102
|
+
const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot, office, message.conversationKind, message.userId, memory, executor.getSandboxConfig(), platform, skills, projection, conversationSkillLoad.skippedSkillLinks);
|
|
766
1103
|
session.agent.state.systemPrompt = systemPrompt;
|
|
767
1104
|
// Cache diagnosis: a byte-stable system prompt is the precondition for
|
|
768
1105
|
// provider prompt caching. If this hash changes between turns of one
|
|
769
1106
|
// conversation, something turn-varying leaked into the prompt; if it is
|
|
770
1107
|
// stable and cacheRead stays 0, the miss is provider-side (e.g. OpenRouter
|
|
771
|
-
// routing the model across upstream hosts).
|
|
1108
|
+
// routing the model across upstream hosts). This is the base prompt mikan
|
|
1109
|
+
// builds; a `before_agent_start` extension may still rewrite it per turn
|
|
1110
|
+
// (logged separately by the runner).
|
|
772
1111
|
const promptHash = createHash("sha256").update(systemPrompt).digest("hex").slice(0, 8);
|
|
773
|
-
log.logInfo(`[${conversationId}] System prompt: ${systemPrompt.length} chars, sha ${promptHash}`);
|
|
1112
|
+
log.logInfo(`[${conversationId}] System prompt (base): ${systemPrompt.length} chars, sha ${promptHash}`);
|
|
774
1113
|
setEventContext({
|
|
775
1114
|
platform: platform.name,
|
|
776
1115
|
conversationId,
|
|
@@ -779,18 +1118,33 @@ async function prepareRunContext(params) {
|
|
|
779
1118
|
});
|
|
780
1119
|
setSandboxContext({ conversationId, userId: message.userId });
|
|
781
1120
|
setUploadFunction(async (filePath, title) => {
|
|
782
|
-
const
|
|
1121
|
+
const runtimePath = normalizeAttachRuntimePath(filePath, pathContext.runtimeWorkspaceRoot);
|
|
1122
|
+
await withStagedRuntimeFile(executor, runtimePath, (stagedPath) => responder.uploadFile(stagedPath, title));
|
|
1123
|
+
});
|
|
1124
|
+
// generate_image writes its file host-side, so it uploads by host path —
|
|
1125
|
+
// no staging through the sandbox, where the file may not be mounted.
|
|
1126
|
+
setImageUploadFunction(async (hostPath, title) => {
|
|
783
1127
|
await responder.uploadFile(hostPath, title);
|
|
784
1128
|
});
|
|
1129
|
+
// The react tool is available only when the responder supports reactions
|
|
1130
|
+
// (interactive turns on platforms with reaction support); otherwise unset
|
|
1131
|
+
// so the tool reports it is unavailable rather than silently no-op'ing.
|
|
1132
|
+
setReactFunction(responder.react ? async (emoji) => responder.react(emoji) : null);
|
|
1133
|
+
// Platform capability packs (e.g. GitHub PR/CI) enable themselves per run;
|
|
1134
|
+
// core does not branch on platform name here.
|
|
1135
|
+
bindPlatformToolPacks({
|
|
1136
|
+
conversationId,
|
|
1137
|
+
platformName: platform.name,
|
|
1138
|
+
threadTs: message.threadTs,
|
|
1139
|
+
});
|
|
785
1140
|
resetRunState(runState, responder, sessionConversation, message.userName, sessionUuid, triggerAttribution);
|
|
786
1141
|
const runQueue = createRunQueue(responder, runState);
|
|
787
1142
|
runState.queue = runQueue.queue;
|
|
788
1143
|
log.logInfo(`Context sizes - system: ${systemPrompt.length} chars, memory: ${memory.length} chars`);
|
|
789
1144
|
log.logInfo(`Channels: ${platform.channels.length}, Users: ${platform.users.length}`);
|
|
790
|
-
const { userMessage, imageAttachments } = buildPromptPayload(message, pathContext.runtimeWorkspaceRoot, pathContext);
|
|
1145
|
+
const { userMessage, imageAttachments } = await buildPromptPayload(message, pathContext.runtimeWorkspaceRoot, pathContext, (runtimePath) => executor.readFileBase64(runtimePath));
|
|
791
1146
|
const turnInstructions = buildTurnInstructions(message.id.startsWith("event:"), triggerAttribution, platform.name);
|
|
792
1147
|
const finalUserMessage = turnInstructions ? `${turnInstructions}\n\n${userMessage}` : userMessage;
|
|
793
|
-
await writePromptDebugContext(conversationDir, systemPrompt, session, finalUserMessage, imageAttachments.length);
|
|
794
1148
|
return {
|
|
795
1149
|
sessionConversation,
|
|
796
1150
|
runQueue,
|
|
@@ -800,6 +1154,62 @@ async function prepareRunContext(params) {
|
|
|
800
1154
|
pathContext,
|
|
801
1155
|
};
|
|
802
1156
|
}
|
|
1157
|
+
/**
|
|
1158
|
+
* The dream run reads a transcript in which the agent held its full tool set,
|
|
1159
|
+
* but `sessionDreamTools` has since narrowed it. Left to infer its grant from
|
|
1160
|
+
* the transcript, the model calls a tool it no longer holds and burns one of
|
|
1161
|
+
* its five turns on the failure — so the grant is stated, and derived from the
|
|
1162
|
+
* tools actually handed to the run rather than restated by hand.
|
|
1163
|
+
*/
|
|
1164
|
+
function sessionDreamPrompt(conversationMemoryPath, toolNames) {
|
|
1165
|
+
// read/edit/write are core tools, so an empty grant does not arise today;
|
|
1166
|
+
// the fallback only keeps this sentence coherent if that ever changes.
|
|
1167
|
+
const grant = toolNames.length === 0
|
|
1168
|
+
? "You have no tools in this run and cannot change memory. Say so and stop."
|
|
1169
|
+
: `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.`;
|
|
1170
|
+
return [
|
|
1171
|
+
"Before this conversation is reset or rotated, preserve only durable information worth carrying into future sessions of this same conversation.",
|
|
1172
|
+
`Review the existing transcript and update only the conversation-specific MEMORY.md at ${conversationMemoryPath}.`,
|
|
1173
|
+
grant,
|
|
1174
|
+
"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.",
|
|
1175
|
+
"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.",
|
|
1176
|
+
"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.",
|
|
1177
|
+
].join("\n");
|
|
1178
|
+
}
|
|
1179
|
+
const SESSION_DREAM_BUDGET = {
|
|
1180
|
+
maxDurationMs: 2 * 60 * 1000,
|
|
1181
|
+
maxLlmCalls: 10,
|
|
1182
|
+
};
|
|
1183
|
+
function sessionDreamTools(tools, conversationMemoryPath) {
|
|
1184
|
+
return tools
|
|
1185
|
+
.filter((tool) => tool.name === "read" || tool.name === "edit" || tool.name === "write")
|
|
1186
|
+
.map((tool) => {
|
|
1187
|
+
if (tool.name === "read")
|
|
1188
|
+
return tool;
|
|
1189
|
+
return Object.assign({}, tool, {
|
|
1190
|
+
execute: async (...args) => {
|
|
1191
|
+
const params = args[1];
|
|
1192
|
+
if (params.path !== conversationMemoryPath) {
|
|
1193
|
+
throw new Error(`Session Dream may only modify ${conversationMemoryPath}`);
|
|
1194
|
+
}
|
|
1195
|
+
return tool.execute(...args);
|
|
1196
|
+
},
|
|
1197
|
+
});
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
async function noopResponderMethod() { }
|
|
1201
|
+
function createNoopResponder() {
|
|
1202
|
+
return {
|
|
1203
|
+
respond: noopResponderMethod,
|
|
1204
|
+
replaceResponse: noopResponderMethod,
|
|
1205
|
+
respondDiagnostic: noopResponderMethod,
|
|
1206
|
+
respondToolResult: noopResponderMethod,
|
|
1207
|
+
setTyping: noopResponderMethod,
|
|
1208
|
+
setWorking: noopResponderMethod,
|
|
1209
|
+
uploadFile: noopResponderMethod,
|
|
1210
|
+
deleteResponse: noopResponderMethod,
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
803
1213
|
function formatAgentActorName(userName, fallback) {
|
|
804
1214
|
return userName ? `DM:${userName}` : fallback;
|
|
805
1215
|
}
|
|
@@ -837,7 +1247,12 @@ function attachSessionEventHandlers(params) {
|
|
|
837
1247
|
label: extractToolLabel(event.toolName, event.args),
|
|
838
1248
|
status: "running",
|
|
839
1249
|
});
|
|
840
|
-
|
|
1250
|
+
if (event.toolName === "subagent") {
|
|
1251
|
+
runState.subagentToolCalls.add(event.toolCallId);
|
|
1252
|
+
}
|
|
1253
|
+
else {
|
|
1254
|
+
queue.enqueue(() => replaceResponseWithToolProgress(responder, runState), "tool progress update");
|
|
1255
|
+
}
|
|
841
1256
|
addLifecycleBreadcrumb("agent.tool.started", {
|
|
842
1257
|
tool: event.toolName,
|
|
843
1258
|
...baseAttrs,
|
|
@@ -845,6 +1260,16 @@ function attachSessionEventHandlers(params) {
|
|
|
845
1260
|
log.logToolStart(logCtx, event.toolName, label, event.args);
|
|
846
1261
|
return;
|
|
847
1262
|
}
|
|
1263
|
+
if (event.type === "tool_execution_update") {
|
|
1264
|
+
const subagentProgress = extractSubagentProgress(event.partialResult);
|
|
1265
|
+
if (subagentProgress) {
|
|
1266
|
+
runState.subagentProgress.set(event.toolCallId, subagentProgress);
|
|
1267
|
+
runState.subagentToolCalls.add(event.toolCallId);
|
|
1268
|
+
runState.suppressResponseDeltas = true;
|
|
1269
|
+
scheduleToolProgressUpdate(responder, runState);
|
|
1270
|
+
}
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
848
1273
|
if (event.type === "tool_execution_end") {
|
|
849
1274
|
const resultStr = extractToolResultText(event.result);
|
|
850
1275
|
const pending = pendingTools.get(event.toolCallId);
|
|
@@ -856,7 +1281,15 @@ function attachSessionEventHandlers(params) {
|
|
|
856
1281
|
const progress = runState.toolProgress.get(event.toolCallId);
|
|
857
1282
|
if (progress)
|
|
858
1283
|
progress.status = event.isError ? "error" : "done";
|
|
859
|
-
|
|
1284
|
+
const subagentProgress = runState.subagentProgress.get(event.toolCallId);
|
|
1285
|
+
if (subagentProgress) {
|
|
1286
|
+
runState.subagentProgress.set(event.toolCallId, settleSubagentProgress(subagentProgress, event.isError));
|
|
1287
|
+
}
|
|
1288
|
+
flushToolProgressUpdate(responder, runState);
|
|
1289
|
+
const completedProgress = runState.subagentProgress.get(event.toolCallId);
|
|
1290
|
+
if (completedProgress)
|
|
1291
|
+
runState.completedSubagentProgress.push(completedProgress);
|
|
1292
|
+
runState.subagentProgress.delete(event.toolCallId);
|
|
860
1293
|
pendingTools.delete(event.toolCallId);
|
|
861
1294
|
const durationMs = pending ? Date.now() - pending.startTime : 0;
|
|
862
1295
|
Sentry.metrics.count("agent.tool.calls", 1, {
|
|
@@ -884,6 +1317,9 @@ function attachSessionEventHandlers(params) {
|
|
|
884
1317
|
}
|
|
885
1318
|
else {
|
|
886
1319
|
log.logToolSuccess(logCtx, event.toolName, durationMs, resultStr);
|
|
1320
|
+
if (event.toolName === "slack_blockkit") {
|
|
1321
|
+
runState.finalResponseHandledByTool = true;
|
|
1322
|
+
}
|
|
887
1323
|
}
|
|
888
1324
|
return;
|
|
889
1325
|
}
|
|
@@ -913,7 +1349,7 @@ function attachSessionEventHandlers(params) {
|
|
|
913
1349
|
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
914
1350
|
event: { kind: "responseDelta", delta: assistantMessageEvent.delta },
|
|
915
1351
|
});
|
|
916
|
-
if (responder.appendResponseDelta) {
|
|
1352
|
+
if (responder.appendResponseDelta && !runState.suppressResponseDeltas) {
|
|
917
1353
|
queue.enqueue(async () => {
|
|
918
1354
|
await responder.appendResponseDelta?.(assistantMessageEvent.delta ?? "");
|
|
919
1355
|
}, "response delta");
|
|
@@ -1010,6 +1446,12 @@ function attachSessionEventHandlers(params) {
|
|
|
1010
1446
|
actorName: formatAgentActorName(logCtx.userName, logCtx.conversationId),
|
|
1011
1447
|
event: { kind: "turnEnd" },
|
|
1012
1448
|
});
|
|
1449
|
+
// A run that produced a subagent dashboard finalizes through it:
|
|
1450
|
+
// finalizeRunResponse renders "dashboard, blank line, answer", and a
|
|
1451
|
+
// finish here would first overwrite the dashboard with the bare
|
|
1452
|
+
// answer on every platform.
|
|
1453
|
+
if (runState.completedSubagentProgress.length > 0)
|
|
1454
|
+
return;
|
|
1013
1455
|
if (responder.finishResponse) {
|
|
1014
1456
|
queue.enqueue(async () => {
|
|
1015
1457
|
await responder.finishResponse?.(finalText);
|
|
@@ -1069,27 +1511,6 @@ function attachSessionEventHandlers(params) {
|
|
|
1069
1511
|
}
|
|
1070
1512
|
});
|
|
1071
1513
|
}
|
|
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
1514
|
/**
|
|
1094
1515
|
* Create a new PiAgentWrapper for a channel.
|
|
1095
1516
|
* Sets up the session and subscribes to events once.
|
|
@@ -1097,32 +1518,45 @@ function extractToolResultText(result) {
|
|
|
1097
1518
|
* Runner caching is handled by the caller (channelStates in main.ts).
|
|
1098
1519
|
* This is a stateless factory function.
|
|
1099
1520
|
*/
|
|
1100
|
-
export async function createRunner(
|
|
1101
|
-
const
|
|
1102
|
-
const
|
|
1103
|
-
const
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
const
|
|
1107
|
-
|
|
1521
|
+
export async function createRunner(options) {
|
|
1522
|
+
const { sandboxConfig, sessionKey, office, sessionScope, vaultManager, provisioner, resourceController, sessionView, platformNotifier, platformReactor, platformUploader, platformBlockKit, platformDmOpener, platformHistoryFetcher, platformUserLister, extensionScheduleEngine, platformToolPackFactories, } = options;
|
|
1523
|
+
const conversationId = office.address.conversationId;
|
|
1524
|
+
const conversationDir = office.dir;
|
|
1525
|
+
const workspaceDir = office.workspace.root;
|
|
1526
|
+
const agentConfig = resolveConversationSettings(office);
|
|
1527
|
+
const projection = resolveWorkspaceProjection(office);
|
|
1528
|
+
assertSandboxSupportsWorkspacePolicy(sandboxConfig, projection.doorPolicy);
|
|
1529
|
+
const { executionResolver, executor, getPathContext, resolveExecutorForRun } = createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner, office.workspace);
|
|
1530
|
+
let pathContext = getUnresolvedSandboxPathContext(sandboxConfig, workspaceDir);
|
|
1531
|
+
const modelRegistry = options.models ?? MikanModels.create();
|
|
1108
1532
|
if (modelRegistry.getError()) {
|
|
1109
1533
|
log.logWarning("models.json load error", modelRegistry.getError());
|
|
1110
1534
|
}
|
|
1111
|
-
const model =
|
|
1535
|
+
const model = modelRegistry.resolve(agentConfig.provider, agentConfig.model);
|
|
1536
|
+
// Create tools (per-runner, with per-runner upload function setter)
|
|
1537
|
+
const { tools, setUploadFunction, setImageUploadFunction, setReactFunction, bindPlatformToolPacks, setEventContext, setSandboxContext, } = createMikanTools(executor, workspaceDir, { sandbox: sandboxConfig, resourceController: resourceController ?? provisioner }, platformToolPackFactories ?? [], {
|
|
1538
|
+
model,
|
|
1539
|
+
getApiKey: () => modelRegistry.getApiKeyForProvider(model.provider),
|
|
1540
|
+
// The conversation's own office dir: mounted into the sandbox, unlike
|
|
1541
|
+
// the workspace base — generated images must land somewhere the agent
|
|
1542
|
+
// (and a future run) can still reach.
|
|
1543
|
+
outputDir: conversationDir,
|
|
1544
|
+
});
|
|
1112
1545
|
// Initial system prompt (will be updated each run with fresh memory/channels/users/skills)
|
|
1113
|
-
const memory = await getMemory(
|
|
1114
|
-
const skills = loadMikanSkills(
|
|
1546
|
+
const memory = await getMemory(projection);
|
|
1547
|
+
const { skills, skippedSkillLinks } = loadMikanSkills(office, pathContext.runtimeWorkspaceRoot, projection);
|
|
1115
1548
|
const emptyPlatform = {
|
|
1116
1549
|
name: "chat",
|
|
1117
1550
|
formattingGuide: "",
|
|
1118
1551
|
channels: [],
|
|
1119
1552
|
users: [],
|
|
1553
|
+
trustModel: "membership",
|
|
1120
1554
|
};
|
|
1121
|
-
const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot,
|
|
1555
|
+
const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot, office, "shared", undefined, memory, sandboxConfig, emptyPlatform, skills, projection, skippedSkillLinks);
|
|
1122
1556
|
// Create session manager and settings manager. Top-level/private sessions
|
|
1123
1557
|
// use the conversation's current pointer; scoped sessions use fixed files.
|
|
1124
1558
|
// Platform-specific scope behavior is resolved before runner creation.
|
|
1125
|
-
const isThread = sessionKey
|
|
1559
|
+
const isThread = isThreadSessionKey(sessionKey);
|
|
1126
1560
|
const { contextFile, threadRootMessage } = sessionScope;
|
|
1127
1561
|
const sessionManager = openManagedSession(contextFile, pathContext.runtimeWorkspaceRoot);
|
|
1128
1562
|
const threadSessionName = buildThreadSessionName(threadRootMessage);
|
|
@@ -1130,10 +1564,9 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1130
1564
|
sessionManager.appendSessionInfo(threadSessionName);
|
|
1131
1565
|
}
|
|
1132
1566
|
const sessionUuid = extractSessionUuid(contextFile);
|
|
1133
|
-
const chatSessionManager = new
|
|
1134
|
-
const { session, extensionSkills } = await createConfiguredAgentSession({
|
|
1135
|
-
|
|
1136
|
-
workspaceDir,
|
|
1567
|
+
const chatSessionManager = new ChatHistorySync();
|
|
1568
|
+
const { session, extensionSkills, extensionRegistry, disposeExtensions } = await createConfiguredAgentSession({
|
|
1569
|
+
office,
|
|
1137
1570
|
systemPrompt,
|
|
1138
1571
|
model,
|
|
1139
1572
|
thinkingLevel: agentConfig.thinkingLevel,
|
|
@@ -1142,6 +1575,13 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1142
1575
|
models: modelRegistry,
|
|
1143
1576
|
vaultManager,
|
|
1144
1577
|
platformNotifier,
|
|
1578
|
+
platformReactor,
|
|
1579
|
+
platformUploader,
|
|
1580
|
+
platformBlockKit,
|
|
1581
|
+
platformDmOpener,
|
|
1582
|
+
platformHistoryFetcher,
|
|
1583
|
+
platformUserLister,
|
|
1584
|
+
extensionScheduleEngine,
|
|
1145
1585
|
});
|
|
1146
1586
|
// Mutable per-run state - event handler references this
|
|
1147
1587
|
const runState = createRunState();
|
|
@@ -1160,8 +1600,7 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1160
1600
|
message,
|
|
1161
1601
|
responder,
|
|
1162
1602
|
platform,
|
|
1163
|
-
|
|
1164
|
-
conversationDir,
|
|
1603
|
+
office,
|
|
1165
1604
|
sessionUuid,
|
|
1166
1605
|
runState,
|
|
1167
1606
|
executor,
|
|
@@ -1173,6 +1612,9 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1173
1612
|
setEventContext,
|
|
1174
1613
|
setSandboxContext,
|
|
1175
1614
|
setUploadFunction,
|
|
1615
|
+
setImageUploadFunction,
|
|
1616
|
+
setReactFunction,
|
|
1617
|
+
bindPlatformToolPacks,
|
|
1176
1618
|
pathContext,
|
|
1177
1619
|
});
|
|
1178
1620
|
pathContext = prepared.pathContext;
|
|
@@ -1201,10 +1643,39 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1201
1643
|
// Autonomous (event/trigger) runs get an explicit resource ceiling since
|
|
1202
1644
|
// no human is watching the loop; interactive turns stay human-gated.
|
|
1203
1645
|
const isEventRun = message.id.startsWith("event:");
|
|
1204
|
-
|
|
1646
|
+
// Event runs have no triggering platform message, so identity fields
|
|
1647
|
+
// stay unset and extensions must null-check them.
|
|
1648
|
+
const origin = isEventRun
|
|
1649
|
+
? { kind: "event", platform: platform.name }
|
|
1650
|
+
: {
|
|
1651
|
+
kind: "interactive",
|
|
1652
|
+
platform: platform.name,
|
|
1653
|
+
messageTs: message.id,
|
|
1654
|
+
userId: message.userId,
|
|
1655
|
+
userName: message.userName,
|
|
1656
|
+
threadTs: message.threadTs,
|
|
1657
|
+
attachments: message.attachments,
|
|
1658
|
+
};
|
|
1659
|
+
const outcome = await session.prompt(prepared.userMessage, {
|
|
1660
|
+
origin,
|
|
1205
1661
|
...(prepared.imageAttachments.length > 0 ? { images: prepared.imageAttachments } : {}),
|
|
1206
1662
|
...(isEventRun ? { budget: DEFAULT_EVENT_BUDGET } : {}),
|
|
1207
1663
|
});
|
|
1664
|
+
if (outcome?.blocked) {
|
|
1665
|
+
const text = outcome.reason
|
|
1666
|
+
? `_Turn blocked by an extension: ${outcome.reason}_`
|
|
1667
|
+
: "_Turn blocked by an extension._";
|
|
1668
|
+
sendAgentEvent({
|
|
1669
|
+
sessionId: sessionUuid,
|
|
1670
|
+
actorName: formatAgentActorName(message.userName, prepared.sessionConversation),
|
|
1671
|
+
event: { kind: "diagnostic", text },
|
|
1672
|
+
});
|
|
1673
|
+
await responder.respondDiagnostic(text, { style: "muted" });
|
|
1674
|
+
runState.responder = null;
|
|
1675
|
+
runState.logCtx = null;
|
|
1676
|
+
runState.queue = null;
|
|
1677
|
+
return { stopReason: "blocked" };
|
|
1678
|
+
}
|
|
1208
1679
|
// Wait for queued messages
|
|
1209
1680
|
await prepared.runQueue.wait();
|
|
1210
1681
|
const sessionViewTokenStore = sessionView?.tokenStore;
|
|
@@ -1247,9 +1718,89 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1247
1718
|
runState.queue = null;
|
|
1248
1719
|
return { stopReason: runState.stopReason, errorMessage: runState.errorMessage };
|
|
1249
1720
|
},
|
|
1721
|
+
async dreamSessionMemory(message, platform) {
|
|
1722
|
+
const responder = createNoopResponder();
|
|
1723
|
+
const prepared = await prepareRunContext({
|
|
1724
|
+
message,
|
|
1725
|
+
responder,
|
|
1726
|
+
platform,
|
|
1727
|
+
office,
|
|
1728
|
+
sessionUuid,
|
|
1729
|
+
runState,
|
|
1730
|
+
executor,
|
|
1731
|
+
executionResolver,
|
|
1732
|
+
resolveExecutorForRun,
|
|
1733
|
+
getPathContext,
|
|
1734
|
+
session,
|
|
1735
|
+
extensionSkills,
|
|
1736
|
+
setEventContext,
|
|
1737
|
+
setSandboxContext,
|
|
1738
|
+
setUploadFunction,
|
|
1739
|
+
setImageUploadFunction,
|
|
1740
|
+
setReactFunction,
|
|
1741
|
+
bindPlatformToolPacks,
|
|
1742
|
+
pathContext,
|
|
1743
|
+
});
|
|
1744
|
+
pathContext = prepared.pathContext;
|
|
1745
|
+
try {
|
|
1746
|
+
const conversationMemoryPath = posix.join(prepared.pathContext.runtimeWorkspaceRoot, office.key, "MEMORY.md");
|
|
1747
|
+
const dreamTools = sessionDreamTools(session.agent.state.tools, conversationMemoryPath);
|
|
1748
|
+
const outcome = await session.prompt(sessionDreamPrompt(conversationMemoryPath, dreamTools.map((tool) => tool.name)), {
|
|
1749
|
+
origin: {
|
|
1750
|
+
kind: "interactive",
|
|
1751
|
+
platform: platform.name,
|
|
1752
|
+
messageTs: message.id,
|
|
1753
|
+
userId: message.userId,
|
|
1754
|
+
userName: message.userName,
|
|
1755
|
+
threadTs: message.threadTs,
|
|
1756
|
+
attachments: message.attachments,
|
|
1757
|
+
},
|
|
1758
|
+
budget: SESSION_DREAM_BUDGET,
|
|
1759
|
+
tools: dreamTools,
|
|
1760
|
+
});
|
|
1761
|
+
if (outcome?.blocked) {
|
|
1762
|
+
return { stopReason: "blocked", errorMessage: outcome.reason };
|
|
1763
|
+
}
|
|
1764
|
+
await prepared.runQueue.wait();
|
|
1765
|
+
// A budget abort carries its reason in the tally, not in errorMessage,
|
|
1766
|
+
// and that reason is the only thing that tells the user why memory was
|
|
1767
|
+
// not preserved.
|
|
1768
|
+
return {
|
|
1769
|
+
stopReason: runState.stopReason,
|
|
1770
|
+
errorMessage: runState.errorMessage ?? session.getLastRunStats().budgetExceededReason,
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
finally {
|
|
1774
|
+
runState.responder = null;
|
|
1775
|
+
runState.logCtx = null;
|
|
1776
|
+
runState.queue = null;
|
|
1777
|
+
}
|
|
1778
|
+
},
|
|
1250
1779
|
abort() {
|
|
1251
1780
|
session.abort();
|
|
1252
1781
|
},
|
|
1782
|
+
async tryExtensionCommand(message, responder) {
|
|
1783
|
+
const parsed = parseCommandInput(message.text);
|
|
1784
|
+
if (!parsed)
|
|
1785
|
+
return false;
|
|
1786
|
+
return extensionRegistry.dispatchCommand(parsed.name, {
|
|
1787
|
+
args: parsed.args,
|
|
1788
|
+
conversationId,
|
|
1789
|
+
userId: message.userId,
|
|
1790
|
+
userName: message.userName,
|
|
1791
|
+
threadTs: message.threadTs,
|
|
1792
|
+
respond: (text) => responder.respond(text),
|
|
1793
|
+
});
|
|
1794
|
+
},
|
|
1795
|
+
async tryExtensionAction(slug, action) {
|
|
1796
|
+
return extensionRegistry.dispatchAction(slug, action);
|
|
1797
|
+
},
|
|
1798
|
+
async tryExtensionScheduleCallback(slug, callback, event) {
|
|
1799
|
+
return extensionRegistry.dispatchScheduleCallback(slug, callback, event);
|
|
1800
|
+
},
|
|
1801
|
+
async dispose() {
|
|
1802
|
+
await disposeExtensions();
|
|
1803
|
+
},
|
|
1253
1804
|
getCurrentStep() {
|
|
1254
1805
|
const pending = runState.pendingTools;
|
|
1255
1806
|
if (pending.size === 0)
|
|
@@ -1265,13 +1816,4 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1265
1816
|
},
|
|
1266
1817
|
};
|
|
1267
1818
|
}
|
|
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
1819
|
//# sourceMappingURL=agent.js.map
|