@rubytech/create-maxy-code 0.1.171 → 0.1.174
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/index.js +12 -1
- package/package.json +1 -1
- package/payload/platform/scripts/verify-skill-tool-surface.sh +98 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +24 -8
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +15 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +78 -8
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js.map +1 -1
- package/payload/platform/templates/specialists/agents/content-producer.md +4 -4
- package/payload/platform/templates/specialists/agents/librarian.md +2 -2
- package/payload/platform/templates/specialists/agents/personal-assistant.md +4 -4
- package/payload/platform/templates/specialists/agents/project-manager.md +2 -2
- package/payload/platform/templates/specialists/agents/research-assistant.md +2 -2
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js +21 -21
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js +18 -18
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js +9 -9
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js +6 -6
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/scripts/smoke.mjs +2 -2
- package/payload/premium-plugins/writer-craft/mcp/src/index.ts +21 -21
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-distil-profile.ts +19 -19
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-record-feedback.ts +10 -10
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-retrieve-conditioning.ts +7 -7
- package/payload/server/public/assets/{admin-Dal5FWaD.js → admin-DH5jp-1u.js} +1 -1
- package/payload/server/public/assets/{data-DbSORCl4.js → data-CtanHhM2.js} +1 -1
- package/payload/server/public/assets/{graph-ys_joP2o.js → graph-6DPD6be1.js} +1 -1
- package/payload/server/public/assets/graph-labels-BMU8LsOD.js +1 -0
- package/payload/server/public/assets/{page-CwmZ76U7.js → page-0lzgQWnS.js} +1 -1
- package/payload/server/public/assets/{page--bl5Y7ZI.js → page-C29S3cBt.js} +1 -1
- package/payload/server/public/data.html +3 -3
- package/payload/server/public/graph.html +3 -3
- package/payload/server/public/index.html +4 -4
- package/payload/server/server.js +27 -3
- package/payload/server/public/assets/graph-labels-BBB5jsZk.js +0 -1
|
@@ -19,9 +19,9 @@ const server = new McpServer({
|
|
|
19
19
|
// refusal preserves account isolation. Mirrors the memory plugin's
|
|
20
20
|
// pattern (Task 202).
|
|
21
21
|
const accountId = process.env.ACCOUNT_ID ?? null;
|
|
22
|
-
const
|
|
22
|
+
const userIdEnv = process.env.ADMIN_USER_ID ?? null;
|
|
23
23
|
process.stderr.write(
|
|
24
|
-
`[writer-craft] boot accountId=${accountId ?? "null"}
|
|
24
|
+
`[writer-craft] boot accountId=${accountId ?? "null"} userId=${userIdEnv ?? "null"}\n`,
|
|
25
25
|
);
|
|
26
26
|
|
|
27
27
|
function refuseNoAccount(toolName: string) {
|
|
@@ -39,11 +39,11 @@ function refuseNoAccount(toolName: string) {
|
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
function
|
|
42
|
+
function resolveUserId(): string | null {
|
|
43
43
|
// ADMIN_USER_ID is stamped by the admin session manager at spawn time.
|
|
44
44
|
// When absent (e.g. specialist subagents), the operator must pass it as
|
|
45
45
|
// a tool argument or the tools refuse rather than orphan a profile.
|
|
46
|
-
return
|
|
46
|
+
return userIdEnv;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
server.tool(
|
|
@@ -95,7 +95,7 @@ server.tool(
|
|
|
95
95
|
"voice-distil-profile",
|
|
96
96
|
"Two-mode tool (Task 424). mode='sample' (default) walks the operator's human-only corpus, returns the exemplars + recent operator-edit intents for the agent to read. mode='write' persists the YAML style card the agent composed from the sample-mode response. Cadence-guarded: returns skip in 'write' mode without writing if corpus didn't grow ≥20% AND <30 days passed (pass force=true to override).",
|
|
97
97
|
{
|
|
98
|
-
|
|
98
|
+
userId: z
|
|
99
99
|
.string()
|
|
100
100
|
.optional()
|
|
101
101
|
.describe(
|
|
@@ -114,16 +114,16 @@ server.tool(
|
|
|
114
114
|
.optional()
|
|
115
115
|
.describe("Required for mode='write'. The YAML style card the agent composed from the sample-mode exemplars + feedback intents."),
|
|
116
116
|
},
|
|
117
|
-
async ({
|
|
117
|
+
async ({ userId, force, mode, styleCardYaml }) => {
|
|
118
118
|
if (!accountId) return refuseNoAccount("voice-distil-profile");
|
|
119
|
-
const
|
|
120
|
-
if (!
|
|
119
|
+
const resolvedUserId = userId ?? resolveUserId();
|
|
120
|
+
if (!resolvedUserId) {
|
|
121
121
|
return {
|
|
122
122
|
content: [
|
|
123
123
|
{
|
|
124
124
|
type: "text" as const,
|
|
125
125
|
text:
|
|
126
|
-
"voice-distil-profile:
|
|
126
|
+
"voice-distil-profile: userId required (no ADMIN_USER_ID in spawn env).",
|
|
127
127
|
},
|
|
128
128
|
],
|
|
129
129
|
isError: true,
|
|
@@ -132,7 +132,7 @@ server.tool(
|
|
|
132
132
|
try {
|
|
133
133
|
const result = await voiceDistilProfile({
|
|
134
134
|
accountId,
|
|
135
|
-
|
|
135
|
+
userId: resolvedUserId,
|
|
136
136
|
force: force === true,
|
|
137
137
|
mode,
|
|
138
138
|
styleCardYaml,
|
|
@@ -161,7 +161,7 @@ server.tool(
|
|
|
161
161
|
"voice-retrieve-conditioning",
|
|
162
162
|
"Return the operator's style card and K voice-matched exemplars for a drafting brief. K=5 short-form, K=15 long-form. Token-budget bounded. Returns empty {styleCard:null,exemplars:[]} when no profile exists.",
|
|
163
163
|
{
|
|
164
|
-
|
|
164
|
+
userId: z
|
|
165
165
|
.string()
|
|
166
166
|
.optional()
|
|
167
167
|
.describe("Operator AdminUser identifier. Defaults to ADMIN_USER_ID env."),
|
|
@@ -175,10 +175,10 @@ server.tool(
|
|
|
175
175
|
register: z.string().optional().describe("Optional register hint"),
|
|
176
176
|
tokenBudget: z.number().int().positive().optional(),
|
|
177
177
|
},
|
|
178
|
-
async ({
|
|
178
|
+
async ({ userId, topic, format, register, tokenBudget }) => {
|
|
179
179
|
if (!accountId) return refuseNoAccount("voice-retrieve-conditioning");
|
|
180
|
-
const
|
|
181
|
-
if (!
|
|
180
|
+
const resolvedUserId = userId ?? resolveUserId();
|
|
181
|
+
if (!resolvedUserId) {
|
|
182
182
|
return {
|
|
183
183
|
content: [
|
|
184
184
|
{
|
|
@@ -191,7 +191,7 @@ server.tool(
|
|
|
191
191
|
try {
|
|
192
192
|
const result = await voiceRetrieveConditioning({
|
|
193
193
|
accountId,
|
|
194
|
-
|
|
194
|
+
userId: resolvedUserId,
|
|
195
195
|
brief: { topic, format, register },
|
|
196
196
|
tokenBudget,
|
|
197
197
|
});
|
|
@@ -222,7 +222,7 @@ server.tool(
|
|
|
222
222
|
"voice-record-feedback",
|
|
223
223
|
"Capture an operator's edit on an agent draft. Writes :VoiceEdit linked to :VoiceProfile via :FEEDBACK_FOR. The calling agent supplies `intent` (one sentence describing what the operator changed and what voice preference it reveals); Task 424 moved the diff-intent summarisation into the agent's turn.",
|
|
224
224
|
{
|
|
225
|
-
|
|
225
|
+
userId: z.string().optional(),
|
|
226
226
|
originalText: z.string().min(1),
|
|
227
227
|
editedText: z.string().min(1),
|
|
228
228
|
intent: z
|
|
@@ -232,15 +232,15 @@ server.tool(
|
|
|
232
232
|
skill: z.string().optional().describe("Calling skill name, for provenance"),
|
|
233
233
|
brief: z.string().optional().describe("Drafting brief that produced the original"),
|
|
234
234
|
},
|
|
235
|
-
async ({
|
|
235
|
+
async ({ userId, originalText, editedText, intent, skill, brief }) => {
|
|
236
236
|
if (!accountId) return refuseNoAccount("voice-record-feedback");
|
|
237
|
-
const
|
|
238
|
-
if (!
|
|
237
|
+
const resolvedUserId = userId ?? resolveUserId();
|
|
238
|
+
if (!resolvedUserId) {
|
|
239
239
|
return {
|
|
240
240
|
content: [
|
|
241
241
|
{
|
|
242
242
|
type: "text" as const,
|
|
243
|
-
text: "voice-record-feedback:
|
|
243
|
+
text: "voice-record-feedback: userId required (no ADMIN_USER_ID in spawn env).",
|
|
244
244
|
},
|
|
245
245
|
],
|
|
246
246
|
isError: true,
|
|
@@ -249,7 +249,7 @@ server.tool(
|
|
|
249
249
|
try {
|
|
250
250
|
const result = await voiceRecordFeedback({
|
|
251
251
|
accountId,
|
|
252
|
-
|
|
252
|
+
userId: resolvedUserId,
|
|
253
253
|
originalText,
|
|
254
254
|
editedText,
|
|
255
255
|
intent,
|
|
@@ -44,7 +44,7 @@ const RE_RUN_AGE_DAYS = 30;
|
|
|
44
44
|
|
|
45
45
|
export interface VoiceDistilProfileParams {
|
|
46
46
|
accountId: string;
|
|
47
|
-
|
|
47
|
+
userId: string;
|
|
48
48
|
force?: boolean;
|
|
49
49
|
/**
|
|
50
50
|
* Operation mode (Task 424):
|
|
@@ -87,9 +87,9 @@ export interface VoiceDistilProfileResult {
|
|
|
87
87
|
export async function voiceDistilProfile(
|
|
88
88
|
params: VoiceDistilProfileParams,
|
|
89
89
|
): Promise<VoiceDistilProfileResult> {
|
|
90
|
-
const { accountId,
|
|
91
|
-
if (!accountId || !
|
|
92
|
-
throw new Error("voice-distil-profile: accountId and
|
|
90
|
+
const { accountId, userId, force = false } = params;
|
|
91
|
+
if (!accountId || !userId) {
|
|
92
|
+
throw new Error("voice-distil-profile: accountId and userId required");
|
|
93
93
|
}
|
|
94
94
|
const session = getSession();
|
|
95
95
|
const now = new Date();
|
|
@@ -98,11 +98,11 @@ export async function voiceDistilProfile(
|
|
|
98
98
|
try {
|
|
99
99
|
// 1. Read existing profile (if any) for cadence-guard comparison.
|
|
100
100
|
const existing = await session.run(
|
|
101
|
-
`MATCH (a:AdminUser {accountId: $accountId,
|
|
101
|
+
`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
102
102
|
OPTIONAL MATCH (a)-[:HAS_VOICE_PROFILE]->(p:VoiceProfile)
|
|
103
103
|
RETURN elementId(p) AS profileId, p.corpusSize AS corpusSize,
|
|
104
104
|
p.generatedAt AS generatedAt`,
|
|
105
|
-
{ accountId,
|
|
105
|
+
{ accountId, userId },
|
|
106
106
|
);
|
|
107
107
|
const existingRow = existing.records[0];
|
|
108
108
|
const prevProfileId = (existingRow?.get("profileId") as string | null) ?? null;
|
|
@@ -123,7 +123,7 @@ export async function voiceDistilProfile(
|
|
|
123
123
|
|
|
124
124
|
if (corpusSize === 0) {
|
|
125
125
|
process.stderr.write(
|
|
126
|
-
`[voice-distil] adminUser=${
|
|
126
|
+
`[voice-distil] adminUser=${userId} skip reason=empty-corpus\n`,
|
|
127
127
|
);
|
|
128
128
|
return {
|
|
129
129
|
profileId: prevProfileId,
|
|
@@ -151,7 +151,7 @@ export async function voiceDistilProfile(
|
|
|
151
151
|
if (!ageTrigger && !growthTrigger) {
|
|
152
152
|
const reason = ageDays < 1 ? "recent" : "below-threshold";
|
|
153
153
|
process.stderr.write(
|
|
154
|
-
`[voice-distil] adminUser=${
|
|
154
|
+
`[voice-distil] adminUser=${userId} skip reason=${reason} corpusSize=${corpusSize} prevCorpus=${prevCorpusSize} ageDays=${ageDays.toFixed(1)}\n`,
|
|
155
155
|
);
|
|
156
156
|
return {
|
|
157
157
|
profileId: prevProfileId,
|
|
@@ -179,7 +179,7 @@ export async function voiceDistilProfile(
|
|
|
179
179
|
coalesce(n.body, n.abstract, n.subject, n.title, n.summary, '') AS body,
|
|
180
180
|
parent.conversationIdentity IS NOT NULL AS isConversationChunk,
|
|
181
181
|
ts
|
|
182
|
-
ORDER BY ts
|
|
182
|
+
ORDER BY ts IS NULL, ts DESC
|
|
183
183
|
LIMIT 500`,
|
|
184
184
|
{ accountId },
|
|
185
185
|
);
|
|
@@ -207,10 +207,10 @@ export async function voiceDistilProfile(
|
|
|
207
207
|
|
|
208
208
|
// 5. Pull feedback intents from existing :VoiceEdit nodes for this operator.
|
|
209
209
|
const feedback = await session.run(
|
|
210
|
-
`MATCH (a:AdminUser {accountId: $accountId,
|
|
211
|
-
MATCH (e:VoiceEdit {
|
|
210
|
+
`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
211
|
+
MATCH (e:VoiceEdit {userId: $userId, accountId: $accountId})
|
|
212
212
|
RETURN e.intent AS intent ORDER BY e.occurredAt DESC LIMIT 50`,
|
|
213
|
-
{ accountId,
|
|
213
|
+
{ accountId, userId },
|
|
214
214
|
);
|
|
215
215
|
const feedbackIntents = feedback.records
|
|
216
216
|
.map((r) => r.get("intent") as string | null)
|
|
@@ -224,7 +224,7 @@ export async function voiceDistilProfile(
|
|
|
224
224
|
const mode = params.mode ?? "sample";
|
|
225
225
|
if (mode === "sample") {
|
|
226
226
|
process.stderr.write(
|
|
227
|
-
`[voice-distil] adminUser=${
|
|
227
|
+
`[voice-distil] adminUser=${userId} mode=sample corpusSize=${corpusSize} ` +
|
|
228
228
|
`exemplars=${samples.length} feedbackEntries=${feedbackIntents.length}\n`,
|
|
229
229
|
);
|
|
230
230
|
return {
|
|
@@ -250,12 +250,12 @@ export async function voiceDistilProfile(
|
|
|
250
250
|
//
|
|
251
251
|
// The :AdminUser must already exist (onboarding/auth is the only
|
|
252
252
|
// legitimate origin for :AdminUser). MATCH not MERGE: a typo in
|
|
253
|
-
//
|
|
253
|
+
// userId, an env mismatch, or a dropped credential surfaces
|
|
254
254
|
// here as a typed error rather than silently minting an orphan
|
|
255
255
|
// AdminUser that bypasses the platform's label-origin protection.
|
|
256
256
|
const writeResult = await session.run(
|
|
257
|
-
`MATCH (a:AdminUser {accountId: $accountId,
|
|
258
|
-
MERGE (a)-[:HAS_VOICE_PROFILE]->(p:VoiceProfile {accountId: $accountId,
|
|
257
|
+
`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
258
|
+
MERGE (a)-[:HAS_VOICE_PROFILE]->(p:VoiceProfile {accountId: $accountId, userId: $userId})
|
|
259
259
|
ON CREATE SET p.createdAt = $now
|
|
260
260
|
SET p.styleCard = $styleCard,
|
|
261
261
|
p.generatedAt = $now,
|
|
@@ -269,7 +269,7 @@ export async function voiceDistilProfile(
|
|
|
269
269
|
RETURN elementId(p) AS profileId`,
|
|
270
270
|
{
|
|
271
271
|
accountId,
|
|
272
|
-
|
|
272
|
+
userId,
|
|
273
273
|
styleCard: styleCardYaml,
|
|
274
274
|
now: nowIso,
|
|
275
275
|
corpusSize,
|
|
@@ -281,13 +281,13 @@ export async function voiceDistilProfile(
|
|
|
281
281
|
// error here rather than returning a half-baked result.
|
|
282
282
|
if (writeResult.records.length === 0) {
|
|
283
283
|
throw new Error(
|
|
284
|
-
`voice-mirror: :AdminUser {accountId='${accountId}',
|
|
284
|
+
`voice-mirror: :AdminUser {accountId='${accountId}', userId='${userId}'} not found. Onboarding must promote the operator to :AdminUser before distillation.`,
|
|
285
285
|
);
|
|
286
286
|
}
|
|
287
287
|
const profileId = writeResult.records[0].get("profileId") as string;
|
|
288
288
|
|
|
289
289
|
process.stderr.write(
|
|
290
|
-
`[voice-distil] adminUser=${
|
|
290
|
+
`[voice-distil] adminUser=${userId} mode=write corpusSize=${corpusSize} generatedAt=${nowIso} feedbackEntries=${feedbackIntents.length}\n`,
|
|
291
291
|
);
|
|
292
292
|
|
|
293
293
|
return {
|
|
@@ -17,7 +17,7 @@ import { getSession } from "../lib/neo4j.js";
|
|
|
17
17
|
|
|
18
18
|
export interface VoiceRecordFeedbackParams {
|
|
19
19
|
accountId: string;
|
|
20
|
-
|
|
20
|
+
userId: string;
|
|
21
21
|
originalText: string;
|
|
22
22
|
editedText: string;
|
|
23
23
|
/**
|
|
@@ -44,9 +44,9 @@ export interface VoiceRecordFeedbackResult {
|
|
|
44
44
|
export async function voiceRecordFeedback(
|
|
45
45
|
params: VoiceRecordFeedbackParams,
|
|
46
46
|
): Promise<VoiceRecordFeedbackResult> {
|
|
47
|
-
const { accountId,
|
|
48
|
-
if (!accountId || !
|
|
49
|
-
throw new Error("voice-record-feedback: accountId and
|
|
47
|
+
const { accountId, userId, originalText, editedText, intent: rawIntent, context } = params;
|
|
48
|
+
if (!accountId || !userId) {
|
|
49
|
+
throw new Error("voice-record-feedback: accountId and userId required");
|
|
50
50
|
}
|
|
51
51
|
if (!originalText || !editedText) {
|
|
52
52
|
throw new Error("voice-record-feedback: originalText and editedText required");
|
|
@@ -65,11 +65,11 @@ export async function voiceRecordFeedback(
|
|
|
65
65
|
const session = getSession();
|
|
66
66
|
try {
|
|
67
67
|
const result = await session.run(
|
|
68
|
-
`MATCH (a:AdminUser {accountId: $accountId,
|
|
68
|
+
`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
69
69
|
CREATE (e:VoiceEdit {
|
|
70
70
|
editId: $editId,
|
|
71
71
|
accountId: $accountId,
|
|
72
|
-
|
|
72
|
+
userId: $userId,
|
|
73
73
|
originalText: $originalText,
|
|
74
74
|
editedText: $editedText,
|
|
75
75
|
intent: $intent,
|
|
@@ -79,14 +79,14 @@ export async function voiceRecordFeedback(
|
|
|
79
79
|
})
|
|
80
80
|
CREATE (a)-[:AUTHORED]->(e)
|
|
81
81
|
WITH e
|
|
82
|
-
OPTIONAL MATCH (:AdminUser {accountId: $accountId,
|
|
82
|
+
OPTIONAL MATCH (:AdminUser {accountId: $accountId, userId: $userId})-[:HAS_VOICE_PROFILE]->(p:VoiceProfile)
|
|
83
83
|
FOREACH (_ IN CASE WHEN p IS NULL THEN [] ELSE [1] END |
|
|
84
84
|
MERGE (e)-[:FEEDBACK_FOR]->(p)
|
|
85
85
|
)
|
|
86
86
|
RETURN elementId(e) AS editId, (p IS NOT NULL) AS hadProfile`,
|
|
87
87
|
{
|
|
88
88
|
accountId,
|
|
89
|
-
|
|
89
|
+
userId,
|
|
90
90
|
editId,
|
|
91
91
|
originalText,
|
|
92
92
|
editedText,
|
|
@@ -98,13 +98,13 @@ export async function voiceRecordFeedback(
|
|
|
98
98
|
);
|
|
99
99
|
if (result.records.length === 0) {
|
|
100
100
|
throw new Error(
|
|
101
|
-
`voice-mirror: :AdminUser {accountId='${accountId}',
|
|
101
|
+
`voice-mirror: :AdminUser {accountId='${accountId}', userId='${userId}'} not found. Onboarding must promote the operator to :AdminUser before feedback can be recorded.`,
|
|
102
102
|
);
|
|
103
103
|
}
|
|
104
104
|
const hadProfile = result.records[0].get("hadProfile") === true;
|
|
105
105
|
|
|
106
106
|
process.stderr.write(
|
|
107
|
-
`[voice-record-feedback] adminUser=${
|
|
107
|
+
`[voice-record-feedback] adminUser=${userId} intent="${cappedIntent.replace(/"/g, "'")}" diffBytes=${editedText.length - originalText.length}\n`,
|
|
108
108
|
);
|
|
109
109
|
|
|
110
110
|
return { editId, intent: cappedIntent, occurredAt, hadProfile };
|
|
@@ -26,7 +26,7 @@ const CHARS_PER_TOKEN = 4;
|
|
|
26
26
|
|
|
27
27
|
export interface VoiceRetrieveConditioningParams {
|
|
28
28
|
accountId: string;
|
|
29
|
-
|
|
29
|
+
userId: string;
|
|
30
30
|
brief: {
|
|
31
31
|
topic?: string;
|
|
32
32
|
format: "short" | "long";
|
|
@@ -52,8 +52,8 @@ const EMPTY: VoiceRetrieveConditioningResult = { styleCard: null, exemplars: []
|
|
|
52
52
|
export async function voiceRetrieveConditioning(
|
|
53
53
|
params: VoiceRetrieveConditioningParams,
|
|
54
54
|
): Promise<VoiceRetrieveConditioningResult> {
|
|
55
|
-
const { accountId,
|
|
56
|
-
if (!accountId || !
|
|
55
|
+
const { accountId, userId, brief } = params;
|
|
56
|
+
if (!accountId || !userId) return EMPTY;
|
|
57
57
|
|
|
58
58
|
const k = brief.format === "long" ? 15 : 5;
|
|
59
59
|
const tokenBudget =
|
|
@@ -65,10 +65,10 @@ export async function voiceRetrieveConditioning(
|
|
|
65
65
|
try {
|
|
66
66
|
// 1. Style card.
|
|
67
67
|
const profile = await session.run(
|
|
68
|
-
`MATCH (a:AdminUser {accountId: $accountId,
|
|
68
|
+
`MATCH (a:AdminUser {accountId: $accountId, userId: $userId})
|
|
69
69
|
OPTIONAL MATCH (a)-[:HAS_VOICE_PROFILE]->(p:VoiceProfile)
|
|
70
70
|
RETURN p.styleCard AS styleCard`,
|
|
71
|
-
{ accountId,
|
|
71
|
+
{ accountId, userId },
|
|
72
72
|
);
|
|
73
73
|
const styleCard = (profile.records[0]?.get("styleCard") as string | null) ?? null;
|
|
74
74
|
|
|
@@ -86,7 +86,7 @@ export async function voiceRetrieveConditioning(
|
|
|
86
86
|
coalesce(n.body, n.abstract, n.subject, n.title, n.summary, '') AS body,
|
|
87
87
|
coalesce(n.subject, n.title, n.name, '') AS source,
|
|
88
88
|
ts
|
|
89
|
-
ORDER BY ts
|
|
89
|
+
ORDER BY ts IS NULL, ts DESC
|
|
90
90
|
LIMIT $k`
|
|
91
91
|
: `MATCH (n)
|
|
92
92
|
WHERE ${VOICE_CORPUS_WHERE}
|
|
@@ -96,7 +96,7 @@ export async function voiceRetrieveConditioning(
|
|
|
96
96
|
coalesce(n.body, n.abstract, n.subject, n.title, n.summary, '') AS body,
|
|
97
97
|
coalesce(n.subject, n.title, n.name, '') AS source,
|
|
98
98
|
ts
|
|
99
|
-
ORDER BY ts
|
|
99
|
+
ORDER BY ts IS NULL, ts DESC
|
|
100
100
|
LIMIT $k`;
|
|
101
101
|
|
|
102
102
|
const result = await session.run(cypher, {
|