@lumi.ai/runner 0.5.3 → 0.5.4
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/cli.js +55 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -474,6 +474,11 @@ var DEFAULT_SHIP_SETTINGS = {
|
|
|
474
474
|
};
|
|
475
475
|
var SHIP_INVITE_TTL_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
476
476
|
|
|
477
|
+
// ../shared/dist/taskRelation.js
|
|
478
|
+
function taskBlockedBy(task) {
|
|
479
|
+
return Array.isArray(task?.blockedBy) ? task.blockedBy : [];
|
|
480
|
+
}
|
|
481
|
+
|
|
477
482
|
// ../shared/dist/usage.js
|
|
478
483
|
var EMPTY_USAGE_TOTALS = {
|
|
479
484
|
inputTokens: 0,
|
|
@@ -575,7 +580,7 @@ function mcpUrl(config2) {
|
|
|
575
580
|
}
|
|
576
581
|
|
|
577
582
|
// src/version.ts
|
|
578
|
-
var RUNNER_VERSION = true ? "0.5.
|
|
583
|
+
var RUNNER_VERSION = true ? "0.5.4" : "0.0.0-dev";
|
|
579
584
|
|
|
580
585
|
// src/auth.ts
|
|
581
586
|
import { signInWithCustomToken } from "firebase/auth";
|
|
@@ -958,6 +963,38 @@ async function withFirestoreRetry(read, sleep2 = (ms) => new Promise((r) => setT
|
|
|
958
963
|
// src/jobs/contextPack.ts
|
|
959
964
|
var MAX_ACTIVITY_IN_PROMPT = 40;
|
|
960
965
|
var MAX_PREVIOUS_JOBS_READ = 5;
|
|
966
|
+
var MAX_BLOCKERS_IN_PROMPT = 20;
|
|
967
|
+
async function loadSettledBlockers(shipRef, task) {
|
|
968
|
+
const ids = taskBlockedBy(task).slice(0, MAX_BLOCKERS_IN_PROMPT);
|
|
969
|
+
if (ids.length === 0) return [];
|
|
970
|
+
try {
|
|
971
|
+
return await Promise.all(
|
|
972
|
+
ids.map(async (id) => {
|
|
973
|
+
const ref = doc(shipRef, COLLECTIONS.tasks, id);
|
|
974
|
+
const [snap, resultSnap] = await Promise.all([
|
|
975
|
+
getDoc(ref),
|
|
976
|
+
getDocs(
|
|
977
|
+
query(
|
|
978
|
+
collection(ref, COLLECTIONS.activity),
|
|
979
|
+
where("kind", "==", "result"),
|
|
980
|
+
orderBy("createdAt", "desc"),
|
|
981
|
+
limit(1)
|
|
982
|
+
)
|
|
983
|
+
).catch(() => null)
|
|
984
|
+
]);
|
|
985
|
+
const data = snap.data();
|
|
986
|
+
return {
|
|
987
|
+
id,
|
|
988
|
+
title: data?.title ?? id,
|
|
989
|
+
status: data?.status ?? "unknown",
|
|
990
|
+
result: resultSnap?.docs[0]?.data()?.content ?? null
|
|
991
|
+
};
|
|
992
|
+
})
|
|
993
|
+
);
|
|
994
|
+
} catch {
|
|
995
|
+
return [];
|
|
996
|
+
}
|
|
997
|
+
}
|
|
961
998
|
async function loadJobContext(db, shipId, job) {
|
|
962
999
|
const shipRef = doc(db, COLLECTIONS.ships, shipId);
|
|
963
1000
|
const taskRef = doc(shipRef, COLLECTIONS.tasks, job.taskId);
|
|
@@ -1025,11 +1062,13 @@ async function loadJobContext(db, shipId, job) {
|
|
|
1025
1062
|
}
|
|
1026
1063
|
const activityDocs = activitySnap.docs.slice(0, MAX_ACTIVITY_IN_PROMPT);
|
|
1027
1064
|
const agent = { id: agentSnap.id, ...agentSnap.data() };
|
|
1065
|
+
const settledBlockers = job.reason === "unblocked" ? await loadSettledBlockers(shipRef, task) : [];
|
|
1028
1066
|
return {
|
|
1029
1067
|
ship: { id: shipSnap.id, ...shipSnap.data() },
|
|
1030
1068
|
agent,
|
|
1031
1069
|
task,
|
|
1032
1070
|
parentTask,
|
|
1071
|
+
settledBlockers,
|
|
1033
1072
|
workflow,
|
|
1034
1073
|
memory: readMemory(agent.memory),
|
|
1035
1074
|
knowledgeIndex: indexSnap?.exists() ? indexSnap.data() : null,
|
|
@@ -1113,6 +1152,10 @@ function buildPrompt(ctx, reason, mcpServers = []) {
|
|
|
1113
1152
|
parts.push(
|
|
1114
1153
|
"# Why this session started\n\nYou asked a captain for permission and stopped. They have now answered \u2014 their decision is the newest entry in the task activity below. Read it first.\n\n**If they approved it, do that thing now** \u2014 the permission is granted for this task and may be single-use, so do not ask again for the same thing. **If they refused, do not retry and do not look for a way around it**: say what you will do instead, or hand the task back with task_assign."
|
|
1115
1154
|
);
|
|
1155
|
+
} else if (reason === "unblocked") {
|
|
1156
|
+
parts.push(
|
|
1157
|
+
'# Why this session started\n\nThis task was blocked and is not any more: everything it was waiting on is now done. Nobody has just assigned it to you \u2014 you have had it all along, and the work has become startable.\n\n**Read "What you were waiting on" below before you do anything else.** It carries what those tasks produced, which is the input this work was held up for; starting without it means redoing or contradicting somebody else' + (playbook ? ", then follow your playbook below." : "'s work.")
|
|
1158
|
+
);
|
|
1116
1159
|
} else if (reason === "schedule") {
|
|
1117
1160
|
parts.push(
|
|
1118
1161
|
"# Why this session started\n\nThis is a scheduled run: one of your own playbooks created this task on its cron and assigned it to you. It is routine work, not a request from a person, so nobody is waiting on a reply" + (playbook ? " \u2014 the playbook below is the work, and the task's description is only a record of why it exists." : ".")
|
|
@@ -1158,6 +1201,17 @@ ${t.description || "(no description)"}
|
|
|
1158
1201
|
|
|
1159
1202
|
Labels: ${t.labels.join(", ") || "none"} \xB7 Status: ${statusLabel} (\`${t.status}\`)` + dates
|
|
1160
1203
|
);
|
|
1204
|
+
if (ctx.settledBlockers.length > 0) {
|
|
1205
|
+
const blockers = ctx.settledBlockers.map((b) => {
|
|
1206
|
+
const label = statusById(statuses, b.status)?.label ?? b.status;
|
|
1207
|
+
return `## ${b.title} (id: ${b.id}) \u2014 ${label}
|
|
1208
|
+
|
|
1209
|
+
` + (b.result ? b.result : "It left no result note. Open it with task_get if you need to know what it did.");
|
|
1210
|
+
}).join("\n\n");
|
|
1211
|
+
parts.push(`# What you were waiting on
|
|
1212
|
+
|
|
1213
|
+
${blockers}`);
|
|
1214
|
+
}
|
|
1161
1215
|
if (ctx.parentTask) {
|
|
1162
1216
|
const p = ctx.parentTask;
|
|
1163
1217
|
const parentStatus = statusById(statuses, p.status)?.label ?? p.status;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumi.ai/runner",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Lumi Crew runner daemon — claims jobs from your Ships and executes them as headless Claude sessions on your own machine.",
|
|
6
6
|
"//name": "The ONLY package in this monorepo published to the public registry, so it is the one that does not follow the internal @lumi/crew-* convention: `@lumi` is not a scope we own, `@lumi.ai` is (the npm org). The workspace DIRECTORY stays packages/crew/runner — renaming the package is not renaming the folder.",
|