@geminixiang/mikan 1.0.0-beta.38 → 1.0.0-beta.39

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.
Files changed (193) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +1 -1
  3. package/dist/adapter.js +1 -1
  4. package/dist/adapter.js.map +1 -1
  5. package/dist/adapters/discord/bot.d.ts +3 -6
  6. package/dist/adapters/discord/bot.d.ts.map +1 -1
  7. package/dist/adapters/discord/bot.js +16 -39
  8. package/dist/adapters/discord/bot.js.map +1 -1
  9. package/dist/adapters/github/bot.d.ts +2 -0
  10. package/dist/adapters/github/bot.d.ts.map +1 -1
  11. package/dist/adapters/github/bot.js +15 -11
  12. package/dist/adapters/github/bot.js.map +1 -1
  13. package/dist/adapters/github/github-ops.d.ts +1 -1
  14. package/dist/adapters/github/github-ops.d.ts.map +1 -1
  15. package/dist/adapters/github/github-ops.js +2 -1
  16. package/dist/adapters/github/github-ops.js.map +1 -1
  17. package/dist/adapters/github/repo.d.ts +2 -1
  18. package/dist/adapters/github/repo.d.ts.map +1 -1
  19. package/dist/adapters/github/repo.js +2 -3
  20. package/dist/adapters/github/repo.js.map +1 -1
  21. package/dist/adapters/github/types.d.ts +1 -1
  22. package/dist/adapters/github/types.d.ts.map +1 -1
  23. package/dist/adapters/github/types.js.map +1 -1
  24. package/dist/adapters/intake.js +1 -1
  25. package/dist/adapters/intake.js.map +1 -1
  26. package/dist/adapters/shared.d.ts +17 -5
  27. package/dist/adapters/shared.d.ts.map +1 -1
  28. package/dist/adapters/shared.js +44 -8
  29. package/dist/adapters/shared.js.map +1 -1
  30. package/dist/adapters/slack/blocks.d.ts +14 -0
  31. package/dist/adapters/slack/blocks.d.ts.map +1 -1
  32. package/dist/adapters/slack/blocks.js +34 -0
  33. package/dist/adapters/slack/blocks.js.map +1 -1
  34. package/dist/adapters/slack/bot.d.ts +19 -6
  35. package/dist/adapters/slack/bot.d.ts.map +1 -1
  36. package/dist/adapters/slack/bot.js +88 -21
  37. package/dist/adapters/slack/bot.js.map +1 -1
  38. package/dist/adapters/slack/types.d.ts +1 -1
  39. package/dist/adapters/slack/types.js.map +1 -1
  40. package/dist/adapters/telegram/bot.d.ts +5 -6
  41. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  42. package/dist/adapters/telegram/bot.js +29 -51
  43. package/dist/adapters/telegram/bot.js.map +1 -1
  44. package/dist/adapters/types.d.ts +19 -1
  45. package/dist/adapters/types.d.ts.map +1 -1
  46. package/dist/adapters/types.js.map +1 -1
  47. package/dist/agent.d.ts.map +1 -1
  48. package/dist/agent.js +55 -54
  49. package/dist/agent.js.map +1 -1
  50. package/dist/cli/ext-dev.d.ts.map +1 -1
  51. package/dist/cli/ext-dev.js +8 -8
  52. package/dist/cli/ext-dev.js.map +1 -1
  53. package/dist/cli/ext.js +3 -3
  54. package/dist/cli/ext.js.map +1 -1
  55. package/dist/cli/office.js +2 -2
  56. package/dist/cli/office.js.map +1 -1
  57. package/dist/commands/auto-reply.d.ts.map +1 -1
  58. package/dist/commands/auto-reply.js +1 -2
  59. package/dist/commands/auto-reply.js.map +1 -1
  60. package/dist/commands/login.js +1 -1
  61. package/dist/commands/login.js.map +1 -1
  62. package/dist/commands/manifest.d.ts.map +1 -1
  63. package/dist/commands/manifest.js +3 -1
  64. package/dist/commands/manifest.js.map +1 -1
  65. package/dist/commands/model.d.ts.map +1 -1
  66. package/dist/commands/model.js +3 -7
  67. package/dist/commands/model.js.map +1 -1
  68. package/dist/commands/sandbox.d.ts.map +1 -1
  69. package/dist/commands/sandbox.js +7 -7
  70. package/dist/commands/sandbox.js.map +1 -1
  71. package/dist/commands/session-view.d.ts.map +1 -1
  72. package/dist/commands/session-view.js +1 -2
  73. package/dist/commands/session-view.js.map +1 -1
  74. package/dist/commands/types.d.ts +2 -1
  75. package/dist/commands/types.d.ts.map +1 -1
  76. package/dist/commands/types.js.map +1 -1
  77. package/dist/config.d.ts +10 -18
  78. package/dist/config.d.ts.map +1 -1
  79. package/dist/config.js +16 -15
  80. package/dist/config.js.map +1 -1
  81. package/dist/execution-resolver.d.ts +4 -6
  82. package/dist/execution-resolver.d.ts.map +1 -1
  83. package/dist/execution-resolver.js +10 -19
  84. package/dist/execution-resolver.js.map +1 -1
  85. package/dist/harness/extensions/loader.js +1 -1
  86. package/dist/harness/extensions/loader.js.map +1 -1
  87. package/dist/index.d.ts +2 -0
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +1 -0
  90. package/dist/index.js.map +1 -1
  91. package/dist/main.js +16 -16
  92. package/dist/main.js.map +1 -1
  93. package/dist/{office-address.d.ts → office/address.d.ts} +13 -14
  94. package/dist/office/address.d.ts.map +1 -0
  95. package/dist/{office-address.js → office/address.js} +13 -18
  96. package/dist/office/address.js.map +1 -0
  97. package/dist/office/index.d.ts +11 -0
  98. package/dist/office/index.d.ts.map +1 -0
  99. package/dist/office/index.js +11 -0
  100. package/dist/office/index.js.map +1 -0
  101. package/dist/office/layout.d.ts +20 -0
  102. package/dist/office/layout.d.ts.map +1 -0
  103. package/dist/office/layout.js +88 -0
  104. package/dist/office/layout.js.map +1 -0
  105. package/dist/{office-migration.d.ts → office/migration.d.ts} +3 -3
  106. package/dist/office/migration.d.ts.map +1 -0
  107. package/dist/{office-migration.js → office/migration.js} +8 -12
  108. package/dist/office/migration.js.map +1 -0
  109. package/dist/{office-registry.d.ts → office/registry.d.ts} +18 -24
  110. package/dist/office/registry.d.ts.map +1 -0
  111. package/dist/{office-registry.js → office/registry.js} +22 -83
  112. package/dist/office/registry.js.map +1 -0
  113. package/dist/office/types.d.ts +71 -0
  114. package/dist/office/types.d.ts.map +1 -0
  115. package/dist/office/types.js +2 -0
  116. package/dist/office/types.js.map +1 -0
  117. package/dist/packages/admin.js +5 -5
  118. package/dist/packages/admin.js.map +1 -1
  119. package/dist/packages/inspect.d.ts.map +1 -1
  120. package/dist/packages/inspect.js +3 -8
  121. package/dist/packages/inspect.js.map +1 -1
  122. package/dist/packages/materialize.js +1 -1
  123. package/dist/packages/materialize.js.map +1 -1
  124. package/dist/packages/resolve.js +5 -8
  125. package/dist/packages/resolve.js.map +1 -1
  126. package/dist/packages/types.d.ts +2 -5
  127. package/dist/packages/types.d.ts.map +1 -1
  128. package/dist/packages/types.js.map +1 -1
  129. package/dist/runtime/conversation-runtime.d.ts.map +1 -1
  130. package/dist/runtime/conversation-runtime.js +13 -15
  131. package/dist/runtime/conversation-runtime.js.map +1 -1
  132. package/dist/runtime/session-lifecycle.js +1 -1
  133. package/dist/runtime/session-lifecycle.js.map +1 -1
  134. package/dist/runtime/types.d.ts +3 -2
  135. package/dist/runtime/types.d.ts.map +1 -1
  136. package/dist/runtime/types.js.map +1 -1
  137. package/dist/sandbox/identity.js +1 -1
  138. package/dist/sandbox/identity.js.map +1 -1
  139. package/dist/settings-mutation.d.ts +3 -2
  140. package/dist/settings-mutation.d.ts.map +1 -1
  141. package/dist/settings-mutation.js +6 -7
  142. package/dist/settings-mutation.js.map +1 -1
  143. package/dist/tools/generate-image.d.ts +8 -2
  144. package/dist/tools/generate-image.d.ts.map +1 -1
  145. package/dist/tools/generate-image.js +5 -3
  146. package/dist/tools/generate-image.js.map +1 -1
  147. package/dist/tools/index.d.ts +5 -0
  148. package/dist/tools/index.d.ts.map +1 -1
  149. package/dist/tools/index.js +3 -5
  150. package/dist/tools/index.js.map +1 -1
  151. package/dist/trigger.d.ts +1 -1
  152. package/dist/trigger.d.ts.map +1 -1
  153. package/dist/trigger.js +5 -10
  154. package/dist/trigger.js.map +1 -1
  155. package/dist/types.d.ts +3 -22
  156. package/dist/types.d.ts.map +1 -1
  157. package/dist/types.js.map +1 -1
  158. package/dist/vault/index.js +1 -1
  159. package/dist/vault/index.js.map +1 -1
  160. package/dist/vault/injection.d.ts +3 -1
  161. package/dist/vault/injection.d.ts.map +1 -1
  162. package/dist/vault/injection.js +2 -2
  163. package/dist/vault/injection.js.map +1 -1
  164. package/dist/web/admin/portal.d.ts.map +1 -1
  165. package/dist/web/admin/portal.js +67 -80
  166. package/dist/web/admin/portal.js.map +1 -1
  167. package/dist/web/admin/types.d.ts +2 -1
  168. package/dist/web/admin/types.d.ts.map +1 -1
  169. package/dist/web/admin/types.js.map +1 -1
  170. package/dist/web/server.d.ts +1 -1
  171. package/dist/web/server.d.ts.map +1 -1
  172. package/dist/web/server.js +3 -3
  173. package/dist/web/server.js.map +1 -1
  174. package/dist/web/session-view/portal.js +1 -1
  175. package/dist/web/session-view/portal.js.map +1 -1
  176. package/dist/workspace-projection/index.d.ts +2 -4
  177. package/dist/workspace-projection/index.d.ts.map +1 -1
  178. package/dist/workspace-projection/index.js +21 -56
  179. package/dist/workspace-projection/index.js.map +1 -1
  180. package/dist/workspace-projection/types.d.ts +0 -2
  181. package/dist/workspace-projection/types.d.ts.map +1 -1
  182. package/dist/workspace-projection/types.js.map +1 -1
  183. package/package.json +41 -16
  184. package/dist/office-address.d.ts.map +0 -1
  185. package/dist/office-address.js.map +0 -1
  186. package/dist/office-migration.d.ts.map +0 -1
  187. package/dist/office-migration.js.map +0 -1
  188. package/dist/office-registry.d.ts.map +0 -1
  189. package/dist/office-registry.js.map +0 -1
  190. package/dist/store.d.ts +0 -51
  191. package/dist/store.d.ts.map +0 -1
  192. package/dist/store.js +0 -185
  193. package/dist/store.js.map +0 -1
