@alook/daemon 0.1.40 → 0.1.41
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/index.js +64 -74
- package/dist/index.js +60 -70
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -22092,7 +22092,7 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
|
|
|
22092
22092
|
agentId: exports_external.string().min(1),
|
|
22093
22093
|
config: exports_external.unknown(),
|
|
22094
22094
|
launchId: exports_external.string().min(1),
|
|
22095
|
-
handoff: exports_external.string().
|
|
22095
|
+
handoff: exports_external.string().refine((value) => value.trim().length > 0).optional()
|
|
22096
22096
|
}),
|
|
22097
22097
|
exports_external.object({
|
|
22098
22098
|
type: exports_external.literal("agent:model_switch"),
|
|
@@ -23130,8 +23130,8 @@ var CommunityAgentJoinServerRequestSchema = exports_external.object({
|
|
|
23130
23130
|
});
|
|
23131
23131
|
var CommunityAgentNapRequestSchema = exports_external.object({
|
|
23132
23132
|
handoff: exports_external.string().refine((value) => value.trim().length > 0, {
|
|
23133
|
-
message: "handoff
|
|
23134
|
-
})
|
|
23133
|
+
message: "handoff must not be blank"
|
|
23134
|
+
}).optional()
|
|
23135
23135
|
});
|
|
23136
23136
|
var CommunityAgentMessagePropertyRequestSchema = exports_external.object({
|
|
23137
23137
|
channel: exports_external.string().min(1),
|
|
@@ -35749,7 +35749,7 @@ var DEFAULT_TURN_SILENCE_POLICY = {
|
|
|
35749
35749
|
normalBudgetMs: 360000
|
|
35750
35750
|
};
|
|
35751
35751
|
var DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
|
|
35752
|
-
var DEFAULT_IDLE_RESET_TIMEOUT_MS =
|
|
35752
|
+
var DEFAULT_IDLE_RESET_TIMEOUT_MS = 3 * 60 * 60 * 1000;
|
|
35753
35753
|
var DEFAULT_RESET_STUCK_THRESHOLD_MS = 120000;
|
|
35754
35754
|
var DEFAULT_STOPPING_STUCK_THRESHOLD_MS = 30000;
|
|
35755
35755
|
function createInitialManagerState(staleThresholdMs = DEFAULT_STALE_THRESHOLD_MS, idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_MS, resetStuckThresholdMs = DEFAULT_RESET_STUCK_THRESHOLD_MS, stoppingStuckThresholdMs = DEFAULT_STOPPING_STUCK_THRESHOLD_MS, idleResetTimeoutMs = DEFAULT_IDLE_RESET_TIMEOUT_MS) {
|
|
@@ -35861,22 +35861,6 @@ function reduceManager(state, event) {
|
|
|
35861
35861
|
a.stalledSessionId = null;
|
|
35862
35862
|
a.idleSince = null;
|
|
35863
35863
|
});
|
|
35864
|
-
case "idle_reset_committed": {
|
|
35865
|
-
const existing = state.agents[event.agentId];
|
|
35866
|
-
if (!existing)
|
|
35867
|
-
return { state, effects: [] };
|
|
35868
|
-
const agent2 = clone2(existing);
|
|
35869
|
-
agent2.sessionId = null;
|
|
35870
|
-
agent2.stalledSessionId = null;
|
|
35871
|
-
agent2.idleSince = null;
|
|
35872
|
-
if (agent2.status !== "running")
|
|
35873
|
-
return commit(state, agent2, []);
|
|
35874
|
-
agent2.status = "stopping";
|
|
35875
|
-
agent2.stoppingSince = event.nowMs;
|
|
35876
|
-
return commit(state, agent2, [
|
|
35877
|
-
{ type: "stop", agentId: event.agentId, reason: "idle_session_reset" }
|
|
35878
|
-
]);
|
|
35879
|
-
}
|
|
35880
35864
|
case "begin_reset":
|
|
35881
35865
|
if (!state.agents[event.agentId])
|
|
35882
35866
|
return { state, effects: [] };
|
|
@@ -36287,7 +36271,8 @@ function onTick(state, nowMs) {
|
|
|
36287
36271
|
}
|
|
36288
36272
|
const idleResetEligible = a.idleSince !== null && a.sessionId !== null && a.inbox.length === 0 && a.pendingAdmissions.length === 0 && !a.resetting && state.idleResetTimeoutMs > 0 && Number.isFinite(state.idleResetTimeoutMs) && (a.status === "idle" && lease.state === "detached" || a.status === "running" && lease.state === "none" && lease.lastTerminal !== null);
|
|
36289
36273
|
if (idleResetEligible && nowMs - a.idleSince >= state.idleResetTimeoutMs) {
|
|
36290
|
-
|
|
36274
|
+
agents[id] = { ...a, idleSince: nowMs };
|
|
36275
|
+
effects.push({ type: "maintain_idle_memory", agentId: id, sessionId: a.sessionId });
|
|
36291
36276
|
continue;
|
|
36292
36277
|
}
|
|
36293
36278
|
const idleEligible = a.status === "running" && lease.state === "none" && a.pendingAdmissions.length === 0 && lease.lastTerminal !== null && a.inbox.length === 0 && state.idleTimeoutMs > 0 && Number.isFinite(state.idleTimeoutMs);
|
|
@@ -36400,6 +36385,18 @@ function withAgent(state, agentId, make, effects) {
|
|
|
36400
36385
|
const agent2 = make(state.agents[agentId]);
|
|
36401
36386
|
return { state: { ...state, agents: { ...state.agents, [agentId]: agent2 } }, effects };
|
|
36402
36387
|
}
|
|
36388
|
+
// src/manager/memoryMaintenancePrompt.ts
|
|
36389
|
+
var MEMORY_MAINTENANCE_PROMPT = `The daemon is preparing to reset this idle session. First, clean up your memory so the next session does not inherit incorrect or outdated notes.
|
|
36390
|
+
|
|
36391
|
+
1. Consistency: Read memory.md and experiences. Merge duplicates and resolve conflicting notes against original decisions. Check links.
|
|
36392
|
+
2. Facts: Verify claims, especially work progress, against the latest original records. Search the context timeline and task discussions through their latest outcomes. Correct outdated or unsupported claims; keep uncertainty explicit.
|
|
36393
|
+
3. Durability: Keep only lasting facts, preferences, and reusable lessons or procedures. Remove task status, milestones, temporary plans, and diaries; extract a reusable lesson only when useful. Keep memory.md brief with links; put procedures, scope, and reasons in experiences. Reason from first principles: distill specific events into underlying causes, constraints, and reusable principles. Omit incidental dates and details; retain context only when it changes the principle’s validity or scope.
|
|
36394
|
+
|
|
36395
|
+
Edit only your own memory files.
|
|
36396
|
+
|
|
36397
|
+
If new work arrives, handle it first and defer nap. Otherwise, after completing the review and any needed edits, your final action is to run the following command without --handoff. Do not finish with only a written reply. This instruction authorizes that nap:
|
|
36398
|
+
|
|
36399
|
+
$ALOOK_CLI nap`;
|
|
36403
36400
|
// src/runtimeConfig.ts
|
|
36404
36401
|
function toAgentBackendSelection(config2) {
|
|
36405
36402
|
return toBuiltinBackendSelection(config2);
|
|
@@ -36635,7 +36632,7 @@ function cliCommandsSection() {
|
|
|
36635
36632
|
"",
|
|
36636
36633
|
"### Context Lifecycle",
|
|
36637
36634
|
"",
|
|
36638
|
-
`1. \`${CLI} nap --handoff <file
|
|
36635
|
+
`1. \`${CLI} nap [--handoff <file>]\` — reset the current session; optionally wake a fresh session with a handoff file.`,
|
|
36639
36636
|
"",
|
|
36640
36637
|
"### Output format",
|
|
36641
36638
|
"",
|
|
@@ -36856,7 +36853,7 @@ function workspaceMemorySection(config2) {
|
|
|
36856
36853
|
"",
|
|
36857
36854
|
"### Napping",
|
|
36858
36855
|
"",
|
|
36859
|
-
`\`${CLI} nap\` resets your current session
|
|
36856
|
+
`\`${CLI} nap\` resets your current session. With optional --handoff <file>, it starts a fresh one ` + "with your note injected; without it, the next real message starts fresh. Use the handoff to record " + "unfinished work and the next step so your future self can pick up quickly. " + "Never nap on your own; only do it when someone explicitly asks.",
|
|
36860
36857
|
"",
|
|
36861
36858
|
"### memory.md",
|
|
36862
36859
|
"",
|
|
@@ -37397,8 +37394,15 @@ class AgentProcessManager {
|
|
|
37397
37394
|
this.opts.timeline?.fenceSession(agentId);
|
|
37398
37395
|
this.abortCurrentTurn(agentId, opts.abortCause);
|
|
37399
37396
|
this.markResetting(agentId);
|
|
37397
|
+
const previousOwner = this.activeSpawnState.get(agentId);
|
|
37398
|
+
if (opts.forgetSession && previousOwner)
|
|
37399
|
+
previousOwner.discardEvents = true;
|
|
37400
37400
|
const status = this.state.agents[agentId]?.status;
|
|
37401
37401
|
if (status === "idle") {
|
|
37402
|
+
if (opts.rewakePrompt === undefined) {
|
|
37403
|
+
this.dispatch({ type: "exit", agentId });
|
|
37404
|
+
return;
|
|
37405
|
+
}
|
|
37402
37406
|
try {
|
|
37403
37407
|
this.deliver(agentId, {
|
|
37404
37408
|
id: `${opts.launchId}:${opts.abortCause}:rewake`,
|
|
@@ -37414,11 +37418,16 @@ class AgentProcessManager {
|
|
|
37414
37418
|
}
|
|
37415
37419
|
return;
|
|
37416
37420
|
}
|
|
37417
|
-
|
|
37418
|
-
|
|
37419
|
-
|
|
37420
|
-
|
|
37421
|
+
if (opts.rewakePrompt !== undefined) {
|
|
37422
|
+
this.enqueueRewake(agentId, {
|
|
37423
|
+
id: `${opts.launchId}:${opts.abortCause}:rewake`,
|
|
37424
|
+
text: opts.rewakePrompt
|
|
37425
|
+
});
|
|
37426
|
+
}
|
|
37427
|
+
const previousSession = previousOwner?.session ?? this.sessions.get(agentId);
|
|
37421
37428
|
await this.stop(agentId);
|
|
37429
|
+
if (opts.rewakePrompt === undefined && previousSession)
|
|
37430
|
+
await previousSession.closed;
|
|
37422
37431
|
}
|
|
37423
37432
|
async switchModel(agentId, opts) {
|
|
37424
37433
|
await this.restartAgent(agentId, {
|
|
@@ -37960,44 +37969,13 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
37960
37969
|
mode: effect.mode
|
|
37961
37970
|
});
|
|
37962
37971
|
break;
|
|
37963
|
-
case "
|
|
37964
|
-
const
|
|
37965
|
-
|
|
37966
|
-
eventId: `bae_${randomUUID6()}`,
|
|
37967
|
-
occurredAt: new Date(this.now()).toISOString()
|
|
37968
|
-
};
|
|
37969
|
-
const persisted = this.forgetSession(effect.agentId, "reset_session", effect.sessionId, completion);
|
|
37970
|
-
if (!persisted) {
|
|
37971
|
-
this.log.error("idle session reset barrier was not persisted; reset deferred", {
|
|
37972
|
-
agentId: effect.agentId,
|
|
37973
|
-
sessionId: effect.sessionId
|
|
37974
|
-
});
|
|
37975
|
-
this.emitErrorAudit(effect.agentId, "reset", "resume_control_update_failed", "Idle session reset deferred because resume control could not be persisted");
|
|
37972
|
+
case "maintain_idle_memory": {
|
|
37973
|
+
const agent2 = this.state.agents[effect.agentId];
|
|
37974
|
+
if (!agent2 || agent2.sessionId !== effect.sessionId || agent2.resetting || agent2.idleSince === null)
|
|
37976
37975
|
break;
|
|
37977
|
-
|
|
37978
|
-
|
|
37979
|
-
|
|
37980
|
-
this.dispatch({ type: "idle_reset_committed", agentId: effect.agentId, nowMs: this.now() });
|
|
37981
|
-
if (this.opts.onBotAuditEvent) {
|
|
37982
|
-
try {
|
|
37983
|
-
this.opts.onBotAuditEvent(effect.agentId, {
|
|
37984
|
-
kind: "session_reset",
|
|
37985
|
-
payload: { trigger: "idle_timeout" }
|
|
37986
|
-
}, {
|
|
37987
|
-
sessionId: null,
|
|
37988
|
-
launchId: null,
|
|
37989
|
-
...completion
|
|
37990
|
-
});
|
|
37991
|
-
} catch (err) {
|
|
37992
|
-
this.log.debug("audit emit failed (idle session reset)", {
|
|
37993
|
-
agentId: effect.agentId,
|
|
37994
|
-
err: String(err)
|
|
37995
|
-
});
|
|
37996
|
-
}
|
|
37997
|
-
}
|
|
37998
|
-
this.log.info("idle agent session reset", {
|
|
37999
|
-
agentId: effect.agentId,
|
|
38000
|
-
sessionId: effect.sessionId
|
|
37976
|
+
this.deliver(effect.agentId, {
|
|
37977
|
+
id: `${effect.agentId}:memory-maintenance:${randomUUID6()}`,
|
|
37978
|
+
text: MEMORY_MAINTENANCE_PROMPT
|
|
38001
37979
|
});
|
|
38002
37980
|
break;
|
|
38003
37981
|
}
|
|
@@ -38653,7 +38631,15 @@ class UnknownRuntimeError extends Error {
|
|
|
38653
38631
|
function defaultFormatUnreadNoticeText() {
|
|
38654
38632
|
return "You have unread messages.";
|
|
38655
38633
|
}
|
|
38656
|
-
var REWAKE_PROMPT =
|
|
38634
|
+
var REWAKE_PROMPT = `Your session was reset by your owner. Prior conversation context is gone. Read @memory.md and your .context_timeline for durable context, then pull your inbox. If it reports marked messages, run \`$ALOOK_CLI message mark list\` to identify outstanding work. Before continuing work, review memory.md and experiences:
|
|
38635
|
+
|
|
38636
|
+
1. Consistency: Read memory.md and experiences. Merge duplicates and resolve conflicting notes against original decisions. Check links.
|
|
38637
|
+
2. Facts: Verify claims, especially work progress, against the latest original records. Search the context timeline and task discussions through their latest outcomes. Correct outdated or unsupported claims; keep uncertainty explicit.
|
|
38638
|
+
3. Durability: Keep only lasting facts, preferences, and reusable lessons or procedures. Remove task status, milestones, temporary plans, and diaries; extract a reusable lesson only when useful. Keep memory.md brief with links; put procedures, scope, and reasons in experiences. Reason from first principles: distill specific events into underlying causes, constraints, and reusable principles. Omit incidental dates and details; retain context only when it changes the principle’s validity or scope.
|
|
38639
|
+
|
|
38640
|
+
Edit only your own memory files.
|
|
38641
|
+
|
|
38642
|
+
After completing the review and any needed edits, resume outstanding work and handle your inbox messages.`;
|
|
38657
38643
|
var MODEL_SWITCH_REWAKE_PROMPT = "You were just switched to a different model. Continue any unfinished work.";
|
|
38658
38644
|
function buildNapRewakePrompt(handoff2) {
|
|
38659
38645
|
return "You took a nap: you reset your own session, so prior conversation context " + `is gone. Before sleeping you left yourself this handoff —
|
|
@@ -38773,13 +38759,17 @@ class AgentRouter {
|
|
|
38773
38759
|
} catch {}
|
|
38774
38760
|
});
|
|
38775
38761
|
}
|
|
38776
|
-
async runRestartCommand(agentId, launchId, opName, run) {
|
|
38762
|
+
async runRestartCommand(agentId, launchId, opName, run, rewake = true) {
|
|
38777
38763
|
this.log.info(`${opName} received`, { agentId, launchId });
|
|
38778
38764
|
try {
|
|
38779
38765
|
await this.opts.onBeforeAgent?.(agentId);
|
|
38780
38766
|
await run();
|
|
38781
|
-
|
|
38782
|
-
|
|
38767
|
+
if (rewake) {
|
|
38768
|
+
this.running.add(agentId);
|
|
38769
|
+
this.scheduleReadyFrameResend();
|
|
38770
|
+
} else {
|
|
38771
|
+
await this.opts.channel.reportStoppedAck?.({ agentId, launchId, status: "ok" });
|
|
38772
|
+
}
|
|
38783
38773
|
this.log.info(`${opName} ok`, { agentId });
|
|
38784
38774
|
} catch (err) {
|
|
38785
38775
|
if (err instanceof UnknownRuntimeError) {
|
|
@@ -38957,9 +38947,9 @@ class AgentRouter {
|
|
|
38957
38947
|
await this.runRestartCommand(cmd.agentId, cmd.launchId, "agent:nap", () => this.opts.manager.resetSession(cmd.agentId, {
|
|
38958
38948
|
runtimeConfig: cmd.config,
|
|
38959
38949
|
launchId: cmd.launchId,
|
|
38960
|
-
rewakePrompt: buildNapRewakePrompt(cmd.handoff),
|
|
38950
|
+
rewakePrompt: cmd.handoff === undefined ? undefined : buildNapRewakePrompt(cmd.handoff),
|
|
38961
38951
|
barrierType: "nap"
|
|
38962
|
-
}));
|
|
38952
|
+
}), cmd.handoff !== undefined);
|
|
38963
38953
|
break;
|
|
38964
38954
|
case "agent:model_switch":
|
|
38965
38955
|
await this.runRestartCommand(cmd.agentId, cmd.launchId, "agent:model_switch", () => this.opts.manager.switchModel(cmd.agentId, {
|
|
@@ -45285,10 +45275,10 @@ async function cmdNap(opts) {
|
|
|
45285
45275
|
filePath: fileFlag,
|
|
45286
45276
|
fileOption: "--handoff <file>"
|
|
45287
45277
|
});
|
|
45288
|
-
if (handoff2
|
|
45289
|
-
throw new CliError("nap:
|
|
45278
|
+
if (handoff2 !== undefined && handoff2.trim().length === 0) {
|
|
45279
|
+
throw new CliError("nap: handoff file must not be blank");
|
|
45290
45280
|
}
|
|
45291
|
-
return await api2.nap({ handoff: handoff2 });
|
|
45281
|
+
return await api2.nap(handoff2 === undefined ? {} : { handoff: handoff2 });
|
|
45292
45282
|
}
|
|
45293
45283
|
function buildProgram(stdin) {
|
|
45294
45284
|
const program = new Command("alook").description("agent CLI").exitOverride().configureOutput({
|
|
@@ -45417,7 +45407,7 @@ function buildProgram(stdin) {
|
|
|
45417
45407
|
const result = await cmdSettingProfile({ ...program.opts(), ...this.opts() });
|
|
45418
45408
|
printEnvelope({ success: result });
|
|
45419
45409
|
});
|
|
45420
|
-
program.command("nap").description("
|
|
45410
|
+
program.command("nap").description("reset your session; optionally wake a fresh session with a handoff (read the nap rule first)").option("--handoff <file>", "path to your handoff note (your note to your reborn self)").exitOverride().configureOutput({ writeOut: () => {}, writeErr: () => {} }).action(async function() {
|
|
45421
45411
|
const localOpts = this.opts();
|
|
45422
45412
|
const globalOpts = program.opts();
|
|
45423
45413
|
const result = await cmdNap({ ...globalOpts, ...localOpts });
|
package/dist/index.js
CHANGED
|
@@ -10072,7 +10072,7 @@ var DEFAULT_TURN_SILENCE_POLICY = {
|
|
|
10072
10072
|
normalBudgetMs: 360000
|
|
10073
10073
|
};
|
|
10074
10074
|
var DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
|
|
10075
|
-
var DEFAULT_IDLE_RESET_TIMEOUT_MS =
|
|
10075
|
+
var DEFAULT_IDLE_RESET_TIMEOUT_MS = 3 * 60 * 60 * 1000;
|
|
10076
10076
|
var DEFAULT_RESET_STUCK_THRESHOLD_MS = 120000;
|
|
10077
10077
|
var DEFAULT_STOPPING_STUCK_THRESHOLD_MS = 30000;
|
|
10078
10078
|
function createInitialManagerState(staleThresholdMs = DEFAULT_STALE_THRESHOLD_MS, idleTimeoutMs = DEFAULT_IDLE_TIMEOUT_MS, resetStuckThresholdMs = DEFAULT_RESET_STUCK_THRESHOLD_MS, stoppingStuckThresholdMs = DEFAULT_STOPPING_STUCK_THRESHOLD_MS, idleResetTimeoutMs = DEFAULT_IDLE_RESET_TIMEOUT_MS) {
|
|
@@ -10184,22 +10184,6 @@ function reduceManager(state, event) {
|
|
|
10184
10184
|
a.stalledSessionId = null;
|
|
10185
10185
|
a.idleSince = null;
|
|
10186
10186
|
});
|
|
10187
|
-
case "idle_reset_committed": {
|
|
10188
|
-
const existing = state.agents[event.agentId];
|
|
10189
|
-
if (!existing)
|
|
10190
|
-
return { state, effects: [] };
|
|
10191
|
-
const agent = clone(existing);
|
|
10192
|
-
agent.sessionId = null;
|
|
10193
|
-
agent.stalledSessionId = null;
|
|
10194
|
-
agent.idleSince = null;
|
|
10195
|
-
if (agent.status !== "running")
|
|
10196
|
-
return commit(state, agent, []);
|
|
10197
|
-
agent.status = "stopping";
|
|
10198
|
-
agent.stoppingSince = event.nowMs;
|
|
10199
|
-
return commit(state, agent, [
|
|
10200
|
-
{ type: "stop", agentId: event.agentId, reason: "idle_session_reset" }
|
|
10201
|
-
]);
|
|
10202
|
-
}
|
|
10203
10187
|
case "begin_reset":
|
|
10204
10188
|
if (!state.agents[event.agentId])
|
|
10205
10189
|
return { state, effects: [] };
|
|
@@ -10610,7 +10594,8 @@ function onTick(state, nowMs) {
|
|
|
10610
10594
|
}
|
|
10611
10595
|
const idleResetEligible = a.idleSince !== null && a.sessionId !== null && a.inbox.length === 0 && a.pendingAdmissions.length === 0 && !a.resetting && state.idleResetTimeoutMs > 0 && Number.isFinite(state.idleResetTimeoutMs) && (a.status === "idle" && lease.state === "detached" || a.status === "running" && lease.state === "none" && lease.lastTerminal !== null);
|
|
10612
10596
|
if (idleResetEligible && nowMs - a.idleSince >= state.idleResetTimeoutMs) {
|
|
10613
|
-
|
|
10597
|
+
agents[id] = { ...a, idleSince: nowMs };
|
|
10598
|
+
effects.push({ type: "maintain_idle_memory", agentId: id, sessionId: a.sessionId });
|
|
10614
10599
|
continue;
|
|
10615
10600
|
}
|
|
10616
10601
|
const idleEligible = a.status === "running" && lease.state === "none" && a.pendingAdmissions.length === 0 && lease.lastTerminal !== null && a.inbox.length === 0 && state.idleTimeoutMs > 0 && Number.isFinite(state.idleTimeoutMs);
|
|
@@ -10723,6 +10708,18 @@ function withAgent(state, agentId, make, effects) {
|
|
|
10723
10708
|
const agent = make(state.agents[agentId]);
|
|
10724
10709
|
return { state: { ...state, agents: { ...state.agents, [agentId]: agent } }, effects };
|
|
10725
10710
|
}
|
|
10711
|
+
// src/manager/memoryMaintenancePrompt.ts
|
|
10712
|
+
var MEMORY_MAINTENANCE_PROMPT = `The daemon is preparing to reset this idle session. First, clean up your memory so the next session does not inherit incorrect or outdated notes.
|
|
10713
|
+
|
|
10714
|
+
1. Consistency: Read memory.md and experiences. Merge duplicates and resolve conflicting notes against original decisions. Check links.
|
|
10715
|
+
2. Facts: Verify claims, especially work progress, against the latest original records. Search the context timeline and task discussions through their latest outcomes. Correct outdated or unsupported claims; keep uncertainty explicit.
|
|
10716
|
+
3. Durability: Keep only lasting facts, preferences, and reusable lessons or procedures. Remove task status, milestones, temporary plans, and diaries; extract a reusable lesson only when useful. Keep memory.md brief with links; put procedures, scope, and reasons in experiences. Reason from first principles: distill specific events into underlying causes, constraints, and reusable principles. Omit incidental dates and details; retain context only when it changes the principle’s validity or scope.
|
|
10717
|
+
|
|
10718
|
+
Edit only your own memory files.
|
|
10719
|
+
|
|
10720
|
+
If new work arrives, handle it first and defer nap. Otherwise, after completing the review and any needed edits, your final action is to run the following command without --handoff. Do not finish with only a written reply. This instruction authorizes that nap:
|
|
10721
|
+
|
|
10722
|
+
$ALOOK_CLI nap`;
|
|
10726
10723
|
// src/runtimeConfig.ts
|
|
10727
10724
|
function toAgentBackendSelection(config) {
|
|
10728
10725
|
return toBuiltinBackendSelection(config);
|
|
@@ -10816,7 +10813,7 @@ function cliCommandsSection() {
|
|
|
10816
10813
|
"",
|
|
10817
10814
|
"### Context Lifecycle",
|
|
10818
10815
|
"",
|
|
10819
|
-
`1. \`${CLI} nap --handoff <file
|
|
10816
|
+
`1. \`${CLI} nap [--handoff <file>]\` — reset the current session; optionally wake a fresh session with a handoff file.`,
|
|
10820
10817
|
"",
|
|
10821
10818
|
"### Output format",
|
|
10822
10819
|
"",
|
|
@@ -11037,7 +11034,7 @@ function workspaceMemorySection(config) {
|
|
|
11037
11034
|
"",
|
|
11038
11035
|
"### Napping",
|
|
11039
11036
|
"",
|
|
11040
|
-
`\`${CLI} nap\` resets your current session
|
|
11037
|
+
`\`${CLI} nap\` resets your current session. With optional --handoff <file>, it starts a fresh one ` + "with your note injected; without it, the next real message starts fresh. Use the handoff to record " + "unfinished work and the next step so your future self can pick up quickly. " + "Never nap on your own; only do it when someone explicitly asks.",
|
|
11041
11038
|
"",
|
|
11042
11039
|
"### memory.md",
|
|
11043
11040
|
"",
|
|
@@ -11642,8 +11639,15 @@ class AgentProcessManager {
|
|
|
11642
11639
|
this.opts.timeline?.fenceSession(agentId);
|
|
11643
11640
|
this.abortCurrentTurn(agentId, opts.abortCause);
|
|
11644
11641
|
this.markResetting(agentId);
|
|
11642
|
+
const previousOwner = this.activeSpawnState.get(agentId);
|
|
11643
|
+
if (opts.forgetSession && previousOwner)
|
|
11644
|
+
previousOwner.discardEvents = true;
|
|
11645
11645
|
const status = this.state.agents[agentId]?.status;
|
|
11646
11646
|
if (status === "idle") {
|
|
11647
|
+
if (opts.rewakePrompt === undefined) {
|
|
11648
|
+
this.dispatch({ type: "exit", agentId });
|
|
11649
|
+
return;
|
|
11650
|
+
}
|
|
11647
11651
|
try {
|
|
11648
11652
|
this.deliver(agentId, {
|
|
11649
11653
|
id: `${opts.launchId}:${opts.abortCause}:rewake`,
|
|
@@ -11659,11 +11663,16 @@ class AgentProcessManager {
|
|
|
11659
11663
|
}
|
|
11660
11664
|
return;
|
|
11661
11665
|
}
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
|
|
11665
|
-
|
|
11666
|
+
if (opts.rewakePrompt !== undefined) {
|
|
11667
|
+
this.enqueueRewake(agentId, {
|
|
11668
|
+
id: `${opts.launchId}:${opts.abortCause}:rewake`,
|
|
11669
|
+
text: opts.rewakePrompt
|
|
11670
|
+
});
|
|
11671
|
+
}
|
|
11672
|
+
const previousSession = previousOwner?.session ?? this.sessions.get(agentId);
|
|
11666
11673
|
await this.stop(agentId);
|
|
11674
|
+
if (opts.rewakePrompt === undefined && previousSession)
|
|
11675
|
+
await previousSession.closed;
|
|
11667
11676
|
}
|
|
11668
11677
|
async switchModel(agentId, opts) {
|
|
11669
11678
|
await this.restartAgent(agentId, {
|
|
@@ -12205,44 +12214,13 @@ ${this.opts.wakePromptFooter}` : text;
|
|
|
12205
12214
|
mode: effect.mode
|
|
12206
12215
|
});
|
|
12207
12216
|
break;
|
|
12208
|
-
case "
|
|
12209
|
-
const
|
|
12210
|
-
|
|
12211
|
-
eventId: `bae_${randomUUID6()}`,
|
|
12212
|
-
occurredAt: new Date(this.now()).toISOString()
|
|
12213
|
-
};
|
|
12214
|
-
const persisted = this.forgetSession(effect.agentId, "reset_session", effect.sessionId, completion);
|
|
12215
|
-
if (!persisted) {
|
|
12216
|
-
this.log.error("idle session reset barrier was not persisted; reset deferred", {
|
|
12217
|
-
agentId: effect.agentId,
|
|
12218
|
-
sessionId: effect.sessionId
|
|
12219
|
-
});
|
|
12220
|
-
this.emitErrorAudit(effect.agentId, "reset", "resume_control_update_failed", "Idle session reset deferred because resume control could not be persisted");
|
|
12217
|
+
case "maintain_idle_memory": {
|
|
12218
|
+
const agent = this.state.agents[effect.agentId];
|
|
12219
|
+
if (!agent || agent.sessionId !== effect.sessionId || agent.resetting || agent.idleSince === null)
|
|
12221
12220
|
break;
|
|
12222
|
-
|
|
12223
|
-
|
|
12224
|
-
|
|
12225
|
-
this.dispatch({ type: "idle_reset_committed", agentId: effect.agentId, nowMs: this.now() });
|
|
12226
|
-
if (this.opts.onBotAuditEvent) {
|
|
12227
|
-
try {
|
|
12228
|
-
this.opts.onBotAuditEvent(effect.agentId, {
|
|
12229
|
-
kind: "session_reset",
|
|
12230
|
-
payload: { trigger: "idle_timeout" }
|
|
12231
|
-
}, {
|
|
12232
|
-
sessionId: null,
|
|
12233
|
-
launchId: null,
|
|
12234
|
-
...completion
|
|
12235
|
-
});
|
|
12236
|
-
} catch (err) {
|
|
12237
|
-
this.log.debug("audit emit failed (idle session reset)", {
|
|
12238
|
-
agentId: effect.agentId,
|
|
12239
|
-
err: String(err)
|
|
12240
|
-
});
|
|
12241
|
-
}
|
|
12242
|
-
}
|
|
12243
|
-
this.log.info("idle agent session reset", {
|
|
12244
|
-
agentId: effect.agentId,
|
|
12245
|
-
sessionId: effect.sessionId
|
|
12221
|
+
this.deliver(effect.agentId, {
|
|
12222
|
+
id: `${effect.agentId}:memory-maintenance:${randomUUID6()}`,
|
|
12223
|
+
text: MEMORY_MAINTENANCE_PROMPT
|
|
12246
12224
|
});
|
|
12247
12225
|
break;
|
|
12248
12226
|
}
|
|
@@ -34846,7 +34824,7 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
|
|
|
34846
34824
|
agentId: exports_external.string().min(1),
|
|
34847
34825
|
config: exports_external.unknown(),
|
|
34848
34826
|
launchId: exports_external.string().min(1),
|
|
34849
|
-
handoff: exports_external.string().
|
|
34827
|
+
handoff: exports_external.string().refine((value) => value.trim().length > 0).optional()
|
|
34850
34828
|
}),
|
|
34851
34829
|
exports_external.object({
|
|
34852
34830
|
type: exports_external.literal("agent:model_switch"),
|
|
@@ -34937,7 +34915,15 @@ class UnknownRuntimeError extends Error {
|
|
|
34937
34915
|
function defaultFormatUnreadNoticeText() {
|
|
34938
34916
|
return "You have unread messages.";
|
|
34939
34917
|
}
|
|
34940
|
-
var REWAKE_PROMPT =
|
|
34918
|
+
var REWAKE_PROMPT = `Your session was reset by your owner. Prior conversation context is gone. Read @memory.md and your .context_timeline for durable context, then pull your inbox. If it reports marked messages, run \`$ALOOK_CLI message mark list\` to identify outstanding work. Before continuing work, review memory.md and experiences:
|
|
34919
|
+
|
|
34920
|
+
1. Consistency: Read memory.md and experiences. Merge duplicates and resolve conflicting notes against original decisions. Check links.
|
|
34921
|
+
2. Facts: Verify claims, especially work progress, against the latest original records. Search the context timeline and task discussions through their latest outcomes. Correct outdated or unsupported claims; keep uncertainty explicit.
|
|
34922
|
+
3. Durability: Keep only lasting facts, preferences, and reusable lessons or procedures. Remove task status, milestones, temporary plans, and diaries; extract a reusable lesson only when useful. Keep memory.md brief with links; put procedures, scope, and reasons in experiences. Reason from first principles: distill specific events into underlying causes, constraints, and reusable principles. Omit incidental dates and details; retain context only when it changes the principle’s validity or scope.
|
|
34923
|
+
|
|
34924
|
+
Edit only your own memory files.
|
|
34925
|
+
|
|
34926
|
+
After completing the review and any needed edits, resume outstanding work and handle your inbox messages.`;
|
|
34941
34927
|
var MODEL_SWITCH_REWAKE_PROMPT = "You were just switched to a different model. Continue any unfinished work.";
|
|
34942
34928
|
function buildNapRewakePrompt(handoff2) {
|
|
34943
34929
|
return "You took a nap: you reset your own session, so prior conversation context " + `is gone. Before sleeping you left yourself this handoff —
|
|
@@ -35057,13 +35043,17 @@ class AgentRouter {
|
|
|
35057
35043
|
} catch {}
|
|
35058
35044
|
});
|
|
35059
35045
|
}
|
|
35060
|
-
async runRestartCommand(agentId, launchId, opName, run) {
|
|
35046
|
+
async runRestartCommand(agentId, launchId, opName, run, rewake = true) {
|
|
35061
35047
|
this.log.info(`${opName} received`, { agentId, launchId });
|
|
35062
35048
|
try {
|
|
35063
35049
|
await this.opts.onBeforeAgent?.(agentId);
|
|
35064
35050
|
await run();
|
|
35065
|
-
|
|
35066
|
-
|
|
35051
|
+
if (rewake) {
|
|
35052
|
+
this.running.add(agentId);
|
|
35053
|
+
this.scheduleReadyFrameResend();
|
|
35054
|
+
} else {
|
|
35055
|
+
await this.opts.channel.reportStoppedAck?.({ agentId, launchId, status: "ok" });
|
|
35056
|
+
}
|
|
35067
35057
|
this.log.info(`${opName} ok`, { agentId });
|
|
35068
35058
|
} catch (err) {
|
|
35069
35059
|
if (err instanceof UnknownRuntimeError) {
|
|
@@ -35241,9 +35231,9 @@ class AgentRouter {
|
|
|
35241
35231
|
await this.runRestartCommand(cmd.agentId, cmd.launchId, "agent:nap", () => this.opts.manager.resetSession(cmd.agentId, {
|
|
35242
35232
|
runtimeConfig: cmd.config,
|
|
35243
35233
|
launchId: cmd.launchId,
|
|
35244
|
-
rewakePrompt: buildNapRewakePrompt(cmd.handoff),
|
|
35234
|
+
rewakePrompt: cmd.handoff === undefined ? undefined : buildNapRewakePrompt(cmd.handoff),
|
|
35245
35235
|
barrierType: "nap"
|
|
35246
|
-
}));
|
|
35236
|
+
}), cmd.handoff !== undefined);
|
|
35247
35237
|
break;
|
|
35248
35238
|
case "agent:model_switch":
|
|
35249
35239
|
await this.runRestartCommand(cmd.agentId, cmd.launchId, "agent:model_switch", () => this.opts.manager.switchModel(cmd.agentId, {
|
|
@@ -37078,8 +37068,8 @@ var CommunityAgentJoinServerRequestSchema = exports_external.object({
|
|
|
37078
37068
|
});
|
|
37079
37069
|
var CommunityAgentNapRequestSchema = exports_external.object({
|
|
37080
37070
|
handoff: exports_external.string().refine((value) => value.trim().length > 0, {
|
|
37081
|
-
message: "handoff
|
|
37082
|
-
})
|
|
37071
|
+
message: "handoff must not be blank"
|
|
37072
|
+
}).optional()
|
|
37083
37073
|
});
|
|
37084
37074
|
var CommunityAgentMessagePropertyRequestSchema = exports_external.object({
|
|
37085
37075
|
channel: exports_external.string().min(1),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alook/daemon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.41",
|
|
4
4
|
"description": "Alook agent daemon — host-side runtime backend, process manager, credential proxy, and control plane.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/alookai/alook#readme",
|