@gethmy/mcp 3.4.1 → 3.5.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/dist/cli.js +27 -1
- package/dist/index.js +27 -1
- package/package.json +1 -1
- package/src/api-client.ts +17 -0
- package/src/server.ts +72 -1
package/dist/cli.js
CHANGED
|
@@ -5693,7 +5693,7 @@ var TOOLS = {
|
|
|
5693
5693
|
}
|
|
5694
5694
|
},
|
|
5695
5695
|
harmony_update_agent_progress: {
|
|
5696
|
-
description: "Update progress on an active agent session. Use to report progress percentage, current task, blockers, or status changes. Check the reply: `session: null` with `stopped: true` means a human stopped this card's run, so reporting progress will no longer open a session here (card #770) — stop work if you were mid-run, and read `recovery` for the one legitimate way back. Otherwise a session is always returned: this call opens one if none is live.",
|
|
5696
|
+
description: "Update progress on an active agent session. Use to report progress percentage, current task, blockers, or status changes. Check the reply: `session: null` with `stopped: true` means a human stopped this card's run, so reporting progress will no longer open a session here (card #770) — stop work if you were mid-run, and read `recovery` for the one legitimate way back. Otherwise a session is always returned: this call opens one if none is live. `sessionStale: true` means it opened one IN PLACE OF a session the inactivity sweep had closed (card #1067): nobody stopped you and the new row keeps the old one's steering channel and driver, so carry on — but the id changed, so poll harmony_get_pending_messages with the new `session.id` from this reply, not the one you were holding. `liveSessionIdChanged: true` is the weaker cousin: the live session is simply not the one you started, so use the new id, but do NOT assume steering survived — read `instruction`.",
|
|
5697
5697
|
inputSchema: {
|
|
5698
5698
|
type: "object",
|
|
5699
5699
|
properties: {
|
|
@@ -7654,6 +7654,32 @@ ${options}
|
|
|
7654
7654
|
if (result.session === null) {
|
|
7655
7655
|
untrack(cardId, deps.getScopeId?.());
|
|
7656
7656
|
}
|
|
7657
|
+
const scopeId = deps.getScopeId?.();
|
|
7658
|
+
const ownSession = memSession && memSession.scopeId === scopeId ? memSession : undefined;
|
|
7659
|
+
const knownSessionId = ownSession?.agentSessionId;
|
|
7660
|
+
const liveSessionId = result.session?.id;
|
|
7661
|
+
const idChangedUnderUs = knownSessionId !== undefined && liveSessionId !== undefined && liveSessionId !== knownSessionId;
|
|
7662
|
+
if (idChangedUnderUs && ownSession && liveSessionId) {
|
|
7663
|
+
ownSession.agentSessionId = liveSessionId;
|
|
7664
|
+
}
|
|
7665
|
+
const newSessionId = liveSessionId ? ` (${liveSessionId})` : "";
|
|
7666
|
+
if (result.sessionStale) {
|
|
7667
|
+
return {
|
|
7668
|
+
success: true,
|
|
7669
|
+
midSessionLearnings: 0,
|
|
7670
|
+
...result,
|
|
7671
|
+
instruction: "Your previous session had gone stale, so this report opened a new one in its place — nobody stopped you, and it kept the steering channel and driver of the run it replaced. Do NOT abandon the work. Poll harmony_get_pending_messages with the NEW session id" + newSessionId + ", not the one you were holding."
|
|
7672
|
+
};
|
|
7673
|
+
}
|
|
7674
|
+
if (idChangedUnderUs) {
|
|
7675
|
+
return {
|
|
7676
|
+
success: true,
|
|
7677
|
+
midSessionLearnings: 0,
|
|
7678
|
+
...result,
|
|
7679
|
+
liveSessionIdChanged: true,
|
|
7680
|
+
instruction: "The live session on this card is no longer the one you started — it may have been reopened, or deliberately ended and replaced. Nobody stopped you, so carry on, but poll harmony_get_pending_messages with the session id from this reply" + newSessionId + ". If steering matters to this run, do not assume it survived: start a session deliberately with harmony_start_agent_session and steerable: true."
|
|
7681
|
+
};
|
|
7682
|
+
}
|
|
7657
7683
|
return { success: true, midSessionLearnings: 0, ...result };
|
|
7658
7684
|
}
|
|
7659
7685
|
case "harmony_end_agent_session": {
|
package/dist/index.js
CHANGED
|
@@ -5476,7 +5476,7 @@ var TOOLS = {
|
|
|
5476
5476
|
}
|
|
5477
5477
|
},
|
|
5478
5478
|
harmony_update_agent_progress: {
|
|
5479
|
-
description: "Update progress on an active agent session. Use to report progress percentage, current task, blockers, or status changes. Check the reply: `session: null` with `stopped: true` means a human stopped this card's run, so reporting progress will no longer open a session here (card #770) — stop work if you were mid-run, and read `recovery` for the one legitimate way back. Otherwise a session is always returned: this call opens one if none is live.",
|
|
5479
|
+
description: "Update progress on an active agent session. Use to report progress percentage, current task, blockers, or status changes. Check the reply: `session: null` with `stopped: true` means a human stopped this card's run, so reporting progress will no longer open a session here (card #770) — stop work if you were mid-run, and read `recovery` for the one legitimate way back. Otherwise a session is always returned: this call opens one if none is live. `sessionStale: true` means it opened one IN PLACE OF a session the inactivity sweep had closed (card #1067): nobody stopped you and the new row keeps the old one's steering channel and driver, so carry on — but the id changed, so poll harmony_get_pending_messages with the new `session.id` from this reply, not the one you were holding. `liveSessionIdChanged: true` is the weaker cousin: the live session is simply not the one you started, so use the new id, but do NOT assume steering survived — read `instruction`.",
|
|
5480
5480
|
inputSchema: {
|
|
5481
5481
|
type: "object",
|
|
5482
5482
|
properties: {
|
|
@@ -7437,6 +7437,32 @@ ${options}
|
|
|
7437
7437
|
if (result.session === null) {
|
|
7438
7438
|
untrack(cardId, deps.getScopeId?.());
|
|
7439
7439
|
}
|
|
7440
|
+
const scopeId = deps.getScopeId?.();
|
|
7441
|
+
const ownSession = memSession && memSession.scopeId === scopeId ? memSession : undefined;
|
|
7442
|
+
const knownSessionId = ownSession?.agentSessionId;
|
|
7443
|
+
const liveSessionId = result.session?.id;
|
|
7444
|
+
const idChangedUnderUs = knownSessionId !== undefined && liveSessionId !== undefined && liveSessionId !== knownSessionId;
|
|
7445
|
+
if (idChangedUnderUs && ownSession && liveSessionId) {
|
|
7446
|
+
ownSession.agentSessionId = liveSessionId;
|
|
7447
|
+
}
|
|
7448
|
+
const newSessionId = liveSessionId ? ` (${liveSessionId})` : "";
|
|
7449
|
+
if (result.sessionStale) {
|
|
7450
|
+
return {
|
|
7451
|
+
success: true,
|
|
7452
|
+
midSessionLearnings: 0,
|
|
7453
|
+
...result,
|
|
7454
|
+
instruction: "Your previous session had gone stale, so this report opened a new one in its place — nobody stopped you, and it kept the steering channel and driver of the run it replaced. Do NOT abandon the work. Poll harmony_get_pending_messages with the NEW session id" + newSessionId + ", not the one you were holding."
|
|
7455
|
+
};
|
|
7456
|
+
}
|
|
7457
|
+
if (idChangedUnderUs) {
|
|
7458
|
+
return {
|
|
7459
|
+
success: true,
|
|
7460
|
+
midSessionLearnings: 0,
|
|
7461
|
+
...result,
|
|
7462
|
+
liveSessionIdChanged: true,
|
|
7463
|
+
instruction: "The live session on this card is no longer the one you started — it may have been reopened, or deliberately ended and replaced. Nobody stopped you, so carry on, but poll harmony_get_pending_messages with the session id from this reply" + newSessionId + ". If steering matters to this run, do not assume it survived: start a session deliberately with harmony_start_agent_session and steerable: true."
|
|
7464
|
+
};
|
|
7465
|
+
}
|
|
7440
7466
|
return { success: true, midSessionLearnings: 0, ...result };
|
|
7441
7467
|
}
|
|
7442
7468
|
case "harmony_end_agent_session": {
|
package/package.json
CHANGED
package/src/api-client.ts
CHANGED
|
@@ -1335,6 +1335,23 @@ export class HarmonyApiClient {
|
|
|
1335
1335
|
stopReason?: "human_stopped";
|
|
1336
1336
|
/** How to legitimately work this card again (an explicit start). */
|
|
1337
1337
|
recovery?: string;
|
|
1338
|
+
/**
|
|
1339
|
+
* This write REPLACED a session the silence sweep had closed (#1067): the
|
|
1340
|
+
* returned session is a new row under a new id, carrying forward the
|
|
1341
|
+
* `steerable`/`driver` of the one it replaced. Not a stop — the run
|
|
1342
|
+
* continues — but every later poll must use the NEW `session.id`.
|
|
1343
|
+
*
|
|
1344
|
+
* Same word `getPendingMessages` answers with, deliberately: one flag name
|
|
1345
|
+
* for one fact across both calls. Absent on an ordinary update, on a
|
|
1346
|
+
* deliberate start, and from a pre-#1067 server.
|
|
1347
|
+
*/
|
|
1348
|
+
sessionStale?: boolean;
|
|
1349
|
+
/**
|
|
1350
|
+
* The swept session that was replaced — never the new one's id. Present
|
|
1351
|
+
* exactly when `sessionStale` is, so it is also the discriminator between
|
|
1352
|
+
* the server's own verdict and the MCP tool's weaker `liveSessionIdChanged`.
|
|
1353
|
+
*/
|
|
1354
|
+
replacedSessionId?: string;
|
|
1338
1355
|
}> {
|
|
1339
1356
|
return this.request("POST", `/cards/${cardId}/agent-context`, data);
|
|
1340
1357
|
}
|
package/src/server.ts
CHANGED
|
@@ -1610,7 +1610,7 @@ export const TOOLS = {
|
|
|
1610
1610
|
},
|
|
1611
1611
|
harmony_update_agent_progress: {
|
|
1612
1612
|
description:
|
|
1613
|
-
"Update progress on an active agent session. Use to report progress percentage, current task, blockers, or status changes. Check the reply: `session: null` with `stopped: true` means a human stopped this card's run, so reporting progress will no longer open a session here (card #770) — stop work if you were mid-run, and read `recovery` for the one legitimate way back. Otherwise a session is always returned: this call opens one if none is live.",
|
|
1613
|
+
"Update progress on an active agent session. Use to report progress percentage, current task, blockers, or status changes. Check the reply: `session: null` with `stopped: true` means a human stopped this card's run, so reporting progress will no longer open a session here (card #770) — stop work if you were mid-run, and read `recovery` for the one legitimate way back. Otherwise a session is always returned: this call opens one if none is live. `sessionStale: true` means it opened one IN PLACE OF a session the inactivity sweep had closed (card #1067): nobody stopped you and the new row keeps the old one's steering channel and driver, so carry on — but the id changed, so poll harmony_get_pending_messages with the new `session.id` from this reply, not the one you were holding. `liveSessionIdChanged: true` is the weaker cousin: the live session is simply not the one you started, so use the new id, but do NOT assume steering survived — read `instruction`.",
|
|
1614
1614
|
inputSchema: {
|
|
1615
1615
|
type: "object",
|
|
1616
1616
|
properties: {
|
|
@@ -4379,6 +4379,77 @@ export async function handleToolCall(
|
|
|
4379
4379
|
untrack(cardId, deps.getScopeId?.());
|
|
4380
4380
|
}
|
|
4381
4381
|
|
|
4382
|
+
// Two DIFFERENT facts, and the earlier cut of #1067 merged them into one
|
|
4383
|
+
// sentence that was false in three reachable cases.
|
|
4384
|
+
//
|
|
4385
|
+
// `result.sessionStale` is the server's own verdict: it replaced a
|
|
4386
|
+
// recently-swept session AND carried its `steerable`/`driver` forward. Only
|
|
4387
|
+
// that verdict licenses saying the steering channel survived.
|
|
4388
|
+
//
|
|
4389
|
+
// The id comparison establishes strictly less — that the live session is
|
|
4390
|
+
// not the one this run recorded at start. It catches the case the flag
|
|
4391
|
+
// cannot: `flushMemoryActions` is fire-and-forget, sends
|
|
4392
|
+
// `implicitCreate: true` and discards its result, so when the sweep has
|
|
4393
|
+
// closed the row that bookkeeping write is what mints the replacement and
|
|
4394
|
+
// consumes the server's one `sessionStale`; this checkpoint then lands on a
|
|
4395
|
+
// live row under a new id with `created: false`. But an id change alone is
|
|
4396
|
+
// ALSO what `harmony_move_card` leaves behind — it ends the session and
|
|
4397
|
+
// untracks the card without calling `cleanupMemorySession`, so the recorded
|
|
4398
|
+
// id outlives a deliberate `completed` end — and what a lapsed recency
|
|
4399
|
+
// window leaves behind, where the new row genuinely is NOT steerable.
|
|
4400
|
+
// Claiming inheritance there tells a run its steering survived when it
|
|
4401
|
+
// did not, which suppresses the one recovery that works (an explicit
|
|
4402
|
+
// `harmony_start_agent_session` with `steerable: true`). Worse than
|
|
4403
|
+
// silence, so the two paths say different things.
|
|
4404
|
+
//
|
|
4405
|
+
// The RESYNC is unconditional and is a fix in its own right: this field
|
|
4406
|
+
// scopes working-memory writes (`sessionScopeFor`) and feeds comment
|
|
4407
|
+
// attribution, so a stale id there is wrong regardless of what is reported.
|
|
4408
|
+
const scopeId = deps.getScopeId?.();
|
|
4409
|
+
// `memorySessions` is keyed by card id ALONE at module scope, so on the
|
|
4410
|
+
// hosted transport a lookup can hand back another user's session for the
|
|
4411
|
+
// same card. Anything that CLAIMS the tracked session compares the scope
|
|
4412
|
+
// first — `chooseCommentSession` does, and #1035 is why.
|
|
4413
|
+
const ownSession =
|
|
4414
|
+
memSession && memSession.scopeId === scopeId ? memSession : undefined;
|
|
4415
|
+
const knownSessionId = ownSession?.agentSessionId;
|
|
4416
|
+
const liveSessionId = (result.session as { id?: string } | null)?.id;
|
|
4417
|
+
const idChangedUnderUs =
|
|
4418
|
+
knownSessionId !== undefined &&
|
|
4419
|
+
liveSessionId !== undefined &&
|
|
4420
|
+
liveSessionId !== knownSessionId;
|
|
4421
|
+
// Report once: the run now knows this id, so a later checkpoint on the
|
|
4422
|
+
// same session is silent again rather than crying change forever.
|
|
4423
|
+
if (idChangedUnderUs && ownSession && liveSessionId) {
|
|
4424
|
+
ownSession.agentSessionId = liveSessionId;
|
|
4425
|
+
}
|
|
4426
|
+
const newSessionId = liveSessionId ? ` (${liveSessionId})` : "";
|
|
4427
|
+
if (result.sessionStale) {
|
|
4428
|
+
return {
|
|
4429
|
+
success: true,
|
|
4430
|
+
midSessionLearnings: 0,
|
|
4431
|
+
...result,
|
|
4432
|
+
instruction:
|
|
4433
|
+
"Your previous session had gone stale, so this report opened a new one in its place — nobody stopped you, and it kept the steering channel and driver of the run it replaced. Do NOT abandon the work. Poll harmony_get_pending_messages with the NEW session id" +
|
|
4434
|
+
newSessionId +
|
|
4435
|
+
", not the one you were holding.",
|
|
4436
|
+
};
|
|
4437
|
+
}
|
|
4438
|
+
if (idChangedUnderUs) {
|
|
4439
|
+
// Everything this branch knows, and nothing it does not: no claim that
|
|
4440
|
+
// anything went stale, and none that any capability was preserved.
|
|
4441
|
+
return {
|
|
4442
|
+
success: true,
|
|
4443
|
+
midSessionLearnings: 0,
|
|
4444
|
+
...result,
|
|
4445
|
+
liveSessionIdChanged: true,
|
|
4446
|
+
instruction:
|
|
4447
|
+
"The live session on this card is no longer the one you started — it may have been reopened, or deliberately ended and replaced. Nobody stopped you, so carry on, but poll harmony_get_pending_messages with the session id from this reply" +
|
|
4448
|
+
newSessionId +
|
|
4449
|
+
". If steering matters to this run, do not assume it survived: start a session deliberately with harmony_start_agent_session and steerable: true.",
|
|
4450
|
+
};
|
|
4451
|
+
}
|
|
4452
|
+
|
|
4382
4453
|
// Phase 0 (memory architecture v2): mid-session learning extraction removed.
|
|
4383
4454
|
return { success: true, midSessionLearnings: 0, ...result };
|
|
4384
4455
|
}
|