package/dist/agent.js CHANGED
@@ -2,7 +2,6 @@
2
2
  * Agent runner: prompt construction, path translation, run lifecycle, and createRunner.
3
3
  * Single module — do not split helpers that only this file uses.
4
4
  */
5
- import { officeDirName } from "./office-address.js";
6
5
  import { DEFAULT_EVENT_BUDGET, formatSkillsForPrompt, loadExtensions, loadSkillsFromDir, MikanAgentSession, MikanModels, parseCommandInput, } from "./harness/index.js";
7
6
  import { runSubagent } from "./harness/subagent-runner.js";
8
7
  import { loadSubagentProfiles } from "./harness/subagent-profiles.js";
@@ -14,7 +13,6 @@ import { tmpdir } from "os";
14
13
  import { basename, isAbsolute, join, posix, relative, resolve, sep } from "path";
15
14
  import { resolveConversationSettings } from "./config.js";
16
15
  import { resolveWorkspaceProjection } from "./workspace-projection/index.js";
17
- import { effectiveStateDir } from "./cli/arg-grammar.js";
18
16
  import { packageSkillRuntimeDir, resolveConversationPackages } from "./packages/index.js";
19
17
  import { ActorExecutionResolver } from "./execution-resolver.js";
20
18
  import * as log from "./log.js";
