@desplega.ai/agent-swarm 1.92.2 → 1.93.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.
Files changed (76) hide show
  1. package/openapi.json +63 -3
  2. package/package.json +5 -5
  3. package/src/be/db.ts +91 -6
  4. package/src/be/memory/boot-reembed.ts +0 -1
  5. package/src/be/memory/providers/sqlite-store.ts +42 -25
  6. package/src/be/memory/raters/llm-client.ts +12 -5
  7. package/src/be/memory/types.ts +3 -0
  8. package/src/be/migrations/088_script_runs_list_indexes.sql +10 -0
  9. package/src/be/migrations/089_harness_variant.sql +2 -0
  10. package/src/be/modelsdev-cache.json +1222 -986
  11. package/src/be/seed-pricing.ts +1 -0
  12. package/src/be/seed-scripts/catalog/boot-triage.inline.ts +221 -0
  13. package/src/be/seed-scripts/catalog/catalog-report.inline.ts +457 -0
  14. package/src/be/seed-scripts/catalog/compound-insights.inline.ts +863 -0
  15. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +506 -0
  16. package/src/be/seed-scripts/index.ts +5 -5
  17. package/src/be/skill-sync.ts +28 -179
  18. package/src/commands/runner.ts +124 -7
  19. package/src/http/api-keys.ts +42 -0
  20. package/src/http/mcp-bridge.ts +1 -1
  21. package/src/http/memory.ts +23 -24
  22. package/src/http/tasks.ts +10 -6
  23. package/src/providers/claude-adapter.ts +33 -1
  24. package/src/providers/claude-managed-adapter.ts +3 -0
  25. package/src/providers/claude-managed-models.ts +7 -0
  26. package/src/providers/codex-adapter.ts +8 -1
  27. package/src/providers/codex-models.ts +1 -0
  28. package/src/providers/codex-oauth/auth-json.ts +1 -0
  29. package/src/providers/harness-version.ts +7 -0
  30. package/src/providers/opencode-adapter.ts +11 -4
  31. package/src/providers/pi-mono-adapter.ts +12 -2
  32. package/src/providers/types.ts +2 -0
  33. package/src/scripts-runtime/egress-secrets.ts +83 -0
  34. package/src/scripts-runtime/eval-harness.ts +4 -0
  35. package/src/scripts-runtime/executors/types.ts +7 -0
  36. package/src/scripts-runtime/loader.ts +2 -0
  37. package/src/server-user.ts +2 -2
  38. package/src/slack/channel-join.ts +41 -0
  39. package/src/tests/additive-buffer.test.ts +0 -1
  40. package/src/tests/api-key-tracking.test.ts +113 -0
  41. package/src/tests/approval-requests.test.ts +0 -6
  42. package/src/tests/claude-managed-setup.test.ts +0 -4
  43. package/src/tests/codex-pool.test.ts +2 -6
  44. package/src/tests/http-api-integration.test.ts +4 -6
  45. package/src/tests/memory-edges.test.ts +0 -2
  46. package/src/tests/memory-rate-endpoint.test.ts +0 -2
  47. package/src/tests/memory-rater-e2e.test.ts +0 -2
  48. package/src/tests/memory-store.test.ts +19 -1
  49. package/src/tests/memory.test.ts +51 -0
  50. package/src/tests/model-control.test.ts +1 -1
  51. package/src/tests/reload-config.test.ts +33 -17
  52. package/src/tests/runner-skills-refresh.test.ts +216 -46
  53. package/src/tests/script-runs-http.test.ts +7 -1
  54. package/src/tests/scripts-runtime-secret-egress.test.ts +129 -0
  55. package/src/tests/seed-scripts.test.ts +13 -1
  56. package/src/tests/session-attach.test.ts +6 -6
  57. package/src/tests/skill-fs-writer.test.ts +250 -0
  58. package/src/tests/slack-attachments-block.test.ts +0 -1
  59. package/src/tests/slack-blocks.test.ts +0 -1
  60. package/src/tests/slack-channel-join.test.ts +80 -0
  61. package/src/tests/slack-identity-resolution.test.ts +0 -1
  62. package/src/tests/structured-output.test.ts +0 -2
  63. package/src/tests/use-dismissible-card.test.ts +0 -4
  64. package/src/tools/schedules/create-schedule.ts +2 -2
  65. package/src/tools/schedules/update-schedule.ts +1 -1
  66. package/src/tools/send-task.ts +2 -2
  67. package/src/tools/slack-post.ts +18 -15
  68. package/src/tools/slack-read.ts +9 -11
  69. package/src/tools/slack-reply.ts +18 -15
  70. package/src/tools/slack-start-thread.ts +17 -14
  71. package/src/tools/task-action.ts +2 -2
  72. package/src/types.ts +11 -0
  73. package/src/utils/context-window.ts +3 -0
  74. package/src/utils/credentials.ts +22 -2
  75. package/src/utils/skill-fs-writer.ts +220 -0
  76. package/src/utils/skills-refresh.ts +123 -40
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.92.2",
5
+ "version": "1.93.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": [
@@ -2740,6 +2740,59 @@
2740
2740
  }
