@genesislcap/ai-assistant 15.86.1 → 15.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/ai-assistant.api.json +5026 -645
  2. package/dist/ai-assistant.d.ts +802 -0
  3. package/dist/chat-driver.cjs +1487 -132
  4. package/dist/chat-driver.cjs.map +4 -4
  5. package/dist/chat-driver.mjs +1480 -132
  6. package/dist/chat-driver.mjs.map +4 -4
  7. package/dist/custom-elements.json +2779 -657
  8. package/dist/dts/autopilot/autopilot-session.d.ts +25 -0
  9. package/dist/dts/autopilot/autopilot-session.d.ts.map +1 -1
  10. package/dist/dts/chat-driver-node.d.ts +2 -0
  11. package/dist/dts/chat-driver-node.d.ts.map +1 -1
  12. package/dist/dts/components/ai-driver/ai-driver.d.ts +15 -0
  13. package/dist/dts/components/ai-driver/ai-driver.d.ts.map +1 -1
  14. package/dist/dts/components/ai-driver/base-driver-decorator.d.ts +6 -0
  15. package/dist/dts/components/ai-driver/base-driver-decorator.d.ts.map +1 -1
  16. package/dist/dts/components/chat-driver/chat-driver.d.ts +7 -0
  17. package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
  18. package/dist/dts/components/chat-driver/interaction-controller.d.ts +12 -0
  19. package/dist/dts/components/chat-driver/interaction-controller.d.ts.map +1 -1
  20. package/dist/dts/headless/describe-interaction.d.ts +17 -0
  21. package/dist/dts/headless/describe-interaction.d.ts.map +1 -0
  22. package/dist/dts/headless/headless-debug.d.ts +28 -0
  23. package/dist/dts/headless/headless-debug.d.ts.map +1 -0
  24. package/dist/dts/headless/headless-persistence.d.ts +35 -0
  25. package/dist/dts/headless/headless-persistence.d.ts.map +1 -0
  26. package/dist/dts/headless/headless-session.d.ts +180 -0
  27. package/dist/dts/headless/headless-session.d.ts.map +1 -0
  28. package/dist/dts/headless/headless.types.d.ts +435 -0
  29. package/dist/dts/headless/headless.types.d.ts.map +1 -0
  30. package/dist/dts/headless/index.d.ts +5 -0
  31. package/dist/dts/headless/index.d.ts.map +1 -0
  32. package/dist/dts/headless-server/compact.d.ts +52 -0
  33. package/dist/dts/headless-server/compact.d.ts.map +1 -0
  34. package/dist/dts/headless-server/index.d.ts +23 -0
  35. package/dist/dts/headless-server/index.d.ts.map +1 -0
  36. package/dist/dts/headless-server/server.d.ts +13 -0
  37. package/dist/dts/headless-server/server.d.ts.map +1 -0
  38. package/dist/dts/headless-server/types.d.ts +210 -0
  39. package/dist/dts/headless-server/types.d.ts.map +1 -0
  40. package/dist/dts/index.d.ts +2 -0
  41. package/dist/dts/index.d.ts.map +1 -1
  42. package/dist/dts/main/main.d.ts.map +1 -1
  43. package/dist/dts/state/debug-event-log.d.ts +1 -1
  44. package/dist/dts/state/debug-event-log.d.ts.map +1 -1
  45. package/dist/dts/state/decision-surface.d.ts +5 -4
  46. package/dist/dts/state/decision-surface.d.ts.map +1 -1
  47. package/dist/dts/state/persistence/debug-log-assembly.d.ts +49 -0
  48. package/dist/dts/state/persistence/debug-log-assembly.d.ts.map +1 -0
  49. package/dist/dts/state/persistence/index.d.ts +1 -0
  50. package/dist/dts/state/persistence/index.d.ts.map +1 -1
  51. package/dist/dts/state/persistence/session-persister.d.ts +7 -0
  52. package/dist/dts/state/persistence/session-persister.d.ts.map +1 -1
  53. package/dist/dts/types/interaction-surface.d.ts +30 -0
  54. package/dist/dts/types/interaction-surface.d.ts.map +1 -1
  55. package/dist/esm/autopilot/autopilot-session.js +31 -16
  56. package/dist/esm/chat-driver-node.js +8 -0
  57. package/dist/esm/components/ai-driver/base-driver-decorator.js +12 -0
  58. package/dist/esm/components/chat-driver/chat-driver.js +8 -0
  59. package/dist/esm/components/chat-driver/interaction-controller.js +66 -0
  60. package/dist/esm/headless/describe-interaction.js +55 -0
  61. package/dist/esm/headless/headless-debug.js +62 -0
  62. package/dist/esm/headless/headless-persistence.js +192 -0
  63. package/dist/esm/headless/headless-session.js +808 -0
  64. package/dist/esm/headless/headless.types.js +1 -0
  65. package/dist/esm/headless/index.js +3 -0
  66. package/dist/esm/headless-server/compact.js +160 -0
  67. package/dist/esm/headless-server/index.js +21 -0
  68. package/dist/esm/headless-server/server.js +746 -0
  69. package/dist/esm/headless-server/types.js +3 -0
  70. package/dist/esm/index.js +3 -0
  71. package/dist/esm/main/main.js +18 -37
  72. package/dist/esm/state/debug-event-log.js +6 -1
  73. package/dist/esm/state/decision-surface.js +75 -48
  74. package/dist/esm/state/persistence/debug-log-assembly.js +69 -0
  75. package/dist/esm/state/persistence/index.js +1 -0
  76. package/dist/esm/state/persistence/session-persister.js +16 -0
  77. package/dist/headless-server.cjs +853 -0
  78. package/dist/headless-server.cjs.map +7 -0
  79. package/dist/headless-server.mjs +819 -0
  80. package/dist/headless-server.mjs.map +7 -0
  81. package/package.json +28 -18
  82. package/scripts/build-headless-server-node.mjs +42 -0
  83. package/scripts/smoke-chat-driver-node.mjs +3 -0
  84. package/scripts/smoke-headless-server-node.mjs +112 -0
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ export { describeInteraction } from './describe-interaction';
2
+ export { headlessCurrentDebugLog, headlessDiagnosticEntries, headlessMetaSnapshot, } from './headless-debug';
3
+ export { HeadlessSession } from './headless-session';
@@ -0,0 +1,160 @@
1
+ /** How much of an assistant message a reply carries: its first lines, and how long it was. */
2
+ const MESSAGE_LINES = 3;
3
+ const MESSAGE_CHARS = 300;
4
+ /** A turn's final text is what a written question looks like, so it gets more room. */
5
+ const TURN_TEXT_CHARS = 1500;
6
+ /** The first `lines` lines of `text`, at most `chars` characters, and its full length when it was cut. */
7
+ export function firstLines(text, lines, chars) {
8
+ const kept = text.split('\n').slice(0, lines).join('\n');
9
+ const cut = kept.length > chars ? `${kept.slice(0, chars)}…` : kept;
10
+ return cut === text ? { text } : { text: cut, chars: text.length };
11
+ }
12
+ /** The keys of `source` that are set, as a new object: a field with nothing to say is dropped. */
13
+ export function present(source) {
14
+ const out = {};
15
+ for (const [key, value] of Object.entries(source)) {
16
+ if (value === undefined || value === null || value === '' || value === false)
17
+ continue;
18
+ if (Array.isArray(value) && value.length === 0)
19
+ continue;
20
+ out[key] = value;
21
+ }
22
+ return out;
23
+ }
24
+ /**
25
+ * One session event, compact. `decision` and `working` are not reported as events: what the person is asked
26
+ * is the reply's `decision`, and what is working is its `working`. A message carries its first lines and
27
+ * its length; a probe event is the host's view of it (see `ServerOptions.probeEvent`).
28
+ */
29
+ export function compactEvent(event, options = {}) {
30
+ switch (event.type) {
31
+ case 'decision':
32
+ case 'working':
33
+ return undefined;
34
+ case 'settled':
35
+ return Object.assign({ event: 'settled', component: event.component }, present({
36
+ answeredBy: event.answeredBy,
37
+ auto: event.auto,
38
+ raw: event.raw,
39
+ resolvedItself: event.resolvedItself,
40
+ }));
41
+ case 'message': {
42
+ const { text, chars } = firstLines(event.text, MESSAGE_LINES, MESSAGE_CHARS);
43
+ return Object.assign({ event: 'message', text }, present({ chars: chars !== null && chars !== void 0 ? chars : event.chars }));
44
+ }
45
+ case 'turn': {
46
+ const out = Object.assign({ event: 'turn', reason: event.reason }, present({ failureReason: event.failureReason }));
47
+ if (event.text) {
48
+ const { text, chars } = firstLines(event.text, Number.MAX_SAFE_INTEGER, TURN_TEXT_CHARS);
49
+ out.text = text;
50
+ if (chars !== null && chars !== void 0 ? chars : event.chars)
51
+ out.chars = chars !== null && chars !== void 0 ? chars : event.chars;
52
+ }
53
+ return out;
54
+ }
55
+ case 'autopilot':
56
+ // An autopilot that is not available says nothing the reader can use.
57
+ if (event.mode === 'unavailable' && !event.needsUser)
58
+ return undefined;
59
+ return Object.assign({ event: 'autopilot', mode: event.mode, status: event.status }, present({ needsUser: event.needsUser, working: event.working, reason: event.reason }));
60
+ case 'error':
61
+ return { event: 'error', where: event.where, message: event.message };
62
+ case 'probe': {
63
+ const view = options.probeEvent;
64
+ if (!view) {
65
+ const changed = Object.fromEntries(event.changed.map((key) => [key, event.probe[key]]));
66
+ return Object.assign({ event: 'probe' }, changed);
67
+ }
68
+ if (!event.changed.some((key) => view.keys.includes(key)))
69
+ return undefined;
70
+ return Object.assign({ event: view.name }, Object.fromEntries(view.keys.map((key) => { var _a; return [key, (_a = event.probe[key]) !== null && _a !== void 0 ? _a : null]; })));
71
+ }
72
+ default:
73
+ return undefined;
74
+ }
75
+ }
76
+ /** How the platform's Views list marks the preview view (`renderViews`), at the end of its line. */
77
+ const PREVIEW_MARK = ' (shown below as Now)';
78
+ /** The line that carries the preview view as JSON (`renderDecision`). */
79
+ const NOW_PREFIX = 'Now: ';
80
+ /** What `capRead` appends, on a line of its own, to a read it cut. It belongs to the `Now:` line. */
81
+ const CUT_PREFIX = '[Cut at ';
82
+ /**
83
+ * A decision's text without its `Now: <the preview view as JSON>` line, and nothing else (`decisionText:
84
+ * "lean"`). `renderDecision` writes the preview as `Now: ${capRead(JSON.stringify(view))}`: `JSON.stringify`
85
+ * with no indent never breaks a line, so the JSON is the one line, and `capRead` adds a second, `[Cut at …]`,
86
+ * only when it cut it. Both go; in their place is a pointer to `read`. The line is found by position, not
87
+ * by prefix alone: it follows the Views list, whose entry for the preview ends `(shown below as Now)`, so a
88
+ * card that itself has a line starting `Now: ` is not mistaken for it.
89
+ *
90
+ * The text comes back as it was when there is no preview to find (a card with no preview view, or a short-form
91
+ * decision, which shows no `Now:`), or when `views` does not name the one the Views list marks.
92
+ */
93
+ export function leanDecisionText(text, views) {
94
+ var _a;
95
+ const names = Object.keys(views !== null && views !== void 0 ? views : {});
96
+ if (!names.length)
97
+ return text;
98
+ const lines = text.split('\n');
99
+ const marked = lines.findIndex((line) => line.endsWith(PREVIEW_MARK));
100
+ if (marked < 0)
101
+ return text;
102
+ // The entry starts at or before the marked line (a description may run to several lines).
103
+ const startsEntry = (line, name) => line === ` ${name}${PREVIEW_MARK}` || line.startsWith(` ${name} — `);
104
+ let entry = marked;
105
+ while (entry >= 0 && !names.some((n) => startsEntry(lines[entry], n)))
106
+ entry -= 1;
107
+ const view = entry < 0 ? undefined : names.find((n) => startsEntry(lines[entry], n));
108
+ if (view === undefined)
109
+ return text;
110
+ const now = lines.findIndex((line, i) => i > marked && line.startsWith(NOW_PREFIX));
111
+ if (now < 0)
112
+ return text;
113
+ const end = ((_a = lines[now + 1]) === null || _a === void 0 ? void 0 : _a.startsWith(CUT_PREFIX)) ? now + 2 : now + 1;
114
+ lines.splice(now, end - now, `(The "${view}" view is not repeated here: read it with read ${view}.)`);
115
+ return lines.join('\n');
116
+ }
117
+ /**
118
+ * A decision as the reply carries it: what to read and what to choose from, and nothing empty. With
119
+ * `decisionText: "lean"` its `text` leaves out the preview view's JSON ({@link leanDecisionText}); nothing
120
+ * else about it changes.
121
+ */
122
+ export function compactDecision(description, decisionText = 'full') {
123
+ const actions = description.actions.map((a) => (Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (a.n !== undefined ? { n: a.n } : {})), { name: a.name }), present({ label: a.label !== a.name ? a.label : undefined })), { enabled: a.enabled }), present({
124
+ unavailable: a.unavailable,
125
+ args: a.args,
126
+ argsSchema: a.args === 'fields' ? a.argsSchema : undefined,
127
+ }))));
128
+ return Object.assign(Object.assign({ interactionId: description.interactionId, component: description.component, text: decisionText === 'lean'
129
+ ? leanDecisionText(description.text, description.views)
130
+ : description.text, actions }, (description.views && Object.keys(description.views).length
131
+ ? { views: Object.assign({}, description.views) }
132
+ : {})), (description.controller ? {} : { controller: false }));
133
+ }
134
+ /**
135
+ * A decision cut to what a caller who has already read the card needs: which interaction, and the actions as
136
+ * `n`, `name`, `enabled`. For the reply to an edit, and to a refused action, where the card has not changed
137
+ * enough to be worth sending again.
138
+ */
139
+ export function shortDecision(interactionId, component, actions) {
140
+ return {
141
+ interactionId,
142
+ component,
143
+ actions: actions.map((a) => (Object.assign(Object.assign({}, (a.n !== undefined ? { n: a.n } : {})), { name: a.name, enabled: a.enabled }))),
144
+ };
145
+ }
146
+ /** The most an action's `output` may take in a reply, as JSON. */
147
+ const OUTPUT_CHARS = 4000;
148
+ /** What an editing action returned, as the reply carries it: whole when small, else its first characters. */
149
+ export function capOutput(output) {
150
+ let json;
151
+ try {
152
+ json = JSON.stringify(output);
153
+ }
154
+ catch (_a) {
155
+ return String(output);
156
+ }
157
+ if (json === undefined || json.length <= OUTPUT_CHARS)
158
+ return output;
159
+ return { truncated: `${json.slice(0, OUTPUT_CHARS)}…`, chars: json.length };
160
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Node-only entry point for the headless assistant protocol server
3
+ * (`@genesislcap/ai-assistant/headless-server`).
4
+ *
5
+ * The server speaks a small HTTP/JSON protocol over a {@link HeadlessSession}: one JSON command in,
6
+ * one compact JSON reply out. A coding agent or a script can drive an assistant journey with no
7
+ * browser. It uses `node:http` and `node:fs`, so it has an entry of its own, built for Node
8
+ * (`dist/headless-server.{mjs,cjs}`), and is never reachable from the package root
9
+ * (`src/index.ts`): a browser bundle must not see a `node:` import.
10
+ *
11
+ * It knows only a session and Node built-ins. Its imports of `../headless` are type-only, so the
12
+ * bundle carries no second copy of `HeadlessSession`: the session it is given comes from
13
+ * `@genesislcap/ai-assistant` (or `/chat-driver`), whichever the host built it with.
14
+ * `headless-server-entry.test.ts` holds all of this.
15
+ *
16
+ * @packageDocumentation
17
+ * @beta
18
+ */
19
+ export { capOutput, compactDecision, compactEvent, firstLines, leanDecisionText, shortDecision, } from './compact';
20
+ export { createHeadlessServer } from './server';
21
+ export { DECISION_TEXTS, DEFAULT_DECISION_TEXT } from './types';