agent-office-studio 0.6.0 → 0.7.0

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/server/index.js CHANGED
@@ -341,6 +341,7 @@ guests = new Guests(DATA, {
341
341
  links,
342
342
  office: {
343
343
  jobs: () => state.jobs,
344
+ repoPath: (name) => repoPath(name),
344
345
  createJob: (body, extra) => createJob(body, extra),
345
346
  replyJob: (job, body) => replyJob(job, body),
346
347
  stopJob: (job, why) => stopJob(job, why),
@@ -740,8 +741,9 @@ function start(job, agentId) {
740
741
  // hooks, or memory: at Full autonomy those would all be the guest's.
741
742
  args.push('--strict-mcp-config', '--setting-sources', 'project,local', '--settings', JSON.stringify({ autoMemoryEnabled: false }));
742
743
  }
743
- const allowed = job.guest ? GUEST_TOOLS : job.away ? [...OFFICE_TOOLS, ...awayTools(job)] : OFFICE_TOOLS;
744
- args.push('--mcp-config', mcpFile, '--allowedTools', allowed.join(','), '--append-system-prompt', job.guest ? guestPrompt(agentId, job) : officePrompt(agentId, job) + awayPrompt(job));
744
+ // A guest's job can be away too: one of our agents, lent to the guest, in the guest's own project.
745
+ const allowed = [...(job.guest ? GUEST_TOOLS : OFFICE_TOOLS), ...(job.away ? awayTools(job) : [])];
746
+ args.push('--mcp-config', mcpFile, '--allowedTools', allowed.join(','), '--append-system-prompt', (job.guest ? guestPrompt(agentId, job) : officePrompt(agentId, job)) + awayPrompt(job));
745
747
  // Being given work in a channel is how you end up in it.
746
748
  try { joinChannel(channelOf(job.channel), agentId); } catch {}
747
749
  const first = job.sessionId ? withClearHint(job, job.pending) : job.pending;
@@ -1024,12 +1026,15 @@ function finish(job, status, error) {
1024
1026
  const text = status === 'done' ? job.lastTurn?.text || 'Done.'
1025
1027
  : status === 'stopped' ? 'Stopped, as asked.'
1026
1028
  : `I hit a wall: ${error || 'something went wrong'}`;
1027
- post(job.agentId, text, { jobId: job.id, status, denials: job.denials });
1029
+ // A borrowed agent's chat belongs to the borrower: the host's feed carries
1030
+ // the finished job over the link, and remoteEnded posts it in their office.
1031
+ // Nothing about a guest's job goes in our own chat.
1032
+ if (!job.guest) post(job.agentId, text, { jobId: job.id, status, denials: job.denials });
1028
1033
  // The result lands in the job's thread, which the boss may never open, so
1029
1034
  // the chief says so in #general. Not for a retry (the work isn't over), a
1030
1035
  // stop (the boss did that), or a colleague's handed-off piece (their asker
1031
1036
  // gets it, and the asker's own finish is the one worth announcing).
1032
- if (!retry && status !== 'stopped' && !job.requestedBy) {
1037
+ if (!retry && status !== 'stopped' && !job.requestedBy && !job.guest) {
1033
1038
  const line = awaiting ? `${nameOf(job.agentId)} is waiting on you for "${clip(job.title, 80)}": ${clip(job.asking.summary, 200)}`
1034
1039
  : status === 'done' ? `${nameOf(job.agentId)} finished "${clip(job.title, 80)}".${briefOf(job.lastTurn?.text) ? `\n\n${briefOf(job.lastTurn.text)}` : ''}` : `${nameOf(job.agentId)} hit a wall on "${clip(job.title, 80)}": ${clip(error || 'something went wrong', 200)}`;
1035
1040
  post('chief', `**${awaiting ? 'Waiting on you' : status === 'done' ? 'Done' : 'Failed'}** · ${line}`, { kind: 'finished', status, awaiting, jobId: job.id, thread: null, channel: GENERAL });
@@ -1404,7 +1409,7 @@ function remoteEnded(job) {
1404
1409
  const name = guests.remoteStatus().find((o) => o.link === job.remote.link)?.staff.find((s) => s.id === job.agentId)?.name || 'Their agent';
1405
1410
  const last = job.log.at(-1);
1406
1411
  const how = { done: 'finished', failed: 'hit a wall on', stopped: 'stopped' }[job.status] || 'stopped';
1407
- const said = last?.kind === 'result' && last.summary ? `\n\n${clip(last.summary, 600)}` : job.error ? ` ${job.error}` : '';
1412
+ const said = last?.kind === 'result' && last.summary ? `\n\n${clip(last.summary, 4000)}` : job.error ? ` ${job.error}` : '';
1408
1413
  post('chief', `${name} at @${job.remote.host} ${how} “${job.title}”.${said}`, { jobId: job.id, channel: job.channel, thread: job.thread || null });
1409
1414
  }
1410
1415
 
@@ -1466,7 +1471,7 @@ function chat({ text, mode = 'edit', model = '', files, thread, channel }) {
1466
1471
  if (remote) {
1467
1472
  if (files.length) return void say(`Files can’t go to @${remote.host}’s office. Paste the text instead.`);
1468
1473
  guests.startRemote({ link: remote.link, staff: remote.staff, text: remote.clean, mode, model, thread: root?.id || msg.id, channel: where })
1469
- .then(({ job, repo, capped }) => say(`${remote.staff.name} at @${remote.host} is on it, in ${repo}.${capped ? ` @${remote.host} allows up to ${MODES[job.mode]?.label || job.mode}, so it runs at that.` : ''}`, { jobId: job.id, thread: root ? root.id : null }))
1474
+ .then(({ job, repo, home, capped }) => say(`${remote.staff.name} at @${remote.host} is on it, in ${home ? `your ${repo}, on @${remote.host}’s account. Their changes go into a copy you review.` : `${repo}.`}${capped ? ` @${remote.host} allows up to ${MODES[job.mode]?.label || job.mode}, so it runs at that.` : ''}`, { jobId: job.id, thread: root ? root.id : null }))
1470
1475
  .catch((err) => say(err.message, { thread: root ? root.id : null }));
1471
1476
  return;
1472
1477
  }