2741
2741
  }
2742
2742
  },
2743
+ "/api/keys/clear-rate-limit": {
2744
+ "post": {
2745
+ "summary": "Clear rate-limited status for a key after a successful use proves it is healthy",
2746
+ "tags": [
2747
+ "API Keys"
2748
+ ],
2749
+ "security": [
2750
+ {
2751
+ "bearerAuth": []
2752
+ }
2753
+ ],
2754
+ "requestBody": {
2755
+ "content": {
2756
+ "application/json": {
2757
+ "schema": {
2758
+ "type": "object",
2759
+ "properties": {
2760
+ "keyType": {
2761
+ "type": "string"
2762
+ },
2763
+ "keySuffix": {
2764
+ "type": "string",
2765
+ "minLength": 1,
2766
+ "maxLength": 10
2767
+ },
2768
+ "scope": {
2769
+ "type": "string"
2770
+ },
2771
+ "scopeId": {
2772
+ "type": "string"
2773
+ }
2774
+ },
2775
+ "required": [
2776
+ "keyType",
2777
+ "keySuffix"
2778
+ ]
2779
+ }
2780
+ }
2781
+ }
2782
+ },
2783
+ "responses": {
2784
+ "200": {
2785
+ "description": "Rate limit cleared (or key was not rate-limited)"
2786
+ },
2787
+ "400": {
2788
+ "description": "Validation error"
2789
+ },
2790
+ "401": {
2791
+ "description": "Unauthorized"
2792
+ }
2793
+ }
2794
+ }
2795
+ },
2743
2796
  "/api/events": {
2744
2797
  "post": {
2745
2798
  "summary": "Store a single event",
@@ -10711,9 +10764,9 @@
10711
10764
  }
10712
10765
  }
10713
10766
  },
