@burtson-labs/agent-core 1.6.46 → 1.6.48
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.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/lessons.d.ts +42 -0
- package/dist/lessons.d.ts.map +1 -0
- package/dist/lessons.js +83 -0
- package/dist/lessons.js.map +1 -0
- package/dist/suggestions.d.ts +38 -0
- package/dist/suggestions.d.ts.map +1 -0
- package/dist/suggestions.js +119 -0
- package/dist/suggestions.js.map +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface CreateAgentRuntimeOptions extends Partial<Omit<AgentRuntimeOpti
|
|
|
13
13
|
export declare const createAgentRuntime: (options?: CreateAgentRuntimeOptions) => AgentRuntime;
|
|
14
14
|
export * from './tools';
|
|
15
15
|
export * from './graph';
|
|
16
|
+
export * from './suggestions';
|
|
17
|
+
export * from './lessons';
|
|
16
18
|
export * from './mcp';
|
|
17
19
|
export { redactSecrets, redactSecretsString, BUILTIN_SECRET_PATTERNS, type SecretPattern, type RedactionResult } from './security/secretPatterns';
|
|
18
20
|
export { TelemetryExporter, resolveTelemetryConfig, TTFT_BUCKETS, DURATION_BUCKETS, type TelemetryConfig } from './telemetry/otlpExporter';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,2BAA2B,EAC3B,2BAA2B,EAC5B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,WAAW,EACX,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,yBAA0B,SAAQ,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,CAAC;IAC/F,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,eAAO,MAAM,kBAAkB,GAAI,UAAS,yBAA8B,KAAG,YAO5E,CAAC;AAGF,cAAc,SAAS,CAAC;AAGxB,cAAc,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,2BAA2B,EAC3B,2BAA2B,EAC5B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,WAAW,EACX,WAAW,EACX,cAAc,EACd,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,yBAA0B,SAAQ,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,CAAC;IAC/F,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,eAAO,MAAM,kBAAkB,GAAI,UAAS,yBAA8B,KAAG,YAO5E,CAAC;AAGF,cAAc,SAAS,CAAC;AAGxB,cAAc,SAAS,CAAC;AAExB,cAAc,eAAe,CAAC;AAE9B,cAAc,WAAW,CAAC;AAK1B,cAAc,OAAO,CAAC;AAKtB,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,uBAAuB,EACvB,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,MAAM,2BAA2B,CAAC;AAInC,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,EAChB,KAAK,eAAe,EACrB,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -41,6 +41,10 @@ __exportStar(require("./tools"), exports);
|
|
|
41
41
|
// Graph runtime (DAG of loop-wrapping nodes). Nothing in the framework
|
|
42
42
|
// consumes it yet — hosts opt in explicitly; zero behavior change until then.
|
|
43
43
|
__exportStar(require("./graph"), exports);
|
|
44
|
+
// Next-prompt prediction (composer "what's next?" suggestions).
|
|
45
|
+
__exportStar(require("./suggestions"), exports);
|
|
46
|
+
// Learning memory — distill durable repo lessons from turns (host stores them).
|
|
47
|
+
__exportStar(require("./lessons"), exports);
|
|
44
48
|
// MCP — Model Context Protocol client (Phase 1: groundwork). See
|
|
45
49
|
// docs/integration-playlist/mcp-roadmap.md. Off by default — hosts
|
|
46
50
|
// that don't construct an McpClientPool get zero behavior change.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AACA,yDAAsD;AACtD,+EAAiF;AAGjF,gDAA8B;AAC9B,gDAA8B;AAC9B,uCAAkD;AAAzC,0GAAA,iBAAiB,OAAA;AAE1B,+DAIqC;AADnC,oHAAA,iBAAiB,OAAA;AAGnB,6EAG4C;AAF1C,qIAAA,2BAA2B,OAAA;AAI7B,uDAUgC;AAT9B,4GAAA,YAAY,OAAA;AAeP,MAAM,kBAAkB,GAAG,CAAC,UAAqC,EAAE,EAAgB,EAAE;IAC1F,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACxD,MAAM,QAAQ,GAAG,gBAAgB,IAAI,IAAI,oDAA2B,EAAE,CAAC;IACvE,OAAO,IAAI,2BAAY,CAAC;QACtB,QAAQ;QACR,GAAI,IAA8C;KACnD,CAAC,CAAC;AACL,CAAC,CAAC;AAPW,QAAA,kBAAkB,sBAO7B;AAEF,cAAc;AACd,0CAAwB;AACxB,uEAAuE;AACvE,8EAA8E;AAC9E,0CAAwB;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AACA,yDAAsD;AACtD,+EAAiF;AAGjF,gDAA8B;AAC9B,gDAA8B;AAC9B,uCAAkD;AAAzC,0GAAA,iBAAiB,OAAA;AAE1B,+DAIqC;AADnC,oHAAA,iBAAiB,OAAA;AAGnB,6EAG4C;AAF1C,qIAAA,2BAA2B,OAAA;AAI7B,uDAUgC;AAT9B,4GAAA,YAAY,OAAA;AAeP,MAAM,kBAAkB,GAAG,CAAC,UAAqC,EAAE,EAAgB,EAAE;IAC1F,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACxD,MAAM,QAAQ,GAAG,gBAAgB,IAAI,IAAI,oDAA2B,EAAE,CAAC;IACvE,OAAO,IAAI,2BAAY,CAAC;QACtB,QAAQ;QACR,GAAI,IAA8C;KACnD,CAAC,CAAC;AACL,CAAC,CAAC;AAPW,QAAA,kBAAkB,sBAO7B;AAEF,cAAc;AACd,0CAAwB;AACxB,uEAAuE;AACvE,8EAA8E;AAC9E,0CAAwB;AACxB,gEAAgE;AAChE,gDAA8B;AAC9B,gFAAgF;AAChF,4CAA0B;AAE1B,iEAAiE;AACjE,mEAAmE;AACnE,kEAAkE;AAClE,wCAAsB;AAEtB,wDAAwD;AACxD,mEAAmE;AACnE,4CAA4C;AAC5C,4DAMmC;AALjC,+GAAA,aAAa,OAAA;AACb,qHAAA,mBAAmB,OAAA;AACnB,yHAAA,uBAAuB,OAAA;AAKzB,iFAAiF;AACjF,iFAAiF;AACjF,yDAMkC;AALhC,iHAAA,iBAAiB,OAAA;AACjB,sHAAA,sBAAsB,OAAA;AACtB,4GAAA,YAAY,OAAA;AACZ,gHAAA,gBAAgB,OAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Learning memory — the distiller half.
|
|
3
|
+
*
|
|
4
|
+
* After a turn, the host may make ONE cheap model call asking: did anything
|
|
5
|
+
* DURABLE and REPO-GENERAL happen here worth remembering for future tasks?
|
|
6
|
+
* ("this project uses pnpm, not npm"; "tests for src/api live in test/api";
|
|
7
|
+
* "the build fails unless you run codegen first"). Most turns yield nothing —
|
|
8
|
+
* the point is to accrue a SMALL set of high-signal, reusable facts about a
|
|
9
|
+
* specific repo, not a diary. Those facts are stored (see host-kit's lesson
|
|
10
|
+
* store) and injected on future turns so the agent gets better at THIS repo
|
|
11
|
+
* over time.
|
|
12
|
+
*
|
|
13
|
+
* This module is the shared, host-agnostic core: build the (small) prompt,
|
|
14
|
+
* parse the reply into a lesson or nothing. Pure + fully unit-testable, same
|
|
15
|
+
* split as the planner and next-prompt suggestions. The host owns the model
|
|
16
|
+
* call, the persistence, and the opt-in gate (off by default — it's an extra
|
|
17
|
+
* call per turn, and a store the model writes to deserves a deliberate opt-in).
|
|
18
|
+
*/
|
|
19
|
+
export interface LessonTurn {
|
|
20
|
+
/** The user's prompt for the turn. */
|
|
21
|
+
prompt: string;
|
|
22
|
+
/** The assistant's final response. */
|
|
23
|
+
assistantResponse: string;
|
|
24
|
+
/** Tool names used this turn, in order (optional but sharpens distillation). */
|
|
25
|
+
toolsUsed?: string[];
|
|
26
|
+
/** Whether the turn succeeded, if the host knows (a failure often teaches
|
|
27
|
+
* the most durable lesson — "X doesn't work here, do Y"). */
|
|
28
|
+
outcome?: 'ok' | 'error';
|
|
29
|
+
}
|
|
30
|
+
/** The sentinel a well-behaved model returns when nothing is worth storing. */
|
|
31
|
+
export declare const NO_LESSON = "NONE";
|
|
32
|
+
export declare function buildLessonPrompt(turn: LessonTurn): string;
|
|
33
|
+
/**
|
|
34
|
+
* Parse the distiller reply into a lesson, or null when nothing was learned.
|
|
35
|
+
* Never throws. Filters NONE, empties, over-long/paragraph replies, and the
|
|
36
|
+
* "here's a lesson:" preamble the model sometimes adds.
|
|
37
|
+
*/
|
|
38
|
+
export declare function parseLesson(text: string): string | null;
|
|
39
|
+
/** Normalize a lesson for dedup comparison (lowercase, collapse whitespace,
|
|
40
|
+
* drop trailing punctuation). Two lessons that normalize equal are dupes. */
|
|
41
|
+
export declare function normalizeLesson(lesson: string): string;
|
|
42
|
+
//# sourceMappingURL=lessons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lessons.d.ts","sourceRoot":"","sources":["../src/lessons.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,UAAU;IACzB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;kEAC8D;IAC9D,OAAO,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC;CAC1B;AAED,+EAA+E;AAC/E,eAAO,MAAM,SAAS,SAAS,CAAC;AAEhC,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAwB1D;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAevD;AAED;8EAC8E;AAC9E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD"}
|
package/dist/lessons.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Learning memory — the distiller half.
|
|
4
|
+
*
|
|
5
|
+
* After a turn, the host may make ONE cheap model call asking: did anything
|
|
6
|
+
* DURABLE and REPO-GENERAL happen here worth remembering for future tasks?
|
|
7
|
+
* ("this project uses pnpm, not npm"; "tests for src/api live in test/api";
|
|
8
|
+
* "the build fails unless you run codegen first"). Most turns yield nothing —
|
|
9
|
+
* the point is to accrue a SMALL set of high-signal, reusable facts about a
|
|
10
|
+
* specific repo, not a diary. Those facts are stored (see host-kit's lesson
|
|
11
|
+
* store) and injected on future turns so the agent gets better at THIS repo
|
|
12
|
+
* over time.
|
|
13
|
+
*
|
|
14
|
+
* This module is the shared, host-agnostic core: build the (small) prompt,
|
|
15
|
+
* parse the reply into a lesson or nothing. Pure + fully unit-testable, same
|
|
16
|
+
* split as the planner and next-prompt suggestions. The host owns the model
|
|
17
|
+
* call, the persistence, and the opt-in gate (off by default — it's an extra
|
|
18
|
+
* call per turn, and a store the model writes to deserves a deliberate opt-in).
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.NO_LESSON = void 0;
|
|
22
|
+
exports.buildLessonPrompt = buildLessonPrompt;
|
|
23
|
+
exports.parseLesson = parseLesson;
|
|
24
|
+
exports.normalizeLesson = normalizeLesson;
|
|
25
|
+
/** The sentinel a well-behaved model returns when nothing is worth storing. */
|
|
26
|
+
exports.NO_LESSON = 'NONE';
|
|
27
|
+
function buildLessonPrompt(turn) {
|
|
28
|
+
const tools = turn.toolsUsed?.length ? `\nTools used: ${turn.toolsUsed.join(', ')}` : '';
|
|
29
|
+
const outcome = turn.outcome ? `\nOutcome: ${turn.outcome}` : '';
|
|
30
|
+
const clip = (s, n) => (s.length > n ? s.slice(0, n) + '…' : s);
|
|
31
|
+
return [
|
|
32
|
+
'You maintain a small memory of DURABLE facts about THIS specific repository, to help future coding tasks.',
|
|
33
|
+
'Look at the turn below and decide: did it reveal a fact that is (a) specific to this repo, (b) still true next week, and (c) genuinely useful for a future task?',
|
|
34
|
+
'',
|
|
35
|
+
'Good lessons (store these):',
|
|
36
|
+
'- "This project uses pnpm; npm install breaks the workspace."',
|
|
37
|
+
'- "Tests for src/api/* live in test/api/* and must be updated alongside."',
|
|
38
|
+
'- "The build needs `pnpm codegen` run before `pnpm build`."',
|
|
39
|
+
'',
|
|
40
|
+
'NOT lessons (never store these):',
|
|
41
|
+
'- Anything about this ONE task ("added a clamp function") — that\'s history, not a durable fact.',
|
|
42
|
+
'- Generic programming advice true of any repo.',
|
|
43
|
+
'- Anything you are not confident is actually true of this repo.',
|
|
44
|
+
'',
|
|
45
|
+
`Reply with ONE short sentence (the lesson, max ~140 chars) OR exactly "${exports.NO_LESSON}" if nothing durable was learned. Most turns are "${exports.NO_LESSON}". No preamble, no quotes, no markdown.`,
|
|
46
|
+
'',
|
|
47
|
+
'--- turn ---',
|
|
48
|
+
`User: ${clip(turn.prompt, 500)}`,
|
|
49
|
+
`Assistant: ${clip(turn.assistantResponse, 800)}${tools}${outcome}`,
|
|
50
|
+
].join('\n');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Parse the distiller reply into a lesson, or null when nothing was learned.
|
|
54
|
+
* Never throws. Filters NONE, empties, over-long/paragraph replies, and the
|
|
55
|
+
* "here's a lesson:" preamble the model sometimes adds.
|
|
56
|
+
*/
|
|
57
|
+
function parseLesson(text) {
|
|
58
|
+
let s = (text ?? '').trim();
|
|
59
|
+
if (!s)
|
|
60
|
+
return null;
|
|
61
|
+
// Strip a leading "lesson:" / "fact:" label if present.
|
|
62
|
+
s = s.replace(/^\s*(lesson|fact|answer)\s*:\s*/i, '').trim();
|
|
63
|
+
// Strip surrounding quotes/backticks/markdown bullet.
|
|
64
|
+
s = s.replace(/^[-*]\s+/, '').replace(/^["'`]+|["'`]+$/g, '').trim();
|
|
65
|
+
if (!s)
|
|
66
|
+
return null;
|
|
67
|
+
// Explicit "nothing to learn" in any casing/punctuation.
|
|
68
|
+
if (/^none[.!]?$/i.test(s))
|
|
69
|
+
return null;
|
|
70
|
+
// A model that ignored instructions and wrote a paragraph isn't a lesson.
|
|
71
|
+
if (s.length > 200)
|
|
72
|
+
return null;
|
|
73
|
+
// Refuse suspiciously generic non-facts.
|
|
74
|
+
if (/^(no|n\/a|nothing|not applicable|no lesson)\b/i.test(s))
|
|
75
|
+
return null;
|
|
76
|
+
return s;
|
|
77
|
+
}
|
|
78
|
+
/** Normalize a lesson for dedup comparison (lowercase, collapse whitespace,
|
|
79
|
+
* drop trailing punctuation). Two lessons that normalize equal are dupes. */
|
|
80
|
+
function normalizeLesson(lesson) {
|
|
81
|
+
return lesson.toLowerCase().replace(/\s+/g, ' ').replace(/[.!]+$/g, '').trim();
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=lessons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lessons.js","sourceRoot":"","sources":["../src/lessons.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;AAiBH,8CAwBC;AAOD,kCAeC;AAID,0CAEC;AAvDD,+EAA+E;AAClE,QAAA,SAAS,GAAG,MAAM,CAAC;AAEhC,SAAgB,iBAAiB,CAAC,IAAgB;IAChD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,iBAAiB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACzF,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,CAAS,EAAU,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxF,OAAO;QACL,2GAA2G;QAC3G,kKAAkK;QAClK,EAAE;QACF,6BAA6B;QAC7B,+DAA+D;QAC/D,2EAA2E;QAC3E,6DAA6D;QAC7D,EAAE;QACF,kCAAkC;QAClC,kGAAkG;QAClG,gDAAgD;QAChD,iEAAiE;QACjE,EAAE;QACF,0EAA0E,iBAAS,qDAAqD,iBAAS,yCAAyC;QAC1L,EAAE;QACF,cAAc;QACd,SAAS,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE;QACjC,cAAc,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,GAAG,CAAC,GAAG,KAAK,GAAG,OAAO,EAAE;KACpE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,SAAgB,WAAW,CAAC,IAAY;IACtC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,wDAAwD;IACxD,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,kCAAkC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7D,sDAAsD;IACtD,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACrE,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,yDAAyD;IACzD,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,0EAA0E;IAC1E,IAAI,CAAC,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,IAAI,CAAC;IAChC,yCAAyC;IACzC,IAAI,gDAAgD,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1E,OAAO,CAAC,CAAC;AACX,CAAC;AAED;8EAC8E;AAC9E,SAAgB,eAAe,CAAC,MAAc;IAC5C,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Next-prompt prediction — the "what will you ask next?" composer feature.
|
|
3
|
+
*
|
|
4
|
+
* After a turn completes, a host may make ONE cheap, separate model call to
|
|
5
|
+
* suggest the user's likely next prompts, rendered as selectable chips (IDE)
|
|
6
|
+
* or a hint line (CLI). This module is the shared, host-agnostic core: it
|
|
7
|
+
* builds the (small) prompt and parses the reply. The host owns the model
|
|
8
|
+
* call + rendering, so CLI and extension share identical behavior.
|
|
9
|
+
*
|
|
10
|
+
* Mirrors the planner's split (buildPlannerPrompt / parseGraphProposal): pure
|
|
11
|
+
* functions, no IO, fully unit-testable. Deliberately tiny — this is a
|
|
12
|
+
* latency- and token-sensitive path that runs after every eligible turn, so
|
|
13
|
+
* the prompt is short and the reply is capped.
|
|
14
|
+
*
|
|
15
|
+
* Cost-gating is the host's job and defaults OFF (an extra call per turn is
|
|
16
|
+
* exactly the kind of opt-in cost the framework keeps off by default).
|
|
17
|
+
*/
|
|
18
|
+
export interface SuggestionTurn {
|
|
19
|
+
role: 'user' | 'assistant';
|
|
20
|
+
content: string;
|
|
21
|
+
}
|
|
22
|
+
export interface SuggestionPromptOptions {
|
|
23
|
+
/** How many suggestions to ask for. Default 3; clamped to 1..5. */
|
|
24
|
+
count?: number;
|
|
25
|
+
/** Recently touched files, to bias suggestions toward the actual work. */
|
|
26
|
+
recentFiles?: string[];
|
|
27
|
+
/** Max chars of each turn we include (keeps the prompt cheap). Default 600. */
|
|
28
|
+
perTurnChars?: number;
|
|
29
|
+
}
|
|
30
|
+
/** Build the suggestion prompt from the tail of the conversation. */
|
|
31
|
+
export declare function buildSuggestionsPrompt(conversation: SuggestionTurn[], opts?: SuggestionPromptOptions): string;
|
|
32
|
+
/**
|
|
33
|
+
* Parse suggestions from the model reply. Accepts a ```json fence or a bare
|
|
34
|
+
* array; tolerates prose around it. Never throws — returns [] on anything
|
|
35
|
+
* unparseable, deduped, trimmed, and capped.
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseSuggestions(text: string, max?: number): string[];
|
|
38
|
+
//# sourceMappingURL=suggestions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggestions.d.ts","sourceRoot":"","sources":["../src/suggestions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACtC,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qEAAqE;AACrE,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,cAAc,EAAE,EAC9B,IAAI,GAAE,uBAA4B,GACjC,MAAM,CAuBR;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAI,GAAG,MAAM,EAAE,CAyBhE"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Next-prompt prediction — the "what will you ask next?" composer feature.
|
|
4
|
+
*
|
|
5
|
+
* After a turn completes, a host may make ONE cheap, separate model call to
|
|
6
|
+
* suggest the user's likely next prompts, rendered as selectable chips (IDE)
|
|
7
|
+
* or a hint line (CLI). This module is the shared, host-agnostic core: it
|
|
8
|
+
* builds the (small) prompt and parses the reply. The host owns the model
|
|
9
|
+
* call + rendering, so CLI and extension share identical behavior.
|
|
10
|
+
*
|
|
11
|
+
* Mirrors the planner's split (buildPlannerPrompt / parseGraphProposal): pure
|
|
12
|
+
* functions, no IO, fully unit-testable. Deliberately tiny — this is a
|
|
13
|
+
* latency- and token-sensitive path that runs after every eligible turn, so
|
|
14
|
+
* the prompt is short and the reply is capped.
|
|
15
|
+
*
|
|
16
|
+
* Cost-gating is the host's job and defaults OFF (an extra call per turn is
|
|
17
|
+
* exactly the kind of opt-in cost the framework keeps off by default).
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.buildSuggestionsPrompt = buildSuggestionsPrompt;
|
|
21
|
+
exports.parseSuggestions = parseSuggestions;
|
|
22
|
+
/** Build the suggestion prompt from the tail of the conversation. */
|
|
23
|
+
function buildSuggestionsPrompt(conversation, opts = {}) {
|
|
24
|
+
const count = Math.min(5, Math.max(1, opts.count ?? 3));
|
|
25
|
+
const perTurnChars = opts.perTurnChars ?? 600;
|
|
26
|
+
// Only the last few turns matter for "what's next"; keep it small.
|
|
27
|
+
const tail = conversation.slice(-4).map((t) => {
|
|
28
|
+
const body = t.content.length > perTurnChars ? t.content.slice(0, perTurnChars) + '…' : t.content;
|
|
29
|
+
return `${t.role === 'user' ? 'User' : 'Assistant'}: ${body}`;
|
|
30
|
+
});
|
|
31
|
+
const filesLine = opts.recentFiles?.length
|
|
32
|
+
? `\nRecently touched: ${opts.recentFiles.slice(0, 8).join(', ')}`
|
|
33
|
+
: '';
|
|
34
|
+
return [
|
|
35
|
+
`You suggest the user's likely NEXT prompts in a coding assistant. Based on the exchange below, output ${count} short, concrete follow-ups the user would plausibly type next — the natural next steps (run the tests, commit, explain a change, handle an edge case, etc.).`,
|
|
36
|
+
'',
|
|
37
|
+
'Rules:',
|
|
38
|
+
`- Each suggestion is an imperative the USER would type (e.g. "run the tests", "commit with a message", "add error handling to the parser"). Not questions you'd ask them.`,
|
|
39
|
+
'- Short: 3-8 words. Specific to what just happened, not generic.',
|
|
40
|
+
`- Output ONLY a JSON array of ${count} strings in a \`\`\`json fence. Nothing else.`,
|
|
41
|
+
filesLine,
|
|
42
|
+
'',
|
|
43
|
+
'Recent exchange:',
|
|
44
|
+
...tail,
|
|
45
|
+
].join('\n');
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parse suggestions from the model reply. Accepts a ```json fence or a bare
|
|
49
|
+
* array; tolerates prose around it. Never throws — returns [] on anything
|
|
50
|
+
* unparseable, deduped, trimmed, and capped.
|
|
51
|
+
*/
|
|
52
|
+
function parseSuggestions(text, max = 5) {
|
|
53
|
+
const raw = extractJsonArray(text);
|
|
54
|
+
if (!raw)
|
|
55
|
+
return [];
|
|
56
|
+
let parsed;
|
|
57
|
+
try {
|
|
58
|
+
parsed = JSON.parse(raw);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
if (!Array.isArray(parsed))
|
|
64
|
+
return [];
|
|
65
|
+
const seen = new Set();
|
|
66
|
+
const out = [];
|
|
67
|
+
for (const item of parsed) {
|
|
68
|
+
if (typeof item !== 'string')
|
|
69
|
+
continue;
|
|
70
|
+
const s = item.trim().replace(/^["'`]|["'`]$/g, '').trim();
|
|
71
|
+
// Drop empties, over-long entries, and question-shaped items (we want
|
|
72
|
+
// user imperatives, not the model interviewing the user).
|
|
73
|
+
if (!s || s.length > 80)
|
|
74
|
+
continue;
|
|
75
|
+
const key = s.toLowerCase();
|
|
76
|
+
if (seen.has(key))
|
|
77
|
+
continue;
|
|
78
|
+
seen.add(key);
|
|
79
|
+
out.push(s);
|
|
80
|
+
if (out.length >= max)
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
/** First ```json (or ```) fenced array, else the first bracket-balanced [...]. */
|
|
86
|
+
function extractJsonArray(text) {
|
|
87
|
+
const fence = /```(?:json)?\s*(\[[\s\S]*?\])\s*```/.exec(text);
|
|
88
|
+
if (fence)
|
|
89
|
+
return fence[1].trim();
|
|
90
|
+
const start = text.indexOf('[');
|
|
91
|
+
if (start === -1)
|
|
92
|
+
return null;
|
|
93
|
+
let depth = 0;
|
|
94
|
+
let inString = false;
|
|
95
|
+
let escaped = false;
|
|
96
|
+
for (let i = start; i < text.length; i++) {
|
|
97
|
+
const ch = text[i];
|
|
98
|
+
if (inString) {
|
|
99
|
+
if (escaped)
|
|
100
|
+
escaped = false;
|
|
101
|
+
else if (ch === '\\')
|
|
102
|
+
escaped = true;
|
|
103
|
+
else if (ch === '"')
|
|
104
|
+
inString = false;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (ch === '"')
|
|
108
|
+
inString = true;
|
|
109
|
+
else if (ch === '[')
|
|
110
|
+
depth += 1;
|
|
111
|
+
else if (ch === ']') {
|
|
112
|
+
depth -= 1;
|
|
113
|
+
if (depth === 0)
|
|
114
|
+
return text.slice(start, i + 1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=suggestions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggestions.js","sourceRoot":"","sources":["../src/suggestions.ts"],"names":[],"mappings":"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"}
|