@desplega.ai/agent-swarm 1.74.3 → 1.75.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/openapi.json +282 -1
- package/package.json +1 -1
- package/src/be/db.ts +36 -0
- package/src/be/memory/edges-store.ts +69 -0
- package/src/be/memory/providers/sqlite-store.ts +4 -0
- package/src/be/memory/raters/explicit-self.ts +22 -0
- package/src/be/memory/raters/implicit-citation.ts +44 -0
- package/src/be/memory/raters/llm-client.ts +172 -0
- package/src/be/memory/raters/llm.ts +394 -0
- package/src/be/memory/raters/noop.ts +14 -0
- package/src/be/memory/raters/registry.ts +86 -0
- package/src/be/memory/raters/retrieval.ts +88 -0
- package/src/be/memory/raters/run-server-raters.ts +97 -0
- package/src/be/memory/raters/store.ts +228 -0
- package/src/be/memory/raters/types.ts +101 -0
- package/src/be/memory/reranker.ts +32 -2
- package/src/be/memory/retrieval-store.ts +95 -0
- package/src/be/memory/types.ts +3 -0
- package/src/be/migrations/051_memory_posteriors_and_retrieval.sql +67 -0
- package/src/be/migrations/052_memory_edges.sql +36 -0
- package/src/be/migrations/053_agent_waiting_for_credentials_status.sql +61 -0
- package/src/commands/credential-wait.ts +186 -0
- package/src/commands/runner.ts +54 -9
- package/src/hooks/hook.ts +67 -10
- package/src/http/agents.ts +110 -0
- package/src/http/core.ts +5 -0
- package/src/http/memory.ts +230 -1
- package/src/prompts/memories.ts +62 -0
- package/src/providers/claude-adapter.ts +17 -0
- package/src/providers/claude-managed-adapter.ts +24 -0
- package/src/providers/codex-adapter.ts +125 -69
- package/src/providers/codex-models.ts +25 -17
- package/src/providers/credentials.ts +74 -0
- package/src/providers/devin-adapter.ts +18 -0
- package/src/providers/index.ts +7 -0
- package/src/providers/opencode-adapter.ts +60 -0
- package/src/providers/pi-mono-adapter.ts +71 -0
- package/src/providers/types.ts +34 -0
- package/src/server.ts +2 -0
- package/src/tests/codex-adapter.test.ts +5 -4
- package/src/tests/credential-check.test.ts +336 -0
- package/src/tests/credential-status-api.test.ts +181 -0
- package/src/tests/credential-status-routing.test.ts +150 -0
- package/src/tests/credential-wait.test.ts +282 -0
- package/src/tests/memory-edges.test.ts +722 -0
- package/src/tests/memory-rate-endpoint.test.ts +330 -0
- package/src/tests/memory-rate-tool.test.ts +252 -0
- package/src/tests/memory-rater-e2e.test.ts +578 -0
- package/src/tests/memory-rater-implicit-citation.test.ts +304 -0
- package/src/tests/memory-rater-llm.test.ts +806 -0
- package/src/tests/memory-rater-store.test.ts +249 -0
- package/src/tests/memory-reranker.test.ts +161 -2
- package/src/tests/mocks/mock-llm-rater-client.ts +35 -0
- package/src/tests/run-server-raters.test.ts +291 -0
- package/src/tests/tool-annotations.test.ts +2 -2
- package/src/tools/memory-rate.ts +166 -0
- package/src/tools/memory-search.ts +18 -0
- package/src/tools/store-progress.ts +37 -0
- package/src/tools/tool-config.ts +1 -0
- package/src/types.ts +5 -1
package/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Agent Swarm API",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.75.0",
|
|
6
6
|
"description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)."
|
|
7
7
|
},
|
|
8
8
|
"servers": [
|
|
@@ -621,6 +621,126 @@
|
|
|
621
621
|
}
|
|
622
622
|
}
|
|
623
623
|
},
|
|
624
|
+
"/api/agents/{id}/credential-status": {
|
|
625
|
+
"put": {
|
|
626
|
+
"summary": "Worker self-report of credential readiness (Phase 3 boot loop)",
|
|
627
|
+
"tags": [
|
|
628
|
+
"Agents"
|
|
629
|
+
],
|
|
630
|
+
"security": [
|
|
631
|
+
{
|
|
632
|
+
"bearerAuth": []
|
|
633
|
+
}
|
|
634
|
+
],
|
|
635
|
+
"parameters": [
|
|
636
|
+
{
|
|
637
|
+
"schema": {
|
|
638
|
+
"type": "string"
|
|
639
|
+
},
|
|
640
|
+
"required": true,
|
|
641
|
+
"name": "id",
|
|
642
|
+
"in": "path"
|
|
643
|
+
}
|
|
644
|
+
],
|
|
645
|
+
"requestBody": {
|
|
646
|
+
"content": {
|
|
647
|
+
"application/json": {
|
|
648
|
+
"schema": {
|
|
649
|
+
"type": "object",
|
|
650
|
+
"properties": {
|
|
651
|
+
"ready": {
|
|
652
|
+
"type": "boolean"
|
|
653
|
+
},
|
|
654
|
+
"missing": {
|
|
655
|
+
"type": [
|
|
656
|
+
"array",
|
|
657
|
+
"null"
|
|
658
|
+
],
|
|
659
|
+
"items": {
|
|
660
|
+
"type": "string"
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
"required": [
|
|
665
|
+
"ready"
|
|
666
|
+
]
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
},
|
|
671
|
+
"responses": {
|
|
672
|
+
"200": {
|
|
673
|
+
"description": "State updated; returns the agent row."
|
|
674
|
+
},
|
|
675
|
+
"404": {
|
|
676
|
+
"description": "Agent not found"
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
},
|
|
680
|
+
"get": {
|
|
681
|
+
"summary": "Single-agent credential-status snapshot for the dashboard",
|
|
682
|
+
"tags": [
|
|
683
|
+
"Agents"
|
|
684
|
+
],
|
|
685
|
+
"security": [
|
|
686
|
+
{
|
|
687
|
+
"bearerAuth": []
|
|
688
|
+
}
|
|
689
|
+
],
|
|
690
|
+
"parameters": [
|
|
691
|
+
{
|
|
692
|
+
"schema": {
|
|
693
|
+
"type": "string"
|
|
694
|
+
},
|
|
695
|
+
"required": true,
|
|
696
|
+
"name": "id",
|
|
697
|
+
"in": "path"
|
|
698
|
+
}
|
|
699
|
+
],
|
|
700
|
+
"responses": {
|
|
701
|
+
"200": {
|
|
702
|
+
"description": "Credential status payload"
|
|
703
|
+
},
|
|
704
|
+
"404": {
|
|
705
|
+
"description": "Agent not found"
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
},
|
|
710
|
+
"/api/agents/credential-status": {
|
|
711
|
+
"get": {
|
|
712
|
+
"summary": "Bulk credential-status across all agents (powers the dashboard)",
|
|
713
|
+
"tags": [
|
|
714
|
+
"Agents"
|
|
715
|
+
],
|
|
716
|
+
"security": [
|
|
717
|
+
{
|
|
718
|
+
"bearerAuth": []
|
|
719
|
+
}
|
|
720
|
+
],
|
|
721
|
+
"parameters": [
|
|
722
|
+
{
|
|
723
|
+
"schema": {
|
|
724
|
+
"type": "string",
|
|
725
|
+
"enum": [
|
|
726
|
+
"idle",
|
|
727
|
+
"busy",
|
|
728
|
+
"offline",
|
|
729
|
+
"waiting_for_credentials"
|
|
730
|
+
]
|
|
731
|
+
},
|
|
732
|
+
"required": false,
|
|
733
|
+
"name": "status",
|
|
734
|
+
"in": "query"
|
|
735
|
+
}
|
|
736
|
+
],
|
|
737
|
+
"responses": {
|
|
738
|
+
"200": {
|
|
739
|
+
"description": "List of {agentId, status, missing[], lastCheckedAt}"
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
},
|
|
624
744
|
"/api/approval-requests": {
|
|
625
745
|
"post": {
|
|
626
746
|
"summary": "Create a new approval request",
|
|
@@ -3031,6 +3151,167 @@
|
|
|
3031
3151
|
}
|
|
3032
3152
|
}
|
|
3033
3153
|
},
|
|
3154
|
+
"/api/memory/rate": {
|
|
3155
|
+
"post": {
|
|
3156
|
+
"summary": "Submit RatingEvents to update memory usefulness posteriors",
|
|
3157
|
+
"tags": [
|
|
3158
|
+
"Memory"
|
|
3159
|
+
],
|
|
3160
|
+
"security": [
|
|
3161
|
+
{
|
|
3162
|
+
"bearerAuth": []
|
|
3163
|
+
}
|
|
3164
|
+
],
|
|
3165
|
+
"requestBody": {
|
|
3166
|
+
"content": {
|
|
3167
|
+
"application/json": {
|
|
3168
|
+
"schema": {
|
|
3169
|
+
"type": "object",
|
|
3170
|
+
"properties": {
|
|
3171
|
+
"events": {
|
|
3172
|
+
"type": "array",
|
|
3173
|
+
"items": {
|
|
3174
|
+
"type": "object",
|
|
3175
|
+
"properties": {
|
|
3176
|
+
"memoryId": {
|
|
3177
|
+
"type": "string",
|
|
3178
|
+
"minLength": 1
|
|
3179
|
+
},
|
|
3180
|
+
"signal": {
|
|
3181
|
+
"type": "number",
|
|
3182
|
+
"minimum": -1,
|
|
3183
|
+
"maximum": 1
|
|
3184
|
+
},
|
|
3185
|
+
"weight": {
|
|
3186
|
+
"type": "number",
|
|
3187
|
+
"minimum": 0,
|
|
3188
|
+
"maximum": 1
|
|
3189
|
+
},
|
|
3190
|
+
"source": {
|
|
3191
|
+
"type": "string",
|
|
3192
|
+
"enum": [
|
|
3193
|
+
"llm",
|
|
3194
|
+
"explicit-self"
|
|
3195
|
+
]
|
|
3196
|
+
},
|
|
3197
|
+
"reasoning": {
|
|
3198
|
+
"type": "string",
|
|
3199
|
+
"maxLength": 500
|
|
3200
|
+
},
|
|
3201
|
+
"taskId": {
|
|
3202
|
+
"type": "string",
|
|
3203
|
+
"format": "uuid"
|
|
3204
|
+
},
|
|
3205
|
+
"referencesSource": {
|
|
3206
|
+
"type": "string",
|
|
3207
|
+
"minLength": 1,
|
|
3208
|
+
"maxLength": 512,
|
|
3209
|
+
"description": "Optional external source ID this memory references. Free-form string, convention \"<source>:<identifier>\" (e.g. \"github:owner/repo#N\", \"linear:KEY-N\", \"customer:<slug>\", \"slack:<channel>:<ts>\", \"agentmail:<thread-id>\"). Pick any prefix that fits — no closed enum. When present, an edge from this memory to the external source is created/updated."
|
|
3210
|
+
}
|
|
3211
|
+
},
|
|
3212
|
+
"required": [
|
|
3213
|
+
"memoryId",
|
|
3214
|
+
"signal",
|
|
3215
|
+
"weight",
|
|
3216
|
+
"source"
|
|
3217
|
+
]
|
|
3218
|
+
},
|
|
3219
|
+
"minItems": 1,
|
|
3220
|
+
"maxItems": 50
|
|
3221
|
+
}
|
|
3222
|
+
},
|
|
3223
|
+
"required": [
|
|
3224
|
+
"events"
|
|
3225
|
+
]
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
},
|
|
3230
|
+
"responses": {
|
|
3231
|
+
"200": {
|
|
3232
|
+
"description": "Ratings applied; per-event rejections returned in body"
|
|
3233
|
+
},
|
|
3234
|
+
"400": {
|
|
3235
|
+
"description": "Validation error or explicit-self R6 spam-guard rejection"
|
|
3236
|
+
},
|
|
3237
|
+
"409": {
|
|
3238
|
+
"description": "Duplicate explicit-self rating for (taskId, memoryId)"
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
},
|
|
3243
|
+
"/api/memory/retrievals": {
|
|
3244
|
+
"get": {
|
|
3245
|
+
"summary": "List memories retrieved for a task or session (rater input)",
|
|
3246
|
+
"tags": [
|
|
3247
|
+
"Memory"
|
|
3248
|
+
],
|
|
3249
|
+
"security": [
|
|
3250
|
+
{
|
|
3251
|
+
"bearerAuth": []
|
|
3252
|
+
}
|
|
3253
|
+
],
|
|
3254
|
+
"parameters": [
|
|
3255
|
+
{
|
|
3256
|
+
"schema": {
|
|
3257
|
+
"type": "string",
|
|
3258
|
+
"format": "uuid"
|
|
3259
|
+
},
|
|
3260
|
+
"required": false,
|
|
3261
|
+
"name": "taskId",
|
|
3262
|
+
"in": "query"
|
|
3263
|
+
},
|
|
3264
|
+
{
|
|
3265
|
+
"schema": {
|
|
3266
|
+
"type": "string"
|
|
3267
|
+
},
|
|
3268
|
+
"required": false,
|
|
3269
|
+
"name": "sessionId",
|
|
3270
|
+
"in": "query"
|
|
3271
|
+
}
|
|
3272
|
+
],
|
|
3273
|
+
"responses": {
|
|
3274
|
+
"200": {
|
|
3275
|
+
"description": "Retrieval rows joined with agent_memory"
|
|
3276
|
+
},
|
|
3277
|
+
"400": {
|
|
3278
|
+
"description": "Missing taskId/sessionId or X-Agent-ID"
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
},
|
|
3283
|
+
"/api/memory/edges": {
|
|
3284
|
+
"get": {
|
|
3285
|
+
"summary": "List references-source edges for a memory",
|
|
3286
|
+
"tags": [
|
|
3287
|
+
"Memory"
|
|
3288
|
+
],
|
|
3289
|
+
"security": [
|
|
3290
|
+
{
|
|
3291
|
+
"bearerAuth": []
|
|
3292
|
+
}
|
|
3293
|
+
],
|
|
3294
|
+
"parameters": [
|
|
3295
|
+
{
|
|
3296
|
+
"schema": {
|
|
3297
|
+
"type": "string",
|
|
3298
|
+
"minLength": 1
|
|
3299
|
+
},
|
|
3300
|
+
"required": true,
|
|
3301
|
+
"name": "memoryId",
|
|
3302
|
+
"in": "query"
|
|
3303
|
+
}
|
|
3304
|
+
],
|
|
3305
|
+
"responses": {
|
|
3306
|
+
"200": {
|
|
3307
|
+
"description": "Edges with computed usefulness scores"
|
|
3308
|
+
},
|
|
3309
|
+
"400": {
|
|
3310
|
+
"description": "Missing memoryId or X-Agent-ID"
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
},
|
|
3034
3315
|
"/api/prompt-templates/resolved": {
|
|
3035
3316
|
"get": {
|
|
3036
3317
|
"summary": "Resolve a prompt template for a given event type and scope chain",
|
package/package.json
CHANGED
package/src/be/db.ts
CHANGED
|
@@ -555,6 +555,8 @@ type AgentRow = {
|
|
|
555
555
|
provider: string | null;
|
|
556
556
|
createdAt: string;
|
|
557
557
|
lastUpdatedAt: string;
|
|
558
|
+
/** JSON array of env-var names; populated only when status is `waiting_for_credentials`. */
|
|
559
|
+
credentialMissing: string | null;
|
|
558
560
|
};
|
|
559
561
|
|
|
560
562
|
function rowToAgent(row: AgentRow): Agent {
|
|
@@ -578,6 +580,9 @@ function rowToAgent(row: AgentRow): Agent {
|
|
|
578
580
|
provider: (row.provider as ProviderName | null) ?? undefined,
|
|
579
581
|
createdAt: row.createdAt,
|
|
580
582
|
lastUpdatedAt: row.lastUpdatedAt,
|
|
583
|
+
credentialMissing: row.credentialMissing
|
|
584
|
+
? (JSON.parse(row.credentialMissing) as string[])
|
|
585
|
+
: null,
|
|
581
586
|
};
|
|
582
587
|
}
|
|
583
588
|
|
|
@@ -596,9 +601,36 @@ export const agentQueries = {
|
|
|
596
601
|
"UPDATE agents SET status = ?, lastUpdatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = ? RETURNING *",
|
|
597
602
|
),
|
|
598
603
|
|
|
604
|
+
updateCredentialState: () =>
|
|
605
|
+
getDb().prepare<AgentRow, [AgentStatus, string | null, string]>(
|
|
606
|
+
"UPDATE agents SET status = ?, credentialMissing = ?, lastUpdatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = ? RETURNING *",
|
|
607
|
+
),
|
|
608
|
+
|
|
599
609
|
delete: () => getDb().prepare<null, [string]>("DELETE FROM agents WHERE id = ?"),
|
|
600
610
|
};
|
|
601
611
|
|
|
612
|
+
/**
|
|
613
|
+
* Phase 3 of the worker credential safe-loop plan.
|
|
614
|
+
*
|
|
615
|
+
* `ready=true` clears the waiting state — the agent transitions to `idle`
|
|
616
|
+
* and the dispatcher will start handing it tasks again.
|
|
617
|
+
*
|
|
618
|
+
* `ready=false` parks the agent on `waiting_for_credentials` with the env-var
|
|
619
|
+
* names it's blocked on. The capacity dispatch query already filters
|
|
620
|
+
* `status === 'idle'` so the new value is implicitly excluded with no other
|
|
621
|
+
* code change.
|
|
622
|
+
*/
|
|
623
|
+
export function updateAgentCredentialState(
|
|
624
|
+
agentId: string,
|
|
625
|
+
ready: boolean,
|
|
626
|
+
missing: string[] | null,
|
|
627
|
+
): Agent | null {
|
|
628
|
+
const status: AgentStatus = ready ? "idle" : "waiting_for_credentials";
|
|
629
|
+
const missingJson = ready ? null : missing && missing.length > 0 ? JSON.stringify(missing) : null;
|
|
630
|
+
const row = agentQueries.updateCredentialState().get(status, missingJson, agentId);
|
|
631
|
+
return row ? rowToAgent(row) : null;
|
|
632
|
+
}
|
|
633
|
+
|
|
602
634
|
export function createAgent(
|
|
603
635
|
agent: Omit<Agent, "id" | "createdAt" | "lastUpdatedAt"> & { id?: string },
|
|
604
636
|
): Agent {
|
|
@@ -774,6 +806,10 @@ export function getRemainingCapacity(agentId: string): number {
|
|
|
774
806
|
export function updateAgentStatusFromCapacity(agentId: string): void {
|
|
775
807
|
const agent = getAgentById(agentId);
|
|
776
808
|
if (!agent || agent.status === "offline") return;
|
|
809
|
+
// `waiting_for_credentials` is owned by the worker's credential-wait
|
|
810
|
+
// tick — task-completion shouldn't accidentally promote a blocked agent
|
|
811
|
+
// back to idle.
|
|
812
|
+
if (agent.status === "waiting_for_credentials") return;
|
|
777
813
|
|
|
778
814
|
const activeCount = getActiveTaskCount(agentId);
|
|
779
815
|
const newStatus = activeCount > 0 ? "busy" : "idle";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-side query helpers for the `agent_memory_edge` table.
|
|
3
|
+
*
|
|
4
|
+
* Plan: thoughts/taras/plans/2026-05-05-memory-rater-v1.5/step-6.md §7
|
|
5
|
+
*
|
|
6
|
+
* The write path lives in `src/be/memory/raters/store.ts` (`applyRating`
|
|
7
|
+
* UPSERTs the edge atomically with the memory's posterior update). This
|
|
8
|
+
* module surfaces reads to the GET `/api/memory/edges` endpoint that powers
|
|
9
|
+
* the homepage demo ("this memory references PR #377").
|
|
10
|
+
*
|
|
11
|
+
* Server-side only.
|
|
12
|
+
*/
|
|
13
|
+
import { getDb } from "@/be/db";
|
|
14
|
+
|
|
15
|
+
const USEFULNESS_FLOOR = 1.0;
|
|
16
|
+
const USEFULNESS_CEILING = 2.0;
|
|
17
|
+
|
|
18
|
+
export type MemoryEdgeRow = {
|
|
19
|
+
to: string;
|
|
20
|
+
type: "references-source";
|
|
21
|
+
alpha: number;
|
|
22
|
+
beta: number;
|
|
23
|
+
/** clamp(2 * α/(α+β), 1.0, 2.0) — same formula as the memory reranker. */
|
|
24
|
+
usefulness: number;
|
|
25
|
+
createdAt: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* List edges for a memory, with defence-in-depth: the joined `agent_memory`
|
|
30
|
+
* row must either be swarm-scope or owned by the requesting agent. Returns
|
|
31
|
+
* `[]` when the memory does not exist or is not visible to the agent — same
|
|
32
|
+
* shape as a memory with no edges, since neither case has anything useful
|
|
33
|
+
* to surface to the caller.
|
|
34
|
+
*/
|
|
35
|
+
export function listEdgesForAgent(agentId: string, memoryId: string): MemoryEdgeRow[] {
|
|
36
|
+
const db = getDb();
|
|
37
|
+
const memory = db
|
|
38
|
+
.prepare<{ scope: string; agentId: string | null }, [string]>(
|
|
39
|
+
"SELECT scope, agentId FROM agent_memory WHERE id = ?",
|
|
40
|
+
)
|
|
41
|
+
.get(memoryId);
|
|
42
|
+
if (!memory) return [];
|
|
43
|
+
if (memory.scope !== "swarm" && memory.agentId !== agentId) return [];
|
|
44
|
+
|
|
45
|
+
const rows = db
|
|
46
|
+
.prepare<{ to_id: string; alpha: number; beta: number; createdAt: string }, [string]>(
|
|
47
|
+
`SELECT to_id, alpha, beta, createdAt
|
|
48
|
+
FROM agent_memory_edge
|
|
49
|
+
WHERE from_id = ? AND type = 'references-source'
|
|
50
|
+
ORDER BY createdAt DESC`,
|
|
51
|
+
)
|
|
52
|
+
.all(memoryId);
|
|
53
|
+
|
|
54
|
+
return rows.map((row) => ({
|
|
55
|
+
to: row.to_id,
|
|
56
|
+
type: "references-source" as const,
|
|
57
|
+
alpha: row.alpha,
|
|
58
|
+
beta: row.beta,
|
|
59
|
+
usefulness: clampUsefulness(row.alpha, row.beta),
|
|
60
|
+
createdAt: row.createdAt,
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function clampUsefulness(alpha: number, beta: number): number {
|
|
65
|
+
const denom = alpha + beta;
|
|
66
|
+
if (denom <= 0) return USEFULNESS_FLOOR;
|
|
67
|
+
const mean = alpha / denom;
|
|
68
|
+
return Math.max(USEFULNESS_FLOOR, Math.min(USEFULNESS_CEILING, 2 * mean));
|
|
69
|
+
}
|
|
@@ -30,6 +30,8 @@ type AgentMemoryRow = {
|
|
|
30
30
|
expiresAt: string | null;
|
|
31
31
|
accessCount: number;
|
|
32
32
|
embeddingModel: string | null;
|
|
33
|
+
alpha: number;
|
|
34
|
+
beta: number;
|
|
33
35
|
};
|
|
34
36
|
|
|
35
37
|
function rowToAgentMemory(row: AgentMemoryRow): AgentMemory {
|
|
@@ -61,6 +63,8 @@ function rowToCandidate(row: AgentMemoryRow, similarity: number): MemoryCandidat
|
|
|
61
63
|
accessCount: row.accessCount ?? 0,
|
|
62
64
|
expiresAt: row.expiresAt ?? null,
|
|
63
65
|
embeddingModel: row.embeddingModel ?? null,
|
|
66
|
+
alpha: row.alpha ?? 1.0,
|
|
67
|
+
beta: row.beta ?? 1.0,
|
|
64
68
|
};
|
|
65
69
|
}
|
|
66
70
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { MemoryRater, RatingEvent } from "./types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Plan: thoughts/taras/plans/2026-05-05-memory-rater-v1.5/step-5.md §3
|
|
5
|
+
*
|
|
6
|
+
* Explicit-self rater — registry sentinel only. Never auto-fires from
|
|
7
|
+
* `applyRating`. Its `RatingEvent`s arrive exclusively through the worker-side
|
|
8
|
+
* `memory_rate` MCP tool, which POSTs to `/api/memory/rate` with
|
|
9
|
+
* `source: "explicit-self"`.
|
|
10
|
+
*
|
|
11
|
+
* The class exists so `MEMORY_RATERS=explicit-self` can register the name —
|
|
12
|
+
* which (per step-5.md §5) unlocks the conditional system-prompt hint that
|
|
13
|
+
* teaches the agent to call `memory_rate`. Stays out of `SERVER_RATERS` so
|
|
14
|
+
* the store-progress hook never invokes it.
|
|
15
|
+
*/
|
|
16
|
+
export class ExplicitSelfRatingRater implements MemoryRater {
|
|
17
|
+
readonly name = "explicit-self";
|
|
18
|
+
|
|
19
|
+
async rate(): Promise<RatingEvent[]> {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { MemoryRater, RatingContext, RatingEvent } from "./types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Implicit-citation rater — pure ID-grep over `evidence`.
|
|
5
|
+
*
|
|
6
|
+
* Plan: thoughts/taras/plans/2026-05-05-memory-rater-v1.5/step-2.md §4
|
|
7
|
+
*
|
|
8
|
+
* For each `memoryId` in `ctx.retrievedMemoryIds`:
|
|
9
|
+
* - if `ctx.evidence` contains the literal `memoryId` → +1 weight=0.5
|
|
10
|
+
* (positive citation; the agent referenced the memory's id somewhere
|
|
11
|
+
* in the task's `session_logs`).
|
|
12
|
+
* - else → -1 weight=0.25 (miss; we surfaced this memory but the agent
|
|
13
|
+
* did not cite it. Negative signal carries less confidence per
|
|
14
|
+
* IR convention from research §3.A and brainstorm Q4).
|
|
15
|
+
*
|
|
16
|
+
* The framework (`applyRating` in ./store.ts) sets `event.source` from the
|
|
17
|
+
* rater's `name`. This rater MUST NOT populate `source` itself — `applyRating`
|
|
18
|
+
* rejects rater-set sources to defend against rater spoofing.
|
|
19
|
+
*
|
|
20
|
+
* Match semantics: literal substring match using `String.prototype.includes`.
|
|
21
|
+
* If two memory IDs share a prefix (e.g. `mem-A` is a prefix of `mem-AB`),
|
|
22
|
+
* citing `mem-AB` will count as a hit for both. UUIDs (the production case)
|
|
23
|
+
* never collide so this is benign; the unit tests lock the behaviour in.
|
|
24
|
+
*
|
|
25
|
+
* Pure / deterministic / no DB I/O.
|
|
26
|
+
*/
|
|
27
|
+
export class ImplicitCitationRater implements MemoryRater {
|
|
28
|
+
readonly name = "implicit-citation";
|
|
29
|
+
|
|
30
|
+
async rate(ctx: RatingContext): Promise<RatingEvent[]> {
|
|
31
|
+
if (ctx.retrievedMemoryIds.length === 0) return [];
|
|
32
|
+
const evidence = ctx.evidence ?? "";
|
|
33
|
+
|
|
34
|
+
const events: RatingEvent[] = [];
|
|
35
|
+
for (const memoryId of ctx.retrievedMemoryIds) {
|
|
36
|
+
if (evidence.length > 0 && evidence.includes(memoryId)) {
|
|
37
|
+
events.push({ memoryId, signal: 1, weight: 0.5, source: "" });
|
|
38
|
+
} else {
|
|
39
|
+
events.push({ memoryId, signal: -1, weight: 0.25, source: "" });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return events;
|
|
43
|
+
}
|
|
44
|
+
}
|