10714
- "/api/tasks/{id}/claude-session": {
10767
+ "/api/tasks/{id}/session": {
10715
10768
  "put": {
10716
- "summary": "Update Claude session ID for a task",
10769
+ "summary": "Update provider session ID and harness metadata for a task",
10717
10770
  "tags": [
10718
10771
  "Tasks"
10719
10772
  ],
@@ -10800,6 +10853,13 @@
10800
10853
  "providerMeta": {
10801
10854
  "type": "object",
10802
10855
  "properties": {}
10856
+ },
10857
+ "harnessVariant": {
10858
+ "type": "string"
10859
+ },
10860
+ "harnessVariantMeta": {
10861
+ "type": "object",
10862
+ "additionalProperties": {}
10803
10863
  }
10804
10864
  },
10805
10865
  "required": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@desplega.ai/agent-swarm",
3
- "version": "1.92.2",
3
+ "version": "1.93.0",
4
4
  "description": "Multi-agent orchestration for Claude Code, Codex, Gemini CLI, and other AI coding assistants",
5
5
  "license": "MIT",
6
6
  "author": "desplega.sh <contact@desplega.sh>",
@@ -112,11 +112,11 @@
112
112
  "@desplega.ai/localtunnel": "^2.2.0",
113
113
  "@inkjs/ui": "^2.0.0",
114
114
  "@linear/sdk": "^77.0.0",
115
- "@earendil-works/pi-agent-core": "^0.78.1",
116
- "@earendil-works/pi-ai": "^0.78.1",
117
- "@earendil-works/pi-coding-agent": "^0.78.1",
115
+ "@earendil-works/pi-agent-core": "^0.79.1",
116
+ "@earendil-works/pi-ai": "^0.79.1",
117
+ "@earendil-works/pi-coding-agent": "^0.79.1",
118
118
  "@modelcontextprotocol/sdk": "^1.25.1",
119
- "@openai/codex-sdk": "^0.137.0",
119
+ "@openai/codex-sdk": "^0.139.0",
120
120
  "@opencode-ai/sdk": "^1.16.2",
121
121
  "@openfort/openfort-node": "^0.9.1",
122
122
  "@opentelemetry/api": "^1.9.1",
package/src/be/db.ts CHANGED
@@ -65,6 +65,7 @@ import type {
65
65
  ScriptRun,
66
66
  ScriptRunJournalEntry,
67
67
  ScriptRunKind,
68
+ ScriptRunListItem,
68
69
  ScriptRunStatus,
69
70
  Service,
70
71
  ServiceStatus,
@@ -1041,6 +1042,8 @@ type AgentTaskRow = {
1041
1042
  swarmVersion: string | null;
1042
1043
  provider: string | null;
1043
1044
  providerMeta: string | null;
1045
+ harnessVariant: string | null;
1046
+ harnessVariantMeta: string | null;
1044
1047
  totalCostUsd?: number | null;
1045
1048
  };
1046
1049
 
@@ -1102,7 +1105,7 @@ function rowToAgentTask(row: AgentTaskRow): AgentTask {
1102
1105
  dir: row.dir ?? undefined,
1103
1106
  parentTaskId: row.parentTaskId ?? undefined,
1104
1107
  claudeSessionId: row.claudeSessionId ?? undefined,
1105
- model: (row.model as "haiku" | "sonnet" | "opus" | null) ?? undefined,
1108
+ model: (row.model as "haiku" | "sonnet" | "opus" | "fable" | null) ?? undefined,
1106
1109
  scheduleId: row.scheduleId ?? undefined,
1107
1110
  workflowRunId: row.workflowRunId ?? undefined,
1108
1111
  workflowRunStepId: row.workflowRunStepId ?? undefined,
@@ -1127,6 +1130,8 @@ function rowToAgentTask(row: AgentTaskRow): AgentTask {
1127
1130
  swarmVersion: row.swarmVersion ?? undefined,
1128
1131
  provider: (row.provider as ProviderName | null) ?? undefined,
1129
1132
  providerMeta: parseProviderMeta(row.provider as ProviderName | null, row.providerMeta),
1133
+ harnessVariant: row.harnessVariant ?? undefined,
1134
+ harnessVariantMeta: row.harnessVariantMeta ? JSON.parse(row.harnessVariantMeta) : undefined,
1130
1135
  totalCostUsd: row.totalCostUsd ?? undefined,
1131
1136
  };
1132
1137
  }
@@ -1398,6 +1403,8 @@ export function updateTaskClaudeSessionId(
1398
1403
  provider?: ProviderName,
1399
1404
  providerMeta?: Record<string, unknown>,
1400
1405
  model?: string,
1406
+ harnessVariant?: string,
1407
+ harnessVariantMeta?: Record<string, unknown>,
1401
1408
  ): AgentTask | null {
1402
1409
  const setClauses = ["claudeSessionId = ?", "lastUpdatedAt = ?"];
1403
1410
  const params: (string | null)[] = [claudeSessionId, new Date().toISOString()];
@@ -1414,6 +1421,14 @@ export function updateTaskClaudeSessionId(
1414
1421
  setClauses.push("model = ?");
1415
1422
  params.push(model);
1416
1423
  }
1424
+ if (harnessVariant !== undefined) {
1425
+ setClauses.push("harnessVariant = ?");
1426
+ params.push(harnessVariant);
1427
+ }
1428
+ if (harnessVariantMeta !== undefined) {
1429
+ setClauses.push("harnessVariantMeta = ?");
1430
+ params.push(JSON.stringify(harnessVariantMeta));
1431
+ }
1417
1432
 
1418
1433
  params.push(taskId);
1419
1434
 
@@ -5291,7 +5306,7 @@ function rowToScheduledTask(row: ScheduledTaskRow): ScheduledTask {
5291
5306
  consecutiveErrors: row.consecutiveErrors ?? 0,
5292
5307
  lastErrorAt: normalizeDate(row.lastErrorAt) ?? undefined,
5293
5308
  lastErrorMessage: row.lastErrorMessage ?? undefined,
5294
- model: (row.model as "haiku" | "sonnet" | "opus" | null) ?? undefined,
5309
+ model: (row.model as "haiku" | "sonnet" | "opus" | "fable" | null) ?? undefined,
5295
5310
  scheduleType: row.scheduleType as "recurring" | "one_time",
5296
5311
  createdAt: normalizeDateRequired(row.createdAt),
5297
5312
  lastUpdatedAt: normalizeDateRequired(row.lastUpdatedAt),
@@ -10058,6 +10073,28 @@ export function setApiKeyName(
10058
10073
  return result.changes > 0;
10059
10074
  }
10060
10075
 
10076
+ /**
10077
+ * Clear a stale rate-limit record after a successful use proves the key is healthy.
10078
+ */
10079
+ export function clearKeyRateLimit(
10080
+ keyType: string,
10081
+ keySuffix: string,
10082
+ scope = "global",
10083
+ scopeId: string | null = null,
10084
+ ): boolean {
10085
+ const now = new Date().toISOString();
10086
+ const effectiveScopeId = scopeId ?? "";
10087
+ const result = getDb()
10088
+ .prepare(
10089
+ `UPDATE api_key_status
10090
+ SET status = 'available', rateLimitedUntil = NULL, updatedAt = ?
10091
+ WHERE keyType = ? AND keySuffix = ? AND scope = ? AND scopeId = ?
10092
+ AND status = 'rate_limited'`,
10093
+ )
10094
+ .run(now, keyType, keySuffix, scope, effectiveScopeId);
10095
+ return result.changes > 0;
10096
+ }
10097
+
10061
10098
  /**
10062
10099
  * Get all key status records for a credential type.
10063
10100
  */
@@ -11574,6 +11611,22 @@ type ScriptRunRow = {
11574
11611
  updated_by: string | null;
11575
11612
  };
11576
11613
 
11614
+ type ScriptRunListRow = Pick<
11615
+ ScriptRunRow,
11616
+ | "id"
11617
+ | "agentId"
11618
+ | "scriptName"
11619
+ | "kind"
11620
+ | "status"
11621
+ | "pid"
11622
+ | "startedAt"
11623
+ | "finishedAt"
11624
+ | "error"
11625
+ | "last_heartbeat_at"
11626
+ | "idempotencyKey"
11627
+ | "requestedByUserId"
11628
+ >;
11629
+
11577
11630
  function parseJsonColumn(value: string | null): unknown | undefined {
11578
11631
  if (value === null) return undefined;
11579
11632
  return JSON.parse(value);
@@ -11599,6 +11652,23 @@ function rowToScriptRun(row: ScriptRunRow): ScriptRun {
11599
11652
  };
11600
11653
  }
11601
11654
 
11655
+ function rowToScriptRunListItem(row: ScriptRunListRow): ScriptRunListItem {
11656
+ return {
11657
+ id: row.id,
11658
+ agentId: row.agentId,
11659
+ scriptName: row.scriptName ?? undefined,
11660
+ kind: row.kind as ScriptRunKind,
11661
+ status: row.status as ScriptRunStatus,
11662
+ pid: row.pid ?? undefined,
11663
+ startedAt: row.startedAt,
11664
+ finishedAt: row.finishedAt ?? undefined,
11665
+ error: row.error ?? undefined,
11666
+ lastHeartbeatAt: row.last_heartbeat_at ?? undefined,
11667
+ idempotencyKey: row.idempotencyKey ?? undefined,
11668
+ requestedByUserId: row.requestedByUserId ?? undefined,
11669
+ };
11670
+ }
11671
+
11602
11672
  export function createScriptRun(data: {
11603
11673
  id: string;
11604
11674
  agentId: string;
@@ -11733,7 +11803,7 @@ export function listScriptRuns(opts?: {
11733
11803
  agentId?: string;
11734
11804
  limit?: number;
11735
11805
  offset?: number;
11736
- }): ScriptRun[] {
11806
+ }): ScriptRunListItem[] {
11737
11807
  const conditions: string[] = [];
11738
11808
  const params: Array<string | number> = [];
11739
11809
  if (opts?.status) {
@@ -11750,11 +11820,26 @@ export function listScriptRuns(opts?: {
11750
11820
  params.push(limit, offset);
11751
11821
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
11752
11822
  const rows = getDb()
11753
- .prepare<ScriptRunRow, Array<string | number>>(
11754
- `SELECT * FROM script_runs ${where} ORDER BY startedAt DESC LIMIT ? OFFSET ?`,
11823
+ .prepare<ScriptRunListRow, Array<string | number>>(
11824
+ `SELECT
11825
+ id,
11826
+ agentId,
11827
+ scriptName,
11828
+ kind,
11829
+ status,
11830
+ pid,
11831
+ startedAt,
11832
+ finishedAt,
11833
+ error,
11834
+ last_heartbeat_at,
11835
+ idempotencyKey,
11836
+ requestedByUserId
11837
+ FROM script_runs ${where}
11838
+ ORDER BY startedAt DESC
11839
+ LIMIT ? OFFSET ?`,
11755
11840
  )
11756
11841
  .all(...params);
11757
- return rows.map(rowToScriptRun);
11842
+ return rows.map(rowToScriptRunListItem);
11758
11843
  }
11759
11844
 
11760
11845
  export function countScriptRuns(opts?: { status?: ScriptRunStatus; agentId?: string }): number {
@@ -13,7 +13,6 @@ import { getEmbeddingProvider, getMemoryStore } from "./index";
13
13
 
14
14
  const VECTOR_BYTES = EMBEDDING_DIMENSIONS * Float32Array.BYTES_PER_ELEMENT;
15
15
  const BATCH_SIZE = 20;
16
- const BACKFILL_KV_KEY = "memory:reembed:backfill_complete";
17
16
 
18
17
  export async function runBootReembed(): Promise<void> {
19
18
  const db = getDb();
@@ -488,29 +488,19 @@ export class SqliteMemoryStore implements MemoryStore {
488
488
  }
489
489
  }
490
490
 
491
- list(agentId: string, options: MemoryListOptions = {}): AgentMemory[] {
492
- const { scope = "all", limit = 20, offset = 0, isLead = false, source } = options;
493
- const db = getDb();
494
-
491
+ private buildListWhereClause(
492
+ agentId: string,
493
+ options: MemoryListOptions,
494
+ ): { whereClause: string; params: (Buffer | string | number | null)[] } {
495
+ const { scope = "all", isLead = false, ownerAgentId, source, sourcePath } = options;
495
496
  const conditions: string[] = [];
496
- const params: (string | number)[] = [];
497
+ const params: (Buffer | string | number | null)[] = [];
497
498
 
498
- if (!isLead) {
499
- if (scope === "agent") {
500
- conditions.push("agentId = ? AND scope = 'agent'");
501
- params.push(agentId);
502
- } else if (scope === "swarm") {
503
- conditions.push("scope = 'swarm'");
504
- } else {
505
- conditions.push("(agentId = ? OR scope = 'swarm')");
506
- params.push(agentId);
507
- }
508
- } else {
509
- if (scope === "agent") {
510
- conditions.push("scope = 'agent'");
511
- } else if (scope === "swarm") {
512
- conditions.push("scope = 'swarm'");
513
- }
499
+ this.addScopeConditions(conditions, params, agentId, scope, isLead);
500
+
501
+ if (ownerAgentId) {
502
+ conditions.push("agentId = ?");
503
+ params.push(ownerAgentId);
514
504
  }
515
505
 
516
506
  if (source) {
@@ -518,18 +508,45 @@ export class SqliteMemoryStore implements MemoryStore {
518
508
  params.push(source);
519
509
  }
520
510
 
521
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
522
- params.push(limit, offset);
511
+ const sourcePathNeedle = sourcePath?.trim().toLowerCase();
512
+ if (sourcePathNeedle) {
513
+ conditions.push("instr(lower(coalesce(sourcePath, '')), ?) > 0");
514
+ params.push(sourcePathNeedle);
515
+ }
516
+
517
+ return {
518
+ whereClause: conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "",
519
+ params,
520
+ };
521
+ }
522
+
523
+ list(agentId: string, options: MemoryListOptions = {}): AgentMemory[] {
524
+ const { limit = 20, offset = 0 } = options;
525
+ const db = getDb();
526
+ const { whereClause, params } = this.buildListWhereClause(agentId, options);
527
+ const queryParams = [...params, limit, offset];
523
528
 
524
529
  const rows = db
525
- .prepare<AgentMemoryRow, (string | number)[]>(
530
+ .prepare<AgentMemoryRow, (Buffer | string | number | null)[]>(
526
531
  `SELECT * FROM agent_memory ${whereClause} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
527
532
  )
528
- .all(...params);
533
+ .all(...queryParams);
529
534
 
530
535
  return rows.map(rowToAgentMemory);
531
536
  }
532
537
 
538
+ count(agentId: string, options: MemoryListOptions = {}): number {
539
+ const db = getDb();
540
+ const { whereClause, params } = this.buildListWhereClause(agentId, options);
541
+ const row = db
542
+ .prepare<{ count: number }, (Buffer | string | number | null)[]>(
543
+ `SELECT COUNT(*) AS count FROM agent_memory ${whereClause}`,
544
+ )
545
+ .get(...params);
546
+
547
+ return row?.count ?? 0;
548
+ }
549
+
533
550
  isSourceProtected(source: AgentMemorySource): boolean {
534
551
  return PROTECTED_SOURCES.has(source);
535
552
  }
@@ -75,6 +75,13 @@ AGENT RESPONSE / SUMMARY:
75
75
 
76
76
  Score 0..1.`;
77
77
 
78
+ const PLACEHOLDER_PREFIX = "$";
79
+ const QUERY_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{query}`;
80
+ const MEMORY_ID_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{memoryId}`;
81
+ const MEMORY_NAME_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{memoryName}`;
82
+ const MEMORY_CONTENT_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{memoryContent}`;
83
+ const RESPONSE_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{response}`;
84
+
78
85
  /**
79
86
  * `claude -p --output-format json` returns a JSON envelope of the shape
80
87
  * `{ result: string, ... }`. We parse the envelope, then JSON-parse the
@@ -83,11 +90,11 @@ Score 0..1.`;
83
90
  type ClaudeCliEnvelope = { result?: unknown };
84
91
 
85
92
  function buildPrompt(input: LlmRaterInput): string {
86
- return PROMPT_TEMPLATE.replace("${query}", input.query)
87
- .replace("${memoryId}", input.memory.id)
88
- .replace("${memoryName}", input.memory.name)
89
- .replace("${memoryContent}", input.memory.content)
90
- .replace("${response}", input.response);
93
+ return PROMPT_TEMPLATE.replace(QUERY_PLACEHOLDER, input.query)
94
+ .replace(MEMORY_ID_PLACEHOLDER, input.memory.id)
95
+ .replace(MEMORY_NAME_PLACEHOLDER, input.memory.name)
96
+ .replace(MEMORY_CONTENT_PLACEHOLDER, input.memory.content)
97
+ .replace(RESPONSE_PLACEHOLDER, input.response);
91
98
  }
92
99
 
93
100
  function parseScoreAndReasoning(raw: unknown): LlmRaterResult | null {
@@ -22,6 +22,7 @@ export interface MemoryStore {
22
22
  peek(id: string): AgentMemory | null;
23
23
  search(embedding: Float32Array, agentId: string, options: MemorySearchOptions): MemoryCandidate[];
24
24
  list(agentId: string, options: MemoryListOptions): AgentMemory[];
25
+ count(agentId: string, options: MemoryListOptions): number;
25
26
  isSourceProtected(source: AgentMemorySource): boolean;
26
27
  listForCuration(
27
28
  agentId?: string,
@@ -80,7 +81,9 @@ export interface MemoryListOptions {
80
81
  limit?: number;
81
82
  offset?: number;
82
83
  isLead?: boolean;
84
+ ownerAgentId?: string;
83
85
  source?: AgentMemorySource;
86
+ sourcePath?: string;
84
87
  }
85
88
 
86
89
  export interface MemoryStats {
@@ -0,0 +1,10 @@
1
+ -- Keep script run list pages fast as historical rows accumulate.
2
+
3
+ CREATE INDEX IF NOT EXISTS idx_script_runs_startedAt
4
+ ON script_runs(startedAt DESC);
5
+
6
+ CREATE INDEX IF NOT EXISTS idx_script_runs_status_startedAt
7
+ ON script_runs(status, startedAt DESC);
8
+
9
+ CREATE INDEX IF NOT EXISTS idx_script_runs_agentId_startedAt
10
+ ON script_runs(agentId, startedAt DESC);
@@ -0,0 +1,2 @@
1
+ ALTER TABLE agent_tasks ADD COLUMN harnessVariant TEXT;
2
+ ALTER TABLE agent_tasks ADD COLUMN harnessVariantMeta TEXT;