@questionbase/deskfree 0.3.0-alpha.36 → 0.3.0-alpha.37

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/dist/index.d.ts CHANGED
@@ -418,7 +418,7 @@ interface WsNotification {
418
418
  interface Task {
419
419
  taskId: string;
420
420
  title: string;
421
- status: 'pending' | 'active' | 'review' | 'done';
421
+ status: 'open' | 'done';
422
422
  instructions?: string;
423
423
  createdAt: string;
424
424
  updatedAt: string;
@@ -431,7 +431,7 @@ interface Task {
431
431
  interface TaskSummary {
432
432
  taskId: string;
433
433
  title: string;
434
- status: 'pending' | 'active' | 'review' | 'done';
434
+ status: 'open' | 'done';
435
435
  instructions: string | null;
436
436
  fileId: string | null;
437
437
  fileName: string | null;
@@ -468,13 +468,20 @@ interface TaskWithContext extends Task {
468
468
  }
469
469
  interface CompleteTaskInput {
470
470
  taskId: string;
471
- outcome: 'done' | 'blocked';
472
- summary?: string;
471
+ learnings?: {
472
+ reasoning: string;
473
+ globalWoW?: string;
474
+ initiativeContent?: string;
475
+ };
476
+ followUps?: Array<{
477
+ title: string;
478
+ instructions?: string;
479
+ }>;
473
480
  }
474
481
  interface WorkspaceStateTask {
475
482
  taskId: string;
476
483
  title: string;
477
- status: 'pending' | 'active' | 'review' | 'done';
484
+ status: 'open' | 'done';
478
485
  instructions?: string | null;
479
486
  fileId?: string | null;
480
487
  fileName?: string | null;
@@ -564,6 +571,7 @@ declare class DeskFreeClient {
564
571
  userId?: string;
565
572
  content: string;
566
573
  taskId?: string;
574
+ messageType?: 'ask' | 'notify';
567
575
  attachments?: Array<{
568
576
  s3Key: string;
569
577
  name: string;
@@ -659,10 +667,8 @@ declare class DeskFreeClient {
659
667
  }): Promise<{
660
668
  success: boolean;
661
669
  }>;
662
- /** Complete a task with an outcome. Moves task to human. */
663
- completeTask(input: CompleteTaskInput): Promise<Task & {
664
- outcome: 'done' | 'blocked';
665
- }>;
670
+ /** Complete a task. Marks it as done. */
671
+ completeTask(input: CompleteTaskInput): Promise<Task>;
666
672
  /** Reopen a completed/human task back to bot status for further work. */
667
673
  reopenTask(input: {
668
674
  taskId: string;
@@ -701,20 +707,10 @@ declare class DeskFreeClient {
701
707
  content: string;
702
708
  };
703
709
  context?: string;
710
+ taskId?: string;
704
711
  }): Promise<{
705
712
  messageId: string;
706
713
  }>;
707
- /** Update ways of working and/or initiative content based on learnings. */
708
- updateKnowledge(input: {
709
- globalWoW?: string;
710
- initiativeId?: string;
711
- initiativeContent?: string;
712
- reasoning: string;
713
- }): Promise<{
714
- success: boolean;
715
- globalVersion?: number;
716
- initiativeVersion?: number;
717
- }>;
718
714
  /**
719
715
  * Lightweight health check that verifies connectivity and authentication.
720
716
  *
package/dist/index.js CHANGED
@@ -3932,7 +3932,7 @@ var DeskFreeClient = class {
3932
3932
  this.requireNonEmpty(input.model, "model");
3933
3933
  return this.request("POST", "tasks.reportUsage", input);
3934
3934
  }
3935
- /** Complete a task with an outcome. Moves task to human. */
3935
+ /** Complete a task. Marks it as done. */
3936
3936
  async completeTask(input) {
3937
3937
  this.requireNonEmpty(input.taskId, "taskId");
3938
3938
  return this.request("POST", "tasks.complete", input);
@@ -3966,11 +3966,6 @@ var DeskFreeClient = class {
3966
3966
  }
3967
3967
  return this.request("POST", "tasks.propose", input);
3968
3968
  }
3969
- /** Update ways of working and/or initiative content based on learnings. */
3970
- async updateKnowledge(input) {
3971
- this.requireNonEmpty(input.reasoning, "reasoning");
3972
- return this.request("POST", "waysOfWorking.update", input);
3973
- }
3974
3969
  /**
3975
3970
  * Lightweight health check that verifies connectivity and authentication.
3976
3971
  *
@@ -4492,10 +4487,10 @@ function buildBodyForAgent(task, content, recentMessages) {
4492
4487
  return prefix + "\n\n" + content;
4493
4488
  }
4494
4489
  function resolveTaskRouting(task, hasAttachments) {
4495
- if (task.status === "active") {
4490
+ if (task.status === "open") {
4496
4491
  return { target: "runner" };
4497
4492
  }
4498
- if (hasAttachments && (task.status === "review" || task.status === "done")) {
4493
+ if (hasAttachments && task.status === "done") {
4499
4494
  return { target: "auto-reopen" };
4500
4495
  }
4501
4496
  return { target: "orchestrator" };
@@ -7982,7 +7977,7 @@ var ORCHESTRATOR_TOOLS = {
7982
7977
  },
7983
7978
  REOPEN_TASK: {
7984
7979
  name: "deskfree_reopen_task",
7985
- description: "Reopen a completed or human-side task back to bot status. Use when a human message in a task thread indicates more work is needed. The task becomes available for a worker to claim.",
7980
+ description: "Reopen a task (from review or done) back to pending. Use when more work is needed on a task. Works on both completed and in-review tasks.",
7986
7981
  parameters: Type.Object({
7987
7982
  taskId: Type.String({ description: "Task UUID to reopen" }),
7988
7983
  reason: Type.Optional(
@@ -7992,30 +7987,6 @@ var ORCHESTRATOR_TOOLS = {
7992
7987
  )
7993
7988
  })
7994
7989
  },
7995
- UPDATE_KNOWLEDGE: {
7996
- name: "deskfree_update_knowledge",
7997
- description: "Update ways of working and/or initiative content based on learnings from completed tasks.",
7998
- parameters: Type.Object({
7999
- globalWoW: Type.Optional(
8000
- Type.String({
8001
- description: "Full updated global ways-of-working markdown content"
8002
- })
8003
- ),
8004
- initiativeId: Type.Optional(
8005
- Type.String({
8006
- description: "Initiative ID to update"
8007
- })
8008
- ),
8009
- initiativeContent: Type.Optional(
8010
- Type.String({
8011
- description: "Full updated initiative content markdown (required if initiativeId provided)"
8012
- })
8013
- ),
8014
- reasoning: Type.String({
8015
- description: "Explanation of why these updates were made and what was learned"
8016
- })
8017
- })
8018
- },
8019
7990
  SEND_MESSAGE: {
8020
7991
  name: "deskfree_send_message",
8021
7992
  description: "Send a message to the human. Keep it short \u2014 1-3 sentences. No walls of text.",
@@ -8124,6 +8095,11 @@ var ORCHESTRATOR_TOOLS = {
8124
8095
  minItems: 1,
8125
8096
  maxItems: 20
8126
8097
  }
8098
+ ),
8099
+ taskId: Type.Optional(
8100
+ Type.String({
8101
+ description: "Task ID to thread this proposal into (for follow-up proposals from within a task)"
8102
+ })
8127
8103
  )
8128
8104
  })
8129
8105
  }
@@ -8146,36 +8122,63 @@ var SHARED_TOOLS = {
8146
8122
  },
8147
8123
  COMPLETE_TASK: {
8148
8124
  name: "deskfree_complete_task",
8149
- description: "Finish a task. Transitions to review/done status based on outcome.",
8125
+ description: "Mark a task as done. Only call when truly finished and human confirmed. Pass learnings to update knowledge atomically with completion. Pass followUps to propose next tasks.",
8150
8126
  parameters: Type.Object({
8151
8127
  taskId: Type.String({ description: "Task UUID" }),
8152
- outcome: Type.Union(
8153
- [
8154
- Type.Literal("review"),
8155
- Type.Literal("done"),
8156
- Type.Literal("blocked"),
8157
- Type.Literal("cancelled")
8158
- ],
8159
- {
8160
- description: '"review" = ready for human review, "done" = work complete, "blocked" = need human input, "cancelled" = task cancelled'
8161
- }
8162
- ),
8163
- summary: Type.Optional(
8164
- Type.String({
8165
- description: "1-2 sentence summary of what was done and the outcome."
8166
- })
8167
- ),
8168
8128
  learnings: Type.Optional(
8169
- Type.String({
8170
- description: "Key insights, patterns, or lessons learned from completing this task. Used to improve future work."
8171
- })
8129
+ Type.Object(
8130
+ {
8131
+ reasoning: Type.String({
8132
+ description: "Why these updates matter \u2014 what was learned from this task"
8133
+ }),
8134
+ globalWoW: Type.Optional(
8135
+ Type.String({
8136
+ description: "Full updated global Ways of Working markdown content (full replacement, not diff)"
8137
+ })
8138
+ ),
8139
+ initiativeId: Type.Optional(
8140
+ Type.String({
8141
+ description: "Initiative ID to update"
8142
+ })
8143
+ ),
8144
+ initiativeContent: Type.Optional(
8145
+ Type.String({
8146
+ description: "Full updated initiative content markdown (full replacement, not diff)"
8147
+ })
8148
+ )
8149
+ },
8150
+ {
8151
+ description: "Knowledge updates to apply atomically with task completion. Include only if there are genuine learnings to record."
8152
+ }
8153
+ )
8154
+ ),
8155
+ followUps: Type.Optional(
8156
+ Type.Array(
8157
+ Type.Object({
8158
+ title: Type.String({
8159
+ description: "Follow-up task title (max 200 chars)"
8160
+ }),
8161
+ instructions: Type.Optional(
8162
+ Type.String({
8163
+ description: "Instructions for the follow-up task"
8164
+ })
8165
+ )
8166
+ }),
8167
+ {
8168
+ description: "Follow-up tasks to propose for human approval (max 10). Use when the work revealed clear next steps.",
8169
+ maxItems: 10
8170
+ }
8171
+ )
8172
8172
  )
8173
8173
  })
8174
8174
  },
8175
8175
  SEND_MESSAGE: {
8176
8176
  name: "deskfree_send_message",
8177
- description: "Send a message in the task thread. Keep it short \u2014 1-3 sentences. No walls of text.",
8177
+ description: "Send a message in the task thread. Keep it short \u2014 1-3 sentences.",
8178
8178
  parameters: Type.Object({
8179
+ type: Type.Union([Type.Literal("notify"), Type.Literal("ask")], {
8180
+ description: "notify = progress update (quiet, collapsible). ask = needs human attention (surfaces to main thread). Terminate after sending an ask."
8181
+ }),
8179
8182
  content: Type.String({
8180
8183
  description: "Message content."
8181
8184
  }),
@@ -8280,6 +8283,11 @@ var SHARED_TOOLS = {
8280
8283
  minItems: 1,
8281
8284
  maxItems: 20
8282
8285
  }
8286
+ ),
8287
+ taskId: Type.Optional(
8288
+ Type.String({
8289
+ description: "Task ID to thread this proposal into (for follow-up proposals from within a task)"
8290
+ })
8283
8291
  )
8284
8292
  })
8285
8293
  }
@@ -8305,7 +8313,9 @@ var WORKER_TOOLS = {
8305
8313
  name: "deskfree_read_skill_section",
8306
8314
  description: "Load full instructions for a skill. Use after deskfree_start_task when you need the complete skill guide beyond the critical section summary.",
8307
8315
  parameters: Type.Object({
8308
- skillId: Type.String({ description: "Skill ID to load instructions for" })
8316
+ skillId: Type.String({
8317
+ description: "Skill ID to load instructions for"
8318
+ })
8309
8319
  })
8310
8320
  }
8311
8321
  };
@@ -8884,8 +8894,8 @@ You are the orchestrator. Your job: turn human intent into approved tasks, then
8884
8894
 
8885
8895
  **Match the human's energy.** Short message \u2192 short reply. Casual tone \u2192 casual response. Don't over-explain, don't lecture, don't pad responses.
8886
8896
 
8887
- You do NOT claim tasks or do work directly. Sub-agents handle execution.
8888
- - When a human writes in a task thread, you receive it with recent context. Use \`deskfree_reopen_task\` if it needs more work.
8897
+ You do NOT claim tasks or do work directly \u2014 you have no access to deskfree_start_task. Spawn a sub-agent for each approved task and pass it the taskId.
8898
+ - When a human writes in a task thread, decide: does it need bot action? If yes \u2192 reopen and spawn sub-agent. If it's confirmation ("looks good") \u2192 complete the task. If deferred ("I'll check later") \u2192 leave it.
8889
8899
  - Write task instructions as rich markdown (bold, lists, inline code \u2014 no # headers). Brief a contractor who has never seen the codebase.
8890
8900
  - Estimate token cost per task \u2014 consider files to read, reasoning, output.
8891
8901
  - One initiative per proposal \u2014 make multiple calls for multiple initiatives.
@@ -8896,10 +8906,12 @@ You are a worker sub-agent. Call \`deskfree_start_task\` with your taskId to cla
8896
8906
  Tools: deskfree_start_task, deskfree_update_file, deskfree_complete_task, deskfree_send_message, deskfree_propose.
8897
8907
  - Claim your task first with deskfree_start_task \u2014 this loads instructions, messages, and file context.
8898
8908
  - Save work to linked files with deskfree_update_file (incrementally).
8899
- - Complete with deskfree_complete_task when done (summary required for outcome "done"). Include learnings if applicable.
8900
- - If you need human input to proceed, send a message explaining what you need, then complete with outcome "review" \u2014 this marks the task as needing attention.
8901
- - Propose follow-up tasks with deskfree_propose if you discover more work.
8902
- - Keep messages and file updates concise. Write like a senior colleague giving a status update \u2014 not a report. 1-3 sentences for messages unless the human asked for detail.`;
8909
+ - Use deskfree_send_message with type "notify" for progress updates \u2014 what you're doing, what you found. Keep it brief.
8910
+ - Use deskfree_send_message with type "ask" when you need human input OR when your work is done for review. This surfaces to the main thread. Terminate after sending an ask.
8911
+ - When completing: pass "learnings" to deskfree_complete_task if you have knowledge updates (WoW or initiative content). Pass "followUps" if the work revealed clear next steps. Knowledge updates and proposals happen atomically with completion \u2014 no separate tool calls needed.
8912
+ - Only complete when the human has confirmed or no review is needed.
8913
+ - Write like a senior colleague giving a status update \u2014 not a report. 1-3 sentences for messages.
8914
+ - On 409 or 404 errors: STOP. Do not retry the same taskId. Call deskfree_state to find available tasks.`;
8903
8915
  function getDeskFreeContext(sessionKey) {
8904
8916
  const isWorker = sessionKey && (sessionKey.includes(":sub:") || sessionKey.includes(":spawn:") || sessionKey.includes(":run:"));
8905
8917
  const directive = isWorker ? DESKFREE_WORKER_DIRECTIVE : DESKFREE_AGENT_DIRECTIVE;
@@ -9108,9 +9120,9 @@ function suggestionForErrorType(type, statusCode) {
9108
9120
  if (statusCode === 429)
9109
9121
  return "Too many requests. Wait a moment before trying again.";
9110
9122
  if (statusCode === 409)
9111
- return "Try calling deskfree_state to see available tasks.";
9123
+ return "STOP \u2014 this task is already claimed or completed. Do NOT retry. Call deskfree_state to find available tasks.";
9112
9124
  if (statusCode === 404)
9113
- return "Use deskfree_state to see all available tasks and verify the taskId.";
9125
+ return "STOP \u2014 task not found or not in claimable state. Do NOT retry. Call deskfree_state to find available tasks.";
9114
9126
  return "Check your input parameters and try again.";
9115
9127
  default:
9116
9128
  return "";
@@ -9280,34 +9292,46 @@ function makeCompleteTaskHandler(client) {
9280
9292
  return async (_id, params) => {
9281
9293
  try {
9282
9294
  const taskId = validateStringParam(params, "taskId", true);
9283
- const outcome = validateEnumParam(
9284
- params,
9285
- "outcome",
9286
- ["done", "blocked"],
9287
- true
9288
- );
9289
- const summary = validateStringParam(params, "summary", false);
9290
- const evaluation = params?.evaluation;
9295
+ let learnings;
9296
+ if (params["learnings"] && typeof params["learnings"] === "object") {
9297
+ const raw = params["learnings"];
9298
+ const reasoning = typeof raw["reasoning"] === "string" ? raw["reasoning"] : "";
9299
+ if (reasoning.trim()) {
9300
+ learnings = {
9301
+ reasoning,
9302
+ globalWoW: typeof raw["globalWoW"] === "string" && raw["globalWoW"].trim() ? raw["globalWoW"] : void 0,
9303
+ initiativeContent: typeof raw["initiativeContent"] === "string" && raw["initiativeContent"].trim() ? raw["initiativeContent"] : void 0
9304
+ };
9305
+ }
9306
+ }
9307
+ let followUps;
9308
+ if (Array.isArray(params["followUps"]) && params["followUps"].length > 0) {
9309
+ const parsed = params["followUps"].filter((item) => typeof item === "object" && item !== null).map((item) => {
9310
+ const obj = item;
9311
+ const title = typeof obj["title"] === "string" ? obj["title"].trim() : "";
9312
+ const instructions = typeof obj["instructions"] === "string" ? obj["instructions"] : void 0;
9313
+ return { title, instructions };
9314
+ }).filter((item) => item.title.length > 0);
9315
+ if (parsed.length > 0) followUps = parsed;
9316
+ }
9291
9317
  const result = await client.completeTask({
9292
9318
  taskId,
9293
- outcome,
9294
- summary,
9295
- ...evaluation ? { evaluation } : {}
9319
+ learnings,
9320
+ followUps
9296
9321
  });
9297
9322
  setActiveTaskId(null);
9298
- const summaryVerb = outcome === "done" ? "completed" : "blocked";
9299
- const icon = outcome === "done" ? "\u2705" : "\u{1F6AB}";
9300
- await client.sendMessage({
9301
- content: `${icon} Task ${summaryVerb}: "${result.title}"`
9302
- }).catch(() => {
9303
- });
9323
+ const actions = ["Use deskfree_state to check for other tasks"];
9324
+ if (learnings?.globalWoW) actions.unshift("Ways of Working updated");
9325
+ if (learnings?.initiativeContent)
9326
+ actions.unshift("Initiative content updated");
9327
+ if (followUps)
9328
+ actions.unshift(
9329
+ `${followUps.length} follow-up task(s) proposed for human approval`
9330
+ );
9304
9331
  return formatTaskResponse(
9305
9332
  result,
9306
- `Task "${result.title}" marked as ${summaryVerb} \u2014 waiting for human`,
9307
- [
9308
- outcome === "done" ? "Human will review your work summary" : "Human will review the blocker and provide guidance",
9309
- "Use deskfree_state to check for other tasks"
9310
- ]
9333
+ `Task "${result.title}" marked as done \u2705`,
9334
+ actions
9311
9335
  );
9312
9336
  } catch (err) {
9313
9337
  return errorResult(err);
@@ -9333,13 +9357,16 @@ function makeSendMessageHandler(client) {
9333
9357
  try {
9334
9358
  const content = validateStringParam(params, "content", true);
9335
9359
  const taskId = validateStringParam(params, "taskId", false);
9336
- await client.sendMessage({ content, taskId });
9360
+ const messageType = validateEnumParam(
9361
+ params,
9362
+ "type",
9363
+ ["notify", "ask"],
9364
+ true
9365
+ );
9366
+ await client.sendMessage({ content, taskId, messageType });
9337
9367
  return formatConfirmation(
9338
- `Message sent${taskId ? ` to task ${taskId}` : ""}`,
9339
- [
9340
- "Message delivered to the human",
9341
- taskId ? "Continue working on the task or wait for response" : "Check for response with task messages"
9342
- ]
9368
+ `Message sent (${messageType})${taskId ? ` to task ${taskId}` : ""}`,
9369
+ messageType === "ask" ? ["Message surfaced to human \u2014 terminate and wait for response"] : ["Progress update sent \u2014 continue working"]
9343
9370
  );
9344
9371
  } catch (err) {
9345
9372
  return errorResult(err);
@@ -9352,6 +9379,7 @@ function makeProposeHandler(client) {
9352
9379
  const tasks = parseProposeTasks(params?.tasks);
9353
9380
  const context = validateStringParam(params, "context", false);
9354
9381
  const initiative = parseInitiative(params?.initiative);
9382
+ const taskId = validateStringParam(params, "taskId", false);
9355
9383
  const result = await client.proposePlan({
9356
9384
  tasks: tasks.map((t) => ({
9357
9385
  title: t.title,
@@ -9362,7 +9390,8 @@ function makeProposeHandler(client) {
9362
9390
  scheduledFor: t.scheduledFor
9363
9391
  })),
9364
9392
  initiative,
9365
- context: context ?? void 0
9393
+ context: context ?? void 0,
9394
+ taskId: taskId ?? void 0
9366
9395
  });
9367
9396
  return formatConfirmation(
9368
9397
  `Proposed ${tasks.length} task${tasks.length === 1 ? "" : "s"} for human approval`,
@@ -9435,41 +9464,6 @@ function createOrchestratorTools(api) {
9435
9464
  ...ORCHESTRATOR_TOOLS.REOPEN_TASK,
9436
9465
  execute: makeReopenTaskHandler(client)
9437
9466
  },
9438
- {
9439
- ...ORCHESTRATOR_TOOLS.UPDATE_KNOWLEDGE,
9440
- async execute(_id, params) {
9441
- try {
9442
- const globalWoW = validateStringParam(params, "globalWoW", false);
9443
- const initiativeId = validateStringParam(
9444
- params,
9445
- "initiativeId",
9446
- false
9447
- );
9448
- const initiativeContent = validateStringParam(
9449
- params,
9450
- "initiativeContent",
9451
- false
9452
- );
9453
- const reasoning = validateStringParam(params, "reasoning", true);
9454
- const result = await client.updateKnowledge({
9455
- globalWoW,
9456
- initiativeId,
9457
- initiativeContent,
9458
- reasoning
9459
- });
9460
- return {
9461
- content: [
9462
- {
9463
- type: "text",
9464
- text: `Knowledge updated successfully: ${JSON.stringify(result, null, 2)}`
9465
- }
9466
- ]
9467
- };
9468
- } catch (err) {
9469
- return errorResult(err);
9470
- }
9471
- }
9472
- },
9473
9467
  {
9474
9468
  ...ORCHESTRATOR_TOOLS.SEND_MESSAGE,
9475
9469
  execute: makeSendMessageHandler(client)
@@ -9498,7 +9492,10 @@ function createWorkerTools(api) {
9498
9492
  cachedSkillContext.clear();
9499
9493
  if (result.skillContext?.length) {
9500
9494
  for (const s of result.skillContext) {
9501
- cachedSkillContext.set(s.skillId, { displayName: s.displayName, instructions: s.instructions });
9495
+ cachedSkillContext.set(s.skillId, {
9496
+ displayName: s.displayName,
9497
+ instructions: s.instructions
9498
+ });
9502
9499
  }
9503
9500
  skillInstructions = result.skillContext.map(
9504
9501
  (s) => `
@@ -9566,15 +9563,24 @@ ${s.criticalSection}`
9566
9563
  const skillId = validateStringParam(params, "skillId", true);
9567
9564
  const cached = cachedSkillContext.get(skillId);
9568
9565
  if (!cached) {
9569
- return { content: [{ type: "text", text: `Skill ${skillId} not found in current task context. Available: ${[...cachedSkillContext.keys()].join(", ") || "none"}` }] };
9566
+ return {
9567
+ content: [
9568
+ {
9569
+ type: "text",
9570
+ text: `Skill ${skillId} not found in current task context. Available: ${[...cachedSkillContext.keys()].join(", ") || "none"}`
9571
+ }
9572
+ ]
9573
+ };
9570
9574
  }
9571
9575
  return {
9572
- content: [{
9573
- type: "text",
9574
- text: `## ${cached.displayName} \u2014 Full Instructions
9576
+ content: [
9577
+ {
9578
+ type: "text",
9579
+ text: `## ${cached.displayName} \u2014 Full Instructions
9575
9580
 
9576
9581
  ${cached.instructions}`
9577
- }]
9582
+ }
9583
+ ]
9578
9584
  };
9579
9585
  } catch (err) {
9580
9586
  return errorResult(err);