@@ -191,12 +189,11 @@ function isRegularFile(path) {
191
189
  return false;
192
190
  }
193
191
  }
194
- function loadMikanSkills(address, conversationDir, workspacePath, projection) {
192
+ function loadMikanSkills(office, workspacePath, projection) {
195
193
  const skillMap = new Map();
196
- // conversationDir is the host path (e.g., /Users/.../data/C0A34FL8PMH)
197
- // hostWorkspacePath is the parent directory on host
198
- // workspacePath is the container path (e.g., /workspace)
199
- const hostWorkspacePath = join(conversationDir, "..");
194
+ // workspacePath is the runtime-side root (e.g. /workspace); host paths under
195
+ // the workspace root translate onto it for prompt references.
196
+ const hostWorkspacePath = office.workspace.root;
200
197
  // Helper to translate host paths to container paths
201
198
  const translatePath = (hostPath) => {
202
199
  if (hostPath.startsWith(hostWorkspacePath)) {
@@ -214,11 +211,7 @@ function loadMikanSkills(address, conversationDir, workspacePath, projection) {
214
211
  // so the agent can read the files — including any scripts or templates the
215
212
  // skill ships alongside its SKILL.md, which inlining could never carry.
216
213
  const mounted = workspacePath !== hostWorkspacePath;
217
- for (const { slug, dir } of resolveConversationPackages({
218
- address,
219
- stateDir: effectiveStateDir(),
220
- conversationDir,
221
- }).skillDirs) {
214
+ for (const { slug, dir } of resolveConversationPackages({ office }).skillDirs) {
222
215
  const runtimeDir = packageSkillRuntimeDir(slug);
223
216
  for (const skill of loadSkillsFromDir({ dir, source: `package:${slug}` }).skills) {
224
217
  // In host mode there is no mount, so the host path is already the path
@@ -265,9 +258,9 @@ function loadMikanSkills(address, conversationDir, workspacePath, projection) {
265
258
  }
266
259
  return { skills: Array.from(skillMap.values()), skippedSkillLinks };
267
260
  }
268
- function buildRuntimePaths(runtimeWorkspaceRoot, address) {
261
+ function buildRuntimePaths(runtimeWorkspaceRoot, office) {
269
262
  const workspaceRoot = runtimeWorkspaceRoot.replace(/\/+$/, "") || "/";
270
- const conversationPath = posix.join(workspaceRoot, officeDirName(address));
263
+ const conversationPath = posix.join(workspaceRoot, office.key);
271
264
  return {
272
265
  workspaceRoot,
273
266
  conversationPath,
@@ -318,8 +311,8 @@ export function resolveTriggerAttribution(message) {
318
311
  return `@${message.userName}`;
319
312
  return undefined;
320
313
  }
321
- function buildSystemPrompt(workspacePath, address, conversationKind, currentUserId, memory, sandboxConfig, platform, skills, projection, skippedSkillLinks = []) {
322
- const { workspaceRoot, conversationPath, scratchPath } = buildRuntimePaths(workspacePath, address);
314
+ function buildSystemPrompt(workspacePath, office, conversationKind, currentUserId, memory, sandboxConfig, platform, skills, projection, skippedSkillLinks = []) {
315
+ const { workspaceRoot, conversationPath, scratchPath } = buildRuntimePaths(workspacePath, office);
323
316
  const sandboxType = sandboxConfig.type;
324
317
  const isContainerLike = sandboxType === "container" || sandboxType === "image";
325
318
  const isFirecracker = sandboxType === "firecracker";
@@ -377,7 +370,7 @@ Channels: ${channelMappings}
377
370
 
378
371
  Users: ${userMappings}
379
372
 
380
- When mentioning users, use <@username> format (e.g., <@mario>).
373
+ 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.
381
374
 
382
375
  ## Environment
383
376
  ${envDescription}
@@ -391,7 +384,7 @@ ${projection.layout === "conversation"
391
384
  : `${workspaceRoot}/
392
385
  ├── MEMORY.md # Global memory (all conversations)
393
386
  ├── skills/ # Global CLI tools you create
394
- └── ${officeDirName(address)}/ # This conversation`}
387
+ └── ${office.key}/ # This conversation`}
395
388
  ├── MEMORY.md # Conversation-specific memory
396
389
  ├── log.jsonl # Human-readable message history (no tool results)
397
390
  ├── sessions/ # Structured session history used for context reconstruction
@@ -888,9 +881,9 @@ function buildThreadSessionName(message) {
888
881
  const userLabel = message?.userName || message?.user || "unknown";
889
882
  return `[${userLabel}]: ${text}`;
890
883
  }
891
- function createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner, workspaceDir, hostWorkspacePath) {
884
+ function createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner, workspace) {
892
885
  const executionResolver = vaultManager && sandboxConfig.type !== "host"
893
- ? new ActorExecutionResolver(sandboxConfig, vaultManager, provisioner, workspaceDir, hostWorkspacePath)
886
+ ? new ActorExecutionResolver(sandboxConfig, vaultManager, provisioner, workspace)
894
887
  : undefined;
895
888
  // activeExecutor is replaced at the start of each run() call when executionResolver
896
889
  // is present, so the stable `executor` wrapper always delegates to the latest resolved value.
@@ -923,7 +916,7 @@ function createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner,
923
916
  return {
924
917
  executionResolver,
925
918
  executor,
926
- getPathContext: () => executor.getPathContext(hostWorkspacePath),
919
+ getPathContext: () => executor.getPathContext(workspace.root),
927
920
  async resolveExecutorForRun(context) {
928
921
  if (!executionResolver)
929
922
  return;
@@ -938,10 +931,10 @@ function createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner,
938
931
  * notify posts through the platform bots when main.ts provides a notifier.
939
932
  */
940
933
  function buildExtensionHostServices(params) {
941
- const { workspaceDir, vaultManager, platformNotifier, platformReactor, platformUploader, platformBlockKit, runSubagentService, } = params;
942
- const eventStore = HostEventStore.fromWorkspaceDir(workspaceDir);
934
+ const { workspace, vaultManager, platformNotifier, platformReactor, platformUploader, platformBlockKit, runSubagentService, } = params;
935
+ const eventStore = HostEventStore.fromWorkspaceDir(workspace.root);
943
936
  return {
944
- stateDir: effectiveStateDir(),
937
+ stateDir: workspace.stateDir,
945
938
  scheduleStore: {
946
939
  write: async (filename, payload) => {
947
940
  await eventStore.write(filename, payload);
@@ -964,7 +957,10 @@ function buildExtensionHostServices(params) {
964
957
  };
965
958
  }
966
959
  async function createConfiguredAgentSession(params) {
967
- const { address, conversationId, conversationDir, workspaceDir, systemPrompt, model, thinkingLevel, tools, sessionStore, models, vaultManager, platformNotifier, platformReactor, platformUploader, platformBlockKit, } = params;
960
+ const { office, systemPrompt, model, thinkingLevel, tools, sessionStore, models, vaultManager, platformNotifier, platformReactor, platformUploader, platformBlockKit, } = params;
961
+ const { address } = office;
962
+ const conversationId = address.conversationId;
963
+ const workspaceDir = office.workspace.root;
968
964
  // Host-only dirs under the state dir: extension code runs in the mikan
969
965
  // process, so it must never load from workspace paths — those are mounted
970
966
  // into sandbox containers and agent-writable (sandbox escape otherwise).
@@ -980,11 +976,7 @@ async function createConfiguredAgentSession(params) {
980
976
  // contributed theirs. Both subagent entry points read this at call time, so
981
977
  // they always agree on which profiles are launchable.
982
978
  let runnableSubagentProfiles = loadedProfiles.profiles;
983
- const resolvedPackages = resolveConversationPackages({
984
- address,
985
- stateDir: effectiveStateDir(),
986
- conversationDir,
987
- });
979
+ const resolvedPackages = resolveConversationPackages({ office });
988
980
  for (const error of resolvedPackages.errors) {
989
981
  log.logWarning(`Package unavailable: ${error.source}`, error.message);
990
982
  }
@@ -993,7 +985,7 @@ async function createConfiguredAgentSession(params) {
993
985
  roots: resolvedPackages.extensionRoots,
994
986
  context: { address, conversationId, workspaceDir, model, thinkingLevel },
995
987
  services: buildExtensionHostServices({
996
- workspaceDir,
988
+ workspace: office.workspace,
997
989
  vaultManager,
998
990
  platformNotifier,
999
991
  platformReactor,
@@ -1070,10 +1062,11 @@ function reloadSessionMessages(session, conversationId) {
1070
1062
  }
1071
1063
  }
1072
1064
  async function prepareRunContext(params) {
1073
- const { message, responder, platform, conversationId, conversationDir, sessionUuid, runState, executor, executionResolver, resolveExecutorForRun, getPathContext, session, setEventContext, setSandboxContext, setUploadFunction, setReactFunction, bindPlatformToolPacks, } = params;
1065
+ const { message, responder, platform, office, sessionUuid, runState, executor, executionResolver, resolveExecutorForRun, getPathContext, session, setEventContext, setSandboxContext, setUploadFunction, setImageUploadFunction, setReactFunction, bindPlatformToolPacks, } = params;
1066
+ const conversationId = office.address.conversationId;
1074
1067
  let pathContext = params.pathContext;
1075
1068
  const sessionConversation = conversationIdOf(message.sessionKey);
1076
- await mkdir(join(conversationDir, "scratch"), { recursive: true });
1069
+ await mkdir(join(office.dir, "scratch"), { recursive: true });
1077
1070
  if (executionResolver) {
1078
1071
  await resolveExecutorForRun({
1079
1072
  address: message.address,
@@ -1083,12 +1076,12 @@ async function prepareRunContext(params) {
1083
1076
  pathContext = getPathContext();
1084
1077
  }
1085
1078
  reloadSessionMessages(session, conversationId);
1086
- const projection = resolveWorkspaceProjection(join(conversationDir, ".."), message.address);
1079
+ const projection = resolveWorkspaceProjection(office);
1087
1080
  const memory = await getMemory(projection);
1088
- const conversationSkillLoad = loadMikanSkills(message.address, conversationDir, pathContext.runtimeWorkspaceRoot, projection);
1081
+ const conversationSkillLoad = loadMikanSkills(office, pathContext.runtimeWorkspaceRoot, projection);
1089
1082
  const skills = mergeExtensionSkills(conversationSkillLoad.skills, params.extensionSkills ?? []);
1090
1083
  const triggerAttribution = resolveTriggerAttribution(message);
1091
- const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot, message.address, message.conversationKind, message.userId, memory, executor.getSandboxConfig(), platform, skills, projection, conversationSkillLoad.skippedSkillLinks);
1084
+ const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot, office, message.conversationKind, message.userId, memory, executor.getSandboxConfig(), platform, skills, projection, conversationSkillLoad.skippedSkillLinks);
1092
1085
  session.agent.state.systemPrompt = systemPrompt;
1093
1086
  // Cache diagnosis: a byte-stable system prompt is the precondition for
1094
1087
  // provider prompt caching. If this hash changes between turns of one
@@ -1110,6 +1103,11 @@ async function prepareRunContext(params) {
1110
1103
  const runtimePath = normalizeAttachRuntimePath(filePath, pathContext.runtimeWorkspaceRoot);
1111
1104
  await withStagedRuntimeFile(executor, runtimePath, (stagedPath) => responder.uploadFile(stagedPath, title));
1112
1105
  });
1106
+ // generate_image writes its file host-side, so it uploads by host path —
1107
+ // no staging through the sandbox, where the file may not be mounted.
1108
+ setImageUploadFunction(async (hostPath, title) => {
1109
+ await responder.uploadFile(hostPath, title);
1110
+ });
1113
1111
  // The react tool is available only when the responder supports reactions
1114
1112
  // (interactive turns on platforms with reaction support); otherwise unset
1115
1113
  // so the tool reports it is unavailable rather than silently no-op'ing.
@@ -1503,26 +1501,32 @@ function attachSessionEventHandlers(params) {
1503
1501
  * This is a stateless factory function.
1504
1502
  */
1505
1503
  export async function createRunner(options) {
1506
- const { sandboxConfig, sessionKey, conversationId, conversationDir, workspaceDir, sessionScope, vaultManager, provisioner, resourceController, sessionView, platformNotifier, platformReactor, platformUploader, platformBlockKit, platformToolPackFactories, } = options;
1507
- const agentConfig = resolveConversationSettings({ address: options.address, conversationDir });
1508
- const workspaceBase = join(conversationDir, "..");
1509
- const projection = resolveWorkspaceProjection(workspaceBase, options.address);
1504
+ const { sandboxConfig, sessionKey, office, sessionScope, vaultManager, provisioner, resourceController, sessionView, platformNotifier, platformReactor, platformUploader, platformBlockKit, platformToolPackFactories, } = options;
1505
+ const conversationId = office.address.conversationId;
1506
+ const conversationDir = office.dir;
1507
+ const workspaceDir = office.workspace.root;
1508
+ const agentConfig = resolveConversationSettings(office);
1509
+ const projection = resolveWorkspaceProjection(office);
1510
1510
  assertSandboxSupportsWorkspacePolicy(sandboxConfig, projection.doorPolicy);
1511
- const { executionResolver, executor, getPathContext, resolveExecutorForRun } = createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner, workspaceDir, workspaceBase);
1512
- let pathContext = getUnresolvedSandboxPathContext(sandboxConfig, workspaceBase);
1511
+ const { executionResolver, executor, getPathContext, resolveExecutorForRun } = createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner, office.workspace);
1512
+ let pathContext = getUnresolvedSandboxPathContext(sandboxConfig, workspaceDir);
1513
1513
  const modelRegistry = options.models ?? MikanModels.create();
1514
1514
  if (modelRegistry.getError()) {
1515
1515
  log.logWarning("models.json load error", modelRegistry.getError());
1516
1516
  }
1517
1517
  const model = modelRegistry.resolve(agentConfig.provider, agentConfig.model);
1518
1518
  // Create tools (per-runner, with per-runner upload function setter)
1519
- const { tools, setUploadFunction, setReactFunction, bindPlatformToolPacks, setEventContext, setSandboxContext, } = createMikanTools(executor, workspaceDir, { sandbox: sandboxConfig, resourceController: resourceController ?? provisioner }, platformToolPackFactories ?? [], {
1519
+ const { tools, setUploadFunction, setImageUploadFunction, setReactFunction, bindPlatformToolPacks, setEventContext, setSandboxContext, } = createMikanTools(executor, workspaceDir, { sandbox: sandboxConfig, resourceController: resourceController ?? provisioner }, platformToolPackFactories ?? [], {
1520
1520
  model,
1521
1521
  getApiKey: () => modelRegistry.getApiKeyForProvider(model.provider),
1522
+ // The conversation's own office dir: mounted into the sandbox, unlike
1523
+ // the workspace base — generated images must land somewhere the agent
1524
+ // (and a future run) can still reach.
1525
+ outputDir: conversationDir,
1522
1526
  });
1523
1527
  // Initial system prompt (will be updated each run with fresh memory/channels/users/skills)
1524
1528
  const memory = await getMemory(projection);
1525
- const { skills, skippedSkillLinks } = loadMikanSkills(options.address, conversationDir, pathContext.runtimeWorkspaceRoot, projection);
1529
+ const { skills, skippedSkillLinks } = loadMikanSkills(office, pathContext.runtimeWorkspaceRoot, projection);
1526
1530
  const emptyPlatform = {
1527
1531
  name: "chat",
1528
1532
  formattingGuide: "",
@@ -1530,7 +1534,7 @@ export async function createRunner(options) {
1530
1534
  users: [],
1531
1535
  trustModel: "membership",
1532
1536
  };
1533
- const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot, options.address, "shared", undefined, memory, sandboxConfig, emptyPlatform, skills, projection, skippedSkillLinks);
1537
+ const systemPrompt = buildSystemPrompt(pathContext.runtimeWorkspaceRoot, office, "shared", undefined, memory, sandboxConfig, emptyPlatform, skills, projection, skippedSkillLinks);
1534
1538
  // Create session manager and settings manager. Top-level/private sessions
1535
1539
  // use the conversation's current pointer; scoped sessions use fixed files.
1536
1540
  // Platform-specific scope behavior is resolved before runner creation.
@@ -1544,10 +1548,7 @@ export async function createRunner(options) {
1544
1548
  const sessionUuid = extractSessionUuid(contextFile);
1545
1549
  const chatSessionManager = new ChatHistorySync();
1546
1550
  const { session, extensionSkills, extensionRegistry, disposeExtensions } = await createConfiguredAgentSession({
1547
- address: options.address,
1548
- conversationId,
1549
- conversationDir,
1550
- workspaceDir,
1551
+ office,
1551
1552
  systemPrompt,
1552
1553
  model,
1553
1554
  thinkingLevel: agentConfig.thinkingLevel,
@@ -1577,8 +1578,7 @@ export async function createRunner(options) {
1577
1578
  message,
1578
1579
  responder,
1579
1580
  platform,
1580
- conversationId,
1581
- conversationDir,
1581
+ office,
1582
1582
  sessionUuid,
1583
1583
  runState,
1584
1584
  executor,
@@ -1590,6 +1590,7 @@ export async function createRunner(options) {
1590
1590
  setEventContext,
1591
1591
  setSandboxContext,
1592
1592
  setUploadFunction,
1593
+ setImageUploadFunction,
1593
1594
  setReactFunction,
1594
1595
  bindPlatformToolPacks,
1595
1596
  pathContext,
@@ -1701,8 +1702,7 @@ export async function createRunner(options) {
1701
1702
  message,
1702
1703
  responder,
1703
1704
  platform,
1704
- conversationId,
1705
- conversationDir,
1705
+ office,
1706
1706
  sessionUuid,
1707
1707
  runState,
1708
1708
  executor,
@@ -1714,13 +1714,14 @@ export async function createRunner(options) {
1714
1714
  setEventContext,
1715
1715
  setSandboxContext,
1716
1716
  setUploadFunction,
1717
+ setImageUploadFunction,
1717
1718
  setReactFunction,
1718
1719
  bindPlatformToolPacks,
1719
1720
  pathContext,
1720
1721
  });
1721
1722
  pathContext = prepared.pathContext;
1722
1723
  try {
1723
- const conversationMemoryPath = posix.join(prepared.pathContext.runtimeWorkspaceRoot, officeDirName(message.address), "MEMORY.md");
1724
+ const conversationMemoryPath = posix.join(prepared.pathContext.runtimeWorkspaceRoot, office.key, "MEMORY.md");
1724
1725
  const dreamTools = sessionDreamTools(session.agent.state.tools, conversationMemoryPath);
1725
1726
  const outcome = await session.prompt(sessionDreamPrompt(conversationMemoryPath, dreamTools.map((tool) => tool.name)), {
1726
1727
  origin: {