switchroom 0.18.3 → 0.18.7
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/agent-scheduler/index.js +3 -1
- package/dist/auth-broker/index.js +3 -1
- package/dist/cli/autoaccept-poll.js +140 -33
- package/dist/cli/notion-write-pretool.mjs +3 -1
- package/dist/cli/switchroom.js +386 -128
- package/dist/host-control/main.js +4 -2
- package/dist/vault/approvals/kernel-server.js +3 -1
- package/dist/vault/broker/server.js +38 -8
- package/package.json +3 -3
- package/profiles/_base/cron-session.sh.hbs +55 -16
- package/profiles/_base/start.sh.hbs +35 -16
- package/profiles/default/CLAUDE.md.hbs +1 -1
- package/skills/switchroom-release/SKILL.md +78 -0
- package/telegram-plugin/auth-snapshot-format.ts +15 -1
- package/telegram-plugin/dist/bridge/bridge.js +22 -0
- package/telegram-plugin/dist/gateway/gateway.js +2852 -1032
- package/telegram-plugin/dist/server.js +24 -0
- package/telegram-plugin/gateway/always-allow-persist-queue.ts +438 -0
- package/telegram-plugin/gateway/approval-timeout-inbound-builders.ts +150 -0
- package/telegram-plugin/gateway/clean-shutdown-marker.ts +68 -20
- package/telegram-plugin/gateway/gateway.ts +1331 -151
- package/telegram-plugin/gateway/inbound-spool.ts +2 -1
- package/telegram-plugin/gateway/inject-handler.test.ts +19 -0
- package/telegram-plugin/gateway/inject-handler.ts +17 -0
- package/telegram-plugin/gateway/ipc-protocol.ts +44 -2
- package/telegram-plugin/gateway/ipc-server.ts +40 -0
- package/telegram-plugin/gateway/model-command.ts +212 -51
- package/telegram-plugin/gateway/pending-card-expiry.ts +98 -0
- package/telegram-plugin/gateway/pending-card-store.ts +173 -0
- package/telegram-plugin/gateway/pending-inbound-buffer.ts +12 -2
- package/telegram-plugin/gateway/resolve-person.ts +304 -0
- package/telegram-plugin/gateway/resume-inbound-builder.ts +240 -2
- package/telegram-plugin/gateway/session-model-source.ts +73 -0
- package/telegram-plugin/gateway/unhandled-rejection-policy.ts +21 -1
- package/telegram-plugin/gateway/worker-feed-dispatch.ts +24 -1
- package/telegram-plugin/hooks/silent-end-scan.mjs +164 -40
- package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +30 -7
- package/telegram-plugin/model-label.ts +69 -0
- package/telegram-plugin/operator-events.ts +45 -0
- package/telegram-plugin/pending-work-progress.ts +42 -7
- package/telegram-plugin/permission-diff.ts +128 -0
- package/telegram-plugin/quota-bar-format.ts +360 -0
- package/telegram-plugin/registry/subagents-schema.ts +80 -1
- package/telegram-plugin/registry/subagents.test.ts +90 -0
- package/telegram-plugin/session-tail.ts +28 -0
- package/telegram-plugin/silent-end.ts +49 -4
- package/telegram-plugin/subagent-watcher.ts +249 -46
- package/telegram-plugin/tests/always-allow-persist-queue.test.ts +529 -0
- package/telegram-plugin/tests/approval-timeout-inbound-builders.test.ts +94 -0
- package/telegram-plugin/tests/auth-snapshot-format.test.ts +21 -0
- package/telegram-plugin/tests/button-tap-turn-gated.test.ts +263 -0
- package/telegram-plugin/tests/gateway-boot-marker-clear.test.ts +3 -3
- package/telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts +85 -27
- package/telegram-plugin/tests/gateway-session-model-relaunch.test.ts +4 -2
- package/telegram-plugin/tests/ipc-server-query-pending-permission.test.ts +157 -0
- package/telegram-plugin/tests/mental-model-propose-callback-gate.test.ts +8 -5
- package/telegram-plugin/tests/model-command.test.ts +202 -42
- package/telegram-plugin/tests/model-label.test.ts +64 -0
- package/telegram-plugin/tests/operator-events.test.ts +17 -0
- package/telegram-plugin/tests/pending-card-durability-wiring.test.ts +202 -0
- package/telegram-plugin/tests/pending-card-expiry.test.ts +190 -0
- package/telegram-plugin/tests/pending-card-store.test.ts +173 -0
- package/telegram-plugin/tests/pending-work-progress.test.ts +116 -3
- package/telegram-plugin/tests/permission-diff.test.ts +111 -0
- package/telegram-plugin/tests/quota-bar-format.test.ts +444 -0
- package/telegram-plugin/tests/resolve-person.test.ts +290 -0
- package/telegram-plugin/tests/resume-inbound-builder.test.ts +286 -0
- package/telegram-plugin/tests/session-model-source.test.ts +67 -0
- package/telegram-plugin/tests/session-tail.test.ts +64 -0
- package/telegram-plugin/tests/silent-end-interrupt-stop-integration.test.ts +53 -0
- package/telegram-plugin/tests/silent-end-interrupt-stop-scan.test.ts +138 -0
- package/telegram-plugin/tests/silent-end.test.ts +46 -1
- package/telegram-plugin/tests/subagent-tracker-hooks.test.ts +39 -0
- package/telegram-plugin/tests/subagent-watcher-boot-promotion-replay.test.ts +107 -4
- package/telegram-plugin/tests/subagent-watcher-handback-gaps.test.ts +42 -4
- package/telegram-plugin/tests/subagent-watcher-parent-turn-key.test.ts +47 -0
- package/telegram-plugin/tests/subagent-watcher-terminated-ids-cap.test.ts +150 -0
- package/telegram-plugin/tests/subagent-watcher.test.ts +115 -0
- package/telegram-plugin/tests/tool-activity-summary.test.ts +37 -0
- package/telegram-plugin/tests/typing-wrap.test.ts +23 -0
- package/telegram-plugin/tests/unhandled-rejection-policy.test.ts +19 -0
- package/telegram-plugin/tests/worker-activity-feed.test.ts +108 -0
- package/telegram-plugin/tests/worker-feed-dispatch.test.ts +126 -0
- package/telegram-plugin/tool-activity-summary.ts +22 -2
- package/telegram-plugin/typing-wrap.ts +72 -25
- package/telegram-plugin/worker-activity-feed.ts +229 -15
- package/profiles/default/CLAUDE.md +0 -116
- package/telegram-plugin/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
- package/vendor/hindsight-memory/scripts/__pycache__/directive_verify.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/__pycache__/drain_pending.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/__pycache__/recall.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/__pycache__/retain.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/__pycache__/session_end.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/bank.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/client.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/config.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/content.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/daemon.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/directives.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/gateway_ipc.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/llm.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/pending.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/state.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/lib/__pycache__/switchroom_envelope.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/__init__.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_config_client_casts.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_config_client_casts.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directive_capture_nudge.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directive_capture_nudge.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directive_verify.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directive_verify.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directives.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directives.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_gateway_ipc.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_gateway_ipc.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_context_slice.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_context_slice.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_integration.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_integration.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_tag_filters.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_tag_filters.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_topic_filter.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_topic_filter.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_trivial_skip.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_trivial_skip.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_retain_window.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_retain_window.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_sender_routing.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_sender_routing.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/scripts/tests/__pycache__/test_switchroom_envelope.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/conftest.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_bank.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_bank.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_client.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_client.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_config.cpython-313-pytest-9.0.3.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_config.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_config.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_content.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_content.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_drain_pending.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_drain_pending.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_hooks.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_hooks.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_manifest.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_manifest.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_pending.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_pending.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_recall_exit_codes.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_recall_exit_codes.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_session_end_pending.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_session_end_pending.cpython-313.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_state.cpython-313-pytest-9.1.1.pyc +0 -0
- package/vendor/hindsight-memory/tests/__pycache__/test_state.cpython-313.pyc +0 -0
|
@@ -70,6 +70,14 @@ export interface WorkerActivityView {
|
|
|
70
70
|
/** Wall-clock since dispatch, ms. */
|
|
71
71
|
elapsedMs: number
|
|
72
72
|
state: WorkerActivityState
|
|
73
|
+
/**
|
|
74
|
+
* Live model the worker is running, as a raw resolved model id sourced from
|
|
75
|
+
* its transcript (`message.model`) or, before its first assistant line, the
|
|
76
|
+
* dispatch-time `tool_input.model` persisted on the registry row. Rendered as
|
|
77
|
+
* a short friendly tag on the worker card's metrics line. Omitted when
|
|
78
|
+
* unknown — never guessed from config.
|
|
79
|
+
*/
|
|
80
|
+
model?: string
|
|
73
81
|
}
|
|
74
82
|
|
|
75
83
|
export interface BotApiForWorkerFeed {
|
|
@@ -133,6 +141,7 @@ export function renderWorkerActivity(v: WorkerActivityView, liveSuffix = ''): st
|
|
|
133
141
|
elapsedMs: v.elapsedMs,
|
|
134
142
|
toolCount: v.toolCount,
|
|
135
143
|
state: v.state,
|
|
144
|
+
model: v.model,
|
|
136
145
|
}
|
|
137
146
|
|
|
138
147
|
// Terminal: latestSummary carries the worker's final result text (gateway
|
|
@@ -220,6 +229,28 @@ interface WorkerHandle {
|
|
|
220
229
|
chain: Promise<void>
|
|
221
230
|
/** Last view rendered into the message (drives the heartbeat re-render). */
|
|
222
231
|
lastView: WorkerActivityView | null
|
|
232
|
+
/**
|
|
233
|
+
* A terminal (`finish`) view whose edit could not land yet — most often
|
|
234
|
+
* because a 429 cooldown was in effect when `doFinish` ran. The heartbeat
|
|
235
|
+
* re-drives `doFinish` with this view once the cooldown expires so a
|
|
236
|
+
* transport hiccup can't leave the card stuck on its last running render
|
|
237
|
+
* ("worker done, card says running"). Cleared on a successful terminal
|
|
238
|
+
* edit, on a permanent failure (message gone), or when the handle is
|
|
239
|
+
* deleted. Null when no finalize is pending.
|
|
240
|
+
*/
|
|
241
|
+
pendingFinish: WorkerActivityView | null
|
|
242
|
+
/**
|
|
243
|
+
* Latched in `doFinish` before the terminal edit. A late watcher
|
|
244
|
+
* `onProgress` tick that arrives after `finish()` queued its chain (but
|
|
245
|
+
* before the `.finally(handles.delete)` microtask drains) must NOT
|
|
246
|
+
* resurrect the handle and paint a fresh `running` message on an
|
|
247
|
+
* already-finalized worker. The heartbeat's orphan-paint guard
|
|
248
|
+
* (`if (!handles.has(h.agentId)) continue`) only covers the heartbeat
|
|
249
|
+
* tick — this flag covers the `update` entry point. Set synchronously
|
|
250
|
+
* inside `doFinish` (runs on the chain), checked synchronously in
|
|
251
|
+
* `update` before handle creation.
|
|
252
|
+
*/
|
|
253
|
+
finished: boolean
|
|
223
254
|
/**
|
|
224
255
|
* Wall-clock ms the worker was dispatched, derived from `now - view.elapsedMs`
|
|
225
256
|
* on the first update. The heartbeat computes a live elapsed from this so the
|
|
@@ -246,6 +277,47 @@ function extractRetryAfterSecs(err: unknown): number | null {
|
|
|
246
277
|
return null
|
|
247
278
|
}
|
|
248
279
|
|
|
280
|
+
/**
|
|
281
|
+
* Classify a card-edit transport error. Card edits are a best-effort
|
|
282
|
+
* liveness surface — a recoverable hiccup must never freeze the card, and
|
|
283
|
+
* a permanent failure must never log a scary warning for something with
|
|
284
|
+
* nothing to update.
|
|
285
|
+
*
|
|
286
|
+
* 'not_modified' — content identical to what's already shown. The card
|
|
287
|
+
* already reads correctly; treat as SUCCESS (no retry, no warning).
|
|
288
|
+
* 'rate_limited' — 429 with retry_after. Back off; the heartbeat re-drives
|
|
289
|
+
* the edit after cooldown (running renders + deferred terminal edits).
|
|
290
|
+
* 'gone' — message/chat deleted or edit window expired. Nothing to
|
|
291
|
+
* update; drop the handle silently (no warning — there is no card).
|
|
292
|
+
* 'transient' — anything else (network blip, 5xx). Retry on the next
|
|
293
|
+
* heartbeat tick; don't spam stderr.
|
|
294
|
+
*/
|
|
295
|
+
type EditOutcome = 'not_modified' | 'rate_limited' | 'gone' | 'transient'
|
|
296
|
+
function classifyEditError(err: unknown): EditOutcome {
|
|
297
|
+
const retryAfter = extractRetryAfterSecs(err)
|
|
298
|
+
if (retryAfter != null) return 'rate_limited'
|
|
299
|
+
const desc =
|
|
300
|
+
err instanceof Error ? err.message : err != null && typeof err === 'object' && 'description' in err
|
|
301
|
+
? String((err as { description?: unknown }).description)
|
|
302
|
+
: String(err)
|
|
303
|
+
const low = desc.toLowerCase()
|
|
304
|
+
// "message is not modified" / "message was not modified" — Telegram's
|
|
305
|
+
// identical-content signal. The card already shows the right thing.
|
|
306
|
+
if (low.includes('not modified')) return 'not_modified'
|
|
307
|
+
// Message or chat no longer exists, or the edit window (48h) has closed.
|
|
308
|
+
// "message to edit not found" / "message to delete not found" / "chat not
|
|
309
|
+
// found" / "message can't be edited". Nothing to update.
|
|
310
|
+
if (
|
|
311
|
+
low.includes('not found') ||
|
|
312
|
+
low.includes("can't be edited") ||
|
|
313
|
+
low.includes('cannot be edited') ||
|
|
314
|
+
low.includes('not enough rights')
|
|
315
|
+
) {
|
|
316
|
+
return 'gone'
|
|
317
|
+
}
|
|
318
|
+
return 'transient'
|
|
319
|
+
}
|
|
320
|
+
|
|
249
321
|
/**
|
|
250
322
|
* Manager owning one live message per background worker. Keyed by jsonl
|
|
251
323
|
* agent id. The gateway calls `update` on each watcher activity cue and
|
|
@@ -294,6 +366,28 @@ export function createWorkerActivityFeed(opts: WorkerActivityFeedOpts): WorkerAc
|
|
|
294
366
|
})
|
|
295
367
|
const clearIntervalFn = opts.clearInterval ?? ((handle: unknown) => clearInterval(handle as ReturnType<typeof setInterval>))
|
|
296
368
|
const handles = new Map<string, WorkerHandle>()
|
|
369
|
+
/**
|
|
370
|
+
* Agent ids that have been finalized (`doFinish` latched). Survives handle
|
|
371
|
+
* deletion so a LATE watcher `onProgress` tick — which can arrive after
|
|
372
|
+
* `finish()`'s chain has fully settled and the handle was deleted — cannot
|
|
373
|
+
* resurrect a fresh handle and paint a running card on a worker that is
|
|
374
|
+
* already done. The per-handle `finished` flag only covers the narrow
|
|
375
|
+
* window between latch and delete; this set is the durable gate. A late
|
|
376
|
+
* tick arrives within seconds of finish (watcher poll cadence), so the set
|
|
377
|
+
* only needs to cover recent finalizations — capped at FINALIZED_CAP and
|
|
378
|
+
* trimmed FIFO to stay bounded across a long gateway lifetime.
|
|
379
|
+
*/
|
|
380
|
+
const finalized = new Set<string>()
|
|
381
|
+
const FINALIZED_CAP = 256
|
|
382
|
+
function markFinalized(agentId: string): void {
|
|
383
|
+
if (finalized.has(agentId)) return
|
|
384
|
+
finalized.add(agentId)
|
|
385
|
+
if (finalized.size > FINALIZED_CAP) {
|
|
386
|
+
// Map-free FIFO trim: Set iterates in insertion order; drop the oldest.
|
|
387
|
+
const oldest = finalized.values().next().value
|
|
388
|
+
if (oldest != null) finalized.delete(oldest)
|
|
389
|
+
}
|
|
390
|
+
}
|
|
297
391
|
let heartbeatTimer: unknown = null
|
|
298
392
|
|
|
299
393
|
function sendOptsFor(h: WorkerHandle): Record<string, unknown> {
|
|
@@ -384,39 +478,99 @@ export function createWorkerActivityFeed(opts: WorkerActivityFeedOpts): WorkerAc
|
|
|
384
478
|
`thread=${h.threadId ?? '-'} msgId=${h.messageId} bytes=${body.length}`,
|
|
385
479
|
)
|
|
386
480
|
} catch (err) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
481
|
+
const outcome = classifyEditError(err)
|
|
482
|
+
if (outcome === 'rate_limited') {
|
|
483
|
+
noteRateLimited(h, err, 'edit')
|
|
484
|
+
return
|
|
485
|
+
}
|
|
486
|
+
if (outcome === 'not_modified') {
|
|
487
|
+
// Card already shows this body — record it as landed and move on.
|
|
488
|
+
h.lastBody = body
|
|
489
|
+
h.lastEditAt = nowFn()
|
|
490
|
+
return
|
|
491
|
+
}
|
|
492
|
+
if (outcome === 'gone') {
|
|
493
|
+
// Message/chat deleted or edit window closed — there is no card to
|
|
494
|
+
// update. Drop the handle silently; a fresh first-paint on the next
|
|
495
|
+
// running tick re-establishes one if the worker is still active. No
|
|
496
|
+
// warning: "no card" is not a liveness-logic error.
|
|
497
|
+
h.messageId = null
|
|
498
|
+
h.lastBody = null
|
|
499
|
+
return
|
|
500
|
+
}
|
|
501
|
+
// 'transient' — network blip / 5xx. Leave the handle intact; the
|
|
502
|
+
// heartbeat re-attempts on its next tick. Log at debug, not stderr-warn:
|
|
503
|
+
// a transport hiccup on a best-effort card is not "shit code", it's a
|
|
504
|
+
// retryable blip the framework rides out deterministically.
|
|
505
|
+
log(`worker-feed: edit transient error agent=${h.agentId}: ${(err as Error).message}`)
|
|
394
506
|
}
|
|
395
507
|
}
|
|
396
508
|
|
|
397
509
|
async function doFinish(h: WorkerHandle, view: WorkerActivityView): Promise<void> {
|
|
510
|
+
// Latch FIRST, before any early return. A `running`-cue tick arriving
|
|
511
|
+
// after `finish()` queued this chain (but before its `.finally(delete)`
|
|
512
|
+
// drains) would otherwise resurrect a handle via `update()` and paint a
|
|
513
|
+
// fresh running message on a finalized worker. Setting this synchronously
|
|
514
|
+
// on the chain — ahead of the cooldown/no-message guards — makes the
|
|
515
|
+
// gate in `update()` authoritative regardless of which guard path runs.
|
|
516
|
+
// The durable `finalized` set survives the subsequent handle deletion so
|
|
517
|
+
// a tick arriving AFTER the full settle still can't resurrect.
|
|
518
|
+
h.finished = true
|
|
519
|
+
markFinalized(h.agentId)
|
|
398
520
|
// No message ever posted → nothing to finalize. The worker's result
|
|
399
521
|
// reaches the user via the handback reply; a bare "done" recap with
|
|
400
522
|
// no preceding activity would be noise.
|
|
401
|
-
if (h.messageId == null)
|
|
523
|
+
if (h.messageId == null) {
|
|
524
|
+
h.pendingFinish = null
|
|
525
|
+
return
|
|
526
|
+
}
|
|
402
527
|
if (nowFn() < h.cooldownUntil) {
|
|
403
|
-
// Honour the flood-wait; a terminal edit isn't worth a ban.
|
|
404
|
-
//
|
|
528
|
+
// Honour the flood-wait; a terminal edit isn't worth a ban. But
|
|
529
|
+
// unlike the prior "stale but harmless" surrender, STAGE the terminal
|
|
530
|
+
// view so the heartbeat re-drives the finalize edit the instant the
|
|
531
|
+
// cooldown expires — a transport hiccup can no longer leave a
|
|
532
|
+
// finished worker's card stuck on its last running render.
|
|
533
|
+
h.pendingFinish = view
|
|
405
534
|
return
|
|
406
535
|
}
|
|
407
536
|
const body = renderWorkerActivity({ ...view, narrativeLines: h.narrative })
|
|
408
|
-
if (body === h.lastBody)
|
|
537
|
+
if (body === h.lastBody) {
|
|
538
|
+
h.pendingFinish = null
|
|
539
|
+
return
|
|
540
|
+
}
|
|
409
541
|
try {
|
|
410
542
|
await opts.bot.editMessageText(h.chatId, h.messageId, body, sendOptsFor(h))
|
|
411
543
|
h.lastBody = body
|
|
412
544
|
h.lastEditAt = nowFn()
|
|
545
|
+
h.pendingFinish = null
|
|
413
546
|
log(
|
|
414
547
|
`worker-feed: finish agent=${h.agentId} chat=${h.chatId} ` +
|
|
415
548
|
`thread=${h.threadId ?? '-'} msgId=${h.messageId} state=${view.state} bytes=${body.length}`,
|
|
416
549
|
)
|
|
417
550
|
} catch (err) {
|
|
418
|
-
|
|
419
|
-
|
|
551
|
+
const outcome = classifyEditError(err)
|
|
552
|
+
if (outcome === 'rate_limited') {
|
|
553
|
+
noteRateLimited(h, err, 'finish')
|
|
554
|
+
// Re-stage for the heartbeat to re-drive after cooldown.
|
|
555
|
+
h.pendingFinish = view
|
|
556
|
+
return
|
|
557
|
+
}
|
|
558
|
+
if (outcome === 'not_modified') {
|
|
559
|
+
// Card already shows the finalized body — terminal edit succeeded.
|
|
560
|
+
h.lastBody = body
|
|
561
|
+
h.lastEditAt = nowFn()
|
|
562
|
+
h.pendingFinish = null
|
|
563
|
+
return
|
|
564
|
+
}
|
|
565
|
+
if (outcome === 'gone') {
|
|
566
|
+
// Message/chat gone — no card to finalize. Drop silently; the
|
|
567
|
+
// handback reply carries the result regardless.
|
|
568
|
+
h.pendingFinish = null
|
|
569
|
+
return
|
|
570
|
+
}
|
|
571
|
+
// 'transient' — re-stage for a heartbeat retry; log at debug.
|
|
572
|
+
h.pendingFinish = view
|
|
573
|
+
log(`worker-feed: finish transient error agent=${h.agentId}: ${(err as Error).message}`)
|
|
420
574
|
}
|
|
421
575
|
}
|
|
422
576
|
|
|
@@ -456,6 +610,36 @@ export function createWorkerActivityFeed(opts: WorkerActivityFeedOpts): WorkerAc
|
|
|
456
610
|
// (which would orphan a card that never finalizes). Restores the
|
|
457
611
|
// structural safety the pre-first-paint `messageId == null` skip gave.
|
|
458
612
|
if (!handles.has(h.agentId)) continue
|
|
613
|
+
|
|
614
|
+
// Deferred-finalize re-drive: a terminal edit that hit a 429 cooldown
|
|
615
|
+
// (or a transient error) was staged on `pendingFinish` by `doFinish`.
|
|
616
|
+
// Re-drive it once the cooldown has expired so a finished worker's card
|
|
617
|
+
// can't get stuck on its last running render. This is the deterministic
|
|
618
|
+
// backstop that replaces the old "stale but harmless" surrender — the
|
|
619
|
+
// framework owns ALIVE-and-done, wall-clock driven, no model in the loop.
|
|
620
|
+
// (The handle is still in the map because `finish()`'s `.finally(delete)`
|
|
621
|
+
// is chained AFTER `doFinish` and won't drain while a re-drive keeps the
|
|
622
|
+
// chain busy; once the terminal edit lands, `pendingFinish` is cleared
|
|
623
|
+
// and the `.finally` runs on the next chain settle.)
|
|
624
|
+
if (h.pendingFinish != null && now >= h.cooldownUntil) {
|
|
625
|
+
const view = h.pendingFinish
|
|
626
|
+
h.chain = h.chain
|
|
627
|
+
.then(() => doFinish(h, view))
|
|
628
|
+
.catch((err) => {
|
|
629
|
+
log(`worker-feed: heartbeat finalize re-drive error ${h.agentId}: ${(err as Error).message}`)
|
|
630
|
+
})
|
|
631
|
+
.finally(() => {
|
|
632
|
+
// Mirror `finish()`'s teardown: once the re-driven `doFinish`
|
|
633
|
+
// clears `pendingFinish` (terminal edit landed OR permanently
|
|
634
|
+
// failed), drop the handle. If it re-staged (another 429), the
|
|
635
|
+
// handle survives for the next heartbeat tick to retry.
|
|
636
|
+
if (handles.get(h.agentId)?.pendingFinish == null) {
|
|
637
|
+
handles.delete(h.agentId)
|
|
638
|
+
}
|
|
639
|
+
})
|
|
640
|
+
continue
|
|
641
|
+
}
|
|
642
|
+
|
|
459
643
|
if (h.lastView == null) continue
|
|
460
644
|
if (h.lastView.state !== 'running') continue
|
|
461
645
|
if (now < h.cooldownUntil) continue
|
|
@@ -523,7 +707,19 @@ export function createWorkerActivityFeed(opts: WorkerActivityFeedOpts): WorkerAc
|
|
|
523
707
|
// No chat to post to (owner DM unconfigured) — don't create a
|
|
524
708
|
// handle that would retry a failing send('') every tick.
|
|
525
709
|
if (chatId.length === 0) return Promise.resolve()
|
|
526
|
-
|
|
710
|
+
// Resurrection guard: a worker that has already been finalized
|
|
711
|
+
// (`doFinish` latched `finalized`) must not get a fresh running cue.
|
|
712
|
+
// A late watcher `onProgress` tick can arrive after `finish()`'s chain
|
|
713
|
+
// has fully settled and the handle was deleted — without this durable
|
|
714
|
+
// gate the tick would create a brand-new handle and paint a fresh
|
|
715
|
+
// `running` message on an already-done worker (the card lies). The
|
|
716
|
+
// heartbeat's orphan-paint guard covers the heartbeat tick only; the
|
|
717
|
+
// per-handle `finished` flag covers the pre-delete window; this set
|
|
718
|
+
// covers the post-delete window.
|
|
719
|
+
if (finalized.has(agentId)) return Promise.resolve()
|
|
720
|
+
const existing = handles.get(agentId)
|
|
721
|
+
if (existing?.finished === true) return Promise.resolve()
|
|
722
|
+
let h = existing
|
|
527
723
|
if (h == null) {
|
|
528
724
|
h = {
|
|
529
725
|
agentId,
|
|
@@ -538,6 +734,8 @@ export function createWorkerActivityFeed(opts: WorkerActivityFeedOpts): WorkerAc
|
|
|
538
734
|
lastView: null,
|
|
539
735
|
dispatchAtMs: null,
|
|
540
736
|
stepStartedAtMs: null,
|
|
737
|
+
finished: false,
|
|
738
|
+
pendingFinish: null,
|
|
541
739
|
}
|
|
542
740
|
handles.set(agentId, h)
|
|
543
741
|
}
|
|
@@ -556,11 +754,27 @@ export function createWorkerActivityFeed(opts: WorkerActivityFeedOpts): WorkerAc
|
|
|
556
754
|
log(`worker-feed: finish chain error ${agentId}: ${(err as Error).message}`)
|
|
557
755
|
})
|
|
558
756
|
.finally(() => {
|
|
559
|
-
|
|
757
|
+
// Only tear down the handle once the terminal edit has actually
|
|
758
|
+
// landed (or permanently failed). If `doFinish` staged the edit on
|
|
759
|
+
// `pendingFinish` (a 429 cooldown / transient error was in effect),
|
|
760
|
+
// the handle must survive so the heartbeat can re-drive the
|
|
761
|
+
// finalize after cooldown. The heartbeat's re-drive chain ends by
|
|
762
|
+
// re-entering `doFinish`, which clears `pendingFinish` on success
|
|
763
|
+
// or permanent-failure — so this `.finally` deletes on the NEXT
|
|
764
|
+
// chain settle once there is nothing left to finalize. Without this
|
|
765
|
+
// guard, the `.finally` would delete the handle (and its staged
|
|
766
|
+
// pendingFinish) immediately after the first staged doFinish,
|
|
767
|
+
// stranding the card on its last running render.
|
|
768
|
+
if (handles.get(agentId)?.pendingFinish == null) {
|
|
769
|
+
handles.delete(agentId)
|
|
770
|
+
}
|
|
560
771
|
})
|
|
561
772
|
return h.chain
|
|
562
773
|
},
|
|
563
774
|
drop(agentId) {
|
|
775
|
+
// A dropped worker is also done — mark finalized so a late watcher
|
|
776
|
+
// tick can't resurrect a running card on it (same gate as `finish`).
|
|
777
|
+
markFinalized(agentId)
|
|
564
778
|
handles.delete(agentId)
|
|
565
779
|
},
|
|
566
780
|
heartbeatTick,
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
# Agent:
|
|
2
|
-
|
|
3
|
-
## What you are
|
|
4
|
-
|
|
5
|
-
You are a **switchroom agent** — an instance of **Claude Code** (Anthropic's official `claude` CLI, unmodified) running in a Linux container, managed by switchroom. Your `$SWITCHROOM_AGENT_NAME` is ``. This is operational context for you; how you present yourself to people is your persona's call (see `SOUL.md`).
|
|
6
|
-
|
|
7
|
-
You are one of several agents here. To see the others, call `peers_list` on the `agent-config` MCP server — returns `[{name, purpose, admin}]` live from `switchroom.yaml`. **Never memorize peers into Hindsight or hard-code them into replies** — drift kills trust. On "who else is here" / "is there an agent that does X" / "who handles Y" / "who can do <admin op>", call `peers_list` first and answer from its result; if no peer matches, say so.
|
|
8
|
-
|
|
9
|
-
## Who you are
|
|
10
|
-
|
|
11
|
-
See `SOUL.md` (in this directory) for your identity, vibe, communication style, and expertise. That file is your persona source of truth.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
## Core Behavior
|
|
15
|
-
- Respond helpfully, concisely, and conversationally.
|
|
16
|
-
- Use your available tools when they add clear value — don't force tool use when a plain answer suffices.
|
|
17
|
-
- Save important facts, preferences, and decisions to memory so you can recall them later.
|
|
18
|
-
- When asked to do something ambiguous, ask one clarifying question rather than guessing.
|
|
19
|
-
- If a task has multiple steps, outline your plan before executing.
|
|
20
|
-
|
|
21
|
-
## Safety
|
|
22
|
-
- Don't exfiltrate private data. Ever.
|
|
23
|
-
- Don't run destructive commands without asking.
|
|
24
|
-
- Prefer `trash` over `rm` when available (recoverable beats gone forever).
|
|
25
|
-
- Safe to do freely: read files, explore, organize, search the web, check calendars, work within this workspace.
|
|
26
|
-
- Ask first: sending emails, tweets, public posts, anything that leaves the machine, anything you're uncertain about.
|
|
27
|
-
- **Batch foreseeable approvals; don't drip surprises.** When you can already see that several actions will each need the user's approval, tell them up front which approvals are coming and why. Request independent ones together so they can decide once; for dependent ones (one's input comes from another), say what you're doing first and what approval comes next — a permission card should never arrive out of the blue.
|
|
28
|
-
- **A timed-out approval isn't a denial.** If a request came back denied only because the user was away (a timeout, not an explicit "no"), don't silently abandon it. When they're back, remind them it's still pending and re-offer it if they still want it.
|
|
29
|
-
|
|
30
|
-
## Memory — Hindsight is your single backend
|
|
31
|
-
|
|
32
|
-
**Claude Code's built-in file-based auto-memory is disabled for this agent.** Don't try to write `.md` files under `.claude/projects/.../memory/` or maintain a `MEMORY.md` index — that whole system is off. There's exactly one memory backend: **Hindsight**.
|
|
33
|
-
|
|
34
|
-
Hindsight is a memory bank with semantic search, knowledge graph, entity resolution, mental models, and directives. You talk to it through MCP tools (all pre-approved):
|
|
35
|
-
|
|
36
|
-
### Day-to-day tools
|
|
37
|
-
- `mcp__hindsight__recall` — semantic-search the bank for relevant past memories. Auto-fires on every inbound user message via the plugin's UserPromptSubmit hook (you'll see "Relevant memories from past conversations" in your context). Call manually when you need a more specific query than the auto-fired one.
|
|
38
|
-
- `mcp__hindsight__retain` — store a new memory. The plugin auto-retains every turn via the Stop hook, but in chunked mode each retain only processes a small recent window (~3 turns) — so it captures memory promptly and survives restarts without re-sending the whole transcript, and you usually don't need this. Call manually for significant decisions, corrections, or facts you want immediately searchable.
|
|
39
|
-
- `mcp__hindsight__reflect` — Hindsight's LLM-powered "answer this query using the bank's content + directives". Use when the user asks a question that requires synthesis across multiple past memories.
|
|
40
|
-
|
|
41
|
-
### Mental Models
|
|
42
|
-
A mental model is a pre-computed semantic summary backed by reflection over the bank — a way to maintain a standing answer to a recurring question, semantically populated and refreshed.
|
|
43
|
-
|
|
44
|
-
- `mcp__hindsight__create_mental_model(name, source_query)` — create one for a recurring synthesis you need. When the user shares a fact about themselves (preferences, background, goals), don't write a file — just **retain** the fact. You do NOT need to build or maintain a per-agent "user profile": who the user is lives in dedicated per-user profile banks that the operator curates out-of-band, and recall surfaces it automatically.
|
|
45
|
-
|
|
46
|
-
### Directives (replaces feedback rules)
|
|
47
|
-
Hard rules the agent must follow during reflect — guardrails that are always applied.
|
|
48
|
-
|
|
49
|
-
- `mcp__hindsight__create_directive(text)` — e.g., `create_directive("Always prefer TypeScript over JavaScript for this user's projects")`. When the user gives you a correction or "always do X" rule, create a directive instead of writing a feedback `.md` file.
|
|
50
|
-
|
|
51
|
-
(Inspection tools like `list_memories`, `list_mental_models`, `update_mental_model`, `refresh_mental_model`, `list_directives`, `delete_directive` are available under the `mcp__hindsight__*` namespace if you ever need them, but you rarely should — Hindsight's own auto-recall surfaces what matters and the operator handles bank curation out-of-band.)
|
|
52
|
-
|
|
53
|
-
### What to retain — and what NOT to retain
|
|
54
|
-
|
|
55
|
-
Retain proactively when:
|
|
56
|
-
- The user shares a preference or fact about themselves
|
|
57
|
-
- The user gives you a correction or rule (these go to directives, not retain)
|
|
58
|
-
- A significant decision was made and the rationale matters for next time
|
|
59
|
-
- You did real work and the result + the path you took would be useful next session
|
|
60
|
-
|
|
61
|
-
Don't retain:
|
|
62
|
-
- Routine pleasantries, "thanks", "got it"
|
|
63
|
-
- Conversation chatter that doesn't carry forward
|
|
64
|
-
- Sensitive content the user explicitly asked you to not remember
|
|
65
|
-
- Things already in a mental model — they'll be re-derived from underlying memories
|
|
66
|
-
|
|
67
|
-
The plugin's auto-retain (Stop hook) fires every turn, but in chunked mode each retain only processes a small recent window (~3 turns) — so storage stays prompt and cheap and survives restarts without re-sending the whole transcript, and you don't need to manually retain everything. Use manual `retain` for high-signal observations you want immediately searchable.
|
|
68
|
-
|
|
69
|
-
## Sub-Agent Delegation
|
|
70
|
-
|
|
71
|
-
The main session is for conversation. Execution belongs in sub-agents. Before making tool calls, classify the request:
|
|
72
|
-
|
|
73
|
-
**Stay in main (conversational):**
|
|
74
|
-
- Quick lookups (1-2 tool calls max)
|
|
75
|
-
- Memory/config reads and writes
|
|
76
|
-
- Questions that need user input before acting
|
|
77
|
-
- Simple status checks, coaching, motivation, emotional support
|
|
78
|
-
|
|
79
|
-
**Delegate to a sub-agent (execution):**
|
|
80
|
-
- Any code change — delegate to `@worker`
|
|
81
|
-
- Research requiring web searches or 3+ file reads — delegate to `@researcher`
|
|
82
|
-
- File creation, code generation, build/deploy, multi-step infra
|
|
83
|
-
- Data analysis or report generation
|
|
84
|
-
- Anything involving 3+ sequential tool calls without needing user input
|
|
85
|
-
- Review of completed work — delegate to `@reviewer`
|
|
86
|
-
|
|
87
|
-
**Golden rule:** when in doubt, delegate. Unnecessary delegation costs slightly more tokens. A blocked session costs the user's attention. Keep your own turns short — dispatch and acknowledge. The user should never wait more than 10 seconds for a response from you.
|
|
88
|
-
|
|
89
|
-
**Anti-patterns:** starting a task inline then realizing it's complex mid-way; doing 5+ tool calls "because it's almost done"; polling sub-agent status in a loop.
|
|
90
|
-
|
|
91
|
-
If no sub-agents are configured, do the work yourself.
|
|
92
|
-
|
|
93
|
-
## Session Continuity
|
|
94
|
-
|
|
95
|
-
By default, every restart starts a **fresh `claude` session** — the in-flight transcript is NOT carried over (`session_continuity.resume_mode: handoff`, the default since switchroom #362). Don't assume tool state, scratch variables, or unread tool output from before the restart are still available. What does survive:
|
|
96
|
-
|
|
97
|
-
- **Handoff briefing** — on a clean shutdown, the Stop hook writes a bounded raw transcript tail of the prior session to `.handoff.md`. On boot, start.sh injects it into your `--append-system-prompt` so you can reorient — read it, and lean on your memory files for anything older. If `.handoff.md` is missing or stale (fresh agent, or pre-Stop-hook crash), `start.sh` runs `handoff-briefing.sh` to assemble `.handoff-briefing.md` from Telegram + Hindsight + today's daily memory, and injects whichever is fresher.
|
|
98
|
-
- **Hindsight memory** — auto-recall fires on every inbound user message and surfaces relevant memories from past sessions. Long-term facts, decisions, and mental models live here, not in the transcript.
|
|
99
|
-
- **Telegram history** — the gateway's SQLite buffer remembers every inbound/outbound message. Use `get_recent_messages` to recover recent chat context if the handoff briefing doesn't cover what you need.
|
|
100
|
-
- **Boot-resume inbound** — if your previous session was killed mid-turn, the gateway wakes you on its own with a synthesized inbound (you'll see `<channel source="resume_interrupted">` or `<channel source="resume_watchdog_timeout">`). You don't poll for this — it arrives as your first turn. Two cases, and the inbound text spells out which:
|
|
101
|
-
- **`resume_interrupted`** (operator restart / SIGTERM / crash): pick the work back up and carry it to completion. Briefly tell the user you're resuming and roughly how long ago it was interrupted — then just do it. Do NOT ask whether to resume.
|
|
102
|
-
- **`resume_watchdog_timeout`** (hang-watchdog killed it after no progress): do NOT silently resume — it may hang the same way. Tell the user plainly that your last turn was killed after N minutes of no progress, roughly what it was doing, and ask whether to retry or take a different angle. Report only the honest cause; don't invent a deeper root cause.
|
|
103
|
-
The one-shot `SWITCHROOM_PENDING_*` env vars are passive forensic context for the wake-audit / "why did you restart" protocols — not the resume trigger.
|
|
104
|
-
- **`.wake-audit-pending`** sentinel — every boot drops this file under `TELEGRAM_STATE_DIR`. On your first turn, run the three-signal check (owed reply / orphan sub-agents / open todos) per the wake-audit protocol in your CLAUDE.md, then `rm -f` the sentinel.
|
|
105
|
-
|
|
106
|
-
A config-summary greeting card is sent automatically by the SessionStart hook — you don't need to announce yourself. If your context feels thin (after compaction or any fresh session), proactively recall from Hindsight before proceeding.
|
|
107
|
-
|
|
108
|
-
(Operators can override the resume policy per-agent via `session_continuity.resume_mode` in switchroom.yaml — `auto`, `continue`, `handoff`, or `none`. The default is `handoff`.)
|
|
109
|
-
|
|
110
|
-
## Admin operations
|
|
111
|
-
|
|
112
|
-
You're NOT `admin: true`. If asked to restart agents / read peer logs / exec into peer containers / run fleet updates, call `peers_list`, find an entry with `admin: true`, and point the user there: _"I can't restart agents from here — ask `<admin-name>`, they're admin on this instance."_ No long apology; just hand off.
|
|
113
|
-
|
|
114
|
-
## Tools
|
|
115
|
-
Use your available tools when appropriate. If you lack the right tool for a task, say so clearly rather than attempting a workaround.
|
|
116
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":"3.2.4","results":[[":tests/worker-activity-feed.test.ts",{"duration":604.6399409999995,"failed":true}]]}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/vendor/hindsight-memory/scripts/tests/__pycache__/test_config_client_casts.cpython-313.pyc
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/vendor/hindsight-memory/scripts/tests/__pycache__/test_directive_verify.cpython-313.pyc
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_context_slice.cpython-313.pyc
DELETED
|
Binary file
|
|
Binary file
|
package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_integration.cpython-313.pyc
DELETED
|
Binary file
|
|
Binary file
|
package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_tag_filters.cpython-313.pyc
DELETED
|
Binary file
|
|
Binary file
|
package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_topic_filter.cpython-313.pyc
DELETED
|
Binary file
|
|
Binary file
|
package/vendor/hindsight-memory/scripts/tests/__pycache__/test_recall_trivial_skip.cpython-313.pyc
DELETED
|
Binary file
|
|
Binary file
|
package/vendor/hindsight-memory/scripts/tests/__pycache__/test_retain_window.cpython-313.pyc
DELETED
|
Binary file
|
|
Binary file
|
package/vendor/hindsight-memory/scripts/tests/__pycache__/test_sender_routing.cpython-313.pyc
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/vendor/hindsight-memory/tests/__pycache__/test_drain_pending.cpython-313-pytest-9.1.1.pyc
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/vendor/hindsight-memory/tests/__pycache__/test_manifest.cpython-313-pytest-9.1.1.pyc
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|