@revealui/ai 0.3.0 → 0.4.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/README.md +200 -26
- package/dist/a2a/handler.d.ts +3 -1
- package/dist/a2a/handler.d.ts.map +1 -1
- package/dist/a2a/handler.js +24 -7
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/a2a/task-store.js +5 -1
- package/dist/client/hooks/useAgentStream.d.ts +84 -1
- package/dist/client/hooks/useAgentStream.d.ts.map +1 -1
- package/dist/client/hooks/useAgentStream.js +106 -10
- package/dist/index.d.ts +4 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -15
- package/dist/llm/client.d.ts +33 -4
- package/dist/llm/client.d.ts.map +1 -1
- package/dist/llm/client.js +70 -21
- package/dist/llm/key-validator.d.ts.map +1 -1
- package/dist/llm/key-validator.js +0 -27
- package/dist/llm/providers/inference-snaps.d.ts +7 -5
- package/dist/llm/providers/inference-snaps.d.ts.map +1 -1
- package/dist/llm/providers/inference-snaps.js +7 -5
- package/dist/llm/providers/openai-compat.d.ts +1 -1
- package/dist/llm/providers/openai-compat.js +1 -1
- package/dist/llm/response-cache.d.ts +1 -2
- package/dist/llm/response-cache.d.ts.map +1 -1
- package/dist/llm/response-cache.js +1 -2
- package/dist/llm/server.d.ts +1 -1
- package/dist/llm/server.d.ts.map +1 -1
- package/dist/llm/server.js +3 -1
- package/dist/memory/services/index.d.ts +2 -0
- package/dist/memory/services/index.d.ts.map +1 -1
- package/dist/memory/services/index.js +1 -0
- package/dist/memory/services/reconciliation-service.d.ts +64 -0
- package/dist/memory/services/reconciliation-service.d.ts.map +1 -0
- package/dist/memory/services/reconciliation-service.js +127 -0
- package/dist/memory/utils/sql-helpers.d.ts +19 -25
- package/dist/memory/utils/sql-helpers.d.ts.map +1 -1
- package/dist/memory/utils/sql-helpers.js +34 -81
- package/dist/memory/vector/vector-memory-service.d.ts.map +1 -1
- package/dist/memory/vector/vector-memory-service.js +6 -1
- package/dist/orchestration/runtime.d.ts +30 -1
- package/dist/orchestration/runtime.d.ts.map +1 -1
- package/dist/orchestration/runtime.js +20 -3
- package/dist/orchestration/streaming-runtime.d.ts +48 -1
- package/dist/orchestration/streaming-runtime.d.ts.map +1 -1
- package/dist/orchestration/ticket-agent.d.ts +10 -1
- package/dist/orchestration/ticket-agent.d.ts.map +1 -1
- package/dist/orchestration/ticket-agent.js +11 -2
- package/dist/tools/mcp-adapter.d.ts +192 -1
- package/dist/tools/mcp-adapter.d.ts.map +1 -1
- package/dist/tools/mcp-adapter.js +434 -1
- package/dist/tools/mcp-elicitation.d.ts +128 -0
- package/dist/tools/mcp-elicitation.d.ts.map +1 -0
- package/dist/tools/mcp-elicitation.js +121 -0
- package/dist/tools/mcp-events.d.ts +270 -0
- package/dist/tools/mcp-events.d.ts.map +1 -0
- package/dist/tools/mcp-events.js +165 -0
- package/dist/tools/mcp-sampling.d.ts +155 -0
- package/dist/tools/mcp-sampling.d.ts.map +1 -0
- package/dist/tools/mcp-sampling.js +171 -0
- package/dist/tools/ticket-tools.d.ts +35 -2
- package/dist/tools/ticket-tools.d.ts.map +1 -1
- package/dist/tools/ticket-tools.js +32 -2
- package/package.json +13 -11
- package/dist/llm/providers/vultr.d.ts +0 -18
- package/dist/llm/providers/vultr.d.ts.map +0 -1
- package/dist/llm/providers/vultr.js +0 -169
- package/dist/memory/utils/deep-clone.d.ts +0 -10
- package/dist/memory/utils/deep-clone.d.ts.map +0 -1
- package/dist/memory/utils/deep-clone.js +0 -9
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reconciliation Service - Fact resolution for multi-agent memory.
|
|
3
|
+
*
|
|
4
|
+
* Reads shared facts from a coordination session, groups related facts,
|
|
5
|
+
* deduplicates, and resolves contradictions. Produces reconciled memories
|
|
6
|
+
* for Layer 3.
|
|
7
|
+
*
|
|
8
|
+
* Layer 3 of the multi-agent shared memory architecture.
|
|
9
|
+
*
|
|
10
|
+
* LICENSING BOUNDARY:
|
|
11
|
+
* - `reconcileHeuristic()` is the production path — no external API calls,
|
|
12
|
+
* safe for all tiers including free customers.
|
|
13
|
+
* - `buildReconciliationPrompt()` and `parseReconciliationResponse()` are
|
|
14
|
+
* reference implementations for internal/developer use only. They build
|
|
15
|
+
* a prompt string but DO NOT call any LLM API. If wired to an LLM provider,
|
|
16
|
+
* the caller is responsible for API pricing and usage compliance.
|
|
17
|
+
* - Customer-facing reconciliation MUST use the heuristic path or a
|
|
18
|
+
* self-hosted model (e.g. Ollama). Do not proxy third-party LLM APIs
|
|
19
|
+
* to end users without a commercial API agreement with the provider.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Build the reconciliation prompt for an LLM.
|
|
23
|
+
* The prompt asks the model to analyze facts from multiple agents and
|
|
24
|
+
* produce a structured reconciliation result.
|
|
25
|
+
*/
|
|
26
|
+
export function buildReconciliationPrompt(facts, scratchpadContent) {
|
|
27
|
+
const factList = facts
|
|
28
|
+
.map((f, i) => `${i + 1}. [${f.factType}] (agent: ${f.agentId}, confidence: ${f.confidence}) ${f.content}` +
|
|
29
|
+
(f.tags.length > 0 ? ` [tags: ${f.tags.join(', ')}]` : ''))
|
|
30
|
+
.join('\n');
|
|
31
|
+
const scratchpadSection = scratchpadContent
|
|
32
|
+
? `\n\nShared scratchpad content:\n${JSON.stringify(scratchpadContent, null, 2)}`
|
|
33
|
+
: '';
|
|
34
|
+
return `You are reconciling discoveries from multiple AI agents working on the same task.
|
|
35
|
+
|
|
36
|
+
Facts discovered by agents:
|
|
37
|
+
${factList}
|
|
38
|
+
${scratchpadSection}
|
|
39
|
+
|
|
40
|
+
Analyze these facts and produce a JSON response with:
|
|
41
|
+
1. "canonicalFacts": Array of canonical truths. For each:
|
|
42
|
+
- "content": The canonical fact statement
|
|
43
|
+
- "type": One of: fact, preference, decision, warning, skill
|
|
44
|
+
- "sourceFactIds": Array of source fact indices (1-based) that support this
|
|
45
|
+
- "confidence": 0-1 confidence score
|
|
46
|
+
2. "contradictions": Array of contradictions found. For each:
|
|
47
|
+
- "factIndices": The conflicting fact indices
|
|
48
|
+
- "description": What contradicts
|
|
49
|
+
- "resolution": How to resolve (which is correct and why)
|
|
50
|
+
3. "duplicates": Array of arrays of fact indices that say the same thing
|
|
51
|
+
4. "summary": One-sentence summary of the reconciliation
|
|
52
|
+
|
|
53
|
+
Rules:
|
|
54
|
+
- Merge duplicate facts into one canonical fact
|
|
55
|
+
- When facts contradict, determine which is correct based on confidence and specificity
|
|
56
|
+
- Preserve the most specific and actionable version of each fact
|
|
57
|
+
- Do not invent facts not supported by the inputs
|
|
58
|
+
|
|
59
|
+
Respond with ONLY valid JSON, no markdown fencing.`;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse the LLM response into a structured reconciliation result.
|
|
63
|
+
* Maps 1-based fact indices back to actual fact IDs.
|
|
64
|
+
*/
|
|
65
|
+
export function parseReconciliationResponse(response, facts) {
|
|
66
|
+
const parsed = JSON.parse(response);
|
|
67
|
+
const mapIndices = (indices) => indices
|
|
68
|
+
.filter((i) => i >= 1 && i <= facts.length)
|
|
69
|
+
.map((i) => facts[i - 1]?.id)
|
|
70
|
+
.filter((id) => id !== undefined);
|
|
71
|
+
return {
|
|
72
|
+
canonicalFacts: (parsed.canonicalFacts ?? []).map((cf) => ({
|
|
73
|
+
content: cf.content,
|
|
74
|
+
type: cf.type,
|
|
75
|
+
sourceFactIds: mapIndices(cf.sourceFactIds ?? []),
|
|
76
|
+
confidence: cf.confidence ?? 1.0,
|
|
77
|
+
})),
|
|
78
|
+
contradictions: (parsed.contradictions ?? []).map((c) => ({
|
|
79
|
+
factIds: mapIndices(c.factIndices ?? []),
|
|
80
|
+
description: c.description ?? '',
|
|
81
|
+
resolution: c.resolution ?? '',
|
|
82
|
+
})),
|
|
83
|
+
duplicates: (parsed.duplicates ?? []).map((group) => mapIndices(group)),
|
|
84
|
+
summary: parsed.summary ?? 'Reconciliation complete.',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Simple heuristic reconciliation (no LLM required).
|
|
89
|
+
* Deduplicates by normalized content and groups by type.
|
|
90
|
+
* Use this as a fallback when no LLM provider is configured.
|
|
91
|
+
*/
|
|
92
|
+
export function reconcileHeuristic(facts) {
|
|
93
|
+
const seen = new Map();
|
|
94
|
+
const canonicalFacts = [];
|
|
95
|
+
const duplicates = [];
|
|
96
|
+
for (const fact of facts) {
|
|
97
|
+
const normalized = fact.content.toLowerCase().trim();
|
|
98
|
+
const existing = seen.get(normalized);
|
|
99
|
+
if (existing) {
|
|
100
|
+
existing.push(fact.id);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
seen.set(normalized, [fact.id]);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
for (const [, ids] of seen) {
|
|
107
|
+
if (ids.length > 1) {
|
|
108
|
+
duplicates.push(ids);
|
|
109
|
+
}
|
|
110
|
+
const sourceFact = facts.find((f) => f.id === ids[0]);
|
|
111
|
+
if (sourceFact) {
|
|
112
|
+
const memoryType = sourceFact.factType === 'bug' || sourceFact.factType === 'warning' ? 'warning' : 'fact';
|
|
113
|
+
canonicalFacts.push({
|
|
114
|
+
content: sourceFact.content,
|
|
115
|
+
type: memoryType,
|
|
116
|
+
sourceFactIds: ids,
|
|
117
|
+
confidence: sourceFact.confidence,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
canonicalFacts,
|
|
123
|
+
contradictions: [],
|
|
124
|
+
duplicates,
|
|
125
|
+
summary: `Reconciled ${facts.length} facts into ${canonicalFacts.length} canonical facts (${duplicates.length} duplicates).`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Memory-layer query helpers
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Small, typed helpers for lookups performed by the agent-memory persistence
|
|
5
|
+
* layer. Every helper returns a Drizzle-inferred row shape — no manual
|
|
6
|
+
* snake_case → camelCase transformation needed.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
8
|
+
* History: originally written with `db.execute(sql`…`)` + hand-rolled result
|
|
9
|
+
* unwrapping as a defensive posture against an early Neon HTTP driver
|
|
10
|
+
* incompatibility with Drizzle's relational query builder (`db.query.*`).
|
|
11
|
+
* Ported to the core query builder (`db.select().from(…).where(…).limit(1)`)
|
|
12
|
+
* in Phase 6.1 — the same callers already use `.update()` and `.insert()`
|
|
13
|
+
* against the same tables on the same Database client without issue, and the
|
|
14
|
+
* core builder is a different code path from the relational one.
|
|
9
15
|
*/
|
|
10
16
|
import type { NodeIdMappingsRow } from '@revealui/contracts/generated';
|
|
11
17
|
import type { Database } from '@revealui/db/client';
|
|
18
|
+
import type { AgentContext, User } from '@revealui/db/schema';
|
|
12
19
|
/**
|
|
13
20
|
* Finds a node ID mapping by hash (primary key).
|
|
14
21
|
*
|
|
@@ -18,7 +25,7 @@ import type { Database } from '@revealui/db/client';
|
|
|
18
25
|
*/
|
|
19
26
|
export declare function findNodeIdMappingByHash(db: Database, hash: string): Promise<NodeIdMappingsRow | undefined>;
|
|
20
27
|
/**
|
|
21
|
-
* Finds a node ID mapping by entity
|
|
28
|
+
* Finds a node ID mapping by entity type + entity ID.
|
|
22
29
|
*
|
|
23
30
|
* @param db - Database client
|
|
24
31
|
* @param entityType - Type of entity ('session' or 'user')
|
|
@@ -27,32 +34,19 @@ export declare function findNodeIdMappingByHash(db: Database, hash: string): Pro
|
|
|
27
34
|
*/
|
|
28
35
|
export declare function findNodeIdMappingByEntity(db: Database, entityType: 'session' | 'user', entityId: string): Promise<NodeIdMappingsRow | undefined>;
|
|
29
36
|
/**
|
|
30
|
-
* Finds an agent context by CRDT ID
|
|
37
|
+
* Finds an agent context by CRDT ID.
|
|
31
38
|
*
|
|
32
39
|
* @param db - Database client
|
|
33
40
|
* @param crdtId - CRDT identifier (format: sessionId:agentId)
|
|
34
|
-
* @returns
|
|
41
|
+
* @returns Agent context row or undefined if not found
|
|
35
42
|
*/
|
|
36
|
-
export declare function findAgentContextById(db: Database, crdtId: string): Promise<
|
|
37
|
-
id: string;
|
|
38
|
-
version: number;
|
|
39
|
-
sessionId: string;
|
|
40
|
-
agentId: string;
|
|
41
|
-
context: unknown;
|
|
42
|
-
priority: number | null;
|
|
43
|
-
embedding: number[] | null;
|
|
44
|
-
createdAt: Date;
|
|
45
|
-
updatedAt: Date;
|
|
46
|
-
} | undefined>;
|
|
43
|
+
export declare function findAgentContextById(db: Database, crdtId: string): Promise<AgentContext | undefined>;
|
|
47
44
|
/**
|
|
48
|
-
* Finds a user by ID.
|
|
45
|
+
* Finds a user by ID, returning only the columns the memory layer needs.
|
|
49
46
|
*
|
|
50
47
|
* @param db - Database client
|
|
51
48
|
* @param userId - User identifier
|
|
52
|
-
* @returns User record or undefined if not found
|
|
49
|
+
* @returns User record (id + preferences) or undefined if not found
|
|
53
50
|
*/
|
|
54
|
-
export declare function findUserById(db: Database, userId: string): Promise<
|
|
55
|
-
id: string;
|
|
56
|
-
preferences: unknown;
|
|
57
|
-
} | undefined>;
|
|
51
|
+
export declare function findUserById(db: Database, userId: string): Promise<Pick<User, 'id' | 'preferences'> | undefined>;
|
|
58
52
|
//# sourceMappingURL=sql-helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql-helpers.d.ts","sourceRoot":"","sources":["../../../src/memory/utils/sql-helpers.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"sql-helpers.d.ts","sourceRoot":"","sources":["../../../src/memory/utils/sql-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAQ9D;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAGxC;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,QAAQ,EACZ,UAAU,EAAE,SAAS,GAAG,MAAM,EAC9B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAOxC;AAMD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAGnC;AAMD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,aAAa,CAAC,GAAG,SAAS,CAAC,CAOvD"}
|
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Memory-layer query helpers
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Small, typed helpers for lookups performed by the agent-memory persistence
|
|
5
|
+
* layer. Every helper returns a Drizzle-inferred row shape — no manual
|
|
6
|
+
* snake_case → camelCase transformation needed.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
8
|
+
* History: originally written with `db.execute(sql`…`)` + hand-rolled result
|
|
9
|
+
* unwrapping as a defensive posture against an early Neon HTTP driver
|
|
10
|
+
* incompatibility with Drizzle's relational query builder (`db.query.*`).
|
|
11
|
+
* Ported to the core query builder (`db.select().from(…).where(…).limit(1)`)
|
|
12
|
+
* in Phase 6.1 — the same callers already use `.update()` and `.insert()`
|
|
13
|
+
* against the same tables on the same Database client without issue, and the
|
|
14
|
+
* core builder is a different code path from the relational one.
|
|
9
15
|
*/
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
if (Array.isArray(result)) {
|
|
13
|
-
return result;
|
|
14
|
-
}
|
|
15
|
-
if (result && typeof result === 'object' && Array.isArray(result.rows)) {
|
|
16
|
-
return result.rows;
|
|
17
|
-
}
|
|
18
|
-
return [];
|
|
19
|
-
};
|
|
16
|
+
import { agentContexts, nodeIdMappings, users } from '@revealui/db/schema';
|
|
17
|
+
import { and, eq } from 'drizzle-orm';
|
|
20
18
|
// =============================================================================
|
|
21
19
|
// Node ID Mappings Queries
|
|
22
20
|
// =============================================================================
|
|
@@ -28,27 +26,11 @@ const getRows = (result) => {
|
|
|
28
26
|
* @returns Node ID mapping or undefined if not found
|
|
29
27
|
*/
|
|
30
28
|
export async function findNodeIdMappingByHash(db, hash) {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
WHERE id = ${hash}
|
|
34
|
-
LIMIT 1`);
|
|
35
|
-
// Handle different result formats (Neon HTTP vs direct Postgres)
|
|
36
|
-
const rows = getRows(result);
|
|
37
|
-
if (!rows[0])
|
|
38
|
-
return undefined;
|
|
39
|
-
// Transform snake_case to camelCase to match NodeIdMappingsRow type
|
|
40
|
-
const row = rows[0];
|
|
41
|
-
return {
|
|
42
|
-
id: row.id,
|
|
43
|
-
entityType: row.entity_type,
|
|
44
|
-
entityId: row.entity_id,
|
|
45
|
-
nodeId: row.node_id,
|
|
46
|
-
createdAt: row.created_at,
|
|
47
|
-
updatedAt: row.updated_at,
|
|
48
|
-
};
|
|
29
|
+
const [row] = await db.select().from(nodeIdMappings).where(eq(nodeIdMappings.id, hash)).limit(1);
|
|
30
|
+
return row;
|
|
49
31
|
}
|
|
50
32
|
/**
|
|
51
|
-
* Finds a node ID mapping by entity
|
|
33
|
+
* Finds a node ID mapping by entity type + entity ID.
|
|
52
34
|
*
|
|
53
35
|
* @param db - Database client
|
|
54
36
|
* @param entityType - Type of entity ('session' or 'user')
|
|
@@ -56,71 +38,42 @@ export async function findNodeIdMappingByHash(db, hash) {
|
|
|
56
38
|
* @returns Node ID mapping or undefined if not found
|
|
57
39
|
*/
|
|
58
40
|
export async function findNodeIdMappingByEntity(db, entityType, entityId) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return undefined;
|
|
66
|
-
// Transform snake_case to camelCase to match NodeIdMappingsRow type
|
|
67
|
-
const row = rows[0];
|
|
68
|
-
return {
|
|
69
|
-
id: row.id,
|
|
70
|
-
entityType: row.entity_type,
|
|
71
|
-
entityId: row.entity_id,
|
|
72
|
-
nodeId: row.node_id,
|
|
73
|
-
createdAt: row.created_at,
|
|
74
|
-
updatedAt: row.updated_at,
|
|
75
|
-
};
|
|
41
|
+
const [row] = await db
|
|
42
|
+
.select()
|
|
43
|
+
.from(nodeIdMappings)
|
|
44
|
+
.where(and(eq(nodeIdMappings.entityType, entityType), eq(nodeIdMappings.entityId, entityId)))
|
|
45
|
+
.limit(1);
|
|
46
|
+
return row;
|
|
76
47
|
}
|
|
77
48
|
// =============================================================================
|
|
78
49
|
// Agent Contexts Queries
|
|
79
50
|
// =============================================================================
|
|
80
51
|
/**
|
|
81
|
-
* Finds an agent context by CRDT ID
|
|
52
|
+
* Finds an agent context by CRDT ID.
|
|
82
53
|
*
|
|
83
54
|
* @param db - Database client
|
|
84
55
|
* @param crdtId - CRDT identifier (format: sessionId:agentId)
|
|
85
|
-
* @returns
|
|
56
|
+
* @returns Agent context row or undefined if not found
|
|
86
57
|
*/
|
|
87
58
|
export async function findAgentContextById(db, crdtId) {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
FROM agent_contexts
|
|
91
|
-
WHERE id = ${crdtId}
|
|
92
|
-
LIMIT 1`);
|
|
93
|
-
const rows = getRows(result);
|
|
94
|
-
if (!rows[0])
|
|
95
|
-
return undefined;
|
|
96
|
-
const row = rows[0];
|
|
97
|
-
return {
|
|
98
|
-
id: row.id,
|
|
99
|
-
version: row.version || 1,
|
|
100
|
-
sessionId: row.session_id,
|
|
101
|
-
agentId: row.agent_id,
|
|
102
|
-
context: row.context || {},
|
|
103
|
-
priority: row.priority || 0.5,
|
|
104
|
-
embedding: row.embedding,
|
|
105
|
-
createdAt: row.created_at,
|
|
106
|
-
updatedAt: row.updated_at,
|
|
107
|
-
};
|
|
59
|
+
const [row] = await db.select().from(agentContexts).where(eq(agentContexts.id, crdtId)).limit(1);
|
|
60
|
+
return row;
|
|
108
61
|
}
|
|
109
62
|
// =============================================================================
|
|
110
63
|
// Users Queries
|
|
111
64
|
// =============================================================================
|
|
112
65
|
/**
|
|
113
|
-
* Finds a user by ID.
|
|
66
|
+
* Finds a user by ID, returning only the columns the memory layer needs.
|
|
114
67
|
*
|
|
115
68
|
* @param db - Database client
|
|
116
69
|
* @param userId - User identifier
|
|
117
|
-
* @returns User record or undefined if not found
|
|
70
|
+
* @returns User record (id + preferences) or undefined if not found
|
|
118
71
|
*/
|
|
119
72
|
export async function findUserById(db, userId) {
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return
|
|
73
|
+
const [row] = await db
|
|
74
|
+
.select({ id: users.id, preferences: users.preferences })
|
|
75
|
+
.from(users)
|
|
76
|
+
.where(eq(users.id, userId))
|
|
77
|
+
.limit(1);
|
|
78
|
+
return row;
|
|
126
79
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-memory-service.d.ts","sourceRoot":"","sources":["../../../src/memory/vector/vector-memory-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAM9D,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,GAAG,CAAmD;IAC9D,OAAO,CAAC,OAAO,CAAiD;IAEhE;;;OAGG;IACH,OAAO,KAAK,EAAE,GAKb;IAED,+DAA+D;IAC/D,OAAO,KAAK,MAAM,GAKjB;IAED;;;;;;;;;;;;;;;;OAgBG;IACG,aAAa,CACjB,cAAc,EAAE,MAAM,EAAE,EACxB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,EAAE,CAAC;IA2GhC;;;;;OAKG;IACG,MAAM,CACV,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,GAAG,YAAY,CAAC,GAAG;QAC7D,EAAE,CAAC,EAAE,MAAM,CAAC;KACb,GACA,OAAO,CAAC,WAAW,CAAC;IA4EvB;;;;;;OAMG;IACG,MAAM,CACV,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,CAAC,CAAC,GACtD,OAAO,CAAC,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"vector-memory-service.d.ts","sourceRoot":"","sources":["../../../src/memory/vector/vector-memory-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAM9D,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,GAAG,CAAmD;IAC9D,OAAO,CAAC,OAAO,CAAiD;IAEhE;;;OAGG;IACH,OAAO,KAAK,EAAE,GAKb;IAED,+DAA+D;IAC/D,OAAO,KAAK,MAAM,GAKjB;IAED;;;;;;;;;;;;;;;;OAgBG;IACG,aAAa,CACjB,cAAc,EAAE,MAAM,EAAE,EACxB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,EAAE,CAAC;IA2GhC;;;;;OAKG;IACG,MAAM,CACV,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,GAAG,YAAY,CAAC,GAAG;QAC7D,EAAE,CAAC,EAAE,MAAM,CAAC;KACb,GACA,OAAO,CAAC,WAAW,CAAC;IA4EvB;;;;;;OAMG;IACG,MAAM,CACV,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,CAAC,CAAC,GACtD,OAAO,CAAC,WAAW,CAAC;IA+EvB;;;;;OAKG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1C;;;;;OAKG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;CA8CvD"}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { getRestClient, getVectorClient } from '@revealui/db/client';
|
|
16
16
|
import { agentMemories } from '@revealui/db/schema';
|
|
17
|
-
import { safeVectorInsert } from '@revealui/db/validation';
|
|
17
|
+
import { assertCrossDbRefs, safeVectorInsert } from '@revealui/db/validation';
|
|
18
18
|
import { and, eq, sql } from 'drizzle-orm';
|
|
19
19
|
/**
|
|
20
20
|
* Vector Memory Service for semantic search operations.
|
|
@@ -257,6 +257,11 @@ export class VectorMemoryService {
|
|
|
257
257
|
if (updates.metadata?.custom?.agentId !== undefined) {
|
|
258
258
|
updateData.agentId = updates.metadata.custom.agentId || null;
|
|
259
259
|
}
|
|
260
|
+
// Validate cross-DB references if siteId is changing
|
|
261
|
+
const newSiteId = updateData.siteId;
|
|
262
|
+
if (newSiteId) {
|
|
263
|
+
await assertCrossDbRefs(this.restDb, { siteId: newSiteId });
|
|
264
|
+
}
|
|
260
265
|
const result = await this.db
|
|
261
266
|
.update(agentMemories)
|
|
262
267
|
.set(updateData)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import type { LLMClient } from '../llm/client.js';
|
|
7
7
|
import type { AgentSkillProvider } from '../skills/integration/agent-skill-provider.js';
|
|
8
8
|
import type { ApprovalCallback } from '../tools/base.js';
|
|
9
|
-
import type { MCPToolSource } from '../tools/mcp-adapter.js';
|
|
9
|
+
import type { MCPToolSource, McpClientLike } from '../tools/mcp-adapter.js';
|
|
10
10
|
import type { Agent, AgentResult, Task } from './agent.js';
|
|
11
11
|
/**
|
|
12
12
|
* Controls how much of the model's token budget is allocated to internal reasoning.
|
|
@@ -39,8 +39,37 @@ export interface RuntimeConfig {
|
|
|
39
39
|
* Optional MCP Hypervisor (or any MCPToolSource). When provided, tools from
|
|
40
40
|
* all healthy MCP servers are merged into the agent's tool set before each
|
|
41
41
|
* task execution. Pass an MCPHypervisor from @revealui/mcp.
|
|
42
|
+
*
|
|
43
|
+
* @deprecated Prefer `mcpClients` (Stage 5.1a). The hypervisor path doesn't
|
|
44
|
+
* expose the full MCP protocol surface (resources, prompts, sampling,
|
|
45
|
+
* elicitation). Standard `McpClient` instances do. This field stays for
|
|
46
|
+
* backwards compatibility and will keep working until a future major.
|
|
42
47
|
*/
|
|
43
48
|
mcpToolSource?: MCPToolSource;
|
|
49
|
+
/**
|
|
50
|
+
* Optional set of standard MCP clients (Stage 5.1a). When provided, each
|
|
51
|
+
* client's tools are listed and merged into the agent's tool set before
|
|
52
|
+
* each task. Tool names are namespaced as `mcp_<name>__<toolName>` so
|
|
53
|
+
* multiple clients can coexist without collisions. Consumers construct the
|
|
54
|
+
* client (stdio / Streamable HTTP + OAuth) and pre-connect it before
|
|
55
|
+
* passing it here. The runtime does NOT own client lifecycle.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* import { McpClient } from '@revealui/mcp/client';
|
|
60
|
+
*
|
|
61
|
+
* const contentClient = new McpClient({ ... });
|
|
62
|
+
* await contentClient.connect();
|
|
63
|
+
*
|
|
64
|
+
* const runtime = new AgentRuntime({
|
|
65
|
+
* mcpClients: [{ name: 'content', client: contentClient }],
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
mcpClients?: ReadonlyArray<{
|
|
70
|
+
name: string;
|
|
71
|
+
client: McpClientLike;
|
|
72
|
+
}>;
|
|
44
73
|
/**
|
|
45
74
|
* Optional skill provider. When set, activated skills are injected into the
|
|
46
75
|
* system prompt before the first LLM call, giving the agent contextual
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/orchestration/runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGlD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AACxF,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,kBAAkB,CAAC;AAE3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/orchestration/runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGlD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AACxF,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,kBAAkB,CAAC;AAE3E,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG5E,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAE3D;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAWpF,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,aAAa,CAAA;KAAE,CAAC,CAAC;IACpE;;;;OAIG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,gCAAgC,EAAE,SAAS,CAAC;IAC/D;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC;AAED,qBAAa,YAAY;IACvB,SAAS,CAAC,MAAM,EAAE,aAAa,CAAC;IAChC,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,cAAc,CAAgD;IACtE,OAAO,CAAC,cAAc,CAAS;gBAEnB,MAAM,GAAE,aAAkB;IA0BtC;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;YAqBzE,OAAO;IAoPrB;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAI7B;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAc9E;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B9B;;OAEG;IACH,SAAS,IAAI;QACX,cAAc,EAAE,OAAO,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;KACxB;CAOF"}
|
|
@@ -7,7 +7,7 @@ import { registerCleanupHandler } from '@revealui/core/monitoring';
|
|
|
7
7
|
import { z } from 'zod/v4';
|
|
8
8
|
import { estimateCost } from '../llm/token-counter.js';
|
|
9
9
|
import { ToolCallDeduplicator } from '../tools/deduplicator.js';
|
|
10
|
-
import { discoverMCPTools } from '../tools/mcp-adapter.js';
|
|
10
|
+
import { createToolsFromMcpClient, discoverMCPTools } from '../tools/mcp-adapter.js';
|
|
11
11
|
import { createWebSearchTool } from '../tools/web/duck-duck-go.js';
|
|
12
12
|
const THINKING_BUDGETS = {
|
|
13
13
|
off: 0,
|
|
@@ -30,6 +30,7 @@ export class AgentRuntime {
|
|
|
30
30
|
maxRetries: config.maxRetries ?? 3,
|
|
31
31
|
enableCache: config.enableCache ?? true, // Enable by default for cost savings
|
|
32
32
|
mcpToolSource: config.mcpToolSource,
|
|
33
|
+
mcpClients: config.mcpClients,
|
|
33
34
|
skillProvider: config.skillProvider,
|
|
34
35
|
thinkingLevel: config.thinkingLevel,
|
|
35
36
|
modelTier: config.modelTier,
|
|
@@ -67,8 +68,24 @@ export class AgentRuntime {
|
|
|
67
68
|
let iterations = 0;
|
|
68
69
|
let totalTokens = 0;
|
|
69
70
|
let totalCostUsd = 0;
|
|
70
|
-
// Merge MCP-discovered tools
|
|
71
|
-
|
|
71
|
+
// Merge MCP-discovered tools into the agent's tool set. Two paths:
|
|
72
|
+
// - Standard `McpClient` instances (Stage 5.1a, preferred)
|
|
73
|
+
// - `MCPToolSource` / hypervisor (legacy, deprecated but supported)
|
|
74
|
+
const mcpTools = [];
|
|
75
|
+
if (this.config.mcpToolSource) {
|
|
76
|
+
mcpTools.push(...discoverMCPTools(this.config.mcpToolSource));
|
|
77
|
+
}
|
|
78
|
+
if (this.config.mcpClients && this.config.mcpClients.length > 0) {
|
|
79
|
+
for (const { name, client } of this.config.mcpClients) {
|
|
80
|
+
try {
|
|
81
|
+
const fromClient = await createToolsFromMcpClient(client, { namespace: name });
|
|
82
|
+
mcpTools.push(...fromClient);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// empty-catch-ok: an unhealthy MCP client shouldn't fail the whole task — other clients + base tools still apply
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
72
89
|
// Swap in a custom WebSearchProvider if the agent config specifies one (P4-3)
|
|
73
90
|
const customProvider = agent.config?.webSearchProvider;
|
|
74
91
|
let baseTools;
|
|
@@ -11,8 +11,32 @@ import type { LLMClient } from '../llm/client.js';
|
|
|
11
11
|
import type { ToolResult } from '../tools/base.js';
|
|
12
12
|
import type { Agent, Task } from './agent.js';
|
|
13
13
|
import { AgentRuntime, type RuntimeConfig } from './runtime.js';
|
|
14
|
+
/**
|
|
15
|
+
* Chunk types emitted over the agent-stream SSE channel.
|
|
16
|
+
*
|
|
17
|
+
* The generator in `StreamingAgentRuntime.streamTask` emits the core turn
|
|
18
|
+
* events (`text`, `tool_call_start`, `tool_call_result`, `error`, `done`).
|
|
19
|
+
*
|
|
20
|
+
* Side-channel events originate outside the generator — route-level
|
|
21
|
+
* handlers (MCP sampling / elicitation) write them to the SSE stream
|
|
22
|
+
* directly between turns:
|
|
23
|
+
*
|
|
24
|
+
* - `session_info` — emitted once at stream start with the
|
|
25
|
+
* agent-run session id. Clients use the id to POST elicitation
|
|
26
|
+
* responses back via `POST /api/agent-stream/elicit`.
|
|
27
|
+
* - `sampling_request` — fired when a connected MCP server calls
|
|
28
|
+
* `sampling/create`; the handler services the request synchronously
|
|
29
|
+
* and emits this chunk for observability.
|
|
30
|
+
* - `elicitation_request` — fired when a connected MCP server calls
|
|
31
|
+
* `elicitation/create`; the handler pauses waiting for a POST
|
|
32
|
+
* response keyed on `(sessionId, elicitationId)`.
|
|
33
|
+
*
|
|
34
|
+
* A.2b of the post-v1 MCP arc — the side-channel types are defined here
|
|
35
|
+
* so the `useAgentStream` consumer + future UI can narrow on them.
|
|
36
|
+
* A.2b-backend wires the emission; A.2b-frontend renders them.
|
|
37
|
+
*/
|
|
14
38
|
export interface AgentStreamChunk {
|
|
15
|
-
type: 'text' | 'tool_call_start' | 'tool_call_result' | 'error' | 'done';
|
|
39
|
+
type: 'text' | 'tool_call_start' | 'tool_call_result' | 'error' | 'done' | 'session_info' | 'sampling_request' | 'elicitation_request';
|
|
16
40
|
content?: string;
|
|
17
41
|
toolCall?: {
|
|
18
42
|
name: string;
|
|
@@ -24,6 +48,29 @@ export interface AgentStreamChunk {
|
|
|
24
48
|
tokensUsed?: number;
|
|
25
49
|
executionTime?: number;
|
|
26
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Present on `session_info`, `sampling_request`, `elicitation_request`.
|
|
53
|
+
* Identifies the agent-run session; clients key elicitation POSTs on
|
|
54
|
+
* this.
|
|
55
|
+
*/
|
|
56
|
+
sessionId?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Namespace (MCP server id) the side-channel event originated from.
|
|
59
|
+
* Present on `sampling_request` + `elicitation_request`.
|
|
60
|
+
*/
|
|
61
|
+
namespace?: string;
|
|
62
|
+
/** Present on `sampling_request` — requested model + shape. */
|
|
63
|
+
sampling?: {
|
|
64
|
+
model: string;
|
|
65
|
+
messageCount: number;
|
|
66
|
+
maxTokens: number;
|
|
67
|
+
};
|
|
68
|
+
/** Present on `elicitation_request` — form payload. */
|
|
69
|
+
elicitation?: {
|
|
70
|
+
elicitationId: string;
|
|
71
|
+
requestedSchema: unknown;
|
|
72
|
+
message?: string;
|
|
73
|
+
};
|
|
27
74
|
}
|
|
28
75
|
export declare class StreamingAgentRuntime extends AgentRuntime {
|
|
29
76
|
constructor(config?: RuntimeConfig);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streaming-runtime.d.ts","sourceRoot":"","sources":["../../src/orchestration/streaming-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAEhE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,
|
|
1
|
+
{"version":3,"file":"streaming-runtime.d.ts","sourceRoot":"","sources":["../../src/orchestration/streaming-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EACA,MAAM,GACN,iBAAiB,GACjB,kBAAkB,GAClB,OAAO,GACP,MAAM,GACN,cAAc,GACd,kBAAkB,GAClB,qBAAqB,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE;QACT,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE;QACT,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,uDAAuD;IACvD,WAAW,CAAC,EAAE;QACZ,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,OAAO,CAAC;QACzB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,qBAAa,qBAAsB,SAAQ,YAAY;gBACzC,MAAM,GAAE,aAAkB;IAItC;;;OAGG;IACI,UAAU,CACf,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,cAAc,CAAC,gBAAgB,CAAC;CAsLpC"}
|
|
@@ -64,7 +64,16 @@ export declare class TicketAgentDispatcher {
|
|
|
64
64
|
* - Have access to all admin tools (create/update/delete content, globals, media, users)
|
|
65
65
|
* - Have access to ticket mutation tools (update status, add comment)
|
|
66
66
|
* - Run the agentic loop until done or max iterations
|
|
67
|
+
*
|
|
68
|
+
* When `options.dispatchId` is provided, id-generating tool calls
|
|
69
|
+
* (currently `add_ticket_comment`) derive their ids deterministically
|
|
70
|
+
* from (dispatchId, call-ordinal). This makes the dispatch retry-safe:
|
|
71
|
+
* a crash-and-resume re-issues tool calls in the same order and
|
|
72
|
+
* produces the same ids, so the persistence layer's PK constraint
|
|
73
|
+
* dedupes naturally. Pair with the durable work queue's jobId.
|
|
67
74
|
*/
|
|
68
|
-
dispatch(ticket: TicketInput
|
|
75
|
+
dispatch(ticket: TicketInput, options?: {
|
|
76
|
+
dispatchId?: string;
|
|
77
|
+
}): Promise<AgentResult>;
|
|
69
78
|
}
|
|
70
79
|
//# sourceMappingURL=ticket-agent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ticket-agent.d.ts","sourceRoot":"","sources":["../../src/orchestration/ticket-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,KAAK,EACV,cAAc,EAEd,kBAAkB,EAClB,cAAc,EACf,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAGrE,OAAO,KAAK,EAAS,WAAW,EAAQ,MAAM,YAAY,CAAC;AAG3D,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,0GAA0G;IAC1G,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,SAAS,EAAE,SAAS,CAAC;IAErB,2DAA2D;IAC3D,SAAS,EAAE,cAAc,CAAC;IAE1B,wEAAwE;IACxE,YAAY,EAAE,oBAAoB,CAAC;IAEnC,yEAAyE;IACzE,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAEnC,yCAAyC;IACzC,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAE3B;;;;OAIG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;IAExB;;;OAGG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IAEd,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAwDD,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,YAAY,CAAoB;gBAE5B,MAAM,EAAE,iBAAiB;IAUrC
|
|
1
|
+
{"version":3,"file":"ticket-agent.d.ts","sourceRoot":"","sources":["../../src/orchestration/ticket-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,KAAK,EACV,cAAc,EAEd,kBAAkB,EAClB,cAAc,EACf,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAGrE,OAAO,KAAK,EAAS,WAAW,EAAQ,MAAM,YAAY,CAAC;AAG3D,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,0GAA0G;IAC1G,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,SAAS,EAAE,SAAS,CAAC;IAErB,2DAA2D;IAC3D,SAAS,EAAE,cAAc,CAAC;IAE1B,wEAAwE;IACxE,YAAY,EAAE,oBAAoB,CAAC;IAEnC,yEAAyE;IACzE,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAEnC,yCAAyC;IACzC,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAE3B;;;;OAIG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;IAExB;;;OAGG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IAEd,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAwDD,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,YAAY,CAAoB;gBAE5B,MAAM,EAAE,iBAAiB;IAUrC;;;;;;;;;;;;;;;OAeG;IACG,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,WAAW,CAAC;CA0DjG"}
|
|
@@ -94,13 +94,22 @@ export class TicketAgentDispatcher {
|
|
|
94
94
|
* - Have access to all admin tools (create/update/delete content, globals, media, users)
|
|
95
95
|
* - Have access to ticket mutation tools (update status, add comment)
|
|
96
96
|
* - Run the agentic loop until done or max iterations
|
|
97
|
+
*
|
|
98
|
+
* When `options.dispatchId` is provided, id-generating tool calls
|
|
99
|
+
* (currently `add_ticket_comment`) derive their ids deterministically
|
|
100
|
+
* from (dispatchId, call-ordinal). This makes the dispatch retry-safe:
|
|
101
|
+
* a crash-and-resume re-issues tool calls in the same order and
|
|
102
|
+
* produces the same ids, so the persistence layer's PK constraint
|
|
103
|
+
* dedupes naturally. Pair with the durable work queue's jobId.
|
|
97
104
|
*/
|
|
98
|
-
async dispatch(ticket) {
|
|
105
|
+
async dispatch(ticket, options = {}) {
|
|
99
106
|
const { apiClient, ticketClient, collections, globals, memory: sharedMemory, db } = this.config;
|
|
100
107
|
// Build tool set: admin tools + ticket mutation tools + web scraper + optional summarizer
|
|
101
108
|
const cmsConfig = { apiClient, collections, globals };
|
|
102
109
|
const cmsTools = createAdminTools(cmsConfig);
|
|
103
|
-
const ticketTools = createTicketTools(ticket.id, ticketClient
|
|
110
|
+
const ticketTools = createTicketTools(ticket.id, ticketClient, {
|
|
111
|
+
dispatchId: options.dispatchId,
|
|
112
|
+
});
|
|
104
113
|
const extraTools = db
|
|
105
114
|
? [webScraperTool, createDocumentSummarizerTool(db, this.config.llmClient)]
|
|
106
115
|
: [webScraperTool];
|