instar 1.3.51 โ 1.3.52
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/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +12 -3
- package/dist/commands/server.js.map +1 -1
- package/dist/server/AgentServer.d.ts +2 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +1 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +4 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +1 -0
- package/dist/server/routes.js.map +1 -1
- package/dist/threadline/hubCommands.d.ts +8 -0
- package/dist/threadline/hubCommands.d.ts.map +1 -1
- package/dist/threadline/hubCommands.js +25 -5
- package/dist/threadline/hubCommands.js.map +1 -1
- package/dist/threadline/openConversationBrief.d.ts +100 -0
- package/dist/threadline/openConversationBrief.d.ts.map +1 -0
- package/dist/threadline/openConversationBrief.js +234 -0
- package/dist/threadline/openConversationBrief.js.map +1 -0
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +47 -47
- package/upgrades/1.3.52.md +39 -0
- package/upgrades/side-effects/threadline-open-this-llm-naming.md +72 -0
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import type { CollaborationSurfacer } from './CollaborationSurfacer.js';
|
|
10
10
|
import type { ConversationStore } from './ConversationStore.js';
|
|
11
11
|
import type { CommitmentTracker } from '../monitoring/CommitmentTracker.js';
|
|
12
|
+
import { type BriefDeps } from './openConversationBrief.js';
|
|
12
13
|
export type HubCommand = {
|
|
13
14
|
action: 'open';
|
|
14
15
|
} | {
|
|
@@ -36,6 +37,13 @@ export interface HubBindDeps {
|
|
|
36
37
|
silent?: boolean;
|
|
37
38
|
}): Promise<unknown>;
|
|
38
39
|
};
|
|
40
|
+
/**
|
|
41
|
+
* Deps for the LLM topic-name + first-message summary (CMT-567). Optional:
|
|
42
|
+
* when absent, the `open` path degrades to the slug name + legacy tie-marker
|
|
43
|
+
* (exactly the pre-CMT-567 behavior). When present but its own sub-deps are
|
|
44
|
+
* null, `generateConversationBrief` degrades to its template/slug tiers.
|
|
45
|
+
*/
|
|
46
|
+
brief?: BriefDeps;
|
|
39
47
|
}
|
|
40
48
|
export interface HubBindArgs {
|
|
41
49
|
action: 'open' | 'tie';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hubCommands.d.ts","sourceRoot":"","sources":["../../src/threadline/hubCommands.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"hubCommands.d.ts","sourceRoot":"","sources":["../../src/threadline/hubCommands.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAEvF,MAAM,MAAM,UAAU,GAClB;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAe/D;AAED,MAAM,WAAW,WAAW;IAC1B,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,iBAAiB,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC5C,QAAQ,EAAE;QACR,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;QACtH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KAC9F,CAAC;IACF;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;gFAE4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC1F;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA+BjD;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAoEtG"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* is a pure, tightly-anchored matcher so ordinary hub chat falls through to the
|
|
7
7
|
* agent.
|
|
8
8
|
*/
|
|
9
|
+
import { generateConversationBrief } from './openConversationBrief.js';
|
|
9
10
|
/**
|
|
10
11
|
* Deterministically classify a hub-topic message. Returns null for anything
|
|
11
12
|
* that isn't *only* a hub command, so "can you open this and explain it?" is
|
|
@@ -82,6 +83,10 @@ export async function bindHubConversation(deps, args) {
|
|
|
82
83
|
try {
|
|
83
84
|
let topicId;
|
|
84
85
|
let topicName;
|
|
86
|
+
// The first message posted into the topic: for `open` it's the conversation
|
|
87
|
+
// brief (LLM summary / deterministic template); for `tie` it's the tie-marker
|
|
88
|
+
// (the target topic is one the operator already named + populated).
|
|
89
|
+
let firstMessage = `๐งต This Threadline conversation is now tied to this topic โ updates will land here.`;
|
|
85
90
|
if (args.action === 'tie') {
|
|
86
91
|
if (typeof args.targetTopicId === 'number') {
|
|
87
92
|
topicId = args.targetTopicId;
|
|
@@ -98,10 +103,25 @@ export async function bindHubConversation(deps, args) {
|
|
|
98
103
|
}
|
|
99
104
|
else {
|
|
100
105
|
const existing = conversationStore.get(threadId);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
106
|
+
// CMT-567: LLM topic name + summary, with deterministic template/slug
|
|
107
|
+
// fallbacks. When `brief` deps aren't wired, degrade to the slug + tie-marker.
|
|
108
|
+
if (deps.brief) {
|
|
109
|
+
// Inject the real slug fn so the brief's fallback name matches the
|
|
110
|
+
// legacy path exactly (topicNameFor is private to this module).
|
|
111
|
+
const b = await generateConversationBrief(threadId, existing ?? null, { ...deps.brief, topicNameFallback: (c, t) => topicNameFor(c, t) });
|
|
112
|
+
const t = await telegram.findOrCreateForumTopic(b.topicName);
|
|
113
|
+
topicId = t.topicId;
|
|
114
|
+
topicName = t.name;
|
|
115
|
+
firstMessage = b.summary; // never empty โ see openConversationBrief
|
|
116
|
+
console.log(`[hub/bind] open threadId=${threadId.slice(0, 8)} topic=${topicId} nameSource=${b.nameSource} summarySource=${b.summarySource} latencyMs=${b.latencyMs} reason=${b.reason}`);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
const name = topicNameFor(existing ?? null, threadId);
|
|
120
|
+
const t = await telegram.findOrCreateForumTopic(name);
|
|
121
|
+
topicId = t.topicId;
|
|
122
|
+
topicName = t.name;
|
|
123
|
+
console.log(`[hub/bind] open threadId=${threadId.slice(0, 8)} topic=${topicId} nameSource=slug summarySource=slug latencyMs=0 reason=no-brief-deps`);
|
|
124
|
+
}
|
|
105
125
|
}
|
|
106
126
|
// Authoritative bind: conversation + commitment.
|
|
107
127
|
await conversationStore.mutate(threadId, (c) => { c.boundTopicId = topicId; return c; });
|
|
@@ -115,7 +135,7 @@ export async function bindHubConversation(deps, args) {
|
|
|
115
135
|
}
|
|
116
136
|
}
|
|
117
137
|
collaborationSurfacer.markBound(threadId);
|
|
118
|
-
await telegram.sendToTopic(topicId,
|
|
138
|
+
await telegram.sendToTopic(topicId, firstMessage).catch(() => { });
|
|
119
139
|
await collaborationSurfacer.noteInHub(`Opened "${topicName}" (conversation ${threadId.slice(0, 8)}).`);
|
|
120
140
|
return { ok: true, action: args.action, threadId, topicId, topicName };
|
|
121
141
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hubCommands.js","sourceRoot":"","sources":["../../src/threadline/hubCommands.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"hubCommands.js","sourceRoot":"","sources":["../../src/threadline/hubCommands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* openConversationBrief โ builds the topic NAME + first-message SUMMARY for a
|
|
3
|
+
* Threadline conversation being promoted into its own topic via "open this"
|
|
4
|
+
* (CMT-567, continuation of the deterministic intercept in CMT-529).
|
|
5
|
+
*
|
|
6
|
+
* Three tiers, best-quality-first, each degrading WITHOUT ever failing the bind
|
|
7
|
+
* (the caller `bindHubConversation` must always get a non-empty name + summary):
|
|
8
|
+
*
|
|
9
|
+
* Tier A โ LLM: a real conversation (>=2 messages) โ a Haiku call using the
|
|
10
|
+
* proven PURPOSE-line convention (NOT JSON โ see TopicSummarizer).
|
|
11
|
+
* PURPOSE โ name, body โ summary. Runs on the `interactive`
|
|
12
|
+
* lane (the operator is watching for the topic to appear).
|
|
13
|
+
* Tier B โ template: deterministic brief from data already on hand (peer,
|
|
14
|
+
* message count, last activity, last inbound line). Zero cost,
|
|
15
|
+
* zero latency. Used when the LLM tier is skipped or fails.
|
|
16
|
+
* Tier C โ slug: no backing conversation at all (a hub-notice-only entry) โ
|
|
17
|
+
* slug name + the legacy tie-marker.
|
|
18
|
+
*
|
|
19
|
+
* The LLM is a GENERATOR, never a gate: any failure degrades the result, never
|
|
20
|
+
* blocks the bind. Spec: docs/specs/THREADLINE-OPEN-THIS-LLM-NAMING-SPEC.md.
|
|
21
|
+
*/
|
|
22
|
+
import type { IntelligenceProvider } from '../core/types.js';
|
|
23
|
+
import type { LlmQueue } from '../monitoring/LlmQueue.js';
|
|
24
|
+
/** A scrubbed, never-empty name + summary for a newly-opened topic. */
|
|
25
|
+
export interface ConversationBrief {
|
|
26
|
+
/** โค 40 chars, scrubbed, NEVER empty. */
|
|
27
|
+
topicName: string;
|
|
28
|
+
/** โค 600 chars, scrubbed, NEVER empty. */
|
|
29
|
+
summary: string;
|
|
30
|
+
/** Where each field actually came from (observability). */
|
|
31
|
+
nameSource: 'llm' | 'template' | 'slug';
|
|
32
|
+
summarySource: 'llm' | 'template' | 'slug';
|
|
33
|
+
/** One-word reason for any non-LLM outcome โ feeds the Fix-1d log line. */
|
|
34
|
+
reason: 'ok' | 'no-conversation' | 'too-few-messages' | 'no-deps' | 'llm-timeout' | 'llm-abort' | 'llm-capped' | 'llm-error' | 'parse-empty' | 'credential-scrub';
|
|
35
|
+
/** Wall-clock ms spent in this call (mostly the LLM wait). */
|
|
36
|
+
latencyMs: number;
|
|
37
|
+
}
|
|
38
|
+
/** Minimal shape of a threadline message row (subset of ThreadlineMessageRow). */
|
|
39
|
+
interface BriefMessageRow {
|
|
40
|
+
direction: 'in' | 'out';
|
|
41
|
+
text: string;
|
|
42
|
+
remoteAgentName: string;
|
|
43
|
+
timestamp: string;
|
|
44
|
+
}
|
|
45
|
+
export interface BriefDeps {
|
|
46
|
+
observability: {
|
|
47
|
+
getThread(threadId: string): {
|
|
48
|
+
messages: BriefMessageRow[];
|
|
49
|
+
} | null;
|
|
50
|
+
} | null;
|
|
51
|
+
llmQueue: LlmQueue | null;
|
|
52
|
+
intelligence: Pick<IntelligenceProvider, 'evaluate'> | null;
|
|
53
|
+
/**
|
|
54
|
+
* Existing topicNameFor() โ always returns a non-empty slug. Optional: the
|
|
55
|
+
* server-built `briefDeps` doesn't carry it (topicNameFor is private to
|
|
56
|
+
* hubCommands); `bindHubConversation` injects the real one so the brief's slug
|
|
57
|
+
* matches the legacy path. A built-in default guards direct callers.
|
|
58
|
+
*/
|
|
59
|
+
topicNameFallback?: (conv: unknown, threadId: string) => string;
|
|
60
|
+
now?: () => number;
|
|
61
|
+
}
|
|
62
|
+
/** Conversation fields the brief reads (subset of the ConversationStore record). */
|
|
63
|
+
export interface BriefConversation {
|
|
64
|
+
subject?: string;
|
|
65
|
+
participants?: {
|
|
66
|
+
peers?: string[];
|
|
67
|
+
};
|
|
68
|
+
remoteAgent?: string;
|
|
69
|
+
lastInboundHash?: string;
|
|
70
|
+
messageCount?: number;
|
|
71
|
+
lastActivityAt?: string;
|
|
72
|
+
}
|
|
73
|
+
/** Scrub + cap a candidate topic name. Returns null if it must degrade. */
|
|
74
|
+
declare function scrubName(raw: string): string | null;
|
|
75
|
+
/** Scrub + cap a candidate summary. Returns null if it must degrade. */
|
|
76
|
+
declare function scrubSummary(raw: string): string | null;
|
|
77
|
+
declare function relativeTime(iso: string | undefined, now: number): string;
|
|
78
|
+
/**
|
|
79
|
+
* Tier-B deterministic template summary. Always non-empty; scrubs the inbound
|
|
80
|
+
* snippet (a cold first message could carry a secret).
|
|
81
|
+
*/
|
|
82
|
+
declare function templateSummary(conv: BriefConversation | null, messages: BriefMessageRow[], now: number): string;
|
|
83
|
+
declare function buildLlmPrompt(messages: BriefMessageRow[]): string;
|
|
84
|
+
/**
|
|
85
|
+
* Build the name + summary for a conversation being opened into its own topic.
|
|
86
|
+
* NEVER throws โ always returns a usable, non-empty ConversationBrief.
|
|
87
|
+
*/
|
|
88
|
+
export declare function generateConversationBrief(threadId: string, conv: BriefConversation | null, deps: BriefDeps, opts?: {
|
|
89
|
+
timeoutMs?: number;
|
|
90
|
+
}): Promise<ConversationBrief>;
|
|
91
|
+
export declare const __testing: {
|
|
92
|
+
scrubName: typeof scrubName;
|
|
93
|
+
scrubSummary: typeof scrubSummary;
|
|
94
|
+
templateSummary: typeof templateSummary;
|
|
95
|
+
buildLlmPrompt: typeof buildLlmPrompt;
|
|
96
|
+
relativeTime: typeof relativeTime;
|
|
97
|
+
LEGACY_MARKER: string;
|
|
98
|
+
};
|
|
99
|
+
export {};
|
|
100
|
+
//# sourceMappingURL=openConversationBrief.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openConversationBrief.d.ts","sourceRoot":"","sources":["../../src/threadline/openConversationBrief.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAG1D,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,UAAU,EAAE,KAAK,GAAG,UAAU,GAAG,MAAM,CAAC;IACxC,aAAa,EAAE,KAAK,GAAG,UAAU,GAAG,MAAM,CAAC;IAC3C,2EAA2E;IAC3E,MAAM,EAAE,IAAI,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,SAAS,GACzD,aAAa,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,GACxD,aAAa,GAAG,kBAAkB,CAAC;IAC3C,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,kFAAkF;AAClF,UAAU,eAAe;IACvB,SAAS,EAAE,IAAI,GAAG,KAAK,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,aAAa,EAAE;QAAE,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG;YAAE,QAAQ,EAAE,eAAe,EAAE,CAAA;SAAE,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9F,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC,GAAG,IAAI,CAAC;IAC5D;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IAChE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAQD,oFAAoF;AACpF,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA4BD,2EAA2E;AAC3E,iBAAS,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAW7C;AAED,wEAAwE;AACxE,iBAAS,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQhD;AAMD,iBAAS,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAUlE;AAED;;;GAGG;AACH,iBAAS,eAAe,CACtB,IAAI,EAAE,iBAAiB,GAAG,IAAI,EAC9B,QAAQ,EAAE,eAAe,EAAE,EAC3B,GAAG,EAAE,MAAM,GACV,MAAM,CAgBR;AAED,iBAAS,cAAc,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,MAAM,CAuB3D;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,iBAAiB,GAAG,IAAI,EAC9B,IAAI,EAAE,SAAS,EACf,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5B,OAAO,CAAC,iBAAiB,CAAC,CAiG5B;AAED,eAAO,MAAM,SAAS;;;;;;;CAA4F,CAAC"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* openConversationBrief โ builds the topic NAME + first-message SUMMARY for a
|
|
3
|
+
* Threadline conversation being promoted into its own topic via "open this"
|
|
4
|
+
* (CMT-567, continuation of the deterministic intercept in CMT-529).
|
|
5
|
+
*
|
|
6
|
+
* Three tiers, best-quality-first, each degrading WITHOUT ever failing the bind
|
|
7
|
+
* (the caller `bindHubConversation` must always get a non-empty name + summary):
|
|
8
|
+
*
|
|
9
|
+
* Tier A โ LLM: a real conversation (>=2 messages) โ a Haiku call using the
|
|
10
|
+
* proven PURPOSE-line convention (NOT JSON โ see TopicSummarizer).
|
|
11
|
+
* PURPOSE โ name, body โ summary. Runs on the `interactive`
|
|
12
|
+
* lane (the operator is watching for the topic to appear).
|
|
13
|
+
* Tier B โ template: deterministic brief from data already on hand (peer,
|
|
14
|
+
* message count, last activity, last inbound line). Zero cost,
|
|
15
|
+
* zero latency. Used when the LLM tier is skipped or fails.
|
|
16
|
+
* Tier C โ slug: no backing conversation at all (a hub-notice-only entry) โ
|
|
17
|
+
* slug name + the legacy tie-marker.
|
|
18
|
+
*
|
|
19
|
+
* The LLM is a GENERATOR, never a gate: any failure degrades the result, never
|
|
20
|
+
* blocks the bind. Spec: docs/specs/THREADLINE-OPEN-THIS-LLM-NAMING-SPEC.md.
|
|
21
|
+
*/
|
|
22
|
+
import { parsePurposeFromResponse } from '../memory/TopicSummarizer.js';
|
|
23
|
+
/** Minimal built-in slug used only when no topicNameFallback is supplied. */
|
|
24
|
+
function defaultSlug(conv, threadId) {
|
|
25
|
+
const peer = (conv?.remoteAgent || conv?.participants?.peers?.[0] || 'agent').replace(/[^\w-]/g, '').slice(0, 24) || 'agent';
|
|
26
|
+
return `${peer} ยท ${(threadId || 'thread').slice(0, 8)}`;
|
|
27
|
+
}
|
|
28
|
+
const NAME_MAX = 40;
|
|
29
|
+
const SUMMARY_MAX = 600;
|
|
30
|
+
const SNIPPET_MAX = 200;
|
|
31
|
+
const MIN_NAME = 4;
|
|
32
|
+
const LEGACY_MARKER = '๐ฌ This Threadline conversation is now tied to this topic โ updates will land here.';
|
|
33
|
+
// A literal secret VALUE (vendor-prefixed token, key block, long bearer-ish blob).
|
|
34
|
+
// Used on LLM output (a name/summary): the english words "token"/"password"/"secret"
|
|
35
|
+
// appear constantly in legitimate technical conversation ("token refresh", "API key
|
|
36
|
+
// rotation") โ matching them would degrade most real summaries. We only block actual
|
|
37
|
+
// credential-looking VALUES here, not topic vocabulary.
|
|
38
|
+
const SECRET_VALUE_RE = /(sk-[A-Za-z0-9]{6,}|xox[baprs]-[A-Za-z0-9-]{6,}|gh[pousr]_[A-Za-z0-9]{6,}|AKIA[0-9A-Z]{8,}|-----BEGIN[ A-Z]*PRIVATE KEY-----|eyJ[A-Za-z0-9_-]{12,}\.[A-Za-z0-9_-]{8,})/;
|
|
39
|
+
// An assignment form ("password: hunter2", "api_key=abc123โฆ") โ only checked on RAW
|
|
40
|
+
// inbound message text (the Tier-B snippet), where a literal value could be pasted.
|
|
41
|
+
const SECRET_ASSIGN_RE = /(password|passwd|secret|api[_-]?key|access[_-]?token|auth[_-]?token|bearer)\s*[:=]\s*\S{6,}/i;
|
|
42
|
+
/** A leaked credential VALUE in LLM-authored prose (name/summary). */
|
|
43
|
+
function hasSecretValue(s) {
|
|
44
|
+
return SECRET_VALUE_RE.test(s);
|
|
45
|
+
}
|
|
46
|
+
/** A credential in RAW message text โ value OR assignment form. */
|
|
47
|
+
function hasSecretInRaw(s) {
|
|
48
|
+
return SECRET_VALUE_RE.test(s) || SECRET_ASSIGN_RE.test(s);
|
|
49
|
+
}
|
|
50
|
+
/** Scrub + cap a candidate topic name. Returns null if it must degrade. */
|
|
51
|
+
function scrubName(raw) {
|
|
52
|
+
const collapsed = (raw ?? '').replace(/[\r\n]+/g, ' ').replace(/\s+/g, ' ').trim();
|
|
53
|
+
if (!collapsed || hasSecretValue(collapsed))
|
|
54
|
+
return null;
|
|
55
|
+
let capped = collapsed.slice(0, NAME_MAX).trim();
|
|
56
|
+
// Cap on a word boundary so a long title doesn't read "โฆpath resol".
|
|
57
|
+
if (collapsed.length > NAME_MAX) {
|
|
58
|
+
const lastSpace = capped.lastIndexOf(' ');
|
|
59
|
+
if (lastSpace >= MIN_NAME)
|
|
60
|
+
capped = capped.slice(0, lastSpace).trim();
|
|
61
|
+
}
|
|
62
|
+
if (capped.length < MIN_NAME)
|
|
63
|
+
return null;
|
|
64
|
+
return capped;
|
|
65
|
+
}
|
|
66
|
+
/** Scrub + cap a candidate summary. Returns null if it must degrade. */
|
|
67
|
+
function scrubSummary(raw) {
|
|
68
|
+
const trimmed = (raw ?? '').trim();
|
|
69
|
+
if (!trimmed || hasSecretValue(trimmed))
|
|
70
|
+
return null;
|
|
71
|
+
if (trimmed.length <= SUMMARY_MAX)
|
|
72
|
+
return trimmed;
|
|
73
|
+
// Cap on a word boundary at/under the limit.
|
|
74
|
+
const slice = trimmed.slice(0, SUMMARY_MAX);
|
|
75
|
+
const lastSpace = slice.lastIndexOf(' ');
|
|
76
|
+
return (lastSpace > SUMMARY_MAX - 80 ? slice.slice(0, lastSpace) : slice).trim();
|
|
77
|
+
}
|
|
78
|
+
function peerName(conv) {
|
|
79
|
+
return conv?.remoteAgent || conv?.participants?.peers?.[0] || 'an agent';
|
|
80
|
+
}
|
|
81
|
+
function relativeTime(iso, now) {
|
|
82
|
+
if (!iso)
|
|
83
|
+
return 'recently';
|
|
84
|
+
const then = Date.parse(iso);
|
|
85
|
+
if (Number.isNaN(then))
|
|
86
|
+
return 'recently';
|
|
87
|
+
const mins = Math.max(0, Math.round((now - then) / 60000));
|
|
88
|
+
if (mins < 1)
|
|
89
|
+
return 'just now';
|
|
90
|
+
if (mins < 60)
|
|
91
|
+
return `${mins} min ago`;
|
|
92
|
+
const hrs = Math.round(mins / 60);
|
|
93
|
+
if (hrs < 24)
|
|
94
|
+
return `${hrs}h ago`;
|
|
95
|
+
return `${Math.round(hrs / 24)}d ago`;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Tier-B deterministic template summary. Always non-empty; scrubs the inbound
|
|
99
|
+
* snippet (a cold first message could carry a secret).
|
|
100
|
+
*/
|
|
101
|
+
function templateSummary(conv, messages, now) {
|
|
102
|
+
const peer = peerName(conv);
|
|
103
|
+
const count = messages.length || conv?.messageCount || 0;
|
|
104
|
+
const lastInbound = [...messages].reverse().find((m) => m.direction === 'in');
|
|
105
|
+
const rawSnippet = (lastInbound?.text ?? conv?.lastInboundHash ?? '').trim();
|
|
106
|
+
const snippet = rawSnippet && !hasSecretInRaw(rawSnippet)
|
|
107
|
+
? rawSnippet.replace(/\s+/g, ' ').slice(0, SNIPPET_MAX)
|
|
108
|
+
: '';
|
|
109
|
+
if (count <= 1) {
|
|
110
|
+
const head = `๐ฌ Conversation with ${peer} ยท just getting started.`;
|
|
111
|
+
return snippet ? `${head}\nOpening message: "${snippet}"` : head;
|
|
112
|
+
}
|
|
113
|
+
const when = relativeTime(conv?.lastActivityAt ?? lastInbound?.timestamp, now);
|
|
114
|
+
const head = `๐ฌ Conversation with ${peer} ยท ${count} messages ยท last activity ${when}.`;
|
|
115
|
+
return snippet ? `${head}\nLatest: "${snippet}"` : head;
|
|
116
|
+
}
|
|
117
|
+
function buildLlmPrompt(messages) {
|
|
118
|
+
const recent = messages.slice(-10).map((m) => {
|
|
119
|
+
const who = m.direction === 'in' ? (m.remoteAgentName || 'them') : 'me';
|
|
120
|
+
const text = m.text.length > 800 ? `${m.text.slice(0, 800)}โฆ` : m.text;
|
|
121
|
+
return `${who}: ${text}`;
|
|
122
|
+
});
|
|
123
|
+
return [
|
|
124
|
+
'You are preparing a forum topic for an operator who is about to open an ongoing',
|
|
125
|
+
'agent-to-agent conversation into its own space. Write a short topic title and a',
|
|
126
|
+
'brief orientation summary.',
|
|
127
|
+
'',
|
|
128
|
+
'Conversation (last messages, oldest โ newest, each side labelled):',
|
|
129
|
+
'<<<',
|
|
130
|
+
recent.join('\n'),
|
|
131
|
+
'>>>',
|
|
132
|
+
'',
|
|
133
|
+
'FORMAT โ your response MUST be exactly:',
|
|
134
|
+
'PURPOSE: <a 4-6 word title naming what this conversation is ABOUT โ not who spoke,',
|
|
135
|
+
' no IDs, no emoji, no quotes>',
|
|
136
|
+
'',
|
|
137
|
+
'<2-4 plain sentences: who the other agent is, what this is about, and where it',
|
|
138
|
+
' currently stands (open question / decision pending / waiting on X). No markdown.>',
|
|
139
|
+
].join('\n');
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Build the name + summary for a conversation being opened into its own topic.
|
|
143
|
+
* NEVER throws โ always returns a usable, non-empty ConversationBrief.
|
|
144
|
+
*/
|
|
145
|
+
export async function generateConversationBrief(threadId, conv, deps, opts) {
|
|
146
|
+
const now = (deps.now ?? Date.now)();
|
|
147
|
+
// 15s default: a real Claude/Codex CLI call on a ~10-message thread measured
|
|
148
|
+
// ~8s end-to-end during test-as-self (CLI cold-start dominates), so the
|
|
149
|
+
// original 3.5s budget would have timed out the happy path on nearly every
|
|
150
|
+
// real "open this" and silently fallen back to the template. 15s keeps the
|
|
151
|
+
// LLM brief as the common outcome; it's a one-shot operator action, the call
|
|
152
|
+
// is non-blocking (onTopicMessage is non-await/non-serial), and the template
|
|
153
|
+
// still covers any call that overruns.
|
|
154
|
+
const timeoutMs = opts?.timeoutMs ?? 15000;
|
|
155
|
+
const slug = (deps.topicNameFallback ?? defaultSlug)(conv, threadId);
|
|
156
|
+
// Tier C โ no backing conversation at all.
|
|
157
|
+
if (!conv) {
|
|
158
|
+
return {
|
|
159
|
+
topicName: slug, summary: LEGACY_MARKER,
|
|
160
|
+
nameSource: 'slug', summarySource: 'slug', reason: 'no-conversation', latencyMs: 0,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
const messages = deps.observability?.getThread(threadId)?.messages ?? [];
|
|
164
|
+
// Tier C โ a conversation record exists but there's nothing to summarize.
|
|
165
|
+
if (messages.length === 0) {
|
|
166
|
+
return {
|
|
167
|
+
topicName: slug, summary: LEGACY_MARKER,
|
|
168
|
+
nameSource: 'slug', summarySource: 'slug', reason: 'no-conversation', latencyMs: 0,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const tmpl = templateSummary(conv, messages, now);
|
|
172
|
+
// Tier B (no LLM possible): deps missing.
|
|
173
|
+
if (!deps.llmQueue || !deps.intelligence) {
|
|
174
|
+
return {
|
|
175
|
+
topicName: slug, summary: tmpl,
|
|
176
|
+
nameSource: 'slug', summarySource: 'template', reason: 'no-deps', latencyMs: 0,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
// Tier B (LLM skipped): too few messages to be worth a call.
|
|
180
|
+
if (messages.length < 2) {
|
|
181
|
+
return {
|
|
182
|
+
topicName: slug, summary: tmpl,
|
|
183
|
+
nameSource: 'slug', summarySource: 'template', reason: 'too-few-messages', latencyMs: 0,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
// Tier A โ LLM. Any failure degrades to the Tier-B template (per-field for scrub).
|
|
187
|
+
const prompt = buildLlmPrompt(messages);
|
|
188
|
+
const intelligence = deps.intelligence;
|
|
189
|
+
let llmReason = 'ok';
|
|
190
|
+
let raw = '';
|
|
191
|
+
try {
|
|
192
|
+
raw = await deps.llmQueue.enqueue('interactive', async (signal) => {
|
|
193
|
+
return await Promise.race([
|
|
194
|
+
intelligence.evaluate(prompt, { model: 'fast', maxTokens: 320, timeoutMs, attribution: { component: 'openConversationBrief' } }),
|
|
195
|
+
new Promise((_, reject) => {
|
|
196
|
+
const t = setTimeout(() => reject(new Error('LLM timeout')), timeoutMs);
|
|
197
|
+
signal.addEventListener('abort', () => { clearTimeout(t); reject(new Error('LLM aborted')); });
|
|
198
|
+
}),
|
|
199
|
+
]);
|
|
200
|
+
}, 2);
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
204
|
+
llmReason = /abort/i.test(msg) ? 'llm-abort'
|
|
205
|
+
: /cap/i.test(msg) ? 'llm-capped'
|
|
206
|
+
: /timeout/i.test(msg) ? 'llm-timeout'
|
|
207
|
+
: 'llm-error';
|
|
208
|
+
}
|
|
209
|
+
if (llmReason !== 'ok' || !raw.trim()) {
|
|
210
|
+
return {
|
|
211
|
+
topicName: slug, summary: tmpl,
|
|
212
|
+
nameSource: 'slug', summarySource: 'template',
|
|
213
|
+
reason: llmReason !== 'ok' ? llmReason : 'parse-empty',
|
|
214
|
+
latencyMs: ((deps.now ?? Date.now)()) - now,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// Parse PURPOSE โ name, body โ summary. Guard the `body || text` echo edge:
|
|
218
|
+
// a PURPOSE-only response returns the whole "PURPOSE: โฆ" string as body.
|
|
219
|
+
const { purpose, body } = parsePurposeFromResponse(raw.trim());
|
|
220
|
+
const llmName = purpose ? scrubName(purpose) : null;
|
|
221
|
+
const bodyIsRealSummary = !!body && !/^purpose:/i.test(body.trim());
|
|
222
|
+
const llmSummary = bodyIsRealSummary ? scrubSummary(body) : null;
|
|
223
|
+
const credentialScrubbed = (purpose && !llmName) || (bodyIsRealSummary && !llmSummary);
|
|
224
|
+
return {
|
|
225
|
+
topicName: llmName ?? slug,
|
|
226
|
+
summary: llmSummary ?? tmpl,
|
|
227
|
+
nameSource: llmName ? 'llm' : 'slug',
|
|
228
|
+
summarySource: llmSummary ? 'llm' : 'template',
|
|
229
|
+
reason: credentialScrubbed ? 'credential-scrub' : (llmName || llmSummary ? 'ok' : 'parse-empty'),
|
|
230
|
+
latencyMs: ((deps.now ?? Date.now)()) - now,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
export const __testing = { scrubName, scrubSummary, templateSummary, buildLlmPrompt, relativeTime, LEGACY_MARKER };
|
|
234
|
+
//# sourceMappingURL=openConversationBrief.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openConversationBrief.js","sourceRoot":"","sources":["../../src/threadline/openConversationBrief.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED