@theronap/agnoclast-mcp 0.9.166 → 0.9.167
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/lib/server.mjs +49 -20
- package/package.json +1 -1
package/lib/server.mjs
CHANGED
|
@@ -291,40 +291,39 @@ function renderSettling(payload) {
|
|
|
291
291
|
if (!offers.length) return ''
|
|
292
292
|
const total = Number(feed?.total ?? offers.length)
|
|
293
293
|
|
|
294
|
+
// ⚠ THE THREE STAGES READ DIFFERENTLY BECAUSE THE RIGHT RESPONSE DIFFERS. A `matched` arrival is
|
|
295
|
+
// probably yours. An `orphan` reached you because it reached NOBODY — you are not the obvious
|
|
296
|
+
// owner, you are the only one looking, and the burden of proof is lower for leaving it. Rendering
|
|
297
|
+
// all three as "matched to what you have open" would be a claim the feed cannot support, and an
|
|
298
|
+
// agent that catches a nudge overstating itself stops trusting the rest of it.
|
|
294
299
|
const lines = offers.map((x) => {
|
|
295
|
-
const why = x.
|
|
296
|
-
|
|
300
|
+
const why = x.via_reason === 'matched' && x.via?.length
|
|
301
|
+
? ` — matches ${x.via.map((v) => `\`${v}\``).join(', ')}`
|
|
302
|
+
: x.via_reason === 'orphan'
|
|
303
|
+
? ' — ⚠ NO session of yours matches this; it is here because it reached nobody'
|
|
304
|
+
: ' — every session that matched it declined, so it is back to everyone'
|
|
297
305
|
const looked = x.looks > 0 ? ` [looked at ${x.looks}x, still unclaimed]` : ''
|
|
298
306
|
return ` - ${x.source} · ${x.hoursAgo}h ago · ${x.intakeItemId}${why}${looked}`
|
|
299
307
|
})
|
|
300
308
|
|
|
301
|
-
// ⚠ SAY THE TRUE TOTAL, NOT THE PAGE SIZE. Measured 2026-09-22: one identifier matched 113 settling
|
|
302
|
-
// units against a cap of 12. A block that says "here are 12" when there are 113 is claiming
|
|
303
|
-
// certainty it does not have — and renders identically every turn, which teaches the reader that
|
|
304
|
-
// it never changes and can be skipped.
|
|
305
309
|
const more = total > offers.length
|
|
306
310
|
? `\n— Showing ${offers.length} of ${total}. \`intake_changes\` lists the rest; this is a sample, not the queue.`
|
|
307
311
|
: ''
|
|
308
312
|
|
|
309
|
-
// ⚠ CONTENTION IS STATED, exactly as the record nudge states `k`. Measured the same day: THREE live
|
|
310
|
-
// sessions each matched the SAME 113 units on one identifier. Silent about that, each would claim
|
|
311
|
-
// the same units and learn about the race from a failed lease.
|
|
312
313
|
const maxHolders = offers.reduce((m, x) => Math.max(m, Number(x.holders ?? 1)), 1)
|
|
313
314
|
const who = maxHolders > 1
|
|
314
315
|
? `\n— ⚠ ${maxHolders} live sessions of yours hold a matching identifier, so these are offered to all of them. \`intake_claim\` takes a lease — claim before you work, not after, or two sessions judge the same arrival.`
|
|
315
|
-
:
|
|
316
|
+
: ''
|
|
316
317
|
|
|
317
318
|
return `\n\n⚡ ARRIVALS SETTLING — yours alone, and no one else can see these yet:\n${lines.join('\n')}\n` +
|
|
318
319
|
`— These are unjudged ARRIVALS, not records. Since automatic materialization was deleted, nothing files them for you.\n` +
|
|
319
320
|
`— \`intake_look <id>\` reads the full body without claiming it — looking is free, non-exclusive and logged, so look rather than guess from the headline.\n` +
|
|
320
|
-
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
more + who +
|
|
327
|
-
`\n— If none are yours, leave them: they stay settling for your other sessions, and become everyone's business once the window closes.`
|
|
321
|
+
`— Then \`intake_claim {intakeItemIds: ["<id>"]}\` to take a lease on THAT unit (the array is required; without an id you claim the head of the queue instead), then \`intake_materialize\` into the brain and pages it belongs to — or \`intake_discard\`, or \`intake_defer\` with a question when only the owner can decide.\n` +
|
|
322
|
+
// ⚠ THE DECLINE IS NAMED HERE BECAUSE IT DID NOT EXIST BEFORE 0.9.167. An offer with no
|
|
323
|
+
// available "no" is re-offered on every tool call until the window closes, which is how an
|
|
324
|
+
// agent learns to skip the block entirely.
|
|
325
|
+
`— NOT yours? \`not_mine {intake_item_id: "<id>", reason: "..."}\` — per session, not a suppression: it keeps going to your other matching sessions, and once they have all declined it comes back to everyone.` +
|
|
326
|
+
more + who
|
|
328
327
|
}
|
|
329
328
|
|
|
330
329
|
function renderNudge(payload) {
|
|
@@ -2852,11 +2851,41 @@ function renderNudge(payload) {
|
|
|
2852
2851
|
title: 'Decline a nudged record — it is not this session\'s business',
|
|
2853
2852
|
description: 'Say a nudged record is NOT your business. Use it when the ⚡ ARRIVED block offered you a record and you have looked and it does not belong to what you are doing. ⚠ THIS IS NOT A CLAIM AND NOT A SUPPRESSION: the record stays unclaimed, stays on the general timeline, and stays offerable to any other session holding a matching identifier. You are saying "not MY business", never "nobody\'s business", and no other session is affected. Declining is a COMPLETE and expected answer — the cascade offers on the evidence of what you have open, which is a good guess and not a fact, and a wrong claim costs more than a decline. Without this the same nudge returns on your next tool call and the disagreement is recorded nowhere.',
|
|
2854
2853
|
inputSchema: {
|
|
2855
|
-
record_id: z.string().describe('the record id from the ⚡ ARRIVED block'),
|
|
2854
|
+
record_id: z.string().optional().describe('the record id from the ⚡ ARRIVED block'),
|
|
2855
|
+
// ⚠ THE TWO BLOCKS OFFER DIFFERENT KINDS OF THING, and this verb now answers both. ⚡ ARRIVED
|
|
2856
|
+
// offers unclaimed RECORDS; ⚡ ARRIVALS SETTLING offers intake ARRIVALS that are not records
|
|
2857
|
+
// and may never become one. Until 0.9.167 the settling block had no decline at all, so a unit
|
|
2858
|
+
// a session had judged irrelevant was re-offered on every tool call — pilot B's 22-hour
|
|
2859
|
+
// re-offer defect (§11), recreated by the fix for the other half of the same problem.
|
|
2860
|
+
intake_item_id: z.string().optional().describe('the ARRIVAL id from the ⚡ ARRIVALS SETTLING block (not a record id)'),
|
|
2856
2861
|
reason: z.string().describe('WHY it is not yours — recorded, and the only thing that can later answer "why did nobody take this"'),
|
|
2857
2862
|
},
|
|
2858
2863
|
},
|
|
2859
|
-
async ({ record_id, reason }) => {
|
|
2864
|
+
async ({ record_id, intake_item_id, reason }) => {
|
|
2865
|
+
// ⚠ REFUSE BOTH AND NEITHER EXPLICITLY. Tonight's other defect was a parameter accepted by the
|
|
2866
|
+
// caller, dropped by the schema, and replaced by a default that did something else entirely.
|
|
2867
|
+
// An ambiguous decline must fail loudly, never pick one.
|
|
2868
|
+
if (record_id && intake_item_id) {
|
|
2869
|
+
return toolError('Pass record_id OR intake_item_id, not both — they are different kinds of thing and I will not guess which you meant.')
|
|
2870
|
+
}
|
|
2871
|
+
if (!record_id && !intake_item_id) {
|
|
2872
|
+
return toolError('Pass record_id (from ⚡ ARRIVED) or intake_item_id (from ⚡ ARRIVALS SETTLING).')
|
|
2873
|
+
}
|
|
2874
|
+
if (intake_item_id) {
|
|
2875
|
+
let r
|
|
2876
|
+
try {
|
|
2877
|
+
r = await fetchCortex(`${BASE}/api/settling/reject`, {
|
|
2878
|
+
method: 'POST',
|
|
2879
|
+
headers: { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json' },
|
|
2880
|
+
body: JSON.stringify({ intakeItemId: intake_item_id, reason }),
|
|
2881
|
+
})
|
|
2882
|
+
} catch (e) {
|
|
2883
|
+
return toolError(`Could not decline ${intake_item_id}: ${e.message}`)
|
|
2884
|
+
}
|
|
2885
|
+
const o = await r.json().catch(() => null)
|
|
2886
|
+
if (!r.ok) return toolError(`Could not decline ${intake_item_id}: ${o?.error ?? r.status}`)
|
|
2887
|
+
return { content: [{ type: 'text', text: `Noted — arrival ${intake_item_id} will not be offered to THIS session again. It stays pending and still goes to your other matching sessions; once they have all declined it, it comes back to everyone as unclaimed.` }] }
|
|
2888
|
+
}
|
|
2860
2889
|
let res
|
|
2861
2890
|
try {
|
|
2862
2891
|
res = await fetchCortex(`${BASE}/api/nudge/reject`, {
|
package/package.json
CHANGED